· 8 years ago · Jul 19, 2018, 05:54 AM
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 PlaySoundFile("Sound\\Interface\\Pickup\\Putdownsmallmetal.Wav");
771 --PlaySoundFile("Sound\\Item\\Weapons\\Mace2h\\2hmacehitplate1a.Wav");
772 end
773
774 if (#(Util.InactiveBars) > 0) then
775 NewBar = table.remove(Util.InactiveBars);
776 NewBar:Configure(BarSave);
777 else
778 NewBar = Bar.New(BarSave);
779 end
780
781 table.insert(Util.ActiveBars, NewBar);
782 if (NewBar.Cols * NewBar.Rows == 0) then
783 --Failed to allocate buttons, get rid of the bar
784 NewBar:Deallocate();
785 return nil;
786 else
787 Util.RefreshTab(NewBar.ControlFrame:GetLeft(), NewBar.ControlFrame:GetTop());
788 return NewBar;
789 end
790end
791
792function Util.NewBonusBar(Left, Top)
793 if (InCombatLockdown()) then
794 return;
795 end
796 local BarSave = Util.NewBarSave();
797 BarSave["BonusBar"] = true;
798 BarSave["Left"] = Left;
799 BarSave["Top"] = Top;
800 BarSave["Rows"] = 1;
801 BarSave["Cols"] = 13;
802 BarSave["HBonusBar"] = false;
803 BarSave["HVehicle"] = false;
804 BarSave["VDriver"] = "[overridebar][vehicleui] show; hide";
805 BarSave["ButtonsLocked"] = true;
806 BarSave["GridAlwaysOn"] = false;
807 table.insert(ButtonForgeSave.Bars, BarSave);
808 PlaySoundFile("Sound\\Interface\\Pickup\\Putdownsmallmetal.Wav");
809 return Util.NewBar(Left, Top, BarSave);
810end
811
812function Util.DeallocateBar(Value)
813 if (InCombatLockdown()) then
814 return;
815 end
816 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)
817 table.remove(Util.ActiveBars, Util.FindInTable(Util.ActiveBars, Value));
818 table.remove(ButtonForgeSave.Bars, Util.FindInTable(ButtonForgeSave.Bars, Value.BarSave));
819 table.insert(Util.InactiveBars, Value);
820 local Left, Top = Value.ControlFrame:GetLeft(), Value.ControlFrame:GetTop();
821 Util.RefreshTab(Left, Top);
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 PickupEquipmentSetByName(Data);
1552 elseif (Command == "bonusaction") then
1553 local page = 12; --The page for vehicleactionbar
1554 if (HasOverrideActionBar()) then
1555 page = 14;
1556 end
1557 local Texture = GetActionTexture(Data + ((page - 1) * 12));
1558 if (Texture and (HasOverrideActionBar() or HasVehicleActionBar())) then
1559 UILib.StartDraggingIcon(Texture, 23, 23, "bonusaction", Data);
1560 else
1561 UILib.StartDraggingIcon(Const.ImagesDir.."Bonus"..Data, 23, 23, "bonusaction", Data);
1562 end
1563 elseif (Command == "flyout") then
1564 local ind, booktype = Util.LookupSpellIndex("FLYOUT"..Data);
1565 if (ind) then
1566 PickupSpellBookItem(ind, booktype);
1567 end
1568 elseif (Command == "customaction") then
1569 CustomAction.SetCursor(Data);
1570 elseif (Command == "battlepet") then
1571 C_PetJournal.PickupPet(Data);
1572 end
1573end
1574
1575--[[ These two functions will take care of non secure gui updates when the player enters or exits combat ]]--
1576function Util.PreCombatStateUpdate()
1577 Util.InCombat = true;
1578 Util.RefreshGridStatus();
1579 Util.RefreshBarStrata(); --Im surprised that these refreshes dont lead to taint, I must be forgetting something??!
1580 UILib.ToggleCreateBarMode(true);
1581 UILib.ToggleDestroyBarMode(true);
1582 Util.RefreshBarGUIStatus();
1583end
1584
1585function Util.PostCombatStateUpdate()
1586 Util.InCombat = false;
1587 Util.VDriverOverride();
1588 Util.RefreshGridStatus();
1589 Util.RefreshBarStrata();
1590 Util.RefreshBarGUIStatus();
1591
1592 if (Util.DelayedRefreshMacros) then
1593 Util.RefreshMacros();
1594 Util.DelayedRefreshMacros = nil;
1595 end
1596 if (Util.DelayedUpdateButtonClickHandling) then
1597 Util.UpdateButtonClickHandling();
1598 Util.DelayedUpdateButtonClickHandling = nil;
1599 end
1600 if (Util.DelayedPromoteSpells) then
1601 Util.PromoteSpells();
1602 Util.DelayedPromoteSpells = nil;
1603 end
1604 if (Util.DelayedRefreshCompanions) then
1605 Util.RefreshCompanions();
1606 Util.DelayedRefreshCompanions = nil;
1607 end
1608 if (Util.DelayedRefreshEquipmentSets) then
1609 Util.RefreshEquipmentSets();
1610 Util.DelayedRefreshEquipmentSets = nil;
1611 end
1612end
1613
1614--[[ Add and remove buttons to a list that gets updated for the range timer --]]
1615function Util.AddToRangeTimer(Value)
1616 if (#Util.RangeTimerButtons == 0) then
1617 --BF
1618 end
1619 Util.RangeTimerButtons[Value] = true;
1620end
1621
1622function Util.RemoveFromRangeTimer(Value)
1623 Util.RangeTimerButtons[Value] = nil;
1624end
1625
1626--[[ Add and remove buttons to a list that gets updated for flashing --]]
1627function Util.AddToFlash(Value)
1628 if (#Util.FlashButtons == 0) then
1629 --BF
1630 end
1631 Util.FlashButtons[Value] = true;
1632end
1633
1634function Util.RemoveFromFlash(Value)
1635 Util.FlashButtons[Value] = nil;
1636end
1637
1638function Util.RightClickSelfCast(Value)
1639 if (InCombatLockdown()) then
1640 return;
1641 end
1642
1643 if (Value) then
1644 for i = 1, #Util.ActiveButtons do
1645 Util.ActiveButtons[i].Widget:SetAttribute("unit2", "player");
1646 end
1647 else
1648 for i = 1, #Util.ActiveButtons do
1649 Util.ActiveButtons[i].Widget:SetAttribute("unit2", nil);
1650 end
1651 end
1652
1653 ButtonForgeSave["RightClickSelfCast"] = Value;
1654end
1655
1656
1657
1658
1659
1660--[[---------------------------------------
1661 Spell Functions
1662-------------------------------------------]]
1663function Util.GetFullSpellName(Name, Rank)
1664 if (Name) then
1665 return Name.."("..Rank..")";
1666 end
1667end
1668
1669function Util.GetSpellId(NameRank)
1670 local Link = GetSpellLink(NameRank);
1671 return select(3, strfind(Link, "spell:(%d+)|"));
1672end
1673
1674function Util.IsSpellIdTalent(SpellId)
1675 local TalentInfoFuncs = {GetTalentInfo, GetPvpTalentInfo};
1676
1677 -- Scan both normal and PvP talents
1678 -- Note rather than assume number of talents, we just scan till the rows and columns till we hit a nil
1679 for _, TalentInfoFunc in ipairs(TalentInfoFuncs) do
1680 local r = 1;
1681 local c = 1;
1682 local TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1683 while (TalentSpellID) do
1684 while (TalentSpellID) do
1685 if (TalentSpellID == SpellId) then
1686 return true;
1687 end
1688 c = c + 1;
1689 TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1690 end
1691 r = r + 1;
1692 c = 1;
1693 TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
1694 end
1695 end
1696 return false;
1697end
1698
1699function Util.CacheSpellIndexes()
1700 local i = 1;
1701 local NewSI = {};
1702 local NewSM = {-10000000, 10000000};
1703 local ManaPoints = {};
1704 local ItemType, Id;
1705 Util.NewSpellIndex = {};
1706
1707 local total = 0;
1708 for j = 1, GetNumSpellTabs() do
1709 total = total + select(4, GetSpellTabInfo(j));
1710 end
1711
1712 for i = total, 1, -1 do
1713 ItemType, Id = GetSpellBookItemInfo(i, BOOKTYPE_SPELL);
1714 --local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(i, BOOKTYPE_SPELL);
1715 local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(Id);
1716 local NameRank = Util.GetFullSpellName(Name, Rank);
1717 if (ItemType == "SPELL") then
1718 NewSI[NameRank] = i;
1719
1720 elseif (ItemType == "FLYOUT") then
1721 NewSI["FLYOUT"..Id] = i;
1722
1723 elseif (ItemType == nil) then
1724 break;
1725
1726 end
1727
1728-- if (not Util.SpellIndex[NameRank]) then
1729 -- Util.NewSpellIndex[NameRank] = i;
1730 --end
1731 if (PowerType == 0 and not ManaPoints[Power]) then
1732 ManaPoints[PowerCost] = true;
1733 table.insert(NewSM, PowerCost);
1734 end
1735 end
1736-- local total = 0;
1737 --for j = 1, GetNumSpellTabs() do
1738 -- total = total + select(4, GetSpellTabInfo(j));
1739 --end
1740 --print("Calc total = "..total, "actual total = "..i);
1741 Util.SpellIndex = NewSI;
1742 table.sort(NewSM);
1743 Util.SpellMana = NewSM;
1744end
1745
1746function Util.CachePetSpellIndexes()
1747 local i = 1;
1748 local NewPSI = {};
1749 --Util.NewPetSpellIndex = {};
1750 while true do
1751 local NameRank = Util.GetFullSpellName(GetSpellInfo(i, BOOKTYPE_PET));
1752 if (not NameRank) then
1753 break;
1754 end
1755 --if (not Util.PetSpellIndex[NameRank]) then
1756 -- Util.NewPetSpellIndex[NameRanl] = i;
1757 --end
1758 NewPSI[NameRank] = i;
1759 i = i + 1;
1760 end
1761
1762 Util.PetSpellIndex = NewPSI;
1763
1764end
1765
1766function Util.LookupSpellIndex(NameRank)
1767 local Index = Util.SpellIndex[NameRank];
1768
1769 if (Index) then
1770 return Index, BOOKTYPE_SPELL;
1771 end
1772 Index = Util.PetSpellIndex[NameRank];
1773 if (Index) then
1774 return Index, BOOKTYPE_PET;
1775 end
1776end
1777
1778function Util.LookupNewSpellIndex(NameRank)
1779 local Index = Util.NewSpellIndex[NameRank];
1780
1781 if (Index) then
1782 return Index, BOOKTYPE_SPELL;
1783 end
1784 Index = Util.NewPetSpellIndex[NameRank];
1785 if (Index) then
1786 return Index, BOOKTYPE_PET;
1787 end
1788end
1789
1790--[[ Used when the players mana crosses a threshold to find the next thresholds to test against --]]
1791function Util.FindNewThresholds(Mana, Index, SearchDown)
1792 local SpellMana = Util.SpellMana;
1793 if (SearchDown) then
1794 for i = Index-1, 1, -1 do
1795 if (SpellMana[i] <= Mana) then
1796 return SpellMana[i], SpellMana[i+1], i;
1797 end
1798 end
1799 else
1800 for i = Index+2, #SpellMana do
1801 if (SpellMana[i] > Mana) then
1802 return SpellMana[i-1], SpellMana[i], i-1;
1803 end
1804 end
1805 end
1806end
1807--[[ I will probably need to do the above for Rage/Energy and Runic Power, but for now will skip such tests --]]
1808
1809--[[ If a spell is learnt this will promote any usage of that spell to it's highest rank --]]
1810function Util.PromoteSpells()
1811 if (InCombatLockdown()) then
1812 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)
1813 return;
1814 end
1815 return;
1816 --for k, v in pairs(Util.ActiveButtons) do
1817 -- v:PromoteSpell();
1818 --end
1819
1820end
1821
1822function Util.RefreshSpells()
1823 --Unlike the others this can be done during combat (ironically)
1824 for k, v in pairs(Util.ActiveButtons) do
1825 v:RefreshSpell();
1826 end
1827end
1828
1829function Util.RefreshBattlePets()
1830 for k, v in pairs(Util.ActiveButtons) do
1831 v:RefreshBattlePet();
1832 end
1833end
1834
1835function Util.AddSpell(Value)
1836 if (not Util.FindInTable(Util.ActiveSpells, Value)) then
1837 table.insert(Util.ActiveSpells, Value);
1838 end
1839end
1840
1841function Util.RemoveSpell(Value)
1842 local Index = Util.FindInTable(Util.ActiveSpells, Value);
1843 if (Index) then
1844 table.remove(Util.ActiveSpells, Index);
1845 end
1846end
1847
1848
1849
1850
1851
1852
1853--[[---------------------------------------
1854 Companion Functions
1855-------------------------------------------]]
1856function Util.CacheCompanions()
1857 --[[Util.Critters = {};
1858 for i = 1, GetNumCompanions("CRITTER") do
1859 local Id, Name = GetCompanionInfo("CRITTER", i);
1860 if (not Name) then
1861 return;
1862 end
1863 Util.Critters[Name] = i;
1864 end]]
1865
1866 --[[Util.Mounts = {};
1867 for i = 1, C_MountJournal.GetNumMounts() do
1868 local Name, Id = C_MountJournal.GetDisplayedMountInfo(i);
1869 if (not Name) then
1870 return;
1871 end
1872 Util.Mounts[Name] = i;
1873 end]]
1874 Util.CompanionsCached = true;
1875end
1876
1877function Util.LookupCompanion(Name)
1878 if (Util.Critters[Name]) then
1879 return "CRITTER", Util.Critters[Name];
1880 elseif (Util.Mounts[Name]) then
1881 return "MOUNT", Util.Mounts[Name];
1882 else
1883 return nil, nil;
1884 end
1885end
1886
1887function Util.RefreshCompanions()
1888 if (InCombatLockdown()) then
1889 Util.DelayedRefreshCompanions = true;
1890 return;
1891 end
1892 for k, v in pairs(Util.ActiveButtons) do
1893 v:RefreshCompanion();
1894 end
1895end
1896
1897
1898
1899
1900--[[---------------------------------------
1901 Item Functions
1902-------------------------------------------]]
1903
1904function Util.GetItemId(Name)
1905 --return select(3, strfind(Link, "item:(%d+)|"));
1906 return Util.InvItemNameId[Name] or Util.BagItemNameId[Name];
1907end
1908
1909function Util.CacheBagItems()
1910 local BagItemNameIndexes = {};
1911 local BagItemIdIndexes = {};
1912 local BagItemNameId = {};
1913 local ItemId;
1914 local ItemName;
1915 for b = 4, 0, -1 do
1916 for s = GetContainerNumSlots(b), 1, -1 do
1917 ItemId = GetContainerItemID(b, s);
1918 ItemName = GetItemInfo(ItemId or "");
1919 if (ItemName ~= nil and ItemName ~= "") then
1920 BagItemNameIndexes[ItemName] = {b, s};
1921 BagItemIdIndexes[ItemId] = {b, s};
1922 BagItemNameId[ItemName] = ItemId;
1923 end
1924 end
1925 end
1926
1927 Util.BagItemNameIndexes = BagItemNameIndexes;
1928 Util.BagItemIdIndexes = BagItemIdIndexes;
1929 Util.BagItemNameId = BagItemNameId;
1930end
1931
1932function Util.CacheInvItems()
1933 local InvItemNameIndexes = {};
1934 local InvItemIdIndexes = {};
1935 local InvItemNameId = {};
1936 local ItemId;
1937 local ItemName;
1938 for s = 32, 0, -1 do
1939 ItemId = GetInventoryItemID("player", s);
1940 ItemName = GetItemInfo(ItemId or "");
1941 if (ItemName ~= nil and ItemName ~= "") then
1942 InvItemNameIndexes[ItemName] = s;
1943 InvItemIdIndexes[ItemId] = s;
1944 InvItemNameId[ItemName] = ItemId;
1945 end
1946 end
1947
1948 Util.InvItemNameIndexes = InvItemNameIndexes;
1949 Util.InvItemIdIndexes = InvItemIdIndexes;
1950 Util.InvItemNameId = InvItemNameId;
1951end
1952
1953--[[ Look for the item in players equipped slots --]]
1954function Util.LookupItemNameEquippedSlot(ItemName)
1955 return Util.InvItemNameIndexes[ItemName];
1956end
1957function Util.LookupItemIdEquippedSlot(ItemId)
1958 return Util.InvItemIdIndexes[ItemId];
1959end
1960
1961--[[ Look for the item in the players inventory --]]
1962function Util.LookupItemNameBagSlot(ItemName)
1963 local Result = Util.BagItemNameIndexes[ItemName];
1964 if (Result) then
1965 return Result[1], Result[2];
1966 else
1967 return nil, nil;
1968 end
1969end
1970function Util.LookupItemIdBagSlot(ItemId)
1971 local Result = Util.BagItemIdIndexes[ItemId];
1972 if (Result) then
1973 return Result[1], Result[2];
1974 else
1975 return nil, nil;
1976 end
1977end
1978
1979
1980
1981--[[ Look for the item in players equipped slots --]]
1982function Util.LookupItemEquippedSlot(ItemId)
1983 for s = 0,23 do
1984 local Id = GetInventoryItemID("player", s);
1985 if (ItemId == Id) then
1986 return s;
1987 end
1988 end
1989 return nil;
1990end
1991
1992--[[ Look for the item in the players inventory
1993Notes: Don't use this function, the above functions are better
1994Reason: In the simple case profiling shows that the performance hit is neglible from doing this scan...
1995That is until GetItemInfo is used to get the name of the item
1996all other things being equal that call increases my perf time from 0.04ms (approx 100 bag slots, with half used) to 0.44ms
1997The 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) --]]
1998function Util.LookupItemInvSlot(ItemId)
1999
2000 local Id;
2001 local Name = "";
2002 for b = 0, 4 do
2003 for s = 1, GetContainerNumSlots(b) do
2004 Id = GetContainerItemID(b, s);
2005 if (Id) then
2006 Name = GetItemInfo(Id);
2007 if (ItemId == Id) then
2008 return b, s;
2009 end
2010 end
2011 end
2012 end
2013 return nil, nil;
2014end
2015--[[ Look the item in the players bank (not sure if I need to make such a function so will leave this stub for now --]]
2016function Util.LookupItemBankSlot(ItemName)
2017 return nil, nil;
2018end
2019
2020function Util.AddItem(Value)
2021 if (not Util.FindInTable(Util.ActiveItems, Value)) then
2022 table.insert(Util.ActiveItems, Value);
2023 end
2024end
2025
2026function Util.RemoveItem(Value)
2027 local Index = Util.FindInTable(Util.ActiveItems, Value);
2028 if (Index) then
2029 table.remove(Util.ActiveItems, Index);
2030 end
2031end
2032
2033
2034
2035--[[---------------------------------------
2036 EquipmentSet Functions
2037-------------------------------------------]]
2038function Util.RefreshEquipmentSets()
2039 if (InCombatLockdown()) then
2040 Util.DelayedRefreshEquipmentSets = true;
2041 return;
2042 end
2043 for k, v in pairs(Util.ActiveButtons) do
2044 v:RefreshEquipmentSet();
2045 end
2046end
2047
2048
2049
2050
2051--[[---------------------------------------
2052 Bonus Action Functions
2053-------------------------------------------]]
2054function Util.AddBonusAction(Value)
2055 if (not Util.FindInTable(Util.ActiveBonusActions, Value)) then
2056 table.insert(Util.ActiveBonusActions, Value);
2057 end
2058end
2059
2060function Util.RemoveBonusAction(Value)
2061 local Index = Util.FindInTable(Util.ActiveBonusActions, Value);
2062 if (Index) then
2063 table.remove(Util.ActiveBonusActions, Index);
2064 end
2065end
2066
2067
2068function Util.UpdateButtonClickHandling()
2069 if (InCombatLockdown() or not Util.Loaded) then
2070 Util.DelayedUpdateButtonClickHandling = true;
2071 return;
2072 end
2073
2074 for i = 1, #Util.ActiveButtons do
2075 Util.ActiveButtons[i]:SetupActionButtonClick();
2076 end
2077 for i = 1, #Util.InactiveButtons do
2078 Util.InactiveButtons[i]:SetupActionButtonClick();
2079 end
2080end
2081
2082
2083--[[---------------------------------------
2084 Macro Functions
2085-------------------------------------------]]
2086function Util.Trim5(S)
2087 return strmatch(S or '', '^%s*(.*%S)') or '';
2088end
2089function Util.IncBetween(Val, Low, High)
2090 return Val >= Low and Val <= High;
2091end
2092
2093function Util.RefreshMacros()
2094 if (InCombatLockdown() or not Util.Loaded) then
2095 Util.DelayedRefreshMacros = true;
2096 return;
2097 end
2098
2099 if (Util.UpdateMacroEventCount < 2) then
2100 --Not all macros have been loaded yet so don't refresh
2101
2102 return;
2103 end
2104
2105 local AccMacros, CharMacros = GetNumMacros();
2106 if (not Util.MacroCount) then
2107 Util.MacroCount = AccMacros + CharMacros;
2108 elseif (Util.MacroCount > AccMacros + CharMacros) then
2109 Util.MacroDeleted = true;
2110 end
2111
2112
2113 for i = 1, #Util.ActiveButtons do
2114 Util.ActiveButtons[i]:RefreshMacro();
2115 end
2116 Util.MacroDeleted = false;
2117 Util.MacroCount = AccMacros + CharMacros;
2118end
2119
2120function Util.AddMacro(Value)
2121 if (not Util.FindInTable(Util.ActiveMacros, Value)) then
2122 table.insert(Util.ActiveMacros, Value);
2123 end
2124 Util.RefreshOnUpdateFunction();
2125end
2126
2127function Util.RemoveMacro(Value)
2128 local Index = Util.FindInTable(Util.ActiveMacros, Value);
2129 if (Index) then
2130 table.remove(Util.ActiveMacros, Index);
2131 Util.RefreshOnUpdateFunction();
2132 end
2133end
2134
2135--[[ Monitor the macro check delay --]]
2136function Util.StartMacroCheckDelay()
2137 Delay:SetScript("OnUpdate", Delay.OnUpdate);
2138end
2139
2140function Util.StopMacroCheckDelay()
2141 Delay:SetScript("OnUpdate", nil);
2142 Util.MacroCheckDelayComplete = true;
2143 Util.RefreshMacros();
2144end
2145
2146
2147
2148--[[
2149 The following creates an OnUpdate function designed to scan for macro conditionals that can't
2150 adequately be covered by events alone - it will only perform processing for conditionals that actually
2151 exist in allocated macros
2152--]]
2153function Util.RefreshOnUpdateFunction()
2154 if (not Util.Loaded) then
2155 return;
2156 end
2157
2158 local ConcatMacros = "";
2159 local FunctionString =
2160 [[return function (self, Elapsed)
2161 ]];
2162
2163 for i = 1, #(Util.ActiveMacros) do
2164 if (Util.ActiveMacros[i].Mode == "macro") then
2165 ConcatMacros = ConcatMacros..":"..(GetMacroBody(Util.ActiveMacros[i].MacroIndex) or "");
2166 end
2167 end
2168
2169 ConcatMacros = strupper(ConcatMacros);
2170
2171 --The following tests should be performed the buttons are updated
2172 if (strfind(ConcatMacros, "FLYING", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlying(); end
2173 if (strfind(ConcatMacros, "MOUNTED", 1, true)) then FunctionString = FunctionString..Util.SnippetIsMounted(); end
2174 FunctionString = FunctionString..Util.SnippetRefreshButtons();
2175
2176 --The following tests need to be performed after the buttons are updated (so that the buttons can be updated at the next onupdate)
2177 if (strfind(ConcatMacros, "FLYABLE", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlyable(); end
2178 if (strfind(ConcatMacros, "MOUSEOVER", 1, true)) then FunctionString = FunctionString..Util.SnippetMouseOver(); end
2179
2180 FunctionString = FunctionString.."end";
2181
2182 local Func = assert(loadstring(FunctionString, "ButtonForgeOnUpdate"));
2183 Util.OnUpdate = Func();
2184 EventFull:SetScript("OnUpdate", Util.OnUpdate);
2185end
2186
2187function Util.SnippetRefreshButtons()
2188 return
2189 [[if (self.RefreshButtons) then
2190 local ActiveButtons = self.Util.ActiveButtons;
2191 for i = 1, #ActiveButtons do
2192 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)
2193 end
2194 if (self.RefChecked) then
2195 for i = 1, #ActiveButtons do
2196 ActiveButtons[i]:UpdateChecked();
2197 end
2198 end
2199 if (self.RefEquipped) then
2200 for i = 1, #ActiveButtons do
2201 ActiveButtons[i]:UpdateEquipped();
2202 end
2203 end
2204 if (self.RefUsable) then
2205 --print("Usable");
2206 for i = 1, #ActiveButtons do
2207 ActiveButtons[i]:UpdateUsable();
2208 end
2209 end
2210 if (self.RefCooldown) then
2211 for i = 1, #ActiveButtons do
2212 ActiveButtons[i]:UpdateCooldown();
2213 end
2214 end
2215 if (self.RefText) then
2216 for i = 1, #ActiveButtons do
2217 ActiveButtons[i]:UpdateTextCount();
2218 end
2219 end
2220 if (self.RefFlyouts) then
2221 for i = 1, #ActiveButtons do
2222 ActiveButtons[i]:UpdateFlyout();
2223 end
2224 end
2225 if (self.RefGlow) then
2226 for i = 1, #ActiveButtons do
2227 ActiveButtons[i]:UpdateGlow();
2228 end
2229 end
2230 if (self.RefConditional) then
2231 local ActiveMacros = self.Util.ActiveMacros;
2232 for i = 1, #ActiveMacros do
2233 ActiveMacros[i]:TranslateMacro();
2234 end
2235 end
2236 self.RefreshButtons = false;
2237 self.RefFull = false;
2238 self.RefChecked = false;
2239 self.RefEquipped = false;
2240 self.RefUsable = false;
2241 self.RefCooldown = false;
2242 self.RefText = false;
2243 self.RefFlyouts = false;
2244 self.RefGlow = false;
2245 self.RefConditional = false;
2246 end
2247 ]];
2248end
2249
2250function Util.SnippetMouseOver()
2251 return
2252 [[if (UnitName("mouseover") ~= self.MOUnit or UnitIsDead("mouseover") ~= self.MOUnitDead) then
2253 self.MOUnit = UnitName("mouseover");
2254 self.MOUnitDead = UnitIsDead("mouseover");
2255 self.RefreshButtons = true;
2256 self.RefConditional = true;
2257 end
2258 ]];
2259end
2260
2261function Util.SnippetIsFlying()
2262 return
2263 [[if (IsFlying() ~= self.IsFlying) then
2264 self.IsFlying = IsFlying();
2265 self.RefreshButtons = true;
2266 self.RefConditional = true;
2267 end
2268 ]];
2269end
2270
2271function Util.SnippetIsMounted()
2272 return
2273 [[if (IsMounted() ~= self.IsMounted) then
2274 self.IsMounted = IsMounted();
2275 self.RefreshButtons = true;
2276 self.RefConditional = true;
2277 end
2278 ]];
2279end
2280
2281function Util.SnippetIsFlyable()
2282 return
2283 [[if (IsFlyableArea() ~= self.IsFlyableArea) then
2284 self.IsFlyableArea = IsFlyableArea();
2285 self.RefreshButtons = true;
2286 self.RefConditional = true;
2287 end
2288 ]];
2289end
2290
2291
2292
2293--[[
2294 API1 Support Functions
2295--]]
2296function Util.RegisterCallback(Callback, Arg)
2297 table.insert(Util.CallbackFunctions, Callback);
2298 table.insert(Util.CallbackArgs, Arg);
2299end
2300
2301function Util.UnregisterCallback(Callback, Arg)
2302 for i = #Util.CallbackFunctions, 1, -1 do
2303 if (Util.CallbackFunctions[i] == Callback and Util.CallbackArgs[i] == Arg) then
2304 table.remove(Util.CallbackFunctions, i);
2305 table.remove(Util.CallbackArgs, i);
2306 end
2307 end
2308end
2309
2310local CallbackFunc;
2311local CallbackArg;
2312local CallbackEvent;
2313local CallbackEventArgs;
2314function Util.CallbackWrapper()
2315 CallbackFunc(CallbackArg, CallbackEvent, unpack(CallbackEventArgs));
2316end
2317
2318function Util.CallbackEvent(Event, ...)
2319 CallbackEvent = Event;
2320 CallbackEventArgs = {...};
2321 --local Args = {...};
2322 for i = 1, #Util.CallbackFunctions do
2323 CallbackFunc = Util.CallbackFunctions[i];
2324 CallbackArg = Util.CallbackArgs[i];
2325 xpcall(Util.CallbackWrapper, geterrorhandler());
2326 --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
2327 end
2328end
2329
2330--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
2331function Util.GetButtonActionInfo(ButtonName)
2332 local Button = Util.ButtonWidgetMap[_G[ButtonName]];
2333
2334 if (not Button) then
2335 return;
2336 end
2337
2338 if (Button.Mode == "spell") then
2339 return "spell", Button.SpellId, Button.SpellBook;
2340 elseif (Button.Mode == "item") then
2341 return "item", Button.ItemId;
2342 elseif (Button.Mode == "macro") then
2343 return "macro", Button.MacroIndex;
2344 elseif (Button.Mode == "companion") then
2345 local spellid = select(3, GetCompanionInfo(Button.CompanionType, Button.CompanionIndex));
2346 return "companion", spellid, Button.CompanionType;
2347 elseif (Button.Mode == "equipmentset") then
2348 return "equipmentset", Button.EquipmentSetName;
2349 elseif (Button.Mode == "flyout") then
2350 return "flyout", Button.FlyoutId;
2351 elseif (Button.Mode == "battlepet") then
2352 return "battlepet", Button.BattlePetId;
2353 end
2354end
2355
2356--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
2357function Util.GetButtonActionInfo2(ButtonName)
2358 local Button = Util.ButtonWidgetMap[_G[ButtonName]];
2359
2360 if (not Button) then
2361 return;
2362 end
2363
2364 --[[
2365 "spell", SpellName, SpellSubName, SpellId, SpellIndex, SpellBook
2366 "item", ItemId, ItemName
2367 "macro", MacroIndex
2368 "companion", CompanionType, CompanionIndex
2369 "equipmentset", Name
2370 "flyout", FlyoutId
2371 "bonusaction", BonusActionSlot
2372 "customaction", CustomActionName
2373 --]]
2374
2375 if (Button.Mode == "spell") then
2376 local Rank = select(2, GetSpellInfo(Button.SpellId));
2377 return "spell", Button.SpellName, Rank, Button.SpellId, Util.LookupSpellIndex(Button.SpellNameRank), Button.SpellBook;
2378 elseif (Button.Mode == "item") then
2379 return "item", Button.ItemId, Button.ItemName;
2380 elseif (Button.Mode == "macro") then
2381 return "macro", Button.MacroIndex;
2382 elseif (Button.Mode == "companion") then
2383 return "companion", Button.CompanionType, Button.CompanionIndex;
2384 elseif (Button.Mode == "equipmentset") then
2385 return "equipmentset", Button.EquipmentSetName;
2386 elseif (Button.Mode == "flyout") then
2387 return "flyout", Button.FlyoutId;
2388 elseif (Button.Mode == "bonusaction") then
2389 return "bonusaction", Button.BonusActionSlot;
2390 elseif (Button.Mode == "customaction") then
2391 return "customaction", Button.CustomActionName;
2392 elseif (Button.Mode == "battlepet") then
2393 return "battlepet", Button.BattlePetId;
2394 end
2395end
2396
2397
2398--[[------------------------------------------------
2399 Get Correct Mount Index
2400 The Hack:
2401 hooksecurefunc
2402 C_MountJournal.Pickup
2403 GameTooltip:SetAction
2404 Both these functions offer a moment when both
2405 the UselessIndex and the actual Index or SpellID
2406 for a mount is available... Also in theory
2407 one of these will have to fire before the player
2408 can actually put a mount on the cursor - so we
2409 simply patch work build a map of these
2410 Useless Index to useful index mappings.
2411 It does rely on the useless index not changing during
2412 a session - i suspect it wont, but it might when a new
2413 mount is learned, something that is hard to test on my
2414 account these days
2415--------------------------------------------------]]
2416--[[ should no longer be needed
2417function Util.HookSecureFunc_C_MountJournal_Pickup(Index)
2418 local UselessIndex = select(2, GetCursorInfo());
2419 if (Index and UselessIndex) then
2420 Util.MountUselessIndexToIndex[select(2, GetCursorInfo())] = Index;
2421 end
2422end
2423hooksecurefunc(C_MountJournal, "Pickup", Util.HookSecureFunc_C_MountJournal_Pickup);
2424
2425function Util.HookSecureFunc_GameTooltip_SetAction(_, Slot)
2426 if (Slot == nil or Slot < 1 or Slot > 1000) then
2427 return;
2428 end
2429 local Command, UselessIndex = GetActionInfo(Slot);
2430 if (Command == "summonmount") then
2431 if (Util.MountUselessIndexToIndex[UselessIndex] == nil) then
2432 Util.MountUselessIndexToIndex[UselessIndex] = Util.GetMountIndexFromSpellID(select(3, GameTooltip:GetSpell()));
2433 end
2434 end
2435end
2436hooksecurefunc(GameTooltip, "SetAction", Util.HookSecureFunc_GameTooltip_SetAction);
2437
2438function Util.GetMountIndexFromUselessIndex(Index)
2439 return Util.MountUselessIndexToIndex[Index];
2440end
2441]]
2442
2443--[[------------------------------------------------
2444 GetCorrectMountIndex
2445--------------------------------------------------]]
2446--[[
2447function Util.GetMountIndexFromSpellID(SpellID)
2448 local Num = C_MountJournal.GetNumMounts();
2449 if (SpellID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) then
2450 return 0; -- This is summon favorite
2451 end
2452 for i = 1, Num do
2453 if (select(2, C_MountJournal.GetDisplayedMountInfo(i)) == SpellID) then
2454 return i;
2455 end
2456 end
2457 return nil;
2458end
2459]]
2460
2461--[[------------------------------------------------
2462
2463--------------------------------------------------]]
2464
2465function Util.GetMountIDFromName(Name)
2466 local Num = C_MountJournal.GetNumMounts();
2467
2468 for i = 1, Num do
2469 if (C_MountJournal.GetDisplayedMountInfo(i) == Name) then
2470 return select(12, C_MountJournal.GetDisplayedMountInfo(i));
2471 end
2472 end
2473 return nil;
2474end
2475
2476function Util.GetMountIndexFromMountID(MountID)
2477 local Num = C_MountJournal.GetNumMounts();
2478 if (MountID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_ID) then
2479 return 0;
2480 end
2481 for i = 1, Num do
2482 if (select(12, C_MountJournal.GetDisplayedMountInfo(i)) == MountID) then
2483 return i;
2484 end
2485 end
2486end
2487
2488function Util.UpdateButtonsCooldownSwipeBling()
2489 local ActiveButtons = Util.ActiveButtons;
2490 for i = 1, #ActiveButtons do
2491 local Alpha = ActiveButtons[i].WCooldown:GetEffectiveAlpha();
2492 ActiveButtons[i].WCooldown:SetDrawBling(Alpha == 1);
2493 ActiveButtons[i].WCooldown:SetSwipeColor(0,0,0,Alpha);
2494 end
2495end
2496
2497--[[
2498 Copied from Bliz implementation
2499 The difference is I use the effective alpha to override the bling and edge settings, and also adjust the swipe alpha
2500
2501 I suspect this will need fine tuning for Masque and perhaps OmniCC, but that can be down the track
2502]]
2503function Util.CooldownFrame_SetTimer(self, start, duration, enable, charges, maxCharges, forceShowDrawEdge)
2504 if(enable) then
2505 if (enable ~= 0) then
2506 local drawEdge = false;
2507 if ( duration > 2 and charges and maxCharges and charges ~= 0) then
2508 drawEdge = true;
2509 end
2510 local Alpha = self:GetEffectiveAlpha();
2511 self:SetSwipeColor(0, 0, 0, Alpha); -- eventually I may need to make this obey the current color!!!
2512 if (Alpha > 0.4) then
2513 self:SetDrawEdge(drawEdge or forceShowDrawEdge);
2514 self:SetDrawBling(true);
2515 else
2516 self:SetDrawEdge(false);
2517 self:SetDrawBling(false);
2518 end
2519 self:SetDrawSwipe(not drawEdge);
2520 self:SetCooldown(start, duration);
2521 else
2522 self:SetCooldown(0, 0);
2523 end
2524 end
2525end
2526
2527
2528function Util.LookupEquipmentSetIndex(EquipmentSetID)
2529
2530 local Total = GetNumEquipmentSets();
2531 for i = 1, Total do
2532 if (select(3, GetEquipmentSetInfo(i)) == EquipmentSetID) then
2533 return i;
2534 end
2535 end
2536 return nil;
2537
2538end