From 4f3bd6a4450a10b1292bef2c9a817b98dea28fd7 Mon Sep 17 00:00:00 2001 From: Tellinq <59412384+Tellinq@users.noreply.github.com> Date: Thu, 12 Nov 2026 20:01:32 -0500 Subject: [PATCH] feat(hud): add Undo all to the HUD designer Jumps back to the layout from when the editor opened, and redo brings it back one step at a time. --- .../internal/ui/hud/HudSettingsReset.kt | 10 +++++++++ .../ui/hud/screens/HudDesignSession.kt | 10 +++++++++ .../ui/hud/screens/HudDesignStudio.kt | 10 +++++++-- .../internal/ui/hud/screens/HudHistory.kt | 18 ++++++++++++++++ .../ui/hud/screens/HudHistoryTest.java | 21 +++++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/HudSettingsReset.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/HudSettingsReset.kt index fa1c2ebf7..57aa7c4a6 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/HudSettingsReset.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/HudSettingsReset.kt @@ -341,6 +341,7 @@ fun HudCanvasResetMenu( undoEnabled: Boolean = false, onRedo: () -> Unit = {}, redoEnabled: Boolean = false, + onUndoAll: () -> Unit = {}, preview: Boolean = false, onMeasured: (IntSize) -> Unit = {}, ) { @@ -480,6 +481,10 @@ fun HudCanvasResetMenu( onRedo() onDismiss() } + HudMenuRow(icon = "undo", text = "Undo all", enabled = undoEnabled) { + onUndoAll() + onDismiss() + } HudMenuDivider() if (actionTargets.any(::hudHasPositionDefaults)) { HudMenuRow( @@ -543,6 +548,7 @@ fun HudCanvasPasteMenu( undoEnabled: Boolean = false, onRedo: () -> Unit = {}, redoEnabled: Boolean = false, + onUndoAll: () -> Unit = {}, onTour: (() -> Unit)? = null, ) { if (!expanded) return @@ -574,6 +580,10 @@ fun HudCanvasPasteMenu( onRedo() onDismiss() } + HudMenuRow(icon = "undo", text = "Undo all", enabled = undoEnabled) { + onUndoAll() + onDismiss() + } HudMenuDivider() HudMenuRow( icon = "clipboard", diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignSession.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignSession.kt index b7d567505..9ec72bede 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignSession.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignSession.kt @@ -31,6 +31,8 @@ internal sealed interface StudioCommand { data object Redo : StudioCommand + data object UndoAll : StudioCommand + data object Search : StudioCommand } @@ -175,6 +177,14 @@ object HudDesignSession { return true } + @JvmStatic + fun handleUndoAll(pressed: Boolean): Boolean { + if (!pressed) return false + if (!HudManager.isEditorOpen) return false + post(StudioCommand.UndoAll) + return true + } + @JvmStatic fun handleRedo(pressed: Boolean): Boolean { if (!pressed) return false diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignStudio.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignStudio.kt index 498527596..d21fc22c1 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignStudio.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudDesignStudio.kt @@ -1368,9 +1368,13 @@ fun HudDesignStudio(visible: Boolean = true) { } } - StudioCommand.Undo, StudioCommand.Redo -> { + StudioCommand.Undo, StudioCommand.Redo, StudioCommand.UndoAll -> { if (!isDragging && !isResizing && pendingPress == null) { - val revived = if (command == StudioCommand.Undo) history.undo() else history.redo() + val revived = when (command) { + StudioCommand.Undo -> history.undo() + StudioCommand.UndoAll -> history.undoAll() + else -> history.redo() + } if (revived != null) { Snapshot.withMutableSnapshot { val live = HudManager.activeInstances @@ -2621,6 +2625,7 @@ fun HudDesignStudio(visible: Boolean = true) { undoEnabled = canUndo, onRedo = { HudDesignSession.handleRedo(true) }, redoEnabled = canRedo, + onUndoAll = { HudDesignSession.handleUndoAll(true) }, ) HudCanvasPasteMenu( @@ -2647,6 +2652,7 @@ fun HudDesignStudio(visible: Boolean = true) { undoEnabled = canUndo, onRedo = { HudDesignSession.handleRedo(true) }, redoEnabled = canRedo, + onUndoAll = { HudDesignSession.handleUndoAll(true) }, onTour = { startTour() }, ) diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistory.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistory.kt index 87e6399c6..6b3cf412c 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistory.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistory.kt @@ -231,6 +231,24 @@ internal class HudHistory { fun redo(): List? = step(redoStack, undoStack) + /** Goes back to how the layout was when this history started, one [redo] per step to bring it back */ + fun undoAll(): List? { + val now = capture() + val last = recorded + if (last == null || last.owner !== now.owner) { + reset(now) + return null + } + if (!sameLayout(last, now)) record(now) + if (undoStack.isEmpty()) return null + recorded?.let(redoStack::addLast) + while (undoStack.size > 1) redoStack.addLast(undoStack.removeLast()) + val revived = restore(undoStack.removeLast()) + recorded = capture() + settling = null + return revived + } + private fun step(from: ArrayDeque, to: ArrayDeque): List? { val now = capture() val last = recorded diff --git a/modules/internal/src/test/java/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistoryTest.java b/modules/internal/src/test/java/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistoryTest.java index b1b35f097..b2be9743b 100644 --- a/modules/internal/src/test/java/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistoryTest.java +++ b/modules/internal/src/test/java/org/polyfrost/oneconfig/internal/ui/hud/screens/HudHistoryTest.java @@ -179,6 +179,27 @@ void addedHudIsRemovedOnUndoAndComesBackOnRedo() { assertNotNull(HudManager.INSTANCE.instanceById(id)); } + @Test + void undoAllCanBeRedoneOneStepAtATime() { + Hud hud = place(); + history.poll(false); + + hud.setAbsolutePosition(100f, 60f); + settle(); + hud.setAbsolutePosition(200f, 120f); + settle(); + + assertNotNull(history.undoAll()); + assertEquals(10f, hud.getX(), 0.01f); + assertNull(history.undo()); + + assertNotNull(history.redo()); + assertEquals(100f, hud.getX(), 0.01f); + assertNotNull(history.redo()); + assertEquals(200f, hud.getX(), 0.01f); + assertNull(history.redo()); + } + private void settle() { history.poll(false); history.poll(false);