From ec84ea603ffe259eff9c02209a55dd4d5c940bb5 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 16:19:12 +0800 Subject: [PATCH 01/15] Use a shared StaticPopup_Show hook --- Modules/TransmogRestorePending.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index 6d5ac3f..c79e514 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -566,16 +566,16 @@ do API.UnregisterFrameForEvents(EL, TRACKED_EVENTS); end - local function OnStaticPopupShown(which, _, _, data) - if which ~= "TRANSMOG_PENDING_CHANGES" or not EL.enabled then return; end + local function OnStaticPopupShown(_, _, _, data) + if not EL.enabled then return; end local hasPending = C_TransmogOutfitInfo.HasPendingOutfitTransmogs() or C_TransmogOutfitInfo.HasPendingOutfitSituations(); if not hasPending then return; end - --Both appearance and situation pending changes now survive an outfit switch, so this warning is stale. - StaticPopup_Hide(which, data); if data and data.confirmCallback then data.confirmCallback(); end + + return true; end --Only treated as a real Undo while the frame is open, otherwise OnSituationsChanged fights back into a stack overflow (oops!). @@ -624,14 +624,15 @@ do EL:SetScript("OnEvent", OnTrackedEvent); TransmogFrame:HookScript("OnShow", TransmogFrame_OnShow); TransmogFrame:HookScript("OnHide", TransmogFrame_OnHide); - -- If we decide not to disable/skip the popup, comment/remove this hooksecurefunc below. - hooksecurefunc("StaticPopup_Show", OnStaticPopupShown); + hooksecurefunc(TransmogFrame, "SelectSlot", OnSlotSelected); HookExplicitClears(); if TransmogFrame:IsShown() then TransmogFrame_OnShow(); end + + addon.StaticPopupUtil:SetStaticPopupHandler("TRANSMOG_PENDING_CHANGES", OnStaticPopupShown); end end From 528890ea3277c594cf28efe20c9bc0f70de0f2e0 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 17:48:13 +0800 Subject: [PATCH 02/15] Alternative to fix two-handed weapon missing issue - Two-handed weapon doesn't show on the model because the off-hand item is equipped after the main-hand and overrides it. - Lua "pairs" order is intricate. So we capture the MH and OH items then equip them in the correct order. - Our old hack (triggering "SetupSlots" by toggling Separate Shoulders) worked, but it had performance issue due to item model refreshing. --- .luacheckrc | 7 +++ Modules/TransmogRestorePending.lua | 70 +++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 7305f9d..0cc9880 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -100,6 +100,7 @@ stds.wow = { "ClearAllPendingSituations", "ClearAllPendingTransmogs", "CommitAndApplyAllPending", + "GetItemModifiedAppearanceEffectiveCategory", }, }, @@ -1707,6 +1708,12 @@ stds.wow = { }, }, + ItemUtil = { + fields = { + "CreateItemTransmogInfo", + }, + }, + Menu = { fields = { "ModifyMenu", diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index c79e514..cab9047 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -220,14 +220,6 @@ do end end - function EL.ForceWeaponSlotWidgetRebuild() - --Toggling shoulder secondary state forces a weapon slot widget rebuild, working around a Blizzard display - --bug where the widget caches the wrong option (e.g. 1H for an equipped 2H) on first build. Must run first. - local liveSecondary = C_TransmogOutfitInfo.GetSecondarySlotState(SHOULDER_RIGHT); - C_TransmogOutfitInfo.SetSecondarySlotState(SHOULDER_RIGHT, not liveSecondary); - C_TransmogOutfitInfo.SetSecondarySlotState(SHOULDER_RIGHT, liveSecondary); - end - --Save all situations-related data (4 id fields) in one string, making it a simple per line row for SavedVariables. local function SituationOptionKey(option) return string.format("%d,%d,%d,%d", option.situationID, option.specID, option.loadoutID, option.equipmentSetID); @@ -425,8 +417,6 @@ do local function ApplyPendingSnapshot(snapshot, pendingSlots, shoulderSecondary, weaponOptions) if not snapshot then return; end - EL.ForceWeaponSlotWidgetRebuild(); - --Must run before ApplySnapshotToPending, toggling this after would wipe the left shoulder's pending value EL.RestoreShoulderSecondaryState(shoulderSecondary); EL.ApplySnapshotToPending(snapshot, pendingSlots or {}); @@ -617,6 +607,65 @@ do end; end + local function OnRefreshSlots() + local f = TransmogFrame.CharacterPreview; + + local mainOrOHSlotSelected = f.selectedSlotData and f.selectedSlotData.transmogLocation:IsEitherHand(); + local rangedSlotSelected = f.selectedSlotData and f.selectedSlotData.transmogLocation:IsRangedSlot(); + local previewRangedWeapon = C_PaperDollInfo.IsRangedSlotShown() and ((C_CVar.GetCVarBool("transmogPreviewedWeaponToggle") and not mainOrOHSlotSelected) or rangedSlotSelected); + + if previewRangedWeapon then return; end + + local actor = f.ModelScene:GetPlayerActor(); + if not actor then return; end + + local weaponSlotItemTransmogInfo = {}; + + for slotFrame in f.CharacterAppearanceSlotFramePool:EnumerateActive() do + local transmogLocation = slotFrame:GetTransmogLocation(); + if transmogLocation then + local slotID = transmogLocation:GetSlotID(); + if slotID == 16 or slotID == 17 then + local illusionSlotFrame = slotFrame:GetIllusionSlotFrame(); + local illusionID = Constants.Transmog.NoTransmogID; + if illusionSlotFrame then + local illusionSlotInfo = illusionSlotFrame:GetSlotInfo(); + if illusionSlotInfo and illusionSlotInfo.warning ~= Enum.TransmogOutfitSlotWarning.WeaponDoesNotSupportIllusions then + illusionID = illusionSlotInfo.transmogID; + end + end + + local secondaryAppearanceID = Constants.Transmog.NoTransmogID; + local appearanceID = slotFrame:GetEffectiveTransmogID(); + local itemTransmogInfo = ItemUtil.CreateItemTransmogInfo(appearanceID, secondaryAppearanceID, illusionID); + + local mainHandCategoryID; + local isLegionArtifact = false; + if transmogLocation:IsMainHand() then + mainHandCategoryID = C_TransmogOutfitInfo.GetItemModifiedAppearanceEffectiveCategory(appearanceID); + isLegionArtifact = TransmogUtil.IsCategoryLegionArtifact(mainHandCategoryID); + itemTransmogInfo:ConfigureSecondaryForMainHand(isLegionArtifact); + end + + if appearanceID == Constants.Transmog.NoTransmogID then + actor:UndressSlot(slotID); + else + local slotToSetID = slotID; + weaponSlotItemTransmogInfo[slotToSetID] = itemTransmogInfo; + end + end + end + end + + -- Weapons must be equipped in specific order + -- So main-hand can correctly override off-hand + for slotToSetID = 17, 16, -1 do + if weaponSlotItemTransmogInfo[slotToSetID] then + actor:SetItemTransmogInfo(weaponSlotItemTransmogInfo[slotToSetID], slotToSetID); + end + end + end + function EL.SnapshotFrame_OnLoad() if EL.snapshotHooked then return end; EL.snapshotHooked = true; @@ -626,6 +675,7 @@ do TransmogFrame:HookScript("OnHide", TransmogFrame_OnHide); hooksecurefunc(TransmogFrame, "SelectSlot", OnSlotSelected); + hooksecurefunc(TransmogFrame.CharacterPreview, "RefreshSlots", OnRefreshSlots); HookExplicitClears(); if TransmogFrame:IsShown() then From 63b59ffb3dda774fe3074497646971c94d929a6d Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 19:56:53 +0800 Subject: [PATCH 03/15] Wrap all "wipe save" into one function --- Modules/TransmogRestorePending.lua | 35 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index cab9047..7177e9d 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -331,6 +331,20 @@ do end EL.SavePendingToDB = SavePendingToDB; + function EL.WipePendingAppearanceFromDB(includeSituations, includeLastViewedOutfitID) + EL.PendingSnapshot = nil; + EL.PendingSlots = nil; + EL.PendingShoulderSecondary = nil; + EL.PendingWeaponOptions = nil; + if includeSituations then + EL.PendingSituations = nil; + end + if includeLastViewedOutfitID then + EL.LastViewedOutfitID = nil; + end + EL.SavePendingToDB(); + end + function EL.LoadPendingFromDB() EL.LastViewedOutfitID = PlumberDB_PC and PlumberDB_PC.TransmogRestoreLastOutfit; @@ -574,11 +588,7 @@ do local originalClearTransmogs = C_TransmogOutfitInfo.ClearAllPendingTransmogs; C_TransmogOutfitInfo.ClearAllPendingTransmogs = function(...) if TransmogFrame:IsShown() then - EL.PendingSnapshot = nil; - EL.PendingSlots = nil; - EL.PendingShoulderSecondary = nil; - EL.PendingWeaponOptions = nil; - EL.SavePendingToDB(); + EL.WipePendingAppearanceFromDB(); end return originalClearTransmogs(...); end; @@ -596,12 +606,7 @@ do local originalCommitAllPending = C_TransmogOutfitInfo.CommitAndApplyAllPending; C_TransmogOutfitInfo.CommitAndApplyAllPending = function(...) if TransmogFrame:IsShown() then - EL.PendingSnapshot = nil; - EL.PendingSlots = nil; - EL.PendingShoulderSecondary = nil; - EL.PendingWeaponOptions = nil; - EL.PendingSituations = nil; - EL.SavePendingToDB(); + EL.WipePendingAppearanceFromDB(true); end return originalCommitAllPending(...); end; @@ -696,13 +701,7 @@ do elseif (not state) and EL.enabled then EL.enabled = nil; addon.CallbackRegistry:UnregisterAddOnLoadedCallback("Blizzard_Transmog", EL.SnapshotFrame_OnLoad); - EL.PendingSnapshot = nil; - EL.PendingSlots = nil; - EL.PendingShoulderSecondary = nil; - EL.PendingWeaponOptions = nil; - EL.PendingSituations = nil; - EL.LastViewedOutfitID = nil; - EL.SavePendingToDB(); + EL.WipePendingAppearanceFromDB(true, true); end end From 43bc692e18fb34bc13c8a9c20ba37a3d4cf8f496 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 20:00:53 +0800 Subject: [PATCH 04/15] Show a popup when switching outfit with pending changes - The native popup only has a "confirm wiping pending changes" option. - We added an option to move the pending changes over to the new outfit. - There is a checkbox to dismiss the popup and always move changes over. - Disgusting. --- Initialization.lua | 2 +- Locales/enUS.lua | 7 +++++ Modules/Shared/SharedEditMode.lua | 3 +- Modules/Shared/SharedWidgets.lua | 10 +++++- Modules/Shared/SharedWidgets_StaticPopup.lua | 13 ++++++-- Modules/TransmogRestorePending.lua | 33 +++++++++++++++++--- 6 files changed, 58 insertions(+), 10 deletions(-) diff --git a/Initialization.lua b/Initialization.lua index 6d3ee60..96add87 100644 --- a/Initialization.lua +++ b/Initialization.lua @@ -247,7 +247,7 @@ local DefaultValues = { HuntTable = true, --Replace generic quest icons with difficulties and add achievement indicators. PreyQuestSuperTrack = true, --During the final stage, clicking the Prey widget also super track the target location. TransmogRaestorePending = true, --Restore unsaved transmog changes - + TransmogRaestorePending_AlwaysMoveChanges = false, --Tooltip TooltipChestKeys = true, --Show keys that unlocked the current chest or door diff --git a/Locales/enUS.lua b/Locales/enUS.lua index 3082e0c..ed71e35 100755 --- a/Locales/enUS.lua +++ b/Locales/enUS.lua @@ -808,6 +808,13 @@ L["Quick Access Outfit Button Tooltip"] = "Click and drag this button to your ac --TransmogRaestorePending L["ModuleName TransmogRaestorePending"] = "Transmog UI: Restore Pending Changes"; L["ModuleDescription TransmogRaestorePending"] = "Pending Transmog changes are automatically restored when reopening the window."; +L["Outfit Popup Warning"] = "The current outfit has pending changes.|n|nDo you wish to move these changes over to the new outfit or discard them?"; +L["Outfit Popup Move Changes"] = "Move"; +L["Outfit Popup Move Changes Tooltip"] = "Move the pending changes over to the newly selected outfit."; +L["Outfit Popup Always Move Changes Over"] = "Always Move Changes Over"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Always move the pending changes to the newly selected outfit.|n|nYou will stop seeing this popup window."; +L["Outfit Popup Discard Changes"] = "Discard"; +L["Outfit Popup Discard Changes Tooltip"] = "Discard the pending changes."; --QuestWatchCycle diff --git a/Modules/Shared/SharedEditMode.lua b/Modules/Shared/SharedEditMode.lua index 02109c2..5d50d82 100644 --- a/Modules/Shared/SharedEditMode.lua +++ b/Modules/Shared/SharedEditMode.lua @@ -299,9 +299,8 @@ do --EditModeSettingsDialog checkbox.useWhiteLabel = true; checkbox:SetData(widgetData); - checkbox:SetChecked(addon.GetDBValue(checkbox.dbKey)); - return checkbox + return checkbox; end function EditModeSettingsDialogMixin:CreateSlider(widgetData) diff --git a/Modules/Shared/SharedWidgets.lua b/Modules/Shared/SharedWidgets.lua index d1d29ee..72d459b 100644 --- a/Modules/Shared/SharedWidgets.lua +++ b/Modules/Shared/SharedWidgets.lua @@ -351,7 +351,7 @@ do -- Checkbox local newState; if self.dbKey then - newState = not addon.GetDBValue(self.dbKey) + newState = not addon.GetDBBool(self.dbKey) addon.SetDBValue(self.dbKey, newState, true); self:SetChecked(newState); else @@ -405,6 +405,12 @@ do -- Checkbox self.checked = state; end + function CheckboxMixin:UpdateChecked() + if self.dbKey then + self:SetChecked(addon.GetDBBool(self.dbKey)); + end + end + function CheckboxMixin:SetFixedWidth(width) self.fixedWidth = width; self:SetWidth(width); @@ -454,6 +460,8 @@ do -- Checkbox self.parentDBKey = data.parentDBKey; self.shouldEnableOption = data.shouldEnableOption; + self:UpdateChecked(); + if data.label then return self:SetLabel(data.label) else diff --git a/Modules/Shared/SharedWidgets_StaticPopup.lua b/Modules/Shared/SharedWidgets_StaticPopup.lua index d4c6779..b1c3a0b 100644 --- a/Modules/Shared/SharedWidgets_StaticPopup.lua +++ b/Modules/Shared/SharedWidgets_StaticPopup.lua @@ -176,7 +176,7 @@ do local button = self.uiPanelButtonPool:Acquire(); button:SetWidth(120); button:SetText(v.label); - button.onEnterFunc = v.onClickFunc; + button.onEnterFunc = v.onEnterFunc; button.onLeaveFunc = v.onLeaveFunc; button.onEnterCallback = function(f) @@ -202,7 +202,16 @@ do button.onLeaveCallback = v.onLeaveFunc; if v.onClickFunc then - button:SetScript("OnClick", v.onClickFunc); + button:SetScript("OnClick", function(f, mouseButton) + v.onClickFunc(f, mouseButton); + if v.closePopup then + self:Hide(); + end + end); + elseif v.closePopup then + button:SetScript("OnClick", function() + self:Hide(); + end); else button:SetScript("OnClick", nil); end diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index 7177e9d..1dc29e8 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -3,6 +3,7 @@ local L = addon.L; local API = addon.API; local EL = CreateFrame("Frame"); +local DBKEY_ALWAYS_MOVE_CHANGED = "TransmogRaestorePending_AlwaysMoveChanges"; local SHOULDER_RIGHT = Enum.TransmogOutfitSlot.ShoulderRight; local WEAPON_SLOTS = { [16] = Enum.TransmogOutfitSlot.WeaponMainHand, @@ -575,11 +576,34 @@ do local hasPending = C_TransmogOutfitInfo.HasPendingOutfitTransmogs() or C_TransmogOutfitInfo.HasPendingOutfitSituations(); if not hasPending then return; end - if data and data.confirmCallback then - data.confirmCallback(); - end + local confirmCallback = data and data.confirmCallback; + if confirmCallback then + if addon.GetDBBool(DBKEY_ALWAYS_MOVE_CHANGED) then + confirmCallback(); + else + addon.ShowCustomPopup({ + text = L["Outfit Popup Warning"], + buttons = { + {label = L["Outfit Popup Move Changes"], tooltip = L["Outfit Popup Move Changes Tooltip"], closePopup = true, onClickFunc = confirmCallback}, + {label = L["Outfit Popup Discard Changes"], tooltip = L["Outfit Popup Discard Changes Tooltip"], closePopup = true, + onClickFunc = function() + addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); + EL.WipePendingAppearanceFromDB(); + confirmCallback(); + end + }, + {label = CANCEL, closePopup = true}, + }, + widgets = { + {type = "checkbox", label = L["Outfit Popup Always Move Changes Over"], tooltip = L["Outfit Popup Always Move Changes Over Tooltip"], dbKey = DBKEY_ALWAYS_MOVE_CHANGED}, + }, + }); + end - return true; + return true; -- This hides the original popup + else + return; + end end --Only treated as a real Undo while the frame is open, otherwise OnSituationsChanged fights back into a stack overflow (oops!). @@ -702,6 +726,7 @@ do EL.enabled = nil; addon.CallbackRegistry:UnregisterAddOnLoadedCallback("Blizzard_Transmog", EL.SnapshotFrame_OnLoad); EL.WipePendingAppearanceFromDB(true, true); + addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); end end From c2d64ca24f03c3e629cb5b0ead8ce5a4734bc810 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 20:08:44 +0800 Subject: [PATCH 05/15] Update .luacheckrc --- .luacheckrc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.luacheckrc b/.luacheckrc index 0cc9880..0db71ab 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -580,6 +580,12 @@ stds.wow = { }, }, + Transmog = { + fields = { + "NoTransmogID", + }, + } + TransmogOutfitDataConsts = { fields = { "EQUIP_TRANSMOG_OUTFIT_MANUAL_SPELL_ID", @@ -980,6 +986,7 @@ stds.wow = { C_PaperDollInfo = { fields = { "CanCursorCanGoInSlot", + "IsRangedSlotShown", }, }, @@ -1613,6 +1620,12 @@ stds.wow = { }, }, + TransmogOutfitSlotWarning = { + fields = { + "WeaponDoesNotSupportIllusions", + }, + }, + TransmogPendingType = { fields = { "Apply", From e83c72100d6e29a4600fb50653106cb4ae4b367d Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Sun, 6 Sep 2026 20:10:35 +0800 Subject: [PATCH 06/15] Update .luacheckrc --- .luacheckrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.luacheckrc b/.luacheckrc index 0db71ab..aec5f7a 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -584,7 +584,7 @@ stds.wow = { fields = { "NoTransmogID", }, - } + }, TransmogOutfitDataConsts = { fields = { From f50a166cb763c93389bca1cff46abe2893df677d Mon Sep 17 00:00:00 2001 From: Raenore <172234435+Raenore@users.noreply.github.com> Date: Sun, 6 Sep 2026 17:08:32 +0200 Subject: [PATCH 07/15] Tab shortages, you're only allowed one sorry --- Initialization.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Initialization.lua b/Initialization.lua index 96add87..f6ffe42 100644 --- a/Initialization.lua +++ b/Initialization.lua @@ -247,7 +247,7 @@ local DefaultValues = { HuntTable = true, --Replace generic quest icons with difficulties and add achievement indicators. PreyQuestSuperTrack = true, --During the final stage, clicking the Prey widget also super track the target location. TransmogRaestorePending = true, --Restore unsaved transmog changes - TransmogRaestorePending_AlwaysMoveChanges = false, + TransmogRaestorePending_AlwaysMoveChanges = false, --Tooltip TooltipChestKeys = true, --Show keys that unlocked the current chest or door From 95c6b1324287234b409b8e2a552326a0e1e15cf3 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 06:25:40 +0800 Subject: [PATCH 08/15] Fix Cancel not cancelling Always Move Changes Over Co-authored-by: Raenore <172234435+Raenore@users.noreply.github.com> --- Modules/TransmogRestorePending.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index 1dc29e8..b9ab737 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -592,7 +592,7 @@ do confirmCallback(); end }, - {label = CANCEL, closePopup = true}, + {label = CANCEL, closePopup = true, onClickFunc = function() addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); end}, }, widgets = { {type = "checkbox", label = L["Outfit Popup Always Move Changes Over"], tooltip = L["Outfit Popup Always Move Changes Over Tooltip"], dbKey = DBKEY_ALWAYS_MOVE_CHANGED}, From 2a6a541cf41ef9c7fb7a0efcddde950ea2c436a9 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 06:57:17 +0800 Subject: [PATCH 09/15] Close our popup when TransmogFrame becomes hidden - Good catch. Co-Authored-By: Raenore <172234435+Raenore@users.noreply.github.com> --- Modules/Shared/SharedWidgets_StaticPopup.lua | 12 ++++++++++++ Modules/TransmogRestorePending.lua | 3 +++ 2 files changed, 15 insertions(+) diff --git a/Modules/Shared/SharedWidgets_StaticPopup.lua b/Modules/Shared/SharedWidgets_StaticPopup.lua index b1c3a0b..ec54661 100644 --- a/Modules/Shared/SharedWidgets_StaticPopup.lua +++ b/Modules/Shared/SharedWidgets_StaticPopup.lua @@ -159,6 +159,7 @@ do end function StaticPopupMixin:Setup(popupInfo) + self.identifier = popupInfo.identifier; self:ReleaseAllWidgets(); if popupInfo.text then @@ -381,6 +382,7 @@ local function ShowClipboard(text, copySuccessMessage) MainFrame:ClearAllPoints(); MainFrame:ReleaseAllWidgets(); + MainFrame.identifier = "clipboard"; MainFrame.EditBox:Show(); MainFrame.EditBox:SetDefaultText(text); @@ -424,3 +426,13 @@ local function ShowCustomPopup(popupInfo) StaticPopup_Show(WHICH_DUMMY, nil, nil, nil, MainFrame); end addon.ShowCustomPopup = ShowCustomPopup; + + +local function HideCustomPopup(identifier) + if MainFrame then + if (not identifier) or (MainFrame.identifier == identifier) then + StaticPopup_Hide(WHICH_DUMMY); + end + end +end +addon.HideCustomPopup = HideCustomPopup; diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index b9ab737..7bc993e 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -4,6 +4,7 @@ local API = addon.API; local EL = CreateFrame("Frame"); local DBKEY_ALWAYS_MOVE_CHANGED = "TransmogRaestorePending_AlwaysMoveChanges"; +local POPUP_IDENTIFIER = "transmogPendingChanges"; local SHOULDER_RIGHT = Enum.TransmogOutfitSlot.ShoulderRight; local WEAPON_SLOTS = { [16] = Enum.TransmogOutfitSlot.WeaponMainHand, @@ -569,6 +570,7 @@ do local function TransmogFrame_OnHide() API.UnregisterFrameForEvents(EL, TRACKED_EVENTS); + addon.HideCustomPopup(POPUP_IDENTIFIER); end local function OnStaticPopupShown(_, _, _, data) @@ -582,6 +584,7 @@ do confirmCallback(); else addon.ShowCustomPopup({ + identifier = POPUP_IDENTIFIER, text = L["Outfit Popup Warning"], buttons = { {label = L["Outfit Popup Move Changes"], tooltip = L["Outfit Popup Move Changes Tooltip"], closePopup = true, onClickFunc = confirmCallback}, From 05b04a77b50b289531f13d170635f257bea7f813 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:02:26 +0800 Subject: [PATCH 10/15] Tab is back on the menu boys - It helps indicate which key is the sub-option. Co-Authored-By: Raenore <172234435+Raenore@users.noreply.github.com> --- Initialization.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Initialization.lua b/Initialization.lua index f6ffe42..96add87 100644 --- a/Initialization.lua +++ b/Initialization.lua @@ -247,7 +247,7 @@ local DefaultValues = { HuntTable = true, --Replace generic quest icons with difficulties and add achievement indicators. PreyQuestSuperTrack = true, --During the final stage, clicking the Prey widget also super track the target location. TransmogRaestorePending = true, --Restore unsaved transmog changes - TransmogRaestorePending_AlwaysMoveChanges = false, + TransmogRaestorePending_AlwaysMoveChanges = false, --Tooltip TooltipChestKeys = true, --Show keys that unlocked the current chest or door From 724ddcdf7465222addb9f284d3fe581290d9a55c Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:04:19 +0800 Subject: [PATCH 11/15] Discard should also wipe pending situations Co-Authored-By: Raenore <172234435+Raenore@users.noreply.github.com> --- Modules/TransmogRestorePending.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index 7bc993e..1c0de0d 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -591,7 +591,7 @@ do {label = L["Outfit Popup Discard Changes"], tooltip = L["Outfit Popup Discard Changes Tooltip"], closePopup = true, onClickFunc = function() addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); - EL.WipePendingAppearanceFromDB(); + EL.WipePendingAppearanceFromDB(true); confirmCallback(); end }, From 7d871ce092759f83f993f7505af596b3d69b1eb5 Mon Sep 17 00:00:00 2001 From: Raenore <172234435+Raenore@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:45:14 +0200 Subject: [PATCH 12/15] Add base translation (can be improved certainly) --- Locales/deDE.lua | 12 ++++++++++++ Locales/enUS.lua | 6 +++--- Locales/esES.lua | 12 ++++++++++++ Locales/frFR.lua | 12 ++++++++++++ Locales/koKR.lua | 12 ++++++++++++ Locales/ptBR.lua | 9 ++++++++- Locales/ruRU.lua | 12 ++++++++++++ Locales/zhCN.lua | 9 ++++++++- Locales/zhTW.lua | 12 ++++++++++++ 9 files changed, 91 insertions(+), 5 deletions(-) diff --git a/Locales/deDE.lua b/Locales/deDE.lua index 746ab81..15f5f42 100644 --- a/Locales/deDE.lua +++ b/Locales/deDE.lua @@ -702,6 +702,18 @@ L["Missing Appearances Format"] = "%d |4Vorlage:Vorlagen fehlen;"; L["Press Key To Copy Format"] = "Zum Kopieren auf die |cffffd100%s|r-Taste drücken"; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "Transmog-UI: Ausstehende Änderungen wiederherstellen"; +L["ModuleDescription TransmogRaestorePending"] = "Ausstehende Transmog-Änderungen werden automatisch wiederhergestellt, wenn Ihr das Fenster erneut öffnet.\n\nAusstehende Änderungen können auf ein anderes Outfit übertragen werden."; +L["Outfit Popup Warning"] = "Das aktuelle Outfit hat ausstehende Änderungen.\n\nMöchtet Ihr diese Änderungen auf das neue Outfit übertragen oder verwerfen?"; +L["Outfit Popup Move Changes"] = "Übertragen"; +L["Outfit Popup Move Changes Tooltip"] = "Überträgt die ausstehenden Änderungen auf das neu ausgewählte Outfit."; +L["Outfit Popup Always Move Changes Over"] = "Änderungen immer übertragen"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Überträgt die ausstehenden Änderungen immer auf das neu ausgewählte Outfit.\n\nDieses Fenster wird nicht mehr angezeigt."; +L["Outfit Popup Discard Changes"] = "Verwerfen"; +L["Outfit Popup Discard Changes Tooltip"] = "Verwirft die ausstehenden Änderungen."; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "Tastenkürzel: Auf ein Quest focussieren"; L["ModuleDescription QuestWatchCycle"] = "Per Tastendruck kann man das vorherige oder nächste Quest im Questzielverfolgungs-Menü auswählen und verfolgen.\n\n|cffd4641cDas Tastenkürzel kann unter \'Optionen> Tastaturbelegung>Plumber Addon\' festgelegt werden.|r"; diff --git a/Locales/enUS.lua b/Locales/enUS.lua index ed71e35..df3bf04 100755 --- a/Locales/enUS.lua +++ b/Locales/enUS.lua @@ -807,12 +807,12 @@ L["Quick Access Outfit Button Tooltip"] = "Click and drag this button to your ac --TransmogRaestorePending L["ModuleName TransmogRaestorePending"] = "Transmog UI: Restore Pending Changes"; -L["ModuleDescription TransmogRaestorePending"] = "Pending Transmog changes are automatically restored when reopening the window."; -L["Outfit Popup Warning"] = "The current outfit has pending changes.|n|nDo you wish to move these changes over to the new outfit or discard them?"; +L["ModuleDescription TransmogRaestorePending"] = "Pending Transmog changes are automatically restored when reopening the window.\n\nPending changes can be moved over to another outfit."; +L["Outfit Popup Warning"] = "The current outfit has pending changes.\n\nDo you wish to move these changes over to the new outfit or discard them?"; L["Outfit Popup Move Changes"] = "Move"; L["Outfit Popup Move Changes Tooltip"] = "Move the pending changes over to the newly selected outfit."; L["Outfit Popup Always Move Changes Over"] = "Always Move Changes Over"; -L["Outfit Popup Always Move Changes Over Tooltip"] = "Always move the pending changes to the newly selected outfit.|n|nYou will stop seeing this popup window."; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Always move the pending changes to the newly selected outfit.\n\nYou will stop seeing this popup window."; L["Outfit Popup Discard Changes"] = "Discard"; L["Outfit Popup Discard Changes Tooltip"] = "Discard the pending changes."; diff --git a/Locales/esES.lua b/Locales/esES.lua index 23ec13e..f249315 100644 --- a/Locales/esES.lua +++ b/Locales/esES.lua @@ -762,6 +762,18 @@ L["Quick Access Outfit Button"] = "Acceso rápido"; L["Quick Access Outfit Button Tooltip"] = "Haz click y arrastra este botón a tus barras de acción para poder cambiar de atuendo en cualquier lugar."; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "Interfaz de transfiguración: restaurar cambios pendientes"; +L["ModuleDescription TransmogRaestorePending"] = "Los cambios de transfiguración pendientes se restauran automáticamente al volver a abrir la ventana.\n\nLos cambios pendientes se pueden trasladar a otro atuendo."; +L["Outfit Popup Warning"] = "El atuendo actual tiene cambios pendientes.\n\n¿Deseas trasladar estos cambios al nuevo atuendo o descartarlos?"; +L["Outfit Popup Move Changes"] = "Trasladar"; +L["Outfit Popup Move Changes Tooltip"] = "Traslada los cambios pendientes al atuendo recién seleccionado."; +L["Outfit Popup Always Move Changes Over"] = "Trasladar Siempre los Cambios"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Traslada siempre los cambios pendientes al atuendo recién seleccionado.\n\nDejarás de ver esta ventana emergente."; +L["Outfit Popup Discard Changes"] = "Descartar"; +L["Outfit Popup Discard Changes Tooltip"] = "Descarta los cambios pendientes."; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "Atajos de teclado: Centrarse en la misión"; L["ModuleDescription QuestWatchCycle"] = "Te permite presionar teclas de acceso rápido para centrarse en la siguiente/anterior misión en el rastreador de objetivos.\n\n|cffd4641cConfigura tus teclas de acceso rápido en Opciones/Atajos de teclado/Plumber.|r"; diff --git a/Locales/frFR.lua b/Locales/frFR.lua index 6fa6add..7e4e608 100644 --- a/Locales/frFR.lua +++ b/Locales/frFR.lua @@ -805,6 +805,18 @@ L["Quick Access Outfit Button"] = "Accès rapide"; L["Quick Access Outfit Button Tooltip"] = "Cliquez sur ce bouton et faites-le glisser vers vos barres d'action afin de pouvoir changer de tenue où que vous soyez."; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "Interface de transmogrification : restaurer les modifications en attente"; +L["ModuleDescription TransmogRaestorePending"] = "Les modifications de transmogrification en attente sont automatiquement restaurées lorsque vous rouvrez la fenêtre.\n\nLes modifications en attente peuvent être transférées vers une autre tenue."; +L["Outfit Popup Warning"] = "La tenue actuelle comporte des modifications en attente.\n\nSouhaitez-vous transférer ces modifications vers la nouvelle tenue ou les abandonner ?"; +L["Outfit Popup Move Changes"] = "Transférer"; +L["Outfit Popup Move Changes Tooltip"] = "Transfère les modifications en attente vers la tenue nouvellement sélectionnée."; +L["Outfit Popup Always Move Changes Over"] = "Toujours transférer les modifications"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Transfère toujours les modifications en attente vers la tenue nouvellement sélectionnée.\n\nCette fenêtre ne s'affichera plus."; +L["Outfit Popup Discard Changes"] = "Abandonner"; +L["Outfit Popup Discard Changes Tooltip"] = "Abandonne les modifications en attente."; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "Raccourcis clavier : focalisation sur la quête"; L["ModuleDescription QuestWatchCycle"] = "Permet d'utiliser des raccourcis clavier pour passer à la quête suivante/précédente dans le suivi des objectifs.\n\n|cffd4641cConfigurer vos raccourcis clavier dans Raccourcis clavier > Plumber.|r"; diff --git a/Locales/koKR.lua b/Locales/koKR.lua index d2a6251..b3831b5 100644 --- a/Locales/koKR.lua +++ b/Locales/koKR.lua @@ -805,6 +805,18 @@ L["Quick Access Outfit Button"] = "빠른 접근"; L["Quick Access Outfit Button Tooltip"] = "의상을 어디서나 변경할 수 있도록 이 버튼을 행동 단축바로 클릭하여 드래그하세요."; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "형상변환 UI: 대기 중인 변경 사항 복원"; +L["ModuleDescription TransmogRaestorePending"] = "형상변환 창을 다시 열면 대기 중인 변경 사항이 자동으로 복원됩니다.\n\n대기 중인 변경 사항을 다른 의상으로 옮길 수 있습니다."; +L["Outfit Popup Warning"] = "현재 의상에 대기 중인 변경 사항이 있습니다.\n\n이 변경 사항을 새 의상으로 옮기시겠습니까, 아니면 폐기하시겠습니까?"; +L["Outfit Popup Move Changes"] = "이동"; +L["Outfit Popup Move Changes Tooltip"] = "대기 중인 변경 사항을 새로 선택한 의상으로 옮깁니다."; +L["Outfit Popup Always Move Changes Over"] = "항상 변경 사항 이동"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "대기 중인 변경 사항을 항상 새로 선택한 의상으로 옮깁니다.\n\n이 창이 더 이상 표시되지 않습니다."; +L["Outfit Popup Discard Changes"] = "폐기"; +L["Outfit Popup Discard Changes Tooltip"] = "대기 중인 변경 사항을 폐기합니다."; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "단축키: 퀘스트 추적 대상 지정"; L["ModuleDescription QuestWatchCycle"] = "단축키를 눌러 목표 추적기에서 다음/이전 퀘스트를 대상으로 지정할 수 있습니다.\n\n|cffd4641c단축키 설정은 단축키 > Plumber 애드온에서 하세요.|r"; diff --git a/Locales/ptBR.lua b/Locales/ptBR.lua index aab0e30..70a4574 100644 --- a/Locales/ptBR.lua +++ b/Locales/ptBR.lua @@ -807,7 +807,14 @@ L["Quick Access Outfit Button Tooltip"] = "Clique e arraste este botão para sua --TransmogRaestorePending L["ModuleName TransmogRaestorePending"] = "Transmogrificação: Restaurar alterações"; -L["ModuleDescription TransmogRaestorePending"] = "As alterações de transmogrificação pendentes são automaticamente restauradas ao reabrir a janela."; +L["ModuleDescription TransmogRaestorePending"] = "As alterações de transmogrificação pendentes são automaticamente restauradas ao reabrir a janela.\n\nAs alterações pendentes podem ser movidas para outra roupa."; +L["Outfit Popup Warning"] = "A roupa atual possui alterações pendentes.\n\nDeseja mover essas alterações para a nova roupa ou descartá-las?"; +L["Outfit Popup Move Changes"] = "Mover"; +L["Outfit Popup Move Changes Tooltip"] = "Move as alterações pendentes para a roupa recém-selecionada."; +L["Outfit Popup Always Move Changes Over"] = "Sempre Mover as Alterações"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Sempre move as alterações pendentes para a roupa recém-selecionada.\n\nVocê não verá mais esta janela."; +L["Outfit Popup Discard Changes"] = "Descartar"; +L["Outfit Popup Discard Changes Tooltip"] = "Descarta as alterações pendentes."; --QuestWatchCycle diff --git a/Locales/ruRU.lua b/Locales/ruRU.lua index 437b6cc..4f52611 100644 --- a/Locales/ruRU.lua +++ b/Locales/ruRU.lua @@ -805,6 +805,18 @@ L["Quick Access Outfit Button"] = "Быстрый доступ"; L["Quick Access Outfit Button Tooltip"] = "Нажмите и перетащите эту кнопку на панель действий, чтобы менять образы в любом месте."; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "Интерфейс трансмогрификации: восстановление несохранённых изменений"; +L["ModuleDescription TransmogRaestorePending"] = "Несохранённые изменения трансмогрификации автоматически восстанавливаются при повторном открытии окна.\n\nНесохранённые изменения можно перенести на другой образ."; +L["Outfit Popup Warning"] = "В текущем образе есть несохранённые изменения.\n\nХотите перенести эти изменения на новый образ или отклонить их?"; +L["Outfit Popup Move Changes"] = "Перенести"; +L["Outfit Popup Move Changes Tooltip"] = "Переносит несохранённые изменения на новый выбранный образ."; +L["Outfit Popup Always Move Changes Over"] = "Всегда переносить изменения"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "Всегда переносит несохранённые изменения на новый выбранный образ.\n\nЭто окно больше не будет отображаться."; +L["Outfit Popup Discard Changes"] = "Отклонить"; +L["Outfit Popup Discard Changes Tooltip"] = "Отклоняет несохранённые изменения."; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "Клавиши: Фокус на задание"; L["ModuleDescription QuestWatchCycle"] = "Позволяет использовать горячие клавиши для фокусировки на следующем/предыдущем задании в трекере целей.\n\n|cffd4641cНастройте горячие клавиши в Привязки клавиш > Аддона Plumber.|r"; diff --git a/Locales/zhCN.lua b/Locales/zhCN.lua index 1b78b39..d55c0bb 100755 --- a/Locales/zhCN.lua +++ b/Locales/zhCN.lua @@ -775,7 +775,14 @@ L["Quick Access Outfit Button Tooltip"] = "点击并拖动此按钮到技能栏 --TransmogRaestorePending L["ModuleName TransmogRaestorePending"] = "幻化界面: 恢复未保存的改动"; -L["ModuleDescription TransmogRaestorePending"] = "未保存的改动将在你重新打开幻化界面时自动恢复。"; +L["ModuleDescription TransmogRaestorePending"] = "未保存的改动将在你重新打开幻化界面时自动恢复。\n\n未保存的改动可以转移至另一个外观方案。"; +L["Outfit Popup Warning"] = "当前外观方案有未保存的改动。\n\n你想将这些改动转移至新的外观方案,还是要舍弃它们?"; +L["Outfit Popup Move Changes"] = "转移"; +L["Outfit Popup Move Changes Tooltip"] = "将未保存的改动转移至新选择的外观方案。"; +L["Outfit Popup Always Move Changes Over"] = "永远转移改动"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "永远将未保存的改动转移至新选择的外观方案。\n\n你将不会再看到这个弹出窗口。"; +L["Outfit Popup Discard Changes"] = "舍弃"; +L["Outfit Popup Discard Changes Tooltip"] = "舍弃未保存的改动。"; --QuestWatchCycle diff --git a/Locales/zhTW.lua b/Locales/zhTW.lua index aaf33bb..e5064b0 100755 --- a/Locales/zhTW.lua +++ b/Locales/zhTW.lua @@ -715,6 +715,18 @@ L["Quick Access Outfit Button"] = "快捷訪問"; L["Quick Access Outfit Button Tooltip"] = "點擊並拖動此按鈕到技能欄上,以便隨時隨地訪問外觀列表。"; +--TransmogRaestorePending +L["ModuleName TransmogRaestorePending"] = "塑形介面:恢復未保存的改動"; +L["ModuleDescription TransmogRaestorePending"] = "未保存的改動將在你重新開啟塑形介面時自動恢復。\n\n未保存的改動可以轉移至另一個外觀方案。"; +L["Outfit Popup Warning"] = "當前外觀方案有未保存的改動。\n\n你想將這些改動轉移至新的外觀方案,還是要捨棄它們?"; +L["Outfit Popup Move Changes"] = "轉移"; +L["Outfit Popup Move Changes Tooltip"] = "將未保存的改動轉移至新選擇的外觀方案。"; +L["Outfit Popup Always Move Changes Over"] = "永遠轉移改動"; +L["Outfit Popup Always Move Changes Over Tooltip"] = "永遠將未保存的改動轉移至新選擇的外觀方案。\n\n你將不會再看到這個彈出視窗。"; +L["Outfit Popup Discard Changes"] = "捨棄"; +L["Outfit Popup Discard Changes Tooltip"] = "捨棄未保存的改動。"; + + --QuestWatchCycle L["ModuleName QuestWatchCycle"] = "快捷鍵:任務焦點"; L["ModuleDescription QuestWatchCycle"] = "允許你設定快捷鍵來聚焦下一個或上一個任務。\n\n|cffd4641c請前往以下位置設定按鍵:遊戲設定> 快捷鍵> Plumber 插件.|r"; From 46d16b2e2fc2287bf8b3c30b1ab6ef01d006cab5 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:49:49 +0800 Subject: [PATCH 13/15] Only save AlwaysMoveChanges if the user click Move Co-Authored-By: Raenore <172234435+Raenore@users.noreply.github.com> --- Modules/Shared/SharedWidgets_StaticPopup.lua | 6 ++++++ Modules/TransmogRestorePending.lua | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Modules/Shared/SharedWidgets_StaticPopup.lua b/Modules/Shared/SharedWidgets_StaticPopup.lua index ec54661..a7031c8 100644 --- a/Modules/Shared/SharedWidgets_StaticPopup.lua +++ b/Modules/Shared/SharedWidgets_StaticPopup.lua @@ -74,6 +74,9 @@ do function StaticPopupMixin:OnHide() PlaySound(SOUNDKIT.IG_MAINMENU_CLOSE); StaticPopup_Hide(WHICH_DUMMY, self.data); + if self.onHideCallback then + self.onHideCallback(self); + end end function StaticPopupMixin:OnLoad() @@ -160,6 +163,8 @@ do function StaticPopupMixin:Setup(popupInfo) self.identifier = popupInfo.identifier; + self.onHideCallback = popupInfo.onHideFunc; + self:ReleaseAllWidgets(); if popupInfo.text then @@ -383,6 +388,7 @@ local function ShowClipboard(text, copySuccessMessage) MainFrame:ClearAllPoints(); MainFrame:ReleaseAllWidgets(); MainFrame.identifier = "clipboard"; + MainFrame.onHideCallback = nil; MainFrame.EditBox:Show(); MainFrame.EditBox:SetDefaultText(text); diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index 1c0de0d..d3483c3 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -583,23 +583,35 @@ do if addon.GetDBBool(DBKEY_ALWAYS_MOVE_CHANGED) then confirmCallback(); else + local checkboxTempDBKey = POPUP_IDENTIFIER.."_TEMP"; + addon.SetDBValue(checkboxTempDBKey, nil) + addon.ShowCustomPopup({ identifier = POPUP_IDENTIFIER, text = L["Outfit Popup Warning"], + buttons = { - {label = L["Outfit Popup Move Changes"], tooltip = L["Outfit Popup Move Changes Tooltip"], closePopup = true, onClickFunc = confirmCallback}, + {label = L["Outfit Popup Move Changes"], tooltip = L["Outfit Popup Move Changes Tooltip"], closePopup = true, onClickFunc = function() + addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, addon.GetDBBool(checkboxTempDBKey)); + confirmCallback(); + end + }, {label = L["Outfit Popup Discard Changes"], tooltip = L["Outfit Popup Discard Changes Tooltip"], closePopup = true, onClickFunc = function() - addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); EL.WipePendingAppearanceFromDB(true); confirmCallback(); end }, {label = CANCEL, closePopup = true, onClickFunc = function() addon.SetDBValue(DBKEY_ALWAYS_MOVE_CHANGED, false); end}, }, + widgets = { - {type = "checkbox", label = L["Outfit Popup Always Move Changes Over"], tooltip = L["Outfit Popup Always Move Changes Over Tooltip"], dbKey = DBKEY_ALWAYS_MOVE_CHANGED}, + {type = "checkbox", label = L["Outfit Popup Always Move Changes Over"], tooltip = L["Outfit Popup Always Move Changes Over Tooltip"], dbKey = checkboxTempDBKey}, }, + + onHideFunc = function() + addon.SetDBValue(checkboxTempDBKey, nil); + end, }); end From c8464ba13a0a1d3cbf67c5c3a69264a30b28dc38 Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:51:18 +0800 Subject: [PATCH 14/15] No popup if showing TransmogFrame away from transmog NPC --- Modules/TransmogRestorePending.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index d3483c3..bee5a6f 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -580,7 +580,7 @@ do local confirmCallback = data and data.confirmCallback; if confirmCallback then - if addon.GetDBBool(DBKEY_ALWAYS_MOVE_CHANGED) then + if addon.GetDBBool(DBKEY_ALWAYS_MOVE_CHANGED) or (not C_Transmog.IsAtTransmogNPC()) then confirmCallback(); else local checkboxTempDBKey = POPUP_IDENTIFIER.."_TEMP"; From d5d77d022dad38eab94949054a08f0204c0d77bf Mon Sep 17 00:00:00 2001 From: Peter Yu <49627468+Peterodox@users.noreply.github.com> Date: Mon, 7 Sep 2026 15:50:48 +0800 Subject: [PATCH 15/15] Fix a conflict with our own OutfitSelect module --- Modules/TransmogRestorePending.lua | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Modules/TransmogRestorePending.lua b/Modules/TransmogRestorePending.lua index bee5a6f..9df4a10 100644 --- a/Modules/TransmogRestorePending.lua +++ b/Modules/TransmogRestorePending.lua @@ -369,7 +369,7 @@ do local isRestoringPending = false; local function CapturePending() - if not EL.enabled or isRestoringPending then return end; + if not EL.enabled or isRestoringPending then return; end local liveList = TransmogFrame.CharacterPreview:GetItemTransmogInfoList(); --Kept even when nothing's pending, so the separate-shoulders fix has a value to fall back to. @@ -400,6 +400,19 @@ do SavePendingToDB(); end + -- Due to unknown reasons our frame could receive "VIEWED_TRANSMOG_OUTFIT_SLOT_REFRESH" before TransmogFrame does + -- And we will end up capturing the old items + -- Use this instead of always capture the current slots + function EL.TryCapturePending() + if not EL.capturePendingQueued then + EL.capturePendingQueued = true; + C_Timer.After(0, function() + EL.capturePendingQueued = nil; + CapturePending(); + end); + end + end + local function RestoreViewedOutfit(outfitID) if outfitID == nil then return; end if outfitID == C_TransmogOutfitInfo.GetCurrentlyViewedOutfitID() then return; end @@ -512,7 +525,7 @@ do local wipedSituations = isOutfitSwitch and EL.PendingSituations and not C_TransmogOutfitInfo.HasPendingOutfitSituations(); if not (wipedTransmogs or wipedSituations) then - CapturePending(); + EL.TryCapturePending(); else isRestoringPending = true; if wipedTransmogs then @@ -557,15 +570,19 @@ do elseif event == "VIEWED_TRANSMOG_OUTFIT_SECONDARY_SLOTS_CHANGED" then FixShoulderSecondaryToggle(); else - CapturePending(); + EL.TryCapturePending(); end end local function TransmogFrame_OnShow() if not EL.enabled then return end; - API.RegisterFrameForEvents(EL, TRACKED_EVENTS); - RestoreAllPending(); + -- You can open TransmogFrame anywhere, like Plumber's OutfitSelect + -- But we only restore and save changes when interacting with transmog NPC + if C_Transmog.IsAtTransmogNPC() then + API.RegisterFrameForEvents(EL, TRACKED_EVENTS); + RestoreAllPending(); + end end local function TransmogFrame_OnHide()