annotate modules/ReAction_Action/ReAction_Action.lua @ 75:06cd74bdc7da

- Cleaned up Bar interface - Move all attribute setting from Bar into State - Separated Moonkin and Tree of Life - Removed PossessBar module - Added some infrastructure for paged/mind control support to Action
author Flick <flickerstreak@gmail.com>
date Mon, 16 Jun 2008 18:46:08 +0000
parents 768be7eb22a0
children da8ba8783924
rev   line source
flickerstreak@24 1 --[[
flickerstreak@53 2 ReAction Action button module.
flickerstreak@24 3
flickerstreak@24 4 The button module implements standard action button functionality by wrapping Blizzard's
flickerstreak@24 5 ActionButton frame and associated functions. It also provides some button layout
flickerstreak@24 6 modification tools.
flickerstreak@24 7
flickerstreak@24 8 --]]
flickerstreak@24 9
flickerstreak@24 10 -- local imports
flickerstreak@24 11 local ReAction = ReAction
flickerstreak@24 12 local L = ReAction.L
flickerstreak@24 13 local _G = _G
flickerstreak@24 14 local CreateFrame = CreateFrame
flickerstreak@24 15
flickerstreak@24 16 -- module declaration
flickerstreak@24 17 local moduleID = "Action"
flickerstreak@28 18 local module = ReAction:NewModule( moduleID )
flickerstreak@24 19
flickerstreak@75 20 -- private --
flickerstreak@75 21 local function GetBarConfig(bar)
flickerstreak@75 22 return module.db.profile.bars[bar:GetName()]
flickerstreak@75 23 end
flickerstreak@75 24
flickerstreak@75 25 local function RefreshLite(bar)
flickerstreak@75 26 local btns = module.buttons[bar]
flickerstreak@75 27 if btns then
flickerstreak@75 28 for _, b in ipairs(btns) do
flickerstreak@75 29 b:Refresh()
flickerstreak@75 30 end
flickerstreak@75 31 end
flickerstreak@75 32 end
flickerstreak@75 33
flickerstreak@75 34
flickerstreak@24 35 -- module methods
flickerstreak@24 36 function module:OnInitialize()
flickerstreak@28 37 self.db = ReAction.db:RegisterNamespace( moduleID,
flickerstreak@24 38 {
flickerstreak@28 39 profile = {
flickerstreak@75 40 buttons = { },
flickerstreak@75 41 bars = { },
flickerstreak@28 42 }
flickerstreak@24 43 }
flickerstreak@24 44 )
flickerstreak@24 45 self.buttons = { }
flickerstreak@49 46
flickerstreak@60 47 ReAction:RegisterOptions(self, {
flickerstreak@60 48 [moduleID] = {
flickerstreak@60 49 type = "group",
flickerstreak@60 50 name = L["Action Bars"],
flickerstreak@60 51 args = {
flickerstreak@60 52 hideEmpty = {
flickerstreak@60 53 type = "toggle",
flickerstreak@60 54 name = L["Hide Empty Buttons"],
flickerstreak@60 55 get = function() return self.db.profile.hideEmptyButtons end,
flickerstreak@60 56 set = function(info, val) module:SetHideEmptyButtons(val) end,
flickerstreak@60 57 }
flickerstreak@60 58 }
flickerstreak@60 59 }
flickerstreak@60 60 })
flickerstreak@63 61
flickerstreak@63 62 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
flickerstreak@63 63
flickerstreak@63 64 ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
flickerstreak@63 65 ReAction.RegisterCallback(self, "OnDestroyBar")
flickerstreak@63 66 ReAction.RegisterCallback(self, "OnRefreshBar")
flickerstreak@63 67 ReAction.RegisterCallback(self, "OnEraseBar")
flickerstreak@63 68 ReAction.RegisterCallback(self, "OnRenameBar")
flickerstreak@63 69 ReAction.RegisterCallback(self, "OnConfigModeChanged")
flickerstreak@63 70
flickerstreak@24 71 end
flickerstreak@24 72
flickerstreak@24 73 function module:OnEnable()
flickerstreak@53 74 ReAction:RegisterBarType(L["Action Bar"],
flickerstreak@53 75 {
flickerstreak@53 76 type = moduleID,
flickerstreak@53 77 defaultButtonSize = 36,
flickerstreak@53 78 defaultBarRows = 1,
flickerstreak@53 79 defaultBarCols = 12,
flickerstreak@53 80 defaultBarSpacing = 3
flickerstreak@53 81 }, true)
flickerstreak@24 82 end
flickerstreak@24 83
flickerstreak@24 84 function module:OnDisable()
flickerstreak@53 85 ReAction:UnregisterBarType(L["Action Bar"])
flickerstreak@24 86 end
flickerstreak@24 87
flickerstreak@63 88 function module:OnRefreshBar(event, bar, name)
flickerstreak@53 89 if bar.config.type == moduleID then
flickerstreak@48 90 if self.buttons[bar] == nil then
flickerstreak@48 91 self.buttons[bar] = { }
flickerstreak@48 92 end
flickerstreak@48 93 local btns = self.buttons[bar]
flickerstreak@48 94 local profile = self.db.profile
flickerstreak@63 95 if profile.buttons[name] == nil then
flickerstreak@63 96 profile.buttons[name] = {}
flickerstreak@48 97 end
flickerstreak@75 98 if profile.bars[name] == nil then
flickerstreak@75 99 profile.bars[name] = {}
flickerstreak@75 100 end
flickerstreak@63 101 local btnCfg = profile.buttons[name]
flickerstreak@75 102 local barCfg = profile.bars[name]
flickerstreak@24 103
flickerstreak@48 104 local r, c = bar:GetButtonGrid()
flickerstreak@48 105 local n = r*c
flickerstreak@48 106 for i = 1, n do
flickerstreak@48 107 if btnCfg[i] == nil then
flickerstreak@48 108 btnCfg[i] = {}
flickerstreak@48 109 end
flickerstreak@48 110 if btns[i] == nil then
flickerstreak@75 111 local ok, b = pcall(self.BtnClass.New, self.BtnClass, bar, i, btnCfg[i], barCfg)
flickerstreak@52 112 if ok and b then
flickerstreak@52 113 btns[i] = b
flickerstreak@75 114 bar:AddButton(i,b)
flickerstreak@52 115 end
flickerstreak@48 116 end
flickerstreak@24 117 end
flickerstreak@48 118 for i = n+1, #btns do
flickerstreak@52 119 if btns[i] then
flickerstreak@75 120 bar:RemoveButton(btns[i])
flickerstreak@52 121 btns[i] = btns[i]:Destroy()
flickerstreak@52 122 if btnCfg[i] then
flickerstreak@52 123 btnCfg[i] = nil
flickerstreak@52 124 end
flickerstreak@48 125 end
flickerstreak@24 126 end
flickerstreak@75 127 RefreshLite(bar)
flickerstreak@24 128 end
flickerstreak@24 129 end
flickerstreak@24 130
flickerstreak@63 131 function module:OnDestroyBar(event, bar, name)
flickerstreak@24 132 if self.buttons[bar] then
flickerstreak@24 133 local btns = self.buttons[bar]
flickerstreak@24 134 for _,b in pairs(btns) do
flickerstreak@24 135 if b then
flickerstreak@24 136 b:Destroy()
flickerstreak@24 137 end
flickerstreak@24 138 end
flickerstreak@24 139 self.buttons[bar] = nil
flickerstreak@24 140 end
flickerstreak@24 141 end
flickerstreak@24 142
flickerstreak@63 143 function module:OnEraseBar(event, bar, name)
flickerstreak@63 144 self.db.profile.buttons[name] = nil
flickerstreak@75 145 self.db.profile.bars[name] = nil
flickerstreak@24 146 end
flickerstreak@24 147
flickerstreak@63 148 function module:OnRenameBar(event, bar, oldname, newname)
flickerstreak@48 149 local b = self.db.profile.buttons
flickerstreak@48 150 b[newname], b[oldname] = b[oldname], nil
flickerstreak@75 151
flickerstreak@75 152 b = self.db.profile.bars
flickerstreak@75 153 b[newname], b[oldname] = b[oldname], nil
flickerstreak@48 154 end
flickerstreak@48 155
flickerstreak@49 156 function module:SetHideEmptyButtons(hide)
flickerstreak@49 157 if hide ~= self.db.profile.hideEmptyButtons then
flickerstreak@49 158 for _, bar in pairs(self.buttons) do
flickerstreak@49 159 for _, b in pairs(bar) do
flickerstreak@49 160 if hide then
flickerstreak@49 161 ActionButton_HideGrid(b.frame)
flickerstreak@49 162 else
flickerstreak@49 163 ActionButton_ShowGrid(b.frame)
flickerstreak@49 164 end
flickerstreak@49 165 end
flickerstreak@49 166 end
flickerstreak@49 167 self.db.profile.hideEmptyButtons = hide
flickerstreak@49 168 end
flickerstreak@49 169 end
flickerstreak@49 170
flickerstreak@63 171 function module:OnConfigModeChanged(event, mode)
flickerstreak@63 172 for _, bar in ReAction:IterateBars() do
flickerstreak@49 173 if bar and self.buttons[bar] then
flickerstreak@49 174 for _, b in pairs(self.buttons[bar]) do
flickerstreak@24 175 if b then
flickerstreak@24 176 if mode then
flickerstreak@49 177 ActionButton_ShowGrid(b.frame)
flickerstreak@50 178 self:showActionIDLabel(b)
flickerstreak@49 179 else
flickerstreak@49 180 ActionButton_HideGrid(b.frame)
flickerstreak@50 181 self:hideActionIDLabel(b)
flickerstreak@24 182 end
flickerstreak@24 183 end
flickerstreak@24 184 end
flickerstreak@24 185 end
flickerstreak@24 186 end
flickerstreak@24 187 end
flickerstreak@24 188
flickerstreak@50 189 function module:showActionIDLabel(button)
flickerstreak@52 190 if not button.actionIDLabel and button:GetActionID() then
flickerstreak@75 191 local f = button:GetFrame()
flickerstreak@75 192 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
flickerstreak@50 193 label:SetAllPoints()
flickerstreak@50 194 label:SetJustifyH("CENTER")
flickerstreak@50 195 label:SetShadowColor(0,0,0,1)
flickerstreak@50 196 label:SetShadowOffset(2,-2)
flickerstreak@50 197 label:SetText(tostring(button:GetActionID()))
flickerstreak@50 198 button.actionIDLabel = label
flickerstreak@75 199 f:HookScript("OnAttributeChanged",
flickerstreak@75 200 function(frame, attr, value)
flickerstreak@75 201 if attr == "state-parent" then
flickerstreak@75 202 label:SetText(tostring(button:GetActionID()))
flickerstreak@75 203 end
flickerstreak@75 204 end)
flickerstreak@50 205 end
flickerstreak@50 206 button.actionIDLabel:Show()
flickerstreak@50 207 end
flickerstreak@50 208
flickerstreak@50 209 function module:hideActionIDLabel(button)
flickerstreak@50 210 if button.actionIDLabel then
flickerstreak@50 211 button.actionIDLabel:Hide()
flickerstreak@50 212 end
flickerstreak@50 213 end
flickerstreak@50 214
flickerstreak@50 215
flickerstreak@60 216 ---- Options ----
flickerstreak@60 217 function module:GetBarOptions(bar)
flickerstreak@63 218 return {
flickerstreak@63 219 type = "group",
flickerstreak@63 220 name = L["Action Buttons"],
flickerstreak@63 221 hidden = function() return bar.config.type ~= moduleID end,
flickerstreak@63 222 args = {
flickerstreak@60 223 }
flickerstreak@63 224 }
flickerstreak@59 225 end
flickerstreak@59 226
flickerstreak@50 227
flickerstreak@24 228 -- use-count of action IDs
flickerstreak@53 229 local nActionIDs = 120
flickerstreak@24 230 local ActionIDList = setmetatable( {}, {
flickerstreak@24 231 __index = function(self, idx)
flickerstreak@24 232 if idx == nil then
flickerstreak@53 233 for i = 1, nActionIDs do
flickerstreak@24 234 if rawget(self,i) == nil then
flickerstreak@24 235 rawset(self,i,1)
flickerstreak@24 236 return i
flickerstreak@24 237 end
flickerstreak@24 238 end
flickerstreak@52 239 error("ran out of action IDs")
flickerstreak@24 240 else
flickerstreak@24 241 local c = rawget(self,idx) or 0
flickerstreak@24 242 rawset(self,idx,c+1)
flickerstreak@24 243 return idx
flickerstreak@24 244 end
flickerstreak@24 245 end,
flickerstreak@24 246 __newindex = function(self,idx,value)
flickerstreak@24 247 if value == nil then
flickerstreak@24 248 value = rawget(self,idx)
flickerstreak@24 249 if value == 1 then
flickerstreak@24 250 value = nil
flickerstreak@24 251 elseif value then
flickerstreak@24 252 value = value - 1
flickerstreak@24 253 end
flickerstreak@24 254 end
flickerstreak@24 255 rawset(self,idx,value)
flickerstreak@24 256 end
flickerstreak@24 257 })
flickerstreak@24 258
flickerstreak@24 259
flickerstreak@24 260
flickerstreak@28 261
flickerstreak@28 262 ------ Button class ------
flickerstreak@28 263 local Button = { }
flickerstreak@28 264
flickerstreak@75 265 local function Constructor( self, bar, idx, config, barConfig )
flickerstreak@75 266 self.bar, self.idx, self.config, self.barConfig = bar, idx, config, barConfig
flickerstreak@24 267
flickerstreak@24 268 local barFrame = bar:GetFrame()
flickerstreak@24 269
flickerstreak@56 270 config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx)
flickerstreak@49 271 self.name = config.name
flickerstreak@24 272 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
flickerstreak@75 273 self.nPages = 1
flickerstreak@24 274
flickerstreak@24 275 local f = CreateFrame("CheckButton", self.name, barFrame, "ActionBarButtonTemplate")
flickerstreak@49 276
flickerstreak@24 277 -- TODO: re-implement ActionButton event handlers that don't do secure stuff
flickerstreak@24 278
flickerstreak@75 279 -- this will probably cause taint and/or performance problems, using right now for display/debugging purposes
flickerstreak@30 280 f:SetScript("OnAttributeChanged", ActionButton_UpdateAction)
flickerstreak@75 281
flickerstreak@24 282 f:SetAttribute("action", config.actionID)
flickerstreak@75 283 -- install mind control action support for all buttons here just for simplicity
flickerstreak@75 284 if self.idx <= 12 then
flickerstreak@75 285 f:SetAttribute("action-mc", 120 + self.idx)
flickerstreak@75 286 end
flickerstreak@49 287
flickerstreak@24 288 barFrame:SetAttribute("addchild",f)
flickerstreak@49 289
flickerstreak@24 290 self.frame = f
flickerstreak@75 291 self:Refresh()
flickerstreak@49 292
flickerstreak@49 293 if not module.db.profile.hideEmptyButtons then
flickerstreak@49 294 ActionButton_ShowGrid(self.frame)
flickerstreak@49 295 end
flickerstreak@50 296
flickerstreak@50 297 if ReAction.configMode then
flickerstreak@50 298 ActionButton_ShowGrid(self.frame)
flickerstreak@50 299 module:showActionIDLabel(self)
flickerstreak@50 300 end
flickerstreak@24 301 end
flickerstreak@24 302
flickerstreak@24 303 function Button:Destroy()
flickerstreak@24 304 local f = self.frame
flickerstreak@24 305 f:UnregisterAllEvents()
flickerstreak@24 306 f:Hide()
flickerstreak@24 307 f:SetParent(UIParent)
flickerstreak@24 308 f:ClearAllPoints()
flickerstreak@28 309 if self.name then
flickerstreak@28 310 _G[self.name] = nil
flickerstreak@24 311 end
flickerstreak@52 312 if self.config.actionID then
flickerstreak@52 313 ActionIDList[self.config.actionID] = nil
flickerstreak@52 314 end
flickerstreak@75 315 if self.config.pages then
flickerstreak@75 316 for _, id in ipairs(self.config.pages) do
flickerstreak@75 317 ActionIDList[id] = nil
flickerstreak@75 318 end
flickerstreak@75 319 end
flickerstreak@24 320 self.frame = nil
flickerstreak@24 321 self.config = nil
flickerstreak@24 322 self.bar = nil
flickerstreak@24 323 end
flickerstreak@24 324
flickerstreak@75 325 function Button:Refresh()
flickerstreak@75 326 local f = self.frame
flickerstreak@75 327 self.bar:PlaceButton(self, 36, 36)
flickerstreak@75 328 if self.barConfig.mckeybinds then
flickerstreak@75 329 f:SetAttribute("bindings-mc", self.barConfig.mckeybinds[self.idx])
flickerstreak@75 330 end
flickerstreak@75 331 self:RefreshPages()
flickerstreak@24 332 end
flickerstreak@24 333
flickerstreak@24 334 function Button:GetFrame()
flickerstreak@24 335 return self.frame
flickerstreak@24 336 end
flickerstreak@24 337
flickerstreak@24 338 function Button:GetName()
flickerstreak@24 339 return self.name
flickerstreak@24 340 end
flickerstreak@24 341
flickerstreak@24 342 function Button:GetActionID()
flickerstreak@75 343 return SecureButton_GetModifiedAttribute(self.frame, "action")
flickerstreak@24 344 end
flickerstreak@28 345
flickerstreak@75 346 function Button:RefreshPages()
flickerstreak@75 347 local nPages = 1 --self.bar:GetNumPages()
flickerstreak@75 348 if nPages ~= self.nPages then
flickerstreak@75 349 local f = self:GetFrame()
flickerstreak@75 350 local c = self.config.pages
flickerstreak@75 351 if nPages > 1 and not c then
flickerstreak@75 352 c = { }
flickerstreak@75 353 self.config.pages = c
flickerstreak@75 354 end
flickerstreak@75 355 for i = 1, nPages do
flickerstreak@75 356 c[i] = ActionIDList[c[i]] -- gets a free one if none configured
flickerstreak@75 357 f:SetAttribute(("action-page%d"):format(i))
flickerstreak@75 358 end
flickerstreak@75 359 for i = nPages+1, #c do
flickerstreak@75 360 ActionIDList[c[i]] = nil
flickerstreak@75 361 c[i] = nil
flickerstreak@75 362 f:SetAttribute(("action-page%d"):format(i))
flickerstreak@75 363 end
flickerstreak@75 364
flickerstreak@75 365 -- TODO:
flickerstreak@75 366 -- apply next-page, prev-page, and direct-page keybinds (via bar:SetStateKeybind abstraction)
flickerstreak@75 367 end
flickerstreak@75 368 end
flickerstreak@28 369
flickerstreak@28 370 -- export as a class-factory to module
flickerstreak@28 371 module.BtnClass = {
flickerstreak@75 372 New = function(self, ...)
flickerstreak@28 373 local x = { }
flickerstreak@28 374 for k,v in pairs(Button) do
flickerstreak@28 375 x[k] = v
flickerstreak@28 376 end
flickerstreak@28 377 Constructor(x, ...)
flickerstreak@28 378 return x
flickerstreak@28 379 end
flickerstreak@28 380 }