diff --git a/Titan/Titan.lua b/Titan/Titan.lua index e71a4ec..fd1776e 100644 --- a/Titan/Titan.lua +++ b/Titan/Titan.lua @@ -1,2564 +1,2428 @@ ----@diagnostic disable: duplicate-set-field ---[===[ File -Contains the basic routines of Titan. -All the event handler routines, initialization routines, Titan menu routines, and select plugin handler routines. ---]===] - --- Locals -local TPC = TITAN_PANEL_CONSTANTS -- shortcut -local TITAN_PANEL_BUTTONS_INIT_FLAG = nil; - -local _G = _G --getfenv(0); -local InCombatLockdown = _G.InCombatLockdown; -local IsTitanPanelReset = nil; - --- Library references -local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) -local AceTimer = LibStub("AceTimer-3.0") -local media = LibStub("LibSharedMedia-3.0") - --- TitanDebug (cmd.." : "..p1.." "..p2.." "..p3.." "..#cmd_list) - --------------------------------------------------------------- --- - ----Titan Give the user an are you sure popup whether to reload the UI or not. -function TitanPanel_OkToReload() - StaticPopupDialogs["TITAN_RESET_RELOAD"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) - .. "\n\n" .. L["TITAN_PANEL_RESET_WARNING"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self) - ReloadUI() - end, - showAlert = 1, - timeout = 0, - whileDead = 1, - hideOnEscape = 1 - }; - StaticPopup_Show("TITAN_RESET_RELOAD"); -end - ----Titan Give the user a 'are you sure' popup whether to reset current toon back to default Titan settings. -function TitanPanel_ResetToDefault() - -- Found as of 2025 Sep, the reload is not needed - -- build debug output - local str = "/titan reset" - .." "..tostring(TITAN_PROFILE_RESET).."" - Titan_Debug.Out('titan', 'profile', str) - - TitanVariables_UseSettings(TitanSettings.Player, TITAN_PROFILE_RESET); - IsTitanPanelReset = true; -end - ----Titan The user wants to save a custom Titan profile. Show the user the dialog boxes to make it happen. ---- The profile is written to the Titan saved variables. A reload of the UI is needed to ensure the profile is written to disk for the user to load later. -function TitanPanel_SaveCustomProfile() - -- Create the dialog box code we'll need... - - ---helper to get the edit box depending on expansion API - ---@param self table - ---@return table - local function GetBox(self) - if self.editBox then - -- Older version of API - return self.editBox - else - return self:GetEditBox() - end - end - - -- helper to actually write the profile to the Titan saved vars - local function Write_profile(name) - local currentprofilevalue, _, _ = TitanUtils_GetPlayer() - local profileName = TitanUtils_CreateName(name, TITAN_CUSTOM_PROFILE_POSTFIX) - TitanSettings.Players[profileName] = - TitanSettings.Players[currentprofilevalue] - TitanPrint(L["TITAN_PANEL_MENU_PROFILE_SAVE_PENDING"] - .. "'" .. name .. "'" - , "info") - end - -- helper to ask the user to overwrite a profile - local function Overwrite_profile(name) - local dialogFrame = - StaticPopup_Show("TITAN_OVERWRITE_CUSTOM_PROFILE", name); - if dialogFrame then - dialogFrame.data = name; - end - end - -- helper to handle getting the profile name from the user - local function Get_profile_name(self) - local rawprofileName = GetBox(self):GetText(); - -- remove any spaces the user may have typed in the name - local conc2profileName = string.gsub(rawprofileName, " ", ""); - if conc2profileName == "" then return; end - -- no '@' is allowed or it will mess with the Titan profile naming convention - local concprofileName = string.gsub(conc2profileName, TITAN_AT, "-"); - local profileName = TitanUtils_CreateName(concprofileName, TITAN_CUSTOM_PROFILE_POSTFIX) - if TitanSettings.Players[profileName] then - -- Warn the user of an existing profile - Overwrite_profile(rawprofileName) - self:Hide(); - return; - else - -- Save the requested profile - Write_profile(rawprofileName) - self:Hide(); - StaticPopup_Show("TITAN_RELOADUI"); - end - end - -- Dialog box to warn the user that the UI will be reloaded - -- This ensures the profile is written to disk - StaticPopupDialogs["TITAN_RELOADUI"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_MENU_PROFILE_RELOADUI"], - button1 = "OKAY", - OnAccept = function(self) - ReloadUI(); -- ensure profile is written to disk - end, - showAlert = 1, - whileDead = 1, - timeout = 0, - }; - - -- Dialog box to warn the user that an existing profile will be overwritten. - StaticPopupDialogs["TITAN_OVERWRITE_CUSTOM_PROFILE"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_MENU_PROFILE_ALREADY_EXISTS"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self, data) - Write_profile(data) - self:Hide(); - StaticPopup_Show("TITAN_RELOADUI"); - end, - showAlert = 1, - whileDead = 1, - timeout = 0, - hideOnEscape = 1 - }; - - -- Dialog box to save the profile. - StaticPopupDialogs["TITAN_SAVE_CUSTOM_PROFILE"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_MENU_PROFILE_SAVE_CUSTOM_TITLE"], - button1 = ACCEPT, - button2 = CANCEL, - hasEditBox = 1, - maxLetters = 20, - OnAccept = function(self) - -- self refers to this frame with the Accept button - Get_profile_name(self) - end, - OnShow = function(self) - GetBox(self):SetFocus(); - end, - OnHide = function(self) - GetBox(self):SetText(""); - end, - EditBoxOnEnterPressed = function(self) - -- We need to get the parent because self refers to the edit box. - Get_profile_name(self:GetParent()) - end, - EditBoxOnEscapePressed = function(self) - self:GetParent():Hide(); - end, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 - }; - - StaticPopup_Show("TITAN_SAVE_CUSTOM_PROFILE"); - - -- Can NOT cleanup. Execution does not stop when a dialog box is invoked! - -- StaticPopupDialogs["TITAN_RELOADUI"] = {} - -- StaticPopupDialogs["TITAN_OVERWRITE_CUSTOM_PROFILE"] = {} - -- StaticPopupDialogs["TITAN_SAVE_CUSTOM_PROFILE"] = {} -end - ----Titan Set or change the font and font size of text on the Titan bar. This affects ALL plugins. ---- Each registered plugin will have its font updated. Then all plugins will be refreshed to show the new font. ----@param fontname string path to font file ----@param fontsize number in points -function TitanSetPanelFont(fontname, fontsize) - -- a couple of arg checks to avoid unpleasant things... - if not fontname then fontname = TPC.FONT_NAME end - if not fontsize then fontsize = TPC.FONT_SIZE end - local newfont = media:Fetch("font", fontname) - for index, id in pairs(TitanPluginsIndex) do - local button = TitanUtils_GetButton(id) - if button then - local buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; - if buttonText then - buttonText:SetFont(newfont, fontsize); - end - end - end - TitanPanel_RefreshPanelButtons(); -end - -local function RegisterForEvents() - -- Need to be careful of regeristering for events that initiate - -- show / hide of Bars before the Bars can be initialized... - _G[TITAN_PANEL_CONTROL]:RegisterEvent("CVAR_UPDATE"); - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_LOGOUT"); - - -- For the pet battle - for now we'll hide the Titan bars... - -- Cannot seem to move the 'top' part of the pet battle frame. - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PET_BATTLE_OPENING_START"); - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PET_BATTLE_CLOSE"); - - -- Hide Titan bars in combat (global or per bar); may be useful when using Short bars - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_REGEN_ENABLED"); - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_REGEN_DISABLED"); - - -- User request to hide Top bar(s) in BG or arena; more areas later? - _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED"); - _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_INDOORS"); - _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_NEW_AREA"); -end - --------------------------------------------------------------- -_G[TITAN_PANEL_CONTROL]:RegisterEvent("ADDON_LOADED"); --- --- Event routine : redirects to TitanPanelBarButton:<registered event> routines below. -_G[TITAN_PANEL_CONTROL]:SetScript("OnEvent", function(_, event, ...) - _G[TITAN_PANEL_CONTROL][event](_G[TITAN_PANEL_CONTROL], ...) -end) - -local function RegisterAddonCompartment() - if AddonCompartmentFrame then - AddonCompartmentFrame:RegisterAddon( - { - text = TITAN_ID, - icon = "Interface\\Icons\\Achievement_Dungeon_UlduarRaid_Titan_01", - notCheckable = true, - func = function(button, menuInputData, menu) - TitanUpdateConfig("init") - Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About) - end, - funcOnEnter = function(button) - MenuUtil.ShowTooltip(button, function(tooltip) - local msg = "" - ..L["TITAN_PANEL"] - .." "..L["TITAN_PANEL_MENU_CONFIGURATION"] - tooltip:SetText(msg) - end) - end, - funcOnLeave = function(button) - MenuUtil.HideTooltip(button) - end, - } - ) - else - end -end - ----Titan Do all the setup needed when a user logs in / reload UI / enter or leave an instance. ---- This is called after the 'player entering world' event is fired by Blizz. ---- This is also called when a LDB plugin is created after Titan runs the 'player entering world' code. ---- The common code section will setup this toon's info ---- 1) Register any plugins ---- 2) Load the plugin vars (UseSettings) ---- 3) Update the Titan config ---- 4) Set the Titan vars ---- 5) Load / register any LDB plugins into Titan ----@param reload boolean true if reload; false if character 'first' enter -function TitanPanel_PlayerEnteringWorld(reload) - if Titan__InitializedPEW then - -- Currently no additional steps needed - else - Titan_Debug.Out('titan', 'p_e_w', "Init settings") - - -- Get Profile and Saved Vars - TitanVariables_InitTitanSettings(); - if TitanAllGetVar("Silenced") then - -- No header output - else - TitanPrint("", "header") - end - - if not ServerTimeOffsets then - ServerTimeOffsets = {}; - end - if not ServerHourFormat then - ServerHourFormat = {}; - end - - -- Set the two anchors in their default positions - -- until the Titan bars are drawn - Titan_Debug.Out('titan', 'p_e_w', "Create anchors for other addons") - TitanPanelTopAnchor:ClearAllPoints(); - TitanPanelTopAnchor:SetPoint("TOPLEFT", "UIParent", "TOPLEFT", 0, 0); - TitanPanelBottomAnchor:ClearAllPoints(); - TitanPanelBottomAnchor:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", 0, 0); - - -- Ensure the bars are created before the plugins are registered. - Titan_Debug.Out('titan', 'p_e_w', "Create frames for Titan bars") - for idx, v in pairs(TitanBarData) do - Titan_Debug.Out('titan', 'bars_setup', "... ".. tostring(v.name)) - - TitanPanelButton_CreateBar(idx) - end - -- Titan_AutoHide_Create_Frames() - - -- Add to Addon Compartment, if feature is present - RegisterAddonCompartment() - - -- Set clock vars based on user setting - if TitanPlugins["Clock"] then - local realmName = GetRealmName() - if ServerTimeOffsets[realmName] then - TitanSetVar("Clock", "OffsetHour", ServerTimeOffsets[realmName]) - elseif TitanGetVar("Clock", "OffsetHour") then - ServerTimeOffsets[realmName] = TitanGetVar("Clock", "OffsetHour") - end - - if ServerHourFormat[realmName] then - TitanSetVar("Clock", "Format", ServerHourFormat[realmName]) - elseif TitanGetVar("Clock", "Format") then - ServerHourFormat[realmName] = TitanGetVar("Clock", "Format") - end - end - - -- Should be safe to register for events that could show / hide Bars - Titan_Debug.Out('titan', 'p_e_w', "Register for events Titan needs") - RegisterForEvents() - end - - --====== Common code login versus reload / portal / ... - - local _ = nil - TitanSettings.Player, _, _ = TitanUtils_GetPlayer() - - -- Some addons wait to create their LDB component or a Titan addon could - -- create additional buttons as needed. - Titan_Debug.Out('titan', 'p_e_w', "Register any plugins found") - TitanUtils_RegisterPluginList() - Titan_Debug.Out('titan', 'p_e_w', "> Register any plugins done") - - -- Now sync saved variables to the profile chosen by the user. - -- This will set the bar(s) and enabled plugins (via OnShow). - Titan_Debug.Out('titan', 'p_e_w', "Synch plugin saved vars") - - Titan_Debug.Out('titan', 'p_e_w', "Synch plugin saved vars") - TitanVariables_UseSettings(nil, TITAN_PROFILE_INIT) - - Titan_Debug.Out('titan', 'p_e_w', "Init config data (right click menu)") - -- all addons are loaded so update the config (options) - -- some could have registered late... - TitanUpdateConfig("init") - - -- Init panel font - local isfontvalid = media:IsValid("font", TitanPanelGetVar("FontName")) - if isfontvalid then - TitanSetPanelFont(TitanPanelGetVar("FontName"), TitanPanelGetVar("FontSize")) - else - -- if the selected font is not valid, revert to default (Friz Quadrata TT) - TitanPanelSetVar("FontName", TPC.FONT_NAME); - TitanSetPanelFont(TPC.FONT_NAME, TitanPanelGetVar("FontSize")) - end - - -- Init panel frame strata - TitanVariables_SetPanelStrata(TitanPanelGetVar("FrameStrata")) - - -- Titan Panel has initialized its variables and registered plugins. - -- Allow Titan - and others - to adjust the bars - Titan__InitializedPEW = true - - -- Move frames - if Titan_Global.switch.can_edit_ui then - -- No need - else - TitanMovable_SecureFrames() - TitanPanel_AdjustFrames(true, "_PlayerEnteringWorld") - end - - -- Loop through the LDB objects to sync with their created Titan plugin - Titan_Debug.Out('titan', 'p_e_w', "Register any LDB (Titan) plugins") - TitanLDBRefreshButton() - Titan_Debug.Out('titan', 'p_e_w', "> Register any LDB (Titan) plugins done") - - Titan_Debug.Out('titan', 'p_e_w', "Titan processing done") -end - --------------------------------------------------------------- --- --- Event handlers --- ---[===[ - local WoWClassicEra, WoWClassicTBC, WoWWOTLKC, WoWRetail - if wowversion < 20000 then - WoWClassicEra = true - elseif wowversion < 30000 then - WoWClassicTBC = true - elseif wowversion < 40000 then - WoWWOTLKC = true - elseif wowversion > 90000 then - WoWRetail = true - else - -- n/a - end ---]===] - - ----Titan Handle ADDON_LOADED Minimal setup in prep for player login. -function TitanPanelBarButton:ADDON_LOADED(addon) - if addon == TITAN_ID then - _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_ENTERING_WORLD") - - Titan_Debug.Out('titan', 'events', "ADDON_LOADED") - - -- Unregister event - saves a few event calls. - self:UnregisterEvent("ADDON_LOADED"); - self.ADDON_LOADED = nil - end -end - ----Titan Handle PLAYER_ENTERING_WORLD Initialize Titan, set and display Titan bars and plugins. -function TitanPanelBarButton:PLAYER_ENTERING_WORLD(arg1, arg2) - local call_success = nil - local ret_val = nil - - Titan_Debug.Out('titan', 'p_e_w', "Titan PLAYER_ENTERING_WORLD pcall setup routine") - - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(TitanPanel_PlayerEnteringWorld, arg2) - -- pcall does not allow errors to propagate out. Any error - -- is returned as text with the success / fail. - -- Think of it as a try - catch block - --[[ -print("_PlayerEnteringWorld" -.." "..tostring(call_success).."" -) ---]] - if call_success then - -- Titan initialized properly - else - -- something really bad occured... - TitanPrint("Titan could not initialize!!!! Cleaning up...", "error") - TitanPrint("--" .. ret_val, "error") - -- Clean up best we can and tell the user to submit a ticket. - -- This could be the 1st log in or a reload (reload, instance, boat, ...) - - -- Hide the bars. At times they are there but at 0% transparency. - -- They can be over the Blizz action bars creating havoc. - TitanPrint("-- Hiding Titan bars...", "warning") - TitanPanelBarButton_HideAllBars() - - -- Remove the options pages - TitanUpdateConfig("nuke") - -- What else to clean up??? - - -- raise the error to WoW for display, if display errors is set. - -- This *must be* the last statement of the routine! - error(ret_val, 1) - end -end - ----Titan Handle CVAR_UPDATE React to user changed WoW options. -function TitanPanelBarButton:CVAR_UPDATE(cvarname, cvarvalue) - if cvarname == "USE_UISCALE" - or cvarname == "WINDOWED_MODE" - or cvarname == "uiScale" then - if TitanPlayerSettings and TitanPanelGetVar("Scale") then - TitanPanel_InitPanelBarButton("CVAR_ " .. tostring(cvarname)) - if Titan_Global.switch.can_edit_ui then - -- No need - else - -- Adjust frame positions - TitanPanel_AdjustFrames(true, "CVAR_UPDATE Scale") - end - end - end -end - ----Titan Handle PLAYER_LOGOUT On logout, set some debug data in saved variables. -function TitanPanelBarButton:PLAYER_LOGOUT() - if not IsTitanPanelReset then - -- for debug - if TitanPanelRegister then - TitanPanelRegister.ToBe = TitanPluginToBeRegistered - TitanPanelRegister.ToBeNum = TitanPluginToBeRegisteredNum - TitanPanelRegister.TitanPlugins = TitanPlugins - end - end - Titan__InitializedPEW = false -end - ----Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena -function TitanPanelBarButton:ZONE_CHANGED() - TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED") -end - ----Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena -function TitanPanelBarButton:ZONE_CHANGED_INDOORS() - TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED_INDOORS") -end - ----Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena -function TitanPanelBarButton:ZONE_CHANGED_NEW_AREA() - TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED_NEW_AREA") -end - ----Titan Handle PET_BATTLE_CLOSE Hide Titan bars during pet battle. -function TitanPanelBarButton:PET_BATTLE_OPENING_START() - TitanPanelBarButton_DisplayBarsWanted("PET_BATTLE_OPENING_START") -end - ----Titan Handle PET_BATTLE_CLOSE Show Titan bars hidden bars during pet battle. -function TitanPanelBarButton:PET_BATTLE_CLOSE() - TitanPanelBarButton_DisplayBarsWanted("PET_BATTLE_CLOSE") -end - -local in_combat = false -- seems InCombatLockdown may not be set fast enough to reliably hide bars... - ----Titan Handle PLAYER_REGEN_ENABLED Titan bars may be hidden during combat. ---- Use local in_combat - seems InCombatLockdown() may not be set fast enough to reliably hide bars... -function TitanPanelBarButton:PLAYER_REGEN_ENABLED() - in_combat = false - TitanPanelBarButton_DisplayBarsWanted("PLAYER_REGEN_ENABLED") - - if Titan_Global.switch.can_edit_ui then - -- No need - else - -- Adjust frame positions - TitanPanel_AdjustFrames(false, "PLAYER_REGEN_ENABLED") - end -end - ----Titan Handle PLAYER_REGEN_DISABLED Titan bars may have been hidden during combat. ---- Use local in_combat - seems InCombatLockdown() may not be set fast enough to reliably hide bars... -function TitanPanelBarButton:PLAYER_REGEN_DISABLED() - in_combat = true - TitanPanelBarButton_DisplayBarsWanted("PLAYER_REGEN_DISABLED") -end - -if Titan_Global.switch.can_edit_ui then - -- Do not need to adjust frames -else - function TitanPanelBarButton:ACTIVE_TALENT_GROUP_CHANGED() - -- Is this needed?? - -- TitanMovable_AdjustTimer("DualSpec") - end - - function TitanPanelBarButton:UNIT_ENTERED_VEHICLE(self, ...) - TitanUtils_CloseAllControlFrames(); - TitanUtils_CloseRightClickMenu(); - - -- Needed because 8.0 made changes to the menu bar processing (see TitanMovable) - TitanMovable_MenuBar_Disable() - end - - function TitanPanelBarButton:UNIT_EXITED_VEHICLE(self, ...) - -- A combat check will be done inside the adjust - TitanPanel_AdjustFrames(true, "UNIT_ENTERED_VEHICLE") - end - - --]] - -- -end - ----Titan Handle the button clicks on any Titan bar. ---- This only reacts to the right or left mouse click without modifiers. ---- Used in the set script for the Titan display and hider frames ----@param self table Titan bar frame ----@param button string Button clicked -function TitanPanelBarButton_OnClick(self, button) - -- ensure that the right-click menu will not appear on "hidden" bottom bar(s) - if (button == "LeftButton") then - TitanUtils_CloseAllControlFrames(); - TitanUtils_CloseRightClickMenu(); - elseif (button == "RightButton") then - TitanUtils_CloseAllControlFrames(); - TitanPanelRightClickMenu_Close(); - -- Show RightClickMenu anyway - TitanPanelRightClickMenu_Toggle(self) - end -end - --- --- Slash command handler --- - - ----local Helper to parse the user commands from Chat. ----@param cmd any ----@return table cmds List of 'words' user typed ---- each 'word' is made lower case for comparison simplicity -local function TitanPanel_ParseSlashCmd(cmd) - local words = {} - for w in string.gmatch(cmd, "%w+") do - words[#words + 1] = (w and string.lower(w) or "?") - end - --[[ - local tmp = "" - for idx,v in pairs (words) do - tmp = tmp.."'"..words[idx].."' " - end - - TitanDebug (tmp.." : "..#words) ---]] - return words -end - ----local Helper to tell the user the relevant Titan help commands. ----@param cmd string? 'all' default | 'reset' | 'gui' | 'silent' -local function handle_slash_help(cmd) - cmd = cmd or "all" - - -- Give the user the general help if we can not figure out what they want - TitanPrint("", "header") - -- Cannot count registered plugins after initial registration TitanUtils_RegisterPluginList() - - if cmd == "reset" then - TitanPrint(L["TITAN_PANEL_SLASH_RESET_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_RESET_1"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_RESET_2"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_RESET_3"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_RESET_4"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_RESET_5"], "plain") - end - if cmd == "gui" then - TitanPrint(L["TITAN_PANEL_SLASH_GUI_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_GUI_1"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_GUI_2"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_GUI_3"], "plain") - end - if cmd == "profile" then - TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_1"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_2"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_3"], "plain") - end - if cmd == "silent" then - TitanPrint(L["TITAN_PANEL_SLASH_SILENT_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_SILENT_1"], "plain") - end - if cmd == "orderhall" then - TitanPrint(L["TITAN_PANEL_SLASH_ORDERHALL_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_ORDERHALL_1"], "plain") - end - if cmd == "help" then - TitanPrint(L["TITAN_PANEL_SLASH_HELP_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_HELP_1"], "plain") - end - if cmd == "all" then - TitanPrint(L["TITAN_PANEL_SLASH_ALL_0"], "plain") - TitanPrint(L["TITAN_PANEL_SLASH_ALL_1"], "plain") - end -end - ----local Helper to handle 'reset' commands. ----@param cmd_list table 'tipfont' | 'panelscale' | "spacing" | none - Reset to Titan defaults -local function handle_reset_cmds(cmd_list) - local cmd = cmd_list[1] - local p1 = cmd_list[2] or nil - -- sanity check - if (not cmd == "reset") then - return - end - - if p1 == nil then - TitanPanel_ResetToDefault(); - elseif p1 == "tipfont" then - TitanPanelSetVar("TooltipFont", 1); - GameTooltip:SetScale(TitanPanelGetVar("TooltipFont")); - TitanPrint(L["TITAN_PANEL_SLASH_RESP1"], "info") - --[[ - elseif p1 == "tipalpha" then - TitanPanelSetVar("TooltipTrans", 1); - local red, green, blue, _ = GameTooltip:GetBackdropColor(); - local red2, green2, blue2, _ = GameTooltip:GetBackdropBorderColor(); - GameTooltip:SetBackdropColor(red,green,blue,TitanPanelGetVar("TooltipTrans")); - GameTooltip:SetBackdropBorderColor(red2,green2,blue2,TitanPanelGetVar("TooltipTrans")); - TitanPrint(L["TITAN_PANEL_SLASH_RESP2"], "info") ---]] - elseif p1 == "panelscale" then - if not InCombatLockdown() then - TitanPanelSetVar("Scale", 1); - TitanPanel_InitPanelBarButton("/panelscale reset ") - if Titan_Global.switch.can_edit_ui then - -- No need - else - -- Adjust frame positions - TitanPanel_AdjustFrames(true, "/panelscale reset ") - end - TitanPrint(L["TITAN_PANEL_SLASH_RESP3"], "info") - else - TitanPrint(L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"], "warning") - end - elseif p1 == "spacing" then - TitanPanelSetVar("ButtonSpacing", 20); - TitanPanel_InitPanelButtons(); - TitanPrint(L["TITAN_PANEL_SLASH_RESP4"], "info") - else - handle_slash_help("reset") - end -end - ----local Helper to handle 'gui' commands - open Titan options. ----@param cmd_list table -local function handle_giu_cmds(cmd_list) - local cmd = cmd_list[1] - local p1 = cmd_list[2] or nil - -- sanity check - if (not cmd == "gui") then - return - end - - -- DF changed how options are called. The best I get is the Titan 'about', not deeper. - Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About, TITAN_PANEL_CONFIG.topic.scale) - -- so the below does not work as expected... -end - ----local Helper to handle profile commands - Set to profile if not using global profile. ----@param cmd_list table -local function handle_profile_cmds(cmd_list) - local cmd = cmd_list[1] - local p1 = cmd_list[2] or nil - local p2 = cmd_list[3] or nil - local p3 = cmd_list[4] or nil - -- sanity check - if (not cmd == "profile") then - return - end - - if p1 == "use" and p2 and p3 then - if TitanAllGetVar("GlobalProfileUse") then - TitanPrint(L["TITAN_PANEL_GLOBAL_ERR_1"], "info") - else - TitanVariables_UseSettings(TitanUtils_CreateName(p2, p3), TITAN_PROFILE_USE) - end - else - handle_slash_help("profile") - end -end - ----local Helper to handle 'silent' commands - Toggle "Silenced" setting. ----@param cmd_list table -local function handle_silent_cmds(cmd_list) - local cmd = cmd_list[1] - -- sanity check - if (not cmd == "silent") then - return - end - - if TitanAllGetVar("Silenced") then - TitanAllSetVar("Silenced", false); - TitanPrint(L["TITAN_PANEL_MENU_SILENT_LOAD"] .. " " .. L["TITAN_PANEL_MENU_DISABLED"], "info") - else - TitanAllSetVar("Silenced", true); - TitanPrint(L["TITAN_PANEL_MENU_SILENT_LOAD"] .. " " .. L["TITAN_PANEL_MENU_ENABLED"], "info") - end -end - ----local Helper to handle 'orderhall' commands - Toggle "OrderHall" setting. ----@param cmd_list table -local function handle_orderhall_cmds(cmd_list) - local cmd = cmd_list[1] - local p1 = cmd_list[2] or nil - -- sanity check - if (not cmd == "orderhall") then - return - end - - if TitanAllGetVar("OrderHall") then - TitanAllSetVar("OrderHall", false); - TitanPrint(L["TITAN_PANEL_MENU_HIDE_ORDERHALL"] .. " " .. L["TITAN_PANEL_MENU_ENABLED"], "info") - StaticPopupDialogs["TITAN_RELOAD"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_RELOAD"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self) - ReloadUI(); - end, - showAlert = 1, - timeout = 0, - whileDead = 1, - hideOnEscape = 1 - }; - StaticPopup_Show("TITAN_RELOAD"); - else - TitanAllSetVar("OrderHall", true); - TitanPrint(L["TITAN_PANEL_MENU_HIDE_ORDERHALL"] .. " " .. L["TITAN_PANEL_MENU_DISABLED"], "info") - StaticPopupDialogs["TITAN_RELOAD"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_RELOAD"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self) - ReloadUI(); - end, - showAlert = 1, - timeout = 0, - whileDead = 1, - hideOnEscape = 1 - }; - StaticPopup_Show("TITAN_RELOAD"); - end -end - ---[=[ local -DESC: Helper to execute the help commands from the user. -VAR: cmd_list - A table containing the list of 'words' the user typed in -OUT: None -local function handle_help_cmds(cmd_list) - local cmd = cmd_list[1] - local p1 = cmd_list[2] or nil - -- sanity check - if (not cmd == "help") then - return - end - - handle_slash_help(p1 or "all") -end ---]=] - ----local Helper to parse and execute all the Titan slash commands from the user. ----@param cmd_str string -local function TitanPanel_RegisterSlashCmd(cmd_str) - local cmd_list = {} - -- parse what the user typed - cmd_list = TitanPanel_ParseSlashCmd(cmd_str) - local cmd = cmd_list[1] or "" - local p1 = cmd_list[2] or "" - local p2 = cmd_list[3] or "" - local p3 = cmd_list[4] or "" - - if (cmd == "reset") then - handle_reset_cmds(cmd_list) - elseif (cmd == "gui") then - handle_giu_cmds(cmd_list) - elseif (cmd == "profile") then - handle_profile_cmds(cmd_list) - elseif (cmd == "silent") then - handle_silent_cmds(cmd_list) - elseif (cmd == "orderhall") then - handle_orderhall_cmds(cmd_list) - elseif (cmd == "help") then - handle_slash_help(p1) - else - handle_slash_help("all") - end -end - ---====== Register slash commands for Titan Panel -SlashCmdList["TitanPanel"] = TitanPanel_RegisterSlashCmd; -SLASH_TitanPanel1 = "/titanpanel"; -SLASH_TitanPanel2 = "/titan"; - --------------------------------------------------------------- --- --- Texture routines - - ----local Set the Titan bar color per user selection ----@param frame string Titan bar name ----@param tex table Texture frame to set ----@param color table Color - RBGA -local function Set_Color(frame, tex, color) - --[[ -print("_Set bar color" -.." "..tostring(TitanBarData[frame].tex_name).."" ---.." "..tostring(tex:GetName()).."" -.." "..tostring(format("%0.1f", color.r)).."" -.." "..tostring(format("%0.1f", color.g)).."" -.." "..tostring(format("%0.1f", color.b)).."" -.." "..tostring(format("%0.1f", color.alpha)).."" -) ---]] - _G[frame]:SetBackdrop({ - bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", - -- edgeFile="Interface\\Tooltips\\UI-Tooltip-Border", - -- edgeFile="Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - edgeFile = "Interface\\Glues\\Common\\TextPanel-Border", - tile = true, - tileEdge = true, - -- insets = { left = 1, right = 1, top = 1, bottom = 1 }, - tileSize = 8, - edgeSize = 8, - }) - - _G[frame]:SetBackdropBorderColor( - TOOLTIP_DEFAULT_COLOR.r, - TOOLTIP_DEFAULT_COLOR.g, - TOOLTIP_DEFAULT_COLOR.b, - color.alpha); -- 2024 AUg : Border will use the color alpha - _G[frame]:SetBackdropColor( - color.r, - color.g, - color.b, - color.alpha); -end - ----local Set the Titan bar texture / skin per user selectable options ----@param frame string Titan bar name ----@param tex table Texture frame to set ----@param skin table Skin to use -local function Set_Skin(frame, tex, skin) - -- skins are in two parts - top & bottom... - -- TODO : have Short bars choose top or bottom skin?? - local edge = "" - if TitanBarData[frame].vert == TITAN_BOTTOM - then - edge = TITAN_BOTTOM - else - edge = TITAN_TOP - end - - -- Apply the texture to the bar, using the system repeat to fill it - local texture_file = skin.path .. "TitanPanelBackground" .. edge .. "0" - --[[ -print("_Skin" -.." "..tostring(TitanBarData[frame].tex_name.."" ---.." "..tostring(tex:GetName()).."" -.." "..tostring(skin.path).."" ---.."\n "..tostring(edge).."" ---.." "..tostring(skin.alpha).."" ---.."\n "..tostring(tex:GetTexture()).."" -) ---]] - --[[ -- appears seeting image this way just smears image... - _G[frame]:SetBackdrop({ - bgFile=texture_file, --- edgeFile=nil, - tile = true, --- tileSize = 256, --- tileEdge = true, --- insets = { left = 1, right = 1, top = 1, bottom = 1 }, --- tileSize = 8, --- edgeSize = 8, - }) ---]] - tex:SetAllPoints() - tex:SetHorizTile(true) -- ensures repeat; 'smears' if not sest to true - tex:SetTexture(texture_file, "REPEAT") - tex:SetVertTile(true) -- ensures image is 'full' height of frame - -- tex:SetHeight(TITAN_PANEL_BAR_TEXTURE_HEIGHT) -- leaves a gap if used - tex:SetAlpha(skin.alpha) -end - ----Titan Set the texture / skin of the bar per the user selection. ----@param frame string Titan bar frame name -function TitanPanel_SetBarTexture(frame) - if frame and TitanBarData[frame] then - -- proceed - else - return - end - - -- Create the path & file name to the texture - local tex = TitanBarData[frame].tex_name - local titanTexture = {} - if _G[tex] then - titanTexture = _G[tex] - else - titanTexture = _G[frame]:CreateTexture(tex, "BACKGROUND") - end - titanTexture:SetTexture() - _G[frame]:SetBackdrop({ - bgFile = "", - }) - - --[[ -print("_Tex" -.." "..tostring(TitanBarData[frame].name).."" ---.." "..tostring(tex).."" -.." "..tostring(titanTexture:GetName()).."" ---.." "..tostring(skin.path).."" ---.."\n "..tostring(edge).."" ---.." "..tostring(skin.alpha).."" ---.."\n "..tostring(tex:GetTexture()).."" -.." "..tostring(TitanBarDataVars["Global"].texure).."" -.." "..tostring(TitanBarDataVars[frame].texure).."" -) ---]] - -- Use the texture / skin per user selectable options - if TitanBarDataVars["Global"].texure == Titan_Global.SKIN then - Set_Skin(frame, titanTexture, TitanBarDataVars["Global"].skin) -- tex_path = TitanPanelGetVar("TexturePath") - elseif TitanBarDataVars["Global"].texure == Titan_Global.COLOR then - Set_Color(frame, titanTexture, TitanBarDataVars["Global"].color) - elseif TitanBarDataVars[frame].texure == Titan_Global.SKIN then - Set_Skin(frame, titanTexture, TitanBarDataVars[frame].skin) - elseif TitanBarDataVars[frame].texure == Titan_Global.COLOR then - Set_Color(frame, titanTexture, TitanBarDataVars[frame].color) - end -end - --------------------------------------------------------------- --- --- auto hide event handlers - - ----Titan On leaving the display check if we have to hide the Titan bar. A timer is used - when it expires the bar is hidden. ----@param self table Titan bar frame -function TitanPanelBarButton_OnLeave(self) - local frame = (self and self:GetName() or nil) - local bar = (TitanBarData[frame] and TitanBarData[frame].name or nil) - - -- if auto hide is active then let the timer hide the bar - local hide = (bar and TitanBarDataVars[frame].auto_hide or nil) - -- local hide = (bar and TitanPanelGetVar(bar.."_Hide") or nil) - if hide then - Titan_AutoHide_Timers(frame, "Leave") - end -end - ----Titan No code - this is a place holder for the XML template. ----@param self table Titan Hider bar frame -function TitanPanelBarButton_OnEnter(self) - -- no work to do -end - ----Titan No code - this is a place holder for the XML template. ----@param self table Titan Hider bar frame -function TitanPanelBarButtonHider_OnLeave(self) - -- no work to do -end - ----Titan On entering the hider, check if we need to show the display bar. ---- No action is taken if the user is on combat. ----@param self table Titan Hider bar frame -function TitanPanelBarButtonHider_OnEnter(self) - -- make sure self is valid - local index = self and self:GetName() or nil - if not index then return end -- sanity check - - -- so the bar does not 'appear' when moused over in combat - if TitanPanelGetVar("LockAutoHideInCombat") and InCombatLockdown() then return end - - -- find the relevant bar data - local frame = nil - for idx, v in pairs(TitanBarData) do - if index == TitanBarData[idx].hider then - frame = idx - end - end - -- Now process that bar - if frame then - Titan_AutoHide_Timers(frame, "Enter") - TitanPanelBarButton_Show(frame) - end -end - ---====== Titan Frames for CLASSIC versions - --- ---========================== --- Routines to handle adjusting some UI frames --- - ---[[ Appears unsed... ----Titan Align the buttons per the user's new choice. ----@param align number left or center -function TitanPanelBarButton_ToggleAlign(align) - -- toggle between left or center - if (TitanPanelGetVar(align) == TITAN_PANEL_BUTTONS_ALIGN_CENTER) then - TitanPanelSetVar(align, TITAN_PANEL_BUTTONS_ALIGN_LEFT); - else - TitanPanelSetVar(align, TITAN_PANEL_BUTTONS_ALIGN_CENTER); - end - - -- Justify button position - TitanPanelButton_Justify(); -end ---]] - ----Titan Toggle the auto hide of the given Titan bar per the user's new choice. ----@param frame string Frame mame of the Titan bar -function TitanPanelBarButton_ToggleAutoHide(frame) - local frName = _G[frame] - local plugin = (TitanBarData[frame] and TitanBarData[frame].auto_hide_plugin or nil) - - if frName then - Titan_AutoHide_ToggleAutoHide(_G[plugin]) - end -end - ----Titan Toggle whether Titan adjusts 'top' frames around Titan bars per the user's new choice. ---- Another addon can tell Titan to NOT adjust some or all frames. -function TitanPanelBarButton_ToggleScreenAdjust() - -- Turn on / off adjusting of other frames around Titan - TitanPanelToggleVar("ScreenAdjust"); - TitanPanel_AdjustFrames(true, "_ToggleScreenAdjust") -end - ----Titan Toggle whether Titan adjusts 'bottom' frames around Titan bars per the user's new choice. ---- Another addon can tell Titan to NOT adjust some or all frames. -function TitanPanelBarButton_ToggleAuxScreenAdjust() - -- turn on / off adjusting of frames at the bottom of the screen - TitanPanelToggleVar("AuxScreenAdjust"); - TitanPanel_AdjustFrames(true, "_ToggleAuxScreenAdjust") -end - ---====== Titan Bar --- ---========================== --- Routines to handle moving and sizing of short bars --- - ----local Check the change in width; snap to edge of any part goes off screen. ----@param self table Titan short bar frame ----@param width number New width ----@param reason string Note on why this was called ----@return table result .ok boolean; .err string -local function CheckBarBounds(self, width, reason) - -- This is a touchy routine - change with care!! :) - -- - -- Let WoW handle any change in game scale. - -- When Titan scaling changes, recalc the bar placement. - -- Although the user may want to move bars in response to any scale change. - local trace = false -- true false - local result = {} - result.ok = true - result.err = "" - local err = "" - - local f_name = self:GetName() - local bar_name = TitanBarData[f_name].name - local locale_name = TitanBarData[f_name].locale_name - - if TitanBarData[f_name].user_move - and TitanBarDataVars[f_name].show - then ----[[ - if trace then - print("Bounds" - .. " " .. tostring(bar_name) .. "" - .. " " .. tostring(width) .. "" - .. " " .. tostring(reason) .. "" - ) - end ---]] - - local tscale = TitanPanelGetVar("Scale") - local x, y, w, scale = TitanVariables_GetBarPos(f_name) - local scale_change = false - if tscale == scale then - -- no need to use scaling to recalc position - else - scale_change = true - -- The 'set' will update the sacaling for next time - end - local screen = TitanUtils_ScreenSize() - local screen_right_scaled = screen.scaled_x - local screen_top_scaled = screen.scaled_y - local screen_right = screen.x - local screen_top = screen.y - local screen_right_t = screen.x * tscale - local screen_top_t = screen.y * tscale - - local bar_left = math.floor(self:GetLeft()) - local bar_right = math.floor(self:GetRight()) - local bar_top = math.floor(self:GetTop()) - local bar_bottom = math.floor(self:GetBottom()) - - local orig_w = self:GetWidth() -- * tscale --math.floor(self:GetWidth() * tscale) - local l_off = bar_left - local r_off = bar_right - local t_off = bar_top - local b_off = bar_bottom - local hght = (t_off - b_off) - - if scale_change then - -- Apply the Titan scaling to get 'real' position within WoW window; - -- Use floor to trunc decimal places where the side could be right on the edge of the screen. - l_off = math.floor(bar_left * tscale) - r_off = math.floor(bar_right * tscale) - t_off = math.floor(bar_top * tscale) - b_off = math.floor(bar_bottom * tscale) - else - -- Just check the bar position - end ----[[ - if trace then - print(">Bounds" - .. " " .. tostring(bar_name) .. "" - .. "\n" - .. " L " .. tostring(format("%0.1f", l_off)) .. "" - .. " R " .. tostring(format("%0.1f", r_off)) .. "" - .. " T " .. tostring(format("%0.1f", t_off)) .. "" - .. " B " .. tostring(format("%0.1f", b_off)) .. "" - .. " W " .. tostring(format("%0.1f", orig_w)) .. "" - .. " H " .. tostring(format("%0.1f", hght)) .. "" - .. "\n" - .. " SR " .. tostring(format("%0.1f", screen_right)) .. "" - .. " ST " .. tostring(format("%0.1f", screen_top)) .. "" - .. " SR_t " .. tostring(format("%0.1f", screen_right_t)) .. "" - .. " ST_t " .. tostring(format("%0.1f", screen_top_t)) .. "" - ) - end ---]] - local w = 0 - local x_off = 0 - local y_off = 0 - local w_off = 0 - - -- Assume all ok :) - x_off = l_off - y_off = b_off - - if (width == 0) then -- drag & drop OR entry / reload - -- Assumes BOTTOMLEFT of screen per Short bar defaults. - -- if resolution is not 'pixel perfect' rounding could cause algorithm to think bar is off screen - - -- Keep the width - w_off = orig_w - - if l_off < 0 then - x_off = 0 - err = "Off left of screen, snap to edge" - elseif (r_off) > screen_right then - x_off = math.floor(screen_right - (r_off - l_off)) - err = "Off right side of screen, snap to edge" - end - if err ~= "" then - result.ok = false - result.err = err - if trace then - TitanPrint(locale_name .. " " .. err .. "!!!!" - , "warning") - end - end - err = "" - if (t_off) > screen_top then - y_off = math.floor(screen_top - (t_off - b_off)) - err = "Off top of screen, snap to edge" - elseif b_off < 0 then - y_off = 0 - err = "Off bottom of screen, snap to edge" - end - if err ~= "" then - result.ok = false - result.err = result.err .. "\n" .. err - if trace then - TitanPrint(locale_name .. " " .. err .. "!!!!" - .. " [" .. tostring(format("%0.1f", x_off)) .. "]" - .. " [" .. tostring(format("%0.1f", y_off)) .. "]" - , "warning") - end - end - else -- width change - local min_w, min_h, max_w, max_h = self:GetResizeBounds() - -- Keep the X and Y - local w_new = orig_w + width - if w_new < min_w then - -- do nothing - too small - w_off = min_w - err = "Width too small. Set to min width." - elseif w_new > max_w then - w_off = max_w - err = "Width too big. Set to max width." -- too wide - elseif x_off + (w_new * tscale) > screen_right then - w_off = orig_w - err = "Off right of screen, snap to edge" - else - w_off = w_new - end - - self:SetSize(w_off, TITAN_PANEL_BAR_HEIGHT) - -- self:SetWidth(w_off) - end - - if scale_change then - -- Back out Titan scaling - x_off = math.floor(x_off / tscale) - y_off = math.floor(y_off / tscale) - else - -- Accept the results of the checks - end - w_off = w_off --/ tscale - TitanVariables_SetBarPos(self, false, x_off, y_off, w_off) - - if trace then - print(">>Bounds" - .. " " .. tostring(bar_name) .. "" - .. " " .. tostring(result.ok) .. "" - .. " SC " .. tostring(scale_change) .. "" - .." X "..tostring(format("%0.1f", x_off)).."("..tostring(bar_left)..")" - .. " Y " .. tostring(format("%0.1f", y_off)).."("..tostring(bar_bottom)..")" - .. " W " .. tostring(format("%0.1f", w_off)) .. "" - ) - if err ~= "" then - TitanPrint(locale_name .. " " .. err .. "!!!!" - .. " [" .. tostring(format("%0.1f", x_off)) .. "]" - .. " [" .. tostring(format("%0.1f", y_off)) .. "]" - .. " [" .. tostring(format("%0.1f", w_off)) .. "]" - , "warning") - end - end - else - -- Controlled with anchor points; cannot move so no check is needed - end - - - return result -end - ----local Start the grap of a Short Titan bar if Shift and left mouse are held. ----@param self table -local function OnMoveStart(self) - if IsShiftKeyDown() then - if self:IsMovable() then - self.isMoving = true - self:StartMoving() - _G.GameTooltip:Hide() - end - else - -- Do not move - end -end - ----local When a Short Titan bar drag is stopped. ----@param self table -local function OnMovingStop(self) - self:StopMovingOrSizing() - self.isMoving = nil - - local res = CheckBarBounds(self, 0, "OnMovingStop") - if res.ok then - -- placement ok - else - -- Need to 'snap' it to an edge - TitanPanel_InitPanelBarButton("OnMovingStop") - end - -- Seems overkill - this will recalc all bars... -end - ----local Change the width of a Short Titan bar when mouse is over the bar and Shift is held when the mouse wheel is used. ----@param self table Frame mouse is over ----@param d integer Mouse wheel direction (1 larger; -1 smaller) ---- Assuming a 1 'click' is a pixel -local function OnMouseWheel(self, d) - -- Can get noisy, "Initializes" all bars at each click to ensure the bar is drawn. - if IsShiftKeyDown() then - local msg = "OnMouseWheel" - local delta = d - if IsControlKeyDown() then - delta = d * 10 - msg = msg.." +Alt" - else - -- use 1 - end - local res = CheckBarBounds(self, delta, msg) - if res.ok then - end - --[[ -print("wheel" -.." "..tostring(self:GetName()).."" -.." "..tostring(d).."" -.." old: "..tostring(format("%0.1f", old_w)).."" -.." new: "..tostring(format("%0.1f", self:GetWidth())).."" -.." ok: "..tostring(res.ok).."" -) ---]] - -- TitanPanel_InitPanelBarButton("OnMouseWheel") - end -end - ----Titan Force all plugins created from LDB addons, visible or not, to be on the right side of the Titan bar. ---- Any visible plugin will be forced to the right side on the same bar it is currently on. -function TitanPanelBarButton_ForceLDBLaunchersRight() - local plugin = {} - for index, id in pairs(TitanPluginsIndex) do - plugin = TitanUtils_GetPlugin(id); - if plugin and plugin.ldb == "launcher" - and not TitanGetVar(id, "DisplayOnRightSide") then - TitanToggleVar(id, "DisplayOnRightSide"); - local button = TitanUtils_GetButton(id) - if button then - local buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; - if not TitanGetVar(id, "ShowIcon") then - TitanToggleVar(id, "ShowIcon"); - end - TitanPanelButton_UpdateButton(id); - if buttonText then - buttonText:SetText("") - button:SetWidth(16); - TitanPlugins[id].buttonTextFunction = nil; - _G[TitanUtils_ButtonName(id) .. TITAN_PANEL_TEXT] = nil; - if button:IsVisible() then - local bar = TitanUtils_GetWhichBar(id) - TitanPanel_RemoveButton(id); - TitanUtils_AddButtonOnBar(bar, id) - end - end - end - end - end -end - ----local Helper to create the 'anchor' frames used by other addons that need to adjust so Titan can be visible. ----The anchor frames are adjusted depending on which Titan bars the user selects to show. ---- - TitanPanelTopAnchor - the frame at the bottom of the top bar(s) shown. ---- - TitanPanelBottomAnchor - the frame at the top of the bottom bar(s) shown. -local function TitanAnchors() - local anchor_top = TitanMovable_GetPanelYOffset(TITAN_PANEL_PLACE_TOP) - local anchor_bot = TitanMovable_GetPanelYOffset(TITAN_PANEL_PLACE_BOTTOM) - anchor_top = anchor_top <= TITAN_WOW_SCREEN_TOP and anchor_top or TITAN_WOW_SCREEN_TOP - anchor_bot = anchor_bot >= TITAN_WOW_SCREEN_BOT and anchor_bot or TITAN_WOW_SCREEN_BOT - - local top_point, top_rel_to, top_rel_point, top_x, top_y = TitanPanelTopAnchor:GetPoint(TitanPanelTopAnchor - :GetNumPoints()) - local bot_point, bot_rel_to, bot_rel_point, bot_x, bot_y = TitanPanelBottomAnchor:GetPoint(TitanPanelBottomAnchor - :GetNumPoints()) - top_y = floor(tonumber(top_y) + 0.5) - bot_y = floor(tonumber(bot_y) + 0.5) - --[[ -TitanDebug("Anc top: "..top_y.." bot: "..bot_y -.." a_top: "..anchor_top.." a_bot: "..anchor_bot -) ---]] - if top_y ~= anchor_top then - TitanPanelTopAnchor:ClearAllPoints() - TitanPanelTopAnchor:SetPoint(top_point, top_rel_to, top_rel_point, top_x, anchor_top); - end - if bot_y ~= anchor_bot then - TitanPanelBottomAnchor:ClearAllPoints() - TitanPanelBottomAnchor:SetPoint(bot_point, bot_rel_to, bot_rel_point, bot_x, anchor_bot) - end -end - ----Titan Show all the Titan bars the user has selected. ----@param reason string Debug note on where the call initiated -function TitanPanelBarButton_DisplayBarsWanted(reason) - -- build debug output - local str = "_DisplayBarsWanted" - .." "..tostring(reason).."" - Titan_Debug.Out('titan', 'bars_setup', str) - - -- Check all bars to see if the user has requested they be shown - for idx, v in pairs(TitanBarData) do - -- Show / hide plus kick auto hide, if needed - Titan_AutoHide_Init(idx) - end - - -- Set anchors for other addons to use. - TitanAnchors() - - if Titan_Global.switch.can_edit_ui then - -- Not needed with UI movable widgets - -- build debug output - local str = "_DisplayBarsWanted" - .." UI user editable - skip adj frames" - Titan_Debug.Out('titan', 'bars_setup', str) - else - -- Adjust other frames because the bars shown / hidden may have changed - TitanPanel_AdjustFrames(true, "_DisplayBarsWanted") - end -end - ----Titan This routine will hide all the Titan bars (and hiders) regardless of what the user has selected. ---- For example when the pet battle is active. We cannot figure out how to move the pet battle frame so we are punting and hiding Titan... ---- We only need to hide the bars (and hiders) - not adjust frames -function TitanPanelBarButton_HideAllBars() - for idx, v in pairs(TitanBarData) do - TitanPanelBarButton_Hide(idx) - end -end - ----local Show the requested Titan bar. ----@param frame_str string Titan bar ----@return boolean CanShow False if there is a restricting condition -local function showBar(frame_str) - local flag = true -- only set false for known conditions - - if frame_str == TitanVariables_GetFrameName("Bar") - or frame_str == TitanVariables_GetFrameName("Bar2") - then - -- ===== Battleground or Arena : User selected --- if (TitanPanelGetVar("HideBarsInPVP")) - if TitanBarDataVars[frame_str].hide_in_pvp - and (C_PvP.IsBattleground() - or C_PvP.IsArena() - -- or GetZoneText() == "Stormwind City" - -- or GetZoneText() == "Tempest Keep" - ) - then - flag = false - end - end - - -- ===== In Combat : User selected - if TitanBarDataVars[frame_str].hide_in_combat --- or TitanPanelGetVar("HideBarsInCombat") - then - if in_combat then -- InCombatLockdown() too slow - flag = false - end - end - - -- ===== In Pet Battle - if C_PetBattles and C_PetBattles.IsInBattle() then - if TitanBarData[frame_str].user_move then - -- leave as is - else - flag = false - end - end - --[[ -print("showBar" ---.." "..tostring(C_PetBattles.IsInBattle()).."" -.." > "..tostring(flag).."" -.." '"..tostring(frame_str).."'" -) ---]] - return flag -end - ----local Set the position of the requested Titan bar. ----@param frame string Titan bar -local function SetBar(frame) - local trace = false - local display = _G[frame]; - - local x, y, w = TitanVariables_GetBarPos(frame) - local tscale = TitanPanelGetVar("Scale") - local show = TitanBarData[frame].show - local bott = TitanBarData[frame].bott - - - display:ClearAllPoints() - if trace then - -- local screen = TitanUtils_ScreenSize() - -- local sx = screen.scaled_x - -- local sy = screen.scaled_y - print("SetBar" - .. " " .. tostring(TitanBarData[frame].name) .. "" - .. " x:" .. tostring(format("%0.1f", x)) .. "" - .. " y:" .. tostring(format("%0.1f", y)) .. "" - .. " w:" .. tostring(format("%0.1f", w)) .. "" - ) - end - - if TitanBarData[frame].user_move then - display:SetPoint(show.pt, show.rel_fr, show.rel_pt, x, y) - display:SetSize(w, TITAN_PANEL_BAR_HEIGHT) - else - display:SetPoint(show.pt, show.rel_fr, show.rel_pt, x, y) - local h = TITAN_PANEL_BAR_HEIGHT - display:SetPoint(bott.pt, bott.rel_fr, bott.rel_pt, x, y - h) - end -end - ----Titan Toggle the given Titan bar based on the user selection. ----@param frame string Frame mame of the Titan bar -function TitanPanelBarButton_Show(frame) - local display = _G[frame]; - - if display and TitanBarData[frame].name - then - if TitanBarDataVars[frame].show -- User requested - and showBar(frame) -- No preventing condition - then -- Place Bar - SetBar(frame) - ---[[ - -- The bar may need to be moved back onto the screen. - local res = CheckBarBounds(display, 0, "_Show the bar") - if res.ok then - -- placement ok - else - -- Need to 'snap' it to an edge - SetBar(frame) - end - --]] - TitanPanel_SetBarTexture(frame) - - if TitanBarData[frame].hider then - _G[TitanBarData[frame].hider]:Hide() - else - -- not allowed for this bar - end - else - -- The user has not elected to show this bar - TitanPanelBarButton_Hide(frame) - end - end -end - ----Titan Hide the given Titan bar based on the user selection. ---- Hide moves rather than just 'not shown'. Otherwise the buttons will stay visible defeating the purpose of hide. ---- Also moves the hider bar if auto hide is not selected. ----@param frame string Frame mame of the Titan bar -function TitanPanelBarButton_Hide(frame) - if TITAN_PANEL_MOVING == 1 then return end - - local display = _G[frame] - local data = TitanBarData[frame] - - if display and data - then - local x, y, w = TitanVariables_GetBarPos(frame) - -- This moves rather than hides. If we just hide then the plugins will still show. - -- Hide by ensuriing the Y offset is off the screen. - display:ClearAllPoints() - local h = (math.abs(y) + TITAN_PANEL_BAR_HEIGHT * 2) * (-1 * y) - local h = data.hide_y - --[[ -print("_Hide" ---.." "..tostring(frame).."" -.." "..tostring(data.name).."" -.." "..tostring(TitanBarDataVars[frame].show).."" -.." "..tostring(h).."" -) ---]] - if TitanBarData[frame].user_move then - display:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, h) - else - display:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, h) - display:SetPoint(data.bott.pt, data.bott.rel_fr, data.bott.rel_pt, x, h - TITAN_PANEL_BAR_HEIGHT) - end - - if TitanBarData[frame].hider then - local hider = _G[data.hider] - if TitanBarDataVars[frame].show - and TitanBarDataVars[frame].auto_hide then - -- if (TitanPanelGetVar(data.name.."_Show")) and (TitanPanelGetVar(data.name.."_Hide")) then - -- Auto hide is requested so show the hider bar in the right place - hider:ClearAllPoints(); - hider:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, y); - hider:Show() - else - -- The bar was not requested - hider:Hide() - end - else - -- not allowed for this bar - end - end -end - ----Titan Show all user selected plugins on the Titan bar(s) then justify per the user selection. ---- This is done an all bars whether shown or not. -function TitanPanel_InitPanelButtons() - local button - local r_prior = {} - local l_prior = {} - local scale = TitanPanelGetVar("Scale"); - local button_spacing = TitanPanelGetVar("ButtonSpacing") * scale - local icon_spacing = TitanPanelGetVar("IconSpacing") * scale - - local prior = {} - -- set prior to the starting offsets - -- The right side plugins are set here. - -- Justify adjusts the left side start according to the user setting - -- The effect is left side plugins has spacing on the right side and - -- right side plugins have spacing on the left. - for idx, v in pairs(TitanBarData) do - local bar = TitanBarData[idx].name - local y_off = TitanBarData[idx].plugin_y_offset - prior[bar] = { - right = { - button = TitanVariables_GetFrameName(bar), - anchor = "RIGHT", - x = 5, -- Offset of first plugin to right side of screen - y = y_off, - }, - left = { - button = TitanVariables_GetFrameName(bar), - anchor = "LEFT", - x = 0, -- Justify adjusts - center or not - y = y_off, - }, - } - end - -- - TitanPanelBarButton_DisplayBarsWanted("TitanPanel_InitPanelButtons"); - - -- Position all the buttons - for idx = 1, table.maxn(TitanPanelSettings.Buttons) do - local id = TitanPanelSettings.Buttons[idx]; - if (TitanUtils_IsPluginRegistered(id)) then - local i = TitanPanel_GetButtonNumber(id); - button = TitanUtils_GetButton(id); - - if button then - -- If the plugin has asked to be on the right - if TitanUtils_ToRight(id) then - -- ========================= - -- position the plugin relative to the prior plugin - -- or the bar if it is the 1st - r_prior = prior[TitanPanelSettings.Location[i]].right - -- ========================= - button:ClearAllPoints(); - button:SetPoint("RIGHT", _G[r_prior.button]:GetName(), r_prior.anchor, (-(r_prior.x) * scale), - r_prior.y) - - -- ========================= - -- capture the button for the next plugin - r_prior.button = TitanUtils_ButtonName(id) - -- set prior[x] the anchor points and offsets for the next plugin - r_prior.anchor = "LEFT" - r_prior.x = icon_spacing - r_prior.y = 0 - -- ========================= - else - -- handle plugins on the left side of the bar - -- - -- ========================= - -- position the plugin relative to the prior plugin - -- or the bar if it is the 1st - l_prior = prior[TitanPanelSettings.Location[i]].left - --[===[ -print("Bar plugins" -.." "..tostring(i).."" -.." "..tostring(TitanPanelSettings.Location[i]).."" -.." "..tostring(id).."" -) ---]===] - -- ========================= - -- - button:ClearAllPoints(); - button:SetPoint("LEFT", _G[l_prior.button]:GetName(), l_prior.anchor, l_prior.x * scale, l_prior.y); - - -- ========================= - -- capture the next plugin - l_prior.button = TitanUtils_ButtonName(id) - -- set prior[x] (anchor points and offsets) for the next plugin - l_prior.anchor = "RIGHT" - l_prior.x = (button_spacing) - l_prior.y = 0 - -- ========================= - end - button:Show() - end - end - end - -- Set panel button init flag - TITAN_PANEL_BUTTONS_INIT_FLAG = 1; - TitanPanelButton_Justify(); -end - ----Titan Reorder all the shown all user selected plugins on the Titan bar(s). Typically used after a button has been removed / hidden. ----@param index number of the plugin removed -function TitanPanel_ReOrder(index) - for i = index, #TitanPanelSettings.Buttons do --- for i = index, table.getn(TitanPanelSettings.Buttons) do - TitanPanelSettings.Location[i] = TitanPanelSettings.Location[i + 1] - end -end - ----Titan Remove a plugin then show the rest of user selected plugins on the Titan bar(s). ----@param id string Unique ID of the plugin ----@param hide_plugin? boolean whether to hide plugin after removal -function TitanPanel_RemoveButton(id, hide_plugin) - if (not TitanPanelSettings) then - return; - end - - local hide_me = hide_plugin - if hide_me == nil then - hide_me = true -- not passed - else - -- was passed - end - - local i = TitanPanel_GetButtonNumber(id) - local currentButton = TitanUtils_GetButton(id); - - -- safeguard ... - -- This cancels all timers of name "TitanPanel"..id as a safeguard to destroy any active plugin timers - -- based on a fixed naming convention : TitanPanel..id, eg. "TitanPanelClock" this prevents "rogue" - -- timers being left behind by lack of an OnHide check ----@diagnostic disable-next-line: missing-parameter - if id then AceTimer.CancelAllTimers() end -- ??? seems confused 0 or 1 params "TitanPanel" .. id - - TitanPanel_ReOrder(i); - table.remove(TitanPanelSettings.Buttons, TitanUtils_GetCurrentIndex(TitanPanelSettings.Buttons, id)); - if currentButton and hide_me then - currentButton:Hide(); - end - -- Show the existing buttons - TitanPanel_InitPanelButtons(); -end - ---- Titan Get the index of the given plugin from the Titan plugin displayed list. ---- The routine returns +1 if not found so it is 'safe' to add to the list ----@param id string Unique ID of the plugin ----@return number num position or num + 1 for end -function TitanPanel_GetButtonNumber(id) - -- getn deprecated as of 5.2 - IDE now complaining 2024 Aug - if (TitanPanelSettings) then - for i = 1, #TitanPanelSettings.Buttons do - if (TitanPanelSettings.Buttons[i] == id) then - return i; - end - end - return #TitanPanelSettings.Buttons + 1; - else - return 0; - end -end - ----Titan Update / refresh each plugin from the Titan plugin list. Used when a Titan option is changed that effects all plugins. -function TitanPanel_RefreshPanelButtons() - if (TitanPanelSettings) then - for i = 1, #TitanPanelSettings.Buttons do - TitanPanelButton_UpdateButton(TitanPanelSettings.Buttons[i], 1); - end - end -end - ----Titan Justify the plugins on each Titan bar. ---- Used when : ----- Init / show of a Titan bar -----the user changes the 'center' option on a Titan bar -function TitanPanelButton_Justify() - -- Only the left side buttons are justified. - if (not TITAN_PANEL_BUTTONS_INIT_FLAG or not TitanPanelSettings) then - return; - end - if InCombatLockdown() then - --TitanDebug("_Justify during combat!!!") - return; - -- Issue 856 where some taint is caused if the plugin size is updated during combat. Seems since Mists was released... - end - - local bar - local x_offset - local y_offset - local firstLeftButton - local scale = TitanPanelGetVar("Scale"); - local button_spacing = TitanPanelGetVar("ButtonSpacing") * scale - local icon_spacing = TitanPanelGetVar("IconSpacing") * scale - local leftWidth = 0; - local rightWidth = 0; - local counter = 0; - local align = 0; - local center_offset = 0; - - -- Look at each bar for plugins. - for idx, v in pairs(TitanBarData) do - bar = TitanBarData[idx].name - y_offset = TitanBarData[idx].plugin_y_offset - x_offset = TitanBarData[idx].plugin_x_offset - firstLeftButton = TitanUtils_GetButton(TitanPanelSettings.Buttons - [TitanUtils_GetFirstButtonOnBar(bar, TITAN_LEFT)]) - align = TitanBarDataVars[idx].align --TitanPanelGetVar(bar.."_Align") - leftWidth = 0; - rightWidth = 0; - counter = 0; - -- If there is a plugin on this bar then justify the first button. - -- The other buttons are relative to the first. - if (firstLeftButton) then - if (align == TITAN_PANEL_BUTTONS_ALIGN_LEFT) then - -- Now offset the plugins - firstLeftButton:ClearAllPoints(); - firstLeftButton:SetPoint("LEFT", idx, "LEFT", x_offset, y_offset); - end - -- Center if requested - if (align == TITAN_PANEL_BUTTONS_ALIGN_CENTER) then - leftWidth = 0; - rightWidth = 0; - counter = 0; - -- Calc the total width of the icons so we know where to start - for index, id in pairs(TitanPanelSettings.Buttons) do - local button = TitanUtils_GetButton(id); - if button and button:GetWidth() then - if TitanUtils_GetWhichBar(id) == bar then - if (TitanGetVar(id, "DisplayOnRightSide")) then - rightWidth = rightWidth - + icon_spacing - + button:GetWidth(); - else - counter = counter + 1; - leftWidth = leftWidth - + button_spacing - + button:GetWidth() - end - end - end - end - -- Now offset the plugins on the bar - firstLeftButton:ClearAllPoints(); - -- remove the last spacing otherwise the buttons appear justified too far left - center_offset = (0 - (leftWidth - button_spacing) / 2) - firstLeftButton:SetPoint("LEFT", idx, "CENTER", center_offset, y_offset); - end - end - end -end - --------------------------------------------------------------- --- --- Local routines for Titan menu creation -local R_ADDONS = "Addons_" -local R_PLUGIN = "Plugin_" -local R_SETTINGS = "Settings" -local R_PROFILE = "Profile_" - ----local Show main Titan (right click) menu. ----@param frame string Frame to add to -local function BuildMainMenu(frame) - local locale_bar = TitanBarData[frame].locale_name - local info = {}; - ----------------- - -- Menu title - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_TITLE"] .. " - " .. locale_bar); - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PLUGINS"]); - - ----------------- - -- Plugin Categories - -- Both arrays are in TitanGlobal - ---@diagnostic disable-next-line: param-type-mismatch - for index, id in pairs(L["TITAN_PANEL_MENU_CATEGORIES"]) do - info = {}; - info.notCheckable = true - info.text = L["TITAN_PANEL_MENU_CATEGORIES"][index]; - info.value = R_ADDONS .. TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY[index]; - info.hasArrow = 1; - TitanPanelRightClickMenu_AddButton(info); - end - - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - ----------------- - -- Options - just one button to open the first Titan option screen - do - info = {}; - info.notCheckable = true - info.text = L["TITAN_PANEL_MENU_CONFIGURATION"]; - info.value = "Bars"; - info.func = function() - TitanUpdateConfig("init") - Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About) - end - TitanPanelRightClickMenu_AddButton(info); - end - - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - ----------------- - -- Profiles - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILES"]); - - ----------------- - -- Load/Delete - info = {}; - info.notCheckable = true - info.text = L["TITAN_PANEL_MENU_MANAGE_SETTINGS"]; - info.value = R_SETTINGS - info.hasArrow = 1; - -- lock this menu in combat - if InCombatLockdown() then - info.disabled = 1; - info.hasArrow = nil; - info.text = info.text .. " " - .. _G["GREEN_FONT_COLOR_CODE"] - .. L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"]; - end - TitanPanelRightClickMenu_AddButton(info); - - ----------------- - -- Save - info = {}; - info.notCheckable = true - info.text = L["TITAN_PANEL_MENU_SAVE_SETTINGS"]; - info.value = "SettingsCustom"; - info.func = TitanPanel_SaveCustomProfile; - -- lock this menu in combat - if InCombatLockdown() then - info.disabled = 1; - info.text = info.text .. " " - .. _G["GREEN_FONT_COLOR_CODE"] - .. L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"]; - end - TitanPanelRightClickMenu_AddButton(info); - - -- TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - local glob, toon, player, server = TitanUtils_GetGlobalProfile() - info = {}; - -- info.text = "Use Global Profile\n "..toon - info.text = L["TITAN_PANEL_GLOBAL_USE"] .. "\n " .. toon; - info.value = "Use Global Profile" - info.func = function() - TitanUtils_SetGlobalProfile(not glob, toon) - TitanVariables_UseSettings(nil, TITAN_PROFILE_USE) - end; - info.checked = glob --TitanAllGetVar("GlobalProfileUse") - info.keepShownOnClick = nil - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - ----------------- - -- Hide this bar - info = {}; - info.text = (HIDE or "Hide") - info.value = "HideMe" - info.notCheckable = true - info.disabled = (TitanUtils_NumActiveBars() == 1) - info.arg1 = frame; - info.func = function(self, frame_str) - TitanBarDataVars[frame_str].show = not TitanBarDataVars[frame_str].show - TitanPanelBarButton_DisplayBarsWanted(frame_str .. " user clicked Hide") - end - info.keepShownOnClick = nil - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); -end - ----local Show list of servers / custom submenu off Profiles/Manage from the Titan (right click) menu. -local function BuildServerProfilesMenu() - local info = {}; - local servers = {}; - local player = nil; - local server = nil; - local s, e, ident; - local setonce = 0; - - if (TitanPanelRightClickMenu_GetDropdMenuValue() == R_SETTINGS) then - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILE_SERVERS"], - TitanPanelRightClickMenu_GetDropdownLevel()); - -- Normal profile per toon - for index, id in pairs(TitanSettings.Players) do - player, server = TitanUtils_ParseName(index) - - if TitanUtils_GetCurrentIndex(servers, server) == nil then - if server ~= TITAN_CUSTOM_PROFILE_POSTFIX then - table.insert(servers, server); - info = {}; - info.notCheckable = true - info.text = server; - info.value = R_PROFILE .. server; - info.hasArrow = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - end - end - -- Custom profiles - for index, id in pairs(TitanSettings.Players) do - player, server = TitanUtils_ParseName(index) - - if TitanUtils_GetCurrentIndex(servers, server) == nil then - if server == TITAN_CUSTOM_PROFILE_POSTFIX then - if setonce and setonce == 0 then - TitanPanelRightClickMenu_AddTitle("", TitanPanelRightClickMenu_GetDropdownLevel()); - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILE_CUSTOM"], - TitanPanelRightClickMenu_GetDropdownLevel()); - setonce = 1; - end - info = {}; - info.notCheckable = true - info.text = player; - info.value = R_PROFILE .. player; - info.hasArrow = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - end - end - end -end - ----local Show list of plugin defined options from the Titan right click menu. -local function BuildPluginMenu() - -- - local info = {}; - - -- Handle the plugins - - for index, id in pairs(TitanPluginsIndex) do - local plugin = TitanUtils_GetPlugin(id) - local par_val = TitanPanelRightClickMenu_GetDropdMenuValue() - local menu_plugin = string.gsub(par_val, R_PLUGIN, "") - if plugin and plugin.id and plugin.id == menu_plugin then - --title - info = {}; - info.text = TitanPlugins[plugin.id].menuText; - info.notCheckable = true - info.notClickable = 1; - info.isTitle = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - --ShowIcon - if plugin.controlVariables.ShowIcon then - info = {}; - info.text = L["TITAN_PANEL_MENU_SHOW_ICON"]; - info.value = plugin.id - info.arg1 = plugin.id - info.func = function(self, p_id) -- (self, info.arg1, info.arg2) - TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowIcon", nil }) - end - info.keepShownOnClick = 1; - info.checked = TitanGetVar(plugin.id, "ShowIcon"); - info.disabled = nil; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - - --ShowLabel - if plugin.controlVariables.ShowLabelText then - info = {}; - info.text = L["TITAN_PANEL_MENU_SHOW_LABEL_TEXT"]; - info.value = plugin.id - info.arg1 = plugin.id - info.func = function(self, p_id) -- (self, info.arg1, info.arg2) - TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowLabelText", nil }) - end - info.keepShownOnClick = 1; - info.checked = TitanGetVar(plugin.id, "ShowLabelText"); - info.disabled = nil; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - - --ShowRegularText (LDB data sources only atm) - if plugin.controlVariables.ShowRegularText then - info = {}; - info.text = L["TITAN_PANEL_MENU_SHOW_PLUGIN_TEXT"] - info.value = plugin.id - info.arg1 = plugin.id - info.func = function(self, p_id) -- (self, info.arg1, info.arg2) - TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowRegularText", nil }) - end - info.keepShownOnClick = 1; - info.checked = TitanGetVar(plugin.id, "ShowRegularText"); - info.disabled = nil; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - - --ShowColoredText - if plugin.controlVariables.ShowColoredText then - info = {}; - info.text = L["TITAN_PANEL_MENU_SHOW_COLORED_TEXT"]; - info.value = plugin.id - info.arg1 = plugin.id - info.func = function(self, p_id) -- (self, info.arg1, info.arg2) - TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowColoredText", nil }) - end - info.keepShownOnClick = 1; - info.checked = TitanGetVar(plugin.id, "ShowColoredText"); - info.disabled = nil; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - - -- Right-side plugin - if plugin.controlVariables.DisplayOnRightSide then - info = {}; - info.text = L["TITAN_PANEL_MENU_LDB_SIDE"]; - info.value = plugin.id - info.arg1 = plugin.id - info.func = function(self, p_id) -- (self, info.arg1, info.arg2) - TitanToggleVar(p_id, "DisplayOnRightSide") - local bar = TitanUtils_GetWhichBar(p_id) - TitanPanel_RemoveButton(p_id); - TitanUtils_AddButtonOnBar(bar, p_id); - end - info.checked = TitanGetVar(plugin.id, "DisplayOnRightSide"); - info.disabled = nil; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - end - end -end - ----local Show alphabetical list of toons submenu off Profiles/Manage/<server or custom> from the Titan right click menu. -local function BuildProfileMenu() - -- - local info = {}; - local setonce = 0; - - -- - -- Handle the profiles - -- - for idx = 1, #Titan_Global.players do - local index = Titan_Global.players[idx] - local player, server = TitanUtils_ParseName(index) - local off = (index == TitanSettings.Player) - or ((index == TitanAllGetVar("GlobalProfileUse")) and (TitanAllGetVar("GlobalProfileUse"))) - local par_val = TitanPanelRightClickMenu_GetDropdMenuValue() - local menu_val = string.gsub(par_val, R_PROFILE, "") - - -- handle custom profiles here - if server == TITAN_CUSTOM_PROFILE_POSTFIX - and player == menu_val then - info = {}; - info.notCheckable = true - info.disabled = TitanAllGetVar("GlobalProfileUse") - info.text = L["TITAN_PANEL_MENU_LOAD_SETTINGS"]; - info.value = index; - info.func = function() - TitanVariables_UseSettings(index, TITAN_PROFILE_USE) - end - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - info = {}; - info.notCheckable = true - info.disabled = off - info.text = L["TITAN_PANEL_MENU_DELETE_SETTINGS"]; - info.value = index; - info.arg1 = index; - info.func = function(self, player) -- (self, info.arg1, info.arg2) - if TitanSettings.Players[player] then - TitanSettings.Players[player] = nil; - local profname = TitanUtils_ParseName(index) - TitanPrint( - L["TITAN_PANEL_MENU_PROFILE"] - .. " '" .. profname .. "' " - .. L["TITAN_PANEL_MENU_PROFILE_DELETED"] - , "info") - table.remove(Titan_Global.players, idx) - TitanPanelRightClickMenu_Close(); - end - end - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end -- if server and player - - -- handle regular profiles here - if server == menu_val then - -- Set the label once - if setonce and setonce == 0 then - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILE_CHARS"], - TitanPanelRightClickMenu_GetDropdownLevel()); - setonce = 1; - end - info = {}; - info.disabled = off - info.notCheckable = true - info.text = player; - info.value = index; - info.hasArrow = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - end -- for players -end - ----local Show save / load submenu off Profiles/Manage/<server or custom>/<profile> from the Titan (right click) menu. -local function BuildAProfileMenu() - local info = {}; - - info = {}; - info.notCheckable = true - info.disabled = TitanAllGetVar("GlobalProfileUse") - info.text = L["TITAN_PANEL_MENU_LOAD_SETTINGS"]; - info.value = TitanPanelRightClickMenu_GetDropdMenuValue(); - info.func = function() - TitanVariables_UseSettings(TitanPanelRightClickMenu_GetDropdMenuValue(), TITAN_PROFILE_USE) - end - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); - - info = {}; - info.notCheckable = true - info.disabled = (TitanPanelRightClickMenu_GetDropdMenuValue() == TitanSettings.Player) - or ((TitanPanelRightClickMenu_GetDropdMenuValue() == TitanAllGetVar("GlobalProfileName")) - and (TitanAllGetVar("GlobalProfileUse"))) - info.text = L["TITAN_PANEL_MENU_DELETE_SETTINGS"]; - info.value = TitanPanelRightClickMenu_GetDropdMenuValue(); - info.func = function() - -- do not delete if current profile - .disabled - if TitanSettings.Players[info.value] then - TitanSettings.Players[info.value] = nil; - TitanPrint( - L["TITAN_PANEL_MENU_PROFILE"] - .. " '" .. info.value .. "' " - .. L["TITAN_PANEL_MENU_PROFILE_DELETED"] - , "info") - TitanPanelRightClickMenu_Close(); - end - end - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); -end - ----local Build the list of plugins for the category the mouse is over - Titan (right click) menu. ----@param frame string Frame to add to -local function BuildPluginCategoryMenu(frame) - local info = {}; - local plugin; - - for index, id in pairs(TitanPluginsIndex) do - plugin = TitanUtils_GetPlugin(id) - if plugin then -- add the plugin to the menu - plugin.category = plugin and plugin.category or "General"; - if (TitanPanelRightClickMenu_GetDropdMenuValue() == R_ADDONS .. plugin.category) then - if not TitanGetVar(id, "ForceBar") - or (TitanGetVar(id, "ForceBar") == TitanBarData[frame].name) then - info = {}; - local ver = plugin and plugin.version or "" - if TitanPanelGetVar("VersionShown") then - if ver == nil or ver == "" then - ver = "" -- safety in case of nil - else - ver = TitanUtils_GetGreenText(" (" .. ver .. ")") - end - else - ver = "" -- not requested - end - info.text = plugin and plugin.menuText .. ver or "" - - -- Add Bar - local internal_bar, which_bar = TitanUtils_GetWhichBar(id) - if which_bar == nil then - -- Plugin not shown - else - -- if internal_bar == TitanBarData[frame].name then - -- info.text = info.text .. TitanUtils_GetGreenText(" (" .. which_bar .. ")") - -- else - info.text = info.text .. TitanUtils_GetGoldText(" (" .. which_bar .. ")") - -- end - end - - if plugin.controlVariables then - info.hasArrow = 1; - end - info.value = R_PLUGIN .. id; -- for next level dropdown - info.arg1 = frame; - info.arg2 = id; - info.func = function(self, frame_str, plugin_id) -- (self, info.arg1, info.arg2) - -- frame_str is the bar the user clicked to get the menu... - local bar = TitanBarData[frame_str].name - - if TitanPanel_IsPluginShown(plugin_id) then - TitanPanel_RemoveButton(plugin_id); - else - TitanUtils_AddButtonOnBar(bar, plugin_id) - end - end - info.checked = TitanPanel_IsPluginShown(id) or nil - info.keepShownOnClick = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - end - else - end - end -end - ----Titan This is the controller for the Titan (right click) menu. ----@param self table Titan bar frame that was right clicked ---- Frame name used is <Titan bar name>RightClickMenu -function TitanPanelRightClickMenu_PrepareBarMenu(self) - -- Determine which bar was clicked on - -- local s, e, frame = string.find(self:GetName(), "(.*)RightClickMenu"); - local s, e, frame = string.find(self:GetName(), "(.*)" .. TITAN_PANEL_CLICK_MENU_SUFFIX); - local lev = (TitanPanelRightClickMenu_GetDropdownLevel() or 1) - --[[ -print("_prep R click" -.." "..tostring(frame).."" -.." "..tostring(lev).."" -) ---]] - - -- Level 1 - --[===[ - Title - <Bar name> - ---- - Plugins - <list of Categories> - ---- - Configuration => Opens Titan Options - ----- - Profiles - Manage > <Level 2> - Save => Save current profile (used for Global) - ----- - Use Global Profile - <Profile name used or <>> - ---- - Hide => Hide this Bar - --]===] - if lev == 1 then - BuildMainMenu(frame) - end - - -- Level 2 - -- Plugin Categories => Plugins in that category - -- OR - -- Profiles => Server / Realm list - if (lev == 2) then - if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), R_ADDONS) then - BuildPluginCategoryMenu(frame) - end - - if (TitanPanelRightClickMenu_GetDropdMenuValue() == R_SETTINGS) then - BuildServerProfilesMenu() - end - return; - end - - -- Level 3 - -- Plugin Categories => Plugins in that category => Plugin defined options - -- OR - -- Profiles > Server / Realm list > Character on realm list - if (lev == 3) then - if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), R_PLUGIN) then - BuildPluginMenu() - end - if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), R_PROFILE) then - BuildProfileMenu() - end - return; - end - - -- Level 4 - -- Profiles > Server / Realm list > Character on realm list > Load / Delete - if (lev == 4) then - BuildAProfileMenu() - return; - end -end - ----Titan Determine if the given plugin is on any Titan bar. ----@param id string Unique ID of the plugin ----@return boolean shown True on a Titan bar even if hidden or on auto hide -function TitanPanel_IsPluginShown(id) - if (id and TitanPanelSettings) then - return TitanUtils_TableContainsValue(TitanPanelSettings.Buttons, id) - else - return false - end -end - ----Titan Determine if the given plugin is / would be on right or left of a Titan bar. ----@param id string Unique ID of the plugin ----@return string R_L TITAN_RIGHT("Right") or TITAN_Left("Left") -function TitanPanel_GetPluginSide(id) - if (TitanGetVar(id, "DisplayOnRightSide")) then - return TITAN_RIGHT; - else - return TITAN_LEFT; - end -end - ----Titan Set the scale, texture (graphic), and transparancy of all the Titan bars based on the user selection. ----@param reason string Debug note on where the call initiated -function TitanPanel_InitPanelBarButton(reason) - -- Set initial Panel Scale - TitanPanel_SetScale(); - - -- build debug output - local str = "_InitPanelBarButton" - .." "..tostring(reason).."" - Titan_Debug.Out('titan', 'bars_setup', str) - TitanPanelBarButton_DisplayBarsWanted("InitPanelBarButton") -end - --- ---========================== --- Routines to handle creation of Titan bars --- - ----Titan Create a Titan bar that can show plugins. ----@param frame_str string Unique ID of the plugin -function TitanPanelButton_CreateBar(frame_str) - local this_bar = frame_str - local a_bar = CreateFrame("Button", this_bar, UIParent, "Titan_Bar__Display_Template") - - local bar_data = TitanBarData[this_bar] - - -- ====== - -- Scripts - a_bar:SetScript("OnEnter", function(self) TitanPanelBarButton_OnEnter(self) end) - a_bar:SetScript("OnLeave", function(self) TitanPanelBarButton_OnLeave(self) end) - a_bar:SetFrameStrata("DIALOG") - - if bar_data.user_move then - a_bar:SetMovable(true) - a_bar:SetResizable(true) - a_bar:EnableMouse(true) - a_bar:RegisterForDrag("LeftButton") - a_bar:SetScript("OnDragStart", OnMoveStart) - a_bar:SetScript("OnDragStop", OnMovingStop) - a_bar:SetScript("OnMouseWheel", OnMouseWheel) - else - -- Static full width bar - end - - -- ====== - -- Bounds only effective on Short bars for now - -- Min : No smaller than the padding & one icon - -- Max : No wider than the screen - -- does not seem to work to restrict size automatically... - local screen = TitanUtils_ScreenSize() - a_bar:SetResizeBounds(TitanBarData[this_bar].plugin_x_offset + 16, TITAN_PANEL_BAR_HEIGHT, screen.x, - TITAN_PANEL_BAR_HEIGHT) - a_bar:RegisterForClicks("LeftButtonUp", "RightButtonUp"); - a_bar:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) - - -- ====== - -- Frame for right clicks - -- Use the plugin naming scheme for one frame to rule them all - -- 2024 Feb : Change to match plugin right click menu scheme so one routine can be used. - local f = CreateFrame("Frame", this_bar .. TITAN_PANEL_CLICK_MENU_SUFFIX, UIParent, "UIDropDownMenuTemplate") - - -- ====== - -- Hider for auto hide feature - local hide_bar_name = TITAN_PANEL_HIDE_PREFIX .. bar_data.name - if bar_data.hider then - local hide_bar = CreateFrame("Button", hide_bar_name, UIParent, "TitanPanelBarButtonHiderTemplate") - hide_bar:SetFrameStrata("DIALOG") - - -- Set script handlers for display - hide_bar:RegisterForClicks("LeftButtonUp", "RightButtonUp"); - hide_bar:SetScript("OnEnter", function(self) TitanPanelBarButtonHider_OnEnter(self) end) - hide_bar:SetScript("OnLeave", function(self) TitanPanelBarButtonHider_OnLeave(self) end) - hide_bar:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) - - hide_bar:SetFrameStrata("BACKGROUND") - hide_bar:SetSize(screen.x, TITAN_PANEL_BAR_HEIGHT) - else - -- Hider not allowed for this bar - end -end - ---====== deprecated / Unused ---[====[ - ---[[ local -NAME: TitanPanel_CreateABar -DESC: Helper to add scripts to the Titan bar passed in. -VAR: frame - The frame name (string) of the Titan bar to create -OUT: None -NOTE: -- This also creates the hider bar in case the user want to use auto hide. -:NOTE ---]] -local function TitanPanel_CreateABar(frame) - if frame then - local bar_name = TitanBarData[frame].name - local bar_width = TitanBarData[frame].width - - if bar_name then - -- Set script handlers for display - _G[frame]:RegisterForClicks("LeftButtonUp", "RightButtonUp"); - _G[frame]:SetScript("OnEnter", function(self) TitanPanelBarButton_OnEnter(self) end) - _G[frame]:SetScript("OnLeave", function(self) TitanPanelBarButton_OnLeave(self) end) - _G[frame]:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) - _G[frame]:SetWidth(bar_width) - - local hide_name = TitanBarData[frame].hider - if hide_name then - -- Set script handlers for display - _G[hide_name]:RegisterForClicks("LeftButtonUp", "RightButtonUp"); - _G[hide_name]:SetScript("OnEnter", function(self) TitanPanelBarButtonHider_OnEnter(self) end) - _G[hide_name]:SetScript("OnLeave", function(self) TitanPanelBarButtonHider_OnLeave(self) end) - _G[hide_name]:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) - - _G[hide_name]:SetFrameStrata("BACKGROUND") - _G[hide_name]:SetWidth(bar_width) - _G[hide_name]:SetHeight(TITAN_PANEL_BAR_HEIGHT/2); - end - - -- Set the display bar - local container = _G[frame] - container:SetHeight(TITAN_PANEL_BAR_HEIGHT); - -- Set local identifier - local container_text = _G[frame.."_Text"] - if container_text then -- was used for debug/creating of the independent bars - container_text:SetText(tostring(bar_name)) - -- for now show it - container:Show() - end - end - else - end -end - ---]====] +---@diagnostic disable: duplicate-set-field +--[===[ File +Contains the basic routines of Titan. +All the event handler routines, initialization routines, Titan menu routines, and select plugin handler routines. +--]===] + +-- Locals +local TPC = TITAN_PANEL_CONSTANTS -- shortcut +local TITAN_PANEL_BUTTONS_INIT_FLAG = nil; + +local _G = _G --getfenv(0); +local InCombatLockdown = _G.InCombatLockdown; +local IsTitanPanelReset = nil; + +-- Library references +local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) +local AceTimer = LibStub("AceTimer-3.0") +local media = LibStub("LibSharedMedia-3.0") +local AceConfigDialog = LibStub("AceConfigDialog-3.0") + +-- TitanDebug (cmd.." : "..p1.." "..p2.." "..p3.." "..#cmd_list) + +-------------------------------------------------------------- +-- + +--[[ +Note: +- Use Settings.OpenToCategory to open all of Titan configa. +- Use AceConfigDialog:Open to open a specific part of the Titan config. + +--]] +---Titan Give the user an are you sure popup whether to reload the UI or not. +function TitanPanel_OkToReload() + StaticPopupDialogs["TITAN_RESET_RELOAD"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) + .. "\n\n" .. L["TITAN_PANEL_RESET_WARNING"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self) + ReloadUI() + end, + showAlert = 1, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 + }; + StaticPopup_Show("TITAN_RESET_RELOAD"); +end + +---Titan Reset current toon to default Titan settings. +function TitanPanel_ResetToDefault() + -- Found as of 2025 Sep, the reload is not needed + -- build debug output + local str = "/titan reset invoked" + Titan_Debug.Out('titan', 'profile', str) + + TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_RESET); + IsTitanPanelReset = true; +end + +---Titan Reset Titan to default settings then reload UI. Equivilant to deleting saved vars. +function TitanPanel_ResetTitanToDefault() + -- A reload is safest course + -- build debug output + local str = "/titan reset all invoked" + Titan_Debug.Out('titan', 'profile', str) + + TitanSettings = nil + TitanAll = nil + + ReloadUI() -- Reuse the PEW code to ensure Titan is whole. +end + +---Titan The user wants to save a custom Titan profile. Show the user the dialog boxes to make it happen. +--- The profile is written to the Titan saved variables. A reload of the UI is needed to ensure the profile is written to disk for the user to load later. +function TitanPanel_SaveCustomProfile() + -- Create the dialog box code we'll need... + + ---helper to get the edit box depending on expansion API + ---@param self table + ---@return table + local function GetBox(self) + if self.editBox then + -- Older version of API + return self.editBox + else + return self:GetEditBox() + end + end + + -- helper to actually write the profile to the Titan saved vars + local function Write_profile(name) + local currentprofilevalue, _, _ = TitanUtils_GetPlayer() + local profileName = TitanUtils_CreateName(name, TITAN_CUSTOM_PROFILE_POSTFIX) + TitanSettings.Players[profileName] = + TitanUtils_DeepCopy(TitanSettings.Players[currentprofilevalue]) + + -- Do NOT allow a sync on a custom profile + TitanSettings.Players[profileName].Panel["SyncWithProfile"] = Titan_Global.profile.NONE + + TitanPrint(L["TITAN_PANEL_MENU_PROFILE_SAVE_PENDING"] + .. "'" .. name .. "'" + , "info") + end + -- helper to ask the user to overwrite a profile + local function Overwrite_profile(name) + local dialogFrame = + StaticPopup_Show("TITAN_OVERWRITE_CUSTOM_PROFILE", name); + if dialogFrame then + dialogFrame.data = name; + end + end + -- helper to handle getting the profile name from the user + local function Get_profile_name(self) + local rawprofileName = GetBox(self):GetText(); + -- remove any spaces the user may have typed in the name + local conc2profileName = string.gsub(rawprofileName, " ", ""); + if conc2profileName == "" then return; end + -- no '@' is allowed or it will mess with the Titan profile naming convention + local concprofileName = string.gsub(conc2profileName, TITAN_AT, "-"); + local profileName = TitanUtils_CreateName(concprofileName, TITAN_CUSTOM_PROFILE_POSTFIX) + if TitanSettings.Players[profileName] then + -- Warn the user of an existing profile + Overwrite_profile(rawprofileName) + self:Hide(); + return; + else + -- Save the requested profile + Write_profile(rawprofileName) + self:Hide(); + StaticPopup_Show("TITAN_RELOADUI"); + end + end + -- Dialog box to warn the user that the UI will be reloaded + -- This ensures the profile is written to disk + StaticPopupDialogs["TITAN_RELOADUI"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_MENU_PROFILE_RELOADUI"], + button1 = "OKAY", + OnAccept = function(self) + ReloadUI(); -- ensure profile is written to disk + end, + showAlert = 1, + whileDead = 1, + timeout = 0, + }; + + -- Dialog box to warn the user that an existing profile will be overwritten. + StaticPopupDialogs["TITAN_OVERWRITE_CUSTOM_PROFILE"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_MENU_PROFILE_ALREADY_EXISTS"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self, data) + Write_profile(data) + self:Hide(); + StaticPopup_Show("TITAN_RELOADUI"); + end, + showAlert = 1, + whileDead = 1, + timeout = 0, + hideOnEscape = 1 + }; + + -- Dialog box to save the profile. + StaticPopupDialogs["TITAN_SAVE_CUSTOM_PROFILE"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_MENU_PROFILE_SAVE_CUSTOM_TITLE"], + button1 = ACCEPT, + button2 = CANCEL, + hasEditBox = 1, + maxLetters = 20, + OnAccept = function(self) + -- self refers to this frame with the Accept button + Get_profile_name(self) + end, + OnShow = function(self) + GetBox(self):SetFocus(); + end, + OnHide = function(self) + GetBox(self):SetText(""); + end, + EditBoxOnEnterPressed = function(self) + -- We need to get the parent because self refers to the edit box. + Get_profile_name(self:GetParent()) + end, + EditBoxOnEscapePressed = function(self) + self:GetParent():Hide(); + end, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 + }; + + StaticPopup_Show("TITAN_SAVE_CUSTOM_PROFILE"); + + -- Can NOT cleanup. Execution does not stop when a dialog box is invoked! + -- StaticPopupDialogs["TITAN_RELOADUI"] = {} + -- StaticPopupDialogs["TITAN_OVERWRITE_CUSTOM_PROFILE"] = {} + -- StaticPopupDialogs["TITAN_SAVE_CUSTOM_PROFILE"] = {} +end + +---Titan Set or change the font and font size of text on the Titan bar. This affects ALL plugins. +--- Each registered plugin will have its font updated. Then all plugins will be refreshed to show the new font. +---@param fontname string path to font file +---@param fontsize number in points +function TitanSetPanelFont(fontname, fontsize) + -- a couple of arg checks to avoid unpleasant things... + if not fontname then fontname = TPC.FONT_NAME end + if not fontsize then fontsize = TPC.FONT_SIZE end + local newfont = media:Fetch("font", fontname) + for index, id in pairs(TitanPluginsIndex) do + local button = TitanUtils_GetButton(id) + if button then + local buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; + if buttonText then + buttonText:SetFont(newfont, fontsize); + end + end + end + TitanPanel_RefreshPanelButtons(); +end + +local function RegisterForEvents() + -- Need to be careful of regeristering for events that initiate + -- show / hide of Bars before the Bars can be initialized... + _G[TITAN_PANEL_CONTROL]:RegisterEvent("CVAR_UPDATE"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_LOGOUT"); + + -- For the pet battle - for now we'll hide the Titan bars... + -- Cannot seem to move the 'top' part of the pet battle frame. + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PET_BATTLE_OPENING_START"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PET_BATTLE_CLOSE"); + + -- Hide Titan bars in combat (global or per bar); may be useful when using Short bars + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_REGEN_ENABLED"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_REGEN_DISABLED"); + + -- User request to hide Top bar(s) in BG or arena; more areas later? + _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_INDOORS"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_NEW_AREA"); +end + +-------------------------------------------------------------- +_G[TITAN_PANEL_CONTROL]:RegisterEvent("ADDON_LOADED"); +-- +-- Event routine : redirects to TitanPanelBarButton:<registered event> routines below. +_G[TITAN_PANEL_CONTROL]:SetScript("OnEvent", function(_, event, ...) + _G[TITAN_PANEL_CONTROL][event](_G[TITAN_PANEL_CONTROL], ...) +end) + +local function RegisterAddonCompartment() + if AddonCompartmentFrame then + AddonCompartmentFrame:RegisterAddon( + { + text = TITAN_ID, + icon = "Interface\\Icons\\Achievement_Dungeon_UlduarRaid_Titan_01", + notCheckable = true, + func = function(button, menuInputData, menu) + TitanUpdateConfig("init") + Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About) + end, + funcOnEnter = function(button) + MenuUtil.ShowTooltip(button, function(tooltip) + local msg = "" + .. L["TITAN_PANEL"] + .. " " .. L["TITAN_PANEL_MENU_CONFIGURATION"] + tooltip:SetText(msg) + end) + end, + funcOnLeave = function(button) + MenuUtil.HideTooltip(button) + end, + } + ) + else + end +end + +---Titan Do all the setup needed when a user logs in / reload UI / enter or leave an instance. +--- This is called after the 'player entering world' event is fired by Blizz. +--- This is also called when a LDB plugin is created after Titan runs the 'player entering world' code. +--- The common code section will setup this toon's info +--- 1) Register any plugins +--- 2) Load the plugin vars (UseSettings) +--- 3) Update the Titan config +--- 4) Set the Titan vars +--- 5) Load / register any LDB plugins into Titan +---@param reload boolean true if reload; false if character 'first' enter +function TitanPanel_PlayerEnteringWorld(reload) + if Titan__InitializedPEW then + -- Currently no additional steps needed + else + Titan_Debug.Out('titan', 'p_e_w', "Init settings") + + -- Get Saved Vars; sync with defaults + TitanVariables_InitTitanSettings(); + if TitanAllGetVar("Silenced") then + -- No header output + else + TitanPrint("", "header") + end + + if not ServerTimeOffsets then + ServerTimeOffsets = {}; + end + if not ServerHourFormat then + ServerHourFormat = {}; + end + + -- Set the two anchors in their default positions + -- until the Titan bars are drawn + Titan_Debug.Out('titan', 'p_e_w', "Create anchors for other addons") + TitanPanelTopAnchor:ClearAllPoints(); + TitanPanelTopAnchor:SetPoint("TOPLEFT", "UIParent", "TOPLEFT", 0, 0); + TitanPanelBottomAnchor:ClearAllPoints(); + TitanPanelBottomAnchor:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", 0, 0); + + -- Ensure the bars are created before the plugins are registered. + Titan_Debug.Out('titan', 'p_e_w', "Create frames for Titan bars") + for idx, v in pairs(TitanBarData) do + Titan_Debug.Out('titan', 'bars_setup', "... " .. tostring(v.name)) + + TitanPanelButton_CreateBar(idx) + end + -- Titan_AutoHide_Create_Frames() + + -- Add to Addon Compartment, if feature is present + RegisterAddonCompartment() + + -- Set clock vars based on user setting + if TitanPlugins["Clock"] then + local realmName = GetRealmName() + if ServerTimeOffsets[realmName] then + TitanSetVar("Clock", "OffsetHour", ServerTimeOffsets[realmName]) + elseif TitanGetVar("Clock", "OffsetHour") then + ServerTimeOffsets[realmName] = TitanGetVar("Clock", "OffsetHour") + end + + if ServerHourFormat[realmName] then + TitanSetVar("Clock", "Format", ServerHourFormat[realmName]) + elseif TitanGetVar("Clock", "Format") then + ServerHourFormat[realmName] = TitanGetVar("Clock", "Format") + end + end + + -- Should be safe to register for events that could show / hide Bars + Titan_Debug.Out('titan', 'p_e_w', "Register for events Titan needs") + RegisterForEvents() + end + + --====== Common code login versus reload / portal / ... + + local _ = nil + TitanSettings.Player, _, _ = TitanUtils_GetPlayer() + + -- Some addons wait to create their LDB component or a Titan addon could + -- create additional buttons as needed. + Titan_Debug.Out('titan', 'p_e_w', "Register any plugins found") + TitanUtils_RegisterPluginList() + Titan_Debug.Out('titan', 'p_e_w', "> Register any plugins done") + + -- Now sync saved variables to the profile chosen by the user. + -- This will set the bar(s) and enabled plugins (via OnShow). + Titan_Debug.Out('titan', 'p_e_w', "Synch plugin saved vars") + + Titan_Debug.Out('titan', 'p_e_w', "Synch plugin saved vars") + TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_INIT) + + Titan_Debug.Out('titan', 'p_e_w', "Init config data (right click menu)") + -- all addons are loaded so update the config (options) + -- some could have registered late... + TitanUpdateConfig("init") + + -- Init panel font + local isfontvalid = media:IsValid("font", TitanPanelGetVar("FontName")) + if isfontvalid then + TitanSetPanelFont(TitanPanelGetVar("FontName"), TitanPanelGetVar("FontSize")) + else + -- if the selected font is not valid, revert to default (Friz Quadrata TT) + TitanPanelSetVar("FontName", TPC.FONT_NAME); + TitanSetPanelFont(TPC.FONT_NAME, TitanPanelGetVar("FontSize")) + end + + -- Init panel frame strata + TitanVariables_SetPanelStrata(TitanPanelGetVar("FrameStrata")) + + -- Titan Panel has initialized its variables and registered plugins. + -- Allow Titan - and others - to adjust the bars + Titan__InitializedPEW = true + + -- Move frames + if Titan_Global.switch.can_edit_ui then + -- No need + else + TitanMovable_SecureFrames() + TitanPanel_AdjustFrames(true, "_PlayerEnteringWorld") + end + + -- Loop through the LDB objects to sync with their created Titan plugin + Titan_Debug.Out('titan', 'p_e_w', "Register any LDB (Titan) plugins") + TitanLDBRefreshButton() + Titan_Debug.Out('titan', 'p_e_w', "> Register any LDB (Titan) plugins done") + + Titan_Debug.Out('titan', 'p_e_w', "Titan processing done") +end + +-------------------------------------------------------------- +-- +-- Event handlers +-- +--[===[ + local WoWClassicEra, WoWClassicTBC, WoWWOTLKC, WoWRetail + if wowversion < 20000 then + WoWClassicEra = true + elseif wowversion < 30000 then + WoWClassicTBC = true + elseif wowversion < 40000 then + WoWWOTLKC = true + elseif wowversion > 90000 then + WoWRetail = true + else + -- n/a + end +--]===] + + +---Titan Handle ADDON_LOADED Minimal setup in prep for player login. +function TitanPanelBarButton:ADDON_LOADED(addon) + if addon == TITAN_ID then + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_ENTERING_WORLD") + + Titan_Debug.Out('titan', 'events', "ADDON_LOADED") + + -- Unregister event - saves a few event calls. + self:UnregisterEvent("ADDON_LOADED"); + self.ADDON_LOADED = nil + end +end + +---Titan Handle PLAYER_ENTERING_WORLD Initialize Titan, set and display Titan bars and plugins. +function TitanPanelBarButton:PLAYER_ENTERING_WORLD(arg1, arg2) + local call_success = nil + local ret_val = nil + + Titan_Debug.Out('titan', 'p_e_w', "Titan PLAYER_ENTERING_WORLD pcall setup routine") + + call_success, -- needed for pcall + ret_val = -- actual return values + pcall(TitanPanel_PlayerEnteringWorld, arg2) + -- pcall does not allow errors to propagate out. Any error + -- is returned as text with the success / fail. + -- Think of it as a try - catch block + --[[ +print("_PlayerEnteringWorld" +.." "..tostring(call_success).."" +) +--]] + if call_success then + -- Titan initialized properly + else + -- something really bad occured... + TitanPrint("Titan could not initialize!!!! Cleaning up...", "error") + TitanPrint("--" .. ret_val, "error") + -- Clean up best we can and tell the user to submit a ticket. + -- This could be the 1st log in or a reload (reload, instance, boat, ...) + + -- Hide the bars. At times they are there but at 0% transparency. + -- They can be over the Blizz action bars creating havoc. + TitanPrint("-- Hiding Titan bars...", "warning") + TitanPanelBarButton_HideAllBars() + + -- Remove the options pages + TitanUpdateConfig("nuke") + -- What else to clean up??? + + -- raise the error to WoW for display, if display errors is set. + -- This *must be* the last statement of the routine! + error(ret_val, 1) + end +end + +---Titan Handle CVAR_UPDATE React to user changed WoW options. +function TitanPanelBarButton:CVAR_UPDATE(cvarname, cvarvalue) + if cvarname == "USE_UISCALE" + or cvarname == "WINDOWED_MODE" + or cvarname == "uiScale" then + if TitanPlayerSettings and TitanPanelGetVar("Scale") then + TitanPanel_InitPanelBarButton("CVAR_ " .. tostring(cvarname)) + if Titan_Global.switch.can_edit_ui then + -- No need + else + -- Adjust frame positions + TitanPanel_AdjustFrames(true, "CVAR_UPDATE Scale") + end + end + end +end + +---Titan Handle PLAYER_LOGOUT On logout, set some debug data in saved variables. +function TitanPanelBarButton:PLAYER_LOGOUT() + if not IsTitanPanelReset then + -- for debug + if TitanPanelRegister then + TitanPanelRegister.ToBe = TitanPluginToBeRegistered + TitanPanelRegister.ToBeNum = TitanPluginToBeRegisteredNum + TitanPanelRegister.TitanPlugins = TitanPlugins + end + end + Titan__InitializedPEW = false +end + +---Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena +function TitanPanelBarButton:ZONE_CHANGED() + TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED") +end + +---Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena +function TitanPanelBarButton:ZONE_CHANGED_INDOORS() + TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED_INDOORS") +end + +---Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena +function TitanPanelBarButton:ZONE_CHANGED_NEW_AREA() + TitanPanelBarButton_DisplayBarsWanted("ZONE_CHANGED_NEW_AREA") +end + +---Titan Handle PET_BATTLE_CLOSE Hide Titan bars during pet battle. +function TitanPanelBarButton:PET_BATTLE_OPENING_START() + TitanPanelBarButton_DisplayBarsWanted("PET_BATTLE_OPENING_START") +end + +---Titan Handle PET_BATTLE_CLOSE Show Titan bars hidden bars during pet battle. +function TitanPanelBarButton:PET_BATTLE_CLOSE() + TitanPanelBarButton_DisplayBarsWanted("PET_BATTLE_CLOSE") +end + +local in_combat = false -- seems InCombatLockdown may not be set fast enough to reliably hide bars... + +---Titan Handle PLAYER_REGEN_ENABLED Titan bars may be hidden during combat. +--- Use local in_combat - seems InCombatLockdown() may not be set fast enough to reliably hide bars... +function TitanPanelBarButton:PLAYER_REGEN_ENABLED() + in_combat = false + TitanPanelBarButton_DisplayBarsWanted("PLAYER_REGEN_ENABLED") + + if Titan_Global.switch.can_edit_ui then + -- No need + else + -- Adjust frame positions + TitanPanel_AdjustFrames(false, "PLAYER_REGEN_ENABLED") + end +end + +---Titan Handle PLAYER_REGEN_DISABLED Titan bars may have been hidden during combat. +--- Use local in_combat - seems InCombatLockdown() may not be set fast enough to reliably hide bars... +function TitanPanelBarButton:PLAYER_REGEN_DISABLED() + in_combat = true + TitanPanelBarButton_DisplayBarsWanted("PLAYER_REGEN_DISABLED") +end + +if Titan_Global.switch.can_edit_ui then + -- Do not need to adjust frames +else + function TitanPanelBarButton:ACTIVE_TALENT_GROUP_CHANGED() + -- Is this needed?? + -- TitanMovable_AdjustTimer("DualSpec") + end + + function TitanPanelBarButton:UNIT_ENTERED_VEHICLE(self, ...) + TitanUtils_CloseAllControlFrames(); + TitanUtils_CloseRightClickMenu(); + + -- Needed because 8.0 made changes to the menu bar processing (see TitanMovable) + TitanMovable_MenuBar_Disable() + end + + function TitanPanelBarButton:UNIT_EXITED_VEHICLE(self, ...) + -- A combat check will be done inside the adjust + TitanPanel_AdjustFrames(true, "UNIT_ENTERED_VEHICLE") + end + + --]] + -- +end + +---Titan Handle the button clicks on any Titan bar. +--- This only reacts to the right or left mouse click without modifiers. +--- Used in the set script for the Titan display and hider frames +---@param self table Titan bar frame +---@param button string Button clicked +function TitanPanelBarButton_OnClick(self, button) + -- ensure that the right-click menu will not appear on "hidden" bottom bar(s) + if (button == "LeftButton") then + TitanUtils_CloseAllControlFrames(); + TitanUtils_CloseRightClickMenu(); + elseif (button == "RightButton") then + TitanUtils_CloseAllControlFrames(); + TitanPanelRightClickMenu_Close(); + -- Show RightClickMenu anyway + TitanPanelRightClickMenu_Toggle(self) + end +end + +-- +-- Slash command handler +-- + + +---local Helper to parse the user commands from Chat. +---@param cmd any +---@return table cmds List of 'words' user typed +--- each 'word' is made lower case for comparison simplicity +local function TitanPanel_ParseSlashCmd(cmd) + local words = {} + for w in string.gmatch(cmd, "%w+") do + words[#words + 1] = (w and string.lower(w) or "?") + end + --[[ + local tmp = "" + for idx,v in pairs (words) do + tmp = tmp.."'"..words[idx].."' " + end + + TitanDebug (tmp.." : "..#words) +--]] + return words +end + +---local Helper to tell the user the relevant Titan help commands. +---@param cmd string? 'all' default | 'reset' | 'gui' | 'silent' +local function handle_slash_help(cmd) + cmd = cmd or "all" + + -- Give the user the general help if we can not figure out what they want + TitanPrint("", "header") + -- Cannot count registered plugins after initial registration TitanUtils_RegisterPluginList() + + if cmd == "reset" then + TitanPrint(L["TITAN_PANEL_SLASH_RESET_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_1"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_2"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_3"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_4"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_5"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_RESET_6"], "plain") + end + if cmd == "gui" then + TitanPrint(L["TITAN_PANEL_SLASH_GUI_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_GUI_1"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_GUI_2"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_GUI_3"], "plain") + end + if cmd == "profile" then + TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_1"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_2"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_PROFILE_3"], "plain") + end + if cmd == "silent" then + TitanPrint(L["TITAN_PANEL_SLASH_SILENT_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_SILENT_1"], "plain") + end + if cmd == "orderhall" then + TitanPrint(L["TITAN_PANEL_SLASH_ORDERHALL_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_ORDERHALL_1"], "plain") + end + if cmd == "help" then + TitanPrint(L["TITAN_PANEL_SLASH_HELP_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_HELP_1"], "plain") + end + if cmd == "all" then + TitanPrint(L["TITAN_PANEL_SLASH_ALL_0"], "plain") + TitanPrint(L["TITAN_PANEL_SLASH_ALL_1"], "plain") + end +end + +---local Helper to handle 'reset' commands. +---@param cmd_list table 'tipfont' | 'panelscale' | "spacing" | none - Reset to Titan defaults +local function handle_reset_cmds(cmd_list) + local cmd = cmd_list[1] + local p1 = cmd_list[2] or nil + -- sanity check + if (not cmd == "reset") then + return + end + + if p1 == nil then + TitanPanel_ResetToDefault() + elseif p1 == "all" then + TitanPanel_ResetTitanToDefault() + elseif p1 == "tipfont" then + TitanPanelSetVar("TooltipFont", 1); + GameTooltip:SetScale(TitanPanelGetVar("TooltipFont")); + TitanPrint(L["TITAN_PANEL_SLASH_RESP1"], "info") + elseif p1 == "panelscale" then + if not InCombatLockdown() then + TitanPanelSetVar("Scale", 1); + TitanPanel_InitPanelBarButton("/panelscale reset ") + if Titan_Global.switch.can_edit_ui then + -- No need + else + -- Adjust frame positions + TitanPanel_AdjustFrames(true, "/panelscale reset ") + end + TitanPrint(L["TITAN_PANEL_SLASH_RESP3"], "info") + else + TitanPrint(L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"], "warning") + end + elseif p1 == "spacing" then + TitanPanelSetVar("ButtonSpacing", 20); + TitanPanel_InitPanelButtons(); + TitanPrint(L["TITAN_PANEL_SLASH_RESP4"], "info") + else + handle_slash_help("reset") + end +end + +---local Helper to handle 'gui' commands - open Titan options. +---@param cmd_list table +local function handle_giu_cmds(cmd_list) + local cmd = cmd_list[1] + local p1 = cmd_list[2] or nil + -- sanity check + if (not cmd == "gui") then + return + end + + -- DF changed how options are called. The best I get is the Titan 'about', not deeper. + Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About, TITAN_PANEL_CONFIG.topic.scale) + -- so the below does not work as expected... +end + +---local Helper to handle profile commands - Set to profile if not using global profile. +---@param cmd_list table +local function handle_profile_cmds(cmd_list) + local cmd = cmd_list[1] + -- sanity check + if (not cmd == "profile") then + return + end + AceConfigDialog:Open("Titan Panel Addon Chars") +end + +---local Helper to handle 'silent' commands - Toggle "Silenced" setting. +---@param cmd_list table +local function handle_silent_cmds(cmd_list) + local cmd = cmd_list[1] + -- sanity check + if (not cmd == "silent") then + return + end + + if TitanAllGetVar("Silenced") then + TitanAllSetVar("Silenced", false); + TitanPrint(L["TITAN_PANEL_MENU_SILENT_LOAD"] .. " " .. L["TITAN_PANEL_MENU_DISABLED"], "info") + else + TitanAllSetVar("Silenced", true); + TitanPrint(L["TITAN_PANEL_MENU_SILENT_LOAD"] .. " " .. L["TITAN_PANEL_MENU_ENABLED"], "info") + end +end + +---local Helper to handle 'orderhall' commands - Toggle "OrderHall" setting. +---@param cmd_list table +local function handle_orderhall_cmds(cmd_list) + local cmd = cmd_list[1] + local p1 = cmd_list[2] or nil + -- sanity check + if (not cmd == "orderhall") then + return + end + + if TitanAllGetVar("OrderHall") then + TitanAllSetVar("OrderHall", false); + TitanPrint(L["TITAN_PANEL_MENU_HIDE_ORDERHALL"] .. " " .. L["TITAN_PANEL_MENU_ENABLED"], "info") + StaticPopupDialogs["TITAN_RELOAD"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_RELOAD"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self) + ReloadUI(); + end, + showAlert = 1, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 + }; + StaticPopup_Show("TITAN_RELOAD"); + else + TitanAllSetVar("OrderHall", true); + TitanPrint(L["TITAN_PANEL_MENU_HIDE_ORDERHALL"] .. " " .. L["TITAN_PANEL_MENU_DISABLED"], "info") + StaticPopupDialogs["TITAN_RELOAD"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_RELOAD"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self) + ReloadUI(); + end, + showAlert = 1, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 + }; + StaticPopup_Show("TITAN_RELOAD"); + end +end + +--[=[ local +DESC: Helper to execute the help commands from the user. +VAR: cmd_list - A table containing the list of 'words' the user typed in +OUT: None +local function handle_help_cmds(cmd_list) + local cmd = cmd_list[1] + local p1 = cmd_list[2] or nil + -- sanity check + if (not cmd == "help") then + return + end + + handle_slash_help(p1 or "all") +end +--]=] + +---local Helper to parse and execute all the Titan slash commands from the user. +---@param cmd_str string +local function TitanPanel_RegisterSlashCmd(cmd_str) + local cmd_list = {} + -- parse what the user typed + cmd_list = TitanPanel_ParseSlashCmd(cmd_str) + local cmd = cmd_list[1] or "" + local p1 = cmd_list[2] or "" + local p2 = cmd_list[3] or "" + local p3 = cmd_list[4] or "" + + if (cmd == "reset") then + handle_reset_cmds(cmd_list) + elseif (cmd == "gui") then + handle_giu_cmds(cmd_list) + elseif (cmd == "profile") then + handle_profile_cmds(cmd_list) + elseif (cmd == "silent") then + handle_silent_cmds(cmd_list) + elseif (cmd == "orderhall") then + handle_orderhall_cmds(cmd_list) + elseif (cmd == "help") then + handle_slash_help(p1) + else + handle_slash_help("all") + end +end + +--====== Register slash commands for Titan Panel +SlashCmdList["TitanPanel"] = TitanPanel_RegisterSlashCmd; +SLASH_TitanPanel1 = "/titanpanel"; +SLASH_TitanPanel2 = "/titan"; + +-------------------------------------------------------------- +-- +-- Texture routines + + +---local Set the Titan bar color per user selection +---@param frame string Titan bar name +---@param tex table Texture frame to set +---@param color table Color - RBGA +local function Set_Color(frame, tex, color) + --[[ +print("_Set bar color" +.." "..tostring(TitanBarData[frame].tex_name).."" +--.." "..tostring(tex:GetName()).."" +.." "..tostring(format("%0.1f", color.r)).."" +.." "..tostring(format("%0.1f", color.g)).."" +.." "..tostring(format("%0.1f", color.b)).."" +.." "..tostring(format("%0.1f", color.alpha)).."" +) +--]] + _G[frame]:SetBackdrop({ + bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + -- edgeFile="Interface\\Tooltips\\UI-Tooltip-Border", + -- edgeFile="Interface\\DialogFrame\\UI-DialogBox-Gold-Border", + edgeFile = "Interface\\Glues\\Common\\TextPanel-Border", + tile = true, + tileEdge = true, + -- insets = { left = 1, right = 1, top = 1, bottom = 1 }, + tileSize = 8, + edgeSize = 8, + }) + + _G[frame]:SetBackdropBorderColor( + TOOLTIP_DEFAULT_COLOR.r, + TOOLTIP_DEFAULT_COLOR.g, + TOOLTIP_DEFAULT_COLOR.b, + color.alpha); -- 2024 AUg : Border will use the color alpha + _G[frame]:SetBackdropColor( + color.r, + color.g, + color.b, + color.alpha); +end + +---local Set the Titan bar texture / skin per user selectable options +---@param frame string Titan bar name +---@param tex table Texture frame to set +---@param skin table Skin to use +local function Set_Skin(frame, tex, skin) + -- skins are in two parts - top & bottom... + -- TODO : have Short bars choose top or bottom skin?? + local edge = "" + if TitanBarData[frame].vert == TITAN_BOTTOM + then + edge = TITAN_BOTTOM + else + edge = TITAN_TOP + end + + -- Apply the texture to the bar, using the system repeat to fill it + local texture_file = skin.path .. "TitanPanelBackground" .. edge .. "0" + --[[ +print("_Skin" +.." "..tostring(TitanBarData[frame].tex_name.."" +--.." "..tostring(tex:GetName()).."" +.." "..tostring(skin.path).."" +--.."\n "..tostring(edge).."" +--.." "..tostring(skin.alpha).."" +--.."\n "..tostring(tex:GetTexture()).."" +) +--]] + --[[ -- appears seeting image this way just smears image... + _G[frame]:SetBackdrop({ + bgFile=texture_file, +-- edgeFile=nil, + tile = true, +-- tileSize = 256, +-- tileEdge = true, +-- insets = { left = 1, right = 1, top = 1, bottom = 1 }, +-- tileSize = 8, +-- edgeSize = 8, + }) +--]] + tex:SetAllPoints() + tex:SetHorizTile(true) -- ensures repeat; 'smears' if not sest to true + tex:SetTexture(texture_file, "REPEAT") + tex:SetVertTile(true) -- ensures image is 'full' height of frame + -- tex:SetHeight(TITAN_PANEL_BAR_TEXTURE_HEIGHT) -- leaves a gap if used + tex:SetAlpha(skin.alpha) +end + +---Titan Set the texture / skin of the bar per the user selection. +---@param frame string Titan bar frame name +function TitanPanel_SetBarTexture(frame) + if frame and TitanBarData[frame] then + -- proceed + else + return + end + + -- Create the path & file name to the texture + local tex = TitanBarData[frame].tex_name + local titanTexture = {} + if _G[tex] then + titanTexture = _G[tex] + else + titanTexture = _G[frame]:CreateTexture(tex, "BACKGROUND") + end + titanTexture:SetTexture() + _G[frame]:SetBackdrop({ + bgFile = "", + }) + + --[[ +print("_Tex" +.." "..tostring(TitanBarData[frame].name).."" +--.." "..tostring(tex).."" +.." "..tostring(titanTexture:GetName()).."" +--.." "..tostring(skin.path).."" +--.."\n "..tostring(edge).."" +--.." "..tostring(skin.alpha).."" +--.."\n "..tostring(tex:GetTexture()).."" +.." "..tostring(TitanBarDataVars["Global"].texure).."" +.." "..tostring(TitanBarDataVars[frame].texure).."" +) +--]] + -- Use the texture / skin per user selectable options + if TitanBarDataVars["Global"].texure == Titan_Global.SKIN then + Set_Skin(frame, titanTexture, TitanBarDataVars["Global"].skin) -- tex_path = TitanPanelGetVar("TexturePath") + elseif TitanBarDataVars["Global"].texure == Titan_Global.COLOR then + Set_Color(frame, titanTexture, TitanBarDataVars["Global"].color) + elseif TitanBarDataVars[frame].texure == Titan_Global.SKIN then + Set_Skin(frame, titanTexture, TitanBarDataVars[frame].skin) + elseif TitanBarDataVars[frame].texure == Titan_Global.COLOR then + Set_Color(frame, titanTexture, TitanBarDataVars[frame].color) + end +end + +-------------------------------------------------------------- +-- +-- auto hide event handlers + + +---Titan On leaving the display check if we have to hide the Titan bar. A timer is used - when it expires the bar is hidden. +---@param self table Titan bar frame +function TitanPanelBarButton_OnLeave(self) + local frame = (self and self:GetName() or nil) + local bar = (TitanBarData[frame] and TitanBarData[frame].name or nil) + + -- if auto hide is active then let the timer hide the bar + local hide = (bar and TitanBarDataVars[frame].auto_hide or nil) + -- local hide = (bar and TitanPanelGetVar(bar.."_Hide") or nil) + if hide then + Titan_AutoHide_Timers(frame, "Leave") + end +end + +---Titan No code - this is a place holder for the XML template. +---@param self table Titan Hider bar frame +function TitanPanelBarButton_OnEnter(self) + -- no work to do +end + +---Titan No code - this is a place holder for the XML template. +---@param self table Titan Hider bar frame +function TitanPanelBarButtonHider_OnLeave(self) + -- no work to do +end + +---Titan On entering the hider, check if we need to show the display bar. +--- No action is taken if the user is on combat. +---@param self table Titan Hider bar frame +function TitanPanelBarButtonHider_OnEnter(self) + -- make sure self is valid + local index = self and self:GetName() or nil + if not index then return end -- sanity check + + -- so the bar does not 'appear' when moused over in combat + if TitanPanelGetVar("LockAutoHideInCombat") and InCombatLockdown() then return end + + -- find the relevant bar data + local frame = nil + for idx, v in pairs(TitanBarData) do + if index == TitanBarData[idx].hider then + frame = idx + end + end + -- Now process that bar + if frame then + Titan_AutoHide_Timers(frame, "Enter") + TitanPanelBarButton_Show(frame) + end +end + +--====== Titan Frames for CLASSIC versions + +-- +--========================== +-- Routines to handle adjusting some UI frames +-- + +--[[ Appears unsed... +---Titan Align the buttons per the user's new choice. +---@param align number left or center +function TitanPanelBarButton_ToggleAlign(align) + -- toggle between left or center + if (TitanPanelGetVar(align) == TITAN_PANEL_BUTTONS_ALIGN_CENTER) then + TitanPanelSetVar(align, TITAN_PANEL_BUTTONS_ALIGN_LEFT); + else + TitanPanelSetVar(align, TITAN_PANEL_BUTTONS_ALIGN_CENTER); + end + + -- Justify button position + TitanPanelButton_Justify(); +end +--]] + +---Titan Toggle the auto hide of the given Titan bar per the user's new choice. +---@param frame string Frame mame of the Titan bar +function TitanPanelBarButton_ToggleAutoHide(frame) + local frName = _G[frame] + local plugin = (TitanBarData[frame] and TitanBarData[frame].auto_hide_plugin or nil) + + if frName then + Titan_AutoHide_ToggleAutoHide(_G[plugin]) + end +end + +---Titan Toggle whether Titan adjusts 'top' frames around Titan bars per the user's new choice. +--- Another addon can tell Titan to NOT adjust some or all frames. +function TitanPanelBarButton_ToggleScreenAdjust() + -- Turn on / off adjusting of other frames around Titan + TitanPanelToggleVar("ScreenAdjust"); + TitanPanel_AdjustFrames(true, "_ToggleScreenAdjust") +end + +---Titan Toggle whether Titan adjusts 'bottom' frames around Titan bars per the user's new choice. +--- Another addon can tell Titan to NOT adjust some or all frames. +function TitanPanelBarButton_ToggleAuxScreenAdjust() + -- turn on / off adjusting of frames at the bottom of the screen + TitanPanelToggleVar("AuxScreenAdjust"); + TitanPanel_AdjustFrames(true, "_ToggleAuxScreenAdjust") +end + +--====== Titan Bar +-- +--========================== +-- Routines to handle moving and sizing of short bars +-- + +---local Check the change in width; snap to edge of any part goes off screen. +---@param self table Titan short bar frame +---@param width number New width +---@param reason string Note on why this was called +---@return table result .ok boolean; .err string +local function CheckBarBounds(self, width, reason) + -- This is a touchy routine - change with care!! :) + -- + -- Let WoW handle any change in game scale. + -- When Titan scaling changes, recalc the bar placement. + -- Although the user may want to move bars in response to any scale change. + local trace = false -- true false + local result = {} + result.ok = true + result.err = "" + local err = "" + + local f_name = self:GetName() + local bar_name = TitanBarData[f_name].name + local locale_name = TitanBarData[f_name].locale_name + + if TitanBarData[f_name].user_move + and TitanBarDataVars[f_name].show + then + ---[[ + if trace then + print("Bounds" + .. " " .. tostring(bar_name) .. "" + .. " " .. tostring(width) .. "" + .. " " .. tostring(reason) .. "" + ) + end + --]] + + local tscale = TitanPanelGetVar("Scale") + local x, y, w, scale = TitanVariables_GetBarPos(f_name) + local scale_change = false + if tscale == scale then + -- no need to use scaling to recalc position + else + scale_change = true + -- The 'set' will update the sacaling for next time + end + local screen = TitanUtils_ScreenSize() + local screen_right_scaled = screen.scaled_x + local screen_top_scaled = screen.scaled_y + local screen_right = screen.x + local screen_top = screen.y + local screen_right_t = screen.x * tscale + local screen_top_t = screen.y * tscale + + local bar_left = math.floor(self:GetLeft()) + local bar_right = math.floor(self:GetRight()) + local bar_top = math.floor(self:GetTop()) + local bar_bottom = math.floor(self:GetBottom()) + + local orig_w = self:GetWidth() -- * tscale --math.floor(self:GetWidth() * tscale) + local l_off = bar_left + local r_off = bar_right + local t_off = bar_top + local b_off = bar_bottom + local hght = (t_off - b_off) + + if scale_change then + -- Apply the Titan scaling to get 'real' position within WoW window; + -- Use floor to trunc decimal places where the side could be right on the edge of the screen. + l_off = math.floor(bar_left * tscale) + r_off = math.floor(bar_right * tscale) + t_off = math.floor(bar_top * tscale) + b_off = math.floor(bar_bottom * tscale) + else + -- Just check the bar position + end + ---[[ + if trace then + print(">Bounds" + .. " " .. tostring(bar_name) .. "" + .. "\n" + .. " L " .. tostring(format("%0.1f", l_off)) .. "" + .. " R " .. tostring(format("%0.1f", r_off)) .. "" + .. " T " .. tostring(format("%0.1f", t_off)) .. "" + .. " B " .. tostring(format("%0.1f", b_off)) .. "" + .. " W " .. tostring(format("%0.1f", orig_w)) .. "" + .. " H " .. tostring(format("%0.1f", hght)) .. "" + .. "\n" + .. " SR " .. tostring(format("%0.1f", screen_right)) .. "" + .. " ST " .. tostring(format("%0.1f", screen_top)) .. "" + .. " SR_t " .. tostring(format("%0.1f", screen_right_t)) .. "" + .. " ST_t " .. tostring(format("%0.1f", screen_top_t)) .. "" + ) + end + --]] + local w = 0 + local x_off = 0 + local y_off = 0 + local w_off = 0 + + -- Assume all ok :) + x_off = l_off + y_off = b_off + + if (width == 0) then -- drag & drop OR entry / reload + -- Assumes BOTTOMLEFT of screen per Short bar defaults. + -- if resolution is not 'pixel perfect' rounding could cause algorithm to think bar is off screen + + -- Keep the width + w_off = orig_w + + if l_off < 0 then + x_off = 0 + err = "Off left of screen, snap to edge" + elseif (r_off) > screen_right then + x_off = math.floor(screen_right - (r_off - l_off)) + err = "Off right side of screen, snap to edge" + end + if err ~= "" then + result.ok = false + result.err = err + if trace then + TitanPrint(locale_name .. " " .. err .. "!!!!" + , "warning") + end + end + err = "" + if (t_off) > screen_top then + y_off = math.floor(screen_top - (t_off - b_off)) + err = "Off top of screen, snap to edge" + elseif b_off < 0 then + y_off = 0 + err = "Off bottom of screen, snap to edge" + end + if err ~= "" then + result.ok = false + result.err = result.err .. "\n" .. err + if trace then + TitanPrint(locale_name .. " " .. err .. "!!!!" + .. " [" .. tostring(format("%0.1f", x_off)) .. "]" + .. " [" .. tostring(format("%0.1f", y_off)) .. "]" + , "warning") + end + end + else -- width change + local min_w, min_h, max_w, max_h = self:GetResizeBounds() + -- Keep the X and Y + local w_new = orig_w + width + if w_new < min_w then + -- do nothing - too small + w_off = min_w + err = "Width too small. Set to min width." + elseif w_new > max_w then + w_off = max_w + err = "Width too big. Set to max width." -- too wide + elseif x_off + (w_new * tscale) > screen_right then + w_off = orig_w + err = "Off right of screen, snap to edge" + else + w_off = w_new + end + + self:SetSize(w_off, TITAN_PANEL_BAR_HEIGHT) + -- self:SetWidth(w_off) + end + + if scale_change then + -- Back out Titan scaling + x_off = math.floor(x_off / tscale) + y_off = math.floor(y_off / tscale) + else + -- Accept the results of the checks + end + w_off = w_off --/ tscale + TitanVariables_SetBarPos(self, false, x_off, y_off, w_off) + + if trace then + print(">>Bounds" + .. " " .. tostring(bar_name) .. "" + .. " " .. tostring(result.ok) .. "" + .. " SC " .. tostring(scale_change) .. "" + .. " X " .. tostring(format("%0.1f", x_off)) .. "(" .. tostring(bar_left) .. ")" + .. " Y " .. tostring(format("%0.1f", y_off)) .. "(" .. tostring(bar_bottom) .. ")" + .. " W " .. tostring(format("%0.1f", w_off)) .. "" + ) + if err ~= "" then + TitanPrint(locale_name .. " " .. err .. "!!!!" + .. " [" .. tostring(format("%0.1f", x_off)) .. "]" + .. " [" .. tostring(format("%0.1f", y_off)) .. "]" + .. " [" .. tostring(format("%0.1f", w_off)) .. "]" + , "warning") + end + end + else + -- Controlled with anchor points; cannot move so no check is needed + end + + + return result +end + +---local Start the grap of a Short Titan bar if Shift and left mouse are held. +---@param self table +local function OnMoveStart(self) + if IsShiftKeyDown() then + if self:IsMovable() then + self.isMoving = true + self:StartMoving() + _G.GameTooltip:Hide() + end + else + -- Do not move + end +end + +---local When a Short Titan bar drag is stopped. +---@param self table +local function OnMovingStop(self) + self:StopMovingOrSizing() + self.isMoving = nil + + local res = CheckBarBounds(self, 0, "OnMovingStop") + if res.ok then + -- placement ok + else + -- Need to 'snap' it to an edge + TitanPanel_InitPanelBarButton("OnMovingStop") + end + -- Seems overkill - this will recalc all bars... +end + +---local Change the width of a Short Titan bar when mouse is over the bar and Shift is held when the mouse wheel is used. +---@param self table Frame mouse is over +---@param d integer Mouse wheel direction (1 larger; -1 smaller) +--- Assuming a 1 'click' is a pixel +local function OnMouseWheel(self, d) + -- Can get noisy, "Initializes" all bars at each click to ensure the bar is drawn. + if IsShiftKeyDown() then + local msg = "OnMouseWheel" + local delta = d + if IsControlKeyDown() then + delta = d * 10 + msg = msg .. " +Alt" + else + -- use 1 + end + local res = CheckBarBounds(self, delta, msg) + if res.ok then + end + --[[ +print("wheel" +.." "..tostring(self:GetName()).."" +.." "..tostring(d).."" +.." old: "..tostring(format("%0.1f", old_w)).."" +.." new: "..tostring(format("%0.1f", self:GetWidth())).."" +.." ok: "..tostring(res.ok).."" +) +--]] + -- TitanPanel_InitPanelBarButton("OnMouseWheel") + end +end + +---Titan Force all plugins created from LDB addons, visible or not, to be on the right side of the Titan bar. +--- Any visible plugin will be forced to the right side on the same bar it is currently on. +function TitanPanelBarButton_ForceLDBLaunchersRight() + local plugin = {} + for index, id in pairs(TitanPluginsIndex) do + plugin = TitanUtils_GetPlugin(id); + if plugin and plugin.ldb == "launcher" + and not TitanGetVar(id, "DisplayOnRightSide") then + TitanToggleVar(id, "DisplayOnRightSide"); + local button = TitanUtils_GetButton(id) + if button then + local buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; + if not TitanGetVar(id, "ShowIcon") then + TitanToggleVar(id, "ShowIcon"); + end + TitanPanelButton_UpdateButton(id); + if buttonText then + buttonText:SetText("") + button:SetWidth(16); + TitanPlugins[id].buttonTextFunction = nil; + _G[TitanUtils_ButtonName(id) .. TITAN_PANEL_TEXT] = nil; + if button:IsVisible() then + local bar = TitanUtils_GetWhichBar(id) + TitanPanel_RemoveButton(id); + TitanUtils_AddButtonOnBar(bar, id) + end + end + end + end + end +end + +---local Helper to create the 'anchor' frames used by other addons that need to adjust so Titan can be visible. +---The anchor frames are adjusted depending on which Titan bars the user selects to show. +--- - TitanPanelTopAnchor - the frame at the bottom of the top bar(s) shown. +--- - TitanPanelBottomAnchor - the frame at the top of the bottom bar(s) shown. +local function TitanAnchors() + local anchor_top = TitanMovable_GetPanelYOffset(TITAN_PANEL_PLACE_TOP) + local anchor_bot = TitanMovable_GetPanelYOffset(TITAN_PANEL_PLACE_BOTTOM) + anchor_top = anchor_top <= TITAN_WOW_SCREEN_TOP and anchor_top or TITAN_WOW_SCREEN_TOP + anchor_bot = anchor_bot >= TITAN_WOW_SCREEN_BOT and anchor_bot or TITAN_WOW_SCREEN_BOT + + local top_point, top_rel_to, top_rel_point, top_x, top_y = TitanPanelTopAnchor:GetPoint(TitanPanelTopAnchor + :GetNumPoints()) + local bot_point, bot_rel_to, bot_rel_point, bot_x, bot_y = TitanPanelBottomAnchor:GetPoint(TitanPanelBottomAnchor + :GetNumPoints()) + top_y = floor(tonumber(top_y) + 0.5) + bot_y = floor(tonumber(bot_y) + 0.5) + --[[ +TitanDebug("Anc top: "..top_y.." bot: "..bot_y +.." a_top: "..anchor_top.." a_bot: "..anchor_bot +) +--]] + if top_y ~= anchor_top then + TitanPanelTopAnchor:ClearAllPoints() + TitanPanelTopAnchor:SetPoint(top_point, top_rel_to, top_rel_point, top_x, anchor_top); + end + if bot_y ~= anchor_bot then + TitanPanelBottomAnchor:ClearAllPoints() + TitanPanelBottomAnchor:SetPoint(bot_point, bot_rel_to, bot_rel_point, bot_x, anchor_bot) + end +end + +---Titan Show all the Titan bars the user has selected. +---@param reason string Debug note on where the call initiated +function TitanPanelBarButton_DisplayBarsWanted(reason) + -- build debug output + local str = "_DisplayBarsWanted" + .. " " .. tostring(reason) .. "" + Titan_Debug.Out('titan', 'bars_setup', str) + + -- Check all bars to see if the user has requested they be shown + for idx, v in pairs(TitanBarData) do + -- Show / hide plus kick auto hide, if needed + Titan_AutoHide_Init(idx) + end + + -- Set anchors for other addons to use. + TitanAnchors() + + if Titan_Global.switch.can_edit_ui then + -- Not needed with UI movable widgets + -- build debug output + local str = "_DisplayBarsWanted" + .. " UI user editable - skip adj frames" + Titan_Debug.Out('titan', 'bars_setup', str) + else + -- Adjust other frames because the bars shown / hidden may have changed + TitanPanel_AdjustFrames(true, "_DisplayBarsWanted") + end +end + +---Titan This routine will hide all the Titan bars (and hiders) regardless of what the user has selected. +--- For example when the pet battle is active. We cannot figure out how to move the pet battle frame so we are punting and hiding Titan... +--- We only need to hide the bars (and hiders) - not adjust frames +function TitanPanelBarButton_HideAllBars() + for idx, v in pairs(TitanBarData) do + TitanPanelBarButton_Hide(idx) + end +end + +---local Show the requested Titan bar. +---@param frame_str string Titan bar +---@return boolean CanShow False if there is a restricting condition +local function showBar(frame_str) + local flag = true -- only set false for known conditions + + if frame_str == TitanVariables_GetFrameName("Bar") + or frame_str == TitanVariables_GetFrameName("Bar2") + then + -- ===== Battleground or Arena : User selected + -- if (TitanPanelGetVar("HideBarsInPVP")) + if TitanBarDataVars[frame_str].hide_in_pvp + and (C_PvP.IsBattleground() + or C_PvP.IsArena() + -- or GetZoneText() == "Stormwind City" + -- or GetZoneText() == "Tempest Keep" + ) + then + flag = false + end + end + + -- ===== In Combat : User selected + if TitanBarDataVars[frame_str].hide_in_combat + -- or TitanPanelGetVar("HideBarsInCombat") + then + if in_combat then -- InCombatLockdown() too slow + flag = false + end + end + + -- ===== In Pet Battle + if C_PetBattles and C_PetBattles.IsInBattle() then + if TitanBarData[frame_str].user_move then + -- leave as is + else + flag = false + end + end + --[[ +print("showBar" +--.." "..tostring(C_PetBattles.IsInBattle()).."" +.." > "..tostring(flag).."" +.." '"..tostring(frame_str).."'" +) +--]] + return flag +end + +---local Set the position of the requested Titan bar. +---@param frame string Titan bar +local function SetBar(frame) + local trace = false + local display = _G[frame]; + + local x, y, w = TitanVariables_GetBarPos(frame) + local tscale = TitanPanelGetVar("Scale") + local show = TitanBarData[frame].show + local bott = TitanBarData[frame].bott + + + display:ClearAllPoints() + if trace then + -- local screen = TitanUtils_ScreenSize() + -- local sx = screen.scaled_x + -- local sy = screen.scaled_y + print("SetBar" + .. " " .. tostring(TitanBarData[frame].name) .. "" + .. " x:" .. tostring(format("%0.1f", x)) .. "" + .. " y:" .. tostring(format("%0.1f", y)) .. "" + .. " w:" .. tostring(format("%0.1f", w)) .. "" + ) + end + + if TitanBarData[frame].user_move then + display:SetPoint(show.pt, show.rel_fr, show.rel_pt, x, y) + display:SetSize(w, TITAN_PANEL_BAR_HEIGHT) + else + display:SetPoint(show.pt, show.rel_fr, show.rel_pt, x, y) + local h = TITAN_PANEL_BAR_HEIGHT + display:SetPoint(bott.pt, bott.rel_fr, bott.rel_pt, x, y - h) + end +end + +---Titan Toggle the given Titan bar based on the user selection. +---@param frame string Frame mame of the Titan bar +function TitanPanelBarButton_Show(frame) + local display = _G[frame]; + + if display and TitanBarData[frame].name + then + if TitanBarDataVars[frame].show -- User requested + and showBar(frame) -- No preventing condition + then -- Place Bar + SetBar(frame) + ---[[ + -- The bar may need to be moved back onto the screen. + local res = CheckBarBounds(display, 0, "_Show the bar") + if res.ok then + -- placement ok + else + -- Need to 'snap' it to an edge + SetBar(frame) + end + --]] + TitanPanel_SetBarTexture(frame) + + if TitanBarData[frame].hider then + _G[TitanBarData[frame].hider]:Hide() + else + -- not allowed for this bar + end + else + -- The user has not elected to show this bar + TitanPanelBarButton_Hide(frame) + end + end +end + +---Titan Hide the given Titan bar based on the user selection. +--- Hide moves rather than just 'not shown'. Otherwise the buttons will stay visible defeating the purpose of hide. +--- Also moves the hider bar if auto hide is not selected. +---@param frame string Frame mame of the Titan bar +function TitanPanelBarButton_Hide(frame) + if TITAN_PANEL_MOVING == 1 then return end + + local display = _G[frame] + local data = TitanBarData[frame] + + if display and data + then + local x, y, w = TitanVariables_GetBarPos(frame) + -- This moves rather than hides. If we just hide then the plugins will still show. + -- Hide by ensuriing the Y offset is off the screen. + display:ClearAllPoints() + local h = (math.abs(y) + TITAN_PANEL_BAR_HEIGHT * 2) * (-1 * y) + local h = data.hide_y + --[[ +print("_Hide" +--.." "..tostring(frame).."" +.." "..tostring(data.name).."" +.." "..tostring(TitanBarDataVars[frame].show).."" +.." "..tostring(h).."" +) +--]] + if TitanBarData[frame].user_move then + display:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, h) + else + display:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, h) + display:SetPoint(data.bott.pt, data.bott.rel_fr, data.bott.rel_pt, x, h - TITAN_PANEL_BAR_HEIGHT) + end + + if TitanBarData[frame].hider then + local hider = _G[data.hider] + if TitanBarDataVars[frame].show + and TitanBarDataVars[frame].auto_hide then + -- if (TitanPanelGetVar(data.name.."_Show")) and (TitanPanelGetVar(data.name.."_Hide")) then + -- Auto hide is requested so show the hider bar in the right place + hider:ClearAllPoints(); + hider:SetPoint(data.show.pt, data.show.rel_fr, data.show.rel_pt, x, y); + hider:Show() + else + -- The bar was not requested + hider:Hide() + end + else + -- not allowed for this bar + end + end +end + +---Titan Show all user selected plugins on the Titan bar(s) then justify per the user selection. +--- This is done an all bars whether shown or not. +function TitanPanel_InitPanelButtons() + local button + local r_prior = {} + local l_prior = {} + local scale = TitanPanelGetVar("Scale"); + local button_spacing = TitanPanelGetVar("ButtonSpacing") * scale + local icon_spacing = TitanPanelGetVar("IconSpacing") * scale + + local prior = {} + -- set prior to the starting offsets + -- The right side plugins are set here. + -- Justify adjusts the left side start according to the user setting + -- The effect is left side plugins has spacing on the right side and + -- right side plugins have spacing on the left. + for idx, v in pairs(TitanBarData) do + local bar = TitanBarData[idx].name + local y_off = TitanBarData[idx].plugin_y_offset + prior[bar] = { + right = { + button = TitanVariables_GetFrameName(bar), + anchor = "RIGHT", + x = 5, -- Offset of first plugin to right side of screen + y = y_off, + }, + left = { + button = TitanVariables_GetFrameName(bar), + anchor = "LEFT", + x = 0, -- Justify adjusts - center or not + y = y_off, + }, + } + end + -- + TitanPanelBarButton_DisplayBarsWanted("TitanPanel_InitPanelButtons"); + + -- Position all the buttons + for idx = 1, table.maxn(TitanPanelSettings.Buttons) do + local id = TitanPanelSettings.Buttons[idx]; + if (TitanUtils_IsPluginRegistered(id)) then + local i = TitanPanel_GetButtonNumber(id); + button = TitanUtils_GetButton(id); + + if button then + -- If the plugin has asked to be on the right + if TitanUtils_ToRight(id) then + -- ========================= + -- position the plugin relative to the prior plugin + -- or the bar if it is the 1st + r_prior = prior[TitanPanelSettings.Location[i]].right + -- ========================= + button:ClearAllPoints(); + button:SetPoint("RIGHT", _G[r_prior.button]:GetName(), r_prior.anchor, (-(r_prior.x) * scale), + r_prior.y) + + -- ========================= + -- capture the button for the next plugin + r_prior.button = TitanUtils_ButtonName(id) + -- set prior[x] the anchor points and offsets for the next plugin + r_prior.anchor = "LEFT" + r_prior.x = icon_spacing + r_prior.y = 0 + -- ========================= + else + -- handle plugins on the left side of the bar + -- + -- ========================= + -- position the plugin relative to the prior plugin + -- or the bar if it is the 1st + l_prior = prior[TitanPanelSettings.Location[i]].left + --[===[ +print("Bar plugins" +.." "..tostring(i).."" +.." "..tostring(TitanPanelSettings.Location[i]).."" +.." "..tostring(id).."" +) +--]===] + -- ========================= + -- + button:ClearAllPoints(); + button:SetPoint("LEFT", _G[l_prior.button]:GetName(), l_prior.anchor, l_prior.x * scale, l_prior.y); + + -- ========================= + -- capture the next plugin + l_prior.button = TitanUtils_ButtonName(id) + -- set prior[x] (anchor points and offsets) for the next plugin + l_prior.anchor = "RIGHT" + l_prior.x = (button_spacing) + l_prior.y = 0 + -- ========================= + end + button:Show() + end + end + end + -- Set panel button init flag + TITAN_PANEL_BUTTONS_INIT_FLAG = 1; + TitanPanelButton_Justify(); +end + +---Titan Reorder all the shown all user selected plugins on the Titan bar(s). Typically used after a button has been removed / hidden. +---@param index number of the plugin removed +function TitanPanel_ReOrder(index) + for i = index, #TitanPanelSettings.Buttons do + -- for i = index, table.getn(TitanPanelSettings.Buttons) do + TitanPanelSettings.Location[i] = TitanPanelSettings.Location[i + 1] + end +end + +---Titan Remove a plugin then show the rest of user selected plugins on the Titan bar(s). +---@param id string Unique ID of the plugin +---@param hide_plugin? boolean whether to hide plugin after removal +function TitanPanel_RemoveButton(id, hide_plugin) + if (not TitanPanelSettings) then + return; + end + + local hide_me = hide_plugin + if hide_me == nil then + hide_me = true -- not passed + else + -- was passed + end + + local i = TitanPanel_GetButtonNumber(id) + local currentButton = TitanUtils_GetButton(id); + + -- safeguard ... + -- This cancels all timers of name "TitanPanel"..id as a safeguard to destroy any active plugin timers + -- based on a fixed naming convention : TitanPanel..id, eg. "TitanPanelClock" this prevents "rogue" + -- timers being left behind by lack of an OnHide check + ---@diagnostic disable-next-line: missing-parameter + if id then AceTimer.CancelAllTimers() end -- ??? seems confused 0 or 1 params "TitanPanel" .. id + + TitanPanel_ReOrder(i); + table.remove(TitanPanelSettings.Buttons, TitanUtils_GetCurrentIndex(TitanPanelSettings.Buttons, id)); + if currentButton and hide_me then + currentButton:Hide(); + end + -- Show the existing buttons + TitanPanel_InitPanelButtons(); +end + +--- Titan Get the index of the given plugin from the Titan plugin displayed list. +--- The routine returns +1 if not found so it is 'safe' to add to the list +---@param id string Unique ID of the plugin +---@return number num position or num + 1 for end +function TitanPanel_GetButtonNumber(id) + -- getn deprecated as of 5.2 - IDE now complaining 2024 Aug + if (TitanPanelSettings) then + for i = 1, #TitanPanelSettings.Buttons do + if (TitanPanelSettings.Buttons[i] == id) then + return i; + end + end + return #TitanPanelSettings.Buttons + 1; + else + return 0; + end +end + +---Titan Update / refresh each plugin from the Titan plugin list. Used when a Titan option is changed that effects all plugins. +function TitanPanel_RefreshPanelButtons() + if (TitanPanelSettings) then + for i = 1, #TitanPanelSettings.Buttons do + TitanPanelButton_UpdateButton(TitanPanelSettings.Buttons[i], 1); + end + end +end + +---Titan Justify the plugins on each Titan bar. +--- Used when : +---- Init / show of a Titan bar +----the user changes the 'center' option on a Titan bar +function TitanPanelButton_Justify() + -- Only the left side buttons are justified. + if (not TITAN_PANEL_BUTTONS_INIT_FLAG or not TitanPanelSettings) then + return; + end + if InCombatLockdown() then + --TitanDebug("_Justify during combat!!!") + return; + -- Issue 856 where some taint is caused if the plugin size is updated during combat. Seems since Mists was released... + end + + local bar + local x_offset + local y_offset + local firstLeftButton + local scale = TitanPanelGetVar("Scale"); + local button_spacing = TitanPanelGetVar("ButtonSpacing") * scale + local icon_spacing = TitanPanelGetVar("IconSpacing") * scale + local leftWidth = 0; + local rightWidth = 0; + local counter = 0; + local align = 0; + local center_offset = 0; + + -- Look at each bar for plugins. + for idx, v in pairs(TitanBarData) do + bar = TitanBarData[idx].name + y_offset = TitanBarData[idx].plugin_y_offset + x_offset = TitanBarData[idx].plugin_x_offset + firstLeftButton = TitanUtils_GetButton(TitanPanelSettings.Buttons + [TitanUtils_GetFirstButtonOnBar(bar, TITAN_LEFT)]) + align = TitanBarDataVars[idx].align --TitanPanelGetVar(bar.."_Align") + leftWidth = 0; + rightWidth = 0; + counter = 0; + -- If there is a plugin on this bar then justify the first button. + -- The other buttons are relative to the first. + if (firstLeftButton) then + if (align == TITAN_PANEL_BUTTONS_ALIGN_LEFT) then + -- Now offset the plugins + firstLeftButton:ClearAllPoints(); + firstLeftButton:SetPoint("LEFT", idx, "LEFT", x_offset, y_offset); + end + -- Center if requested + if (align == TITAN_PANEL_BUTTONS_ALIGN_CENTER) then + leftWidth = 0; + rightWidth = 0; + counter = 0; + -- Calc the total width of the icons so we know where to start + for index, id in pairs(TitanPanelSettings.Buttons) do + local button = TitanUtils_GetButton(id); + if button and button:GetWidth() then + if TitanUtils_GetWhichBar(id) == bar then + if (TitanGetVar(id, "DisplayOnRightSide")) then + rightWidth = rightWidth + + icon_spacing + + button:GetWidth(); + else + counter = counter + 1; + leftWidth = leftWidth + + button_spacing + + button:GetWidth() + end + end + end + end + -- Now offset the plugins on the bar + firstLeftButton:ClearAllPoints(); + -- remove the last spacing otherwise the buttons appear justified too far left + center_offset = (0 - (leftWidth - button_spacing) / 2) + firstLeftButton:SetPoint("LEFT", idx, "CENTER", center_offset, y_offset); + end + end + end +end + +-------------------------------------------------------------- +-- +-- Local routines for Titan menu creation +local R_ADDONS = "Addons_" +local R_PLUGIN = "Plugin_" +local R_SETTINGS = "Settings" +local R_PROFILE = "Profile_" +local R_BARS_SETTING = "Bar_Show_Hide" + +---local Show main Titan (right click) menu. +---@param frame string Frame to add to +local function BuildMainMenu(frame) + local locale_bar = TitanBarData[frame].locale_name + local info = {}; + ----------------- + -- Menu title + TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_TITLE"] .. " - " .. locale_bar); + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PLUGINS"]); + + ----------------- + -- Plugin Categories + -- Both arrays are in TitanGlobal + ---@diagnostic disable-next-line: param-type-mismatch + for index, id in pairs(L["TITAN_PANEL_MENU_CATEGORIES"]) do + info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_CATEGORIES"][index]; + info.value = R_ADDONS .. TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY[index]; + info.hasArrow = 1; + TitanPanelRightClickMenu_AddButton(info); + end + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + ----------------- + -- Bars - Show / Hide + + info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_OPTIONS_BARS"]; + info.value = R_BARS_SETTING + info.hasArrow = 1; + TitanPanelRightClickMenu_AddButton(info); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + ----------------- + -- Config - just one button to open the first Titan option screen + do + info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_CONFIGURATION"]; + info.value = "Config"; + info.func = function() + TitanUpdateConfig("init") + Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About) + end + TitanPanelRightClickMenu_AddButton(info); + end + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + ----------------- + -- Profiles + -- TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILES"]); + + info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_PROFILES"] .. " " .. L["TITAN_PANEL_MENU_CONFIGURATION"] + info.value = "ConfigProfile"; + info.func = function() + TitanUpdateConfig("init") + AceConfigDialog:Open("Titan Panel Addon Chars") + -- Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.profiles) + end + TitanPanelRightClickMenu_AddButton(info); + + local res = TitanUtils_GetProfile() + info = {}; + info.notCheckable = true + info.text = res.cname + info.value = "Global_value" + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_HELP"] + info.value = "ConfigProfile"; + info.func = function() + TitanUpdateConfig("init") + AceConfigDialog:Open("Titan Panel Help List") + -- Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.profiles) + end + TitanPanelRightClickMenu_AddButton(info); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + ----------------- + -- Hide this bar + info = {}; + info.text = (HIDE or "Hide") + info.value = "HideMe" + info.notCheckable = true + info.disabled = (TitanUtils_NumActiveBars() == 1) + info.arg1 = frame; + info.func = function(self, frame_str) + TitanBarDataVars[frame_str].show = not TitanBarDataVars[frame_str].show + TitanPanelBarButton_DisplayBarsWanted(frame_str .. " user clicked Hide") + end + info.keepShownOnClick = nil + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); +end + +---local Show list of plugin defined options from the Titan right click menu. +local function BuildPluginMenu() + -- + local info = {}; + + -- Handle the plugins + + for index, id in pairs(TitanPluginsIndex) do + local plugin = TitanUtils_GetPlugin(id) + local par_val = TitanPanelRightClickMenu_GetDropdMenuValue() + local menu_plugin = string.gsub(par_val, R_PLUGIN, "") + if plugin and plugin.id and plugin.id == menu_plugin then + --title + info = {}; + info.text = TitanPlugins[plugin.id].menuText; + info.notCheckable = true + info.notClickable = 1; + info.isTitle = 1; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + --ShowIcon + if plugin.controlVariables.ShowIcon then + info = {}; + info.text = L["TITAN_PANEL_MENU_SHOW_ICON"]; + info.value = plugin.id + info.arg1 = plugin.id + info.func = function(self, p_id) -- (self, info.arg1, info.arg2) + TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowIcon", nil }) + end + info.keepShownOnClick = 1; + info.checked = TitanGetVar(plugin.id, "ShowIcon"); + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + + --ShowLabel + if plugin.controlVariables.ShowLabelText then + info = {}; + info.text = L["TITAN_PANEL_MENU_SHOW_LABEL_TEXT"]; + info.value = plugin.id + info.arg1 = plugin.id + info.func = function(self, p_id) -- (self, info.arg1, info.arg2) + TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowLabelText", nil }) + end + info.keepShownOnClick = 1; + info.checked = TitanGetVar(plugin.id, "ShowLabelText"); + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + + --ShowRegularText (LDB data sources only atm) + if plugin.controlVariables.ShowRegularText then + info = {}; + info.text = L["TITAN_PANEL_MENU_SHOW_PLUGIN_TEXT"] + info.value = plugin.id + info.arg1 = plugin.id + info.func = function(self, p_id) -- (self, info.arg1, info.arg2) + TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowRegularText", nil }) + end + info.keepShownOnClick = 1; + info.checked = TitanGetVar(plugin.id, "ShowRegularText"); + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + + --ShowColoredText + if plugin.controlVariables.ShowColoredText then + info = {}; + info.text = L["TITAN_PANEL_MENU_SHOW_COLORED_TEXT"]; + info.value = plugin.id + info.arg1 = plugin.id + info.func = function(self, p_id) -- (self, info.arg1, info.arg2) + TitanPanelRightClickMenu_ToggleVar({ p_id, "ShowColoredText", nil }) + end + info.keepShownOnClick = 1; + info.checked = TitanGetVar(plugin.id, "ShowColoredText"); + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + + -- Right-side plugin + if plugin.controlVariables.DisplayOnRightSide then + info = {}; + info.text = L["TITAN_PANEL_MENU_LDB_SIDE"]; + info.value = plugin.id + info.arg1 = plugin.id + info.func = function(self, p_id) -- (self, info.arg1, info.arg2) + TitanToggleVar(p_id, "DisplayOnRightSide") + local bar = TitanUtils_GetWhichBar(p_id) + TitanPanel_RemoveButton(p_id); + TitanUtils_AddButtonOnBar(bar, p_id); + end + info.checked = TitanGetVar(plugin.id, "DisplayOnRightSide"); + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + end + end +end + +---local Build the list of plugins for the category the mouse is over - Titan (right click) menu. +---@param frame string Frame to add to +local function BuildPluginCategoryMenu(frame) + local info = {}; + local plugin; + + for index, id in pairs(TitanPluginsIndex) do + plugin = TitanUtils_GetPlugin(id) + if plugin then -- add the plugin to the menu + plugin.category = plugin and plugin.category or "General"; + if (TitanPanelRightClickMenu_GetDropdMenuValue() == R_ADDONS .. plugin.category) then + if not TitanGetVar(id, "ForceBar") + or (TitanGetVar(id, "ForceBar") == TitanBarData[frame].name) then + info = {}; + local ver = plugin and plugin.version or "" + if TitanPanelGetVar("VersionShown") then + if ver == nil or ver == "" then + ver = "" -- safety in case of nil + else + ver = TitanUtils_GetGreenText(" (" .. ver .. ")") + end + else + ver = "" -- not requested + end + info.text = plugin and plugin.menuText .. ver or "" + + -- Add Bar + local internal_bar, which_bar = TitanUtils_GetWhichBar(id) + if which_bar == nil then + -- Plugin not shown + else + -- if internal_bar == TitanBarData[frame].name then + -- info.text = info.text .. TitanUtils_GetGreenText(" (" .. which_bar .. ")") + -- else + info.text = info.text .. TitanUtils_GetGoldText(" (" .. which_bar .. ")") + -- end + end + + if plugin.controlVariables then + info.hasArrow = 1; + end + info.value = R_PLUGIN .. id; -- for next level dropdown + info.arg1 = frame; + info.arg2 = id; + info.func = function(self, frame_str, plugin_id) -- (self, info.arg1, info.arg2) + -- frame_str is the bar the user clicked to get the menu... + local bar = TitanBarData[frame_str].name + + if TitanPanel_IsPluginShown(plugin_id) then + TitanPanel_RemoveButton(plugin_id); + else + TitanUtils_AddButtonOnBar(bar, plugin_id) + end + end + info.checked = TitanPanel_IsPluginShown(id) or nil + info.keepShownOnClick = 1; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end + end + else + end + end +end + +local function BuildBarList() + local info = {}; + + -- sort the bar data by their intended order + local bar_list = {} + for _, v in pairs(TitanBarData) do + bar_list[v.order] = v + end + table.sort(bar_list, function(a, b) + return a.order < b.order + end) + + for idx = 1, #bar_list do + local v = bar_list[idx] -- process this bar + local name = v.locale_name + local bar_data = TitanBarDataVars[v.frame_name] + + info = {}; + info.text = name + info.value = v.frame_name + info.arg1 = v.frame_name + info.func = function(self, arg1) -- (self, info.arg1, info.arg2) + TitanBarDataVars[arg1].show = not TitanBarDataVars[arg1].show + TitanPanelBarButton_DisplayBarsWanted(arg1 .. " right click menu " .. tostring(TitanBarDataVars[arg1].show)) + end + --info.keepShownOnClick = 1; + info.checked = bar_data.show + info.disabled = nil; + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + end +end + +---Titan This is the controller for the Titan (right click) menu. +---@param self table Titan bar frame that was right clicked +--- Frame name used is <Titan bar name>RightClickMenu +function TitanPanelRightClickMenu_PrepareBarMenu(self) + -- Determine which bar was clicked on + -- local s, e, frame = string.find(self:GetName(), "(.*)RightClickMenu"); + local s, e, frame = string.find(self:GetName(), "(.*)" .. TITAN_PANEL_CLICK_MENU_SUFFIX); + local lev = (TitanPanelRightClickMenu_GetDropdownLevel() or 1) + --[[ +print("_prep R click" +.." "..tostring(frame).."" +.." "..tostring(lev).."" +) +--]] + + -- Level 1 + --[===[ + Title - <Bar name> + ---- + Plugins + <list of Categories> + ---- + Configuration => Opens Titan Options + ----- + Profiles + Manage > <Level 2> + Save => Save current profile (used for Global) + ----- + Use Global Profile + <Profile name used or <>> + ---- + Hide => Hide this Bar + --]===] + if lev == 1 then + BuildMainMenu(frame) + end + + -- Level 2 + -- Plugin Categories => Plugins in that category + -- OR + -- Profiles => Server / Realm list + -- OR + -- Bars =? Show checkbox + if (lev == 2) then + if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), R_ADDONS) then + BuildPluginCategoryMenu(frame) + end + + if (TitanPanelRightClickMenu_GetDropdMenuValue() == R_BARS_SETTING) then + BuildBarList() + end + + return; + end + + -- Level 3 + -- Plugin Categories => Plugins in that category => Plugin defined options + -- OR + -- Profiles > Server / Realm list > Character on realm list + if (lev == 3) then + if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), R_PLUGIN) then + BuildPluginMenu() + end + return; + end +end + +---Titan Determine if the given plugin is on any Titan bar. +---@param id string Unique ID of the plugin +---@return boolean shown True on a Titan bar even if hidden or on auto hide +function TitanPanel_IsPluginShown(id) + if (id and TitanPanelSettings) then + return TitanUtils_TableContainsValue(TitanPanelSettings.Buttons, id) + else + return false + end +end + +---Titan Determine if the given plugin is / would be on right or left of a Titan bar. +---@param id string Unique ID of the plugin +---@return string R_L TITAN_RIGHT("Right") or TITAN_Left("Left") +function TitanPanel_GetPluginSide(id) + if (TitanGetVar(id, "DisplayOnRightSide")) then + return TITAN_RIGHT; + else + return TITAN_LEFT; + end +end + +---Titan Set the scale, texture (graphic), and transparancy of all the Titan bars based on the user selection. +---@param reason string Debug note on where the call initiated +function TitanPanel_InitPanelBarButton(reason) + -- Set initial Panel Scale + TitanPanel_SetScale(); + + -- build debug output + local str = "_InitPanelBarButton" + .. " " .. tostring(reason) .. "" + Titan_Debug.Out('titan', 'bars_setup', str) + TitanPanelBarButton_DisplayBarsWanted("InitPanelBarButton") +end + +-- +--========================== +-- Routines to handle creation of Titan bars +-- + +---Titan Create a Titan bar that can show plugins. +---@param frame_str string Unique ID of the plugin +function TitanPanelButton_CreateBar(frame_str) + local this_bar = frame_str + local a_bar = CreateFrame("Button", this_bar, UIParent, "Titan_Bar__Display_Template") + + local bar_data = TitanBarData[this_bar] + + -- ====== + -- Scripts + a_bar:SetScript("OnEnter", function(self) TitanPanelBarButton_OnEnter(self) end) + a_bar:SetScript("OnLeave", function(self) TitanPanelBarButton_OnLeave(self) end) + a_bar:SetFrameStrata("DIALOG") + + if bar_data.user_move then + a_bar:SetMovable(true) + a_bar:SetResizable(true) + a_bar:EnableMouse(true) + a_bar:RegisterForDrag("LeftButton") + a_bar:SetScript("OnDragStart", OnMoveStart) + a_bar:SetScript("OnDragStop", OnMovingStop) + a_bar:SetScript("OnMouseWheel", OnMouseWheel) + else + -- Static full width bar + end + + -- ====== + -- Bounds only effective on Short bars for now + -- Min : No smaller than the padding & one icon + -- Max : No wider than the screen + -- does not seem to work to restrict size automatically... + local screen = TitanUtils_ScreenSize() + a_bar:SetResizeBounds(TitanBarData[this_bar].plugin_x_offset + 16, TITAN_PANEL_BAR_HEIGHT, screen.x, + TITAN_PANEL_BAR_HEIGHT) + a_bar:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + a_bar:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) + + -- ====== + -- Frame for right clicks + -- Use the plugin naming scheme for one frame to rule them all + -- 2024 Feb : Change to match plugin right click menu scheme so one routine can be used. + local f = CreateFrame("Frame", this_bar .. TITAN_PANEL_CLICK_MENU_SUFFIX, UIParent, "UIDropDownMenuTemplate") + + -- ====== + -- Hider for auto hide feature + local hide_bar_name = TITAN_PANEL_HIDE_PREFIX .. bar_data.name + if bar_data.hider then + local hide_bar = CreateFrame("Button", hide_bar_name, UIParent, "TitanPanelBarButtonHiderTemplate") + hide_bar:SetFrameStrata("DIALOG") + + -- Set script handlers for display + hide_bar:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + hide_bar:SetScript("OnEnter", function(self) TitanPanelBarButtonHider_OnEnter(self) end) + hide_bar:SetScript("OnLeave", function(self) TitanPanelBarButtonHider_OnLeave(self) end) + hide_bar:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) + + hide_bar:SetFrameStrata("BACKGROUND") + hide_bar:SetSize(screen.x, TITAN_PANEL_BAR_HEIGHT) + else + -- Hider not allowed for this bar + end +end + +--====== deprecated / Unused +--[====[ + +--[[ local +NAME: TitanPanel_CreateABar +DESC: Helper to add scripts to the Titan bar passed in. +VAR: frame - The frame name (string) of the Titan bar to create +OUT: None +NOTE: +- This also creates the hider bar in case the user want to use auto hide. +:NOTE +--]] +local function TitanPanel_CreateABar(frame) + if frame then + local bar_name = TitanBarData[frame].name + local bar_width = TitanBarData[frame].width + + if bar_name then + -- Set script handlers for display + _G[frame]:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + _G[frame]:SetScript("OnEnter", function(self) TitanPanelBarButton_OnEnter(self) end) + _G[frame]:SetScript("OnLeave", function(self) TitanPanelBarButton_OnLeave(self) end) + _G[frame]:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) + _G[frame]:SetWidth(bar_width) + + local hide_name = TitanBarData[frame].hider + if hide_name then + -- Set script handlers for display + _G[hide_name]:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + _G[hide_name]:SetScript("OnEnter", function(self) TitanPanelBarButtonHider_OnEnter(self) end) + _G[hide_name]:SetScript("OnLeave", function(self) TitanPanelBarButtonHider_OnLeave(self) end) + _G[hide_name]:SetScript("OnClick", function(self, button) TitanPanelBarButton_OnClick(self, button) end) + + _G[hide_name]:SetFrameStrata("BACKGROUND") + _G[hide_name]:SetWidth(bar_width) + _G[hide_name]:SetHeight(TITAN_PANEL_BAR_HEIGHT/2); + end + + -- Set the display bar + local container = _G[frame] + container:SetHeight(TITAN_PANEL_BAR_HEIGHT); + -- Set local identifier + local container_text = _G[frame.."_Text"] + if container_text then -- was used for debug/creating of the independent bars + container_text:SetText(tostring(bar_name)) + -- for now show it + container:Show() + end + end + else + end +end + +--]====] diff --git a/Titan/Titan.toc b/Titan/Titan.toc index 4291dd8..fbca080 100644 --- a/Titan/Titan.toc +++ b/Titan/Titan.toc @@ -19,6 +19,7 @@ ## X-Credits: TitanMod, Dark Imakuni, Adsertor, Titan Dev Team ## X-Category: Interface Enhancements ## X-Website: http://www.titanpanel.org +## X-Discord: https://discord.gg/ckNAVvbE ## X-Email: honorgog@gmail.com ## X-Localizations: enUS, ptBR, zhCN, deDE, esES, frFR, itIT, koKR, ruRU, zhTW ## X-License: All rights reserved (See license.txt) @@ -35,7 +36,6 @@ libs\Ace\AceGUI-3.0\AceGUI-3.0.xml libs\Ace\AceConfig-3.0\AceConfig-3.0.xml libs\Ace\AceLocale-3.0\AceLocale-3.0.xml libs\Ace\LibSharedMedia-3.0\lib.xml -libs\Ace\AceGUI-3.0-SharedMediaWidgets\widget.xml libs\Ace\LibQTip-1.0\lib.xml libs\LibDataBroker-1.1.lua diff --git a/Titan/TitanAutoHide.lua b/Titan/TitanAutoHide.lua index d06e024..b9a53cb 100644 --- a/Titan/TitanAutoHide.lua +++ b/Titan/TitanAutoHide.lua @@ -2,7 +2,7 @@ Contains the routines of AutoHide Titan plugin to auto hide a Titan bar. Auto hide uses a data driven approach. Rather than seperate routines for each bar, auto hide is implemented in a general manner. -The table TitanBarData hold relevant data needed to control auto hide. +The table TitanBarData holds relevant data needed to control auto hide. If auto hide is turned on these routines will show / hide the proper bar (and plugins on the bar). These routines control the 'push pin' on each bar, if shown. diff --git a/Titan/TitanConfig.lua b/Titan/TitanConfig.lua index 65613cd..5af81eb 100644 --- a/Titan/TitanConfig.lua +++ b/Titan/TitanConfig.lua @@ -4,103 +4,129 @@ Titan uses Ace libraries to place the Titan options within the Blizzard option s Most routines in this file are local because they create the Titan options. These routines are called first when Titan processes the 'player entering world' event. -If an options list (skins, extra, etc) is changed by the user then the Ace table needs to be updated and WoW server informed to 'redraw'. +If an options list (skins, extra, etc) is changed by the user then the Ace table needs to be updated and WoW server is informed to 'redraw'. --]===] local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) local AceConfigDialog = LibStub("AceConfigDialog-3.0") local AceConfigRegistry = LibStub("AceConfigRegistry-3.0") local AceConfig = LibStub("AceConfig-3.0") +local media = LibStub("LibSharedMedia-3.0") local TitanSkinToRemove = "None"; local TitanSkinName, TitanSkinPath = "", ""; -local TitanGlobalProfile = "" TITAN_PANEL_CONFIG = { topic = { - About = L["TITAN_PANEL"], - top = L["TITAN_PANEL_MENU_OPTIONS_BARS"], - globals = L["TITAN_PANEL_MENU_OPTIONS_BARS_ALL"], - bottom = L["TITAN_PANEL_MENU_BOTTOM_BARS"], - plugins = L["TITAN_PANEL_MENU_PLUGINS"], - profiles = L["TITAN_PANEL_MENU_PROFILES"], - tooltips = L["TITAN_PANEL_MENU_OPTIONS_SHORT"], - scale = L["TITAN_PANEL_UISCALE_MENU_TEXT_SHORT"], - trans = L["TITAN_PANEL_TRANS_MENU_TEXT_SHORT"], - skins = L["TITAN_PANEL_MENU_TEXTURE_SETTINGS"], - skinscust = L["TITAN_PANEL_SKINS_OPTIONS_CUSTOM"], - extras = L["TITAN_PANEL_EXTRAS_SHORT"], - attempts = L["TITAN_PANEL_ATTEMPTS_SHORT"], - advanced = L["TITAN_PANEL_MENU_ADV"], - changes = L["TITAN_PANEL_MENU_CHANGE_HISTORY"], - slash = L["TITAN_PANEL_MENU_SLASH_COMMAND"], - help = L["TITAN_PANEL_MENU_HELP"], - adjust = "Frame Adjustment", - adjust_classic = "Frame Adjustment - Classic", + About = L["TITAN_PANEL"], + top = L["TITAN_PANEL_MENU_OPTIONS_BARS"], + globals = L["TITAN_PANEL_MENU_OPTIONS_BARS_ALL"], + plugins = L["TITAN_PANEL_MENU_PLUGINS"], + profiles = L["TITAN_PANEL_MENU_PROFILES"], + tooltips = L["TITAN_PANEL_MENU_OPTIONS_SHORT"], + scale = L["TITAN_PANEL_UISCALE_MENU_TEXT_SHORT"], + trans = L["TITAN_PANEL_TRANS_MENU_TEXT_SHORT"], + skins = L["TITAN_PANEL_MENU_TEXTURE_SETTINGS"], + skinscust = L["TITAN_PANEL_SKINS_OPTIONS_CUSTOM"], + extras = L["TITAN_PANEL_EXTRAS_SHORT"], + attempts = L["TITAN_PANEL_ATTEMPTS_SHORT"], + advanced = L["TITAN_PANEL_MENU_ADV"], + changes = L["TITAN_PANEL_MENU_CHANGE_HISTORY"], + slash = L["TITAN_PANEL_MENU_SLASH_COMMAND"], + -- help = L["TITAN_PANEL_MENU_HELP"], + help_list = "Help List", --L["TITAN_PANEL_MENU_HELP"], + adjust = "Frame Adjustment", } } -- Titan local helper funcs -local function TitanPanel_GetTitle() +local function GetTitle() return TitanUtils_GetAddOnMetadata(TITAN_ID, "Title") or L["TITAN_PANEL_NA"]; end -local function TitanPanel_GetAuthor() +local function GetAuthor() return TitanUtils_GetAddOnMetadata(TITAN_ID, "Author") or L["TITAN_PANEL_NA"]; end -local function TitanPanel_GetCredits() +local function GetCredits() return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-Credits") or L["TITAN_PANEL_NA"]; end -local function TitanPanel_GetCategory() +local function GetCategory() return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-Category") or L["TITAN_PANEL_NA"]; end -local function TitanPanel_GetEmail() +local function GetEmail() return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-Email") or L["TITAN_PANEL_NA"]; end --[[ not used -local function TitanPanel_GetWebsite() +local function GetWebsite() return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-Website") or L["TITAN_PANEL_NA"]; end --]] -local function TitanPanel_GetLicense() +local function GetLicense() return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-License") or L["TITAN_PANEL_NA"]; end +local function GetDiscord() + return TitanUtils_GetAddOnMetadata(TITAN_ID, "X-Discord") or L["TITAN_PANEL_NA"]; +end + -- helper functions --[[ local -NAME: TitanAdjustPanelScale +NAME: AdjustPanelScale DESC: Set the Tian bars and plugins to the selected scale then adjust other frames as needed. VAR: scale - the scale the user has selected for Titan OUT: None --]] - local function TitanAdjustPanelScale(scale) - Titan_AdjustScale() +local function AustPanelScale(scale) + Titan_AdjustScale() - -- Adjust frame positions - TitanPanel_AdjustFrames(true, "TitanAdjustPanelScale") - end + -- Adjust frame positions + TitanPanel_AdjustFrames(true, "AdjustPanelScale") +end - -- helper functions - --[[ local -NAME: TitanPanel_TicketReload +-- helper functions +--[[ local +NAME: TicketReload DESC: When the user changes the option to adjust for the Blizz ticket frame the UI must be reloaded. Ask the user if they want to do it now. VAR: None OUT: None --]] - local function TitanPanel_TicketReload() +local function TicketReload() + StaticPopupDialogs["TITAN_RELOAD"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_RELOAD"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self) + TitanPanelBarButton_ToggleScreenAdjust() + ReloadUI(); + end, + showAlert = 1, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 + }; + StaticPopup_Show("TITAN_RELOAD"); +end + +local function ScreenAdjustReload() + if TitanPanelGetVar("ScreenAdjust") then + -- if set then clear it - the screen will adjust + TitanPanelBarButton_ToggleScreenAdjust() + else + -- if NOT set then need a reload - the screen will NOT adjust StaticPopupDialogs["TITAN_RELOAD"] = { text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" .. L["TITAN_PANEL_RELOAD"], button1 = ACCEPT, button2 = CANCEL, OnAccept = function(self) - TitanPanelBarButton_ToggleScreenAdjust() + TitanPanelToggleVar("ScreenAdjust"); ReloadUI(); end, showAlert = 1, @@ -110,56 +136,33 @@ OUT: None }; StaticPopup_Show("TITAN_RELOAD"); end - - local function TitanPanel_ScreenAdjustReload() - if TitanPanelGetVar("ScreenAdjust") then - -- if set then clear it - the screen will adjust - TitanPanelBarButton_ToggleScreenAdjust() - else - -- if NOT set then need a reload - the screen will NOT adjust - StaticPopupDialogs["TITAN_RELOAD"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_RELOAD"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self) - TitanPanelToggleVar("ScreenAdjust"); - ReloadUI(); - end, - showAlert = 1, - timeout = 0, - whileDead = 1, - hideOnEscape = 1 - }; - StaticPopup_Show("TITAN_RELOAD"); - end - end - local function TitanPanel_AuxScreenAdjustReload() - if TitanPanelGetVar("AuxScreenAdjust") then - -- if set then clear it - the screen will adjust - TitanPanelBarButton_ToggleAuxScreenAdjust() - else - -- if NOT set then need a reload - the screen will NOT adjust - StaticPopupDialogs["TITAN_RELOAD"] = { - text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" - .. L["TITAN_PANEL_RELOAD"], - button1 = ACCEPT, - button2 = CANCEL, - OnAccept = function(self) - TitanPanelToggleVar("AuxScreenAdjust"); - ReloadUI(); - -- TitanPanelBarButton_ToggleAuxScreenAdjust(); - end, - showAlert = 1, - timeout = 0, - whileDead = 1, - hideOnEscape = 1 - }; - StaticPopup_Show("TITAN_RELOAD"); - end +end +local function AuxScreenAdjustReload() + if TitanPanelGetVar("AuxScreenAdjust") then + -- if set then clear it - the screen will adjust + TitanPanelBarButton_ToggleAuxScreenAdjust() + else + -- if NOT set then need a reload - the screen will NOT adjust + StaticPopupDialogs["TITAN_RELOAD"] = { + text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"]) .. "\n\n" + .. L["TITAN_PANEL_RELOAD"], + button1 = ACCEPT, + button2 = CANCEL, + OnAccept = function(self) + TitanPanelToggleVar("AuxScreenAdjust"); + ReloadUI(); + -- TitanPanelBarButton_ToggleAuxScreenAdjust(); + end, + showAlert = 1, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 + }; + StaticPopup_Show("TITAN_RELOAD"); end +end ---============= Titan Panel entry +--============= Titan Panel entry / About -- --[[ local NAME: titan_entry @@ -194,39 +197,6 @@ local titan_entry = { }, } }, - confnotes = { - name = "Notes", - order = 3, - type = "group", - inline = true, - args = { - confversiondesc = { - order = 1, - type = "description", - name = "" .. Titan_Global.config_notes, - cmdHidden = true - }, - } - }, - confthanks = { - name = "Thank You", - order = 5, - type = "group", - inline = true, - args = { - confversiondesc = { - order = 1, - type = "description", - name = "" - .. "We would like to thank all of the users of TitanPanel." - .. "\n" - .. "We understand you have many choices on which addons to enhance your World of Warcraft experience." - .. - " Our Mission has always been to provide you with a tool to help add and improve your experience without impeding your enjoyment of the game. ", - cmdHidden = true - }, - } - }, confinfodesc = { name = L["TITAN_PANEL_ABOUT"], order = 7, @@ -244,44 +214,42 @@ local titan_entry = { order = 2, type = "description", name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_AUTHOR"] .. ": ") - .. TitanUtils_GetGreenText(TitanPanel_GetAuthor()), + .. TitanUtils_GetGreenText(GetAuthor()), cmdHidden = true }, confcreditsdesc = { order = 3, type = "description", name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_CREDITS"] .. ": ") - .. TitanUtils_GetGreenText(TitanPanel_GetCredits()), + .. TitanUtils_GetGreenText(GetCredits()), cmdHidden = true }, confcatdesc = { order = 4, type = "description", name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_CATEGORY"] .. ": ") - .. TitanUtils_GetGreenText(TitanPanel_GetCategory()), + .. TitanUtils_GetGreenText(GetCategory()), cmdHidden = true }, confemaildesc = { order = 5, type = "description", name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_EMAIL"] .. ": ") - .. TitanUtils_GetGreenText(TitanPanel_GetEmail()), + .. TitanUtils_GetGreenText(GetEmail()), cmdHidden = true }, - --[[ has not been updated in quite a while... - confwebsitedesc = { - order = 6, + confdiscorddesc = { + order = 5, type = "description", - name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_WEB"]..": ") - ..TitanUtils_GetGreenText(TitanPanel_GetWebsite()), + name = TitanUtils_GetGoldText("Discord Site: ") --(L["TITAN_PANEL_ABOUT_EMAIL"] .. ": ") + .. TitanUtils_GetGreenText(GetDiscord()), cmdHidden = true }, ---]] conflicensedesc = { order = 7, type = "description", name = TitanUtils_GetGoldText(L["TITAN_PANEL_ABOUT_LICENSE"] .. ": ") - .. TitanUtils_GetGreenText(TitanPanel_GetLicense()), + .. TitanUtils_GetGreenText(GetLicense()), cmdHidden = true }, } @@ -373,7 +341,7 @@ local function TitanUpdateAdj(t, pos) args[f_name].args.show = { type = "toggle", width = .75, --"fill", - name = USE or "Use", --L["TITAN_PANEL_MENU_DISPLAY_BAR"], + name = Titan_Global.literals.use, order = position, get = function(info) local frame_str = info[1] @@ -392,7 +360,7 @@ local function TitanUpdateAdj(t, pos) args[f_name].args.offset = { type = "range", width = "full", - name = "Vertical Adjustment", --L["TITAN_PANEL_TRANS_MENU_TEXT_SHORT"], + name = "Vertical Adjustment", order = position, min = -200, max = 600, @@ -607,8 +575,8 @@ local function TitanUpdateConfigBars(t, pos) args[v.name].args.hideinpvp = { type = "toggle", width = .75, --"fill", - name = L["TITAN_PANEL_MENU_HIDE_IN_COMBAT"].." PvP", - desc = L["TITAN_PANEL_MENU_HIDE_IN_COMBAT_DESC"], + name = L["TITAN_PANEL_MENU_HIDE_IN_COMBAT"] .. " " .. Titan_Global.literals.pvp, + desc = L["TITAN_PANEL_MENU_HIDE_IN_COMBAT_DESC"] .. " " .. Titan_Global.literals.pvp, order = position, get = function(info) local frame_str = TitanVariables_GetFrameName(info[1]) @@ -692,8 +660,8 @@ local function TitanUpdateConfigBars(t, pos) end, args = { settextousebar = { - name = "", --L["TITAN_PANEL_MENU_GLOBAL_SKIN"], - desc = "", --L["TITAN_PANEL_MENU_GLOBAL_SKIN_TIP"], + name = "", + desc = "", order = 110, type = "select", width = "full", @@ -736,7 +704,7 @@ local function TitanUpdateConfigBars(t, pos) colorselect = { type = "color", width = "Full", - name = "Select Bar Color", -- L["TITAN_PANEL_MENU_RESET_POSITION"], + name = L["TITAN_PANEL_BAR_COLOR"], order = 340, -- disabled = (v.vert == TITAN_TOP or v.vert == TITAN_BOTTOM), hasAlpha = true, @@ -779,7 +747,7 @@ local function TitanUpdateConfigBars(t, pos) skinselect = { type = "select", width = "normal", - name = "", --v.locale_name, + name = "", order = 130, get = function(info) local frame_str = TitanVariables_GetFrameName(info[1]) @@ -832,7 +800,7 @@ local function TitanUpdateConfigBars(t, pos) imageWidth = 256, order = 300, type = "description", - width = .5, --"60", + width = .5, --"60", }, trans = { type = "range", @@ -859,7 +827,7 @@ local function TitanUpdateConfigBars(t, pos) end -- Config Tables changed! --- AceConfigRegistry:NotifyChange("Titan Panel Bars") + -- AceConfigRegistry:NotifyChange("Titan Panel Bars") --[===[ print("Color new:" .." "..tostring(format("%0.1f", r)).."" @@ -881,23 +849,10 @@ end local optionsGlobals = { name = TITAN_PANEL_CONFIG.topic.globals, type = "group", - args = { } - } - -local function TitanUpdateConfigBarsAll(t, pos) - - local function IfHide(check) - local tex = TitanBarDataVars["Global"].texure - local res = true -- assume we need to hide - - if (tex == check) then - res = false - else - res = true - end - return res - end + args = {} +} +local function ConfigBarsAll(t, pos) local args = t local position = pos @@ -921,14 +876,14 @@ local function TitanUpdateConfigBarsAll(t, pos) } position = position + 1 args.settopbar = { - name = L["TITAN_PANEL_MENU_TOP_BARS"].." "..L["TITAN_PANEL_MENU_DISABLE_PUSH"], --- desc = L["TITAN_PANEL_MENU_DISABLE_PUSH"], + name = L["TITAN_PANEL_MENU_TOP_BARS"] .. " " .. L["TITAN_PANEL_MENU_DISABLE_PUSH"], + -- desc = L["TITAN_PANEL_MENU_DISABLE_PUSH"], order = position, type = "toggle", width = "full", disabled = (Titan_Global.switch.can_edit_ui == true), get = function() return TitanPanelGetVar("ScreenAdjust") end, - set = function() TitanPanel_ScreenAdjustReload() end, + set = function() ScreenAdjustReload() end, } position = position + 1 args.bottombarspacer = { -- spacer @@ -946,20 +901,19 @@ local function TitanUpdateConfigBarsAll(t, pos) } position = position + 1 args.setbottombar = { - name = L["TITAN_PANEL_MENU_BOTTOM_BARS"].." "..L["TITAN_PANEL_MENU_DISABLE_PUSH"], --- desc = L["TITAN_PANEL_MENU_DISABLE_PUSH"], + name = L["TITAN_PANEL_MENU_BOTTOM_BARS"] .. " " .. L["TITAN_PANEL_MENU_DISABLE_PUSH"], + -- desc = L["TITAN_PANEL_MENU_DISABLE_PUSH"], order = position, type = "toggle", width = "full", disabled = (Titan_Global.switch.can_edit_ui == true), get = function() return TitanPanelGetVar("AuxScreenAdjust") end, - set = function() TitanPanel_AuxScreenAdjustReload() end, + set = function() AuxScreenAdjustReload() end, } - end local function BuildBarsAll() - TitanUpdateConfigBarsAll(optionsGlobals.args, 1000) + ConfigBarsAll(optionsGlobals.args, 1000) AceConfigRegistry:NotifyChange("Titan Panel Globals") end @@ -967,16 +921,17 @@ end --============= Plugins ---[[ local -NAME: optionsAddons -DESC: This is the table shell. The plugin controls will be added by another routine. ---]] +---The plugin controls will be added here. local optionsAddons = { - name = TITAN_PANEL_CONFIG.topic.plugins, --"Titan "..L["TITAN_PANEL_MENU_PLUGINS"], + name = TITAN_PANEL_CONFIG.topic.plugins, type = "group", args = {} } +---Color the list - is shown versus not shown +---@param id string +---@param name string +---@return string colorized local function ColorVisible(id, name) local res = "?" if TitanPanel_IsPluginShown(id) then @@ -989,8 +944,6 @@ local function ColorVisible(id, name) end --[[ local -NAME: TitanUpdateConfigAddons -DESC: Allow the user to control each plugin registered to Titan. Controls honored from the plugin .registry: - Show - Show label text @@ -1006,11 +959,10 @@ Bar: - Drop down so the user can pick the bar the plugin is to be shown on. - The list contains only the bars the user has selected to be shown. - The user can not move a plugin to a hidden bar to 'hide' it. The user should ensure "Show Plugin" is unchecked. -:DESC -VAR: None -OUT: None --]] -local function TitanUpdateConfigAddons() + +---Allow the user to control each plugin registered to Titan. +local function UpdateConfigAddons() local args = optionsAddons.args local plug_in = nil local plug_category = "" @@ -1043,11 +995,14 @@ local function TitanUpdateConfigAddons() local name = info[1] if v then -- Show / add local bar = (TitanGetVar(name, "ForceBar") or TitanUtils_PickBar()) - TitanUtils_AddButtonOnBar(bar, name) + if type(bar) == string then -- sanity and IDE + ---@diagnostic disable-next-line: param-type-mismatch + TitanUtils_AddButtonOnBar(bar, name) + end else -- Hide / remove TitanPanel_RemoveButton(name) end - TitanUpdateConfigAddons() + UpdateConfigAddons() end, }, } @@ -1364,99 +1319,64 @@ end --============= Profiles ---[[ local -NAME: optionsChars -DESC: This is the table shell. The toon info will be added by another routine. ---]] +---The toon profile info will be added here local optionsChars = { - name = TITAN_PANEL_CONFIG.topic.profiles, --"Titan "..L["TITAN_PANEL_MENU_PROFILES"], + name = TITAN_PANEL_CONFIG.topic.profiles, type = "group", args = {} } ---[[ local -NAME: TitanUpdateChars -DESC: Allow the user to delete toon data (just not the one they are logged into). -VAR: None -OUT: None -NOTE: -- Users can delete toons but the saved variable data is still stored by Titan. -- The old toon data can be removed by the user. -- This routine is called to 'redraw' the list as a user deletes toon data. -- A message is sent to chat that the plugin data has been deleted. -:NOTE ---]] +---Allow the user to load / delete / reset / sync profile data local function TitanUpdateChars() - local players = {}; + local players = {} -- used for left side list of profiles + local p_info = {} -- used to hold info about each toon in players + local p_sync = {} -- profiles used as Sync + -- Rip through the players (with server name) to sort them for index, id in pairs(TitanSettings.Players) do table.insert(players, index); + + TitanUtil_CheckProfile(index) -- ensure valid sync + + -- collect some info on THIS toon for the config + local this_toon = {} + + local _, server = TitanUtils_ParseName(index) + -- color code the name + -- - gold for normal profiles + -- - green for custom profiles + if server == TITAN_CUSTOM_PROFILE_POSTFIX then + this_toon.fancy_name = TitanUtils_GetGreenText((index or "?")) + else + this_toon.fancy_name = TitanUtils_GetGoldText((index or "?")) + end + + this_toon.name = index + this_toon.is_player = (index == TitanUtils_GetPlayer()) + this_toon.sync_set = not (id.Panel["SyncWithProfile"] == Titan_Global.profile.NONE) + this_toon.sync_name = id.Panel["SyncWithProfile"] + table.insert(p_info, this_toon) -- table index matches players table... + + p_sync[this_toon.sync_name] = this_toon.sync_set end + --Ace or Blizz sorts the toons... + -- table.sort(players, function(a, b) + -- return a < b + -- end) -- set up the options for the user local args = optionsChars.args - local plug_in = nil wipe(args) + local header = "" + header = header .. L["TITAN_PANEL_CHARS_DESC"] .. "\n" + args["desc"] = { order = 1, type = "description", - name = L["TITAN_PANEL_CHARS_DESC"] .. "\n", - cmdHidden = true, - } - args["custom_header"] = { - order = 10, - type = "header", - name = L["TITAN_PANEL_MENU_PROFILE_CUSTOM"] .. "\n", - cmdHidden = true, - } - args["custom_save"] = { - order = 11, - type = "execute", - name = L["TITAN_PANEL_MENU_SAVE_SETTINGS"] .. "\n", - func = function(info, v) - TitanPanel_SaveCustomProfile() - TitanUpdateChars() -- rebuild the toons - end, - } - args["sp_1"] = { - type = "description", - name = "", - cmdHidden = true, - order = 12, - } - args["global_header"] = { - order = 20, - type = "header", - name = L["TITAN_PANEL_GLOBAL"], - cmdHidden = true, - } - args["global_use"] = { - order = 21, - type = "toggle", - width = "full", - name = L["TITAN_PANEL_GLOBAL_USE"], - desc = L["TITAN_PANEL_GLOBAL_USE_DESC"], - get = function() return TitanAllGetVar("GlobalProfileUse") end, - set = function() - TitanUtils_SetGlobalProfile(not TitanAllGetVar("GlobalProfileUse"), nil) - TitanUpdateChars() -- rebuild the toons - AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") - end, - } - args["global_name"] = { - order = 22, - type = "description", - width = "full", - name = L["TITAN_PANEL_GLOBAL_PROFILE"] .. - ": " .. TitanUtils_GetGoldText(TitanAllGetVar("GlobalProfileName") or "?"), - } - args["sp_20"] = { - type = "description", - name = "", + name = header .. "\n", cmdHidden = true, - order = 23, } args["profile_header"] = { order = 30, @@ -1464,223 +1384,334 @@ local function TitanUpdateChars() name = L["TITAN_PANEL_MENU_PROFILES"] .. "\n", cmdHidden = true } - for idx, value in pairs(players) do - local name = (players[idx] or "?") - local s, e, ident, server, player - local fancy_name = "" - local disallow = false - disallow = -- looks weird but we need to force a true or Ace complains - ((name == TitanSettings.Player) - or ((name == TitanAllGetVar("GlobalProfileName")) - and (TitanAllGetVar("GlobalProfileUse"))) - ) and true or false - - if name then - -- color code the name - -- - gold for normal profiles - -- - green for custom profiles - player, server = TitanUtils_ParseName(name) - -- handle custom profiles here - if server == TITAN_CUSTOM_PROFILE_POSTFIX then - fancy_name = TitanUtils_GetGreenText((name or "?")) - else - fancy_name = TitanUtils_GetGoldText((name or "?")) - end - -- end color code - args[name] = { - type = "group", - name = fancy_name, - desc = "", - order = 40, - args = { - name = { - type = "header", - name = TitanUtils_GetGoldText(name or "?"), - cmdHidden = true, - order = 10, - }, - sp_1 = { - type = "description", - name = "", - cmdHidden = true, - order = 11, - }, - optionload = { - name = L["TITAN_PANEL_MENU_LOAD_SETTINGS"], - order = 20, - type = "execute", - width = "full", - func = function(info, v) - TitanVariables_UseSettings(info[1], TITAN_PROFILE_USE) - end, - -- does not make sense to load current character profile or global profile - disabled = disallow, - }, - sp_20 = { - type = "description", - name = "", - cmdHidden = true, - order = 21, - }, - optionreset = { - name = L["TITAN_PANEL_MENU_DELETE_SETTINGS"], - order = 30, - type = "execute", - width = "full", - func = function(info, v) - TitanSettings.Players[info[1]] = nil -- delete the config entry - TitanPrint( - L["TITAN_PANEL_MENU_PROFILE"] - .. info[1] - .. L["TITAN_PANEL_MENU_PROFILE_DELETED"] - , "info") - if name == TitanAllGetVar("GlobalProfileName") then - TitanAllSetVar("GlobalProfileName", TITAN_PROFILE_NONE) - end - TitanUpdateChars() -- rebuild the toons - AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") - end, - -- can not delete current character profile or global profile - disabled = disallow, - }, - sp_30 = { - type = "description", - name = "", - cmdHidden = true, - order = 31, - }, - sp_31 = { - type = "description", - name = "", - cmdHidden = true, - order = 32, - }, - global_header = { - order = 40, - type = "header", - name = "Global", --L["TITAN_PANEL_MENU_VERSION_SHOWN"], - cmdHidden = true, - }, - use_as_global = { - order = 41, - type = "toggle", - width = "full", - name = L["TITAN_PANEL_GLOBAL_USE_AS"], - get = function() return TitanPanelGetVar("GlobalProfileName") == name end, - set = function() - if TitanPanelGetVar("GlobalProfileName") == name then - -- Was unchecked so clear the saved var - TitanAllSetVar("GlobalProfileName", TITAN_PROFILE_NONE) - else - -- Was checked so set the saved var - TitanAllSetVar("GlobalProfileName", name) - end - if TitanAllGetVar("GlobalProfileUse") then - -- Use whatever toon the user picked, if not use current toon - if TitanAllGetVar("GlobalProfileName") == TITAN_PROFILE_NONE then - TitanAllSetVar("GlobalProfileName", TitanSettings.Player) - end - TitanVariables_UseSettings(TitanAllGetVar("GlobalProfileName"), TITAN_PROFILE_USE) - TitanPrint( - L["TITAN_PANEL_MENU_PROFILE"] - .. ":" .. (TitanAllGetVar("GlobalProfileName") or "?") - .. ": " .. L["TITAN_PANEL_GLOBAL_RESET_PART"] .. "..." - , "info") - else - -- - end - TitanUpdateChars() - AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") - end, - -- can not uncheck current global profile - disabled = disallow, - }, - sp_40 = { - type = "description", - name = "", - cmdHidden = true, - order = 42, - }, - }, - } - end - end - -- tell the options screen there is a new list - AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") -end -------------- - ---============= Tooltips and Frames + for idx = 1, #players do + local this_toon = p_info[idx] + local position = 100 + args[this_toon.name] = { + type = "group", + name = this_toon.fancy_name, + desc = "", + order = position, + args = {} + } + local p_args = args[this_toon.name].args -- shartcut ---[[ local -NAME: optionsFrames -DESC: Show the general Tian options that hte user can change: -Tooltips: -- Hide in combat -- Show (or not) -Frames (bars): -- Lock buttons (plugins) - do not allow plugins to be moved via drag & drop. Shift left / right is still allowwed. -- Show plugin versions - show the version in the tooltips -Actions: -- Force LDB laucnhers to right side - This will move all converted LDB plugins of type launcher to the right side of the Titan bar. -- Refresh plugins - This can be used when a plugin has not updated its text. It may allow a plugin to show if it is not visible but the user has selected show. -- Reset Titan to default - used when the user wants to reset Titan options to a fresh install state. No plugins are removed by this. -:DESC ---]] -local optionsFrames = { - name = TITAN_PANEL_CONFIG.topic.tooltips, --L["TITAN_PANEL_MENU_OPTIONS"], - type = "group", - args = { - confdesc2 = { - order = 200, + -- assemble the profile section + position = position + 1 + p_args.name = { type = "header", - name = L["TITAN_PANEL_MENU_OPTIONS_TOOLTIPS"], - }, - optiontooltip = { - name = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN"], - -- desc = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN"], - order = 201, - type = "toggle", - width = "full", - get = function() return TitanPanelGetVar("ToolTipsShown") end, - set = function() TitanPanelToggleVar("ToolTipsShown"); end, - }, - optiontooltipcombat = { - name = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN_IN_COMBAT"], - -- desc = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN_IN_COMBAT"], - order = 210, - type = "toggle", - width = "full", - get = function() return TitanPanelGetVar("HideTipsInCombat") end, - set = function() TitanPanelToggleVar("HideTipsInCombat"); end, - }, - conftooltipdesc = { - name = "Tooltip Modifier", - type = "group", - inline = true, - order = 220, - args = { - confdesc = { - order = 110, - type = "description", - name = "", - cmdHidden = true, - }, - advname = { - name = L["TITAN_PANEL_MENU_TOOLTIP_MOD"], - desc = "", -- L[""], - order = 120, - type = "toggle", - width = "full", - get = function() return TitanAllGetVar("UseTooltipModifer") end, - set = function(_, a) - TitanAllSetVar("UseTooltipModifer", a); - end, - }, - tooltipmod = { - name = "", - type = "group", + name = TitanUtils_GetGoldText(this_toon.name or "?"), + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.sp_1 = { + type = "description", + name = "", + cmdHidden = true, + order = position, + } + position = position + 1 + local l_reason = "" + if this_toon.is_player then + l_reason = L["TITAN_PANEL_MENU_LOAD_SETTINGS_ERR1"] + else + l_reason = "." + end + p_args.optionload = { + name = L["TITAN_PANEL_MENU_LOAD_SETTINGS"], + desc = L["TITAN_PANEL_MENU_LOAD_SETTINGS_DESC"], + order = position, + type = "execute", + -- width = "0.4", + func = function(info, v) + TitanVariables_UseSettings(info[1], TitanUtils_GetPlayer(), TITAN_PROFILE_USE) + end, + -- does not make sense to load current character profile + disabled = this_toon.is_player, + } + position = position + 1 + local del_reason = "" + if p_sync[this_toon.name] then + del_reason = L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_ERR1"] + elseif this_toon.is_player then + del_reason = L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_ERR2"] + -- elseif this_toon.sync_set then + -- del_reason = "Delete not allowed, Sync is set." + else + del_reason = "." + end + p_args.optiondelete = { + name = L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS"], + desc = L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_DESC"], + order = position, + type = "execute", + -- width = "0.4", + func = function(info, v) + TitanSettings.Players[info[1]] = nil -- delete the entry + TitanPrint( + L["TITAN_PANEL_MENU_PROFILE"] + .. info[1] + .. L["TITAN_PANEL_MENU_PROFILE_DELETED"] + , "info") + TitanUpdateChars() -- rebuild the toons + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") + end, + -- can not delete current character profile + disabled = this_toon.is_player + -- or this_toon.sync_set + or p_sync[this_toon.name], + } + position = position + 1 + p_args.sp_30 = { + type = "description", + name = " "..TitanUtils_GetHexText(l_reason, Titan_Global.colors.orange).."\n", + cmdHidden = true, + order = position, + } + p_args.sp_31 = { + type = "description", + name = " "..TitanUtils_GetHexText(del_reason, Titan_Global.colors.orange).."\n", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.sp_35 = { + type = "description", + name = "\n", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.optionsave = { + order = position, + type = "execute", + -- width = "0.5", + name = L["TITAN_PANEL_MENU_PROFILE_SAVE"] .. " " .. L["TITAN_PANEL_MENU_PROFILE_CUSTOM"], + desc = L["TITAN_PANEL_MENU_PROFILE_SAVE_DESC"], + func = function(info, v) + TitanPanel_SaveCustomProfile() + TitanUpdateChars() -- rebuild the toons + end, + } + position = position + 1 + p_args.reset_this = { + name = L["TITAN_PANEL_MENU_PROFILE_RESET"], -- + desc = L["TITAN_PANEL_MENU_PROFILE_RESET_DESC"], + order = position, + type = "execute", + -- width = "0.5", + func = function(info, v) + local str = "" + str = str + .. " " .. tostring(Titan_Global.profile.TOON) .. "" + .. " > '" .. tostring(info[1]) .. "'" + .. " : '" .. tostring(TITAN_PROFILE_RESET) .. "'" + .. " | '" .. tostring(this_toon.is_player) .. "'" + + Titan_Debug.Out('titan', 'profile', str) + + -- Reset the profile + TitanSettings.Players[info[1]] = nil + + if this_toon.is_player then + -- Change over to new profile + TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_USE) + else + -- Not this toon. Next time user plays this toon it will reset + end + + TitanUpdateChars() + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") + end, + } + position = position + 1 + p_args.sp_39 = { + type = "description", + name = " ", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.sync_title = { + type = "header", + name = TitanUtils_GetGoldText("Sync"), + cmdHidden = true, + order = position, + } + position = position + 1 + local s_reason = "" + if this_toon.sync_set then + s_reason = L["TITAN_PANEL_MENU_PROFILE_SYNC_ERR1"] + elseif this_toon.is_player then + s_reason = L["TITAN_PANEL_MENU_PROFILE_SYNC_ERR2"] + else + s_reason = "" -- no error + end + p_args.sync_with = { + name = L["TITAN_PANEL_MENU_PROFILE_SYNC"], + desc = L["TITAN_PANEL_MENU_PROFILE_SYNC_DESC"], + order = position, + type = "execute", + --width = "full", + func = function(info, v) + local str = "" + TitanUtils_SetProfile(TitanUtils_GetPlayer(), Titan_Global.profile.SYNC, info[1]) + str = str + .. " " .. tostring(Titan_Global.profile.SYNC) .. "" + .. " > '" .. tostring(info[1]) .. "'" + .. " : '" .. tostring(TITAN_PROFILE_USE) .. "'" + + Titan_Debug.Out('titan', 'profile', str) + -- Change over to new profile + TitanVariables_UseSettings(nil, info[1], TITAN_PROFILE_USE) + TitanUpdateChars() + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") + end, + -- cannot sync to yourself or if sync already set + disabled = this_toon.is_player or this_toon.sync_set, + } + position = position + 1 + p_args.sync_clear = { + name = L["TITAN_PANEL_MENU_PROFILE_CLEAR_SYNC"], + desc = L["TITAN_PANEL_MENU_PROFILE_CLEAR_SYNC_DESC"], + order = position, + type = "execute", + func = function(info, v) + local str = "" + TitanUtils_SetProfile(info[1], Titan_Global.profile.SYNC, Titan_Global.profile.NONE) + str = str + .. " " .. tostring(Titan_Global.profile.SYNC) .. "" + .. " > '" .. tostring(info[1]) .. "'" + .. " : '" .. tostring(Titan_Global.profile.NONE) .. "'" + .. " | '" .. tostring(this_toon.is_player) .. "'" + + Titan_Debug.Out('titan', 'profile', str) + + if this_toon.is_player then + -- Change over to new profile + TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_USE) + else + -- Not this toon + end + + TitanUpdateChars() + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") + end, + disabled = (not this_toon.sync_set), + } + position = position + 1 + p_args.sp_50 = { + type = "description", + name = " "..TitanUtils_GetHexText(s_reason, Titan_Global.colors.orange).."\n", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.sp_51 = { + type = "description", + name = " ",--..TitanUtils_GetHexText(cs_reason, Titan_Global.colors.orange).."\n", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.sp_60 = { + type = "description", + name = "", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.setting_title = { + type = "header", + name = TitanUtils_GetGoldText("-"), + cmdHidden = true, + order = position, + } + position = position + 1 + p_args.setting_sync = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_SYNC"].." : " .. this_toon.sync_name, + cmdHidden = true, + order = position, + } + + -- tell the options screen there is a new list + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") + end +end +------------- + +--============= Tooltips and Frames + +--[[ local +Tooltips: +- Hide in combat +- Show (or not) +Frames (bars): +- Lock buttons (plugins) - do not allow plugins to be moved via drag & drop. Shift left / right is still allowwed. +- Show plugin versions - show the version in the tooltips +Actions: +- Force LDB laucnhers to right side - This will move all converted LDB plugins of type launcher to the right side of the Titan bar. +- Refresh plugins - This can be used when a plugin has not updated its text. It may allow a plugin to show if it is not visible but the user has selected show. +- Reset Titan to default - used when the user wants to reset Titan options to a fresh install state. No plugins are removed by this. +--]] + +---Show the general Titan options that the user can change. +local optionsFrames = { + name = TITAN_PANEL_CONFIG.topic.tooltips, + type = "group", + args = { + confdesc2 = { + order = 200, + type = "header", + name = L["TITAN_PANEL_MENU_OPTIONS_TOOLTIPS"], + }, + optiontooltip = { + name = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN"], + -- desc = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN"], + order = 201, + type = "toggle", + width = "full", + get = function() return TitanPanelGetVar("ToolTipsShown") end, + set = function() TitanPanelToggleVar("ToolTipsShown"); end, + }, + optiontooltipcombat = { + name = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN_IN_COMBAT"], + -- desc = L["TITAN_PANEL_MENU_TOOLTIPS_SHOWN_IN_COMBAT"], + order = 210, + type = "toggle", + width = "full", + get = function() return TitanPanelGetVar("HideTipsInCombat") end, + set = function() TitanPanelToggleVar("HideTipsInCombat"); end, + }, + conftooltipdesc = { + name = L["TITAN_PANEL_TOOLTIP_MODIFIER"], + type = "group", + inline = true, + order = 220, + args = { + confdesc = { + order = 110, + type = "description", + name = "", + cmdHidden = true, + }, + advname = { + name = L["TITAN_PANEL_MENU_TOOLTIP_MOD"], + desc = "", -- L[""], + order = 120, + type = "toggle", + width = "full", + get = function() return TitanAllGetVar("UseTooltipModifer") end, + set = function(_, a) + TitanAllSetVar("UseTooltipModifer", a); + end, + }, + tooltipmod = { + name = "", + type = "group", inline = true, order = 140, args = { @@ -1747,70 +1778,15 @@ local optionsFrames = { get = function() return TitanPanelGetVar("LockAutoHideInCombat") end, set = function() TitanPanelToggleVar("LockAutoHideInCombat") end, }, - space_400_1 = { - order = 400, - type = "description", - name = " ", - cmdHidden = true, - }, - optionlaunchers = { - name = L["TITAN_PANEL_MENU_LDB_FORCE_LAUNCHER"], - order = 401, - type = "execute", - width = "full", - func = function() TitanPanelBarButton_ForceLDBLaunchersRight() end, - }, - space_500_1 = { - order = 500, - type = "description", - name = " ", - cmdHidden = true, - }, - pluginreset = { - name = L["TITAN_PANEL_MENU_PLUGIN_RESET"], - desc = L["TITAN_PANEL_MENU_PLUGIN_RESET_DESC"], - order = 501, - type = "execute", - width = "full", - func = function() TitanPanel_InitPanelButtons() end, - }, - space_600_1 = { - order = 600, - type = "description", - name = " ", - cmdHidden = true, - }, - optionreset = { - name = L["TITAN_PANEL_MENU_RESET"] .. " " - .. _G["GREEN_FONT_COLOR_CODE"] - .. L["TITAN_PANEL_MENU_RELOADUI"], - order = 601, - type = "execute", - width = "full", - func = function() TitanPanel_ResetToDefault() end, - } } } ------------- --============= Scale and Font ---[[ local -NAME: optionsUIScale -DESC: Local table to hold the Titan options that allow a user to adjust: -- UI scale -- Titan scale for bars -- Spacing between Titan plugins (right side) -- Spacing between Titan icons (left side) -- Titan tooltip font scale (bar and plugins) -- Toggle the tooltip font scale (allow Titan or Blizz to control) -- Set Titan font (bar and plugins) -- Set Titan font size -- Set Titan bar strata (tells Blizz which frames could go over Titan bar (and plugins) -:DESC ---]] +---Show the Titan options that allow a user to adjust Titan scale and font local optionsUIScale = { - name = TITAN_PANEL_CONFIG.topic.scale, --L["TITAN_PANEL_UISCALE_MENU_TEXT"], + name = TITAN_PANEL_CONFIG.topic.scale, type = "group", args = { confdesc = { @@ -1871,7 +1847,7 @@ local optionsUIScale = { TitanPanel_InitPanelButtons(); end, }, - iconspacing = { -- right side plugins + iconspacing = { name = L["TITAN_PANEL_UISCALE_CONTROL_TITLE_ICON"], desc = L["TITAN_PANEL_UISCALE_ICON_SLIDER_DESC"], order = 5, @@ -1897,7 +1873,7 @@ local optionsUIScale = { order = 20, width = "full", type = "header", - name = "Tooltip", --L["TITAN_PANEL_MENU_GLOBAL_SKIN_TITLE"], + name = L["TITAN_PANEL_TOOLTIP"], }, tooltipfont = { name = L["TITAN_PANEL_UISCALE_CONTROL_TOOLTIP_TOOLTIPFONT"], @@ -1928,7 +1904,7 @@ local optionsUIScale = { order = 30, width = "full", type = "header", - name = "Font", --L["TITAN_PANEL_MENU_GLOBAL_SKIN_TITLE"], + name = "Font", }, fontselection = { name = L["TITAN_PANEL_MENU_LSM_FONTS"], @@ -1944,7 +1920,7 @@ local optionsUIScale = { TitanPanelSetVar("FontName", v) TitanSetPanelFont(v, TitanPanelGetVar("FontSize")) end, - values = AceGUIWidgetLSMlists.font, + values = media:HashTable("font"), --AceGUIWidgetLSMlists.font, }, fontspacer = { order = 32, @@ -1971,7 +1947,7 @@ local optionsUIScale = { order = 40, width = "full", type = "header", - name = "Strata", --L["TITAN_PANEL_MENU_GLOBAL_SKIN_TITLE"], + name = "Strata", }, panelstrata = { name = L["TITAN_PANEL_MENU_FRAME_STRATA"], @@ -2012,10 +1988,7 @@ local optionsUIScale = { --============= Skins ---[[ local -NAME: optionsSkins -DESC: Local table to hold the Titan skins options. Shows default Titan and any custom skins the user has added. ---]] +--- local optionsSkins = { name = TITAN_PANEL_CONFIG.topic.skins, type = "group", @@ -2023,6 +1996,7 @@ local optionsSkins = { } } +---Show the default Titan skins and any custom skins the user has added. local function Show_Skins(t, position) --[[ table.sort(TitanSkins, function(a, b) @@ -2123,25 +2097,23 @@ end --============= Skins - Custom ---[[ local -NAME: TitanPanel_AddNewSkin -DESC: Add each skin to the options list. If the user had added custom skins these will be shown as well. -VAR: skinname - the file name to use -VAR: skinpath - the file path to use -OUT: None -NOTE: +--[[ NOTE: - Blizz *does not allow* LUA to access the user file system dynamically so the skins have to be input by hand. Titan can not search for available skins in the Artwork folder. - On the flip side a user can add a custom skin to the Titan saved variables then later delete the skin from the file system. This will not cause an error when the user tries to use (show) that skin but Titan will show a 'blank' skin. :NOTE --]] -local function TitanPanel_AddNewSkin(skinname, skin_path) + + +---Helper to add each skin to the options list. +---@param skinname string Shown to user +---@param skin_path string folder name of skin ONLY; prefix (Titan path) will be added +local function AddNewSkin(skinname, skin_path) local out_str = "Start : " local msg_type = "warning" -- assume something went wrong :) local skinpath = TitanSkinsCustomPath .. skin_path .. TitanSkinsPathEnd -- name and path must be provided if skinname and skinpath then -- continue - -- name cannot be empty or "None", path cannot be empty if skinname == "" or skinname == L["TITAN_PANEL_NONE"] or skinpath == "" then out_str = L["TITAN_PANEL_SKINS_BLANK_VALUE"] @@ -2157,7 +2129,7 @@ local function TitanPanel_AddNewSkin(skinname, skin_path) -- The skin is new so add it to the Titan saved variables list if found then - out_str = L["TITAN_PANEL_SKINS_ALREADY_LISTED"] + out_str = L["TITAN_PANEL_SKINS_ALREADY_LISTED"] else table.insert(TitanSkins, { name = skinname, path = skinpath }) msg_type = "info" @@ -2172,28 +2144,19 @@ local function TitanPanel_AddNewSkin(skinname, skin_path) BuildSkins() out_str = out_str - .." '"..tostring(skinname).."'" - .."\n Full Path:"..tostring(skinpath).."" + .. " '" .. tostring(skinname) .. "'" + .. "\n Full Path:" .. tostring(skinpath) .. "" TitanPrint(out_str, msg_type) end ---[[ local -NAME: Remove_Skin -DESC: Remove requested skin from selectable list. -VAR: skinname - the file name to use -VAR: skinpath - the file path to use -OUT: None -NOTE: -- Blizz *does not allow* LUA to access the user file system dynamically so the skins have to be input by hand. Titan can not search for available skins in the Artwork folder. -- On the flip side a user can add a custom skin to the Titan saved variables then later delete the skin from the file system. This will not cause an error when the user tries to use (show) that skin but Titan will show a 'blank' skin. -:NOTE ---]] +---Remove requested skin from selectable list. +---@param skinname string Shown to user local function Remove_Skin(skinname) local out_str = "Start : " local msg_type = "warning" -- assume something went wrong :) local found = false - if skinname == "None" then + if skinname == "None" then out_str = L["TITAN_PANEL_SKINS_NONE_SELECTED"] else local k, v; @@ -2213,18 +2176,17 @@ local function Remove_Skin(skinname) end out_str = out_str - .." '"..tostring(skinname).."'" + .. " '" .. tostring(skinname) .. "'" TitanPrint(out_str, msg_type) end ---[[ local -NAME: optionsSkinsCustom -DESC: Local table to hold the Titan custom skins options that allow a user to add or delete skins. +--[[ NOTE - You may not remove the currently used skin - or the default one - or a Titan default skin (it would only come back...) -:DESC --]] + +---hold the Titan custom skins options that allow a user to add or delete skins. local optionsSkinsCustom = { name = TITAN_PANEL_CONFIG.topic.skinscust, --L["TITAN_PANEL_SKINS_TITLE_CUSTOM"], type = "group", @@ -2271,11 +2233,11 @@ local optionsSkinsCustom = { type = "execute", desc = L["TITAN_PANEL_SKINS_ADD_DESC"], func = function() - TitanPanel_AddNewSkin(TitanSkinName, TitanSkinPath) - TitanSkinName = "" - TitanSkinPath = "" - -- Config Tables changed! - AceConfigRegistry:NotifyChange("Titan Panel Skin Custom") + AddNewSkin(TitanSkinName, TitanSkinPath) + TitanSkinName = "" + TitanSkinPath = "" + -- Config Tables changed! + AceConfigRegistry:NotifyChange("Titan Panel Skin Custom") end, }, nulloption2 = { @@ -2370,28 +2332,21 @@ local optionsSkinsCustom = { --============= Extras ---[[ local -NAME: optionsExtras -DESC: This is the table shell. The plugin info will be added by another routine. ---]] local optionsExtras = { - name = TITAN_PANEL_CONFIG.topic.extras, --L["TITAN_PANEL_EXTRAS"], + name = TITAN_PANEL_CONFIG.topic.extras, type = "group", args = {} } ---[[ local -NAME: TitanUpdateAddonAttempts -DESC: Show plugins that are not registered (loaded) but have config data. The data can be deleted by the user. -VAR: None -OUT: None -NOTE: +--[[ NOTE: - As users change the plugins they use the old ones still have saved variable data stored by Titan. -- The old plugin data can be removed by the user when they will not longer use that plugin. +- The old plugin data can be removed by the user when they no longer use that plugin. - This routine is called to 'redraw' the list as a user deletes data. - A message is sent to chat that the plugin data has been deleted. -:NOTE --]] + + +---Show plugins that are not registered (loaded) but have config data. The data can be deleted by the user. local function TitanUpdateExtras() local args = optionsExtras.args local plug_in = nil @@ -2445,30 +2400,24 @@ end --============= Attempts ---[[ local -NAME: optionsAddonAttempts -DESC: This is the table shell. The plugin info will be added by another routine. ---]] local optionsAddonAttempts = { - name = TITAN_PANEL_CONFIG.topic.attempts, --L["TITAN_PANEL_ATTEMPTS"], + name = TITAN_PANEL_CONFIG.topic.attempts, type = "group", args = {} } ---[[ local -NAME: TitanUpdateAddonAttempts -DESC: Show the each plugin that attempted to register with Titan. This can be used by plugin developers as the create / update plugins (Titan or LDB). It can also be used by user to attempt to figure out why a plugin is not shown or to report an issue to Titan. -VAR: None -OUT: None -NOTE: +---Show the each plugin that attempted to register with Titan. +local function TitanUpdateAddonAttempts() + local args = optionsAddonAttempts.args + local plug_in = nil + +--[[ NOTE: - This is called after the plugins are registered in the 'player entering world' event. It can be called again as plugins registered. - Any plugins that attempted to register are shown. See the Titan Utils section for more details on plugin registration. - This option page is for display only. The user can take not action. -:NOTE +- This can be used by plugin developers as the create / update plugins (Titan or LDB). +- It can also be used by user to attempt to figure out why a plugin is not shown or to report an issue to Titan. --]] -local function TitanUpdateAddonAttempts() - local args = optionsAddonAttempts.args - local plug_in = nil wipe(args) @@ -2624,8 +2573,8 @@ local confbuffdesc = { cmdHidden = true }, advbuffadj = { - name = "Buff", --L["TITAN_PANEL_MENU_ADV_PEW"], - desc = "", -- L["TITAN_PANEL_MENU_ADV_PEW_DESC"], + name = " ", + desc = "", order = 120, type = "range", width = "full", @@ -2642,14 +2591,6 @@ local confbuffdesc = { }, } ---[[ local -NAME: optionsAdvanced -DESC: Set the table to allow the user to control advanced features. -Controls: -- Entering world timer - some users need Titan to wait longer whenever the splash / loading screen is shown before adjusting frames and (re)setting data. -- Vehicle timer - some users need Titan to wait longer whenever entering or leaving a vehicle before adjusting frames. -:DESC ---]] local optionsAdvanced = { name = TITAN_PANEL_CONFIG.topic.advanced, --L["TITAN_PANEL_MENU_ADV"], type = "group", @@ -2690,9 +2631,59 @@ local optionsAdvanced = { }, }, }, + confadvanved = { + name = L["TITAN_PANEL_MENU_ADV"], + type = "group", + inline = true, + order = 100, + args = { + space_400_1 = { + order = 400, + type = "description", + name = " ", + cmdHidden = true, + }, + optionlaunchers = { + name = L["TITAN_PANEL_MENU_LDB_FORCE_LAUNCHER"], + order = 401, + type = "execute", + width = "full", + func = function() TitanPanelBarButton_ForceLDBLaunchersRight() end, + }, + space_500_1 = { + order = 500, + type = "description", + name = " ", + cmdHidden = true, + }, + pluginreset = { + name = L["TITAN_PANEL_MENU_PLUGIN_RESET"], + desc = L["TITAN_PANEL_MENU_PLUGIN_RESET_DESC"], + order = 501, + type = "execute", + width = "full", + func = function() TitanPanel_InitPanelButtons() end, + }, + space_600_1 = { + order = 600, + type = "description", + name = " ", + cmdHidden = true, + }, + optionreset = { + name = L["TITAN_PANEL_MENU_RESET"] .. " " + .. TitanUtils_GetGreenText(L["TITAN_PANEL_MENU_RELOADUI"]), + order = 601, + type = "execute", + width = "full", + func = function() TitanPanel_ResetTitanToDefault() end, + } + }, + }, }, } +---Allow the user to control advanced features. local function BuildAdv() if Titan_Global.switch.can_edit_ui then else @@ -2708,18 +2699,14 @@ end --============= Change History ---[[ local -NAME: Recent change history -DESC: Show change history of releases -:DESC ---]] +---Recent change history; stored in History.lua local changeHistory = { - name = TITAN_PANEL_CONFIG.topic.changes, --L["TITAN_PANEL_MENU_ADV"], + name = TITAN_PANEL_CONFIG.topic.changes, type = "group", args = { confchanges = { order = 7, - name = " ", --CHANGES_COLON, + name = " ", type = "group", inline = true, args = { @@ -2737,11 +2724,7 @@ local changeHistory = { --============= / Command ---[[ local -NAME: slash command help -DESC: Show detailed help for slash commands -:DESC ---]] +---Show detailed help for slash commands local slashHelp = { name = TITAN_PANEL_CONFIG.topic.slash, type = "group", @@ -2802,144 +2785,354 @@ local slashHelp = { --============= / Help -local help_text = "" -do -- set help_text - help_text = "" - .. TitanUtils_GetGreenText("Plugins: \n") - .. TitanUtils_GetGoldText("Show / Hide Plugins :") - .. TitanUtils_GetHighlightText("" - .. " Use one of the methods below:\n" - .. "- Open the right-click Bar menu; find the plugin in a category then click to toggle Show on the plugin.\n" - .. - "- Open Titan Configuration > Plugins then select the plugin by name then toggle Show. Uuse the Bar dropdown to select the Bar the plugin should be on.\n" - ) - .. TitanUtils_GetGoldText("Moving Plugins :") - .. TitanUtils_GetHighlightText("" - .. " Use one of the methods below:\n" - .. - "- Open the right-click Bar menu of the Bar you want the plugin on; find the plugin in a category then toggle Show. If plugin is already shown on another Bar then toggle again to have it appear in this Bar.\n" - .. "- Drag and drop on another bar or on the same bar.\n" - .. "- Drag and drop on another plugin to swap the plugins.\n" - .. - "- Open Titan Configuration > Plugins then toggle Show. Use the Bar dropdown and Right / Left buttons to place the plugin as desired.\n" - ) - .. "\n\n" - .. TitanUtils_GetGreenText("Short Bars: \n") - .. TitanUtils_GetHighlightText("" - .. "Short bars are 10 shorter Titan bars that the user can place and change width.\n" - .. "- Short bars are independent. They may be used with or without the full width Titan bars.\n" - .. - "- Titan does not restrict plugins to fit within the visible width (background). Using Configuration, plugins can be assigned well beyond the visible side. This may be desirable for some users.\n" - .. - "- Setting a plugin to right-side will use the visible right side (background); and may overlap with left or center aligned plugins.\n" - ) - .. TitanUtils_GetGoldText("Enable :\n") - .. TitanUtils_GetHighlightText("" - .. "- Open Configuration > Bars to enable and change Bar options.\n" - .. "- The default position is the top center under the full width bars. They will be stacked to not overlap.\n" - ) - .. TitanUtils_GetGoldText("Change Size :\n") - .. TitanUtils_GetHighlightText("" - .. "- Change width by 1 : Use Shift + mouse wheel.\n" - .. "- Change width by 10: Use Shift + Ctrl + mouse wheel.\n" - .. "- WIll not go beyond right side of screen.\n" - ) - .. TitanUtils_GetGoldText("Move :\n") - .. TitanUtils_GetHighlightText("" - .. "- Use Shift + left mouse on Bar, not plugins, and drag.\n" - .. "- When dragging, best to place your mouse over the left side padding before moving or changing width.\n" - .. "- When dragging stops, if the Short Bar is beyond the screen edge the Short Bar should 'snap' to the edge.\n" - ) - .. TitanUtils_GetGoldText("Reset :\n") - .. TitanUtils_GetHighlightText("" - .. - " In case a Short bar gets messed up, use Config > Bar > <Pick the Bar> then click Reset Position to place it at original position and width.\n" - ) - .. TitanUtils_GetGoldText("Skin :\n") - .. TitanUtils_GetHighlightText("" - .. "- Can select Skin per Short bar BUT only the 'top' skin is used; some skins have a different top & bottom.\n" - ) - .. TitanUtils_GetGoldText("Limitations :\n") - .. TitanUtils_GetHighlightText("" - .. "- Min width : Left side padding plus one icon width.\n" - .. "- Max width : Screen width.\n" - .. "- There is no 'snap together' or grid for placing Short Bars.\n" - .. "\n" - ) - .. TitanUtils_GetGreenText("All Bars: \n") - .. TitanUtils_GetHighlightText("" - .. "- Bar Right click menu shows the name of the Bar in the menu title. Same name in configuration options.\n" - .. "- Hide any Titan bar by using the Bar Right click menu then click Hide.\n" - ) - .. TitanUtils_GetGoldText("Skins :\n") - .. TitanUtils_GetHighlightText("" - .. "- Select per Titan bar.\n" - .. "- Select a skin for all Titan bars. This does NOT change the individual Titan bar skin settings.\n" - ) - .. TitanUtils_GetGoldText("Hide in Combat :\n") - .. TitanUtils_GetHighlightText("" - .. "- Select per Titan bar.\n" - .. "- Hide all Titan bars during combat. This does NOT change the individual Titan bar hide in combat settings.\n" - ) - .. TitanUtils_GetGoldText("Bar Order (English) :") - .. TitanUtils_GetHighlightText("" - .. " Configuration > Bars shows localized Bar names.\n" - .. "- Top : Always top of screen\n" - .. "- Top 2 : Always under Top Bar\n" - .. "- Bottom 2 : Always above Bottom Bar\n" - .. "- Bottom : Always bottom of screen\n" - .. "- Short 01 - 10 : User placed\n" - ) - .. "\n\n" +---Format a known table - topic, subtopic, lines +---@param topic table +---@return string topic Single formatted string +local function ParseHelp(topic) + -- Topic header is green + -- Subtopic is gold + -- Lines are white (highlight) + local str = "" + str = str .. TitanUtils_GetGreenText(topic.topic .. " : \n") + + for idx = 1, #topic.subs do + str = str .. " \n" -- space before sub topic + str = str .. TitanUtils_GetGoldText(topic.subs[idx].sub .. " : \n") + str = str .. TitanUtils_GetHighlightText(topic.subs[idx].line .. "\n") + end + + return str end ---[[ local -NAME: helpBars -DESC: Help for the Titan Panel user -:DESC ---]] -local helpBars = { - name = TITAN_PANEL_CONFIG.topic.help, - type = "group", - args = { - confgendesc = { - name = "Help", - order = 1, - type = "group", - inline = true, - args = { - confdesc = { - order = 1, - type = "description", - name = help_text, - cmdHidden = true - }, - } + +-- carriage returns (backslash n) are needed only inside line text. +-- An blank line is added before each sub topic. +-- A carriage return is added after each topic. sub topic, and line. +local help_list_topics = { + [1] = { -- plugins + topic = L["TITAN_PANEL_MENU_PLUGINS"], + subs = { + [1] = { + sub = "Show / Hide Plugins", + line = "" + .. " Use one of the methods below:\n" + .. "- Open the right-click Bar menu; find the plugin in a category then click to toggle Show on the plugin.\n" + .. + "- Open Titan Configuration > Plugins then select the plugin by name then toggle Show. Use the Bar dropdown to select the Bar the plugin should be on." + , + }, + [2] = { + sub = "Moving Plugins", + line = "" + .. " Use one of the methods below:\n" + .. + "- Open the right-click Titan Bar menu of the Bar you want the plugin on; find the plugin in a category then toggle Show.\n" + .. "-- If plugin is already shown on another Bar then toggle again to have it appear in this Bar.\n" + .. "- Open Titan Configuration > Plugins.\n" + .. "-- Use the Bar dropdown to change bars.\n" + .. "-- Use Right / Left buttons to place the plugin as desired.\n" + .. "- Drag and drop : Drag (hold left mouse button on plugin) to another bar (any where, even over a plugin).\n" + .. "-- This honors right side setting.\n" + .. "-- This honors 'force bar' such as auto hide 'pins'.\n" + .. + "-- If not over a bar, the plugin will return to the bar it came from at 'end'. If right side, it will be left of right side plugins. Otherwise right of left side plugins." + , + }, }, - } + }, + [2] = { -- bars overview + topic = L["TITAN_PANEL_MENU_OPTIONS_BARS_ALL"], + subs = { + [1] = { + sub = "Overview", + line = "" + .. "- Titan Bars include 2 top bars, 2 bottom bars, and 10 short bars.\n" + .. "- The top and bottom bars are screen width. They can not be movad.\n" + .. "- Short bars are movable with changeable width.\n" + .. "- Bar Right click menu shows the name of the Bar in the menu title.\n" + .. "- All Bars be shown or hidden from the Titan menu or Titan Config.\n" + .. "- Hide any Titan bar by using the Bar Right click menu then click Hide." + , + }, + }, + }, + [3] = { -- short bars + topic = "Short Bars", + subs = { + [1] = { + sub = "Overview", + line = "" .. "Short bars are 10 shorter Titan bars that the user can place and change width.\n" + .. "- Short bars are independent. They may be used with or without the full width Titan bars.\n" + .. + "- Titan does not restrict plugins to fit within the visible width (background). Using Configuration, plugins can be assigned well beyond the visible side. This may be desirable for some users.\n" + .. + "- Setting a plugin to right-side will use the visible right side (background); and may overlap with left or center aligned plugins." + , + }, + [2] = { + sub = "Enable", + line = "" + .. "- Open Configuration > Bars to enable and change Bar options.\n" + .. "- The default position is the top center under the full width bars. They will be stacked to not overlap." + , + }, + [3] = { + sub = "Change Size", + line = "" + .. "- Change width by 1 : Use Shift + mouse wheel.\n" + .. "- Change width by 10: Use Shift + Ctrl + mouse wheel.\n" + .. "- WIll not go beyond right side of screen." + , + }, + [4] = { + sub = "Move", + line = "" + .. "- Use Shift + left mouse on Bar, not plugins, and drag.\n" + .. "- When dragging, best to place your mouse over the left side padding before moving or changing width.\n" + .. "- When dragging stops, if the Short Bar is beyond the screen edge the Short Bar should 'snap' to the edge." + , + }, + [5] = { + sub = "Reset", + line = "" + .. + "- In case a Short bar gets messed up, use Config > Bar > <Pick the Bar> then click Reset Position to place it at original position and width." + , + }, + [6] = { + sub = "Skin", + line = "" + .. "- Can select Skin per Short bar BUT only the 'top' skin is used; some skins have a different top & bottom." + , + }, + [7] = { + sub = "Limitations", + line = "" + .. "- Min width : Left side padding plus one icon width.\n" + .. "- Max width : Screen width.\n" + .. "- There is no 'snap together' or grid for placing Short Bars." + , + }, + }, + }, + [4] = { -- profiles + topic = L["TITAN_PANEL_MENU_PROFILES"], + subs = { + [1] = { + sub = "Overview", + line = "" + .. "- Every toon logged into has a profile that stores the settings on next login / reload.\n" + .. "- The Titan menu will show the profile being used.\n" + .. "- The profiles are listed in Titan > Config > Profiles.\n" + .. "-- You can Load / Save the profile.\n" + .. "-- The current profile is gray to prevent loading from or deleting.\n" + .. "-- Loading a profile is a COPY." + .. " \n" + .. "- Profiles are part of Titan saved vars which are saved to disk on logout or reload.\n" + .. " \n" + .. "- Titan 9.* Changed from a Global profile to a Sync scheme. This allows greater flexibility.\n" + .. "A Global profiole can be done by syncing all toons with the same profile.\n" + , + }, + [2] = { + sub = "Sync a profile", + line = "" + .. + "- You may Sync a profile or multiple profiles a profile. When you sync a profile any changes to bars and plugins are made to the Sync profile.\n" + .. "- To Sync a profile use Titan > Config > Profiles Click. Then select the profile to use. Then click Sync.\n" + .. " Now Titan changes will be made to the Sync profile. " + .. " The settings for the current toon will be saved and used when the Sync is cleared." + , + }, + [3] = { + sub = "Clear Sync a profile", + line = "" + .. + "- You may Clear Sync (remove) the current Sync being used by a profile. \n" + .. "- To Clear Sync a profile use Titan > Config > Profiles Click. \n" + .. "-- Then select the profile to use. \n" + .. "-- Then click Clear Sync.\n" + .. "- Now Titan changes will be made to that toon profile. " + .. "- The settings prior to the Sync will be used." + , + }, + [4] = { + sub = "Load a Profile", + line = "" + .. "- Use Titan Menu > Profile Configuration; select the profile you want then click Load.\n" + .. "-- The current profile is gray to prevent loading.\n" + .. "-- Load will COPY the profile over the logged in toon." + , + }, + [5] = { + sub = "Delete a Profile", + line = "" + .. "- Use Titan Menu > Profile Configuration; select the profile you want then click Delete.\n" + .. "-- The current profile is gray to prevent deleting.\n" + .. "-- Delete of a profile should be done on a toon that was deleted from the game.\n" + .. "-- Delete can act as a Titan reset for that toon." + , + }, + [6] = { + sub = "Custom Profile", + line = "" + .. "- Use Titan Menu > Profile Configuration; select the profile you want then click Save Custom.\n" + .. "- Name the profile. It will be saved with a 'server' of 'TitanCustomProfile'.\n" + .. " \n" + .. "- Name the profile. It will be saved with a 'server' of 'TitanCustomProfile'.\n" + .. "- There are two ways to change a custom profile.\n" + .. "-- Sync a toon to the custom profile then update Titn config while logged into that toon.\n" + .. "-- Overwrite the profile by using Save Custom again then input the same name. An 'are you sure' prompt will appear." + .. " \n" + .. "- On create or overwrite of a custom profile, Titan will reload to ensure the profile is saved." + + }, + }, + }, + [5] = { -- slash commands + topic = L["TITAN_PANEL_MENU_SLASH_COMMAND"], + subs = { + [1] = { + sub = L["TITAN_PANEL_MENU_HELP"], + line = "" + .. TitanUtils_GetGoldText("reset\n") + .. L["TITAN_PANEL_SLASH_RESET_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_1"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_2"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_3"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_4"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_5"] .. "\n" + .. L["TITAN_PANEL_SLASH_RESET_6"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("gui\n") + .. L["TITAN_PANEL_SLASH_GUI_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_GUI_1"] .. "\n" + .. L["TITAN_PANEL_SLASH_GUI_2"] .. "\n" + .. L["TITAN_PANEL_SLASH_GUI_3"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("profile\n") + .. L["TITAN_PANEL_SLASH_PROFILE_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_PROFILE_1"] .. "\n" + .. L["TITAN_PANEL_SLASH_PROFILE_2"] .. "\n" + .. L["TITAN_PANEL_SLASH_PROFILE_3"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("silent\n") + .. L["TITAN_PANEL_SLASH_SILENT_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_SILENT_1"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("orderhall\n") + .. L["TITAN_PANEL_SLASH_ORDERHALL_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_ORDERHALL_1"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("help\n") + .. L["TITAN_PANEL_SLASH_HELP_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_HELP_1"] .. "\n" + .. "\n" + .. TitanUtils_GetGoldText("all\n") + .. L["TITAN_PANEL_SLASH_ALL_0"] .. "\n" + .. L["TITAN_PANEL_SLASH_ALL_1"] .. "\n" + .. "", + }, + }, + }, + [6] = { -- notes + topic = "Notes", + subs = { + [1] = { + sub = "Changing Titan Scaling", + line = + "Short bars will move on screen. They should not go off screen. If Short bars move then drag to desired location. You may have to Reset the Short bar or temporarily disable top or bottom bars to drag the Short bar." + , + }, + }, + }, + [7] = { -- issues + topic = "Known Issues", + subs = { + [1] = { + sub = "Titan", + line = "No known major issues." + , + }, + [2] = { + sub = "Repair", + line = "Selling all grey items may take 2, possibly 3 clicks. There is no known fix atm." + , + }, + }, + }, + [8] = { -- TY + topic = "Thank You", + subs = { + [1] = { + sub = "From Titan Dev Team", + line = "" + .. "We would like to thank all of the users of TitanPanel." + , + }, + }, + }, } + +local helplist = { + name = TITAN_PANEL_CONFIG.topic.help_list, + type = "group", + args = {} +} + +---Format the help to display in Config +local function BuildHelpList() + local args = helplist.args + -- list element + + for idx = 1, #help_list_topics do + -- Create the list of topics + local index = tostring(idx) + args[index] = { + name = help_list_topics[idx].topic, + order = idx, + type = "group", + args = {}, + } + -- Add the text... + args[index].args.show = { + order = 1, + type = "description", + name = ParseHelp(help_list_topics[idx]), + cmdHidden = true + } + end +end + ------------- ------------- ----Titan This routine will handle the requests to update the various data items in Titan options screens. +---Build the entire Config table Ace will display +local function BuildAll() + -- Update the tables for the latest lists + UpdateConfigAddons() + TitanUpdateAddonAttempts() + TitanUpdateExtras() + TitanUpdateChars() + BuildSkins() + BuildBars() + BuildBarsAll() + BuildAdj() + BuildAdv() + BuildHelpList() +end + +---Titan This routine will handle the requests to build or clear the Titan Config screens. --- This is called after the plugins are registered in the 'player entering world' event. It can be called again as more plugins are registered. ---@param action string "init" or "nuke" function TitanUpdateConfig(action) if action == "init" then - -- Update the tables for the latest lists - TitanUpdateConfigAddons() - TitanUpdateAddonAttempts() - TitanUpdateExtras() - TitanUpdateChars() - BuildSkins() - BuildBars() - BuildBarsAll() - BuildAdj() - BuildAdv() + BuildAll() end + if action == "nuke" then local nuked = { - name = "Titan could not initialize properly.", --L["TITAN_PANEL_DEBUG"], + name = "Titan could not initialize properly.", type = "group", args = {} } @@ -2965,49 +3158,50 @@ function TitanUpdateConfig(action) end end ---[[ -Register the options tables with Ace then register the options with Blizz so the user can use them. ---]] --- Add Blizzard Configuration Panels ---[[ The first param needs to used for the 'add to options' -The second param must be the table Ace will use to create the user options ---]] -AceConfig:RegisterOptionsTable("Titan Panel Main", titan_entry) -AceConfig:RegisterOptionsTable("Titan Panel Bars", optionsBars) -AceConfig:RegisterOptionsTable("Titan Panel Globals", optionsGlobals) -AceConfig:RegisterOptionsTable("Titan Panel Adjust", optionsAdjust) -AceConfig:RegisterOptionsTable("Titan Panel Frames", optionsFrames) -AceConfig:RegisterOptionsTable("Titan Panel Panel Control", optionsUIScale) -AceConfig:RegisterOptionsTable("Titan Panel Skin Control", optionsSkins) -AceConfig:RegisterOptionsTable("Titan Panel Skin Custom", optionsSkinsCustom) -AceConfig:RegisterOptionsTable("Titan Panel Addon Control", optionsAddons) -AceConfig:RegisterOptionsTable("Titan Panel Addon Attempts", optionsAddonAttempts) -AceConfig:RegisterOptionsTable("Titan Panel Addon Extras", optionsExtras) -AceConfig:RegisterOptionsTable("Titan Panel Addon Chars", optionsChars) -AceConfig:RegisterOptionsTable("Titan Panel Addon Advanced", optionsAdvanced) -AceConfig:RegisterOptionsTable("Titan Panel Addon Changes", changeHistory) -AceConfig:RegisterOptionsTable("Titan Panel Addon Slash", slashHelp) -AceConfig:RegisterOptionsTable("Titan Panel Help", helpBars) ---]] --- Set the main options pages ---[[ The first param must be the same as the cooresponding 'Ace register' -The second param should be the same as the .name of the cooresponding table that was registered, -if not, any 'open' may fail. ---]] ---AceConfigDialog:AddToBlizOptions("Titan Panel Main", L["TITAN_PANEL"]) -AceConfigDialog:AddToBlizOptions("Titan Panel Main", titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Bars", optionsBars.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Globals", optionsGlobals.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Adjust", optionsAdjust.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Control", optionsAddons.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Chars", optionsChars.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Frames", optionsFrames.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Panel Control", optionsUIScale.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Skin Control", optionsSkins.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Skin Custom", optionsSkinsCustom.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Extras", optionsExtras.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Attempts", optionsAddonAttempts.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Advanced", optionsAdvanced.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Changes", changeHistory.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Addon Slash", slashHelp.name, titan_entry.name) -AceConfigDialog:AddToBlizOptions("Titan Panel Help", helpBars.name, titan_entry.name) +do -- Register Titan main options list + -- Register the options tables with Ace then register the options with Blizz so the user can use them. + -- Add Blizzard Configuration Panels + -- The first param needs to used for the 'add to options' + -- The second param must be the table Ace will use to create the user options + -- + AceConfig:RegisterOptionsTable("Titan Panel Main", titan_entry) + AceConfig:RegisterOptionsTable("Titan Panel Bars", optionsBars) + AceConfig:RegisterOptionsTable("Titan Panel Globals", optionsGlobals) + AceConfig:RegisterOptionsTable("Titan Panel Adjust", optionsAdjust) + AceConfig:RegisterOptionsTable("Titan Panel Frames", optionsFrames) + AceConfig:RegisterOptionsTable("Titan Panel Panel Control", optionsUIScale) + AceConfig:RegisterOptionsTable("Titan Panel Skin Control", optionsSkins) + AceConfig:RegisterOptionsTable("Titan Panel Skin Custom", optionsSkinsCustom) + AceConfig:RegisterOptionsTable("Titan Panel Addon Control", optionsAddons) + AceConfig:RegisterOptionsTable("Titan Panel Addon Attempts", optionsAddonAttempts) + AceConfig:RegisterOptionsTable("Titan Panel Addon Extras", optionsExtras) + AceConfig:RegisterOptionsTable("Titan Panel Addon Chars", optionsChars) + AceConfig:RegisterOptionsTable("Titan Panel Addon Advanced", optionsAdvanced) + AceConfig:RegisterOptionsTable("Titan Panel Addon Changes", changeHistory) + AceConfig:RegisterOptionsTable("Titan Panel Addon Slash", slashHelp) + AceConfig:RegisterOptionsTable("Titan Panel Help List", helplist) +end + +do -- Register the options for each entry in Titan option list + -- Set the main options pages + -- The first param must be the same as the cooresponding 'Ace RegisterOptionsTable' + -- The second param should be the same as the .name of the cooresponding table that was registered, + -- if not, any 'open' may fail. + -- + AceConfigDialog:AddToBlizOptions("Titan Panel Main", titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Bars", optionsBars.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Globals", optionsGlobals.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Adjust", optionsAdjust.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Control", optionsAddons.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Chars", optionsChars.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Frames", optionsFrames.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Panel Control", optionsUIScale.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Skin Control", optionsSkins.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Skin Custom", optionsSkinsCustom.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Extras", optionsExtras.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Attempts", optionsAddonAttempts.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Advanced", optionsAdvanced.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Changes", changeHistory.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Addon Slash", slashHelp.name, titan_entry.name) + AceConfigDialog:AddToBlizOptions("Titan Panel Help List", helplist.name, titan_entry.name) +end diff --git a/Titan/TitanDebug.lua b/Titan/TitanDebug.lua index fdd635b..66be0a8 100644 --- a/Titan/TitanDebug.lua +++ b/Titan/TitanDebug.lua @@ -1,79 +1,104 @@ ---[===[ File -This file contains the debug class used throughout Titan Panel and plugins. - -This file is loaded first so NO other Titan routines are to be used. - -The intent is a simple, flexible debug framework to enable: -- a consistent output -- enable / disable across an arbitrary scope - across addons; single addon; or partial addon -- enable / disable rather than comment out ---]===] - -Titan_Debug = {} - -local text_color = "1DA6C5" -- light blue -local head_color = "f2e699" -- yellow gold -local err_color = "ff2020" -- red - -local function Encode(color, text) - -- Color the string using WoW encoding - local res = "" - local c = tostring(color) - local t = tostring(text) - if (c and t) then - res = "|cff" .. c .. t .. "|r" - else - if (t) then - res = tostring(t) - else - -- return blank string - end - end - - return res -end - ----Simple debug to output plugin/Titan, the topic, and info ----@param who string ----@param topic string ----@param str string -function Titan_Debug.Out(who, topic, str) - - if Titan_Debug[who] - and Titan_Debug[who][topic] - and Titan_Debug[who][topic] == true - then - local msg = "" - .. Encode(head_color, - date("%H:%M:%S") - .. " <" .. tostring(who) .. "" - .. " : " .. tostring(topic) .. ">" - ) - .. Encode(text_color, - " " .. str .. "" - ) - - _G["DEFAULT_CHAT_FRAME"]:AddMessage(msg) - else - -- silently proceed - end -end - --- For debug across Titan Panel --- Keep two levels deep, to use .Out !!! --- Titan_Debug.<plugin or 'titan'>.<debug topic> --- -Titan_Debug.titan = {} -Titan_Debug.titan.bars_setup = false -Titan_Debug.titan.events = false -Titan_Debug.titan.ldb_setup = false -Titan_Debug.titan.menu = false -Titan_Debug.titan.p_e_w = false -- player entering world -Titan_Debug.titan.plugin_text = false -Titan_Debug.titan.plugin_register = false -Titan_Debug.titan.plugin_register_deep = false -Titan_Debug.titan.plugin_drag_drop = false -Titan_Debug.titan.profile = false -Titan_Debug.titan.movable = false -Titan_Debug.titan.startup = false -Titan_Debug.titan.tool_tips = false +--[===[ File +This file contains the debug class used throughout Titan Panel and plugins. + +This file is loaded first so NO other Titan routines are to be used! + +--]===] + +--[[ +The intent is a simple, flexible debug framework to enable: +- a consistent output +- enable / disable across an arbitrary scope - across addons; single addon; or partial addon +- enable / disable rather than comment out + +Setting is TitanDebug.<plugin>.<topic> +Plugins may assume Titan_Debug exists and can be added to. +<plugin> needs to be unique for each plugin. +<topic> is arbitrary and based on the debug needs. + +An output routine is provided : Titan_Debug.Out(who, topic, str) +Out ensures TitanDebug.<who>.<topic> exists before output of the string to Chat. +If the entry is not found, returns silently. +Out has no dependencies. Out only assumes DEFAULT_CHAT_FRAME:AddMessage is available. + + +Example: +For debug of Titan events we create : +Titan_Debug.titan = {} +Titan_Debug.titan.events = false + +Then place calls in code : +Titan_Debug.Out("titan", "events", debug_str) + +Then set to turn display them. +Titan_Debug.titan.events = true + + +--]] +Titan_Debug = {} + +local text_color = "1DA6C5" -- light blue +local head_color = "f2e699" -- yellow gold +local err_color = "ff2020" -- red + +local function Encode(color, text) + -- Color the string using WoW encoding + local res = "" + local c = tostring(color) + local t = tostring(text) + if (c and t) then + res = "|cff" .. c .. t .. "|r" + else + if (t) then + res = tostring(t) + else + -- return blank string + end + end + + return res +end + +---Simple debug to output plugin/Titan, the topic, and info +---@param who string +---@param topic string +---@param str string +function Titan_Debug.Out(who, topic, str) + + if Titan_Debug[who] + and Titan_Debug[who][topic] + and Titan_Debug[who][topic] == true + then + local msg = "" + .. Encode(head_color, + date("%H:%M:%S") + .. " " .. tostring(who) .. "" + .. ":" .. tostring(topic) .. "" + ) + .. Encode(text_color, + " " .. str .. "" + ) + _G["DEFAULT_CHAT_FRAME"]:AddMessage(msg) + else + -- silently proceed + end +end + +-- For debug across Titan Panel +-- Keep two levels deep, to use .Out !!! +-- Titan_Debug.<plugin>.<debug topic> +-- +Titan_Debug.titan = {} +Titan_Debug.titan.bars_setup = false +Titan_Debug.titan.events = false +Titan_Debug.titan.ldb_setup = false +Titan_Debug.titan.menu = false +Titan_Debug.titan.p_e_w = false -- player entering world +Titan_Debug.titan.plugin_text = false +Titan_Debug.titan.plugin_register = false +Titan_Debug.titan.plugin_register_deep = false +Titan_Debug.titan.plugin_drag_drop = false +Titan_Debug.titan.profile = false +Titan_Debug.titan.movable = false +Titan_Debug.titan.startup = false +Titan_Debug.titan.tool_tips = false diff --git a/Titan/TitanGame.lua b/Titan/TitanGame.lua index 2d4d3be..58e37cd 100644 --- a/Titan/TitanGame.lua +++ b/Titan/TitanGame.lua @@ -1,10 +1,19 @@ ---[===[ File -NAME: TitanGame.lua -DESC: This file contains the 'game version' Titan or TitanClassic. Used to set up libs, locale, ... -Different folders are required because Titan used Titan as a name (& folder) for the Classic WoW versions. -The saved variables for Classic WoW are in TitanClassic.lua - not Titan.lua. -:DESC ---]===] - -TITAN_ID = "Titan" - +--[===[ File +This file contains the 'Titan ID' Titan or TitanClassic. Used to set up libs, locale, ... +Different folders are required because Titan used Titan as a name (& folder) for the Classic WoW versions. +The saved variables for Classic WoW are in TitanClassic.lua - not Titan.lua. + +--]===] +--[[ +Way back different Titan used TitanClassic as a name (& folder) for Classic versions - Classic BC and Era. +TITAN_ID was set to Titan or TitanClassic depending on the expansion the player was loading. + +For Titan 8.* we decided to combine code into one version rather than fighting to release potentially three distinct WoW versions - Retail; <xpac> Classic; and Classic Era. +However the saved variables for Classic WoW are in TitanClassic.lua - not Titan.lua. + +For Burning Crusades; Legion; and Cataclysm this worked because the API was very close to Classic Era. +However when Mists of Pandaria came out, the API was much closer to retail than Classic Era. +--]] + +TITAN_ID = "Titan" + diff --git a/Titan/TitanHistory.lua b/Titan/TitanHistory.lua index 94a9824..732a4db 100644 --- a/Titan/TitanHistory.lua +++ b/Titan/TitanHistory.lua @@ -1,5 +1,5 @@ --[===[ File -This file contains Config 'recent changes' and notes. +This file contains 'recent changes' and notes for Titan Config. It should be updated for each Titan release! These are in a seperate file to @@ -7,14 +7,120 @@ These are in a seperate file to 2) Decrease the chance of breaking the code :). --]===] ---[[ Var Release Notes -Detail changes for last 4 - 5 releases. -Format : -Gold - version & date -Green - 'header' - Titan or plugin -Highlight - notes. tips. and details ---]] -Titan_Global.recent_changes = "" +--- Release notes. Keep structure; most recent on 'top' +local recent_changes = { + { + version = "9.0.0", + when = "2025/11/06", + topics = { + { + topic = "Profiles", + lines = { + "Profiles are greatly changed.", + "- Global is gone; replaced by a Sync scheme.", + "- See Config > Help > Profiles for more details on how this works.", + }, + }, + { + topic = "Reset", + lines = { + "Due to the Profile changing to Sync :", + "- /titan reset will reset the Profile used (could be a Sync).", + "- /titan reset all ", + "--- NEW slash command will act as a delete of Titan saved vars", + "--- Also accessable in Titan > Config > Advanced", + }, + }, + { + topic = "TitanUI", + lines = { + "NEW built-in!", + "Left click will reload UI.", + "Menu gives access to :", + "- Select Titan config pages.", + "- Titan reset of profile (could be a Sync).", + "- Select dev tools, if available.", + }, + }, + { + topic = "Titan", + lines = { + "Plugins : Should be less space after, esp. for those with multiple info displayed such as Perf and Repair.", + }, + }, + }, + }, + { + version = "8.4.2", + when = "2025/11/01", + topics = { + { + topic = "Titan", + lines = { + "TOC update only.", + }, + }, + }, + }, + { + version = "8.4.1", + when = "2025/10/11", + topics = { + { + topic = "Titan", + lines = { + "TOC update only.", + }, + }, + }, + }, + { + version = "8.4.0", + when = "2025/08/27", + topics = { + { + topic = "Titan", + lines = { + "- /titan reset working again; no reload needed!", + "- Hopefully fix bar transparency values resetting on logout or reload.", + "- Moved most bar settings from 'Bars - All' to each bar - use profiles instead.", + "--- Bar skin / color settings", + "--- Hide Bar during combat", + "--- Hide Bar in PvP and BG zones", + "- Fix drag & drop of Titan plugins, per an API change in 11.2.0.", + } + }, + { + topic = "Titan Internal", + lines = { + "- Global profiles should be working again.", + "- More debug statements on login, reload, profile reset.", + "- Removed code for old DewDrop and Tablet from tooltip code.", + }, + }, + }, + }, +} + +local recent_changes_old = "" +.. TitanUtils_GetGoldText("9.0.0 : 2025/11/06\n") +.. TitanUtils_GetGreenText("Titan : \n") +.. TitanUtils_GetHighlightText("" +.. "- Profiles are greatly changed.\n" +.. "--- Global is gone; replaced by a Sync scheme.\n" +.. "--- See Config > Help > Profiles for more details on how this works.\n" +.. "- Plugins : Should be less space after, esp. for those with multiple info displayed such as Perf and Repair.\n" +) +.. TitanUtils_GetGoldText("8.4.2 : 2025/11/01\n") +.. TitanUtils_GetGreenText("Titan : \n") +.. TitanUtils_GetHighlightText("" +.. "- TOC update only \n" +) +.. TitanUtils_GetGoldText("8.4.1 : 2025/10/11\n") +.. TitanUtils_GetGreenText("Titan : \n") +.. TitanUtils_GetHighlightText("" +.. "- TOC update only \n" +) .. TitanUtils_GetGoldText("8.4.0 : 2025/09/07\n") .. TitanUtils_GetGreenText("Titan : \n") .. TitanUtils_GetHighlightText("" @@ -32,50 +138,52 @@ Titan_Global.recent_changes = "" .. "- - : Removed code for old DewDrop and Tablet from tooltip code.\n" ) .. TitanUtils_GetGoldText("8.3.5 : 2025/08/27\n") -.. TitanUtils_GetGreenText("Titan : \n") +.. TitanUtils_GetGreenText("Repair : \n") .. TitanUtils_GetHighlightText("" -.. "- Repair : \n" -.. "- - : Restore accidently removed 'use guild funds' option.\n" -.. "- Loot : \n" -.. "- - : Classic : Restore ability to resize Loot window frame.\n" -.. "- - : Retail : Get ahead of deprecated APIs GetSpecialization and GetSpecializationInfo into C_SpecializationInfo.\n" -.. "- Internal : \n" -.. "- - : Config updates to Vars and Bars All when choosing global versus single bar values.\n" +.. "- Restore accidently removed 'use guild funds' option.\n" ) -.. TitanUtils_GetGoldText("8.3.4 : 2025/08/24\n") -.. TitanUtils_GetGreenText("Titan : \n") -.. TitanUtils_GetHighlightText("" -.. "- LootType : \n" -.. "- - : Fix error per Curse comments (line 179).\n" -.. "- ClassicLootType : \n" -.. "- - : Prep for API change to GetLootMethod.\n" -.. "- Internal : \n" -.. "- - : Config updates to Vars and Bars All when choosing skins versus color.\n" -.. "- - : New locale strings for the above Config change.\n" -) -.. TitanUtils_GetGoldText("8.3.3 : 2025/08/12\n") -.. TitanUtils_GetGreenText("Titan : \n") +.. TitanUtils_GetGreenText("Loot : \n") .. TitanUtils_GetHighlightText("" -.. "- LootType : \n" -.. "- - : Fix API change to GetLootMethod, retail only.\n" -.. "- Location : \n" -.. "- - : Fix map coords being off map in retail; Top and Bottom should now work in retail.\n" -.. "- - : Fix rare error that shows error on button text.\n" -.. "- Internally : \n" -.. "- - : Fix profile not saving (#1439).\n" -.. "- - : Expand Battle Ground widget adjust (allow 'up').\n" -.. "- - : Make Classic TOC show as Classic to help avoid confusion.\n" +.. "- Classic : Restore ability to resize Loot window frame.\n" +.. "- Retail : Get ahead of deprecated APIs GetSpecialization and GetSpecializationInfo into C_SpecializationInfo.\n" ) -.. TitanUtils_GetGoldText("8.3.2 : 2025/08/01\n") .. TitanUtils_GetGreenText("Titan : \n") .. TitanUtils_GetHighlightText("" -.. "- Ammo : \n" -.. "- - : Fix missing icon.\n" -.. "- Internally : \n" -.. "- - : Several tweaks for MoP.\n" +.. "- Internal : Config updates to Vars and Bars All when choosing global versus single bar values.\n" ) .. "\n\n" + +---Format the release notes +local function BuildList() + local max = 5 + local res = "" + for idx = 1, #recent_changes do -- A release + res = res.."\n" -- spacer + local rc = recent_changes[idx] + + if idx <= max then + res = res + ..TitanUtils_GetGoldText(rc.version.." : "..rc.when.."\n") + + for tops = 1, #rc.topics do -- Topic of change + local rct = rc.topics[tops] + res = res + ..TitanUtils_GetGreenText(rct.topic.." : \n") + + for line = 1, #rct.lines do -- Change details + local rctl = rct.lines[line] + res = res..TitanUtils_GetHighlightText(rctl.." \n") + end + end + end + end + + return res +end +Titan_Global.recent_changes = BuildList() + + --[[ Var Notes Use for important notes in the Titan Config About --]] @@ -88,5 +196,5 @@ Titan_Global.config_notes = "" .. "\n" .. TitanUtils_GetGoldText("Known Issues:\n") .. TitanUtils_GetHighlightText("" - .. "- Cata : Titan right-click menu may stay visible even if click elsewhere. Hit Esc twice. Investigating...\n" + .. "- All : No known major issues.\n" ) diff --git a/Titan/TitanLDB.lua b/Titan/TitanLDB.lua index 85d1ac1..10e8603 100644 --- a/Titan/TitanLDB.lua +++ b/Titan/TitanLDB.lua @@ -1,930 +1,931 @@ ---[===[ File -A "bridge" module to ensure proper registration and communication of LDB plugins with Titan Panel - -By Titan Dev team -Originally by Tristanian aka "TristTitan" as a Titan member -Created and initially commited on : July 29th, 2008 ---]===] - ---[===[ Var Titan LDB overview -The spec: https://github.com/tekkub/libdatabroker-1-1 -LDB (libdatabroker) is a small library that enables an addon to hook into a 'display' addon such as Titan. - ---- Creation -The addon dev creates an LDB object which the lib places in storage accessible by lib:DataObjectIterator(). -It also fires a "LibDataBroker_DataObjectCreated" callback. - -LDB objects work by callbacks. -When an LDB addon changes one of its values, the lib fires a callback for the display addon. - -The LDB addon may declare scripts (tooltip, mouse clicks, etc.) per the spec for the display addon to use. - ---- Starting from Titan view -On PLAYER_ENTERING_WORLD, Titan will use the iterator to wrap each LDB type addon into a Titan plugin. -Once done processing the known LDB objects, -Titan registers for the callback to handle LDB objects created later or on demand. - -Titan registers for callbacks on text and icon updates - depending on the LDB type. - ---- Running from Titan view -The LDB addon is responsible for setting and changing its text and icon. -Titan is responsible for updating the Titan plugin in response. - -The Titan plugin will use the LDB addon scripts IF declared, again depending on the LDB type. - - ---- Supported -Only LDB types listed in the LDB 1.1 spec are supported by Titan. - -- "launcher" become "icon" plugins - TitanPanelIconTemplate - icon* - always shown - OnClick* - - label^ - - right side^ - default - tooltip -- "data source" become "combo" plugins - TitanPanelComboTemplate - icon^ - - OnClick - - text*^ - or value & suffix - label^ - - OnEnter - - OnLeave - - tooltip - OnTooltipShow - - -* required by LDB spec -^ Titan user controlled show / hide - ---]===] - -local xcategories = { - -- Titan categories mapping to match addon metadata information - ["Combat"] = "Combat", - ["General"] = "General", - ["Information"] = "Information", - ["Interface"] = "Interface", - ["Profession"] = "Profession", - -- Ace2 table mapping to Titan categories in order to match - -- addon metadata information - ["Action Bars"] = "Interface", - ["Auction"] = "Information", - ["Audio"] = "Interface", - ["Battlegrounds/PvP"] = "Information", - ["Buffs"] = "Information", - ["Chat/Communication"] = "Interface", - ["Druid"] = "Information", - ["Hunter"] = "Information", - ["Mage"] = "Information", - ["Paladin"] = "Information", - ["Priest"] = "Information", - ["Rogue"] = "Information", - ["Shaman"] = "Information", - ["Warlock"] = "Information", - ["Warrior"] = "Information", - ["Healer"] = "Information", - ["Tank"] = "Information", - ["Caster"] = "Information", - -- ["Combat"] = "Combat", - ["Compilations"] = "General", - ["Data Export"] = "General", - ["Development Tools "] = "General", - ["Guild"] = "Information", - ["Frame Modification"] = "Interface", - ["Interface Enhancements"] = "Interface", - ["Inventory"] = "Information", - ["Library"] = "General", - ["Map"] = "Interface", - ["Mail"] = "Information", - ["Miscellaneous"] = "General", - ["Misc"] = "General", - ["Quest"] = "Information", - ["Raid"] = "Information", - ["Tradeskill"] = "Profession", - ["UnitFrame"] = "Interface", -} -local LAUNCHER = "launcher" -local DATA_SOURCE = "data source" -local SupportedDOTypes = { DATA_SOURCE, LAUNCHER } -- in the 1.1 spec --- "macro" : this was attempted but Blizzard locked most macro to 'user click only'. --- By adding a Titan template to any secure button, WoW thinks it could be a bot and errors. - --- constants & variables -local CALLBACK_PREFIX = "LibDataBroker_AttributeChanged_" -local _G = getfenv(0); -local InCombatLockdown = _G.InCombatLockdown; --- Create control frame so we can get events -local LDBToTitan = CreateFrame("Frame", "LDBTitan") -local ldb = LibStub:GetLibrary("LibDataBroker-1.1") -local LibQTip = nil -local media = LibStub("LibSharedMedia-3.0") --- generic icon in case the DO does not provide one -local iconTitanDefault = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon"; - --- Events we want for LDBToTitan -LDBToTitan:RegisterEvent("PLAYER_LOGIN") ---LDBToTitan:RegisterEvent("PLAYER_ENTERING_WORLD") - ----local OK to show tooltip? ----@return boolean -local function If_Show_Tooltip() - local use_mod = TitanAllGetVar("UseTooltipModifer") - local use_alt = TitanAllGetVar("TooltipModiferAlt") - local use_ctrl = TitanAllGetVar("TooltipModiferCtrl") - local use_shift = TitanAllGetVar("TooltipModiferShift") - local ok = false - local tmp_txt = "" - if use_mod then - if (use_alt and IsAltKeyDown()) - or (use_ctrl and IsControlKeyDown()) - or (use_shift and IsShiftKeyDown()) - then - ok = true - end - else - ok = true - end - return ok -end - ----Titan Properly anchor tooltips of the Titan (LDB) plugin ----@param parent table Parent frame ----@param anchorPoint string ----@param relativeToFrame table|string ----@param relativePoint string ----@param xOffset number ----@param yOffset number ----@param frame table|string Tooltip frame ---- relativeToFrame and frame are really ScriptRegion|string for GameTooltip -function LDBToTitan:TitanLDBSetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame) - if frame:GetName() == "GameTooltip" then - -- Changes for 9.1.5 Removed the background template from the GameTooltip - -- Making changes to it difficult and possibly changing the tooltip globally. - - frame:SetOwner(parent, "ANCHOR_NONE"); - - -- set font size for the Game Tooltip - if not TitanPanelGetVar("DisableTooltipFont") then - if TitanTooltipScaleSet < 1 then - TitanTooltipOrigScale = GameTooltip:GetScale(); - TitanTooltipScaleSet = TitanTooltipScaleSet + 1; - end - frame:SetScale(TitanPanelGetVar("TooltipFont")); - end - end - frame:ClearAllPoints(); - frame:SetPoint(anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset); -end - ----Titan Fill in the tooltip for the Titan (LDB) plugin ----@param name string Plugin id name for LDB ----@param frame table Tooltip frame ----@param tt_func function? Tooltip function to be run -function LDBToTitan:TitanLDBSetTooltip(name, frame, tt_func) - -- Check to see if we allow tooltips to be shown - if not TitanPanelGetVar("ToolTipsShown") - or (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then - return - end - - local button = TitanUtils_GetButton(name); - local scale = TitanPanelGetVar("Scale"); - local offscreenX, offscreenY; - local i = TitanPanel_GetButtonNumber(name); - local bar = TITAN_PANEL_DISPLAY_PREFIX .. TitanUtils_GetWhichBar(name) - local vert = TitanBarData[bar].vert - -- Get TOP or BOTTOM for the anchor and relative anchor - local rel_pt, pt - if vert == TITAN_TOP then - pt = "TOP" - rel_pt = "BOTTOM" - else - pt = "BOTTOM" - rel_pt = "TOP" - end - - if _G[bar] and button then - self:TitanLDBSetOwnerPosition(button, pt .. "LEFT", button:GetName(), - rel_pt .. "LEFT", -10, 0, frame); -- y 4 * scale - -- Adjust frame position if it's off the screen - offscreenX, offscreenY = TitanUtils_GetOffscreen(frame); - if (offscreenX == -1) then - self:TitanLDBSetOwnerPosition(button, pt .. "LEFT", bar, - rel_pt .. "LEFT", 0, 0, frame); - elseif (offscreenX == 1) then - self:TitanLDBSetOwnerPosition(button, pt .. "RIGHT", bar, - rel_pt .. "RIGHT", 0, 0, frame); - end - else - end - - if tt_func and If_Show_Tooltip() then tt_func(frame) end; -- TODO: use pcall?? - frame:Show(); -end - ----Titan Script Handler for the Titan (LDB) plugin ---- This implementation will work fine for a static tooltip but may have implications for dynamic ones so for now, ---- we'll only set it once (no callback) and see what happens ----@param event string Event name ----@param name string Plugin id name for LDB ----@param _ any not used ----@param func function LDB data object ----@param obj table LDB data object -function LDBToTitan:TitanLDBHandleScripts(event, name, _, func, obj) - local TitanPluginframe = _G["TitanPanel" .. name .. "Button"]; - - -- tooltip - if event:find("tooltip") and not event:find("OnTooltipShow") then - local pluginframe = _G[obj.tooltip] or obj.tooltip - if pluginframe then - TitanPluginframe:SetScript("OnEnter", function(self) - TitanPanelButton_OnEnter(self); - LDBToTitan:TitanLDBSetTooltip(name, pluginframe, nil) - end - ) - - TitanPluginframe:SetScript("OnMouseDown", function(self) - pluginframe:Hide(); - end - ) - - if pluginframe:GetScript("OnLeave") then - -- do nothing - else - TitanPluginframe:SetScript("OnLeave", function(self) - if obj.OnLeave then - obj.OnLeave(self) - end - pluginframe:Hide(); - TitanPanelButton_OnLeave(self); - end - ) - end - - if pluginframe:GetName() ~= "GameTooltip" then - if pluginframe:GetScript("OnShow") then - -- do nothing - else - pluginframe:SetScript("OnShow", function(self) - LDBToTitan:TitanLDBSetTooltip(name, pluginframe, nil) - end - ) - end - end - end - - -- OnTooltipShow - elseif event:find("OnTooltipShow") then - TitanPluginframe:SetScript("OnEnter", function(self) - if TITAN_PANEL_MOVING == 0 and func then - LDBToTitan:TitanLDBSetTooltip(name, GameTooltip, func); - end - TitanPanelButton_OnEnter(self); - end - ) - TitanPluginframe:SetScript("OnLeave", function(self) - GameTooltip:Hide(); - TitanPanelButton_OnLeave(self); - end - ) - - -- OnDoubleClick - elseif event:find("OnDoubleClick") and not event:find("OnClick") then - TitanPluginframe:SetScript("OnDoubleClick", function(self, button) - if TITAN_PANEL_MOVING == 0 then - func(self, button) - end - end - ) - - -- OnClick - elseif event:find("OnClick") then - TitanPluginframe:SetScript("OnClick", function(self, button) - if TITAN_PANEL_MOVING == 0 then - func(self, button) - end - -- implement a safeguard, since the DO may actually use - -- Blizzy dropdowns ! - if not TitanPanelRightClickMenu_IsVisible() then - TitanPanelButton_OnClick(self, button); - else - TitanUtils_CloseAllControlFrames(); - end - end - ) - -- OnEnter - else - TitanPluginframe:SetScript("OnEnter", function(self) - -- Check for tooltip libs without embedding them - - -- Dropped Ace Tablet-2.0 lib as of 2025 Sep; last updated 2008 Sep - LibQTip = LibStub("LibQTip-1.0", true) - -- Check to see if we allow tooltips to be shown - if not TitanPanelGetVar("ToolTipsShown") - or (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then - -- if a plugin is using tablet, then detach and close the tooltip - return; - else - -- if a plugin is using tablet, then re-attach the tooltip - -- (it will auto-open on mouseover) - end - - -- set original tooltip scale for GameTooltip - if not TitanPanelGetVar("DisableTooltipFont") then - TitanTooltipOrigScale = GameTooltip:GetScale(); - end - -- call OnEnter on LDB Object - if TITAN_PANEL_MOVING == 0 and func and If_Show_Tooltip() then - func(self) - end - - TitanPanelButton_OnEnter(self); - -- LibQTip-1.0 support code - if LibQTip then - local tt = nil - local key, tip - for key, tip in LibQTip:IterateTooltips() do - if tip then - local _, relativeTo = tip:GetPoint() - if relativeTo - and relativeTo:GetName() == TitanPluginframe:GetName() then - tt = tip - break - end - end - end - if tt then - -- set transparency - local red, green, blue, _ = tt:GetBackdropColor() - local red2, green2, blue2, _ = tt:GetBackdropBorderColor() - tt:SetBackdropColor(red, green, blue, - TitanPanelGetVar("TooltipTrans")) - tt:SetBackdropBorderColor(red2, green2, blue2, - TitanPanelGetVar("TooltipTrans")) - end - end - -- /LibQTip-1.0 support code - end - ) - - -- OnLeave - TitanPluginframe:SetScript("OnLeave", function(self) - if obj.OnLeave then - obj.OnLeave(self) - end - TitanPanelButton_OnLeave(self); - end - ) - end -end - ----Titan Text callback for the Titan (LDB) plugin when the LDB addon changes display text of the LDB object ----@param _ any not used ----@param name string Plugin id name for LDB ----@param attr string "value" or "suffix" or "text" or "label" ----@param value any Should be string ----@param dataobj table LDB data object -function LDBToTitan:TitanLDBTextUpdate(_, name, attr, value, dataobj) - -- just in case the LDB is active before Titan can register it... - if not Titan__InitializedPEW then - -- plugins have not been registered yet. - return - end - -- This check is overkill but just in case... - local plugin = TitanUtils_GetPlugin(name) - local ldb = plugin and plugin.LDBVariables - if not ldb then - -- This plugin has not been registered - return - end - - -- Accept the various display elements and update the Titan plugin - if attr == "value" then ldb.value = value end - if attr == "suffix" then ldb.suffix = value end - if attr == "text" then ldb.text = value end - if attr == "label" then ldb.label = value end - - -- Now update the button with the change - TitanPanelButton_UpdateButton(name) -end - ----Titan Text callback when the LDB addon changes display text ----@param name string Plugin id name for LDB ----@return string label ----@return string value -function TitanLDBShowText(name) - -- Set 'label1' and 'value1' for the Titan button display - local nametrim = string.gsub(name, "LDBT_", ""); - local fontstring = _G[TitanUtils_ButtonName(nametrim) .. TITAN_PANEL_TEXT]; - local separator = ": " - local lab1, val1 = "", "" - local plugin = TitanUtils_GetPlugin(name) - local ldb = plugin and plugin.LDBVariables - - if ldb then -- sanity check - -- Check for display label - if TitanGetVar(name, "ShowLabelText") then - lab1 = (ldb.label or "") - else - lab1 = "" - end - - if lab1 == "" then - -- leave alone - else - lab1 = lab1 .. separator - end - - -- Check for display text - -- Check for display text - -- .text is required to show - -- .value is the text of the value - 100.0 in 100.0 FPS - -- .suffix is the text after the value - FPS in 100.0 FPS - if TitanGetVar(name, "ShowRegularText") then - val1 = (ldb.text or "") - else - val1 = "" - end - else - -- return values will be empty strings - end - - if lab1 == "" then - -- just empty - else - lab1 = TitanUtils_GetNormalText(lab1) - end - if val1 == "" then - -- just empty - else - val1 = TitanGetVar(name, "ShowColoredText") - and TitanUtils_GetGreenText(val1) or TitanUtils_GetHighlightText(val1) - end - return lab1, val1 -end - ----Titan Icon callback for the Titan (LDB) plugin when the LDB addon changes the icon of the LDB object ----@param _ any not used ----@param name string Plugin id name for LDB ----@param attr string "icon" or "iconCoords" or "iconR" "iconB" "iconR" ----@param value any icon : Path to icon file; iconCoords : coords ----@param dataobj table LDB data object -function LDBToTitan:TitanLDBIconUpdate(_, name, attr, value, dataobj) - -- just in case the LDB is active before Titan can register it... - if not Titan__InitializedPEW then - -- no plugins are registered yet - return - end - -- This check is overkill but just in case... - local plugin = TitanUtils_GetPlugin(name) - local ldb = plugin and plugin.LDBVariables - if ldb then - if attr == "icon" then - TitanPlugins[name].icon = value; - TitanPanelButton_SetButtonIcon(name); - end - - -- support for iconCoords, iconR, iconG, iconB attributes - if attr == "iconCoords" then - TitanPanelButton_SetButtonIcon(name, value); - end - - if attr == "iconR" or attr == "iconB" or attr == "iconG" then - TitanPanelButton_SetButtonIcon(name, nil, - dataobj.iconR, dataobj.iconG, dataobj.iconB); - end - else - -- This plugin is not registered yet - return - end -end - ----Titan Refresh all text & icon for LDB addons that were successfully registered ---- Ensure all the LDB buttons are updated. ---- This is called once x seconds after PEW. This helps close the gap where LDB addons set their text on their PEW event -function TitanLDBRefreshButton() - -- TitanDebug("LDB: RefreshButton") - for name, obj in ldb:DataObjectIterator() do - if obj then - local unused = nil - LDBToTitan:TitanLDBTextUpdate(unused, name, "text", (obj.text or ""), obj) - LDBToTitan:TitanLDBIconUpdate(unused, name, "icon", (obj.icon or iconTitanDefault), obj) - else - -- TitanDebug("LDB: '"..name.."' no refresh") - end - end -end - ----Titan Create a Titan plugin from the DO (Data Object) ---- This is the heart of the LDB to Titan. It reads the LDB DO (Data Object) and creates a Titan plugin. ---- This takes a stricter interpretation of the LDB 1.1 spec rather than guessing what LDB addon developers intended. ----@param self table LDB frame ----@param name_str string LDB id name ----@param obj table LDB data object -function TitanLDBCreateObject(self, name_str, obj) - local name = name_str - Titan_Debug.Out('titan', 'ldb_setup', tostring(name) .. " : Attempting to register "); - - -- couple sanity checks - -- if not obj or not name then - if name and type(name) == 'string' then - -- The name should be reasonable - else - local issue = "LDB request name " - .. " '" .. tostring(name) .. "'" - .. " unrecognizable !!!!" - Titan_Debug.Out('titan', 'ldb_setup', issue); - error(issue) -- get out - end - if obj and type(obj) == 'table' then - -- The LDB obj should be reasonable - else - local object = "" - if obj then - object = "is not a table" - else - object = "does not exist" - end - local issue = "LDB request object for " - .. " '" .. tostring(name) .. "'" - .. " " .. tostring(object) .. "" - .. " !!!!" - Titan_Debug.Out('titan', 'ldb_setup', issue); - error(issue) -- get out - end - - -- anything to pass to the developer / user - local notes = "" - - -- sanity check for supported types - obj.type = obj.type or "Unknown" - local supported = false -- assume failure - for idx in ipairs(SupportedDOTypes) do - if obj.type and obj.type == SupportedDOTypes[idx] then - supported = true - end - end - if supported then - -- all is good - continue plugin creation - else - -- Create enough of a plugin to tell the user / developer - -- that this plugin failed miserably - local issue = "Unsupported LDB type '" .. tostring(obj.type) .. "'" - Titan_Debug.Out('titan', 'ldb_setup', TITAN_REGISTER_FAILED .. " " .. issue); - error(issue) - -- return TITAN_REGISTER_FAILED -- get out, there is nothing more that can be done - end - - -- - -- Handle the display attributes of the DO and register the appropriate callbacks - -- - -- Init the display elements of the plugin - local ldb__label = obj.label or "" - local ldb__suffix = obj.suffix or "" - local ldb__value = obj.value or "" - local ldb__text = obj.text or "" - local ldb__icon = obj.icon or iconTitanDefault - - -- if .icon exists honor it and assume the addon may change it - if obj.icon then - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_icon", "TitanLDBIconUpdate") - end - - -- LAUNCHER text display elements - if obj.type == LAUNCHER then - if obj.label then - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_label", "TitanLDBTextUpdate") - elseif obj.text then - -- This is a 'be nice' check. It technically violates the 1.1 spec. - -- Blank the .text so the rest of the routines work - ldb__label = obj.text - obj.text = "" - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_text", "TitanLDBTextUpdate") - notes = notes .. "\n" - .. "This is a LDB '" .. LAUNCHER - .. "' without .label using .text instead!!!!" - end - end - if Titan__InitializedPEW then - notes = notes .. "\n" - .. "Will be registered as single LDB plugin after the normal registration." - end - -- DATA_SOURCE text display elements - if obj.type == DATA_SOURCE then - -- .text so always allow it - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_text", "TitanLDBTextUpdate") - if obj.label then - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_label", "TitanLDBTextUpdate") - end - if obj.suffix then - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_suffix", "TitanLDBTextUpdate") - end - if obj.value then - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_value", "TitanLDBTextUpdate") - end - end - - -- - -- These are icon extensions listed within the 1.1 spec - -- - -- support for iconCoords, iconR, iconG, iconB attributes - -- Due to the callbacks being fired these can easily affect - -- performance, BEWARE when using them ! - -- - -- capture the icon coords & color for the Titan plugin - if obj.iconCoords then - self:TitanLDBIconUpdate(nil, name, "iconCoords", obj.iconCoords, obj) - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_iconCoords", "TitanLDBIconUpdate") - end - if obj.iconR and obj.iconG and obj.iconB then - self:TitanLDBIconUpdate(nil, name, "iconR", obj.iconR, obj) - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_iconR", "TitanLDBIconUpdate") - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_iconG", "TitanLDBIconUpdate") - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_iconB", "TitanLDBIconUpdate") - end - - -- - -- Setup the Titan plugin for this LDB addon - -- - - -- Create the appropriate Titan registry for the DO - local registry = { - id = name, - ldb = tostring(obj.type), - -- per 1.1 spec if .label exists use it else use data object's name - menuText = obj.label or name, - buttonTextFunction = "TitanLDBShowText", - icon = ldb__icon, - iconWidth = 16, - controlVariables = { - ShowIcon = true, - ShowLabelText = true, - ShowRegularText = false, - ShowColoredText = false, - DisplayOnRightSide = true - }, - savedVariables = { - ShowIcon = true, - ShowLabelText = true, - ShowRegularText = true, - ShowColoredText = false, - DisplayOnRightSide = false - }, - LDBVariables = { - value = ldb__value, - suffix = ldb__suffix, - text = ldb__text, - label = ldb__label, - name = name, - type = (obj.type or ""), - }, - notes = notes, - iconCoords = (obj.iconCoords or nil), - iconR = (obj.iconR or nil), - iconB = (obj.iconB or nil), - iconG = (obj.iconG or nil), - }; - - Titan_Debug.Out('titan', 'ldb_setup', "" - .. " type: '" .. tostring(registry.ldb) .. "' " - ) - - -- Set the plugin category, if it exists, else default to "General" - -- Per the 1.1 LDB spec we check for a tocname attrib first, - -- if found we use it, if not we assume that the DO "name" - -- attribute is the same as the actual - -- addon name, which might not always be the case. - -- Titan defaults again to "General" if no categoy is found - -- via a check in the menu implementation, later on. - local addoncategory, addonversion; - local tempname = obj.tocname or name; - - -- This was a sanity check but does not allow for multiple - -- LDB to be within an addon yet act as their own addon. - -- if IsAddOnLoaded(tempname) then - addoncategory = TitanUtils_GetAddOnMetadata(tempname, "X-Category"); - registry.category = (addoncategory and xcategories[addoncategory]) - or (obj.category) - or "General" - addonversion = TitanUtils_GetAddOnMetadata(tempname, "Version") - or (obj.version) - or "" - registry["version"] = addonversion; - registry["notes"] = (TitanUtils_GetAddOnMetadata(tempname, "Notes") or "") .. "\n" - -- end - - -- Depending on the LDB type set the control and saved Variables appropriately - if obj.type == LAUNCHER then - -- controls - -- one interpretation of the LDB spec is launchers - -- should always have an icon. - registry["controlVariables"].ShowIcon = true; - registry["controlVariables"].ShowRegularText = false; -- no text - -- defaults - registry["savedVariables"].ShowRegularText = false; - registry["savedVariables"].DisplayOnRightSide = true; -- start on right side - end - - if obj.type == DATA_SOURCE then - -- controls - registry["controlVariables"].ShowRegularText = true; - -- defaults - registry["savedVariables"].ShowRegularText = true; - end - - -- - -- Create the Titan frame for this LDB addon - -- Titan _OnLoad will be used to request the plugin be registered by Titan (Template) - local newTitanFrame -- a frame - --[===[ - if obj.type == "macro" then -- custom - newTitanFrame = CreateFrame("Button", - TitanUtils_ButtonName(name), - UIParent, "SecureActionButtonTemplate, TitanPanelComboTemplate") --- UIParent, "TitanPanelComboTemplate") - newTitanFrame:RegisterForClicks("AnyUp", "AnyDown") - newTitanFrame:SetMouseClickEnabled(true) - newTitanFrame:SetAttribute("type", "macro") --- newTitanFrame:SetAttribute("macro", obj.commandtext) - newTitanFrame:SetAttribute("macrotext", obj.commandtext) - newTitanFrame:SetScript("OnClick", function(self, button, down) - SecureUnitButton_OnClick(self, button, down) - --TitanPanelBarButton_OnClick(self, button) - end) - else - newTitanFrame = CreateFrame("Button", - TitanUtils_ButtonName(name), - UIParent, "TitanPanelComboTemplate") - end ---]===] - newTitanFrame = CreateFrame("Button", - TitanUtils_ButtonName(name), - UIParent, "TitanPanelComboTemplate") - - newTitanFrame.TitanCreatedBy = "LDB" - -- newTitanFrame.TitanType = "macro" - newTitanFrame.TitanName = (name or "?") - newTitanFrame.TitanAction = (obj.commandtext or "None") - - newTitanFrame.registry = registry - newTitanFrame:SetFrameStrata("FULLSCREEN"); - newTitanFrame:SetToplevel(true); - newTitanFrame:RegisterForClicks("LeftButtonUp", "RightButtonUp"); - - -- Use the routines given by the DO in this precedence - -- tooltip > OnEnter > OnTooltipShow > - -- or register a callback in case it is created later. Per the 1.1 LDB spec - if obj.tooltip then - self:TitanLDBHandleScripts("tooltip", name, nil, obj.tooltip, obj) - elseif obj.OnEnter then - self:TitanLDBHandleScripts("OnEnter", name, nil, obj.OnEnter, obj) - elseif obj.OnTooltipShow then - self:TitanLDBHandleScripts("OnTooltipShow", name, nil, obj.OnTooltipShow, obj) - else - self:TitanLDBHandleScripts("OnEnter", name, nil, nil, obj) - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_OnEnter", "TitanLDBHandleScripts") - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_OnTooltipShow", "TitanLDBHandleScripts") - end - - -- Use the OnClick given by the DO - -- or register a callback in case it is created later. - if obj.OnClick then - self:TitanLDBHandleScripts("OnClick", name, nil, obj.OnClick) - else - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_OnClick", "TitanLDBHandleScripts") - end - - -- - -- OnDoubleClick is UNDOCUMENTED in the 1.1 spec - -- but was implemented by the original developer - -- - -- Use the OnDoubleClick given by the DO - -- or register a callback in case it is created later. - if obj.OnDoubleClick then - self:TitanLDBHandleScripts("OnDoubleClick", name, nil, obj.OnDoubleClick) - else - ldb.RegisterCallback(self, - CALLBACK_PREFIX .. name .. "_OnDoubleClick", "TitanLDBHandleScripts") - end - - local pew = "event" - if Titan__InitializedPEW then - pew = "post event" - -- Plugins have already been registered and loaded - -- Get this one loaded - -- This works because the .registry is now set - TitanUtils_RegisterPluginList() - TitanVariables_SyncSinglePluginSettings(registry.id) - TitanPanel_InitPanelButtons() -- Show it... - end - Titan_Debug.Out('titan', 'ldb_setup', "LDB create" - .. " " .. tostring(pew) .. "" - .. " '" .. tostring(registry.id) .. "'" - .. " '" .. tostring(registry.ldb) .. "'" - .. "\n...'" .. tostring(newTitanFrame:GetName()) .. "'" - ) - return "Success" -end - ----Titan OnEvent handler for LDBToTitan ---- Read through all the LDB objects requesting creation so far. Try to create cooresponding Titan plugins. ----@param sender any !! Not Used !! ----@param name string LDB id name ----@param obj table LDB data object -function LDBToTitan:TitanLDBCreateObject(sender, name, obj) - local call_success = true - local ret_val = "" - - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(TitanLDBCreateObject, self, name, obj) - - if call_success then - -- Registration request created - else - -- Create enough of a plugin to tell the user / developer - -- that this plugin failed - local plugin = - { - self = nil, - button = nil, - name = tostring(name), - issue = ret_val, - notes = "", - status = TITAN_REGISTER_FAILED, - category = "", - plugin_type = tostring(obj.type or "LDB"), - } - TitanUtils_PluginFail(plugin) - end - - Titan_Debug.Out('titan', 'ldb_setup', "LDB Create:" - -- .." "..tostring(sender).."" - .. " " .. tostring(name) .. "" - .. " " .. tostring(call_success) .. "" - .. " " .. tostring(ret_val) .. "" - ) -end - ---- OnEvent - PLAYER_LOGIN - handler for LDBToTitan ----@param self table Plugin frame ----@param event string Event name ----@param ... any Event args -LDBToTitan:SetScript("OnEvent", function(self, event, ...) - if (event == "PLAYER_LOGIN") then - self:UnregisterEvent("PLAYER_LOGIN") - -- Register the LDB plugins that have been created so far - for name, obj in ldb:DataObjectIterator() do - local call_success = true - local ret_val = "" - - -- Just in case, catch any errors - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(TitanLDBCreateObject, self, name, obj) - - if call_success then - -- Registration request created - else - -- Create enough of a plugin to tell the user / developer - -- that this plugin failed - local plugin = - { - self = nil, - button = nil, - name = tostring(name), - issue = ret_val, - notes = "", - status = TITAN_REGISTER_FAILED, - category = "", - plugin_type = tostring(obj.type or "LDB"), - } - TitanUtils_PluginFail(plugin) - end - - Titan_Debug.Out('titan', 'ldb_setup', "LDB" - .. " " .. tostring(name) .. "" - .. " " .. tostring(call_success) .. "" - .. " " .. tostring(ret_val) .. "" - ) - end - - -- In case a LDB plugin is created later... - ldb.RegisterCallback(self, - "LibDataBroker_DataObjectCreated", "TitanLDBCreateObject") - end -end -) +--[===[ File +A "bridge" module to ensure proper registration and communication of LDB plugins with Titan Panel +--]===] + +--[===[ +Originally by Tristanian aka "TristTitan" as a Titan member +Created and initially commited on : July 29th, 2008 +--]===] + +--[===[ Var Titan LDB overview +The spec: https://github.com/tekkub/libdatabroker-1-1 +LDB (libdatabroker) is a small library that enables an addon to hook into a 'display' addon such as Titan. + +--- Creation +The addon dev creates an LDB object which the lib places in storage accessible by lib:DataObjectIterator(). +It also fires a "LibDataBroker_DataObjectCreated" callback. + +LDB objects work by callbacks. +When an LDB addon changes one of its values, the lib fires a callback for the display addon. + +The LDB addon may declare scripts (tooltip, mouse clicks, etc.) per the spec for the display addon to use. + +--- Starting from Titan view +On PLAYER_ENTERING_WORLD, Titan will use the iterator to wrap each LDB type addon into a Titan plugin. +Once done processing the known LDB objects, +Titan registers for the callback to handle LDB objects created later or on demand. + +Titan registers for callbacks on text and icon updates - depending on the LDB type. + +--- Running from Titan view +The LDB addon is responsible for setting and changing its text and icon. +Titan is responsible for updating the Titan plugin in response. + +The Titan plugin will use the LDB addon scripts IF declared, again depending on the LDB type. + + +--- Supported +Only LDB types listed in the LDB 1.1 spec are supported by Titan. + +- "launcher" become "icon" plugins - TitanPanelIconTemplate + icon* - always shown + OnClick* - + label^ - + right side^ - default + tooltip +- "data source" become "combo" plugins - TitanPanelComboTemplate + icon^ - + OnClick - + text*^ - or value & suffix + label^ - + OnEnter - + OnLeave - + tooltip + OnTooltipShow - + +* required by LDB spec +^ Titan user controlled show / hide + +--]===] + +local xcategories = { + -- Titan categories mapping to match addon metadata information + ["Combat"] = "Combat", + ["General"] = "General", + ["Information"] = "Information", + ["Interface"] = "Interface", + ["Profession"] = "Profession", + -- Ace2 table mapping to Titan categories in order to match + -- addon metadata information + ["Action Bars"] = "Interface", + ["Auction"] = "Information", + ["Audio"] = "Interface", + ["Battlegrounds/PvP"] = "Information", + ["Buffs"] = "Information", + ["Chat/Communication"] = "Interface", + ["Druid"] = "Information", + ["Hunter"] = "Information", + ["Mage"] = "Information", + ["Paladin"] = "Information", + ["Priest"] = "Information", + ["Rogue"] = "Information", + ["Shaman"] = "Information", + ["Warlock"] = "Information", + ["Warrior"] = "Information", + ["Healer"] = "Information", + ["Tank"] = "Information", + ["Caster"] = "Information", + -- ["Combat"] = "Combat", + ["Compilations"] = "General", + ["Data Export"] = "General", + ["Development Tools "] = "General", + ["Guild"] = "Information", + ["Frame Modification"] = "Interface", + ["Interface Enhancements"] = "Interface", + ["Inventory"] = "Information", + ["Library"] = "General", + ["Map"] = "Interface", + ["Mail"] = "Information", + ["Miscellaneous"] = "General", + ["Misc"] = "General", + ["Quest"] = "Information", + ["Raid"] = "Information", + ["Tradeskill"] = "Profession", + ["UnitFrame"] = "Interface", +} +local LAUNCHER = "launcher" +local DATA_SOURCE = "data source" +local SupportedDOTypes = { DATA_SOURCE, LAUNCHER } -- in the 1.1 spec +-- "macro" : this was attempted but Blizzard locked most macro to 'user click only'. +-- By adding a Titan template to any secure button, WoW thinks it could be a bot and errors. + +-- constants & variables +local CALLBACK_PREFIX = "LibDataBroker_AttributeChanged_" +local _G = getfenv(0); +local InCombatLockdown = _G.InCombatLockdown; +-- Create control frame so we can get events +local LDBToTitan = CreateFrame("Frame", "LDBTitan") +local ldb = LibStub:GetLibrary("LibDataBroker-1.1") +local LibQTip = nil +local media = LibStub("LibSharedMedia-3.0") +-- generic icon in case the DO does not provide one +local iconTitanDefault = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon"; + +-- Events we want for LDBToTitan +LDBToTitan:RegisterEvent("PLAYER_LOGIN") +--LDBToTitan:RegisterEvent("PLAYER_ENTERING_WORLD") + +---local OK to show tooltip? +---@return boolean +local function If_Show_Tooltip() + local use_mod = TitanAllGetVar("UseTooltipModifer") + local use_alt = TitanAllGetVar("TooltipModiferAlt") + local use_ctrl = TitanAllGetVar("TooltipModiferCtrl") + local use_shift = TitanAllGetVar("TooltipModiferShift") + local ok = false + local tmp_txt = "" + if use_mod then + if (use_alt and IsAltKeyDown()) + or (use_ctrl and IsControlKeyDown()) + or (use_shift and IsShiftKeyDown()) + then + ok = true + end + else + ok = true + end + return ok +end + +---Titan Properly anchor tooltips of the Titan (LDB) plugin +---@param parent table Parent frame +---@param anchorPoint string +---@param relativeToFrame table|string +---@param relativePoint string +---@param xOffset number +---@param yOffset number +---@param frame table|string Tooltip frame +--- relativeToFrame and frame are really ScriptRegion|string for GameTooltip +function LDBToTitan:TitanLDBSetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame) + if frame:GetName() == "GameTooltip" then + -- Changes for 9.1.5 Removed the background template from the GameTooltip + -- Making changes to it difficult and possibly changing the tooltip globally. + + frame:SetOwner(parent, "ANCHOR_NONE"); + + -- set font size for the Game Tooltip + if not TitanPanelGetVar("DisableTooltipFont") then + if TitanTooltipScaleSet < 1 then + TitanTooltipOrigScale = GameTooltip:GetScale(); + TitanTooltipScaleSet = TitanTooltipScaleSet + 1; + end + frame:SetScale(TitanPanelGetVar("TooltipFont")); + end + end + frame:ClearAllPoints(); + frame:SetPoint(anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset); +end + +---Titan Fill in the tooltip for the Titan (LDB) plugin +---@param name string Plugin id name for LDB +---@param frame table Tooltip frame +---@param tt_func function? Tooltip function to be run +function LDBToTitan:TitanLDBSetTooltip(name, frame, tt_func) + -- Check to see if we allow tooltips to be shown + if not TitanPanelGetVar("ToolTipsShown") + or (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then + return + end + + local button = TitanUtils_GetButton(name); + local scale = TitanPanelGetVar("Scale"); + local offscreenX, offscreenY; + local i = TitanPanel_GetButtonNumber(name); + local bar = TITAN_PANEL_DISPLAY_PREFIX .. TitanUtils_GetWhichBar(name) + local vert = TitanBarData[bar].vert + -- Get TOP or BOTTOM for the anchor and relative anchor + local rel_pt, pt + if vert == TITAN_TOP then + pt = "TOP" + rel_pt = "BOTTOM" + else + pt = "BOTTOM" + rel_pt = "TOP" + end + + if _G[bar] and button then + self:TitanLDBSetOwnerPosition(button, pt .. "LEFT", button:GetName(), + rel_pt .. "LEFT", -10, 0, frame); -- y 4 * scale + -- Adjust frame position if it's off the screen + offscreenX, offscreenY = TitanUtils_GetOffscreen(frame); + if (offscreenX == -1) then + self:TitanLDBSetOwnerPosition(button, pt .. "LEFT", bar, + rel_pt .. "LEFT", 0, 0, frame); + elseif (offscreenX == 1) then + self:TitanLDBSetOwnerPosition(button, pt .. "RIGHT", bar, + rel_pt .. "RIGHT", 0, 0, frame); + end + else + end + + if tt_func and If_Show_Tooltip() then tt_func(frame) end; -- TODO: use pcall?? + frame:Show(); +end + +---Titan Script Handler for the Titan (LDB) plugin +--- This implementation will work fine for a static tooltip but may have implications for dynamic ones so for now, +--- we'll only set it once (no callback) and see what happens +---@param event string Event name +---@param name string Plugin id name for LDB +---@param _ any not used +---@param func function LDB data object +---@param obj table LDB data object +function LDBToTitan:TitanLDBHandleScripts(event, name, _, func, obj) + local TitanPluginframe = _G["TitanPanel" .. name .. "Button"]; + + -- tooltip + if event:find("tooltip") and not event:find("OnTooltipShow") then + local pluginframe = _G[obj.tooltip] or obj.tooltip + if pluginframe then + TitanPluginframe:SetScript("OnEnter", function(self) + TitanPanelButton_OnEnter(self); + LDBToTitan:TitanLDBSetTooltip(name, pluginframe, nil) + end + ) + + TitanPluginframe:SetScript("OnMouseDown", function(self) + pluginframe:Hide(); + end + ) + + if pluginframe:GetScript("OnLeave") then + -- do nothing + else + TitanPluginframe:SetScript("OnLeave", function(self) + if obj.OnLeave then + obj.OnLeave(self) + end + pluginframe:Hide(); + TitanPanelButton_OnLeave(self); + end + ) + end + + if pluginframe:GetName() ~= "GameTooltip" then + if pluginframe:GetScript("OnShow") then + -- do nothing + else + pluginframe:SetScript("OnShow", function(self) + LDBToTitan:TitanLDBSetTooltip(name, pluginframe, nil) + end + ) + end + end + end + + -- OnTooltipShow + elseif event:find("OnTooltipShow") then + TitanPluginframe:SetScript("OnEnter", function(self) + if TITAN_PANEL_MOVING == 0 and func then + LDBToTitan:TitanLDBSetTooltip(name, GameTooltip, func); + end + TitanPanelButton_OnEnter(self); + end + ) + TitanPluginframe:SetScript("OnLeave", function(self) + GameTooltip:Hide(); + TitanPanelButton_OnLeave(self); + end + ) + + -- OnDoubleClick + elseif event:find("OnDoubleClick") and not event:find("OnClick") then + TitanPluginframe:SetScript("OnDoubleClick", function(self, button) + if TITAN_PANEL_MOVING == 0 then + func(self, button) + end + end + ) + + -- OnClick + elseif event:find("OnClick") then + TitanPluginframe:SetScript("OnClick", function(self, button) + if TITAN_PANEL_MOVING == 0 then + func(self, button) + end + -- implement a safeguard, since the DO may actually use + -- Blizzy dropdowns ! + if not TitanPanelRightClickMenu_IsVisible() then + TitanPanelButton_OnClick(self, button); + else + TitanUtils_CloseAllControlFrames(); + end + end + ) + -- OnEnter + else + TitanPluginframe:SetScript("OnEnter", function(self) + -- Check for tooltip libs without embedding them + + -- Dropped Ace Tablet-2.0 lib as of 2025 Sep; last updated 2008 Sep + LibQTip = LibStub("LibQTip-1.0", true) + -- Check to see if we allow tooltips to be shown + if not TitanPanelGetVar("ToolTipsShown") + or (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then + -- if a plugin is using tablet, then detach and close the tooltip + return; + else + -- if a plugin is using tablet, then re-attach the tooltip + -- (it will auto-open on mouseover) + end + + -- set original tooltip scale for GameTooltip + if not TitanPanelGetVar("DisableTooltipFont") then + TitanTooltipOrigScale = GameTooltip:GetScale(); + end + -- call OnEnter on LDB Object + if TITAN_PANEL_MOVING == 0 and func and If_Show_Tooltip() then + func(self) + end + + TitanPanelButton_OnEnter(self); + -- LibQTip-1.0 support code + if LibQTip then + local tt = nil + local key, tip + for key, tip in LibQTip:IterateTooltips() do + if tip then + local _, relativeTo = tip:GetPoint() + if relativeTo + and relativeTo:GetName() == TitanPluginframe:GetName() then + tt = tip + break + end + end + end + if tt then + -- set transparency + local red, green, blue, _ = tt:GetBackdropColor() + local red2, green2, blue2, _ = tt:GetBackdropBorderColor() + tt:SetBackdropColor(red, green, blue, + TitanPanelGetVar("TooltipTrans")) + tt:SetBackdropBorderColor(red2, green2, blue2, + TitanPanelGetVar("TooltipTrans")) + end + end + -- /LibQTip-1.0 support code + end + ) + + -- OnLeave + TitanPluginframe:SetScript("OnLeave", function(self) + if obj.OnLeave then + obj.OnLeave(self) + end + TitanPanelButton_OnLeave(self); + end + ) + end +end + +---Titan Text callback for the Titan (LDB) plugin when the LDB addon changes display text of the LDB object +---@param _ any not used +---@param name string Plugin id name for LDB +---@param attr string "value" or "suffix" or "text" or "label" +---@param value any Should be string +---@param dataobj table LDB data object +function LDBToTitan:TitanLDBTextUpdate(_, name, attr, value, dataobj) + -- just in case the LDB is active before Titan can register it... + if not Titan__InitializedPEW then + -- plugins have not been registered yet. + return + end + -- This check is overkill but just in case... + local plugin = TitanUtils_GetPlugin(name) + local ldb = plugin and plugin.LDBVariables + if not ldb then + -- This plugin has not been registered + return + end + + -- Accept the various display elements and update the Titan plugin + if attr == "value" then ldb.value = value end + if attr == "suffix" then ldb.suffix = value end + if attr == "text" then ldb.text = value end + if attr == "label" then ldb.label = value end + + -- Now update the button with the change + TitanPanelButton_UpdateButton(name) +end + +---Titan Text callback when the LDB addon changes display text +---@param name string Plugin id name for LDB +---@return string label +---@return string value +function TitanLDBShowText(name) + -- Set 'label1' and 'value1' for the Titan button display + local nametrim = string.gsub(name, "LDBT_", ""); + local fontstring = _G[TitanUtils_ButtonName(nametrim) .. TITAN_PANEL_TEXT]; + local separator = ": " + local lab1, val1 = "", "" + local plugin = TitanUtils_GetPlugin(name) + local ldb = plugin and plugin.LDBVariables + + if ldb then -- sanity check + -- Check for display label + if TitanGetVar(name, "ShowLabelText") then + lab1 = (ldb.label or "") + else + lab1 = "" + end + + if lab1 == "" then + -- leave alone + else + lab1 = lab1 .. separator + end + + -- Check for display text + -- Check for display text + -- .text is required to show + -- .value is the text of the value - 100.0 in 100.0 FPS + -- .suffix is the text after the value - FPS in 100.0 FPS + if TitanGetVar(name, "ShowRegularText") then + val1 = (ldb.text or "") + else + val1 = "" + end + else + -- return values will be empty strings + end + + if lab1 == "" then + -- just empty + else + lab1 = TitanUtils_GetNormalText(lab1) + end + if val1 == "" then + -- just empty + else + val1 = TitanGetVar(name, "ShowColoredText") + and TitanUtils_GetGreenText(val1) or TitanUtils_GetHighlightText(val1) + end + return lab1, val1 +end + +---Titan Icon callback for the Titan (LDB) plugin when the LDB addon changes the icon of the LDB object +---@param _ any not used +---@param name string Plugin id name for LDB +---@param attr string "icon" or "iconCoords" or "iconR" "iconB" "iconR" +---@param value any icon : Path to icon file; iconCoords : coords +---@param dataobj table LDB data object +function LDBToTitan:TitanLDBIconUpdate(_, name, attr, value, dataobj) + -- just in case the LDB is active before Titan can register it... + if not Titan__InitializedPEW then + -- no plugins are registered yet + return + end + -- This check is overkill but just in case... + local plugin = TitanUtils_GetPlugin(name) + local ldb = plugin and plugin.LDBVariables + if ldb then + if attr == "icon" then + TitanPlugins[name].icon = value; + TitanPanelButton_SetButtonIcon(name); + end + + -- support for iconCoords, iconR, iconG, iconB attributes + if attr == "iconCoords" then + TitanPanelButton_SetButtonIcon(name, value); + end + + if attr == "iconR" or attr == "iconB" or attr == "iconG" then + TitanPanelButton_SetButtonIcon(name, nil, + dataobj.iconR, dataobj.iconG, dataobj.iconB); + end + else + -- This plugin is not registered yet + return + end +end + +---Titan Refresh all text & icon for LDB addons that were successfully registered +--- Ensure all the LDB buttons are updated. +--- This is called once x seconds after PEW. This helps close the gap where LDB addons set their text on their PEW event +function TitanLDBRefreshButton() + -- TitanDebug("LDB: RefreshButton") + for name, obj in ldb:DataObjectIterator() do + if obj then + local unused = nil + LDBToTitan:TitanLDBTextUpdate(unused, name, "text", (obj.text or ""), obj) + LDBToTitan:TitanLDBIconUpdate(unused, name, "icon", (obj.icon or iconTitanDefault), obj) + else + -- TitanDebug("LDB: '"..name.."' no refresh") + end + end +end + +---Titan Create a Titan plugin from the DO (Data Object) +--- This is the heart of the LDB to Titan. It reads the LDB DO (Data Object) and creates a Titan plugin. +--- This takes a stricter interpretation of the LDB 1.1 spec rather than guessing what LDB addon developers intended. +---@param self table LDB frame +---@param name_str string LDB id name +---@param obj table LDB data object +function TitanLDBCreateObject(self, name_str, obj) + local name = name_str + Titan_Debug.Out('titan', 'ldb_setup', tostring(name) .. " : Attempting to register "); + + -- couple sanity checks + -- if not obj or not name then + if name and type(name) == 'string' then + -- The name should be reasonable + else + local issue = "LDB request name " + .. " '" .. tostring(name) .. "'" + .. " unrecognizable !!!!" + Titan_Debug.Out('titan', 'ldb_setup', issue); + error(issue) -- get out + end + if obj and type(obj) == 'table' then + -- The LDB obj should be reasonable + else + local object = "" + if obj then + object = "is not a table" + else + object = "does not exist" + end + local issue = "LDB request object for " + .. " '" .. tostring(name) .. "'" + .. " " .. tostring(object) .. "" + .. " !!!!" + Titan_Debug.Out('titan', 'ldb_setup', issue); + error(issue) -- get out + end + + -- anything to pass to the developer / user + local notes = "" + + -- sanity check for supported types + obj.type = obj.type or "Unknown" + local supported = false -- assume failure + for idx in ipairs(SupportedDOTypes) do + if obj.type and obj.type == SupportedDOTypes[idx] then + supported = true + end + end + if supported then + -- all is good - continue plugin creation + else + -- Create enough of a plugin to tell the user / developer + -- that this plugin failed miserably + local issue = "Unsupported LDB type '" .. tostring(obj.type) .. "'" + Titan_Debug.Out('titan', 'ldb_setup', TITAN_REGISTER_FAILED .. " " .. issue); + error(issue) + -- return TITAN_REGISTER_FAILED -- get out, there is nothing more that can be done + end + + -- + -- Handle the display attributes of the DO and register the appropriate callbacks + -- + -- Init the display elements of the plugin + local ldb__label = obj.label or "" + local ldb__suffix = obj.suffix or "" + local ldb__value = obj.value or "" + local ldb__text = obj.text or "" + local ldb__icon = obj.icon or iconTitanDefault + + -- if .icon exists honor it and assume the addon may change it + if obj.icon then + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_icon", "TitanLDBIconUpdate") + end + + -- LAUNCHER text display elements + if obj.type == LAUNCHER then + if obj.label then + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_label", "TitanLDBTextUpdate") + elseif obj.text then + -- This is a 'be nice' check. It technically violates the 1.1 spec. + -- Blank the .text so the rest of the routines work + ldb__label = obj.text + obj.text = "" + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_text", "TitanLDBTextUpdate") + notes = notes .. "\n" + .. "This is a LDB '" .. LAUNCHER + .. "' without .label using .text instead!!!!" + end + end + if Titan__InitializedPEW then + notes = notes .. "\n" + .. "Will be registered as single LDB plugin after the normal registration." + end + -- DATA_SOURCE text display elements + if obj.type == DATA_SOURCE then + -- .text so always allow it + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_text", "TitanLDBTextUpdate") + if obj.label then + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_label", "TitanLDBTextUpdate") + end + if obj.suffix then + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_suffix", "TitanLDBTextUpdate") + end + if obj.value then + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_value", "TitanLDBTextUpdate") + end + end + + -- + -- These are icon extensions listed within the 1.1 spec + -- + -- support for iconCoords, iconR, iconG, iconB attributes + -- Due to the callbacks being fired these can easily affect + -- performance, BEWARE when using them ! + -- + -- capture the icon coords & color for the Titan plugin + if obj.iconCoords then + self:TitanLDBIconUpdate(nil, name, "iconCoords", obj.iconCoords, obj) + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_iconCoords", "TitanLDBIconUpdate") + end + if obj.iconR and obj.iconG and obj.iconB then + self:TitanLDBIconUpdate(nil, name, "iconR", obj.iconR, obj) + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_iconR", "TitanLDBIconUpdate") + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_iconG", "TitanLDBIconUpdate") + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_iconB", "TitanLDBIconUpdate") + end + + -- + -- Setup the Titan plugin for this LDB addon + -- + + -- Create the appropriate Titan registry for the DO + local registry = { + id = name, + ldb = tostring(obj.type), + -- per 1.1 spec if .label exists use it else use data object's name + menuText = obj.label or name, + buttonTextFunction = "TitanLDBShowText", + icon = ldb__icon, + iconWidth = 16, + controlVariables = { + ShowIcon = true, + ShowLabelText = true, + ShowRegularText = false, + ShowColoredText = false, + DisplayOnRightSide = true + }, + savedVariables = { + ShowIcon = true, + ShowLabelText = true, + ShowRegularText = true, + ShowColoredText = false, + DisplayOnRightSide = false + }, + LDBVariables = { + value = ldb__value, + suffix = ldb__suffix, + text = ldb__text, + label = ldb__label, + name = name, + type = (obj.type or ""), + }, + notes = notes, + iconCoords = (obj.iconCoords or nil), + iconR = (obj.iconR or nil), + iconB = (obj.iconB or nil), + iconG = (obj.iconG or nil), + }; + + Titan_Debug.Out('titan', 'ldb_setup', "" + .. " type: '" .. tostring(registry.ldb) .. "' " + ) + + -- Set the plugin category, if it exists, else default to "General" + -- Per the 1.1 LDB spec we check for a tocname attrib first, + -- if found we use it, if not we assume that the DO "name" + -- attribute is the same as the actual + -- addon name, which might not always be the case. + -- Titan defaults again to "General" if no categoy is found + -- via a check in the menu implementation, later on. + local addoncategory, addonversion; + local tempname = obj.tocname or name; + + -- This was a sanity check but does not allow for multiple + -- LDB to be within an addon yet act as their own addon. + -- if IsAddOnLoaded(tempname) then + addoncategory = TitanUtils_GetAddOnMetadata(tempname, "X-Category"); + registry.category = (addoncategory and xcategories[addoncategory]) + or (obj.category) + or "General" + addonversion = TitanUtils_GetAddOnMetadata(tempname, "Version") + or (obj.version) + or "" + registry["version"] = addonversion; + registry["notes"] = (TitanUtils_GetAddOnMetadata(tempname, "Notes") or "") .. "\n" + -- end + + -- Depending on the LDB type set the control and saved Variables appropriately + if obj.type == LAUNCHER then + -- controls + -- one interpretation of the LDB spec is launchers + -- should always have an icon. + registry["controlVariables"].ShowIcon = true; + registry["controlVariables"].ShowRegularText = false; -- no text + -- defaults + registry["savedVariables"].ShowRegularText = false; + registry["savedVariables"].DisplayOnRightSide = true; -- start on right side + end + + if obj.type == DATA_SOURCE then + -- controls + registry["controlVariables"].ShowRegularText = true; + -- defaults + registry["savedVariables"].ShowRegularText = true; + end + + -- + -- Create the Titan frame for this LDB addon + -- Titan _OnLoad will be used to request the plugin be registered by Titan (Template) + local newTitanFrame -- a frame + --[===[ + if obj.type == "macro" then -- custom + newTitanFrame = CreateFrame("Button", + TitanUtils_ButtonName(name), + UIParent, "SecureActionButtonTemplate, TitanPanelComboTemplate") +-- UIParent, "TitanPanelComboTemplate") + newTitanFrame:RegisterForClicks("AnyUp", "AnyDown") + newTitanFrame:SetMouseClickEnabled(true) + newTitanFrame:SetAttribute("type", "macro") +-- newTitanFrame:SetAttribute("macro", obj.commandtext) + newTitanFrame:SetAttribute("macrotext", obj.commandtext) + newTitanFrame:SetScript("OnClick", function(self, button, down) + SecureUnitButton_OnClick(self, button, down) + --TitanPanelBarButton_OnClick(self, button) + end) + else + newTitanFrame = CreateFrame("Button", + TitanUtils_ButtonName(name), + UIParent, "TitanPanelComboTemplate") + end +--]===] + newTitanFrame = CreateFrame("Button", + TitanUtils_ButtonName(name), + UIParent, "TitanPanelComboTemplate") + + newTitanFrame.TitanCreatedBy = "LDB" + -- newTitanFrame.TitanType = "macro" + newTitanFrame.TitanName = (name or "?") + newTitanFrame.TitanAction = (obj.commandtext or "None") + + newTitanFrame.registry = registry + newTitanFrame:SetFrameStrata("FULLSCREEN"); + newTitanFrame:SetToplevel(true); + newTitanFrame:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + + -- Use the routines given by the DO in this precedence + -- tooltip > OnEnter > OnTooltipShow > + -- or register a callback in case it is created later. Per the 1.1 LDB spec + if obj.tooltip then + self:TitanLDBHandleScripts("tooltip", name, nil, obj.tooltip, obj) + elseif obj.OnEnter then + self:TitanLDBHandleScripts("OnEnter", name, nil, obj.OnEnter, obj) + elseif obj.OnTooltipShow then + self:TitanLDBHandleScripts("OnTooltipShow", name, nil, obj.OnTooltipShow, obj) + else + self:TitanLDBHandleScripts("OnEnter", name, nil, nil, obj) + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_OnEnter", "TitanLDBHandleScripts") + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_OnTooltipShow", "TitanLDBHandleScripts") + end + + -- Use the OnClick given by the DO + -- or register a callback in case it is created later. + if obj.OnClick then + self:TitanLDBHandleScripts("OnClick", name, nil, obj.OnClick) + else + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_OnClick", "TitanLDBHandleScripts") + end + + -- + -- OnDoubleClick is UNDOCUMENTED in the 1.1 spec + -- but was implemented by the original developer + -- + -- Use the OnDoubleClick given by the DO + -- or register a callback in case it is created later. + if obj.OnDoubleClick then + self:TitanLDBHandleScripts("OnDoubleClick", name, nil, obj.OnDoubleClick) + else + ldb.RegisterCallback(self, + CALLBACK_PREFIX .. name .. "_OnDoubleClick", "TitanLDBHandleScripts") + end + + local pew = "event" + if Titan__InitializedPEW then + pew = "post event" + -- Plugins have already been registered and loaded + -- Get this one loaded + -- This works because the .registry is now set + TitanUtils_RegisterPluginList() + TitanVariables_SyncSinglePluginSettings(registry.id) + TitanPanel_InitPanelButtons() -- Show it... + end + Titan_Debug.Out('titan', 'ldb_setup', "LDB create" + .. " " .. tostring(pew) .. "" + .. " '" .. tostring(registry.id) .. "'" + .. " '" .. tostring(registry.ldb) .. "'" + .. "\n...'" .. tostring(newTitanFrame:GetName()) .. "'" + ) + return "Success" +end + +---Titan OnEvent handler for LDBToTitan +--- Read through all the LDB objects requesting creation so far. Try to create cooresponding Titan plugins. +---@param sender any !! Not Used !! +---@param name string LDB id name +---@param obj table LDB data object +function LDBToTitan:TitanLDBCreateObject(sender, name, obj) + local call_success = true + local ret_val = "" + + call_success, -- needed for pcall + ret_val = -- actual return values + pcall(TitanLDBCreateObject, self, name, obj) + + if call_success then + -- Registration request created + else + -- Create enough of a plugin to tell the user / developer + -- that this plugin failed + local plugin = + { + self = nil, + button = nil, + name = tostring(name), + issue = ret_val, + notes = "", + status = TITAN_REGISTER_FAILED, + category = "", + plugin_type = tostring(obj.type or "LDB"), + } + TitanUtils_PluginFail(plugin) + end + + Titan_Debug.Out('titan', 'ldb_setup', "LDB Create:" + -- .." "..tostring(sender).."" + .. " " .. tostring(name) .. "" + .. " " .. tostring(call_success) .. "" + .. " " .. tostring(ret_val) .. "" + ) +end + +--- OnEvent - PLAYER_LOGIN - handler for LDBToTitan +---@param self table Plugin frame +---@param event string Event name +---@param ... any Event args +LDBToTitan:SetScript("OnEvent", function(self, event, ...) + if (event == "PLAYER_LOGIN") then + self:UnregisterEvent("PLAYER_LOGIN") + -- Register the LDB plugins that have been created so far + for name, obj in ldb:DataObjectIterator() do + local call_success = true + local ret_val = "" + + -- Just in case, catch any errors + call_success, -- needed for pcall + ret_val = -- actual return values + pcall(TitanLDBCreateObject, self, name, obj) + + if call_success then + -- Registration request created + else + -- Create enough of a plugin to tell the user / developer + -- that this plugin failed + local plugin = + { + self = nil, + button = nil, + name = tostring(name), + issue = ret_val, + notes = "", + status = TITAN_REGISTER_FAILED, + category = "", + plugin_type = tostring(obj.type or "LDB"), + } + TitanUtils_PluginFail(plugin) + end + + Titan_Debug.Out('titan', 'ldb_setup', "LDB" + .. " " .. tostring(name) .. "" + .. " " .. tostring(call_success) .. "" + .. " " .. tostring(ret_val) .. "" + ) + end + + -- In case a LDB plugin is created later... + ldb.RegisterCallback(self, + "LibDataBroker_DataObjectCreated", "TitanLDBCreateObject") + end +end +) diff --git a/Titan/TitanMovable.lua b/Titan/TitanMovable.lua index 55037ea..629fe7a 100755 --- a/Titan/TitanMovable.lua +++ b/Titan/TitanMovable.lua @@ -1,13 +1,11 @@ ---@diagnostic disable: param-type-mismatch --[===[ File -Titan adjusts some WoW frames based on the WoW version! -Mainly used when user can NOT edit / move most UI frames. - +Titan adjusts some WoW frames prior to DragonFlight. DragonFlight introduced an Edit Mode for the user to move various frames where they want them. Titan no longer needs to do this work for most frames. There are a small number of frames that WoW does not have in Edit mode. These will be added to the table over time as users request. -The scheme has changed to be more like 'move any/thing' which hooks the SetPoint of the frame. +The scheme has changed to be more like 'move anything' which hooks the SetPoint of the frame. Titan still only allows vertical adjust - not move anywhere. --]===] -- Globals diff --git a/Titan/TitanTemplate.lua b/Titan/TitanTemplate.lua index 582a694..078dcb0 100644 --- a/Titan/TitanTemplate.lua +++ b/Titan/TitanTemplate.lua @@ -1,1190 +1,1201 @@ ---[===[ File -Creates the following frames: -- TitanPanelBarButton : Main Titan frame handling events -- TitanPanelTooltip : Used? Inherits from GameTooltipTemplate - -Contains the routines to control a Titan template frame. -These could be: -- A Titan bar (full or short) -- A Titan plugin (built-in, thrid party, or LDB) - -The Titan templates are defined in .xml. -There appears to be no other way to make frame templates - virtual="true". ---]===] - ---[===[ Var API TitanPanelTemplate overview -See TitanPanelButtonTemplate.xml also for more detail. - -TitanTemplate (Lua and XML) contain the basics for Titan plugin frames. -Titan templates contain elements used by Titan. - -A Titan plugin is a frame created using one of the button types in TitanPanelButtonTemplate.xml. -The available plugin types are: -- TitanPanelTextTemplate - * A frame that only displays text ("$parentText") -- TitanPanelIconTemplate - * A frame that only displays an icon ("$parentIcon") -- TitanPanelComboTemplate - * A frame that displays an icon then text ("$parentIcon" "$parentText") -- TitanOptionsSliderTemplate - A frame that contains the basics for a vertical slider control. See TitanVolume for an example. - -* Templates inherit TitanPanelButtonTemplate for common elements. - -Most plugins use the combo template. - -TitanPanelButtonTemplate contains: -- a frame to handle a menu invoked by a right mouse click ("$parentRightClickMenu") -- default event handlers for - <OnLoad> - TitanPanelButton_OnLoad(self); - </OnLoad> - <OnShow> - TitanPanelButton_OnShow(self); - </OnShow> - <OnClick> - TitanPanelButton_OnClick(self, button); - </OnClick> - <OnEnter> - TitanPanelButton_OnEnter(self); - </OnEnter> - <OnLeave> - TitanPanelButton_OnLeave(self); - </OnLeave> -If these events are overridden then the default routine needs to be included! - - -NOTE: TitanPanelChildButtonTemplate - Removed 2024 Jun ---]===] - --- Globals - --- Constants -local TITAN_PANEL_LABEL_SEPARATOR = " " -local TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE = 10; -local TITAN_PANEL_BUTTON_TYPE_TEXT = 1; -local TITAN_PANEL_BUTTON_TYPE_ICON = 2; -local TITAN_PANEL_BUTTON_TYPE_COMBO = 3; -local TITAN_PANEL_BUTTON_TYPE_CUSTOM = 4; -local pluginOnEnter = nil; - --- Used for drag and drop, assuming one can only drag one plugin :) -local TITAN_PANEL_MOVE_ADDON = ""; -local TITAN_PANEL_DROPOFF_ADDON = ""; -local Drag_init = {} -local drag = Drag_init -local FROM_BAR_SHORT = "" -local FROM_BAR_FRAME = "" - --- Library instances -local LibQTip = nil -local _G = getfenv(0); -local InCombatLockdown = _G.InCombatLockdown -local media = LibStub("LibSharedMedia-3.0") - ---[[ -print("B text" -.." "..tostring(id).."" -.." "..tostring(type(bFunction)).."" -.." '"..tostring(bFunction).."'" -.." '"..tostring(buttonTextFunction).."'" -) ---]] ---========================== - ---[[ local -NAME: TitanPanel_SetScale -DESC: Set the scale of each plugin and each Titan bar. -VAR: None -OUT: None ---]] -function TitanPanel_SetScale() - local scale = TitanPanelGetVar("Scale"); - - -- Set all the Titan bars - for idx, v in pairs(TitanBarData) do - _G[idx]:SetScale(scale) - end - -- Set all the registered plugins - for index, value in pairs(TitanPlugins) do - if index then - TitanUtils_GetButton(index):SetScale(scale); - end - end -end - ----local Helper to add a line of tooltip text to the tooltip. ----@param text string To add ----@param frame table Tooltip frame ---- Append a "\n" to the end if there is not one already there -local function TitanTooltip_AddTooltipText(text, frame) - if (text) then - -- Append a "\n" to the end - if (string.sub(text, -1, -1) ~= "\n") then - text = text .. "\n"; - end - - -- See if the string is intended for a double column - for text1, text2 in string.gmatch(text, "([^\t\n]*)\t?([^\t\n]*)\n") do - if (text2 ~= "") then - -- Add as double wide - frame:AddDoubleLine(text1, text2); - elseif (text1 ~= "") then - -- Add single column line - frame:AddLine(text1); - else - -- Assume a blank line - frame:AddLine("\n"); - end - end - else - -- No text to display - end -end - ----local Helper to set both the parent and the position of GameTooltip for the plugin tooltip. ----@param parent table Reference to the frame to attach the tooltip to ----@param anchorPoint string Tooltip anchor location (side or corner) to use ----@param relativeToFrame string name name of the frame, usually the plugin), to attach the tooltip to ----@param relativePoint string Parent anchor location (side or corner) to use ----@param xOffset number X offset ----@param yOffset number Y offset ----@param frame table Tooltip frame ---- Set Titan_Debug.titan.tool_tips to output debug -local function TitanTooltip_SetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame) - -- Changes for 9.1.5 Removed the background template from the GameTooltip - -- Making changes to it difficult and possibly changing the tooltip globally. - - frame:SetOwner(parent, "ANCHOR_NONE"); - frame:SetPoint(anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset); - - -- set font size for the Game Tooltip - if TitanPanelGetVar("DisableTooltipFont") then - -- use UI scale - else - if TitanTooltipScaleSet < 1 then - TitanTooltipOrigScale = frame:GetScale(); - TitanTooltipScaleSet = TitanTooltipScaleSet + 1; - end - frame:SetScale(TitanPanelGetVar("TooltipFont")); - end - - local dbg_msg = "_pos" - .. " '" .. tostring(frame:GetName()) .. "'" - .. " " .. tostring(frame:IsShown()) .. "" - .. " @ '" .. tostring(relativeToFrame) .. "'" - .. " " .. tostring(_G[relativeToFrame]:IsShown()) .. "" - Titan_Debug.Out('titan', 'tool_tips', dbg_msg) - dbg_msg = ">>_pos" - .. " " .. tostring(anchorPoint) .. "" - .. " " .. tostring(relativePoint) .. "" - .. " w" .. tostring(format("%0.1f", frame:GetWidth())) .. "" - .. " h" .. tostring(format("%0.1f", frame:GetHeight())) .. "" - Titan_Debug.Out('titan', 'tool_tips', dbg_msg) -end - ----local Helper to set the screen position of the tooltip frame ----@param self table Tooltip frame ----@param id string Plugin id name ----@param frame table Tooltip frame - expected to be GameTooltip -local function TitanTooltip_SetPanelTooltip(self, id, frame) - local button = TitanUtils_GetButton(id) - - if button then - -- Adjust the Y offset as needed - local rel_y = self:GetTop() - frame:GetHeight() - local pt = "" - local rel_pt = "" - if rel_y > 0 then - pt = "TOP"; - rel_pt = "BOTTOM"; - else - -- too close to bottom of screen - pt = "BOTTOM"; - rel_pt = "TOP"; - end - local rel_x = self:GetLeft() + frame:GetHeight() - if (rel_x < GetScreenWidth()) then - -- menu will fit - pt = pt .. "LEFT"; - rel_pt = rel_pt .. "LEFT"; - else - pt = pt .. "RIGHT"; - rel_pt = rel_pt .. "RIGHT"; - end - - TitanTooltip_SetOwnerPosition(button, pt, button:GetName(), rel_pt, 0, 0, frame) - end -end - ----local Set the tooltip (GameTooltip) of the given Titan plugin. ----@param self table Plugin frame ---- Set Titan_Debug.titan.tool_tips to output debug of this routine -local function TitanPanelButton_SetTooltip(self) - local dbg_msg = "TT:" - local ok = false - local frame = GameTooltip - local id = self.registry.id - - -- ensure that the 'self' passed is a valid frame reference - if self:GetName() then - dbg_msg = dbg_msg .. "'" .. self:GetName() .. "'" - -- sanity checks - if (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then - dbg_msg = dbg_msg .. " HideTipsInCombat" - else - if TitanPanelGetVar("ToolTipsShown") then - ok = true - else - dbg_msg = dbg_msg .. " ToolTipsShown false" - end - end - else - dbg_msg = dbg_msg .. " No frame" - -- Cannot even start - end - - if ok then - local call_success = nil - local tmp_txt = "" - local use_mod = TitanAllGetVar("UseTooltipModifer") - local use_alt = TitanAllGetVar("TooltipModiferAlt") - local use_ctrl = TitanAllGetVar("TooltipModiferCtrl") - local use_shift = TitanAllGetVar("TooltipModiferShift") - - if use_mod then - if (use_alt and IsAltKeyDown()) - or (use_ctrl and IsControlKeyDown()) - or (use_shift and IsShiftKeyDown()) - then - ok = true - end - else - ok = true - end - - self.tooltipCustomFunction = nil; - self.titan_tt_func = "" - self.titan_tt_err = "" - - if ok and (id and TitanUtils_IsPluginRegistered(id)) then - local plugin = TitanUtils_GetPlugin(id) - -- 2024 Jun Add id and frame name to 'pass' to tooltip routine. - -- A compromise given that this mechanism is used by nearly all plugins. - -- Used by Titan auto hide to better determine which bar the 'pin' / icon is on. - self.plugin_id = id - self.plugin_frame = TitanUtils_ButtonName(id) - if (plugin and plugin.tooltipCustomFunction) then - -- Hide the GameTooltip while being updated, to avoid race conditions. - frame:Hide() - -- Prep the tooltip frame - TitanTooltip_SetPanelTooltip(self, id, frame); - - -- Fill the tooltip - self.tooltipCustomFunction = plugin.tooltipCustomFunction; - dbg_msg = dbg_msg .. " | custom" - call_success, -- for pcall - tmp_txt = pcall(self.tooltipCustomFunction, self) - if call_success then - -- all is good - dbg_msg = dbg_msg .. " | ok" - else - dbg_msg = dbg_msg .. " | Err: " .. tmp_txt - end - - frame:Show(); -- now show it - elseif (plugin and plugin.tooltipTitle) then - local tooltipTextFunc = {} ---@type function - local tt_func = plugin.tooltipTextFunction - - if type(tt_func) == 'string' then - -- Function MUST be in global namespace - tooltipTextFunc = _G[tt_func] - dbg_msg = dbg_msg .. " | string" - elseif type(tt_func) == 'function' then - -- Can be global or local to the plugin - tooltipTextFunc = tt_func - dbg_msg = dbg_msg .. " | function" - else - -- silently leave... - dbg_msg = dbg_msg .. " | none found" - end - - if (tooltipTextFunc) then - -- Hide the GameTooltip while being updated, to avoid race conditions. - frame:Hide() - -- Prep the tooltip frame - TitanTooltip_SetPanelTooltip(self, id, frame); - self.tooltipTitle = plugin.tooltipTitle; - call_success, -- for pcall - tmp_txt = pcall(tooltipTextFunc, self) - - -- Fill the tooltip - self.tooltipText = tmp_txt - frame:SetText(self.tooltipTitle, - HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); - if (self.tooltipText) then - TitanTooltip_AddTooltipText(self.tooltipText, frame) - dbg_msg = dbg_msg .. " | ok" - else - dbg_msg = dbg_msg .. " | No text" - end - - frame:Show() -- now show it - end - else - -- no recognized method to create tooltip - dbg_msg = "No recognized tooltip method [.tooltipCustomFunction then .tooltipTitle /.tooltipText]" - end - end - else - -- no need to waste cycles - end - - Titan_Debug.Out('titan', 'tool_tips', dbg_msg) -end - ----local Is the given Titan plugin template type text? ----@param id string Plugin id name ----@return boolean IsText -local function TitanPanelButton_IsText(id) - if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_TEXT) then - return true - else - return false - end -end - ----local Is the given Titan plugin of type combo? ----@param id string Plugin id name ----@return boolean IsCombo -local function TitanPanelButton_IsCombo(id) - if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_COMBO) then - return true - else - return false - end -end - ----Titan Is the given Titan plugin of type icon? ----@param id string Plugin id name ----@return boolean is_icon -function TitanPanelButton_IsIcon(id) - local res = false - if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_ICON) then - res = true - else - res = false - end - - return res -end - ----local Handle the OnDragStart event of the given Titan plugin. ----@param self table Plugin frame ---- Do nothing if the user has locked plugins or if in combat. ---- Set the .isMoving of the plugin (frame) so other routine can check it. ---- Set TITAN_PANEL_MOVING so any Titan routine will know a 'drag & drop' is in progress. ---- Set TITAN_PANEL_MOVE_ADDON so sanity checks can be done on the 'drop'. -local function TitanPanelButton_OnDragStart(self) - -- Due to API change in 11.2.0, :ClearAllPoints immediately invalidates the rect... - -- Need to change order of events between drag start and stop: - -- - Remove but not Hide() the plugin - seems Hide() triggers OnDragStop without release of mouse button... - -- - Make ALL 'do not drag' checks BEFORE remove!! - -- - -- Dropped Ace Dewdrop-2.0 lib support as of 2025 Sep; last updated 2008 Sep - -- Dropped Ace Tablet-2.0 lib support as of 2025 Sep; last updated 2009 Jan (marked as abandoned) - - if TitanPanelGetVar("LockButtons") or InCombatLockdown() then - return -- not requested or not allowed - else - -- Proceed - end - - local frname = self - local frstr = self:GetName() - local plugin_id = TitanUtils_GetButtonID(frstr) - local str = "" - str = "_OnDragStart start " - .." "..tostring(plugin_id).."" --- .." from "..tostring(FROM_BAR_SHORT).."" - Titan_Debug.Out('titan', 'plugin_drag_drop', str) - - - -- Tell Titan that a drag & drop is in process - TITAN_PANEL_MOVING = 1; - -- Start the drag - frname:StartMoving(); - frname.isMoving = true; - - -- Close any tooltips and control frames - TitanUtils_CloseAllControlFrames(); - TitanPanelRightClickMenu_Close(); - GameTooltip:Hide(); - - -- LibQTip-1.0 support code - LibQTip = LibStub("LibQTip-1.0", true) - if LibQTip then - for key, tip in LibQTip:IterateTooltips() do - if tip then - local _, relativeTo = tip:GetPoint() - if relativeTo and relativeTo:GetName() == frstr then - tip:Hide() - break - end - end - end - end - -- /LibQTip-1.0 support code - - FROM_BAR_SHORT = TitanUtils_GetWhichBar(plugin_id) -- short name - str = "_OnDragStart moving" - .." "..tostring(plugin_id).."" - .." from "..tostring(FROM_BAR_SHORT).."" - Titan_Debug.Out('titan', 'plugin_drag_drop', str) - -- Clear the plugin placement so we only move the intended plugin - TitanPanel_RemoveButton(plugin_id, false) - frname:Show() -- 'remove' hid the plugin - - -- Hold the plugin id so we can do checks on the drop - TITAN_PANEL_MOVE_ADDON = plugin_id - - -- Store the OnEnter handler so the tooltip does not show - or other oddities - pluginOnEnter = self:GetScript("OnEnter") - self:SetScript("OnEnter", nil) -end - ----local Handle the OnDragStop event of the given Titan plugin. ----@param self table Plugin frame ---- Clear the .isMoving of the plugin (frame). ---- Clear TITAN_PANEL_MOVING. ---- Clear TITAN_PANEL_MOVE_ADDON. -local function TitanPanelButton_OnDragStop(self) - -- The plugin is under the cursor so we MUST place the plugin somewhere! - -- We cannot just return. - -- Also means we can no longer swap plugins. - -- For now, we will drop the plugin on the bar under the cursor; - -- placing the plugin 'right' if set for that plugin - - local frname = self - local frstr = self:GetName() - local plugin_id = TitanUtils_GetButtonID(frstr) - - local str = "" - str = "_OnDragStop start " - .." "..tostring(plugin_id).."" - Titan_Debug.Out('titan', 'plugin_drag_drop', str) - - if TITAN_PANEL_MOVING == 1 then - frname:StopMovingOrSizing(); - frname.isMoving = false; - TITAN_PANEL_MOVING = 0; - - local bar - local tbar = "" -- bar short name - local fbar = TitanGetVar(plugin_id, "ForceBar") - - str = "_OnDragStop " - .." "..tostring(plugin_id).."" - if fbar == nil - or fbar == false then - -- Find which bar it was dropped on - for idx, v in pairs(TitanBarData) do - bar = idx - if (bar and MouseIsOver(_G[bar])) then - tbar = TitanBarData[bar].name - end - end - if tbar == "" then - -- not sure what the user did... - -- Likely released on UI so put back on the bar it came from - str = str .." back to" - tbar = FROM_BAR_SHORT - else - str = str .." onto" - end - else - str = str .." force to" - tbar = fbar -- put it back; allows user to shift it - end - - str = str .." "..tostring(tbar).."" - Titan_Debug.Out('titan', 'plugin_drag_drop', str) - TitanUtils_AddButtonOnBar(tbar, TITAN_PANEL_MOVE_ADDON) - - -- The plugin was added a bar so clean up. - TITAN_PANEL_MOVE_ADDON = ""; - if pluginOnEnter then - -- Restore the OnEnter script handler - self:SetScript("OnEnter", pluginOnEnter) - else - -- No OnEnter was found at drag start - end - pluginOnEnter = nil; - - end -end - ----API Set the color of the tooltip text to normal (white) with the value in green. ----@param text string Label to show ----@param value any Value to show; something tostring() can handle ----@return string str Formatted text and value ---- self.tooltipText = TitanOptionSlider_TooltipText("Addons", TitanGetVar(TITAN_PERFORMANCE_ID, "NumOfAddons")); -function TitanOptionSlider_TooltipText(text, value) - return tostring(text) .. " " .. GREEN_FONT_COLOR_CODE .. tostring(value) .. FONT_COLOR_CODE_CLOSE; -end - ----API Handle the OnLoad event of the requested Titan plugin. Ensure the plugin is set to be registered. ----@param self table Plugin frame ---- This is called from the Titan plugin frame in the OnLoad event - usually as the frame is created in the Titan template. -function TitanPanelButton_OnLoad(self) - -- Used by plugins - --[[ ---- This is called from the Titan plugin frame in the OnLoad event - usually as the frame is created in the Titan template. ---- This starts the plugin registration process. See TitanUtils for more details on plugin registration. ---- The plugin registration is a two step process because not all addons create Titan plugins in the frame create. ---- The Titan feature of converting LDB addons to Titan plugins is an example. ---- If the plugin needs an OnLoad process it should call this routine after its own. I.E. ---- TitanPanelLootTypeButton_OnLoad(self) ---- TitanPanelButton_OnLoad(self) ---]] - TitanUtils_PluginToRegister(self) -end - ----API Handle the OnShow event of the requested Titan plugin. ----@param self table Plugin frame -function TitanPanelButton_OnShow(self) - local id = nil; - -- ensure that the 'self' passed is a valid frame reference - if self and self:GetName() then - id = TitanUtils_GetButtonID(self:GetName()); - end - -- ensure that id is a valid Titan plugin - if (id) then - TitanPanelButton_UpdateButton(id, 1); - end -end - ----API Handle the OnClick mouse event of the requested Titan plugin. ----@param self table Plugin frame ----@param button string Mouse button clicked ---- Only the left and right mouse buttons are handled by Titan. ---- Called from Titan templates unless overriden by plugin. If overridden the plugin should call this routine. -function TitanPanelButton_OnClick(self, button) - local id - -- ensure that the 'self' passed is a valid frame reference - if self and self:GetName() then - id = TitanUtils_GetButtonID(self:GetName()) - end - - if id then - local controlFrame = TitanUtils_GetControlFrame(id); - - if controlFrame and (button == "LeftButton") then - local isControlFrameShown; - if (not controlFrame) then - isControlFrameShown = false; - elseif (controlFrame:IsVisible()) then - isControlFrameShown = false; - else - isControlFrameShown = true; - end - - TitanUtils_CloseAllControlFrames(); - TitanPanelRightClickMenu_Close(); - - -- local position = TitanUtils_GetWhichBar(id) - if (isControlFrameShown) then - -- Note: This uses anchor points to place the control frame relative to the plugin on the screen. - local parent = self:GetName() -- plugin with the control frame - local point = "" -- point of the control frame - local rel_point = "" -- The middle - top or bottom edge - of the plugin to anchor to - --[[ Mar 2023 : removed reference to Titan bar reference - Instead use the relative position on the screen to show the control (plugin) frame properly. - NOTE: If Titan bars need a left click to show a control frame the offset - will need to be changed to use the cursor position like right click menu!! - --]] - if (self:GetTop() - controlFrame:GetHeight()) > 0 then - point = "TOP" - rel_point = "BOTTOM" - else -- below screen - point = "BOTTOM" - rel_point = "TOP" - end - - local x = 0 - local y = 0 - - controlFrame:ClearAllPoints(); - controlFrame:SetPoint(point .. "LEFT", parent, rel_point, 0, 0) -- default left of plugin - - -- Adjust control frame position if it's off the screen - local offscreenX, offscreenY = TitanUtils_GetOffscreen(controlFrame); - if (offscreenX == -1) then - -- Off to left of screen which should not happen... - elseif (offscreenX == 1) then - -- off to right of screen, flip to right of plugin - controlFrame:ClearAllPoints(); - controlFrame:SetPoint(point .. "RIGHT", parent, rel_point, 0, 0) - end - - controlFrame:Show(); - end - elseif (button == "RightButton") then - TitanUtils_CloseAllControlFrames(); - -- Show RightClickMenu anyway - TitanPanelRightClickMenu_Close(); - TitanPanelRightClickMenu_Toggle(self); - end - - GameTooltip:Hide(); - end -end - ----API Handle the OnEnter event of the requested Titan plugin. ----@param self table Plugin frame ---- 1. The cursor has moved over the plugin so show the plugin tooltip. ---- 2. Return if plugin "is moving" or if tooltip is already shown. -function TitanPanelButton_OnEnter(self) - local id = nil; - -- ensure that the 'self' passed is a valid frame reference - if self and self:GetName() then - id = TitanUtils_GetButtonID(self:GetName()) - end - - if (id) then - local controlFrame = TitanUtils_GetControlFrame(id); - if (controlFrame and controlFrame:IsVisible()) then - return; - elseif (TitanPanelRightClickMenu_IsVisible()) then - return; - else - if TITAN_PANEL_MOVING == 0 then - TitanPanelButton_SetTooltip(self); - end - if self.isMoving then - GameTooltip:Hide(); - end - end - end -end - ----API Handle the OnLeave event of the requested Titan plugin. ----@param self table Plugin frame ---- 1. The cursor has moved over the plugin so hide the plugin tooltip. -function TitanPanelButton_OnLeave(self) - local id = nil; - -- ensure that the 'self' passed is a valid frame reference - if self and self:GetName() then - id = TitanUtils_GetButtonID(self:GetName()) - end - - if (id) then - GameTooltip:Hide(); - end - - if TitanPanelGetVar("DisableTooltipFont") then - -- use game font & scale - else - -- use Titan font & scale - GameTooltip:SetScale(TitanTooltipOrigScale); - TitanTooltipScaleSet = 0; - end -end - --- local routines for Update Button - - -local format_with_label = { [0] = "" } -- Set format string once -for idx = 1, 4 do - format_with_label[idx] = "%s%s" .. (TITAN_PANEL_LABEL_SEPARATOR .. "%s%s"):rep(idx - 1) -end ----local Set the width of the given icon Titan plugin - icon only. ----@param id string Plugin id ---- The plugin is expected to tell Titan what routine is to be called in <self>.registry.buttonTextFunction. ---- Note: Titan handles up to 4 label-value pairs. User may customize (override) the plugin labels. ---- The text routine is called in protected mode (pcall) to ensure the Titan main routines still run. -local function TitanPanelButton_SetButtonText(id) - --- There are several places that return in this routine. Not best practice but more readable. - local dbg_msg = "ptxt : '" .. tostring(id) .. "'" - local ok = false - - if (id and TitanUtils_IsPluginRegistered(id)) then - -- seems valid, registered plugin - ok = true - else - -- return silently; The plugin is not registered! - -- output here could be a lot and really annoy the user... - dbg_msg = dbg_msg .. " | unregistered plugin" - end - - local pdata = TitanUtils_GetPlugin(id) -- get plugin data - local buttonTextFunction = {} ---@type function - - if pdata then - local bFunction = pdata.buttonTextFunction - if type(bFunction) == 'string' then - -- Function MUST be in global namespace - buttonTextFunction = _G[bFunction] - ok = true - elseif type(bFunction) == 'function' then - -- Can be global or local to the plugin - buttonTextFunction = bFunction - ok = true - else - dbg_msg = dbg_msg .. " | invalid function type" - -- silently leave... - end - else - -- silently leave... - dbg_msg = dbg_msg .. " | invalid plugin data" - end - - if ok and buttonTextFunction then - local label1, value1, label2, value2, label3, value3, label4, value4 - local call_success = false - local button = TitanUtils_GetButton(id) -- get plugin frame - local buttonText = {} - - local text = false - if button then - buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; - - local newfont = media:Fetch("font", TitanPanelGetVar("FontName")) - if newfont then - buttonText:SetFont(newfont, TitanPanelGetVar("FontSize")) - end - - -- We'll be paranoid here and call the button text in protected mode. - -- In case the button text fails it will not take Titan with it... - call_success, -- for pcall - label1, value1, label2, value2, label3, value3, label4, value4 = - pcall(buttonTextFunction, id) - - if call_success then - -- All is good - text = true - else - buttonText:SetText("<?>") - dbg_msg = dbg_msg .. " | Err '" .. tostring(label1) .. "'" - end - else - dbg_msg = dbg_msg .. " | invalid plugin id" - end - - --===================================== - -- Determine the label value pairs : 1 - 4 - -- Each could be custom per user - -- - -- NumLabelsSeen - used for the config to avoid confusing user - -- Plugin MUST have been shown at least once. - - -- In the case of first label only (no value), set the button and return. - if text and - label1 and - not (label2 or label3 or label4 - or value1 or value2 or value3 or value4) then - buttonText:SetText(label1) - - TitanSetVar(id, "NumLabelsSeen", 1) - - dbg_msg = dbg_msg .. " | single label; no value | " - else - local show_label = TitanGetVar(id, "ShowLabelText") - local values = 0 - if label1 or value1 then - values = 1 - if show_label then - if TitanGetVar(id, "CustomLabelTextShow") then - -- override the label per the user - label1 = TitanGetVar(id, "CustomLabelText") - else - end - else - label1 = "" - end - if label2 or value2 then - values = 2 - if show_label then - if TitanGetVar(id, "CustomLabel2TextShow") then - -- override the label per the user - label2 = TitanGetVar(id, "CustomLabel2Text") - else - end - else - label2 = "" - end - if label3 or value3 then - if show_label then - if TitanGetVar(id, "CustomLabel3TextShow") then - -- override the label per the user - label3 = TitanGetVar(id, "CustomLabel3Text") - else - end - else - label3 = "" - end - values = 3 - if label4 or value4 then - values = 4 - if show_label then - if TitanGetVar(id, "CustomLabel43TextShow") then - -- override the label per the user - label4 = TitanGetVar(id, "CustomLabel4Text") - else - end - else - label4 = "" - end - end - end - end - dbg_msg = dbg_msg .. " | ok | " .. tostring(values) - else - -- no label or value - -- Do nothing, it could be the right action for the plugin - dbg_msg = dbg_msg .. " | no label or value : " .. tostring(values) - end - - TitanSetVar(id, "NumLabelsSeen", values) - - -- values tells which format to use from the array - buttonText:SetFormattedText(format_with_label[values], - label1 or "", value1 or "", - label2 or "", value2 or "", - label3 or "", value3 or "", - label4 or "", value4 or "" - ) - end - else - -- no valid routine to update the plugin text - dbg_msg = dbg_msg .. " | no valid routine found" - end - Titan_Debug.Out('titan', 'plugin_text', dbg_msg) -end - ----local Set the width of the given Titan plugin - text only. ----@param id string Plugin id ----@param setButtonWidth? integer Width in pixels ---- Titan uses a tolerance setting to prevent endless updating of the text width. -local function TitanPanelButton_SetTextButtonWidth(id, setButtonWidth) - if (id) then - local button = TitanUtils_GetButton(id) - if button then - local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; - if (setButtonWidth - or button:GetWidth() == 0 - or button:GetWidth() - text:GetWidth() > TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE - or button:GetWidth() - text:GetWidth() < -TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE) then - button:SetWidth(text:GetWidth()); - TitanPanelButton_Justify(); - end - else - -- no plugin registered, be silent - end - else - -- no plugin received, be silent - end -end - ----local Set the width of the given Titan plugin - icon only. ----@param id string Plugin id ---- Wrap up by (re)drawing the plugins on the Bar. ---- Titan uses a tolerance setting to prevent endless updating of the text width. -local function TitanPanelButton_SetIconButtonWidth(id) - if (id) then - local button = TitanUtils_GetButton(id) - if button and (TitanUtils_GetPlugin(id).iconButtonWidth) then - button:SetWidth(TitanUtils_GetPlugin(id).iconButtonWidth); - else - -- no plugin registered, be silent - end - else - -- no plugin received, be silent - end -end - ----local Set the width of the given Titan plugin - combo icon & text. ----@param id string Plugin id ----@param setButtonWidth? integer Width in pixels; default to .registry.iconWidth ---- Wrap up by (re)drawing the plugins on the Bar. ---- Titan uses a tolerance setting to prevent endless updating of the text width. -local function TitanPanelButton_SetComboButtonWidth(id, setButtonWidth) - -- TODO - ensure this routine is proper - need this param? - -- icon width default to .registry.iconWidth before getting the actual width - if (id) then - local button = TitanUtils_GetButton(id) - if not button then return end -- sanity check - - local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; - local icon = _G[button:GetName() .. "Icon"]; - local iconWidth, iconButtonWidth, newButtonWidth; - - -- Get icon button width - iconButtonWidth = 0; - if (TitanUtils_GetPlugin(id).iconButtonWidth) then - iconButtonWidth = TitanUtils_GetPlugin(id).iconButtonWidth; - elseif (icon:GetWidth()) then - iconButtonWidth = icon:GetWidth(); - end - - if (TitanGetVar(id, "ShowIcon") and (iconButtonWidth ~= 0)) then - icon:Show(); - text:ClearAllPoints(); - text:SetPoint("LEFT", icon:GetName(), "RIGHT", 2, 1); - - newButtonWidth = text:GetWidth() + iconButtonWidth; - else - icon:Hide(); - text:ClearAllPoints(); - text:SetPoint("LEFT", button:GetName(), "LEFT", 0, 1); - - newButtonWidth = text:GetWidth(); - end - - if (setButtonWidth - or button:GetWidth() == 0 - or button:GetWidth() - newButtonWidth > TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE - or button:GetWidth() - newButtonWidth < -TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE) - then - button:SetWidth(newButtonWidth); - TitanPanelButton_Justify(); - end - end -end - ----API Update the display of the given Titan plugin. ----@param id string Plugin id ----@param setButtonWidth? integer Width in pixels ---- Use after any change to icon, label, or text (depending on Titan template used) ---- TitanPanelButton_UpdateButton(TITAN_CLOCK_ID) -function TitanPanelButton_UpdateButton(id, setButtonWidth) - -- Used by plugins - local plugin = TitanUtils_GetPlugin(id) - -- safeguard to avoid errors - if plugin and TitanUtils_IsPluginRegistered(id) then - if (TitanPanelButton_IsText(id)) then - -- Update textButton - TitanPanelButton_SetButtonText(id); - TitanPanelButton_SetTextButtonWidth(id, setButtonWidth); - elseif (TitanPanelButton_IsIcon(id)) then - -- Update iconButton - TitanPanelButton_SetButtonIcon(id, (plugin.iconCoords or nil), - (plugin.iconR or nil), (plugin.iconG or nil), (plugin.iconB or nil) - ); - TitanPanelButton_SetIconButtonWidth(id); - elseif (TitanPanelButton_IsCombo(id)) then - -- Update comboButton - TitanPanelButton_SetButtonText(id); - TitanPanelButton_SetButtonIcon(id, (plugin.iconCoords or nil), - (plugin.iconR or nil), (plugin.iconG or nil), (plugin.iconB or nil) - ); - TitanPanelButton_SetComboButtonWidth(id, setButtonWidth); - end - else - return - end -end - ----API Update the tooltip of the given Titan plugin. ----@param self table Plugin frame -function TitanPanelButton_UpdateTooltip(self) - if not self then return end - if (GameTooltip:IsOwned(self)) then - local id = TitanUtils_GetButtonID(self:GetName()); - - TitanPanelButton_SetTooltip(self); - end -end - ----API Refresh the display of the passed in Titan plugin. ----@param table table | string Either {plugin id, action} OR plugin id ----@param oldarg string? action OR nil ---- This is used by some plugins. It is not used within Titan. ---- Action : ---- 1 = refresh button ---- 2 = refresh tooltip ---- 3 = refresh button and tooltip -function TitanPanelPluginHandle_OnUpdate(table, oldarg) - --- This is used by some plugins. - local id, updateType = nil, nil - -- set the id and updateType - -- old method - if table and type(table) == "string" and oldarg then - id = table - updateType = oldarg - end - -- new method - if table and type(table) == "table" then - if table[1] then id = table[1] end - if table[2] then updateType = table[2] end - end - - -- id is required - if id then - if updateType == TITAN_PANEL_UPDATE_BUTTON - or updateType == TITAN_PANEL_UPDATE_ALL then - TitanPanelButton_UpdateButton(id) - end - - if (updateType == TITAN_PANEL_UPDATE_TOOLTIP - or updateType == TITAN_PANEL_UPDATE_ALL) - and MouseIsOver(_G[TitanUtils_ButtonName(id)]) then - if TitanPanelRightClickMenu_IsVisible() or TITAN_PANEL_MOVING == 1 then - return - end - - TitanPanelButton_SetTooltip(_G[TitanUtils_ButtonName(id)]) - end - end -end - ----Titan Poorly named routine that sets the OnDragStart & OnDragStop scripts of a Titan plugin. ----@param id string Plugin id -function TitanPanelDetectPluginMethod(id) - -- Ensure the id is not nil - if not id then return end - local TitanPluginframe = _G[TitanUtils_ButtonName(id)]; - -- Ensure the frame is valid - if not TitanPluginframe and TitanPluginframe:GetName() then return end -- sanity check... - - -- Set the OnDragStart script - TitanPluginframe:SetScript("OnDragStart", function(self) - if not IsShiftKeyDown() - and not IsControlKeyDown() - and not IsAltKeyDown() then - TitanPanelButton_OnDragStart(self); - end - end) - - -- Set the OnDragStop script - TitanPluginframe:SetScript("OnDragStop", function(self) - TitanPanelButton_OnDragStop(self); - end) -end - ----Titan Sets the OnDragStart & OnDragStop scripts of a Titan plugin. ----@param self Button Plugin -function TitanPanelButton_AddMouseScripts(self) - -- Ensure the id is not nil - if self then - self:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp"); - self:RegisterForDrag("LeftButton") - - -- Set the OnDragStart script - self:SetScript("OnDragStart", function(self) - if not IsShiftKeyDown() - and not IsControlKeyDown() - and not IsAltKeyDown() then - TitanPanelButton_OnDragStart(self) - end - end) - - -- Set the OnDragStop script - self:SetScript("OnDragStop", function(self) - TitanPanelButton_OnDragStop(self) - end) - else - -- nothing to add to ?? - end -end - ----API Set the icon of the given Titan plugin. ----@param id string Plugin id ----@param iconCoords table? As {left, right, top, bottom} ----@param iconR number? Red (.0. - 1.0) ----@param iconG number? Green (.0. - 1.0) ----@param iconB number? Blue (.0. - 1.0) ---- Using TitanPanelButton_UpdateButton is preferred unless coords are needed -function TitanPanelButton_SetButtonIcon(id, iconCoords, iconR, iconG, iconB) - if (id and TitanUtils_IsPluginRegistered(id)) then - local button = TitanUtils_GetButton(id) - if button then - local icon = _G[button:GetName() .. "Icon"]; - local iconTexture = TitanUtils_GetPlugin(id).icon; - local iconWidth = TitanUtils_GetPlugin(id).iconWidth; - - if (iconTexture) and icon then - icon:SetTexture(iconTexture); - end - if (iconWidth) and icon then - icon:SetWidth(iconWidth); - end - - -- support for iconCoords, iconR, iconG, iconB attributes - if iconCoords and icon then - icon:SetTexCoord(unpack(iconCoords)) - end - if iconR and iconG and iconB and icon then - icon:SetVertexColor(iconR, iconG, iconB) - end - else - -- plugin not registered - end - end -end - ----Titan Get the type of the given Titan plugin. ---- This assumes that the developer is playing nice and is using the Titan templates as is... ----@param id string Plugin id name ----@return integer type (text-1, icon-2, combo-3 (default)) -function TitanPanelButton_GetType(id) - -- This assumes that the developer is playing nice and is using the Titan templates as is... - -- id is required - local type = 0 -- unknown - if id then - local button = TitanUtils_GetButton(id); - if button then - local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; - local icon = _G[button:GetName() .. "Icon"]; - - if (text and icon) then - type = TITAN_PANEL_BUTTON_TYPE_COMBO; - elseif (text and not icon) then - type = TITAN_PANEL_BUTTON_TYPE_TEXT; - elseif (not text and icon) then - type = TITAN_PANEL_BUTTON_TYPE_ICON; - elseif (not text and not icon) then - type = TITAN_PANEL_BUTTON_TYPE_CUSTOM; - end - else - type = TITAN_PANEL_BUTTON_TYPE_COMBO; - end - else - -- no id... - end - - return type -end - ----Titan Apply saved Bar position to the Bar frame. ---- Bit of a sledge hammer; used when loading a profile over the current so the Bars are properly placed. ----@param frame_str string Bar frame name -function TitanPanelButton_ApplyBarPos(frame_str) - -- - local frame = _G[frame_str] - local bdata = TitanBarData[frame_str] - if frame then - frame:ClearAllPoints(); - if bdata.user_move then - local x, y, w = TitanVariables_GetBarPos(frame_str) - frame:SetPoint(bdata.show.pt, bdata.show.rel_fr, bdata.show.rel_pt, x, y) - else - -- full bar, ignore - end - end -end - ----Titan Loads the Backdrop for TitanOptionsSliderTemplate with new 9.0 API ----@param self table Control frame -function TitanOptionsSliderTemplate_OnLoad(self) - self:SetBackdrop({ - bgFile = "Interface\\Buttons\\UI-SliderBar-Background", - edgeFile = "Interface\\Buttons\\UI-SliderBar-Border", - tile = true, - insets = { - left = 6, - right = 6, - top = 3, - bottom = 3, - }, - tileSize = 8, - edgeSize = 8, - }) -end +--[===[ File +Contains routines defined in TitanTemplate.xml. + +Contains the routines to control a Titan template frame whether Titan bar or plugin. +--]===] + +--[===[ Var API TitanPanelTemplate overview +Creates the following frames: +- TitanPanelBarButton : Main Titan frame handling events +TODO - TitanPanelTooltip : Used? Inherits from GameTooltipTemplate + +Contains the routines to control a Titan template frame. +These could be: +- A Titan bar (full or short) +- A Titan plugin (built-in, thrid party, or LDB) + +The Titan templates are defined in .xml. +There appears to be no other way to make frame templates - virtual="true". +See TitanPanelButtonTemplate.xml also for more detail. + +TitanTemplate (Lua and XML) contain the basics for Titan plugin frames. +Titan templates contain elements used by Titan. + +A Titan plugin is a frame created using one of the button types in TitanPanelButtonTemplate.xml. +The available plugin types are: +- TitanPanelTextTemplate - * A frame that only displays text ("$parentText") +- TitanPanelIconTemplate - * A frame that only displays an icon ("$parentIcon") +- TitanPanelComboTemplate - * A frame that displays an icon then text ("$parentIcon" "$parentText") +- TitanOptionsSliderTemplate - A frame that contains the basics for a vertical slider control. See TitanVolume for an example. + +* Templates inherit TitanPanelButtonTemplate for common elements. + +Most plugins use the combo template. + +TitanPanelButtonTemplate contains: +- a frame to handle a menu invoked by a right mouse click ("$parentRightClickMenu") +- default event handlers for + <OnLoad> + TitanPanelButton_OnLoad(self); + </OnLoad> + <OnShow> + TitanPanelButton_OnShow(self); + </OnShow> + <OnClick> + TitanPanelButton_OnClick(self, button); + </OnClick> + <OnEnter> + TitanPanelButton_OnEnter(self); + </OnEnter> + <OnLeave> + TitanPanelButton_OnLeave(self); + </OnLeave> +If these events are overridden then the default routine needs to be included! + + +NOTE: TitanPanelChildButtonTemplate - Removed 2024 Jun +--]===] + +-- Globals + +-- Constants +local TITAN_PANEL_LABEL_SEPARATOR = " " +local TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE = 10; +local TITAN_PANEL_BUTTON_TYPE_TEXT = 1; +local TITAN_PANEL_BUTTON_TYPE_ICON = 2; +local TITAN_PANEL_BUTTON_TYPE_COMBO = 3; +local TITAN_PANEL_BUTTON_TYPE_CUSTOM = 4; +local pluginOnEnter = nil; + +-- Used for drag and drop, assuming one can only drag one plugin :) +local TITAN_PANEL_MOVE_ADDON = ""; +local TITAN_PANEL_DROPOFF_ADDON = ""; +local Drag_init = {} +local drag = Drag_init +local FROM_BAR_SHORT = "" +local FROM_BAR_FRAME = "" + +-- Library instances +local LibQTip = nil +local _G = getfenv(0); +local InCombatLockdown = _G.InCombatLockdown +local media = LibStub("LibSharedMedia-3.0") + +--[[ +print("B text" +.." "..tostring(id).."" +.." "..tostring(type(bFunction)).."" +.." '"..tostring(bFunction).."'" +.." '"..tostring(buttonTextFunction).."'" +) +--]] +--========================== + +--[[ local +NAME: TitanPanel_SetScale +DESC: Set the scale of each plugin and each Titan bar. +VAR: None +OUT: None +--]] +function TitanPanel_SetScale() + local scale = TitanPanelGetVar("Scale"); + + -- Set all the Titan bars + for idx, v in pairs(TitanBarData) do + _G[idx]:SetScale(scale) + end + -- Set all the registered plugins + for index, value in pairs(TitanPlugins) do + if index then + TitanUtils_GetButton(index):SetScale(scale); + end + end +end + +---local Helper to add a line of tooltip text to the tooltip. +---@param text string To add +---@param frame table Tooltip frame +--- Append a "\n" to the end if there is not one already there +local function TitanTooltip_AddTooltipText(text, frame) + if (text) then + -- Append a "\n" to the end + if (string.sub(text, -1, -1) ~= "\n") then + text = text .. "\n"; + end + + -- See if the string is intended for a double column + for text1, text2 in string.gmatch(text, "([^\t\n]*)\t?([^\t\n]*)\n") do + if (text2 ~= "") then + -- Add as double wide + frame:AddDoubleLine(text1, text2); + elseif (text1 ~= "") then + -- Add single column line + frame:AddLine(text1); + else + -- Assume a blank line + frame:AddLine("\n"); + end + end + else + -- No text to display + end +end + +---local Helper to set both the parent and the position of GameTooltip for the plugin tooltip. +---@param parent table Reference to the frame to attach the tooltip to +---@param anchorPoint string Tooltip anchor location (side or corner) to use +---@param relativeToFrame string name name of the frame, usually the plugin), to attach the tooltip to +---@param relativePoint string Parent anchor location (side or corner) to use +---@param xOffset number X offset +---@param yOffset number Y offset +---@param frame table Tooltip frame +--- Set Titan_Debug.titan.tool_tips to output debug +local function TitanTooltip_SetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame) + -- Changes for 9.1.5 Removed the background template from the GameTooltip + -- Making changes to it difficult and possibly changing the tooltip globally. + + frame:SetOwner(parent, "ANCHOR_NONE"); + frame:SetPoint(anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset); + + -- set font size for the Game Tooltip + if TitanPanelGetVar("DisableTooltipFont") then + -- use UI scale + else + if TitanTooltipScaleSet < 1 then + TitanTooltipOrigScale = frame:GetScale(); + TitanTooltipScaleSet = TitanTooltipScaleSet + 1; + end + frame:SetScale(TitanPanelGetVar("TooltipFont")); + end + + local dbg_msg = "_pos" + .. " '" .. tostring(frame:GetName()) .. "'" + .. " " .. tostring(frame:IsShown()) .. "" + .. " @ '" .. tostring(relativeToFrame) .. "'" + .. " " .. tostring(_G[relativeToFrame]:IsShown()) .. "" + Titan_Debug.Out('titan', 'tool_tips', dbg_msg) + dbg_msg = ">>_pos" + .. " " .. tostring(anchorPoint) .. "" + .. " " .. tostring(relativePoint) .. "" + .. " w" .. tostring(format("%0.1f", frame:GetWidth())) .. "" + .. " h" .. tostring(format("%0.1f", frame:GetHeight())) .. "" + Titan_Debug.Out('titan', 'tool_tips', dbg_msg) +end + +---local Helper to set the screen position of the tooltip frame +---@param self table Tooltip frame +---@param id string Plugin id name +---@param frame table Tooltip frame - expected to be GameTooltip +local function TitanTooltip_SetPanelTooltip(self, id, frame) + local button = TitanUtils_GetButton(id) + + if button then + -- Adjust the Y offset as needed + local rel_y = self:GetTop() - frame:GetHeight() + local pt = "" + local rel_pt = "" + if rel_y > 0 then + pt = "TOP"; + rel_pt = "BOTTOM"; + else + -- too close to bottom of screen + pt = "BOTTOM"; + rel_pt = "TOP"; + end + local rel_x = self:GetLeft() + frame:GetHeight() + if (rel_x < GetScreenWidth()) then + -- menu will fit + pt = pt .. "LEFT"; + rel_pt = rel_pt .. "LEFT"; + else + pt = pt .. "RIGHT"; + rel_pt = rel_pt .. "RIGHT"; + end + + TitanTooltip_SetOwnerPosition(button, pt, button:GetName(), rel_pt, 0, 0, frame) + end +end + +---local Set the tooltip (GameTooltip) of the given Titan plugin. +---@param self table Plugin frame +--- Set Titan_Debug.titan.tool_tips to output debug of this routine +local function TitanPanelButton_SetTooltip(self) + local dbg_msg = "TT:" + local ok = false + local frame = GameTooltip + local id = self.registry.id + + -- ensure that the 'self' passed is a valid frame reference + if self:GetName() then + dbg_msg = dbg_msg .. "'" .. self:GetName() .. "'" + -- sanity checks + if (TitanPanelGetVar("HideTipsInCombat") and InCombatLockdown()) then + dbg_msg = dbg_msg .. " HideTipsInCombat" + else + if TitanPanelGetVar("ToolTipsShown") then + ok = true + else + dbg_msg = dbg_msg .. " ToolTipsShown false" + end + end + else + dbg_msg = dbg_msg .. " No frame" + -- Cannot even start + end + + if ok then + local call_success = nil + local tmp_txt = "" + local use_mod = TitanAllGetVar("UseTooltipModifer") + local use_alt = TitanAllGetVar("TooltipModiferAlt") + local use_ctrl = TitanAllGetVar("TooltipModiferCtrl") + local use_shift = TitanAllGetVar("TooltipModiferShift") + + if use_mod then + if (use_alt and IsAltKeyDown()) + or (use_ctrl and IsControlKeyDown()) + or (use_shift and IsShiftKeyDown()) + then + ok = true + end + else + ok = true + end + + self.tooltipCustomFunction = nil; + self.titan_tt_func = "" + self.titan_tt_err = "" + + if ok and (id and TitanUtils_IsPluginRegistered(id)) then + local plugin = TitanUtils_GetPlugin(id) + -- 2024 Jun Add id and frame name to 'pass' to tooltip routine. + -- A compromise given that this mechanism is used by nearly all plugins. + -- Used by Titan auto hide to better determine which bar the 'pin' / icon is on. + self.plugin_id = id + self.plugin_frame = TitanUtils_ButtonName(id) + if (plugin and plugin.tooltipCustomFunction) then + -- Hide the GameTooltip while being updated, to avoid race conditions. + frame:Hide() + -- Prep the tooltip frame + TitanTooltip_SetPanelTooltip(self, id, frame); + + -- Fill the tooltip + self.tooltipCustomFunction = plugin.tooltipCustomFunction; + dbg_msg = dbg_msg .. " | custom" + call_success, -- for pcall + tmp_txt = pcall(self.tooltipCustomFunction, self) + if call_success then + -- all is good + dbg_msg = dbg_msg .. " | ok" + else + dbg_msg = dbg_msg .. " | Err: " .. tmp_txt + end + + frame:Show(); -- now show it + elseif (plugin and plugin.tooltipTitle) then + local tooltipTextFunc = {} ---@type function + local tt_func = plugin.tooltipTextFunction + + if type(tt_func) == 'string' then + -- Function MUST be in global namespace + tooltipTextFunc = _G[tt_func] + dbg_msg = dbg_msg .. " | string" + elseif type(tt_func) == 'function' then + -- Can be global or local to the plugin + tooltipTextFunc = tt_func + dbg_msg = dbg_msg .. " | function" + else + -- silently leave... + dbg_msg = dbg_msg .. " | none found" + end + + if (tooltipTextFunc) then + -- Hide the GameTooltip while being updated, to avoid race conditions. + frame:Hide() + -- Prep the tooltip frame + TitanTooltip_SetPanelTooltip(self, id, frame); + self.tooltipTitle = plugin.tooltipTitle; + call_success, -- for pcall + tmp_txt = pcall(tooltipTextFunc, self) + + -- Fill the tooltip + self.tooltipText = tmp_txt + frame:SetText(self.tooltipTitle, + HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); + if (self.tooltipText) then + TitanTooltip_AddTooltipText(self.tooltipText, frame) + dbg_msg = dbg_msg .. " | ok" + else + dbg_msg = dbg_msg .. " | No text" + end + + frame:Show() -- now show it + end + else + -- no recognized method to create tooltip + dbg_msg = "No recognized tooltip method [.tooltipCustomFunction then .tooltipTitle /.tooltipText]" + end + end + else + -- no need to waste cycles + end + + Titan_Debug.Out('titan', 'tool_tips', dbg_msg) +end + +---local Is the given Titan plugin template type text? +---@param id string Plugin id name +---@return boolean IsText +local function TitanPanelButton_IsText(id) + if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_TEXT) then + return true + else + return false + end +end + +---local Is the given Titan plugin of type combo? +---@param id string Plugin id name +---@return boolean IsCombo +local function TitanPanelButton_IsCombo(id) + if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_COMBO) then + return true + else + return false + end +end + +---Titan Is the given Titan plugin of type icon? +---@param id string Plugin id name +---@return boolean is_icon +function TitanPanelButton_IsIcon(id) + local res = false + if (TitanPanelButton_GetType(id) == TITAN_PANEL_BUTTON_TYPE_ICON) then + res = true + else + res = false + end + + return res +end + +---local Handle the OnDragStart event of the given Titan plugin. +---@param self table Plugin frame +--- Do nothing if the user has locked plugins or if in combat. +--- Set the .isMoving of the plugin (frame) so other routine can check it. +--- Set TITAN_PANEL_MOVING so any Titan routine will know a 'drag & drop' is in progress. +--- Set TITAN_PANEL_MOVE_ADDON so sanity checks can be done on the 'drop'. +local function TitanPanelButton_OnDragStart(self) + -- Due to API change in 11.2.0, :ClearAllPoints immediately invalidates the rect... + -- Need to change order of events between drag start and stop: + -- - Remove but not Hide() the plugin - seems Hide() triggers OnDragStop without release of mouse button... + -- - Make ALL 'do not drag' checks BEFORE remove!! + -- + -- Dropped Ace Dewdrop-2.0 lib support as of 2025 Sep; last updated 2008 Sep + -- Dropped Ace Tablet-2.0 lib support as of 2025 Sep; last updated 2009 Jan (marked as abandoned) + + if TitanPanelGetVar("LockButtons") or InCombatLockdown() then + return -- not requested or not allowed + else + -- Proceed + end + + local frname = self + local frstr = self:GetName() + local plugin_id = TitanUtils_GetButtonID(frstr) + local str = "" + str = "_OnDragStart start " + .." "..tostring(plugin_id).."" +-- .." from "..tostring(FROM_BAR_SHORT).."" + Titan_Debug.Out('titan', 'plugin_drag_drop', str) + + + -- Tell Titan that a drag & drop is in process + TITAN_PANEL_MOVING = 1; + -- Start the drag + frname:StartMoving(); + frname.isMoving = true; + + -- Close any tooltips and control frames + TitanUtils_CloseAllControlFrames(); + TitanPanelRightClickMenu_Close(); + GameTooltip:Hide(); + + -- LibQTip-1.0 support code + LibQTip = LibStub("LibQTip-1.0", true) + if LibQTip then + for key, tip in LibQTip:IterateTooltips() do + if tip then + local _, relativeTo = tip:GetPoint() + if relativeTo and relativeTo:GetName() == frstr then + tip:Hide() + break + end + end + end + end + -- /LibQTip-1.0 support code + + FROM_BAR_SHORT = TitanUtils_GetWhichBar(plugin_id) -- short name + str = "_OnDragStart moving" + .." "..tostring(plugin_id).."" + .." from "..tostring(FROM_BAR_SHORT).."" + Titan_Debug.Out('titan', 'plugin_drag_drop', str) + -- Clear the plugin placement so we only move the intended plugin + TitanPanel_RemoveButton(plugin_id, false) + frname:Show() -- 'remove' hid the plugin + + -- Hold the plugin id so we can do checks on the drop + TITAN_PANEL_MOVE_ADDON = plugin_id + + -- Store the OnEnter handler so the tooltip does not show - or other oddities + pluginOnEnter = self:GetScript("OnEnter") + self:SetScript("OnEnter", nil) +end + +---local Handle the OnDragStop event of the given Titan plugin. +---@param self table Plugin frame +--- Clear the .isMoving of the plugin (frame). +--- Clear TITAN_PANEL_MOVING. +--- Clear TITAN_PANEL_MOVE_ADDON. +local function TitanPanelButton_OnDragStop(self) + -- The plugin is under the cursor so we MUST place the plugin somewhere! + -- We cannot just return. + -- Also means we can no longer swap plugins. + -- For now, we will drop the plugin on the bar under the cursor; + -- placing the plugin 'right' if set for that plugin + + local frname = self + local frstr = self:GetName() + local plugin_id = TitanUtils_GetButtonID(frstr) + + local str = "" + str = "_OnDragStop start " + .." "..tostring(plugin_id).."" + Titan_Debug.Out('titan', 'plugin_drag_drop', str) + + if TITAN_PANEL_MOVING == 1 then + frname:StopMovingOrSizing(); + frname.isMoving = false; + TITAN_PANEL_MOVING = 0; + + local bar + local tbar = "" -- bar short name + local fbar = TitanGetVar(plugin_id, "ForceBar") + + str = "_OnDragStop " + .." "..tostring(plugin_id).."" + if fbar == nil + or fbar == false then + -- Find which bar it was dropped on + for idx, v in pairs(TitanBarData) do + bar = idx + if (bar and MouseIsOver(_G[bar])) then + tbar = TitanBarData[bar].name + end + end + if tbar == "" then + -- not sure what the user did... + -- Likely released on UI so put back on the bar it came from + str = str .." back to" + tbar = FROM_BAR_SHORT + else + str = str .." onto" + end + else + str = str .." force to" + tbar = fbar -- put it back; allows user to shift it + end + + str = str .." "..tostring(tbar).."" + Titan_Debug.Out('titan', 'plugin_drag_drop', str) + TitanUtils_AddButtonOnBar(tbar, TITAN_PANEL_MOVE_ADDON) + + -- The plugin was added a bar so clean up. + TITAN_PANEL_MOVE_ADDON = ""; + if pluginOnEnter then + -- Restore the OnEnter script handler + self:SetScript("OnEnter", pluginOnEnter) + else + -- No OnEnter was found at drag start + end + pluginOnEnter = nil; + + end +end + +---API Set the color of the tooltip text to normal (white) with the value in green. +---@param text string Label to show +---@param value any Value to show; something tostring() can handle +---@return string str Formatted text and value +--- self.tooltipText = TitanOptionSlider_TooltipText("Addons", TitanGetVar(TITAN_PERFORMANCE_ID, "NumOfAddons")); +function TitanOptionSlider_TooltipText(text, value) + return tostring(text) .. " " .. GREEN_FONT_COLOR_CODE .. tostring(value) .. FONT_COLOR_CODE_CLOSE; +end + +---API Handle the OnLoad event of the requested Titan plugin. Ensure the plugin is set to be registered. +---@param self table Plugin frame +--- This is called from the Titan plugin frame in the OnLoad event - usually as the frame is created in the Titan template. +function TitanPanelButton_OnLoad(self) + -- Used by plugins + --[[ +--- This is called from the Titan plugin frame in the OnLoad event - usually as the frame is created in the Titan template. +--- This starts the plugin registration process. See TitanUtils for more details on plugin registration. +--- The plugin registration is a two step process because not all addons create Titan plugins in the frame create. +--- The Titan feature of converting LDB addons to Titan plugins is an example. +--- If the plugin needs an OnLoad process it should call this routine after its own. I.E. +--- TitanPanelLootTypeButton_OnLoad(self) +--- TitanPanelButton_OnLoad(self) +--]] + TitanUtils_PluginToRegister(self) +end + +---API Handle the OnShow event of the requested Titan plugin. +---@param self table Plugin frame +function TitanPanelButton_OnShow(self) + local id = nil; + -- ensure that the 'self' passed is a valid frame reference + if self and self:GetName() then + id = TitanUtils_GetButtonID(self:GetName()); + end + -- ensure that id is a valid Titan plugin + if (id) then + TitanPanelButton_UpdateButton(id, 1); + end +end + +---API Handle the OnClick mouse event of the requested Titan plugin. +---@param self table Plugin frame +---@param button string Mouse button clicked +--- Only the left and right mouse buttons are handled by Titan. +--- Called from Titan templates unless overriden by plugin. If overridden the plugin should call this routine. +function TitanPanelButton_OnClick(self, button) + local id + -- ensure that the 'self' passed is a valid frame reference + if self and self:GetName() then + id = TitanUtils_GetButtonID(self:GetName()) + end + + if id then + local controlFrame = TitanUtils_GetControlFrame(id); + + if controlFrame and (button == "LeftButton") then + local isControlFrameShown; + if (not controlFrame) then + isControlFrameShown = false; + elseif (controlFrame:IsVisible()) then + isControlFrameShown = false; + else + isControlFrameShown = true; + end + + TitanUtils_CloseAllControlFrames(); + TitanPanelRightClickMenu_Close(); + + -- local position = TitanUtils_GetWhichBar(id) + if (isControlFrameShown) then + -- Note: This uses anchor points to place the control frame relative to the plugin on the screen. + local parent = self:GetName() -- plugin with the control frame + local point = "" -- point of the control frame + local rel_point = "" -- The middle - top or bottom edge - of the plugin to anchor to + --[[ Mar 2023 : removed reference to Titan bar reference + Instead use the relative position on the screen to show the control (plugin) frame properly. + NOTE: If Titan bars need a left click to show a control frame the offset + will need to be changed to use the cursor position like right click menu!! + --]] + if (self:GetTop() - controlFrame:GetHeight()) > 0 then + point = "TOP" + rel_point = "BOTTOM" + else -- below screen + point = "BOTTOM" + rel_point = "TOP" + end + + local x = 0 + local y = 0 + + controlFrame:ClearAllPoints(); + controlFrame:SetPoint(point .. "LEFT", parent, rel_point, 0, 0) -- default left of plugin + + -- Adjust control frame position if it's off the screen + local offscreenX, offscreenY = TitanUtils_GetOffscreen(controlFrame); + if (offscreenX == -1) then + -- Off to left of screen which should not happen... + elseif (offscreenX == 1) then + -- off to right of screen, flip to right of plugin + controlFrame:ClearAllPoints(); + controlFrame:SetPoint(point .. "RIGHT", parent, rel_point, 0, 0) + end + + controlFrame:Show(); + end + elseif (button == "RightButton") then + TitanUtils_CloseAllControlFrames(); + -- Show RightClickMenu anyway + TitanPanelRightClickMenu_Close(); + TitanPanelRightClickMenu_Toggle(self); + end + + GameTooltip:Hide(); + end +end + +---API Handle the OnEnter event of the requested Titan plugin. +---@param self table Plugin frame +--- 1. The cursor has moved over the plugin so show the plugin tooltip. +--- 2. Return if plugin "is moving" or if tooltip is already shown. +function TitanPanelButton_OnEnter(self) + local id = nil; + -- ensure that the 'self' passed is a valid frame reference + if self and self:GetName() then + id = TitanUtils_GetButtonID(self:GetName()) + end + + if (id) then + local controlFrame = TitanUtils_GetControlFrame(id); + if (controlFrame and controlFrame:IsVisible()) then + return; + elseif (TitanPanelRightClickMenu_IsVisible()) then + return; + else + if TITAN_PANEL_MOVING == 0 then + TitanPanelButton_SetTooltip(self); + end + if self.isMoving then + GameTooltip:Hide(); + end + end + end +end + +---API Handle the OnLeave event of the requested Titan plugin. +---@param self table Plugin frame +--- 1. The cursor has moved over the plugin so hide the plugin tooltip. +function TitanPanelButton_OnLeave(self) + local id = nil; + -- ensure that the 'self' passed is a valid frame reference + if self and self:GetName() then + id = TitanUtils_GetButtonID(self:GetName()) + end + + if (id) then + GameTooltip:Hide(); + end + + if TitanPanelGetVar("DisableTooltipFont") then + -- use game font & scale + else + -- use Titan font & scale + GameTooltip:SetScale(TitanTooltipOrigScale); + TitanTooltipScaleSet = 0; + end +end + +-- local routines for Update Button + + +local format_with_label = { [0] = "" } -- Set format string once +for idx = 1, 4 do + format_with_label[idx] = "%s%s" .. (TITAN_PANEL_LABEL_SEPARATOR .. "%s%s"):rep(idx - 1) +end +---local Set the width of the given icon Titan plugin - icon only. +---@param id string Plugin id +--- The plugin is expected to tell Titan what routine is to be called in <self>.registry.buttonTextFunction. +--- Note: Titan handles up to 4 label-value pairs. User may customize (override) the plugin labels. +--- The text routine is called in protected mode (pcall) to ensure the Titan main routines still run. +local function TitanPanelButton_SetButtonText(id) + --- There are several places that return in this routine. Not best practice but more readable. + local dbg_msg = "ptxt : '" .. tostring(id) .. "'" + local ok = false + + if (id and TitanUtils_IsPluginRegistered(id)) then + -- seems valid, registered plugin + ok = true + else + -- return silently; The plugin is not registered! + -- output here could be a lot and really annoy the user... + dbg_msg = dbg_msg .. " | unregistered plugin" + end + + local pdata = TitanUtils_GetPlugin(id) -- get plugin data + local buttonTextFunction = {} ---@type function + + if pdata then + local bFunction = pdata.buttonTextFunction + if type(bFunction) == 'string' then + -- Function MUST be in global namespace + buttonTextFunction = _G[bFunction] + ok = true + elseif type(bFunction) == 'function' then + -- Can be global or local to the plugin + buttonTextFunction = bFunction + ok = true + else + dbg_msg = dbg_msg .. " | invalid function type" + -- silently leave... + end + else + -- silently leave... + dbg_msg = dbg_msg .. " | invalid plugin data" + end + + if ok and buttonTextFunction then + local label1, value1, label2, value2, label3, value3, label4, value4 + local call_success = false + local button = TitanUtils_GetButton(id) -- get plugin frame + local buttonText = {} + + local text = false + if button then + buttonText = _G[button:GetName() .. TITAN_PANEL_TEXT]; + + local newfont = media:Fetch("font", TitanPanelGetVar("FontName")) + if newfont then + buttonText:SetFont(newfont, TitanPanelGetVar("FontSize")) + end + + -- We'll be paranoid here and call the button text in protected mode. + -- In case the button text fails it will not take Titan with it... + call_success, -- for pcall + label1, value1, label2, value2, label3, value3, label4, value4 = + pcall(buttonTextFunction, id) + + if call_success then + -- All is good + text = true + else + buttonText:SetText("<?>") + dbg_msg = dbg_msg .. " | Err '" .. tostring(label1) .. "'" + end + else + dbg_msg = dbg_msg .. " | invalid plugin id" + end + + --===================================== + -- Determine the label value pairs : 1 - 4 + -- Each could be custom per user + -- + -- NumLabelsSeen - used for the config to avoid confusing user + -- Plugin MUST have been shown at least once. + + -- In the case of first label only (no value), set the button and return. + if text and + label1 and + not (label2 or label3 or label4 + or value1 or value2 or value3 or value4) then + buttonText:SetText(label1) + + TitanSetVar(id, "NumLabelsSeen", 1) + + dbg_msg = dbg_msg .. " | single label; no value | " + else + local show_label = TitanGetVar(id, "ShowLabelText") + local values = 0 + if label1 or value1 then + values = 1 + if show_label then + if TitanGetVar(id, "CustomLabelTextShow") then + -- override the label per the user + label1 = TitanGetVar(id, "CustomLabelText") + else + end + else + label1 = "" + end + if label2 or value2 then + values = 2 + if show_label then + if TitanGetVar(id, "CustomLabel2TextShow") then + -- override the label per the user + label2 = TitanGetVar(id, "CustomLabel2Text") + else + end + else + label2 = "" + end + if label3 or value3 then + if show_label then + if TitanGetVar(id, "CustomLabel3TextShow") then + -- override the label per the user + label3 = TitanGetVar(id, "CustomLabel3Text") + else + end + else + label3 = "" + end + values = 3 + if label4 or value4 then + values = 4 + if show_label then + if TitanGetVar(id, "CustomLabel43TextShow") then + -- override the label per the user + label4 = TitanGetVar(id, "CustomLabel4Text") + else + end + else + label4 = "" + end + end + end + end + dbg_msg = dbg_msg .. " | ok | " .. tostring(values) + else + -- no label or value + -- Do nothing, it could be the right action for the plugin + dbg_msg = dbg_msg .. " | no label or value : " .. tostring(values) + end + + TitanSetVar(id, "NumLabelsSeen", values) + + --[==[ + -- values tells which format to use from the array + buttonText:SetFormattedText(format_with_label[values], + label1 or "", value1 or "", + label2 or "", value2 or "", + label3 or "", value3 or "", + label4 or "", value4 or "" + ) + --]==] + buttonText:SetText("" -- formatting was inserting undesired spaces + ..(label1 or "")..(value1 or "") + ..(label2 or "")..(value2 or "") + ..(label3 or "")..(value3 or "") + ..(label4 or "")..(value4 or "") + ) + end + else + -- no valid routine to update the plugin text + dbg_msg = dbg_msg .. " | no valid routine found" + end + Titan_Debug.Out('titan', 'plugin_text', dbg_msg) +end + +---local Set the width of the given Titan plugin - text only. +---@param id string Plugin id +---@param setButtonWidth? integer Width in pixels +--- Titan uses a tolerance setting to prevent endless updating of the text width. +local function TitanPanelButton_SetTextButtonWidth(id, setButtonWidth) + if (id) then + local button = TitanUtils_GetButton(id) + if button then + local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; + if (setButtonWidth + or button:GetWidth() == 0 + or button:GetWidth() - text:GetWidth() > TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE + or button:GetWidth() - text:GetWidth() < -TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE) then + button:SetWidth(text:GetWidth()); + TitanPanelButton_Justify(); + end + else + -- no plugin registered, be silent + end + else + -- no plugin received, be silent + end +end + +---local Set the width of the given Titan plugin - icon only. +---@param id string Plugin id +--- Wrap up by (re)drawing the plugins on the Bar. +--- Titan uses a tolerance setting to prevent endless updating of the text width. +local function TitanPanelButton_SetIconButtonWidth(id) + if (id) then + local button = TitanUtils_GetButton(id) + if button and (TitanUtils_GetPlugin(id).iconButtonWidth) then + button:SetWidth(TitanUtils_GetPlugin(id).iconButtonWidth); + else + -- no plugin registered, be silent + end + else + -- no plugin received, be silent + end +end + +---local Set the width of the given Titan plugin - combo icon & text. +---@param id string Plugin id +---@param setButtonWidth? integer Width in pixels; default to .registry.iconWidth +--- Wrap up by (re)drawing the plugins on the Bar. +--- Titan uses a tolerance setting to prevent endless updating of the text width. +local function TitanPanelButton_SetComboButtonWidth(id, setButtonWidth) + -- TODO - ensure this routine is proper - need this param? + -- icon width default to .registry.iconWidth before getting the actual width + if (id) then + local button = TitanUtils_GetButton(id) + if not button then return end -- sanity check + + local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; + local icon = _G[button:GetName() .. "Icon"]; + local iconWidth, iconButtonWidth, newButtonWidth; + + -- Get icon button width + iconButtonWidth = 0; + if (TitanUtils_GetPlugin(id).iconButtonWidth) then + iconButtonWidth = TitanUtils_GetPlugin(id).iconButtonWidth; + elseif (icon:GetWidth()) then + iconButtonWidth = icon:GetWidth(); + end + + if (TitanGetVar(id, "ShowIcon") and (iconButtonWidth ~= 0)) then + icon:Show(); + text:ClearAllPoints(); + text:SetPoint("LEFT", icon:GetName(), "RIGHT", 2, 1); + + newButtonWidth = text:GetWidth() + iconButtonWidth; + else + icon:Hide(); + text:ClearAllPoints(); + text:SetPoint("LEFT", button:GetName(), "LEFT", 0, 1); + + newButtonWidth = text:GetWidth(); + end + + if (setButtonWidth + or button:GetWidth() == 0 + or button:GetWidth() - newButtonWidth > TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE + or button:GetWidth() - newButtonWidth < -TITAN_PANEL_BUTTON_WIDTH_CHANGE_TOLERANCE) + then + button:SetWidth(newButtonWidth); + TitanPanelButton_Justify(); + end + end +end + +---API Update the display of the given Titan plugin. +---@param id string Plugin id +---@param setButtonWidth? integer Width in pixels +--- Use after any change to icon, label, or text (depending on Titan template used) +--- TitanPanelButton_UpdateButton(TITAN_CLOCK_ID) +function TitanPanelButton_UpdateButton(id, setButtonWidth) + -- Used by plugins + local plugin = TitanUtils_GetPlugin(id) + -- safeguard to avoid errors + if plugin and TitanUtils_IsPluginRegistered(id) then + if (TitanPanelButton_IsText(id)) then + -- Update textButton + TitanPanelButton_SetButtonText(id); + TitanPanelButton_SetTextButtonWidth(id, setButtonWidth); + elseif (TitanPanelButton_IsIcon(id)) then + -- Update iconButton + TitanPanelButton_SetButtonIcon(id, (plugin.iconCoords or nil), + (plugin.iconR or nil), (plugin.iconG or nil), (plugin.iconB or nil) + ); + TitanPanelButton_SetIconButtonWidth(id); + elseif (TitanPanelButton_IsCombo(id)) then + -- Update comboButton + TitanPanelButton_SetButtonText(id); + TitanPanelButton_SetButtonIcon(id, (plugin.iconCoords or nil), + (plugin.iconR or nil), (plugin.iconG or nil), (plugin.iconB or nil) + ); + TitanPanelButton_SetComboButtonWidth(id, setButtonWidth); + end + else + return + end +end + +---API Update the tooltip of the given Titan plugin. +---@param self table Plugin frame +function TitanPanelButton_UpdateTooltip(self) + if not self then return end + if (GameTooltip:IsOwned(self)) then + local id = TitanUtils_GetButtonID(self:GetName()); + + TitanPanelButton_SetTooltip(self); + end +end + +---API Refresh the display of the passed in Titan plugin. +---@param table table | string Either {plugin id, action} OR plugin id +---@param oldarg string? action OR nil +--- This is used by some plugins. It is not used within Titan. +--- Action : +--- 1 = refresh button +--- 2 = refresh tooltip +--- 3 = refresh button and tooltip +function TitanPanelPluginHandle_OnUpdate(table, oldarg) + --- This is used by some plugins. + local id, updateType = nil, nil + -- set the id and updateType + -- old method + if table and type(table) == "string" and oldarg then + id = table + updateType = oldarg + end + -- new method + if table and type(table) == "table" then + if table[1] then id = table[1] end + if table[2] then updateType = table[2] end + end + + -- id is required + if id then + if updateType == TITAN_PANEL_UPDATE_BUTTON + or updateType == TITAN_PANEL_UPDATE_ALL then + TitanPanelButton_UpdateButton(id) + end + + if (updateType == TITAN_PANEL_UPDATE_TOOLTIP + or updateType == TITAN_PANEL_UPDATE_ALL) + and MouseIsOver(_G[TitanUtils_ButtonName(id)]) then + if TitanPanelRightClickMenu_IsVisible() or TITAN_PANEL_MOVING == 1 then + return + end + + TitanPanelButton_SetTooltip(_G[TitanUtils_ButtonName(id)]) + end + end +end + +---Titan Poorly named routine that sets the OnDragStart & OnDragStop scripts of a Titan plugin. +---@param id string Plugin id +function TitanPanelDetectPluginMethod(id) + -- Ensure the id is not nil + if not id then return end + local TitanPluginframe = _G[TitanUtils_ButtonName(id)]; + -- Ensure the frame is valid + if not TitanPluginframe and TitanPluginframe:GetName() then return end -- sanity check... + + -- Set the OnDragStart script + TitanPluginframe:SetScript("OnDragStart", function(self) + if not IsShiftKeyDown() + and not IsControlKeyDown() + and not IsAltKeyDown() then + TitanPanelButton_OnDragStart(self); + end + end) + + -- Set the OnDragStop script + TitanPluginframe:SetScript("OnDragStop", function(self) + TitanPanelButton_OnDragStop(self); + end) +end + +---Titan Sets the OnDragStart & OnDragStop scripts of a Titan plugin. +---@param self Button Plugin +function TitanPanelButton_AddMouseScripts(self) + -- Ensure the id is not nil + if self then + self:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp"); + self:RegisterForDrag("LeftButton") + + -- Set the OnDragStart script + self:SetScript("OnDragStart", function(self) + if not IsShiftKeyDown() + and not IsControlKeyDown() + and not IsAltKeyDown() then + TitanPanelButton_OnDragStart(self) + end + end) + + -- Set the OnDragStop script + self:SetScript("OnDragStop", function(self) + TitanPanelButton_OnDragStop(self) + end) + else + -- nothing to add to ?? + end +end + +---API Set the icon of the given Titan plugin. +---@param id string Plugin id +---@param iconCoords table? As {left, right, top, bottom} +---@param iconR number? Red (.0. - 1.0) +---@param iconG number? Green (.0. - 1.0) +---@param iconB number? Blue (.0. - 1.0) +--- Using TitanPanelButton_UpdateButton is preferred unless coords are needed +function TitanPanelButton_SetButtonIcon(id, iconCoords, iconR, iconG, iconB) + if (id and TitanUtils_IsPluginRegistered(id)) then + local button = TitanUtils_GetButton(id) + if button then + local icon = _G[button:GetName() .. "Icon"]; + local iconTexture = TitanUtils_GetPlugin(id).icon; + local iconWidth = TitanUtils_GetPlugin(id).iconWidth; + + if (iconTexture) and icon then + icon:SetTexture(iconTexture); + end + if (iconWidth) and icon then + icon:SetWidth(iconWidth); + end + + -- support for iconCoords, iconR, iconG, iconB attributes + if iconCoords and icon then + icon:SetTexCoord(unpack(iconCoords)) + end + if iconR and iconG and iconB and icon then + icon:SetVertexColor(iconR, iconG, iconB) + end + else + -- plugin not registered + end + end +end + +---Titan Get the type of the given Titan plugin. +--- This assumes that the developer is playing nice and is using the Titan templates as is... +---@param id string Plugin id name +---@return integer type (text-1, icon-2, combo-3 (default)) +function TitanPanelButton_GetType(id) + -- This assumes that the developer is playing nice and is using the Titan templates as is... + -- id is required + local type = 0 -- unknown + if id then + local button = TitanUtils_GetButton(id); + if button then + local text = _G[button:GetName() .. TITAN_PANEL_TEXT]; + local icon = _G[button:GetName() .. "Icon"]; + + if (text and icon) then + type = TITAN_PANEL_BUTTON_TYPE_COMBO; + elseif (text and not icon) then + type = TITAN_PANEL_BUTTON_TYPE_TEXT; + elseif (not text and icon) then + type = TITAN_PANEL_BUTTON_TYPE_ICON; + elseif (not text and not icon) then + type = TITAN_PANEL_BUTTON_TYPE_CUSTOM; + end + else + type = TITAN_PANEL_BUTTON_TYPE_COMBO; + end + else + -- no id... + end + + return type +end + +---Titan Apply saved Bar position to the Bar frame. +--- Bit of a sledge hammer; used when loading a profile over the current so the Bars are properly placed. +---@param frame_str string Bar frame name +function TitanPanelButton_ApplyBarPos(frame_str) + -- + local frame = _G[frame_str] + local bdata = TitanBarData[frame_str] + if frame then + frame:ClearAllPoints(); + if bdata.user_move then + local x, y, w = TitanVariables_GetBarPos(frame_str) + frame:SetPoint(bdata.show.pt, bdata.show.rel_fr, bdata.show.rel_pt, x, y) + else + -- full bar, ignore + end + end +end + +---Titan Loads the Backdrop for TitanOptionsSliderTemplate with new 9.0 API +---@param self table Control frame +function TitanOptionsSliderTemplate_OnLoad(self) + self:SetBackdrop({ + bgFile = "Interface\\Buttons\\UI-SliderBar-Background", + edgeFile = "Interface\\Buttons\\UI-SliderBar-Border", + tile = true, + insets = { + left = 6, + right = 6, + top = 3, + bottom = 3, + }, + tileSize = 8, + edgeSize = 8, + }) +end diff --git a/Titan/TitanUtils.lua b/Titan/TitanUtils.lua index 1fdd87c..0fdf099 100644 --- a/Titan/TitanUtils.lua +++ b/Titan/TitanUtils.lua @@ -1,4 +1,12 @@ --[===[ File +Contains various utility routines used by +- Titan +- Plugin developers for strings; create menus; and more +- Addon developers that want to know which Titan full bars is on the UI +- Dropdown menu +--]===] + +--[===[ This large file contains various utility routines used by - Titan - Plugin developers for strings; create menus; and more @@ -33,7 +41,6 @@ Dec 2018 : Replace the Ace lib with the Blizzard drop down routines local _G = getfenv(0); local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) -local media = LibStub("LibSharedMedia-3.0") local AceHook = LibStub("AceHook-3.0") local drop_down_1 = "" -- changes if using Blizz drop down (retail) or lib (Classic) @@ -908,6 +915,24 @@ function TitanUtils_GetControlFrame(id) end end +---Titan Original : lua-users.org/wiki/CopyTable +---@param orig any +---@return any +function TitanUtils_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[TitanUtils_DeepCopy(orig_key)] = TitanUtils_DeepCopy(orig_value) + end + setmetatable(copy, TitanUtils_DeepCopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + ---API Routine that index of the value given. ---@param table table Array to check ---@param value any Value to look for @@ -2473,47 +2498,6 @@ function TitanUtils_GetPlayer() return toon, playerName, serverName end ----Titan Return the global profile setting and the global profile name, if any. ----@return boolean global_in_use ----@return string profile name or "<>" ----@return string player_name or "" ----@return string server_name or "" -function TitanUtils_GetGlobalProfile() - local playerName = "" - local serverName = "" - local glob = TitanAllGetVar("GlobalProfileUse") - local toon = TitanAllGetVar("GlobalProfileName") - - if not toon then - -- this is a new install or toon - toon = TITAN_PROFILE_NONE - TitanAllSetVar("GlobalProfileName", TITAN_PROFILE_NONE) - end - if (toon == TITAN_PROFILE_NONE) then - -- - else - -- If the profile name is not the default then split the name - playerName, serverName = TitanUtils_ParseName(toon) - end - - return glob, toon, playerName, serverName -end - ----Titan Return the global profile setting and the global profile name, if any. ----@param glob boolean Use global profile ----@param toon string? Global profile name or default -function TitanUtils_SetGlobalProfile(glob, toon) - TitanAllSetVar("GlobalProfileUse", glob) - if glob then - -- The user asked for global - if toon == nil or toon == TITAN_PROFILE_NONE then - -- nothing was set before so use current player - toon = TitanUtils_GetPlayer() - end - end - TitanAllSetVar("GlobalProfileName", toon or TITAN_PROFILE_NONE) -end - ---Titan Return the screen size after scaling ---@return table screenXY { x | y | scaled_x | scaled_y } all numbers function TitanUtils_ScreenSize() @@ -2549,6 +2533,102 @@ function TitanUtils_ScreenSize() return screen end +--====== Profile specifc routines + +---Check the given profile ensuring any profile pointed to exists +---@param profile string +function TitanUtil_CheckProfile(profile) + local str = "_CheckProfile ["..tostring(profile).."]" + + local sync = TitanSettings.Players[profile].Panel["SyncWithProfile"] +-- local play = TitanUtils_GetPlayer() + + -- see if sync is set + str = str.." s'"..sync.."'" + if (sync == Titan_Global.profile.NONE) then + -- Nothing to do + else + if TitanSettings.Players[profile] then + -- Nothing to do + else + -- Need to clear, the profile is not known... + TitanSettings.Players[profile].Panel["SyncWithProfile"] = Titan_Global.profile.NONE + end + end + str = str.." > '"..TitanSettings.Players[profile].Panel["SyncWithProfile"].."'" + + Titan_Debug.Out('titan', 'profile', str) +end + +---@class Get_Profile_Result +---@field ptype string Type of profile being used +---@field pname string Name of profile being used +---@field cname string Name of profile being used color coded +---@field glob string Value of global profile +---@field sync string Value of sync profile + +---Get the current profile per user settings with type and color-code version +---@param get_me? string +---@return table result Profile info +function TitanUtils_GetProfile(get_me) + local ptype = "" + local profile = "" + local cprofile = "" + local res = {} + + -- Used by config for loolup and Titan for current toon + if get_me == nil then + get_me = TitanUtils_GetPlayer() + end + + local sync = TitanSettings.Players[get_me].Panel["SyncWithProfile"] + local play = get_me --TitanUtils_GetPlayer() + + -- see if sync is set + if (sync == Titan_Global.profile.NONE) then + -- Use the current player + ptype = Titan_Global.profile.TOON + profile = play + cprofile = TitanUtils_GetHexText(profile, Titan_Global.colors.gold) + else + -- use the sync as set + ptype = Titan_Global.profile.SYNC + profile = sync + cprofile = TitanUtils_GetHexText(profile, Titan_Global.colors.green) + end + + local str = "_GetProfile" + .." "..tostring(ptype).."" + .." '"..tostring(cprofile).."'" + .." s'"..tostring(sync).."'" + .." t'"..tostring(play).."'" + Titan_Debug.Out('titan', 'profile', str) + + res.ptype = ptype + res.pname = profile + res.cname = cprofile + res.sync = sync + return res +end + +---Set the profile per user settings +---@param set_me? string +---@param ptype string +---@param to_profile string +function TitanUtils_SetProfile(set_me, ptype, to_profile) + local str = "_SetProfile" + .." ["..tostring(set_me).."]" + .." "..tostring(ptype).."" + .." to '"..tostring(to_profile).."'" + Titan_Debug.Out('titan', 'profile', str) + + if ptype == Titan_Global.profile.SYNC then + TitanSettings.Players[set_me].Panel["SyncWithProfile"] = to_profile + else + -- just current toon + end +end + -------------------------------------------------------------- -- Various debug routines --[[ diff --git a/Titan/TitanVariables.lua b/Titan/TitanVariables.lua index a43d491..15d04f7 100644 --- a/Titan/TitanVariables.lua +++ b/Titan/TitanVariables.lua @@ -544,22 +544,33 @@ TitanPluginExtrasNum = 0 -- Global to hold where the Titan menu orginated from... TitanPanel_DropMenu = nil -local Default_Plugins = { - { id = "Location", loc = "Bar" }, - { id = "XP", loc = "Bar" }, - { id = "Gold", loc = "Bar" }, - { id = "Clock", loc = "Bar" }, - { id = "Volume", loc = "Bar" }, - { id = "AutoHide_Bar", loc = "Bar" }, - { id = "Bag", loc = "Bar" }, - { id = "Repair", loc = "Bar" }, -} --[===[ Var TITAN_PANEL_SAVED_VARIABLES table holds the Titan Panel Default SavedVars. --]===] +-- These two MUST be in sync, same number of entries +local Default_Buttons = { + "Location", + "XP", + "Gold", + "Clock", + "Volume", + "AutoHide_Bar", + "Bag", + "Repair", +} +local Default_Button_Locs = { + "Bar", + "Bar", + "Bar", + "Bar", + "Bar", + "Bar", + "Bar", + "Bar", +} TITAN_PANEL_SAVED_VARIABLES = { - Buttons = {}, - Location = {}, + Buttons = Default_Buttons, + Location = Default_Button_Locs, TexturePath = "Interface\\AddOns\\Titan\\Artwork\\", Transparency = 0.7, AuxTransparency = 0.7, @@ -583,8 +594,8 @@ TITAN_PANEL_SAVED_VARIABLES = { VersionShown = 1, ToolTipsShown = 1, HideTipsInCombat = false, --- HideBarsInCombat = false, -- removed for 8.4.0 Sep 2025 --- HideBarsInPVP = false, -- removed for 8.4.0 Sep 2025 + -- HideBarsInCombat = false, -- removed for 8.4.0 Sep 2025 + -- HideBarsInPVP = false, -- removed for 8.4.0 Sep 2025 -- Classic ScreenAdjust = false, AuxScreenAdjust = false, @@ -608,6 +619,8 @@ TITAN_PANEL_SAVED_VARIABLES = { AuxBar2_Hide = false, AuxBar2_Transparency = 0.7, AuxBar2_Align = TITAN_PANEL_BUTTONS_ALIGN_LEFT, + -- + SyncWithProfile = "<>" -- new Oct 2025 }; --[===[ Var @@ -734,47 +747,6 @@ print("_sync" end end ----local Set the plugins (if registered) ----@param reset boolean ---- - true : Use Titan default ---- - false : Use current profile -local function Plugin_settings(reset) - --[[ -- It is assumed this is a plugin wipe of the given profile. -- Use the default Titan plugin list to display on the given bar. -- These will be saved on exit or reload in the given profile. ---]] - local plugin_list = {} - if reset then -- use the default install list - plugin_list = Default_Plugins - --[[ -print("plugins init" -.." "..tostring(reset).."" -) ---]] - else -- use the current profile - plugin_list = TitanPanelSettings.Buttons - end - - -- Init each and every default plugin - for idx, default_plugin in pairs(plugin_list) do - local id = default_plugin.id - local loc = default_plugin.loc - local plugin = TitanUtils_GetPlugin(id) --- TitanDebug("Plugin: "..tostring(id).." "..(plugin and "T" or "F")) - -- See if plugin is registered - if (plugin) then --- TitanDebug("__Plugin: "..tostring(id).." "..tostring(loc)) - -- Synchronize registered and saved variables - TitanPluginSettings[id] = {} - TitanVariables_SyncRegisterSavedVariables( - plugin.savedVariables, TitanPluginSettings[id]) - TitanUtils_AddButtonOnBar(loc, id) - TitanPanelButton_UpdateButton(id) - end - end -end - ---local Set the plugins (if registered) per the curent profile. local function TitanVariables_PluginSettingsInit() --[[ @@ -941,25 +913,74 @@ local function Titan_SyncAdjList() end end ----Titan Ensure TitanSettings (one of the saved vars in the toc) exists and set the Titan version. ---- Called when Titan is loaded (ADDON_LOADED event) -function TitanVariables_InitTitanSettings() - local player = TitanUtils_GetPlayer() - Titan_Debug.Out('titan', 'profile', "_Init begin " .. tostring(player)) +---local Set the Titan bar settings of the given profile from saved variables +---@param to_profile string +--- If no profile found, use Titan defaults +local function Set_bar_vars(to_profile) + local str = "" -- for debug output + + if TitanSettings.Players[to_profile].BarVars == nil then + -- Likely a new toon or new to Titan so just get defaults. + -- build debug output + str = "Set_bar_vars init" + .. " " .. tostring(to_profile) .. "" + Titan_Debug.Out('titan', 'profile', str) + + -- Set to defaults + TitanSettings.Players[to_profile].BarVars = TitanBarVarsDefaults + local BV = TitanSettings.Players[to_profile].BarVars + + -- Cannot assume profile is current / cannot use Get Var routines. + local panel = TitanSettings.Players[to_profile].Panel + + local tex = panel["TexturePath"]:gsub("TitanClassic", "Titan") -- hold over, just in case... + Titan_Debug.Out('titan', 'profile', "tex path '" .. tex .. "'") + + for idx, v in pairs(TitanBarData) do + if v.user_move == false then + -- Set original Bar options from the 'old' saved vars location + BV[idx].show = panel[v.name .. "_Show"] + BV[idx].auto_hide = panel[v.name .. "_Hide"] + BV[idx].align = panel[v.name .. "_Align"] + -- only skins before 7.x + BV[idx].texure = Titan_Global.SKIN + BV[idx].skin.alpha = panel[v.name .. "_Transparency"] + BV[idx].skin.path = tex + end + end + else + -- All good + -- build debug output + str = "Set_bar_vars found" + .. " " .. tostring(to_profile) .. "" + Titan_Debug.Out('titan', 'profile', str) + end +end +local function Check_Titan_settings() + -- ==== Ensure Titan level settings are whole if (TitanSettings) then -- all is good else + -- empty saved vars. New install or wipe TitanSettings = {} - Titan_Debug.Out('titan', 'profile', "TitanSettings {}") + Titan_Debug.Out('titan', 'profile', "TitanSettings {}") end -- check for player list per issue #745 if TitanSettings.Players then -- all is good else - TitanSettings.Players = {} -- empty saved vars. New install or wipe - Titan_Debug.Out('titan', 'profile', "TitanSettings.Players {}") + TitanSettings.Players = {} + Titan_Debug.Out('titan', 'profile', "TitanSettings.Players {}") + end + -- ==== At minimum, THIS toon must exist + local profile = TitanUtils_GetPlayer() -- only need profile + if TitanSettings.Players[profile] == nil then + TitanSettings.Players[profile] = {} + -- = TitanBarVarsDefaults + else + -- exists, good end if (TitanAll) then @@ -967,34 +988,108 @@ function TitanVariables_InitTitanSettings() else TitanAll = {} end +end - Titan_Debug.Out('titan', 'profile', "Sync Titan Panel saved variables with TitanAll") - TitanVariables_SyncRegisterSavedVariables(TITAN_ALL_SAVED_VARIABLES, TitanAll) - Titan_Debug.Out('titan', 'profile', "> Sync Done") +--- Ensure the given toon is ready to accept profile values; sync to defaults +---@param toon string Toon name <name>@<server> +---@param toon_table table From TitanSettings (saved vars) +local function Check_toon_settings(toon, toon_table) + local v = toon_table + local str = "" + + if TitanSettings.Players[toon] == nil + or TitanSettings.Players[toon] == {} then + -- build debug output + str = "Init_player_settings" + .. " " .. tostring("TitanSettings.Players[] {}") .. "" + Titan_Debug.Out('titan', 'profile', str) + + -- Create the bare player tables so profile(s) can be added + TitanSettings.Players[toon] = {} + + -- ptr changed + v = TitanSettings.Players[toon] + else + -- all is good + -- build debug output + str = "Init_player_settings" + .. " " .. tostring("TitanSettings.Players[] ") .. "" + .. " " .. tostring(toon) .. "" + Titan_Debug.Out('titan', 'profile', str) + end + + -- The saved vars were grown organically over years making this section piece meal + Titan_Debug.Out('titan', 'profile', "Sync " .. toon .. " toon defaults (Panel)(BarVars)") + if v["Panel"] then + -- exists + else + v["Panel"] = {} + end + -- Note: the sync routine only ensures first level, NOT recursive + TitanVariables_SyncRegisterSavedVariables(TITAN_PANEL_SAVED_VARIABLES, v["Panel"]) - Titan_Debug.Out('titan', 'profile', "_Init end " .. tostring(player)) - -- Current Titan list known - all toons player has profiles for + -- ====== New Mar 2023 : TitanSettings.Players[player].BarData to hold Short bar data + Set_bar_vars(toon) + + -- These are dynamically filled, just make sure the entry exists + if v.Plugins then + -- exists + else + v.Plugins = {} + end + if v.Register then + -- exists + else + v.Register = {} + end + if v.Adjust then -- New May 2023 + -- exists + else + v.Adjust = {} + end + + -- Toon is now ready to accept profile values +end + +---Titan Ensure TitanSettings (one of the saved vars in the toc) exists and set the Titan version. +--- Called early when processing PLAYER_ENTERING_WORLD event) +function TitanVariables_InitTitanSettings() + local player = TitanUtils_GetPlayer() + Titan_Debug.Out('titan', 'profile', "_Init begin " .. tostring(player)) + + -- ==== Ensure Titan level settings are whole and contain this toon at min + Check_Titan_settings() + + Titan_Debug.Out('titan', 'profile', "Sync TitanAll defaults") + TitanVariables_SyncRegisterSavedVariables(TITAN_ALL_SAVED_VARIABLES, TitanAll) + -- Titan_Debug.Out('titan', 'profile', "> Sync Done") + + -- ==== Create Titan toon list and ensure settings are whole. -- Sort in alphabetical order. + -- Sync *each* toon with defaults to ensure latest data changes are applied. -- Used for menus. - Titan_Global.players = {} + local str = "" for idx, v in pairs(TitanSettings.Players) do - table.insert(Titan_Global.players, idx) + if type(idx) == string then -- for sanity and IDE + table.insert(Titan_Global.players, idx) + end + + -- Sync with defaults - in case of changed defaults + -- New Oct 2025 : All toons instead of current toon (Init_player_settings) + Titan_Debug.Out('titan', 'profile', "Sync " .. idx .. " toon defaults (Panel)(BarVars)") + Check_toon_settings(idx, v) end table.sort(Titan_Global.players, function(a, b) return a < b end) - --[===[ -for idx = 1, #Titan_Global.players do - print("["..idx.."] : '"..Titan_Global.players[idx].."'") -end ---]===] TitanSettings.Version = TITAN_VERSION; + + Titan_Debug.Out('titan', 'profile', "_Init end " .. tostring(player)) end ---Titan Update local and saved vars to new bar position per user or reset to default ---- Called when Titan is loaded (ADDON_LOADED event) ---@param self table Bar frame ---@param reset boolean Set to default position ---@param x_off? number Set to X @@ -1062,50 +1157,6 @@ local function deepcopy(orig) return copy end ----local Set the Titan bar settings of the given profile from saved variables ----@param to_profile string ---- If no profile found, use Titan defaults -local function Set_bar_vars(to_profile) - local str = "" -- for debug output - - if TitanSettings.Players[to_profile].BarVars then - -- All good - -- build debug output - str = "Set_bar_vars found" - .." "..tostring(to_profile).."" - Titan_Debug.Out('titan', 'profile', str) - else - -- Likely a new toon or new to Titan so just get defaults. - -- build debug output - str = "Set_bar_vars init" - .." "..tostring(to_profile).."" - Titan_Debug.Out('titan', 'profile', str) - - -- Set to defaults - TitanSettings.Players[to_profile].BarVars = TitanBarVarsDefaults - local BV = TitanSettings.Players[to_profile].BarVars - - -- Cannot assume profile is current / cannot use Get Var routines. - local panel = TitanSettings.Players[to_profile].Panel - - local tex = panel["TexturePath"]:gsub("TitanClassic", "Titan") -- hold over, just in case... - Titan_Debug.Out('titan', 'profile', "tex path '" .. tex .. "'") - - for idx, v in pairs(TitanBarData) do - if v.user_move == false then - -- Set original Bar options from the 'old' saved vars location - BV[idx].show = panel[v.name .. "_Show"] - BV[idx].auto_hide = panel[v.name .. "_Hide"] - BV[idx].align = panel[v.name .. "_Align"] - -- only skins before 7.x - BV[idx].texure = Titan_Global.SKIN - BV[idx].skin.alpha = panel[v.name .. "_Transparency"] - BV[idx].skin.path = tex - end - end - end -end - ---local Use the Titan settings, the plugin settings, the 'extras' data of the given profile. ---@param from_profile string? ---@param to_profile string @@ -1114,14 +1165,14 @@ end --- Create the "to" profile if it does not exist. local function Init_player_settings(from_profile, to_profile, action) --[[ -- Called at PLAYER_ENTERING_WORLD event after we know Titan has registered plugins. +- Called at PLAYER_ENTERING_WORLD event after Titan has registered plugins. - There are 3 actions: USE, RESET, and INIT - USE: From: the user chosen profile - To: Player or Global profile + To: Player or profile - RESET: From: Titan defaults - To: Player or Global profile + To: Player or profile - INIT: From: saved variables of that profile To: Player or Global profile @@ -1132,83 +1183,47 @@ local function Init_player_settings(from_profile, to_profile, action) local old_plugins = {} local reset = (action == TITAN_PROFILE_RESET) - str = "Init_player_settings" - .. " from: " .. tostring(from_profile) .. "" - .. " to: " .. tostring(to_profile) .. "" - .. " action: " .. tostring(action) .. "" - Titan_Debug.Out('titan', 'profile', str) + str = "Init_player_settings" + .. " from: " .. tostring(from_profile) .. "" + .. " to: " .. tostring(to_profile) .. "" + .. " action: " .. tostring(action) .. "" + Titan_Debug.Out('titan', 'profile', str) CleanupProfile() -- hide currently shown plugins if reset then - -- ensure the rpofile is rebuilt with defaults + -- ensure the profile is rebuilt with defaults TitanSettings.Players[to_profile] = nil else -- proceed end - + -- === Ensure we have a place to store profile, could be new toon or new install - if TitanSettings.Players[to_profile] == nil - or TitanSettings.Players[to_profile] == {} then - -- build debug output - str = "Init_player_settings" - .." "..tostring("TitanSettings.Players[] {}").."" - Titan_Debug.Out('titan', 'profile', str) + Check_toon_settings(to_profile, TitanSettings.Players[to_profile]) - -- Create the bare player tables so profile(s) can be added - TitanSettings.Players[to_profile] = {} - TitanSettings.Players[to_profile].Plugins = {} - TitanSettings.Players[to_profile].Panel = TITAN_PANEL_SAVED_VARIABLES - TitanSettings.Players[to_profile].Panel.Buttons = {} - TitanSettings.Players[to_profile].Panel.Location = {} - TitanPlayerSettings = {} - TitanPlayerSettings["Plugins"] = {} - TitanPlayerSettings["Panel"] = {} - TitanPlayerSettings["Register"] = {} - TitanPlayerSettings["BarVars"] = TitanBarVarsDefaults -- New Mar 2023 - TitanPlayerSettings["Adjust"] = {} -- New May 2023 - else - -- all is good - -- build debug output - str = "Init_player_settings" - .." "..tostring("TitanSettings.Players[] ").."" - .." "..tostring(to_profile).."" - Titan_Debug.Out('titan', 'profile', str) - end - -- Set global variables + -- Set variables used to reference this profile TitanPlayerSettings = TitanSettings.Players[to_profile]; TitanPluginSettings = TitanPlayerSettings["Plugins"]; TitanPanelSettings = TitanPlayerSettings["Panel"]; - TitanVariables_SyncRegisterSavedVariables(TitanBarVarsDefaults, TitanPlayerSettings["BarVars"]) + -- TitanVariables_SyncRegisterSavedVariables(TitanBarVarsDefaults, TitanPlayerSettings["BarVars"]) -- ====== New May 2023 : Back to adjusting a couple frames per user settings - -- Could be new toon / ... - if TitanPlayerSettings["Adjust"] then - -- No action needed - else - TitanPlayerSettings["Adjust"] = {} - end TitanAdjustSettings = TitanPlayerSettings["Adjust"] Titan_SyncAdjList() -- The player settings are known, init the adjustable frames for idx, v in pairs(Titan_Global.AdjList) do TitanPanel_AdjustFrameInit(idx) end - -- ====== - -- ====== New Mar 2023 : TitanSettings.Players[player].BarData to hold Short bar data - Set_bar_vars(to_profile) -- ====== - -- === if action == TITAN_PROFILE_RESET then - -- default is global profile OFF TitanAll = {} TitanVariables_SyncRegisterSavedVariables(TITAN_ALL_SAVED_VARIABLES, TitanAll) elseif action == TITAN_PROFILE_INIT then -- elseif action == TITAN_PROFILE_USE then - -- Copy from the from_profile to profile - not anything in saved vars + -- Copy the from_profile to profile - not anything in saved vars if from_profile and TitanSettings.Players[from_profile] then old_player = TitanSettings.Players[from_profile] @@ -1220,10 +1235,9 @@ local function Init_player_settings(from_profile, to_profile, action) old_plugins = old_player["Plugins"] end - -- Ensure the old profile Bar data is whole... - Set_bar_vars(from_profile) + -- Get the profile Bar data... TitanSettings.Players[to_profile]["BarVars"] = deepcopy(old_player["BarVars"]) ---[[ + --[[ if Titan_Global.titan.profile then -- Apply the new bar positions for idx, v in pairs(TitanBarData) do @@ -1250,24 +1264,20 @@ local function Init_player_settings(from_profile, to_profile, action) end TitanBarDataVars = TitanPlayerSettings["BarVars"] -- works here, after setting BarVars + -- build debug output + str = "Init_player_settings" + .. " " .. tostring("BarVars now set") .. "" + Titan_Debug.Out('titan', 'profile', str) + + if (TitanPlayerSettings) then -- build debug output str = "Init_player_settings" - .." "..tostring("BarVars now set").."" + .. " " .. tostring("_SyncPluginSettings") .. "" Titan_Debug.Out('titan', 'profile', str) - - if (TitanPlayerSettings) then - -- build debug output - str = "Init_player_settings" - .." "..tostring("_SyncPluginSettings").."" - Titan_Debug.Out('titan', 'profile', str) -- Synchronize plugin settings with plugins that were registered TitanVariables_SyncPluginSettings() -- Display the plugins the user selected AND are registered - if reset then - Plugin_settings(reset) - else - TitanVariables_PluginSettingsInit() - end + TitanVariables_PluginSettingsInit() end TitanSkins = TitanVariables_SyncSkins() @@ -1275,15 +1285,7 @@ local function Init_player_settings(from_profile, to_profile, action) Set_Timers(reset) -- for debug if a user needs to send in the Titan saved vars - if TitanPlayerSettings["Register"] then - -- From WoW saved vars - else - -- New install or after reset - TitanPlayerSettings["Register"] = {} - end TitanPanelRegister = TitanPlayerSettings["Register"] - - TitanSettings.Profile = to_profile end ---API Get the value of the requested plugin variable. @@ -1438,35 +1440,72 @@ function TitanVariables_SetPanelStrata(value) end end +local function Check_sync_profile(profile) + local str = "" -- for debug output if requested + local from_profile = nil + -- Assuming the var is set per prior init routines!! + local sync = TitanSettings.Players[profile].Panel.SyncWithProfile + + if sync == Titan_Global.profile.NONE then + from_profile = profile -- no sync, use given profile + else + from_profile = sync -- use the sync profile, not the one passed + end + + str = "_sync_profile" + .. " " .. tostring(profile) .. "" + .. " >> '" .. tostring(from_profile) .. "'" + Titan_Debug.Out('titan', 'profile', str) + + return from_profile +end + ---Titan Set the Titan variables and plugin variables to the passed in profile. --- Called from the Titan right click menu ---- profile is compared as 'lower' so the case of profile does not matter ----@param profile? string name ----@param action string Use | Reset -function TitanVariables_UseSettings(profile, action) +--- profile is compared using 'lower' so the case does not matter +---@param from? string profile to copy from +---@param profile string required: profile to use, may not be player! +---@param action string Use | Reset | Init +function TitanVariables_UseSettings(from, profile, action) local str = "" -- for debug output if requested - local _ = nil -- for scope; do not care about this value + local _ = nil -- for scope; do not care about this value - local from_profile = nil - if action == TITAN_PROFILE_USE then -- needed? - -- Grab the old profile currently in use - from_profile = profile or nil - end + -- Oct 2025 : + -- Added 'from' to be explicit when needing a source profile + -- profile param is now required and represents the target profile + -- The target profile could be overridden by 'sync with' feature - local glob, name, player, server = TitanUtils_GetGlobalProfile() + local from_profile = from - -- Get the profile according to the user settings and choices - if action == TITAN_PROFILE_RESET then - -- Use current toon; reset will clear global for ALL toons - profile, _, _ = TitanUtils_GetPlayer() + str = "_UseSettings" + .. " " .. tostring(action) .. "" + .. " : '" .. tostring(from) .. "'" + .. " > '" .. tostring(profile) .. "'" + Titan_Debug.Out('titan', 'profile', str) + + -- ==== Determine the profile to use based on action + + -- User setting 'sync with' will cause profile to change to the user selected sync. + if action == TITAN_PROFILE_USE then + -- Will copy profile to current toon + -- Assumed to be NOT nil! + profile = Check_sync_profile(profile) + elseif action == TITAN_PROFILE_RESET then + -- Nuke given profile to defaults + -- Reset will clear global for ALL toons else - if glob then - -- Use global toon per user setting - profile = name - else - -- Use current toon; each toon is unique + -- action == TITAN_PROFILE_INIT + -- OR something bad; use curent toon + if profile == nil then + -- Likely login of current toon profile, _, _ = TitanUtils_GetPlayer() + else + -- Use what was given end + str = "_UseSettings - init check" + .. " for '" .. tostring(profile) .. "'" + Titan_Debug.Out('titan', 'profile', str) + profile = Check_sync_profile(profile) end -- Find the profile in a case insensitive manner @@ -1478,18 +1517,16 @@ function TitanVariables_UseSettings(profile, action) end end if new_profile == "" then - -- Assume we need the current player + -- new toon to Titan; needs to be created new_profile = TitanUtils_GetPlayer() --TitanSettings.Player - -- And it needs to be created action = TITAN_PROFILE_RESET end -- Now that we know what profile to use - act on the data - -- build debug output str = "_UseSettings" - .." "..tostring(action).."" - .." from '"..tostring(from_profile).."'" - .." to '"..tostring(new_profile).."'" + .. " " .. tostring(action) .. "" + .. " from '" .. tostring(from_profile) .. "'" + .. " to '" .. tostring(new_profile) .. "'" Titan_Debug.Out('titan', 'profile', str) Init_player_settings(from_profile, new_profile, action) @@ -1497,15 +1534,15 @@ function TitanVariables_UseSettings(profile, action) TitanVariables_SetPanelStrata(TitanPanelGetVar("FrameStrata")) -- show the new profile - -- build debug output - str = "...init bars" - .." "..tostring(action).."" - Titan_Debug.Out('titan', 'profile', str) + -- build debug output + str = "...init bars" + .. " " .. tostring(action) .. "" + Titan_Debug.Out('titan', 'profile', str) TitanPanel_InitPanelBarButton("UseSettings"); - -- build debug output - str = "...init plugins on bars" - .." "..tostring(action).."" - Titan_Debug.Out('titan', 'profile', str) + -- build debug output + str = "...init plugins on bars" + .. " " .. tostring(action) .. "" + Titan_Debug.Out('titan', 'profile', str) TitanPanel_InitPanelButtons(); end diff --git a/Titan/_TitanIDE.lua b/Titan/_TitanIDE.lua index 2d407ba..9a231df 100644 --- a/Titan/_TitanIDE.lua +++ b/Titan/_TitanIDE.lua @@ -1,226 +1,246 @@ ---[===[ File - This file is NOT to be included in the TOC file! - This is intended for IDE Intellisense. ---]===] - ---[[ IDE - This file is NOT to be included in the TOC file! - This is intended to be used for IDE Intellisense. - - Tools used: - Visual Studio Code - https://code.visualstudio.com/ - Other IDEs accept Lua Language Server, see if your prefered IDE will accept LLS - - Lua Language Server (LLS) - https://marketplace.visualstudio.com/items?itemName=sumneko.lua - https://github.com/LuaLS/lua-language-server - WoW API - LLS extension - https://marketplace.visualstudio.com/items?itemName=ketho.wow-api - https://github.com/Ketho/vscode-wow-api - - This file is to remove errors and warnings thrown by the tools used. - It declares variables and tables : - - That are not readily available to the IDE - - That are declared via indirection as the drop down lib is - - When Lua 'best practice' parser is stricter than Lua is - - When Titan is checking for an addon the user may or may not have loaded - - Titan may contain IDE annotations. - These are ---@<tag> to help the parser understand the intent of the code. - - Some Titan files may contain lines beginning with ----@diagnostic - These remove LLS errors where - - Titan is handling Classic versions that use deprecated routines - - Possibly the WoW extension is out of date or the Blizz documentation is wrong - - Note the diagnostic could be by line, file, or workspace / project. ---]] - --- Use Linux command below to get a rough line count of a Titan release. --- find . -wholename "*.tga" -prune -o -wholename "*.code*" -prune -o -wholename "*.blp" -prune -o -wholename "*/libs/*" -prune -o -wholename "*/Artwork/*" -prune -o -print | xargs wc -l - ---====== Frames from Titan Template XML -TitanPanelButtonTemplate = {} -TitanPanelTextTemplate = {} -TitanPanelIconTemplate = {} -TitanPanelComboTemplate = {} -TitanOptionsSliderTemplate = {} -TitanPanelTooltip = {} -TitanPanelBarButtonHiderTemplate = {} -TitanPanelBarButton = {} -Titan_Bar__Display_Template = {} - ---====== Frames from Titan XML -TitanPanelTopAnchor = {} -TitanPanelBottomAnchor = {} - ---====== Frames from Titan plugins created in XML or in Titan code -TitanPanelAmmoButton = {} - -TitanRepairTooltip = {} - -TitanPanelLocationButton = {} -TitanMapPlayerLocation = {} -TitanMapCursorLocation = {} - -TitanPanelLootTypeFrame = {} -TitanPanelLootTypeButton = {} -TitanPanelLootTypeMainWindow = {} -TitanPanelLootTypeFrameClearButton = {} -TitanPanelLootTypeFrameAnnounceButton = {} -TitanPanelLootTypeFrameNotRolledButton = {} -TitanPanelLootTypeFrameRollButton = {} -TitanPanelLootTypeFramePassButton = {} -RollTrackerRollText = {} -TitanPanelLootTypeFrameStatusText = {} -TitanPanelLootTypeFrameHelperButton = {} -TitanPanelLootTypeMainWindowTitle = {} - -TitanPanelPerfControlFrame = {} - -TitanPanelMasterVolumeControlSlider = {} -TitanPanelAmbienceVolumeControlSlider = {} -TitanPanelDialogVolumeControlSlider = {} -TitanPanelSoundVolumeControlSlider = {} -TitanPanelMusicVolumeControlSlider = {} - -TitanPanelXPButton = {} -TitanPanelXPButtonIcon = {} - ---====== Libs that may exist or adjusting for libs -AceLibrary = {} - ----@class AceAddon - -AceHook = {} --- @param obj string | function The object or frame to unhook from --- @param method function The name of the method, function or script to unhook from. -function AceHook:IsHooked(obj, method) - -- Ace does a parameter shift if obj is a string - -- But the param does not reflect this... -end - ---====== WoW localized globals --- Should be handled by the WoW extension -ACCOUNT_QUEST_LABEL = "" -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon -ACCOUNT_BANK_PANEL_TITLE = "" -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon - ---====== WoW frames -PetActionBarFrame = {} -StanceBarFrame = {} -PossessBarFrame = {} -MinimapBorderTop = {} -MinimapZoneTextButton = {} -MiniMapWorldMapButton = {} -VideoOptionsFrame = {} - ----@class FrameSizeBorder - ---====== WoW tables or routines -UIPARENT_MANAGED_FRAME_POSITIONS = {} -FCF_UpdateDockPosition = {} -TargetFrame_Update = {} -VideoOptionsFrameOkay_OnClick = {} - -C_Bank = {} -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon - - ---====== Convince IDE we know what we are doing --- Lua allows table updates but the IDE complains about 'injecting' a field it does not know about. --- Adding a function or variable to a frame in this case. - ----@class UIParent WoW frame ----@field GetScale function WoW region routine - ----@class Frame frame for a Titan template ----@field showTimer number time to close in seconds ----@field isCounting number | nil 1 or nil ----@field parent table | nil Anchor tooltip - ---====== Plugin frames from Template XML --- These fields are used by Titan to store plugin info. --- This can avoid 'convoluted' lookups and be faster. --- ----@class Button Plugin frame from a Titan template ----@field TitanLDBSetOwnerPosition function Anchor tooltip ----@field TitanLDBSetTooltip function Fill tooltip ----@field TitanLDBHandleScripts function Set frame scripts ----@field TitanLDBTextUpdate function Update plugin text ----@field TitanLDBIconUpdate function Update plugin icon ----@field TitanLDBCreateObject function Create plugin ----@field TitanCreatedBy string Only LDB ATM ----@field TitanType string Not used ATM ----@field TitanName string Used for LDB name / id ----@field TitanAction string Not used ATM ----@field bar_name string Used by auto hide built-in ----@field registry table Any Titan plugin (built-in; third party; or LDB) ----@field tooltipText string Titan text for the tool tip ----@field RequestTimePlayed table Override default - XP ----@field TIME_PLAYED_MSG table Override default - XP ----@field short_name string Placeholder for short bar name ----@field RegisterForClicks function Variable params missed by VS Code plugin - --- Ace references -AceGUIWidgetLSMlists = {} - ---====== Ace Drop down menu -L_UIDROPDOWNMENU_MENU_LEVEL = 1 -L_UIDROPDOWNMENU_MENU_VALUE = 1 - ---====== WoW Drop down menu -UIDROPDOWNMENU_MENU_VALUE = 1 - ----@class LibUIDropDownMenu ----@field UIDropDownMenu_InitializeHelper function ----@field Create_UIDropDownMenu function ----@field UIDropDownMenu_Initialize function ----@field UIDropDownMenu_SetInitializeFunction function ----@field UIDropDownMenu_SetDisplayMode function ----@field UIDropDownMenu_RefreshDropDownSize function ----@field UIDropDownMenu_StartCounting function ----@field UIDropDownMenu_StopCounting function ----@field UIDropDownMenu_CreateInfo function ----@field UIDropDownMenu_CreateFrames function ----@field UIDropDownMenu_AddSeparator function ----@field UIDropDownMenu_AddSpace function ----@field UIDropDownMenu_AddButton function ----@field UIDropDownMenu_CheckAddCustomFrame function ----@field UIDropDownMenu_RegisterCustomFrame function ----@field UIDropDownMenu_GetMaxButtonWidth function ----@field UIDropDownMenu_GetButtonWidth function ----@field UIDropDownMenu_Refresh function ----@field UIDropDownMenu_RefreshAll function ----@field UIDropDownMenu_SetIconImage function ----@field UIDropDownMenu_SetSelectedName function ----@field UIDropDownMenu_SetSelectedValue function ----@field UIDropDownMenu_GetSelectedName function ----@field UIDropDownMenu_GetSelectedID function ----@field UIDropDownMenu_SetSelectedID function ----@field UIDropDownMenu_GetSelectedValue function ----@field HideDropDownMenu function ----@field ToggleDropDownMenu function ----@field CloseDropDownMenus function ----@field UIDropDownMenu_SetWidth function ----@field UIDropDownMenu_SetButtonWidth function ----@field UIDropDownMenu_SetText function ----@field UIDropDownMenu_GetText function ----@field UIDropDownMenu_ClearAll function ----@field UIDropDownMenu_JustifyText function ----@field UIDropDownMenu_SetAnchor function ----@field UIDropDownMenu_GetCurrentDropDown function ----@field UIDropDownMenuButton_GetChecked function ----@field UIDropDownMenuButton_GetName function ----@field UIDropDownMenuButton_OpenColorPicker function ----@field UIDropDownMenu_DisableButton function ----@field UIDropDownMenu_EnableButton function ----@field UIDropDownMenu_SetButtonText function ----@field UIDropDownMenu_SetButtonNotClickable function ----@field UIDropDownMenu_SetButtonClickable function ----@field UIDropDownMenu_DisableDropDown function ----@field UIDropDownMenu_EnableDropDown function ----@field UIDropDownMenu_IsEnabled function ----@field UIDropDownMenu_GetValue function ----@field OpenColorPicker function ----@field ColorPicker_GetPreviousValues function - - ---====== API routines +--[===[ File + This file is NOT to be included in the TOC file! + This is intended for IDE Intellisense. +--]===] + +--[[ IDE + This file is NOT to be included in the TOC file! + This is intended to be used for IDE Intellisense. + + These tools can make dev a lot easier. + Visual Studio Code - https://code.visualstudio.com/ + Other IDEs accept Lua Language Server, see if your prefered IDE will accept language servers. + + - Lua Language Server (LLS) : + https://marketplace.visualstudio.com/items?itemName=sumneko.lua + or https://github.com/LuaLS/lua-language-server + + - WoW API - LLS extension : + https://marketplace.visualstudio.com/items?itemName=ketho.wow-api + or https://github.com/Ketho/vscode-wow-api + + - WoW TOC can be useful : + - https://marketplace.visualstudio.com/items?itemName=stanzilla.vscode-wow-toc + + + And a tiny Python parser to pull these comments. + + Notes: + - The WoW API in both IDE plugins is geared to Retail. + - There is no option to automatically include 'Classic' deprecated routines. + - There are diagnostic annotations used to ignore some warnings. + - Ignore warning annotations were limited as much as practical to 'this line' to point out usage of Classic routines. + - Files or folders for the IDE such as .vscode; Titan.code-workspace; and others are included in the TItan release. + + + This file is to remove errors and warnings thrown by the Intellisense tools used. + It declares variables and tables : + - That are not readily available to the IDE + - That are declared via indirection as the drop down lib is + - When Lua Intellisense parser is stricter than Lua is + - When Titan is checking for an addon the user may or may not have loaded + + Titan may contain IDE annotations. + These are ---@<tag> to help the parser understand the intent of the code. + + Some Titan files may contain lines beginning with +---@diagnostic + These remove LLS errors where + - Titan is handling Classic versions that use deprecated routines + - Possibly the WoW extension is out of date or the Blizz documentation is wrong + + Note: the diagnostic could be by line, file, or workspace / project. +--]] + +-- Use Linux command below to get a rough line count of a Titan release. +-- find . -wholename "*.tga" -prune -o -wholename "*.code*" -prune -o -wholename "*.blp" -prune -o -wholename "*/libs/*" -prune -o -wholename "*/Artwork/*" -prune -o -print | xargs wc -l + +-- Note: The IDE does not understand the frames and widgets relationship between XML and Lua. Declare UI objects defined in XML or Lua here. + +--====== Frames from Titan Template XML +TitanPanelButtonTemplate = {} +TitanPanelTextTemplate = {} +TitanPanelIconTemplate = {} +TitanPanelComboTemplate = {} +TitanOptionsSliderTemplate = {} +TitanPanelTooltip = {} +TitanPanelBarButtonHiderTemplate = {} +TitanPanelBarButton = {} +Titan_Bar__Display_Template = {} + +--====== Frames from Titan XML +TitanPanelTopAnchor = {} +TitanPanelBottomAnchor = {} + +--====== Frames from Titan plugins created in XML or in Titan code +TitanPanelAmmoButton = {} + +TitanRepairTooltip = {} + +TitanPanelLocationButton = {} +TitanMapPlayerLocation = {} +TitanMapCursorLocation = {} + +TitanPanelLootTypeFrame = {} +TitanPanelLootTypeButton = {} +TitanPanelLootTypeMainWindow = {} +TitanPanelLootTypeFrameClearButton = {} +TitanPanelLootTypeFrameAnnounceButton = {} +TitanPanelLootTypeFrameNotRolledButton = {} +TitanPanelLootTypeFrameRollButton = {} +TitanPanelLootTypeFramePassButton = {} +RollTrackerRollText = {} +TitanPanelLootTypeFrameStatusText = {} +TitanPanelLootTypeFrameHelperButton = {} +TitanPanelLootTypeMainWindowTitle = {} + +TitanPanelPerfControlFrame = {} + +TitanPanelMasterVolumeControlSlider = {} +TitanPanelAmbienceVolumeControlSlider = {} +TitanPanelDialogVolumeControlSlider = {} +TitanPanelSoundVolumeControlSlider = {} +TitanPanelMusicVolumeControlSlider = {} + +TitanPanelXPButton = {} +TitanPanelXPButtonIcon = {} + +--====== Libs that may exist or adjusting for libs +-- Ace lib references +AceLibrary = {} + +---@class AceAddon + +AceGUIWidgetLSMlists = {} + +AceHook = {} +-- @param obj string | function The object or frame to unhook from +-- @param method function The name of the method, function or script to unhook from. +function AceHook:IsHooked(obj, method) + -- Ace does a parameter shift if obj is a string + -- But the param does not reflect this... +end + +--====== WoW localized globals +-- Should be handled by the WoW extension +ACCOUNT_QUEST_LABEL = "" -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon +ACCOUNT_BANK_PANEL_TITLE = "" -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon +LABEL_NOTE = "" + +--====== WoW defined frames +PetActionBarFrame = {} +StanceBarFrame = {} +PossessBarFrame = {} +MinimapBorderTop = {} +MinimapZoneTextButton = {} +MiniMapWorldMapButton = {} +VideoOptionsFrame = {} + +---@class FrameSizeBorder + +--====== WoW tables or routines +UIPARENT_MANAGED_FRAME_POSITIONS = {} +FCF_UpdateDockPosition = {} +TargetFrame_Update = {} +VideoOptionsFrameOkay_OnClick = {} + +C_Bank = {} -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up soon + + +--====== Convince IDE we know what we are doing +-- Lua allows table updates but the IDE complains about 'injecting' a field it does not know about. +-- Adding a function or variable to a frame in this case. + +---@class UIParent WoW frame +---@field GetScale function WoW region routine + +---@class Frame frame for a Titan template +---@field showTimer number time to close in seconds +---@field isCounting number | nil 1 or nil +---@field parent table | nil Anchor tooltip + +--====== Plugin frames from Template XML +-- These fields are used by Titan to store plugin info. +-- This can avoid 'convoluted' lookups and be faster. +-- +---@class Button Plugin frame from a Titan template +---@field TitanLDBSetOwnerPosition function Anchor tooltip +---@field TitanLDBSetTooltip function Fill tooltip +---@field TitanLDBHandleScripts function Set frame scripts +---@field TitanLDBTextUpdate function Update plugin text +---@field TitanLDBIconUpdate function Update plugin icon +---@field TitanLDBCreateObject function Create plugin +---@field TitanCreatedBy string Only LDB ATM +---@field TitanType string Not used ATM +---@field TitanName string Used for LDB name / id +---@field TitanAction string Not used ATM +---@field bar_name string Used by auto hide built-in +---@field registry table Any Titan plugin (built-in; third party; or LDB) +---@field tooltipText string Titan text for the tool tip +---@field RequestTimePlayed table Override default - XP +---@field TIME_PLAYED_MSG table Override default - XP +---@field short_name string Placeholder for short bar name +---@field RegisterForClicks function Variable params missed by VS Code plugin + +--====== Ace Drop down menu +L_UIDROPDOWNMENU_MENU_LEVEL = 1 +L_UIDROPDOWNMENU_MENU_VALUE = 1 + +--====== WoW Drop down menu +UIDROPDOWNMENU_MENU_VALUE = 1 + +---@class LibUIDropDownMenu +---@field UIDropDownMenu_InitializeHelper function +---@field Create_UIDropDownMenu function +---@field UIDropDownMenu_Initialize function +---@field UIDropDownMenu_SetInitializeFunction function +---@field UIDropDownMenu_SetDisplayMode function +---@field UIDropDownMenu_RefreshDropDownSize function +---@field UIDropDownMenu_StartCounting function +---@field UIDropDownMenu_StopCounting function +---@field UIDropDownMenu_CreateInfo function +---@field UIDropDownMenu_CreateFrames function +---@field UIDropDownMenu_AddSeparator function +---@field UIDropDownMenu_AddSpace function +---@field UIDropDownMenu_AddButton function +---@field UIDropDownMenu_CheckAddCustomFrame function +---@field UIDropDownMenu_RegisterCustomFrame function +---@field UIDropDownMenu_GetMaxButtonWidth function +---@field UIDropDownMenu_GetButtonWidth function +---@field UIDropDownMenu_Refresh function +---@field UIDropDownMenu_RefreshAll function +---@field UIDropDownMenu_SetIconImage function +---@field UIDropDownMenu_SetSelectedName function +---@field UIDropDownMenu_SetSelectedValue function +---@field UIDropDownMenu_GetSelectedName function +---@field UIDropDownMenu_GetSelectedID function +---@field UIDropDownMenu_SetSelectedID function +---@field UIDropDownMenu_GetSelectedValue function +---@field HideDropDownMenu function +---@field ToggleDropDownMenu function +---@field CloseDropDownMenus function +---@field UIDropDownMenu_SetWidth function +---@field UIDropDownMenu_SetButtonWidth function +---@field UIDropDownMenu_SetText function +---@field UIDropDownMenu_GetText function +---@field UIDropDownMenu_ClearAll function +---@field UIDropDownMenu_JustifyText function +---@field UIDropDownMenu_SetAnchor function +---@field UIDropDownMenu_GetCurrentDropDown function +---@field UIDropDownMenuButton_GetChecked function +---@field UIDropDownMenuButton_GetName function +---@field UIDropDownMenuButton_OpenColorPicker function +---@field UIDropDownMenu_DisableButton function +---@field UIDropDownMenu_EnableButton function +---@field UIDropDownMenu_SetButtonText function +---@field UIDropDownMenu_SetButtonNotClickable function +---@field UIDropDownMenu_SetButtonClickable function +---@field UIDropDownMenu_DisableDropDown function +---@field UIDropDownMenu_EnableDropDown function +---@field UIDropDownMenu_IsEnabled function +---@field UIDropDownMenu_GetValue function +---@field OpenColorPicker function +---@field ColorPicker_GetPreviousValues function + + +--====== API routines diff --git a/Titan/_Titan_Lib_Notes.txt b/Titan/_Titan_Lib_Notes.txt index 9925a52..8bc9a4b 100644 --- a/Titan/_Titan_Lib_Notes.txt +++ b/Titan/_Titan_Lib_Notes.txt @@ -1,12 +1,15 @@ From: Ace3 - https://www.curseforge.com/wow/addons/ace3 -AceGUI-3.0-SharedMediaWidgets - https://www.curseforge.com/wow/addons/ace-gui-3-0-shared-media-widgets LibQTip-1.0 - https://www.curseforge.com/wow/addons/libqtip-1-0 -LibSharedMedia-3.0 - https://www.curseforge.com/wow/addons/libsharedmedia-3-0 +LibSharedMedia-3.0 - https://www.wowace.com/projects/libsharedmedia-3-0 : https://www.curseforge.com/wow/addons/libsharedmedia-3-0 *** 2025-May *** +- AceSerializer-3.0 taken from Release-r1349 2024-07-24 +- Dropped AceGUI-3.0-SharedMediaWidgets, not used + +*** 2025-Sep* - Dropped !LibUIDropDownMenu, again; updated wrappers to Blizz version LibUIDropDownMenu - https://www.curseforge.com/wow/addons/libuidropdownmenu diff --git a/Titan/locale/Localization.lua b/Titan/locale/Localization.lua index 83e7f8f..c395526 100644 --- a/Titan/locale/Localization.lua +++ b/Titan/locale/Localization.lua @@ -249,7 +249,6 @@ L["TITAN_PANEL_MENU_CENTER_TEXT"] = "Center Text"; L["TITAN_PANEL_MENU_CHANGE_HISTORY"] = "Recent Change History"; L["TITAN_PANEL_MENU_COMMAND"] = (COMMAND or "Command") L["TITAN_PANEL_MENU_CONFIGURATION"] = "Configuration"; -L["TITAN_PANEL_MENU_DELETE_SETTINGS"] = "Delete"; L["TITAN_PANEL_MENU_DISABLE_PUSH"] = "Disable Screen Adjust"; L["TITAN_PANEL_MENU_DISABLED"] = "Disabled"; L["TITAN_PANEL_MENU_DISPLAY_BAR"] = "Show Bar"; @@ -271,6 +270,8 @@ L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"] = "(In Combat)"; L["TITAN_PANEL_MENU_LDB_FORCE_LAUNCHER"] = "Force LDB Launchers to Right-Side"; L["TITAN_PANEL_MENU_LDB_SIDE"] = "Right-Side Plugin"; L["TITAN_PANEL_MENU_LOAD_SETTINGS"] = "Load"; +L["TITAN_PANEL_MENU_LOAD_SETTINGS_DESC"] = "Copy this profile into the current character."; +L["TITAN_PANEL_MENU_LOAD_SETTINGS_ERR1"] = "Load not allowed, same toon."; L["TITAN_PANEL_MENU_LOCK_BUTTONS"] = "Lock Buttons"; L["TITAN_PANEL_MENU_LSM_FONTS_DESC"] = "Select the font type for the various plugins on the "..TITAN_PANEL.." Bars."; L["TITAN_PANEL_MENU_LSM_FONTS"] = "Panel Font"; @@ -287,18 +288,31 @@ L["TITAN_PANEL_MENU_PLUGINS"] = "Plugins"; L["TITAN_PANEL_MENU_POSITION"] = "Position"; L["TITAN_PANEL_MENU_PROFILE_ALREADY_EXISTS"] = "The profile name entered already exists. Are you sure you want to overwrite it ? Push 'Accept' if yes, otherwise push 'Cancel' or the 'Escape' key."; L["TITAN_PANEL_MENU_PROFILE_CHARS"] = "Character"; +L["TITAN_PANEL_MENU_PROFILE_CLEAR_SYNC"] = "Clear Sync"; +L["TITAN_PANEL_MENU_PROFILE_CLEAR_SYNC_DESC"] = "Clear Sync to use profile of this toon."; L["TITAN_PANEL_MENU_PROFILE_CUSTOM"] = "Custom"; +L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS"] = "Delete"; +L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_DESC"] = "Delete this profile from the list."; +L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_ERR1"] = "Delete not allowed, used as Sync by another profile."; +L["TITAN_PANEL_MENU_PROFILE_DELETE_SETTINGS_ERR2"] = "Delete not allowed, cannot delete yourself."; L["TITAN_PANEL_MENU_PROFILE_DELETED"] = " has been deleted."; L["TITAN_PANEL_MENU_PROFILE_RELOADUI"] = "Your UI will now reload upon pushing 'Okay' to allow saving of your custom profile."; +L["TITAN_PANEL_MENU_PROFILE_RESET"] = "Reset Profile"; +L["TITAN_PANEL_MENU_PROFILE_RESET_DESC"] = "Reset just this profile to defaults."; +L["TITAN_PANEL_MENU_PROFILE_SAVE"] = "Save"; +L["TITAN_PANEL_MENU_PROFILE_SAVE_DESC"] = "Save this profile as a custom profile."; L["TITAN_PANEL_MENU_PROFILE_SAVE_CUSTOM_TITLE"] = "Enter a name for your custom profile:\n(20 chars max, no spaces allowed, case sensitive)"; L["TITAN_PANEL_MENU_PROFILE_SAVE_PENDING"] = "Current settings are to be saved under profile name: "; L["TITAN_PANEL_MENU_PROFILE_SERVERS"] = "Server"; +L["TITAN_PANEL_MENU_PROFILE_SYNC"] = "Sync"; +L["TITAN_PANEL_MENU_PROFILE_SYNC_DESC"] = "Sync this profile with current character. Changes on current character will be made to this profile."; +L["TITAN_PANEL_MENU_PROFILE_SYNC_ERR1"] = "Sync not allowed, cannot Sync to a toon that has a Sync."; +L["TITAN_PANEL_MENU_PROFILE_SYNC_ERR2"] = "Sync not allowed, cannot Sync to yourself."; L["TITAN_PANEL_MENU_PROFILE"] = "Profile "; L["TITAN_PANEL_MENU_PROFILES"] = "Profiles"; L["TITAN_PANEL_MENU_RELOADUI"] = "(Reload UI)"; L["TITAN_PANEL_MENU_RESET_POSITION"] = (RESET_POSITION or "Reset Position Only") L["TITAN_PANEL_MENU_RESET"] = "Reset "..TITAN_PANEL.." to Default"; -L["TITAN_PANEL_MENU_SAVE_SETTINGS"] = "Save"; L["TITAN_PANEL_MENU_SHOW_COLORED_TEXT"] = "Show Colored Text"; L["TITAN_PANEL_MENU_SHOW_ICON"] = "Show Icon"; L["TITAN_PANEL_MENU_SHOW_LABEL_TEXT"] = "Show Label Text"; diff --git a/TitanAmmo/TitanClassicAmmo.lua b/TitanAmmo/TitanClassicAmmo.lua index c271e7e..d83315d 100644 --- a/TitanAmmo/TitanClassicAmmo.lua +++ b/TitanAmmo/TitanClassicAmmo.lua @@ -1,489 +1,494 @@ ---[[ --- ************************************************************************** --- * TitanAmmo.lua --- * --- * By: Titan Panel Development Team --- ************************************************************************** --- 2024 Jan - Combined Classic Era and Wrath into one version --- 2019 Aug - reverted and updated for Classic --- --- This will track the count of ammo (bows and guns) or thrown (knives) equipped. --- Ammo is placed in the 'ammo' slot where Blizzard counts ALL of that *type of ammo* --- regardless of where it is in your bags. --- Thrown is placed in the actual display.weapon slot where Blizzard counts ALL of that *type of thrown*. --- This forces a different routine to be used so the ammo must always be checked for type and count. --- --- Note: Thrown has no durability. Not sure when Blizz implemented this ---]] --- ******************************** Constants ******************************* -local _G = getfenv(0); -local TITAN_AMMO_ID = "Ammo"; -local TITAN_BUTTON = "TitanPanel"..TITAN_AMMO_ID.."Button" - -local SHOOT_STACK = 200 -local ARROW_STACK = 200 -local THROW_STACK = 200 - -local LIM_GOOD = 2 -local LIM_OK = 1.5 -local LIM_BAD = .5 - -local game_version = select(4, GetBuildInfo()) - -local TITAN_AMMO_THRESHOLD_TABLE = { -- Use ammo stack and threshold limits above to calc colored text - ["INVTYPE_RANGEDRIGHT"] = { - Values = { SHOOT_STACK*LIM_BAD, SHOOT_STACK*LIM_OK, SHOOT_STACK*LIM_GOOD }, -- 100,150,400 - Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, - }, - ["INVTYPE_RANGED"] = { - Values = { ARROW_STACK*LIM_BAD, ARROW_STACK*LIM_OK, ARROW_STACK*LIM_GOOD }, -- 100,150,400 - Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, - }, - ["INVTYPE_THROWN"] = { - Values = { THROW_STACK/10, THROW_STACK/4, THROW_STACK/2 }, -- 20, 50, 100 - Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, - }, -}; - --- ******************************** Variables ******************************* -local ammoSlotID = GetInventorySlotInfo("AMMOSLOT") -local rangedSlotID = GetInventorySlotInfo("RANGEDSLOT") - --- Info to show on the plugin -local display = { - ammo_count = 0, - ammo_type = "", - ammo_name = "", -- L["TITAN_AMMO_BUTTON_NOAMMO"] - weapon = "", - weapon_type = "", - mismatch = false, - mismatch_text = "", - } - -local L = LibStub("AceLocale-3.0"):GetLocale("Titan", true) - -local debug_flow = false - ----@diagnostic disable-next-line: deprecated -local GetItem = C_Item.GetItemInfo or GetItemInfo -- For Classic versions - --- ******************************** Functions ******************************* ---[[ local --- ************************************************************************** --- NAME : debug_msg(Message) --- DESC : Debug function to print message to chat frame --- VARS : Message = message to print to chat frame --- ************************************************************************** ---]] -local function debug_msg(Message) - local msg = "" - local stamp = date("%H:%M:%S") -- date("%m/%d/%y %H:%M:%S") - local milli = GetTime() -- seconds with millisecond precision (float) - local milli_str = string.format("%0.2F", milli - math.modf(milli)) - msg = msg..TitanUtils_GetGoldText(stamp..milli_str.." "..TITAN_AMMO_ID..": ") - msg = msg..TitanUtils_GetGreenText(Message) - DEFAULT_CHAT_FRAME:AddMessage(msg) --- DEFAULT_CHAT_FRAME:AddMessage(TITAN_AMMO_ID..": " .. Message, 1.00, 0.49, 0.04) -end - -local function ClrAmmoInfo() - display.ammo_count = 0; - display.ammo_type = L["TITAN_AMMO_BUTTON_NOAMMO"] - display.ammo_name = "" - display.weapon = "" - display.weapon_type = "" - display.mismatch = false - display.mismatch_text = "" -end - -local function GetItemLink(rangedSlotID) - return GetInventoryItemLink("player", rangedSlotID) -end - -local function IsAmmoClass() - local class = select(2, UnitClass("player")) - local res = false - if class == "ROGUE" - or class == "WARRIOR" - or class == "HUNTER" - then - res = true - else - res = false - end - return res -end - -local function GetAmmoCount() - local ammo = "" - local mis = false - local mist = "" - local ammo_name = "" - local ammo_count = 0 - local label = "" - local text = "" - local tool_tip = "" - - ClrAmmoInfo() - -- weapon info - local itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, - itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType, expacID, setID, isCraftingReagent - -- ammo info - local ammoName, ammoLink, ammoQuality, ammoLevel, ammoMinLevel, ammoType, ammoSubType, ammoStackCount, - ammoEquipLoc, ammoTexture, _, ammoID, subammoID - - local weap = GetInventoryItemID("player", rangedSlotID) - if weap == nil then - -- nothing in slot - ammo = L["TITAN_AMMO_BUTTON_NOAMMO"] - else - -- get weapon info (thrown) or ammo info (guns & bows) - itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, - itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType, expacID, setID, isCraftingReagent - = GetItem(weap) - ammo = itemEquipLoc - - -- set ammo name and count - if (subclassID == 16) -- Thrown - then - -- treat thrown as ther ammo with 0 count - ammo_name = itemName or "" - ammo_count = 0 - - ammoID = classID - subammoID = subclassID - - label = L["TITAN_AMMO_BUTTON_LABEL_THROWN"] - - ammo_name = select(1, GetItem(GetInventoryItemID("player", rangedSlotID))) or _G["UNKNOWN"] - if ammo_name == _G["UNKNOWN"] then - ammo_count = 0 - else - if game_version < 30000 then - -- CE thrown has count - ammo_count = GetInventoryItemCount("player", rangedSlotID) or ammo_count - text = format(L["TITAN_AMMO_FORMAT"], ammo_count); - else - -- Wrath thrown has no count or durability - text = TitanUtils_GetGoldText("*") - end - end - if TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName") and ammo_name ~= "" then - text = text.."|cffffff9a".." ("..ammo_name..")".."|r" - end - tool_tip = itemName - -- no mismatch - elseif (subclassID == 3) -- Gun - or (subclassID == 2) -- Bow - or (subclassID == 18) -- Crossbow - then - ammoName, ammoLink, ammoQuality, ammoLevel, ammoMinLevel, ammoType, ammoSubType, ammoStackCount, - ammoEquipLoc, ammoTexture, _, ammoID, subammoID, _, _, _, _ - = GetItem(GetInventoryItemID("player", ammoSlotID)) --- ammo_name = select(1, GetItemInfo(GetInventoryItemID("player", ammoSlotID))) or UNKNOWN - ammo_name = ammoName or "" - if ammoName == nil then - ammo_count = 0 - else - ammo_count = GetInventoryItemCount("player", ammoSlotID) or display.ammo_count - end - text = format(L["TITAN_AMMO_FORMAT"], ammo_count); - if TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName") and ammo_name ~= "" then - text = text.."|cffffff9a".." ("..ammo_name..")".."|r" - end - label = L["TITAN_AMMO_BUTTON_LABEL_AMMO"] - tool_tip = "" - ..tostring(itemName) - .."\n"..tostring(ammo_name).."" - - - -- check for mismatch - if (subclassID == 3) -- Bullet - and (subammoID == 2) -- Arrow - then - mis = true - mist = "" - ..tostring(itemName) - .." <> " - ..tostring(ammoName) - mist = TitanUtils_GetRedText(mist) - elseif ((subclassID == 2) -- Bow - or (subclassID == 18)) -- Crossbow - and (subammoID == 3) -- Bullets - then - mis = true - mist = "" - ..tostring(itemName) - .." <> " - ..tostring(ammoName) - mist = TitanUtils_GetRedText(mist) - else - end - else - ammo_name = UNKNOWN - ammo_count = 0 - - -- no mismatch - end ---[[ -local msg = - "GII-ammo" - .." ("..tostring(itemType).."" - .." "..tostring(classID).."" - .." "..tostring(subclassID) ..")" - .." ? ("..tostring(ammoID).."" - .." "..tostring(subammoID)..")" - .." "..tostring(mis).."" -debug_msg(msg) -local msg = - "GII-ammo > " - .." '"..tostring(label).."'" - .." '"..tostring(text).."'" -debug_msg(msg) ---]] - end - - -- Set variables - display.label = label - display.text = text - display.tool_tip = tool_tip - display.weapon = itemName - display.weapon_type = itemSubType - display.ammo_name = ammo_name - display.ammo_count = ammo_count - display.ammo_type = ammo - display.ammo_type_id = subclassID - display.mismatch = mis - display.mismatch_text = mist - - if debug_flow then - local msg = - "Count" - .." '"..tostring(itemSubType).."'" - .." '"..tostring(itemName).."'" - debug_msg(msg) - else - -- not requested - end -end - -local function Events(action, reason) ---[[ -- Thrown has no durability so do not register for that event -- Remove ACTIONBAR_HIDEGRID; this is triggered when dragging an item to actionbar - Not sure why this was implemented - use of event changed? ---]] - if action == "register" then - TitanPanelAmmoButton:RegisterEvent("UNIT_INVENTORY_CHANGED") - TitanPanelAmmoButton:RegisterEvent("MERCHANT_CLOSED") - elseif action == "unregister" then - TitanPanelAmmoButton:UnregisterEvent("UNIT_INVENTORY_CHANGED") - TitanPanelAmmoButton:UnregisterEvent("MERCHANT_CLOSED") - else - -- action unknown ??? - end - - if debug_flow then - local msg = - "Events" - .." "..tostring(reason).."" - debug_msg(msg) - else - -- not requested - end -end - ---[[ --- ************************************************************************** --- NAME : GetButtonText(id) --- DESC : Calculate ammo/thrown logic then put on button --- VARS : id = button ID --- ************************************************************************** ---]] -function GetButtonText(id) - - local labelText, ammoText, ammoRichText, color; - - labelText = display.label - ammoText = display.text or "-" - - if display.mismatch then - ammoRichText = tostring(display.mismatch_text) - elseif (TitanGetVar(TITAN_AMMO_ID, "ShowColoredText")) then - color = TitanUtils_GetThresholdColor(TITAN_AMMO_THRESHOLD_TABLE[display.ammo_type], display.ammo_count); - ammoRichText = TitanUtils_GetColoredText(ammoText, color); - else - ammoRichText = TitanUtils_GetHighlightText(ammoText); - end - - if debug_flow then - local msg = - "Btn_Text" - .." '"..tostring(display.weapon_type).."'" - .." '"..tostring(ammoRichText).."'" - debug_msg(msg) - else - -- not requested - end - - return labelText, ammoRichText; -end - ---[[ --- ************************************************************************** --- NAME : CreateMenu() --- DESC : Display rightclick menu options --- ************************************************************************** ---]] -function CreateMenu() - TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_AMMO_ID].menuText); - - local info = {}; - info.text = L["TITAN_AMMO_BULLET_NAME"]; - info.func = function() TitanPanelRightClickMenu_ToggleVar({TITAN_AMMO_ID, "ShowAmmoName"}) - GetAmmoCount() - TitanPanelButton_UpdateButton(TITAN_AMMO_ID); - end - info.checked = TitanUtils_Ternary(TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName"), 1, nil); - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()) - TitanPanelRightClickMenu_AddSpacer(); - - info = {}; - TitanPanelRightClickMenu_AddToggleIcon(TITAN_AMMO_ID); - TitanPanelRightClickMenu_AddToggleLabelText(TITAN_AMMO_ID); - TitanPanelRightClickMenu_AddToggleColoredText(TITAN_AMMO_ID); - - TitanPanelRightClickMenu_AddToggleRightSide(TITAN_AMMO_ID); - TitanPanelRightClickMenu_AddSpacer(); - TitanPanelRightClickMenu_AddCommand(L["TITAN_PANEL_MENU_HIDE"], TITAN_AMMO_ID, TITAN_PANEL_MENU_FUNC_HIDE); -end - -function GetTooltipText() - local txt = display.tool_tip - if display.mismatch then - txt = txt - .."\n\n" - ..tostring(display.mismatch_text).."" - else - -- weapon and projectile match - end - return txt -end - ---[[ --- ************************************************************************** --- NAME : TitanPanelAmmoButton_OnLoad() --- DESC : Registers the plugin upon it loading --- ************************************************************************** ---]] -local function OnLoad(self) - self.registry = { - id = TITAN_AMMO_ID, - --builtIn = 1, - category = "Built-ins", - version = TITAN_VERSION, - menuText = L["TITAN_AMMO_MENU_TEXT"], - menuTextFunction = CreateMenu, - buttonTextFunction = GetButtonText, - tooltipTitle = L["TITAN_AMMO_TOOLTIP"], - tooltipTextFunction = GetTooltipText, - icon = "Interface\\AddOns\\TitanAmmo\\TitanClassicThrown", - iconWidth = 16, - controlVariables = { - ShowIcon = true, - ShowLabelText = true, - ShowRegularText = false, - ShowColoredText = true, - DisplayOnRightSide = true - }, - savedVariables = { - ShowIcon = 1, - ShowLabelText = 1, - ShowColoredText = 1, - ShowAmmoName = false, - DisplayOnRightSide = false, - } - } -end - -local function OnShow(self) - ClrAmmoInfo() - - if IsAmmoClass() then - -- No need to start events and consume cycles if no ammo - GetAmmoCount() - - Events("register", "OnShow") - else - -- Just set the default text on button - -- for a class w/o ammo - end - - TitanPanelButton_UpdateButton(TITAN_AMMO_ID); -end - -local function OnHide(self) - ClrAmmoInfo() - - Events("unregister", "OnHide") -end - -local function UpdateDisplay() - GetAmmoCount() - - TitanPanelButton_UpdateButton(TITAN_AMMO_ID); -end - ---[[ --- ************************************************************************** --- NAME : TitanPanelAmmoButton_OnEvent() --- DESC : React to any registered Events --- ************************************************************************** ---]] -local function OnEvent(self, event, arg1, arg2, ...) - if event == "PLAYER_ENTERING_WORLD" then - if arg1 == true then -- login - -- EnterWorld() - end - if arg2 == true then -- reload / zoning - UpdateDisplay() - end - elseif event == "UNIT_INVENTORY_CHANGED" then - if arg1 == "player" then - UpdateDisplay() - end - elseif event == "MERCHANT_CLOSED" then - UpdateDisplay() - end -end - --- ====== Create needed frames -local function Create_Frames() - if _G[TITAN_BUTTON] then - return -- if already created - end - - -- general container frame - local f = CreateFrame("Frame", nil, UIParent) --- f:Hide() - - -- Titan plugin button - local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") - window:SetFrameStrata("FULLSCREEN") - -- Using SetScript("OnLoad", does not work - OnLoad(window); --- TitanPanelButton_OnLoad(window); -- Titan XML template calls this... - - window:SetScript("OnEvent", function(self, event, ...) - OnEvent(self, event, ...) - end) - window:SetScript("OnShow", function(self, button) - OnShow(self) - end) - window:SetScript("OnHide", function(self, button) - OnHide(self) - end) - -end - -Create_Frames() -- do the work +--[===[ File +This file contains the TitanAmmo plugin. +--]===] + +--[[ +-- ************************************************************************** +-- * TitanAmmo.lua +-- * +-- * By: Titan Panel Development Team +-- ************************************************************************** +-- 2024 Jan - Combined Classic Era and Wrath into one version +-- 2019 Aug - reverted and updated for Classic +-- +-- This will track the count of ammo (bows and guns) or thrown (knives) equipped. +-- Ammo is placed in the 'ammo' slot where Blizzard counts ALL of that *type of ammo* +-- regardless of where it is in your bags. +-- Thrown is placed in the actual display.weapon slot where Blizzard counts ALL of that *type of thrown*. +-- This forces a different routine to be used so the ammo must always be checked for type and count. +-- +-- Note: Thrown has no durability. Not sure when Blizz implemented this +--]] + +-- ******************************** Constants ******************************* +local _G = getfenv(0); +local TITAN_AMMO_ID = "Ammo"; +local TITAN_BUTTON = "TitanPanel"..TITAN_AMMO_ID.."Button" + +local SHOOT_STACK = 200 +local ARROW_STACK = 200 +local THROW_STACK = 200 + +local LIM_GOOD = 2 +local LIM_OK = 1.5 +local LIM_BAD = .5 + +local game_version = select(4, GetBuildInfo()) + +local TITAN_AMMO_THRESHOLD_TABLE = { -- Use ammo stack and threshold limits above to calc colored text + ["INVTYPE_RANGEDRIGHT"] = { + Values = { SHOOT_STACK*LIM_BAD, SHOOT_STACK*LIM_OK, SHOOT_STACK*LIM_GOOD }, -- 100,150,400 + Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, + }, + ["INVTYPE_RANGED"] = { + Values = { ARROW_STACK*LIM_BAD, ARROW_STACK*LIM_OK, ARROW_STACK*LIM_GOOD }, -- 100,150,400 + Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, + }, + ["INVTYPE_THROWN"] = { + Values = { THROW_STACK/10, THROW_STACK/4, THROW_STACK/2 }, -- 20, 50, 100 + Colors = { RED_FONT_COLOR, ORANGE_FONT_COLOR, NORMAL_FONT_COLOR, HIGHLIGHT_FONT_COLOR }, + }, +}; + +-- ******************************** Variables ******************************* +local ammoSlotID = GetInventorySlotInfo("AMMOSLOT") +local rangedSlotID = GetInventorySlotInfo("RANGEDSLOT") + +-- Info to show on the plugin +local display = { + ammo_count = 0, + ammo_type = "", + ammo_name = "", -- L["TITAN_AMMO_BUTTON_NOAMMO"] + weapon = "", + weapon_type = "", + mismatch = false, + mismatch_text = "", + } + +local L = LibStub("AceLocale-3.0"):GetLocale("Titan", true) + +local debug_flow = false + +---@diagnostic disable-next-line: deprecated +local GetItem = C_Item.GetItemInfo or GetItemInfo -- For Classic versions + +-- ******************************** Functions ******************************* +--[[ local +-- ************************************************************************** +-- NAME : debug_msg(Message) +-- DESC : Debug function to print message to chat frame +-- VARS : Message = message to print to chat frame +-- ************************************************************************** +--]] +local function debug_msg(Message) + local msg = "" + local stamp = date("%H:%M:%S") -- date("%m/%d/%y %H:%M:%S") + local milli = GetTime() -- seconds with millisecond precision (float) + local milli_str = string.format("%0.2F", milli - math.modf(milli)) + msg = msg..TitanUtils_GetGoldText(stamp..milli_str.." "..TITAN_AMMO_ID..": ") + msg = msg..TitanUtils_GetGreenText(Message) + DEFAULT_CHAT_FRAME:AddMessage(msg) +-- DEFAULT_CHAT_FRAME:AddMessage(TITAN_AMMO_ID..": " .. Message, 1.00, 0.49, 0.04) +end + +local function ClrAmmoInfo() + display.ammo_count = 0; + display.ammo_type = L["TITAN_AMMO_BUTTON_NOAMMO"] + display.ammo_name = "" + display.weapon = "" + display.weapon_type = "" + display.mismatch = false + display.mismatch_text = "" +end + +local function GetItemLink(rangedSlotID) + return GetInventoryItemLink("player", rangedSlotID) +end + +local function IsAmmoClass() + local class = select(2, UnitClass("player")) + local res = false + if class == "ROGUE" + or class == "WARRIOR" + or class == "HUNTER" + then + res = true + else + res = false + end + return res +end + +local function GetAmmoCount() + local ammo = "" + local mis = false + local mist = "" + local ammo_name = "" + local ammo_count = 0 + local label = "" + local text = "" + local tool_tip = "" + + ClrAmmoInfo() + -- weapon info + local itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, + itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType, expacID, setID, isCraftingReagent + -- ammo info + local ammoName, ammoLink, ammoQuality, ammoLevel, ammoMinLevel, ammoType, ammoSubType, ammoStackCount, + ammoEquipLoc, ammoTexture, _, ammoID, subammoID + + local weap = GetInventoryItemID("player", rangedSlotID) + if weap == nil then + -- nothing in slot + ammo = L["TITAN_AMMO_BUTTON_NOAMMO"] + else + -- get weapon info (thrown) or ammo info (guns & bows) + itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, + itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType, expacID, setID, isCraftingReagent + = GetItem(weap) + ammo = itemEquipLoc + + -- set ammo name and count + if (subclassID == 16) -- Thrown + then + -- treat thrown as ther ammo with 0 count + ammo_name = itemName or "" + ammo_count = 0 + + ammoID = classID + subammoID = subclassID + + label = L["TITAN_AMMO_BUTTON_LABEL_THROWN"] + + ammo_name = select(1, GetItem(GetInventoryItemID("player", rangedSlotID))) or _G["UNKNOWN"] + if ammo_name == _G["UNKNOWN"] then + ammo_count = 0 + else + if game_version < 30000 then + -- CE thrown has count + ammo_count = GetInventoryItemCount("player", rangedSlotID) or ammo_count + text = format(L["TITAN_AMMO_FORMAT"], ammo_count); + else + -- Wrath thrown has no count or durability + text = TitanUtils_GetGoldText("*") + end + end + if TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName") and ammo_name ~= "" then + text = text.."|cffffff9a".." ("..ammo_name..")".."|r" + end + tool_tip = itemName + -- no mismatch + elseif (subclassID == 3) -- Gun + or (subclassID == 2) -- Bow + or (subclassID == 18) -- Crossbow + then + ammoName, ammoLink, ammoQuality, ammoLevel, ammoMinLevel, ammoType, ammoSubType, ammoStackCount, + ammoEquipLoc, ammoTexture, _, ammoID, subammoID, _, _, _, _ + = GetItem(GetInventoryItemID("player", ammoSlotID)) +-- ammo_name = select(1, GetItemInfo(GetInventoryItemID("player", ammoSlotID))) or UNKNOWN + ammo_name = ammoName or "" + if ammoName == nil then + ammo_count = 0 + else + ammo_count = GetInventoryItemCount("player", ammoSlotID) or display.ammo_count + end + text = format(L["TITAN_AMMO_FORMAT"], ammo_count); + if TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName") and ammo_name ~= "" then + text = text.."|cffffff9a".." ("..ammo_name..")".."|r" + end + label = L["TITAN_AMMO_BUTTON_LABEL_AMMO"] + tool_tip = "" + ..tostring(itemName) + .."\n"..tostring(ammo_name).."" + + + -- check for mismatch + if (subclassID == 3) -- Bullet + and (subammoID == 2) -- Arrow + then + mis = true + mist = "" + ..tostring(itemName) + .." <> " + ..tostring(ammoName) + mist = TitanUtils_GetRedText(mist) + elseif ((subclassID == 2) -- Bow + or (subclassID == 18)) -- Crossbow + and (subammoID == 3) -- Bullets + then + mis = true + mist = "" + ..tostring(itemName) + .." <> " + ..tostring(ammoName) + mist = TitanUtils_GetRedText(mist) + else + end + else + ammo_name = UNKNOWN + ammo_count = 0 + + -- no mismatch + end +--[[ +local msg = + "GII-ammo" + .." ("..tostring(itemType).."" + .." "..tostring(classID).."" + .." "..tostring(subclassID) ..")" + .." ? ("..tostring(ammoID).."" + .." "..tostring(subammoID)..")" + .." "..tostring(mis).."" +debug_msg(msg) +local msg = + "GII-ammo > " + .." '"..tostring(label).."'" + .." '"..tostring(text).."'" +debug_msg(msg) +--]] + end + + -- Set variables + display.label = label + display.text = text + display.tool_tip = tool_tip + display.weapon = itemName + display.weapon_type = itemSubType + display.ammo_name = ammo_name + display.ammo_count = ammo_count + display.ammo_type = ammo + display.ammo_type_id = subclassID + display.mismatch = mis + display.mismatch_text = mist + + if debug_flow then + local msg = + "Count" + .." '"..tostring(itemSubType).."'" + .." '"..tostring(itemName).."'" + debug_msg(msg) + else + -- not requested + end +end + +local function Events(action, reason) +--[[ +- Thrown has no durability so do not register for that event +- Remove ACTIONBAR_HIDEGRID; this is triggered when dragging an item to actionbar + Not sure why this was implemented - use of event changed? +--]] + if action == "register" then + TitanPanelAmmoButton:RegisterEvent("UNIT_INVENTORY_CHANGED") + TitanPanelAmmoButton:RegisterEvent("MERCHANT_CLOSED") + elseif action == "unregister" then + TitanPanelAmmoButton:UnregisterEvent("UNIT_INVENTORY_CHANGED") + TitanPanelAmmoButton:UnregisterEvent("MERCHANT_CLOSED") + else + -- action unknown ??? + end + + if debug_flow then + local msg = + "Events" + .." "..tostring(reason).."" + debug_msg(msg) + else + -- not requested + end +end + +--[[ +-- ************************************************************************** +-- NAME : GetButtonText(id) +-- DESC : Calculate ammo/thrown logic then put on button +-- VARS : id = button ID +-- ************************************************************************** +--]] +function GetButtonText(id) + + local labelText, ammoText, ammoRichText, color; + + labelText = display.label + ammoText = display.text or "-" + + if display.mismatch then + ammoRichText = tostring(display.mismatch_text) + elseif (TitanGetVar(TITAN_AMMO_ID, "ShowColoredText")) then + color = TitanUtils_GetThresholdColor(TITAN_AMMO_THRESHOLD_TABLE[display.ammo_type], display.ammo_count); + ammoRichText = TitanUtils_GetColoredText(ammoText, color); + else + ammoRichText = TitanUtils_GetHighlightText(ammoText); + end + + if debug_flow then + local msg = + "Btn_Text" + .." '"..tostring(display.weapon_type).."'" + .." '"..tostring(ammoRichText).."'" + debug_msg(msg) + else + -- not requested + end + + return labelText, ammoRichText; +end + +--[[ +-- ************************************************************************** +-- NAME : CreateMenu() +-- DESC : Display rightclick menu options +-- ************************************************************************** +--]] +function CreateMenu() + TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_AMMO_ID].menuText); + + local info = {}; + info.text = L["TITAN_AMMO_BULLET_NAME"]; + info.func = function() TitanPanelRightClickMenu_ToggleVar({TITAN_AMMO_ID, "ShowAmmoName"}) + GetAmmoCount() + TitanPanelButton_UpdateButton(TITAN_AMMO_ID); + end + info.checked = TitanUtils_Ternary(TitanGetVar(TITAN_AMMO_ID, "ShowAmmoName"), 1, nil); + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()) + TitanPanelRightClickMenu_AddSpacer(); + + info = {}; + TitanPanelRightClickMenu_AddToggleIcon(TITAN_AMMO_ID); + TitanPanelRightClickMenu_AddToggleLabelText(TITAN_AMMO_ID); + TitanPanelRightClickMenu_AddToggleColoredText(TITAN_AMMO_ID); + + TitanPanelRightClickMenu_AddToggleRightSide(TITAN_AMMO_ID); + TitanPanelRightClickMenu_AddSpacer(); + TitanPanelRightClickMenu_AddCommand(L["TITAN_PANEL_MENU_HIDE"], TITAN_AMMO_ID, TITAN_PANEL_MENU_FUNC_HIDE); +end + +function GetTooltipText() + local txt = display.tool_tip + if display.mismatch then + txt = txt + .."\n\n" + ..tostring(display.mismatch_text).."" + else + -- weapon and projectile match + end + return txt +end + +--[[ +-- ************************************************************************** +-- NAME : TitanPanelAmmoButton_OnLoad() +-- DESC : Registers the plugin upon it loading +-- ************************************************************************** +--]] +local function OnLoad(self) + self.registry = { + id = TITAN_AMMO_ID, + --builtIn = 1, + category = "Built-ins", + version = TITAN_VERSION, + menuText = L["TITAN_AMMO_MENU_TEXT"], + menuTextFunction = CreateMenu, + buttonTextFunction = GetButtonText, + tooltipTitle = L["TITAN_AMMO_TOOLTIP"], + tooltipTextFunction = GetTooltipText, + icon = "Interface\\AddOns\\TitanAmmo\\TitanClassicThrown", + iconWidth = 16, + controlVariables = { + ShowIcon = true, + ShowLabelText = true, + ShowRegularText = false, + ShowColoredText = true, + DisplayOnRightSide = true + }, + savedVariables = { + ShowIcon = 1, + ShowLabelText = 1, + ShowColoredText = 1, + ShowAmmoName = false, + DisplayOnRightSide = false, + } + } +end + +local function OnShow(self) + ClrAmmoInfo() + + if IsAmmoClass() then + -- No need to start events and consume cycles if no ammo + GetAmmoCount() + + Events("register", "OnShow") + else + -- Just set the default text on button + -- for a class w/o ammo + end + + TitanPanelButton_UpdateButton(TITAN_AMMO_ID); +end + +local function OnHide(self) + ClrAmmoInfo() + + Events("unregister", "OnHide") +end + +local function UpdateDisplay() + GetAmmoCount() + + TitanPanelButton_UpdateButton(TITAN_AMMO_ID); +end + +--[[ +-- ************************************************************************** +-- NAME : TitanPanelAmmoButton_OnEvent() +-- DESC : React to any registered Events +-- ************************************************************************** +--]] +local function OnEvent(self, event, arg1, arg2, ...) + if event == "PLAYER_ENTERING_WORLD" then + if arg1 == true then -- login + -- EnterWorld() + end + if arg2 == true then -- reload / zoning + UpdateDisplay() + end + elseif event == "UNIT_INVENTORY_CHANGED" then + if arg1 == "player" then + UpdateDisplay() + end + elseif event == "MERCHANT_CLOSED" then + UpdateDisplay() + end +end + +-- ====== Create needed frames +local function Create_Frames() + if _G[TITAN_BUTTON] then + return -- if already created + end + + -- general container frame + local f = CreateFrame("Frame", nil, UIParent) +-- f:Hide() + + -- Titan plugin button + local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") + window:SetFrameStrata("FULLSCREEN") + -- Using SetScript("OnLoad", does not work + OnLoad(window); +-- TitanPanelButton_OnLoad(window); -- Titan XML template calls this... + + window:SetScript("OnEvent", function(self, event, ...) + OnEvent(self, event, ...) + end) + window:SetScript("OnShow", function(self, button) + OnShow(self) + end) + window:SetScript("OnHide", function(self, button) + OnHide(self) + end) + +end + +Create_Frames() -- do the work diff --git a/TitanRepair/TitanRepair.lua b/TitanRepair/TitanRepair.lua index 6de0528..791354d 100644 --- a/TitanRepair/TitanRepair.lua +++ b/TitanRepair/TitanRepair.lua @@ -102,9 +102,10 @@ end --debug -TR.show_debug = false -- will tell you a lot about what's happening +TR.show_debug = false -- will tell you a lot about what's happening in the addon TR.show_debug_scan = false -- shows items processed during scan -TR.show_debug_tooltip = false -- shows items processed during scan +TR.show_debug_grey = true -- shows items processed during sell grey items +TR.show_debug_tooltip = false -- details of creating the tooltip -- ******************************** Functions ******************************* @@ -113,9 +114,11 @@ TR.show_debug_tooltip = false -- shows items processed during scan local function debug_msg(Message) local msg = "" local stamp = date("%H:%M:%S") -- date("%m/%d/%y %H:%M:%S") - local milli = GetTime() -- seconds with millisecond precision (float) - local milli_str = string.format("%0.2F", milli - math.modf(milli)) - msg = msg..TitanUtils_GetGoldText(stamp..milli_str.." "..TITAN_REPAIR_ID..": ") +-- local milli = GetTime() -- seconds with millisecond precision (float) + local milli = GetTimePreciseSec() -- seconds with millisecond precision (float) since last call +-- local milli_str = string.format("%0.2F", milli - math.modf(milli)) + local milli_str = string.format("%0.2F", milli) + msg = msg..TitanUtils_GetGoldText(stamp.." {"..milli_str.."} "..TITAN_REPAIR_ID..": ") msg = msg..TitanUtils_GetGreenText(Message) DEFAULT_CHAT_FRAME:AddMessage(msg) -- DEFAULT_CHAT_FRAME:AddMessage(TITAN_REPAIR_ID..": " .. Message, 1.00, 0.49, 0.04) @@ -707,56 +710,120 @@ Realized the Disable also changes the button so the DeSat is redundent end end +local function Sell_grey(bag, slot, idx, max) + if TR.show_debug_grey then + local msg = "..." + .." ["..string.format("%02d", bag).."]" + .." ["..string.format("%02d", slot).."]" + .." :"..tostring(idx).."" + .." / "..tostring(max).."" + debug_msg(msg) + end + C_Container.UseContainerItem(bag, slot) +end + ---local Rummage through bags, selling any gray items. local function TitanRepair_SellGrayItems() - if TR.show_debug then + if TR.show_debug + or TR.show_debug_grey + then debug_msg("Selling gray items") end + -- Keep a count to add a small delay between messages. + -- Hopefully, ALL grey items will be sold by avoiding the message spam filter which may stop Repair before done. + local cnt = 0 + local msg = "" + +-- for sell_all = 1, 2 do for bag = 0, 4 do for slot = 1, C_Container.GetContainerNumSlots(bag) do local info = C_Container.GetContainerItemInfo(bag, slot) - if info and info.quality == 0 then - if TR.show_debug then - local name, _, value - name, - _, -- link - _, -- quality - _, -- level - _, -- min level - _, -- type - _, -- sub type - _, -- stack count - _, -- loc - _, -- texture - value, - _, -- class id - _, -- sub class id - _, -- bind type - _, -- xpac id - _, -- set id - _ -- is crafting reagent - = GetItem(info.itemID) - local msg = "Selling" - .." "..tostring(info.stackCount).."" - .." "..tostring(name).."" - .." $ "..tostring(GetGSC(info.stackCount * value)).."" - .." "..tostring(bag).."" - .." "..tostring(slot).."" - debug_msg(msg) - end - + if info and info.quality == 0 then + local name, _, value + name, + _, -- link + _, -- quality + _, -- level + _, -- min level + _, -- type + _, -- sub type + _, -- stack count + _, -- loc + _, -- texture + value, + _, -- class id + _, -- sub class id + _, -- bind type + _, -- xpac id + _, -- set id + _ -- is crafting reagent + = GetItem(info.itemID) + -- Sell item(s) - for i = 1, info.stackCount do - C_Container.UseContainerItem(bag, slot) + if value == 0 or value == nil then + -- -- No value, merchant prob does not want; tell user + msg = "Not sold, no sell price" + .." "..tostring(info.hyperlink).."" + + TitanPrint(msg, "warning") + else + if TR.show_debug_grey then + msg = "Selling" + .." ["..string.format("%02d", bag).."]" + .." ["..string.format("%02d", slot).."]" + .." :"..tostring(info.stackCount).."" + .." "..tostring(name).."" + .." $ "..tostring(GetGSC(info.stackCount * value)).."" + debug_msg(msg) + end + for i = 1, info.stackCount do + Sell_grey(bag, slot, i, info.stackCount) + end end else -- ignore - not gray end end end +-- end end - +--[[ +print("+++++") +local bag = 0 +local slot = 4 +local info = C_Container.GetContainerItemInfo(bag, slot) +print(tostring(info)) +TitanDumpTable(info) +local GetItem = C_Item.GetItemInfo or GetItemInfo -- For Classic versions +local name, _, value +name, +_, -- link +_, -- quality +_, -- level +_, -- min level +_, -- type +_, -- sub type +_, -- stack count +_, -- loc +_, -- texture +value, +_, -- class id +_, -- sub class id +_, -- bind type +_, -- xpac id +_, -- set id +_ -- is crafting reagent += GetItem(info.itemID) +local msg = "Selling" +.." "..tostring(info.stackCount).."" +.." "..tostring(name).."" +.." $ "..tostring((info.stackCount * value)).."" +.." "..tostring(bag).."" +.." "..tostring(slot).."" +print(msg) +-- +--]] ---local Color (green / white / red) the given string based on its durability % ---@param item_frac number ---@param valueText string diff --git a/TitanUI/Artwork/TitanReload.blp b/TitanUI/Artwork/TitanReload.blp new file mode 100755 index 0000000..09af6da Binary files /dev/null and b/TitanUI/Artwork/TitanReload.blp differ diff --git a/TitanUI/TitanUI.toc b/TitanUI/TitanUI.toc new file mode 100755 index 0000000..daa8ba1 --- /dev/null +++ b/TitanUI/TitanUI.toc @@ -0,0 +1,12 @@ +## Interface: 110205, 50502, 11507 +## Title: Titan Panel [|cffeda55fUI|r] |cff00aa008.4.2|r +## Author: Titan Panel Dev Team +## Version: 8.4.2 +## Notes: Adds Reload and select functions in a plugin +## Author: Titan Panel Development Team (http://www.titanpanel.org) +## IconTexture: Interface\AddOns\TitanUI\Artwork\TitanReload +## SavedVariables: +## Dependencies: Titan +## DefaultState: Enabled + +Tools.lua diff --git a/TitanUI/Tools.lua b/TitanUI/Tools.lua new file mode 100755 index 0000000..96a634e --- /dev/null +++ b/TitanUI/Tools.lua @@ -0,0 +1,199 @@ +---@diagnostic disable: duplicate-set-field +--[[ +-- ************************************************************************** +-- * TitanUI.lua +-- * +-- * By: The Titan Panel Development Team +-- ************************************************************************** +--]] +-- ******************************** Constants ******************************* +local add_on = ... +local _G = _G --getfenv(0); +local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) +local AceConfigDialog = LibStub("AceConfigDialog-3.0") + +local artwork_path = "Interface\\AddOns\\TitanUI\\Artwork\\" +local TITAN_PLUGIN = "TitanUI" +local TITLE = "Titan UI" +local TITAN_BUTTON = "TitanPanel" .. TITAN_PLUGIN .. "Button" +local VERSION = C_AddOns.GetAddOnMetadata(add_on, "Version") + +-- ******************************** Variables ******************************* +local trace = false -- true / false Make true when debug output is needed. + +local function SendSlash(slash, params) + DEFAULT_CHAT_FRAME.editBox:SetText(_G[slash].." "..tostring(params)) + ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox, 0) +end + +-- Create the right click menu for this plugin +local function CreateMenu() + + TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_PLUGIN].menuText); + + local info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_OPTIONS_BARS"] + info.func = function() + TitanUpdateConfig("init") + AceConfigDialog:Open("Titan Panel Bars") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + local info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_PLUGINS"] + info.func = function() + TitanUpdateConfig("init") + AceConfigDialog:Open("Titan Panel Addon Control") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + local info = {}; + info.notCheckable = true + info.text = L["TITAN_PANEL_MENU_PROFILES"] + info.func = function() + TitanUpdateConfig("init") + AceConfigDialog:Open("Titan Panel Addon Chars") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + -- Option to toggle the framestack cmd + local info = {}; + info.notCheckable = true + info.text = "/titanpanel reset" + info.func = function() + SendSlash("SLASH_TitanPanel1", "reset") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + -- Option to toggle the framestack cmd + local info = {}; + info.notCheckable = true + info.text = "Toggle frame details" + info.func = function() + SendSlash("SLASH_FRAMESTACK1") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel()); + + -- Option to open WoWLua. if loaded + local info = {}; + info.notCheckable = true + info.text = "Open WoWLua" + info.disabled = (SLASH_WOWLUA1 == nil) + info.func = function() + SendSlash("SLASH_WOWLUA1") + end + TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); + + TitanPanelRightClickMenu_AddControlVars(TITAN_PLUGIN) +end + +-- Grab the button text to display +local function GetButtonText(id) + local strA, strB = TITLE, "" + return strA, strB +end + +-- Create the tooltip string +local function GetTooltipText() + local returnstring = "" + returnstring = returnstring.."Left Click: Reloads the User Interface\n" + returnstring = returnstring.."Right Click: For Debug Tools\n" + return returnstring +end + +-- Create the .registry for Titan so it can register and place the plugin +-- Icon from : https://www.wowhead.com/icon=236372/achievement-bg-returnxflags-def-wsg + +local function OnLoad(self) + local notes = "" + .. "Adds Reload UI an dsome tools to Titan Panel.\n" + -- .."- xxx.\n" + self.registry = { + id = TITAN_PLUGIN, + category = "Built-ins", + version = VERSION, + menuText = TITLE, + menuTextFunction = CreateMenu, + buttonTextFunction = GetButtonText, + tooltipTitle = TITLE, + tooltipTextFunction = GetTooltipText, + icon = artwork_path .. "TitanReload", + iconWidth = 16, + notes = notes, + controlVariables = { + ShowIcon = true, + ShowLabelText = true, +-- ShowColoredText = true, + DisplayOnRightSide = true, + }, + savedVariables = { + ShowIcon = 1, + ShowLabelText = 1, +-- ShowColoredText = 1, + DisplayOnRightSide = false, + } + }; +end + +-- Parse and react to registered events +local function OnEvent(self, event, a1, a2, ...) +end + +-- Handle mouse clicks +local function OnClick(self, button) + if trace then + TitanPluginDebug(TITAN_PLUGIN, "TUI click" + .. " " .. tostring(button) .. "" + ) + end + if (button == "LeftButton") then + ReloadUI() + end +end + +local function OnShow(self) + TitanPanelButton_UpdateButton(TITAN_PLUGIN); +end + +-- ====== Create needed frames +local function Create_Frames() + if _G[TITAN_BUTTON] then + return -- if already created + end + + if trace then + TitanPluginDebug(TITAN_PLUGIN, "TS frames" + .. " '" .. tostring(TITAN_BUTTON) .. "'" + ) + end + + -- general container frame + local f = CreateFrame("Frame", nil, UIParent) + local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") + window:SetFrameStrata("FULLSCREEN") + -- Using SetScript to set "OnLoad" does not work + -- + -- This routine sets the guts of the plugin - the .registry + OnLoad(window); + + window:SetScript("OnShow", function(self) + OnShow(self) + -- This routine ensures the plugin is put where the user requested it. + -- Titan saves the bar the plugin was on. It does not save the relative order. + TitanPanelButton_OnShow(self); + end) + window:SetScript("OnClick", function(self, button) + -- Typically this routine handles actions on left click + OnClick(self, button); + -- Typically this routine handles the menu creation on right click + TitanPanelButton_OnClick(self, button); + end) +end + +Create_Frames() -- do the work