From 7b8c0251fc063d0266ea802596c98f5635518ae3 Mon Sep 17 00:00:00 2001 From: Bluewhale1337 <295648290+Bluewhale1337@users.noreply.github.com> Date: Wed, 21 Oct 2026 22:33:01 +0200 Subject: [PATCH] fix: dropdown syntax + converted to named click handlers --- HealBot_Controller_Events.lua | 22 ++++++ HealBot_Data.lua | 4 + HealBot_Integrations.lua | 3 + HealBot_Options_Integrations.lua | 119 ++++++++++++++++++++++++++++ HealBot_Options_Integrations.xml | 76 +++++++++++++++++- HealBot_View_Layout.lua | 130 ++++++++++++++++++++++++++----- README.md | 1 + 7 files changed, 334 insertions(+), 21 deletions(-) diff --git a/HealBot_Controller_Events.lua b/HealBot_Controller_Events.lua index bad14f4..b26d44e 100644 --- a/HealBot_Controller_Events.lua +++ b/HealBot_Controller_Events.lua @@ -197,6 +197,28 @@ function HealBot_OnUpdate(this, arg1) if HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1 then if not HealBot_HoT_Update_Timer or GetTime() >= HealBot_HoT_Update_Timer then HealBot_HoT_Update_Timer = GetTime() + 0.25 + local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0 + if displayMode == 1 then + -- Icon Overlay mode: dirty-flag units with active Nampower auras + if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then + local now = GetTime() + for guid, auras in pairs(HealBot_Nampower_Auras) do + local hasActive = false + for _, exp in pairs(auras) do + if exp > now then hasActive = true; break end + end + if hasActive then + local unitID = (HealBot_Model and HealBot_Model:GetUnitByGUID(guid)) + if not unitID and HealBot_PlayerGUID and guid == HealBot_PlayerGUID then + unitID = "player" + end + if unitID and not string.find(unitID, "pet") then + HealBot_View_DirtyUnits[unitID] = true + end + end + end + end + end if HealBot_Action_UpdatePlayerHoTs then HealBot_Action_UpdatePlayerHoTs() end diff --git a/HealBot_Data.lua b/HealBot_Data.lua index 3ab8840..0184c6a 100644 --- a/HealBot_Data.lua +++ b/HealBot_Data.lua @@ -269,6 +269,8 @@ HealBot_ConfigDefaults = { HealBot_Integrations_SuperWoW = 0, HealBot_Integrations_ClassicAPI = 0, HealBot_Integrations_ShowHoTTimers = 0, + HealBot_Integrations_HoTTimerPosition = "BELOW", + HealBot_Integrations_HoTTimerDisplayMode = 0, }; HealBot_Config = {}; @@ -621,11 +623,13 @@ HealBot_TrackedAura_Spells = {}; function HealBot_Init_TrackedAuras() for spell, info in pairs(HealBot_TrackedAuras) do + info.spell = spell HealBot_TrackedAura_Textures[info.texture] = info HealBot_TrackedAura_Spells[spell] = info if info.locKey then local locName = getglobal(info.locKey) if locName and locName ~= "" then + info.locName = locName HealBot_TrackedAura_Spells[locName] = info end end diff --git a/HealBot_Integrations.lua b/HealBot_Integrations.lua index 65a34a7..f6e0884 100644 --- a/HealBot_Integrations.lua +++ b/HealBot_Integrations.lua @@ -145,5 +145,8 @@ end HealBot_Options_Integrations_ShowHoTTimers:SetChecked(0) HealBot_Config.HealBot_Integrations_ShowHoTTimers = 0 end + if HealBot_Options_Integrations_UpdateDropdownStates then + HealBot_Options_Integrations_UpdateDropdownStates() + end end end diff --git a/HealBot_Options_Integrations.lua b/HealBot_Options_Integrations.lua index d9d754b..ffd541c 100644 --- a/HealBot_Options_Integrations.lua +++ b/HealBot_Options_Integrations.lua @@ -1,3 +1,34 @@ +-- HealBot_Options_Integrations.lua + +local function HealBot_Options_SetDropDownState(frame, enabled) + if not frame then return end + local button = getglobal(frame:GetName() .. "Button") + local text = getglobal(frame:GetName() .. "Text") + if button then + if enabled then + button:Enable() + else + button:Disable() + end + end + if text then + if enabled then + text:SetTextColor(1, 1, 1) + else + text:SetTextColor(0.5, 0.5, 0.5) + end + end +end + +-- Update enabled/disabled state of dropdowns based on current config +function HealBot_Options_Integrations_UpdateDropdownStates() + local timersEnabled = HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1 + local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0 + + HealBot_Options_SetDropDownState(HealBot_Options_Integrations_DisplayModeDropdown, timersEnabled) + HealBot_Options_SetDropDownState(HealBot_Options_Integrations_PositionDropdown, timersEnabled and (displayMode == 0)) +end + -- HealBot_Options_Integrations_OnShow: UI handler for OnShow options panel. function HealBot_Options_Integrations_OnShow(this) HealBot_Options_Integrations_UnitXP:SetChecked(HealBot_Config.HealBot_Integrations_UnitXP); @@ -5,4 +36,92 @@ function HealBot_Options_Integrations_OnShow(this) HealBot_Options_Integrations_SuperWoW:SetChecked(HealBot_Config.HealBot_Integrations_SuperWoW); HealBot_Options_Integrations_ClassicAPI:SetChecked(HealBot_Config.HealBot_Integrations_ClassicAPI); HealBot_Options_Integrations_ShowHoTTimers:SetChecked(HealBot_Config.HealBot_Integrations_ShowHoTTimers); + + -- Set display mode dropdown text + local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0 + if displayMode == 1 then + UIDropDownMenu_SetText("Icon Overlay", HealBot_Options_Integrations_DisplayModeDropdown) + else + UIDropDownMenu_SetText("List", HealBot_Options_Integrations_DisplayModeDropdown) + end + + -- Set position dropdown text + local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW" + local posLabels = { BELOW = "Below", ABOVE = "Above", LEFT = "Left", RIGHT = "Right" } + UIDropDownMenu_SetText(posLabels[pos] or "Below", HealBot_Options_Integrations_PositionDropdown) + + -- Update enabled/disabled state + HealBot_Options_Integrations_UpdateDropdownStates() +end + +-- Display Mode dropdown click handler (relying on global this) +function HealBot_Options_Integrations_DisplayModeDropdown_OnClick() + UIDropDownMenu_SetSelectedID(HealBot_Options_Integrations_DisplayModeDropdown, this:GetID()) + HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode = this.value + UIDropDownMenu_SetText(this:GetText(), HealBot_Options_Integrations_DisplayModeDropdown) + HealBot_Options_Integrations_UpdateDropdownStates() + if HealBot_Action_UnitButtons then + for u in pairs(HealBot_Action_UnitButtons) do + HealBot_View_DirtyUnits[u] = true + end + end + if HealBot_Action_UpdatePlayerHoTs then + HealBot_Action_UpdatePlayerHoTs() + end +end + +-- Display Mode dropdown init +function HealBot_Options_Integrations_DisplayModeDropdown_Init() + local mode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0 + local info + + info = {} + info.text = "List" + info.value = 0 + info.func = HealBot_Options_Integrations_DisplayModeDropdown_OnClick + if mode == 0 then + info.checked = 1 + end + UIDropDownMenu_AddButton(info) + + info = {} + info.text = "Icon Overlay" + info.value = 1 + info.func = HealBot_Options_Integrations_DisplayModeDropdown_OnClick + if mode == 1 then + info.checked = 1 + end + UIDropDownMenu_AddButton(info) +end + +-- Position dropdown click handler (relying on global this) +function HealBot_Options_Integrations_PositionDropdown_OnClick() + UIDropDownMenu_SetSelectedID(HealBot_Options_Integrations_PositionDropdown, this:GetID()) + HealBot_Config.HealBot_Integrations_HoTTimerPosition = this.value + UIDropDownMenu_SetText(this:GetText(), HealBot_Options_Integrations_PositionDropdown) + if HealBot_Action_UpdatePlayerHoTs then + HealBot_Action_UpdatePlayerHoTs() + end +end + +-- Position dropdown init +function HealBot_Options_Integrations_PositionDropdown_Init() + local positions = { + { value = "BELOW", label = "Below" }, + { value = "ABOVE", label = "Above" }, + { value = "LEFT", label = "Left" }, + { value = "RIGHT", label = "Right" }, + } + local currentPos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW" + + for _, p in ipairs(positions) do + local info = {} + info.text = p.label + info.value = p.value + info.func = HealBot_Options_Integrations_PositionDropdown_OnClick + if currentPos == p.value then + info.checked = 1 + end + UIDropDownMenu_AddButton(info) + end end diff --git a/HealBot_Options_Integrations.xml b/HealBot_Options_Integrations.xml index bec1dde..47795a9 100644 --- a/HealBot_Options_Integrations.xml +++ b/HealBot_Options_Integrations.xml @@ -94,9 +94,81 @@ HealBot_Config.HealBot_Integrations_ShowHoTTimers = this:GetChecked() and 1 or 0; + HealBot_Options_Integrations_UpdateDropdownStates(); + if HealBot_Action_UnitButtons then + for u in pairs(HealBot_Action_UnitButtons) do + HealBot_View_DirtyUnits[u] = true; + end + end + if HealBot_Action_UpdatePlayerHoTs then + HealBot_Action_UpdatePlayerHoTs(); + end + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(120, this); + UIDropDownMenu_Initialize(this, HealBot_Options_Integrations_DisplayModeDropdown_Init); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(120, this); + UIDropDownMenu_Initialize(this, HealBot_Options_Integrations_PositionDropdown_Init); + + + + @@ -114,9 +186,9 @@ - + - + diff --git a/HealBot_View_Layout.lua b/HealBot_View_Layout.lua index e5bf629..8e06ccc 100644 --- a/HealBot_View_Layout.lua +++ b/HealBot_View_Layout.lua @@ -283,6 +283,10 @@ function HealBot_Action_EnableButton(button) end local iconSize = HealBot_Config.biconsize[HealBot_Config.Current_Skin] or 12 + local isPet = string.find(unit, "pet") ~= nil + local overlayMode = (HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1) and ((HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0) == 1) and not isPet + local unitGUID = overlayMode and ((HealBot_GetUnitGUID and HealBot_GetUnitGUID(unit)) or (unit == "player" and HealBot_PlayerGUID)) + local currentTime = overlayMode and GetTime() for i = 1, 10 do local icon = button["icon"..i] if not icon then @@ -305,10 +309,54 @@ function HealBot_Action_EnableButton(button) if not icon:IsVisible() then icon:Show() end + + -- Icon overlay timer text + local iconText = button["iconText"..i] + if not iconText then + iconText = button:CreateFontString(nil, "OVERLAY") + iconText:SetFont("Fonts\\ARIALN.TTF", 10, "OUTLINE") + iconText:SetPoint("CENTER", icon, "CENTER", 0, 0) + iconText:SetTextColor(1, 1, 1, 1) + button["iconText"..i] = iconText + end + if overlayMode and unitGUID and HealBot_Nampower_Auras and HealBot_Nampower_Auras[unitGUID] then + local texturePath = HealBot_UnitIcons[unit][i] + local auraInfo = HealBot_TrackedAura_Textures and HealBot_TrackedAura_Textures[texturePath] + if auraInfo and auraInfo.showTimer then + local expiration = (auraInfo.locName and HealBot_Nampower_Auras[unitGUID][auraInfo.locName]) + or (auraInfo.spell and HealBot_Nampower_Auras[unitGUID][auraInfo.spell]) + if not expiration and HealBot_TrackedAura_Spells then + for spellName, spInfo in pairs(HealBot_TrackedAura_Spells) do + if spInfo.texture == texturePath and spInfo.showTimer then + expiration = HealBot_Nampower_Auras[unitGUID][spellName] + if expiration then break end + end + end + end + if expiration and expiration > currentTime then + local timeLeft = math.floor(expiration - currentTime) + iconText:SetText(timeLeft) + iconText:Show() + else + iconText:SetText("") + iconText:Hide() + end + else + iconText:SetText("") + iconText:Hide() + end + else + iconText:SetText("") + iconText:Hide() + end else if icon:IsVisible() then icon:Hide() end + local iconText = button["iconText"..i] + if iconText and iconText:IsVisible() then + iconText:Hide() + end end end end @@ -1380,22 +1428,65 @@ local function HealBot_PlayerHoTs_SortComparator(a, b) return (a.expires or 0) < (b.expires or 0) end +-- Reposition the HoT timer list frame based on config +local function HealBot_HoTTimerList_Reanchor() + if not HealBot_PlayerHoTsListFrame then return end + local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW" + HealBot_PlayerHoTsListFrame:ClearAllPoints() + if pos == "ABOVE" then + HealBot_PlayerHoTsListFrame:SetPoint("BOTTOMLEFT", HealBot_Action, "TOPLEFT", 0, 2) + elseif pos == "RIGHT" then + HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "TOPRIGHT", 2, 0) + elseif pos == "LEFT" then + HealBot_PlayerHoTsListFrame:SetPoint("TOPRIGHT", HealBot_Action, "TOPLEFT", -2, 0) + else -- BELOW (default) + HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "BOTTOMLEFT", 0, -2) + end +end + +-- Reposition child HoT frames for stacking direction +local function HealBot_HoTTimerList_StackChild(frame, index) + local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW" + frame:ClearAllPoints() + if pos == "ABOVE" then + if index == 1 then + frame:SetPoint("BOTTOMLEFT", HealBot_PlayerHoTsListFrame, "BOTTOMLEFT", 0, 0) + else + frame:SetPoint("BOTTOMLEFT", HealBot_PlayerHoTFrames[index-1], "TOPLEFT", 0, 2) + end + else + if index == 1 then + frame:SetPoint("TOPLEFT", HealBot_PlayerHoTsListFrame, "TOPLEFT", 0, 0) + else + frame:SetPoint("TOPLEFT", HealBot_PlayerHoTFrames[index-1], "BOTTOMLEFT", 0, -2) + end + end +end + function HealBot_Action_UpdatePlayerHoTs() if not HealBot_PlayerHoTsListFrame then HealBot_PlayerHoTsListFrame = CreateFrame("Frame", "HealBot_PlayerHoTsListFrame", HealBot_Action) HealBot_PlayerHoTsListFrame:SetWidth(128) HealBot_PlayerHoTsListFrame:SetHeight(1) - HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "BOTTOMLEFT", 0, -2) HealBot_PlayerHoTsListFrame:Show() end - + + HealBot_HoTTimerList_Reanchor() + if HealBot_Config.HealBot_Integrations_ShowHoTTimers ~= 1 then HealBot_PlayerHoTsListFrame:Hide() return - else - HealBot_PlayerHoTsListFrame:Show() end + -- If display mode is Icon Overlay, hide the list and return + local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0 + if displayMode == 1 then + HealBot_PlayerHoTsListFrame:Hide() + return + end + + HealBot_PlayerHoTsListFrame:Show() + local currentTime = GetTime() -- Clear cache instead of reallocating @@ -1403,17 +1494,20 @@ function HealBot_Action_UpdatePlayerHoTs() if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then for targetName, auras in pairs(HealBot_Nampower_Auras) do - for spellName, expiration in pairs(auras) do - local auraInfo = HealBot_TrackedAura_Spells and HealBot_TrackedAura_Spells[spellName] - if auraInfo and auraInfo.showTimer then - if expiration > currentTime then - numHoTs = numHoTs + 1 - if not HealBot_PlayerHoTs_ListCache[numHoTs] then - HealBot_PlayerHoTs_ListCache[numHoTs] = {} + local unitID = HealBot_Model:GetUnitByGUID(targetName) or HealBot_Model:GetUnitIDByName(targetName) + if not (unitID and string.find(unitID, "pet")) then + for spellName, expiration in pairs(auras) do + local auraInfo = HealBot_TrackedAura_Spells and HealBot_TrackedAura_Spells[spellName] + if auraInfo and auraInfo.showTimer then + if expiration > currentTime then + numHoTs = numHoTs + 1 + if not HealBot_PlayerHoTs_ListCache[numHoTs] then + HealBot_PlayerHoTs_ListCache[numHoTs] = {} + end + HealBot_PlayerHoTs_ListCache[numHoTs].name = targetName + HealBot_PlayerHoTs_ListCache[numHoTs].spell = spellName + HealBot_PlayerHoTs_ListCache[numHoTs].expires = expiration end - HealBot_PlayerHoTs_ListCache[numHoTs].name = targetName - HealBot_PlayerHoTs_ListCache[numHoTs].spell = spellName - HealBot_PlayerHoTs_ListCache[numHoTs].expires = expiration end end end @@ -1435,11 +1529,6 @@ function HealBot_Action_UpdatePlayerHoTs() frame = CreateFrame("Frame", "HealBot_PlayerHoT" .. i, HealBot_PlayerHoTsListFrame) frame:SetWidth(128) frame:SetHeight(16) - if i == 1 then - frame:SetPoint("TOPLEFT", HealBot_PlayerHoTsListFrame, "TOPLEFT", 0, 0) - else - frame:SetPoint("TOPLEFT", HealBot_PlayerHoTFrames[i-1], "BOTTOMLEFT", 0, -2) - end local icon = frame:CreateTexture(nil, "ARTWORK") icon:SetWidth(14) @@ -1454,6 +1543,9 @@ function HealBot_Action_UpdatePlayerHoTs() HealBot_PlayerHoTFrames[i] = frame end + + -- Reposition child for stacking direction + HealBot_HoTTimerList_StackChild(frame, i) local hot = HealBot_PlayerHoTs_ListCache[i] local timeLeft = math.floor(hot.expires - currentTime) diff --git a/README.md b/README.md index 53fa0d1..4578ab4 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\ ### Change Log **v1.7.6** +* **Feature - HoT Timer Position & Icon Overlay Display Modes** - Added configurable HoT Timer list position dropdown (`Below`, `Above`, `Left`, `Right`) relative to raid frames. Added alternative `Icon Overlay` display mode rendering countdown numbers directly on unit bar HoT icons. Excluded pets from timer lists and overlay numbers. Optimized expiration lookup with O(1) cached texture-to-spell mappings. * **Refactor & Feature - Unified Aura & HoT Tracking** - Unified bar icons and HoT timers into a single master dictionary (`HealBot_TrackedAuras`) in `HealBot_Data.lua`. Added Weakened Soul, Fear Ward, Abolish Disease, and Abolish Poison to active timer bars with localized client support and debuff-aware pruning. **v1.7.5**