· 8 years ago · Aug 17, 2018, 04:52 PM
1--[[
2 Author: Alternator (Massiner of Nathrezim)
3 Copyright 2010
4
5 Notes:
6]]
7
8local Util = BFUtil;
9local Const = BFConst;
10local UILib = BFUILib;
11local CustomAction = BFCustomAction;
12local Button = BFButton;
13local Bar = BFBar;
14local EventFull = BFEventFrames["Full"];
15local MiscFrame = BFEventFrames["Misc"];
16local Delay = BFEventFrames["Delay"];
17local ConfigureLayer = BFConfigureLayer;
18local DestroyBarOverlay = BFDestroyBarOverlay;
19
20--This will get the currently applicable locale, or allocate it if needed (note that locales other than enUS will need the metatable set)
21BFLocales[GetLocale()] = BFLocales[GetLocale()] or {};
22local Locale = BFLocales[GetLocale()];
23if (GetLocale() ~= "enUS") then
24 setmetatable(Locale, BFLocales["enUS"]);
25end
26
27
28
29Util.ActiveButtons = {};
30Util.InactiveButtons = {};
31Util.ActiveMacros = {};
32Util.ActiveSpells = {};
33Util.ActiveItems = {};
34Util.ActiveBonusActions = {};
35
36Util.RangeTimerButtons = {};
37Util.FlashButtons = {};
38
39Util.ActiveBars = {};
40Util.InactiveBars = {};
41
42Util.ActiveTabs = {};
43Util.InactiveTabs = {};
44
45Util.SpellIndex = {};
46Util.SpellMana = {};
47Util.NewSpellIndex = {};
48Util.GlowSpells = {};
49Util.PetSpellIndex = {};
50Util.NewPetSpellIndex = {};
51
52Util.BagItemNameIndex = {};
53Util.BagItemIdIndex = {};
54Util.BagItemNameId = {};
55Util.InvItemNameIndex = {};
56Util.InvItemIdIndex = {};
57Util.InvItemNameId = {};
58
59Util.GridHidden = true;
60Util.LowStrata = true;
61Util.BlizBarWrappers = {};
62Util.BlizEnabledBars = {};
63
64Util.CallbackFunctions = {};
65Util.CallbackArgs = {};
66Util.ButtonWidgetMap = {};
67
68Util.UpdateMacroEventCount = 0;
69Util.MacroCheckDelayComplete = false;
70Util.ForceOffCastOnKeyDown = false;
71Util.MountUselessIndexToIndex = {};
72
73--One quick override function
74local G_PickupSpellBookItem = PickupSpellBookItem;
75local function PickupSpellBookItem(NameRank, Book)
76 local Index, Alt_Book = Util.LookupSpellIndex(NameRank);
77 if (Index) then
78 return G_PickupSpellBookItem(Index, Alt_Book);
79 elseif (Book) then
80 return G_PickupSpellBookItem(NameRank, Book);
81 end
82 return G_PickupSpellBookItem(NameRank);
83end
84
85
86
87--[[
88 Make sure that the saved data is kept inline with the version being run
89--]]
90function Util.UpdateSavedData()
91
92 ---- FIX for MACS, if character data hasn't loaded but is otherwise available in the global save ----
93 local CharRealm = UnitName("player");
94 CharRealm = CharRealm.."-"..GetRealmName();
95 if (ButtonForgeSave == nil
96 and ButtonForgeGlobalBackup ~= nil
97 and ButtonForgeGlobalBackup[CharRealm] ~= nil) then
98 ButtonForgeSave = ButtonForgeGlobalBackup[CharRealm];
99 end
100
101
102 ------The following section updates the per character saved data------
103
104 --Need to allocate save structure
105 if (not ButtonForgeSave) then
106 --Swap v0.9.0 / v0.9.1 / v0.9.2 users to the new save structure
107 if (type(BFSave) == "table" and BFSave["Version"] and BFSave["VersionMinor"] and
108 BFSave["Version"] == 0.9 and BFSave["VersionMinor"] <= 2) then
109 --the above test checks if a legitimate ButtonForge BFSave exists before we adopt it to the new table name
110 ButtonForgeSave = BFSave;
111 BFSave = nil;
112 else
113 ButtonForgeSave = {};
114 ButtonForgeSave["ConfigureMode"] = true;
115 ButtonForgeSave["AdvancedMode"] = false;
116 ButtonForgeSave["RightClickSelfCast"] = false;
117 ButtonForgeSave["Version"] = Const.Version;
118 ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
119 ButtonForgeSave.Bars = {};
120 end
121 ButtonForgeSave["AddonName"] = "Button Forge";
122 end
123
124 --v0.9.3 update
125 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 3) then
126 for i = 1, #ButtonForgeSave.Bars do
127 ButtonForgeSave.Bars[i]["HBonusBar"] = true;
128 end
129 ButtonForgeSave["VersionMinor"] = 3;
130 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.3", .5, 1, 0, 1);
131 end
132
133 --v0.9.12 update
134 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 12) then
135 for i = 1, #ButtonForgeSave.Bars do
136 ButtonForgeSave.Bars[i]["MacroText"] = true;
137 ButtonForgeSave.Bars[i]["KeyBindText"] = true;
138 end
139 ButtonForgeSave["VersionMinor"] = 12;
140 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.12", .5, 1, 0, 1);
141 end
142
143 --v0.9.13 update
144 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 13) then
145 for i = 1, #ButtonForgeSave.Bars do
146 ButtonForgeSave.Bars[i]["Enabled"] = true;
147 ButtonForgeSave.Bars[i]["ButtonGap"] = 6;
148 end
149 ButtonForgeSave["VersionMinor"] = 13;
150 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.13", .5, 1, 0, 1);
151 end
152
153
154 --v0.9.17 update
155 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 17) then
156 for i = 1, #ButtonForgeSave.Bars do
157 ButtonForgeSave.Bars[i]["GUI"] = true;
158 ButtonForgeSave.Bars[i]["Alpha"] = 1;
159 end
160 ButtonForgeSave["VersionMinor"] = 17;
161 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.17", .5, 1, 0, 1);
162 end
163
164 --v0.9.22 update
165 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 22) then
166 for i = 1, #ButtonForgeSave.Bars do
167 if (ButtonForgeSave.Bars[i]["VDriver"] == "[bonusbar:5] show; hide") then
168 ButtonForgeSave.Bars[i]["VDriver"] = "[overridebar][vehicleui] show; hide";
169 end
170 end
171 ButtonForgeSave["VersionMinor"] = 22;
172 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.22", .5, 1, 0, 1);
173 end
174
175 --v0.9.25 update
176 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 25) then
177 for i = 1, #ButtonForgeSave.Bars do
178 ButtonForgeSave.Bars[i]["HPetBattle"] = true;
179 end
180 ButtonForgeSave["VersionMinor"] = 25;
181 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.25", .5, 1, 0, 1);
182 end
183
184 -- v0.9.34 update
185 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 34) then
186 for i = 1, #ButtonForgeSave.Bars do
187 Util.UpdateMounts602(ButtonForgeSave.Bars[i].Buttons);
188 end
189 ButtonForgeSave["VersionMinor"] = 34;
190 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.34", .5, 1, 0, 1);
191 end
192
193 -- v0.9.36 update
194 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 36) then
195 for i = 1, #ButtonForgeSave.Bars do
196 Util.UpdateBattlePets602(ButtonForgeSave.Bars[i].Buttons);
197 end
198
199 if (ButtonForgeSave.UndoProfileBars ~= nil) then
200 for i = 1, #ButtonForgeSave.UndoProfileBars do
201 Util.UpdateMounts602(ButtonForgeSave.UndoProfileBars[i].Buttons);
202 Util.UpdateBattlePets602(ButtonForgeSave.UndoProfileBars[i].Buttons);
203 end
204 end
205 ButtonForgeSave["VersionMinor"] = 36;
206 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.36", .5, 1, 0, 1);
207 end
208
209 -- v0.9.41 update
210 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 41) then
211 for i = 1, #ButtonForgeSave.Bars do
212 Util.UpdateMounts700(ButtonForgeSave.Bars[i].Buttons);
213 end
214
215 if (ButtonForgeSave.UndoProfileBars ~= nil) then
216 for i = 1, #ButtonForgeSave.UndoProfileBars do
217 Util.UpdateMounts700(ButtonForgeSave.UndoProfileBars[i].Buttons);
218 end
219 end
220 ButtonForgeSave["VersionMinor"] = 41;
221 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.41", .5, 1, 0, 1);
222 end
223
224 -- v0.9.42 update
225 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 42) then
226 for i = 1, #ButtonForgeSave.Bars do
227 ButtonForgeSave.Bars[i].HSpec3 = false;
228 ButtonForgeSave.Bars[i].HSpec4 = false;
229 end
230
231 if (ButtonForgeSave.UndoProfileBars ~= nil) then
232 for i = 1, #ButtonForgeSave.UndoProfileBars do
233 ButtonForgeSave.UndoProfileBars[i].HSpec3 = false;
234 ButtonForgeSave.UndoProfileBars[i].HSpec4 = false;
235 end
236 end
237 ButtonForgeSave["VersionMinor"] = 42;
238 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.42", .5, 1, 0, 1);
239 end
240
241 -- v0.9.44 update
242 if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 44) then
243 for i = 1, #ButtonForgeSave.Bars do
244 Util.RemoveCancelPossession700(ButtonForgeSave.Bars[i].Buttons);
245 end
246
247 if (ButtonForgeSave.UndoProfileBars ~= nil) then
248 for i = 1, #ButtonForgeSave.UndoProfileBars do
249 Util.RemoveCancelPossession700(ButtonForgeSave.UndoProfileBars[i].Buttons);
250 end
251 end
252 ButtonForgeSave["VersionMinor"] = 44;
253 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.44", .5, 1, 0, 1);
254 end
255
256
257
258 --Bring v up to the latest version
259 if (ButtonForgeSave["Version"] < Const.Version) then
260 ButtonForgeSave["Version"] = Const.Version;
261 ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
262 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v"..Const.Version.."."..Const.VersionMinor, .5, 1, 0, 1);
263 elseif (ButtonForgeSave["Version"] == Const.Version and ButtonForgeSave["VersionMinor"] < Const.VersionMinor) then
264 ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
265 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v"..Const.Version.."."..Const.VersionMinor, .5, 1, 0, 1);
266 end
267
268
269 -----This section updates the global button forge data (introduced at 0.9.16)
270 if (not ButtonForgeGlobalSettings) then
271 ButtonForgeGlobalSettings = {};
272 ButtonForgeGlobalSettings["Version"] = 0.9;
273 ButtonForgeGlobalSettings["VersionMinor"] = 16;
274 ButtonForgeGlobalSettings["MacroCheckDelay"] = 3;
275 ButtonForgeGlobalSettings["RemoveMissingMacros"] = true;
276 end
277
278 --v0.9.30 update (to global settings)
279 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 30) then
280 ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"] = false;
281 ButtonForgeGlobalSettings["VersionMinor"] = 30;
282 end
283
284 --v0.9.31 update (to global profiles)
285 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 31) then
286 ButtonForgeGlobalProfiles = {};
287 ButtonForgeGlobalSettings["VersionMinor"] = 31;
288 end
289
290 --pre v0.9.36 Safety process
291 if (not ButtonForgeGlobalProfiles) then
292 ButtonForgeGlobalProfiles = {};
293 end
294
295 --v0.9.36 update
296 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 36) then
297 for k,v in pairs(ButtonForgeGlobalProfiles) do
298 for i = 1, #v.Bars do
299 Util.UpdateMounts602(v.Bars[i].Buttons);
300 Util.UpdateBattlePets602(v.Bars[i].Buttons);
301 end
302 end
303 ButtonForgeGlobalSettings["VersionMinor"] = 36;
304 end
305
306 --v0.9.38 update
307 if (ButtonForgeGlobalBackup == nil) then
308 ButtonForgeGlobalBackup = {};
309 end
310
311 -- v0.9.41
312 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 41) then
313 for k, v in pairs(ButtonForgeGlobalProfiles) do
314 for i = 1, #v.Bars do
315 Util.UpdateMounts700(v.Bars[i].Buttons);
316 end
317 end
318 ButtonForgeGlobalSettings["VersionMinor"] = 41;
319 end
320
321 -- v0.9.42
322 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 42) then
323 for k, v in pairs(ButtonForgeGlobalProfiles) do
324 for i = 1, #v.Bars do
325 v.Bars[i].HSpec3 = false;
326 v.Bars[i].HSpec4 = false;
327 end
328 end
329 ButtonForgeGlobalSettings["VersionMinor"] = 42;
330 end
331
332 -- v0.9.44
333 if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 44) then
334 ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"] = not AreDangerousScriptsAllowed();
335 ButtonForgeGlobalSettings["VersionMinor"] = 44;
336
337 for k, v in pairs(ButtonForgeGlobalProfiles) do
338 for i = 1, #v.Bars do
339 Util.RemoveCancelPossession700(v.Bars[i].Buttons);
340 end
341 end
342 end
343
344
345
346
347
348 --Bring the global settings up to the latest version
349 if (ButtonForgeGlobalSettings["Version"] < Const.Version) then
350 ButtonForgeGlobalSettings["Version"] = Const.Version;
351 ButtonForgeGlobalSettings["VersionMinor"] = Const.VersionMinor;
352 elseif (ButtonForgeGlobalSettings["Version"] == Const.Version and ButtonForgeGlobalSettings["VersionMinor"] < Const.VersionMinor) then
353 ButtonForgeGlobalSettings["VersionMinor"] = Const.VersionMinor;
354 end
355end
356
357
358function Util.UpdateMounts602(Buttons)
359 Util.UpdateMounts700(Buttons)
360 for j = 1, #Buttons do
361 if (Buttons[j]["Mode"] == "companion") then
362 -- Either fix the mapping, or clear the mount
363 local MountID = Util.GetMountIDFromName(Buttons[j]["CompanionName"]);
364
365 Buttons[j]["Mode"] = nil;
366 Buttons[j]["CompanionId"] = nil;
367 Buttons[j]["CompanionType"] = nil;
368 Buttons[j]["CompanionIndex"] = nil;
369 Buttons[j]["CompanionName"] = nil;
370 Buttons[j]["CompanionSpellName"] = nil;
371 if (Index) then
372 Buttons[j]["Mode"] = "mount";
373 Buttons[j]["MountID"] = MountID;
374 end
375 end
376 end
377end
378
379function Util.UpdateBattlePets602(Buttons)
380 for j = 1, #Buttons do
381 if (Buttons[j]["Mode"] == "battlepet") then
382 Buttons[j]["Mode"] = nil;
383 Buttons[j]["BattlePetId"] = nil;
384 end
385 end
386end
387
388function Util.UpdateMounts700(Buttons)
389 for j = 1, #Buttons do
390 if (Buttons[j]["Mode"] == "mount") then
391 local MountIndex = Buttons[j]["MountIndex"];
392 local MountName = Buttons[j]["MountName"];
393
394 Buttons[j]["MountID"] = nil;
395 Buttons[j]["MountSpellID"] = nil;
396 Buttons[j]["MountName"] = nil;
397 Buttons[j]["MountIndex"] = nil;
398 if (MountIndex == 0) then
399 Buttons[j]["MountID"] = Const.SUMMON_RANDOM_FAVORITE_MOUNT_ID;
400 else
401 local MountID = Util.GetMountIDFromName(MountName);
402 if (MountID) then
403 Buttons[j]["MountID"] = MountID;
404 else
405 Buttons[j]["Mode"] = nil;
406 end
407 end
408 end
409 end
410end
411
412function Util.RemoveCancelPossession700(Buttons)
413 for j = 1, #Buttons do
414 if (Buttons[j]["Mode"] == "customaction" and Buttons[j]["CustomActionName"] == "possesscancel") then
415 Buttons[j]["Mode"] = nil;
416 Buttons[j]["CustomActionName"] = nil;
417 end
418 end
419end
420
421--[[
422 Load the bars and buttons from the saved addon values
423--]]
424function Util.Load()
425
426 local CharRealm = UnitName("player");
427 CharRealm = CharRealm.."-"..GetRealmName();
428 ButtonForgeGlobalBackup[CharRealm] = ButtonForgeSave;
429
430 Util.ForceOffCastOnKeyDown = ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"];
431 if (not Util.ForceOffCastOnKeyDown) then
432 hooksecurefunc("SetCVar", MiscFrame.SetCVarCalled);
433 end
434 if (ButtonForgeSave.ConfigureMode) then
435 ConfigureLayer:Show();
436 end
437 if (ButtonForgeSave.AdvancedMode) then
438 UILib.ToggleAdvancedTools();
439 end
440 --if (Util.LBFMasterGroup and ButtonForgeSave["SkinID"]) then
441 -- Util.LBFMasterGroup:Skin(ButtonForgeSave.SkinID, ButtonForgeSave.Gloss, ButtonForgeSave.Backdrop, ButtonForgeSave.Colors);
442 --end
443 for i = 1, #ButtonForgeSave.Bars do
444 Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
445 end
446 UILib.ToggleRightClickSelfCast(ButtonForgeSave["RightClickSelfCast"] or false);
447 Util.Loaded = true;
448 Util.StartMacroCheckDelay();
449 Util.RefreshOnUpdateFunction();
450
451 SLASH_BUTTONFORGE1 = Util.GetLocaleString("SlashButtonForge1"); -- = "/buttonforge"; --these two identifiers probably shouldn't change, but if need be they can be?!
452 SLASH_BUTTONFORGE2 = Util.GetLocaleString("SlashButtonForge2"); -- = "/bufo";
453 collectgarbage("collect");
454 Util.CallbackEvent("INITIALISED");
455end
456
457-- Grabbed from the Lua wiki
458function Util.deepcopy(orig)
459 local orig_type = type(orig)
460 local copy
461 if orig_type == 'table' then
462 copy = {}
463 for orig_key, orig_value in next, orig, nil do
464 copy[Util.deepcopy(orig_key)] = Util.deepcopy(orig_value)
465 end
466 -- setmetatable(copy, Util.deepcopy(getmetatable(orig))) -- I don't need this specifically for ButtonForge
467 else -- number, string, boolean, etc
468 copy = orig
469 end
470 return copy
471end
472
473--[[
474 Load the bars and buttons from a profile
475--]]
476function Util.LoadProfile(ProfileName)
477 if (InCombatLockdown()) then
478 Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
479 return;
480 end
481 if (ButtonForgeGlobalProfiles[string.upper(ProfileName)] == nil) then
482 Util.SlashShowMessageByLine(Util.GetLocaleString("ProfileNotFound"));
483 return;
484 end
485
486 -- 1. Store the current configuration as the revert configuration for this character, in case the players wishes to go back
487 ButtonForgeSave.UndoProfileBars = Util.deepcopy(ButtonForgeSave.Bars);
488
489 -- 2. Deallocate the current UI
490 for i = #Util.ActiveBars, 1, -1 do
491 Util.DeallocateBar(Util.ActiveBars[i]);
492 end
493
494 -- 3. Apply the profile as the new bars/buttons for this character
495 ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeGlobalProfiles[string.upper(ProfileName)].Bars);
496
497 -- 4. Attach the Bars back to the UI
498 for i = 1, #ButtonForgeSave.Bars do
499 Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
500 end
501 Util.RefreshCompanions();
502 Util.RefreshMacros();
503 Util.RefreshEquipmentSets();
504 Util.RefreshSpells();
505 Util.RefreshGridStatus(true);
506 Util.RefreshBarStrata(true);
507 Util.RefreshBarGUIStatus();
508 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("LoadedProfile"), .5, 1, 0, 1);
509end
510
511--[[
512 Load the bars and buttons from a profile
513--]]
514function Util.LoadProfileTemplate(ProfileName)
515 if (InCombatLockdown()) then
516 Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
517 return;
518 end
519 if (ButtonForgeGlobalProfiles[string.upper(ProfileName)] == nil) then
520 Util.SlashShowMessageByLine(Util.GetLocaleString("ProfileNotFound"));
521 return;
522 end
523
524 -- 1. Store the current configuration as the revert configuration for this character, in case the players wishes to go back
525 ButtonForgeSave.UndoProfileBars = Util.deepcopy(ButtonForgeSave.Bars);
526
527 -- 2. Deallocate the current UI
528 for i = #Util.ActiveBars, 1, -1 do
529 Util.DeallocateBar(Util.ActiveBars[i]);
530 end
531
532 -- 3. Apply the profile as the new bars/buttons for this character
533 ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeGlobalProfiles[string.upper(ProfileName)].Bars);
534
535 -- 4. Attach the Bars back to the UI
536 for i = 1, #ButtonForgeSave.Bars do
537 Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
538 end
539
540 -- 5. Blank all the buttons - this is programatically the easiest way to handle it
541 for i = 1, #Util.ActiveButtons do
542 if (Util.ActiveButtons[i].Mode ~= "bonusaction") then
543 Util.ActiveButtons[i]:SetCommandFromTriplet();
544 end
545 end
546
547 Util.RefreshGridStatus(true);
548 Util.RefreshBarStrata(true);
549 Util.RefreshBarGUIStatus();
550 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("LoadedProfileTemplate"), .5, 1, 0, 1);
551
552end
553
554
555
556
557--[[
558 Save the bars and buttons to a profile, NB ProfileName is case insenstive for the purposes of saving loading deleting
559--]]
560function Util.SaveProfile(ProfileName)
561 local NewProfile = {};
562 NewProfile.Name = ProfileName; -- To capture the case sensitive version
563
564 -- Record this extra info in case it is useful later, probably wont be but could help keep profiles organised with a future update??
565 NewProfile.Icon = "INV_Misc_QuestionMark"; --"Interface/Icons/".. for when/if a gui gets setup it will be good to assign an icon
566 NewProfile.Date = date("%c");
567 NewProfile.Realm = GetRealmName();
568 NewProfile.Char = UnitName("player");
569 NewProfile.Class = UnitClass("player");
570
571 NewProfile.Bars = Util.deepcopy(ButtonForgeSave.Bars)
572 ButtonForgeGlobalProfiles[string.upper(ProfileName)] = NewProfile;
573
574 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SavedProfile"), .5, 1, 0, 1);
575end
576
577
578--[[
579 -- Lazy, I should've factored this with the save profile function
580
581--]]
582function Util.UndoProfile()
583 if (InCombatLockdown()) then
584 Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
585 return;
586 end
587
588 if (ButtonForgeSave.UndoProfileBars == nil) then
589 return;
590 end
591
592 for i = #Util.ActiveBars, 1, -1 do
593 Util.DeallocateBar(Util.ActiveBars[i]);
594 end
595
596 ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeSave.UndoProfileBars);
597
598
599 for i = 1, #ButtonForgeSave.Bars do
600 Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
601 end
602 Util.RefreshCompanions();
603 Util.RefreshMacros();
604 Util.RefreshEquipmentSets();
605 Util.RefreshSpells();
606 Util.RefreshGridStatus(true);
607 Util.RefreshBarStrata(true);
608 Util.RefreshBarGUIStatus();
609 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UndoneProfile"), .5, 1, 0, 1);
610end
611
612
613function Util.DeleteProfile(ProfileName)
614 ProfileName = string.upper(ProfileName);
615
616 if (ButtonForgeGlobalProfiles[ProfileName]) then
617 ButtonForgeGlobalProfiles[ProfileName] = nil;
618 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("DeletedProfile"), .5, 1, 0, 1);
619 end
620
621 -- Some day I may add comfirmations, at least perhaps for the /slash commands... perhaps also a session log?? But when?!
622end
623
624
625--[[
626 Save Button Facade settings if present
627--]]
628function Util:ButtonFacadeCallback(SkinID, Gloss, Backdrop, Group, Button, Colors)
629 -- If no group is specified, save the data as the root add-on skin.
630 -- This will allow the ButtonFacade GUI to display it correctly.
631 return; -- This may longer be necessary
632 --[[if not Group then
633 ButtonForgeSave["SkinID"] = SkinID;
634 ButtonForgeSave["Gloss"] = Gloss;
635 ButtonForgeSave["Backdrop"] = Backdrop;
636 ButtonForgeSave["Colors"] = Colors;
637 else
638 --not presently implemented by Button Forge --
639 ButtonForgeSave[Group]["SkinID"] = SkinID;
640 ButtonForgeSave[Group]["Gloss"] = Gloss;
641 ButtonForgeSave[Group]["Backdrop"] = Backdrop;
642 ButtonForgeSave[Group]["Colors"] = Colors;
643 end]]
644end
645
646
647--[[
648 To allow auto-alignment to also consider the blizzard multibars, this function will create wrappers to go on these bars
649 which will also be considered when dragging a Button Forge bar... Since this is possibly a compatibility point, it can be
650 hard disabled by a const param, it will also disable in the presence of Bartender which I know it doesn't function properly with
651--]]
652function Util.CreateBlizzardBarWrappers()
653 if (IsAddOnLoaded("Bartender4") or Const.DisableAutoAlignAgainstDefaultBars) then
654 return;
655 end
656
657 Util.BlizBarWrappers[1] = CreateFrame("FRAME", nil, UIParent);
658 Util.BlizBarWrappers[1]:SetPoint("TOPLEFT", MultiBarBottomLeftButton1, "TOPLEFT", -Const.I, Const.I + 1);
659 Util.BlizBarWrappers[1]:SetPoint("BOTTOMRIGHT", MultiBarBottomLeftButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
660
661 Util.BlizBarWrappers[2] = CreateFrame("FRAME", nil, UIParent);
662 Util.BlizBarWrappers[2]:SetPoint("TOPLEFT", MultiBarBottomRightButton1, "TOPLEFT", -Const.I, Const.I + 1);
663 Util.BlizBarWrappers[2]:SetPoint("BOTTOMRIGHT", MultiBarBottomRightButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
664
665 Util.BlizBarWrappers[3] = CreateFrame("FRAME", nil, UIParent);
666 Util.BlizBarWrappers[3]:SetPoint("TOPLEFT", MultiBarRightButton1, "TOPLEFT", -Const.I, Const.I + 1);
667 Util.BlizBarWrappers[3]:SetPoint("BOTTOMRIGHT", MultiBarRightButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
668
669 Util.BlizBarWrappers[4] = CreateFrame("FRAME", nil, UIParent);
670 Util.BlizBarWrappers[4]:SetPoint("TOPLEFT", MultiBarLeftButton1, "TOPLEFT", -Const.I, Const.I + 1);
671 Util.BlizBarWrappers[4]:SetPoint("BOTTOMRIGHT", MultiBarLeftButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
672
673
674end
675
676function Util.UpdateBlizzardEnabledBarsMap()
677 Util.BlizEnabledBars = {GetActionBarToggles()};
678end
679
680--[[
681 Button Allocation Functions
682--]]
683function Util.NewButton(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText)
684 if (InCombatLockdown()) then
685 return;
686 end
687 local NewButton;
688 if (#(Util.InactiveButtons) > 0) then
689 NewButton = table.remove(Util.InactiveButtons);
690 NewButton:Configure(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText);
691 else
692 NewButton = Button.New(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText);
693 Util.ButtonWidgetMap[NewButton.Widget] = NewButton;
694 end
695
696 table.insert(Util.ActiveButtons, NewButton);
697
698 Util.CallbackEvent("BUTTON_ALLOCATED", NewButton.Widget:GetName());
699 return NewButton;
700end
701
702function Util.DeallocateButton(Value)
703 if (InCombatLockdown()) then
704 return;
705 end
706 Value:Deallocate();
707 table.remove(Util.ActiveButtons, Util.FindInTable(Util.ActiveButtons, Value));
708 table.insert(Util.InactiveButtons, Value);
709 Util.CallbackEvent("BUTTON_DEALLOCATED", Value.Widget:GetName());
710end
711
712function Util.DetachButton(Value)
713 if (InCombatLockdown()) then
714 return;
715 end
716 Value:Detach();
717 table.remove(Util.ActiveButtons, Util.FindInTable(Util.ActiveButtons, Value));
718 table.insert(Util.InactiveButtons, Value);
719 Util.CallbackEvent("BUTTON_DEALLOCATED", Value.Widget:GetName());
720end
721
722
723
724--[[
725 Bar Allocation Functions
726--]]
727function Util.NewBarSave()
728 local Save = {};
729 Save["Left"] = 0;
730 Save["Top"] = 0;
731 Save["Scale"] = 1;
732 Save["Order"] = #Util.ActiveBars;
733 Save["Label"] = nil;
734 Save["Rows"] = Const.DefaultRows;
735 Save["Cols"] = Const.DefaultCols;
736 Save["VDriver"] = nil;
737 Save["HVehicle"] = true;
738 Save["HSpec1"] = false;
739 Save["HSpec2"] = false;
740 Save["HSpec3"] = false;
741 Save["HSpec4"] = false;
742 Save["HBonusBar"] = true;
743 Save["HPetBattle"] = true;
744 Save["GridAlwaysOn"] = true;
745 Save["ButtonsLocked"] = false;
746 Save["TooltipsOn"] = true;
747 Save["MacroText"] = true;
748 Save["KeyBindText"] = true;
749 Save["ButtonGap"] = 6;
750 Save["Enabled"] = true;
751 Save["BonusBar"] = false;
752 Save["GUI"] = true;
753 Save["Alpha"] = 1;
754 Save["Buttons"] = {};
755
756 return Save;
757end
758
759function Util.NewBar(Left, Top, BarSave)
760 if (InCombatLockdown()) then
761 return;
762 end
763 local NewBar;
764
765 if (not BarSave) then
766 BarSave = Util.NewBarSave();
767 BarSave["Left"] = Left;
768 BarSave["Top"] = Top;
769 table.insert(ButtonForgeSave.Bars, BarSave);
770 PlaySound(177, "Master");
771 end
772
773 if (#(Util.InactiveBars) > 0) then
774 NewBar = table.remove(Util.InactiveBars);
775 NewBar:Configure(BarSave);
776 else
777 NewBar = Bar.New(BarSave);
778 end
779
780 table.insert(Util.ActiveBars, NewBar);
781 if (NewBar.Cols * NewBar.Rows == 0) then
782 --Failed to allocate buttons, get rid of the bar
783 NewBar:Deallocate();
784 return nil;
785 else
786 Util.RefreshTab(NewBar.ControlFrame:GetLeft(), NewBar.ControlFrame:GetTop());
787 return NewBar;
788 end
789end
790
791function Util.NewBonusBar(Left, Top)
792 if (InCombatLockdown()) then
793 return;
794 end
795 local BarSave = Util.NewBarSave();
796 BarSave["BonusBar"] = true;
797 BarSave["Left"] = Left;
798 BarSave["Top"] = Top;
799 BarSave["Rows"] = 1;
800 BarSave["Cols"] = 13;
801 BarSave["HBonusBar"] = false;
802 BarSave["HVehicle"] = false;
803 BarSave["VDriver"] = "[overridebar][vehicleui] show; hide";
804 BarSave["ButtonsLocked"] = true;
805 BarSave["GridAlwaysOn"] = false;
806 table.insert(ButtonForgeSave.Bars, BarSave);
807 PlaySound(177, "Master");
808 return Util.NewBar(Left, Top, BarSave);
809end
810
811function Util.DeallocateBar(Value)
812 if (InCombatLockdown()) then
813 return;
814 end
815 Value:Deallocate(); --Note that deallocating a bar will call a function that changes the bars state (primarily it removes all buttons, and changes it's order... both of which change the save state data)
816 table.remove(Util.ActiveBars, Util.FindInTable(Util.ActiveBars, Value));
817 table.remove(ButtonForgeSave.Bars, Util.FindInTable(ButtonForgeSave.Bars, Value.BarSave));
818 table.insert(Util.InactiveBars, Value);
819 local Left, Top = Value.ControlFrame:GetLeft(), Value.ControlFrame:GetTop();
820 Util.RefreshTab(Left, Top);
821 PlaySound(6523, "Master");
822end
823
824function Util.DetachBar(Value)
825 if (InCombatLockdown()) then
826 return;
827 end
828 Value:Detach();
829 table.remove(Util.ActiveBars, Util.FindInTable(Util.ActiveBars, Value));
830 table.insert(Util.InactiveBars, Value);
831 local Left, Top = Value.ControlFrame:GetLeft(), Value.ControlFrame:GetTop();
832 Util.RefreshTab(Left, Top);
833end
834
835function Util.GetButtonFrameName(Label)
836
837 Label = Label or "";
838 local Name = Const.BarNaming.."Bar_"..(Label or "");
839 if (not _G[Name.."_ButtonFrame"] and Label ~= "") then
840 return Name.."_ButtonFrame";
841 end
842
843 while true do
844 if (not _G[Name..Const.BarSeq.."_ButtonFrame"]) then
845 return Name..Const.BarSeq.."_ButtonFrame";
846 end
847 Const.BarSeq = Const.BarSeq + 1;
848 end
849end
850
851
852--[[
853 Bar Management Functions
854--]]
855function Util.ReorderBar(Bar, NewPosition)
856 local CurrentPosition = Bar.BarSave["Order"];
857 local Order;
858 if (CurrentPosition > NewPosition) then
859 for i = 1, #Util.ActiveBars do
860 Order = Util.ActiveBars[i].BarSave["Order"];
861 if (Order < CurrentPosition and Order >= NewPosition) then
862 Util.ActiveBars[i]:SetOrder(Order + 1);
863 end
864 end
865 elseif (CurrentPosition < NewPosition) then
866 for i = 1, #Util.ActiveBars do
867 Order = Util.ActiveBars[i].BarSave["Order"];
868 if (Order > CurrentPosition and Order <= NewPosition) then
869 Util.ActiveBars[i]:SetOrder(Order - 1);
870 end
871 end
872 end
873 Bar:SetOrder(NewPosition);
874end
875
876function Util.DockCoords(Left, Top, ExcludeBar)
877 local CLeft, CTop, CDist, CBar = 0, 0, 100000000, nil; --This is an arbitrary number that will be big enough here
878 local Dist, X, Y;
879 local Bars = Util.ActiveBars;
880 for i = 1, #Bars do
881 X = Bars[i].ControlFrame:GetLeft();--BarSave["Left"];
882 Y = Bars[i].ControlFrame:GetTop();--BarSave["Top"];
883 Dist = ((Left - X) ^ 2)+ ((Top - Y) ^ 2);
884 if (Dist < CDist and Bars[i] ~= ExcludeBar) then
885 CLeft = X;
886 CTop = Y;
887 CDist = Dist;
888 CBar = Bars[i];
889 end
890 end
891 return CLeft, CTop, CDist, CBar;
892end
893
894
895
896
897function Util.FindClosestPoint(Coord, Points, Offsets, ExcludeBar)
898 local MatchedBar, MatchedPoint, Shift, MatchedCoord = nil, 0, 0, 0;
899 local Calc, CalcCoord, MinCalc = 0, 0, 10000000;
900 local Bars = Util.ActiveBars;
901 for i = 1, #Bars do
902 if (Bars[i] ~= ExcludeBar) then
903 for j = 1, #Points do
904 CalcCoord = Bars[i].ControlFrame[Points[j]](Bars[i].ControlFrame) + Offsets[j]; --basically translates down to things like Bars[i]:GetLeft() + Offset[j]; if Points[j] is "GetLeft"
905 Calc = CalcCoord - Coord;
906 Calc = Calc * Calc;
907 if (Calc < MinCalc - 0.1) then
908 MinCalc = Calc;
909 MatchedCoord = CalcCoord;
910 Shift = CalcCoord - Coord;
911 MatchedBar = Bars[i].ControlFrame;
912 MatchedPoint = j;
913 end
914 end
915 end
916 end
917
918 Bars = Util.BlizBarWrappers;
919 local EnabledBars = Util.BlizEnabledBars;
920 for i = 1, #Bars do
921 if (EnabledBars[i]) then
922 for j = 1, #Points do
923 CalcCoord = Bars[i][Points[j]](Bars[i]);
924 if (not CalcCoord) then
925 Util.BlizEnabledBars[i] = false;
926 break;
927 else
928 CalcCoord = CalcCoord + Offsets[j]; --basically translates down to things like Bars[i]:GetLeft() + Offset[j]; if Points[j] is "GetLeft"
929 Calc = CalcCoord - Coord;
930 Calc = Calc * Calc;
931 if (Calc < MinCalc - 0.1) then
932 MinCalc = Calc;
933 MatchedCoord = CalcCoord;
934 Shift = CalcCoord - Coord;
935 MatchedBar = Bars[i];
936 MatchedPoint = j;
937 end
938 end
939 end
940 end
941 end
942
943 return MatchedBar, MatchedPoint, MinCalc, Shift, MatchedCoord;
944end
945
946--[[ While the Configure overlay is shown make sure that all bars are visible (unless in combat), this function also cleansup when the overlay is hidden again --]]
947function Util.VDriverOverride()
948 if (InCombatLockdown()) then
949 return;
950 end
951 local Bars = Util.ActiveBars;
952 if (ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown()) then
953 for i = 1, #Bars do
954 Bars[i]:SetTempShowVD();
955 end
956 else
957 for i = 1, #Bars do
958 Bars[i]:ClearTempShowVD();
959 end
960 end
961end
962
963
964--[[ Since the Spellbook has an annoying tendancy to cover bars this function will raise (or relower) the buttons to so they can be clicked
965 Note: It will do this for everything but items - since that could quickly get annoying when moving items around (there isn't really a perfect solution, so best to not go overboard)
966 Also it doesn't do a combat lockdown check, it is expected that this has been done up the chain (the bars will auto drop to the low strata if combat begins!)
967--]]
968function Util.RefreshBarStrata(ForceUpdate)
969 local LowStrata = Util.InCombat or DestroyBarOverlay:IsShown() or (GetCursorInfo() == "item" and not IsShiftKeyDown()) or not Util.CursorAction;
970 if (LowStrata ~= Util.LowStrata or ForceUpdate) then
971 Util.LowStrata = LowStrata;
972 local Bars = Util.ActiveBars;
973 if (LowStrata) then
974 for i = 1, #Bars do
975 Bars[i].ButtonFrame:SetFrameStrata("LOW");
976 Bars[i]:SetOrder(); --without a param this will cause a refresh (just in case moving the strata causes the level to change)
977 end
978 else
979 for i = 1, #Bars do
980 Bars[i].ButtonFrame:SetFrameStrata("DIALOG");
981 Bars[i]:SetOrder(); --without a param this will cause a refresh (just in case moving the strata causes the level to change)
982 end
983 end
984 end
985end
986
987
988function Util.RefreshGridStatus(ForceUpdate)
989 local Hide = Util.InCombat or not (Util.CursorAction or ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown());
990 if (Hide ~= Util.GridHidden or ForceUpdate) then
991 Util.GridHidden = Hide;
992 local Bars = Util.ActiveBars;
993 if (Hide) then
994 for i = 1, #Bars do
995 if (not Bars[i].BarSave["GridAlwaysOn"]) then
996 Bars[i]:GridHide();
997 end
998 end
999 else
1000 for i = 1, #Bars do
1001 if (not Bars[i].BarSave["GridAlwaysOn"]) then
1002 Bars[i]:GridShow();
1003 end
1004 end
1005 end
1006 end
1007end
1008
1009function Util.RefreshBarGUIStatus()
1010 local BarGUIForceOn = (not Util.InCombat) and (ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown() or (IsShiftKeyDown() and Util.CursorAction));
1011 local Bars = Util.ActiveBars;
1012 if (BarGUIForceOn) then
1013 for i = 1, #Bars do
1014
1015 Bars[i]:GUIOn();
1016 end
1017 else
1018 for i = 1, #Bars do
1019 if (not Bars[i].BarSave["GUI"]) then
1020 Bars[i]:GUIOff();
1021 end
1022 end
1023 end
1024end
1025
1026
1027function Util.SetControlFrameAlphas(Alpha)
1028 local Bars = Util.ActiveBars;
1029
1030 for i = 1, #Bars do
1031 Bars[i].ControlFrame:SetAlpha(Alpha);
1032 end
1033
1034end
1035
1036function Util.RefreshTab(Left, Top)
1037
1038 local Count = 0;
1039 local Bar;
1040 local StackedBar;
1041 local Label;
1042 for i = 1, #Util.ActiveBars do
1043 Bar = Util.ActiveBars[i];
1044
1045 if (math.abs(Bar.ControlFrame:GetLeft() - Left) < 0.01 and math.abs(Bar.ControlFrame:GetTop() - Top) < 0.01) then
1046 Count = Count + 1;
1047 StackedBar = Bar;
1048 end
1049 end
1050
1051 if (Count == 0) then
1052 return;
1053 end
1054 if (Count == 1) then
1055 --Set it's label back in and dealloc the tabframe
1056 StackedBar.Tabbed = false;
1057 Label = StackedBar.LabelFrame;
1058 Label:ClearAllPoints();
1059 Label:SetPoint("TOPLEFT", StackedBar.TopIconsFrame, "TOPLEFT", Const.BarInset, -Const.BarEdge); --Const.MiniIconSize + Const.MiniIconGap +Const.BarEdge, -Const.BarEdge);
1060 Label:SetBackdropColor(0, 0, 0, 1);
1061 Label:SetAlpha(1);
1062 Label:EnableMouse(false);
1063 Label:SetScript("OnMouseDown", nil);
1064 Label:SetScript("OnEnter", nil);
1065 Label:SetScript("OnLeave", nil);
1066 Util.DeallocateTab(Left, Top);
1067 StackedBar:ReflowUI();
1068 return;
1069 end
1070
1071 local Offset = 0;
1072 local HighestBar;
1073 local TabFrame = Util.GetTabFrame(Left, Top);
1074 for i = 1, #Util.ActiveBars do
1075 Bar = Util.ActiveBars[i];
1076 if (math.abs(Bar.ControlFrame:GetLeft() - Left) < 0.01 and math.abs(Bar.ControlFrame:GetTop() - Top) < 0.01) then
1077 if (not HighestBar) then
1078 --anchor tabframe
1079 HighestBar = Bar;
1080 TabFrame:ClearAllPoints();
1081 TabFrame:SetPoint("TOPLEFT", Bar.ControlFrame, "TOPLEFT", 0, Const.MiniIconSize);
1082 elseif (HighestBar.BarSave["Order"] < Bar.BarSave["Order"]) then
1083 HighestBar = Bar;
1084 end
1085 Bar.Tabbed = true;
1086 Label = Bar.LabelFrame;
1087 Label:ClearAllPoints();
1088 Label:SetPoint("TOPLEFT", TabFrame, "TOPLEFT", Offset, 0);
1089 Label:SetBackdropColor(0, 0, 0, 1);
1090 Label:SetAlpha(.5);
1091 Label:EnableMouse(true);
1092 Label:SetScript("OnMouseDown", Bar.SendToFront);
1093 Label:SetScript("OnEnter", Bar.LabelOnEnter);
1094 Label:SetScript("OnLeave", Bar.LabelOnLeave);
1095 if (Label:GetWidth() > 4.5) then
1096 Offset = Offset + Label:GetWidth();
1097 end
1098 Bar:ReflowUI();
1099 end
1100 end
1101 TabFrame:SetSize(Offset, Const.MiniIconSize);
1102 Label = HighestBar.LabelFrame;
1103 Label:SetAlpha(1);
1104 --Label:SetScript("OnMouseDown", nil);
1105 Label:SetScript("OnEnter", nil);
1106 Label:SetScript("OnLeave", nil);
1107end
1108
1109function Util.DeallocateTab(Left, Top)
1110 if (Util.ActiveTabs[Left.." "..Top]) then
1111 table.insert(Util.InactiveTabs, Util.ActiveTabs[Left.." "..Top]);
1112 Util.ActiveTabs[Left.." "..Top] = nil;
1113 end
1114end
1115
1116function Util.GetTabFrame(Left, Top)
1117 if (not Util.ActiveTabs[Left.." "..Top]) then
1118 if (#Util.InactiveTabs > 0) then
1119 Util.ActiveTabs[Left.." "..Top] = table.remove(Util.InactiveTabs);
1120 else
1121 Util.ActiveTabs[Left.." "..Top] = CreateFrame("FRAME", nil, ConfigureLayer);
1122 Util.ActiveTabs[Left.." "..Top]:SetSize(1, 1);
1123 Util.ActiveTabs[Left.." "..Top]:SetClampedToScreen(true);
1124 end
1125 end
1126 return Util.ActiveTabs[Left.." "..Top];
1127end
1128
1129function Util.BarHasButton(Bar, Command, Data, Subvalue)
1130 local BCommand, BData, BSubvalue
1131 for i = 1, #Bar.Buttons do
1132 BCommand, BData, BSubvalue = Bar.Buttons[i]:GetCursor();
1133 if (Command == BCommand and Data == BData and Subvalue == BSubvalue) then
1134 return true;
1135 end
1136 end
1137 return false;
1138end
1139
1140
1141
1142--[[
1143 Helper functions
1144--]]
1145function Util.FindInTable(Table, Value, Start)
1146 for i = Start or 1, #Table do
1147 if (Table[i] == Value) then
1148 return i;
1149 end
1150 end
1151 return nil;
1152end
1153
1154function Util.GetLocaleString(Value)
1155 return Locale[Value];
1156end
1157
1158function Util.GetLocaleEnabledDisabled(Value)
1159 if (Value) then
1160 return Locale["Enabled"];
1161 else
1162 return Locale["Disabled"];
1163 end
1164end
1165
1166function Util.CastBool(Value)
1167 return Locale.BoolTable[strlower(Value or '')];
1168end
1169
1170function Util.ProcessSlashCommandParams(Command, Params)
1171 Params = Params or "";
1172 if (Const.SlashCommands[Command].params == "bool") then
1173 local Bool = Util.CastBool(Params, "^%s*(%w*)%s*$");
1174 if (Bool == nil) then
1175 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..Command.." "..Params, .5, 1, 0, 1);
1176 return;
1177 end
1178 return {Bool};
1179 else
1180 local Values = {string.match(Params, Const.SlashCommands[Command].params)};
1181 if (Values[1] == nil) then
1182 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..Command.." "..Params, .5, 1, 0, 1);
1183 return;
1184 end
1185 return Values;
1186 end
1187
1188end
1189
1190--[[Unused function for allowing a more... ]]--
1191local SlashRemainingMessage = '';
1192function Util.SlashShowRemainingMessage()
1193 local Display, Remainder = string.match(SlashRemainingMessage, "^("..strrep(".-\n", Const.SlashNumLines-1)..".-)\n(.-)$");
1194 if (Display) then
1195 SlashRemainingMessage = Remainder;
1196 else
1197 Display = SlashRemainingMessage;
1198 SlashRemainingMessage = '';
1199 end
1200 DEFAULT_CHAT_FRAME:AddMessage(' '..Display, .5, 1, 0, 1);
1201end
1202
1203
1204function Util.SlashShowMessageByLine(Message)
1205 for Line in string.gmatch(Message, '([^\n]*)') do
1206 DEFAULT_CHAT_FRAME:AddMessage(Line, .5, 1, 0, 1);
1207 end
1208end
1209
1210function SlashCmdList.BUTTONFORGE(msg, editbox)
1211 local PreparedCommands = {};
1212 local Command, Params;
1213 local Count = 0;
1214 Params = '';
1215 for Token, Space in string.gmatch(msg, '([^%s]+)([%s]*)') do
1216 if (Const.SlashCommands[strlower(Token)]) then
1217 if (Command) then
1218 Count = Count + 1;
1219 --PreparedCommands["Count"] = Count;
1220 PreparedCommands[Command] = Util.ProcessSlashCommandParams(Command, Params);
1221
1222 if (PreparedCommands[Command] == nil) then
1223 return;
1224 end
1225 end
1226 Command = strlower(Token);
1227 Params = '';
1228 elseif (string.match(Token, '^-') == '-') then
1229 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashCommandNotRecognised")..Token, .5, 1, 0, 1);
1230 return;
1231 else
1232 Params = Params..Token..Space;
1233 end
1234 end
1235 if (Command) then
1236 Count = Count + 1;
1237 --PreparedCommands["Count"] = Count;
1238 PreparedCommands[Command] = Util.ProcessSlashCommandParams(Command, Params);
1239 if (PreparedCommands[Command] == nil) then
1240 return;
1241 end
1242
1243 local Bars = Util.ActiveBars;
1244 local Commands = PreparedCommands;
1245
1246 -- Check the constraint rules
1247 -- 1. Only 1 group is allowed
1248 -- 2. A rules required's must be present
1249 -- 3. A rules exclusions must not be present
1250 local Group;
1251 local FirstCommand;
1252 for k, v in pairs(Commands) do
1253 FirstCommand = FirstCommand or k;
1254 if (Group ~= nil and Group ~= Const.SlashCommands[k].group) then
1255 -- must be the same group
1256 DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandIncompatible"), "<COMMANDA>", FirstCommand), "<COMMANDB>", k), .5, 1, 0, 1);
1257 return;
1258 end
1259 Group = Const.SlashCommands[k].group;
1260
1261 local Requires = Const.SlashCommands[k].requires;
1262 if (Requires) then
1263 for k1, v1 in pairs(Requires) do
1264 if (Commands[v1] == nil) then
1265 -- Missing a required command
1266 DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandRequired"), "<COMMANDA>", k), "<COMMANDB>", v1), .5, 1, 0, 1);
1267 return;
1268 end
1269 end
1270 end
1271
1272 local Incompat = Const.SlashCommands[k].incompat;
1273 if (Incompat) then
1274 for k1, v1 in pairs(Incompat) do
1275 if (Commands[v1]) then
1276 -- Incompatible command present
1277 DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandIncompatible"), "<COMMANDA>", k), "<COMMANDB>", v1), .5, 1, 0, 1);
1278 return;
1279 end
1280 if (v1 == "ALL" and Count > 1) then
1281 -- Only 1 command would be allowed
1282 DEFAULT_CHAT_FRAME:AddMessage(string.gsub(Util.GetLocaleString("SlashCommandAlone"), "<COMMANDA>", k), .5, 1, 0, 1);
1283 return;
1284 end
1285 end
1286 end
1287
1288
1289 local Validate = Const.SlashCommands[k].validate;
1290 if (Validate) then
1291 if (not Validate(unpack(v))) then
1292 -- Validate function failed
1293 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..k.." "..table.concat(v, " "), .5, 1, 0, 1);
1294 return;
1295 end
1296 end
1297 end
1298
1299 if (Group == "bar") then
1300 if (Commands["-createbar"]) then
1301 Util.ApplySlashCommands(Commands);
1302 else
1303 local BarName;
1304 if (Commands["-bar"]) then
1305 BarName = Commands["-bar"][1];
1306 elseif (Commands["-destroybar"]) then
1307 BarName = Commands["-destroybar"][1];
1308 end
1309 for i = 1, #Bars do
1310 if ((not BarName) or strlower(BarName) == strlower(Bars[i].BarSave["Label"])) then
1311 Util.ApplySlashCommands(Commands, Bars[i]);
1312 end
1313 end
1314 end
1315 else
1316 Util.ApplySlashCommands(Commands);
1317 end
1318
1319 else
1320 Util.SlashShowMessageByLine(Util.GetLocaleString("SlashHelpFormatted")); --]]
1321 end
1322
1323end
1324
1325
1326function Util.ApplySlashCommands(Commands, Bar)
1327 if (Commands["-createbar"]) then
1328 Bar = Util.NewBar(0, 0);
1329 if (Bar == nil) then
1330 DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashCreateBarFailed"), .5, 1, 0, 1);
1331 return
1332 end
1333 Commands["-rename"] = Commands["-createbar"]; --this could arguably work by having an empty param to createbar but I think it will feel more natural to require a name with this command
1334 end
1335
1336 if (Commands["-destroybar"]) then
1337 Util.DeallocateBar(Bar);
1338 end
1339
1340 if (Commands["-macrotext"]) then
1341 Bar:SetMacroText(Commands["-macrotext"][1]);
1342 end
1343
1344 if (Commands["-keybindtext"]) then
1345 Bar:SetKeyBindText(Commands["-keybindtext"][1]);
1346 end
1347
1348 if (Commands["-tooltips"]) then
1349 Bar:SetTooltips(Commands["-tooltips"][1]);
1350 end
1351
1352 if (Commands["-emptybuttons"]) then
1353 Bar:SetGridAlwaysOn(Commands["-emptybuttons"][1]);
1354 end
1355
1356 if (Commands["-lockbuttons"]) then
1357 Bar:SetButtonsLocked(Commands["-lockbuttons"][1]);
1358 end
1359
1360 if (Commands["-scale"]) then
1361 Bar:SetScale(tonumber(Commands["-scale"][1]));
1362 end
1363
1364 if (Commands["-rows"]) then
1365 Bar:SetNumButtons(Bar.BarSave["Cols"], tonumber(Commands["-rows"][1]));
1366 end
1367
1368 if (Commands["-cols"]) then
1369 Bar:SetNumButtons(tonumber(Commands["-cols"][1]), Bar.BarSave["Rows"]);
1370 end
1371
1372 if (Commands["-coords"]) then
1373 Bar:SetPosition(tonumber(Commands["-coords"][1]), tonumber(Commands["-coords"][2]));
1374 end
1375
1376 if (Commands["-rename"]) then
1377 Bar:SetLabel(Commands["-rename"][1]);
1378 end
1379
1380 if (Commands["-hidespec1"]) then
1381 Bar:SetHSpec1(Commands["-hidespec1"][1]);
1382 end
1383
1384 if (Commands["-hidespec2"]) then
1385 Bar:SetHSpec2(Commands["-hidespec2"][1]);
1386 end
1387
1388 if (Commands["-hidespec3"]) then
1389 Bar:SetHSpec3(Commands["-hidespec3"][1]);
1390 end
1391
1392 if (Commands["-hidespec4"]) then
1393 Bar:SetHSpec4(Commands["-hidespec4"][1]);
1394 end
1395
1396 if (Commands["-hidevehicle"]) then
1397 Bar:SetHVehicle(Commands["-hidevehicle"][1]);
1398 end
1399
1400 if (Commands["-hideoverridebar"]) then
1401 Bar:SetHBonusBar(Commands["-hideoverridebar"][1]);
1402 end
1403
1404 if (Commands["-hidepetbattle"]) then
1405 Bar:SetHPetBattle(Commands["-hidepetbattle"][1]);
1406 end
1407
1408 if (Commands["-vismacro"]) then
1409 Bar:SetVD(Commands["-vismacro"][1]);
1410 end
1411
1412 if (Commands["-gui"]) then
1413 Bar:SetGUI(Commands["-gui"][1]);
1414 end
1415
1416 if (Commands["-alpha"]) then
1417 Bar:SetAlpha(tonumber(Commands["-alpha"][1]));
1418 end
1419
1420 if (Commands["-enabled"]) then
1421 Bar:SetEnabled(Commands["-enabled"][1]);
1422 end
1423
1424 if (Commands["-gap"]) then
1425 Bar:SetButtonGap(tonumber(Commands["-gap"][1]));
1426 end
1427
1428 if (Commands["-info"]) then
1429 --print out the bar info's
1430 local String = Util.GetLocaleString("InfoLabel")..": "..(Bar:GetLabel() or "").."\n"..
1431 Util.GetLocaleString("InfoRowsCols")..": "..select(3, Bar:GetNumButtons()).."\n"..
1432 Util.GetLocaleString("InfoScale")..": "..Bar:GetScale().."\n"..
1433 Util.GetLocaleString("InfoGap")..": "..Bar:GetButtonGap().."\n"..
1434 Util.GetLocaleString("InfoCoords")..": "..select(3, Bar:GetPosition()).."\n"..
1435 Util.GetLocaleString("InfoTooltips")..": "..select(2, Bar:GetTooltips()).."\n"..
1436 Util.GetLocaleString("InfoEmptyGrid")..": "..select(2, Bar:GetGridAlwaysOn()).."\n"..
1437 Util.GetLocaleString("InfoLock")..": "..select(2, Bar:GetButtonsLocked()).."\n"..
1438 Util.GetLocaleString("InfoMacroText")..": "..select(2, Bar:GetMacroText()).."\n"..
1439 Util.GetLocaleString("InfoKeybindText")..": "..select(2, Bar:GetKeyBindText()).."\n"..
1440 Util.GetLocaleString("InfoHSpec1")..": "..select(2, Bar:GetHSpec1()).."\n"..
1441 Util.GetLocaleString("InfoHSpec2")..": "..select(2, Bar:GetHSpec2()).."\n"..
1442 Util.GetLocaleString("InfoHSpec3")..": "..select(2, Bar:GetHSpec3()).."\n"..
1443 Util.GetLocaleString("InfoHSpec4")..": "..select(2, Bar:GetHSpec4()).."\n"..
1444 Util.GetLocaleString("InfoHVehicle")..": "..select(2, Bar:GetHVehicle()).."\n"..
1445 Util.GetLocaleString("InfoHBonusBar5")..": "..select(2, Bar:GetHBonusBar()).."\n"..
1446 Util.GetLocaleString("InfoHPetBattle")..": "..select(2, Bar:GetHPetBattle()).."\n"..
1447 Util.GetLocaleString("InfoVisibilityMacro")..": "..(Bar:GetVD() or "").."\n"..
1448 Util.GetLocaleString("InfoGUI")..": "..select(2, Bar:GetGUI()).."\n"..
1449 Util.GetLocaleString("InfoAlpha")..": "..Bar:GetAlpha().."\n"..
1450 Util.GetLocaleString("InfoEnabled")..": "..select(2, Bar:GetEnabled());
1451
1452 Util.SlashShowMessageByLine(String);
1453
1454 end
1455
1456 if (Commands["-technicalinfo"]) then
1457 --print out technical info for the bar
1458 local String = Util.GetLocaleString("InfoButtonFrameName")..": "..Bar.ButtonFrame:GetName();
1459 Util.SlashShowMessageByLine(String);
1460 end
1461
1462
1463 if (Commands["-saveprofile"]) then
1464 Util.SaveProfile(Commands["-saveprofile"][1]);
1465 end
1466
1467 if (Commands["-loadprofile"]) then
1468 Util.LoadProfile(Commands["-loadprofile"][1]);
1469 end
1470
1471 if (Commands["-loadprofiletemplate"]) then
1472 Util.LoadProfileTemplate(Commands["-loadprofiletemplate"][1]);
1473 end
1474
1475 if (Commands["-undoprofile"]) then
1476 Util.UndoProfile();
1477 end
1478
1479 if (Commands["-listprofiles"]) then
1480 local String = Util.GetLocaleString("BFProfiles").."\n---------------------\n";
1481 for k,v in pairs(ButtonForgeGlobalProfiles) do
1482 String = String..v.Name.."\n";
1483 end
1484 String = String.."---------------------\n";
1485 Util.SlashShowMessageByLine(String);
1486 end
1487
1488 if (Commands["-deleteprofile"]) then
1489 Util.DeleteProfile(Commands["-deleteprofile"][1]);
1490 end
1491
1492 if (Commands["-macrocheckdelay"]) then
1493 ButtonForgeGlobalSettings["MacroCheckDelay"] = tonumber(Commands["-macrocheckdelay"][1]);
1494 end
1495
1496 if (Commands["-removemissingmacros"]) then
1497 ButtonForgeGlobalSettings["RemoveMissingMacros"] = Commands["-removemissingmacros"][1];
1498 end
1499
1500 if (Commands["-forceoffcastonkeydown"]) then
1501 ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"] = Commands["-forceoffcastonkeydown"][1];
1502 end
1503
1504 if (Commands["-usecollectionsfavoritemountbutton"]) then
1505 ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"] = Commands["-usecollectionsfavoritemountbutton"][1];
1506 end
1507
1508
1509 if (Commands["-globalsettings"]) then
1510 --print out what the global settings for Button Forge are
1511 local String = Util.GetLocaleString("InfoMacroCheckDelay")..": "..ButtonForgeGlobalSettings["MacroCheckDelay"].."\n"..
1512 Util.GetLocaleString("InfoRemoveMissingMacros")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["RemoveMissingMacros"]).."\n"..
1513 Util.GetLocaleString("InfoForceOffCastOnKeyDown")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"]).."\n"..
1514 Util.GetLocaleString("InfoUseCollectionsFavoriteMountButton")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"]);
1515
1516 Util.SlashShowMessageByLine(String);
1517 end
1518
1519end
1520
1521--[[ Store cursor type info for later use --]]
1522function Util.StoreCursor(Command, Data, Subvalue, Subsubvalue)
1523 Util.Command = Command;
1524 Util.Data = Data;
1525 Util.Subvalue = Subvalue;
1526 Util.Subsubvalue = Subsubvalue
1527end
1528
1529function Util.GetStoredCursor()
1530 return Util.Command, Util.Data, Util.Subvalue, Util.Subsubvalue;
1531end
1532
1533--[[ Set the cursor based on the triplet passed in --]]
1534function Util.SetCursor(Command, Data, Subvalue, Subsubvalue)
1535 ClearCursor();
1536 UILib.StopDraggingIcon();
1537 SpellFlyout:Hide();
1538 if (Command == "spell") then
1539 --PickupSpellBookItem(Data, Subvalue);
1540 PickupSpell(Subsubvalue);
1541 elseif (Command == "item") then
1542 PickupItem(Data);
1543 elseif (Command == "macro") then
1544 PickupMacro(Data);
1545 elseif (Command == "mount") then
1546 --if (Subvalue == nil) then
1547 -- Data = Util.GetMountIndexFromUselessIndex(Data);
1548 --end
1549 C_MountJournal.Pickup(Util.GetMountIndexFromMountID(Data));
1550 elseif (Command == "equipmentset") then
1551 local SetCount = C_EquipmentSet.GetNumEquipmentSets();
1552 for i=0,SetCount-1 do
1553 name, _, setIndex = C_EquipmentSet.GetEquipmentSetInfo(i);
1554 if (name == Data) then
1555 C_EquipmentSet.PickupEquipmentSet(setIndex);
1556 break;
1557 end
1558 end;
1559elseif (Command == "bonusaction") then
1560 local page = 12; --The page for vehicleactionbar
1561 if (HasOverrideActionBar()) then
1562 page = 14;
1563 end
1564 local Texture = GetActionTexture(Data + ((page - 1) * 12));
1565 if (Texture and (HasOverrideActionBar() or HasVehicleActionBar())) then
1566 UILib.StartDraggingIcon(Texture, 23, 23, "bonusaction", Data);
1567 else
1568 UILib.StartDraggingIcon(Const.ImagesDir.."Bonus"..Data, 23, 23, "bonusaction", Data);
1569 end
1570 elseif (Command == "flyout") then
1571 local ind, booktype = Util.LookupSpellIndex("FLYOUT"..Data);
1572 if (ind) then
1573 PickupSpellBookItem(ind, booktype);
1574 end
1575 elseif (Command == "customaction") then
1576 CustomAction.SetCursor(Data);
1577 elseif (Command == "battlepet") then
1578 C_PetJournal.PickupPet(Data);
1579 end
1580end
1581
1582--[[ These two functions will take care of non secure gui updates when the player enters or exits combat ]]--
1583function Util.PreCombatStateUpdate()
1584 Util.InCombat = true;
1585 Util.RefreshGridStatus();
1586 Util.RefreshBarStrata(); --Im surprised that these refreshes dont lead to taint, I must be forgetting something??!
1587 UILib.ToggleCreateBarMode(true);
1588 UILib.ToggleDestroyBarMode(true);
1589 Util.RefreshBarGUIStatus();
1590end
1591
1592function Util.PostCombatStateUpdate()
1593 Util.InCombat = false;
1594 Util.VDriverOverride();
1595 Util.RefreshGridStatus();
1596 Util.RefreshBarStrata();
1597 Util.RefreshBarGUIStatus();
1598
1599 if (Util.DelayedRefreshMacros) then
1600 Util.RefreshMacros();
1601 Util.DelayedRefreshMacros = nil;
1602 end
1603 if (Util.DelayedUpdateButtonClickHandling) then
1604 Util.UpdateButtonClickHandling();
1605 Util.DelayedUpdateButtonClickHandling = nil;
1606 end
1607 if (Util.DelayedPromoteSpells) then
1608 Util.PromoteSpells();
1609 Util.DelayedPromoteSpells = nil;
1610 end
1611 if (Util.DelayedRefreshCompanions) then
1612 Util.RefreshCompanions();
1613 Util.DelayedRefreshCompanions = nil;
1614 end
1615 if (Util.DelayedRefreshEquipmentSets) then
1616 Util.RefreshEquipmentSets();
1617 Util.DelayedRefreshEquipmentSets = nil;
1618 end
1619end
1620
1621--[[ Add and remove buttons to a list that gets updated for the range timer --]]
1622function Util.AddToRangeTimer(Value)
1623 if (#Util.RangeTimerButtons == 0) then
1624 --BF
1625 end
1626 Util.RangeTimerButtons[Value] = true;
1627end
1628
1629function Util.RemoveFromRangeTimer(Value)
1630 Util.RangeTimerButtons[Value] = nil;
1631end
1632
1633--[[ Add and remove buttons to a list that gets updated for flashing --]]
1634function Util.AddToFlash(Value)
1635 if (#Util.FlashButtons == 0) then
1636 --BF
1637 end
1638 Util.FlashButtons[Value] = true;
1639end
1640
1641function Util.RemoveFromFlash(Value)
1642 Util.FlashButtons[Value] = nil;
1643end
1644
1645function Util.RightClickSelfCast(Value)
1646 if (InCombatLockdown()) then
1647 return;
1648 end
1649
1650 if (Value) then
1651 for i = 1, #Util.ActiveButtons do
1652 Util.ActiveButtons[i].Widget:SetAttribute("unit2", "player");
1653 end
1654 else
1655 for i = 1, #Util.ActiveButtons do
1656 Util.ActiveButtons[i].Widget:SetAttribute("unit2", nil);
1657 end
1658 end
1659
1660 ButtonForgeSave["RightClickSelfCast"] = Value;
1661end
1662
1663
1664
1665
1666
1667--[[---------------------------------------
1668 Spell Functions
1669-------------------------------------------]]
1670function Util.GetFullSpellName(Name, Rank)
1671--BFA fix: GetSpellInfo now returns a nil for the rank. That's passed in here
1672--So we check to make sure ranx exists or only pass back the name itself.
1673 if (Rank) then
1674 Rank = "("..Rank..")";
1675 else
1676 Rank = "";
1677 end
1678 if (Name) then
1679 return Name..Rank;
1680 end
1681end
1682
1683function Util.GetSpellId(NameRank)
1684 local Link = GetSpellLink(NameRank);
1685 return select(3, strfind(Link, "spell:(%d+)|"));
1686end
1687
1688function Util.IsSpellIdTalent(SpellId)
1689 local TalentInfoFuncs = {GetTalentInfo, GetPvpTalentInfo};
1690
1691 -- Scan both normal and PvP talents
1692 -- Note rather than assume number of talents, we just scan till the rows and columns till we hit a nil
1693 for _, TalentInfoFunc in ipairs(TalentInfoFuncs) do
1694 local r = 1;
1695 local c = 1;
1696 local TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1697 while (TalentSpellID) do
1698 while (TalentSpellID) do
1699 if (TalentSpellID == SpellId) then
1700 return true;
1701 end
1702 c = c + 1;
1703 TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1704 end
1705 r = r + 1;
1706 c = 1;
1707 TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1708 end
1709 end
1710 return false;
1711end
1712
1713function Util.CacheSpellIndexes()
1714 local i = 1;
1715 local NewSI = {};
1716 local NewSM = {-10000000, 10000000};
1717 local ManaPoints = {};
1718 local ItemType, Id;
1719 Util.NewSpellIndex = {};
1720
1721 local total = 0;
1722 for j = 1, GetNumSpellTabs() do
1723 total = total + select(4, GetSpellTabInfo(j));
1724 end
1725
1726 for i = total, 1, -1 do
1727 ItemType, Id = GetSpellBookItemInfo(i, BOOKTYPE_SPELL);
1728 --local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(i, BOOKTYPE_SPELL);
1729 local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(Id);
1730 local NameRank = Util.GetFullSpellName(Name, Rank);
1731 if (ItemType == "SPELL") then
1732 NewSI[NameRank] = i;
1733
1734 elseif (ItemType == "FLYOUT") then
1735 NewSI["FLYOUT"..Id] = i;
1736
1737 elseif (ItemType == nil) then
1738 break;
1739
1740 end
1741
1742-- if (not Util.SpellIndex[NameRank]) then
1743 -- Util.NewSpellIndex[NameRank] = i;
1744 --end
1745 if (PowerType == 0 and not ManaPoints[Power]) then
1746 ManaPoints[PowerCost] = true;
1747 table.insert(NewSM, PowerCost);
1748 end
1749 end
1750-- local total = 0;
1751 --for j = 1, GetNumSpellTabs() do
1752 -- total = total + select(4, GetSpellTabInfo(j));
1753 --end
1754 --print("Calc total = "..total, "actual total = "..i);
1755 Util.SpellIndex = NewSI;
1756 table.sort(NewSM);
1757 Util.SpellMana = NewSM;
1758end
1759
1760function Util.CachePetSpellIndexes()
1761 local i = 1;
1762 local NewPSI = {};
1763 --Util.NewPetSpellIndex = {};
1764 while true do
1765 local NameRank = Util.GetFullSpellName(GetSpellInfo(i, BOOKTYPE_PET));
1766 if (not NameRank) then
1767 break;
1768 end
1769 --if (not Util.PetSpellIndex[NameRank]) then
1770 -- Util.NewPetSpellIndex[NameRanl] = i;
1771 --end
1772 NewPSI[NameRank] = i;
1773 i = i + 1;
1774 end
1775
1776 Util.PetSpellIndex = NewPSI;
1777
1778end
1779
1780function Util.LookupSpellIndex(NameRank)
1781 local Index = Util.SpellIndex[NameRank];
1782
1783 if (Index) then
1784 return Index, BOOKTYPE_SPELL;
1785 end
1786 Index = Util.PetSpellIndex[NameRank];
1787 if (Index) then
1788 return Index, BOOKTYPE_PET;
1789 end
1790end
1791
1792function Util.LookupNewSpellIndex(NameRank)
1793 local Index = Util.NewSpellIndex[NameRank];
1794
1795 if (Index) then
1796 return Index, BOOKTYPE_SPELL;
1797 end
1798 Index = Util.NewPetSpellIndex[NameRank];
1799 if (Index) then
1800 return Index, BOOKTYPE_PET;
1801 end
1802end
1803
1804--[[ Used when the players mana crosses a threshold to find the next thresholds to test against --]]
1805function Util.FindNewThresholds(Mana, Index, SearchDown)
1806 local SpellMana = Util.SpellMana;
1807 if (SearchDown) then
1808 for i = Index-1, 1, -1 do
1809 if (SpellMana[i] <= Mana) then
1810 return SpellMana[i], SpellMana[i+1], i;
1811 end
1812 end
1813 else
1814 for i = Index+2, #SpellMana do
1815 if (SpellMana[i] > Mana) then
1816 return SpellMana[i-1], SpellMana[i], i-1;
1817 end
1818 end
1819 end
1820end
1821--[[ I will probably need to do the above for Rage/Energy and Runic Power, but for now will skip such tests --]]
1822
1823--[[ If a spell is learnt this will promote any usage of that spell to it's highest rank --]]
1824function Util.PromoteSpells()
1825 if (InCombatLockdown()) then
1826 Util.DelayedPromoteSpells = true; --Since this relies on the NewSpell table this may not work too well? (ultimately this is minor and perhaps not worth the extra code paths to manage)
1827 return;
1828 end
1829 return;
1830 --for k, v in pairs(Util.ActiveButtons) do
1831 -- v:PromoteSpell();
1832 --end
1833
1834end
1835
1836function Util.RefreshSpells()
1837 --Unlike the others this can be done during combat (ironically)
1838 for k, v in pairs(Util.ActiveButtons) do
1839 v:RefreshSpell();
1840 end
1841end
1842
1843function Util.RefreshBattlePets()
1844 for k, v in pairs(Util.ActiveButtons) do
1845 v:RefreshBattlePet();
1846 end
1847end
1848
1849function Util.AddSpell(Value)
1850 if (not Util.FindInTable(Util.ActiveSpells, Value)) then
1851 table.insert(Util.ActiveSpells, Value);
1852 end
1853end
1854
1855function Util.RemoveSpell(Value)
1856 local Index = Util.FindInTable(Util.ActiveSpells, Value);
1857 if (Index) then
1858 table.remove(Util.ActiveSpells, Index);
1859 end
1860end
1861
1862
1863
1864
1865
1866
1867--[[---------------------------------------
1868 Companion Functions
1869-------------------------------------------]]
1870function Util.CacheCompanions()
1871 --[[Util.Critters = {};
1872 for i = 1, GetNumCompanions("CRITTER") do
1873 local Id, Name = GetCompanionInfo("CRITTER", i);
1874 if (not Name) then
1875 return;
1876 end
1877 Util.Critters[Name] = i;
1878 end]]
1879
1880 --[[Util.Mounts = {};
1881 for i = 1, C_MountJournal.GetNumMounts() do
1882 local Name, Id = C_MountJournal.GetDisplayedMountInfo(i);
1883 if (not Name) then
1884 return;
1885 end
1886 Util.Mounts[Name] = i;
1887 end]]
1888 Util.CompanionsCached = true;
1889end
1890
1891function Util.LookupCompanion(Name)
1892 if (Util.Critters[Name]) then
1893 return "CRITTER", Util.Critters[Name];
1894 elseif (Util.Mounts[Name]) then
1895 return "MOUNT", Util.Mounts[Name];
1896 else
1897 return nil, nil;
1898 end
1899end
1900
1901function Util.RefreshCompanions()
1902 if (InCombatLockdown()) then
1903 Util.DelayedRefreshCompanions = true;
1904 return;
1905 end
1906 for k, v in pairs(Util.ActiveButtons) do
1907 v:RefreshCompanion();
1908 end
1909end
1910
1911
1912
1913
1914--[[---------------------------------------
1915 Item Functions
1916-------------------------------------------]]
1917
1918function Util.GetItemId(Name)
1919 --return select(3, strfind(Link, "item:(%d+)|"));
1920 return Util.InvItemNameId[Name] or Util.BagItemNameId[Name];
1921end
1922
1923function Util.CacheBagItems()
1924 local BagItemNameIndexes = {};
1925 local BagItemIdIndexes = {};
1926 local BagItemNameId = {};
1927 local ItemId;
1928 local ItemName;
1929 for b = 4, 0, -1 do
1930 for s = GetContainerNumSlots(b), 1, -1 do
1931 ItemId = GetContainerItemID(b, s);
1932 ItemName = GetItemInfo(ItemId or "");
1933 if (ItemName ~= nil and ItemName ~= "") then
1934 BagItemNameIndexes[ItemName] = {b, s};
1935 BagItemIdIndexes[ItemId] = {b, s};
1936 BagItemNameId[ItemName] = ItemId;
1937 end
1938 end
1939 end
1940
1941 Util.BagItemNameIndexes = BagItemNameIndexes;
1942 Util.BagItemIdIndexes = BagItemIdIndexes;
1943 Util.BagItemNameId = BagItemNameId;
1944end
1945
1946function Util.CacheInvItems()
1947 local InvItemNameIndexes = {};
1948 local InvItemIdIndexes = {};
1949 local InvItemNameId = {};
1950 local ItemId;
1951 local ItemName;
1952 for s = 32, 0, -1 do
1953 ItemId = GetInventoryItemID("player", s);
1954 ItemName = GetItemInfo(ItemId or "");
1955 if (ItemName ~= nil and ItemName ~= "") then
1956 InvItemNameIndexes[ItemName] = s;
1957 InvItemIdIndexes[ItemId] = s;
1958 InvItemNameId[ItemName] = ItemId;
1959 end
1960 end
1961
1962 Util.InvItemNameIndexes = InvItemNameIndexes;
1963 Util.InvItemIdIndexes = InvItemIdIndexes;
1964 Util.InvItemNameId = InvItemNameId;
1965end
1966
1967--[[ Look for the item in players equipped slots --]]
1968function Util.LookupItemNameEquippedSlot(ItemName)
1969 return Util.InvItemNameIndexes[ItemName];
1970end
1971function Util.LookupItemIdEquippedSlot(ItemId)
1972 return Util.InvItemIdIndexes[ItemId];
1973end
1974
1975--[[ Look for the item in the players inventory --]]
1976function Util.LookupItemNameBagSlot(ItemName)
1977 local Result = Util.BagItemNameIndexes[ItemName];
1978 if (Result) then
1979 return Result[1], Result[2];
1980 else
1981 return nil, nil;
1982 end
1983end
1984function Util.LookupItemIdBagSlot(ItemId)
1985 local Result = Util.BagItemIdIndexes[ItemId];
1986 if (Result) then
1987 return Result[1], Result[2];
1988 else
1989 return nil, nil;
1990 end
1991end
1992
1993
1994
1995--[[ Look for the item in players equipped slots --]]
1996function Util.LookupItemEquippedSlot(ItemId)
1997 for s = 0,23 do
1998 local Id = GetInventoryItemID("player", s);
1999 if (ItemId == Id) then
2000 return s;
2001 end
2002 end
2003 return nil;
2004end
2005
2006--[[ Look for the item in the players inventory
2007Notes: Don't use this function, the above functions are better
2008Reason: In the simple case profiling shows that the performance hit is neglible from doing this scan...
2009That is until GetItemInfo is used to get the name of the item
2010all other things being equal that call increases my perf time from 0.04ms (approx 100 bag slots, with half used) to 0.44ms
2011The above caching mechanism requires more work of the addon (not a good thing, complexity breeds issues) but it avoids the whole perf issue and doesn't even register (i.e. 0.00ms) --]]
2012function Util.LookupItemInvSlot(ItemId)
2013
2014 local Id;
2015 local Name = "";
2016 for b = 0, 4 do
2017 for s = 1, GetContainerNumSlots(b) do
2018 Id = GetContainerItemID(b, s);
2019 if (Id) then
2020 Name = GetItemInfo(Id);
2021 if (ItemId == Id) then
2022 return b, s;
2023 end
2024 end
2025 end
2026 end
2027 return nil, nil;
2028end
2029--[[ Look the item in the players bank (not sure if I need to make such a function so will leave this stub for now --]]
2030function Util.LookupItemBankSlot(ItemName)
2031 return nil, nil;
2032end
2033
2034function Util.AddItem(Value)
2035 if (not Util.FindInTable(Util.ActiveItems, Value)) then
2036 table.insert(Util.ActiveItems, Value);
2037 end
2038end
2039
2040function Util.RemoveItem(Value)
2041 local Index = Util.FindInTable(Util.ActiveItems, Value);
2042 if (Index) then
2043 table.remove(Util.ActiveItems, Index);
2044 end
2045end
2046
2047
2048
2049--[[---------------------------------------
2050 EquipmentSet Functions
2051-------------------------------------------]]
2052function Util.RefreshEquipmentSets()
2053 if (InCombatLockdown()) then
2054 Util.DelayedRefreshEquipmentSets = true;
2055 return;
2056 end
2057 for k, v in pairs(Util.ActiveButtons) do
2058 v:RefreshEquipmentSet();
2059 end
2060end
2061
2062
2063
2064
2065--[[---------------------------------------
2066 Bonus Action Functions
2067-------------------------------------------]]
2068function Util.AddBonusAction(Value)
2069 if (not Util.FindInTable(Util.ActiveBonusActions, Value)) then
2070 table.insert(Util.ActiveBonusActions, Value);
2071 end
2072end
2073
2074function Util.RemoveBonusAction(Value)
2075 local Index = Util.FindInTable(Util.ActiveBonusActions, Value);
2076 if (Index) then
2077 table.remove(Util.ActiveBonusActions, Index);
2078 end
2079end
2080
2081
2082function Util.UpdateButtonClickHandling()
2083 if (InCombatLockdown() or not Util.Loaded) then
2084 Util.DelayedUpdateButtonClickHandling = true;
2085 return;
2086 end
2087
2088 for i = 1, #Util.ActiveButtons do
2089 Util.ActiveButtons[i]:SetupActionButtonClick();
2090 end
2091 for i = 1, #Util.InactiveButtons do
2092 Util.InactiveButtons[i]:SetupActionButtonClick();
2093 end
2094end
2095
2096
2097--[[---------------------------------------
2098 Macro Functions
2099-------------------------------------------]]
2100function Util.Trim5(S)
2101 return strmatch(S or '', '^%s*(.*%S)') or '';
2102end
2103function Util.IncBetween(Val, Low, High)
2104 return Val >= Low and Val <= High;
2105end
2106
2107function Util.RefreshMacros()
2108 if (InCombatLockdown() or not Util.Loaded) then
2109 Util.DelayedRefreshMacros = true;
2110 return;
2111 end
2112
2113 if (Util.UpdateMacroEventCount < 2) then
2114 --Not all macros have been loaded yet so don't refresh
2115
2116 return;
2117 end
2118
2119 local AccMacros, CharMacros = GetNumMacros();
2120 if (not Util.MacroCount) then
2121 Util.MacroCount = AccMacros + CharMacros;
2122 elseif (Util.MacroCount > AccMacros + CharMacros) then
2123 Util.MacroDeleted = true;
2124 end
2125
2126
2127 for i = 1, #Util.ActiveButtons do
2128 Util.ActiveButtons[i]:RefreshMacro();
2129 end
2130 Util.MacroDeleted = false;
2131 Util.MacroCount = AccMacros + CharMacros;
2132end
2133
2134function Util.AddMacro(Value)
2135 if (not Util.FindInTable(Util.ActiveMacros, Value)) then
2136 table.insert(Util.ActiveMacros, Value);
2137 end
2138 Util.RefreshOnUpdateFunction();
2139end
2140
2141function Util.RemoveMacro(Value)
2142 local Index = Util.FindInTable(Util.ActiveMacros, Value);
2143 if (Index) then
2144 table.remove(Util.ActiveMacros, Index);
2145 Util.RefreshOnUpdateFunction();
2146 end
2147end
2148
2149--[[ Monitor the macro check delay --]]
2150function Util.StartMacroCheckDelay()
2151 Delay:SetScript("OnUpdate", Delay.OnUpdate);
2152end
2153
2154function Util.StopMacroCheckDelay()
2155 Delay:SetScript("OnUpdate", nil);
2156 Util.MacroCheckDelayComplete = true;
2157 Util.RefreshMacros();
2158end
2159
2160
2161
2162--[[
2163 The following creates an OnUpdate function designed to scan for macro conditionals that can't
2164 adequately be covered by events alone - it will only perform processing for conditionals that actually
2165 exist in allocated macros
2166--]]
2167function Util.RefreshOnUpdateFunction()
2168 if (not Util.Loaded) then
2169 return;
2170 end
2171
2172 local ConcatMacros = "";
2173 local FunctionString =
2174 [[return function (self, Elapsed)
2175 ]];
2176
2177 for i = 1, #(Util.ActiveMacros) do
2178 if (Util.ActiveMacros[i].Mode == "macro") then
2179 ConcatMacros = ConcatMacros..":"..(GetMacroBody(Util.ActiveMacros[i].MacroIndex) or "");
2180 end
2181 end
2182
2183 ConcatMacros = strupper(ConcatMacros);
2184
2185 --The following tests should be performed the buttons are updated
2186 if (strfind(ConcatMacros, "FLYING", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlying(); end
2187 if (strfind(ConcatMacros, "MOUNTED", 1, true)) then FunctionString = FunctionString..Util.SnippetIsMounted(); end
2188 FunctionString = FunctionString..Util.SnippetRefreshButtons();
2189
2190 --The following tests need to be performed after the buttons are updated (so that the buttons can be updated at the next onupdate)
2191 if (strfind(ConcatMacros, "FLYABLE", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlyable(); end
2192 if (strfind(ConcatMacros, "MOUSEOVER", 1, true)) then FunctionString = FunctionString..Util.SnippetMouseOver(); end
2193
2194 FunctionString = FunctionString.."end";
2195
2196 local Func = assert(loadstring(FunctionString, "ButtonForgeOnUpdate"));
2197 Util.OnUpdate = Func();
2198 EventFull:SetScript("OnUpdate", Util.OnUpdate);
2199end
2200
2201function Util.SnippetRefreshButtons()
2202 return
2203 [[if (self.RefreshButtons) then
2204 local ActiveButtons = self.Util.ActiveButtons;
2205 for i = 1, #ActiveButtons do
2206 ActiveButtons[i]:UpdateTexture(); --make sure the texture is always upto date (most actions wont need to do anything here, really this is just for spellwisp)
2207 end
2208 if (self.RefChecked) then
2209 for i = 1, #ActiveButtons do
2210 ActiveButtons[i]:UpdateChecked();
2211 end
2212 end
2213 if (self.RefEquipped) then
2214 for i = 1, #ActiveButtons do
2215 ActiveButtons[i]:UpdateEquipped();
2216 end
2217 end
2218 if (self.RefUsable) then
2219 --print("Usable");
2220 for i = 1, #ActiveButtons do
2221 ActiveButtons[i]:UpdateUsable();
2222 end
2223 end
2224 if (self.RefCooldown) then
2225 for i = 1, #ActiveButtons do
2226 ActiveButtons[i]:UpdateCooldown();
2227 end
2228 end
2229 if (self.RefText) then
2230 for i = 1, #ActiveButtons do
2231 ActiveButtons[i]:UpdateTextCount();
2232 end
2233 end
2234 if (self.RefFlyouts) then
2235 for i = 1, #ActiveButtons do
2236 ActiveButtons[i]:UpdateFlyout();
2237 end
2238 end
2239 if (self.RefGlow) then
2240 for i = 1, #ActiveButtons do
2241 ActiveButtons[i]:UpdateGlow();
2242 end
2243 end
2244 if (self.RefConditional) then
2245 local ActiveMacros = self.Util.ActiveMacros;
2246 for i = 1, #ActiveMacros do
2247 ActiveMacros[i]:TranslateMacro();
2248 end
2249 end
2250 self.RefreshButtons = false;
2251 self.RefFull = false;
2252 self.RefChecked = false;
2253 self.RefEquipped = false;
2254 self.RefUsable = false;
2255 self.RefCooldown = false;
2256 self.RefText = false;
2257 self.RefFlyouts = false;
2258 self.RefGlow = false;
2259 self.RefConditional = false;
2260 end
2261 ]];
2262end
2263
2264function Util.SnippetMouseOver()
2265 return
2266 [[if (UnitName("mouseover") ~= self.MOUnit or UnitIsDead("mouseover") ~= self.MOUnitDead) then
2267 self.MOUnit = UnitName("mouseover");
2268 self.MOUnitDead = UnitIsDead("mouseover");
2269 self.RefreshButtons = true;
2270 self.RefConditional = true;
2271 end
2272 ]];
2273end
2274
2275function Util.SnippetIsFlying()
2276 return
2277 [[if (IsFlying() ~= self.IsFlying) then
2278 self.IsFlying = IsFlying();
2279 self.RefreshButtons = true;
2280 self.RefConditional = true;
2281 end
2282 ]];
2283end
2284
2285function Util.SnippetIsMounted()
2286 return
2287 [[if (IsMounted() ~= self.IsMounted) then
2288 self.IsMounted = IsMounted();
2289 self.RefreshButtons = true;
2290 self.RefConditional = true;
2291 end
2292 ]];
2293end
2294
2295function Util.SnippetIsFlyable()
2296 return
2297 [[if (IsFlyableArea() ~= self.IsFlyableArea) then
2298 self.IsFlyableArea = IsFlyableArea();
2299 self.RefreshButtons = true;
2300 self.RefConditional = true;
2301 end
2302 ]];
2303end
2304
2305
2306
2307--[[
2308 API1 Support Functions
2309--]]
2310function Util.RegisterCallback(Callback, Arg)
2311 table.insert(Util.CallbackFunctions, Callback);
2312 table.insert(Util.CallbackArgs, Arg);
2313end
2314
2315function Util.UnregisterCallback(Callback, Arg)
2316 for i = #Util.CallbackFunctions, 1, -1 do
2317 if (Util.CallbackFunctions[i] == Callback and Util.CallbackArgs[i] == Arg) then
2318 table.remove(Util.CallbackFunctions, i);
2319 table.remove(Util.CallbackArgs, i);
2320 end
2321 end
2322end
2323
2324local CallbackFunc;
2325local CallbackArg;
2326local CallbackEvent;
2327local CallbackEventArgs;
2328function Util.CallbackWrapper()
2329 CallbackFunc(CallbackArg, CallbackEvent, unpack(CallbackEventArgs));
2330end
2331
2332function Util.CallbackEvent(Event, ...)
2333 CallbackEvent = Event;
2334 CallbackEventArgs = {...};
2335 --local Args = {...};
2336 for i = 1, #Util.CallbackFunctions do
2337 CallbackFunc = Util.CallbackFunctions[i];
2338 CallbackArg = Util.CallbackArgs[i];
2339 xpcall(Util.CallbackWrapper, geterrorhandler());
2340 --xpcall(function () Util.CallbackFunctions[i](Util.CallbackArgs[i], Event, unpack(Args)); end, geterrorhandler()); --The other way provides a little more context if an error occurs
2341 end
2342end
2343
2344--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
2345function Util.GetButtonActionInfo(ButtonName)
2346 local Button = Util.ButtonWidgetMap[_G[ButtonName]];
2347
2348 if (not Button) then
2349 return;
2350 end
2351
2352 if (Button.Mode == "spell") then
2353 return "spell", Button.SpellId, Button.SpellBook;
2354 elseif (Button.Mode == "item") then
2355 return "item", Button.ItemId;
2356 elseif (Button.Mode == "macro") then
2357 return "macro", Button.MacroIndex;
2358 elseif (Button.Mode == "companion") then
2359 local spellid = select(3, GetCompanionInfo(Button.CompanionType, Button.CompanionIndex));
2360 return "companion", spellid, Button.CompanionType;
2361 elseif (Button.Mode == "equipmentset") then
2362 return "equipmentset", Button.EquipmentSetName;
2363 elseif (Button.Mode == "flyout") then
2364 return "flyout", Button.FlyoutId;
2365 elseif (Button.Mode == "battlepet") then
2366 return "battlepet", Button.BattlePetId;
2367 end
2368end
2369
2370--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
2371function Util.GetButtonActionInfo2(ButtonName)
2372 local Button = Util.ButtonWidgetMap[_G[ButtonName]];
2373
2374 if (not Button) then
2375 return;
2376 end
2377
2378 --[[
2379 "spell", SpellName, SpellSubName, SpellId, SpellIndex, SpellBook
2380 "item", ItemId, ItemName
2381 "macro", MacroIndex
2382 "companion", CompanionType, CompanionIndex
2383 "equipmentset", Name
2384 "flyout", FlyoutId
2385 "bonusaction", BonusActionSlot
2386 "customaction", CustomActionName
2387 --]]
2388
2389 if (Button.Mode == "spell") then
2390 local Rank = select(2, GetSpellInfo(Button.SpellId));
2391 return "spell", Button.SpellName, Rank, Button.SpellId, Util.LookupSpellIndex(Button.SpellNameRank), Button.SpellBook;
2392 elseif (Button.Mode == "item") then
2393 return "item", Button.ItemId, Button.ItemName;
2394 elseif (Button.Mode == "macro") then
2395 return "macro", Button.MacroIndex;
2396 elseif (Button.Mode == "companion") then
2397 return "companion", Button.CompanionType, Button.CompanionIndex;
2398 elseif (Button.Mode == "equipmentset") then
2399 return "equipmentset", Button.EquipmentSetName;
2400 elseif (Button.Mode == "flyout") then
2401 return "flyout", Button.FlyoutId;
2402 elseif (Button.Mode == "bonusaction") then
2403 return "bonusaction", Button.BonusActionSlot;
2404 elseif (Button.Mode == "customaction") then
2405 return "customaction", Button.CustomActionName;
2406 elseif (Button.Mode == "battlepet") then
2407 return "battlepet", Button.BattlePetId;
2408 end
2409end
2410
2411
2412--[[------------------------------------------------
2413 Get Correct Mount Index
2414 The Hack:
2415 hooksecurefunc
2416 C_MountJournal.Pickup
2417 GameTooltip:SetAction
2418 Both these functions offer a moment when both
2419 the UselessIndex and the actual Index or SpellID
2420 for a mount is available... Also in theory
2421 one of these will have to fire before the player
2422 can actually put a mount on the cursor - so we
2423 simply patch work build a map of these
2424 Useless Index to useful index mappings.
2425 It does rely on the useless index not changing during
2426 a session - i suspect it wont, but it might when a new
2427 mount is learned, something that is hard to test on my
2428 account these days
2429--------------------------------------------------]]
2430--[[ should no longer be needed
2431function Util.HookSecureFunc_C_MountJournal_Pickup(Index)
2432 local UselessIndex = select(2, GetCursorInfo());
2433 if (Index and UselessIndex) then
2434 Util.MountUselessIndexToIndex[select(2, GetCursorInfo())] = Index;
2435 end
2436end
2437hooksecurefunc(C_MountJournal, "Pickup", Util.HookSecureFunc_C_MountJournal_Pickup);
2438
2439function Util.HookSecureFunc_GameTooltip_SetAction(_, Slot)
2440 if (Slot == nil or Slot < 1 or Slot > 1000) then
2441 return;
2442 end
2443 local Command, UselessIndex = GetActionInfo(Slot);
2444 if (Command == "summonmount") then
2445 if (Util.MountUselessIndexToIndex[UselessIndex] == nil) then
2446 Util.MountUselessIndexToIndex[UselessIndex] = Util.GetMountIndexFromSpellID(select(3, GameTooltip:GetSpell()));
2447 end
2448 end
2449end
2450hooksecurefunc(GameTooltip, "SetAction", Util.HookSecureFunc_GameTooltip_SetAction);
2451
2452function Util.GetMountIndexFromUselessIndex(Index)
2453 return Util.MountUselessIndexToIndex[Index];
2454end
2455]]
2456
2457--[[------------------------------------------------
2458 GetCorrectMountIndex
2459--------------------------------------------------]]
2460--[[
2461function Util.GetMountIndexFromSpellID(SpellID)
2462 local Num = C_MountJournal.GetNumMounts();
2463 if (SpellID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) then
2464 return 0; -- This is summon favorite
2465 end
2466 for i = 1, Num do
2467 if (select(2, C_MountJournal.GetDisplayedMountInfo(i)) == SpellID) then
2468 return i;
2469 end
2470 end
2471 return nil;
2472end
2473]]
2474
2475--[[------------------------------------------------
2476
2477--------------------------------------------------]]
2478
2479function Util.GetMountIDFromName(Name)
2480 local Num = C_MountJournal.GetNumMounts();
2481
2482 for i = 1, Num do
2483 if (C_MountJournal.GetDisplayedMountInfo(i) == Name) then
2484 return select(12, C_MountJournal.GetDisplayedMountInfo(i));
2485 end
2486 end
2487 return nil;
2488end
2489
2490function Util.GetMountIndexFromMountID(MountID)
2491 local Num = C_MountJournal.GetNumMounts();
2492 if (MountID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_ID) then
2493 return 0;
2494 end
2495 for i = 1, Num do
2496 if (select(12, C_MountJournal.GetDisplayedMountInfo(i)) == MountID) then
2497 return i;
2498 end
2499 end
2500end
2501
2502function Util.UpdateButtonsCooldownSwipeBling()
2503 local ActiveButtons = Util.ActiveButtons;
2504 for i = 1, #ActiveButtons do
2505 local Alpha = ActiveButtons[i].WCooldown:GetEffectiveAlpha();
2506 ActiveButtons[i].WCooldown:SetDrawBling(Alpha == 1);
2507 ActiveButtons[i].WCooldown:SetSwipeColor(0,0,0,Alpha);
2508 end
2509end
2510
2511--[[
2512 Copied from Bliz implementation
2513 The difference is I use the effective alpha to override the bling and edge settings, and also adjust the swipe alpha
2514
2515 I suspect this will need fine tuning for Masque and perhaps OmniCC, but that can be down the track
2516]]
2517function Util.CooldownFrame_SetTimer(self, start, duration, enable, charges, maxCharges, forceShowDrawEdge)
2518 if(enable) then
2519 if (enable ~= 0) then
2520 local drawEdge = false;
2521 if ( duration > 2 and charges and maxCharges and charges ~= 0) then
2522 drawEdge = true;
2523 end
2524 local Alpha = self:GetEffectiveAlpha();
2525 self:SetSwipeColor(0, 0, 0, Alpha); -- eventually I may need to make this obey the current color!!!
2526 if (Alpha > 0.4) then
2527 self:SetDrawEdge(drawEdge or forceShowDrawEdge);
2528 self:SetDrawBling(true);
2529 else
2530 self:SetDrawEdge(false);
2531 self:SetDrawBling(false);
2532 end
2533 self:SetDrawSwipe(not drawEdge);
2534 self:SetCooldown(start, duration);
2535 else
2536 self:SetCooldown(0, 0);
2537 end
2538 end
2539end
2540
2541
2542function Util.LookupEquipmentSetIndex(EquipmentSetID)
2543
2544 local Total = C_EquipmentSet.GetNumEquipmentSets();
2545 for i = 0, Total-1 do
2546 if (select(3, C_EquipmentSet.GetEquipmentSetInfo(i)) == EquipmentSetID) then
2547 return i;
2548 end
2549 end
2550 return nil;
2551
2552end