From 2cc8b6697f878c15a706932baf004cf7d2e48b05 Mon Sep 17 00:00:00 2001 From: Donovan Hutchence Date: Fri, 12 Jul 2024 13:25:19 +0100 Subject: [PATCH] Make gizmo consistent size, update key focus (#131) --- package-lock.json | 4 +- package.json | 2 +- src/camera.ts | 2 + src/drop-handler.ts | 87 +++++++++++++++++-------------------- src/file-handler.ts | 2 +- src/main.ts | 6 +-- src/style.scss | 25 ++++++----- src/tools/transform-tool.ts | 16 ++++++- src/ui/editor.ts | 21 ++++++++- 9 files changed, 99 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index c9a3dec..498e0a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "supersplat", - "version": "0.22.1", + "version": "0.22.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "supersplat", - "version": "0.22.1", + "version": "0.22.2", "license": "MIT", "devDependencies": { "@playcanvas/eslint-config": "^1.7.1", diff --git a/package.json b/package.json index acd1bdd..07435e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "supersplat", - "version": "0.22.1", + "version": "0.22.2", "author": "PlayCanvas", "homepage": "https://playcanvas.com/supersplat/editor", "description": "3D Gaussian Splat Editor", diff --git a/src/camera.ts b/src/camera.ts index 2d847fa..ee1ceb7 100644 --- a/src/camera.ts +++ b/src/camera.ts @@ -296,6 +296,8 @@ class Camera extends Element { samples: samples, autoResolve: false }); + + this.scene.events.fire('camera.resize', {width, height}); } onUpdate(deltaTime: number) { diff --git a/src/drop-handler.ts b/src/drop-handler.ts index 66473d6..da7734d 100644 --- a/src/drop-handler.ts +++ b/src/drop-handler.ts @@ -1,4 +1,4 @@ -import {path} from 'playcanvas'; +import { path } from 'playcanvas'; class DroppedFile { filename: string; @@ -79,56 +79,49 @@ const removeCommonPrefix = (urls: Array) => { // configure drag and drop const CreateDropHandler = (target: HTMLElement, dropHandler: DropHandlerFunc) => { - target.addEventListener( - 'dragstart', - ev => { - ev.preventDefault(); - ev.stopPropagation(); - ev.dataTransfer.effectAllowed = 'all'; - }, - false - ); - - target.addEventListener( - 'dragover', - ev => { - ev.preventDefault(); - ev.stopPropagation(); - ev.dataTransfer.effectAllowed = 'all'; - }, - false - ); - - target.addEventListener( - 'drop', - async ev => { - ev.preventDefault(); - - // resolve directories to files - const entries = await resolveDirectories( - Array.from(ev.dataTransfer.items).map(item => item.webkitGetAsEntry()) - ); - const files = await Promise.all( - entries.map(entry => { - return new Promise((resolve, reject) => { - entry.file((entryFile: any) => { - resolve(new DroppedFile(entry.fullPath.substring(1), entryFile)); - }); + const dragstart = (ev: DragEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + ev.dataTransfer.effectAllowed = 'all'; + }; + + const dragover = (ev: DragEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + ev.dataTransfer.effectAllowed = 'all'; + }; + + const drop = async (ev: DragEvent) => { + ev.preventDefault(); + + // resolve directories to files + const entries = await resolveDirectories( + Array.from(ev.dataTransfer.items).map(item => item.webkitGetAsEntry()) + ); + + const files = await Promise.all( + entries.map(entry => { + return new Promise((resolve, reject) => { + entry.file((entryFile: any) => { + resolve(new DroppedFile(entry.fullPath.substring(1), entryFile)); }); - }) - ); + }); + }) + ); - if (files.length > 1) { - // if all files share a common filename prefix, remove it - removeCommonPrefix(files); - } + if (files.length > 1) { + // if all files share a common filename prefix, remove it + removeCommonPrefix(files); + } + + // finally, call the drop handler + dropHandler(files, !ev.shiftKey); + }; - // finally, call the drop handler - dropHandler(files, !ev.shiftKey); - }, - false - ); + target.addEventListener('dragstart', dragstart, true); + target.addEventListener('dragover', dragover, true); + target.addEventListener('drop', drop, true); }; export { CreateDropHandler }; diff --git a/src/file-handler.ts b/src/file-handler.ts index 40695bc..e7c5f80 100644 --- a/src/file-handler.ts +++ b/src/file-handler.ts @@ -109,7 +109,7 @@ const initFileHandler = async (scene: Scene, events: Events, canvas: HTMLCanvasE } // create the file drag & drop handler - CreateDropHandler(canvas, async (entries) => { + CreateDropHandler(document.body, async (entries) => { const modelExtensions = ['.ply']; for (let i = 0; i < entries.length; i++) { const entry = entries[i]; diff --git a/src/main.ts b/src/main.ts index 2c278ab..bd8b64f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -154,9 +154,9 @@ const main = async () => { toolManager.register('move', new MoveTool(events, editHistory, scene)); toolManager.register('rotate', new RotateTool(events, editHistory, scene)); toolManager.register('scale', new ScaleTool(events, editHistory, scene)); - toolManager.register('rectSelection', new RectSelection(events, editorUI.canvasContainer.dom, editorUI.canvas)); - toolManager.register('brushSelection', new BrushSelection(events, editorUI.canvasContainer.dom, editorUI.canvas)); - toolManager.register('pickerSelection', new PickerSelection(events, editorUI.canvasContainer.dom, editorUI.canvas)); + toolManager.register('rectSelection', new RectSelection(events, editorUI.toolsContainer.dom, editorUI.canvas)); + toolManager.register('brushSelection', new BrushSelection(events, editorUI.toolsContainer.dom, editorUI.canvas)); + toolManager.register('pickerSelection', new PickerSelection(events, editorUI.toolsContainer.dom, editorUI.canvas)); window.scene = scene; diff --git a/src/style.scss b/src/style.scss index 09082e5..e24c08c 100644 --- a/src/style.scss +++ b/src/style.scss @@ -52,16 +52,6 @@ body { flex-grow: 1; } -#canvas-container { - width: 100%; - background-color: #666666; - display: flex; - border: 0; - padding: 0; - margin: 0; - flex-grow: 1; -} - #data-panel { width: 100%; height: 320px; @@ -412,6 +402,21 @@ body { flex-grow: 1; } +#tools-container { + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; +} + +#focus-capture { + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; + opacity: 0; +} + #canvas { width: 100%; height: 100%; diff --git a/src/tools/transform-tool.ts b/src/tools/transform-tool.ts index 6f6a4cd..e05dc54 100644 --- a/src/tools/transform-tool.ts +++ b/src/tools/transform-tool.ts @@ -30,7 +30,6 @@ class TransformTool { patchGizmoMaterials(this.gizmo); this.gizmo.coordSpace = events.invoke('tool.coordSpace'); - this.gizmo.size = 1.2; this.gizmo.on('render:update', () => { scene.forceRender = true; @@ -100,6 +99,21 @@ class TransformTool { events.on('selection.changed', () => { this.update(); }); + + const updateGizmoSize = () => { + const canvas = document.getElementById('canvas'); + if (canvas) { + const w = canvas.clientWidth; + const h = canvas.clientHeight; + this.gizmo.size = 1200 / Math.max(w, h); + } + }; + + events.on('camera.resize', () => { + this.scene.events.on('camera.resize', updateGizmoSize); + }); + + updateGizmoSize(); } update() { diff --git a/src/ui/editor.ts b/src/ui/editor.ts index 232ed06..7487d72 100644 --- a/src/ui/editor.ts +++ b/src/ui/editor.ts @@ -1,4 +1,4 @@ -import { Container, Label } from 'pcui'; +import { Element, Container, Label } from 'pcui'; import { ControlPanel } from './control-panel'; import { DataPanel } from './data-panel'; import { Toolbar } from './toolbar'; @@ -11,6 +11,7 @@ class EditorUI { topContainer: Container; controlPanel: ControlPanel; canvasContainer: Container; + toolsContainer: Container; canvas: HTMLCanvasElement; filenameLabel: Label; popup: Popup; @@ -68,8 +69,24 @@ class EditorUI { const canvasContainer = new Container({ id: 'canvas-container' }); + + // tools container + const toolsContainer = new Container({ + id: 'tools-container' + }); + + // focus capture + const focusCapture = new Element({ + id: 'focus-capture' + }); + focusCapture.dom.addEventListener('pointerdown', (event: PointerEvent) => { + document.body.focus(); + }, true); + canvasContainer.dom.appendChild(canvas); canvasContainer.append(filenameLabel); + canvasContainer.append(toolsContainer); + canvasContainer.append(focusCapture); // control panel const controlPanel = new ControlPanel(events, remoteStorageMode); @@ -99,10 +116,12 @@ class EditorUI { this.topContainer = topContainer; this.controlPanel = controlPanel; this.canvasContainer = canvasContainer; + this.toolsContainer = toolsContainer; this.canvas = canvas; this.filenameLabel = filenameLabel; document.body.appendChild(appContainer.dom); + document.body.setAttribute('tabIndex', '-1'); events.function('showPopup', (options: { type: 'error' | 'info' | 'yesno' | 'okcancel', message: string, value: string}) => { return this.popup.show(options.type, options.message, options.value);