Advertisement
Guest User

Untitled

a guest
Jul 19th, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 76.86 KB | None | 0 0
  1. --[[
  2. Author: Alternator (Massiner of Nathrezim)
  3. Copyright 2010
  4.  
  5. Notes:
  6. ]]
  7.  
  8. local Util = BFUtil;
  9. local Const = BFConst;
  10. local UILib = BFUILib;
  11. local CustomAction = BFCustomAction;
  12. local Button = BFButton;
  13. local Bar = BFBar;
  14. local EventFull = BFEventFrames["Full"];
  15. local MiscFrame = BFEventFrames["Misc"];
  16. local Delay = BFEventFrames["Delay"];
  17. local ConfigureLayer = BFConfigureLayer;
  18. local 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)
  21. BFLocales[GetLocale()] = BFLocales[GetLocale()] or {};
  22. local Locale = BFLocales[GetLocale()];
  23. if (GetLocale() ~= "enUS") then
  24. setmetatable(Locale, BFLocales["enUS"]);
  25. end
  26.  
  27.  
  28.  
  29. Util.ActiveButtons = {};
  30. Util.InactiveButtons = {};
  31. Util.ActiveMacros = {};
  32. Util.ActiveSpells = {};
  33. Util.ActiveItems = {};
  34. Util.ActiveBonusActions = {};
  35.  
  36. Util.RangeTimerButtons = {};
  37. Util.FlashButtons = {};
  38.  
  39. Util.ActiveBars = {};
  40. Util.InactiveBars = {};
  41.  
  42. Util.ActiveTabs = {};
  43. Util.InactiveTabs = {};
  44.  
  45. Util.SpellIndex = {};
  46. Util.SpellMana = {};
  47. Util.NewSpellIndex = {};
  48. Util.GlowSpells = {};
  49. Util.PetSpellIndex = {};
  50. Util.NewPetSpellIndex = {};
  51.  
  52. Util.BagItemNameIndex = {};
  53. Util.BagItemIdIndex = {};
  54. Util.BagItemNameId = {};
  55. Util.InvItemNameIndex = {};
  56. Util.InvItemIdIndex = {};
  57. Util.InvItemNameId = {};
  58.  
  59. Util.GridHidden = true;
  60. Util.LowStrata = true;
  61. Util.BlizBarWrappers = {};
  62. Util.BlizEnabledBars = {};
  63.  
  64. Util.CallbackFunctions = {};
  65. Util.CallbackArgs = {};
  66. Util.ButtonWidgetMap = {};
  67.  
  68. Util.UpdateMacroEventCount = 0;
  69. Util.MacroCheckDelayComplete = false;
  70. Util.ForceOffCastOnKeyDown = false;
  71. Util.MountUselessIndexToIndex = {};
  72.  
  73. --One quick override function
  74. local G_PickupSpellBookItem = PickupSpellBookItem;
  75. local 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);
  83. end
  84.  
  85.  
  86.  
  87. --[[
  88. Make sure that the saved data is kept inline with the version being run
  89. --]]
  90. function 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
  355. end
  356.  
  357.  
  358. function 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
  377. end
  378.  
  379. function 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
  386. end
  387.  
  388. function 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
  410. end
  411.  
  412. function 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
  419. end
  420.  
  421. --[[
  422. Load the bars and buttons from the saved addon values
  423. --]]
  424. function 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");
  455. end
  456.  
  457. -- Grabbed from the Lua wiki
  458. function 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
  471. end
  472.  
  473. --[[
  474. Load the bars and buttons from a profile
  475. --]]
  476. function 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);
  509. end
  510.  
  511. --[[
  512. Load the bars and buttons from a profile
  513. --]]
  514. function 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.  
  552. end
  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. --]]
  560. function 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);
  575. end
  576.  
  577.  
  578. --[[
  579. -- Lazy, I should've factored this with the save profile function
  580.  
  581. --]]
  582. function 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);
  610. end
  611.  
  612.  
  613. function 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?!
  622. end
  623.  
  624.  
  625. --[[
  626. Save Button Facade settings if present
  627. --]]
  628. function 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]]
  644. end
  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. --]]
  652. function 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.  
  674. end
  675.  
  676. function Util.UpdateBlizzardEnabledBarsMap()
  677. Util.BlizEnabledBars = {GetActionBarToggles()};
  678. end
  679.  
  680. --[[
  681. Button Allocation Functions
  682. --]]
  683. function 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;
  700. end
  701.  
  702. function 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());
  710. end
  711.  
  712. function 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());
  720. end
  721.  
  722.  
  723.  
  724. --[[
  725. Bar Allocation Functions
  726. --]]
  727. function 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;
  757. end
  758.  
  759. function 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
  790. end
  791.  
  792. function 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);
  810. end
  811.  
  812. function 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);
  822. end
  823.  
  824. function 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);
  833. end
  834.  
  835. function 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
  849. end
  850.  
  851.  
  852. --[[
  853. Bar Management Functions
  854. --]]
  855. function 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);
  874. end
  875.  
  876. function 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;
  892. end
  893.  
  894.  
  895.  
  896.  
  897. function 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;
  944. end
  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 --]]
  947. function 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
  961. end
  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. --]]
  968. function 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
  985. end
  986.  
  987.  
  988. function 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
  1007. end
  1008.  
  1009. function 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
  1024. end
  1025.  
  1026.  
  1027. function Util.SetControlFrameAlphas(Alpha)
  1028. local Bars = Util.ActiveBars;
  1029.  
  1030. for i = 1, #Bars do
  1031. Bars[i].ControlFrame:SetAlpha(Alpha);
  1032. end
  1033.  
  1034. end
  1035.  
  1036. function 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);
  1107. end
  1108.  
  1109. function 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
  1114. end
  1115.  
  1116. function 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];
  1127. end
  1128.  
  1129. function 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;
  1138. end
  1139.  
  1140.  
  1141.  
  1142. --[[
  1143. Helper functions
  1144. --]]
  1145. function 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;
  1152. end
  1153.  
  1154. function Util.GetLocaleString(Value)
  1155. return Locale[Value];
  1156. end
  1157.  
  1158. function Util.GetLocaleEnabledDisabled(Value)
  1159. if (Value) then
  1160. return Locale["Enabled"];
  1161. else
  1162. return Locale["Disabled"];
  1163. end
  1164. end
  1165.  
  1166. function Util.CastBool(Value)
  1167. return Locale.BoolTable[strlower(Value or '')];
  1168. end
  1169.  
  1170. function 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.  
  1188. end
  1189.  
  1190. --[[Unused function for allowing a more... ]]--
  1191. local SlashRemainingMessage = '';
  1192. function 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);
  1201. end
  1202.  
  1203.  
  1204. function Util.SlashShowMessageByLine(Message)
  1205. for Line in string.gmatch(Message, '([^\n]*)') do
  1206. DEFAULT_CHAT_FRAME:AddMessage(Line, .5, 1, 0, 1);
  1207. end
  1208. end
  1209.  
  1210. function 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.  
  1323. end
  1324.  
  1325.  
  1326. function 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.  
  1519. end
  1520.  
  1521. --[[ Store cursor type info for later use --]]
  1522. function Util.StoreCursor(Command, Data, Subvalue, Subsubvalue)
  1523. Util.Command = Command;
  1524. Util.Data = Data;
  1525. Util.Subvalue = Subvalue;
  1526. Util.Subsubvalue = Subsubvalue
  1527. end
  1528.  
  1529. function Util.GetStoredCursor()
  1530. return Util.Command, Util.Data, Util.Subvalue, Util.Subsubvalue;
  1531. end
  1532.  
  1533. --[[ Set the cursor based on the triplet passed in --]]
  1534. function 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
  1573. end
  1574.  
  1575. --[[ These two functions will take care of non secure gui updates when the player enters or exits combat ]]--
  1576. function 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();
  1583. end
  1584.  
  1585. function 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
  1612. end
  1613.  
  1614. --[[ Add and remove buttons to a list that gets updated for the range timer --]]
  1615. function Util.AddToRangeTimer(Value)
  1616. if (#Util.RangeTimerButtons == 0) then
  1617. --BF
  1618. end
  1619. Util.RangeTimerButtons[Value] = true;
  1620. end
  1621.  
  1622. function Util.RemoveFromRangeTimer(Value)
  1623. Util.RangeTimerButtons[Value] = nil;
  1624. end
  1625.  
  1626. --[[ Add and remove buttons to a list that gets updated for flashing --]]
  1627. function Util.AddToFlash(Value)
  1628. if (#Util.FlashButtons == 0) then
  1629. --BF
  1630. end
  1631. Util.FlashButtons[Value] = true;
  1632. end
  1633.  
  1634. function Util.RemoveFromFlash(Value)
  1635. Util.FlashButtons[Value] = nil;
  1636. end
  1637.  
  1638. function 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;
  1654. end
  1655.  
  1656.  
  1657.  
  1658.  
  1659.  
  1660. --[[---------------------------------------
  1661. Spell Functions
  1662. -------------------------------------------]]
  1663. function Util.GetFullSpellName(Name, Rank)
  1664. if (Name) then
  1665. return Name.."("..Rank..")";
  1666. end
  1667. end
  1668.  
  1669. function Util.GetSpellId(NameRank)
  1670. local Link = GetSpellLink(NameRank);
  1671. return select(3, strfind(Link, "spell:(%d+)|"));
  1672. end
  1673.  
  1674. function 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;
  1697. end
  1698.  
  1699. function 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;
  1744. end
  1745.  
  1746. function 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.  
  1764. end
  1765.  
  1766. function 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
  1776. end
  1777.  
  1778. function 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
  1788. end
  1789.  
  1790. --[[ Used when the players mana crosses a threshold to find the next thresholds to test against --]]
  1791. function 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
  1806. end
  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 --]]
  1810. function 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.  
  1820. end
  1821.  
  1822. function 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
  1827. end
  1828.  
  1829. function Util.RefreshBattlePets()
  1830. for k, v in pairs(Util.ActiveButtons) do
  1831. v:RefreshBattlePet();
  1832. end
  1833. end
  1834.  
  1835. function Util.AddSpell(Value)
  1836. if (not Util.FindInTable(Util.ActiveSpells, Value)) then
  1837. table.insert(Util.ActiveSpells, Value);
  1838. end
  1839. end
  1840.  
  1841. function Util.RemoveSpell(Value)
  1842. local Index = Util.FindInTable(Util.ActiveSpells, Value);
  1843. if (Index) then
  1844. table.remove(Util.ActiveSpells, Index);
  1845. end
  1846. end
  1847.  
  1848.  
  1849.  
  1850.  
  1851.  
  1852.  
  1853. --[[---------------------------------------
  1854. Companion Functions
  1855. -------------------------------------------]]
  1856. function 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;
  1875. end
  1876.  
  1877. function 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
  1885. end
  1886.  
  1887. function 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
  1895. end
  1896.  
  1897.  
  1898.  
  1899.  
  1900. --[[---------------------------------------
  1901. Item Functions
  1902. -------------------------------------------]]
  1903.  
  1904. function Util.GetItemId(Name)
  1905. --return select(3, strfind(Link, "item:(%d+)|"));
  1906. return Util.InvItemNameId[Name] or Util.BagItemNameId[Name];
  1907. end
  1908.  
  1909. function 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;
  1930. end
  1931.  
  1932. function 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;
  1951. end
  1952.  
  1953. --[[ Look for the item in players equipped slots --]]
  1954. function Util.LookupItemNameEquippedSlot(ItemName)
  1955. return Util.InvItemNameIndexes[ItemName];
  1956. end
  1957. function Util.LookupItemIdEquippedSlot(ItemId)
  1958. return Util.InvItemIdIndexes[ItemId];
  1959. end
  1960.  
  1961. --[[ Look for the item in the players inventory --]]
  1962. function 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
  1969. end
  1970. function 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
  1977. end
  1978.  
  1979.  
  1980.  
  1981. --[[ Look for the item in players equipped slots --]]
  1982. function 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;
  1990. end
  1991.  
  1992. --[[ Look for the item in the players inventory
  1993. Notes: Don't use this function, the above functions are better
  1994. Reason: In the simple case profiling shows that the performance hit is neglible from doing this scan...
  1995. That is until GetItemInfo is used to get the name of the item
  1996. all other things being equal that call increases my perf time from 0.04ms (approx 100 bag slots, with half used) to 0.44ms
  1997. The 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) --]]
  1998. function 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;
  2014. end
  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 --]]
  2016. function Util.LookupItemBankSlot(ItemName)
  2017. return nil, nil;
  2018. end
  2019.  
  2020. function Util.AddItem(Value)
  2021. if (not Util.FindInTable(Util.ActiveItems, Value)) then
  2022. table.insert(Util.ActiveItems, Value);
  2023. end
  2024. end
  2025.  
  2026. function Util.RemoveItem(Value)
  2027. local Index = Util.FindInTable(Util.ActiveItems, Value);
  2028. if (Index) then
  2029. table.remove(Util.ActiveItems, Index);
  2030. end
  2031. end
  2032.  
  2033.  
  2034.  
  2035. --[[---------------------------------------
  2036. EquipmentSet Functions
  2037. -------------------------------------------]]
  2038. function 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
  2046. end
  2047.  
  2048.  
  2049.  
  2050.  
  2051. --[[---------------------------------------
  2052. Bonus Action Functions
  2053. -------------------------------------------]]
  2054. function Util.AddBonusAction(Value)
  2055. if (not Util.FindInTable(Util.ActiveBonusActions, Value)) then
  2056. table.insert(Util.ActiveBonusActions, Value);
  2057. end
  2058. end
  2059.  
  2060. function Util.RemoveBonusAction(Value)
  2061. local Index = Util.FindInTable(Util.ActiveBonusActions, Value);
  2062. if (Index) then
  2063. table.remove(Util.ActiveBonusActions, Index);
  2064. end
  2065. end
  2066.  
  2067.  
  2068. function 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
  2080. end
  2081.  
  2082.  
  2083. --[[---------------------------------------
  2084. Macro Functions
  2085. -------------------------------------------]]
  2086. function Util.Trim5(S)
  2087. return strmatch(S or '', '^%s*(.*%S)') or '';
  2088. end
  2089. function Util.IncBetween(Val, Low, High)
  2090. return Val >= Low and Val <= High;
  2091. end
  2092.  
  2093. function 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;
  2118. end
  2119.  
  2120. function Util.AddMacro(Value)
  2121. if (not Util.FindInTable(Util.ActiveMacros, Value)) then
  2122. table.insert(Util.ActiveMacros, Value);
  2123. end
  2124. Util.RefreshOnUpdateFunction();
  2125. end
  2126.  
  2127. function 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
  2133. end
  2134.  
  2135. --[[ Monitor the macro check delay --]]
  2136. function Util.StartMacroCheckDelay()
  2137. Delay:SetScript("OnUpdate", Delay.OnUpdate);
  2138. end
  2139.  
  2140. function Util.StopMacroCheckDelay()
  2141. Delay:SetScript("OnUpdate", nil);
  2142. Util.MacroCheckDelayComplete = true;
  2143. Util.RefreshMacros();
  2144. end
  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. --]]
  2153. function 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);
  2185. end
  2186.  
  2187. function 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. ]];
  2248. end
  2249.  
  2250. function 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. ]];
  2259. end
  2260.  
  2261. function 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. ]];
  2269. end
  2270.  
  2271. function 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. ]];
  2279. end
  2280.  
  2281. function 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. ]];
  2289. end
  2290.  
  2291.  
  2292.  
  2293. --[[
  2294. API1 Support Functions
  2295. --]]
  2296. function Util.RegisterCallback(Callback, Arg)
  2297. table.insert(Util.CallbackFunctions, Callback);
  2298. table.insert(Util.CallbackArgs, Arg);
  2299. end
  2300.  
  2301. function 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
  2308. end
  2309.  
  2310. local CallbackFunc;
  2311. local CallbackArg;
  2312. local CallbackEvent;
  2313. local CallbackEventArgs;
  2314. function Util.CallbackWrapper()
  2315. CallbackFunc(CallbackArg, CallbackEvent, unpack(CallbackEventArgs));
  2316. end
  2317.  
  2318. function 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
  2328. end
  2329.  
  2330. --This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
  2331. function 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
  2354. end
  2355.  
  2356. --This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
  2357. function 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
  2395. end
  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
  2417. function 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
  2422. end
  2423. hooksecurefunc(C_MountJournal, "Pickup", Util.HookSecureFunc_C_MountJournal_Pickup);
  2424.  
  2425. function 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
  2435. end
  2436. hooksecurefunc(GameTooltip, "SetAction", Util.HookSecureFunc_GameTooltip_SetAction);
  2437.  
  2438. function Util.GetMountIndexFromUselessIndex(Index)
  2439. return Util.MountUselessIndexToIndex[Index];
  2440. end
  2441. ]]
  2442.  
  2443. --[[------------------------------------------------
  2444. GetCorrectMountIndex
  2445. --------------------------------------------------]]
  2446. --[[
  2447. function 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;
  2458. end
  2459. ]]
  2460.  
  2461. --[[------------------------------------------------
  2462.  
  2463. --------------------------------------------------]]
  2464.  
  2465. function 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;
  2474. end
  2475.  
  2476. function 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
  2486. end
  2487.  
  2488. function 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
  2495. end
  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. ]]
  2503. function 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
  2525. end
  2526.  
  2527.  
  2528. function 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.  
  2538. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement