flickerstreak@161
|
1 local ReAction = ReAction
|
flickerstreak@161
|
2 local L = ReAction.L
|
flickerstreak@161
|
3 local _G = _G
|
flickerstreak@161
|
4 local CreateFrame = CreateFrame
|
flickerstreak@161
|
5 local format = string.format
|
flickerstreak@161
|
6 local unpack = unpack
|
flickerstreak@161
|
7 local GetCVar = GetCVar
|
flickerstreak@161
|
8 local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
|
flickerstreak@161
|
9 local CooldownFrame_SetTimer = CooldownFrame_SetTimer
|
flickerstreak@161
|
10 local InCombatLockdown = InCombatLockdown
|
flickerstreak@161
|
11 local IsUsableSpell = IsUsableSpell
|
flickerstreak@161
|
12 local IsUsableAction = IsUsableAction
|
flickerstreak@161
|
13 local IsSpellKnown = IsSpellKnown
|
flickerstreak@161
|
14 local IsSpellInRange = IsSpellInRange
|
flickerstreak@161
|
15 local IsActionInRange = IsActionInRange
|
flickerstreak@161
|
16 local GetSpellInfo = GetSpellInfo
|
flickerstreak@161
|
17 local GetSpellCooldown = GetSpellCooldown
|
flickerstreak@161
|
18 local GetActionCooldown = GetActionCooldown
|
flickerstreak@161
|
19 local GetSpellTexture = GetSpellTexture
|
flickerstreak@161
|
20 local GetActionTexture = GetActionTexture
|
flickerstreak@161
|
21 local GetMultiCastTotemSpells = GetMultiCastTotemSpells
|
flickerstreak@161
|
22
|
flickerstreak@161
|
23 ReAction:UpdateRevision("$Revision: 154 $")
|
flickerstreak@161
|
24
|
flickerstreak@161
|
25
|
flickerstreak@161
|
26 --[[
|
flickerstreak@161
|
27 Blizzard Constants:
|
flickerstreak@161
|
28 - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4
|
flickerstreak@161
|
29 - NUM_MULTI_CAST_PAGES = 3
|
flickerstreak@161
|
30 - TOTEM_PRIORITIES = { } -- sets the order of the totems
|
flickerstreak@161
|
31 - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs
|
flickerstreak@161
|
32 - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs
|
flickerstreak@161
|
33
|
flickerstreak@161
|
34 Blizzard Events:
|
flickerstreak@161
|
35 - UPDATE_MULTI_CAST_ACTIONBAR
|
flickerstreak@161
|
36
|
flickerstreak@161
|
37 Blizzard APIs:
|
flickerstreak@161
|
38 - GetMultiCastBarOffset() : returns 6
|
flickerstreak@161
|
39
|
flickerstreak@161
|
40 - SetMultiCastSpell(actionID, spellID) (protected) OR
|
flickerstreak@161
|
41 SetAttribute("type","multispell")
|
flickerstreak@161
|
42 SetAttribute("action",actionID)
|
flickerstreak@161
|
43 SetAttribute("spell",spellID)
|
flickerstreak@161
|
44
|
flickerstreak@161
|
45 note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(),
|
flickerstreak@161
|
46 so that's action ID 132-144.
|
flickerstreak@161
|
47
|
flickerstreak@161
|
48 - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot)
|
flickerstreak@161
|
49 returns spellIDs for all totems that fit that slot.
|
flickerstreak@161
|
50 Note this is available in the secure environment, but because IsSpellKnown() is not,
|
flickerstreak@161
|
51 it makes it pretty much useless.
|
flickerstreak@161
|
52
|
flickerstreak@161
|
53 Blizzard textures:
|
flickerstreak@161
|
54 All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single
|
flickerstreak@161
|
55 texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose
|
flickerstreak@161
|
56 this is to slightly optimize texture load performance, but it makes the UI code more clumsy.
|
flickerstreak@161
|
57
|
flickerstreak@161
|
58 Each totem button and arrow has a colored border indicating its elemental type.
|
flickerstreak@161
|
59 TODO: update code to use these pretty per-slot icons, or start setting a border.
|
flickerstreak@161
|
60
|
flickerstreak@161
|
61 Design Notes:
|
flickerstreak@161
|
62 - Only the header has a secure context. All other frames execute in its context.
|
flickerstreak@161
|
63
|
flickerstreak@161
|
64 - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are
|
flickerstreak@161
|
65 GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by
|
flickerstreak@161
|
66 the summon flyout, which is also paged with the summon spells (the recall button is not paged)
|
flickerstreak@161
|
67
|
flickerstreak@161
|
68 - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new
|
flickerstreak@161
|
69 spells) with the list of spells known for each slot.
|
flickerstreak@161
|
70
|
flickerstreak@161
|
71 - Each button (except recall) has an arrow button which appears on mouseover and when clicked
|
flickerstreak@161
|
72 opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not
|
flickerstreak@161
|
73 appear.
|
flickerstreak@161
|
74 TODO: add an alt-button ("SHOWMULTICASTFLYOUT") statemachine to the bar to listen for alt key
|
flickerstreak@161
|
75 presses and open/close the bar. Tapping the alt key toggles the flyout.
|
flickerstreak@161
|
76
|
flickerstreak@161
|
77 - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child
|
flickerstreak@161
|
78 of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding
|
flickerstreak@161
|
79 spell/type from the list, according to the slot which opened the flyout. Each button either sets
|
flickerstreak@161
|
80 the current page (summon) or sets a multispell to an actionID via type="multispell". None of them
|
flickerstreak@161
|
81 actually cast any spells (though, I suppose we could modify this so that e.g. configurable
|
flickerstreak@161
|
82 right-click casts the spell). The flyout also has a close button which closes the flyout: the
|
flickerstreak@161
|
83 flyout-open code positions the close button anchored to the last button in the flyout (which
|
flickerstreak@161
|
84 changes dynamically because each slot has a different number of items in the list).
|
flickerstreak@161
|
85
|
flickerstreak@161
|
86 - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of
|
flickerstreak@161
|
87 the summon spells is cast from elsewhere. Additionally, in the default UI Call of the Elements
|
flickerstreak@161
|
88 always appears as the active summon when the UI is loaded, which is bad design that could be improved
|
flickerstreak@161
|
89 upon. TODO: Store state in a config variable and restore it at load time.
|
flickerstreak@161
|
90
|
flickerstreak@161
|
91
|
flickerstreak@161
|
92 ]]--
|
flickerstreak@161
|
93
|
flickerstreak@161
|
94
|
flickerstreak@161
|
95 --
|
flickerstreak@161
|
96 -- Secure snippets
|
flickerstreak@161
|
97 --
|
flickerstreak@161
|
98
|
flickerstreak@161
|
99 -- bar
|
flickerstreak@161
|
100 local _bar_init = -- function(self)
|
flickerstreak@161
|
101 [[
|
flickerstreak@161
|
102 -- set up some globals in the secure environment
|
flickerstreak@161
|
103 flyout = self:GetFrameRef("flyout")
|
flickerstreak@161
|
104 flyoutChildren = newtable()
|
flickerstreak@161
|
105 nMultiCastSlots = self:GetAttribute("nMultiCastSlots")
|
flickerstreak@161
|
106 baseActionID = self:GetAttribute("baseActionID")
|
flickerstreak@163
|
107 currentMultiCastPage = currentMultiCastPage or self:GetAttribute("lastSummon") or 1
|
flickerstreak@161
|
108 multiCastSpellList = newtable()
|
flickerstreak@161
|
109 for i = 1, nMultiCastSlots do
|
flickerstreak@161
|
110 tinsert(multiCastSpellList, newtable())
|
flickerstreak@161
|
111 end
|
flickerstreak@161
|
112 ]]
|
flickerstreak@161
|
113
|
flickerstreak@161
|
114 local _onstate_multispellpage = -- function(self, stateid, newstate)
|
flickerstreak@161
|
115 [[
|
flickerstreak@161
|
116 currentMultiCastPage = tonumber(newstate)
|
flickerstreak@163
|
117 control:CallMethod("UpdateLastSummon",currentMultiCastPage)
|
flickerstreak@161
|
118 control:ChildUpdate()
|
flickerstreak@161
|
119 ]]
|
flickerstreak@161
|
120
|
flickerstreak@161
|
121
|
flickerstreak@161
|
122 -- buttons
|
flickerstreak@161
|
123 local _childupdate = -- function(self, snippetid, message)
|
flickerstreak@161
|
124 [[
|
flickerstreak@161
|
125 if self:GetAttribute("type") == "spell" then
|
flickerstreak@161
|
126 self:SetAttribute("spell", self:GetAttribute("spell-page"..currentMultiCastPage))
|
flickerstreak@161
|
127 elseif self:GetAttribute("type") == "action" then
|
flickerstreak@161
|
128 self:SetAttribute("action", self:GetAttribute("action-page"..currentMultiCastPage))
|
flickerstreak@161
|
129 end
|
flickerstreak@161
|
130 ]]
|
flickerstreak@161
|
131
|
flickerstreak@161
|
132 local _onEnter = -- function(self)
|
flickerstreak@161
|
133 -- for whatever reason, RegisterAutoHide is unreliable
|
flickerstreak@161
|
134 -- unless you re-anchor the frame prior to calling it.
|
flickerstreak@161
|
135 -- Even then, it's still not terribly reliable.
|
flickerstreak@161
|
136 [[
|
flickerstreak@161
|
137 local idx = self:GetAttribute("bar-idx")
|
flickerstreak@161
|
138 if not (flyout:IsVisible() and flyoutIdx == idx) then
|
flickerstreak@161
|
139 local arrow = owner:GetFrameRef("arrow-"..idx)
|
flickerstreak@161
|
140 if arrow and not arrow:IsShown() then
|
flickerstreak@161
|
141 arrow:ClearAllPoints()
|
flickerstreak@161
|
142 arrow:SetPoint("BOTTOM",self,"TOP",0,0) -- TODO: better anchoring
|
flickerstreak@161
|
143 arrow:Show()
|
flickerstreak@161
|
144 arrow:RegisterAutoHide(0)
|
flickerstreak@161
|
145 arrow:AddToAutoHide(self)
|
flickerstreak@161
|
146 end
|
flickerstreak@161
|
147 end
|
flickerstreak@161
|
148 ]]
|
flickerstreak@161
|
149
|
flickerstreak@161
|
150 local _onLeave = -- function(self)
|
flickerstreak@161
|
151 -- to increase reliability (somewhat), re-register it for hide on leave
|
flickerstreak@161
|
152 [[
|
flickerstreak@161
|
153 local arrow = owner:GetFrameRef("arrow-"..self:GetAttribute("bar-idx"))
|
flickerstreak@161
|
154 if arrow then
|
flickerstreak@161
|
155 arrow:RegisterAutoHide(0)
|
flickerstreak@161
|
156 arrow:AddToAutoHide(self)
|
flickerstreak@161
|
157 end
|
flickerstreak@161
|
158 ]]
|
flickerstreak@161
|
159
|
flickerstreak@161
|
160
|
flickerstreak@161
|
161 -- flyout arrow
|
flickerstreak@161
|
162 local _arrow_openFlyout = -- function(self)
|
flickerstreak@161
|
163 [[
|
flickerstreak@161
|
164 local currentMultiCastSlot = self:GetAttribute("bar-idx")
|
flickerstreak@161
|
165 local lastButton, lastIdx
|
flickerstreak@161
|
166 for idx, b in ipairs(flyoutChildren) do
|
flickerstreak@161
|
167 b:Hide() -- force the OnShow handler to run later
|
flickerstreak@161
|
168 local spellID = multiCastSpellList[currentMultiCastSlot][idx]
|
flickerstreak@161
|
169 if spellID then
|
flickerstreak@161
|
170 b:SetAttribute("spell",spellID) -- does passing 0 work for no-totem? Do we have to convert to nil?
|
flickerstreak@161
|
171 if currentMultiCastSlot == 1 then
|
flickerstreak@161
|
172 b:SetAttribute("type","changePage")
|
flickerstreak@161
|
173 else
|
flickerstreak@161
|
174 b:SetAttribute("type","multispell")
|
flickerstreak@161
|
175 local totemID = owner:GetAttribute("TOTEM_PRIORITY_"..(currentMultiCastSlot - 1))
|
flickerstreak@161
|
176 b:SetAttribute("action", baseActionID + (currentMultiCastPage - 1)*(nMultiCastSlots-2) + totemID)
|
flickerstreak@161
|
177 end
|
flickerstreak@161
|
178 b:Show()
|
flickerstreak@161
|
179 lastButton = b
|
flickerstreak@161
|
180 lastIdx = idx
|
flickerstreak@161
|
181 end
|
flickerstreak@161
|
182 end
|
flickerstreak@161
|
183
|
flickerstreak@161
|
184 local close = owner:GetFrameRef("close")
|
flickerstreak@161
|
185 if lastButton and close then
|
flickerstreak@161
|
186 close:ClearAllPoints()
|
flickerstreak@161
|
187 close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring
|
flickerstreak@161
|
188 close:Show()
|
flickerstreak@161
|
189 end
|
flickerstreak@161
|
190
|
flickerstreak@161
|
191 flyout:ClearAllPoints()
|
flickerstreak@161
|
192 flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring
|
flickerstreak@161
|
193 if lastIdx then
|
flickerstreak@161
|
194 flyout:SetHeight(lastIdx * 27 + (close and close:GetHeight() or 0))
|
flickerstreak@161
|
195 end
|
flickerstreak@161
|
196 flyout:Show()
|
flickerstreak@161
|
197 flyout:RegisterAutoHide(1) -- TODO: configurable
|
flickerstreak@161
|
198 flyout:AddToAutoHide(owner)
|
flickerstreak@161
|
199 flyoutIdx = currentMultiCastSlot
|
flickerstreak@161
|
200 self:Hide()
|
flickerstreak@161
|
201 ]]
|
flickerstreak@161
|
202
|
flickerstreak@161
|
203 local _closeFlyout = -- function(self)
|
flickerstreak@161
|
204 [[
|
flickerstreak@161
|
205 flyout:Hide()
|
flickerstreak@161
|
206 ]]
|
flickerstreak@161
|
207
|
flickerstreak@161
|
208
|
flickerstreak@161
|
209 -- flyout child buttons
|
flickerstreak@161
|
210 local _flyout_child_preClick = -- function(self, button, down)
|
flickerstreak@161
|
211 [[
|
flickerstreak@161
|
212 local button = button
|
flickerstreak@161
|
213 if self:GetAttribute("type") == "changePage" then
|
flickerstreak@161
|
214 owner:SetAttribute("state-multispellpage",self:GetAttribute("index"))
|
flickerstreak@161
|
215 self:GetParent():Hide()
|
flickerstreak@161
|
216 return false
|
flickerstreak@161
|
217 else
|
flickerstreak@161
|
218 return nil, "close"
|
flickerstreak@161
|
219 end
|
flickerstreak@161
|
220 ]]
|
flickerstreak@161
|
221
|
flickerstreak@161
|
222 local _flyout_child_postClick = -- function(self, message, button, down)
|
flickerstreak@161
|
223 [[
|
flickerstreak@161
|
224 if message == "close" then
|
flickerstreak@161
|
225 self:GetParent():Hide() -- hide flyout after selecting
|
flickerstreak@161
|
226 end
|
flickerstreak@161
|
227 ]]
|
flickerstreak@161
|
228
|
flickerstreak@161
|
229
|
flickerstreak@161
|
230 --
|
flickerstreak@161
|
231 -- The Blizzard totem bar textures are all actually one big texture,
|
flickerstreak@161
|
232 -- with texcoord offsets
|
flickerstreak@161
|
233 --
|
flickerstreak@161
|
234 local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar"
|
flickerstreak@161
|
235 local FLYOUT_UP_BUTTON_TCOORDS = { 99/128, 127/128, 84/256, 102/256 }
|
flickerstreak@161
|
236 local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 }
|
flickerstreak@161
|
237 local FLYOUT_DOWN_BUTTON_TCOORDS = { 99/128, 127/128, 65/256, 83/256 }
|
flickerstreak@161
|
238 local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 }
|
flickerstreak@161
|
239 local EMPTY_SLOT_TCOORDS = { 66/128, 96/128, 3/256, 33/256 }
|
flickerstreak@161
|
240
|
flickerstreak@161
|
241 local eventList = {
|
flickerstreak@161
|
242 "ACTIONBAR_SLOT_CHANGED",
|
flickerstreak@161
|
243 "ACTIONBAR_UPDATE_STATE",
|
flickerstreak@161
|
244 "ACTIONBAR_UPDATE_USABLE",
|
flickerstreak@161
|
245 "ACTIONBAR_UPDATE_COOLDOWN",
|
flickerstreak@162
|
246 "UPDATE_BINDINGS",
|
flickerstreak@161
|
247 "UPDATE_MULTI_CAST_ACTIONBAR",
|
flickerstreak@161
|
248 }
|
flickerstreak@161
|
249
|
flickerstreak@161
|
250 --
|
flickerstreak@161
|
251 -- MultiCast Button class
|
flickerstreak@161
|
252 -- Inherits implementation methods from Action button class, but circumvents the constructor
|
flickerstreak@161
|
253 -- and redefines/removes some methods.
|
flickerstreak@161
|
254 --
|
flickerstreak@161
|
255 local Super = ReAction.Button
|
flickerstreak@161
|
256 local Action = ReAction.Button.Action
|
flickerstreak@161
|
257 local MultiCast = setmetatable( { }, { __index = Action } )
|
flickerstreak@161
|
258 ReAction.Button.MultiCast = MultiCast
|
flickerstreak@161
|
259
|
flickerstreak@161
|
260 function MultiCast:New( idx, btnConfig, bar )
|
flickerstreak@161
|
261 if idx < 1 or idx > NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then
|
flickerstreak@161
|
262 error("Multicast button index out of range")
|
flickerstreak@161
|
263 end
|
flickerstreak@161
|
264
|
flickerstreak@163
|
265 if idx > bar.nMultiCastSlots then
|
flickerstreak@163
|
266 return false
|
flickerstreak@163
|
267 end
|
flickerstreak@163
|
268
|
flickerstreak@161
|
269 local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
|
flickerstreak@161
|
270
|
flickerstreak@161
|
271 self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
|
flickerstreak@161
|
272
|
flickerstreak@161
|
273 local barFrame = bar:GetFrame()
|
flickerstreak@161
|
274 local f = self:GetFrame()
|
flickerstreak@161
|
275
|
flickerstreak@161
|
276 -- attributes
|
flickerstreak@163
|
277 local page = (idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2) and 1 or (bar:GetConfig().lastSummon or 1)
|
flickerstreak@161
|
278 if idx == 1 or idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then
|
flickerstreak@161
|
279 f:SetAttribute("type","spell")
|
flickerstreak@161
|
280 local spells = idx == 1 and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS
|
flickerstreak@163
|
281 f:SetAttribute("spell",spells[page])
|
flickerstreak@161
|
282 for i, spell in ipairs(spells) do
|
flickerstreak@161
|
283 if spell and IsSpellKnown(spell) then
|
flickerstreak@161
|
284 f:SetAttribute("spell-page"..i, spell)
|
flickerstreak@161
|
285 end
|
flickerstreak@161
|
286 end
|
flickerstreak@161
|
287 else
|
flickerstreak@161
|
288 local baseAction = barFrame:GetAttribute("baseActionID") + TOTEM_PRIORITIES[idx-1]
|
flickerstreak@161
|
289 f:SetAttribute("type","action")
|
flickerstreak@163
|
290 f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
|
flickerstreak@161
|
291 for i = 1, NUM_MULTI_CAST_PAGES do
|
flickerstreak@161
|
292 f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
|
flickerstreak@161
|
293 end
|
flickerstreak@161
|
294 end
|
flickerstreak@161
|
295 f:SetAttribute("bar-idx",idx)
|
flickerstreak@161
|
296 barFrame:SetFrameRef("slot-"..idx,f)
|
flickerstreak@161
|
297
|
flickerstreak@161
|
298 -- non secure scripts
|
flickerstreak@161
|
299 f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
|
flickerstreak@161
|
300 f:SetScript("OnEnter", function(frame) self:OnEnter() end)
|
flickerstreak@161
|
301 f:SetScript("OnLeave", function(frame) self:OnLeave() end)
|
flickerstreak@161
|
302 f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
|
flickerstreak@161
|
303 f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
|
flickerstreak@161
|
304
|
flickerstreak@161
|
305 -- secure handlers
|
flickerstreak@161
|
306 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then
|
flickerstreak@161
|
307 f:SetAttribute("_childupdate",_childupdate)
|
flickerstreak@161
|
308 end
|
flickerstreak@161
|
309 barFrame:WrapScript(f, "OnEnter", _onEnter)
|
flickerstreak@161
|
310
|
flickerstreak@161
|
311 -- event registration
|
flickerstreak@161
|
312 f:EnableMouse(true)
|
flickerstreak@161
|
313 f:RegisterForClicks("AnyUp")
|
flickerstreak@161
|
314 for _, evt in pairs(eventList) do
|
flickerstreak@161
|
315 f:RegisterEvent(evt)
|
flickerstreak@161
|
316 end
|
flickerstreak@161
|
317
|
flickerstreak@162
|
318 -- Set up a proxy for the icon texture for use with ButtonFacade
|
flickerstreak@162
|
319 self.frames.icon.SetTexCoordRaw = self.frames.icon.SetTexCoord
|
flickerstreak@162
|
320 self.frames.icon.SetTexCoord = function( tx, ... )
|
flickerstreak@162
|
321 if self:GetIconTexture() == TOTEM_TEXTURE then
|
flickerstreak@162
|
322 tx:SetTexCoordRaw(unpack(EMPTY_SLOT_TCOORDS))
|
flickerstreak@162
|
323 else
|
flickerstreak@162
|
324 tx:SetTexCoordRaw(...)
|
flickerstreak@162
|
325 end
|
flickerstreak@162
|
326 end
|
flickerstreak@162
|
327
|
flickerstreak@161
|
328 -- attach to skinner
|
flickerstreak@161
|
329 bar:SkinButton(self)
|
flickerstreak@161
|
330
|
flickerstreak@161
|
331 f:Show()
|
flickerstreak@161
|
332
|
flickerstreak@161
|
333 -- open arrow
|
flickerstreak@161
|
334 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then
|
flickerstreak@161
|
335 local arrow = CreateFrame("Button", nil, f, "SecureFrameTemplate")
|
flickerstreak@161
|
336 arrow:SetWidth(28)
|
flickerstreak@161
|
337 arrow:SetHeight(12)
|
flickerstreak@161
|
338 arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring
|
flickerstreak@161
|
339 arrow:SetNormalTexture(TOTEM_TEXTURE)
|
flickerstreak@161
|
340 arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS) )
|
flickerstreak@161
|
341 arrow:SetHighlightTexture(TOTEM_TEXTURE)
|
flickerstreak@161
|
342 arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) )
|
flickerstreak@161
|
343 arrow:SetAttribute("bar-idx",idx)
|
flickerstreak@161
|
344 arrow:Hide()
|
flickerstreak@161
|
345 barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout)
|
flickerstreak@161
|
346 local arrowRef = "arrow-"..idx
|
flickerstreak@161
|
347 barFrame:SetFrameRef(arrowRef,arrow)
|
flickerstreak@161
|
348 end
|
flickerstreak@161
|
349
|
flickerstreak@161
|
350 self:Refresh()
|
flickerstreak@161
|
351
|
flickerstreak@161
|
352 return self
|
flickerstreak@161
|
353 end
|
flickerstreak@161
|
354
|
flickerstreak@161
|
355 function MultiCast:Destroy()
|
flickerstreak@161
|
356 local barFrame = self:GetFrame()
|
flickerstreak@161
|
357 Super.Destroy(self)
|
flickerstreak@161
|
358 end
|
flickerstreak@161
|
359
|
flickerstreak@161
|
360 function MultiCast:Refresh()
|
flickerstreak@161
|
361 Super.Refresh(self)
|
flickerstreak@161
|
362 self:UpdateAction()
|
flickerstreak@161
|
363 end
|
flickerstreak@161
|
364
|
flickerstreak@161
|
365 function MultiCast:ShowGrid( show )
|
flickerstreak@161
|
366 end
|
flickerstreak@161
|
367
|
flickerstreak@161
|
368 function MultiCast:ShowGridTemp( show )
|
flickerstreak@161
|
369 end
|
flickerstreak@161
|
370
|
flickerstreak@161
|
371 function MultiCast:AcquireActionID()
|
flickerstreak@161
|
372 end
|
flickerstreak@161
|
373
|
flickerstreak@161
|
374 function MultiCast:ReleaseActionID()
|
flickerstreak@161
|
375 end
|
flickerstreak@161
|
376
|
flickerstreak@161
|
377 function MultiCast:UpdateShowGrid()
|
flickerstreak@161
|
378 end
|
flickerstreak@161
|
379
|
flickerstreak@161
|
380 function MultiCast:UpdateBorder()
|
flickerstreak@161
|
381 end
|
flickerstreak@161
|
382
|
flickerstreak@161
|
383 function MultiCast:UpdateMacroText()
|
flickerstreak@161
|
384 end
|
flickerstreak@161
|
385
|
flickerstreak@161
|
386 function MultiCast:UpdateCount()
|
flickerstreak@161
|
387 end
|
flickerstreak@161
|
388
|
flickerstreak@161
|
389 function MultiCast:UpdateCheckedState()
|
flickerstreak@161
|
390 local action = self:GetActionID()
|
flickerstreak@161
|
391 if action and IsCurrentAction(action) then
|
flickerstreak@161
|
392 self:GetFrame():SetChecked(1)
|
flickerstreak@161
|
393 else
|
flickerstreak@161
|
394 self:GetFrame():SetChecked(0)
|
flickerstreak@161
|
395 end
|
flickerstreak@161
|
396 end
|
flickerstreak@161
|
397
|
flickerstreak@161
|
398 function MultiCast:RefreshHasActionAttributes()
|
flickerstreak@161
|
399 end
|
flickerstreak@161
|
400
|
flickerstreak@161
|
401 function MultiCast:UpdateFlash()
|
flickerstreak@161
|
402 end
|
flickerstreak@161
|
403
|
flickerstreak@161
|
404 function MultiCast:GetIconTexture()
|
flickerstreak@161
|
405 local tx
|
flickerstreak@161
|
406 if self.spellID then
|
flickerstreak@161
|
407 tx = GetSpellTexture(GetSpellInfo(self.spellID))
|
flickerstreak@161
|
408 elseif self.actionID then
|
flickerstreak@161
|
409 tx = GetActionTexture(self.actionID)
|
flickerstreak@161
|
410 end
|
flickerstreak@161
|
411 if tx then
|
flickerstreak@161
|
412 return tx
|
flickerstreak@161
|
413 else
|
flickerstreak@161
|
414 return TOTEM_TEXTURE, unpack(EMPTY_SLOT_TCOORDS)
|
flickerstreak@161
|
415 end
|
flickerstreak@161
|
416 end
|
flickerstreak@161
|
417
|
flickerstreak@161
|
418 function MultiCast:UpdateAction()
|
flickerstreak@161
|
419 local action = self:GetActionID()
|
flickerstreak@161
|
420 if action then
|
flickerstreak@161
|
421 if action ~= self.actionID then
|
flickerstreak@161
|
422 self.actionID = action
|
flickerstreak@161
|
423 self:UpdateAll()
|
flickerstreak@161
|
424 end
|
flickerstreak@161
|
425 else
|
flickerstreak@161
|
426 local spellID = self:GetSpellID()
|
flickerstreak@161
|
427 if spellID ~= self.spellID then
|
flickerstreak@161
|
428 self.spellID = spellID
|
flickerstreak@161
|
429 self:UpdateAll()
|
flickerstreak@161
|
430 end
|
flickerstreak@161
|
431 end
|
flickerstreak@161
|
432 end
|
flickerstreak@161
|
433
|
flickerstreak@161
|
434 function MultiCast:GetActionID(page)
|
flickerstreak@161
|
435 return self:GetFrame():GetAttribute("action")
|
flickerstreak@161
|
436 end
|
flickerstreak@161
|
437
|
flickerstreak@161
|
438 function MultiCast:GetSpellID(page)
|
flickerstreak@161
|
439 return self:GetFrame():GetAttribute("spell")
|
flickerstreak@161
|
440 end
|
flickerstreak@161
|
441
|
flickerstreak@161
|
442 function MultiCast:SetActionID( id )
|
flickerstreak@161
|
443 error("Can not set action ID of multicast buttons")
|
flickerstreak@161
|
444 end
|
flickerstreak@161
|
445
|
flickerstreak@161
|
446 function MultiCast:SetTooltip()
|
flickerstreak@161
|
447 local barFrame = self:GetFrame()
|
flickerstreak@161
|
448 if GetCVar("UberTooltips") == "1" then
|
flickerstreak@161
|
449 GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
|
flickerstreak@161
|
450 else
|
flickerstreak@161
|
451 GameTooltip:SetOwner(barFrame)
|
flickerstreak@161
|
452 end
|
flickerstreak@161
|
453 if self.spellID then
|
flickerstreak@161
|
454 GameTooltip:SetSpellByID(self.spellID,false,true)
|
flickerstreak@161
|
455 elseif self.actionID then
|
flickerstreak@161
|
456 GameTooltip:SetAction(self.actionID)
|
flickerstreak@161
|
457 end
|
flickerstreak@161
|
458 end
|
flickerstreak@161
|
459
|
flickerstreak@161
|
460 function MultiCast:GetUsable()
|
flickerstreak@161
|
461 if self.spellID then
|
flickerstreak@161
|
462 return IsUsableSpell((GetSpellInfo(self.spellID)))
|
flickerstreak@161
|
463 elseif self.actionID then
|
flickerstreak@161
|
464 return IsUsableAction(self.actionID)
|
flickerstreak@161
|
465 end
|
flickerstreak@161
|
466 end
|
flickerstreak@161
|
467
|
flickerstreak@161
|
468 function MultiCast:GetInRange()
|
flickerstreak@161
|
469 if self.spellID then
|
flickerstreak@161
|
470 return IsSpellInRange((GetSpellInfo(self.spellID))) == 0
|
flickerstreak@161
|
471 elseif self.actionID then
|
flickerstreak@161
|
472 return IsActionInRange(self.actionID) == 0
|
flickerstreak@161
|
473 end
|
flickerstreak@161
|
474 end
|
flickerstreak@161
|
475
|
flickerstreak@161
|
476 function MultiCast:GetCooldown()
|
flickerstreak@161
|
477 if self.spellID then
|
flickerstreak@161
|
478 return GetSpellCooldown((GetSpellInfo(self.spellID)))
|
flickerstreak@161
|
479 elseif self.actionID then
|
flickerstreak@161
|
480 return GetActionCooldown(self.actionID)
|
flickerstreak@161
|
481 else
|
flickerstreak@161
|
482 return 0, 0, 0
|
flickerstreak@161
|
483 end
|
flickerstreak@161
|
484 end
|
flickerstreak@161
|
485
|
flickerstreak@161
|
486 function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR()
|
flickerstreak@161
|
487 self:UpdateAll()
|
flickerstreak@161
|
488 end
|
flickerstreak@161
|
489
|
flickerstreak@161
|
490
|
flickerstreak@161
|
491 --
|
flickerstreak@161
|
492 -- flyout setup
|
flickerstreak@161
|
493 --
|
flickerstreak@161
|
494 local function ShowFlyoutTooltip(barFrame)
|
flickerstreak@161
|
495 if GetCVar("UberTooltips") == "1" then
|
flickerstreak@161
|
496 GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
|
flickerstreak@161
|
497 else
|
flickerstreak@161
|
498 GameTooltip:SetOwner(barFrame)
|
flickerstreak@161
|
499 end
|
flickerstreak@161
|
500 local spell = barFrame:GetAttribute("spell")
|
flickerstreak@161
|
501 if barFrame == 0 then
|
flickerstreak@161
|
502 GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
flickerstreak@161
|
503 else
|
flickerstreak@161
|
504 GameTooltip:SetSpellByID(barFrame:GetAttribute("spell"),false,true)
|
flickerstreak@161
|
505 end
|
flickerstreak@161
|
506 end
|
flickerstreak@161
|
507
|
flickerstreak@161
|
508 local function HideFlyoutTooltip()
|
flickerstreak@161
|
509 GameTooltip:Hide()
|
flickerstreak@161
|
510 end
|
flickerstreak@161
|
511
|
flickerstreak@161
|
512 local function UpdateFlyoutIcon(frame)
|
flickerstreak@161
|
513 local spellID = frame:GetAttribute("spell")
|
flickerstreak@161
|
514 if spellID == 0 then
|
flickerstreak@161
|
515 frame.icon:SetTexture(TOTEM_TEXTURE)
|
flickerstreak@161
|
516 frame.icon:SetTexCoord( unpack(EMPTY_SLOT_TCOORDS) )
|
flickerstreak@161
|
517 elseif spellID then
|
flickerstreak@161
|
518 frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID)))
|
flickerstreak@161
|
519 frame.icon:SetTexCoord(0,1,0,1)
|
flickerstreak@161
|
520 end
|
flickerstreak@161
|
521 end
|
flickerstreak@161
|
522
|
flickerstreak@161
|
523 function MultiCast.SetupBarHeader( bar ) -- call this as a static method
|
flickerstreak@161
|
524 local summon = { }
|
flickerstreak@161
|
525 local recall = { }
|
flickerstreak@161
|
526 local maxIdx = 1
|
flickerstreak@161
|
527
|
flickerstreak@161
|
528 for idx, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do
|
flickerstreak@161
|
529 if spell and IsSpellKnown(spell) then
|
flickerstreak@161
|
530 tinsert(summon,spell)
|
flickerstreak@161
|
531 maxIdx = max(idx,maxIdx)
|
flickerstreak@161
|
532 end
|
flickerstreak@161
|
533 end
|
flickerstreak@161
|
534
|
flickerstreak@161
|
535 for idx, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do
|
flickerstreak@161
|
536 if spell and IsSpellKnown(spell) then
|
flickerstreak@161
|
537 tinsert(recall,spell)
|
flickerstreak@161
|
538 maxIdx = max(idx,maxIdx)
|
flickerstreak@161
|
539 end
|
flickerstreak@161
|
540 end
|
flickerstreak@161
|
541
|
flickerstreak@161
|
542 if #summon == 0 and #recall == 0 then
|
flickerstreak@163
|
543 bar.nMultiCastSlots = 0 -- no multicast capability
|
flickerstreak@163
|
544 return
|
flickerstreak@161
|
545 end
|
flickerstreak@161
|
546
|
flickerstreak@161
|
547 local slots = { }
|
flickerstreak@161
|
548
|
flickerstreak@161
|
549 tinsert(slots, summon)
|
flickerstreak@161
|
550
|
flickerstreak@161
|
551 for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
|
flickerstreak@161
|
552 local slotSpells = { 0, GetMultiCastTotemSpells(TOTEM_PRIORITIES[i]) }
|
flickerstreak@161
|
553 maxIdx = max(maxIdx, #slotSpells)
|
flickerstreak@161
|
554 tinsert(slots,slotSpells)
|
flickerstreak@161
|
555 end
|
flickerstreak@161
|
556
|
flickerstreak@161
|
557 tinsert(slots, recall)
|
flickerstreak@161
|
558
|
flickerstreak@161
|
559 local barFrame = bar:GetFrame()
|
flickerstreak@161
|
560
|
flickerstreak@161
|
561 -- init bar secure environment
|
flickerstreak@163
|
562 barFrame:SetAttribute("lastSummon",bar:GetConfig().lastSummon)
|
flickerstreak@161
|
563 barFrame:SetAttribute("nMultiCastSlots",#slots)
|
flickerstreak@161
|
564 barFrame:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS)
|
flickerstreak@161
|
565 barFrame:SetAttribute("_onstate-multispellpage", _onstate_multispellpage)
|
flickerstreak@161
|
566 barFrame:Execute(_bar_init)
|
flickerstreak@161
|
567
|
flickerstreak@163
|
568 function barFrame:UpdateLastSummon(value)
|
flickerstreak@163
|
569 bar:GetConfig().lastSummon = value
|
flickerstreak@163
|
570 end
|
flickerstreak@163
|
571
|
flickerstreak@161
|
572 for i, p in ipairs(TOTEM_PRIORITIES) do
|
flickerstreak@161
|
573 barFrame:SetAttribute("TOTEM_PRIORITY_"..i,p)
|
flickerstreak@161
|
574 end
|
flickerstreak@161
|
575
|
flickerstreak@161
|
576 -- create flyout container frame and close arrow
|
flickerstreak@161
|
577 local flyout = bar._flyoutFrame
|
flickerstreak@161
|
578 if not flyout then
|
flickerstreak@161
|
579 flyout = CreateFrame("Frame", nil, barFrame, "SecureFrameTemplate")
|
flickerstreak@161
|
580 bar._flyoutFrame = flyout
|
flickerstreak@161
|
581 barFrame:SetFrameRef("flyout",flyout)
|
flickerstreak@161
|
582 flyout.buttons = { }
|
flickerstreak@161
|
583 flyout:Hide()
|
flickerstreak@161
|
584 flyout:SetWidth(24)
|
flickerstreak@161
|
585 flyout:SetHeight(1)
|
flickerstreak@161
|
586 flyout:SetPoint("BOTTOM",barFrame,"TOP",0,0)
|
flickerstreak@161
|
587
|
flickerstreak@161
|
588 local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate")
|
flickerstreak@161
|
589 close:SetWidth(28)
|
flickerstreak@161
|
590 close:SetHeight(12)
|
flickerstreak@161
|
591 close:SetPoint("TOP")
|
flickerstreak@161
|
592 close:SetNormalTexture(TOTEM_TEXTURE)
|
flickerstreak@161
|
593 close:GetNormalTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_TCOORDS) )
|
flickerstreak@161
|
594 close:SetHighlightTexture(TOTEM_TEXTURE)
|
flickerstreak@161
|
595 close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) )
|
flickerstreak@161
|
596 barFrame:SetFrameRef("close",close)
|
flickerstreak@161
|
597 barFrame:WrapScript(close, "OnClick", _closeFlyout)
|
flickerstreak@161
|
598 end
|
flickerstreak@161
|
599
|
flickerstreak@161
|
600 -- create flyout buttons
|
flickerstreak@161
|
601 for i = #flyout.buttons + 1, maxIdx do
|
flickerstreak@161
|
602 local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate")
|
flickerstreak@161
|
603 b:SetWidth(24)
|
flickerstreak@161
|
604 b:SetHeight(24)
|
flickerstreak@161
|
605 local prev = flyout.buttons[i-1]
|
flickerstreak@161
|
606 b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring
|
flickerstreak@161
|
607 b.icon = b:CreateTexture("BACKGROUND")
|
flickerstreak@161
|
608 b.icon:SetAllPoints()
|
flickerstreak@161
|
609 b.icon:Show()
|
flickerstreak@161
|
610 b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
|
flickerstreak@161
|
611 b:GetHighlightTexture():SetBlendMode("ADD")
|
flickerstreak@161
|
612 b:RegisterForClicks("AnyUp")
|
flickerstreak@161
|
613 b:SetScript("OnShow",UpdateFlyoutIcon)
|
flickerstreak@161
|
614 b:SetScript("OnEnter",ShowFlyoutTooltip)
|
flickerstreak@161
|
615 b:SetScript("OnLeave",HideFlyoutTooltip)
|
flickerstreak@161
|
616 b:SetAttribute("index",i)
|
flickerstreak@161
|
617 b:Show()
|
flickerstreak@161
|
618 barFrame:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick)
|
flickerstreak@161
|
619 flyout.buttons[i] = b
|
flickerstreak@161
|
620 end
|
flickerstreak@161
|
621
|
flickerstreak@161
|
622 for i, b in ipairs(flyout.buttons) do
|
flickerstreak@161
|
623 barFrame:SetFrameRef("flyout-child",b)
|
flickerstreak@161
|
624 barFrame:Execute([[
|
flickerstreak@161
|
625 tinsert(flyoutChildren,self:GetFrameRef("flyout-child"))
|
flickerstreak@161
|
626 ]])
|
flickerstreak@161
|
627 end
|
flickerstreak@161
|
628
|
flickerstreak@161
|
629 -- transfer the table of spell IDs into the secure environment
|
flickerstreak@161
|
630 for i, spells in ipairs(slots) do
|
flickerstreak@161
|
631 barFrame:SetAttribute("spell-slot", i)
|
flickerstreak@161
|
632 for j, spell in ipairs(spells) do
|
flickerstreak@161
|
633 barFrame:SetAttribute("spell-index", j)
|
flickerstreak@161
|
634 barFrame:SetAttribute("spell-id", spell)
|
flickerstreak@161
|
635 barFrame:Execute([[
|
flickerstreak@161
|
636 multiCastSpellList[self:GetAttribute("spell-slot")][self:GetAttribute("spell-index")] = self:GetAttribute("spell-id")
|
flickerstreak@161
|
637 ]])
|
flickerstreak@161
|
638 end
|
flickerstreak@161
|
639 end
|
flickerstreak@161
|
640
|
flickerstreak@163
|
641 bar.nMultiCastSlots = #slots
|
flickerstreak@161
|
642 end
|
flickerstreak@161
|
643
|