Mercurial > wow > reaction
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 76:c8c8610fd864 | 77:da8ba8783924 |
|---|---|
| 1 --[[ | 1 --[[ |
| 2 ReAction Action button module. | 2 ReAction Action button module. |
| 3 | 3 |
| 4 The button module implements standard action button functionality by wrapping Blizzard's | 4 The button module implements standard action button functionality by wrapping Blizzard's |
| 5 ActionButton frame and associated functions. It also provides some button layout | 5 ActionButton frame and associated functions. |
| 6 modification tools. | 6 |
| 7 It also provides support for multiple pages (interacting with the State module) as well | |
| 8 as optional action remapping for possessed targets (mind control). | |
| 7 | 9 |
| 8 --]] | 10 --]] |
| 9 | 11 |
| 10 -- local imports | 12 -- local imports |
| 11 local ReAction = ReAction | 13 local ReAction = ReAction |
| 12 local L = ReAction.L | 14 local L = ReAction.L |
| 13 local _G = _G | 15 local _G = _G |
| 14 local CreateFrame = CreateFrame | 16 local CreateFrame = CreateFrame |
| 15 | 17 |
| 18 ReAction:UpdateRevision("$Revision: 103 $") | |
| 19 | |
| 16 -- module declaration | 20 -- module declaration |
| 17 local moduleID = "Action" | 21 local moduleID = "Action" |
| 18 local module = ReAction:NewModule( moduleID ) | 22 local module = ReAction:NewModule( moduleID ) |
| 19 | 23 |
| 24 -- Button class declaration | |
| 25 local Button = { } | |
| 26 | |
| 20 -- private -- | 27 -- private -- |
| 21 local function GetBarConfig(bar) | |
| 22 return module.db.profile.bars[bar:GetName()] | |
| 23 end | |
| 24 | |
| 25 local function RefreshLite(bar) | 28 local function RefreshLite(bar) |
| 26 local btns = module.buttons[bar] | 29 local btns = module.buttons[bar] |
| 27 if btns then | 30 if btns then |
| 28 for _, b in ipairs(btns) do | 31 for _, b in ipairs(btns) do |
| 29 b:Refresh() | 32 b:Refresh() |
| 30 end | 33 end |
| 31 end | 34 end |
| 32 end | 35 end |
| 33 | 36 |
| 34 | 37 -- Event handlers |
| 35 -- module methods | |
| 36 function module:OnInitialize() | 38 function module:OnInitialize() |
| 37 self.db = ReAction.db:RegisterNamespace( moduleID, | 39 self.db = ReAction.db:RegisterNamespace( moduleID, |
| 38 { | 40 { |
| 39 profile = { | 41 profile = { |
| 40 buttons = { }, | 42 buttons = { }, |
| 42 } | 44 } |
| 43 } | 45 } |
| 44 ) | 46 ) |
| 45 self.buttons = { } | 47 self.buttons = { } |
| 46 | 48 |
| 47 ReAction:RegisterOptions(self, { | |
| 48 [moduleID] = { | |
| 49 type = "group", | |
| 50 name = L["Action Bars"], | |
| 51 args = { | |
| 52 hideEmpty = { | |
| 53 type = "toggle", | |
| 54 name = L["Hide Empty Buttons"], | |
| 55 get = function() return self.db.profile.hideEmptyButtons end, | |
| 56 set = function(info, val) module:SetHideEmptyButtons(val) end, | |
| 57 } | |
| 58 } | |
| 59 } | |
| 60 }) | |
| 61 | |
| 62 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") | 49 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") |
| 63 | 50 |
| 64 ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar") | 51 ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar") |
| 65 ReAction.RegisterCallback(self, "OnDestroyBar") | 52 ReAction.RegisterCallback(self, "OnDestroyBar") |
| 66 ReAction.RegisterCallback(self, "OnRefreshBar") | 53 ReAction.RegisterCallback(self, "OnRefreshBar") |
| 106 for i = 1, n do | 93 for i = 1, n do |
| 107 if btnCfg[i] == nil then | 94 if btnCfg[i] == nil then |
| 108 btnCfg[i] = {} | 95 btnCfg[i] = {} |
| 109 end | 96 end |
| 110 if btns[i] == nil then | 97 if btns[i] == nil then |
| 111 local ok, b = pcall(self.BtnClass.New, self.BtnClass, bar, i, btnCfg[i], barCfg) | 98 local b = Button:New(bar, i, btnCfg[i], barCfg) |
| 112 if ok and b then | 99 btns[i] = b |
| 113 btns[i] = b | 100 bar:AddButton(i,b) |
| 114 bar:AddButton(i,b) | |
| 115 end | |
| 116 end | 101 end |
| 117 end | 102 end |
| 118 for i = n+1, #btns do | 103 for i = n+1, #btns do |
| 119 if btns[i] then | 104 if btns[i] then |
| 120 bar:RemoveButton(btns[i]) | 105 bar:RemoveButton(btns[i]) |
| 151 | 136 |
| 152 b = self.db.profile.bars | 137 b = self.db.profile.bars |
| 153 b[newname], b[oldname] = b[oldname], nil | 138 b[newname], b[oldname] = b[oldname], nil |
| 154 end | 139 end |
| 155 | 140 |
| 156 function module:SetHideEmptyButtons(hide) | |
| 157 if hide ~= self.db.profile.hideEmptyButtons then | |
| 158 for _, bar in pairs(self.buttons) do | |
| 159 for _, b in pairs(bar) do | |
| 160 if hide then | |
| 161 ActionButton_HideGrid(b.frame) | |
| 162 else | |
| 163 ActionButton_ShowGrid(b.frame) | |
| 164 end | |
| 165 end | |
| 166 end | |
| 167 self.db.profile.hideEmptyButtons = hide | |
| 168 end | |
| 169 end | |
| 170 | |
| 171 function module:OnConfigModeChanged(event, mode) | 141 function module:OnConfigModeChanged(event, mode) |
| 172 for _, bar in ReAction:IterateBars() do | 142 for _, bar in pairs(self.buttons) do |
| 173 if bar and self.buttons[bar] then | 143 for _, b in pairs(bar) do |
| 174 for _, b in pairs(self.buttons[bar]) do | 144 b:ShowGrid(mode) |
| 175 if b then | 145 b:ShowActionIDLabel(mode) |
| 176 if mode then | 146 end |
| 177 ActionButton_ShowGrid(b.frame) | |
| 178 self:showActionIDLabel(b) | |
| 179 else | |
| 180 ActionButton_HideGrid(b.frame) | |
| 181 self:hideActionIDLabel(b) | |
| 182 end | |
| 183 end | |
| 184 end | |
| 185 end | |
| 186 end | |
| 187 end | |
| 188 | |
| 189 function module:showActionIDLabel(button) | |
| 190 if not button.actionIDLabel and button:GetActionID() then | |
| 191 local f = button:GetFrame() | |
| 192 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | |
| 193 label:SetAllPoints() | |
| 194 label:SetJustifyH("CENTER") | |
| 195 label:SetShadowColor(0,0,0,1) | |
| 196 label:SetShadowOffset(2,-2) | |
| 197 label:SetText(tostring(button:GetActionID())) | |
| 198 button.actionIDLabel = label | |
| 199 f:HookScript("OnAttributeChanged", | |
| 200 function(frame, attr, value) | |
| 201 if attr == "state-parent" then | |
| 202 label:SetText(tostring(button:GetActionID())) | |
| 203 end | |
| 204 end) | |
| 205 end | |
| 206 button.actionIDLabel:Show() | |
| 207 end | |
| 208 | |
| 209 function module:hideActionIDLabel(button) | |
| 210 if button.actionIDLabel then | |
| 211 button.actionIDLabel:Hide() | |
| 212 end | 147 end |
| 213 end | 148 end |
| 214 | 149 |
| 215 | 150 |
| 216 ---- Options ---- | 151 ---- Options ---- |
| 152 local Handler = { } | |
| 153 | |
| 154 local options = { | |
| 155 hideEmpty = { | |
| 156 name = L["Hide Empty Buttons"], | |
| 157 desc = L["Hide buttons when empty. This option is not supported for multi-state bars"], | |
| 158 order = 1, | |
| 159 type = "toggle", | |
| 160 get = "GetHideEmpty", | |
| 161 set = "SetHideEmpty", | |
| 162 }, | |
| 163 } | |
| 164 | |
| 217 function module:GetBarOptions(bar) | 165 function module:GetBarOptions(bar) |
| 218 return { | 166 return { |
| 219 type = "group", | 167 type = "group", |
| 220 name = L["Action Buttons"], | 168 name = L["Action Buttons"], |
| 221 hidden = function() return bar.config.type ~= moduleID end, | 169 handler = Handler:New(bar), |
| 222 args = { | 170 hidden = "Hidden", |
| 223 } | 171 args = options |
| 224 } | 172 } |
| 225 end | 173 end |
| 226 | 174 |
| 175 -- options handler private | |
| 176 do | |
| 177 local function GetBarConfig( bar ) | |
| 178 return module.db.profile.bars[bar:GetName()] | |
| 179 end | |
| 180 | |
| 181 function Handler:New(bar) | |
| 182 return setmetatable( { bar = bar }, { __index = Handler } ) | |
| 183 end | |
| 184 | |
| 185 function Handler:Hidden() | |
| 186 return self.bar.config.type ~= moduleID | |
| 187 end | |
| 188 | |
| 189 function Handler:SetHideEmpty(info, value) | |
| 190 local c = GetBarConfig(self.bar) | |
| 191 if value ~= c.hideEmpty then | |
| 192 for b in self.bar:IterateButtons() do | |
| 193 b:ShowGrid(not value) | |
| 194 end | |
| 195 c.hideEmpty = value | |
| 196 end | |
| 197 end | |
| 198 | |
| 199 function Handler:GetHideEmpty() | |
| 200 return GetBarConfig(self.bar).hideEmpty | |
| 201 end | |
| 202 end | |
| 203 | |
| 204 | |
| 205 ------ Button class ------ | |
| 227 | 206 |
| 228 -- use-count of action IDs | 207 -- use-count of action IDs |
| 229 local nActionIDs = 120 | 208 local nActionIDs = 120 |
| 230 local ActionIDList = setmetatable( {}, { | 209 local ActionIDList = setmetatable( {}, { |
| 231 __index = function(self, idx) | 210 __index = function(self, idx) |
| 254 end | 233 end |
| 255 rawset(self,idx,value) | 234 rawset(self,idx,value) |
| 256 end | 235 end |
| 257 }) | 236 }) |
| 258 | 237 |
| 259 | 238 function Button:New( bar, idx, config, barConfig ) |
| 260 | 239 -- create new self |
| 261 | 240 self = setmetatable( { }, {__index = Button} ) |
| 262 ------ Button class ------ | |
| 263 local Button = { } | |
| 264 | |
| 265 local function Constructor( self, bar, idx, config, barConfig ) | |
| 266 self.bar, self.idx, self.config, self.barConfig = bar, idx, config, barConfig | 241 self.bar, self.idx, self.config, self.barConfig = bar, idx, config, barConfig |
| 267 | |
| 268 local barFrame = bar:GetFrame() | |
| 269 | 242 |
| 270 config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx) | 243 config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx) |
| 271 self.name = config.name | 244 self.name = config.name |
| 272 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured | 245 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured |
| 273 self.nPages = 1 | 246 self.nPages = 1 |
| 274 | 247 |
| 275 local f = CreateFrame("CheckButton", self.name, barFrame, "ActionBarButtonTemplate") | 248 local f = CreateFrame("CheckButton", self.name, bar:GetButtonFrame(), "ActionBarButtonTemplate") |
| 276 | |
| 277 -- TODO: re-implement ActionButton event handlers that don't do secure stuff | |
| 278 | 249 |
| 279 -- this will probably cause taint and/or performance problems, using right now for display/debugging purposes | 250 -- this will probably cause taint and/or performance problems, using right now for display/debugging purposes |
| 280 f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) | 251 f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) |
| 281 | 252 |
| 282 f:SetAttribute("action", config.actionID) | 253 f:SetAttribute("action", config.actionID) |
| 283 -- install mind control action support for all buttons here just for simplicity | 254 -- install mind control action support for all buttons here just for simplicity |
| 284 if self.idx <= 12 then | 255 if self.idx <= 12 then |
| 285 f:SetAttribute("action-mc", 120 + self.idx) | 256 f:SetAttribute("action-mc", 120 + self.idx) |
| 286 end | 257 end |
| 287 | 258 |
| 288 barFrame:SetAttribute("addchild",f) | |
| 289 | |
| 290 self.frame = f | 259 self.frame = f |
| 260 self.normalTexture = getglobal(format("%sNormalTexture",f:GetName())) | |
| 261 | |
| 262 -- initialize the hide state | |
| 263 self:ShowGrid(not barConfig.hideEmpty) | |
| 264 if ReAction:GetConfigMode() then | |
| 265 self:ShowGrid(true) | |
| 266 end | |
| 267 | |
| 268 -- show the ID label if applicable | |
| 269 self:ShowActionIDLabel(ReAction:GetConfigMode()) | |
| 270 | |
| 291 self:Refresh() | 271 self:Refresh() |
| 292 | 272 return self |
| 293 if not module.db.profile.hideEmptyButtons then | |
| 294 ActionButton_ShowGrid(self.frame) | |
| 295 end | |
| 296 | |
| 297 if ReAction.configMode then | |
| 298 ActionButton_ShowGrid(self.frame) | |
| 299 module:showActionIDLabel(self) | |
| 300 end | |
| 301 end | 273 end |
| 302 | 274 |
| 303 function Button:Destroy() | 275 function Button:Destroy() |
| 304 local f = self.frame | 276 local f = self.frame |
| 305 f:UnregisterAllEvents() | 277 f:UnregisterAllEvents() |
| 365 -- TODO: | 337 -- TODO: |
| 366 -- apply next-page, prev-page, and direct-page keybinds (via bar:SetStateKeybind abstraction) | 338 -- apply next-page, prev-page, and direct-page keybinds (via bar:SetStateKeybind abstraction) |
| 367 end | 339 end |
| 368 end | 340 end |
| 369 | 341 |
| 370 -- export as a class-factory to module | 342 function Button:ShowGrid( show ) |
| 371 module.BtnClass = { | 343 if not InCombatLockdown() then |
| 372 New = function(self, ...) | 344 -- new in 2.4.1: can't call ActionButton_ShowGrid/HideGrid because they won't update the attribute |
| 373 local x = { } | 345 local f = self.frame |
| 374 for k,v in pairs(Button) do | 346 local count = f:GetAttribute("showgrid") |
| 375 x[k] = v | 347 if show then |
| 376 end | 348 count = count + 1 |
| 377 Constructor(x, ...) | 349 else |
| 378 return x | 350 count = count - 1 |
| 379 end | 351 end |
| 380 } | 352 if count < 0 then |
| 353 count = 0 | |
| 354 end | |
| 355 f:SetAttribute("showgrid",count) | |
| 356 | |
| 357 if count >= 1 and not f:GetAttribute("statehidden") then | |
| 358 self.normalTexture:SetVertexColor(1.0, 1.0, 1.0, 0.5); | |
| 359 f:Show() | |
| 360 elseif count < 1 and not HasAction(self:GetActionID()) then | |
| 361 f:Hide() | |
| 362 end | |
| 363 end | |
| 364 end | |
| 365 | |
| 366 function Button:ShowActionIDLabel( show ) | |
| 367 if show then | |
| 368 local id = self:GetActionID() | |
| 369 if not self.actionIDLabel and id and id ~= 0 then | |
| 370 local f = self:GetFrame() | |
| 371 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | |
| 372 label:SetAllPoints() | |
| 373 label:SetJustifyH("CENTER") | |
| 374 label:SetShadowColor(0,0,0,1) | |
| 375 label:SetShadowOffset(2,-2) | |
| 376 label:SetText(tostring(id)) | |
| 377 self.actionIDLabel = label | |
| 378 f:HookScript("OnAttributeChanged", | |
| 379 function(frame, attr, value) | |
| 380 if attr == "state-parent" then | |
| 381 label:SetText(tostring(self:GetActionID())) | |
| 382 end | |
| 383 end) | |
| 384 end | |
| 385 self.actionIDLabel:Show() | |
| 386 elseif self.actionIDLabel then | |
| 387 self.actionIDLabel:Hide() | |
| 388 end | |
| 389 end | |
| 390 |
