Mercurial > wow > reaction
comparison modules/PetAction.lua @ 109:410d036c43b2
- reorganize modularity file structure (part 1)
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Thu, 08 Jan 2009 00:57:27 +0000 |
parents | modules/ReAction_PetAction/ReAction_PetAction.lua@b2fb8f7dc780 |
children | fb48811a8736 |
comparison
equal
deleted
inserted
replaced
108:b2fb8f7dc780 | 109:410d036c43b2 |
---|---|
1 --[[ | |
2 ReAction Pet Action button module | |
3 | |
4 The button module implements standard action button functionality by wrapping Blizzard's | |
5 PetActionButton frame and associated functions. | |
6 | |
7 --]] | |
8 | |
9 -- local imports | |
10 local ReAction = ReAction | |
11 local L = ReAction.L | |
12 local _G = _G | |
13 local CreateFrame = CreateFrame | |
14 local format = string.format | |
15 | |
16 ReAction:UpdateRevision("$Revision$") | |
17 | |
18 -- libraries | |
19 local KB = LibStub("LibKeyBound-1.0") | |
20 | |
21 -- module declaration | |
22 local moduleID = "PetAction" | |
23 local module = ReAction:NewModule( moduleID ) | |
24 | |
25 -- Button class declaration | |
26 local Button = { } | |
27 | |
28 -- private | |
29 local function UpdateButtonLock(bar) | |
30 local f = bar:GetFrame() | |
31 f:SetAttribute("lockbuttons",bar.config.lockButtons) | |
32 f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat) | |
33 f:Execute( | |
34 [[ | |
35 lockButtons = self:GetAttribute("lockbuttons") | |
36 lockButtonsCombat = self:GetAttribute("lockbuttonscombat") | |
37 ]]) | |
38 end | |
39 | |
40 -- module methods | |
41 function module:OnInitialize() | |
42 self.db = ReAction.db:RegisterNamespace( moduleID, | |
43 { | |
44 profile = { | |
45 buttons = { } | |
46 } | |
47 } | |
48 ) | |
49 self.buttons = { } | |
50 | |
51 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") | |
52 | |
53 ReAction.RegisterCallback(self, "OnCreateBar") | |
54 ReAction.RegisterCallback(self, "OnDestroyBar") | |
55 ReAction.RegisterCallback(self, "OnRefreshBar") | |
56 ReAction.RegisterCallback(self, "OnEraseBar") | |
57 ReAction.RegisterCallback(self, "OnRenameBar") | |
58 ReAction.RegisterCallback(self, "OnConfigModeChanged") | |
59 | |
60 KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED") | |
61 KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED") | |
62 KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") | |
63 end | |
64 | |
65 function module:OnEnable() | |
66 ReAction:RegisterBarType(L["Pet Action Bar"], | |
67 { | |
68 type = moduleID , | |
69 defaultButtonSize = 30, | |
70 defaultBarRows = 1, | |
71 defaultBarCols = 10, | |
72 defaultBarSpacing = 8 | |
73 }) | |
74 end | |
75 | |
76 function module:OnDisable() | |
77 ReAction:UnregisterBarType(L["Pet Action Bar"]) | |
78 end | |
79 | |
80 function module:OnCreateBar(event, bar, name) | |
81 if bar.config.type == moduleID then | |
82 -- auto show/hide when pet exists | |
83 bar:GetFrame():SetAttribute("unit","pet") | |
84 if not ReAction:GetConfigMode() then | |
85 RegisterUnitWatch(bar:GetFrame()) | |
86 end | |
87 self:OnRefreshBar(event, bar, name) | |
88 end | |
89 end | |
90 | |
91 function module:OnRefreshBar(event, bar, name) | |
92 if bar.config.type == moduleID then | |
93 if self.buttons[bar] == nil then | |
94 self.buttons[bar] = { } | |
95 end | |
96 local btns = self.buttons[bar] | |
97 local profile = self.db.profile | |
98 if profile.buttons[name] == nil then | |
99 profile.buttons[name] = {} | |
100 end | |
101 local btnCfg = profile.buttons[name] | |
102 | |
103 local r, c = bar:GetButtonGrid() | |
104 local n = r*c | |
105 for i = 1, n do | |
106 if btnCfg[i] == nil then | |
107 btnCfg[i] = {} | |
108 end | |
109 if btns[i] == nil then | |
110 local success, r = pcall(Button.New,Button,bar,i,btnCfg[i]) | |
111 if success and r then | |
112 btns[i] = r | |
113 bar:AddButton(i,r) | |
114 else | |
115 n = i - 1 | |
116 bar:ClipNButtons(n) | |
117 break | |
118 end | |
119 end | |
120 btns[i]:Refresh() | |
121 end | |
122 for i = n+1, #btns do | |
123 if btns[i] then | |
124 bar:RemoveButton(btns[i]) | |
125 btns[i] = btns[i]:Destroy() | |
126 if btnCfg[i] then | |
127 btnCfg[i] = nil | |
128 end | |
129 end | |
130 end | |
131 UpdateButtonLock(bar) | |
132 end | |
133 end | |
134 | |
135 function module:OnDestroyBar(event, bar, name) | |
136 if self.buttons[bar] then | |
137 local btns = self.buttons[bar] | |
138 for _,b in pairs(btns) do | |
139 if b then | |
140 b:Destroy() | |
141 end | |
142 end | |
143 self.buttons[bar] = nil | |
144 end | |
145 end | |
146 | |
147 function module:OnEraseBar(event, bar, name) | |
148 self.db.profile.buttons[name] = nil | |
149 end | |
150 | |
151 function module:OnRenameBar(event, bar, oldname, newname) | |
152 local b = self.db.profile.buttons | |
153 b[newname], b[oldname] = b[oldname], nil | |
154 end | |
155 | |
156 | |
157 function module:OnConfigModeChanged(event, mode) | |
158 for _, buttons in pairs(self.buttons) do | |
159 for _, b in pairs(buttons) do | |
160 b:ShowActionIDLabel(mode) | |
161 end | |
162 end | |
163 for _, bar in ReAction:IterateBars() do | |
164 if bar and self.buttons[bar] then | |
165 local f = bar:GetFrame() | |
166 if mode then | |
167 UnregisterUnitWatch(f) | |
168 f:Show() | |
169 else | |
170 RegisterUnitWatch(f) | |
171 end | |
172 end | |
173 end | |
174 end | |
175 | |
176 function module:LIBKEYBOUND_ENABLED(evt) | |
177 for _, buttons in pairs(self.buttons) do | |
178 for _, b in pairs(buttons) do | |
179 b:SetKeybindMode(true) | |
180 end | |
181 end | |
182 end | |
183 | |
184 function module:LIBKEYBOUND_DISABLED(evt) | |
185 for _, buttons in pairs(self.buttons) do | |
186 for _, b in pairs(buttons) do | |
187 b:SetKeybindMode(false) | |
188 end | |
189 end | |
190 end | |
191 | |
192 | |
193 ---- Options ---- | |
194 local Handler = { } | |
195 local meta = { __index = Handler } | |
196 | |
197 function Handler:New(bar) | |
198 return setmetatable( | |
199 { | |
200 bar = bar, | |
201 config = bar.config | |
202 }, meta) | |
203 end | |
204 | |
205 function Handler:GetLockButtons() | |
206 return LOCK_ACTIONBAR == "1" or self.config.lockButtons | |
207 end | |
208 | |
209 function Handler:SetLockButtons(info, value) | |
210 self.config.lockButtons = value | |
211 UpdateButtonLock(self.bar) | |
212 end | |
213 | |
214 function Handler:LockButtonsDisabled() | |
215 return LOCK_ACTIONBAR == "1" | |
216 end | |
217 | |
218 function Handler:GetLockButtonsCombat() | |
219 return self.config.lockButtonsCombat | |
220 end | |
221 | |
222 function Handler:SetLockButtonsCombat(info, value) | |
223 self.config.lockButtonsCombat = value | |
224 UpdateButtonLock(self.bar) | |
225 end | |
226 | |
227 function Handler:LockButtonsCombatDisabled() | |
228 return LOCK_ACTIONBAR == "1" or not self.config.lockButtons | |
229 end | |
230 | |
231 | |
232 function module:GetBarOptions(bar) | |
233 if bar.config.type == moduleID then | |
234 return { | |
235 type = "group", | |
236 name = L["Pet Buttons"], | |
237 handler = Handler:New(bar), | |
238 args = { | |
239 lockButtons = { | |
240 name = L["Lock Buttons"], | |
241 desc = L["Prevents picking up/dragging actions.|nNOTE: This setting is overridden by the global setting in Blizzard's Action Buttons tab"], | |
242 order = 2, | |
243 type = "toggle", | |
244 disabled = "LockButtonsDisabled", | |
245 get = "GetLockButtons", | |
246 set = "SetLockButtons", | |
247 }, | |
248 lockOnlyCombat = { | |
249 name = L["Only in Combat"], | |
250 desc = L["Only lock the buttons when in combat"], | |
251 order = 3, | |
252 type = "toggle", | |
253 disabled = "LockButtonsCombatDisabled", | |
254 get = "GetLockButtonsCombat", | |
255 set = "SetLockButtonsCombat", | |
256 }, | |
257 } | |
258 } | |
259 end | |
260 end | |
261 | |
262 | |
263 | |
264 ------ Button class ------ | |
265 | |
266 -- use-count of action IDs | |
267 local nActionIDs = NUM_PET_ACTION_SLOTS | |
268 local ActionIDList = setmetatable( {}, { | |
269 __index = function(self, idx) | |
270 if idx == nil then | |
271 for i = 1, nActionIDs do | |
272 if rawget(self,i) == nil then | |
273 rawset(self,i,1) | |
274 return i | |
275 end | |
276 end | |
277 error("ran out of pet action IDs") | |
278 else | |
279 local c = rawget(self,idx) or 0 | |
280 rawset(self,idx,c+1) | |
281 return idx | |
282 end | |
283 end, | |
284 __newindex = function(self,idx,value) | |
285 if value == nil then | |
286 value = rawget(self,idx) | |
287 if value == 1 then | |
288 value = nil | |
289 elseif value then | |
290 value = value - 1 | |
291 end | |
292 end | |
293 rawset(self,idx,value) | |
294 end | |
295 }) | |
296 | |
297 local frameRecycler = {} | |
298 local trash = CreateFrame("Frame") | |
299 local KBAttach, GetActionName, GetHotkey, SetKey, FreeKey, ClearBindings, GetBindings, OnEnter, OnLeave | |
300 do | |
301 local buttonLookup = setmetatable({},{__mode="kv"}) | |
302 | |
303 -- Use KeyBound-1.0 for binding, but use Override bindings instead of | |
304 -- regular bindings to support multiple profile use. This is a little | |
305 -- weird with the KeyBound dialog box (which has per-char selector as well | |
306 -- as an OK/Cancel box) but it's the least amount of effort to implement. | |
307 function GetActionName(f) | |
308 local b = buttonLookup[f] | |
309 if b then | |
310 return format("%s:%s", b.bar:GetName(), b.idx) | |
311 end | |
312 end | |
313 | |
314 function GetHotkey(f) | |
315 local b = buttonLookup[f] | |
316 if b then | |
317 return KB:ToShortKey(b:GetConfig().hotkey) | |
318 end | |
319 end | |
320 | |
321 function SetKey(f, key) | |
322 local b = buttonLookup[f] | |
323 if b then | |
324 local c = b:GetConfig() | |
325 if c.hotkey then | |
326 SetOverrideBinding(f, false, c.hotkey, nil) | |
327 end | |
328 if key then | |
329 SetOverrideBindingClick(f, false, key, f:GetName(), nil) | |
330 end | |
331 c.hotkey = key | |
332 b:DisplayHotkey(GetHotkey(f)) | |
333 end | |
334 end | |
335 | |
336 function FreeKey(f, key) | |
337 local b = buttonLookup[f] | |
338 if b then | |
339 local c = b:GetConfig() | |
340 if c.hotkey == key then | |
341 local action = f:GetActionName() | |
342 SetOverrideBinding(f, false, c.hotkey, nil) | |
343 c.hotkey = nil | |
344 b:DisplayHotkey(nil) | |
345 return action | |
346 end | |
347 end | |
348 return ReAction:FreeOverrideHotkey(key) | |
349 end | |
350 | |
351 function ClearBindings(f) | |
352 SetKey(f, nil) | |
353 end | |
354 | |
355 function GetBindings(f) | |
356 local b = buttonLookup[f] | |
357 if b then | |
358 return b:GetConfig().hotkey | |
359 end | |
360 end | |
361 | |
362 function KBAttach( button ) | |
363 local f = button:GetFrame() | |
364 f.GetActionName = GetActionName | |
365 f.GetHotkey = GetHotkey | |
366 f.SetKey = SetKey | |
367 f.FreeKey = FreeKey | |
368 f.ClearBindings = ClearBindings | |
369 f.GetBindings = GetBindings | |
370 buttonLookup[f] = button | |
371 f:SetKey(button:GetConfig().hotkey) | |
372 ReAction:RegisterKeybindFrame(f) | |
373 if ReAction:GetKeybindMode() then | |
374 button.border:SetVertexColor(KB:GetColorKeyBoundMode()) | |
375 button.border:Show() | |
376 end | |
377 end | |
378 | |
379 function OnEnter( self ) | |
380 if not self.tooltipName then | |
381 return; | |
382 end | |
383 local uber = GetCVar("UberTooltips") | |
384 if self.isToken or (uber == "0") then | |
385 if uber == "0" then | |
386 GameTooltip:SetOwner(self, "ANCHOR_RIGHT") | |
387 else | |
388 GameTooltip_SetDefaultAnchor(GameTooltip, self) | |
389 end | |
390 local tooltip = self.tooltipName | |
391 local k = GetBindings(self) | |
392 if k then | |
393 tooltip = tooltip .. format(" %s(%s)%s", NORMAL_FONT_COLOR_CODE, k, FONT_COLOR_CODE_CLOSE) | |
394 end | |
395 GameTooltip:SetText(tooltip) | |
396 if self.tooltipSubtext then | |
397 GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5) | |
398 end | |
399 GameTooltip:Show() | |
400 else | |
401 GameTooltip_SetDefaultAnchor(GameTooltip, self) | |
402 GameTooltip:SetPetAction(self:GetID()) | |
403 end | |
404 end | |
405 | |
406 function OnLeave() | |
407 GameTooltip:Hide() | |
408 end | |
409 | |
410 end | |
411 | |
412 local meta = { __index = Button } | |
413 | |
414 function Button:New( bar, idx, config ) | |
415 -- create new self | |
416 self = setmetatable( | |
417 { | |
418 bar = bar, | |
419 idx = idx, | |
420 config = config, | |
421 }, meta ) | |
422 | |
423 local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx) | |
424 config.name = name | |
425 self.name = name | |
426 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured | |
427 | |
428 -- have to recycle frames with the same name: | |
429 -- otherwise you either get references to old textures because named CreateFrame() | |
430 -- doesn't overwrite existing globals. Can't set them to nil in the global table, | |
431 -- as it causes taint. | |
432 local parent = bar:GetFrame() | |
433 local f = frameRecycler[name] | |
434 if f then | |
435 f:SetParent(parent) | |
436 else | |
437 f = CreateFrame("CheckButton", name, parent, "PetActionButtonTemplate") | |
438 -- ditch the old hotkey text because it's tied in ActionButton_Update() to the | |
439 -- standard binding. We use override bindings. | |
440 local hotkey = _G[name.."HotKey"] | |
441 hotkey:SetParent(trash) | |
442 hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray") | |
443 hotkey:SetWidth(36) | |
444 hotkey:SetHeight(18) | |
445 hotkey:SetJustifyH("RIGHT") | |
446 hotkey:SetJustifyV("TOP") | |
447 hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2) | |
448 f.hotkey = hotkey | |
449 f:HookScript("OnDragStart", function() self:Update() end) | |
450 f:HookScript("OnReceiveDrag", function() self:Update() end) | |
451 f:SetScript("OnEnter", OnEnter) | |
452 f:SetScript("OnLeave", OnLeave) | |
453 end | |
454 if config.actionID then | |
455 f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton | |
456 end | |
457 f:SetFrameStrata("MEDIUM") | |
458 self.frame = f | |
459 self.icon = _G[("%sIcon"):format(name)] | |
460 self.acTex = _G[("%sAutoCastable"):format(name)] | |
461 self.acModel = _G[("%sShine"):format(name)] | |
462 self.cooldown = _G[("%sCooldown"):format(name)] | |
463 self.hotkey = f.hotkey | |
464 self.border = _G[("%sBorder"):format(name)] | |
465 | |
466 | |
467 f:RegisterEvent("PLAYER_CONTROL_LOST"); | |
468 f:RegisterEvent("PLAYER_CONTROL_GAINED"); | |
469 f:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED"); | |
470 f:RegisterEvent("UNIT_PET"); | |
471 f:RegisterEvent("UNIT_FLAGS"); | |
472 f:RegisterEvent("UNIT_AURA"); | |
473 f:RegisterEvent("PET_BAR_UPDATE"); | |
474 f:RegisterEvent("PET_BAR_UPDATE_COOLDOWN"); | |
475 | |
476 f:SetScript("OnEvent", | |
477 function(event,arg1) | |
478 if event =="PET_BAR_UPDATE_COOLDOWN" then | |
479 self:UpdateCooldown() | |
480 elseif event == "UPDATE_BINDINGS" then | |
481 self:UpdateHotkey() | |
482 else | |
483 self:Update() | |
484 end | |
485 end) | |
486 | |
487 -- install drag wrappers to lock buttons | |
488 bar:GetFrame():WrapScript(f, "OnDragStart", | |
489 -- OnDragStart(self, button, kind, value, ...) | |
490 [[ | |
491 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then | |
492 return "clear" | |
493 end | |
494 ]]) | |
495 | |
496 KBAttach(self) | |
497 | |
498 -- attach to skinner | |
499 bar:SkinButton(self, | |
500 { | |
501 HotKey = self.hotkey, | |
502 } | |
503 ) | |
504 | |
505 self:Refresh() | |
506 self:SetKeybindMode(ReAction:GetKeybindMode()) | |
507 | |
508 return self | |
509 end | |
510 | |
511 function Button:Destroy() | |
512 local f = self.frame | |
513 f:UnregisterAllEvents() | |
514 f:Hide() | |
515 f:SetParent(UIParent) | |
516 f:ClearAllPoints() | |
517 if self.name then | |
518 frameRecycler[self.name] = f | |
519 _G[self.name] = nil | |
520 end | |
521 if self.config.actionID then | |
522 ActionIDList[self.config.actionID] = nil | |
523 end | |
524 self.frame = nil | |
525 self.config = nil | |
526 self.bar = nil | |
527 end | |
528 | |
529 function Button:Refresh() | |
530 self.bar:PlaceButton(self, 30, 30) | |
531 self:Update() | |
532 self:UpdateHotkey() | |
533 self.frame:Show() | |
534 end | |
535 | |
536 function Button:GetFrame() | |
537 return self.frame | |
538 end | |
539 | |
540 function Button:GetName() | |
541 return self.name | |
542 end | |
543 | |
544 function Button:GetConfig() | |
545 return self.config | |
546 end | |
547 | |
548 function Button:GetActionID() | |
549 return self.config.actionID | |
550 end | |
551 | |
552 function Button:Update() | |
553 local id = self.frame:GetID() | |
554 local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id); | |
555 local f = self.frame | |
556 --ReAction:Print(("id %d: '%s', '%s', '%s', '%s', '%s', '%s', '%s'"):format(tostring(id), tostring(name),tostring(subtext),tostring(texture),tostring(isToken),tostring(isActive),tostring(autoCastAllowed),tostring(autoCastEnabled))) | |
557 | |
558 if isToken then | |
559 self.icon:SetTexture(_G[texture]); | |
560 f.tooltipName = _G[name]; | |
561 else | |
562 self.icon:SetTexture(texture); | |
563 f.tooltipName = name; | |
564 end | |
565 | |
566 f.isToken = isToken; | |
567 f.tooltipSubtext = subtext; | |
568 f:SetChecked( isActive and 1 or 0); | |
569 | |
570 if autoCastAllowed then | |
571 self.acTex:Show(); | |
572 else | |
573 self.acTex:Hide(); | |
574 end | |
575 | |
576 if autoCastEnabled then | |
577 AutoCastShine_AutoCastStart(self.acModel) | |
578 else | |
579 AutoCastShine_AutoCastStop(self.acModel) | |
580 end | |
581 | |
582 if texture then | |
583 if GetPetActionSlotUsable(id) then | |
584 SetDesaturation(self.icon,nil) | |
585 else | |
586 SetDesaturation(self.icon,1) | |
587 end | |
588 self.icon:Show(); | |
589 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2"); | |
590 else | |
591 self.icon:Hide(); | |
592 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot"); | |
593 end | |
594 | |
595 self:UpdateCooldown() | |
596 end | |
597 | |
598 function Button:UpdateCooldown() | |
599 local start, duration, enable = GetPetActionCooldown(self.frame:GetID()); | |
600 CooldownFrame_SetTimer(self.cooldown, start, duration, enable); | |
601 end | |
602 | |
603 function Button:UpdateHotkey() | |
604 self:DisplayHotkey(GetHotkey(self.frame)) | |
605 end | |
606 | |
607 function Button:ShowActionIDLabel(show) | |
608 if show then | |
609 -- store the action ID label in the frame due to frame recycling | |
610 if not self.actionIDLabel and self:GetActionID() then | |
611 local label = self.frame:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | |
612 label:SetAllPoints() | |
613 label:SetJustifyH("CENTER") | |
614 label:SetShadowColor(0,0,0,1) | |
615 label:SetShadowOffset(2,-2) | |
616 label:SetText(tostring(self:GetActionID())) | |
617 self.actionIDLabel = label | |
618 end | |
619 self.actionIDLabel:Show() | |
620 elseif self.actionIDLabel then | |
621 self.actionIDLabel:Hide() | |
622 end | |
623 end | |
624 | |
625 | |
626 function Button:SetKeybindMode(mode) | |
627 if mode then | |
628 self.border:SetVertexColor(KB:GetColorKeyBoundMode()) | |
629 self.border:Show() | |
630 else | |
631 self.border:Hide() | |
632 end | |
633 end | |
634 | |
635 function Button:DisplayHotkey( key ) | |
636 self.hotkey:SetText(key or "") | |
637 end |