flickerstreak@28
|
1 --[[
|
flickerstreak@53
|
2 ReAction Pet Action button module
|
flickerstreak@53
|
3
|
flickerstreak@53
|
4 The button module implements standard action button functionality by wrapping Blizzard's
|
flickerstreak@53
|
5 PetActionButton frame and associated functions. It also provides some button layout
|
flickerstreak@53
|
6 modification tools.
|
flickerstreak@28
|
7
|
flickerstreak@28
|
8 --]]
|
flickerstreak@28
|
9
|
flickerstreak@28
|
10 -- local imports
|
flickerstreak@28
|
11 local ReAction = ReAction
|
flickerstreak@28
|
12 local L = ReAction.L
|
flickerstreak@28
|
13 local _G = _G
|
flickerstreak@53
|
14 local CreateFrame = CreateFrame
|
flickerstreak@28
|
15
|
flickerstreak@28
|
16 -- module declaration
|
flickerstreak@28
|
17 local moduleID = "PetAction"
|
flickerstreak@28
|
18 local module = ReAction:NewModule( moduleID )
|
flickerstreak@28
|
19
|
flickerstreak@28
|
20 -- module methods
|
flickerstreak@28
|
21 function module:OnInitialize()
|
flickerstreak@53
|
22 self.db = ReAction.db:RegisterNamespace( moduleID,
|
flickerstreak@28
|
23 {
|
flickerstreak@28
|
24 profile = {
|
flickerstreak@28
|
25 buttons = { }
|
flickerstreak@28
|
26 }
|
flickerstreak@28
|
27 }
|
flickerstreak@28
|
28 )
|
flickerstreak@53
|
29 self.buttons = { }
|
flickerstreak@60
|
30 self.options = setmetatable({},{__mode="k"})
|
flickerstreak@28
|
31 end
|
flickerstreak@28
|
32
|
flickerstreak@28
|
33 function module:OnEnable()
|
flickerstreak@53
|
34 ReAction:RegisterBarType(L["Pet Action Bar"],
|
flickerstreak@53
|
35 {
|
flickerstreak@53
|
36 type = moduleID ,
|
flickerstreak@53
|
37 defaultButtonSize = 30,
|
flickerstreak@53
|
38 defaultBarRows = 1,
|
flickerstreak@53
|
39 defaultBarCols = 10,
|
flickerstreak@53
|
40 defaultBarSpacing = 8
|
flickerstreak@53
|
41 })
|
flickerstreak@28
|
42 end
|
flickerstreak@28
|
43
|
flickerstreak@28
|
44 function module:OnDisable()
|
flickerstreak@53
|
45 ReAction:UnregisterBarType(L["Pet Action Bar"])
|
flickerstreak@28
|
46 end
|
flickerstreak@28
|
47
|
flickerstreak@53
|
48 function module:ApplyToBar(bar)
|
flickerstreak@53
|
49 if bar.config.type == moduleID then
|
flickerstreak@53
|
50 -- auto show/hide when pet exists
|
flickerstreak@53
|
51 bar:GetFrame():SetAttribute("unit","pet")
|
flickerstreak@53
|
52 RegisterUnitWatch(bar:GetFrame())
|
flickerstreak@53
|
53 self:RefreshBar(bar)
|
flickerstreak@28
|
54 end
|
flickerstreak@28
|
55 end
|
flickerstreak@28
|
56
|
flickerstreak@53
|
57 function module:RefreshBar(bar)
|
flickerstreak@53
|
58 if bar.config.type == moduleID then
|
flickerstreak@53
|
59 if self.buttons[bar] == nil then
|
flickerstreak@53
|
60 self.buttons[bar] = { }
|
flickerstreak@53
|
61 end
|
flickerstreak@53
|
62 local btns = self.buttons[bar]
|
flickerstreak@53
|
63 local profile = self.db.profile
|
flickerstreak@53
|
64 local barName = bar:GetName()
|
flickerstreak@53
|
65 if profile.buttons[barName] == nil then
|
flickerstreak@53
|
66 profile.buttons[barName] = {}
|
flickerstreak@53
|
67 end
|
flickerstreak@53
|
68 local btnCfg = profile.buttons[barName]
|
flickerstreak@53
|
69
|
flickerstreak@53
|
70 local r, c = bar:GetButtonGrid()
|
flickerstreak@53
|
71 local n = r*c
|
flickerstreak@53
|
72 for i = 1, n do
|
flickerstreak@53
|
73 if btnCfg[i] == nil then
|
flickerstreak@53
|
74 btnCfg[i] = {}
|
flickerstreak@53
|
75 end
|
flickerstreak@53
|
76 if btns[i] == nil then
|
flickerstreak@53
|
77 local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i])
|
flickerstreak@53
|
78 if ok and b then
|
flickerstreak@53
|
79 btns[i] = b
|
flickerstreak@53
|
80 end
|
flickerstreak@53
|
81 else
|
flickerstreak@53
|
82 btns[i]:Refresh(bar,i)
|
flickerstreak@53
|
83 end
|
flickerstreak@53
|
84 end
|
flickerstreak@53
|
85 for i = n+1, #btns do
|
flickerstreak@53
|
86 if btns[i] then
|
flickerstreak@53
|
87 btns[i] = btns[i]:Destroy()
|
flickerstreak@53
|
88 if btnCfg[i] then
|
flickerstreak@53
|
89 btnCfg[i] = nil
|
flickerstreak@53
|
90 end
|
flickerstreak@53
|
91 end
|
flickerstreak@53
|
92 end
|
flickerstreak@53
|
93 end
|
flickerstreak@53
|
94 end
|
flickerstreak@53
|
95
|
flickerstreak@53
|
96 function module:RemoveFromBar(bar)
|
flickerstreak@53
|
97 if self.buttons[bar] then
|
flickerstreak@53
|
98 local btns = self.buttons[bar]
|
flickerstreak@53
|
99 for _,b in pairs(btns) do
|
flickerstreak@53
|
100 if b then
|
flickerstreak@53
|
101 b:Destroy()
|
flickerstreak@53
|
102 end
|
flickerstreak@53
|
103 end
|
flickerstreak@53
|
104 self.buttons[bar] = nil
|
flickerstreak@53
|
105 end
|
flickerstreak@53
|
106 end
|
flickerstreak@53
|
107
|
flickerstreak@53
|
108 function module:EraseBarConfig(barName)
|
flickerstreak@53
|
109 self.db.profile.buttons[barName] = nil
|
flickerstreak@53
|
110 end
|
flickerstreak@53
|
111
|
flickerstreak@53
|
112 function module:RenameBarConfig(oldname, newname)
|
flickerstreak@53
|
113 local b = self.db.profile.buttons
|
flickerstreak@53
|
114 b[newname], b[oldname] = b[oldname], nil
|
flickerstreak@53
|
115 end
|
flickerstreak@53
|
116
|
flickerstreak@53
|
117
|
flickerstreak@53
|
118 function module:ApplyConfigMode(mode,bars)
|
flickerstreak@53
|
119 for _, bar in pairs(bars) do
|
flickerstreak@53
|
120 if bar and self.buttons[bar] then
|
flickerstreak@53
|
121 for _, b in pairs(self.buttons[bar]) do
|
flickerstreak@53
|
122 if b then
|
flickerstreak@53
|
123 if mode then
|
flickerstreak@53
|
124 self:showActionIDLabel(b)
|
flickerstreak@53
|
125 else
|
flickerstreak@53
|
126 self:hideActionIDLabel(b)
|
flickerstreak@53
|
127 end
|
flickerstreak@53
|
128 end
|
flickerstreak@53
|
129 end
|
flickerstreak@53
|
130 local f = bar:GetFrame()
|
flickerstreak@53
|
131 if mode then
|
flickerstreak@53
|
132 UnregisterUnitWatch(f)
|
flickerstreak@53
|
133 f:Show()
|
flickerstreak@53
|
134 else
|
flickerstreak@53
|
135 RegisterUnitWatch(f)
|
flickerstreak@53
|
136 end
|
flickerstreak@53
|
137 end
|
flickerstreak@53
|
138 end
|
flickerstreak@53
|
139 end
|
flickerstreak@53
|
140
|
flickerstreak@53
|
141 function module:showActionIDLabel(button)
|
flickerstreak@53
|
142 -- store the action ID label in the frame due to frame recycling
|
flickerstreak@53
|
143 if not button:GetFrame().actionIDLabel and button:GetActionID() then
|
flickerstreak@53
|
144 local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
|
flickerstreak@53
|
145 label:SetAllPoints()
|
flickerstreak@53
|
146 label:SetJustifyH("CENTER")
|
flickerstreak@53
|
147 label:SetShadowColor(0,0,0,1)
|
flickerstreak@53
|
148 label:SetShadowOffset(2,-2)
|
flickerstreak@53
|
149 label:SetText(tostring(button:GetActionID()))
|
flickerstreak@53
|
150 button:GetFrame().actionIDLabel = label
|
flickerstreak@53
|
151 end
|
flickerstreak@53
|
152 button:GetFrame().actionIDLabel:Show()
|
flickerstreak@53
|
153 end
|
flickerstreak@53
|
154
|
flickerstreak@53
|
155 function module:hideActionIDLabel(button)
|
flickerstreak@53
|
156 if button:GetFrame().actionIDLabel then
|
flickerstreak@53
|
157 button:GetFrame().actionIDLabel:Hide()
|
flickerstreak@53
|
158 end
|
flickerstreak@53
|
159 end
|
flickerstreak@53
|
160
|
flickerstreak@60
|
161 ---- Options ----
|
flickerstreak@60
|
162 function module:GetBarOptions(bar)
|
flickerstreak@60
|
163 if not self.options[bar] then
|
flickerstreak@60
|
164 self.options[bar] = {
|
flickerstreak@60
|
165 type = "group",
|
flickerstreak@60
|
166 name = L["Pet Buttons"],
|
flickerstreak@60
|
167 hidden = function() return bar.config.type ~= moduleID end,
|
flickerstreak@60
|
168 args = {
|
flickerstreak@60
|
169 }
|
flickerstreak@60
|
170 }
|
flickerstreak@60
|
171 end
|
flickerstreak@60
|
172 return self.options[bar]
|
flickerstreak@59
|
173 end
|
flickerstreak@59
|
174
|
flickerstreak@53
|
175
|
flickerstreak@28
|
176
|
flickerstreak@28
|
177 -- use-count of action IDs
|
flickerstreak@53
|
178 local nActionIDs = NUM_PET_ACTION_SLOTS
|
flickerstreak@28
|
179 local ActionIDList = setmetatable( {}, {
|
flickerstreak@28
|
180 __index = function(self, idx)
|
flickerstreak@28
|
181 if idx == nil then
|
flickerstreak@53
|
182 for i = 1, nActionIDs do
|
flickerstreak@28
|
183 if rawget(self,i) == nil then
|
flickerstreak@28
|
184 rawset(self,i,1)
|
flickerstreak@28
|
185 return i
|
flickerstreak@28
|
186 end
|
flickerstreak@28
|
187 end
|
flickerstreak@53
|
188 error("ran out of pet action IDs")
|
flickerstreak@28
|
189 else
|
flickerstreak@28
|
190 local c = rawget(self,idx) or 0
|
flickerstreak@28
|
191 rawset(self,idx,c+1)
|
flickerstreak@28
|
192 return idx
|
flickerstreak@28
|
193 end
|
flickerstreak@28
|
194 end,
|
flickerstreak@28
|
195 __newindex = function(self,idx,value)
|
flickerstreak@28
|
196 if value == nil then
|
flickerstreak@28
|
197 value = rawget(self,idx)
|
flickerstreak@28
|
198 if value == 1 then
|
flickerstreak@28
|
199 value = nil
|
flickerstreak@28
|
200 elseif value then
|
flickerstreak@28
|
201 value = value - 1
|
flickerstreak@28
|
202 end
|
flickerstreak@28
|
203 end
|
flickerstreak@28
|
204 rawset(self,idx,value)
|
flickerstreak@28
|
205 end
|
flickerstreak@28
|
206 })
|
flickerstreak@28
|
207
|
flickerstreak@53
|
208 local frameRecycler = {}
|
flickerstreak@28
|
209
|
flickerstreak@53
|
210
|
flickerstreak@53
|
211 ------ Button class ------
|
flickerstreak@28
|
212 local Button = { }
|
flickerstreak@28
|
213
|
flickerstreak@28
|
214 local function Constructor( self, bar, idx, config )
|
flickerstreak@28
|
215 self.bar, self.idx, self.config = bar, idx, config
|
flickerstreak@28
|
216
|
flickerstreak@28
|
217 local barFrame = bar:GetFrame()
|
flickerstreak@28
|
218
|
flickerstreak@56
|
219 local name = config.name or ("ReAction_%s_Pet_%d"):format(bar:GetName(),idx)
|
flickerstreak@53
|
220 config.name = name
|
flickerstreak@53
|
221 self.name = config.name
|
flickerstreak@28
|
222 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
|
flickerstreak@28
|
223
|
flickerstreak@53
|
224 -- have to recycle frames with the same name:
|
flickerstreak@53
|
225 -- otherwise you either get references to old textures because named CreateFrame()
|
flickerstreak@53
|
226 -- doesn't overwrite existing globals (below)
|
flickerstreak@53
|
227 -- or, if you set them to nil in the global table, you get taint because of the
|
flickerstreak@53
|
228 -- crappy PetActionBar code.
|
flickerstreak@53
|
229 local f = frameRecycler[name]
|
flickerstreak@53
|
230 if f then
|
flickerstreak@53
|
231 f:SetParent(barFrame)
|
flickerstreak@53
|
232 f:Show()
|
flickerstreak@53
|
233 else
|
flickerstreak@53
|
234 f = CreateFrame("CheckButton", name, barFrame, "PetActionButtonTemplate")
|
flickerstreak@53
|
235 end
|
flickerstreak@53
|
236 if config.actionID then
|
flickerstreak@53
|
237 f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton
|
flickerstreak@53
|
238 end
|
flickerstreak@53
|
239 f:SetFrameStrata("MEDIUM")
|
flickerstreak@53
|
240
|
flickerstreak@28
|
241 barFrame:SetAttribute("addchild",f)
|
flickerstreak@28
|
242
|
flickerstreak@53
|
243 self.frame = f
|
flickerstreak@53
|
244 self.icon = _G[("%sIcon"):format(name)]
|
flickerstreak@53
|
245 self.acTex = _G[("%sAutoCastable"):format(name)]
|
flickerstreak@53
|
246 self.acModel = _G[("%sAutoCast"):format(name)]
|
flickerstreak@53
|
247 self.cooldown = _G[("%sCooldown"):format(name)]
|
flickerstreak@53
|
248 self.hotkey = _G[("%sHotKey"):format(name)]
|
flickerstreak@53
|
249
|
flickerstreak@53
|
250 f:HookScript("OnDragStart", function() self:Update() end)
|
flickerstreak@53
|
251 f:HookScript("OnReceiveDrag", function() self:Update() end)
|
flickerstreak@53
|
252
|
flickerstreak@53
|
253 f:RegisterEvent("PLAYER_CONTROL_LOST");
|
flickerstreak@53
|
254 f:RegisterEvent("PLAYER_CONTROL_GAINED");
|
flickerstreak@53
|
255 f:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED");
|
flickerstreak@53
|
256 f:RegisterEvent("UNIT_PET");
|
flickerstreak@53
|
257 f:RegisterEvent("UNIT_FLAGS");
|
flickerstreak@53
|
258 f:RegisterEvent("UNIT_AURA");
|
flickerstreak@53
|
259 f:RegisterEvent("PET_BAR_UPDATE");
|
flickerstreak@53
|
260 f:RegisterEvent("PET_BAR_UPDATE_COOLDOWN");
|
flickerstreak@53
|
261
|
flickerstreak@53
|
262 f:SetScript("OnEvent",
|
flickerstreak@53
|
263 function(event,arg1)
|
flickerstreak@53
|
264 if event =="PET_BAR_UPDATE_COOLDOWN" then
|
flickerstreak@53
|
265 self:UpdateCooldown()
|
flickerstreak@53
|
266 elseif event == "UPDATE_BINDINGS" then
|
flickerstreak@53
|
267 self:UpdateHotkey()
|
flickerstreak@53
|
268 else
|
flickerstreak@53
|
269 self:Update()
|
flickerstreak@53
|
270 end
|
flickerstreak@53
|
271 end)
|
flickerstreak@28
|
272
|
flickerstreak@28
|
273 self:Refresh(bar,idx)
|
flickerstreak@28
|
274 end
|
flickerstreak@28
|
275
|
flickerstreak@28
|
276 function Button:Destroy()
|
flickerstreak@28
|
277 local f = self.frame
|
flickerstreak@28
|
278 f:UnregisterAllEvents()
|
flickerstreak@28
|
279 f:Hide()
|
flickerstreak@28
|
280 f:SetParent(UIParent)
|
flickerstreak@28
|
281 f:ClearAllPoints()
|
flickerstreak@28
|
282 if self.name then
|
flickerstreak@53
|
283 frameRecycler[self.name] = f
|
flickerstreak@28
|
284 _G[self.name] = nil
|
flickerstreak@28
|
285 end
|
flickerstreak@53
|
286 if self.config.actionID then
|
flickerstreak@53
|
287 ActionIDList[self.config.actionID] = nil
|
flickerstreak@53
|
288 end
|
flickerstreak@28
|
289 self.frame = nil
|
flickerstreak@28
|
290 self.config = nil
|
flickerstreak@28
|
291 self.bar = nil
|
flickerstreak@28
|
292 end
|
flickerstreak@28
|
293
|
flickerstreak@53
|
294 function Button:Refresh(bar,idx)
|
flickerstreak@53
|
295 bar:PlaceButton(self.frame, idx, 30, 30)
|
flickerstreak@53
|
296 self:Update()
|
flickerstreak@53
|
297 self:UpdateHotkey()
|
flickerstreak@53
|
298 end
|
flickerstreak@53
|
299
|
flickerstreak@53
|
300 function Button:GetFrame()
|
flickerstreak@53
|
301 return self.frame
|
flickerstreak@53
|
302 end
|
flickerstreak@53
|
303
|
flickerstreak@53
|
304 function Button:GetName()
|
flickerstreak@53
|
305 return self.name
|
flickerstreak@53
|
306 end
|
flickerstreak@53
|
307
|
flickerstreak@53
|
308 function Button:GetActionID()
|
flickerstreak@53
|
309 return self.config.actionID
|
flickerstreak@53
|
310 end
|
flickerstreak@53
|
311
|
flickerstreak@53
|
312 function Button:Update()
|
flickerstreak@53
|
313 local id = self.frame:GetID()
|
flickerstreak@53
|
314 local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id);
|
flickerstreak@53
|
315 local f = self.frame
|
flickerstreak@53
|
316 --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)))
|
flickerstreak@53
|
317
|
flickerstreak@53
|
318 if isToken then
|
flickerstreak@53
|
319 self.icon:SetTexture(_G[texture]);
|
flickerstreak@53
|
320 f.tooltipName = _G[name];
|
flickerstreak@53
|
321 else
|
flickerstreak@53
|
322 self.icon:SetTexture(texture);
|
flickerstreak@53
|
323 f.tooltipName = name;
|
flickerstreak@53
|
324 end
|
flickerstreak@53
|
325
|
flickerstreak@53
|
326 f.isToken = isToken;
|
flickerstreak@53
|
327 f.tooltipSubtext = subtext;
|
flickerstreak@53
|
328 f:SetChecked( isActive and 1 or 0);
|
flickerstreak@53
|
329
|
flickerstreak@53
|
330 if autoCastAllowed then
|
flickerstreak@53
|
331 self.acTex:Show();
|
flickerstreak@53
|
332 else
|
flickerstreak@53
|
333 self.acTex:Hide();
|
flickerstreak@53
|
334 end
|
flickerstreak@53
|
335
|
flickerstreak@53
|
336 if autoCastEnabled then
|
flickerstreak@53
|
337 self.acModel:Show();
|
flickerstreak@53
|
338 else
|
flickerstreak@53
|
339 self.acModel:Hide();
|
flickerstreak@53
|
340 end
|
flickerstreak@53
|
341
|
flickerstreak@53
|
342 if texture then
|
flickerstreak@53
|
343 if GetPetActionsUsable() then
|
flickerstreak@53
|
344 SetDesaturation(self.icon,nil)
|
flickerstreak@53
|
345 else
|
flickerstreak@53
|
346 SetDesaturation(self.icon,1)
|
flickerstreak@53
|
347 end
|
flickerstreak@53
|
348 self.icon:Show();
|
flickerstreak@53
|
349 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
|
flickerstreak@53
|
350 else
|
flickerstreak@53
|
351 self.icon:Hide();
|
flickerstreak@53
|
352 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
|
flickerstreak@53
|
353 end
|
flickerstreak@53
|
354
|
flickerstreak@53
|
355 self:UpdateCooldown()
|
flickerstreak@53
|
356 end
|
flickerstreak@53
|
357
|
flickerstreak@53
|
358 function Button:UpdateCooldown()
|
flickerstreak@53
|
359 local start, duration, enable = GetPetActionCooldown(self.frame:GetID());
|
flickerstreak@53
|
360 CooldownFrame_SetTimer(self.cooldown, start, duration, enable);
|
flickerstreak@53
|
361 end
|
flickerstreak@53
|
362
|
flickerstreak@53
|
363 function Button:UpdateHotkey()
|
flickerstreak@53
|
364
|
flickerstreak@53
|
365 end
|
flickerstreak@28
|
366
|
flickerstreak@28
|
367 -- export as a class-factory to module
|
flickerstreak@28
|
368 module.BtnClass = {
|
flickerstreak@28
|
369 new = function(self, ...)
|
flickerstreak@28
|
370 local x = { }
|
flickerstreak@28
|
371 for k,v in pairs(Button) do
|
flickerstreak@28
|
372 x[k] = v
|
flickerstreak@28
|
373 end
|
flickerstreak@28
|
374 Constructor(x, ...)
|
flickerstreak@28
|
375 return x
|
flickerstreak@28
|
376 end
|
flickerstreak@28
|
377 }
|