Mercurial > wow > reaction
view modules/ReAction_Action/ReAction_Action.lua @ 77:da8ba8783924
- added revision updater to each code file
- Changed button/bar class mechanic to metatable-based
- Changed buttons to live within a sub-frame, to play nicely between show-empty-buttons and hidestates
- bar frame is now available only via accessor
- Changed some semantics with AddButton/PlaceButton
- Cleaned up action buttons options, fixed hide-when-empty option
- moved show-action-ID-label as a button method
- converted drag overlay from nested-frame to :Raise()
- fixed ReAction:SetConfigMode() to not call event when mode doesn't change
- Fixed ordering for dynamic state tab (always last)
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Mon, 23 Jun 2008 22:27:50 +0000 |
parents | 06cd74bdc7da |
children | 502cdb5666e2 |
line wrap: on
line source
--[[ ReAction Action button module. The button module implements standard action button functionality by wrapping Blizzard's ActionButton frame and associated functions. It also provides support for multiple pages (interacting with the State module) as well as optional action remapping for possessed targets (mind control). --]] -- local imports local ReAction = ReAction local L = ReAction.L local _G = _G local CreateFrame = CreateFrame ReAction:UpdateRevision("$Revision: 103 $") -- module declaration local moduleID = "Action" local module = ReAction:NewModule( moduleID ) -- Button class declaration local Button = { } -- private -- local function RefreshLite(bar) local btns = module.buttons[bar] if btns then for _, b in ipairs(btns) do b:Refresh() end end end -- Event handlers function module:OnInitialize() self.db = ReAction.db:RegisterNamespace( moduleID, { profile = { buttons = { }, bars = { }, } } ) self.buttons = { } ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar") ReAction.RegisterCallback(self, "OnDestroyBar") ReAction.RegisterCallback(self, "OnRefreshBar") ReAction.RegisterCallback(self, "OnEraseBar") ReAction.RegisterCallback(self, "OnRenameBar") ReAction.RegisterCallback(self, "OnConfigModeChanged") end function module:OnEnable() ReAction:RegisterBarType(L["Action Bar"], { type = moduleID, defaultButtonSize = 36, defaultBarRows = 1, defaultBarCols = 12, defaultBarSpacing = 3 }, true) end function module:OnDisable() ReAction:UnregisterBarType(L["Action Bar"]) end function module:OnRefreshBar(event, bar, name) if bar.config.type == moduleID then if self.buttons[bar] == nil then self.buttons[bar] = { } end local btns = self.buttons[bar] local profile = self.db.profile if profile.buttons[name] == nil then profile.buttons[name] = {} end if profile.bars[name] == nil then profile.bars[name] = {} end local btnCfg = profile.buttons[name] local barCfg = profile.bars[name] local r, c = bar:GetButtonGrid() local n = r*c for i = 1, n do if btnCfg[i] == nil then btnCfg[i] = {} end if btns[i] == nil then local b = Button:New(bar, i, btnCfg[i], barCfg) btns[i] = b bar:AddButton(i,b) end end for i = n+1, #btns do if btns[i] then bar:RemoveButton(btns[i]) btns[i] = btns[i]:Destroy() if btnCfg[i] then btnCfg[i] = nil end end end RefreshLite(bar) end end function module:OnDestroyBar(event, bar, name) if self.buttons[bar] then local btns = self.buttons[bar] for _,b in pairs(btns) do if b then b:Destroy() end end self.buttons[bar] = nil end end function module:OnEraseBar(event, bar, name) self.db.profile.buttons[name] = nil self.db.profile.bars[name] = nil end function module:OnRenameBar(event, bar, oldname, newname) local b = self.db.profile.buttons b[newname], b[oldname] = b[oldname], nil b = self.db.profile.bars b[newname], b[oldname] = b[oldname], nil end function module:OnConfigModeChanged(event, mode) for _, bar in pairs(self.buttons) do for _, b in pairs(bar) do b:ShowGrid(mode) b:ShowActionIDLabel(mode) end end end ---- Options ---- local Handler = { } local options = { hideEmpty = { name = L["Hide Empty Buttons"], desc = L["Hide buttons when empty. This option is not supported for multi-state bars"], order = 1, type = "toggle", get = "GetHideEmpty", set = "SetHideEmpty", }, } function module:GetBarOptions(bar) return { type = "group", name = L["Action Buttons"], handler = Handler:New(bar), hidden = "Hidden", args = options } end -- options handler private do local function GetBarConfig( bar ) return module.db.profile.bars[bar:GetName()] end function Handler:New(bar) return setmetatable( { bar = bar }, { __index = Handler } ) end function Handler:Hidden() return self.bar.config.type ~= moduleID end function Handler:SetHideEmpty(info, value) local c = GetBarConfig(self.bar) if value ~= c.hideEmpty then for b in self.bar:IterateButtons() do b:ShowGrid(not value) end c.hideEmpty = value end end function Handler:GetHideEmpty() return GetBarConfig(self.bar).hideEmpty end end ------ Button class ------ -- use-count of action IDs local nActionIDs = 120 local ActionIDList = setmetatable( {}, { __index = function(self, idx) if idx == nil then for i = 1, nActionIDs do if rawget(self,i) == nil then rawset(self,i,1) return i end end error("ran out of action IDs") else local c = rawget(self,idx) or 0 rawset(self,idx,c+1) return idx end end, __newindex = function(self,idx,value) if value == nil then value = rawget(self,idx) if value == 1 then value = nil elseif value then value = value - 1 end end rawset(self,idx,value) end }) function Button:New( bar, idx, config, barConfig ) -- create new self self = setmetatable( { }, {__index = Button} ) self.bar, self.idx, self.config, self.barConfig = bar, idx, config, barConfig config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx) self.name = config.name config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured self.nPages = 1 local f = CreateFrame("CheckButton", self.name, bar:GetButtonFrame(), "ActionBarButtonTemplate") -- this will probably cause taint and/or performance problems, using right now for display/debugging purposes f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) f:SetAttribute("action", config.actionID) -- install mind control action support for all buttons here just for simplicity if self.idx <= 12 then f:SetAttribute("action-mc", 120 + self.idx) end self.frame = f self.normalTexture = getglobal(format("%sNormalTexture",f:GetName())) -- initialize the hide state self:ShowGrid(not barConfig.hideEmpty) if ReAction:GetConfigMode() then self:ShowGrid(true) end -- show the ID label if applicable self:ShowActionIDLabel(ReAction:GetConfigMode()) self:Refresh() return self end function Button:Destroy() local f = self.frame f:UnregisterAllEvents() f:Hide() f:SetParent(UIParent) f:ClearAllPoints() if self.name then _G[self.name] = nil end if self.config.actionID then ActionIDList[self.config.actionID] = nil end if self.config.pages then for _, id in ipairs(self.config.pages) do ActionIDList[id] = nil end end self.frame = nil self.config = nil self.bar = nil end function Button:Refresh() local f = self.frame self.bar:PlaceButton(self, 36, 36) if self.barConfig.mckeybinds then f:SetAttribute("bindings-mc", self.barConfig.mckeybinds[self.idx]) end self:RefreshPages() end function Button:GetFrame() return self.frame end function Button:GetName() return self.name end function Button:GetActionID() return SecureButton_GetModifiedAttribute(self.frame, "action") end function Button:RefreshPages() local nPages = 1 --self.bar:GetNumPages() if nPages ~= self.nPages then local f = self:GetFrame() local c = self.config.pages if nPages > 1 and not c then c = { } self.config.pages = c end for i = 1, nPages do c[i] = ActionIDList[c[i]] -- gets a free one if none configured f:SetAttribute(("action-page%d"):format(i)) end for i = nPages+1, #c do ActionIDList[c[i]] = nil c[i] = nil f:SetAttribute(("action-page%d"):format(i)) end -- TODO: -- apply next-page, prev-page, and direct-page keybinds (via bar:SetStateKeybind abstraction) end end function Button:ShowGrid( show ) if not InCombatLockdown() then -- new in 2.4.1: can't call ActionButton_ShowGrid/HideGrid because they won't update the attribute local f = self.frame local count = f:GetAttribute("showgrid") if show then count = count + 1 else count = count - 1 end if count < 0 then count = 0 end f:SetAttribute("showgrid",count) if count >= 1 and not f:GetAttribute("statehidden") then self.normalTexture:SetVertexColor(1.0, 1.0, 1.0, 0.5); f:Show() elseif count < 1 and not HasAction(self:GetActionID()) then f:Hide() end end end function Button:ShowActionIDLabel( show ) if show then local id = self:GetActionID() if not self.actionIDLabel and id and id ~= 0 then local f = self:GetFrame() local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") label:SetAllPoints() label:SetJustifyH("CENTER") label:SetShadowColor(0,0,0,1) label:SetShadowOffset(2,-2) label:SetText(tostring(id)) self.actionIDLabel = label f:HookScript("OnAttributeChanged", function(frame, attr, value) if attr == "state-parent" then label:SetText(tostring(self:GetActionID())) end end) end self.actionIDLabel:Show() elseif self.actionIDLabel then self.actionIDLabel:Hide() end end