You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

586 lines
13 KiB

--[[
This file is part of 'Masque', an add-on for World of Warcraft. For bug reports,
suggestions and license information, please visit https://github.com/SFX-WoW/Masque.
* File...: Core\Group.lua
* Author.: StormFX, JJSheets
Group API
]]
local MASQUE, Core = ...
----------------------------------------
-- Lua API
---
local error, pairs, type = error, pairs, type
----------------------------------------
-- Internal
---
-- @ Skins\Skins
local Skins = Core.Skins
-- @ Skins\Blizzard(_Classic)
local DEFAULT_SKIN = Core.DEFAULT_SKIN
-- @ Skins\Regions
local ActionTypes, RegTypes = Core.ActionTypes, Core.RegTypes
-- @ Core\Utility
local GetColor, GetScale, NoOp = Core.GetColor, Core.GetScale, Core.NoOp
-- @ Core\Core
local GetRegion, GetType = Core.GetRegion, Core.GetType
-- @ Core\Button
local SkinButton = Core.SkinButton
-- @ Core\Callback
local Callback = Core.Callback
-- @ Core\Regions\*
local SetPulse, SetTextureColor = Core.SetPulse, Core.SetTextureColor
----------------------------------------
-- Locals
---
-- Group Tables
local Group, GMT = {}, {}
-- layers with Color Options
local C_Layers = {
Backdrop = true,
Checked = true,
Cooldown = true,
Flash = true,
Gloss = true,
Highlight = true,
Normal = true,
Pushed = true,
Shadow = true,
}
----------------------------------------
-- Group Metatable
---
-- Adds or reassigns a button to the group.
function GMT:AddButton(Button, Regions, Type, Strict)
local oType, bType = GetType(Button, Type)
if not oType then
if Core.Debug then
error("Bad argument to group method 'AddButton'. 'Button' must be a Button, CheckButton or Frame object.", 2)
end
return
elseif oType == "Frame" then
Strict = true
end
Regions = Regions or Button.__Regions
local Parent = Group[Button]
if Parent then
if Parent == self then
return
else
Regions = Regions or Parent.Buttons[Button]
Parent.Buttons[Button] = nil
end
end
Group[Button] = self
if ActionTypes[bType] then
self.ActionButtons = true
end
if type(Regions) ~= "table" then
Regions = {}
end
if not Strict then
local Layers = RegTypes[bType]
for Layer, Info in pairs(Layers) do
local Region = Regions[Layer]
if Region == nil and not Info.Ignore then
if Layer == "AutoCastShine" then
Region = Regions.Shine or Regions.AutoCast or GetRegion(Button, Info)
elseif Layer == "Backdrop" then
Region = Regions.FloatingBG or GetRegion(Button, Info)
else
Region = GetRegion(Button, Info)
end
Regions[Layer] = Region
end
end
end
self.Buttons[Button] = Regions
Button.__Regions = Regions
Button.__MSQ_Addon = self.Addon
local db = self.db
if not self.Queued then
if Parent and not Parent.db.Disabled and db.Disabled then
SkinButton(Button, Regions, false)
elseif not db.Disabled then
SkinButton(Button, Regions, db.SkinID, db.Backdrop, db.Shadow, db.Gloss, db.Colors, db.Scale, db.Pulse)
end
end
end
-- Deletes the group and applies the default skin to its buttons.
function GMT:Delete()
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:Delete()
end
end
for Button in pairs(self.Buttons) do
self:RemoveButton(Button)
end
local Parent = self.Parent
if Parent then
Parent.SubList[self.ID] = nil
end
Core:UpdateSkinOptions(self, true)
Core.Groups[self.ID] = nil
end
-- Returns a layer's current color.
function GMT:GetColor(Layer)
if Layer then
local Skin = Skins[self.db.SkinID] or DEFAULT_SKIN
return GetColor(self.db.Colors[Layer] or Skin[Layer].Color)
end
end
-- Returns a button region.
function GMT:GetLayer(Button, Layer)
if Button and Layer then
local Regions = self.Buttons[Button]
if Regions then
return Regions[Layer]
end
end
end
-- Creates and returns an AceConfig-3.0 options table for the group.
function GMT:GetOptions(Order)
return Core.GetOptions(self, Order)
end
-- Registers a group-specific callback.
function GMT:RegisterCallback(func, arg)
if self.ID == MASQUE then return end
if type(func) ~= "function" then
if Core.Debug then
error("Bad argument to Group method 'RegisterCallback'. 'func' must be a function.", 2)
end
return
elseif arg and type(arg) ~= "table" then
if Core.Debug then
error("Bad argument to Group method 'RegisterCallback'. 'arg' must be a table or nil.", 2)
end
return
end
self.__arg = arg
self.__func = func
end
-- Removes a button from the group and applies the default skin.
function GMT:RemoveButton(Button)
if Button then
local Regions = self.Buttons[Button]
if Regions and not self.db.Disabled then
SkinButton(Button, Regions, false)
end
Group[Button] = nil
self.Buttons[Button] = nil
end
end
-- Reskins the group with its current settings.
function GMT:ReSkin(Button)
local db = self.db
if not db.Disabled then
if type(Button) == "table" then
local Regions = self.Buttons[Button]
if Regions then
SkinButton(Button, Regions, db.SkinID, db.Backdrop, db.Shadow, db.Gloss, db.Colors, db.Scale, db.Pulse)
end
else
local SkinID, Backdrop, Shadow = db.SkinID, db.Backdrop, db.Shadow
local Gloss, Colors, Pulse = db.Gloss, db.Colors, db.Pulse
for Button, Regions in pairs(self.Buttons) do
SkinButton(Button, Regions, SkinID, Backdrop, Shadow, Gloss, Colors, db.Scale, Pulse)
end
end
end
end
-- Registers a group-specific callback.
function GMT:SetCallback(func, arg, selfCB)
if self.ID == MASQUE then return end
if type(func) ~= "function" then
if Core.Debug then
error("Bad argument to Group method 'SetCallback'. 'func' must be a function.", 2)
end
return
elseif arg and type(arg) ~= "table" then
if Core.Debug then
error("Bad argument to Group method 'SetCallback'. 'arg' must be a table or nil.", 2)
end
return
end
self.__arg = arg
self.__carg = (selfCB and self) or self.ID
self.__func = func
local Warn = Core.db.profile.CB_Warn
local Addon = self.Addon
if Warn[Addon] then
print("|cffff8800Masque Warning:|r", Addon, "called the deprecated API method, |cff000099'SetCallback'|r. Please notify the author or post in the relevant issue on the Masque project page.")
Warn[Addon] = false
end
end
-- Renames the group.
function GMT:SetName(Name)
if not self.StaticID then
return
elseif type(Name) ~= "string" or self.ID == MASQUE then
if Core.Debug then
error("Bad argument to group method 'SetName'. 'Name' must be a string.", 2)
end
return
end
self.Group = Name
Core:UpdateSkinOptions(self)
end
----------------------------------------
-- Internal Methods
---
-- Disables the group.
-- * This methods is intended for internal use only.
function GMT:__Disable(Silent)
self.db.Disabled = true
self.db.Scale = 1
self.db.UseScale = false
for Button, Regions in pairs(self.Buttons) do
SkinButton(Button, Regions, false)
end
if not Silent then
self:__FireCB("Disabled", true)
end
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__Disable(Silent)
end
end
end
-- Enables the group.
-- * This methods is intended for internal use only.
function GMT:__Enable()
self.db.Disabled = false
self:ReSkin()
self:__FireCB("Disabled", false)
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__Enable()
end
end
end
-- Fires the callback.
-- * This methods is intended for internal use only.
-- * Update this in 10.1.0 to remove deprecated callback logic.
function GMT:__FireCB(Option, Value)
local ao = self.Addon or false -- Remove in 10.1.0
local arg = self.__arg
local carg = self.__carg -- Remove in 10.1.0
local func = self.__func
-- Deprecated Callback logic - Remove in 10.1.0
if carg then
local db = self.db
if arg then
func(arg, carg, self.Group, db.SkinID, db.Backdrop, db.Shadow, db.Gloss, db.Colors, db.Disabled)
else
func(carg, self.Group, db.SkinID, db.Backdrop, db.Shadow, db.Gloss, db.Colors, db.Disabled)
end
-- New Callback Logic
elseif func then
if arg then
func(arg, self, Option, Value)
else
func(self, Option, Value)
end
-- Deprecated Callback logic - Remove in 10.1.0
elseif ao then
local db = self.db
Callback(ao, self.Group, db.SkinID, db.Backdrop, db.Shadow, db.Gloss, db.Colors, db.Disabled)
end
end
-- Resets the group's skin settings.
-- * This methods is intended for internal use only.
function GMT:__Reset()
self.db.Backdrop = false
self.db.Shadow = false
self.db.Gloss = false
self.db.Pulse = true
self.db.Scale = 1
self.db.UseScale = false
for Layer in pairs(self.db.Colors) do
self.db.Colors[Layer] = nil
end
self:ReSkin()
self:__FireCB("Reset", true)
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__Reset()
end
end
end
-- Validates and sets a skin option.
-- * This methods is intended for internal use only.
function GMT:__Set(Option, Value)
if not Option then return end
local db = self.db
if Option == "SkinID" then
if Value and Skins[Value] then
db.SkinID = Value
end
self:ReSkin()
elseif Option == "Scale" then
db.Scale = Value or 1
self:ReSkin()
elseif db[Option] ~= nil then
Value = (Value and true) or false
db[Option] = Value
if Option == "Pulse" then
for Button in pairs(self.Buttons) do
SetPulse(Button, Value)
end
elseif Option == "UseScale" and not Value then
db.Scale = 1
self:ReSkin()
else
local func = Core["Skin"..Option]
if func then
local Skin = Skins[db.SkinID] or DEFAULT_SKIN
if Option == "Backdrop" then
for Button, Regions in pairs(self.Buttons) do
func(Value, Regions.Backdrop, Button, Skin.Backdrop, db.Colors.Backdrop, GetScale(Button))
end
else
for Button in pairs(self.Buttons) do
func(Value, Button, Skin[Option], db.Colors[Option], GetScale(Button))
end
end
end
end
else
return
end
self:__FireCB(Option, Value)
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__Set(Option, Value)
end
end
end
-- Sets the specified layer color.
-- * This methods is intended for internal use only.
function GMT:__SetColor(Layer, r, g, b, a)
if not Layer then return end
local db = self.db
local Skin = Skins[db.SkinID] or DEFAULT_SKIN
local sr, sg, sb, sa = GetColor(Skin[Layer].Color)
-- Prevent saving the skin's default color.
if r and ((r ~= sr) or (g ~= sg) or (b ~= sb) or (a ~= sa)) then
db.Colors[Layer] = {r, g, b, a}
else
db.Colors[Layer] = nil
end
local func = Core["Set"..Layer.."Color"]
if func then
for Button, Regions in pairs(self.Buttons) do
func(Regions[Layer], Button, Skin[Layer], db.Colors[Layer])
end
else
for Button, Regions in pairs(self.Buttons) do
SetTextureColor(Layer, Regions[Layer], Button, Skin[Layer], db.Colors[Layer])
end
end
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__SetColor(Layer, r, g, b, a)
end
end
end
-- Updates the group on creation or profile activity.
-- * This methods is intended for internal use only.
function GMT:__Update(IsNew)
local db_Groups = Core.db.profile.Groups
local db = db_Groups[self.ID]
if db == self.db then return end
-- Update the DB the first time a StaticID is used.
if self.StaticID and not db.Upgraded then
local o_id = Core.GetID(self.Addon, self.Group)
local o_db = db_Groups[o_id]
if not o_db.Inherit then
db_Groups[self.ID] = o_db
db = db_Groups[self.ID]
end
db_Groups[o_id] = nil
db.Upgraded = true
end
self.db = db
-- Inheritance
if self.Parent then
local p_db = self.Parent.db
if db.Inherit then
local Options = {"SkinID", "Backdrop", "Shadow", "Gloss", "Pulse", "Scale", "UseScale"}
for i, v in ipairs(Options) do
db[v] = p_db[v]
end
local Colors = db.Colors
local p_Colors = p_db.Colors
for Layer in pairs(C_Layers) do
local Color = Colors[Layer]
local p_Color = p_Colors[Layer]
if type(p_Color) == "table" then
Color = Color or {}
Color[1] = p_Color[1]
Color[2] = p_Color[2]
Color[3] = p_Color[3]
Color[4] = p_Color[4]
Colors[Layer] = Color
else
Colors[Layer] = nil
end
end
db.Inherit = false
end
if p_db.Disabled then
db.Disabled = true
end
end
if IsNew then
-- Queue the group if PLAYER_LOGIN hasn't fired and the skin hasn't loaded.
if Core.Queue and not self.Queued and not Skins[db.SkinID] then
Core.Queue(self)
end
Core:UpdateSkinOptions(self)
else
if db.Disabled then
for Button, Regions in pairs(self.Buttons) do
SkinButton(Button, Regions, false)
end
else
self:ReSkin()
end
local Subs = self.SubList
if Subs then
for _, Sub in pairs(Subs) do
Sub:__Update()
end
end
end
end
----------------------------------------
-- Core
---
Core.Group_MT = {__index = GMT}