diff --git a/src/ThreeEditor/css/main.css b/src/ThreeEditor/css/main.css index ec907ec42..ebd90aca3 100644 --- a/src/ThreeEditor/css/main.css +++ b/src/ThreeEditor/css/main.css @@ -428,7 +428,7 @@ select:hover { margin: 0 !important; } -#sidebar { +:is(#sidebar,.sidebar) { position: absolute; right: 0; top: 32px; @@ -438,23 +438,24 @@ select:hover { overflow: auto; } -#sidebar .Panel { +:is(#sidebar,.sidebar) .Panel { color: #888; padding: 10px; border-top: 1px solid #ccc; } -#sidebar .Panel.collapsed { +:is(#sidebar,.sidebar) .Panel.collapsed { margin-bottom: 0; } -#sidebar .Row { +:is(#sidebar,.sidebar) .Row { min-height: 20px; margin-bottom: 10px; display: flex; + align-items: center; } -#sidebar canvas { +:is(#sidebar,.sidebar) canvas { vertical-align: middle; } @@ -580,7 +581,7 @@ select:hover { height: calc(100% - 352px); } - #sidebar { + :is(#sidebar,.sidebar) { left: 0; width: 100%; top: calc(100% - 320px); @@ -651,15 +652,15 @@ select:hover { color: #444; } - #sidebar { + :is(#sidebar,.sidebar) { background-color: #111; } - #sidebar .Panel { + :is(#sidebar,.sidebar) .Panel { border-top: 1px solid #222; } - #sidebar .Panel.Material canvas { + :is(#sidebar,.sidebar) .Panel.Material canvas { border: solid 1px #5a5a5a; } diff --git a/src/ThreeEditor/js/Editor.js b/src/ThreeEditor/js/Editor.js index 298b02a65..2779fcb3f 100644 --- a/src/ThreeEditor/js/Editor.js +++ b/src/ThreeEditor/js/Editor.js @@ -115,7 +115,9 @@ export function Editor(container) { viewportConfigChanged: new Signal(), // Viewport config signal - CSGManagerStateChanged: new Signal() // State of CSGmanager changed + CSGManagerStateChanged: new Signal(), // State of CSGmanager changed + + exampleLoaded: new Signal(), }; this.container = container; @@ -549,6 +551,9 @@ Editor.prototype = { async fromJSON(json) { this.config.setKey('project/title', json.project.title ?? ''); + this.config.setKey('project/description', json.project.description ?? ''); + this.signals.projectChanged.dispatch(); + const loader = new EditorObjectLoader(this); this.signals.cameraResetted.dispatch(); @@ -592,6 +597,7 @@ Editor.prototype = { }, project: { title: this.config.getKey('project/title'), + description: this.config.getKey('project/description'), shadows: this.config.getKey('project/renderer/shadows'), shadowType: this.config.getKey('project/renderer/shadowType'), physicallyCorrectLights: this.config.getKey( diff --git a/src/ThreeEditor/js/menubar/Menubar.Examples.js b/src/ThreeEditor/js/menubar/Menubar.Examples.js index a237e21b1..cda132881 100644 --- a/src/ThreeEditor/js/menubar/Menubar.Examples.js +++ b/src/ThreeEditor/js/menubar/Menubar.Examples.js @@ -23,6 +23,7 @@ export function MenubarExamples(editor) { function loadExample(example) { editor.clear(); editor.fromJSON(example); + editor.signals.exampleLoaded.dispatch(); } // YAPTIDE examples diff --git a/src/ThreeEditor/js/menubar/Menubar.File.js b/src/ThreeEditor/js/menubar/Menubar.File.js index 603e57b03..da29af5cb 100644 --- a/src/ThreeEditor/js/menubar/Menubar.File.js +++ b/src/ThreeEditor/js/menubar/Menubar.File.js @@ -1,6 +1,7 @@ -import { UIHorizontalRule, UIPanel } from '../libs/ui.js'; +import { UIHorizontalRule, UIPanel, UIRow, UIText } from '../libs/ui.js'; import { createOption } from './Menubar.js'; import { saveString } from '../../../util/File'; +import { MenubarSettings, MenubarSettingsEvent } from './Menubar.Settings.js'; function MenubarFile(editor) { const container = new UIPanel(); @@ -62,9 +63,33 @@ function MenubarFile(editor) { const fileName = window.prompt('Name of the file', 'editor'); if (fileName) saveString(output, `${fileName}.json`); + }), + new UIHorizontalRule() + ); + + + // Settings + const settingsModal = new UIPanel(); + settingsModal.setClass('sidebar'); + settingsModal.dom.style.left = '0'; + settingsModal.setDisplay('none'); + + const settings = new MenubarSettings(editor); + settings.dom.addEventListener(MenubarSettingsEvent.close, () => { + settingsModal.setDisplay('none'); + }) + settingsModal.add(settings); + editor.container.appendChild(settingsModal.dom); + + + options.add( + createOption('option', 'Settings', () => { + settingsModal.setDisplay(''); }) + ); + return container; } diff --git a/src/ThreeEditor/js/sidebar/Sidebar.Settings.History.js b/src/ThreeEditor/js/menubar/Menubar.Settings.History.js similarity index 96% rename from src/ThreeEditor/js/sidebar/Sidebar.Settings.History.js rename to src/ThreeEditor/js/menubar/Menubar.Settings.History.js index 960f24f3f..aff2ea670 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.Settings.History.js +++ b/src/ThreeEditor/js/menubar/Menubar.Settings.History.js @@ -1,7 +1,7 @@ import { UIPanel, UIBreak, UIText } from '../libs/ui.js'; import { UIBoolean, UIOutliner } from '../libs/ui.three.js'; -function SidebarSettingsHistory(editor) { +function MenubarSettingsHistory(editor) { const { signals, config, history } = editor; const container = new UIPanel(); @@ -99,4 +99,4 @@ function SidebarSettingsHistory(editor) { return container; } -export { SidebarSettingsHistory }; +export { MenubarSettingsHistory }; diff --git a/src/ThreeEditor/js/sidebar/Sidebar.Settings.Shortcuts.js b/src/ThreeEditor/js/menubar/Menubar.Settings.Shortcuts.js similarity index 93% rename from src/ThreeEditor/js/sidebar/Sidebar.Settings.Shortcuts.js rename to src/ThreeEditor/js/menubar/Menubar.Settings.Shortcuts.js index dcfccebdf..7956d5ac8 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.Settings.Shortcuts.js +++ b/src/ThreeEditor/js/menubar/Menubar.Settings.Shortcuts.js @@ -9,13 +9,13 @@ import { } from '../commands/Commands'; import { UIInput, UIPanel, UIRow, UIText } from '../libs/ui.js'; -function SidebarSettingsShortcuts(editor) { +function MenubarSettingsShortcuts(editor) { const { signals, config } = editor; const IS_MAC = navigator.platform.toUpperCase().indexOf('MAC') >= 0; function isValidKeyBinding(key) { - return key.match(/^[A-Za-z0-9]$/i); // Can't use z currently due to undo/redo + return /^[A-Za-z0-9]$/i.test(key); // Can't use z currently due to undo/redo } const container = new UIPanel(); @@ -76,7 +76,7 @@ function SidebarSettingsShortcuts(editor) { createShortcutInput(shortcuts[i]); } - const getRemoveCommand = (editor, object) => { + const getRemoveCommand = (object) => { switch (true) { case object.isDetectGeometry: return new RemoveDetectGeometryCommand(editor, object); @@ -108,7 +108,7 @@ function SidebarSettingsShortcuts(editor) { if (object === null || object.notRemovable === true) return; const parent = object.parent; - if (parent !== null) editor.execute(getRemoveCommand(editor, object)); + if (parent !== null) editor.execute(getRemoveCommand(object)); break; case config.getKey('settings/shortcuts/translate'): @@ -156,4 +156,4 @@ function SidebarSettingsShortcuts(editor) { return container; } -export { SidebarSettingsShortcuts }; +export { MenubarSettingsShortcuts }; diff --git a/src/ThreeEditor/js/sidebar/Sidebar.Settings.Viewport.js b/src/ThreeEditor/js/menubar/Menubar.Settings.Viewport.js similarity index 91% rename from src/ThreeEditor/js/sidebar/Sidebar.Settings.Viewport.js rename to src/ThreeEditor/js/menubar/Menubar.Settings.Viewport.js index 25c5fbe26..8bba88516 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.Settings.Viewport.js +++ b/src/ThreeEditor/js/menubar/Menubar.Settings.Viewport.js @@ -1,7 +1,7 @@ import { UIPanel, UIText, UIRow } from '../libs/ui.js'; import { UIBoolean } from '../libs/ui.three.js'; -function SidebarSettingsViewport(editor) { +function MenubarSettingsViewport(editor) { const { signals } = editor; const container = new UIPanel(); @@ -37,4 +37,4 @@ function SidebarSettingsViewport(editor) { return container; } -export { SidebarSettingsViewport }; +export { MenubarSettingsViewport }; diff --git a/src/ThreeEditor/js/sidebar/Sidebar.Settings.js b/src/ThreeEditor/js/menubar/Menubar.Settings.js similarity index 79% rename from src/ThreeEditor/js/sidebar/Sidebar.Settings.js rename to src/ThreeEditor/js/menubar/Menubar.Settings.js index 018884cb9..6bbf3cd38 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.Settings.js +++ b/src/ThreeEditor/js/menubar/Menubar.Settings.js @@ -1,14 +1,29 @@ import * as THREE from 'three'; -import { UIColor, UIPanel, UIRow, UISelect, UISpan, UIText } from '../libs/ui.js'; +import { UIButton, UIColor, UIPanel, UIRow, UISelect, UIText } from '../libs/ui.js'; import { UITexture } from '../libs/ui.three.js'; -import { SidebarSettingsHistory } from './Sidebar.Settings.History.js'; -import { SidebarSettingsShortcuts } from './Sidebar.Settings.Shortcuts.js'; -import { SidebarSettingsViewport } from './Sidebar.Settings.Viewport.js'; +import { SidebarProjectRenderer } from '../sidebar/Sidebar.Project.Renderer.js'; +import { MenubarSettingsHistory } from './Menubar.Settings.History.js'; +import { MenubarSettingsShortcuts } from './Menubar.Settings.Shortcuts.js'; +import { MenubarSettingsViewport } from './Menubar.Settings.Viewport.js'; -function SidebarSettings(editor) { +const MenubarSettingsEvent = { + close: 'closeMenubarSettings', +} + +function MenubarSettings(editor) { const { signals, scene } = editor; - const container = new UISpan(); + const container = new UIPanel(); + + const headerRow = new UIRow(); + headerRow.add(new UIText('Settings'.toUpperCase())); + const closeButton = new UIButton('Close').onClick(() => { + const event = new CustomEvent(MenubarSettingsEvent.close); + container.dom.dispatchEvent(event); + + }).setMarginLeft('auto'); + headerRow.add(closeButton); + container.add(headerRow); const settings = new UIPanel(); settings.setBorderTop('0'); @@ -115,9 +130,10 @@ function SidebarSettings(editor) { // - container.add(new SidebarSettingsViewport(editor)); - container.add(new SidebarSettingsShortcuts(editor)); - container.add(new SidebarSettingsHistory(editor)); + container.add(new MenubarSettingsViewport(editor)); + container.add(new MenubarSettingsShortcuts(editor)); + container.add(new MenubarSettingsHistory(editor)); + container.add(new SidebarProjectRenderer(editor)) // @@ -165,4 +181,4 @@ function SidebarSettings(editor) { return container; } -export { SidebarSettings }; +export { MenubarSettings,MenubarSettingsEvent }; diff --git a/src/ThreeEditor/js/sidebar/Sidebar.Project.js b/src/ThreeEditor/js/sidebar/Sidebar.Project.js index 49995b2c0..c14bd6421 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.Project.js +++ b/src/ThreeEditor/js/sidebar/Sidebar.Project.js @@ -1,6 +1,4 @@ -import { UIPanel, UIRow, UIInput, UICheckbox, UIText, UISpan } from '../libs/ui.js'; - -import { SidebarProjectRenderer } from './Sidebar.Project.Renderer.js'; +import { UIPanel, UIRow, UIInput, UIText, UISpan, UITextArea } from '../libs/ui.js'; function SidebarProject(editor) { const { signals, config } = editor; @@ -19,7 +17,7 @@ function SidebarProject(editor) { .setLeft('100px') .setWidth('160px') .onChange(() => { - config.setKey('project/title', this.getValue()); + config.setKey('project/title', title.getValue()); editor.signals.projectChanged.dispatch(); }); @@ -28,29 +26,41 @@ function SidebarProject(editor) { settings.add(titleRow); - // Editable + // Description - const editableRow = new UIRow(); - const editable = new UICheckbox(config.getKey('project/editable')) - .setLeft('100px') + const descriptionRow = new UIRow(); + descriptionRow.add(new UIText('Description').setWidth('90px')); + settings.add(descriptionRow); + + const description = new UITextArea() + .setWidth('100%') + .setHeight('400px') .onChange(() => { - config.setKey('project/editable', this.getValue()); + config.setKey('project/description', description.getValue()); + editor.signals.projectChanged.dispatch(); }); + description.setValue(config.getKey('project/description')); + description.dom.wrap = 'soft'; + description.dom.style.whiteSpace = 'break-spaces'; - editableRow.add(new UIText('Editable').setWidth('90px')); - editableRow.add(editable); - - settings.add(editableRow); + settings.add(new UIRow().add(description)); // - container.add(new SidebarProjectRenderer(editor)); + // Signals + signals.projectChanged.add(() => { + title.setValue(config.getKey('project/title')); + description.setValue(config.getKey('project/description')); + }) + signals.editorCleared.add(() => { title.setValue(''); config.setKey('project/title', ''); + description.setValue(''); + config.setKey('project/description', ''); }); return container; diff --git a/src/ThreeEditor/js/sidebar/Sidebar.js b/src/ThreeEditor/js/sidebar/Sidebar.js index 15a00e676..4e4e17527 100644 --- a/src/ThreeEditor/js/sidebar/Sidebar.js +++ b/src/ThreeEditor/js/sidebar/Sidebar.js @@ -3,7 +3,6 @@ import { SidebarScoring } from './Sidebar.Scoring'; import { SidebarProject } from './Sidebar.Project'; import { SidebarProperties } from './Sidebar.Properties'; import { SidebarScene } from './Sidebar.Scene'; -import { SidebarSettings } from './Sidebar.Settings'; function Sidebar(editor) { const { signals } = editor; @@ -17,13 +16,11 @@ function Sidebar(editor) { new SidebarScoring(editor).setBorderTop('0').setPaddingTop('20px') ); const project = new SidebarProject(editor); - const settings = new SidebarSettings(editor); let ignoreContextChangedSignal = false; tabbed.addTab('scene', 'SCENE', scene); tabbed.addTab('scoring', 'SCORING', scoring); - tabbed.addTab('parameters', 'PARAMETERS', project); - tabbed.addTab('settings', 'SETTINGS', settings); + tabbed.addTab('project', 'PROJECT', project); tabbed._select = tabbed.select; tabbed.select = function (id) { @@ -39,6 +36,10 @@ function Sidebar(editor) { ignoreContextChangedSignal || tabbed._select(id); }); + editor.signals.exampleLoaded.add(() => { + tabbed.select('project'); + }) + container.add(tabbed); container.add(properties); diff --git a/src/ThreeEditor/main.js b/src/ThreeEditor/main.js index 5103547c3..028a4b9dd 100644 --- a/src/ThreeEditor/main.js +++ b/src/ThreeEditor/main.js @@ -18,24 +18,24 @@ export function initEditor(container) { // - var editor = new Editor(container); + const editor = new Editor(container); window.editor = editor; // Expose editor to Console window.THREE = THREE; // Expose THREE to APP Scripts and Console - var viewManager = new ViewManager(editor); + const viewManager = new ViewManager(editor); container.appendChild(viewManager.dom); - var toolbar = new Toolbar(editor); + const toolbar = new Toolbar(editor); container.appendChild(toolbar.dom); - var sidebar = new Sidebar(editor); + const sidebar = new Sidebar(editor); container.appendChild(sidebar.dom); - var menubar = new Menubar(editor); + const menubar = new Menubar(editor); container.appendChild(menubar.dom); - var resizer = new Resizer(editor); + const resizer = new Resizer(editor); container.appendChild(resizer.dom); // @@ -57,7 +57,7 @@ export function initEditor(container) { if (versionIsOk) editor.fromJSON(state); } - var selected = editor.config.getKey('selected'); + const selected = editor.config.getKey('selected'); if (typeof selected !== 'undefined') { editor.selectByUuid(selected); @@ -66,7 +66,7 @@ export function initEditor(container) { // - var timeout; + let timeout; function saveState() { if (editor.config.getKey('autosave') === false) { @@ -85,6 +85,7 @@ export function initEditor(container) { }, 100); }, 1000); } + const stateChangedSignals = [ signals.geometryChanged, signals.objectAdded, @@ -97,7 +98,8 @@ export function initEditor(container) { signals.historyChanged, signals.detectFilterChanged, signals.scoringQuantityChanged, - signals.CSGManagerStateChanged + signals.CSGManagerStateChanged, + signals.projectChanged ]; stateChangedSignals.forEach(signal => signal.add(saveState)); }); @@ -141,11 +143,11 @@ export function initEditor(container) { // - var isLoadingFromHash = false; - var hash = window.location.hash; + let isLoadingFromHash = false; + const hash = window.location.hash; if (hash.substr(1, 5) === 'file=') { - var file = hash.substr(6); + const file = hash.substr(6); if (window.confirm('Any unsaved data will be lost. Are you sure?')) { var loader = new THREE.FileLoader();