mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 17:58:55 +00:00
PageScene: route create/delete/lock/visible/paste through HistoryManager
Wires creation, deletion, lock, visibility, and paste through the new HistoryManager. Mutator-recorded — every external call site keeps the same signature it had before; recording happens inside the mutator or its dep callback, so callers don't grow new responsibilities. Recordings added: - actions/addObject, addCharacter, addShape: editor.history.recordCreate(obj) replaces the legacy add_creation_undostack call. - editor.deleteObject: snapshots the target before delegating to utils.deleteObject so undo can fully reconstruct it. - SelectionBridge.lockUnlockObject: takes a recordLockChange dep callback, records before/after locked state inline. No coupling back to HistoryManager from the bridge. - Outliner.handleToggleVisibility: records visible before/after at the call site (hideObject lives on SceneManager which has no history dep). - SceneManager.paste: now returns the new Object3D so keymap's paste handler can record it via editor.history.recordCreate. The legacy add_creation_undostack call inside paste is removed. keymap.ts: undo/redo target editor.history; deleteSelected routes through editor.deleteObject (so history records); paste captures the returned object and records. Transform recording (gizmo drag, panel inputs) and color stay on the old check_scene_for_updates diff path until follow-up commits. Old SceneManager undo machinery (undoStack, undo/redo methods, add_creation_undostack, the diff helpers) is still in place but only the diff path drives transforms now.
This commit is contained in:
1 parent
94430a8817
commit
6632dd34cf
8 files changed
+25
-9
No files matched your search
@@ -17,7 +17,7 @@ export async function addCharacter(
|
||||
|
||||
obj.userData.isCharacter = true;
|
||||
|
||||
await editor.sceneManager?.add_creation_undostack(obj);
|
||||
editor.history.recordCreate(obj);
|
||||
|
||||
usePageSceneStore.getState().addCharacter({
|
||||
id: obj.uuid,
|
||||
|
||||
@@ -15,7 +15,7 @@ export async function addObject(
|
||||
);
|
||||
if (!obj) return undefined;
|
||||
|
||||
await editor.sceneManager?.add_creation_undostack(obj);
|
||||
editor.history.recordCreate(obj);
|
||||
|
||||
usePageSceneStore.getState().addObject({
|
||||
id: obj.uuid,
|
||||
|
||||
@@ -16,7 +16,7 @@ export async function addShape(
|
||||
if (!obj) return undefined;
|
||||
obj.name = item.name ?? "shape";
|
||||
|
||||
await editor.sceneManager?.add_creation_undostack(obj);
|
||||
editor.history.recordCreate(obj);
|
||||
|
||||
usePageSceneStore.getState().addShape({
|
||||
id: obj.uuid,
|
||||
|
||||
@@ -53,8 +53,10 @@ const OutlinerRow = ({ item }: { item: OutlinerItem }) => {
|
||||
|
||||
const handleToggleVisibility = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
const before = item.visible;
|
||||
usePageSceneStore.getState().toggleOutlinerVisibility(item.id);
|
||||
editorEngine?.sceneManager?.hideObject(item.id);
|
||||
editorEngine?.history.recordSetVisible(item.id, before, !before);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -171,6 +171,8 @@ class Editor {
|
||||
const selected = this.sceneManager?.selected_objects?.[0];
|
||||
if (selected) this.gizmo.attach(selected);
|
||||
},
|
||||
recordLockChange: (uuid, before, after) =>
|
||||
this.history.recordSetLocked(uuid, before, after),
|
||||
});
|
||||
|
||||
this.activeScene = new Scene(
|
||||
@@ -732,6 +734,9 @@ class Editor {
|
||||
}
|
||||
|
||||
deleteObject(uuid: string) {
|
||||
// Snapshot for the undo stack before the object is gone.
|
||||
const obj = this.activeScene.scene.getObjectByProperty("uuid", uuid);
|
||||
if (obj) this.history.recordDelete(obj);
|
||||
this.mouse_controls?.clearFKVisuals();
|
||||
this.mouse_controls?.removeTransformControls(true);
|
||||
this.utils.deleteObject(uuid);
|
||||
|
||||
@@ -29,6 +29,9 @@ export type SelectionBridgeDeps = {
|
||||
isObjectLocked: (uuid: string) => boolean;
|
||||
removeTransformControls: () => void;
|
||||
attachGizmoToCurrentSelection: () => void;
|
||||
// Push a lock-toggle entry onto the undo stack. Optional so the bridge
|
||||
// can be constructed before HistoryManager (and to keep tests simple).
|
||||
recordLockChange?: (uuid: string, before: boolean, after: boolean) => void;
|
||||
};
|
||||
|
||||
export class SelectionBridge {
|
||||
@@ -46,6 +49,7 @@ export class SelectionBridge {
|
||||
// the gizmo (lock) or re-attach it to the current selection (unlock).
|
||||
// Returns the new locked state.
|
||||
lockUnlockObject(object_uuid: string): boolean {
|
||||
const before = this.engine.isObjectLocked(object_uuid);
|
||||
const locked = this.engine.toggleObjectLocked(object_uuid);
|
||||
if (locked) {
|
||||
this.engine.removeTransformControls();
|
||||
@@ -53,6 +57,7 @@ export class SelectionBridge {
|
||||
this.engine.attachGizmoToCurrentSelection();
|
||||
}
|
||||
this.updateSelectedUI();
|
||||
this.engine.recordLockChange?.(object_uuid, before, locked);
|
||||
return locked;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,10 @@ const setGizmoMode = (
|
||||
const deleteSelected = (editor: Editor) => {
|
||||
const mc = editor.mouse_controls;
|
||||
if (!mc?.selected) return;
|
||||
// Route through editor.deleteObject so HistoryManager records the
|
||||
// deletion. mc.deleteObject (the legacy direct path) bypasses history.
|
||||
mc.selected.forEach((sel) => {
|
||||
mc.deleteObject(sel.uuid);
|
||||
editor.deleteObject(sel.uuid);
|
||||
});
|
||||
mc.selected = [];
|
||||
mc.removeTransformControls();
|
||||
@@ -70,11 +72,11 @@ const openAssetModal = () => {
|
||||
};
|
||||
|
||||
const undo = async (editor: Editor) => {
|
||||
await editor.sceneManager?.undo();
|
||||
await editor.history.undo();
|
||||
};
|
||||
|
||||
const redo = async (editor: Editor) => {
|
||||
await editor.sceneManager?.redo();
|
||||
await editor.history.redo();
|
||||
};
|
||||
|
||||
const copy = async (editor: Editor) => {
|
||||
@@ -82,7 +84,8 @@ const copy = async (editor: Editor) => {
|
||||
};
|
||||
|
||||
const paste = async (editor: Editor) => {
|
||||
await editor.sceneManager?.paste();
|
||||
const obj = await editor.sceneManager?.paste();
|
||||
if (obj) editor.history.recordCreate(obj);
|
||||
};
|
||||
|
||||
export const buildKeymap = (): KeyBinding[] => [
|
||||
|
||||
@@ -306,7 +306,7 @@ export class SceneManager implements SceneManagerAPI {
|
||||
}
|
||||
}
|
||||
|
||||
public async paste() {
|
||||
public async paste(): Promise<THREE.Object3D | undefined> {
|
||||
if (this.copiedObject && this.copiedObject.name != "::CAM::") {
|
||||
const userdata = this.copiedObject.userData;
|
||||
const position = this.copiedObject.position.clone();
|
||||
@@ -353,8 +353,9 @@ export class SceneManager implements SceneManagerAPI {
|
||||
}
|
||||
|
||||
await this.copy();
|
||||
await this.add_creation_undostack(obj);
|
||||
return obj;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public onMouseMove(event: MouseEvent) {
|
||||
|
||||
Reference in new issue
Block a user