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