From 156d0858d8fc2830b4b13cf9cc334e2cb2352af5 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Fri, 28 Jul 2023 13:04:08 -0500 Subject: [PATCH] change from always add to also update in persistenceManager.ts --- src/app.ts | 4 ++ src/controllers/base.ts | 6 ++- src/diagram/diagramManager.ts | 6 ++- src/diagram/indexdbPersistenceManager.ts | 48 +++++++++++++++++------- src/diagram/meshConverter.ts | 36 +++++++++++++----- src/diagram/persistenceManager.ts | 3 +- src/menus/configMenu.ts | 25 +++++++----- src/util/appConfig.ts | 35 +++++++++++------ 8 files changed, 115 insertions(+), 48 deletions(-) diff --git a/src/app.ts b/src/app.ts index fb9bbe7..31e1e0e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -32,6 +32,7 @@ export class App { //preTasks = [havokModule]; private logger = log.getLogger('App'); + private scene: Scene; private xr: WebXRDefaultExperience; private rig: Rigplatform; @@ -40,6 +41,9 @@ export class App { const config = AppConfig.config; log.setLevel('info'); + log.getLogger('AppConfig').setLevel('debug'); + log.getLogger('IndexdbPersistenceManager').setLevel('debug'); + const canvas = document.createElement("canvas"); canvas.style.width = "100%"; canvas.style.height = "100%"; diff --git a/src/controllers/base.ts b/src/controllers/base.ts index 28937f6..ce85155 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -105,7 +105,11 @@ export class Base { newMesh.material = mesh.material; newMesh.metadata = mesh.metadata; newMesh && newMesh.setParent(this.controller.motionController.rootMesh); - + const event: DiagramEvent = { + type: DiagramEventType.ADD, + entity: MeshConverter.toDiagramEntity(newMesh) + } + this.diagramManager.onDiagramEventObservable.notifyObservers(event); this.grabbedMesh = newMesh; this.previousParent = null; } diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts index e4fa510..79c89fa 100644 --- a/src/diagram/diagramManager.ts +++ b/src/diagram/diagramManager.ts @@ -56,12 +56,14 @@ export class DiagramManager { case DiagramEventType.DROPPED: break; case DiagramEventType.DROP: - this.getPersistenceManager()?.add(mesh) + this.getPersistenceManager()?.modify(mesh); + MeshConverter.updateTextNode(mesh, entity.text); break; case DiagramEventType.ADD: + this.getPersistenceManager()?.add(mesh); break; case DiagramEventType.MODIFY: - this.getPersistenceManager()?.modify(mesh) + this.getPersistenceManager()?.modify(mesh); break; case DiagramEventType.CHANGECOLOR: this.getPersistenceManager()?.changeColor(event.oldColor, event.newColor); diff --git a/src/diagram/indexdbPersistenceManager.ts b/src/diagram/indexdbPersistenceManager.ts index aab1744..8cc2291 100644 --- a/src/diagram/indexdbPersistenceManager.ts +++ b/src/diagram/indexdbPersistenceManager.ts @@ -4,18 +4,25 @@ import {DiagramEntity} from "./diagramEntity"; import Dexie from "dexie"; import {MeshConverter} from "./meshConverter"; import log from "loglevel"; +import {AppConfigType} from "../util/appConfig"; -export class IndexdbPersistenceManager implements IPersistenceManager { + +export class IndexdbPersistenceManager implements IPersistenceManager { private readonly logger = log.getLogger('IndexdbPersistenceManager'); - public updateObserver: Observable = new Observable(); + public readonly updateObserver: Observable = new Observable(); + public readonly configObserver: Observable = new Observable(); private db: Dexie; + constructor(name: string) { this.db = new Dexie(name); - this.db.version(1).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"}); + const version = 2; + this.db.version(2).stores({config: "id,gridSnap,rotateSnap,createSnap"}); + this.db.version(2).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"}); this.logger.debug("IndexdbPersistenceManager constructed"); } - public add(mesh: AbstractMesh) { + + public add(mesh: AbstractMesh) { if (!mesh) { this.logger.error("Adding null mesh, early return"); return; @@ -24,27 +31,35 @@ export class IndexdbPersistenceManager implements IPersistenceManager { entity.position = this.vectoxys(mesh.position); entity.rotation = this.vectoxys(mesh.rotation); entity.scale = this.vectoxys(mesh.scaling); - this.db["entities"].add(entity); this.logger.debug('add', mesh, entity); } public remove(mesh: AbstractMesh) { + if (!mesh) { + this.logger.error("Removing null mesh, early return"); + return; + } this.db["entities"].delete(mesh.id); } - public getConfig(): any { - this.logger.warn('getConfig not implemented'); - //@todo implement - } - - public setConfig(config: any) { - this.logger.warn('setConfig not implemented, value not persisted', config); - //@todo implement + public setConfig(config: AppConfigType) { + config.id = 1; + this.db["config"].put(config); + this.logger.debug('setConfig', config); + this.configObserver.notifyObservers(config); } public modify(mesh) { + if (!mesh) { + this.logger.error("Modifying null mesh, early return"); + return; + } const entity = MeshConverter.toDiagramEntity(mesh); + if (!entity) { + this.logger.error("Modifying null mesh, early return"); + return; + } entity.position = this.vectoxys(mesh.position); entity.rotation = this.vectoxys(mesh.rotation); entity.scale = this.vectoxys(mesh.scaling); @@ -61,10 +76,17 @@ export class IndexdbPersistenceManager implements IPersistenceManager { this.logger.debug('adding', e); this.updateObserver.notifyObservers(e); }); + this.db['config'].each((c) => { + this.configObserver.notifyObservers(c); + }); this.logger.info("initialize finished"); } public changeColor(oldColor, newColor) { + if (!oldColor || !newColor) { + this.logger.error("changeColor called with null color, early return"); + return; + } this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`); this.db['entities'].where('color').equals(oldColor.toHexString()).modify({color: newColor.toHexString()}); } diff --git a/src/diagram/meshConverter.ts b/src/diagram/meshConverter.ts index c14b3c3..5344d30 100644 --- a/src/diagram/meshConverter.ts +++ b/src/diagram/meshConverter.ts @@ -15,7 +15,12 @@ import log from "loglevel"; export class MeshConverter { + private static logger = log.getLogger('MeshConverter'); public static toDiagramEntity(mesh: AbstractMesh): DiagramEntity { + if (!mesh) { + this.logger.error("toDiagramEntity: mesh is null"); + return null; + } const entity = {}; if ("new" == mesh?.id) { mesh.id = "id" + uuidv4(); @@ -29,11 +34,17 @@ export class MeshConverter { entity.scale = mesh.scaling; if (mesh.material) { entity.color = (mesh.material as any).diffuseColor.toHexString(); + } else { + this.logger.error("toDiagramEntity: mesh.material is null"); } return entity; } public static fromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh { + if (!entity) { + this.logger.error("fromDiagramEntity: entity is null"); + return null; + } if (!entity.id) { entity.id = "id" + uuidv4(); } @@ -64,10 +75,7 @@ export class MeshConverter { if (mesh) { mesh.metadata = {template: entity.template}; - if (entity.text) { - mesh.metadata.text = entity.text; - this.updateTextNode(mesh, entity.text); - } + if (entity.position) { mesh.position = entity.position; } @@ -85,7 +93,12 @@ export class MeshConverter { material.diffuseColor = Color3.FromHexString(entity.color); mesh.material = material; } - + if (entity.text) { + mesh.metadata.text = entity.text; + this.updateTextNode(mesh, entity.text); + } + } else { + this.logger.error("fromDiagramEntity: mesh is null after it should have been created"); } return mesh; @@ -93,12 +106,19 @@ export class MeshConverter { } public static updateTextNode(mesh: AbstractMesh, text: string) { + if (!mesh) { + this.logger.error("updateTextNode: mesh is null"); + return null; + } let textNode = (mesh.getChildren((node) => { return node.name == 'text' })[0] as Mesh); if (textNode) { textNode.dispose(false, true); } + if (!text) { + return null; + } //Set font const height = 0.125; @@ -110,7 +130,7 @@ export class MeshConverter { const ratio = height / DTHeight; //Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas - const temp = new DynamicTexture("DynamicTexture", 64, mesh.getScene()); + const temp = new DynamicTexture("DynamicTexture", 32, mesh.getScene()); const tmpctx = temp.getContext(); tmpctx.font = font; const DTWidth = tmpctx.measureText(text).width + 8; @@ -133,9 +153,7 @@ export class MeshConverter { plane.billboardMode = Mesh.BILLBOARDMODE_ALL; //textNode = this.updateTextNode(mesh, entity.text); plane.parent = mesh; - log.getLogger('bmenu').debug("max y", mesh.getBoundingInfo().boundingBox.maximum.y); - plane.position.y = .5+ (height / 2); - + plane.position.y = .5 + (.125 / 2); return plane; } } \ No newline at end of file diff --git a/src/diagram/persistenceManager.ts b/src/diagram/persistenceManager.ts index 6fcfaa4..c12abb2 100644 --- a/src/diagram/persistenceManager.ts +++ b/src/diagram/persistenceManager.ts @@ -11,12 +11,11 @@ export interface IPersistenceManager { initialize(); - getConfig(): AppConfigType; - setConfig(config: AppConfigType); changeColor(oldColor: Color3, newColor: Color3) updateObserver: Observable; + configObserver: Observable; } diff --git a/src/menus/configMenu.ts b/src/menus/configMenu.ts index b5fc124..2d31aab 100644 --- a/src/menus/configMenu.ts +++ b/src/menus/configMenu.ts @@ -26,21 +26,24 @@ export class ConfigMenu { this.configPlane = null; return; } + const width = .25; + const height = .55; + const res = 256; + const heightPixels = Math.round((height / width) * res); this.configPlane = MeshBuilder .CreatePlane("gridSizePlane", { width: .25, height: .5 }, this.scene); - const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, 256, 512); + const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, res, heightPixels); configTexture.background = "white"; const selectionPanel = new SelectionPanel("selectionPanel"); - selectionPanel.fontSize = "24px"; - selectionPanel.height = "100%"; configTexture.addControl(selectionPanel) - selectionPanel.addGroup(this.buildGridSizeControl()); - selectionPanel.addGroup(this.buildRotationSnapControl()); - selectionPanel.addGroup(this.buildCreateScaleControl()); + this.buildGridSizeControl(selectionPanel); + this.buildRotationSnapControl(selectionPanel); + this.buildCreateScaleControl(selectionPanel); + this.configPlane.position = CameraHelper.getFrontPosition(2, this.scene); this.configPlane.rotation.y = Angle.FromDegrees(180).radians(); } @@ -50,8 +53,10 @@ export class ConfigMenu { log.debug("configMenu", "create Snap", value); } - private buildCreateScaleControl(): RadioGroup { + private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Create Scale"); + selectionPanel.addGroup(radio); + for (const [index, snap] of AppConfig.config.createSnaps().entries()) { const selected = AppConfig.config.currentCreateSnapIndex == index; radio.addRadio(snap.label, this.createVal, selected); @@ -59,8 +64,9 @@ export class ConfigMenu { return radio; } - private buildRotationSnapControl(): RadioGroup { + private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Rotation Snap"); + selectionPanel.addGroup(radio); for (const [index, snap] of AppConfig.config.rotateSnaps().entries()) { const selected = AppConfig.config.currentRotateSnapIndex == index; radio.addRadio(snap.label, this.rotateVal, selected); @@ -68,8 +74,9 @@ export class ConfigMenu { return radio; } - private buildGridSizeControl(): RadioGroup { + private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Grid Snap"); + selectionPanel.addGroup(radio); for (const [index, snap] of AppConfig.config.gridSnaps().entries()) { const selected = AppConfig.config.currentGridSnapIndex == index; radio.addRadio(snap.label, this.gridVal, selected); diff --git a/src/util/appConfig.ts b/src/util/appConfig.ts index 0b6e30a..33bb92d 100644 --- a/src/util/appConfig.ts +++ b/src/util/appConfig.ts @@ -8,13 +8,15 @@ export type SnapValue = { label: string } export type AppConfigType = { + id?: number, gridSnap: number, rotateSnap: number, createSnap: number } export class AppConfig { - private gridSnap = 0; + private readonly logger = log.getLogger('AppConfig'); + private gridSnap = 1; private rotateSnap = 0; private createSnap = 0; private readonly defaultGridSnapIndex = 1; @@ -75,7 +77,7 @@ export class AppConfig { this.createSnap = val; if (this.currentGridSnapIndex == this.defaultGridSnapIndex) { this.currentGridSnap.value = this.currentCreateSnap.value / 2; - log.getLogger('AppConfig').debug("Set grid snap to " + this.currentGridSnap.value); + this.logger.debug("Set grid snap to " + this.currentGridSnap.value); } this.save(); } @@ -95,7 +97,7 @@ export class AppConfig { public setPersistenceManager(persistenceManager: IPersistenceManager) { this.persistenceManager = persistenceManager; - this.load(); + this.persistenceManager.configObserver.add(this.configObserver, -1, false, this); } public gridSnaps(): SnapValue[] { @@ -141,23 +143,32 @@ export class AppConfig { }); } - private load() { - const config = this.persistenceManager.getConfig(); + private configObserver(config: AppConfigType) { if (config) { - this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap); - this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap); - const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap); - if (gridSnap == -1) { - this.gridSnap = this.defaultGridSnapIndex; - this.currentGridSnap.value = config.gridSnap; + if (config.createSnap != this.currentCreateSnap.value || + config.gridSnap != this.currentGridSnap.value || + config.rotateSnap != this.currentRotateSnap.value) { + this.logger.debug("Config changed", config); + + this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap); + this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap); + const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap); + if (gridSnap == -1) { + this.gridSnap = this.defaultGridSnapIndex; + this.currentGridSnap.value = config.gridSnap; + } + } else { + this.logger.debug("Config unchanged", config); } + } else { + this.logger.debug("Config not set"); } } private snapAngle(val: number): number { const deg = Angle.FromRadians(val).degrees(); const snappedDegrees = round(deg, this.currentRotateSnap.value); - log.getLogger('AppConfig').debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value); + this.logger.debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value); return Angle.FromDegrees(snappedDegrees).radians(); } } \ No newline at end of file