Add support for whitebox selection mode and hover labels in ViewportCanvas and ViewportPanel
This commit is contained in:
@@ -4,7 +4,9 @@ import type { LoadedModelAsset } from "../assets/gltf-model-import";
|
||||
import type { LoadedImageAsset } from "../assets/image-assets";
|
||||
import type { ProjectAssetRecord } from "../assets/project-assets";
|
||||
import type { EditorSelection } from "../core/selection";
|
||||
import { getWhiteboxSelectionFeedbackLabel } from "../core/whitebox-selection-feedback";
|
||||
import type { ToolMode } from "../core/tool-mode";
|
||||
import { getWhiteboxSelectionModeLabel, type WhiteboxSelectionMode } from "../core/whitebox-selection-mode";
|
||||
import type { Vec3 } from "../core/vector";
|
||||
import type { ActiveTransformSession, TransformSessionState } from "../core/transform-session";
|
||||
import type { SceneDocument } from "../document/scene-document";
|
||||
@@ -32,6 +34,7 @@ interface ViewportCanvasProps {
|
||||
projectAssets: Record<string, ProjectAssetRecord>;
|
||||
loadedModelAssets: Record<string, LoadedModelAsset>;
|
||||
loadedImageAssets: Record<string, LoadedImageAsset>;
|
||||
whiteboxSelectionMode: WhiteboxSelectionMode;
|
||||
whiteboxSnapEnabled: boolean;
|
||||
whiteboxSnapStep: number;
|
||||
selection: EditorSelection;
|
||||
@@ -61,6 +64,7 @@ export function ViewportCanvas({
|
||||
projectAssets,
|
||||
loadedModelAssets,
|
||||
loadedImageAssets,
|
||||
whiteboxSelectionMode,
|
||||
whiteboxSnapEnabled,
|
||||
whiteboxSnapStep,
|
||||
selection,
|
||||
@@ -85,6 +89,7 @@ export function ViewportCanvas({
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const hostRef = useRef<ViewportHost | null>(null);
|
||||
const [viewportMessage, setViewportMessage] = useState<string | null>(null);
|
||||
const [hoveredWhiteboxLabel, setHoveredWhiteboxLabel] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
@@ -138,6 +143,10 @@ export function ViewportCanvas({
|
||||
hostRef.current?.setWhiteboxSnapSettings(whiteboxSnapEnabled, whiteboxSnapStep);
|
||||
}, [whiteboxSnapEnabled, whiteboxSnapStep]);
|
||||
|
||||
useEffect(() => {
|
||||
hostRef.current?.setWhiteboxSelectionMode(whiteboxSelectionMode);
|
||||
}, [whiteboxSelectionMode]);
|
||||
|
||||
useEffect(() => {
|
||||
hostRef.current?.updateDocument(sceneDocument, selection);
|
||||
}, [sceneDocument, selection]);
|
||||
@@ -158,6 +167,10 @@ export function ViewportCanvas({
|
||||
hostRef.current?.setBrushSelectionChangeHandler(onSelectionChange);
|
||||
}, [onSelectionChange]);
|
||||
|
||||
useEffect(() => {
|
||||
hostRef.current?.setWhiteboxHoverLabelChangeHandler(setHoveredWhiteboxLabel);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
hostRef.current?.setCameraStateChangeHandler(onCameraStateChange);
|
||||
}, [onCameraStateChange]);
|
||||
@@ -213,8 +226,10 @@ export function ViewportCanvas({
|
||||
|
||||
const previewVisible = toolMode === "create" && toolPreview.kind === "create" && toolPreview.center !== null;
|
||||
const transformPreviewVisible = transformSession.kind === "active";
|
||||
const selectionModeVisible = toolMode === "select";
|
||||
const selectedWhiteboxLabel = selectionModeVisible ? getWhiteboxSelectionFeedbackLabel(sceneDocument, selection) : null;
|
||||
const showViewModeOverlay = layoutMode === "quad";
|
||||
const showOverlay = showViewModeOverlay || previewVisible || transformPreviewVisible;
|
||||
const showOverlay = showViewModeOverlay || selectionModeVisible || previewVisible || transformPreviewVisible || selectedWhiteboxLabel !== null || hoveredWhiteboxLabel !== null;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -237,6 +252,24 @@ export function ViewportCanvas({
|
||||
{!showViewModeOverlay ? null : (
|
||||
<div className="viewport-canvas__overlay-badges">
|
||||
<div className="viewport-canvas__overlay-badge viewport-canvas__overlay-badge--view">{getViewportViewModeLabel(viewMode)}</div>
|
||||
{!selectionModeVisible ? null : (
|
||||
<div
|
||||
className="viewport-canvas__overlay-badge viewport-canvas__overlay-badge--selection"
|
||||
data-testid={`viewport-selection-mode-${panelId}`}
|
||||
>
|
||||
{getWhiteboxSelectionModeLabel(whiteboxSelectionMode)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{showViewModeOverlay || !selectionModeVisible ? null : (
|
||||
<div className="viewport-canvas__overlay-badges">
|
||||
<div
|
||||
className="viewport-canvas__overlay-badge viewport-canvas__overlay-badge--selection"
|
||||
data-testid={`viewport-selection-mode-${panelId}`}
|
||||
>
|
||||
{getWhiteboxSelectionModeLabel(whiteboxSelectionMode)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!previewVisible ? null : (
|
||||
@@ -251,6 +284,16 @@ export function ViewportCanvas({
|
||||
: `${transformSession.operation}${transformSession.axisConstraint === null ? "" : ` · ${transformSession.axisConstraint.toUpperCase()}`}`}
|
||||
</div>
|
||||
)}
|
||||
{selectedWhiteboxLabel === null ? null : (
|
||||
<div className="viewport-canvas__overlay-preview" data-testid={`viewport-selected-whitebox-${panelId}`}>
|
||||
Selected: {selectedWhiteboxLabel}
|
||||
</div>
|
||||
)}
|
||||
{hoveredWhiteboxLabel === null ? null : (
|
||||
<div className="viewport-canvas__overlay-preview" data-testid={`viewport-hovered-whitebox-${panelId}`}>
|
||||
Hover: {hoveredWhiteboxLabel}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { LoadedModelAsset } from "../assets/gltf-model-import";
|
||||
import type { LoadedImageAsset } from "../assets/image-assets";
|
||||
import type { ProjectAssetRecord } from "../assets/project-assets";
|
||||
import type { EditorSelection } from "../core/selection";
|
||||
import type { WhiteboxSelectionMode } from "../core/whitebox-selection-mode";
|
||||
import type { ActiveTransformSession, TransformSessionState } from "../core/transform-session";
|
||||
import type { ToolMode } from "../core/tool-mode";
|
||||
import type { SceneDocument } from "../document/scene-document";
|
||||
@@ -33,6 +34,7 @@ interface ViewportPanelProps {
|
||||
projectAssets: Record<string, ProjectAssetRecord>;
|
||||
loadedModelAssets: Record<string, LoadedModelAsset>;
|
||||
loadedImageAssets: Record<string, LoadedImageAsset>;
|
||||
whiteboxSelectionMode: WhiteboxSelectionMode;
|
||||
whiteboxSnapEnabled: boolean;
|
||||
whiteboxSnapStep: number;
|
||||
selection: EditorSelection;
|
||||
@@ -66,6 +68,7 @@ export function ViewportPanel({
|
||||
projectAssets,
|
||||
loadedModelAssets,
|
||||
loadedImageAssets,
|
||||
whiteboxSelectionMode,
|
||||
whiteboxSnapEnabled,
|
||||
whiteboxSnapStep,
|
||||
selection,
|
||||
@@ -102,6 +105,18 @@ export function ViewportPanel({
|
||||
onFocusCapture={() => onActivatePanel(panelId)}
|
||||
>
|
||||
<div className="viewport-panel__header">
|
||||
{layoutMode !== "quad" ? null : (
|
||||
<div className="viewport-panel__meta">
|
||||
<div className="viewport-panel__title-row">
|
||||
<div className="viewport-panel__title">{getViewportPanelLabel(panelId)}</div>
|
||||
{!isActive ? null : (
|
||||
<div className="viewport-panel__active-badge" data-testid={`viewport-panel-active-badge-${panelId}`}>
|
||||
Active
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="viewport-panel__controls">
|
||||
<div className="viewport-panel__control-group" role="group" aria-label={`${getViewportPanelLabel(panelId)} view mode`}>
|
||||
{VIEWPORT_VIEW_MODES.map((viewMode) => (
|
||||
@@ -142,6 +157,7 @@ export function ViewportPanel({
|
||||
projectAssets={projectAssets}
|
||||
loadedModelAssets={loadedModelAssets}
|
||||
loadedImageAssets={loadedImageAssets}
|
||||
whiteboxSelectionMode={whiteboxSelectionMode}
|
||||
whiteboxSnapEnabled={whiteboxSnapEnabled}
|
||||
whiteboxSnapStep={whiteboxSnapStep}
|
||||
selection={selection}
|
||||
|
||||
Reference in New Issue
Block a user