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