diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index 8628c85..c67dd88 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -19,12 +19,13 @@ namespace Glamourer.Designs; public class DesignManager { - private readonly CustomizationService _customizations; - private readonly ItemManager _items; - private readonly HumanModelList _humans; - private readonly SaveService _saveService; - private readonly DesignChanged _event; - private readonly List _designs = new(); + private readonly CustomizationService _customizations; + private readonly ItemManager _items; + private readonly HumanModelList _humans; + private readonly SaveService _saveService; + private readonly DesignChanged _event; + private readonly List _designs = new(); + private readonly Dictionary _undoStore = new(); public IReadOnlyList Designs => _designs; @@ -83,6 +84,10 @@ public class DesignManager _event.Invoke(DesignChanged.Type.ReloadedAll, null!); } + /// Whether an Undo for the given design is possible. + public bool CanUndo(Design? design) + => design != null && _undoStore.ContainsKey(design.Identifier); + /// Create a new temporary design without adding it to the manager. public DesignBase CreateTemporary() => new(_items); @@ -463,6 +468,7 @@ public class DesignManager /// Apply an entire design based on its appliance rules piece by piece. public void ApplyDesign(Design design, DesignBase other) { + _undoStore[design.Identifier] = design.DesignData; if (other.DoApplyWetness()) design.DesignData.SetIsWet(other.DesignData.IsWet()); if (other.DoApplyHatVisible()) @@ -503,6 +509,16 @@ public class DesignManager ChangeStain(design, EquipSlot.OffHand, other.DesignData.Stain(EquipSlot.OffHand)); } + public void UndoDesignChange(Design design) + { + if (!_undoStore.Remove(design.Identifier, out var otherData)) + return; + + var other = CreateTemporary(); + other.DesignData = otherData; + ApplyDesign(design, other); + } + private void MigrateOldDesigns() { if (!File.Exists(_saveService.FileNames.MigrationDesignFile)) diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs index 53f1ef5..013d35d 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs @@ -84,6 +84,16 @@ public class DesignPanel Disabled = _selector.Selected?.WriteProtected() ?? true, }; + private HeaderDrawer.Button UndoButton() + => new() + { + Description = "Undo the last change if you accidentally overwrote your design with a different one.", + Icon = FontAwesomeIcon.Undo, + OnClick = UndoOverwrite, + Visible = _selector.Selected != null, + Disabled = !_manager.CanUndo(_selector.Selected), + }; + private HeaderDrawer.Button ExportToClipboardButton() => new() { @@ -95,7 +105,7 @@ public class DesignPanel private void DrawHeader() => HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), - 2, SetFromClipboardButton(), ExportToClipboardButton(), LockButton(), + 3, SetFromClipboardButton(), UndoButton(), ExportToClipboardButton(), LockButton(), HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); private string SelectionName @@ -411,6 +421,18 @@ public class DesignPanel } } + private void UndoOverwrite() + { + try + { + _manager.UndoDesignChange(_selector.Selected!); + } + catch (Exception ex) + { + Glamourer.Messager.NotificationMessage(ex, $"Could not undo last changes to {_selector.Selected!.Name}.", NotificationType.Error, false); + } + } + private void ExportToClipboard() { try