diff --git a/Titan/Titan.lua b/Titan/Titan.lua
index da6ca44..8b051e2 100644
--- a/Titan/Titan.lua
+++ b/Titan/Titan.lua
@@ -920,23 +920,35 @@ SLASH_TitanPanel2 = "/titan";
---@param tex table Texture frame to set
---@param color table Color - RBGA
local function Set_Color(frame, tex, color)
+ -- Jan 2026 : Put gorder on option
+ local edge = TitanBarDataVars[frame].color_border
+ local edge_file = ""
+ if edge then
+ edge_file = "Interface\\Glues\\Common\\TextPanel-Border"
+ else
+ edge_file = ""
+ end
+
--[[
print("_Set bar color"
+.." '"..tostring(frame).."'"
.." "..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))..""
+.." "..tostring(edge)..""
)
--]]
+
_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",
+ edgeFile = edge_file,
tile = true,
- tileEdge = true,
+ tileEdge = edge,
-- insets = { left = 1, right = 1, top = 1, bottom = 1 },
tileSize = 8,
edgeSize = 8,
@@ -946,8 +958,9 @@ print("_Set bar color"
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.alpha); -- 2024 Aug : Border will use the color alpha
+
+ _G[frame]:SetBackdropColor(
color.r,
color.g,
color.b,
@@ -1037,11 +1050,14 @@ print("_Tex"
)
--]]
-- 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
+ else
+--]]
+ if 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)
diff --git a/Titan/TitanConfig.lua b/Titan/TitanConfig.lua
index f0179dc..904b13c 100644
--- a/Titan/TitanConfig.lua
+++ b/Titan/TitanConfig.lua
@@ -403,7 +403,6 @@ local function Format_coord(coord)
return (tostring(format("%0.2f", coord)))
end
-local color_trans = 0
--[[ local
NAME: TitanUpdateConfigBars
DESC: Allow the user to control each Titan bar.
@@ -569,7 +568,7 @@ local function TitanUpdateConfigBars(t, pos)
TitanPanelBarButton_DisplayBarsWanted("Bar reset to default position - " .. tostring(info[1]))
end,
}
-
+--[[
-- ======
-- Background group
position = position + 1 -- global background
@@ -596,13 +595,14 @@ local function TitanUpdateConfigBars(t, pos)
},
},
}
-
+--]]
position = position + 1 -- background
args[v.name].args.background = {
name = BACKGROUND,
type = "group",
inline = true,
order = position,
+ --[[
hidden = function(info)
local hide = false
if TitanBarDataVars["Global"].texure == Titan_Global.NONE then
@@ -612,6 +612,7 @@ local function TitanUpdateConfigBars(t, pos)
end
return hide
end,
+ --]]
args = {
settextousebar = {
name = "",
@@ -649,15 +650,9 @@ local function TitanUpdateConfigBars(t, pos)
order = 320,
width = "full",
},
- colorspacer = {
- order = 330,
- type = "description",
- width = "full",
- name = " ",
- },
colorselect = {
type = "color",
- width = "Full",
+ width = "normal",
name = L["TITAN_PANEL_BAR_COLOR"],
order = 340,
-- disabled = (v.vert == TITAN_TOP or v.vert == TITAN_BOTTOM),
@@ -678,9 +673,24 @@ local function TitanUpdateConfigBars(t, pos)
TitanBarDataVars[frame_str].color.b = b
TitanBarDataVars[frame_str].color.alpha = a
TitanPanel_SetBarTexture(frame_str)
- color_trans = a
end,
},
+ showborder = {
+ type = "toggle",
+ width = "normal",
+ name = "Show Border", --L["TITAN_PANEL_MENU_DISPLAY_BAR"],
+ order = 350,
+ get = function(info)
+ local frame_str = TitanVariables_GetFrameName(info[1])
+ return TitanBarDataVars[frame_str].color_border
+ end,
+ set = function(info, val)
+ local frame_str = TitanVariables_GetFrameName(info[1])
+ TitanBarDataVars[frame_str].color_border = not TitanBarDataVars[frame_str].color_border
+ TitanPanel_SetBarTexture(frame_str)
+-- TitanUpdateConfigBars(optionsBars.args, 1000)
+ end,
+ }
},
},
skingroup = {
diff --git a/Titan/TitanVariables.lua b/Titan/TitanVariables.lua
index d1be1c6..93c677c 100644
--- a/Titan/TitanVariables.lua
+++ b/Titan/TitanVariables.lua
@@ -323,6 +323,7 @@ TitanSkinsPathEnd = "\\"
---Global is an additional index used if the user wants all Bars to be the same skin or color.
TitanBarVarsDefaults = {
+ --[[
["Global"] = -- holds 'global' user settings; NOT for use in the frame loop!
{
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
@@ -330,12 +331,14 @@ TitanBarVarsDefaults = {
texure = Titan_Global.NONE, -- Titan_Global.NONE or Titan_Global.SKIN or Titan_Global.COLOR
hide_in_combat = false,
},
+ --]]
[TITAN_PANEL_DISPLAY_PREFIX .. "Bar"] = {
off_x = 0,
off_y = 0,
off_w = x_max,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN, -- or Titan_Global.COLOR
show = true,
auto_hide = false,
@@ -349,6 +352,7 @@ TitanBarVarsDefaults = {
off_w = x_max,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -362,6 +366,7 @@ TitanBarVarsDefaults = {
off_w = x_max,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -375,6 +380,7 @@ TitanBarVarsDefaults = {
off_w = x_max,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -388,6 +394,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -401,6 +408,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -414,6 +422,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -427,6 +436,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -440,6 +450,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -453,6 +464,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -466,6 +478,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -479,6 +492,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -492,6 +506,7 @@ TitanBarVarsDefaults = {
off_w = SHORT_WIDTH,
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
+ color_border = true,
texure = Titan_Global.SKIN,
show = false,
auto_hide = false,
@@ -506,6 +521,7 @@ TitanBarVarsDefaults = {
skin = { path = TitanSkinsDefaultPath, alpha = 0.7 },
color = { r = 1.0, g = .5, b = 1.0, alpha = 1.0 },
texure = Titan_Global.SKIN,
+ color_border = true,
show = false,
auto_hide = false,
align = TITAN_PANEL_BUTTONS_ALIGN_LEFT, -- TITAN_PANEL_BUTTONS_ALIGN_CENTER
@@ -913,6 +929,15 @@ local function Titan_SyncAdjList()
end
end
+local function AdjBarVars(to_profile)
+ local BV = TitanSettings.Players[to_profile].BarVars
+ for idx, v in pairs(TitanBarData) do
+ if v.color_border == nil then -- NEW Jan 2026
+ BV[idx].color_border = true
+ end
+ end
+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
@@ -955,6 +980,9 @@ local function Set_bar_vars(to_profile)
.. " " .. tostring(to_profile) .. ""
Titan_Debug.Out('titan', 'profile', str)
end
+
+ -- New 2026 : Add any new BarVar or delete removed fields to ALL known profiles
+ AdjBarVars(to_profile)
end
local function Check_Titan_settings()
diff --git a/TitanPost/TitanPost.lua b/TitanPost/TitanPost.lua
index cca38a2..f06701a 100644
--- a/TitanPost/TitanPost.lua
+++ b/TitanPost/TitanPost.lua
@@ -15,17 +15,19 @@ local FolderPre = "Interface\\AddOns\\TitanPost\\artwork\\"
-- Local variables
local L = LibStub("AceLocale-3.0"):GetLocale("Titan", true)
local AceConfigDialog = LibStub("AceConfigDialog-3.0")
+local AceTimer = LibStub("AceTimer-3.0")
+local AceHook = LibStub("AceHook-3.0")
local mailbox = {} -- default on load; store display info here
mailbox.opened = false
+mailbox.open_now = false
mailbox.new = 0
mailbox.expiry_text = ""
mailbox.expiry_num = 0
-
-local enter_or_reload = true
+mailbox.ignore_next_pending = false
local player = TitanUtils_GetPlayer()
-local debug = false;
+local debug = true;
local SECONDS_PER_DAY = 24 * 60 * 60
local SECONDS_PER_HOUR = 60 * 60
local MAX_MAIL_DAYS = 30
@@ -34,12 +36,12 @@ local expiry_warn_days = 7
local expiry_err_days = 2
local DAYS_REM = "Days Remaining"
-local MAIL_OPENED = "Mail Opened"
+local MAIL_OPENED = "Opened"
local CHAR = "Character"
-local NEW_PRE = " + "
-local EXP_PRE = " ! "
-local READ_TT_PRE = "About : "
+local READ_PRE = " ?? "
+local NEW_PRE = " ++ "
+local EXP_PRE = " !! "
local READ_TT_POST = " : About read / total "
local NEW_TT_POST = " : New Mail this session "
local EXP_TT_POST = " : Characters with expiring Mail "
@@ -52,7 +54,10 @@ TitanPost.mailbox = mailbox
function Debug(str)
if (debug) then
- DEFAULT_CHAT_FRAME:AddMessage("TitanPost " .. str);
+ DEFAULT_CHAT_FRAME:AddMessage("TitanPost "
+ .. date("%H:%M:%S ", _G.time())
+ .. str
+ );
end
end
@@ -81,18 +86,21 @@ local function FormatTS(time_sec, with_time)
return str
end
+---Start / stop the timer to check expiry
+---@param action string 'start' | 'stop'
+local function ExpiryTimer(action) end -- real declaration later...
+
---Format an expiry text for a single toon
---@param toon_name string
----@param next_expiry number timestamp
----@param last_update number timestamp
+---@param toon_info table toon
---@return string
-local function ShowExpiry(toon_name, next_expiry, last_update)
+local function ShowExpiry(toon_name, toon_info)
local now = _G.time()
local res = ""
local use_color = true -- TitanGetVar(TITAN_POST_ID, "ShowColoredText")
- local days = math.floor((next_expiry - now) / SECONDS_PER_DAY)
- local last = FormatTS(last_update, true)
+ local days = math.floor((toon_info.nextExpiry - now) / SECONDS_PER_DAY)
+ local last = toon_info.lastUpdate_str
local estr = toon_name
.. " : " .. days
.. " : " .. last
@@ -141,24 +149,25 @@ local function CheckExpiry()
str = "CheckExpiry"
.. " @ " .. FormatTS(expiry_check, true)
- .. " " .. tostring(expiry_check) .. ""
+ .. " (" .. tostring(expiry_check) .. ")"
Debug(str)
for toon_name, characterList in pairs(TitanPostDB) do
str = ".CheckExpiry"
.. " " .. tostring(toon_name) .. ""
.. " # " .. tostring(characterList.mailCount) .. ""
- Debug(str)
+ -- Debug(str)
if (characterList.mailCount > 0) then
str = "...CheckExpiry"
+ .. " [" .. tostring(characterList.nextExpiry_str) .. "]"
.. " " .. tostring(characterList.nextExpiry) .. ""
.. " < " .. tostring(expiry_check) .. ""
.. " = " .. tostring((characterList.nextExpiry < expiry_check)) .. ""
- Debug(str)
+ -- Debug(str)
if (characterList.nextExpiry < expiry_check) then -- add to list for user
has_expiry = true
- local estr = ShowExpiry(toon_name, characterList.nextExpiry, characterList.lastUpdate)
+ local estr = ShowExpiry(toon_name, characterList)
exp_str = exp_str .. estr
expiry_toons = expiry_toons + 1 -- count the number of toons with expiring mail
@@ -177,7 +186,9 @@ local function CheckExpiry()
-- still time
end
- str = "CheckExpiry"
+ ExpiryTimer('start')
+
+ str = "=CheckExpiry"
.. " " .. tostring(expiry_toons) .. ""
.. " \n" .. tostring(res) .. ""
Debug(str)
@@ -185,6 +196,35 @@ local function CheckExpiry()
return expiry_toons, res
end
+local expiry_timer = nil
+function ExpiryTimer(action) -- prior declaration
+ if action == 'start' then
+ -- stop current, just in case for sanity
+ if expiry_timer == nil then
+ -- no timer
+ else
+ AceTimer.CancelTimer(_G[TITAN_BUTTON], expiry_timer)
+ end
+ local time_int = TitanGetVar(TITAN_POST_ID, "ExpiryTimer")
+ expiry_timer =
+ AceTimer.ScheduleRepeatingTimer(_G[TITAN_BUTTON], CheckExpiry, time_int * 60) -- in seconds
+ local str = "Expiry next check in"
+ .. " " .. tostring(time_int) .. " minutes"
+ Debug(str)
+ elseif action == 'stop' then
+ if expiry_timer == nil then
+ -- no timer
+ else
+ AceTimer.CancelTimer(_G[TITAN_BUTTON], expiry_timer)
+ expiry_timer = nil
+ end
+ end
+
+ local str = "ExpiryTimer"
+ .. " " .. tostring(action) .. ""
+ Debug(str)
+end
+
---Create an x/y string for Mail
---@param playerName string
---@param addOpen boolean
@@ -197,12 +237,12 @@ local function GetCountsStr(playerName, addOpen)
if mailbox.opened then
res = res .. " " -- counts should be accurate for this session
else
- res = res .. "? " -- counts may not be accurate
+ res = res .. READ_PRE -- counts may not be accurate
end
end
if (toon.lastUpdate == 0) then
- res = res .. L["TITAN_PANEL_NA"] --NOT_OPENED for first time yet
+ res = res .. L["TITAN_PANEL_NA"] --NOT_OPENED yet
else
if toon.mailCount > 0 then
res = res .. toon.mailReadNum .. "/" .. toon.mailCount
@@ -249,15 +289,16 @@ function GetTooltipText()
local res = ""
local toon = TitanPostDB[player]
- res = MAIL_TT_PRE .. FormatTS(toon.lastUpdate, true) .. "\n"
- res = res.. " "
+ res = MAIL_TT_PRE .. tostring(toon.lastUpdate_str) .. "\n"
+ res = res .. " "
.. GetCountsStr(player, true)
.. READ_TT_POST .. "\n"
local new = ""
if (mailbox.new > 0) then
- new = NEW_PRE .. tostring(mailbox.new) .. NEW_TT_POST .. "\n"
+ -- new = NEW_PRE .. tostring(mailbox.new) .. NEW_TT_POST .. "\n"
+ new = NEW_PRE .. NEW_TT_POST .. "\n"
else
new = ""
end
@@ -282,7 +323,7 @@ local function UpdateInboxData()
return
end
- local inboxCount = _G.GetInboxNumItems()
+ local inboxCount, totalCount = _G.GetInboxNumItems()
local playerData = TitanPostDB[player]
local remainingDays = MAX_MAIL_DAYS
local mailReadNum = 0
@@ -293,6 +334,7 @@ local function UpdateInboxData()
local str = "UpdateInboxData"
.. " " .. tostring(playerData) .. ""
.. " #" .. tostring(inboxCount) .. ""
+ .. " #" .. tostring(totalCount) .. ""
Debug(str)
for index = 1, inboxCount do
@@ -334,9 +376,12 @@ local function UpdateInboxData()
end
playerData.lastUpdate = now
+ playerData.lastUpdate_str = FormatTS(playerData.lastUpdate, true)
playerData.mailCount = inboxCount
playerData.mailReadNum = mailReadNum
- playerData.nextExpiry = math.floor(remainingDays * SECONDS_PER_DAY) + now -- make timestamp
+ local ex_ts = math.floor(remainingDays * SECONDS_PER_DAY) + now -- make timestamp
+ playerData.nextExpiry = ex_ts
+ playerData.nextExpiry_str = FormatTS(ex_ts, true)
end
---Look for expiry notifications, the routine will include the current too
@@ -372,33 +417,68 @@ local function InitVars()
end
---Process the MAIL_INBOX_UPDATE event while mailbox is open
-local function MailInboxUpdate()
- local str = "MAIL_INBOX_UPDATE"
- .. " " .. tostring(mailbox.opened) .. ""
+local function MailInboxUpdate(reason)
+ local str = "MailInboxUpdate"
+ .. " o: " .. tostring(mailbox.opened) .. ""
+ .. " on: " .. tostring(mailbox.open_now) .. ""
+ .. " " .. tostring(reason) .. ""
Debug(str)
UpdateInboxData()
UpdateInfo()
- Debug("Inbox: " .. GetInboxNumItems());
+
+ local numItems, totalItems = GetInboxNumItems()
+ Debug("Inbox: "
+ .. " #" .. numItems .. ""
+ .. " #" .. totalItems .. ""
+ )
TitanPanelButton_UpdateButton(TITAN_POST_ID)
end
+local function OpenMailbox()
+ mailbox.opened = true -- this session only
+ mailbox.open_now = true
+
+ MailInboxUpdate("Mailbox opened")
+end
+
+local function CloseMailbox()
+ mailbox.open_now = false -- this session only
+
+ if HasNewMail() then
+ -- has unread mail, expect a nag event :)
+ mailbox.ignore_next_pending = true
+ else
+ -- no unread mail
+ end
+
+ local reason = "Mailbox closed " .. tostring(mailbox.ignore_next_pending)
+ MailInboxUpdate(reason)
+end
+
---Process the UPDATE_PENDING_MAIL event
local function UpdatePending()
+ local action = ""
-- Fires on entering world if player has unread mail...
- if enter_or_reload then
+ if mailbox.ignore_next_pending then
-- ignore 1st event on entering world (first or instance or reload)
- enter_or_reload = false
+ mailbox.ignore_next_pending = false
+ action = "ignored"
else
-- Likely a brand new mail
mailbox.new = mailbox.new + 1
+ action = "+ 1"
end
- local str = "UPDATE_PENDING_MAIL"
- .. " " .. tostring(mailbox.opened) .. ""
- .. " " .. tostring(HasNewMail()) .. ""
- .. " " .. tostring(GetInboxNumItems()) .. ""
+ local numItems, totalItems = GetInboxNumItems()
+ local str = "UpdatePending"
+ .. " o:" .. tostring(mailbox.opened) .. ""
+ .. " on: " .. tostring(mailbox.open_now) .. ""
+ .. " n:" .. tostring(HasNewMail()) .. ""
+ .. " #" .. numItems .. ""
+ .. " #" .. totalItems .. ""
+ .. " " .. tostring(action) .. ""
Debug(str)
@@ -421,16 +501,16 @@ end
---@param event string
---@param ... unknown
local function OnEvent(self, event, arg1, ...)
- Debug(time() .. " " .. event);
+ Debug("New > " .. event);
if (event == "VARIABLES_LOADED") then
InitVars()
end
if (event == "PLAYER_ENTERING_WORLD") then
-- ignore 1st UPDATE_PENDING_MAIL event on entering world (first or instance or reload)
- enter_or_reload = true
+ mailbox.ignore_next_pending = true
end
+ ---[===[
if (event == "MAIL_INBOX_UPDATE") then
- mailbox.opened = true -- this session only
--[[ Dec 2025 https://warcraft.wiki.gg/wiki/MAIL_INBOX_UPDATE
Fires when the inbox list is loaded while the frame is open
Fires when mail item changes from new to read
@@ -438,6 +518,7 @@ Fires when mail item is opened for the first time in a session
--]]
MailInboxUpdate()
end
+ --]===]
if (event == "UPDATE_PENDING_MAIL") then
--[[ Dec 2025 https://warcraft.wiki.gg/wiki/UPDATE_PENDING_MAIL
Fired when the player enters the world and enters/leaves an instance, if there is mail in the player's mailbox.
@@ -445,7 +526,12 @@ Fired when new mail is received.
Fired when mailbox window is closed if the number of mail items in the inbox changed (I.E. you deleted mail)
Does not appear to trigger when auction outbid mail is received... may not in other cases as well
--]]
- UpdatePending()
+
+ if mailbox.ignore_next_pending then
+ -- ignore this event
+ else
+ UpdatePending()
+ end
end
if (event == "CHAT_MSG_SYSTEM") then
--[[ Dec 2025 https://warcraft.wiki.gg/wiki/UPDATE_PENDING_MAIL
@@ -455,26 +541,68 @@ Appears to be a long standing bug that AH 'out bid' message does not fire a 'mai
end
end
+TitanPost.time_ints = {
+ { min = 1, set = false },
+ { min = 10, set = false },
+ { min = 30, set = false },
+ { min = 60, set = false },
+}
+local function SetTimer(val)
+ local timer = val or 10
+ local time_ints = TitanPost.time_ints
+ for idx = 1, #time_ints do
+ if time_ints[idx].min == timer then
+ time_ints[idx].set = true
+ else
+ time_ints[idx].set = false
+ end
+ end
+end
+
---First level of right click menu
---@param frame Button
local function BuildMainMenu(frame)
local info;
- TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_POST_ID].menuText);
- TitanPanelRightClickMenu_AddSpacer();
+ TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_POST_ID].menuText, TitanPanelRightClickMenu_GetDropdownLevel());
+
+ TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel());
+
+ info = {};
+ info.notCheckable = true
+ info.text = "Expiry Check Interval"
+ info.value = "ExpiryInterval";
+ TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());
+
+ SetTimer(TitanGetVar(TITAN_POST_ID, "ExpiryTimer"))
+ local time_ints = TitanPost.time_ints
+ for idx = 1, #time_ints do
+ info = {};
+ info.text = tostring(time_ints[idx].min) .. L["TITAN_PANEL_MINUTES_ABBR"]
+ info.checked = time_ints[idx].set
+ ---@diagnostic disable-next-line: duplicate-set-field
+ info.func = function()
+ SetTimer(time_ints[idx].min)
+ TitanSetVar(TITAN_POST_ID, "ExpiryTimer", time_ints[idx].min)
+ end
+ TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());
+ end
+ TitanPanelRightClickMenu_AddSeparator(TitanPanelRightClickMenu_GetDropdownLevel());
+
info = {};
info.notCheckable = true
info.text = L["TITAN_PANEL_MENU_PROFILES"] .. " " .. L["TITAN_PANEL_MENU_CONFIGURATION"]
info.value = "ConfigProfile";
+ ---@diagnostic disable-next-line: duplicate-set-field
info.func = function()
TitanUpdateConfig("init")
-- Open the profile config as distinct frame
AceConfigDialog:Open("Titan Panel Addon Chars")
end
- TitanPanelRightClickMenu_AddButton(info);
- TitanPanelRightClickMenu_AddSpacer();
+ TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());
+ -- TitanPanelRightClickMenu_AddSpacer(TitanPanelRightClickMenu_GetDropdownLevel());
- TitanPanelRightClickMenu_AddControlVars(TITAN_POST_ID)
+ TitanPanelRightClickMenu_AddControlVars(TITAN_POST_ID, TitanPanelRightClickMenu_GetDropdownLevel())
end
---Handle navigating within right click menu
@@ -497,8 +625,21 @@ local function OnShow(self)
self:RegisterEvent("UPDATE_PENDING_MAIL")
self:RegisterEvent("PLAYER_ENTERING_WORLD")
- -- self:RegisterEvent("MAIL_SHOW") -- use MAIL_INBOX_UPDATE
- -- self:RegisterEvent("MAIL_CLOSED") -- In retail, does NOT fire
+ -- Ace does parameter shuffling under the hood depending on the types passed
+ -- hence the ignore diagnostic...
+ ---@diagnostic disable-next-line: param-type-mismatch
+ if AceHook:IsHooked("MailFrame_Show", OpenMailbox) then
+ -- Already hooked
+ else
+ AceHook:SecureHook("MailFrame_Show", OpenMailbox) -- MailFrame.lua
+ end
+ ---@diagnostic disable-next-line: param-type-mismatch
+ if AceHook:IsHooked("MailFrame_Hide", CloseMailbox) then
+ -- Already hooked
+ else
+ -- Ace does parameter shuffling under the hood depending on the types passed
+ AceHook:SecureHook("MailFrame_Hide", CloseMailbox) -- MailFrame.lua
+ end
UpdateInfo()
TitanPanelButton_UpdateButton(TITAN_POST_ID)
@@ -513,6 +654,23 @@ local function OnHide(self)
self:UnregisterEvent("MAIL_INBOX_UPDATE");
self:UnregisterEvent("UPDATE_PENDING_MAIL");
self:UnregisterEvent("PLAYER_ENTERING_WORLD");
+
+ ---@diagnostic disable-next-line: param-type-mismatch
+ if AceHook:IsHooked("MailFrame_Show", OpenMailbox) then
+ ---@diagnostic disable-next-line: param-type-mismatch
+ AceHook:Unhook("MailFrame_Show", OpenMailbox) -- MailFrame.lua
+ else
+ -- nothing to do
+ end
+ ---@diagnostic disable-next-line: param-type-mismatch
+ if AceHook:IsHooked("MailFrame_Hide", CloseMailbox) then
+ ---@diagnostic disable-next-line: param-type-mismatch
+ AceHook:Unhook("MailFrame_Hide", CloseMailbox) -- MailFrame.lua
+ else
+ -- nothing to do
+ end
+
+ ExpiryTimer('stop')
end
---Handle any mouse clicks
@@ -555,11 +713,8 @@ local function OnLoad(self)
ShowLabelText = true,
-- ShowColoredText = true,
DisplayOnRightSide = false,
- ShowCount = 1,
- ShowText = 1,
- new = 0,
- total = 0,
- chat = 1,
+ ExpiryTimer = 10,
+ ShowToonList = true,
}
};
@@ -568,6 +723,45 @@ local function OnLoad(self)
self:RegisterEvent("PLAYER_ENTERING_WORLD");
end
+local function FormatCounts(playerName, now)
+ local toon = TitanPostDB[playerName]
+ local res = ""
+ local div = " : "
+
+ local last_open = ""
+ local counts = ""
+ local warning = ""
+ if (toon.lastUpdate == 0) then
+ last_open = L["TITAN_PANEL_NA"] --NOT_OPENED yet
+ else
+ last_open = tostring(toon.lastUpdate_str)
+
+ if toon.mailCount >= 0 then
+ -- counts may not be accurate
+ counts = div .. READ_PRE .. toon.mailReadNum .. "/" .. toon.mailCount
+ else
+ -- leave blank
+ end
+
+ if (toon.nextExpiry < ExpiryWarn()) then
+ -- add to list for user
+ local days = math.floor((toon.nextExpiry - now) / SECONDS_PER_DAY)
+ local color = TitanUtils_GetThresholdColor(ThresholdTable, days)
+ local days_str = DAYS_REM .. " : " .. tostring(days)
+ days_str = TitanUtils_GetColoredText(days_str, color)
+ warning = div .. days_str
+ else
+ -- no mail to warn about
+ warning = ""
+ end
+ end
+
+ res = MAIL_OPENED .. " " .. last_open .. counts .. warning .. "\n"
+
+ return res
+end
+
+
---Titan Allow Titan to lookup mail info for a toon; return a formatted string
---@param playerName string
---@return string
@@ -581,33 +775,7 @@ function TitanPost.GetMailInfo(playerName)
if _G[TITAN_BUTTON]:IsShown() then
if TitanPostDB and TitanPostDB[playerName] then
- local p = TitanPostDB[playerName]
- local estr = ""
- local last = ""
-
- if p.lastUpdate == 0 then
- -- not opened mail yet
- res = L["TITAN_PANEL_NA"]
- else
- if (p.mailCount > 0) then
- estr = GetCountsStr(playerName, false) .. "? "
- if (p.nextExpiry < ExpiryWarn()) then -- add to list for user
- local days = math.floor((p.nextExpiry - now) / SECONDS_PER_DAY)
- local color = TitanUtils_GetThresholdColor(ThresholdTable, days)
- local days_str = DAYS_REM .. " : " .. tostring(days)
- days_str = TitanUtils_GetColoredText(days_str, color)
- estr = estr .. days_str .. "\n"
- else
- -- no mail to warn about
- estr = ""
- end
- else
- -- empty
- end
-
- last = MAIL_OPENED .. " : " .. FormatTS(p.lastUpdate, true) .. "\n"
- res = estr .. last
- end
+ res = FormatCounts(playerName, now)
else
res = L["TITAN_PANEL_NA"]
end
@@ -741,7 +909,13 @@ end
function TitanPost.SimUpdateExpiry()
UpdateInfo()
- Debug("Inbox: " .. GetInboxNumItems());
+
+ local numItems, totalItems = GetInboxNumItems()
+ local str = "Inbox Sim : "
+ .. " " .. numItems .. ""
+ .. " " .. totalItems .. ""
+ Debug(str);
+
TitanPanelButton_UpdateButton(TITAN_POST_ID)
end
diff --git a/TitanUI/Tools.lua b/TitanUI/Tools.lua
index 1171d7a..7f094d7 100755
--- a/TitanUI/Tools.lua
+++ b/TitanUI/Tools.lua
@@ -22,7 +22,7 @@ local VERSION = C_AddOns.GetAddOnMetadata(add_on, "Version")
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))
+ DEFAULT_CHAT_FRAME.editBox:SetText(_G[slash] .. " " .. tostring(params))
ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox, 0)
end
@@ -85,7 +85,7 @@ local function CreateMenu()
info = {};
info.notCheckable = true
info.text = "Open WoWLua"
----@diagnostic disable-next-line: undefined-global
+ ---@diagnostic disable-next-line: undefined-global
info.disabled = (SLASH_WOWLUA1 == nil)
info.func = function()
SendSlash("SLASH_WOWLUA1")
@@ -103,10 +103,36 @@ end
-- Create the tooltip string
local function GetTooltipText()
- local returnstring = ""
- returnstring = returnstring.."Left Click: Reloads the User Interface\n"
- returnstring = returnstring.."Right Click: For Shortcuts and Debug Tools\n"
- return returnstring
+ local res = ""
+ local rtn = "\n"
+ local tab = "\t"
+
+ local realm = TitanUtils_GetNormalText("Current Server :") .. tab
+ .. TitanUtils_GetHighlightText(GetRealmName()) .. rtn
+
+ local now = _G.time()
+
+ local resets = "Resets in Server Time" .. rtn
+ local week_reset = C_DateAndTime.GetSecondsUntilWeeklyReset()
+ local weekly = TitanUtils_GetNormalText("Weekly :") .. tab
+ .. TitanUtils_GetHighlightText(TitanUtils_GetDateText(week_reset + now, true)) .. rtn
+
+ local day_reset = C_DateAndTime.GetSecondsUntilDailyReset()
+ local daily = TitanUtils_GetNormalText("Daily :") .. tab
+ .. TitanUtils_GetHighlightText(TitanUtils_GetDateText(day_reset + now, true)) .. rtn
+
+ local hints = ""
+ .. TitanUtils_GetGreenText("Left Click: Reloads the User Interface") .. rtn
+ .. TitanUtils_GetGreenText("Right Click: For Shortcuts and Debug Tools") .. rtn
+
+ res = res
+ .. realm
+ .. rtn
+ .. resets .. daily .. weekly
+ .. rtn
+ .. hints
+
+ return res
end
-- Create the .registry for Titan so it can register and place the plugin
@@ -131,13 +157,13 @@ local function OnLoad(self)
controlVariables = {
ShowIcon = true,
ShowLabelText = true,
--- ShowColoredText = true,
+ -- ShowColoredText = true,
DisplayOnRightSide = true,
},
savedVariables = {
ShowIcon = 1,
ShowLabelText = 1,
--- ShowColoredText = 1,
+ -- ShowColoredText = 1,
DisplayOnRightSide = false,
}
};
@@ -155,7 +181,7 @@ local function OnClick(self, button)
)
end
if (button == "LeftButton") then
- ReloadUI()
+ C_UI.Reload() --ReloadUI()
end
end