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 |