mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 02:52:12 +00:00
PageScene: route lock undo through gizmo side effects
SelectionBridge.lockUnlockObject toggled userData.locked AND attached/detached the gizmo, but HistoryContext.setLocked only did the userData write. After Ctrl+Z the lock flag reverted but the gizmo state stayed wrong. Extract the side-effect chain (setObjectLocked + gizmo attach/detach + updateSelectedUI) into a private SelectionBridge.applyLockState helper. Both lockUnlockObject (toggle path) and the new setLockState (history-replay path) call it. Add a SceneUtils direct-set helper (setObjectLocked) so applyLockState can target a specific state instead of toggling. Wire HistoryContext.setLocked through selection.setLockState so undo of a lock toggle re-runs the gizmo attach/detach. The recordLockChange dep stays for now; it moves to the call site in a later commit when the action layer migrates to LockAction.
This commit is contained in:
1 parent
4a837d49a7
commit
d9680ae0a8
3 files changed
+36
-11
No files matched your search
@@ -163,6 +163,8 @@ class Editor {
|
||||
cameraName: this.cameraController.camera_name,
|
||||
version: this.version,
|
||||
toggleObjectLocked: (uuid) => this.utils.toggleObjectLocked(uuid),
|
||||
setObjectLocked: (uuid, locked) =>
|
||||
this.utils.setObjectLocked(uuid, locked),
|
||||
isObjectLocked: (uuid) => this.utils.isObjectLocked(uuid),
|
||||
removeTransformControls: () =>
|
||||
this.utils.removeTransformControls(false),
|
||||
@@ -256,9 +258,9 @@ class Editor {
|
||||
this.activeScene.setColor(uuid, color);
|
||||
},
|
||||
setLocked: (uuid, locked) => {
|
||||
const obj = this.activeScene.scene.getObjectByProperty("uuid", uuid);
|
||||
if (!obj) return;
|
||||
obj.userData.locked = locked;
|
||||
// Routes through SelectionBridge so the gizmo attach/detach
|
||||
// side effects fire (matches the original lock toggle path).
|
||||
this.selection.setLockState(uuid, locked);
|
||||
},
|
||||
setVisible: (uuid, visible) => {
|
||||
const obj = this.activeScene.scene.getObjectByProperty("uuid", uuid);
|
||||
|
||||
@@ -26,6 +26,7 @@ export type SelectionBridgeDeps = {
|
||||
// and the gizmo attach/detach lives on GizmoController. The bridge
|
||||
// calls them through these callbacks instead of importing either.
|
||||
toggleObjectLocked: (uuid: string) => boolean; // returns new locked state
|
||||
setObjectLocked: (uuid: string, locked: boolean) => void; // direct set (history replay)
|
||||
isObjectLocked: (uuid: string) => boolean;
|
||||
removeTransformControls: () => void;
|
||||
attachGizmoToCurrentSelection: () => void;
|
||||
@@ -45,20 +46,35 @@ export class SelectionBridge {
|
||||
|
||||
constructor(private readonly engine: SelectionBridgeDeps) {}
|
||||
|
||||
// Toggle the locked flag on an object's userData, then either yank
|
||||
// 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);
|
||||
// Centralized side-effect chain shared by the user-toggle path and
|
||||
// history replay. Sets userData.locked, attaches/detaches the gizmo,
|
||||
// refreshes the inspector. No recording — the user-facing entry
|
||||
// points decide whether to push to the undo stack.
|
||||
private applyLockState(object_uuid: string, locked: boolean) {
|
||||
this.engine.setObjectLocked(object_uuid, locked);
|
||||
if (locked) {
|
||||
this.engine.removeTransformControls();
|
||||
} else {
|
||||
this.engine.attachGizmoToCurrentSelection();
|
||||
}
|
||||
this.updateSelectedUI();
|
||||
this.engine.recordLockChange?.(object_uuid, before, locked);
|
||||
return locked;
|
||||
}
|
||||
|
||||
// Toggle the locked flag on an object's userData, then either yank
|
||||
// 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 after = !before;
|
||||
this.applyLockState(object_uuid, after);
|
||||
this.engine.recordLockChange?.(object_uuid, before, after);
|
||||
return after;
|
||||
}
|
||||
|
||||
// For history replay: set the locked state directly without recording.
|
||||
// Runs the same gizmo attach/detach side effects as lockUnlockObject.
|
||||
setLockState(object_uuid: string, locked: boolean) {
|
||||
this.applyLockState(object_uuid, locked);
|
||||
}
|
||||
|
||||
// True if the object is currently locked. Pure passthrough.
|
||||
|
||||
@@ -43,6 +43,13 @@ export class SceneUtils {
|
||||
return object.userData["locked"];
|
||||
}
|
||||
|
||||
// Direct setter used by history replay — sets userData.locked without
|
||||
// toggling. Side effects (gizmo attach/detach) live on SelectionBridge.
|
||||
setObjectLocked(object_uuid: string, locked: boolean) {
|
||||
const object = this.scene.get_object_by_uuid(object_uuid);
|
||||
if (object) object.userData["locked"] = locked;
|
||||
}
|
||||
|
||||
// Removes transform controls and publishes selected.
|
||||
removeTransformControls(remove_outline: boolean = true) {
|
||||
if (this.editor.gizmo.control == undefined) {
|
||||
|
||||
Reference in new issue
Block a user