From e43a9e9d412d7c78981d57a7bd47a576482b7ab7 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Fri, 25 Aug 2023 13:26:19 -0500 Subject: [PATCH] Fixed up menu system. --- src/controllers/base.ts | 6 ++- src/information/inputTextView.ts | 78 ++++++++++++++++++++------- src/menus/configMenu.ts | 73 +++++++++++++++++-------- src/menus/editMenu.ts | 6 +-- src/menus/menuHandle.ts | 30 +++++++++++ src/toolbox/toolbox.ts | 20 ++----- src/util/functions/setMenuPosition.ts | 6 +-- 7 files changed, 154 insertions(+), 65 deletions(-) create mode 100644 src/menus/menuHandle.ts diff --git a/src/controllers/base.ts b/src/controllers/base.ts index a900d9c..03c53e5 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -96,11 +96,13 @@ export class Base { } public disable() { + this.scene.preventDefaultOnPointerDown = true; this.controller.motionController.rootMesh.setEnabled(false) this.controller.pointer.setEnabled(false); } public enable() { + this.scene.preventDefaultOnPointerDown = false; this.controller.motionController.rootMesh.setEnabled(true); this.controller.pointer.setEnabled(true) } @@ -112,7 +114,7 @@ export class Base { } const template = mesh?.metadata?.template; if (!template) { - if (mesh?.id == "handle") { + if (mesh?.metadata?.handle == true) { mesh && mesh.setParent(this.controller.motionController.rootMesh); this.grabbedMesh = mesh; } else { @@ -163,7 +165,7 @@ export class Base { private toolboxHandleWasGrabbed(mesh: AbstractMesh): boolean { if (!mesh?.metadata?.template - && mesh?.id == "handle") { + && mesh?.metadata?.handle == true) { this.grabbedMesh = null; this.previousParentId = null; mesh.setParent(null); diff --git a/src/information/inputTextView.ts b/src/information/inputTextView.ts index 37a88d3..cff7a34 100644 --- a/src/information/inputTextView.ts +++ b/src/information/inputTextView.ts @@ -1,7 +1,8 @@ -import {Observable, Scene, WebXRDefaultExperience} from "@babylonjs/core"; +import {MeshBuilder, Observable, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import log from "loglevel"; -import {AdvancedDynamicTexture, InputText} from "@babylonjs/gui"; +import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui"; import {ControllerEventType, Controllers} from "../controllers/controllers"; +import {setMenuPosition} from "../util/functions/setMenuPosition"; export type TextEvent = { text: string; @@ -15,33 +16,71 @@ export type InputTextViewOptions = { export class InputTextView { public readonly onTextObservable: Observable = new Observable(); - private readonly text: string; + private readonly text: string = ""; private readonly scene: Scene; private readonly controllers: Controllers; private readonly xr: WebXRDefaultExperience; - constructor(options: InputTextViewOptions) { - if (options.text) { - this.text = options.text; - } - if (options.xr) { - this.xr = options.xr; - } - if (options.scene) { - this.scene = options.scene; - } - if (options.controllers) { - this.controllers = options.controllers; - } + constructor(text: string, xr: WebXRDefaultExperience, scene: Scene) { + this.text = text ? text : ""; + this.xr = xr; + this.scene = scene; } public show() { - - if ((this.xr as WebXRDefaultExperience).baseExperience?.sessionManager?.inXRSession) { + this.showVirtualKeyboard(); + /*if ((this.xr as WebXRDefaultExperience).baseExperience?.sessionManager?.inXRSession) { this.showXr(); } else { this.showWeb(); - } + }*/ + } + + public showVirtualKeyboard() { + + + const inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene); + const advancedTexture = AdvancedDynamicTexture.CreateForMesh(inputMesh, 2048, 1024, false); + + const input = new InputText(); + + input.width = 0.5; + input.maxWidth = 0.5; + input.height = "64px"; + input.text = this.text; + + input.fontSize = "32px"; + input.color = "white"; + input.background = "black"; + input.thickness = 3; + input.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; + advancedTexture.addControl(input); + + const keyboard = VirtualKeyboard.CreateDefaultLayout(); + keyboard.scaleY = 2; + keyboard.scaleX = 2; + keyboard.transformCenterY = 0; + keyboard.transformCenterX = .5; + keyboard.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; + keyboard.paddingTop = "70px" + keyboard.height = "768px"; + keyboard.fontSizeInPixels = 24; + advancedTexture.addControl(keyboard); + keyboard.connect(input); + keyboard.isVisible = true; + keyboard.isEnabled = true; + + + keyboard.onKeyPressObservable.add((key) => { + if (key === '↵') { + this.onTextObservable.notifyObservers({text: input.text}); + input.dispose(); + keyboard.dispose(); + advancedTexture.dispose(); + inputMesh.dispose(); + } + }); + setMenuPosition(inputMesh, this.scene, new Vector3(0, .4, 0)); } public showWeb() { @@ -59,6 +98,7 @@ export class InputTextView { this.onTextObservable.notifyObservers({text: textInput.text}); textInput.dispose(); advancedTexture.dispose(); + } }); diff --git a/src/menus/configMenu.ts b/src/menus/configMenu.ts index f647b57..195d5e6 100644 --- a/src/menus/configMenu.ts +++ b/src/menus/configMenu.ts @@ -1,14 +1,14 @@ -import {AdvancedDynamicTexture, RadioGroup, SelectionPanel} from "@babylonjs/gui"; -import {AbstractMesh, MeshBuilder, Scene, WebXRDefaultExperience} from "@babylonjs/core"; +import {AdvancedDynamicTexture, RadioGroup, SelectionPanel, StackPanel} from "@babylonjs/gui"; +import {MeshBuilder, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {AppConfig} from "../util/appConfig"; import {ControllerEventType, Controllers} from "../controllers/controllers"; import {DiaSounds} from "../util/diaSounds"; import {AbstractMenu} from "./abstractMenu"; import {setMenuPosition} from "../util/functions/setMenuPosition"; +import {MenuHandle} from "./menuHandle"; export class ConfigMenu extends AbstractMenu { private sounds: DiaSounds; - private configPlane: AbstractMesh = null; private yObserver; private config: AppConfig; @@ -42,44 +42,68 @@ export class ConfigMenu extends AbstractMenu { } + private handle: MenuHandle; + public toggle() { - if (this.configPlane) { + if (this.handle) { + this.handle.mesh.dispose(false, true); this.sounds.exit.play(); - this.configPlane.dispose(); - this.configPlane = null; + this.handle = null; return; } this.sounds.enter.play(); - const width = .25; - const height = .75; - const res = 256; - const heightPixels = Math.round((height / width) * res); - this.configPlane = MeshBuilder + const configPlane = MeshBuilder .CreatePlane("gridSizePlane", { - width: .25, - height: .75 + width: .6, + height: .3 }, this.scene); - const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, res, heightPixels); - configTexture.background = "white"; - const selectionPanel = new SelectionPanel("selectionPanel"); - configTexture.addControl(selectionPanel) - this.buildGridSizeControl(selectionPanel); - this.buildCreateScaleControl(selectionPanel); - this.buildRotationSnapControl(selectionPanel); - this.buildTurnSnapControl(selectionPanel); + this.handle = new MenuHandle(configPlane); + const configTexture = AdvancedDynamicTexture.CreateForMesh(configPlane, 2048, 1024); - setMenuPosition(this.configPlane, this.scene); + configTexture.background = "white"; + const columnPanel = new StackPanel('columns'); + columnPanel.fontSize = "48px"; + columnPanel.isVertical = false; + configTexture.addControl(columnPanel); + const selectionPanel1 = new SelectionPanel("selectionPanel1"); + selectionPanel1.width = .5; + columnPanel.addControl(selectionPanel1); + this.buildGridSizeControl(selectionPanel1); + this.buildCreateScaleControl(selectionPanel1); + const selectionPanel2 = new SelectionPanel("selectionPanel2"); + selectionPanel2.width = .5; + columnPanel.addControl(selectionPanel2); + this.buildRotationSnapControl(selectionPanel2); + this.buildTurnSnapControl(selectionPanel2); + configPlane.position.set(0, .2, 0); + setMenuPosition(this.handle.mesh, this.scene, new Vector3(0, .4, 0)); + } + + private adjustRadio(radio: RadioGroup) { + radio.groupPanel.height = "512px"; + radio.groupPanel.fontSize = "64px"; + radio.groupPanel.children[0].height = "70px"; + radio.groupPanel.paddingLeft = "16px"; + radio.selectors.forEach((panel) => { + panel.children[0].height = "64px"; + panel.children[0].width = "64px"; + panel.children[1].paddingLeft = "32px"; + panel.paddingTop = "16px"; + panel.fontSize = "60px"; + panel.adaptHeightToChildren = true; + }); } private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Create Scale"); - selectionPanel.addGroup(radio); + selectionPanel.addGroup(radio); for (const [index, snap] of this.gridSnaps.entries()) { const selected = (this.config.current.createSnap == snap.value); radio.addRadio(snap.label, this.createVal.bind(this), selected); } + this.adjustRadio(radio); return radio; } @@ -90,6 +114,7 @@ export class ConfigMenu extends AbstractMenu { const selected = (this.config.current.rotateSnap == snap.value); radio.addRadio(snap.label, this.rotateVal.bind(this), selected); } + this.adjustRadio(radio); return radio; } @@ -103,6 +128,7 @@ export class ConfigMenu extends AbstractMenu { radio.addRadio(snap.label, this.gridVal.bind(this), selected); } + this.adjustRadio(radio); return radio; } @@ -113,6 +139,7 @@ export class ConfigMenu extends AbstractMenu { const selected = (this.config.current.turnSnap == snap.value); radio.addRadio(snap.label, this.turnVal.bind(this), selected); } + this.adjustRadio(radio); return radio; } diff --git a/src/menus/editMenu.ts b/src/menus/editMenu.ts index 76787b2..a7e2dfe 100644 --- a/src/menus/editMenu.ts +++ b/src/menus/editMenu.ts @@ -129,7 +129,7 @@ export class EditMenu extends AbstractMenu { } else { this.sounds.enter.play(); - setMenuPosition(this.manager.rootContainer.children[0].node, this.scene); + setMenuPosition(this.manager.rootContainer.children[0].node, this.scene, new Vector3(0, .4, 0)); this.isVisible = true; } } @@ -252,7 +252,7 @@ export class EditMenu extends AbstractMenu { if (mesh?.metadata?.text) { text = mesh.metadata.text; } - const textInput = new InputTextView({xr: this.xr, text: text, controllers: this.controllers}); + const textInput = new InputTextView(text, this.xr, this.scene); textInput.show(); textInput.onTextObservable.addOnce((value) => { @@ -264,7 +264,7 @@ export class EditMenu extends AbstractMenu { } private showNewRelic() { - const inputTextView = new InputTextView({xr: this.xr, scene: this.scene, text: "New Relic"}); + const inputTextView = new InputTextView('test', this.xr, this.scene); inputTextView.show(); inputTextView.onTextObservable.addOnce((value) => { const config = this.diagramManager.config.current; diff --git a/src/menus/menuHandle.ts b/src/menus/menuHandle.ts new file mode 100644 index 0000000..f11c7f3 --- /dev/null +++ b/src/menus/menuHandle.ts @@ -0,0 +1,30 @@ +import {AbstractMesh, Color3, MeshBuilder, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core"; + +export class MenuHandle { + public mesh: AbstractMesh; + private menuTransformNode: TransformNode; + + constructor(mesh: TransformNode) { + this.menuTransformNode = mesh; + this.buildHandle(mesh.getScene()); + } + + private buildHandle(scene: Scene) { + const handle = MeshBuilder.CreateCapsule("handle", { + radius: .05, + orientation: Vector3.Right(), + height: .4 + }, scene); + handle.id = "handle-" + this.menuTransformNode.id + "-mesh"; + const handleMaterial = new StandardMaterial("handle-" + this.menuTransformNode.id, scene); + handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF"); + handleMaterial.alpha = .8; + handle.material = handleMaterial; + handle.position = Vector3.Zero(); + handle.metadata = {handle: true}; + if (this.menuTransformNode) { + this.menuTransformNode.setParent(handle); + } + this.mesh = handle; + } +} \ No newline at end of file diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index dbf400f..1238216 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -1,9 +1,10 @@ -import {Color3, Mesh, MeshBuilder, Observable, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core"; +import {Color3, Mesh, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core"; import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui"; import {ControllerEventType, Controllers} from "../controllers/controllers"; import {setMenuPosition} from "../util/functions/setMenuPosition"; import {buildColor} from "./functions/buildColor"; +import {MenuHandle} from "../menus/menuHandle"; export class Toolbox { private index = 0; @@ -15,7 +16,7 @@ export class Toolbox { private readonly xObserver; public readonly colorChangeObservable: Observable<{ oldColor: string, newColor: string }> = new Observable<{ oldColor: string; newColor: string }>() - + private handle: MenuHandle; constructor(scene: Scene, controllers: Controllers) { this.scene = scene; this.controllers = controllers; @@ -23,20 +24,9 @@ export class Toolbox { this.manager = new GUI3DManager(scene); this.manager.addControl(this.addPanel); this.node = new TransformNode("toolbox", this.scene); - const handle = MeshBuilder.CreateCapsule("handle", { - radius: .05, - orientation: Vector3.Right(), - height: .4 - }, this.scene); - handle.id = "handle"; - const handleMaterial = new StandardMaterial("handle-material", this.scene); - handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF"); - handleMaterial.alpha = .8; - handle.material = handleMaterial; - handle.position = Vector3.Zero(); - - this.node.parent = handle; + this.handle = new MenuHandle(this.node); this.node.position.y = .1; + this.node.position.z = .2; this.node.scaling = new Vector3(0.6, 0.6, 0.6); this.buildToolbox(); diff --git a/src/util/functions/setMenuPosition.ts b/src/util/functions/setMenuPosition.ts index 2d56689..f114148 100644 --- a/src/util/functions/setMenuPosition.ts +++ b/src/util/functions/setMenuPosition.ts @@ -3,11 +3,11 @@ import {getFrontPosition} from "./getFrontPosition"; export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vector3 = Vector3.Zero()) { const front = getFrontPosition(.8, scene); - front.y = scene.activeCamera.globalPosition.y; + //front.y = scene.activeCamera.globalPosition.y; node.position = front; node.position.addInPlace(offset); - node.lookAt(scene.activeCamera.globalPosition); - node.rotation.y = node.rotation.y + Math.PI; node.position.y -= .5; + node.lookAt(scene.activeCamera.globalPosition); + node.rotation.y = node.rotation.y + Math.PI; } \ No newline at end of file