2512 lignes
74 Kio
Lua
2512 lignes
74 Kio
Lua
--[[
|
|
Author: Alternator (Massiner of Nathrezim)
|
|
Copyright 2010
|
|
|
|
Notes:
|
|
]]
|
|
|
|
local Util = BFUtil;
|
|
local Const = BFConst;
|
|
local UILib = BFUILib;
|
|
local CustomAction = BFCustomAction;
|
|
local Button = BFButton;
|
|
local Bar = BFBar;
|
|
local EventFull = BFEventFrames["Full"];
|
|
local MiscFrame = BFEventFrames["Misc"];
|
|
local Delay = BFEventFrames["Delay"];
|
|
local ConfigureLayer = BFConfigureLayer;
|
|
local DestroyBarOverlay = BFDestroyBarOverlay;
|
|
|
|
--This will get the currently applicable locale, or allocate it if needed (note that locales other than enUS will need the metatable set)
|
|
BFLocales[GetLocale()] = BFLocales[GetLocale()] or {};
|
|
local Locale = BFLocales[GetLocale()];
|
|
if (GetLocale() ~= "enUS") then
|
|
setmetatable(Locale, BFLocales["enUS"]);
|
|
end
|
|
|
|
|
|
|
|
Util.ActiveButtons = {};
|
|
Util.InactiveButtons = {};
|
|
Util.ActiveMacros = {};
|
|
Util.ActiveSpells = {};
|
|
Util.ActiveItems = {};
|
|
Util.ActiveBonusActions = {};
|
|
|
|
Util.RangeTimerButtons = {};
|
|
Util.FlashButtons = {};
|
|
|
|
Util.ActiveBars = {};
|
|
Util.InactiveBars = {};
|
|
|
|
Util.ActiveTabs = {};
|
|
Util.InactiveTabs = {};
|
|
|
|
Util.SpellIndex = {};
|
|
Util.SpellMana = {};
|
|
Util.NewSpellIndex = {};
|
|
Util.GlowSpells = {};
|
|
Util.PetSpellIndex = {};
|
|
Util.NewPetSpellIndex = {};
|
|
|
|
Util.BagItemNameIndex = {};
|
|
Util.BagItemIdIndex = {};
|
|
Util.BagItemNameId = {};
|
|
Util.InvItemNameIndex = {};
|
|
Util.InvItemIdIndex = {};
|
|
Util.InvItemNameId = {};
|
|
|
|
Util.GridHidden = true;
|
|
Util.LowStrata = true;
|
|
Util.BlizBarWrappers = {};
|
|
Util.BlizEnabledBars = {};
|
|
|
|
Util.CallbackFunctions = {};
|
|
Util.CallbackArgs = {};
|
|
Util.ButtonWidgetMap = {};
|
|
|
|
Util.UpdateMacroEventCount = 0;
|
|
Util.MacroCheckDelayComplete = false;
|
|
Util.ForceOffCastOnKeyDown = false;
|
|
Util.MountUselessIndexToIndex = {};
|
|
|
|
--One quick override function
|
|
local G_PickupSpellBookItem = PickupSpellBookItem;
|
|
local function PickupSpellBookItem(NameRank, Book)
|
|
local Index, Alt_Book = Util.LookupSpellIndex(NameRank);
|
|
if (Index) then
|
|
return G_PickupSpellBookItem(Index, Alt_Book);
|
|
elseif (Book) then
|
|
return G_PickupSpellBookItem(NameRank, Book);
|
|
end
|
|
return G_PickupSpellBookItem(NameRank);
|
|
end
|
|
|
|
--Dirty fix for classic, will keep it as is until i know what the hell does HasOverrideActionBar...
|
|
function HasOverrideActionBar()
|
|
return false;
|
|
end
|
|
|
|
--[[
|
|
Make sure that the saved data is kept inline with the version being run
|
|
--]]
|
|
function Util.UpdateSavedData()
|
|
|
|
---- FIX for MACS, if character data hasn't loaded but is otherwise available in the global save ----
|
|
local CharRealm = UnitName("player");
|
|
CharRealm = CharRealm.."-"..GetRealmName();
|
|
if (ButtonForgeSave == nil
|
|
and ButtonForgeGlobalBackup ~= nil
|
|
and ButtonForgeGlobalBackup[CharRealm] ~= nil) then
|
|
ButtonForgeSave = ButtonForgeGlobalBackup[CharRealm];
|
|
end
|
|
|
|
|
|
------The following section updates the per character saved data------
|
|
|
|
--Need to allocate save structure
|
|
if (not ButtonForgeSave or ButtonForgeSave["Version"] == nil ) then
|
|
--Swap v0.9.0 / v0.9.1 / v0.9.2 users to the new save structure
|
|
ButtonForgeSave = {};
|
|
ButtonForgeSave["ConfigureMode"] = true;
|
|
ButtonForgeSave["AdvancedMode"] = false;
|
|
ButtonForgeSave["RightClickSelfCast"] = false;
|
|
ButtonForgeSave["Version"] = Const.Version;
|
|
ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
|
|
ButtonForgeSave.Bars = {};
|
|
ButtonForgeSave["AddonName"] = "Button Forge";
|
|
end
|
|
|
|
--v0.9.3 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 3) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
ButtonForgeSave.Bars[i]["HBonusBar"] = true;
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 3;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.3", .5, 1, 0, 1);
|
|
end
|
|
|
|
--v0.9.12 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 12) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
ButtonForgeSave.Bars[i]["MacroText"] = true;
|
|
ButtonForgeSave.Bars[i]["KeyBindText"] = true;
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 12;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.12", .5, 1, 0, 1);
|
|
end
|
|
|
|
--v0.9.13 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 13) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
ButtonForgeSave.Bars[i]["Enabled"] = true;
|
|
ButtonForgeSave.Bars[i]["ButtonGap"] = 6;
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 13;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.13", .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
--v0.9.17 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 17) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
ButtonForgeSave.Bars[i]["GUI"] = true;
|
|
ButtonForgeSave.Bars[i]["Alpha"] = 1;
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 17;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.17", .5, 1, 0, 1);
|
|
end
|
|
|
|
--v0.9.22 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 22) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
if (ButtonForgeSave.Bars[i]["VDriver"] == "[bonusbar:5] show; hide") then
|
|
ButtonForgeSave.Bars[i]["VDriver"] = "[overridebar][vehicleui] show; hide";
|
|
end
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 22;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.22", .5, 1, 0, 1);
|
|
end
|
|
|
|
-- v0.9.34 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 34) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.UpdateMounts602(ButtonForgeSave.Bars[i].Buttons);
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 34;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.34", .5, 1, 0, 1);
|
|
end
|
|
|
|
-- v0.9.36 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 36) then
|
|
if (ButtonForgeSave.UndoProfileBars ~= nil) then
|
|
for i = 1, #ButtonForgeSave.UndoProfileBars do
|
|
Util.UpdateMounts602(ButtonForgeSave.UndoProfileBars[i].Buttons);
|
|
end
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 36;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.36", .5, 1, 0, 1);
|
|
end
|
|
|
|
-- v0.9.41 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 41) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.UpdateMounts700(ButtonForgeSave.Bars[i].Buttons);
|
|
end
|
|
|
|
if (ButtonForgeSave.UndoProfileBars ~= nil) then
|
|
for i = 1, #ButtonForgeSave.UndoProfileBars do
|
|
Util.UpdateMounts700(ButtonForgeSave.UndoProfileBars[i].Buttons);
|
|
end
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 41;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.41", .5, 1, 0, 1);
|
|
end
|
|
|
|
-- v0.9.42 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 42) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
ButtonForgeSave.Bars[i].HSpec3 = false;
|
|
ButtonForgeSave.Bars[i].HSpec4 = false;
|
|
end
|
|
|
|
if (ButtonForgeSave.UndoProfileBars ~= nil) then
|
|
for i = 1, #ButtonForgeSave.UndoProfileBars do
|
|
ButtonForgeSave.UndoProfileBars[i].HSpec3 = false;
|
|
ButtonForgeSave.UndoProfileBars[i].HSpec4 = false;
|
|
end
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 42;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.42", .5, 1, 0, 1);
|
|
end
|
|
|
|
-- v0.9.44 update
|
|
if (ButtonForgeSave["Version"] == 0.9 and ButtonForgeSave["VersionMinor"] < 44) then
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.RemoveCancelPossession700(ButtonForgeSave.Bars[i].Buttons);
|
|
end
|
|
|
|
if (ButtonForgeSave.UndoProfileBars ~= nil) then
|
|
for i = 1, #ButtonForgeSave.UndoProfileBars do
|
|
Util.RemoveCancelPossession700(ButtonForgeSave.UndoProfileBars[i].Buttons);
|
|
end
|
|
end
|
|
ButtonForgeSave["VersionMinor"] = 44;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v0.9.44", .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
|
|
--Bring v up to the latest version
|
|
if (ButtonForgeSave["Version"] < Const.Version) then
|
|
ButtonForgeSave["Version"] = Const.Version;
|
|
ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v"..Const.Version.."."..Const.VersionMinor, .5, 1, 0, 1);
|
|
elseif (ButtonForgeSave["Version"] == Const.Version and ButtonForgeSave["VersionMinor"] < Const.VersionMinor) then
|
|
ButtonForgeSave["VersionMinor"] = Const.VersionMinor;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UpgradedChatMsg").."v"..Const.Version.."."..Const.VersionMinor, .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
-----This section updates the global button forge data (introduced at 0.9.16)
|
|
if (not ButtonForgeGlobalSettings) or (ButtonForgeGlobalSettings == nil) or (ButtonForgeGlobalSettings["Version"] == nil) then
|
|
ButtonForgeGlobalSettings = {};
|
|
ButtonForgeGlobalSettings["Version"] = 0.9;
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 16;
|
|
ButtonForgeGlobalSettings["MacroCheckDelay"] = 3;
|
|
ButtonForgeGlobalSettings["RemoveMissingMacros"] = true;
|
|
end
|
|
|
|
--v0.9.30 update (to global settings)
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 30) then
|
|
ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"] = false;
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 30;
|
|
end
|
|
|
|
--v0.9.31 update (to global profiles)
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 31) then
|
|
ButtonForgeGlobalProfiles = {};
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 31;
|
|
end
|
|
|
|
--pre v0.9.36 Safety process
|
|
if (not ButtonForgeGlobalProfiles) or (ButtonForgeGlobalProfiles == nil) then
|
|
ButtonForgeGlobalProfiles = {};
|
|
end
|
|
|
|
--v0.9.36 update
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 36) then
|
|
for k,v in pairs(ButtonForgeGlobalProfiles) do
|
|
for i = 1, #v.Bars do
|
|
Util.UpdateMounts602(v.Bars[i].Buttons);
|
|
end
|
|
end
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 36;
|
|
end
|
|
|
|
--v0.9.38 update
|
|
if (ButtonForgeGlobalBackup == nil) then
|
|
ButtonForgeGlobalBackup = {};
|
|
end
|
|
|
|
-- v0.9.41
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 41) then
|
|
for k, v in pairs(ButtonForgeGlobalProfiles) do
|
|
for i = 1, #v.Bars do
|
|
Util.UpdateMounts700(v.Bars[i].Buttons);
|
|
end
|
|
end
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 41;
|
|
end
|
|
|
|
-- v0.9.42
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 42) then
|
|
for k, v in pairs(ButtonForgeGlobalProfiles) do
|
|
for i = 1, #v.Bars do
|
|
v.Bars[i].HSpec3 = false;
|
|
v.Bars[i].HSpec4 = false;
|
|
end
|
|
end
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 42;
|
|
end
|
|
|
|
-- v0.9.44
|
|
if (ButtonForgeGlobalSettings["Version"] == 0.9 and ButtonForgeGlobalSettings["VersionMinor"] < 44) then
|
|
ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"] = not AreDangerousScriptsAllowed();
|
|
ButtonForgeGlobalSettings["VersionMinor"] = 44;
|
|
|
|
for k, v in pairs(ButtonForgeGlobalProfiles) do
|
|
for i = 1, #v.Bars do
|
|
Util.RemoveCancelPossession700(v.Bars[i].Buttons);
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--Bring the global settings up to the latest version
|
|
if (ButtonForgeGlobalSettings["Version"] < Const.Version) then
|
|
ButtonForgeGlobalSettings["Version"] = Const.Version;
|
|
ButtonForgeGlobalSettings["VersionMinor"] = Const.VersionMinor;
|
|
elseif (ButtonForgeGlobalSettings["Version"] == Const.Version and ButtonForgeGlobalSettings["VersionMinor"] < Const.VersionMinor) then
|
|
ButtonForgeGlobalSettings["VersionMinor"] = Const.VersionMinor;
|
|
end
|
|
end
|
|
|
|
|
|
function Util.UpdateMounts602(Buttons)
|
|
Util.UpdateMounts700(Buttons)
|
|
for j = 1, #Buttons do
|
|
if (Buttons[j]["Mode"] == "companion") then
|
|
-- Either fix the mapping, or clear the mount
|
|
local MountID = Util.GetMountIDFromName(Buttons[j]["CompanionName"]);
|
|
|
|
Buttons[j]["Mode"] = nil;
|
|
Buttons[j]["CompanionId"] = nil;
|
|
Buttons[j]["CompanionType"] = nil;
|
|
Buttons[j]["CompanionIndex"] = nil;
|
|
Buttons[j]["CompanionName"] = nil;
|
|
Buttons[j]["CompanionSpellName"] = nil;
|
|
if (Index) then
|
|
Buttons[j]["Mode"] = "mount";
|
|
Buttons[j]["MountID"] = MountID;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Util.UpdateMounts700(Buttons)
|
|
for j = 1, #Buttons do
|
|
if (Buttons[j]["Mode"] == "mount") then
|
|
local MountIndex = Buttons[j]["MountIndex"];
|
|
local MountName = Buttons[j]["MountName"];
|
|
|
|
Buttons[j]["MountID"] = nil;
|
|
Buttons[j]["MountSpellID"] = nil;
|
|
Buttons[j]["MountName"] = nil;
|
|
Buttons[j]["MountIndex"] = nil;
|
|
if (MountIndex == 0) then
|
|
Buttons[j]["MountID"] = Const.SUMMON_RANDOM_FAVORITE_MOUNT_ID;
|
|
else
|
|
local MountID = Util.GetMountIDFromName(MountName);
|
|
if (MountID) then
|
|
Buttons[j]["MountID"] = MountID;
|
|
else
|
|
Buttons[j]["Mode"] = nil;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Util.RemoveCancelPossession700(Buttons)
|
|
for j = 1, #Buttons do
|
|
if (Buttons[j]["Mode"] == "customaction" and Buttons[j]["CustomActionName"] == "possesscancel") then
|
|
Buttons[j]["Mode"] = nil;
|
|
Buttons[j]["CustomActionName"] = nil;
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Load the bars and buttons from the saved addon values
|
|
--]]
|
|
function Util.Load()
|
|
|
|
local CharRealm = UnitName("player");
|
|
CharRealm = CharRealm.."-"..GetRealmName();
|
|
ButtonForgeGlobalBackup[CharRealm] = ButtonForgeSave;
|
|
|
|
Util.ForceOffCastOnKeyDown = ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"];
|
|
if (not Util.ForceOffCastOnKeyDown) then
|
|
hooksecurefunc("SetCVar", MiscFrame.SetCVarCalled);
|
|
end
|
|
if (ButtonForgeSave.ConfigureMode) then
|
|
ConfigureLayer:Show();
|
|
end
|
|
if (ButtonForgeSave.AdvancedMode) then
|
|
UILib.ToggleAdvancedTools();
|
|
end
|
|
--if (Util.LBFMasterGroup and ButtonForgeSave["SkinID"]) then
|
|
-- Util.LBFMasterGroup:Skin(ButtonForgeSave.SkinID, ButtonForgeSave.Gloss, ButtonForgeSave.Backdrop, ButtonForgeSave.Colors);
|
|
--end
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
|
|
end
|
|
UILib.ToggleRightClickSelfCast(ButtonForgeSave["RightClickSelfCast"] or false);
|
|
Util.Loaded = true;
|
|
Util.StartMacroCheckDelay();
|
|
Util.RefreshOnUpdateFunction();
|
|
|
|
SLASH_BUTTONFORGE1 = Util.GetLocaleString("SlashButtonForge1"); -- = "/buttonforge"; --these two identifiers probably shouldn't change, but if need be they can be?!
|
|
SLASH_BUTTONFORGE2 = Util.GetLocaleString("SlashButtonForge2"); -- = "/bufo";
|
|
collectgarbage("collect");
|
|
Util.CallbackEvent("INITIALISED");
|
|
end
|
|
|
|
-- Grabbed from the Lua wiki
|
|
function Util.deepcopy(orig)
|
|
local orig_type = type(orig)
|
|
local copy
|
|
if orig_type == 'table' then
|
|
copy = {}
|
|
for orig_key, orig_value in next, orig, nil do
|
|
copy[Util.deepcopy(orig_key)] = Util.deepcopy(orig_value)
|
|
end
|
|
-- setmetatable(copy, Util.deepcopy(getmetatable(orig))) -- I don't need this specifically for ButtonForge
|
|
else -- number, string, boolean, etc
|
|
copy = orig
|
|
end
|
|
return copy
|
|
end
|
|
|
|
--[[
|
|
Load the bars and buttons from a profile
|
|
--]]
|
|
function Util.LoadProfile(ProfileName)
|
|
if (InCombatLockdown()) then
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
|
|
return;
|
|
end
|
|
if (ButtonForgeGlobalProfiles[string.upper(ProfileName)] == nil) then
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("ProfileNotFound"));
|
|
return;
|
|
end
|
|
|
|
-- 1. Store the current configuration as the revert configuration for this character, in case the players wishes to go back
|
|
ButtonForgeSave.UndoProfileBars = Util.deepcopy(ButtonForgeSave.Bars);
|
|
|
|
-- 2. Deallocate the current UI
|
|
for i = #Util.ActiveBars, 1, -1 do
|
|
Util.DeallocateBar(Util.ActiveBars[i]);
|
|
end
|
|
|
|
-- 3. Apply the profile as the new bars/buttons for this character
|
|
ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeGlobalProfiles[string.upper(ProfileName)].Bars);
|
|
|
|
-- 4. Attach the Bars back to the UI
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
|
|
end
|
|
Util.RefreshCompanions();
|
|
Util.RefreshMacros();
|
|
Util.RefreshEquipmentSets();
|
|
Util.RefreshSpells();
|
|
Util.RefreshGridStatus(true);
|
|
Util.RefreshBarStrata(true);
|
|
Util.RefreshBarGUIStatus();
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("LoadedProfile"), .5, 1, 0, 1);
|
|
end
|
|
|
|
--[[
|
|
Load the bars and buttons from a profile
|
|
--]]
|
|
function Util.LoadProfileTemplate(ProfileName)
|
|
if (InCombatLockdown()) then
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
|
|
return;
|
|
end
|
|
if (ButtonForgeGlobalProfiles[string.upper(ProfileName)] == nil) then
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("ProfileNotFound"));
|
|
return;
|
|
end
|
|
|
|
-- 1. Store the current configuration as the revert configuration for this character, in case the players wishes to go back
|
|
ButtonForgeSave.UndoProfileBars = Util.deepcopy(ButtonForgeSave.Bars);
|
|
|
|
-- 2. Deallocate the current UI
|
|
for i = #Util.ActiveBars, 1, -1 do
|
|
Util.DeallocateBar(Util.ActiveBars[i]);
|
|
end
|
|
|
|
-- 3. Apply the profile as the new bars/buttons for this character
|
|
ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeGlobalProfiles[string.upper(ProfileName)].Bars);
|
|
|
|
-- 4. Attach the Bars back to the UI
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
|
|
end
|
|
|
|
-- 5. Blank all the buttons - this is programatically the easiest way to handle it
|
|
for i = 1, #Util.ActiveButtons do
|
|
if (Util.ActiveButtons[i].Mode ~= "bonusaction") then
|
|
Util.ActiveButtons[i]:SetCommandFromTriplet();
|
|
end
|
|
end
|
|
|
|
Util.RefreshGridStatus(true);
|
|
Util.RefreshBarStrata(true);
|
|
Util.RefreshBarGUIStatus();
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("LoadedProfileTemplate"), .5, 1, 0, 1);
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--[[
|
|
Save the bars and buttons to a profile, NB ProfileName is case insenstive for the purposes of saving loading deleting
|
|
--]]
|
|
function Util.SaveProfile(ProfileName)
|
|
local NewProfile = {};
|
|
NewProfile.Name = ProfileName; -- To capture the case sensitive version
|
|
|
|
-- Record this extra info in case it is useful later, probably wont be but could help keep profiles organised with a future update??
|
|
NewProfile.Icon = "INV_Misc_QuestionMark"; --"Interface/Icons/".. for when/if a gui gets setup it will be good to assign an icon
|
|
NewProfile.Date = date("%c");
|
|
NewProfile.Realm = GetRealmName();
|
|
NewProfile.Char = UnitName("player");
|
|
NewProfile.Class = UnitClass("player");
|
|
|
|
NewProfile.Bars = Util.deepcopy(ButtonForgeSave.Bars)
|
|
ButtonForgeGlobalProfiles[string.upper(ProfileName)] = NewProfile;
|
|
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SavedProfile"), .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
--[[
|
|
-- Lazy, I should've factored this with the save profile function
|
|
|
|
--]]
|
|
function Util.UndoProfile()
|
|
if (InCombatLockdown()) then
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("ActionFailedCombatLockdown"));
|
|
return;
|
|
end
|
|
|
|
if (ButtonForgeSave.UndoProfileBars == nil) then
|
|
return;
|
|
end
|
|
|
|
for i = #Util.ActiveBars, 1, -1 do
|
|
Util.DeallocateBar(Util.ActiveBars[i]);
|
|
end
|
|
|
|
ButtonForgeSave.Bars = Util.deepcopy(ButtonForgeSave.UndoProfileBars);
|
|
|
|
|
|
for i = 1, #ButtonForgeSave.Bars do
|
|
Util.NewBar(0, 0, ButtonForgeSave.Bars[i]);
|
|
end
|
|
Util.RefreshCompanions();
|
|
Util.RefreshMacros();
|
|
Util.RefreshEquipmentSets();
|
|
Util.RefreshSpells();
|
|
Util.RefreshGridStatus(true);
|
|
Util.RefreshBarStrata(true);
|
|
Util.RefreshBarGUIStatus();
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("UndoneProfile"), .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
function Util.DeleteProfile(ProfileName)
|
|
ProfileName = string.upper(ProfileName);
|
|
|
|
if (ButtonForgeGlobalProfiles[ProfileName]) then
|
|
ButtonForgeGlobalProfiles[ProfileName] = nil;
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("DeletedProfile"), .5, 1, 0, 1);
|
|
end
|
|
|
|
-- Some day I may add comfirmations, at least perhaps for the /slash commands... perhaps also a session log?? But when?!
|
|
end
|
|
|
|
|
|
--[[
|
|
Save Button Facade settings if present
|
|
--]]
|
|
function Util:ButtonFacadeCallback(SkinID, Gloss, Backdrop, Group, Button, Colors)
|
|
-- If no group is specified, save the data as the root add-on skin.
|
|
-- This will allow the ButtonFacade GUI to display it correctly.
|
|
return; -- This may longer be necessary
|
|
--[[if not Group then
|
|
ButtonForgeSave["SkinID"] = SkinID;
|
|
ButtonForgeSave["Gloss"] = Gloss;
|
|
ButtonForgeSave["Backdrop"] = Backdrop;
|
|
ButtonForgeSave["Colors"] = Colors;
|
|
else
|
|
--not presently implemented by Button Forge --
|
|
ButtonForgeSave[Group]["SkinID"] = SkinID;
|
|
ButtonForgeSave[Group]["Gloss"] = Gloss;
|
|
ButtonForgeSave[Group]["Backdrop"] = Backdrop;
|
|
ButtonForgeSave[Group]["Colors"] = Colors;
|
|
end]]
|
|
end
|
|
|
|
|
|
--[[
|
|
To allow auto-alignment to also consider the blizzard multibars, this function will create wrappers to go on these bars
|
|
which will also be considered when dragging a Button Forge bar... Since this is possibly a compatibility point, it can be
|
|
hard disabled by a const param, it will also disable in the presence of Bartender which I know it doesn't function properly with
|
|
--]]
|
|
function Util.CreateBlizzardBarWrappers()
|
|
if (IsAddOnLoaded("Bartender4") or Const.DisableAutoAlignAgainstDefaultBars) then
|
|
return;
|
|
end
|
|
|
|
Util.BlizBarWrappers[1] = CreateFrame("FRAME", nil, UIParent);
|
|
Util.BlizBarWrappers[1]:SetPoint("TOPLEFT", MultiBarBottomLeftButton1, "TOPLEFT", -Const.I, Const.I + 1);
|
|
Util.BlizBarWrappers[1]:SetPoint("BOTTOMRIGHT", MultiBarBottomLeftButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
|
|
|
|
Util.BlizBarWrappers[2] = CreateFrame("FRAME", nil, UIParent);
|
|
Util.BlizBarWrappers[2]:SetPoint("TOPLEFT", MultiBarBottomRightButton1, "TOPLEFT", -Const.I, Const.I + 1);
|
|
Util.BlizBarWrappers[2]:SetPoint("BOTTOMRIGHT", MultiBarBottomRightButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
|
|
|
|
Util.BlizBarWrappers[3] = CreateFrame("FRAME", nil, UIParent);
|
|
Util.BlizBarWrappers[3]:SetPoint("TOPLEFT", MultiBarRightButton1, "TOPLEFT", -Const.I, Const.I + 1);
|
|
Util.BlizBarWrappers[3]:SetPoint("BOTTOMRIGHT", MultiBarRightButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
|
|
|
|
Util.BlizBarWrappers[4] = CreateFrame("FRAME", nil, UIParent);
|
|
Util.BlizBarWrappers[4]:SetPoint("TOPLEFT", MultiBarLeftButton1, "TOPLEFT", -Const.I, Const.I + 1);
|
|
Util.BlizBarWrappers[4]:SetPoint("BOTTOMRIGHT", MultiBarLeftButton12, "BOTTOMRIGHT", Const.I, -Const.I + 1);
|
|
|
|
|
|
end
|
|
|
|
function Util.UpdateBlizzardEnabledBarsMap()
|
|
Util.BlizEnabledBars = {GetActionBarToggles()};
|
|
end
|
|
|
|
--[[
|
|
Button Allocation Functions
|
|
--]]
|
|
function Util.NewButton(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
local NewButton;
|
|
if (#(Util.InactiveButtons) > 0) then
|
|
NewButton = table.remove(Util.InactiveButtons);
|
|
NewButton:Configure(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText);
|
|
else
|
|
NewButton = Button.New(Parent, ButtonSave, ButtonLocked, TooltipOn, MacroText, KeyBindText);
|
|
Util.ButtonWidgetMap[NewButton.Widget] = NewButton;
|
|
end
|
|
|
|
table.insert(Util.ActiveButtons, NewButton);
|
|
|
|
Util.CallbackEvent("BUTTON_ALLOCATED", NewButton.Widget:GetName());
|
|
return NewButton;
|
|
end
|
|
|
|
function Util.DeallocateButton(Value)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
Value:Deallocate();
|
|
table.remove(Util.ActiveButtons, Util.FindInTable(Util.ActiveButtons, Value));
|
|
table.insert(Util.InactiveButtons, Value);
|
|
Util.CallbackEvent("BUTTON_DEALLOCATED", Value.Widget:GetName());
|
|
end
|
|
|
|
function Util.DetachButton(Value)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
Value:Detach();
|
|
table.remove(Util.ActiveButtons, Util.FindInTable(Util.ActiveButtons, Value));
|
|
table.insert(Util.InactiveButtons, Value);
|
|
Util.CallbackEvent("BUTTON_DEALLOCATED", Value.Widget:GetName());
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
Bar Allocation Functions
|
|
--]]
|
|
function Util.NewBarSave()
|
|
local Save = {};
|
|
Save["Left"] = 0;
|
|
Save["Top"] = 0;
|
|
Save["Scale"] = 1;
|
|
Save["Order"] = #Util.ActiveBars;
|
|
Save["Label"] = nil;
|
|
Save["Rows"] = Const.DefaultRows;
|
|
Save["Cols"] = Const.DefaultCols;
|
|
Save["VDriver"] = nil;
|
|
Save["HVehicle"] = true;
|
|
Save["HSpec1"] = false;
|
|
Save["HSpec2"] = false;
|
|
Save["HSpec3"] = false;
|
|
Save["HSpec4"] = false;
|
|
Save["HBonusBar"] = true;
|
|
Save["GridAlwaysOn"] = true;
|
|
Save["ButtonsLocked"] = false;
|
|
Save["TooltipsOn"] = true;
|
|
Save["MacroText"] = true;
|
|
Save["KeyBindText"] = true;
|
|
Save["ButtonGap"] = 6;
|
|
Save["Enabled"] = true;
|
|
Save["BonusBar"] = false;
|
|
Save["GUI"] = true;
|
|
Save["Alpha"] = 1;
|
|
Save["Buttons"] = {};
|
|
|
|
return Save;
|
|
end
|
|
|
|
function Util.NewBar(Left, Top, BarSave)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
local NewBar;
|
|
|
|
if (not BarSave) then
|
|
BarSave = Util.NewBarSave();
|
|
BarSave["Left"] = Left;
|
|
BarSave["Top"] = Top;
|
|
if (ButtonForgeSave.Bars == nil) then
|
|
ButtonForgeSave.Bars = {};
|
|
end;
|
|
table.insert(ButtonForgeSave.Bars, BarSave);
|
|
PlaySound(177, "Master");
|
|
end
|
|
|
|
if (#(Util.InactiveBars) > 0) then
|
|
NewBar = table.remove(Util.InactiveBars);
|
|
NewBar:Configure(BarSave);
|
|
else
|
|
NewBar = Bar.New(BarSave);
|
|
end
|
|
|
|
table.insert(Util.ActiveBars, NewBar);
|
|
if (NewBar.Cols * NewBar.Rows == 0) then
|
|
--Failed to allocate buttons, get rid of the bar
|
|
NewBar:Deallocate();
|
|
return nil;
|
|
else
|
|
Util.RefreshTab(NewBar.ControlFrame:GetLeft(), NewBar.ControlFrame:GetTop());
|
|
return NewBar;
|
|
end
|
|
end
|
|
|
|
function Util.NewBonusBar(Left, Top)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
local BarSave = Util.NewBarSave();
|
|
BarSave["BonusBar"] = true;
|
|
BarSave["Left"] = Left;
|
|
BarSave["Top"] = Top;
|
|
BarSave["Rows"] = 1;
|
|
BarSave["Cols"] = 13;
|
|
BarSave["HBonusBar"] = false;
|
|
BarSave["HVehicle"] = false;
|
|
BarSave["VDriver"] = "[overridebar][vehicleui] show; hide";
|
|
BarSave["ButtonsLocked"] = true;
|
|
BarSave["GridAlwaysOn"] = false;
|
|
if (ButtonForgeSave.Bars == nil) then
|
|
ButtonForgeSave.Bars = {};
|
|
end;
|
|
table.insert(ButtonForgeSave.Bars, BarSave);
|
|
PlaySound(177, "Master");
|
|
return Util.NewBar(Left, Top, BarSave);
|
|
end
|
|
|
|
function Util.DeallocateBar(Value)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
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)
|
|
table.remove(Util.ActiveBars, Util.FindInTable(Util.ActiveBars, Value));
|
|
table.remove(ButtonForgeSave.Bars, Util.FindInTable(ButtonForgeSave.Bars, Value.BarSave));
|
|
table.insert(Util.InactiveBars, Value);
|
|
local Left, Top = Value.ControlFrame:GetLeft(), Value.ControlFrame:GetTop();
|
|
Util.RefreshTab(Left, Top);
|
|
PlaySound(6523, "Master");
|
|
end
|
|
|
|
function Util.DetachBar(Value)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
Value:Detach();
|
|
table.remove(Util.ActiveBars, Util.FindInTable(Util.ActiveBars, Value));
|
|
table.insert(Util.InactiveBars, Value);
|
|
local Left, Top = Value.ControlFrame:GetLeft(), Value.ControlFrame:GetTop();
|
|
Util.RefreshTab(Left, Top);
|
|
end
|
|
|
|
function Util.GetButtonFrameName(Label)
|
|
|
|
Label = Label or "";
|
|
local Name = Const.BarNaming.."Bar_"..(Label or "");
|
|
if (not _G[Name.."_ButtonFrame"] and Label ~= "") then
|
|
return Name.."_ButtonFrame";
|
|
end
|
|
|
|
while true do
|
|
if (not _G[Name..Const.BarSeq.."_ButtonFrame"]) then
|
|
return Name..Const.BarSeq.."_ButtonFrame";
|
|
end
|
|
Const.BarSeq = Const.BarSeq + 1;
|
|
end
|
|
end
|
|
|
|
|
|
--[[
|
|
Bar Management Functions
|
|
--]]
|
|
function Util.ReorderBar(Bar, NewPosition)
|
|
local CurrentPosition = Bar.BarSave["Order"];
|
|
local Order;
|
|
if (CurrentPosition > NewPosition) then
|
|
for i = 1, #Util.ActiveBars do
|
|
Order = Util.ActiveBars[i].BarSave["Order"];
|
|
if (Order < CurrentPosition and Order >= NewPosition) then
|
|
Util.ActiveBars[i]:SetOrder(Order + 1);
|
|
end
|
|
end
|
|
elseif (CurrentPosition < NewPosition) then
|
|
for i = 1, #Util.ActiveBars do
|
|
Order = Util.ActiveBars[i].BarSave["Order"];
|
|
if (Order > CurrentPosition and Order <= NewPosition) then
|
|
Util.ActiveBars[i]:SetOrder(Order - 1);
|
|
end
|
|
end
|
|
end
|
|
Bar:SetOrder(NewPosition);
|
|
end
|
|
|
|
function Util.DockCoords(Left, Top, ExcludeBar)
|
|
local CLeft, CTop, CDist, CBar = 0, 0, 100000000, nil; --This is an arbitrary number that will be big enough here
|
|
local Dist, X, Y;
|
|
local Bars = Util.ActiveBars;
|
|
for i = 1, #Bars do
|
|
X = Bars[i].ControlFrame:GetLeft();--BarSave["Left"];
|
|
Y = Bars[i].ControlFrame:GetTop();--BarSave["Top"];
|
|
Dist = ((Left - X) ^ 2)+ ((Top - Y) ^ 2);
|
|
if (Dist < CDist and Bars[i] ~= ExcludeBar) then
|
|
CLeft = X;
|
|
CTop = Y;
|
|
CDist = Dist;
|
|
CBar = Bars[i];
|
|
end
|
|
end
|
|
return CLeft, CTop, CDist, CBar;
|
|
end
|
|
|
|
|
|
|
|
|
|
function Util.FindClosestPoint(Coord, Points, Offsets, ExcludeBar)
|
|
local MatchedBar, MatchedPoint, Shift, MatchedCoord = nil, 0, 0, 0;
|
|
local Calc, CalcCoord, MinCalc = 0, 0, 10000000;
|
|
local Bars = Util.ActiveBars;
|
|
for i = 1, #Bars do
|
|
if (Bars[i] ~= ExcludeBar) then
|
|
for j = 1, #Points do
|
|
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"
|
|
Calc = CalcCoord - Coord;
|
|
Calc = Calc * Calc;
|
|
if (Calc < MinCalc - 0.1) then
|
|
MinCalc = Calc;
|
|
MatchedCoord = CalcCoord;
|
|
Shift = CalcCoord - Coord;
|
|
MatchedBar = Bars[i].ControlFrame;
|
|
MatchedPoint = j;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Bars = Util.BlizBarWrappers;
|
|
local EnabledBars = Util.BlizEnabledBars;
|
|
for i = 1, #Bars do
|
|
if (EnabledBars[i]) then
|
|
for j = 1, #Points do
|
|
CalcCoord = Bars[i][Points[j]](Bars[i]);
|
|
if (not CalcCoord) then
|
|
Util.BlizEnabledBars[i] = false;
|
|
break;
|
|
else
|
|
CalcCoord = CalcCoord + Offsets[j]; --basically translates down to things like Bars[i]:GetLeft() + Offset[j]; if Points[j] is "GetLeft"
|
|
Calc = CalcCoord - Coord;
|
|
Calc = Calc * Calc;
|
|
if (Calc < MinCalc - 0.1) then
|
|
MinCalc = Calc;
|
|
MatchedCoord = CalcCoord;
|
|
Shift = CalcCoord - Coord;
|
|
MatchedBar = Bars[i];
|
|
MatchedPoint = j;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return MatchedBar, MatchedPoint, MinCalc, Shift, MatchedCoord;
|
|
end
|
|
|
|
--[[ 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 --]]
|
|
function Util.VDriverOverride()
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
local Bars = Util.ActiveBars;
|
|
if (ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown()) then
|
|
for i = 1, #Bars do
|
|
Bars[i]:SetTempShowVD();
|
|
end
|
|
else
|
|
for i = 1, #Bars do
|
|
Bars[i]:ClearTempShowVD();
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--[[ Since the Spellbook has an annoying tendancy to cover bars this function will raise (or relower) the buttons to so they can be clicked
|
|
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)
|
|
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!)
|
|
--]]
|
|
function Util.RefreshBarStrata(ForceUpdate)
|
|
local LowStrata = Util.InCombat or DestroyBarOverlay:IsShown() or (GetCursorInfo() == "item" and not IsShiftKeyDown()) or not Util.CursorAction;
|
|
if (LowStrata ~= Util.LowStrata or ForceUpdate) then
|
|
Util.LowStrata = LowStrata;
|
|
local Bars = Util.ActiveBars;
|
|
if (LowStrata) then
|
|
for i = 1, #Bars do
|
|
Bars[i].ButtonFrame:SetFrameStrata("LOW");
|
|
Bars[i]:SetOrder(); --without a param this will cause a refresh (just in case moving the strata causes the level to change)
|
|
end
|
|
else
|
|
for i = 1, #Bars do
|
|
Bars[i].ButtonFrame:SetFrameStrata("DIALOG");
|
|
Bars[i]:SetOrder(); --without a param this will cause a refresh (just in case moving the strata causes the level to change)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function Util.RefreshGridStatus(ForceUpdate)
|
|
local Hide = Util.InCombat or not (Util.CursorAction or ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown());
|
|
if (Hide ~= Util.GridHidden or ForceUpdate) then
|
|
Util.GridHidden = Hide;
|
|
local Bars = Util.ActiveBars;
|
|
if (Hide) then
|
|
for i = 1, #Bars do
|
|
if (not Bars[i].BarSave["GridAlwaysOn"]) then
|
|
Bars[i]:GridHide();
|
|
end
|
|
end
|
|
else
|
|
for i = 1, #Bars do
|
|
if (not Bars[i].BarSave["GridAlwaysOn"]) then
|
|
Bars[i]:GridShow();
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Util.RefreshBarGUIStatus()
|
|
local BarGUIForceOn = (not Util.InCombat) and (ConfigureLayer:IsShown() or DestroyBarOverlay:IsShown() or (IsShiftKeyDown() and Util.CursorAction));
|
|
local Bars = Util.ActiveBars;
|
|
if (BarGUIForceOn) then
|
|
for i = 1, #Bars do
|
|
|
|
Bars[i]:GUIOn();
|
|
end
|
|
else
|
|
for i = 1, #Bars do
|
|
if (not Bars[i].BarSave["GUI"]) then
|
|
Bars[i]:GUIOff();
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function Util.SetControlFrameAlphas(Alpha)
|
|
local Bars = Util.ActiveBars;
|
|
|
|
for i = 1, #Bars do
|
|
Bars[i].ControlFrame:SetAlpha(Alpha);
|
|
end
|
|
|
|
end
|
|
|
|
function Util.RefreshTab(Left, Top)
|
|
|
|
local Count = 0;
|
|
local Bar;
|
|
local StackedBar;
|
|
local Label;
|
|
for i = 1, #Util.ActiveBars do
|
|
Bar = Util.ActiveBars[i];
|
|
|
|
if (math.abs(Bar.ControlFrame:GetLeft() - Left) < 0.01 and math.abs(Bar.ControlFrame:GetTop() - Top) < 0.01) then
|
|
Count = Count + 1;
|
|
StackedBar = Bar;
|
|
end
|
|
end
|
|
|
|
if (Count == 0) then
|
|
return;
|
|
end
|
|
if (Count == 1) then
|
|
--Set it's label back in and dealloc the tabframe
|
|
StackedBar.Tabbed = false;
|
|
Label = StackedBar.LabelFrame;
|
|
Label:ClearAllPoints();
|
|
Label:SetPoint("TOPLEFT", StackedBar.TopIconsFrame, "TOPLEFT", Const.BarInset, -Const.BarEdge); --Const.MiniIconSize + Const.MiniIconGap +Const.BarEdge, -Const.BarEdge);
|
|
Label:SetBackdropColor(0, 0, 0, 1);
|
|
Label:SetAlpha(1);
|
|
Label:EnableMouse(false);
|
|
Label:SetScript("OnMouseDown", nil);
|
|
Label:SetScript("OnEnter", nil);
|
|
Label:SetScript("OnLeave", nil);
|
|
Util.DeallocateTab(Left, Top);
|
|
StackedBar:ReflowUI();
|
|
return;
|
|
end
|
|
|
|
local Offset = 0;
|
|
local HighestBar;
|
|
local TabFrame = Util.GetTabFrame(Left, Top);
|
|
for i = 1, #Util.ActiveBars do
|
|
Bar = Util.ActiveBars[i];
|
|
if (math.abs(Bar.ControlFrame:GetLeft() - Left) < 0.01 and math.abs(Bar.ControlFrame:GetTop() - Top) < 0.01) then
|
|
if (not HighestBar) then
|
|
--anchor tabframe
|
|
HighestBar = Bar;
|
|
TabFrame:ClearAllPoints();
|
|
TabFrame:SetPoint("TOPLEFT", Bar.ControlFrame, "TOPLEFT", 0, Const.MiniIconSize);
|
|
elseif (HighestBar.BarSave["Order"] < Bar.BarSave["Order"]) then
|
|
HighestBar = Bar;
|
|
end
|
|
Bar.Tabbed = true;
|
|
Label = Bar.LabelFrame;
|
|
Label:ClearAllPoints();
|
|
Label:SetPoint("TOPLEFT", TabFrame, "TOPLEFT", Offset, 0);
|
|
Label:SetBackdropColor(0, 0, 0, 1);
|
|
Label:SetAlpha(.5);
|
|
Label:EnableMouse(true);
|
|
Label:SetScript("OnMouseDown", Bar.SendToFront);
|
|
Label:SetScript("OnEnter", Bar.LabelOnEnter);
|
|
Label:SetScript("OnLeave", Bar.LabelOnLeave);
|
|
if (Label:GetWidth() > 4.5) then
|
|
Offset = Offset + Label:GetWidth();
|
|
end
|
|
Bar:ReflowUI();
|
|
end
|
|
end
|
|
TabFrame:SetSize(Offset, Const.MiniIconSize);
|
|
Label = HighestBar.LabelFrame;
|
|
Label:SetAlpha(1);
|
|
--Label:SetScript("OnMouseDown", nil);
|
|
Label:SetScript("OnEnter", nil);
|
|
Label:SetScript("OnLeave", nil);
|
|
end
|
|
|
|
function Util.DeallocateTab(Left, Top)
|
|
if (Util.ActiveTabs[Left.." "..Top]) then
|
|
table.insert(Util.InactiveTabs, Util.ActiveTabs[Left.." "..Top]);
|
|
Util.ActiveTabs[Left.." "..Top] = nil;
|
|
end
|
|
end
|
|
|
|
function Util.GetTabFrame(Left, Top)
|
|
if (not Util.ActiveTabs[Left.." "..Top]) then
|
|
if (#Util.InactiveTabs > 0) then
|
|
Util.ActiveTabs[Left.." "..Top] = table.remove(Util.InactiveTabs);
|
|
else
|
|
Util.ActiveTabs[Left.." "..Top] = CreateFrame("FRAME", nil, ConfigureLayer);
|
|
Util.ActiveTabs[Left.." "..Top]:SetSize(1, 1);
|
|
Util.ActiveTabs[Left.." "..Top]:SetClampedToScreen(true);
|
|
end
|
|
end
|
|
return Util.ActiveTabs[Left.." "..Top];
|
|
end
|
|
|
|
function Util.BarHasButton(Bar, Command, Data, Subvalue)
|
|
local BCommand, BData, BSubvalue
|
|
for i = 1, #Bar.Buttons do
|
|
BCommand, BData, BSubvalue = Bar.Buttons[i]:GetCursor();
|
|
if (Command == BCommand and Data == BData and Subvalue == BSubvalue) then
|
|
return true;
|
|
end
|
|
end
|
|
return false;
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
Helper functions
|
|
--]]
|
|
function Util.FindInTable(Table, Value, Start)
|
|
for i = Start or 1, #Table do
|
|
if (Table[i] == Value) then
|
|
return i;
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
function Util.GetLocaleString(Value)
|
|
return Locale[Value];
|
|
end
|
|
|
|
function Util.GetLocaleEnabledDisabled(Value)
|
|
if (Value) then
|
|
return Locale["Enabled"];
|
|
else
|
|
return Locale["Disabled"];
|
|
end
|
|
end
|
|
|
|
function Util.CastBool(Value)
|
|
return Locale.BoolTable[strlower(Value or '')];
|
|
end
|
|
|
|
function Util.ProcessSlashCommandParams(Command, Params)
|
|
Params = Params or "";
|
|
if (Const.SlashCommands[Command].params == "bool") then
|
|
local Bool = Util.CastBool(Params, "^%s*(%w*)%s*$");
|
|
if (Bool == nil) then
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..Command.." "..Params, .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
return {Bool};
|
|
else
|
|
local Values = {string.match(Params, Const.SlashCommands[Command].params)};
|
|
if (Values[1] == nil) then
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..Command.." "..Params, .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
return Values;
|
|
end
|
|
|
|
end
|
|
|
|
--[[Unused function for allowing a more... ]]--
|
|
local SlashRemainingMessage = '';
|
|
function Util.SlashShowRemainingMessage()
|
|
local Display, Remainder = string.match(SlashRemainingMessage, "^("..strrep(".-\n", Const.SlashNumLines-1)..".-)\n(.-)$");
|
|
if (Display) then
|
|
SlashRemainingMessage = Remainder;
|
|
else
|
|
Display = SlashRemainingMessage;
|
|
SlashRemainingMessage = '';
|
|
end
|
|
DEFAULT_CHAT_FRAME:AddMessage(' '..Display, .5, 1, 0, 1);
|
|
end
|
|
|
|
|
|
function Util.SlashShowMessageByLine(Message)
|
|
for Line in string.gmatch(Message, '([^\n]*)') do
|
|
DEFAULT_CHAT_FRAME:AddMessage(Line, .5, 1, 0, 1);
|
|
end
|
|
end
|
|
|
|
function SlashCmdList.BUTTONFORGE(msg, editbox)
|
|
local PreparedCommands = {};
|
|
local Command, Params;
|
|
local Count = 0;
|
|
Params = '';
|
|
for Token, Space in string.gmatch(msg, '([^%s]+)([%s]*)') do
|
|
if (Const.SlashCommands[strlower(Token)]) then
|
|
if (Command) then
|
|
Count = Count + 1;
|
|
--PreparedCommands["Count"] = Count;
|
|
PreparedCommands[Command] = Util.ProcessSlashCommandParams(Command, Params);
|
|
|
|
if (PreparedCommands[Command] == nil) then
|
|
return;
|
|
end
|
|
end
|
|
Command = strlower(Token);
|
|
Params = '';
|
|
elseif (string.match(Token, '^-') == '-') then
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashCommandNotRecognised")..Token, .5, 1, 0, 1);
|
|
return;
|
|
else
|
|
Params = Params..Token..Space;
|
|
end
|
|
end
|
|
if (Command) then
|
|
Count = Count + 1;
|
|
--PreparedCommands["Count"] = Count;
|
|
PreparedCommands[Command] = Util.ProcessSlashCommandParams(Command, Params);
|
|
if (PreparedCommands[Command] == nil) then
|
|
return;
|
|
end
|
|
|
|
local Bars = Util.ActiveBars;
|
|
local Commands = PreparedCommands;
|
|
|
|
-- Check the constraint rules
|
|
-- 1. Only 1 group is allowed
|
|
-- 2. A rules required's must be present
|
|
-- 3. A rules exclusions must not be present
|
|
local Group;
|
|
local FirstCommand;
|
|
for k, v in pairs(Commands) do
|
|
FirstCommand = FirstCommand or k;
|
|
if (Group ~= nil and Group ~= Const.SlashCommands[k].group) then
|
|
-- must be the same group
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandIncompatible"), "<COMMANDA>", FirstCommand), "<COMMANDB>", k), .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
Group = Const.SlashCommands[k].group;
|
|
|
|
local Requires = Const.SlashCommands[k].requires;
|
|
if (Requires) then
|
|
for k1, v1 in pairs(Requires) do
|
|
if (Commands[v1] == nil) then
|
|
-- Missing a required command
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandRequired"), "<COMMANDA>", k), "<COMMANDB>", v1), .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
|
|
local Incompat = Const.SlashCommands[k].incompat;
|
|
if (Incompat) then
|
|
for k1, v1 in pairs(Incompat) do
|
|
if (Commands[v1]) then
|
|
-- Incompatible command present
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.gsub(string.gsub(Util.GetLocaleString("SlashCommandIncompatible"), "<COMMANDA>", k), "<COMMANDB>", v1), .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
if (v1 == "ALL" and Count > 1) then
|
|
-- Only 1 command would be allowed
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.gsub(Util.GetLocaleString("SlashCommandAlone"), "<COMMANDA>", k), .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local Validate = Const.SlashCommands[k].validate;
|
|
if (Validate) then
|
|
if (not Validate(unpack(v))) then
|
|
-- Validate function failed
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashParamsInvalid")..k.." "..table.concat(v, " "), .5, 1, 0, 1);
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
|
|
if (Group == "bar") then
|
|
if (Commands["-createbar"]) then
|
|
Util.ApplySlashCommands(Commands);
|
|
else
|
|
local BarName;
|
|
if (Commands["-bar"]) then
|
|
BarName = Commands["-bar"][1];
|
|
elseif (Commands["-destroybar"]) then
|
|
BarName = Commands["-destroybar"][1];
|
|
end
|
|
for i = 1, #Bars do
|
|
if ((not BarName) or strlower(BarName) == strlower(Bars[i].BarSave["Label"])) then
|
|
Util.ApplySlashCommands(Commands, Bars[i]);
|
|
end
|
|
end
|
|
end
|
|
else
|
|
Util.ApplySlashCommands(Commands);
|
|
end
|
|
|
|
else
|
|
Util.SlashShowMessageByLine(Util.GetLocaleString("SlashHelpFormatted")); --]]
|
|
end
|
|
|
|
end
|
|
|
|
|
|
function Util.ApplySlashCommands(Commands, Bar)
|
|
if (Commands["-createbar"]) then
|
|
Bar = Util.NewBar(0, 0);
|
|
if (Bar == nil) then
|
|
DEFAULT_CHAT_FRAME:AddMessage(Util.GetLocaleString("SlashCreateBarFailed"), .5, 1, 0, 1);
|
|
return
|
|
end
|
|
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
|
|
end
|
|
|
|
if (Commands["-destroybar"]) then
|
|
Util.DeallocateBar(Bar);
|
|
end
|
|
|
|
if (Commands["-macrotext"]) then
|
|
Bar:SetMacroText(Commands["-macrotext"][1]);
|
|
end
|
|
|
|
if (Commands["-keybindtext"]) then
|
|
Bar:SetKeyBindText(Commands["-keybindtext"][1]);
|
|
end
|
|
|
|
if (Commands["-tooltips"]) then
|
|
Bar:SetTooltips(Commands["-tooltips"][1]);
|
|
end
|
|
|
|
if (Commands["-emptybuttons"]) then
|
|
Bar:SetGridAlwaysOn(Commands["-emptybuttons"][1]);
|
|
end
|
|
|
|
if (Commands["-lockbuttons"]) then
|
|
Bar:SetButtonsLocked(Commands["-lockbuttons"][1]);
|
|
end
|
|
|
|
if (Commands["-scale"]) then
|
|
Bar:SetScale(tonumber(Commands["-scale"][1]));
|
|
end
|
|
|
|
if (Commands["-rows"]) then
|
|
Bar:SetNumButtons(Bar.BarSave["Cols"], tonumber(Commands["-rows"][1]));
|
|
end
|
|
|
|
if (Commands["-cols"]) then
|
|
Bar:SetNumButtons(tonumber(Commands["-cols"][1]), Bar.BarSave["Rows"]);
|
|
end
|
|
|
|
if (Commands["-coords"]) then
|
|
Bar:SetPosition(tonumber(Commands["-coords"][1]), tonumber(Commands["-coords"][2]));
|
|
end
|
|
|
|
if (Commands["-rename"]) then
|
|
Bar:SetLabel(Commands["-rename"][1]);
|
|
end
|
|
|
|
if (Commands["-hidespec1"]) then
|
|
Bar:SetHSpec1(Commands["-hidespec1"][1]);
|
|
end
|
|
|
|
if (Commands["-hidespec2"]) then
|
|
Bar:SetHSpec2(Commands["-hidespec2"][1]);
|
|
end
|
|
|
|
if (Commands["-hidespec3"]) then
|
|
Bar:SetHSpec3(Commands["-hidespec3"][1]);
|
|
end
|
|
|
|
if (Commands["-hidespec4"]) then
|
|
Bar:SetHSpec4(Commands["-hidespec4"][1]);
|
|
end
|
|
|
|
if (Commands["-hidevehicle"]) then
|
|
Bar:SetHVehicle(Commands["-hidevehicle"][1]);
|
|
end
|
|
|
|
if (Commands["-hideoverridebar"]) then
|
|
Bar:SetHBonusBar(Commands["-hideoverridebar"][1]);
|
|
end
|
|
|
|
if (Commands["-vismacro"]) then
|
|
Bar:SetVD(Commands["-vismacro"][1]);
|
|
end
|
|
|
|
if (Commands["-gui"]) then
|
|
Bar:SetGUI(Commands["-gui"][1]);
|
|
end
|
|
|
|
if (Commands["-alpha"]) then
|
|
Bar:SetAlpha(tonumber(Commands["-alpha"][1]));
|
|
end
|
|
|
|
if (Commands["-enabled"]) then
|
|
Bar:SetEnabled(Commands["-enabled"][1]);
|
|
end
|
|
|
|
if (Commands["-gap"]) then
|
|
Bar:SetButtonGap(tonumber(Commands["-gap"][1]));
|
|
end
|
|
|
|
if (Commands["-info"]) then
|
|
--print out the bar info's
|
|
local String = Util.GetLocaleString("InfoLabel")..": "..(Bar:GetLabel() or "").."\n"..
|
|
Util.GetLocaleString("InfoRowsCols")..": "..select(3, Bar:GetNumButtons()).."\n"..
|
|
Util.GetLocaleString("InfoScale")..": "..Bar:GetScale().."\n"..
|
|
Util.GetLocaleString("InfoGap")..": "..Bar:GetButtonGap().."\n"..
|
|
Util.GetLocaleString("InfoCoords")..": "..select(3, Bar:GetPosition()).."\n"..
|
|
Util.GetLocaleString("InfoTooltips")..": "..select(2, Bar:GetTooltips()).."\n"..
|
|
Util.GetLocaleString("InfoEmptyGrid")..": "..select(2, Bar:GetGridAlwaysOn()).."\n"..
|
|
Util.GetLocaleString("InfoLock")..": "..select(2, Bar:GetButtonsLocked()).."\n"..
|
|
Util.GetLocaleString("InfoMacroText")..": "..select(2, Bar:GetMacroText()).."\n"..
|
|
Util.GetLocaleString("InfoKeybindText")..": "..select(2, Bar:GetKeyBindText()).."\n"..
|
|
Util.GetLocaleString("InfoHSpec1")..": "..select(2, Bar:GetHSpec1()).."\n"..
|
|
Util.GetLocaleString("InfoHSpec2")..": "..select(2, Bar:GetHSpec2()).."\n"..
|
|
Util.GetLocaleString("InfoHSpec3")..": "..select(2, Bar:GetHSpec3()).."\n"..
|
|
Util.GetLocaleString("InfoHSpec4")..": "..select(2, Bar:GetHSpec4()).."\n"..
|
|
Util.GetLocaleString("InfoHVehicle")..": "..select(2, Bar:GetHVehicle()).."\n"..
|
|
Util.GetLocaleString("InfoHBonusBar5")..": "..select(2, Bar:GetHBonusBar()).."\n"..
|
|
Util.GetLocaleString("InfoVisibilityMacro")..": "..(Bar:GetVD() or "").."\n"..
|
|
Util.GetLocaleString("InfoGUI")..": "..select(2, Bar:GetGUI()).."\n"..
|
|
Util.GetLocaleString("InfoAlpha")..": "..Bar:GetAlpha().."\n"..
|
|
Util.GetLocaleString("InfoEnabled")..": "..select(2, Bar:GetEnabled());
|
|
|
|
Util.SlashShowMessageByLine(String);
|
|
|
|
end
|
|
|
|
if (Commands["-technicalinfo"]) then
|
|
--print out technical info for the bar
|
|
local String = Util.GetLocaleString("InfoButtonFrameName")..": "..Bar.ButtonFrame:GetName();
|
|
Util.SlashShowMessageByLine(String);
|
|
end
|
|
|
|
|
|
if (Commands["-saveprofile"]) then
|
|
Util.SaveProfile(Commands["-saveprofile"][1]);
|
|
end
|
|
|
|
if (Commands["-loadprofile"]) then
|
|
Util.LoadProfile(Commands["-loadprofile"][1]);
|
|
end
|
|
|
|
if (Commands["-loadprofiletemplate"]) then
|
|
Util.LoadProfileTemplate(Commands["-loadprofiletemplate"][1]);
|
|
end
|
|
|
|
if (Commands["-undoprofile"]) then
|
|
Util.UndoProfile();
|
|
end
|
|
|
|
if (Commands["-listprofiles"]) then
|
|
local String = Util.GetLocaleString("BFProfiles").."\n---------------------\n";
|
|
for k,v in pairs(ButtonForgeGlobalProfiles) do
|
|
String = String..v.Name.."\n";
|
|
end
|
|
String = String.."---------------------\n";
|
|
Util.SlashShowMessageByLine(String);
|
|
end
|
|
|
|
if (Commands["-deleteprofile"]) then
|
|
Util.DeleteProfile(Commands["-deleteprofile"][1]);
|
|
end
|
|
|
|
if (Commands["-macrocheckdelay"]) then
|
|
ButtonForgeGlobalSettings["MacroCheckDelay"] = tonumber(Commands["-macrocheckdelay"][1]);
|
|
end
|
|
|
|
if (Commands["-removemissingmacros"]) then
|
|
ButtonForgeGlobalSettings["RemoveMissingMacros"] = Commands["-removemissingmacros"][1];
|
|
end
|
|
|
|
if (Commands["-forceoffcastonkeydown"]) then
|
|
ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"] = Commands["-forceoffcastonkeydown"][1];
|
|
end
|
|
|
|
if (Commands["-usecollectionsfavoritemountbutton"]) then
|
|
ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"] = Commands["-usecollectionsfavoritemountbutton"][1];
|
|
end
|
|
|
|
|
|
if (Commands["-globalsettings"]) then
|
|
--print out what the global settings for Button Forge are
|
|
local String = Util.GetLocaleString("InfoMacroCheckDelay")..": "..ButtonForgeGlobalSettings["MacroCheckDelay"].."\n"..
|
|
Util.GetLocaleString("InfoRemoveMissingMacros")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["RemoveMissingMacros"]).."\n"..
|
|
Util.GetLocaleString("InfoForceOffCastOnKeyDown")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["ForceOffCastOnKeyDown"]).."\n"..
|
|
Util.GetLocaleString("InfoUseCollectionsFavoriteMountButton")..": "..Util.GetLocaleEnabledDisabled(ButtonForgeGlobalSettings["UseCollectionsFavoriteMountButton"]);
|
|
|
|
Util.SlashShowMessageByLine(String);
|
|
end
|
|
|
|
end
|
|
|
|
--[[ Store cursor type info for later use --]]
|
|
function Util.StoreCursor(Command, Data, Subvalue, Subsubvalue)
|
|
Util.Command = Command;
|
|
Util.Data = Data;
|
|
Util.Subvalue = Subvalue;
|
|
Util.Subsubvalue = Subsubvalue
|
|
end
|
|
|
|
function Util.GetStoredCursor()
|
|
return Util.Command, Util.Data, Util.Subvalue, Util.Subsubvalue;
|
|
end
|
|
|
|
--[[ Set the cursor based on the triplet passed in --]]
|
|
function Util.SetCursor(Command, Data, Subvalue, Subsubvalue)
|
|
ClearCursor();
|
|
UILib.StopDraggingIcon();
|
|
-- SpellFlyout:Hide();
|
|
if (Command == "spell") then
|
|
PickupSpell(Subsubvalue);
|
|
elseif (Command == "item") then
|
|
PickupItem(Data);
|
|
elseif (Command == "macro") then
|
|
PickupMacro(Data);
|
|
elseif (Command == "mount") then
|
|
--if (Subvalue == nil) then
|
|
-- Data = Util.GetMountIndexFromUselessIndex(Data);
|
|
--end
|
|
C_MountJournal.Pickup(Util.GetMountIndexFromMountID(Data));
|
|
elseif (Command == "equipmentset") then
|
|
local SetCount = C_EquipmentSet.GetNumEquipmentSets();
|
|
for i=0,SetCount-1 do
|
|
name, _, setIndex = C_EquipmentSet.GetEquipmentSetInfo(i);
|
|
if (name == Data) then
|
|
C_EquipmentSet.PickupEquipmentSet(setIndex);
|
|
break;
|
|
end
|
|
end;
|
|
elseif (Command == "bonusaction") then
|
|
local page = 12; --The page for vehicleactionbar
|
|
if (HasOverrideActionBar()) then
|
|
page = 14;
|
|
end
|
|
local Texture = GetActionTexture(Data + ((page - 1) * 12));
|
|
if (Texture and (HasOverrideActionBar() or HasVehicleActionBar())) then
|
|
UILib.StartDraggingIcon(Texture, 23, 23, "bonusaction", Data);
|
|
else
|
|
UILib.StartDraggingIcon(Const.ImagesDir.."Bonus"..Data, 23, 23, "bonusaction", Data);
|
|
end
|
|
elseif (Command == "flyout") then
|
|
local ind, booktype = Util.LookupSpellIndex("FLYOUT"..Data);
|
|
if (ind) then
|
|
PickupSpellBookItem(ind, booktype);
|
|
end
|
|
elseif (Command == "customaction") then
|
|
CustomAction.SetCursor(Data);
|
|
end
|
|
end
|
|
|
|
--[[ These two functions will take care of non secure gui updates when the player enters or exits combat ]]--
|
|
function Util.PreCombatStateUpdate()
|
|
Util.InCombat = true;
|
|
Util.RefreshGridStatus();
|
|
Util.RefreshBarStrata(); --Im surprised that these refreshes dont lead to taint, I must be forgetting something??!
|
|
UILib.ToggleCreateBarMode(true);
|
|
UILib.ToggleDestroyBarMode(true);
|
|
Util.RefreshBarGUIStatus();
|
|
end
|
|
|
|
function Util.PostCombatStateUpdate()
|
|
Util.InCombat = false;
|
|
Util.VDriverOverride();
|
|
Util.RefreshGridStatus();
|
|
Util.RefreshBarStrata();
|
|
Util.RefreshBarGUIStatus();
|
|
|
|
if (Util.DelayedRefreshMacros) then
|
|
Util.RefreshMacros();
|
|
Util.DelayedRefreshMacros = nil;
|
|
end
|
|
if (Util.DelayedUpdateButtonClickHandling) then
|
|
Util.UpdateButtonClickHandling();
|
|
Util.DelayedUpdateButtonClickHandling = nil;
|
|
end
|
|
if (Util.DelayedPromoteSpells) then
|
|
Util.PromoteSpells();
|
|
Util.DelayedPromoteSpells = nil;
|
|
end
|
|
if (Util.DelayedRefreshCompanions) then
|
|
Util.RefreshCompanions();
|
|
Util.DelayedRefreshCompanions = nil;
|
|
end
|
|
if (Util.DelayedRefreshEquipmentSets) then
|
|
Util.RefreshEquipmentSets();
|
|
Util.DelayedRefreshEquipmentSets = nil;
|
|
end
|
|
end
|
|
|
|
--[[ Add and remove buttons to a list that gets updated for the range timer --]]
|
|
function Util.AddToRangeTimer(Value)
|
|
if (#Util.RangeTimerButtons == 0) then
|
|
--BF
|
|
end
|
|
Util.RangeTimerButtons[Value] = true;
|
|
end
|
|
|
|
function Util.RemoveFromRangeTimer(Value)
|
|
Util.RangeTimerButtons[Value] = nil;
|
|
end
|
|
|
|
--[[ Add and remove buttons to a list that gets updated for flashing --]]
|
|
function Util.AddToFlash(Value)
|
|
if (#Util.FlashButtons == 0) then
|
|
--BF
|
|
end
|
|
Util.FlashButtons[Value] = true;
|
|
end
|
|
|
|
function Util.RemoveFromFlash(Value)
|
|
Util.FlashButtons[Value] = nil;
|
|
end
|
|
|
|
function Util.RightClickSelfCast(Value)
|
|
if (InCombatLockdown()) then
|
|
return;
|
|
end
|
|
|
|
if (Value) then
|
|
for i = 1, #Util.ActiveButtons do
|
|
Util.ActiveButtons[i].Widget:SetAttribute("unit2", "player");
|
|
end
|
|
else
|
|
for i = 1, #Util.ActiveButtons do
|
|
Util.ActiveButtons[i].Widget:SetAttribute("unit2", nil);
|
|
end
|
|
end
|
|
|
|
ButtonForgeSave["RightClickSelfCast"] = Value;
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--[[---------------------------------------
|
|
Spell Functions
|
|
-------------------------------------------]]
|
|
function Util.GetFullSpellName(Name, Rank)
|
|
--BFA fix: GetSpellInfo now returns a nil for the rank. That's passed in here
|
|
--So we check to make sure ranx exists or only pass back the name itself.
|
|
if (Rank) then
|
|
Rank = "("..Rank..")";
|
|
else
|
|
Rank = "";
|
|
end
|
|
if (Name) then
|
|
return Name..Rank;
|
|
end
|
|
end
|
|
|
|
function Util.GetSpellId(NameRank)
|
|
local Link = GetSpellLink(NameRank);
|
|
return select(3, strfind(Link, "spell:(%d+)|"));
|
|
end
|
|
|
|
function Util.IsSpellIdTalent(SpellId)
|
|
local TalentInfoFuncs = {GetTalentInfo, GetPvpTalentInfo};
|
|
|
|
-- Scan both normal and PvP talents
|
|
-- Note rather than assume number of talents, we just scan till the rows and columns till we hit a nil
|
|
for _, TalentInfoFunc in ipairs(TalentInfoFuncs) do
|
|
local r = 1;
|
|
local c = 1;
|
|
local TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
|
|
while (TalentSpellID) do
|
|
while (TalentSpellID) do
|
|
if (TalentSpellID == SpellId) then
|
|
return true;
|
|
end
|
|
c = c + 1;
|
|
TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
|
|
end
|
|
r = r + 1;
|
|
c = 1;
|
|
TalentSpellID = select(6, TalentInfoFunc(r, c, 1));
|
|
end
|
|
end
|
|
return false;
|
|
end
|
|
|
|
function Util.CacheSpellIndexes()
|
|
local i = 1;
|
|
local NewSI = {};
|
|
local NewSM = {-10000000, 10000000};
|
|
local ManaPoints = {};
|
|
local ItemType, Id;
|
|
Util.NewSpellIndex = {};
|
|
|
|
local total = 0;
|
|
for j = 1, GetNumSpellTabs() do
|
|
total = total + select(4, GetSpellTabInfo(j));
|
|
end
|
|
|
|
for i = total, 1, -1 do
|
|
ItemType, Id = GetSpellBookItemInfo(i, BOOKTYPE_SPELL);
|
|
--local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(i, BOOKTYPE_SPELL);
|
|
local Name, Rank, Icon, PowerCost, IsFunnel, PowerType = GetSpellInfo(Id);
|
|
local NameRank = Util.GetFullSpellName(Name, Rank);
|
|
if (ItemType == "SPELL") then
|
|
NewSI[NameRank] = i;
|
|
|
|
elseif (ItemType == "FLYOUT") then
|
|
NewSI["FLYOUT"..Id] = i;
|
|
|
|
elseif (ItemType == nil) then
|
|
break;
|
|
|
|
end
|
|
|
|
-- if (not Util.SpellIndex[NameRank]) then
|
|
-- Util.NewSpellIndex[NameRank] = i;
|
|
--end
|
|
if (PowerType == 0 and not ManaPoints[Power]) then
|
|
ManaPoints[PowerCost] = true;
|
|
table.insert(NewSM, PowerCost);
|
|
end
|
|
end
|
|
-- local total = 0;
|
|
--for j = 1, GetNumSpellTabs() do
|
|
-- total = total + select(4, GetSpellTabInfo(j));
|
|
--end
|
|
--print("Calc total = "..total, "actual total = "..i);
|
|
Util.SpellIndex = NewSI;
|
|
table.sort(NewSM);
|
|
Util.SpellMana = NewSM;
|
|
end
|
|
|
|
function Util.CachePetSpellIndexes()
|
|
local i = 1;
|
|
local NewPSI = {};
|
|
--Util.NewPetSpellIndex = {};
|
|
while true do
|
|
local NameRank = Util.GetFullSpellName(GetSpellInfo(i, BOOKTYPE_PET));
|
|
if (not NameRank) then
|
|
break;
|
|
end
|
|
--if (not Util.PetSpellIndex[NameRank]) then
|
|
-- Util.NewPetSpellIndex[NameRanl] = i;
|
|
--end
|
|
NewPSI[NameRank] = i;
|
|
i = i + 1;
|
|
end
|
|
|
|
Util.PetSpellIndex = NewPSI;
|
|
|
|
end
|
|
|
|
function Util.LookupSpellIndex(NameRank)
|
|
local Index = Util.SpellIndex[NameRank];
|
|
|
|
if (Index) then
|
|
return Index, BOOKTYPE_SPELL;
|
|
end
|
|
Index = Util.PetSpellIndex[NameRank];
|
|
if (Index) then
|
|
return Index, BOOKTYPE_PET;
|
|
end
|
|
end
|
|
|
|
function Util.LookupNewSpellIndex(NameRank)
|
|
local Index = Util.NewSpellIndex[NameRank];
|
|
|
|
if (Index) then
|
|
return Index, BOOKTYPE_SPELL;
|
|
end
|
|
Index = Util.NewPetSpellIndex[NameRank];
|
|
if (Index) then
|
|
return Index, BOOKTYPE_PET;
|
|
end
|
|
end
|
|
|
|
--[[ Used when the players mana crosses a threshold to find the next thresholds to test against --]]
|
|
function Util.FindNewThresholds(Mana, Index, SearchDown)
|
|
local SpellMana = Util.SpellMana;
|
|
if (SearchDown) then
|
|
for i = Index-1, 1, -1 do
|
|
if (SpellMana[i] <= Mana) then
|
|
return SpellMana[i], SpellMana[i+1], i;
|
|
end
|
|
end
|
|
else
|
|
for i = Index+2, #SpellMana do
|
|
if (SpellMana[i] > Mana) then
|
|
return SpellMana[i-1], SpellMana[i], i-1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--[[ I will probably need to do the above for Rage/Energy and Runic Power, but for now will skip such tests --]]
|
|
|
|
--[[ If a spell is learnt this will promote any usage of that spell to it's highest rank --]]
|
|
function Util.PromoteSpells()
|
|
if (InCombatLockdown()) then
|
|
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)
|
|
return;
|
|
end
|
|
return;
|
|
--for k, v in pairs(Util.ActiveButtons) do
|
|
-- v:PromoteSpell();
|
|
--end
|
|
|
|
end
|
|
|
|
function Util.RefreshSpells()
|
|
--Unlike the others this can be done during combat (ironically)
|
|
for k, v in pairs(Util.ActiveButtons) do
|
|
v:RefreshSpell();
|
|
end
|
|
end
|
|
|
|
function Util.AddSpell(Value)
|
|
if (not Util.FindInTable(Util.ActiveSpells, Value)) then
|
|
table.insert(Util.ActiveSpells, Value);
|
|
end
|
|
end
|
|
|
|
function Util.RemoveSpell(Value)
|
|
local Index = Util.FindInTable(Util.ActiveSpells, Value);
|
|
if (Index) then
|
|
table.remove(Util.ActiveSpells, Index);
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--[[---------------------------------------
|
|
Companion Functions
|
|
-------------------------------------------]]
|
|
function Util.CacheCompanions()
|
|
Util.Critters = {};
|
|
--[[
|
|
for i = 1, GetNumCompanions("CRITTER") do
|
|
local Id, Name = GetCompanionInfo("CRITTER", i);
|
|
if (not Name) then
|
|
return;
|
|
end
|
|
Util.Critters[Name] = i;
|
|
end]]
|
|
|
|
Util.Mounts = {};
|
|
-- for i, mountID in pairs(C_MountJournal.GetMountIDs()) do
|
|
-- local creatureName, spellID = C_MountJournal.GetMountInfoByID(mountID);
|
|
-- if (not creatureName) then
|
|
-- return;
|
|
-- end
|
|
-- Util.Mounts[spellID] = mountID;
|
|
-- end
|
|
end
|
|
|
|
function Util.LookupCompanion(Name)
|
|
if (Util.Critters[Name]) then
|
|
return "CRITTER", Util.Critters[Name];
|
|
elseif (Util.Mounts[Name]) then
|
|
return "MOUNT", Util.Mounts[Name];
|
|
else
|
|
return nil, nil;
|
|
end
|
|
end
|
|
|
|
function Util.RefreshCompanions()
|
|
if (InCombatLockdown()) then
|
|
Util.DelayedRefreshCompanions = true;
|
|
return;
|
|
end
|
|
for k, v in pairs(Util.ActiveButtons) do
|
|
v:RefreshCompanion();
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
--[[---------------------------------------
|
|
Item Functions
|
|
-------------------------------------------]]
|
|
|
|
function Util.GetItemId(Name)
|
|
--return select(3, strfind(Link, "item:(%d+)|"));
|
|
return Util.InvItemNameId[Name] or Util.BagItemNameId[Name];
|
|
end
|
|
|
|
function Util.CacheBagItems()
|
|
local BagItemNameIndexes = {};
|
|
local BagItemIdIndexes = {};
|
|
local BagItemNameId = {};
|
|
local ItemId;
|
|
local ItemName;
|
|
for b = 4, 0, -1 do
|
|
for s = GetContainerNumSlots(b), 1, -1 do
|
|
ItemId = GetContainerItemID(b, s);
|
|
ItemName = GetItemInfo(ItemId or "");
|
|
if (ItemName ~= nil and ItemName ~= "") then
|
|
BagItemNameIndexes[ItemName] = {b, s};
|
|
BagItemIdIndexes[ItemId] = {b, s};
|
|
BagItemNameId[ItemName] = ItemId;
|
|
end
|
|
end
|
|
end
|
|
|
|
Util.BagItemNameIndexes = BagItemNameIndexes;
|
|
Util.BagItemIdIndexes = BagItemIdIndexes;
|
|
Util.BagItemNameId = BagItemNameId;
|
|
end
|
|
|
|
function Util.CacheInvItems()
|
|
local InvItemNameIndexes = {};
|
|
local InvItemIdIndexes = {};
|
|
local InvItemNameId = {};
|
|
local ItemId;
|
|
local ItemName;
|
|
for s = 32, 0, -1 do
|
|
ItemId = GetInventoryItemID("player", s);
|
|
ItemName = GetItemInfo(ItemId or "");
|
|
if (ItemName ~= nil and ItemName ~= "") then
|
|
InvItemNameIndexes[ItemName] = s;
|
|
InvItemIdIndexes[ItemId] = s;
|
|
InvItemNameId[ItemName] = ItemId;
|
|
end
|
|
end
|
|
|
|
Util.InvItemNameIndexes = InvItemNameIndexes;
|
|
Util.InvItemIdIndexes = InvItemIdIndexes;
|
|
Util.InvItemNameId = InvItemNameId;
|
|
end
|
|
|
|
--[[ Look for the item in players equipped slots --]]
|
|
function Util.LookupItemNameEquippedSlot(ItemName)
|
|
return Util.InvItemNameIndexes[ItemName];
|
|
end
|
|
function Util.LookupItemIdEquippedSlot(ItemId)
|
|
return Util.InvItemIdIndexes[ItemId];
|
|
end
|
|
|
|
--[[ Look for the item in the players inventory --]]
|
|
function Util.LookupItemNameBagSlot(ItemName)
|
|
local Result = Util.BagItemNameIndexes[ItemName];
|
|
if (Result) then
|
|
return Result[1], Result[2];
|
|
else
|
|
return nil, nil;
|
|
end
|
|
end
|
|
function Util.LookupItemIdBagSlot(ItemId)
|
|
local Result = Util.BagItemIdIndexes[ItemId];
|
|
if (Result) then
|
|
return Result[1], Result[2];
|
|
else
|
|
return nil, nil;
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--[[ Look for the item in players equipped slots --]]
|
|
function Util.LookupItemEquippedSlot(ItemId)
|
|
for s = 0,23 do
|
|
local Id = GetInventoryItemID("player", s);
|
|
if (ItemId == Id) then
|
|
return s;
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
--[[ Look for the item in the players inventory
|
|
Notes: Don't use this function, the above functions are better
|
|
Reason: In the simple case profiling shows that the performance hit is neglible from doing this scan...
|
|
That is until GetItemInfo is used to get the name of the item
|
|
all other things being equal that call increases my perf time from 0.04ms (approx 100 bag slots, with half used) to 0.44ms
|
|
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) --]]
|
|
function Util.LookupItemInvSlot(ItemId)
|
|
|
|
local Id;
|
|
local Name = "";
|
|
for b = 0, 4 do
|
|
for s = 1, GetContainerNumSlots(b) do
|
|
Id = GetContainerItemID(b, s);
|
|
if (Id) then
|
|
Name = GetItemInfo(Id);
|
|
if (ItemId == Id) then
|
|
return b, s;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return nil, nil;
|
|
end
|
|
--[[ Look the item in the players bank (not sure if I need to make such a function so will leave this stub for now --]]
|
|
function Util.LookupItemBankSlot(ItemName)
|
|
return nil, nil;
|
|
end
|
|
|
|
function Util.AddItem(Value)
|
|
if (not Util.FindInTable(Util.ActiveItems, Value)) then
|
|
table.insert(Util.ActiveItems, Value);
|
|
end
|
|
end
|
|
|
|
function Util.RemoveItem(Value)
|
|
local Index = Util.FindInTable(Util.ActiveItems, Value);
|
|
if (Index) then
|
|
table.remove(Util.ActiveItems, Index);
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--[[---------------------------------------
|
|
EquipmentSet Functions
|
|
-------------------------------------------]]
|
|
function Util.RefreshEquipmentSets()
|
|
if (InCombatLockdown()) then
|
|
Util.DelayedRefreshEquipmentSets = true;
|
|
return;
|
|
end
|
|
for k, v in pairs(Util.ActiveButtons) do
|
|
v:RefreshEquipmentSet();
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
--[[---------------------------------------
|
|
Bonus Action Functions
|
|
-------------------------------------------]]
|
|
function Util.AddBonusAction(Value)
|
|
if (not Util.FindInTable(Util.ActiveBonusActions, Value)) then
|
|
table.insert(Util.ActiveBonusActions, Value);
|
|
end
|
|
end
|
|
|
|
function Util.RemoveBonusAction(Value)
|
|
local Index = Util.FindInTable(Util.ActiveBonusActions, Value);
|
|
if (Index) then
|
|
table.remove(Util.ActiveBonusActions, Index);
|
|
end
|
|
end
|
|
|
|
|
|
function Util.UpdateButtonClickHandling()
|
|
if (InCombatLockdown() or not Util.Loaded) then
|
|
Util.DelayedUpdateButtonClickHandling = true;
|
|
return;
|
|
end
|
|
|
|
for i = 1, #Util.ActiveButtons do
|
|
Util.ActiveButtons[i]:SetupActionButtonClick();
|
|
end
|
|
for i = 1, #Util.InactiveButtons do
|
|
Util.InactiveButtons[i]:SetupActionButtonClick();
|
|
end
|
|
end
|
|
|
|
|
|
--[[---------------------------------------
|
|
Macro Functions
|
|
-------------------------------------------]]
|
|
function Util.Trim5(S)
|
|
return strmatch(S or '', '^%s*(.*%S)') or '';
|
|
end
|
|
function Util.IncBetween(Val, Low, High)
|
|
return Val >= Low and Val <= High;
|
|
end
|
|
|
|
function Util.RefreshMacros()
|
|
if (InCombatLockdown() or not Util.Loaded) then
|
|
Util.DelayedRefreshMacros = true;
|
|
return;
|
|
end
|
|
|
|
if (Util.UpdateMacroEventCount < 2) then
|
|
--Not all macros have been loaded yet so don't refresh
|
|
|
|
return;
|
|
end
|
|
|
|
local AccMacros, CharMacros = GetNumMacros();
|
|
if (not Util.MacroCount) then
|
|
Util.MacroCount = AccMacros + CharMacros;
|
|
elseif (Util.MacroCount > AccMacros + CharMacros) then
|
|
Util.MacroDeleted = true;
|
|
end
|
|
|
|
|
|
for i = 1, #Util.ActiveButtons do
|
|
Util.ActiveButtons[i]:RefreshMacro();
|
|
end
|
|
Util.MacroDeleted = false;
|
|
Util.MacroCount = AccMacros + CharMacros;
|
|
end
|
|
|
|
function Util.AddMacro(Value)
|
|
if (not Util.FindInTable(Util.ActiveMacros, Value)) then
|
|
table.insert(Util.ActiveMacros, Value);
|
|
end
|
|
Util.RefreshOnUpdateFunction();
|
|
end
|
|
|
|
function Util.RemoveMacro(Value)
|
|
local Index = Util.FindInTable(Util.ActiveMacros, Value);
|
|
if (Index) then
|
|
table.remove(Util.ActiveMacros, Index);
|
|
Util.RefreshOnUpdateFunction();
|
|
end
|
|
end
|
|
|
|
--[[ Monitor the macro check delay --]]
|
|
function Util.StartMacroCheckDelay()
|
|
Delay:SetScript("OnUpdate", Delay.OnUpdate);
|
|
end
|
|
|
|
function Util.StopMacroCheckDelay()
|
|
Delay:SetScript("OnUpdate", nil);
|
|
Util.MacroCheckDelayComplete = true;
|
|
Util.RefreshMacros();
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
The following creates an OnUpdate function designed to scan for macro conditionals that can't
|
|
adequately be covered by events alone - it will only perform processing for conditionals that actually
|
|
exist in allocated macros
|
|
--]]
|
|
function Util.RefreshOnUpdateFunction()
|
|
if (not Util.Loaded) then
|
|
return;
|
|
end
|
|
|
|
local ConcatMacros = "";
|
|
local FunctionString =
|
|
[[return function (self, Elapsed)
|
|
]];
|
|
|
|
for i = 1, #(Util.ActiveMacros) do
|
|
if (Util.ActiveMacros[i].Mode == "macro") then
|
|
ConcatMacros = ConcatMacros..":"..(GetMacroBody(Util.ActiveMacros[i].MacroIndex) or "");
|
|
end
|
|
end
|
|
|
|
ConcatMacros = strupper(ConcatMacros);
|
|
|
|
--The following tests should be performed the buttons are updated
|
|
if (strfind(ConcatMacros, "FLYING", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlying(); end
|
|
if (strfind(ConcatMacros, "MOUNTED", 1, true)) then FunctionString = FunctionString..Util.SnippetIsMounted(); end
|
|
FunctionString = FunctionString..Util.SnippetRefreshButtons();
|
|
|
|
--The following tests need to be performed after the buttons are updated (so that the buttons can be updated at the next onupdate)
|
|
if (strfind(ConcatMacros, "FLYABLE", 1, true)) then FunctionString = FunctionString..Util.SnippetIsFlyable(); end
|
|
if (strfind(ConcatMacros, "MOUSEOVER", 1, true)) then FunctionString = FunctionString..Util.SnippetMouseOver(); end
|
|
|
|
FunctionString = FunctionString.."end";
|
|
|
|
local Func = assert(loadstring(FunctionString, "ButtonForgeOnUpdate"));
|
|
Util.OnUpdate = Func();
|
|
EventFull:SetScript("OnUpdate", Util.OnUpdate);
|
|
end
|
|
|
|
function Util.SnippetRefreshButtons()
|
|
return
|
|
[[if (self.RefreshButtons) then
|
|
local ActiveButtons = self.Util.ActiveButtons;
|
|
for i = 1, #ActiveButtons do
|
|
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)
|
|
end
|
|
if (self.RefChecked) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateChecked();
|
|
end
|
|
end
|
|
if (self.RefEquipped) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateEquipped();
|
|
end
|
|
end
|
|
if (self.RefUsable) then
|
|
--print("Usable");
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateUsable();
|
|
end
|
|
end
|
|
if (self.RefCooldown) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateCooldown();
|
|
end
|
|
end
|
|
if (self.RefText) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateTextCount();
|
|
end
|
|
end
|
|
if (self.RefFlyouts) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateFlyout();
|
|
end
|
|
end
|
|
if (self.RefGlow) then
|
|
for i = 1, #ActiveButtons do
|
|
ActiveButtons[i]:UpdateGlow();
|
|
end
|
|
end
|
|
if (self.RefConditional) then
|
|
local ActiveMacros = self.Util.ActiveMacros;
|
|
for i = 1, #ActiveMacros do
|
|
ActiveMacros[i]:TranslateMacro();
|
|
end
|
|
end
|
|
self.RefreshButtons = false;
|
|
self.RefFull = false;
|
|
self.RefChecked = false;
|
|
self.RefEquipped = false;
|
|
self.RefUsable = false;
|
|
self.RefCooldown = false;
|
|
self.RefText = false;
|
|
self.RefFlyouts = false;
|
|
self.RefGlow = false;
|
|
self.RefConditional = false;
|
|
end
|
|
]];
|
|
end
|
|
|
|
function Util.SnippetMouseOver()
|
|
return
|
|
[[if (UnitName("mouseover") ~= self.MOUnit or UnitIsDead("mouseover") ~= self.MOUnitDead) then
|
|
self.MOUnit = UnitName("mouseover");
|
|
self.MOUnitDead = UnitIsDead("mouseover");
|
|
self.RefreshButtons = true;
|
|
self.RefConditional = true;
|
|
end
|
|
]];
|
|
end
|
|
|
|
function Util.SnippetIsFlying()
|
|
return
|
|
[[if (IsFlying() ~= self.IsFlying) then
|
|
self.IsFlying = IsFlying();
|
|
self.RefreshButtons = true;
|
|
self.RefConditional = true;
|
|
end
|
|
]];
|
|
end
|
|
|
|
function Util.SnippetIsMounted()
|
|
return
|
|
[[if (IsMounted() ~= self.IsMounted) then
|
|
self.IsMounted = IsMounted();
|
|
self.RefreshButtons = true;
|
|
self.RefConditional = true;
|
|
end
|
|
]];
|
|
end
|
|
|
|
function Util.SnippetIsFlyable()
|
|
return
|
|
[[if (IsFlyableArea() ~= self.IsFlyableArea) then
|
|
self.IsFlyableArea = IsFlyableArea();
|
|
self.RefreshButtons = true;
|
|
self.RefConditional = true;
|
|
end
|
|
]];
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
API1 Support Functions
|
|
--]]
|
|
function Util.RegisterCallback(Callback, Arg)
|
|
table.insert(Util.CallbackFunctions, Callback);
|
|
table.insert(Util.CallbackArgs, Arg);
|
|
end
|
|
|
|
function Util.UnregisterCallback(Callback, Arg)
|
|
for i = #Util.CallbackFunctions, 1, -1 do
|
|
if (Util.CallbackFunctions[i] == Callback and Util.CallbackArgs[i] == Arg) then
|
|
table.remove(Util.CallbackFunctions, i);
|
|
table.remove(Util.CallbackArgs, i);
|
|
end
|
|
end
|
|
end
|
|
|
|
local CallbackFunc;
|
|
local CallbackArg;
|
|
local CallbackEvent;
|
|
local CallbackEventArgs;
|
|
function Util.CallbackWrapper()
|
|
CallbackFunc(CallbackArg, CallbackEvent, unpack(CallbackEventArgs));
|
|
end
|
|
|
|
function Util.CallbackEvent(Event, ...)
|
|
CallbackEvent = Event;
|
|
CallbackEventArgs = {...};
|
|
--local Args = {...};
|
|
for i = 1, #Util.CallbackFunctions do
|
|
CallbackFunc = Util.CallbackFunctions[i];
|
|
CallbackArg = Util.CallbackArgs[i];
|
|
xpcall(Util.CallbackWrapper, geterrorhandler());
|
|
--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
|
|
end
|
|
end
|
|
|
|
--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
|
|
function Util.GetButtonActionInfo(ButtonName)
|
|
local Button = Util.ButtonWidgetMap[_G[ButtonName]];
|
|
|
|
if (not Button) then
|
|
return;
|
|
end
|
|
|
|
if (Button.Mode == "spell") then
|
|
return "spell", Button.SpellId, Button.SpellBook;
|
|
elseif (Button.Mode == "item") then
|
|
return "item", Button.ItemId;
|
|
elseif (Button.Mode == "macro") then
|
|
return "macro", Button.MacroIndex;
|
|
elseif (Button.Mode == "companion") then
|
|
local spellid = select(3, GetCompanionInfo(Button.CompanionType, Button.CompanionIndex));
|
|
return "companion", spellid, Button.CompanionType;
|
|
elseif (Button.Mode == "equipmentset") then
|
|
return "equipmentset", Button.EquipmentSetName;
|
|
elseif (Button.Mode == "flyout") then
|
|
return "flyout", Button.FlyoutId;
|
|
end
|
|
end
|
|
|
|
--This one breaks with the philosophy of the Button implementation but for now should be sufficient to support the API function
|
|
function Util.GetButtonActionInfo2(ButtonName)
|
|
local Button = Util.ButtonWidgetMap[_G[ButtonName]];
|
|
|
|
if (not Button) then
|
|
return;
|
|
end
|
|
|
|
--[[
|
|
"spell", SpellName, SpellSubName, SpellId, SpellIndex, SpellBook
|
|
"item", ItemId, ItemName
|
|
"macro", MacroIndex
|
|
"companion", CompanionType, CompanionIndex
|
|
"equipmentset", Name
|
|
"flyout", FlyoutId
|
|
"bonusaction", BonusActionSlot
|
|
"customaction", CustomActionName
|
|
--]]
|
|
|
|
if (Button.Mode == "spell") then
|
|
local Rank = select(2, GetSpellInfo(Button.SpellId));
|
|
return "spell", Button.SpellName, Rank, Button.SpellId, Util.LookupSpellIndex(Button.SpellNameRank), Button.SpellBook;
|
|
elseif (Button.Mode == "item") then
|
|
return "item", Button.ItemId, Button.ItemName;
|
|
elseif (Button.Mode == "macro") then
|
|
return "macro", Button.MacroIndex;
|
|
elseif (Button.Mode == "companion") then
|
|
return "companion", Button.CompanionType, Button.CompanionIndex;
|
|
elseif (Button.Mode == "equipmentset") then
|
|
return "equipmentset", Button.EquipmentSetName;
|
|
elseif (Button.Mode == "flyout") then
|
|
return "flyout", Button.FlyoutId;
|
|
elseif (Button.Mode == "bonusaction") then
|
|
return "bonusaction", Button.BonusActionSlot;
|
|
elseif (Button.Mode == "customaction") then
|
|
return "customaction", Button.CustomActionName;
|
|
end
|
|
end
|
|
|
|
|
|
--[[------------------------------------------------
|
|
Get Correct Mount Index
|
|
The Hack:
|
|
hooksecurefunc
|
|
C_MountJournal.Pickup
|
|
GameTooltip:SetAction
|
|
Both these functions offer a moment when both
|
|
the UselessIndex and the actual Index or SpellID
|
|
for a mount is available... Also in theory
|
|
one of these will have to fire before the player
|
|
can actually put a mount on the cursor - so we
|
|
simply patch work build a map of these
|
|
Useless Index to useful index mappings.
|
|
It does rely on the useless index not changing during
|
|
a session - i suspect it wont, but it might when a new
|
|
mount is learned, something that is hard to test on my
|
|
account these days
|
|
--------------------------------------------------]]
|
|
--[[ should no longer be needed
|
|
function Util.HookSecureFunc_C_MountJournal_Pickup(Index)
|
|
local UselessIndex = select(2, GetCursorInfo());
|
|
if (Index and UselessIndex) then
|
|
Util.MountUselessIndexToIndex[select(2, GetCursorInfo())] = Index;
|
|
end
|
|
end
|
|
hooksecurefunc(C_MountJournal, "Pickup", Util.HookSecureFunc_C_MountJournal_Pickup);
|
|
|
|
function Util.HookSecureFunc_GameTooltip_SetAction(_, Slot)
|
|
if (Slot == nil or Slot < 1 or Slot > 1000) then
|
|
return;
|
|
end
|
|
local Command, UselessIndex = GetActionInfo(Slot);
|
|
if (Command == "summonmount") then
|
|
if (Util.MountUselessIndexToIndex[UselessIndex] == nil) then
|
|
Util.MountUselessIndexToIndex[UselessIndex] = Util.GetMountIndexFromSpellID(select(3, GameTooltip:GetSpell()));
|
|
end
|
|
end
|
|
end
|
|
hooksecurefunc(GameTooltip, "SetAction", Util.HookSecureFunc_GameTooltip_SetAction);
|
|
|
|
function Util.GetMountIndexFromUselessIndex(Index)
|
|
return Util.MountUselessIndexToIndex[Index];
|
|
end
|
|
]]
|
|
|
|
--[[------------------------------------------------
|
|
GetCorrectMountIndex
|
|
--------------------------------------------------]]
|
|
--[[
|
|
function Util.GetMountIndexFromSpellID(SpellID)
|
|
local Num = C_MountJournal.GetNumMounts();
|
|
if (SpellID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) then
|
|
return 0; -- This is summon favorite
|
|
end
|
|
for i = 1, Num do
|
|
if (select(2, C_MountJournal.GetDisplayedMountInfo(i)) == SpellID) then
|
|
return i;
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
]]
|
|
|
|
--[[------------------------------------------------
|
|
|
|
--------------------------------------------------]]
|
|
|
|
function Util.GetMountIDFromName(Name)
|
|
local Num = C_MountJournal.GetNumMounts();
|
|
|
|
for i = 1, Num do
|
|
if (C_MountJournal.GetDisplayedMountInfo(i) == Name) then
|
|
return select(12, C_MountJournal.GetDisplayedMountInfo(i));
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
function Util.GetMountIndexFromMountID(MountID)
|
|
local Num = C_MountJournal.GetNumMounts();
|
|
if (MountID == Const.SUMMON_RANDOM_FAVORITE_MOUNT_ID) then
|
|
return 0;
|
|
end
|
|
for i = 1, Num do
|
|
if (select(12, C_MountJournal.GetDisplayedMountInfo(i)) == MountID) then
|
|
return i;
|
|
end
|
|
end
|
|
end
|
|
|
|
function Util.UpdateButtonsCooldownSwipeBling()
|
|
local ActiveButtons = Util.ActiveButtons;
|
|
for i = 1, #ActiveButtons do
|
|
local Alpha = ActiveButtons[i].WCooldown:GetEffectiveAlpha();
|
|
ActiveButtons[i].WCooldown:SetDrawBling(Alpha == 1);
|
|
ActiveButtons[i].WCooldown:SetSwipeColor(0,0,0,Alpha);
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Copied from Bliz implementation
|
|
The difference is I use the effective alpha to override the bling and edge settings, and also adjust the swipe alpha
|
|
|
|
I suspect this will need fine tuning for Masque and perhaps OmniCC, but that can be down the track
|
|
]]
|
|
function Util.CooldownFrame_SetTimer(self, start, duration, enable, charges, maxCharges, forceShowDrawEdge)
|
|
if(enable) then
|
|
if (enable ~= 0) then
|
|
local drawEdge = false;
|
|
if ( duration > 2 and charges and maxCharges and charges ~= 0) then
|
|
drawEdge = true;
|
|
end
|
|
local Alpha = self:GetEffectiveAlpha();
|
|
self:SetSwipeColor(0, 0, 0, Alpha); -- eventually I may need to make this obey the current color!!!
|
|
if (Alpha > 0.4) then
|
|
self:SetDrawEdge(drawEdge or forceShowDrawEdge);
|
|
self:SetDrawBling(true);
|
|
else
|
|
self:SetDrawEdge(false);
|
|
self:SetDrawBling(false);
|
|
end
|
|
self:SetDrawSwipe(not drawEdge);
|
|
self:SetCooldown(start, duration);
|
|
else
|
|
self:SetCooldown(0, 0);
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function Util.LookupEquipmentSetIndex(EquipmentSetID)
|
|
|
|
local Total = C_EquipmentSet.GetNumEquipmentSets();
|
|
for i = 0, Total-1 do
|
|
if (select(3, C_EquipmentSet.GetEquipmentSetInfo(i)) == EquipmentSetID) then
|
|
return i;
|
|
end
|
|
end
|
|
return nil;
|
|
|
|
end
|
|
|