NodeEditor: undo/redo, keymap commands, grid snapping and comment boxes - #469
Merged
Merged
Conversation
…ment boxes Undo/redo (#467), built on ktsu.UndoRedo and ktsu.Keybinding: - NodeEditorHistory records each change as the difference it made: node create/delete/duplicate, links, drags, comment boxes and pin values. Undoing a deletion restores the node under its original id with its pins, values, links and factory binding. - Pin value edits from the inline editors and inspector are recorded automatically; writes within one widget gesture merge into one step. - NodeEditorInputHandler reports UndoRequested/RedoRequested and can take its chords from an IKeybindingService; NodeEditorCommands registers the commands and default chords. Layout tools (#468): - NodeEditorRenderer.SnapToGrid / GridSpacing use ImNodes' grid snapping; SnapNodesToGrid snaps nodes placed in code. - CommentBox: labelled regions drawn behind the nodes; drag the title to carry contained nodes, resize from the corner, double-click to rename, close with the cross. The renderer now forgets nodes it did not draw, so a restored node is repositioned in ImNodes instead of being read back as a drag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FF1fUCCNeDokGnSmbKnkTY
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FF1fUCCNeDokGnSmbKnkTY
…boxes Make the filters and mappings the analyzer flagged explicit, keep the two side-effecting loops as statements rather than lazy filters, and issue gesture tokens from a static method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FF1fUCCNeDokGnSmbKnkTY
|
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #467
Closes #468
Undo/redo (#467)
As the comment on #467 suggested, this uses
ktsu.UndoRedoandktsu.Keybindingdirectly.NodeEditorHistoryrecords onto anIUndoRedoService. You can let it make its own stack, or pass in the host's stack so graph steps sit alongside the host's own undo steps. Each step stores only what changed: the graph is captured before and after the change runs insideRecord(...). So undoing a delete puts back that node (same id, pins, values, seeded defaults and links) and leaves every node the layout moved since where it is.Record("...", () => ...).NodeInspectorPanelare recorded without the host doing anything. A newSetPinValue(int, object?, long? editGesture)overload plus a newPinValueChangedevent let all the writes from one widget gesture (one slider drag, one typing session) merge into a single step.renderer.History.AttributeBasedNodeFactory.RestoreBinding.engine.Clear()called outside a recording empties the history, because it restarts the id counters. Called insideRecordit is a normal undoable step, as the demo's Reset/Clear buttons show.NodeEditorInputHandlernow reportsUndoRequestedandRedoRequested. If you give it anIKeybindingService, it reads the delete, duplicate, undo and redo chords from the active profile every frame.NodeEditorCommands.Registerregisters those commands and their default chords, and it never overwrites a chord the user has already bound. Without a keymap the keys are Delete/Backspace, Ctrl+D, Ctrl+Z, and Ctrl+Y or Ctrl+Shift+Z.Grid snapping and comment boxes (#468)
renderer.SnapToGridandrenderer.GridSpacingturn on ImNodes' own grid snapping for each frame. Nodes land on the grid that's drawn on screen, and a multi-node selection keeps its shape.SnapNodesToGridsnaps nodes that were placed in code. Only drags snap, so a graph meant to stay on the grid needs physics off or its nodes pinned.CommentBoxis a labelled, optionally coloured region drawn in ImNodes' background channel: above the grid, below every node and link.Other changes
Testing
NodeEditorHistoryTests(17) andCommentBoxTests(6) run against the engine alone.NodeEditorGestureTests(15) run headless frames through the harness. They cover drag recording and undo, snapping, Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z, a rebound keymap, undo of a delete redrawing the node in place, and an inline-editor drag undoing in one step. For comment boxes they check placement, pixel-level draw order under nodes, no ImGui misuse errors, title drag, resize, close and rename.ImGuiAppDemo.UITestslocally: this checkout has no Git LFS, soicon.pngis a pointer file and every test fails in setup. CI will exercise it.🤖 Generated with Claude Code
https://claude.ai/code/session_01FF1fUCCNeDokGnSmbKnkTY