diff --git a/UI/MultiBotMainUI.lua b/UI/MultiBotMainUI.lua index d0b5ccd..b00a4a8 100644 --- a/UI/MultiBotMainUI.lua +++ b/UI/MultiBotMainUI.lua @@ -145,8 +145,21 @@ local function refreshLeftLayout() else leftRoot.buttons["ExpandFollow"]:Hide() leftRoot.buttons["ExpandStay"]:Hide() - leftRoot.buttons["Follow"]:Show() - leftRoot.buttons["Stay"]:Show() + + local followButton = leftRoot.buttons["Follow"] + local stayButton = leftRoot.buttons["Stay"] + local followShown = followButton and followButton:IsShown() + local stayShown = stayButton and stayButton:IsShown() + + -- Garder Follow/Stay mutuellement exclusifs en layout collapsed. + -- On préserve l'état courant; en cas d'état ambigu, on retombe sur Stay visible. + if followShown and not stayShown then + followButton:Show() + stayButton:Hide() + else + stayButton:Show() + followButton:Hide() + end end end) end @@ -362,6 +375,8 @@ local function isMouseOverFrameNode(node) return false end +local syncMainBarDetectorPosition + local function hideMainBarForAutoHide(state) if state.hidden then return @@ -372,6 +387,10 @@ local function hideMainBarForAutoHide(state) return end + if syncMainBarDetectorPosition then + syncMainBarDetectorPosition(state) + end + multiBar:Hide() state.hidden = true if state.detector then @@ -400,7 +419,7 @@ local function markMainBarInteraction(state) showMainBarFromAutoHide(state) end -local function syncMainBarDetectorPosition(state) +syncMainBarDetectorPosition = function(state) local detector = state and state.detector local multiBar = state and state.multiBar if not detector or not multiBar then @@ -503,6 +522,31 @@ function MultiBot.InitializeMainUI(tMultiBar) detector:Hide() autoHideState.detector = detector + -- Resync hotspot on every programmatic bar move (layout restore, RTSC restore, reset coords, etc.). + if autoHideState.multiBar + and type(autoHideState.multiBar.setPoint) == "function" + and not autoHideState.multiBar.__mbAutoHideSetPointHooked + then + local originalSetPoint = autoHideState.multiBar.setPoint + autoHideState.multiBar.setPoint = function(...) + originalSetPoint(...) + syncMainBarDetectorPosition(autoHideState) + markMainBarInteraction(autoHideState) + end + autoHideState.multiBar.__mbAutoHideSetPointHooked = true + end + + -- If hidden/shown by external paths, keep detector aligned. + if autoHideState.multiBar + and autoHideState.multiBar.HookScript + and not autoHideState.multiBar.__mbAutoHideOnHideHooked + then + autoHideState.multiBar:HookScript("OnHide", function() + syncMainBarDetectorPosition(autoHideState) + end) + autoHideState.multiBar.__mbAutoHideOnHideHooked = true + end + detector:SetScript("OnEnter", function() markMainBarInteraction(autoHideState) end) diff --git a/UI/MultiBotQuestsMenu.lua b/UI/MultiBotQuestsMenu.lua index d618d77..a601ae4 100644 --- a/UI/MultiBotQuestsMenu.lua +++ b/UI/MultiBotQuestsMenu.lua @@ -32,6 +32,19 @@ local function clearTableInPlace(tbl) end end +local function resetQuestResultFrame(frame, loadingText) + if type(frame) ~= "table" then + return + end + + if frame.scroll and frame.scroll.ReleaseChildren then + frame.scroll:ReleaseChildren() + end + if frame.summary and frame.summary.SetText then + frame.summary:SetText(loadingText or "") + end +end + local function getTargetBotOrError() local botName = UnitName("target") if botName and UnitIsPlayer("target") then @@ -118,6 +131,7 @@ local function sendIncomplete(method) MultiBot._lastIncWhisperBot = bot ensureRuntimeTable("_awaitingQuestsIncompleted")[bot] = true ensureRuntimeTable("BotQuestsIncompleted")[bot] = {} + resetQuestResultFrame(frame, MultiBot.L("tips.quests.incomplist") or "") MultiBot.ActionToTarget("quests incompleted", bot) frame:Show() MultiBot.TimerAfter(0.5, function() @@ -129,6 +143,7 @@ local function sendIncomplete(method) end clearTableInPlace(ensureRuntimeTable("BotQuestsIncompleted")) + resetQuestResultFrame(frame, MultiBot.L("tips.quests.incomplist") or "") MultiBot.ActionToGroup("quests incompleted") frame:Show() end @@ -151,6 +166,7 @@ local function sendCompleted(method) MultiBot._lastCompWhisperBot = bot ensureRuntimeTable("_awaitingQuestsCompleted")[bot] = true ensureRuntimeTable("BotQuestsCompleted")[bot] = {} + resetQuestResultFrame(frame, MultiBot.L("tips.quests.complist") or "") MultiBot.ActionToTarget("quests completed", bot) frame:Show() MultiBot.TimerAfter(0.5, function() @@ -162,6 +178,7 @@ local function sendCompleted(method) end clearTableInPlace(ensureRuntimeTable("BotQuestsCompleted")) + resetQuestResultFrame(frame, MultiBot.L("tips.quests.complist") or "") MultiBot.ActionToGroup("quests completed") frame:Show() end @@ -215,8 +232,8 @@ function MultiBot.InitializeQuestsMenu(tRight) MultiBot.InitializeQuestIncompleteFrame() MultiBot.InitializeQuestCompletedFrame() MultiBot.InitializeQuestAllFrame() - if MultiBot.InitializeGameObjectResultsFrame then MultiBot.InitializeGameObjectResultsFrame() end - if MultiBot.InitializeGameObjectCopyFrame then MultiBot.InitializeGameObjectCopyFrame() end + --if MultiBot.InitializeGameObjectResultsFrame then MultiBot.InitializeGameObjectResultsFrame() end + --if MultiBot.InitializeGameObjectCopyFrame then MultiBot.InitializeGameObjectCopyFrame() end local button = tRight.addButton("Quests Menu", 0, 0, "achievement_quests_completed_06", MultiBot.L("tips.quests.main")) local menu = tRight.addFrame("QuestMenu", -2, 64) diff --git a/UI/MultiBotRewardFrame.lua b/UI/MultiBotRewardFrame.lua index 598afa2..bda1a60 100644 --- a/UI/MultiBotRewardFrame.lua +++ b/UI/MultiBotRewardFrame.lua @@ -194,7 +194,7 @@ function MultiBot.InitializeRewardFrame() window:SetTitle(MultiBot.L("info.reward")) window:SetLayout("Manual") window:SetWidth(460) - window:SetHeight(430) + window:SetHeight(454) window.frame:SetClampedToScreen(true) window.frame:SetMovable(true) window.frame:EnableMouse(true) diff --git a/UI/MultiBotStats.lua b/UI/MultiBotStats.lua index 56a1386..535f0dd 100644 --- a/UI/MultiBotStats.lua +++ b/UI/MultiBotStats.lua @@ -1,3 +1,22 @@ +local function applySavedStatsPoint(frame) + if not frame then + return + end + + local savedPoint = MultiBot.GetSavedLayoutValue and MultiBot.GetSavedLayoutValue("StatsPoint") or nil + if type(savedPoint) ~= "string" or savedPoint == "" then + return + end + + local pointX, pointY = string.match(savedPoint, "^%s*(-?%d+)%s*,%s*(-?%d+)%s*$") + pointX = tonumber(pointX) + pointY = tonumber(pointY) + if pointX and pointY then + frame:ClearAllPoints() + frame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", pointX, pointY) + end +end + local function shortLabel(key, fallback) return MultiBot.L("info.shorts." .. key, fallback) end @@ -166,8 +185,10 @@ function MultiBot.InitializeStatsUI() end local statsFrame = MultiBot.newFrame(MultiBot, STATS_ROOT_X, STATS_ROOT_Y, STATS_ROOT_SIZE) + applySavedStatsPoint(statsFrame) statsFrame:SetMovable(true) statsFrame:Hide() + statsFrame.movButton("Move", STATS_MOVE_BUTTON_X, STATS_MOVE_BUTTON_Y, STATS_MOVE_BUTTON_WIDTH, MultiBot.L("tips.move.stats")) for _, slot in ipairs(STATS_PARTY_SLOTS) do diff --git a/UI/MultiBotTalentFrame.lua b/UI/MultiBotTalentFrame.lua index 873585b..69163ce 100644 --- a/UI/MultiBotTalentFrame.lua +++ b/UI/MultiBotTalentFrame.lua @@ -664,9 +664,16 @@ function MultiBot.InitializeTalentFrameModule() return (tonumber(MultiBot.talent.points) or 0) > 0 end + function MultiBot.talent.hasPendingTalentsApplyChange() + return MultiBot.talent.__talentsApplyPending == true + end + function MultiBot.talent.hasTalentsApplySelection() return MultiBot.talent.getActiveTabState() == MultiBot.TalentTabStates.TALENTS - and MultiBot.talent.hasUnspentTalentPoints() + and ( + MultiBot.talent.hasUnspentTalentPoints() + or MultiBot.talent.hasPendingTalentsApplyChange() + ) end function MultiBot.talent.isTalentEditingEnabledForCurrentTab() @@ -752,7 +759,24 @@ function MultiBot.InitializeTalentFrameModule() return end - local shouldShow = MultiBot.talent.canApplySelectionForState(MultiBot.talent.getActiveTabState()) + local activeState = MultiBot.talent.getActiveTabState() + if activeState == MultiBot.TalentTabStates.TALENTS then + if MultiBot.talent.__talentsTabApplyMode == nil then + MultiBot.talent.__talentsTabApplyMode = MultiBot.talent.hasUnspentTalentPoints() and "apply" or "copy" + end + + if MultiBot.talent.__talentsTabApplyMode == "apply" then + MultiBot.talent.setCopyTabMode(false, false) + MultiBot.talent.applyTabBtn.doShow() + MultiBot.talent.setBottomTabVisualState(MultiBot.TalentTabKeys.APPLY, true, MultiBot.TalentTabLabels.APPLY) + else + MultiBot.talent.setCopyTabMode(true, true) + MultiBot.talent.applyTabBtn.doHide() + end + return + end + + local shouldShow = MultiBot.talent.canApplySelectionForState(activeState) if shouldShow then MultiBot.talent.applyTabBtn.doShow() MultiBot.talent.setBottomTabVisualState(MultiBot.TalentTabKeys.APPLY, true, MultiBot.TalentTabLabels.APPLY) @@ -1617,6 +1641,9 @@ function MultiBot.InitializeTalentFrameModule() MultiBot.talent.updateTalentPoints(-1) MultiBot.talent.applyTalentRankDelta(pButton, tTab, 1) + if MultiBot.talent.getActiveTabState() == MultiBot.TalentTabStates.TALENTS then + MultiBot.talent.__talentsApplyPending = true + end MultiBot.talent.updateTalentValueFrame(pButton, tValue, false) MultiBot.talent.setTalentValueVisibility(tValue, true) @@ -1642,6 +1669,9 @@ function MultiBot.InitializeTalentFrameModule() MultiBot.talent.updateTalentPoints(1) MultiBot.talent.applyTalentRankDelta(pButton, tTab, -1) + if MultiBot.talent.getActiveTabState() == MultiBot.TalentTabStates.TALENTS then + MultiBot.talent.__talentsApplyPending = true + end MultiBot.talent.updateTalentValueFrame(pButton, tValue, true) local shouldShowValue = not (MultiBot.talent.points == 0 and pButton.value == 0) MultiBot.talent.setTalentValueVisibility(tValue, shouldShowValue) @@ -1892,8 +1922,9 @@ function MultiBot.InitializeTalentFrameModule() end, resolveTalent = MultiBot.talent.buildActiveTalentsResolver(activeGroup), onSuccess = function() + MultiBot.talent.__talentsTabApplyMode = MultiBot.talent.hasUnspentTalentPoints() and "apply" or "copy" MultiBot.talent.activateTalentsTabContext() - MultiBot.auto.talent = false + MultiBot.auto.talent = false end, }) end @@ -1916,6 +1947,8 @@ function MultiBot.InitializeTalentFrameModule() end MultiBot.talent.setTalents = function() + MultiBot.talent.__talentsTabApplyMode = nil + MultiBot.talent.__talentsApplyPending = false MultiBot.talent.renderTalentBuild(MultiBot.talent.getTalentsBuildOptions()) end @@ -2361,8 +2394,14 @@ function MultiBot.InitializeTalentFrameModule() end function MultiBot.talent.runApplyTabAction() - MultiBot.talent.applyActiveTabSelection() + local activeState = MultiBot.talent.getActiveTabState() + local applied = MultiBot.talent.applyActiveTabSelection() + if applied and activeState == MultiBot.TalentTabStates.TALENTS then + MultiBot.talent.__talentsApplyPending = false + end + MultiBot.talent.refreshApplyTabVisibility() + return applied end function MultiBot.talent.onCopyTabClick() diff --git a/UI/MultiBotUnitsRootUI.lua b/UI/MultiBotUnitsRootUI.lua index 7fe0326..30ff617 100644 --- a/UI/MultiBotUnitsRootUI.lua +++ b/UI/MultiBotUnitsRootUI.lua @@ -122,13 +122,15 @@ local function getDisplayableUnits(unitsFrame, sourceTable) return display end -local function layoutVisibleUnits(unitsButton, unitsFrame, display, fromIndex, toIndex) - local visibleCount = 0 - local startIndex = fromIndex or 1 - local endIndex = toIndex or 0 +local function hideTrackedVisibleUnits(unitsButton, unitsFrame) + local visibleNames = unitsButton and unitsButton._visibleNames + if type(visibleNames) ~= "table" then + unitsButton._visibleNames = {} + return + end - for index = 1, #display do - local name = display[index] + for index = 1, #visibleNames do + local name = visibleNames[index] local unitButton = name and unitsFrame.buttons[name] local unitFrame = name and unitsFrame.frames[name] if unitFrame then @@ -139,6 +141,16 @@ local function layoutVisibleUnits(unitsButton, unitsFrame, display, fromIndex, t end end + unitsButton._visibleNames = {} +end + +local function layoutVisibleUnits(unitsButton, unitsFrame, display, fromIndex, toIndex) + local visibleCount = 0 + local startIndex = fromIndex or 1 + local endIndex = toIndex or 0 + + local newVisible = {} + for index = startIndex, endIndex do local name = display[index] local unitButton = name and unitsFrame.buttons[name] @@ -153,12 +165,14 @@ local function layoutVisibleUnits(unitsButton, unitsFrame, display, fromIndex, t unitFrame:Show() end unitButton:Show() + table.insert(newVisible, name) end end unitsButton.from = startIndex unitsButton.to = endIndex unitsFrame.frames.Control.setPoint(-2, (unitsFrame.size + 2) * visibleCount) + unitsButton._visibleNames = newVisible end local function refreshUnitsDisplay(unitsButton, requestedRoster, requestedFilter) @@ -206,6 +220,7 @@ local function refreshUnitsDisplay(unitsButton, requestedRoster, requestedFilter unitsButton.to = UNITS_PAGE_SIZE local toIndex = math.min(unitsButton.limit, UNITS_PAGE_SIZE) + hideTrackedVisibleUnits(unitsButton, unitsFrame) layoutVisibleUnits(unitsButton, unitsFrame, display, 1, toIndex) if unitsButton.limit < UNITS_PAGE_SIZE + 1 then @@ -616,6 +631,7 @@ local function createBrowseButton(controlFrame) end local display = getDisplayableUnits(unitsFrame, sourceTable) + hideTrackedVisibleUnits(unitsButton, unitsFrame) layoutVisibleUnits(unitsButton, unitsFrame, display, fromIndex, math.min(toIndex, #display)) end end