108 lines
3.6 KiB
TypeScript
108 lines
3.6 KiB
TypeScript
import * as THREE from "three";
|
|
import { InlineBlock } from "@/core/libs/three-mesh-ui/src/three-mesh-ui.js";
|
|
import App from "@/core/app/App";
|
|
import { findUIPanelRoot } from "@/utils/scene/uipanel";
|
|
import {
|
|
UIPanelElementController,
|
|
UIPanelElementInit,
|
|
UIPanelNode,
|
|
extractUIPanelProps,
|
|
normalizeUIPanelElementOptions,
|
|
} from "./UIPanelElementBase";
|
|
|
|
const InlineBlockBase = InlineBlock as unknown as new (options?: Record<string, any>) => THREE.Object3D;
|
|
|
|
export default class UIPanelInlineBlock extends InlineBlockBase {
|
|
type = "UIPanelInlineBlock";
|
|
isUIPanelElement = true;
|
|
options: UIPanelNode;
|
|
declare set: (options: Record<string, any>) => void;
|
|
private controller: UIPanelElementController;
|
|
private handleAdded = () => {
|
|
const parent = this.parent as any;
|
|
if (!parent || !this.isValidParent(parent)) {
|
|
parent?.remove?.(this);
|
|
return;
|
|
}
|
|
const panel = findUIPanelRoot(this) as any;
|
|
if (!panel) return;
|
|
this.controller.updateRootId(panel.uuid);
|
|
panel.registerElement?.(this);
|
|
panel.requestUpdate?.();
|
|
};
|
|
private handleRemoved = () => {
|
|
const rootId = (this as any).metadata?.__uiPanelRootId;
|
|
const panel = rootId ? App.getObjectByUuid(rootId) : null;
|
|
panel?.unregisterElement?.(this);
|
|
};
|
|
|
|
constructor(options: Partial<UIPanelNode> = {}, init: UIPanelElementInit = {}) {
|
|
const normalized = normalizeUIPanelElementOptions(options, "inlineBlock", "InlineBlock");
|
|
const { props } = extractUIPanelProps(normalized);
|
|
super(props);
|
|
this.options = normalized;
|
|
this.name = normalized.name || "InlineBlock";
|
|
this.controller = new UIPanelElementController(this, this.options, this.type, init);
|
|
|
|
this.addEventListener("added", this.handleAdded);
|
|
this.addEventListener("removed", this.handleRemoved);
|
|
}
|
|
|
|
updateRootId(rootId: string) {
|
|
this.controller.updateRootId(rootId);
|
|
}
|
|
|
|
updateOptions(options: Partial<UIPanelNode>) {
|
|
if (options.name !== undefined) {
|
|
this.options.name = options.name;
|
|
this.name = options.name || this.name;
|
|
}
|
|
if (options.props) this.setProps(options.props);
|
|
if (options.states !== undefined) this.setStates(options.states);
|
|
}
|
|
|
|
setProps(patch: Record<string, any>) {
|
|
this.controller.setProps(patch);
|
|
}
|
|
|
|
setStates(states?: Record<string, Record<string, any>>) {
|
|
this.controller.setStates(states);
|
|
const rootId = (this as any).metadata?.__uiPanelRootId;
|
|
const panel = rootId ? App.getObjectByUuid(rootId) : null;
|
|
panel?.refreshInteraction?.();
|
|
}
|
|
|
|
applyState(state: string | null) {
|
|
this.controller.applyState(state);
|
|
}
|
|
|
|
hasInteractiveState() {
|
|
return this.controller.hasInteractiveState();
|
|
}
|
|
|
|
dispose() {
|
|
this.controller.dispose();
|
|
}
|
|
|
|
toJSON(meta?: THREE.JSONMeta) {
|
|
const snapshot = this.controller.detachInternalMeshes();
|
|
const data = super.toJSON(meta) as any;
|
|
this.controller.restoreInternalMeshes(snapshot);
|
|
|
|
data.object.type = this.type;
|
|
const options = JSON.parse(JSON.stringify(this.options)) as UIPanelNode;
|
|
options.name = this.name;
|
|
data.object.options = options;
|
|
|
|
return data;
|
|
}
|
|
|
|
static fromJSON(json: { options: UIPanelNode }, init: UIPanelElementInit = {}) {
|
|
return new UIPanelInlineBlock(json.options, init);
|
|
}
|
|
|
|
private isValidParent(parent: any) {
|
|
return parent?.type === "UIPanel" || parent?.type === "UIPanelBlock";
|
|
}
|
|
}
|