diff --git a/Titan/Titan.lua b/Titan/Titan.lua index 9410675..763b8d3 100644 --- a/Titan/Titan.lua +++ b/Titan/Titan.lua @@ -220,6 +220,10 @@ local function RegisterForEvents() _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED"); _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_INDOORS"); _G[TITAN_PANEL_CONTROL]:RegisterEvent("ZONE_CHANGED_NEW_AREA"); + + -- 2026 Apr Add more info for Alts + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_MONEY"); + _G[TITAN_PANEL_CONTROL]:RegisterEvent("PLAYER_EQUIPMENT_CHANGED"); end -------------------------------------------------------------- @@ -268,15 +272,15 @@ local function SetToonInfo(toon) toon_info.name = p toon_info.server = s - local classFilename, classID = UnitClassBase(unit) -- regardless of comsetic changes + local classFilename, classID = UnitClassBase(unit) -- regardless of cosmetic changes local classInfo = C_CreatureInfo.GetClassInfo(classID) if classInfo == nil then toon_info.class = "??" toon_info.className = "??" toon_info.classId = 0 else - toon_info.class = classInfo.className - toon_info.className = classInfo.classFile + toon_info.class = classInfo.className -- localized + toon_info.className = classInfo.classFile -- for comparison toon_info.classId = classInfo.classID end @@ -292,6 +296,15 @@ local function SetToonInfo(toon) toon_info.race = localizedRaceName toon_info.raceName = englishRaceName toon_info.raceId = raceID + + -- 2026 Apr Add more info for Alts + -- Set initially, updates via events + toon_info.gold_toon = GetMoney() -- NO Warband + + local avgItemLevel, avgItemLevelEquipped, avgItemLevelPvp = GetAverageItemLevel() + toon_info.itemLevelAve = avgItemLevel -- using ony equp change event, this may not be accurate... + toon_info.itemLevelEquipped = avgItemLevelEquipped -- this is the one we are tracking + toon_info.itemLevelPvp = avgItemLevelPvp end local function SetToonLogout(toon) @@ -470,7 +483,7 @@ end ---@param arg1 boolean isLogin ---@param arg2 boolean isReload function TitanPanelBarButton:PLAYER_ENTERING_WORLD(arg1, arg2, arg3, arg4) - local call_success = nil + local call_ok = nil local ret_val = nil Titan_Debug.Out('titan', 'p_e_w', "Titan PLAYER_ENTERING_WORLD pcall setup routine") @@ -501,22 +514,22 @@ function TitanPanelBarButton:PLAYER_ENTERING_WORLD(arg1, arg2, arg3, arg4) then -- StopTitan will force error and end this routine - call_success, ret_val = pcall(SetupTitan) - if call_success then + call_ok, ret_val = pcall(SetupTitan) + if call_ok then -- Titan initialized properly else StopTitan("Could not initialize", ret_val) -- something really bad occured... end - call_success, ret_val = pcall(SetupUser) - if call_success then + call_ok, ret_val = pcall(SetupUser) + if call_ok then -- Titan initialized properly else StopTitan("Setup error", ret_val) -- something really bad occured... end - call_success, ret_val = pcall(ShowTitan) - if call_success then + call_ok, ret_val = pcall(ShowTitan) + if call_ok then -- Titan initialized properly else StopTitan("Could not show Bars", ret_val) -- something really bad occured... @@ -555,6 +568,7 @@ end ---Titan Handle PLAYER_LOGOUT On logout, set some debug data in saved variables. function TitanPanelBarButton:PLAYER_LOGOUT() + -- many API calls will not work; data is not caught before the actual logout... --[[ if not IsTitanPanelReset then -- for debug @@ -564,9 +578,9 @@ function TitanPanelBarButton:PLAYER_LOGOUT() TitanPanelRegister.TitanPlugins = TitanPlugins end end - --]] Titan__InitializedPEW = false + --]] SetToonLogout(TitanSettings.Player) end @@ -618,6 +632,27 @@ function TitanPanelBarButton:PLAYER_REGEN_DISABLED() TitanPanelBarButton_DisplayBarsWanted("PLAYER_REGEN_DISABLED") end +---Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena +function TitanPanelBarButton:PLAYER_MONEY() + local toon_info = TitanSettings.Players[TitanSettings.Player].Info + -- 2026 Mar Add more info for Alts + toon_info.gold_toon = GetMoney() -- NO Warband +end + +---Titan Handle ZONE_CHANGED_INDOORS Hide Titan top bars if user requested to hide Top bar(s) in BG or arena +function TitanPanelBarButton:PLAYER_EQUIPMENT_CHANGED() + local toon_info = TitanSettings.Players[TitanSettings.Player].Info + -- 2026 Mar Add more info for Alts + local avgItemLevel, avgItemLevelEquipped, avgItemLevelPvp = GetAverageItemLevel() + toon_info.itemLevelAve = avgItemLevel + toon_info.itemLevelEquipped = avgItemLevelEquipped + toon_info.itemLevelPvp = avgItemLevelPvp + -- Poss info to save for Alts + -- professions, XP (Rested), level %, bags (free/total), connected realms (server click) + -- raid (locked list on click), num quests, currencies (on click - virtual) + +end + if Titan_Global.switch.can_edit_ui then -- Do not need to adjust frames else @@ -693,7 +728,6 @@ local function handle_slash_help(cmd) -- 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") diff --git a/Titan/TitanConfig.lua b/Titan/TitanConfig.lua index 9fe47f1..a0fdb48 100644 --- a/Titan/TitanConfig.lua +++ b/Titan/TitanConfig.lua @@ -38,7 +38,7 @@ local Config_locale = { slash = L["TITAN_PANEL_MENU_SLASH_COMMAND"], help_list = L["TITAN_PANEL_MENU_HELP_LIST"], im_ex_port = L["TITAN_PANEL_MENU_IMPEXP_LABEL"], - adjust = L["TITAN_PANEL_MENU_ADJUST_LABEL"] , + adjust = L["TITAN_PANEL_MENU_ADJUST_LABEL"], } } @@ -428,7 +428,7 @@ local function CreateBarsList(pos) TitanPanelButton_Justify(); end, } ---]] + --]] position = position + 1 -- background args[v.name].args.background = { @@ -632,7 +632,7 @@ end ---@param pos number Options order start ---@return table Config options local function CreateBarsAll(pos) --- AceConfigRegistry:NotifyChange("Titan Panel Globals") + -- AceConfigRegistry:NotifyChange("Titan Panel Globals") local args = {} local position = 1000 @@ -1215,7 +1215,7 @@ local function CreateProfiles(pos) 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 + for index, id in TitanUtils_PlayerIter() do -- collect some info on THIS toon for the config local this_toon = {} @@ -1235,17 +1235,20 @@ local function CreateProfiles(pos) this_toon.profile = TitanVariables_GetProfile(index) local res = "" - if this_toon.profile.ptype == Titan_Global.profile.GLOBAL then - res = L["TITAN_PANEL_GLOBAL"] .. " : " .. this_toon.profile.cname + -- Create string after Profile name in header + if is_custom then + res = "" + elseif this_toon.profile.ptype == Titan_Global.profile.GLOBAL then + res = " < " .. L["TITAN_PANEL_GLOBAL"] .. " : " .. this_toon.profile.cname elseif this_toon.profile.ptype == Titan_Global.profile.SYNC then - res = L["TITAN_PANEL_MENU_PROFILE_SYNC"] .. " : " .. this_toon.profile.cname + res = " < " .. L["TITAN_PANEL_MENU_PROFILE_SYNC"] .. " : " .. this_toon.profile.cname elseif this_toon.profile.ptype == Titan_Global.profile.TOON then - res = L["TITAN_PANEL_MENU_PROFILE_CHARS"] .. " : " .. Titan_Global.profile.NONE + res = " < " .. L["TITAN_PANEL_MENU_PROFILE_CHARS"] .. " : " .. Titan_Global.profile.NONE else - res = "?" .. " : " .. Titan_Global.profile.NONE + res = " < " .. "?" .. " : " .. Titan_Global.profile.NONE end - this_toon.toon_header = this_toon.fancy_name .. res --EndProfileText(this_toon.profile) + this_toon.toon_header = this_toon.fancy_name .. " "..res 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"] @@ -1310,66 +1313,75 @@ local function CreateProfiles(pos) } do -- profile toon info - local custom_toon, toon_info = TitanUtils_GetPlayerInfo(this_toon.name) - if custom_toon then + local result, toon_info = TitanUtils_GetProfileInfo(this_toon.name, "Info", false) + -- is_custom | found | not_found | created + if result == "is_custom" then -- Cannot login; There is no info to show. - elseif toon_info == nil then + elseif result == "not_found" then -- For now show nothing - else -- display - local itoon = toon_info - local logout = (itoon.logoutStr == nil) and L["TITAN_PANEL_NA"] or itoon.logoutStr - position = position + 1 - p_args[tostring(position)] = { - type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_LOGOUT"].." : " .. logout, - --width = "0.5", - cmdHidden = true, - order = position, - } - if itoon.zoneText == nil or itoon.subZoneText == nil then - -- not filled in + elseif result == "found" then + if toon_info == nil then + -- satisfy IDE OR routine failed miserably + -- Show nothing else + local itoon = toon_info + local logout = (itoon.logoutStr == nil) and L["TITAN_PANEL_NA"] or itoon.logoutStr position = position + 1 p_args[tostring(position)] = { type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_LOC"].." : " .. itoon.zoneText .. " " .. itoon.subZoneText, + name = L["TITAN_PANEL_MENU_PROFILE_LOGOUT"] .. " : " .. logout, --width = "0.5", cmdHidden = true, order = position, } + if itoon.zoneText == nil or itoon.subZoneText == nil then + -- not filled in + else + position = position + 1 + p_args[tostring(position)] = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_LOC"] .. + " : " .. itoon.zoneText .. " " .. itoon.subZoneText, + --width = "0.5", + cmdHidden = true, + order = position, + } + end + position = position + 1 + p_args[tostring(position)] = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_LEVEL"] .. " : " .. itoon.levelText, + width = "0.5", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args[tostring(position)] = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_FACTION"] .. " : " .. itoon.faction, + width = "0.5", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args[tostring(position)] = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_CLASS"] .. " : " .. itoon.class, + width = "0.5", + cmdHidden = true, + order = position, + } + position = position + 1 + p_args[tostring(position)] = { + type = "description", + name = L["TITAN_PANEL_MENU_PROFILE_RACE"] .. " : " .. itoon.race, + width = "0.5", + cmdHidden = true, + order = position, + } end - position = position + 1 - p_args[tostring(position)] = { - type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_LEVEL"] .." : " .. itoon.levelText, - width = "0.5", - cmdHidden = true, - order = position, - } - position = position + 1 - p_args[tostring(position)] = { - type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_FACTION"].." : " .. itoon.faction, - width = "0.5", - cmdHidden = true, - order = position, - } - position = position + 1 - p_args[tostring(position)] = { - type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_CLASS"].." : " .. itoon.class, - width = "0.5", - cmdHidden = true, - order = position, - } - position = position + 1 - p_args[tostring(position)] = { - type = "description", - name = L["TITAN_PANEL_MENU_PROFILE_RACE"].." : " .. itoon.race, - width = "0.5", - cmdHidden = true, - order = position, - } + else + -- not sure what happened, show nothing for now end end @@ -1487,6 +1499,7 @@ local function CreateProfiles(pos) L["TITAN_PANEL_MENU_LOAD_SETTINGS"] .. " > " .. this_toon.name .. "" , "info") + AceConfigRegistry:NotifyChange("Titan Panel Addon Chars") end, -- does not make sense to load current character profile disabled = (this_toon.is_player or g_sync), @@ -1522,7 +1535,7 @@ local function CreateProfiles(pos) end, -- can not delete current character profile disabled = (this_toon.is_player - or g_sync + -- or g_sync or p_sync[this_toon.name]), } position = position + 1 @@ -1797,7 +1810,7 @@ local function CreateProfiles(pos) } else local has_sync = false - for index, id in pairs(TitanSettings.Players) do + for index, id in TitanUtils_PlayerIter() do if id.Panel["SyncWithProfile"] == this_toon.name then -- This profile uses this toon as a Sync position = position + 1 @@ -1845,7 +1858,7 @@ local function CreateImportExportList(pos) local p_info = {} -- used to hold info about each toon in players -- Rip through the players (with server name) to sort them - for index, id in pairs(TitanSettings.Players) do + for index, id in TitanUtils_PlayerIter() do -- table.insert(players, {index = index}); -- table.insert(export, {index = false}); players[index] = index @@ -1902,7 +1915,7 @@ local function CreateImportExportList(pos) args["export_header"] = { order = position, type = "header", - name = L["TITAN_PANEL_MENU_IMPEXP_IMPORT"].." \n", + name = L["TITAN_PANEL_MENU_IMPEXP_IMPORT"] .. " \n", cmdHidden = true } local ex_desc = "" @@ -2411,7 +2424,7 @@ local function CreateUIOptions(pos) width = ".5", order = 42, type = "description", - name = L["TITAN_PANEL_MENU_FRAME_STRATA_ORDER"].."\n" + name = L["TITAN_PANEL_MENU_FRAME_STRATA_ORDER"] .. "\n" .. "- BACKGROUND\n" .. "- LOW - default\n" .. "- MEDIUM\n" @@ -3648,7 +3661,7 @@ local function BuildAll() AceConfig:RegisterOptionsTable("Titan Panel Addon Changes", titan_options.args.changeHistory) AceConfig:RegisterOptionsTable("Titan Panel Help List", titan_options.args.helplist) --- AceConfig:RegisterOptionsTable("Titan", titan_options) + -- AceConfig:RegisterOptionsTable("Titan", titan_options) AceConfig:RegisterOptionsTable(config_parent, titan_options) -- AceConfigRegistry:RegisterOptionsTable("Titan", titan_options) end diff --git a/Titan/TitanLDB.lua b/Titan/TitanLDB.lua index 683b936..df430fd 100644 --- a/Titan/TitanLDB.lua +++ b/Titan/TitanLDB.lua @@ -2,55 +2,50 @@ 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 +Titan implements the LDB 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. - +On PLAYER_ENTERING_WORLD, Titan will use the iterator to transform each LDB type addon into a Titan plugin. Titan registers for callbacks on text and icon updates - depending on the LDB type. +Once done, Titan registers for the callback to handle LDB objects created later or on demand. + --- Running from Titan view The LDB addon is responsible for setting and changing its text and icon. +When an LDB addon changes one of its values, the lib fires a callback for the display addon. 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. - +The Titan plugin will use the LDB addon scripts IF declared. --- Supported Only LDB types listed in the LDB 1.1 spec are supported by Titan. - "launcher" become "icon" plugins - TitanPanelIconTemplate + type* - "launcher" icon* - always shown OnClick* - label^ - right side^ - default - tooltip + tocname - "data source" become "combo" plugins - TitanPanelComboTemplate + type* - "data source" icon^ - OnClick - text*^ - or value & suffix + value - + suffix - label^ - OnEnter - OnLeave - - tooltip + tooltip - Frame should NOT be type GameTooltip!!!! OnTooltipShow - * required by LDB spec @@ -112,322 +107,150 @@ local SupportedDOTypes = { DATA_SOURCE, LAUNCHER } -- in the 1.1 spec -- constants & variables local CALLBACK_PREFIX = "LibDataBroker_AttributeChanged_" local _G = getfenv(0); -local InCombatLockdown = _G.InCombatLockdown; + -- Create control frame so we can get events +-- RegisterCallback assumes the method called is ON the frame (self) passed +-- The IDE assumes RegisterCallback method is a string <sigh> 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"; +local iconTitanDefault = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon" --- Events we want for LDBToTitan +-- Events we want 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" +---local Add scripts and info to plugin frame for tooltip processsing. +---@param frame table Titan frame created for LDB object +local function GenTooltipScripts(frame) + local dbg_msg = "LDB-TT " + dbg_msg = dbg_msg .. tostring(frame.registry.id) + -- Technically the spec states only a data source can have .tooltip and .OnTooltipShow + -- but the original development allowed them to exist if the LDB dev added them. + if frame.ldb_obj.tooltip then + dbg_msg = dbg_msg .. " | tooltip" + frame.registry.tooltipDisplayFrame = frame.ldb_obj.tooltip else - pt = "BOTTOM" - rel_pt = "TOP" + -- not on LDB 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 + if frame.ldb_obj.OnTooltipShow then + dbg_msg = dbg_msg .. " | OnTooltipShow" + frame.registry.tooltipTemplateFunction = frame.ldb_obj.OnTooltipShow else + -- not on LDB end - if tt_func and If_Show_Tooltip() then - frame:ClearLines() - tt_func(frame) -- TODO: use pcall?? - end - 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 - ) + -- 2026 Mar : + -- This was rewritten to share tooltip processes with Titan + -- by setting a registry attribute for the type of tooltip processing needed. + -- + -- Another change was to always create the On* scripts on the Titan plugin + -- then call the LDB routine, if it exists. + -- This may use a few more cycle but removes the need for callbacks and still + -- allows the LDB to update the scripts. Titan will use them on the next On* call. + + -- OnEnter + -- Technically a launcher does not have OnEnter / Onleave but the original developer + -- allowed them to exist if the LDB dev added them. + -- If they do not exist, Titan takes no action. + frame:SetScript("OnEnter", function(self) + -- Per the spec, tooltip preferred order is: + -- tooltip > OnEnter/OnLeave > OnTooltipShow. + if self.registry.tooltipDisplayFrame then + TitanPanelButton_OnEnter(self) -- Use the .tooltip as is + elseif self.ldb_obj.OnEnter then + self.ldb_obj.OnEnter(self) -- Plugin will control all aspects + elseif self.registry.tooltipTemplateFunction then + TitanPanelButton_OnEnter(self) -- Pass a Titan tooltip to be filled by plugin + else + -- No recognized tooltip method, move on... + 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) + -- Dropped Ace Tablet-2.0 lib as of 2025 Sep; last updated 2008 Sep + + -- LibQTip-1.0 support code + LibQTip = LibStub("LibQTip-1.0", true) + 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() == self:GetName() then + tt = tip + break 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 + 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 + ) - -- OnTooltipShow - elseif event:find("OnTooltipShow") then - TitanPluginframe:SetScript("OnEnter", function(self) - if TITAN_PANEL_MOVING == 0 and func then - TitanPanelTooltip.TitanAddonName = name - LDBToTitan:TitanLDBSetTooltip(name, TitanPanelTooltip, func); - end - TitanPanelButton_OnEnter(self); - end - ) - TitanPluginframe:SetScript("OnLeave", function(self) - TitanPanelTooltip:Hide(); - TitanPanelButton_OnLeave(self); + -- OnLeave + frame:SetScript("OnLeave", function(self) + if self.ldb_obj.OnLeave then + self.ldb_obj.OnLeave(self) + else + TitanPanelButton_OnLeave(self) end - ) + 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) + -- Use the OnClick given, if exists + frame:SetScript("OnClick", function(self, button) + if TITAN_PANEL_MOVING == 0 then -- no move in progress + if self.ldb_obj.OnClick then + self.ldb_obj.OnClick(self, button) end end - ) - -- OnClick - elseif event:find("OnClick") then - TitanPluginframe:SetScript("OnClick", function(self, button) - if TITAN_PANEL_MOVING == 0 then -- no move in progress - func(self, button) - end - - --[[ 2026 Mar - Discovered that the Blizzard_Menu system, when used by an LDB, + --[[ 2026 Mar + Discovered when LDB uses Blizzard_Menu system is set up and shown before we get here. So... make assumption that menus will be closed on a mouse click. - --]] - - --[===[ - -- 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 - ) - else -- OnEnter / OnLeave - 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 - ) + It is conceivable that two menus could be open at the same time hopefully never ... + --]] + end + ) - -- OnLeave - TitanPluginframe:SetScript("OnLeave", function(self) - if obj.OnLeave then - obj.OnLeave(self) + -- + -- OnDoubleClick is UNDOCUMENTED in the 1.1 spec + -- but was implemented by the original developer + -- + -- Use the OnDoubleClick, if exists + frame:SetScript("OnDoubleClick", function(self, button) + if TITAN_PANEL_MOVING == 0 then + if self.ldb_obj.OnDoubleClick then + self.ldb_obj.OnDoubleClick(self, button) 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) + Titan_Debug.Out('titan', 'ldb_setup', dbg_msg); end ----Titan Text callback when the LDB addon changes display text +---Titan Update Titan button ---@param name string Plugin id name for LDB ---@return string label ---@return string value -function TitanLDBShowText(name) +local function UpdateButton(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 nametrim = string.gsub(name, "LDBT_", ""); +-- local fontstring = _G[TitanUtils_ButtonName(nametrim) .. TITAN_PANEL_TEXT]; local separator = ": " local lab1, val1 = "", "" local plugin = TitanUtils_GetPlugin(name) @@ -448,10 +271,11 @@ function TitanLDBShowText(name) 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 + -- This has been 'broken' for ages... + -- not sure value / suffix were ever used... if TitanGetVar(name, "ShowRegularText") then val1 = (ldb.text or "") else @@ -475,65 +299,13 @@ function TitanLDBShowText(name) 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) +---local Create a Titan plugin from the LDB 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 function TitanLDBCreateObject(self, name_str, obj) local name = name_str Titan_Debug.Out('titan', 'ldb_setup', tostring(name) .. " : Attempting to register "); @@ -676,7 +448,7 @@ function TitanLDBCreateObject(self, name_str, obj) 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", + buttonTextFunction = UpdateButton, icon = ldb__icon, iconWidth = 16, controlVariables = { @@ -759,37 +531,16 @@ function TitanLDBCreateObject(self, name_str, obj) -- 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.ldb_obj = obj -- attach for processing within scripts and Titan newTitanFrame:SetFrameStrata("FULLSCREEN"); newTitanFrame:SetToplevel(true); newTitanFrame:RegisterForClicks("LeftButtonUp", "RightButtonUp"); @@ -797,41 +548,10 @@ function TitanLDBCreateObject(self, name_str, obj) -- 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 + -- 2026 Mar Major rewrite to move tooltip logic into TitanTemplate. + -- The two LDB schemes (tooltip and OnTooltipShow) will be captured in the registry + -- which makes the schemes available to Titan plugins. + GenTooltipScripts(newTitanFrame) local pew = "event" if Titan__InitializedPEW then @@ -850,10 +570,78 @@ function TitanLDBCreateObject(self, name_str, obj) .. "\n...'" .. tostring(newTitanFrame:GetName()) .. "'" ) return "Success" + +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 + local val = tostring(value) -- be paranoid :) + if attr == "value" then ldb.value = val end + if attr == "suffix" then ldb.suffix = val end + if attr == "text" then ldb.text = val end + if attr == "label" then ldb.label = val end + + -- Now update the button with the change + TitanPanelButton_UpdateButton(name) +end + +---Titan Callback 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 OnEvent handler for LDBToTitan ---- Read through all the LDB objects requesting creation so far. Try to create cooresponding Titan plugins. +--- Accept the LDB object to create a cooresponding Titan plugin. ---@param sender any !! Not Used !! ---@param name string LDB id name ---@param obj table LDB data object @@ -892,52 +680,67 @@ function LDBToTitan:TitanLDBCreateObject(sender, name, obj) ) 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) +---Titan OnEvent handler for LDBToTitan +local function InitLoad() + 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, ret_val = 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 - Titan_Debug.Out('titan', 'ldb_setup', "LDB" - .. " " .. tostring(name) .. "" - .. " " .. tostring(call_success) .. "" - .. " " .. tostring(ret_val) .. "" - ) + -- In case a LDB plugin is created later... + ldb.RegisterCallback(self, "LibDataBroker_DataObjectCreated", "TitanLDBCreateObject") end + end + ) +end - -- In case a LDB plugin is created later... - ldb.RegisterCallback(self, - "LibDataBroker_DataObjectCreated", "TitanLDBCreateObject") +---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 -) + +InitLoad() +-- \ No newline at end of file diff --git a/Titan/TitanMenu.lua b/Titan/TitanMenu.lua index 8c22ddc..61ecb6d 100644 --- a/Titan/TitanMenu.lua +++ b/Titan/TitanMenu.lua @@ -956,7 +956,7 @@ In order these are : On right click, Titan will, in order : 1) Create the context menu 2) Add a menu title at top using .registry.id -3) Call the plugin to fill it as before - using pcall, placing error in the menu +3) Call the plugin to fill it as before - using protected call, placing error in the menu 4) Add the plugin designated control vars + right side + Hide on bottom of menu The top and bottom of the menu are common so Titan adds: - a title diff --git a/Titan/TitanMovable.lua b/Titan/TitanMovable.lua index 4fc313f..6cd58f0 100755 --- a/Titan/TitanMovable.lua +++ b/Titan/TitanMovable.lua @@ -216,15 +216,6 @@ else local hooks_done = false; local move_count = 0 ---[[ -Declare the Ace routines - local AceTimer = LibStub("AceTimer-3.0") - i.e. TitanPanelAce.ScheduleTimer("LDBToTitanSetText", TitanLDBRefreshButton, 2); - or - i.e. TitanPanelAce:ScheduleTimer(TitanLDBRefreshButton, 2); - - Be careful that the 'self' is proper to cancel timers!!! ---]] --local TitanPanelAce = LibStub("AceAddon-3.0"):NewAddon("TitanPanel", "AceHook-3.0", "AceTimer-3.0") diff --git a/Titan/TitanTemplate.lua b/Titan/TitanTemplate.lua index e56d4fc..5179633 100644 --- a/Titan/TitanTemplate.lua +++ b/Titan/TitanTemplate.lua @@ -104,6 +104,19 @@ function TitanPanel_SetScale() end --]] +local function GetTooltipLines(tooltip) + local textLines = {} + local regions = {tooltip:GetRegions()} + local cnt = 1 + for _, r in ipairs(regions) do + if r:IsObjectType("FontString") then + print(cnt..": "..tostring(r:GetText())) + cnt = cnt + 1 + end + end + return textLines +end + ---local Helper to add a line of tooltip text to the tooltip. ---@param text string To add ---@param frame table Tooltip frame @@ -141,11 +154,17 @@ end ---@param xOffset number X offset ---@param yOffset number Y offset ---@param frame table Tooltip frame -local function TitanTooltip_SetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame) +---@param custom boolean If custom / not tooltip frame +local function SetOwnerPosition(parent, anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset, frame, custom) -- Changes for 9.1.5 Removed the background template from the Tooltip -- Making changes to it difficult and possibly changing the tooltip globally. - frame:SetOwner(parent, "ANCHOR_NONE"); + if custom then + -- do NOT set owner - it clears the contents! + else + frame:SetOwner(parent, "ANCHOR_NONE") + end + frame:SetPoint(anchorPoint, relativeToFrame, relativePoint, xOffset, yOffset); -- set font size for the Game Tooltip @@ -177,7 +196,9 @@ end ---@param self table Plugin frame ---@param id string Plugin id name ---@param frame table Tooltip frame to use -local function TitanTooltip_SetPanelTooltip(self, id, frame) +---@param custom? boolean If custom / not tooltip frame +local function SetPanelTooltip(self, id, frame, custom) + local is_custom = custom or false local button = TitanUtils_GetButton(id) if button then @@ -207,7 +228,7 @@ local function TitanTooltip_SetPanelTooltip(self, id, frame) rel_pt = rel_pt .. "RIGHT"; end - TitanTooltip_SetOwnerPosition(button, pt, button:GetName(), rel_pt, 0, 0, frame) + SetOwnerPosition(button, pt, button:GetName(), rel_pt, 0, 0, frame, is_custom) end end @@ -287,13 +308,14 @@ local function TitanPanelButton_SetTooltip(self) ok = AllowTooltip(frame) if ok then - local call_success = nil + local call_ok = nil local tmp_txt = "" self.tooltipCustomFunction = nil; self.titan_tt_func = "" self.titan_tt_err = "" + dbg_msg = dbg_msg .." "..tostring(id).."" if (id and TitanUtils_IsPluginRegistered(id)) then local plugin = TitanUtils_GetPlugin(id) -- 2024 Jun Add id and frame name to 'pass' to tooltip routine. @@ -301,8 +323,20 @@ local function TitanPanelButton_SetTooltip(self) -- 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.ldb) then - -- assume the TitanLDB processing will handle the tooltip. + if (plugin and plugin.tooltipDisplayFrame) then + -- 2026 Mar : Added from LDB to take advantage of Titan processing. + -- PLugin is expected to handle its frame! + -- Titan will position and show only! + -- Plugin must handle any timeout and any other features. + + -- Hide the Titan Tooltip in case it is open. + frame:Hide() + + dbg_msg = dbg_msg .. " | tooltipDisplayFrame" + .." '"..tostring(plugin.tooltipDisplayFrame:GetName()).."'" + SetPanelTooltip(self, id, plugin.tooltipDisplayFrame, true) + + plugin.tooltipDisplayFrame:Show() -- now show it elseif (plugin and plugin.tooltipTemplateFunction) then -- 2026 Mar Added to pass a tooltip frame to a plugin as an explicit agreement. -- This acts as Blizz GameTooltip so plugin can 'add line' etc. @@ -310,14 +344,13 @@ local function TitanPanelButton_SetTooltip(self) -- Hide the Titan Tooltip in case it is open. frame:Hide() frame:ClearLines() -- Hand off a blank tooltip - TitanTooltip_SetPanelTooltip(self, id, frame) + SetPanelTooltip(self, id, frame) - -- The plugin is in full control of contents. + -- The plugin is in full control of contents; pass it the tooltip frame to fill self.tooltipTemplateFunction = plugin.tooltipTemplateFunction; - dbg_msg = dbg_msg .. " | custom" - call_success, -- for pcall - tmp_txt = pcall(self.tooltipTemplateFunction, frame) - if call_success then + dbg_msg = dbg_msg .. " | tooltipTemplateFunction" + call_ok, tmp_txt = pcall(self.tooltipTemplateFunction, frame) + if call_ok then -- all is good dbg_msg = dbg_msg .. " | ok" else @@ -334,14 +367,13 @@ local function TitanPanelButton_SetTooltip(self) -- It is left so older plugins will work - but they error as of Midnight (12.0.0) -- Use tooltipTemplateFunction instead! local custom_f = GameTooltip - TitanTooltip_SetPanelTooltip(self, id, custom_f); + SetPanelTooltip(self, id, custom_f); -- 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 + call_ok, tmp_txt = pcall(self.tooltipCustomFunction, self) + if call_ok then -- all is good dbg_msg = dbg_msg .. " | ok" else @@ -354,6 +386,7 @@ local function TitanPanelButton_SetTooltip(self) -- From Lingkan dev of Titan Rep Continued local tooltipTextFunc = {} ---@type function local tt_func = plugin.tooltipTextFunction + local func_ok = true if type(tt_func) == 'string' then -- Function MUST be in global namespace @@ -366,14 +399,15 @@ local function TitanPanelButton_SetTooltip(self) else -- silently leave... dbg_msg = dbg_msg .. " | none found" + func_ok = false end - if (tooltipTextFunc) then + if func_ok then -- Hide the Tooltip while being updated, to avoid race conditions. frame:Hide() GameTooltip:Hide() -- Also hide in case. Cannot hide completly custom tool tips -- Prep the tooltip frame - TitanTooltip_SetPanelTooltip(self, id, frame); + SetPanelTooltip(self, id, frame); if plugin.tooltipTitle then self.tooltipTitle = plugin.tooltipTitle; frame:SetText(self.tooltipTitle, @@ -381,11 +415,10 @@ local function TitanPanelButton_SetTooltip(self) else -- assume dev is doing their own thing end - call_success, -- for pcall - tmp_txt = pcall(tooltipTextFunc, self) + call_ok, tmp_txt = pcall(tooltipTextFunc, self) -- Fill the tooltip - -- If pcall errors, the error will be in the tooltip + -- Any error will be in the tooltip self.tooltipText = tmp_txt if (self.tooltipText) then TitanTooltip_AddTooltipText(self.tooltipText, frame) @@ -768,7 +801,7 @@ end ---@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. +--- The text routine is called in protected mode to ensure the Titan main routines still run. local function TitanPanelButton_SetButtonText(id) local dbg_msg = "ptxt : '" .. tostring(id) .. "'" local ok = false @@ -805,7 +838,7 @@ local function TitanPanelButton_SetButtonText(id) if ok and buttonTextFunction then local label1, value1, label2, value2, label3, value3, label4, value4 - local call_success = false + local call_ok = false local button = TitanUtils_GetButton(id) -- get plugin frame local buttonText = {} @@ -821,11 +854,11 @@ local function TitanPanelButton_SetButtonText(id) -- We'll be paranoid here and call the button text function in protected mode. -- In case the function fails it will not take Titan with it... - call_success, -- for pcall + call_ok, label1, value1, label2, value2, label3, value3, label4, value4 = pcall(buttonTextFunction, id) - if call_success then + if call_ok then -- All is good text = true else diff --git a/Titan/TitanUtils.lua b/Titan/TitanUtils.lua index 3d47b3e..2544029 100644 --- a/Titan/TitanUtils.lua +++ b/Titan/TitanUtils.lua @@ -1257,13 +1257,11 @@ function TitanUtils_GetAddOnMetadata(name, field) ---@diagnostic disable-next-line: deprecated, undefined-global local GetMeta = C_AddOns and C_AddOns.GetAddOnMetadata or GetAddOnMetadata - local call_success, ret_val + local call_ok, ret_val -- Just in case, catch any errors - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(GetMeta, name, field) - if call_success then + call_ok, ret_val = pcall(GetMeta, name, field) + if call_ok then -- all is good return ret_val else @@ -1365,7 +1363,7 @@ local function NoColor(name) return no_color end ----local This routine is a protected manner (pcall) by Titan when it attempts to register a plugin. +---local This routine is a protected manner by Titan when it attempts to register a plugin. ---@param plugin table Plugin frame - Titan template ---@return table Results of the registration - pass (TitanPlugins) or fail --- See routine for output table values @@ -1512,20 +1510,16 @@ end --- Lets be extremely paranoid here because registering plugins that do not play nice can cause real headaches... ---@param plugin table Plugin frame - Titan template function TitanUtils_RegisterPlugin(plugin) - local call_success, ret_val + local call_ok, ret_val -- Ensure we have a glimmer of a plugin and that the plugin has not -- already been registered. if plugin and plugin.status == TITAN_NOT_REGISTERED then -- See if the request to register has a shot at success if plugin.self then -- Just in case, catch any errors - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(TitanUtils_RegisterPluginProtected, plugin) - -- 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 - if call_success then + call_ok, ret_val = pcall(TitanUtils_RegisterPluginProtected, plugin) + -- Any error is returned as text with the success / fail. + if call_ok then -- all is good so write the return values to the plugin plugin.status = ret_val.result plugin.issue = ret_val.issue @@ -1679,6 +1673,90 @@ function TitanUtils_GetPlayerInfo(toon) return is_custom, p_info end +---Titan Get the data table from player Titan settings. +---Intent is encapsulate plugins from where data is stored. +---@param profile string A player name to look up +---@param attrib string Specific data to look up +---@param create boolean If true and no data table, create an empty table +---@return string result is_custom | found | not_found | created +---@return table? data nil or table of data found/created +function TitanUtils_GetProfileInfo(profile, attrib, create) + local _, server, is_custom = TitanUtils_ParseName(profile) + -- Design intent is have a place to store data that is accessed across toons. + -- This routine abstracts ;where; the data table exists. + -- This returns a pointer to the data table so a plugin can manage the data elements + -- and Titan manages where the data table resides. + -- + -- Base : TitanSettings.Players[profile] - Titan managed + -- + -- [attrib] assigned by plugin by create = true - plugin managed + -- - Info- toon data for profiles; Alts, poss Config + -- - Gold- Gold plugin + -- + -- [attrib].* managed by plugin + -- + -- returns : + -- custom - true if the profile is custom else false + -- + -- data - + -- if custom always return nil + -- if create = false : a plugin wants to know if data exists - return table or nil + -- if create = true : a plugin needs to create to store - return table or {} (empty table) + + local p_info = nil + local action = "" + if is_custom then + -- there is no Info table... cannnot log into a custom profile + -- NEVER create... + action = "is_custom" + elseif TitanSettings.Players[profile] + and TitanSettings.Players[profile][attrib] + then + p_info = TitanSettings.Players[profile][attrib] -- return the pointer + action = "found" + else + -- New or may not have logged into this toon in ages :) + if create then + TitanSettings.Players[profile][attrib] = {} -- create for caller + p_info = TitanSettings.Players[profile][attrib] -- return the pointer + action = "created" + else + p_info = nil -- tell caller no Info exists + action = "not_found" + end + end + + return action, p_info +end + +---Titan Allow iteration over the player list without the caller knowing where the list is. +--- Usage : for player, data in TitanUtils_PlayerIter() end +---@return function +function TitanUtils_PlayerIter() + local t = TitanSettings.Players + -- Create a list of keys that match the filter pattern + local keys = {} + for k, v in pairs(t) do + table.insert(keys, k) + end + + -- Define the iterator function that steps through the 'keys' list + local index = 0 + local function iterator() + index = index + 1 + local key = keys[index] + if key then + return key, t[key] -- Return key and value from original table + end + return nil -- End of iteration + end + + -- Return the triplet: iterator, state (nil here, as state is internal), initial (0 handled in closure) + -- Note: We return the iterator function and the 'keys' table as state if we wanted to expose state, + -- but a closure over 'keys' is sufficient for hiding the original table. + return iterator +end + ---Titan Return the screen size after scaling ---@return table screenXY { x | y | scaled_x | scaled_y } all numbers function TitanUtils_ScreenSize() @@ -2030,6 +2108,19 @@ function TitanFindIndex(tb, val) end end +local function GetTooltipLines(tooltip) + local textLines = {} + local regions = {tooltip:GetRegions()} + local cnt = 1 + for _, r in ipairs(regions) do + if r:IsObjectType("FontString") then + print(cnt..": "..tostring(r:GetText())) + cnt = cnt + 1 + end + end + return textLines +end + --====== Deprecated routines -- These routines will be commented out for a couple releases then deleted. -- diff --git a/Titan/TitanVariables.lua b/Titan/TitanVariables.lua index daded03..8312258 100644 --- a/Titan/TitanVariables.lua +++ b/Titan/TitanVariables.lua @@ -1219,6 +1219,30 @@ local function Check_toon_settings(toon, toon_table) -- Note: the sync routine only ensures first level, NOT recursive TitanVariables_SyncRegisterSavedVariables(TITAN_PANEL_SAVED_VARIABLES, v["Panel"]) +---[[ + -- 2026 Mar - transfer Gold and Post to same level as Info + -- Remove the old one. + if TitanSettings.Players[toon] + and TitanSettings.Players[toon].Info + and TitanSettings.Players[toon].Info.Gold then + TitanSettings.Players[toon].Gold = {} + TitanVariables_SyncRegisterSavedVariables( + TitanSettings.Players[toon].Info.Gold, TitanSettings.Players[toon].Gold) + TitanSettings.Players[toon].Info.Gold = nil + else + -- already transfered + end + if TitanSettings.Players[toon] + and TitanSettings.Players[toon].Info + and TitanSettings.Players[toon].Info.Post then + TitanSettings.Players[toon].Post = {} + TitanVariables_SyncRegisterSavedVariables( + TitanSettings.Players[toon].Info.Post, TitanSettings.Players[toon].Post) + TitanSettings.Players[toon].Info.Post = nil + else + -- already transfered + end +--]] -- ====== New Mar 2023 : TitanSettings.Players[player].BarData to hold Short bar data Set_bar_vars(toon) diff --git a/Titan/_TitanIDE.lua b/Titan/_TitanIDE.lua index e8c6003..2aaa335 100644 --- a/Titan/_TitanIDE.lua +++ b/Titan/_TitanIDE.lua @@ -212,6 +212,10 @@ C_Bank = {} -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up so ---@field race string ---@field raceName string ---@field raceId number +---@field gold_toon number +---@field itemLevelAve number +---@field itemLevelEquipped number +---@field itemLevelPvp number --====== Profile output from Utils ---@class Get_Profile_Result diff --git a/TitanBag/TitanBag.lua b/TitanBag/TitanBag.lua index 8606855..9da20bb 100644 --- a/TitanBag/TitanBag.lua +++ b/TitanBag/TitanBag.lua @@ -1071,15 +1071,23 @@ Titan_Menu expects an object approach. The older scheme uses a table driven whic If Titan finds a tooltip function, Titan will assume it needs to position, show, and hide the tooltip. Titan looks for a function to create a tooltip, in order: -1) .tooltipTemplateFunction : New 2026 Mar +1) .tooltipDisplayFrame : New 2026 Mar + 2026 Mar : Added from LDB (.tooltip) to take advantage of Titan processing. + It allows the plugin full control BUT the plugin must take nearly full responsibility. + Titan will position and show only! + Plugin must handle timeout and any other features. + Note: If using a frame of type GameTooltip, the plugin MUST set owner. + If Titan does a set oener on display, it wipes the contents... + +2) .tooltipTemplateFunction : New 2026 Mar A game tooltip template is passed to plugin as an explicit agreement pcall(self.tooltipTemplateFunction, self, frame) -2) .tooltipCustomFunction : Deprecated Midnight (12.0.0) / 2026 Mar : +3) .tooltipCustomFunction : Deprecated Midnight (12.0.0) / 2026 Mar : Assumes GameTooltip as implicit agreement tmp_txt = pcall(self.tooltipCustomFunction, self) -3) .tooltipTextFunction : Titan adds plugin name as Title; expects text in return to fill the tooltip. +4) .tooltipTextFunction : Titan adds plugin name as Title; expects text in return to fill the tooltip. The tooltip function is called when the mouse enters the plugin frame - OnEnter. Titan templates set the OnEnter script for the plugin frame. diff --git a/TitanGold/TitanGold.lua b/TitanGold/TitanGold.lua index 16b1a7a..de43f35 100644 --- a/TitanGold/TitanGold.lua +++ b/TitanGold/TitanGold.lua @@ -55,9 +55,8 @@ Titan_Debug.gold.eval = false ---@class GoldData ---@field gold number ---@field show boolean -local GoldData = nil -- pointer to this player plugin data +local GoldData = nil ---@class GoldInfo local GoldInfo = nil ---@class CharInfo ---TitanSettings.Players[toon].Info ---@type CharInfo ---@class IndexInfo Index flags ---@field valid boolean Saved toon is valid @@ -145,17 +144,13 @@ function Warband.SetSum() -- Really just prevents errors if not implemented in the WoW version -- There *may* have been instances of failure reported as Titan errors - -- Wrap in pcall for safety - --Warband.bank_sum = C_Bank.FetchDepositedMoney(Enum.BankType.Account) local sum = 0 - local call_success = false + local call_ok = false local ret_val = nil - call_success, -- needed for pcall - ret_val = -- actual return values - pcall(C_Bank.FetchDepositedMoney, Enum.BankType.Account) + call_ok, ret_val = pcall(C_Bank.FetchDepositedMoney, Enum.BankType.Account) - if call_success then + if call_ok then -- Assume a valid Warband cash amount (WOWMONEY) sum = ret_val else @@ -216,19 +211,6 @@ local function GetConnectedRealms() return realms end ----local Use index to get toon info from Titan ----@param info string ----@return string Character name - no server ----@return string Server name ----@return string Faction internal, not localized -local function GetIndexInfo(info) - local t_info = TitanSettings.Players[info].Info ---@type CharInfo - local character = t_info.name - local charserver = t_info.server - local char_faction = t_info.factionName - return character, charserver, char_faction -end - ---local Take Gold index and return parts plus various flags ---@param index string ---@return IndexInfo @@ -236,77 +218,86 @@ local function EvalIndexInfo(index) local str = "" str = str .. tostring(index) - local res = { valid = false } -- The return table will be built as needed. + local res = { valid = false } + -- The return table will be built as needed. local character, charserver, is_custom = TitanUtils_ParseName(index) - local toon_info = TitanSettings.Players[index].Info ---@class CharInfo - if is_custom then + local result = "" + local toon_info ---@class CharInfo + result, toon_info = TitanUtils_GetProfileInfo(index, "Info", false) + if result == "is_custom" then -- do not fill in res.valid = false str = str .. " ignored : is_custom" Titan_Debug.Out('gold', 'eval', str) - elseif toon_info == nil then + elseif result == "not_found" then -- do not fill in res.valid = false str = str .. " ignored : no data yet" - else - local toon_gold = toon_info[TITAN_GOLD_ID] ---@class GoldData - if toon_gold == nil then - res.valid = false - - str = str .. " ignored : info but no gold data yet" + elseif result == "found" then + if toon_info == nil then else - res.valid = true + local toon_gold ---@class GoldData + result, toon_gold = TitanUtils_GetProfileInfo(index, "Gold", false) + if toon_gold == nil then + res.valid = false - res.char_name = character -- set in Info 9.1 - res.server = charserver -- set in Info 9.1 - res.faction = toon_info.faction + str = str .. " ignored : info but no gold data yet" + else + res.valid = true - res.ignore_faction = TitanGetVar(TITAN_GOLD_ID, "IgnoreFaction") + res.char_name = character -- set in Info 9.1 + res.server = charserver -- set in Info 9.1 + res.faction = toon_info.faction - if (res.faction == GoldInfo.faction) then - res.same_faction = true - else - res.same_faction = false - end + res.ignore_faction = TitanGetVar(TITAN_GOLD_ID, "IgnoreFaction") - if (res.server == GoldInfo.server) then - res.same_realm = true - else - res.same_realm = false - end + if (res.faction == GoldInfo.faction) then + res.same_faction = true + else + res.same_faction = false + end - local saved_server = string.gsub(res.server, "%s", "") -- GetAutoCompleteRealms removes spaces, idk why... - if merged_realms[saved_server] then - res.merge_realm = true - else - res.merge_realm = false - end + if (res.server == GoldInfo.server) then + res.same_realm = true + else + res.same_realm = false + end - -- Assume server option is satisfied; check other options - if (res.ignore_faction or res.same_faction) - and toon_gold.show - then - res.show_toon = true - else - res.show_toon = false - end + local saved_server = string.gsub(res.server, "%s", "") -- GetAutoCompleteRealms removes spaces, idk why... + if merged_realms[saved_server] then + res.merge_realm = true + else + res.merge_realm = false + end - res.gold = toon_gold.gold - res.show = toon_gold.show -- user option - - str = str - .. " n:" .. tostring(res.char_name) .. "" - .. " s:" .. tostring(res.server) .. "" - .. " ss:" .. tostring(res.same_realm) .. "" - .. " ms:" .. tostring(res.merge_realm) .. "" - .. " f:" .. tostring(res.faction) .. "" - .. " if:" .. tostring(res.ignore_faction) .. "" - .. " sf:" .. tostring(res.same_faction) .. "" - .. " show:" .. tostring(res.show_toon) .. "" - .. " gold:" .. tostring(res.gold) .. "" + -- Assume server option is satisfied; check other options + if (res.ignore_faction or res.same_faction) + and toon_gold.show + then + res.show_toon = true + else + res.show_toon = false + end + + res.gold = toon_gold.gold + res.show = toon_gold.show -- user option + + str = str + .. " n:" .. tostring(res.char_name) .. "" + .. " s:" .. tostring(res.server) .. "" + .. " ss:" .. tostring(res.same_realm) .. "" + .. " ms:" .. tostring(res.merge_realm) .. "" + .. " f:" .. tostring(res.faction) .. "" + .. " if:" .. tostring(res.ignore_faction) .. "" + .. " sf:" .. tostring(res.same_faction) .. "" + .. " show:" .. tostring(res.show_toon) .. "" + .. " gold:" .. tostring(res.gold) .. "" + end end + else + str = str .. " ignored : no data yet" end Titan_Debug.Out('gold', 'eval', str) @@ -339,7 +330,7 @@ local function TotalGold() if TitanGetVar(TITAN_GOLD_ID, "SeparateServers") then Titan_Debug.Out('gold', 'total_gold', "=== SeparateServers") -- Parse the database and display all characters on this server - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.same_realm and char.show_toon then @@ -356,7 +347,7 @@ local function TotalGold() elseif TitanGetVar(TITAN_GOLD_ID, "MergeServers") then Titan_Debug.Out('gold', 'total_gold', "=== MergeServers") -- Parse the database and display characters on merged / connected servers - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.merge_realm and char.show_toon then @@ -373,7 +364,7 @@ local function TotalGold() elseif TitanGetVar(TITAN_GOLD_ID, "AllServers") then Titan_Debug.Out('gold', 'total_gold', "=== AllServers") -- Parse the database and display characters on all servers - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.show_toon then @@ -458,7 +449,7 @@ local function GetTooltipText() if TitanGetVar(TITAN_GOLD_ID, "SeparateServers") then -- Parse the database and display characters from this server Titan_Debug.Out('gold', 'tool_tip', "=== SeparateServers") - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.same_realm and char.show_toon then @@ -470,7 +461,7 @@ local function GetTooltipText() elseif TitanGetVar(TITAN_GOLD_ID, "MergeServers") then -- Parse the database and display characters from merged / connected servers Titan_Debug.Out('gold', 'tool_tip', "=== MergeServers") - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.merge_realm and char.show_toon then @@ -482,7 +473,7 @@ local function GetTooltipText() elseif TitanGetVar(TITAN_GOLD_ID, "AllServers") then -- Parse the database and display characters from all servers Titan_Debug.Out('gold', 'tool_tip', "=== AllServers") - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid then if char.show_toon then @@ -510,7 +501,7 @@ local function GetTooltipText() charserver = toon.server char_faction = toon.faction - local t_gold = toon.gold --TitanSettings.Players[toon].Info[TITAN_GOLD_ID].gold + local t_gold = toon.gold coin_str = NiceCash(t_gold, false, false) show_dash = false show_realm = true @@ -679,7 +670,7 @@ end ---local See if this toon is in saved vars AFTER PEW event. --- Get current total and session start time. Toon gold is available via API AFTER PEW event. -local function Initialize_Array() +local function Initialize_Array(action) Titan_Debug.Out('gold', 'flow', "Init inititated") local info = "" @@ -690,52 +681,53 @@ local function Initialize_Array() -- See if this is a new toon to Gold saved vars or reset local gindex, _, _ = TitanUtils_GetPlayer() - -- TitanSettings.Players[toon].Info.[TITAN_GOLD_ID] + local result = "" + result, GoldInfo = TitanUtils_GetProfileInfo(gindex, "Info", false) - GoldInfo = TitanSettings.Players[gindex].Info - - if GoldInfo[TITAN_GOLD_ID] then - -- use existing data - else - GoldInfo[TITAN_GOLD_ID] = {} - GoldData = GoldInfo[TITAN_GOLD_ID] - GoldData.gold = 0 + -- Ensure the saved vars are what we need for valid toons + for index, money in TitanUtils_PlayerIter() do + local char = EvalIndexInfo(index) + if char.valid then + local toon_gold ---@class GoldData + result, toon_gold = TitanUtils_GetProfileInfo(index, "Gold", false) + if result == "found" then + if toon_gold == nil then + -- not sure !? + else + -- Added 2026 Feb + if toon_gold.show == nil then + toon_gold.show = true -- default + else + -- exists, use as is + end + + if action == "reset" then + toon_gold.gold = 0 + else + -- use as is + end + end + else + -- ignore + end + else + -- ignore custom profiles or toons not logged into yet + end end + result, GoldData = TitanUtils_GetProfileInfo(gindex, "Gold", true) + GoldData.gold = Get_Money() + Warband.Init() GOLD_STARTINGGOLD = Get_Money(); GOLD_SESSIONSTART = GetTime(); GOLD_INITIALIZED = true; - GoldData = GoldInfo[TITAN_GOLD_ID] - GoldData.gold = Get_Money() - info = "" .. " " .. tostring(GOLD_SESSIONSTART) .. "" .. " " .. tostring(GOLD_STARTINGGOLD) .. "" .. " " .. tostring(Warband.GetSum()) .. "" - - -- Ensure the saved vars are what we need for valid toons - for index, money in pairs(TitanSettings.Players) do - local char = EvalIndexInfo(index) - if char.valid then - -- Added 2026 Feb - if TitanSettings.Players[index].Info[TITAN_GOLD_ID].show == nil then - TitanSettings.Players[index].Info[TITAN_GOLD_ID].show = true -- default - else - -- exists, use as is - end - - if TitanSettings.Players[index].Info[TITAN_GOLD_ID].show == nil then - TitanSettings.Players[index].Info[TITAN_GOLD_ID].show = true -- default - else - -- exists, use as is - end - else - -- ignore custom profiles or toons not logged into yet - end - end end -- 2026 Mar : Repurposed to add sort gold decsending @@ -754,13 +746,12 @@ local function Initialize_Array() .. " " .. info .. "" Titan_Debug.Out('gold', 'flow', msg) end - ---local Clear the gold array and rebuild ---@param self Button local function ClearData(self) GOLD_INITIALIZED = false; - Initialize_Array(); + Initialize_Array("reset"); TitanPanelButton_UpdateButton(TITAN_GOLD_ID) @@ -792,7 +783,7 @@ end local function ShowMenuButtons(faction, level) -- create the list and sort by alpha with server local list_alpha = {} - for index, money in pairs(TitanSettings.Players) do + for index, money in TitanUtils_PlayerIter() do local char = EvalIndexInfo(index) if char.valid and char.faction == faction then table.insert(list_alpha, index); @@ -813,14 +804,26 @@ local function ShowMenuButtons(faction, level) Titan_Menu.AddSelectorGeneric(level, toon, function(data) - local toon_info = TitanSettings.Players[data.c_name].Info ---@class CharInfo - local toon_gold = toon_info[TITAN_GOLD_ID] ---@class GoldData - return toon_gold.show + local res = false + local result = "" + local toon_gold ---@class GoldData + result, toon_gold = TitanUtils_GetProfileInfo(data.c_name, "Gold", false) + if result == "found" and toon_gold ~= nil then + res = toon_gold.show + else + -- !? something bad happened... + end + return res end, function(data) - local toon_info = TitanSettings.Players[data.c_name].Info ---@class CharInfo - local toon_gold = toon_info[TITAN_GOLD_ID] ---@class GoldData - toon_gold.show = not toon_gold.show + local result = "" + local toon_gold ---@class GoldData + result, toon_gold = TitanUtils_GetProfileInfo(data.c_name, "Gold", false) + if result == "found" and toon_gold ~= nil then + toon_gold.show = not toon_gold.show + else + -- !? do nothing + end TitanPanelButton_UpdateButton(TITAN_GOLD_ID); end, { c_name = toon } @@ -836,8 +839,6 @@ local function GeneratorFunction(owner, rootDescription) do -- next level options -- NameAsc | GoldAsc | GoldDec [Ascend, Descend] local disp = { -- selectors using the same option - label, value --- { L["TITAN_GOLD_TOGGLE_SORT_GOLD"], false }, --- { L["TITAN_GOLD_TOGGLE_SORT_NAME"], "true" }, { "Sort by Name", "NameAsc" }, { "Sort by Gold Ascending", "GoldAsc" }, { "Sort by Gold Descending", "GoldDec" }, @@ -896,7 +897,6 @@ local function GeneratorFunction(owner, rootDescription) Titan_Menu.AddDivider(root) local opts_show = Titan_Menu.AddButton(root, L["TITAN_GOLD_SHOW_PLAYER"]) --- .." : "..L["TITAN_GOLD_FACTION_PLAYER_ALLY"]) do local opts_alliance = Titan_Menu.AddButton(opts_show, L["TITAN_GOLD_FACTION_PLAYER_ALLY"]) ShowMenuButtons(TITAN_ALLIANCE, opts_alliance) @@ -906,7 +906,7 @@ local function GeneratorFunction(owner, rootDescription) ShowMenuButtons(TITAN_HORDE, opts_horde) end --- Titan_Menu.AddCommand(root, id, L["TITAN_GOLD_CLEAR_DATA_TEXT"], TitanGold_ClearDB) + Titan_Menu.AddCommand(root, id, L["TITAN_GOLD_CLEAR_DATA_TEXT"], TitanGold_ClearDB) Titan_Menu.AddCommand(root, id, L["TITAN_GOLD_RESET_SESS_TEXT"], ResetSession) end @@ -994,7 +994,7 @@ end ---local When shown, register needed events and start timer for gold per hour ---@param self Button local function OnShow(self) - Initialize_Array() + Initialize_Array("set") self:RegisterEvent("PLAYER_MONEY") if TitanGetVar(TITAN_GOLD_ID, "DisplayGoldPerHour") then @@ -1013,7 +1013,7 @@ local function OnShow(self) Titan_Debug.Out('gold', 'flow', msg) end ----local When shown, unregister needed events and stop timer for gold per hour +---local When hidden, unregister needed events and stop timer for gold per hour ---@param self Button local function OnHide(self) self:UnregisterEvent("PLAYER_MONEY"); @@ -1083,25 +1083,29 @@ function TitanGold.GetInfo(player, add_label) label = "" end + local result = "" + local toon_gold ---@class GoldData + result, toon_gold = TitanUtils_GetProfileInfo(player, "Gold", false) local character, charserver, is_custom = TitanUtils_ParseName(player) - if is_custom then - res = L["TITAN_PANEL_NA"] + if result == "is_custom" then + res = L["TITAN_PANEL_NA"] .. " - Custom profile." elseif _G[TITAN_BUTTON]:IsShown() then - local toon_gold = nil - if TitanSettings.Players[player] - and TitanSettings.Players[player].Info - and TitanSettings.Players[player].Info[TITAN_GOLD_ID] then - toon_gold = TitanSettings.Players[player].Info[TITAN_GOLD_ID] ---@class GoldData - res = NiceCash(toon_gold.gold, true, false) + if result == "found" then + if toon_gold == nil then + res = L["TITAN_PANEL_NA"] .. " - Data empty!?." + else + res = NiceCash(toon_gold.gold, true, false) + end else - res = L["TITAN_PANEL_NA"].." - Not logged in yet with Gold enabled." + res = L["TITAN_PANEL_NA"] .. " - Not logged in yet with Gold enabled." end else res = L["TITAN_PANEL_MENU_DISABLED"] end - return label..res + return label .. res end + ---local Create required Gold frames local function Create_Frames() if _G[TITAN_BUTTON] then