Add transform session management to EditorStore and ViewportTransientState

This commit is contained in:
2026-04-03 02:10:45 +02:00
parent e6d9704b49
commit 92e4c2eeaf
2 changed files with 95 additions and 4 deletions

View File

@@ -1,7 +1,14 @@
import { CommandHistory } from "../commands/command-history"; import { CommandHistory } from "../commands/command-history";
import type { CommandContext, EditorCommand } from "../commands/command"; import type { CommandContext, EditorCommand } from "../commands/command";
import type { EditorSelection } from "../core/selection"; import { areEditorSelectionsEqual, type EditorSelection } from "../core/selection";
import type { ToolMode } from "../core/tool-mode"; import type { ToolMode } from "../core/tool-mode";
import {
areTransformSessionsEqual,
cloneTransformSession,
createInactiveTransformSession,
type TransformAxis,
type TransformSessionState
} from "../core/transform-session";
import { createEmptySceneDocument, type SceneDocument } from "../document/scene-document"; import { createEmptySceneDocument, type SceneDocument } from "../document/scene-document";
import { import {
DEFAULT_SCENE_DRAFT_STORAGE_KEY, DEFAULT_SCENE_DRAFT_STORAGE_KEY,
@@ -129,7 +136,17 @@ export class EditorStore {
this.toolMode = toolMode; this.toolMode = toolMode;
if (!isViewportToolPreviewCompatible(toolMode, this.viewportTransientState.toolPreview)) { if (!isViewportToolPreviewCompatible(toolMode, this.viewportTransientState.toolPreview)) {
this.viewportTransientState = createDefaultViewportTransientState(); this.viewportTransientState = {
...this.viewportTransientState,
toolPreview: createDefaultViewportTransientState().toolPreview
};
}
if (toolMode !== "select" && this.viewportTransientState.transformSession.kind !== "none") {
this.viewportTransientState = {
...this.viewportTransientState,
transformSession: createInactiveTransformSession()
};
} }
this.emit(); this.emit();
@@ -235,7 +252,55 @@ export class EditorStore {
return; return;
} }
this.viewportTransientState = createDefaultViewportTransientState(); this.viewportTransientState = {
...this.viewportTransientState,
toolPreview: createDefaultViewportTransientState().toolPreview
};
this.emit();
}
setTransformSession(transformSession: TransformSessionState) {
const nextTransformSession = cloneTransformSession(transformSession);
if (areTransformSessionsEqual(this.viewportTransientState.transformSession, nextTransformSession)) {
return;
}
this.viewportTransientState = {
...this.viewportTransientState,
transformSession: nextTransformSession
};
this.emit();
}
clearTransformSession() {
if (this.viewportTransientState.transformSession.kind === "none") {
return;
}
this.viewportTransientState = {
...this.viewportTransientState,
transformSession: createInactiveTransformSession()
};
this.emit();
}
setTransformAxisConstraint(axisConstraint: TransformAxis | null) {
if (this.viewportTransientState.transformSession.kind !== "active") {
return;
}
if (this.viewportTransientState.transformSession.axisConstraint === axisConstraint) {
return;
}
this.viewportTransientState = {
...this.viewportTransientState,
transformSession: {
...cloneTransformSession(this.viewportTransientState.transformSession),
axisConstraint
}
};
this.emit(); this.emit();
} }
@@ -268,6 +333,13 @@ export class EditorStore {
} }
setSelection(selection: EditorSelection) { setSelection(selection: EditorSelection) {
if (this.viewportTransientState.transformSession.kind === "active" && !areEditorSelectionsEqual(this.selection, selection)) {
this.viewportTransientState = {
...this.viewportTransientState,
transformSession: createInactiveTransformSession()
};
}
this.selection = selection; this.selection = selection;
this.emit(); this.emit();
} }

View File

@@ -1,5 +1,11 @@
import type { Vec3 } from "../core/vector"; import type { Vec3 } from "../core/vector";
import type { ToolMode } from "../core/tool-mode"; import type { ToolMode } from "../core/tool-mode";
import {
areTransformSessionsEqual,
cloneTransformSession,
createInactiveTransformSession,
type TransformSessionState
} from "../core/transform-session";
import type { EntityKind } from "../entities/entity-instances"; import type { EntityKind } from "../entities/entity-instances";
import type { ViewportPanelId } from "./viewport-layout"; import type { ViewportPanelId } from "./viewport-layout";
@@ -28,13 +34,15 @@ export type ViewportToolPreview = CreationViewportToolPreview | { kind: "none" }
export interface ViewportTransientState { export interface ViewportTransientState {
toolPreview: ViewportToolPreview; toolPreview: ViewportToolPreview;
transformSession: TransformSessionState;
} }
export function createDefaultViewportTransientState(): ViewportTransientState { export function createDefaultViewportTransientState(): ViewportTransientState {
return { return {
toolPreview: { toolPreview: {
kind: "none" kind: "none"
} },
transformSession: createInactiveTransformSession()
}; };
} }
@@ -110,3 +118,14 @@ export function isViewportToolPreviewCompatible(toolMode: ToolMode, toolPreview:
return toolMode === "create" && toolPreview.kind === "create"; return toolMode === "create" && toolPreview.kind === "create";
} }
export function cloneViewportTransientState(transientState: ViewportTransientState): ViewportTransientState {
return {
toolPreview: cloneViewportToolPreview(transientState.toolPreview),
transformSession: cloneTransformSession(transientState.transformSession)
};
}
export function areViewportTransientStatesEqual(left: ViewportTransientState, right: ViewportTransientState): boolean {
return areViewportToolPreviewsEqual(left.toolPreview, right.toolPreview) && areTransformSessionsEqual(left.transformSession, right.transformSession);
}