flickerstreak@24: --[[ flickerstreak@53: ReAction Action button module. flickerstreak@24: flickerstreak@24: The button module implements standard action button functionality by wrapping Blizzard's flickerstreak@24: ActionButton frame and associated functions. It also provides some button layout flickerstreak@24: modification tools. flickerstreak@24: flickerstreak@24: --]] flickerstreak@24: flickerstreak@24: -- local imports flickerstreak@24: local ReAction = ReAction flickerstreak@24: local L = ReAction.L flickerstreak@24: local _G = _G flickerstreak@24: local CreateFrame = CreateFrame flickerstreak@24: flickerstreak@24: -- module declaration flickerstreak@24: local moduleID = "Action" flickerstreak@28: local module = ReAction:NewModule( moduleID ) flickerstreak@24: flickerstreak@24: -- module methods flickerstreak@24: function module:OnInitialize() flickerstreak@28: self.db = ReAction.db:RegisterNamespace( moduleID, flickerstreak@24: { flickerstreak@28: profile = { flickerstreak@28: buttons = { } flickerstreak@28: } flickerstreak@24: } flickerstreak@24: ) flickerstreak@24: self.buttons = { } flickerstreak@49: flickerstreak@49: ReAction:RegisterOptions("global", self, { flickerstreak@49: hideEmpty = { flickerstreak@49: type = "toggle", flickerstreak@49: name = L["Hide Empty Buttons"], flickerstreak@49: get = function() return self.db.profile.hideEmptyButtons end, flickerstreak@49: set = function(info, val) module:SetHideEmptyButtons(val) end, flickerstreak@49: } flickerstreak@49: }) flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:OnEnable() flickerstreak@53: ReAction:RegisterBarType(L["Action Bar"], flickerstreak@53: { flickerstreak@53: type = moduleID, flickerstreak@53: defaultButtonSize = 36, flickerstreak@53: defaultBarRows = 1, flickerstreak@53: defaultBarCols = 12, flickerstreak@53: defaultBarSpacing = 3 flickerstreak@53: }, true) flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:OnDisable() flickerstreak@53: ReAction:UnregisterBarType(L["Action Bar"]) flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:ApplyToBar(bar) flickerstreak@52: self:RefreshBar(bar) flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:RefreshBar(bar) flickerstreak@53: if bar.config.type == moduleID then flickerstreak@48: if self.buttons[bar] == nil then flickerstreak@48: self.buttons[bar] = { } flickerstreak@48: end flickerstreak@48: local btns = self.buttons[bar] flickerstreak@48: local profile = self.db.profile flickerstreak@48: local barName = bar:GetName() flickerstreak@48: if profile.buttons[barName] == nil then flickerstreak@48: profile.buttons[barName] = {} flickerstreak@48: end flickerstreak@48: local btnCfg = profile.buttons[barName] flickerstreak@24: flickerstreak@48: local r, c = bar:GetButtonGrid() flickerstreak@48: local n = r*c flickerstreak@48: for i = 1, n do flickerstreak@48: if btnCfg[i] == nil then flickerstreak@48: btnCfg[i] = {} flickerstreak@48: end flickerstreak@48: if btns[i] == nil then flickerstreak@52: local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) flickerstreak@52: if ok and b then flickerstreak@52: btns[i] = b flickerstreak@52: end flickerstreak@48: else flickerstreak@48: btns[i]:Refresh(bar,i) flickerstreak@48: end flickerstreak@24: end flickerstreak@48: for i = n+1, #btns do flickerstreak@52: if btns[i] then flickerstreak@52: btns[i] = btns[i]:Destroy() flickerstreak@52: if btnCfg[i] then flickerstreak@52: btnCfg[i] = nil flickerstreak@52: end flickerstreak@48: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:RemoveFromBar(bar) flickerstreak@24: if self.buttons[bar] then flickerstreak@24: local btns = self.buttons[bar] flickerstreak@24: for _,b in pairs(btns) do flickerstreak@24: if b then flickerstreak@24: b:Destroy() flickerstreak@24: end flickerstreak@24: end flickerstreak@24: self.buttons[bar] = nil flickerstreak@24: end flickerstreak@24: end flickerstreak@24: flickerstreak@24: function module:EraseBarConfig(barName) flickerstreak@24: self.db.profile.buttons[barName] = nil flickerstreak@24: end flickerstreak@24: flickerstreak@48: function module:RenameBarConfig(oldname, newname) flickerstreak@48: local b = self.db.profile.buttons flickerstreak@48: b[newname], b[oldname] = b[oldname], nil flickerstreak@48: end flickerstreak@48: flickerstreak@49: function module:SetHideEmptyButtons(hide) flickerstreak@49: if hide ~= self.db.profile.hideEmptyButtons then flickerstreak@49: for _, bar in pairs(self.buttons) do flickerstreak@49: for _, b in pairs(bar) do flickerstreak@49: if hide then flickerstreak@49: ActionButton_HideGrid(b.frame) flickerstreak@49: else flickerstreak@49: ActionButton_ShowGrid(b.frame) flickerstreak@49: end flickerstreak@49: end flickerstreak@49: end flickerstreak@49: self.db.profile.hideEmptyButtons = hide flickerstreak@49: end flickerstreak@49: end flickerstreak@49: flickerstreak@24: function module:ApplyConfigMode(mode,bars) flickerstreak@49: for _, bar in pairs(bars) do flickerstreak@49: if bar and self.buttons[bar] then flickerstreak@49: for _, b in pairs(self.buttons[bar]) do flickerstreak@24: if b then flickerstreak@24: if mode then flickerstreak@49: ActionButton_ShowGrid(b.frame) flickerstreak@50: self:showActionIDLabel(b) flickerstreak@49: else flickerstreak@49: ActionButton_HideGrid(b.frame) flickerstreak@50: self:hideActionIDLabel(b) flickerstreak@24: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: end flickerstreak@24: flickerstreak@50: function module:showActionIDLabel(button) flickerstreak@52: if not button.actionIDLabel and button:GetActionID() then flickerstreak@50: local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge") flickerstreak@50: label:SetAllPoints() flickerstreak@50: label:SetJustifyH("CENTER") flickerstreak@50: label:SetShadowColor(0,0,0,1) flickerstreak@50: label:SetShadowOffset(2,-2) flickerstreak@50: label:SetText(tostring(button:GetActionID())) flickerstreak@50: button.actionIDLabel = label flickerstreak@50: end flickerstreak@50: button.actionIDLabel:Show() flickerstreak@50: end flickerstreak@50: flickerstreak@50: function module:hideActionIDLabel(button) flickerstreak@50: if button.actionIDLabel then flickerstreak@50: button.actionIDLabel:Hide() flickerstreak@50: end flickerstreak@50: end flickerstreak@50: flickerstreak@50: flickerstreak@50: flickerstreak@24: -- use-count of action IDs flickerstreak@53: local nActionIDs = 120 flickerstreak@24: local ActionIDList = setmetatable( {}, { flickerstreak@24: __index = function(self, idx) flickerstreak@24: if idx == nil then flickerstreak@53: for i = 1, nActionIDs do flickerstreak@24: if rawget(self,i) == nil then flickerstreak@24: rawset(self,i,1) flickerstreak@24: return i flickerstreak@24: end flickerstreak@24: end flickerstreak@52: error("ran out of action IDs") flickerstreak@24: else flickerstreak@24: local c = rawget(self,idx) or 0 flickerstreak@24: rawset(self,idx,c+1) flickerstreak@24: return idx flickerstreak@24: end flickerstreak@24: end, flickerstreak@24: __newindex = function(self,idx,value) flickerstreak@24: if value == nil then flickerstreak@24: value = rawget(self,idx) flickerstreak@24: if value == 1 then flickerstreak@24: value = nil flickerstreak@24: elseif value then flickerstreak@24: value = value - 1 flickerstreak@24: end flickerstreak@24: end flickerstreak@24: rawset(self,idx,value) flickerstreak@24: end flickerstreak@24: }) flickerstreak@24: flickerstreak@24: flickerstreak@24: flickerstreak@28: flickerstreak@28: ------ Button class ------ flickerstreak@28: local Button = { } flickerstreak@28: flickerstreak@28: local function Constructor( self, bar, idx, config ) flickerstreak@24: self.bar, self.idx, self.config = bar, idx, config flickerstreak@24: flickerstreak@24: local barFrame = bar:GetFrame() flickerstreak@24: flickerstreak@56: config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx) flickerstreak@49: self.name = config.name flickerstreak@24: config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured flickerstreak@24: flickerstreak@24: local f = CreateFrame("CheckButton", self.name, barFrame, "ActionBarButtonTemplate") flickerstreak@49: flickerstreak@24: -- TODO: re-implement ActionButton event handlers that don't do secure stuff flickerstreak@24: flickerstreak@24: -- this will probably cause taint, using right now for display/debugging purposes flickerstreak@30: f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) flickerstreak@24: f:SetAttribute("action", config.actionID) flickerstreak@49: flickerstreak@24: barFrame:SetAttribute("addchild",f) flickerstreak@49: flickerstreak@24: self.frame = f flickerstreak@24: self:Refresh(bar,idx) flickerstreak@49: flickerstreak@49: if not module.db.profile.hideEmptyButtons then flickerstreak@49: ActionButton_ShowGrid(self.frame) flickerstreak@49: end flickerstreak@50: flickerstreak@50: if ReAction.configMode then flickerstreak@50: ActionButton_ShowGrid(self.frame) flickerstreak@50: module:showActionIDLabel(self) flickerstreak@50: end flickerstreak@24: end flickerstreak@24: flickerstreak@24: function Button:Destroy() flickerstreak@24: local f = self.frame flickerstreak@24: f:UnregisterAllEvents() flickerstreak@24: f:Hide() flickerstreak@24: f:SetParent(UIParent) flickerstreak@24: f:ClearAllPoints() flickerstreak@28: if self.name then flickerstreak@28: _G[self.name] = nil flickerstreak@24: end flickerstreak@52: if self.config.actionID then flickerstreak@52: ActionIDList[self.config.actionID] = nil flickerstreak@52: end flickerstreak@24: self.frame = nil flickerstreak@24: self.config = nil flickerstreak@24: self.bar = nil flickerstreak@24: end flickerstreak@24: flickerstreak@24: function Button:Refresh(bar,idx) flickerstreak@24: bar:PlaceButton(self.frame, idx, 36, 36) flickerstreak@24: end flickerstreak@24: flickerstreak@24: function Button:GetFrame() flickerstreak@24: return self.frame flickerstreak@24: end flickerstreak@24: flickerstreak@24: function Button:GetName() flickerstreak@24: return self.name flickerstreak@24: end flickerstreak@24: flickerstreak@24: function Button:GetActionID() flickerstreak@24: return self.config.actionID flickerstreak@24: end flickerstreak@28: flickerstreak@28: flickerstreak@28: -- export as a class-factory to module flickerstreak@28: module.BtnClass = { flickerstreak@28: new = function(self, ...) flickerstreak@28: local x = { } flickerstreak@28: for k,v in pairs(Button) do flickerstreak@28: x[k] = v flickerstreak@28: end flickerstreak@28: Constructor(x, ...) flickerstreak@28: return x flickerstreak@28: end flickerstreak@28: }