From 159e687c19a98c6dbe9f410d921bfd90c5d42434 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Fri, 12 Apr 2024 13:33:52 -0500 Subject: [PATCH] Simplified interactions, changed menu interactions for changing entities. --- src/controllers/base.ts | 12 ++++- src/diagram/diagramConnection.ts | 10 ++--- src/diagram/functions/diagramEventHandler.ts | 1 + src/information/inputTextView.ts | 45 ++++++++++++------- src/menus/clickMenu.ts | 47 +++++++++++++++++--- src/menus/editMenu.ts | 2 +- src/objects/handle.ts | 5 +++ src/toolbox/toolbox.ts | 34 +++++++------- 8 files changed, 111 insertions(+), 45 deletions(-) diff --git a/src/controllers/base.ts b/src/controllers/base.ts index c6adc2b..ebc512d 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -41,6 +41,7 @@ export class Base { private logger: log.Logger; private lastPosition: Vector3 = null; protected controllers: Controllers; + private clickMenu: ClickMenu; constructor(controller: WebXRInputSource, scene: Scene, @@ -262,9 +263,18 @@ export class Base { private click() { let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId); + if (pointable(mesh)) { this.logger.debug("click on " + mesh.id); - const menu = new ClickMenu(mesh, this.diagramManager); + if (this.clickMenu && !this.clickMenu.isDisposed) { + if (this.clickMenu.isConnecting) { + this.clickMenu.connect(mesh); + this.clickMenu = null; + } + } else { + this.clickMenu = new ClickMenu(mesh, this.diagramManager, this.controller.grip); + } + } else { this.logger.debug("click on nothing"); } diff --git a/src/diagram/diagramConnection.ts b/src/diagram/diagramConnection.ts index 98ececc..120b787 100644 --- a/src/diagram/diagramConnection.ts +++ b/src/diagram/diagramConnection.ts @@ -1,4 +1,4 @@ -import {AbstractMesh, MeshBuilder, PointerInfo, Scene, TransformNode, Vector3} from "@babylonjs/core"; +import {AbstractMesh, MeshBuilder, Scene, TransformNode, Vector3} from "@babylonjs/core"; import {v4 as uuidv4} from 'uuid'; import log, {Logger} from "loglevel"; import {buildStandardMaterial} from "../materials/functions/buildStandardMaterial"; @@ -8,7 +8,7 @@ export class DiagramConnection { private logger: Logger = log.getLogger('DiagramConnection'); private readonly id: string; - constructor(from: string, to: string, id: string, scene?: Scene, pointerInfo?: PointerInfo) { + constructor(from: string, to: string, id: string, scene?: Scene, gripTransform?: TransformNode) { this.logger.debug('buildConnection constructor'); if (id) { this.id = id; @@ -34,8 +34,8 @@ export class DiagramConnection { to.ignoreNonUniformScaling = true; to.id = this.id + "_to"; to.position = fromMesh.absolutePosition.clone(); - if (pointerInfo) { - to.setParent(pointerInfo.pickInfo.gripTransform); + if (gripTransform) { + to.setParent(gripTransform); } this.toAnchor = to; @@ -105,7 +105,7 @@ export class DiagramConnection { private buildConnection() { this.logger.debug(`buildConnection from ${this._from} to ${this._to}`); this._mesh = MeshBuilder.CreateCylinder(this.id + "_connection", {diameter: .02, height: 1}, this.scene); - this._mesh.material = buildStandardMaterial(this.id + "_material", this.scene, "#000000"); + this._mesh.material = buildStandardMaterial(this.id + "_material", this.scene, "#FFFFFF"); this.transformNode = new TransformNode(this.id + "_transform", this.scene); this.transformNode.metadata = {exportable: true}; this._mesh.setParent(this.transformNode); diff --git a/src/diagram/functions/diagramEventHandler.ts b/src/diagram/functions/diagramEventHandler.ts index 5d091d0..7efc3b9 100644 --- a/src/diagram/functions/diagramEventHandler.ts +++ b/src/diagram/functions/diagramEventHandler.ts @@ -66,6 +66,7 @@ export function diagramEventHandler(event: DiagramEvent, if (physicsEnabled) { applyPhysics(sounds, mesh, scene); } + updateTextNode(mesh, entity.text); break; case DiagramEventType.REMOVE: if (mesh) { diff --git a/src/information/inputTextView.ts b/src/information/inputTextView.ts index 3f5c3b8..aa43cd5 100644 --- a/src/information/inputTextView.ts +++ b/src/information/inputTextView.ts @@ -20,6 +20,7 @@ export class InputTextView { private readonly handle: Handle; private inputText: InputText; private diagramMesh: AbstractMesh; + private keyboard: VirtualKeyboard; constructor(scene: Scene, controllers: Controllers) { this.controllers = controllers; @@ -31,41 +32,49 @@ export class InputTextView { } public show(mesh: AbstractMesh) { - this.inputText.text = mesh.metadata?.label || ""; this.handle.mesh.setEnabled(true); + if (mesh.metadata?.label) { + this.inputText.text = mesh.metadata?.label; + } this.diagramMesh = mesh; + this.keyboard.isVisible = true; + this.inputText.focus(); console.log(mesh.metadata); } public createKeyboard() { const platform = this.scene.getMeshById('platform'); - let position = new Vector3(0, 1.66, .5); - let rotation = new Vector3(0, .9, 0); + const position = new Vector3(0, 1.66, .5); + const rotation = new Vector3(.9, 0, 0); const handle = this.handle; - if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { + /*if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { position = handle.mesh.position; } if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) { rotation = handle.mesh.rotation; - } + }*/ if (!platform) { this.scene.onNewMeshAddedObservable.add((mesh) => { if (mesh.id == 'platform') { this.logger.debug("platform added"); - handle.mesh.setParent(platform); - - handle.mesh.position = position; - handle.mesh.rotation = rotation; + handle.mesh.parent = mesh; + if (!handle.idStored) { + handle.mesh.position = position; + handle.mesh.rotation = rotation; + } } - }); + }, -1, false, this, false); } else { - handle.mesh.parent = platform; - handle.mesh.position = position; - handle.mesh.rotation = rotation; + handle.mesh.setParent(platform); + if (!handle.idStored) { + handle.mesh.position = position; + handle.mesh.rotation = rotation; + } } //setMenuPosition(handle.mesh, this.scene, new Vector3(0, .4, 0)); const advancedTexture = AdvancedDynamicTexture.CreateForMesh(this.inputMesh, 2048, 1024, false); + const input = new InputText(); input.width = 0.5; input.maxWidth = 0.5; @@ -110,11 +119,17 @@ export class InputTextView { }); keyboard.onKeyPressObservable.add((key) => { if (key === '↵') { - this.logger.error(this.inputText.text); - this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: this.inputText.text}); + if (this.inputText.text && this.inputText.text.length > 0) { + this.logger.error(this.inputText.text); + this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: this.inputText.text}); + } else { + this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: null}); + } + this.hide(); } }, -1, false, this, false); + this.keyboard = keyboard; this.handle.mesh.setEnabled(false); } diff --git a/src/menus/clickMenu.ts b/src/menus/clickMenu.ts index 9cd3ee4..581965c 100644 --- a/src/menus/clickMenu.ts +++ b/src/menus/clickMenu.ts @@ -3,6 +3,8 @@ import {AbstractMesh, TransformNode} from "@babylonjs/core"; import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity"; import {toDiagramEntity} from "../diagram/functions/toDiagramEntity"; import {DiagramManager} from "../diagram/diagramManager"; +import {DiagramConnection} from "../diagram/diagramConnection"; +import {isDiagramEntity} from "../diagram/functions/isDiagramEntity"; export class ClickMenu { private static readonly sounds; @@ -11,7 +13,10 @@ export class ClickMenu { private readonly transform: TransformNode; private readonly diagramManager: DiagramManager; - constructor(entity: AbstractMesh, diagramManager: DiagramManager) { + + private connection: DiagramConnection = null; + + constructor(entity: AbstractMesh, diagramManager: DiagramManager, grip: TransformNode) { this.entity = entity; this.diagramManager = diagramManager; const scene = entity.getScene(); @@ -29,17 +34,39 @@ export class ClickMenu { manager.controlScaling = .1; manager.addControl(panel); - panel.addControl(this.makeButton("Remove", "remove")); - panel.addControl(this.makeButton("Label", "label")); - panel.addControl(this.makeButton("Connect", "connect")); - panel.addControl(this.makeButton("Close", "close")); + panel.addControl(this.makeButton("Remove", "remove", grip)); + panel.addControl(this.makeButton("Label", "label", grip)); + panel.addControl(this.makeButton("Connect", "connect", grip)); + panel.addControl(this.makeButton("Close", "close", grip)); panel.linkToTransformNode(transform); this.transform = transform; this.manager = manager; } - private makeButton(name: string, id: string) { + public get isConnecting() { + return this.connection != null; + } + + public get isDisposed(): boolean { + return this.transform.isDisposed(); + } + + public connect(mesh: AbstractMesh) { + if (this.connection) { + if (mesh && isDiagramEntity(mesh)) { + this.connection.to = mesh.id; + this.diagramManager.onDiagramEventObservable.notifyObservers({ + type: DiagramEventType.ADD, + entity: toDiagramEntity(this.connection.mesh) + }, -1); + this.connection = null; + this.dispose(); + } + } + } + + private makeButton(name: string, id: string, grip: TransformNode) { const button = new Button3D(name); //button.scaling = new Vector3(.1, .1, .1); button.name = id; @@ -66,7 +93,8 @@ export class ClickMenu { this.diagramManager.editText(this.entity); this.dispose(); break; - + case "connect": + this.createMeshConnection(this.entity, grip); } @@ -74,8 +102,13 @@ export class ClickMenu { return button; } + private createMeshConnection(mesh: AbstractMesh, grip: TransformNode) { + this.connection = new DiagramConnection(mesh.id, null, null, this.transform.getScene(), grip); + } + private dispose() { this.manager.dispose(); this.transform.dispose(); + } } \ No newline at end of file diff --git a/src/menus/editMenu.ts b/src/menus/editMenu.ts index d9064bc..fdb4fbf 100644 --- a/src/menus/editMenu.ts +++ b/src/menus/editMenu.ts @@ -147,7 +147,7 @@ export class EditMenu extends AbstractMenu { }, -1); this.connection = null; } else { - this.connection = new DiagramConnection(mesh.id, null, null, this.scene, pointerInfo); + this.connection = new DiagramConnection(mesh.id, null, null, this.scene, pointerInfo.pickInfo.gripTransform); } } diff --git a/src/objects/handle.ts b/src/objects/handle.ts index 78cb8c9..429b882 100644 --- a/src/objects/handle.ts +++ b/src/objects/handle.ts @@ -4,12 +4,16 @@ import {buildStandardMaterial} from "../materials/functions/buildStandardMateria export class Handle { public mesh: AbstractMesh; private readonly transformNode: TransformNode; + private _isStored: boolean = false; constructor(mesh: TransformNode) { this.transformNode = mesh; this.buildHandle(); } + public get idStored() { + return this._isStored; + } private buildHandle() { const scene: Scene = this.transformNode.getScene(); const handle = getHandleMesh("handle-" + this.transformNode.id + "-mesh", scene); @@ -22,6 +26,7 @@ export class Handle { const locationdata = JSON.parse(stored); handle.position = new Vector3(locationdata.position.x, locationdata.position.y, locationdata.position.z); handle.rotation = new Vector3(locationdata.rotation.x, locationdata.rotation.y, locationdata.rotation.z); + this._isStored = true; } catch (e) { console.error(e); handle.position = Vector3.Zero(); diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index e935077..4b4488a 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -93,38 +93,40 @@ export class Toolbox { } } //this.toolboxBaseNode.parent.setEnabled(false); - let offset = new Vector3(-.50, 1.6, .38); - let rotation = new Vector3(.5, -.6, .18); + const offset = new Vector3(-.50, 1.6, .38); + const rotation = new Vector3(.5, -.6, .18); if (this.toolboxBaseNode.parent) { const platform = this.scene.getNodeById("platform"); if (platform) { const handle = this.handle; - if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { + handle.mesh.parent = platform; + /*if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { offset = handle.mesh.position; } if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) { rotation = handle.mesh.rotation; + }*/ + //handle.mesh.parent = platform; + if (!handle.idStored) { + handle.mesh.position = offset; + handle.mesh.rotation = rotation; } - handle.mesh.parent = platform; - handle.mesh.position = offset; - handle.mesh.rotation = rotation; + } else { this.scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => { - if (mesh.id == "platform") { + if (mesh && mesh.id == "platform") { const handle = this.handle; - if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { - offset = handle.mesh.position; - } - if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) { - rotation = handle.mesh.rotation; - } handle.mesh.parent = mesh; - handle.mesh.position = offset; - handle.mesh.rotation = rotation; + if (!handle.idStored) { + handle.mesh.position = offset; + handle.mesh.rotation = rotation; + } + //handle.mesh.parent = mesh; + } - }); + }, -1, false, this, false); } }