Manage undo and redo operations in CE.SDK programmatically, subscribe to history changes, and use multiple independent history stacks for isolated editing contexts.
CE.SDK automatically tracks editing operations, enabling users to undo and redo changes. The engine creates undo steps for most operations automatically. You can also create multiple independent history stacks to isolate editing contexts — for example, separate histories for a main canvas and an overlay editor.
Setup#
We start by creating a scene and page. The engine automatically creates a history stack when it initializes.
let scene = try engine.scene.create()let page = try engine.block.create(.page)try engine.block.setWidth(page, value: 800)try engine.block.setHeight(page, value: 600)try engine.block.appendChild(to: scene, child: page)Subscribing to History Changes#
Use engine.editor.onHistoryUpdatedWithKind to receive notifications when the history state changes. Each emission is a HistoryUpdate value that describes the kind of change:
.updated— the active history’s snapshots changed because of an edit, anaddUndoStep()call, or anundo()/redo(). The scene reflects the new state..activated— a different history buffer was made active viasetActiveHistory(_:). The undo/redo stack visible to the user changed, but no new snapshot was created and no undo or redo was applied.
This separation matters for save-button or dirty-state logic: switching the active history (for example when toggling a preview mode) should not be treated as an unsaved change.
// Subscribe to history updates.let historyTask = Task { for await kind in engine.editor.onHistoryUpdatedWithKind { switch kind { case .activated: print("Active history switched, scene unchanged.") case .updated: let canUndo = try engine.editor.canUndo() let canRedo = try engine.editor.canRedo() print("History updated — canUndo: \(canUndo), canRedo: \(canRedo)") @unknown default: break } }}Cancel the Task when you no longer need notifications, such as when dismissing a view.
Automatic Undo Step Creation#
Most editing operations automatically create undo steps. Adding a block to the scene records this operation in the history stack.
let block = try engine.block.create(.graphic)try engine.block.setShape(block, shape: engine.block.createShape(.rect))try engine.block.setWidth(block, value: 100)try engine.block.setHeight(block, value: 100)try engine.block.setFill(block, fill: engine.block.createFill(.color))try engine.block.appendChild(to: page, child: block)After creating the block, canUndo() returns true.
Performing Undo and Redo#
Use engine.editor.undo() and engine.editor.redo() to revert or restore changes. Always check availability with canUndo() and canRedo() first.
if try engine.editor.canUndo() { try engine.editor.undo()}After undoing, canRedo() returns true. Call redo() to restore the change.
if try engine.editor.canRedo() { try engine.editor.redo()}Managing Undo Steps Manually#
Most operations are tracked automatically. For custom operations that the engine doesn’t track, use addUndoStep() to create a checkpoint manually.
try engine.block.setWidth(block, value: 200)try engine.editor.addUndoStep()Use removeUndoStep() to discard the most recent undo step without affecting the redo stack.
if try engine.editor.canUndo() { try engine.editor.removeUndoStep()}Working with Multiple History Stacks#
CE.SDK supports multiple independent history stacks. This is useful when different parts of your app need separate undo/redo histories. Only the active history responds to undo/redo operations.
let primaryHistory = engine.editor.getActiveHistory()let secondaryHistory = engine.editor.createHistory()engine.editor.setActiveHistory(secondaryHistory)
// Operations here only affect secondaryHistorytry engine.block.setWidth(block, value: 300)
engine.editor.setActiveHistory(primaryHistory)engine.editor.destroyHistory(secondaryHistory)- Create a stack with
createHistory()and activate it withsetActiveHistory() - Operations while a stack is active only affect that stack
- Always call
destroyHistory()when a stack is no longer needed to free resources
API Reference#
| Method | Purpose |
|---|---|
engine.editor.createHistory() | Create a new undo/redo history stack |
engine.editor.destroyHistory(_:) | Destroy a history stack and free resources |
engine.editor.setActiveHistory(_:) | Set a history stack as the active one |
engine.editor.getActiveHistory() | Get the currently active history stack |
engine.editor.addUndoStep() | Manually add a checkpoint to the undo stack |
engine.editor.removeUndoStep() | Remove the most recent undo step |
engine.editor.undo() | Revert to the previous history state |
engine.editor.redo() | Restore the next history state |
engine.editor.canUndo() | Check if an undo operation is available |
engine.editor.canRedo() | Check if a redo operation is available |
engine.editor.onHistoryUpdatedWithKind | Subscribe to history change notifications |
Next Steps#
- Events — subscribe to block creation, update, and deletion events
- Editor State — track selection and edit mode changes
- Scenes — create and manage design scenes