From 85c61e042f80f5f727dca6c609d34c07c7a9ee47 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Wed, 29 Jun 2022 14:54:39 +0300 Subject: [PATCH 01/15] feat: clone atoms inside parent instead of top level --- editor/js/Menubar.Edit.js | 3 ++- editor/js/Sidebar.Scene.js | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/editor/js/Menubar.Edit.js b/editor/js/Menubar.Edit.js index cea91b86fc6d0..e7de551e050c5 100644 --- a/editor/js/Menubar.Edit.js +++ b/editor/js/Menubar.Edit.js @@ -120,12 +120,13 @@ function MenubarEdit( editor ) { option.onClick( function () { let object = editor.selected; + const originalParent = editor.selected.parent; if ( object === null || object.parent === null ) return; // avoid cloning the camera or scene object = object.clone(); - editor.execute( new AddObjectCommand( editor, object ) ); + editor.execute( new AddObjectCommand( editor, object, originalParent ) ); } ); options.add( option ); diff --git a/editor/js/Sidebar.Scene.js b/editor/js/Sidebar.Scene.js index f224ddbff3817..c9fd114e20466 100644 --- a/editor/js/Sidebar.Scene.js +++ b/editor/js/Sidebar.Scene.js @@ -2,6 +2,7 @@ import * as THREE from 'three'; import { UIPanel, UIBreak, UIRow, UIColor, UISelect, UIText, UINumber } from './libs/ui.js'; import { UIOutliner, UITexture } from './libs/ui.three.js'; +import { AddObjectCommand, RemoveObjectCommand } from './commands/Commands.js'; function SidebarScene( editor ) { @@ -349,7 +350,7 @@ function SidebarScene( editor ) { } - // Hide utility scene objects and labels from materials editor + // Hide utility scene objects and labels from materials editor if ( ! [ 'OrthographicCamera', @@ -391,15 +392,15 @@ function SidebarScene( editor ) { } else if ( value === 'Cut' ) { copiedObject = editor.selected; - editor.execute( new RemoveObjectCommand( editor.selected ) ); + editor.execute( new RemoveObjectCommand( editor, editor.selected ) ); } else if ( value === 'Delete' ) { - editor.execute( new RemoveObjectCommand( editor.selected ) ); + editor.execute( new RemoveObjectCommand( editor, editor.selected ) ); } else if ( value === 'Clone' ) { - editor.execute( new AddObjectCommand( editor.selected.clone() ) ); + editor.execute( new AddObjectCommand( editor, editor.selected.clone(), editor.selected.parent ) ); } else if ( value === 'Paste' && copiedObject !== undefined ) { @@ -409,7 +410,7 @@ function SidebarScene( editor ) { } - editor.execute( new AddObjectCommand( copiedObject, editor.selected ) ); + editor.execute( new AddObjectCommand( editor, copiedObject, editor.selected ) ); } From 71d611831bf11ac0a29980aa7c9b258757bb2e7f Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Tue, 5 Jul 2022 21:31:41 +0300 Subject: [PATCH 02/15] feat: add "multiple selection" option to toolbar --- editor/images/multiple-selection.svg | 49 +++++++++++++++++++++++++ editor/js/Config.js | 3 +- editor/js/Editor.js | 3 ++ editor/js/Sidebar.Settings.Shortcuts.js | 8 +++- editor/js/Strings.js | 3 ++ editor/js/Toolbar.js | 26 +++++++++++++ editor/js/Viewport.js | 10 ++++- 7 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 editor/images/multiple-selection.svg diff --git a/editor/images/multiple-selection.svg b/editor/images/multiple-selection.svg new file mode 100644 index 0000000000000..74df8d3e9cd7e --- /dev/null +++ b/editor/images/multiple-selection.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editor/js/Config.js b/editor/js/Config.js index c586fe86fb74d..c883496f85953 100644 --- a/editor/js/Config.js +++ b/editor/js/Config.js @@ -24,7 +24,8 @@ function Config() { 'settings/shortcuts/rotate': 'e', 'settings/shortcuts/scale': 'r', 'settings/shortcuts/undo': 'z', - 'settings/shortcuts/focus': 'f' + 'settings/shortcuts/focus': 'f', + 'settings/shortcuts/multiple-selection': 'm' }; if ( window.localStorage[ name ] === undefined ) { diff --git a/editor/js/Editor.js b/editor/js/Editor.js index 3282c13dfd1d2..7931c861ce808 100644 --- a/editor/js/Editor.js +++ b/editor/js/Editor.js @@ -19,6 +19,9 @@ function Editor( providedDefaultCamera ) { var signal = new Signal(); this.signals = { + // multipleSelection + + toggleMultipleSelection: new Signal(), // script diff --git a/editor/js/Sidebar.Settings.Shortcuts.js b/editor/js/Sidebar.Settings.Shortcuts.js index 12dccbd78ff1b..a8847f471f101 100644 --- a/editor/js/Sidebar.Settings.Shortcuts.js +++ b/editor/js/Sidebar.Settings.Shortcuts.js @@ -23,7 +23,7 @@ function SidebarSettingsShortcuts( editor ) { headerRow.add( new UIText( strings.getKey( 'sidebar/settings/shortcuts' ).toUpperCase() ) ); container.add( headerRow ); - const shortcuts = [ 'translate', 'rotate', 'scale', 'undo', 'focus' ]; + const shortcuts = [ 'translate', 'rotate', 'scale', 'multiple-selection', 'undo', 'focus' ]; function createShortcutInput( name ) { @@ -134,6 +134,12 @@ function SidebarSettingsShortcuts( editor ) { break; + case config.getKey( 'settings/shortcuts/multiple-selection' ) : + + signals.toggleMultipleSelection.dispatch(); + + break; + case config.getKey( 'settings/shortcuts/undo' ): if ( IS_MAC ? event.metaKey : event.ctrlKey ) { diff --git a/editor/js/Strings.js b/editor/js/Strings.js index af67edd890933..18fd294af05f0 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -331,6 +331,7 @@ function Strings( config ) { 'toolbar/rotate': 'Rotate', 'toolbar/scale': 'Scale', 'toolbar/local': 'Local', + 'toolbar/multiple-selection': 'Toggle multiple selection', 'viewport/info/objects': 'Objects', 'viewport/info/vertices': 'Vertices', @@ -666,6 +667,7 @@ function Strings( config ) { 'toolbar/rotate': 'Rotation', 'toolbar/scale': 'Échelle', 'toolbar/local': 'Local', + 'toolbar/multiple-selection': 'Basculer la sélection multiple', 'viewport/info/objects': 'Objets', 'viewport/info/vertices': 'Sommets', @@ -1001,6 +1003,7 @@ function Strings( config ) { 'toolbar/rotate': '旋转', 'toolbar/scale': '缩放', 'toolbar/local': '本地', + 'toolbar/multiple-selection': '切换多项选择', 'viewport/info/objects': '物体', 'viewport/info/vertices': '顶点', diff --git a/editor/js/Toolbar.js b/editor/js/Toolbar.js index 164034510363f..f328ed22a5994 100644 --- a/editor/js/Toolbar.js +++ b/editor/js/Toolbar.js @@ -6,6 +6,8 @@ const translateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNv const rotateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTI0Ny44IDQ3NC4xMmM2MS4zMTUgMCAxMTIuMDktMjYuNjkyIDE0Ny42NS01OS40OTVsLTEuNjk0NyA3NS41OGMtMC4xNzY5NyAxMC41MDkgOC4yMDYzIDE5LjE3OCAxOC43MjEgMTkuMzQ5aDAuMzIzMThjMTAuMzY0IDAgMTguODU1LTguMzE5OCAxOS4wMzMtMTguNzIxbDIuNTM4Mi0xMjYuMThjMC4wODI3LTUuMTU5Mi0xLjkyOTQtMTAuMTM1LTUuNTg0My0xMy43ODQtMy42NDkyLTMuNjQ5Mi04LjU5ODctNS42NjAzLTEzLjc4NC01LjU3MThsLTEyNi43MyAyLjUzODNjLTEwLjUwOSAwLjE4MzcxLTE4Ljg4NSA4Ljg0NjktMTguNzA4IDE5LjM2MiAwLjE3Nzk0IDEwLjQwMSA4LjY2ODkgMTguNzE0IDE5LjAzMiAxOC43MTRoMC4zMjk5MWw4My4xOTUtMS43OTU3Yy0yOS4zNSAyNy44MTUtNzIuNjU2IDUxLjkzLTEyNC4zMyA1MS45My0xMDUuOTEgMC0xNzcuMDUtOTEuNTQ4LTE3Ny4wNS0xNzcuMDUtMC4zMTcwNC0xMC4yNDgtNi4yOTUxLTE5LjI1MS0xOC41MzItMTkuNDc5LTEyLjIzNy0wLjIyNzY0LTE5LjE5NiA4LjE4MzEtMTkuNTQzIDE5LjQ4NiAwIDEwMy44OSA4Ni40NDYgMjE1LjEzIDIxNS4xMyAyMTUuMTN6bTQuMzUzOC00MzUuMjVjLTYxLjMxNSAwLTExMi4wOSAyNi42OTItMTQ3LjY1IDU5LjQ5NWwxLjY5NDctNzUuNTc5YzAuMTc2OTgtMTAuNTA5LTguMjA2My0xOS4xNzgtMTguNzIxLTE5LjM0OWgtMC4zMjMxN2MtMTAuMzY0IDAtMTguODU1IDguMzE5OC0xOS4wMzMgMTguNzIxbC0yLjUzODMgMTI2LjE4Yy0wLjA4MjcyIDUuMTU5MiAxLjkyOTQgMTAuMTM1IDUuNTg0NCAxMy43ODQgMy42NDkyIDMuNjQ5MiA4LjU5ODcgNS42NjAzIDEzLjc4NCA1LjU3MTlsMTI2LjczLTIuNTM4M2MxMC41MDktMC4xODM3MSAxOC44ODUtOC44NDY5IDE4LjcwOC0xOS4zNjItMC4xNzc5NC0xMC40MDEtOC42Njg5LTE4LjcxNC0xOS4wMzItMTguNzE0aC0wLjMyOTkxbC04My4xOTUgMS43OTU3YzI5LjM1LTI3LjgxNSA3Mi42NTYtNTEuOTMgMTI0LjMzLTUxLjkzIDEwNS45MSAwIDE3Ny4wNSA5MS41NDggMTc3LjA1IDE3Ny4wNSAwLjMxNzAzIDEwLjI0OCA2LjI5NTEgMTkuMjUxIDE4LjUzMiAxOS40NzkgMTIuMjM3IDAuMjI3NjMgMTkuMTk2LTguMTgzMSAxOS41NDMtMTkuNDg2IDAtMTAzLjg5LTg2LjQ0Ni0yMTUuMTMtMjE1LjEzLTIxNS4xM3oiLz4KPC9zdmc+Cg=='; /* '../images/scale.svg' */ const scaleImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTQ1MC4yNSA0NC4xODItMTMzLjEzIDEuMTY5OWMtOS42OTEgMC4wNzYtMTcuNDgyIDcuOTg0OS0xNy40MDYgMTcuNjcgMC4wNzYgOS42MzggMjcuMTU1IDE3LjQgMTcuNTM1IDE3LjRoMC4xMjg5bDkwLjM1LTAuODQzNzUtMTE2Ljg4IDExNi44N2MtNi44NSA2Ljg0NC02Ljg1IDE3Ljk0OSAwIDI0Ljc5MyAzLjQyNSAzLjQyNSA3LjkwNzUgNS4xMzg3IDEyLjM5NiA1LjEzODcgNC40ODMgMCA4Ljk3MzQtMS43MTM3IDEyLjM5OC01LjEzODdsMTE2Ljg3LTExNi44OC0wLjg0MTc5IDkwLjM0NGMtMC4wNyA5LjY4NSA3LjcxOTMgMTcuNTk0IDE3LjQwNCAxNy42N2gwLjEyODkxYzkuNjIgMCAxNy40NTktNy43NjI0IDE3LjUzNS0xNy40bDEuMTY4LTEzMy4xM2MxLjNlLTQgLTAuMDE2MzctMmUtMyAtMC4wMzI0Ni0yZS0zIC0wLjA0ODgzIDNlLTMgLTAuNTE0NzEtMC4wMjM5LTEuMDI5Ny0wLjA2NjQtMS41NDMtNGUtMyAtMC4wNTMyNS05LjZlLTQgLTAuMTA2OTUtNmUtMyAtMC4xNjAxNi0yLjRlLTQgLTAuMDAyNy0yZS0zIC0wLjAwNTEtMmUtMyAtMC4wMDc4LTAuMjYyMjQtMi44MzQ1LTEuMjEzMi01LjYxNDUtMi44NTE2LTguMDc0Mi0wLjMxODc2LTAuNDc4NTgtMC42NjIzNS0wLjk0NjMxLTEuMDMzMi0xLjM5ODQtMC4zNjgzMS0wLjQ1MDI5LTAuNzYwNzktMC44ODM4My0xLjE3NTgtMS4yOTg4LTAuNDE2NTgtMC40MTczNS0wLjg1MjE4LTAuODExNTYtMS4zMDQ3LTEuMTgxNi0wLjI0MTc2LTAuMTk4MDQtMC40OTY1Ni0wLjM2OTU3LTAuNzQ2MS0wLjU1MjczLTAuMjE1MTQtMC4xNTc2Mi0wLjQyMjkzLTAuMzI1MzgtMC42NDQ1My0wLjQ3MjY2LTAuMzU2MTQtMC4yMzcyMy0wLjcyNDk0LTAuNDQ1OS0xLjA5MzgtMC42NTQzLTAuMTI1NzQtMC4wNzA5Ni0wLjI0NTY3LTAuMTUyOTItMC4zNzMwNC0wLjIyMDctMC40MjQ4MS0wLjIyNjMxLTAuODYwNTktMC40MjQ0Mi0xLjI5ODgtMC42MTMyOC0wLjA4MjQtMC4wMzU1NC0wLjE2MTE3LTAuMDc5MDEtMC4yNDQxNC0wLjExMzI4LTAuNDI3MDYtMC4xNzYyOS0wLjg2MTgxLTAuMzI1NzEtMS4yOTg4LTAuNDY2OC0wLjEwNzYxLTAuMDM0ODMtMC4yMTIwMS0wLjA3ODU4LTAuMzIwMzEtMC4xMTEzMy0wLjM3NjA0LTAuMTEzNDEtMC43NTcyNC0wLjE5OTUyLTEuMTM4Ny0wLjI4NzExLTAuMTgwNDQtMC4wNDE2MS0wLjM1NzE1LTAuMDk0OTQtMC41MzkwNi0wLjEzMDg2LTAuMzA4NjctMC4wNjA2OC0wLjYyMDcxLTAuMDk0NzEtMC45MzE2NC0wLjEzODY3LTAuMjU2NzktMC4wMzY1MS0wLjUxMDYyLTAuMDg2Mi0wLjc2OTUzLTAuMTExMzMtMC41NjMxOS0wLjA1NDQtMS4xMjgtMC4wODM5NC0xLjY5MzQtMC4wODM5OHptLTM4Ny40NSAyNTUuNjJjLTkuNjIgMC0xNy40NTkgNy43NjYzLTE3LjUzNSAxNy40MDRsLTEuMTY5OSAxMzMuMTJjLTEuMjJlLTQgMC4wMTY0IDJlLTMgMC4wMzI1IDJlLTMgMC4wNDg4LTAuMDAyNSAwLjUxMzk1IDAuMDIzOTUgMS4wMjg1IDAuMDY2NDEgMS41NDEgMC4wMDQ2IDAuMDU1NyAwLjAwMjYgMC4xMTIzMyAwLjAwNzggMC4xNjc5NyAwLjMxMjk5IDMuMzg1NSAxLjYwNTkgNi42OTUgMy44ODA5IDkuNDcyNyAwLjM2NjYgMC40NDc2MSAwLjc1NjI4IDAuODgyODcgMS4xNzM4IDEuMzAwOGgyZS0zYzAuMjA3MzEgMC4yMDcyOCAwLjQyOTY2IDAuMzg5MjUgMC42NDQ1MyAwLjU4Mzk4IDAuMjE3OTUgMC4xOTc1NSAwLjQyNzY0IDAuNDA2MjYgMC42NTQzIDAuNTkxOCAwLjI5Nzg5IDAuMjQ0MTcgMC42MTAyOCAwLjQ2MDA0IDAuOTE5OTIgMC42ODE2NCAwLjE1OTE5IDAuMTEzNzMgMC4zMTAwNCAwLjIzOTUyIDAuNDcyNjYgMC4zNDc2NiAwLjM3NDU0IDAuMjQ5NTQgMC43NjE4NSAwLjQ2OTgzIDEuMTUwNCAwLjY4NzUgMC4xMDg5NyAwLjA2MSAwLjIxMjA4IDAuMTMyOCAwLjMyMjI3IDAuMTkxNCAwLjM4NzI2IDAuMjA2MTYgMC43ODUwNiAwLjM4MzUzIDEuMTgzNiAwLjU1ODYgMC4xMjU1MiAwLjA1NTIgMC4yNDYyOCAwLjEyMTYxIDAuMzczMDUgMC4xNzM4MiAwLjM2OTA4IDAuMTUxODcgMC43NDY0MiAwLjI3NjczIDEuMTIzIDAuNDAyMzUgMC4xNjY0NSAwLjA1NTYgMC4zMjc5NiAwLjEyMzE4IDAuNDk2MDkgMC4xNzM4MyAwLjQ2OTU2IDAuMTQxMTEgMC45NDQxNyAwLjI1NDU0IDEuNDIxOSAwLjM1NTQ3IDAuMDcyODUgMC4wMTU0IDAuMTQzNzIgMC4wMzgyIDAuMjE2OCAwLjA1MjcgMC40NjgyIDAuMDkyNyAwLjk0MTAyIDAuMTU2NjYgMS40MTQxIDAuMjEwOTQgMC4wOTgyMSAwLjAxMTMgMC4xOTQ0NiAwLjAzMTMgMC4yOTI5NyAwLjA0MSAwLjU3MDc2IDAuMDU1OCAxLjY3ODMtMC40ODU3OCAxLjcxNjggMC4wODU5aDAuMTM0NzdsMTMzLjEzLTEuMTY5OWM5LjY4NS0wLjA3IDE3LjQ3Ni03Ljk4MzEgMTcuNC0xNy42NjItMC4wNzYtOS42OS04LjEyNTktMTcuMzg3LTE3LjY3LTE3LjQwNGwtOTAuMzM4IDAuODM5OTYgMTE2Ljg3LTExNi44N2M2Ljg0NC02Ljg0NCA2Ljg1LTE3Ljk0MyAwLTI0Ljc5M3MtMTcuOTU1LTYuODUtMjQuNzk5IDBsLTExNi44NyAxMTYuODYgMC44NDM3NS05MC4zNDRjMC4wNzYtOS42NzktNy43MTU0LTE3LjU4Ni0xNy40LTE3LjY2MnoiLz4KPC9zdmc+Cg=='; +/* '../images/multiple-selection.svg' */ +const multipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIxMC40MTYgMjEwLjQxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEwLjQxNiAyMTAuNDE2OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTIwNi41MTksMTU1Ljg2M2gtMTkuNDgzVjU0LjU1MmgxOS40ODFjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzLjg5N2MwLTIuMTUyLTEuNzQ1LTMuODk3LTMuODk3LTMuODk3aC00Ni43NTkNCgkJCWMtMi4xNTIsMC0zLjg5NywxLjc0NS0zLjg5NywzLjg5N1YyMy4zOEg1NC41NTJWMy44OTdDNTQuNTUyLDEuNzQ1LDUyLjgwNywwLDUwLjY1NSwwSDMuODk3QzEuNzQ1LDAsMCwxLjc0NSwwLDMuODk3djQ2Ljc1OQ0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdIMjMuMzh2MTAxLjMxSDMuODk3Yy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djQ2Ljc1OWMwLDIuMTUyLDEuNzQ1LDMuODk3LDMuODk3LDMuODk3DQoJCQloNDYuNzU5YzIuMTUyLDAsMy44OTctMS43NDUsMy44OTctMy44OTd2LTE5LjQ4M2gxMDEuMzF2MTkuNDgzYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoNDYuNzU5DQoJCQljMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YxNTkuNzZDMjEwLjQxNiwxNTcuNjA4LDIwOC42NzEsMTU1Ljg2MywyMDYuNTE5LDE1NS44NjN6IE0yMDIuNjIxLDcuNzkzdjM4Ljk2NmgtMTUuNTg2aC03Ljc5Mw0KCQkJaC0xNS41ODZWMzEuMTcydi03Ljc5M1Y3Ljc5M0gyMDIuNjIxeiBNMjMuMzc5LDQ2Ljc1OEg3Ljc5M1Y3Ljc5M2gzOC45NjZ2MTUuNTg2djcuNzkzdjE1LjU4NkgzMS4xNzJIMjMuMzc5eiBNNy43OTMsMjAyLjYyMQ0KCQkJdi0zOC45NjZoMTUuNTg2aDcuNzkzaDE1LjU4NnYxNS41ODZ2Ny43OTN2MTUuNTg3SDcuNzkzeiBNMTU5Ljc1OCwxNTUuODYyYy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djE5LjQ4M0g1NC41NTINCgkJCXYtMTkuNDgzYzAtMi4xNTItMS43NDUtMy44OTctMy44OTctMy44OTdIMzEuMTcyVjU0LjU1MmgxOS40ODNjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzMS4xNzJoMTAxLjMxdjE5LjQ4Mw0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoMTkuNDgzdjEwMS4zMWgtMC4wMDFIMTU5Ljc1OHogTTIwMi42MjEsMjAyLjYyMWgtMzguOTY2di0xNS41ODZ2LTcuNzkzdi0xNS41ODZoMTUuNTg2aDcuNzkzDQoJCQloMTUuNTg3VjIwMi42MjF6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; function Toolbar( editor ) { @@ -57,6 +59,19 @@ function Toolbar( editor ) { } ); container.add( scale ); + const multipleSelectionIcon = document.createElement( 'img' ); + multipleSelectionIcon.title = strings.getKey( 'toolbar/multiple-selection' ); + multipleSelectionIcon.src = multipleSelectionImg; + + const multipleSelection = new UIButton(); + multipleSelection.dom.appendChild( multipleSelectionIcon ); + multipleSelection.onClick( function () { + + signals.toggleMultipleSelection.dispatch( 'multiple-selection' ); + + } ); + container.add( multipleSelection ); + const local = new UICheckbox( false ); local.dom.title = strings.getKey( 'toolbar/local' ); local.onChange( function () { @@ -73,6 +88,7 @@ function Toolbar( editor ) { translate.dom.classList.remove( 'selected' ); rotate.dom.classList.remove( 'selected' ); scale.dom.classList.remove( 'selected' ); + multipleSelection.dom.classList.remove( 'selected' ); switch ( mode ) { @@ -84,6 +100,16 @@ function Toolbar( editor ) { } ); + signals.toggleMultipleSelection.add( function () { + + translate.dom.classList.remove( 'selected' ); + rotate.dom.classList.remove( 'selected' ); + scale.dom.classList.remove( 'selected' ); + + multipleSelection.dom.classList.toggle( 'selected' ); + + } ); + return container; } diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index ccbaa00141205..91f5eaea69070 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -55,7 +55,7 @@ function Viewport( editor ) { grid.rotateX( Math.PI / 2 ); - // additioanl axis lines for usability considerations + // additioanl axis lines for usability considerations const length = 30; const lineMaterial = new THREE.LineDashedMaterial( { dashSize: 1, @@ -333,6 +333,8 @@ function Viewport( editor ) { const controls = new EditorControls( camera, container.dom ); controls.addEventListener( 'change', function () { + console.log( { camera } ); + signals.cameraChanged.dispatch( camera ); signals.refreshSidebarObject3D.dispatch( camera ); @@ -348,6 +350,12 @@ function Viewport( editor ) { } ); + signals.toggleMultipleSelection.add( function () { + + console.log( 'toggle multiple selection' ); + + } ); + signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); From 2eead04f6a72cad39122fa6141509a96ae46e2fb Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Thu, 7 Jul 2022 21:57:17 +0300 Subject: [PATCH 03/15] feat: basic implementation of capturing selected data --- editor/js/Viewport.js | 9 +- .../multiple-selection/multiple-selection.js | 98 +++++++++++++++++++ .../multiple-selection/selection-drawer.js | 81 +++++++++++++++ 3 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 editor/js/libs/multiple-selection/multiple-selection.js create mode 100644 editor/js/libs/multiple-selection/selection-drawer.js diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 91f5eaea69070..69eb1414621c3 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -16,6 +16,7 @@ import { SetRotationCommand } from './commands/SetRotationCommand.js'; import { SetScaleCommand } from './commands/SetScaleCommand.js'; import { RoomEnvironment } from '../../examples/jsm/environments/RoomEnvironment.js'; +import { MultipleSelection } from './libs/multiple-selection/multiple-selection.js'; function Viewport( editor ) { @@ -90,6 +91,8 @@ function Viewport( editor ) { selectionBox.visible = false; sceneHelpers.add( selectionBox ); + const multipleSelection = new MultipleSelection( editor.viewportCamera, scene ); + let objectPositionOnDown = null; let objectRotationOnDown = null; let objectScaleOnDown = null; @@ -333,8 +336,6 @@ function Viewport( editor ) { const controls = new EditorControls( camera, container.dom ); controls.addEventListener( 'change', function () { - console.log( { camera } ); - signals.cameraChanged.dispatch( camera ); signals.refreshSidebarObject3D.dispatch( camera ); @@ -352,7 +353,8 @@ function Viewport( editor ) { signals.toggleMultipleSelection.add( function () { - console.log( 'toggle multiple selection' ); + multipleSelection.toggle(); + controls.enabled = ! multipleSelection.enabled; } ); @@ -406,6 +408,7 @@ function Viewport( editor ) { renderer.setAnimationLoop( animate ); renderer.setClearColor( 0xaaaaaa ); + multipleSelection.renderer = renderer; if ( window.matchMedia ) { diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js new file mode 100644 index 0000000000000..31f17c73d8518 --- /dev/null +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -0,0 +1,98 @@ +import { SelectionBox } from '../../../../examples/jsm/interactive/SelectionBox.js'; +import { SelectionDrawer } from './selection-drawer.js'; + +class MultipleSelection { + + constructor( camera, scene, renderer ) { + + this.enabled = false; + this._camera = camera; + this._scene = scene; + this._renderer = renderer; + this._selectionDrawer = null; + this._selectionBox = null; + + console.log( this.enabled, this._camera, this._scene, this._renderer ); + + } + + set renderer( renderer ) { + + console.log( { renderer } ); + + this._renderer = renderer; + + } + + toggle() { + + this.enabled = ! this.enabled; + + if ( this.enabled ) { + + this._selectionBox = new SelectionBox( this._camera, this._scene ); + this._selectionDrawer = new SelectionDrawer( this._renderer, 'selectBox' ); + + document.addEventListener( 'pointerdown', this._pointerDown ); + document.addEventListener( 'pointerup', this._pointerUp ); + + } else { + + this._selectionBox = null; + this._selectionDrawer = null; + + document.removeEventListener( 'pointerdown', this._pointerDown ); + document.removeEventListener( 'pointerup', this._pointerUp ); + + } + + } + + _pointerDown = ( event ) => { + + this._selectionDrawer.onPointerDown( event ); + + this._selectionBox.startPoint.set( + ( event.clientX / window.innerWidth ) * 2 - 1, + - ( event.clientY / window.innerHeight ) * 2 + 1, + 0.5 ); + + console.log( 'pointerdown', event ); + + document.addEventListener( 'pointermove', this._pointerMove ); + + }; + + _pointerMove = ( event ) => { + + this._selectionDrawer.onPointerMove( event ); + + this._selectionBox.endPoint.set( + ( event.clientX / window.innerWidth ) * 2 - 1, + - ( event.clientY / window.innerHeight ) * 2 + 1, + 0.5 ); + + console.log( 'pointermove', event ); + + }; + + _pointerUp = ( event ) => { + + this._selectionDrawer.onPointerUp(); + + this._selectionBox.endPoint.set( + ( event.clientX / window.innerWidth ) * 2 - 1, + - ( event.clientY / window.innerHeight ) * 2 + 1, + 0.5 ); + + const intersectedMeshes = this._selectionBox.select(); + + alert( 'Intersected meshes: ' + ( intersectedMeshes.map( m => m.name ).join( ',' ) || 'Not Found' ) ); + + document.removeEventListener( 'pointermove', this._pointerMove ); + + }; + +} + +export { MultipleSelection }; diff --git a/editor/js/libs/multiple-selection/selection-drawer.js b/editor/js/libs/multiple-selection/selection-drawer.js new file mode 100644 index 0000000000000..7736d9195af90 --- /dev/null +++ b/editor/js/libs/multiple-selection/selection-drawer.js @@ -0,0 +1,81 @@ +import { Vector2 } from 'three'; + +class SelectionDrawer { + + constructor( renderer, cssClassName ) { + + this.element = document.createElement( 'div' ); + this.element.classList.add( cssClassName ); + this.element.style.pointerEvents = 'none'; + + this.renderer = renderer; + + this.startPoint = new Vector2(); + this.pointTopLeft = new Vector2(); + this.pointBottomRight = new Vector2(); + + this.isDown = false; + + this.onPointerDown = function ( event ) { + + this.isDown = true; + this.onSelectStart( event ); + + }.bind( this ); + + this.onPointerMove = function ( event ) { + + if ( this.isDown ) { + + this.onSelectMove( event ); + + } + + }.bind( this ); + + this.onPointerUp = function ( ) { + + this.isDown = false; + this.onSelectOver(); + + }.bind( this ); + + } + + onSelectStart( event ) { + + this.renderer.domElement.parentElement.appendChild( this.element ); + + this.element.style.left = event.clientX + 'px'; + this.element.style.top = event.clientY + 'px'; + this.element.style.width = '0px'; + this.element.style.height = '0px'; + + this.startPoint.x = event.clientX; + this.startPoint.y = event.clientY; + + } + + onSelectMove( event ) { + + this.pointBottomRight.x = Math.max( this.startPoint.x, event.clientX ); + this.pointBottomRight.y = Math.max( this.startPoint.y, event.clientY ); + this.pointTopLeft.x = Math.min( this.startPoint.x, event.clientX ); + this.pointTopLeft.y = Math.min( this.startPoint.y, event.clientY ); + + this.element.style.left = this.pointTopLeft.x + 'px'; + this.element.style.top = this.pointTopLeft.y + 'px'; + this.element.style.width = ( this.pointBottomRight.x - this.pointTopLeft.x ) + 'px'; + this.element.style.height = ( this.pointBottomRight.y - this.pointTopLeft.y ) + 'px'; + + } + + onSelectOver() { + + this.element.parentElement.removeChild( this.element ); + + } + +} + +export { SelectionDrawer }; From 3e8e431abbef333366f6740261ecffd72154a56b Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Tue, 12 Jul 2022 19:33:35 +0300 Subject: [PATCH 04/15] feat: create a group from multiple selection captured items --- editor/js/Viewport.js | 14 ++++- .../multiple-selection/multiple-selection.js | 57 ++++++++++++++++--- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 69eb1414621c3..2b1935cd45bc6 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -17,6 +17,7 @@ import { SetScaleCommand } from './commands/SetScaleCommand.js'; import { RoomEnvironment } from '../../examples/jsm/environments/RoomEnvironment.js'; import { MultipleSelection } from './libs/multiple-selection/multiple-selection.js'; +import { AddObjectCommand } from './commands/AddObjectCommand.js'; function Viewport( editor ) { @@ -92,6 +93,17 @@ function Viewport( editor ) { sceneHelpers.add( selectionBox ); const multipleSelection = new MultipleSelection( editor.viewportCamera, scene ); + multipleSelection.addEventListener( 'pointerup', ( selectedMeshes ) => { + + if ( ! selectedMeshes.length ) return; + + const group = new THREE.Group(); + group.name = 'Multiple Selection Group'; + selectedMeshes.forEach( mesh => group.add( mesh ) ); + + editor.execute( new AddObjectCommand( editor, group ) ); + + } ); let objectPositionOnDown = null; let objectRotationOnDown = null; @@ -114,7 +126,7 @@ function Viewport( editor ) { } - signals.refreshSidebarObject3D.dispatch( object ); + signals.sceneGraphChanged.dispatch( ); } diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js index 31f17c73d8518..97efe4c8954d3 100644 --- a/editor/js/libs/multiple-selection/multiple-selection.js +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -1,3 +1,4 @@ +import { Object3D } from 'three'; import { SelectionBox } from '../../../../examples/jsm/interactive/SelectionBox.js'; import { SelectionDrawer } from './selection-drawer.js'; @@ -11,15 +12,15 @@ class MultipleSelection { this._renderer = renderer; this._selectionDrawer = null; this._selectionBox = null; - - console.log( this.enabled, this._camera, this._scene, this._renderer ); + this._selectedMeshes = []; + this._pointerUpCustomCallback = null; + this._pointerDownCustomCallback = null; + this._pointerMoveCustomCallback = null; } set renderer( renderer ) { - console.log( { renderer } ); - this._renderer = renderer; } @@ -48,6 +49,32 @@ class MultipleSelection { } + addEventListener( event, callback ) { + + switch ( event ) { + + case 'pointerup': + this._pointerUpCustomCallback = callback; + break; + case 'pointerdown': + this._pointerDownCustomCallback = callback; + break; + case 'pointermove': + this._pointerMoveCustomCallback = callback; + break; + default: + break; + + } + + } + + _keepOnlyMeshes( sceneObjects ) { + + return sceneObjects.filter( object => object instanceof Object3D && object.isMesh ); + + } + _pointerDown = ( event ) => { this._selectionDrawer.onPointerDown( event ); @@ -57,7 +84,11 @@ class MultipleSelection { - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); - console.log( 'pointerdown', event ); + if ( this._pointerDownCustomCallback ) { + + this._pointerDownCustomCallback( event ); + + } document.addEventListener( 'pointermove', this._pointerMove ); @@ -72,7 +103,13 @@ class MultipleSelection { - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); - console.log( 'pointermove', event ); + this._selectedMeshes = this._keepOnlyMeshes( this._selectionBox.select() ); + + if ( this._pointerMoveCustomCallback ) { + + this._pointerMoveCustomCallback( this._selectedMeshes ); + + } }; @@ -85,9 +122,13 @@ class MultipleSelection { - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); - const intersectedMeshes = this._selectionBox.select(); + this._selectedMeshes = this._keepOnlyMeshes( this._selectionBox.select() ); + + if ( this._pointerUpCustomCallback ) { - alert( 'Intersected meshes: ' + ( intersectedMeshes.map( m => m.name ).join( ',' ) || 'Not Found' ) ); + this._pointerUpCustomCallback( this._selectedMeshes ); + + } document.removeEventListener( 'pointermove', this._pointerMove ); From b4bef633c8b5c294feb79e2ccba4b4f175d0da26 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Tue, 12 Jul 2022 22:11:08 +0300 Subject: [PATCH 05/15] feat: keep only one instance of active multiple selection group --- editor/js/Viewport.js | 34 ++++++++++- .../multiple-selection/multiple-selection.js | 57 ++++++++++++++++--- 2 files changed, 81 insertions(+), 10 deletions(-) diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 2b1935cd45bc6..4a10da8a443d7 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -18,6 +18,7 @@ import { SetScaleCommand } from './commands/SetScaleCommand.js'; import { RoomEnvironment } from '../../examples/jsm/environments/RoomEnvironment.js'; import { MultipleSelection } from './libs/multiple-selection/multiple-selection.js'; import { AddObjectCommand } from './commands/AddObjectCommand.js'; +import { RemoveObjectCommand } from './commands/Commands.js'; function Viewport( editor ) { @@ -93,9 +94,34 @@ function Viewport( editor ) { sceneHelpers.add( selectionBox ); const multipleSelection = new MultipleSelection( editor.viewportCamera, scene ); + + multipleSelection.addEventListener( 'pointerdown', () => { + + const group = scene.getObjectByName( 'Multiple Selection Group' ); + + if ( group ) { + + editor.execute( new RemoveObjectCommand( editor, group ) ); + + } + + } ); + multipleSelection.addEventListener( 'pointerup', ( selectedMeshes ) => { - if ( ! selectedMeshes.length ) return; + if ( ! selectedMeshes.length ) { + + const previousMultipleSelectionGroup = scene.getObjectByName( 'Multiple Selection Group' ); + + if ( previousMultipleSelectionGroup ) { + + editor.execute( new RemoveObjectCommand( editor, previousMultipleSelectionGroup ) ); + + } + + return; + + } const group = new THREE.Group(); group.name = 'Multiple Selection Group'; @@ -105,6 +131,12 @@ function Viewport( editor ) { } ); + multipleSelection.addEventListener( 'pointermove', ( ) => { + + console.log( 'pointermove' ); + + } ); + let objectPositionOnDown = null; let objectRotationOnDown = null; let objectScaleOnDown = null; diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js index 97efe4c8954d3..4ebfaed8ce89a 100644 --- a/editor/js/libs/multiple-selection/multiple-selection.js +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -13,6 +13,7 @@ class MultipleSelection { this._selectionDrawer = null; this._selectionBox = null; this._selectedMeshes = []; + this._hiddenOriginalMeshes = []; this._pointerUpCustomCallback = null; this._pointerDownCustomCallback = null; this._pointerMoveCustomCallback = null; @@ -34,16 +35,16 @@ class MultipleSelection { this._selectionBox = new SelectionBox( this._camera, this._scene ); this._selectionDrawer = new SelectionDrawer( this._renderer, 'selectBox' ); - document.addEventListener( 'pointerdown', this._pointerDown ); - document.addEventListener( 'pointerup', this._pointerUp ); + this._renderer.domElement.parentElement.addEventListener( 'pointerdown', this._pointerDown ); + this._renderer.domElement.parentElement.addEventListener( 'pointerup', this._pointerUp ); } else { this._selectionBox = null; this._selectionDrawer = null; - document.removeEventListener( 'pointerdown', this._pointerDown ); - document.removeEventListener( 'pointerup', this._pointerUp ); + this._renderer.domElement.parentElement.removeEventListener( 'pointerdown', this._pointerDown ); + this._renderer.domElement.parentElement.removeEventListener( 'pointerup', this._pointerUp ); } @@ -69,6 +70,42 @@ class MultipleSelection { } + _displayOriginalMeshes() { + + this._hiddenOriginalMeshes.forEach( mesh => { + + mesh.visible = true; + + } ); + + this._hiddenOriginalMeshes = []; + + } + + _hideOriginalMeshes( clonedMeshes ) { + + clonedMeshes.forEach( mesh => { + + mesh._original_mesh.visible = false; + this._hiddenOriginalMeshes.push( mesh._original_mesh ); + + } ); + + } + + _cloneMeshes( meshes ) { + + return meshes.map( mesh => { + + const clone = mesh.clone(); + clone._original_mesh = mesh; + + return clone; + + } ); + + } + _keepOnlyMeshes( sceneObjects ) { return sceneObjects.filter( object => object instanceof Object3D && object.isMesh ); @@ -77,6 +114,8 @@ class MultipleSelection { _pointerDown = ( event ) => { + this._displayOriginalMeshes(); + this._selectionDrawer.onPointerDown( event ); this._selectionBox.startPoint.set( @@ -90,7 +129,7 @@ class MultipleSelection { } - document.addEventListener( 'pointermove', this._pointerMove ); + this._renderer.domElement.parentElement.addEventListener( 'pointermove', this._pointerMove ); }; @@ -103,8 +142,6 @@ class MultipleSelection { - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); - this._selectedMeshes = this._keepOnlyMeshes( this._selectionBox.select() ); - if ( this._pointerMoveCustomCallback ) { this._pointerMoveCustomCallback( this._selectedMeshes ); @@ -122,7 +159,9 @@ class MultipleSelection { - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); - this._selectedMeshes = this._keepOnlyMeshes( this._selectionBox.select() ); + this._selectedMeshes = this._cloneMeshes( this._keepOnlyMeshes( this._selectionBox.select() ) ); + + this._hideOriginalMeshes( this._selectedMeshes ); if ( this._pointerUpCustomCallback ) { @@ -130,7 +169,7 @@ class MultipleSelection { } - document.removeEventListener( 'pointermove', this._pointerMove ); + this._renderer.domElement.parentElement.removeEventListener( 'pointermove', this._pointerMove ); }; From db4d7306011fabfa04d86e88400cc08f5707e504 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Thu, 14 Jul 2022 20:45:38 +0300 Subject: [PATCH 06/15] fix: selection accuracy issue --- .../multiple-selection/multiple-selection.js | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js index 4ebfaed8ce89a..f6bffbe19b9ee 100644 --- a/editor/js/libs/multiple-selection/multiple-selection.js +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -112,16 +112,26 @@ class MultipleSelection { } + _getCursorPosition( event ) { + + const rect = event.target.getBoundingClientRect(); + + const x = ( ( event.clientX - rect.x ) / rect.width ) * 2 - 1; + const y = - ( ( event.clientY - rect.y ) / rect.height ) * 2 + 1; + + return { x, y }; + + } + _pointerDown = ( event ) => { this._displayOriginalMeshes(); this._selectionDrawer.onPointerDown( event ); - this._selectionBox.startPoint.set( - ( event.clientX / window.innerWidth ) * 2 - 1, - - ( event.clientY / window.innerHeight ) * 2 + 1, - 0.5 ); + const cursorPosition = this._getCursorPosition( event ); + + this._selectionBox.startPoint.set( cursorPosition.x, cursorPosition.y, 0.5 ); if ( this._pointerDownCustomCallback ) { @@ -137,10 +147,9 @@ class MultipleSelection { this._selectionDrawer.onPointerMove( event ); - this._selectionBox.endPoint.set( - ( event.clientX / window.innerWidth ) * 2 - 1, - - ( event.clientY / window.innerHeight ) * 2 + 1, - 0.5 ); + const cursorPosition = this._getCursorPosition( event ); + + this._selectionBox.endPoint.set( cursorPosition.x, cursorPosition.y, 0.5 ); if ( this._pointerMoveCustomCallback ) { @@ -154,10 +163,9 @@ class MultipleSelection { this._selectionDrawer.onPointerUp(); - this._selectionBox.endPoint.set( - ( event.clientX / window.innerWidth ) * 2 - 1, - - ( event.clientY / window.innerHeight ) * 2 + 1, - 0.5 ); + const cursorPosition = this._getCursorPosition( event ); + + this._selectionBox.endPoint.set( cursorPosition.x, cursorPosition.y, 0.5 ); this._selectedMeshes = this._cloneMeshes( this._keepOnlyMeshes( this._selectionBox.select() ) ); From b1af054f3e3421e3c1cb53d15a8d9fbd5ac9e012 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Thu, 14 Jul 2022 20:55:05 +0300 Subject: [PATCH 07/15] feat: add "submit" and "cancel" buttons for selection process --- editor/js/Editor.js | 2 + editor/js/Toolbar.js | 4 +- editor/js/Viewport.js | 48 +++++----- .../js/commands/AddMultipleSelectionGroup.js | 28 ++++++ editor/js/commands/Commands.js | 2 + .../commands/RemoveMultipleSelectionGroup.js | 28 ++++++ .../multiple-selection/multiple-selection.js | 89 ++++++++++++++++--- 7 files changed, 167 insertions(+), 34 deletions(-) create mode 100644 editor/js/commands/AddMultipleSelectionGroup.js create mode 100644 editor/js/commands/RemoveMultipleSelectionGroup.js diff --git a/editor/js/Editor.js b/editor/js/Editor.js index 7931c861ce808..c296c0e187cfa 100644 --- a/editor/js/Editor.js +++ b/editor/js/Editor.js @@ -22,6 +22,8 @@ function Editor( providedDefaultCamera ) { // multipleSelection toggleMultipleSelection: new Signal(), + enableMultipleSelection: new Signal(), + disableMultipleSelection: new Signal(), // script diff --git a/editor/js/Toolbar.js b/editor/js/Toolbar.js index f328ed22a5994..d8ca7991ffd4b 100644 --- a/editor/js/Toolbar.js +++ b/editor/js/Toolbar.js @@ -67,7 +67,7 @@ function Toolbar( editor ) { multipleSelection.dom.appendChild( multipleSelectionIcon ); multipleSelection.onClick( function () { - signals.toggleMultipleSelection.dispatch( 'multiple-selection' ); + signals.toggleMultipleSelection.dispatch(); } ); container.add( multipleSelection ); @@ -90,6 +90,8 @@ function Toolbar( editor ) { scale.dom.classList.remove( 'selected' ); multipleSelection.dom.classList.remove( 'selected' ); + signals.disableMultipleSelection.dispatch(); + switch ( mode ) { case 'translate': translate.dom.classList.add( 'selected' ); break; diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 4a10da8a443d7..b2d170bf577e1 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -17,8 +17,7 @@ import { SetScaleCommand } from './commands/SetScaleCommand.js'; import { RoomEnvironment } from '../../examples/jsm/environments/RoomEnvironment.js'; import { MultipleSelection } from './libs/multiple-selection/multiple-selection.js'; -import { AddObjectCommand } from './commands/AddObjectCommand.js'; -import { RemoveObjectCommand } from './commands/Commands.js'; +import { AddMultipleSelectionGroup, RemoveMultipleSelectionGroup } from './commands/Commands.js'; function Viewport( editor ) { @@ -97,13 +96,9 @@ function Viewport( editor ) { multipleSelection.addEventListener( 'pointerdown', () => { - const group = scene.getObjectByName( 'Multiple Selection Group' ); + editor.execute( new RemoveMultipleSelectionGroup( editor ) ); - if ( group ) { - - editor.execute( new RemoveObjectCommand( editor, group ) ); - - } + multipleSelection.hideControlButtons(); } ); @@ -111,29 +106,23 @@ function Viewport( editor ) { if ( ! selectedMeshes.length ) { - const previousMultipleSelectionGroup = scene.getObjectByName( 'Multiple Selection Group' ); - - if ( previousMultipleSelectionGroup ) { - - editor.execute( new RemoveObjectCommand( editor, previousMultipleSelectionGroup ) ); - - } + editor.execute( new RemoveMultipleSelectionGroup( editor ) ); return; } - const group = new THREE.Group(); - group.name = 'Multiple Selection Group'; - selectedMeshes.forEach( mesh => group.add( mesh ) ); + editor.execute( new AddMultipleSelectionGroup( editor, selectedMeshes ) ); - editor.execute( new AddObjectCommand( editor, group ) ); + multipleSelection.showControlButtons(); } ); - multipleSelection.addEventListener( 'pointermove', ( ) => { + multipleSelection.addEventListener( 'cancel-selection', () => { + + editor.execute( new RemoveMultipleSelectionGroup( editor ) ); - console.log( 'pointermove' ); + multipleSelection.hideControlButtons(); } ); @@ -397,11 +386,26 @@ function Viewport( editor ) { signals.toggleMultipleSelection.add( function () { + multipleSelection.toggle(); controls.enabled = ! multipleSelection.enabled; } ); + signals.enableMultipleSelection.add( function () { + + multipleSelection.enable(); + controls.enabled = false; + + } ); + + signals.disableMultipleSelection.add( function () { + + multipleSelection.disable(); + controls.enabled = true; + + } ); + signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); @@ -562,6 +566,8 @@ function Viewport( editor ) { signals.objectRemoved.add( function ( object ) { + if ( multipleSelection.enabled ) return; + controls.enabled = true; // see #14180 if ( object === transformControls.object ) { diff --git a/editor/js/commands/AddMultipleSelectionGroup.js b/editor/js/commands/AddMultipleSelectionGroup.js new file mode 100644 index 0000000000000..c951a3d23916b --- /dev/null +++ b/editor/js/commands/AddMultipleSelectionGroup.js @@ -0,0 +1,28 @@ +import { Group } from 'three'; +import { Command } from '../Command.js'; +import { AddObjectCommand } from './AddObjectCommand.js'; + +class AddMultipleSelectionGroup extends Command { + + constructor( editor, meshes ) { + + super( editor ); + + this.type = 'AddMultipleSelectionGroup'; + this.meshes = meshes; + + } + + execute() { + + const group = new Group(); + group.name = 'Multiple Selection Group'; + this.meshes.forEach( mesh => group.add( mesh ) ); + + this.editor.execute( new AddObjectCommand( this.editor, group ) ); + + } + +} + +export { AddMultipleSelectionGroup }; diff --git a/editor/js/commands/Commands.js b/editor/js/commands/Commands.js index 40dd6ec045f27..5b6158c8cf3f9 100644 --- a/editor/js/commands/Commands.js +++ b/editor/js/commands/Commands.js @@ -19,3 +19,5 @@ export { SetSceneCommand } from './SetSceneCommand.js'; export { SetScriptValueCommand } from './SetScriptValueCommand.js'; export { SetUuidCommand } from './SetUuidCommand.js'; export { SetValueCommand } from './SetValueCommand.js'; +export { RemoveMultipleSelectionGroup } from './RemoveMultipleSelectionGroup.js'; +export { AddMultipleSelectionGroup } from './AddMultipleSelectionGroup.js'; diff --git a/editor/js/commands/RemoveMultipleSelectionGroup.js b/editor/js/commands/RemoveMultipleSelectionGroup.js new file mode 100644 index 0000000000000..0131fb40e8e1a --- /dev/null +++ b/editor/js/commands/RemoveMultipleSelectionGroup.js @@ -0,0 +1,28 @@ +import { Command } from '../Command.js'; +import { RemoveObjectCommand } from './RemoveObjectCommand.js'; + +class RemoveMultipleSelectionGroup extends Command { + + constructor( editor ) { + + super( editor ); + + this.type = 'RemoveMultipleSelectionGroup'; + + } + + execute() { + + const group = this.editor.scene.getObjectByName( 'Multiple Selection Group' ); + + if ( group ) { + + this.editor.execute( new RemoveObjectCommand( this.editor, group ) ); + + } + + } + +} + +export { RemoveMultipleSelectionGroup }; diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js index f6bffbe19b9ee..9249f242ec566 100644 --- a/editor/js/libs/multiple-selection/multiple-selection.js +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -17,6 +17,9 @@ class MultipleSelection { this._pointerUpCustomCallback = null; this._pointerDownCustomCallback = null; this._pointerMoveCustomCallback = null; + this._cancelBtnClickCustomCallback = null; + this._submitBtn = null; + this._cancelBtn = null; } @@ -28,28 +31,42 @@ class MultipleSelection { toggle() { - this.enabled = ! this.enabled; - if ( this.enabled ) { - this._selectionBox = new SelectionBox( this._camera, this._scene ); - this._selectionDrawer = new SelectionDrawer( this._renderer, 'selectBox' ); - - this._renderer.domElement.parentElement.addEventListener( 'pointerdown', this._pointerDown ); - this._renderer.domElement.parentElement.addEventListener( 'pointerup', this._pointerUp ); + this.disable(); } else { - this._selectionBox = null; - this._selectionDrawer = null; - - this._renderer.domElement.parentElement.removeEventListener( 'pointerdown', this._pointerDown ); - this._renderer.domElement.parentElement.removeEventListener( 'pointerup', this._pointerUp ); + this.enable(); } } + enable() { + + this.enabled = true; + + this._selectionBox = new SelectionBox( this._camera, this._scene ); + this._selectionDrawer = new SelectionDrawer( this._renderer, 'selectBox' ); + + this._renderer.domElement.parentElement.addEventListener( 'pointerdown', this._pointerDown ); + this._renderer.domElement.parentElement.addEventListener( 'pointerup', this._pointerUp ); + + } + + disable() { + + this.enabled = false; + + this._selectionBox = null; + this._selectionDrawer = null; + + this._renderer.domElement.parentElement.removeEventListener( 'pointerdown', this._pointerDown ); + this._renderer.domElement.parentElement.removeEventListener( 'pointerup', this._pointerUp ); + + } + addEventListener( event, callback ) { switch ( event ) { @@ -63,6 +80,9 @@ class MultipleSelection { case 'pointermove': this._pointerMoveCustomCallback = callback; break; + case 'cancel-selection': + this._cancelBtnClickCustomCallback = callback; + break; default: break; @@ -70,6 +90,51 @@ class MultipleSelection { } + showControlButtons() { + + this._submitBtn = document.createElement( 'button' ); + this._submitBtn.innerHTML = 'Submit'; + this._renderer.domElement.parentElement.appendChild( this._submitBtn ); + + this._submitBtn.style = 'position: absolute; top: 50px; right: 10px;'; + + this._cancelBtn = document.createElement( 'button' ); + this._cancelBtn.innerHTML = 'Cancel'; + this._renderer.domElement.parentElement.appendChild( this._cancelBtn ); + + this._cancelBtn.style = 'position: absolute; top: 50px; right: 75px;'; + + this._cancelBtn.addEventListener( 'click', this._cancelBtnClick ); + + } + + hideControlButtons() { + + if ( this._submitBtn ) { + + this._submitBtn.remove(); + + } + + if ( this._cancelBtn ) { + + this._cancelBtn.removeEventListener( 'click', this._cancelBtnClick ); + this._cancelBtn.remove(); + + } + + } + + _cancelBtnClick() { + + if ( this._cancelBtnClickCustomCallback ) { + + this._cancelBtnClickCustomCallback(); + + } + + } + _displayOriginalMeshes() { this._hiddenOriginalMeshes.forEach( mesh => { From c74438a9b3e45570a675befa6e9c6dc7364356bc Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Mon, 18 Jul 2022 20:34:55 +0300 Subject: [PATCH 08/15] feat: implement "cancel" and "submit" handlers functionality --- editor/images/multiple-selection.svg | 49 ----------- editor/js/Editor.js | 4 + editor/js/MultipleSelectionControls.js | 85 +++++++++++++++++++ editor/js/Strings.js | 12 ++- editor/js/Toolbar.js | 25 +++--- editor/js/Viewport.js | 41 +++++---- ...js => AddMultipleSelectionGroupCommand.js} | 6 +- .../CancelMultipleSelectionCommand.js | 27 ++++++ editor/js/commands/Commands.js | 6 +- ...=> RemoveMultipleSelectionGroupCommand.js} | 6 +- .../SubmitMultipleSelectionCommand.js | 34 ++++++++ .../multiple-selection/multiple-selection.js | 67 ++------------- 12 files changed, 213 insertions(+), 149 deletions(-) delete mode 100644 editor/images/multiple-selection.svg create mode 100644 editor/js/MultipleSelectionControls.js rename editor/js/commands/{AddMultipleSelectionGroup.js => AddMultipleSelectionGroupCommand.js} (73%) create mode 100644 editor/js/commands/CancelMultipleSelectionCommand.js rename editor/js/commands/{RemoveMultipleSelectionGroup.js => RemoveMultipleSelectionGroupCommand.js} (68%) create mode 100644 editor/js/commands/SubmitMultipleSelectionCommand.js diff --git a/editor/images/multiple-selection.svg b/editor/images/multiple-selection.svg deleted file mode 100644 index 74df8d3e9cd7e..0000000000000 --- a/editor/images/multiple-selection.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/editor/js/Editor.js b/editor/js/Editor.js index c296c0e187cfa..7fea3ae5b3d9c 100644 --- a/editor/js/Editor.js +++ b/editor/js/Editor.js @@ -24,6 +24,10 @@ function Editor( providedDefaultCamera ) { toggleMultipleSelection: new Signal(), enableMultipleSelection: new Signal(), disableMultipleSelection: new Signal(), + showMultipleSelectionControls: new Signal(), + hideMultipleSelectionControls: new Signal(), + cancelMultipleSelection: new Signal(), + submitMultipleSelection: new Signal(), // script diff --git a/editor/js/MultipleSelectionControls.js b/editor/js/MultipleSelectionControls.js new file mode 100644 index 0000000000000..cfdc98c6af00e --- /dev/null +++ b/editor/js/MultipleSelectionControls.js @@ -0,0 +1,85 @@ +import { UIButton, UIPanel } from './libs/ui.js'; + +const toggleMultipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIxMC40MTYgMjEwLjQxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEwLjQxNiAyMTAuNDE2OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTIwNi41MTksMTU1Ljg2M2gtMTkuNDgzVjU0LjU1MmgxOS40ODFjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzLjg5N2MwLTIuMTUyLTEuNzQ1LTMuODk3LTMuODk3LTMuODk3aC00Ni43NTkNCgkJCWMtMi4xNTIsMC0zLjg5NywxLjc0NS0zLjg5NywzLjg5N1YyMy4zOEg1NC41NTJWMy44OTdDNTQuNTUyLDEuNzQ1LDUyLjgwNywwLDUwLjY1NSwwSDMuODk3QzEuNzQ1LDAsMCwxLjc0NSwwLDMuODk3djQ2Ljc1OQ0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdIMjMuMzh2MTAxLjMxSDMuODk3Yy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djQ2Ljc1OWMwLDIuMTUyLDEuNzQ1LDMuODk3LDMuODk3LDMuODk3DQoJCQloNDYuNzU5YzIuMTUyLDAsMy44OTctMS43NDUsMy44OTctMy44OTd2LTE5LjQ4M2gxMDEuMzF2MTkuNDgzYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoNDYuNzU5DQoJCQljMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YxNTkuNzZDMjEwLjQxNiwxNTcuNjA4LDIwOC42NzEsMTU1Ljg2MywyMDYuNTE5LDE1NS44NjN6IE0yMDIuNjIxLDcuNzkzdjM4Ljk2NmgtMTUuNTg2aC03Ljc5Mw0KCQkJaC0xNS41ODZWMzEuMTcydi03Ljc5M1Y3Ljc5M0gyMDIuNjIxeiBNMjMuMzc5LDQ2Ljc1OEg3Ljc5M1Y3Ljc5M2gzOC45NjZ2MTUuNTg2djcuNzkzdjE1LjU4NkgzMS4xNzJIMjMuMzc5eiBNNy43OTMsMjAyLjYyMQ0KCQkJdi0zOC45NjZoMTUuNTg2aDcuNzkzaDE1LjU4NnYxNS41ODZ2Ny43OTN2MTUuNTg3SDcuNzkzeiBNMTU5Ljc1OCwxNTUuODYyYy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djE5LjQ4M0g1NC41NTINCgkJCXYtMTkuNDgzYzAtMi4xNTItMS43NDUtMy44OTctMy44OTctMy44OTdIMzEuMTcyVjU0LjU1MmgxOS40ODNjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzMS4xNzJoMTAxLjMxdjE5LjQ4Mw0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoMTkuNDgzdjEwMS4zMWgtMC4wMDFIMTU5Ljc1OHogTTIwMi42MjEsMjAyLjYyMWgtMzguOTY2di0xNS41ODZ2LTcuNzkzdi0xNS41ODZoMTUuNTg2aDcuNzkzDQoJCQloMTUuNTg3VjIwMi42MjF6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; +const submitMultipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE4LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIzNi45ODggMjM2Ljk4OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjM2Ljk4OCAyMzYuOTg4OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8cG9seWdvbiBwb2ludHM9IjE5OC4wOTgsMjQuMzI2IDg3LjU0MywxMzQuODgxIDM4Ljg5MSw4Ni4yMjkgMCwxMjUuMTIxIDg3LjU0MywyMTIuNjYyIDIzNi45ODgsNjMuMjE3ICIvPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; +const cancelMultipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDQ5MiA0OTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDQ5MiA0OTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxnPg0KCQk8cGF0aCBkPSJNMzAwLjE4OCwyNDZMNDg0LjE0LDYyLjA0YzUuMDYtNS4wNjQsNy44NTItMTEuODIsNy44Ni0xOS4wMjRjMC03LjIwOC0yLjc5Mi0xMy45NzItNy44Ni0xOS4wMjhMNDY4LjAyLDcuODcyDQoJCQljLTUuMDY4LTUuMDc2LTExLjgyNC03Ljg1Ni0xOS4wMzYtNy44NTZjLTcuMiwwLTEzLjk1NiwyLjc4LTE5LjAyNCw3Ljg1NkwyNDYuMDA4LDE5MS44Mkw2Mi4wNDgsNy44NzINCgkJCWMtNS4wNi01LjA3Ni0xMS44Mi03Ljg1Ni0xOS4wMjgtNy44NTZjLTcuMiwwLTEzLjk2LDIuNzgtMTkuMDIsNy44NTZMNy44NzIsMjMuOTg4Yy0xMC40OTYsMTAuNDk2LTEwLjQ5NiwyNy41NjgsMCwzOC4wNTINCgkJCUwxOTEuODI4LDI0Nkw3Ljg3Miw0MjkuOTUyYy01LjA2NCw1LjA3Mi03Ljg1MiwxMS44MjgtNy44NTIsMTkuMDMyYzAsNy4yMDQsMi43ODgsMTMuOTYsNy44NTIsMTkuMDI4bDE2LjEyNCwxNi4xMTYNCgkJCWM1LjA2LDUuMDcyLDExLjgyNCw3Ljg1NiwxOS4wMiw3Ljg1NmM3LjIwOCwwLDEzLjk2OC0yLjc4NCwxOS4wMjgtNy44NTZsMTgzLjk2LTE4My45NTJsMTgzLjk1MiwxODMuOTUyDQoJCQljNS4wNjgsNS4wNzIsMTEuODI0LDcuODU2LDE5LjAyNCw3Ljg1NmgwLjAwOGM3LjIwNCwwLDEzLjk2LTIuNzg0LDE5LjAyOC03Ljg1NmwxNi4xMi0xNi4xMTYNCgkJCWM1LjA2LTUuMDY0LDcuODUyLTExLjgyNCw3Ljg1Mi0xOS4wMjhjMC03LjIwNC0yLjc5Mi0xMy45Ni03Ljg1Mi0xOS4wMjhMMzAwLjE4OCwyNDZ6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; + +function MultipleSelectionControls( editor ) { + + const signals = editor.signals; + const strings = editor.strings; + + const container = new UIPanel(); + container.setId( 'multiple-selection-buttons' ); + + // Toggle Button + const toggleIcon = document.createElement( 'img' ); + toggleIcon.title = strings.getKey( 'toolbar/toggle-multiple-selection' ); + toggleIcon.src = toggleMultipleSelectionImg; + + const toggleBtn = new UIButton(); + toggleBtn.setClass( 'ms-button ms-button__toggle' ); + toggleBtn.dom.appendChild( toggleIcon ); + toggleBtn.onClick( function () { + + signals.toggleMultipleSelection.dispatch(); + + } ); + + // Cancel Button + const cancelIcon = document.createElement( 'img' ); + cancelIcon.title = strings.getKey( 'toolbar/cancel-multiple-selection' ); + cancelIcon.src = cancelMultipleSelectionImg; + + const cancelBtn = new UIButton(); + cancelBtn.setClass( 'ms-button ms-button__cancel' ); + cancelBtn.dom.appendChild( cancelIcon ); + cancelBtn.dom.style.display = 'none'; + cancelBtn.onClick( function () { + + signals.cancelMultipleSelection.dispatch(); + + } ); + + // Submit Button + const submitIcon = document.createElement( 'img' ); + submitIcon.title = strings.getKey( 'toolbar/submit-multiple-selection' ); + submitIcon.src = submitMultipleSelectionImg; + + const submitBtn = new UIButton(); + submitBtn.setClass( 'ms-button ms-button__submit' ); + submitBtn.dom.appendChild( submitIcon ); + submitBtn.dom.style.display = 'none'; + submitBtn.onClick( function () { + + signals.submitMultipleSelection.dispatch(); + + } ); + + container.add( toggleBtn ); + container.add( cancelBtn ); + container.add( submitBtn ); + + signals.showMultipleSelectionControls.add( function () { + + submitBtn.dom.style.display = 'block'; + cancelBtn.dom.style.display = 'block'; + + } ); + + signals.hideMultipleSelectionControls.add( function () { + + submitBtn.dom.style.display = 'none'; + cancelBtn.dom.style.display = 'none'; + + } ); + + container.toggleBtn = toggleBtn; + container.cancelBtn = cancelBtn; + container.submitBtn = submitBtn; + + return container; + +} + +export { MultipleSelectionControls }; diff --git a/editor/js/Strings.js b/editor/js/Strings.js index 18fd294af05f0..bfb15fbccd8e3 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -331,7 +331,9 @@ function Strings( config ) { 'toolbar/rotate': 'Rotate', 'toolbar/scale': 'Scale', 'toolbar/local': 'Local', - 'toolbar/multiple-selection': 'Toggle multiple selection', + 'toolbar/toggle-multiple-selection': 'Toggle multiple selection', + 'toolbar/submit-multiple-selection': 'Submit multiple selection', + 'toolbar/cancel-multiple-selection': 'Cancel multiple selection', 'viewport/info/objects': 'Objects', 'viewport/info/vertices': 'Vertices', @@ -667,7 +669,9 @@ function Strings( config ) { 'toolbar/rotate': 'Rotation', 'toolbar/scale': 'Échelle', 'toolbar/local': 'Local', - 'toolbar/multiple-selection': 'Basculer la sélection multiple', + 'toolbar/toggle-multiple-selection': 'Basculer la sélection multiple', + 'toolbar/submit-multiple-selection': 'Soumettre une sélection multiple', + 'toolbar/cancel-multiple-selection': 'Annuler la sélection multiple', 'viewport/info/objects': 'Objets', 'viewport/info/vertices': 'Sommets', @@ -1003,7 +1007,9 @@ function Strings( config ) { 'toolbar/rotate': '旋转', 'toolbar/scale': '缩放', 'toolbar/local': '本地', - 'toolbar/multiple-selection': '切换多项选择', + 'toolbar/toggle-multiple-selection': '切换多项选择', + 'toolbar/submit-multiple-selection': '提交多项选择', + 'toolbar/cancel-multiple-selection': '取消多项选择', 'viewport/info/objects': '物体', 'viewport/info/vertices': '顶点', diff --git a/editor/js/Toolbar.js b/editor/js/Toolbar.js index d8ca7991ffd4b..1ba7f90fd9a2f 100644 --- a/editor/js/Toolbar.js +++ b/editor/js/Toolbar.js @@ -1,4 +1,5 @@ import { UIPanel, UIButton, UICheckbox } from './libs/ui.js'; +import { MultipleSelectionControls } from './MultipleSelectionControls.js'; /* '../images/translate.svg' */ const translateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTI1NiAwYy0xLjI0NTIgMC0yLjQ1ODYgMC4xMjc5MS0zLjYzODcgMC4zNTE1Ni0wLjA2NTkgMC4wMTI1NjctMC4xMzM0OSAwLjAxODAwOC0wLjE5OTIyIDAuMDMxMjUtMC41Nzg5NCAwLjExNTk1LTEuMTQ2IDAuMjYzNTctMS43MDUxIDAuNDI5NjktMC4wNDcgMC4wMTM5OS0wLjA5NTcgMC4wMjI3NjctMC4xNDI1OCAwLjAzNzEwOS0xLjgxNTEgMC41NTQzNi0zLjUxNTkgMS4zNjgyLTUuMDYyNSAyLjM5NjUtMC4wMzEyIDAuMDIwNzAzLTAuMDY0NiAwLjAzNzcwNi0wLjA5NTcgMC4wNTg1OTQtMC4zMjU3NiAwLjIxOTMxLTAuNjMyMDEgMC40NjMwNy0wLjk0MzM2IDAuNzAxMTctMC43MDYwNSAwLjUzNzg3LTEuMzkwNiAxLjEwNTktMi4wMjM0IDEuNzQyMmwtNzUuMTggNzUuODI4Yy03LjU2MyA3LjYyOC03LjUwNDggMTkuOTM3IDAuMTE3MTggMjcuNSA3LjYyOCA3LjU1NyAxOS45NDEgNy41MDQ4IDI3LjQ5OC0wLjExNzE5bDQxLjkzMi00Mi4yOTF2MTY5Ljg5aC0xNjkuODhsNDIuMjk1LTQxLjkyNmM3LjYyMi03LjU2MyA3LjY3ODItMTkuODcgMC4xMTUyMy0yNy40OThzLTE5Ljg3Ni03LjY4MDItMjcuNDk4LTAuMTE3MTlsLTc1LjgyOCA3NS4xOGMtMC4wMDI5NyAzZS0zIC0wLjAwNDg1IDdlLTMgLTAuMDA3ODEgMC4wMS0yLjI0NjMgMi4yMzAyLTMuOTUwMSA1LjAwNDEtNC44OTg0IDguMTA5NC0wLjAwNDcwOCAwLjAxNTQtMC4wMDcwNDkgMC4wMzE1LTAuMDExNzE5IDAuMDQ2OS0wLjE3ODM5IDAuNTg5MzUtMC4zMzI2IDEuMTg5Mi0wLjQ1NTA4IDEuODAwOC0wLjAxMzI0OCAwLjA2NTctMC4wMTg2NzcgMC4xMzMzMi0wLjAzMTI1IDAuMTk5MjItMC4xMDY1NSAwLjU2MjIzLTAuMTk4ODMgMS4xMjg4LTAuMjU1ODYgMS43MDctMC4wNjI2NzEgMC42MzUyMi0wLjA5NTcwNiAxLjI3OTQtMC4wOTU3MDYgMS45MzE0czAuMDMzMDM1IDEuMjk2MiAwLjA5NTcwMyAxLjkzMTZjMC4wNTcwMjUgMC41NzgyNCAwLjE0OTMxIDEuMTQ0OCAwLjI1NTg2IDEuNzA3IDAuMDEyNTcyIDAuMDY1OSAwLjAxODAwMyAwLjEzMzQ5IDAuMDMxMjUgMC4xOTkyMiAwLjExNTk1IDAuNTc4OTQgMC4yNjM1NyAxLjE0NiAwLjQyOTY5IDEuNzA1MSAwLjAxNDc2MSAwLjA0OTYgMC4wMjM5MDkgMC4xMDA5MyAwLjAzOTA2MiAwLjE1MDM5IDAuNTY1MDMgMS44NDczIDEuMzk2IDMuNTc4MyAyLjQ1MTIgNS4xNDY1IDAuMzU1MTEgMC41Mjc3NSAwLjczMjkzIDEuMDM4MSAxLjEzNjcgMS41Mjc0IDAuMDAyNjUgM2UtMyAwLjAwNTE2IDdlLTMgMC4wMDc4MSAwLjAxIDAuMDY3MTU4IDAuMDgxNSAwLjE0NjI5IDAuMTUzOTEgMC4yMTQ4NCAwLjIzNDM4IDAuMzM4OTEgMC4zOTY4MSAwLjY4NTM1IDAuNzg4MDEgMS4wNTQ3IDEuMTU2MiAwLjAxMzc2IDAuMDEzNyAwLjAyNTI1NyAwLjAyOTMgMC4wMzkwNjMgMC4wNDNsNzUuODI2IDc1LjE4YzMuNzkxIDMuNzUzIDguNzM3NSA1LjYzMjggMTMuNjg5IDUuNjMyOCA1LjAwMyAwIDEwLjAwNy0xLjkxODkgMTMuODA1LTUuNzU1OSA3LjU2My03LjYyOCA3LjUwNDgtMTkuOTM1LTAuMTE3MTktMjcuNDk4bC00Mi4yODktNDEuOTI2aDE2OS44OXYxNjkuODlsLTQxLjkyNi00Mi4yODljLTcuNTU3LTcuNjM1LTE5Ljg3LTcuNjY3LTI3LjQ5OC0wLjEyMzA1LTcuNjIyIDcuNTYzLTcuNjgwMiAxOS44NzItMC4xMTcxOSAyNy41bDc1LjE4IDc1LjgyNmMzZS0zIDNlLTMgN2UtMyA1ZS0zIDAuMDEgOGUtMyAxLjM0NTggMS4zNTU2IDIuODg4NSAyLjUxNTggNC41ODQgMy40Mjk3IDAuMDYzNyAwLjAzNDMgMC4xMzEyOCAwLjA2MDIgMC4xOTUzMiAwLjA5MzcgMC41MDAwNiAwLjI2MjM5IDEuMDA4NiAwLjUwOTU4IDEuNTMzMiAwLjcyODUyIDAuMDI4NyAwLjAxMiAwLjA1OTEgMC4wMTk0IDAuMDg3OSAwLjAzMTIgMC41NTE0OCAwLjIyNzA2IDEuMTEzOSAwLjQzMjkyIDEuNjg5NCAwLjYwOTM3IDAuMTMwNTkgMC4wNDAxIDAuMjY1MDEgMC4wNjYyIDAuMzk2NDkgMC4xMDM1MiAwLjQ4NDU5IDAuMTM3NDEgMC45NzE0OSAwLjI2OTE2IDEuNDcwNyAwLjM2OTE0IDAuMDY1NyAwLjAxMzIgMC4xMzMzMiAwLjAxODcgMC4xOTkyMiAwLjAzMTIgMS4xNzk4IDAuMjIzNjEgMi4zOTMyIDAuMzUxNTIgMy42Mzg0IDAuMzUxNTIgMS44MTk0IDAgMy41NzItMC4yNjkwOSA1LjI0MjItMC43MzYzMyAwLjE1NTQzLTAuMDQzNSAwLjMxNDU0LTAuMDczOCAwLjQ2ODc1LTAuMTIxMDkgMS4xMDExLTAuMzM3OTIgMi4xNTM5LTAuNzgwMjUgMy4xNjIxLTEuMjk4OCAwLjExNDcyLTAuMDU4OCAwLjIzNDA3LTAuMTA2ODUgMC4zNDc2NS0wLjE2Nzk3IDAuMzcyNTktMC4yMDExMSAwLjcyODQ4LTAuNDI4MTIgMS4wODU5LTAuNjUyMzQgMC4xODY4LTAuMTE2NzYgMC4zODE0My0wLjIyMDUyIDAuNTY0NDUtMC4zNDM3NSAwLjEwNDY3LTAuMDcwNyAwLjE5OTUzLTAuMTUzODggMC4zMDI3NC0wLjIyNjU3IDAuOTM1NzEtMC42NTY3MyAxLjgyNzEtMS4zODU3IDIuNjQ0NS0yLjIwOWw3NS4xOC03NS44MjZjNy41NTYtNy42MjggNy41MDMtMTkuOTM3LTAuMTI1LTI3LjUtNy42MzUtNy41NTctMTkuOTQxLTcuNTA1LTI3LjQ5OCAwLjEyMzA1bC00MS45MzIgNDIuMjk5di0xNjkuOWgxNjkuODlsLTQyLjI5MyA0MS45MjZjLTcuNjI4IDcuNTYzLTcuNjggMTkuODctMC4xMjMwNSAyNy40OTggMy44MDQgMy44MzcgOC44MDc2IDUuNzU1OSAxMy44MTEgNS43NTU5IDQuOTQ1IDAgOS44OTg0LTEuODgwOCAxMy42ODktNS42MzI4bDc1LjgyNi03NS4xOGMwLjAxNDEtMC4wMTQgMC4wMjY5LTAuMDI4OSAwLjA0MS0wLjA0MyAwLjI1MTUtMC4yNTA4IDAuNDgxMjEtMC41MjI5MiAwLjcxODc1LTAuNzg3MTEgMC4xODQ0Ny0wLjIwNTM0IDAuMzgxNjgtMC40MDEwNSAwLjU1NjY0LTAuNjEzMjggMC40MDQtMC40ODk1NSAwLjc4MzM5LTAuOTk5MyAxLjEzODctMS41Mjc0IDAuMDI0OS0wLjAzNzEgMC4wNDM3LTAuMDc3OSAwLjA2ODQtMC4xMTUyMyAwLjMyNzEzLTAuNDkzNSAwLjYzODAyLTAuOTk5NzIgMC45MTk5Mi0xLjUyMzQgMC4wMzI0LTAuMDYwNCAwLjA1NjEtMC4xMjQ4NCAwLjA4NzktMC4xODU1NSAwLjI2MzA2LTAuNTAxMzMgMC41MTEwOS0xLjAxMTIgMC43MzA0Ny0xLjUzNzEgMC4wMTI1LTAuMDMwMSAwLjAyMDgtMC4wNjE3IDAuMDMzMi0wLjA5MTggMC4yMjQ5Ny0wLjU0NzA3IDAuNDI4MzQtMS4xMDUgMC42MDM1Mi0xLjY3NTggMC4wNDczLTAuMTU0MTkgMC4wNzc2LTAuMzEzMzQgMC4xMjEwOS0wLjQ2ODc1IDAuMTMwMTktMC40NjUzNyAwLjI1OTc0LTAuOTMxMzkgMC4zNTU0Ny0xLjQxMDIgMC4wMTI4LTAuMDYzNyAwLjAxNzEtMC4xMjk0OCAwLjAyOTMtMC4xOTMzNiAwLjIyMzYyLTEuMTgwMSAwLjM1MTUzLTIuMzkzNCAwLjM1MTUzLTMuNjM4NiAwLTEuMzEyNS0wLjEzMzAyLTIuNTkyNS0wLjM4MDg2LTMuODMyLTRlLTQgLTJlLTMgLTJlLTMgLTRlLTMgLTJlLTMgLTZlLTMgLTAuMDk1NS0wLjQ3Njc0LTAuMjIzODctMC45NDA4NS0wLjM1MzUyLTEuNDA0My0wLjA0MzUtMC4xNTU0MS0wLjA3MzgtMC4zMTQ1Ni0wLjEyMTA5LTAuNDY4NzUtMC4xODQ3OC0wLjYwMjA3LTAuMzk2NjMtMS4xOTItMC42MzY3Mi0xLjc2NzYtNS42ZS00IC0xZS0zIC0xZS0zIC0zZS0zIC0yZS0zIC00ZS0zIC0wLjI0NTQyLTAuNTg4MDEtMC41MTY1Ny0xLjE2MTctMC44MTY0MS0xLjcxODgtMmUtMyAtM2UtMyAtNGUtMyAtNmUtMyAtNmUtMyAtMC4wMS0wLjMwMTY1LTAuNTU5NjMtMC42MjkyMS0xLjEwMzktMC45ODI0Mi0xLjYyODktOGUtNCAtMWUtMyAtMWUtMyAtM2UtMyAtMmUtMyAtNGUtMyAtMC4zNTQ1OS0wLjUyNjc2LTAuNzMzNjQtMS4wMzUtMS4xMzY3LTEuNTIzNC0wLjE3NDk2LTAuMjEyMjMtMC4zNzIxNy0wLjQwNzk0LTAuNTU2NjQtMC42MTMyOC0wLjIzNzU0LTAuMjY0MTktMC40NjcyNS0wLjUzNjMxLTAuNzE4NzUtMC43ODcxMS0wLjAxNDEtMC4wMTQtMC4wMjY5LTAuMDI5LTAuMDQxLTAuMDQzbC03NS44MjYtNzUuMThjLTcuNjM1LTcuNTYzLTE5Ljk0My03LjUwNDgtMjcuNSAwLjExNzE4LTcuNTU3IDcuNjI4LTcuNTA1IDE5LjkzNSAwLjEyMzA1IDI3LjQ5OGw0Mi4yOTUgNDEuOTMyaC0xNjkuODl2LTE2OS44OWw0MS45MjYgNDIuMjg5YzMuODA0IDMuODM3IDguODA3NiA1Ljc1NTkgMTMuODExIDUuNzU1OSA0Ljk0NSAwIDkuODk1NS0xLjg3MzggMTMuNjg4LTUuNjMyOCA3LjYyOC03LjU2MyA3LjY4LTE5Ljg3MiAwLjEyMzA0LTI3LjVsLTc1LjE4LTc1LjgyNmMtMC4wMTM3LTAuMDEzODA1LTAuMDI5Mi0wLjAyNTMwMy0wLjA0My0wLjAzOTA2My0wLjQ0MTc1LTAuNDQzMDYtMC45MDQxMy0wLjg2NjYyLTEuMzg2Ny0xLjI2NTYtNWUtMyAtMC4wMDM4Mi05ZS0zIC0wLjAwNzktMC4wMTM3LTAuMDExNzE5LTMuMzYwOC0yLjc3MzUtNy42Njg4LTQuNDM5NS0xMi4zNjctNC40Mzk1eiIvPgo8L3N2Zz4K'; @@ -6,8 +7,6 @@ const translateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNv const rotateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTI0Ny44IDQ3NC4xMmM2MS4zMTUgMCAxMTIuMDktMjYuNjkyIDE0Ny42NS01OS40OTVsLTEuNjk0NyA3NS41OGMtMC4xNzY5NyAxMC41MDkgOC4yMDYzIDE5LjE3OCAxOC43MjEgMTkuMzQ5aDAuMzIzMThjMTAuMzY0IDAgMTguODU1LTguMzE5OCAxOS4wMzMtMTguNzIxbDIuNTM4Mi0xMjYuMThjMC4wODI3LTUuMTU5Mi0xLjkyOTQtMTAuMTM1LTUuNTg0My0xMy43ODQtMy42NDkyLTMuNjQ5Mi04LjU5ODctNS42NjAzLTEzLjc4NC01LjU3MThsLTEyNi43MyAyLjUzODNjLTEwLjUwOSAwLjE4MzcxLTE4Ljg4NSA4Ljg0NjktMTguNzA4IDE5LjM2MiAwLjE3Nzk0IDEwLjQwMSA4LjY2ODkgMTguNzE0IDE5LjAzMiAxOC43MTRoMC4zMjk5MWw4My4xOTUtMS43OTU3Yy0yOS4zNSAyNy44MTUtNzIuNjU2IDUxLjkzLTEyNC4zMyA1MS45My0xMDUuOTEgMC0xNzcuMDUtOTEuNTQ4LTE3Ny4wNS0xNzcuMDUtMC4zMTcwNC0xMC4yNDgtNi4yOTUxLTE5LjI1MS0xOC41MzItMTkuNDc5LTEyLjIzNy0wLjIyNzY0LTE5LjE5NiA4LjE4MzEtMTkuNTQzIDE5LjQ4NiAwIDEwMy44OSA4Ni40NDYgMjE1LjEzIDIxNS4xMyAyMTUuMTN6bTQuMzUzOC00MzUuMjVjLTYxLjMxNSAwLTExMi4wOSAyNi42OTItMTQ3LjY1IDU5LjQ5NWwxLjY5NDctNzUuNTc5YzAuMTc2OTgtMTAuNTA5LTguMjA2My0xOS4xNzgtMTguNzIxLTE5LjM0OWgtMC4zMjMxN2MtMTAuMzY0IDAtMTguODU1IDguMzE5OC0xOS4wMzMgMTguNzIxbC0yLjUzODMgMTI2LjE4Yy0wLjA4MjcyIDUuMTU5MiAxLjkyOTQgMTAuMTM1IDUuNTg0NCAxMy43ODQgMy42NDkyIDMuNjQ5MiA4LjU5ODcgNS42NjAzIDEzLjc4NCA1LjU3MTlsMTI2LjczLTIuNTM4M2MxMC41MDktMC4xODM3MSAxOC44ODUtOC44NDY5IDE4LjcwOC0xOS4zNjItMC4xNzc5NC0xMC40MDEtOC42Njg5LTE4LjcxNC0xOS4wMzItMTguNzE0aC0wLjMyOTkxbC04My4xOTUgMS43OTU3YzI5LjM1LTI3LjgxNSA3Mi42NTYtNTEuOTMgMTI0LjMzLTUxLjkzIDEwNS45MSAwIDE3Ny4wNSA5MS41NDggMTc3LjA1IDE3Ny4wNSAwLjMxNzAzIDEwLjI0OCA2LjI5NTEgMTkuMjUxIDE4LjUzMiAxOS40NzkgMTIuMjM3IDAuMjI3NjMgMTkuMTk2LTguMTgzMSAxOS41NDMtMTkuNDg2IDAtMTAzLjg5LTg2LjQ0Ni0yMTUuMTMtMjE1LjEzLTIxNS4xM3oiLz4KPC9zdmc+Cg=='; /* '../images/scale.svg' */ const scaleImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTQ1MC4yNSA0NC4xODItMTMzLjEzIDEuMTY5OWMtOS42OTEgMC4wNzYtMTcuNDgyIDcuOTg0OS0xNy40MDYgMTcuNjcgMC4wNzYgOS42MzggMjcuMTU1IDE3LjQgMTcuNTM1IDE3LjRoMC4xMjg5bDkwLjM1LTAuODQzNzUtMTE2Ljg4IDExNi44N2MtNi44NSA2Ljg0NC02Ljg1IDE3Ljk0OSAwIDI0Ljc5MyAzLjQyNSAzLjQyNSA3LjkwNzUgNS4xMzg3IDEyLjM5NiA1LjEzODcgNC40ODMgMCA4Ljk3MzQtMS43MTM3IDEyLjM5OC01LjEzODdsMTE2Ljg3LTExNi44OC0wLjg0MTc5IDkwLjM0NGMtMC4wNyA5LjY4NSA3LjcxOTMgMTcuNTk0IDE3LjQwNCAxNy42N2gwLjEyODkxYzkuNjIgMCAxNy40NTktNy43NjI0IDE3LjUzNS0xNy40bDEuMTY4LTEzMy4xM2MxLjNlLTQgLTAuMDE2MzctMmUtMyAtMC4wMzI0Ni0yZS0zIC0wLjA0ODgzIDNlLTMgLTAuNTE0NzEtMC4wMjM5LTEuMDI5Ny0wLjA2NjQtMS41NDMtNGUtMyAtMC4wNTMyNS05LjZlLTQgLTAuMTA2OTUtNmUtMyAtMC4xNjAxNi0yLjRlLTQgLTAuMDAyNy0yZS0zIC0wLjAwNTEtMmUtMyAtMC4wMDc4LTAuMjYyMjQtMi44MzQ1LTEuMjEzMi01LjYxNDUtMi44NTE2LTguMDc0Mi0wLjMxODc2LTAuNDc4NTgtMC42NjIzNS0wLjk0NjMxLTEuMDMzMi0xLjM5ODQtMC4zNjgzMS0wLjQ1MDI5LTAuNzYwNzktMC44ODM4My0xLjE3NTgtMS4yOTg4LTAuNDE2NTgtMC40MTczNS0wLjg1MjE4LTAuODExNTYtMS4zMDQ3LTEuMTgxNi0wLjI0MTc2LTAuMTk4MDQtMC40OTY1Ni0wLjM2OTU3LTAuNzQ2MS0wLjU1MjczLTAuMjE1MTQtMC4xNTc2Mi0wLjQyMjkzLTAuMzI1MzgtMC42NDQ1My0wLjQ3MjY2LTAuMzU2MTQtMC4yMzcyMy0wLjcyNDk0LTAuNDQ1OS0xLjA5MzgtMC42NTQzLTAuMTI1NzQtMC4wNzA5Ni0wLjI0NTY3LTAuMTUyOTItMC4zNzMwNC0wLjIyMDctMC40MjQ4MS0wLjIyNjMxLTAuODYwNTktMC40MjQ0Mi0xLjI5ODgtMC42MTMyOC0wLjA4MjQtMC4wMzU1NC0wLjE2MTE3LTAuMDc5MDEtMC4yNDQxNC0wLjExMzI4LTAuNDI3MDYtMC4xNzYyOS0wLjg2MTgxLTAuMzI1NzEtMS4yOTg4LTAuNDY2OC0wLjEwNzYxLTAuMDM0ODMtMC4yMTIwMS0wLjA3ODU4LTAuMzIwMzEtMC4xMTEzMy0wLjM3NjA0LTAuMTEzNDEtMC43NTcyNC0wLjE5OTUyLTEuMTM4Ny0wLjI4NzExLTAuMTgwNDQtMC4wNDE2MS0wLjM1NzE1LTAuMDk0OTQtMC41MzkwNi0wLjEzMDg2LTAuMzA4NjctMC4wNjA2OC0wLjYyMDcxLTAuMDk0NzEtMC45MzE2NC0wLjEzODY3LTAuMjU2NzktMC4wMzY1MS0wLjUxMDYyLTAuMDg2Mi0wLjc2OTUzLTAuMTExMzMtMC41NjMxOS0wLjA1NDQtMS4xMjgtMC4wODM5NC0xLjY5MzQtMC4wODM5OHptLTM4Ny40NSAyNTUuNjJjLTkuNjIgMC0xNy40NTkgNy43NjYzLTE3LjUzNSAxNy40MDRsLTEuMTY5OSAxMzMuMTJjLTEuMjJlLTQgMC4wMTY0IDJlLTMgMC4wMzI1IDJlLTMgMC4wNDg4LTAuMDAyNSAwLjUxMzk1IDAuMDIzOTUgMS4wMjg1IDAuMDY2NDEgMS41NDEgMC4wMDQ2IDAuMDU1NyAwLjAwMjYgMC4xMTIzMyAwLjAwNzggMC4xNjc5NyAwLjMxMjk5IDMuMzg1NSAxLjYwNTkgNi42OTUgMy44ODA5IDkuNDcyNyAwLjM2NjYgMC40NDc2MSAwLjc1NjI4IDAuODgyODcgMS4xNzM4IDEuMzAwOGgyZS0zYzAuMjA3MzEgMC4yMDcyOCAwLjQyOTY2IDAuMzg5MjUgMC42NDQ1MyAwLjU4Mzk4IDAuMjE3OTUgMC4xOTc1NSAwLjQyNzY0IDAuNDA2MjYgMC42NTQzIDAuNTkxOCAwLjI5Nzg5IDAuMjQ0MTcgMC42MTAyOCAwLjQ2MDA0IDAuOTE5OTIgMC42ODE2NCAwLjE1OTE5IDAuMTEzNzMgMC4zMTAwNCAwLjIzOTUyIDAuNDcyNjYgMC4zNDc2NiAwLjM3NDU0IDAuMjQ5NTQgMC43NjE4NSAwLjQ2OTgzIDEuMTUwNCAwLjY4NzUgMC4xMDg5NyAwLjA2MSAwLjIxMjA4IDAuMTMyOCAwLjMyMjI3IDAuMTkxNCAwLjM4NzI2IDAuMjA2MTYgMC43ODUwNiAwLjM4MzUzIDEuMTgzNiAwLjU1ODYgMC4xMjU1MiAwLjA1NTIgMC4yNDYyOCAwLjEyMTYxIDAuMzczMDUgMC4xNzM4MiAwLjM2OTA4IDAuMTUxODcgMC43NDY0MiAwLjI3NjczIDEuMTIzIDAuNDAyMzUgMC4xNjY0NSAwLjA1NTYgMC4zMjc5NiAwLjEyMzE4IDAuNDk2MDkgMC4xNzM4MyAwLjQ2OTU2IDAuMTQxMTEgMC45NDQxNyAwLjI1NDU0IDEuNDIxOSAwLjM1NTQ3IDAuMDcyODUgMC4wMTU0IDAuMTQzNzIgMC4wMzgyIDAuMjE2OCAwLjA1MjcgMC40NjgyIDAuMDkyNyAwLjk0MTAyIDAuMTU2NjYgMS40MTQxIDAuMjEwOTQgMC4wOTgyMSAwLjAxMTMgMC4xOTQ0NiAwLjAzMTMgMC4yOTI5NyAwLjA0MSAwLjU3MDc2IDAuMDU1OCAxLjY3ODMtMC40ODU3OCAxLjcxNjggMC4wODU5aDAuMTM0NzdsMTMzLjEzLTEuMTY5OWM5LjY4NS0wLjA3IDE3LjQ3Ni03Ljk4MzEgMTcuNC0xNy42NjItMC4wNzYtOS42OS04LjEyNTktMTcuMzg3LTE3LjY3LTE3LjQwNGwtOTAuMzM4IDAuODM5OTYgMTE2Ljg3LTExNi44N2M2Ljg0NC02Ljg0NCA2Ljg1LTE3Ljk0MyAwLTI0Ljc5M3MtMTcuOTU1LTYuODUtMjQuNzk5IDBsLTExNi44NyAxMTYuODYgMC44NDM3NS05MC4zNDRjMC4wNzYtOS42NzktNy43MTU0LTE3LjU4Ni0xNy40LTE3LjY2MnoiLz4KPC9zdmc+Cg=='; -/* '../images/multiple-selection.svg' */ -const multipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIxMC40MTYgMjEwLjQxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEwLjQxNiAyMTAuNDE2OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTIwNi41MTksMTU1Ljg2M2gtMTkuNDgzVjU0LjU1MmgxOS40ODFjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzLjg5N2MwLTIuMTUyLTEuNzQ1LTMuODk3LTMuODk3LTMuODk3aC00Ni43NTkNCgkJCWMtMi4xNTIsMC0zLjg5NywxLjc0NS0zLjg5NywzLjg5N1YyMy4zOEg1NC41NTJWMy44OTdDNTQuNTUyLDEuNzQ1LDUyLjgwNywwLDUwLjY1NSwwSDMuODk3QzEuNzQ1LDAsMCwxLjc0NSwwLDMuODk3djQ2Ljc1OQ0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdIMjMuMzh2MTAxLjMxSDMuODk3Yy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djQ2Ljc1OWMwLDIuMTUyLDEuNzQ1LDMuODk3LDMuODk3LDMuODk3DQoJCQloNDYuNzU5YzIuMTUyLDAsMy44OTctMS43NDUsMy44OTctMy44OTd2LTE5LjQ4M2gxMDEuMzF2MTkuNDgzYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoNDYuNzU5DQoJCQljMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YxNTkuNzZDMjEwLjQxNiwxNTcuNjA4LDIwOC42NzEsMTU1Ljg2MywyMDYuNTE5LDE1NS44NjN6IE0yMDIuNjIxLDcuNzkzdjM4Ljk2NmgtMTUuNTg2aC03Ljc5Mw0KCQkJaC0xNS41ODZWMzEuMTcydi03Ljc5M1Y3Ljc5M0gyMDIuNjIxeiBNMjMuMzc5LDQ2Ljc1OEg3Ljc5M1Y3Ljc5M2gzOC45NjZ2MTUuNTg2djcuNzkzdjE1LjU4NkgzMS4xNzJIMjMuMzc5eiBNNy43OTMsMjAyLjYyMQ0KCQkJdi0zOC45NjZoMTUuNTg2aDcuNzkzaDE1LjU4NnYxNS41ODZ2Ny43OTN2MTUuNTg3SDcuNzkzeiBNMTU5Ljc1OCwxNTUuODYyYy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djE5LjQ4M0g1NC41NTINCgkJCXYtMTkuNDgzYzAtMi4xNTItMS43NDUtMy44OTctMy44OTctMy44OTdIMzEuMTcyVjU0LjU1MmgxOS40ODNjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzMS4xNzJoMTAxLjMxdjE5LjQ4Mw0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoMTkuNDgzdjEwMS4zMWgtMC4wMDFIMTU5Ljc1OHogTTIwMi42MjEsMjAyLjYyMWgtMzguOTY2di0xNS41ODZ2LTcuNzkzdi0xNS41ODZoMTUuNTg2aDcuNzkzDQoJCQloMTUuNTg3VjIwMi42MjF6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; function Toolbar( editor ) { @@ -59,17 +58,7 @@ function Toolbar( editor ) { } ); container.add( scale ); - const multipleSelectionIcon = document.createElement( 'img' ); - multipleSelectionIcon.title = strings.getKey( 'toolbar/multiple-selection' ); - multipleSelectionIcon.src = multipleSelectionImg; - - const multipleSelection = new UIButton(); - multipleSelection.dom.appendChild( multipleSelectionIcon ); - multipleSelection.onClick( function () { - - signals.toggleMultipleSelection.dispatch(); - - } ); + const multipleSelection = new MultipleSelectionControls( editor ); container.add( multipleSelection ); const local = new UICheckbox( false ); @@ -88,7 +77,7 @@ function Toolbar( editor ) { translate.dom.classList.remove( 'selected' ); rotate.dom.classList.remove( 'selected' ); scale.dom.classList.remove( 'selected' ); - multipleSelection.dom.classList.remove( 'selected' ); + multipleSelection.toggleBtn.dom.classList.remove( 'selected' ); signals.disableMultipleSelection.dispatch(); @@ -108,7 +97,13 @@ function Toolbar( editor ) { rotate.dom.classList.remove( 'selected' ); scale.dom.classList.remove( 'selected' ); - multipleSelection.dom.classList.toggle( 'selected' ); + multipleSelection.toggleBtn.dom.classList.toggle( 'selected' ); + + } ); + + signals.disableMultipleSelection.add( function () { + + multipleSelection.toggleBtn.dom.classList.remove( 'selected' ); } ); diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index b2d170bf577e1..dd10c6fe3166d 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -17,7 +17,12 @@ import { SetScaleCommand } from './commands/SetScaleCommand.js'; import { RoomEnvironment } from '../../examples/jsm/environments/RoomEnvironment.js'; import { MultipleSelection } from './libs/multiple-selection/multiple-selection.js'; -import { AddMultipleSelectionGroup, RemoveMultipleSelectionGroup } from './commands/Commands.js'; +import { + AddMultipleSelectionGroupCommand, + RemoveMultipleSelectionGroupCommand, + SubmitMultipleSelectionCommand, + CancelMultipleSelectionCommand +} from './commands/Commands.js'; function Viewport( editor ) { @@ -92,13 +97,13 @@ function Viewport( editor ) { selectionBox.visible = false; sceneHelpers.add( selectionBox ); - const multipleSelection = new MultipleSelection( editor.viewportCamera, scene ); + const multipleSelection = new MultipleSelection( editor ); multipleSelection.addEventListener( 'pointerdown', () => { - editor.execute( new RemoveMultipleSelectionGroup( editor ) ); + editor.execute( new RemoveMultipleSelectionGroupCommand( editor ) ); - multipleSelection.hideControlButtons(); + signals.hideMultipleSelectionControls.dispatch(); } ); @@ -106,23 +111,15 @@ function Viewport( editor ) { if ( ! selectedMeshes.length ) { - editor.execute( new RemoveMultipleSelectionGroup( editor ) ); + editor.execute( new RemoveMultipleSelectionGroupCommand( editor ) ); return; } - editor.execute( new AddMultipleSelectionGroup( editor, selectedMeshes ) ); + editor.execute( new AddMultipleSelectionGroupCommand( editor, selectedMeshes ) ); - multipleSelection.showControlButtons(); - - } ); - - multipleSelection.addEventListener( 'cancel-selection', () => { - - editor.execute( new RemoveMultipleSelectionGroup( editor ) ); - - multipleSelection.hideControlButtons(); + signals.showMultipleSelectionControls.dispatch(); } ); @@ -406,6 +403,20 @@ function Viewport( editor ) { } ); + signals.submitMultipleSelection.add( function () { + + editor.execute( new SubmitMultipleSelectionCommand( editor, multipleSelection ) ); + render(); + + } ); + + signals.cancelMultipleSelection.add( function () { + + editor.execute( new CancelMultipleSelectionCommand( editor, multipleSelection ) ); + render(); + + } ); + signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); diff --git a/editor/js/commands/AddMultipleSelectionGroup.js b/editor/js/commands/AddMultipleSelectionGroupCommand.js similarity index 73% rename from editor/js/commands/AddMultipleSelectionGroup.js rename to editor/js/commands/AddMultipleSelectionGroupCommand.js index c951a3d23916b..5aacea1c7d21f 100644 --- a/editor/js/commands/AddMultipleSelectionGroup.js +++ b/editor/js/commands/AddMultipleSelectionGroupCommand.js @@ -2,13 +2,13 @@ import { Group } from 'three'; import { Command } from '../Command.js'; import { AddObjectCommand } from './AddObjectCommand.js'; -class AddMultipleSelectionGroup extends Command { +class AddMultipleSelectionGroupCommand extends Command { constructor( editor, meshes ) { super( editor ); - this.type = 'AddMultipleSelectionGroup'; + this.type = 'AddMultipleSelectionGroupCommand'; this.meshes = meshes; } @@ -25,4 +25,4 @@ class AddMultipleSelectionGroup extends Command { } -export { AddMultipleSelectionGroup }; +export { AddMultipleSelectionGroupCommand }; diff --git a/editor/js/commands/CancelMultipleSelectionCommand.js b/editor/js/commands/CancelMultipleSelectionCommand.js new file mode 100644 index 0000000000000..4355a02af7b68 --- /dev/null +++ b/editor/js/commands/CancelMultipleSelectionCommand.js @@ -0,0 +1,27 @@ +import { Command } from '../Command.js'; +import { RemoveMultipleSelectionGroupCommand } from './RemoveMultipleSelectionGroupCommand.js'; + +class CancelMultipleSelectionCommand extends Command { + + constructor( editor, multipleSelection ) { + + super( editor ); + + this.type = 'CancelMultipleSelectionCommand'; + this.multipleSelection = multipleSelection; + + } + + execute() { + + this.editor.execute( new RemoveMultipleSelectionGroupCommand( this.editor ) ); + this.multipleSelection.disable(); + this.multipleSelection._displayOriginalMeshes(); + this.editor.signals.hideMultipleSelectionControls.dispatch(); + this.editor.signals.disableMultipleSelection.dispatch(); + + } + +} + +export { CancelMultipleSelectionCommand }; diff --git a/editor/js/commands/Commands.js b/editor/js/commands/Commands.js index 5b6158c8cf3f9..81b65acb3940d 100644 --- a/editor/js/commands/Commands.js +++ b/editor/js/commands/Commands.js @@ -19,5 +19,7 @@ export { SetSceneCommand } from './SetSceneCommand.js'; export { SetScriptValueCommand } from './SetScriptValueCommand.js'; export { SetUuidCommand } from './SetUuidCommand.js'; export { SetValueCommand } from './SetValueCommand.js'; -export { RemoveMultipleSelectionGroup } from './RemoveMultipleSelectionGroup.js'; -export { AddMultipleSelectionGroup } from './AddMultipleSelectionGroup.js'; +export { RemoveMultipleSelectionGroupCommand } from './RemoveMultipleSelectionGroupCommand.js'; +export { AddMultipleSelectionGroupCommand } from './AddMultipleSelectionGroupCommand.js'; +export { CancelMultipleSelectionCommand } from './CancelMultipleSelectionCommand.js'; +export { SubmitMultipleSelectionCommand } from './SubmitMultipleSelectionCommand.js'; diff --git a/editor/js/commands/RemoveMultipleSelectionGroup.js b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js similarity index 68% rename from editor/js/commands/RemoveMultipleSelectionGroup.js rename to editor/js/commands/RemoveMultipleSelectionGroupCommand.js index 0131fb40e8e1a..81fc152abe50a 100644 --- a/editor/js/commands/RemoveMultipleSelectionGroup.js +++ b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js @@ -1,13 +1,13 @@ import { Command } from '../Command.js'; import { RemoveObjectCommand } from './RemoveObjectCommand.js'; -class RemoveMultipleSelectionGroup extends Command { +class RemoveMultipleSelectionGroupCommand extends Command { constructor( editor ) { super( editor ); - this.type = 'RemoveMultipleSelectionGroup'; + this.type = 'RemoveMultipleSelectionGroupCommand'; } @@ -25,4 +25,4 @@ class RemoveMultipleSelectionGroup extends Command { } -export { RemoveMultipleSelectionGroup }; +export { RemoveMultipleSelectionGroupCommand }; diff --git a/editor/js/commands/SubmitMultipleSelectionCommand.js b/editor/js/commands/SubmitMultipleSelectionCommand.js new file mode 100644 index 0000000000000..e7274da7d3b41 --- /dev/null +++ b/editor/js/commands/SubmitMultipleSelectionCommand.js @@ -0,0 +1,34 @@ +import { Command } from '../Command.js'; +import { SetPositionCommand } from './SetPositionCommand.js'; +import { RemoveMultipleSelectionGroupCommand } from './RemoveMultipleSelectionGroupCommand.js'; + +class SubmitMultipleSelectionCommand extends Command { + + constructor( editor, multipleSelection ) { + + super( editor ); + + this.type = 'SubmitMultipleSelectionCommand'; + this.multipleSelection = multipleSelection; + + } + + execute() { + + for ( const selectedMesh of this.multipleSelection.selectedMeshes ) { + + this.editor.execute( new SetPositionCommand( this.editor, selectedMesh._original_mesh, selectedMesh.matrixWorld.getPosition() ) ); + + } + + this.editor.execute( new RemoveMultipleSelectionGroupCommand( this.editor ) ); + this.multipleSelection.disable(); + this.multipleSelection._displayOriginalMeshes(); + this.editor.signals.hideMultipleSelectionControls.dispatch(); + this.editor.signals.disableMultipleSelection.dispatch(); + + } + +} + +export { SubmitMultipleSelectionCommand }; diff --git a/editor/js/libs/multiple-selection/multiple-selection.js b/editor/js/libs/multiple-selection/multiple-selection.js index 9249f242ec566..6e7efe06ee9c1 100644 --- a/editor/js/libs/multiple-selection/multiple-selection.js +++ b/editor/js/libs/multiple-selection/multiple-selection.js @@ -4,22 +4,19 @@ import { SelectionDrawer } from './selection-drawer.js'; class MultipleSelection { - constructor( camera, scene, renderer ) { + constructor( editor, renderer ) { this.enabled = false; - this._camera = camera; - this._scene = scene; + this._camera = editor.camera; + this._scene = editor.scene; this._renderer = renderer; this._selectionDrawer = null; this._selectionBox = null; - this._selectedMeshes = []; + this.selectedMeshes = []; this._hiddenOriginalMeshes = []; this._pointerUpCustomCallback = null; this._pointerDownCustomCallback = null; this._pointerMoveCustomCallback = null; - this._cancelBtnClickCustomCallback = null; - this._submitBtn = null; - this._cancelBtn = null; } @@ -80,9 +77,6 @@ class MultipleSelection { case 'pointermove': this._pointerMoveCustomCallback = callback; break; - case 'cancel-selection': - this._cancelBtnClickCustomCallback = callback; - break; default: break; @@ -90,51 +84,6 @@ class MultipleSelection { } - showControlButtons() { - - this._submitBtn = document.createElement( 'button' ); - this._submitBtn.innerHTML = 'Submit'; - this._renderer.domElement.parentElement.appendChild( this._submitBtn ); - - this._submitBtn.style = 'position: absolute; top: 50px; right: 10px;'; - - this._cancelBtn = document.createElement( 'button' ); - this._cancelBtn.innerHTML = 'Cancel'; - this._renderer.domElement.parentElement.appendChild( this._cancelBtn ); - - this._cancelBtn.style = 'position: absolute; top: 50px; right: 75px;'; - - this._cancelBtn.addEventListener( 'click', this._cancelBtnClick ); - - } - - hideControlButtons() { - - if ( this._submitBtn ) { - - this._submitBtn.remove(); - - } - - if ( this._cancelBtn ) { - - this._cancelBtn.removeEventListener( 'click', this._cancelBtnClick ); - this._cancelBtn.remove(); - - } - - } - - _cancelBtnClick() { - - if ( this._cancelBtnClickCustomCallback ) { - - this._cancelBtnClickCustomCallback(); - - } - - } - _displayOriginalMeshes() { this._hiddenOriginalMeshes.forEach( mesh => { @@ -218,7 +167,7 @@ class MultipleSelection { if ( this._pointerMoveCustomCallback ) { - this._pointerMoveCustomCallback( this._selectedMeshes ); + this._pointerMoveCustomCallback( this.selectedMeshes ); } @@ -232,13 +181,13 @@ class MultipleSelection { this._selectionBox.endPoint.set( cursorPosition.x, cursorPosition.y, 0.5 ); - this._selectedMeshes = this._cloneMeshes( this._keepOnlyMeshes( this._selectionBox.select() ) ); + this.selectedMeshes = this._cloneMeshes( this._keepOnlyMeshes( this._selectionBox.select() ) ); - this._hideOriginalMeshes( this._selectedMeshes ); + this._hideOriginalMeshes( this.selectedMeshes ); if ( this._pointerUpCustomCallback ) { - this._pointerUpCustomCallback( this._selectedMeshes ); + this._pointerUpCustomCallback( this.selectedMeshes ); } From 253af73ec31080507e13a0d0eb95050780b52bca Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Tue, 19 Jul 2022 20:29:45 +0300 Subject: [PATCH 09/15] feat: add more specific MultipleSelectionGroup, preserve scale and rotation changes on submit too --- .../AddMultipleSelectionGroupCommand.js | 5 +-- .../RemoveMultipleSelectionGroupCommand.js | 2 +- .../SubmitMultipleSelectionCommand.js | 36 ++++++++++++++++++- editor/js/objects/MultipleSelectionGroup.js | 17 +++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 editor/js/objects/MultipleSelectionGroup.js diff --git a/editor/js/commands/AddMultipleSelectionGroupCommand.js b/editor/js/commands/AddMultipleSelectionGroupCommand.js index 5aacea1c7d21f..2a5a7d198a196 100644 --- a/editor/js/commands/AddMultipleSelectionGroupCommand.js +++ b/editor/js/commands/AddMultipleSelectionGroupCommand.js @@ -1,6 +1,6 @@ -import { Group } from 'three'; import { Command } from '../Command.js'; import { AddObjectCommand } from './AddObjectCommand.js'; +import { MultipleSelectionGroup } from '../objects/MultipleSelectionGroup.js'; class AddMultipleSelectionGroupCommand extends Command { @@ -15,8 +15,9 @@ class AddMultipleSelectionGroupCommand extends Command { execute() { - const group = new Group(); + const group = new MultipleSelectionGroup(); group.name = 'Multiple Selection Group'; + this.meshes.forEach( mesh => group.add( mesh ) ); this.editor.execute( new AddObjectCommand( this.editor, group ) ); diff --git a/editor/js/commands/RemoveMultipleSelectionGroupCommand.js b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js index 81fc152abe50a..d09616526cc9f 100644 --- a/editor/js/commands/RemoveMultipleSelectionGroupCommand.js +++ b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js @@ -13,7 +13,7 @@ class RemoveMultipleSelectionGroupCommand extends Command { execute() { - const group = this.editor.scene.getObjectByName( 'Multiple Selection Group' ); + const group = this.editor.scene.getObjectByProperty( 'type', 'MultipleSelectionGroup' ); if ( group ) { diff --git a/editor/js/commands/SubmitMultipleSelectionCommand.js b/editor/js/commands/SubmitMultipleSelectionCommand.js index e7274da7d3b41..7360ad7d49342 100644 --- a/editor/js/commands/SubmitMultipleSelectionCommand.js +++ b/editor/js/commands/SubmitMultipleSelectionCommand.js @@ -1,5 +1,8 @@ +import { Vector3, Quaternion, Euler } from 'three'; import { Command } from '../Command.js'; import { SetPositionCommand } from './SetPositionCommand.js'; +import { SetScaleCommand } from './SetScaleCommand.js'; +import { SetRotationCommand } from './SetRotationCommand.js'; import { RemoveMultipleSelectionGroupCommand } from './RemoveMultipleSelectionGroupCommand.js'; class SubmitMultipleSelectionCommand extends Command { @@ -13,11 +16,42 @@ class SubmitMultipleSelectionCommand extends Command { } + _getPositionValue( mesh ) { + + const vector = new Vector3(); + mesh.getWorldPosition( vector ); + + return vector; + + } + + _getRotationValue( mesh ) { + + const quaternion = new Quaternion(); + mesh.getWorldQuaternion( quaternion ); + const rotation = new Euler(); + rotation.setFromQuaternion( quaternion ); + + return rotation; + + } + + _getScaleValue( mesh ) { + + const vector = new Vector3(); + mesh.getWorldScale( vector ); + + return vector; + + } + execute() { for ( const selectedMesh of this.multipleSelection.selectedMeshes ) { - this.editor.execute( new SetPositionCommand( this.editor, selectedMesh._original_mesh, selectedMesh.matrixWorld.getPosition() ) ); + this.editor.execute( new SetPositionCommand( this.editor, selectedMesh._original_mesh, this._getPositionValue( selectedMesh ) ) ); + this.editor.execute( new SetScaleCommand( this.editor, selectedMesh._original_mesh, this._getScaleValue( selectedMesh ) ) ); + this.editor.execute( new SetRotationCommand( this.editor, selectedMesh._original_mesh, this._getRotationValue( selectedMesh ) ) ); } diff --git a/editor/js/objects/MultipleSelectionGroup.js b/editor/js/objects/MultipleSelectionGroup.js new file mode 100644 index 0000000000000..e40492ab421d5 --- /dev/null +++ b/editor/js/objects/MultipleSelectionGroup.js @@ -0,0 +1,17 @@ +import { Group } from 'three'; + +class MultipleSelectionGroup extends Group { + + constructor() { + + super(); + + this.type = 'MultipleSelectionGroup'; + + } + +} + +MultipleSelectionGroup.prototype.isGroup = true; + +export { MultipleSelectionGroup }; From eb18708a96ceab5bca08411d122affdadce61cb2 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Wed, 20 Jul 2022 21:28:04 +0300 Subject: [PATCH 10/15] feat: enhance context menu options for multiple selection group --- editor/js/Sidebar.Scene.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/editor/js/Sidebar.Scene.js b/editor/js/Sidebar.Scene.js index c9fd114e20466..de12f7ade309a 100644 --- a/editor/js/Sidebar.Scene.js +++ b/editor/js/Sidebar.Scene.js @@ -379,7 +379,15 @@ function SidebarScene( editor ) { outliner.setOptions( options ); - outliner.setContextMenuOptions( [ 'Copy', 'Cut', 'Paste', 'Clone', 'Delete' ] ); + if ( editor.selected && editor.selected.type === 'MultipleSelectionGroup' ) { + + outliner.setContextMenuOptions( [ 'Cancel', 'Submit' ] ); + + } else { + + outliner.setContextMenuOptions( [ 'Copy', 'Cut', 'Paste', 'Clone', 'Delete' ] ); + + } outliner.onContextMenuChange( function ( value ) { @@ -412,6 +420,14 @@ function SidebarScene( editor ) { editor.execute( new AddObjectCommand( editor, copiedObject, editor.selected ) ); + } else if ( value === 'Submit' ) { + + signals.submitMultipleSelection.dispatch(); + + } else if ( value === 'Cancel' ) { + + signals.cancelMultipleSelection.dispatch(); + } } From c33ea5b4705882f472da1032ac83d09dbdd9f267 Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Wed, 27 Jul 2022 13:45:29 +0300 Subject: [PATCH 11/15] chore: add brief explanation of camera blocking functionality --- editor/js/Viewport.js | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index dd10c6fe3166d..6d6758bd1c61d 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -577,6 +577,7 @@ function Viewport( editor ) { signals.objectRemoved.add( function ( object ) { + // we explicitly prevent manipulations of the camera when multiple selection is enabled if ( multipleSelection.enabled ) return; controls.enabled = true; // see #14180 From 3878f1ab9c71b0f328bf06ceeb81444dc2d72d7f Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Wed, 27 Jul 2022 14:14:45 +0300 Subject: [PATCH 12/15] feat: add "File/Exit" option to the menubar --- editor/js/Editor.js | 1 + editor/js/Menubar.File.js | 14 ++++++++++++++ editor/js/Strings.js | 3 +++ 3 files changed, 18 insertions(+) diff --git a/editor/js/Editor.js b/editor/js/Editor.js index 7fea3ae5b3d9c..83306cfc9a7d1 100644 --- a/editor/js/Editor.js +++ b/editor/js/Editor.js @@ -46,6 +46,7 @@ function Editor( providedDefaultCamera ) { // notifications editorCleared: new Signal(), + editorClosed: new Signal(), savingStarted: new Signal(), savingFinished: new Signal(), diff --git a/editor/js/Menubar.File.js b/editor/js/Menubar.File.js index 59eb58236d139..4118f4f8c042f 100644 --- a/editor/js/Menubar.File.js +++ b/editor/js/Menubar.File.js @@ -8,6 +8,7 @@ function MenubarFile( editor ) { const config = editor.config; const strings = editor.strings; + const signals = editor.signals; const container = new UIPanel(); container.setClass( 'menu' ); @@ -481,6 +482,19 @@ function MenubarFile( editor ) { } ); options.add( option ); + // Exit + option = new UIRow(); + option.setClass( 'option' ); + option.setTextContent( strings.getKey( 'menubar/file/exit' ) ); + option.onClick( function () { + + signals.editorClosed.dispatch(); + + } ); + + options.add( option ); + + // const link = document.createElement( 'a' ); diff --git a/editor/js/Strings.js b/editor/js/Strings.js index bfb15fbccd8e3..46ea3d9a37bf3 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -23,6 +23,7 @@ function Strings( config ) { 'menubar/file/export/stl_binary': 'Export STL (Binary)', 'menubar/file/export/usdz': 'Export USDZ', 'menubar/file/publish': 'Publish', + 'menubar/file/exit': 'Exit', 'menubar/edit': 'Edit', 'menubar/edit/undo': 'Undo (Ctrl+Z)', @@ -361,6 +362,7 @@ function Strings( config ) { 'menubar/file/export/stl_binary': 'Exporter STL (Binaire)', 'menubar/file/export/usdz': 'Exporter USDZ', 'menubar/file/publish': 'Publier', + 'menubar/file/exit': 'Quitter', 'menubar/edit': 'Edition', 'menubar/edit/undo': 'Annuler (Ctrl+Z)', @@ -699,6 +701,7 @@ function Strings( config ) { 'menubar/file/export/stl_binary': '导出STL(二进制)', 'menubar/file/export/usdz': '导出USDZ', 'menubar/file/publish': '发布', + 'menubar/file/exit': '退出', 'menubar/edit': '编辑', 'menubar/edit/undo': '撤销 (Ctrl+Z)', From 2a48f6781b311034db53c0a3a9071e317a0446ff Mon Sep 17 00:00:00 2001 From: fluoxe7ine Date: Wed, 27 Jul 2022 14:43:56 +0300 Subject: [PATCH 13/15] feat: add shortcut info in toolbar button hint text --- editor/js/MultipleSelectionControls.js | 8 +++++--- editor/js/Strings.js | 6 +++--- editor/js/Toolbar.js | 10 ++++++---- editor/js/libs/getToolbarBtnHintText.js | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 editor/js/libs/getToolbarBtnHintText.js diff --git a/editor/js/MultipleSelectionControls.js b/editor/js/MultipleSelectionControls.js index cfdc98c6af00e..3a674ba202b27 100644 --- a/editor/js/MultipleSelectionControls.js +++ b/editor/js/MultipleSelectionControls.js @@ -1,4 +1,5 @@ import { UIButton, UIPanel } from './libs/ui.js'; +import { getToolbarBtnHintText } from './libs/getToolbarBtnHintText.js'; const toggleMultipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIxMC40MTYgMjEwLjQxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEwLjQxNiAyMTAuNDE2OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTIwNi41MTksMTU1Ljg2M2gtMTkuNDgzVjU0LjU1MmgxOS40ODFjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzLjg5N2MwLTIuMTUyLTEuNzQ1LTMuODk3LTMuODk3LTMuODk3aC00Ni43NTkNCgkJCWMtMi4xNTIsMC0zLjg5NywxLjc0NS0zLjg5NywzLjg5N1YyMy4zOEg1NC41NTJWMy44OTdDNTQuNTUyLDEuNzQ1LDUyLjgwNywwLDUwLjY1NSwwSDMuODk3QzEuNzQ1LDAsMCwxLjc0NSwwLDMuODk3djQ2Ljc1OQ0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdIMjMuMzh2MTAxLjMxSDMuODk3Yy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djQ2Ljc1OWMwLDIuMTUyLDEuNzQ1LDMuODk3LDMuODk3LDMuODk3DQoJCQloNDYuNzU5YzIuMTUyLDAsMy44OTctMS43NDUsMy44OTctMy44OTd2LTE5LjQ4M2gxMDEuMzF2MTkuNDgzYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoNDYuNzU5DQoJCQljMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YxNTkuNzZDMjEwLjQxNiwxNTcuNjA4LDIwOC42NzEsMTU1Ljg2MywyMDYuNTE5LDE1NS44NjN6IE0yMDIuNjIxLDcuNzkzdjM4Ljk2NmgtMTUuNTg2aC03Ljc5Mw0KCQkJaC0xNS41ODZWMzEuMTcydi03Ljc5M1Y3Ljc5M0gyMDIuNjIxeiBNMjMuMzc5LDQ2Ljc1OEg3Ljc5M1Y3Ljc5M2gzOC45NjZ2MTUuNTg2djcuNzkzdjE1LjU4NkgzMS4xNzJIMjMuMzc5eiBNNy43OTMsMjAyLjYyMQ0KCQkJdi0zOC45NjZoMTUuNTg2aDcuNzkzaDE1LjU4NnYxNS41ODZ2Ny43OTN2MTUuNTg3SDcuNzkzeiBNMTU5Ljc1OCwxNTUuODYyYy0yLjE1MiwwLTMuODk3LDEuNzQ1LTMuODk3LDMuODk3djE5LjQ4M0g1NC41NTINCgkJCXYtMTkuNDgzYzAtMi4xNTItMS43NDUtMy44OTctMy44OTctMy44OTdIMzEuMTcyVjU0LjU1MmgxOS40ODNjMi4xNTIsMCwzLjg5Ny0xLjc0NSwzLjg5Ny0zLjg5N1YzMS4xNzJoMTAxLjMxdjE5LjQ4Mw0KCQkJYzAsMi4xNTIsMS43NDUsMy44OTcsMy44OTcsMy44OTdoMTkuNDgzdjEwMS4zMWgtMC4wMDFIMTU5Ljc1OHogTTIwMi42MjEsMjAyLjYyMWgtMzguOTY2di0xNS41ODZ2LTcuNzkzdi0xNS41ODZoMTUuNTg2aDcuNzkzDQoJCQloMTUuNTg3VjIwMi42MjF6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; const submitMultipleSelectionImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE4LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDIzNi45ODggMjM2Ljk4OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjM2Ljk4OCAyMzYuOTg4OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8cG9seWdvbiBwb2ludHM9IjE5OC4wOTgsMjQuMzI2IDg3LjU0MywxMzQuODgxIDM4Ljg5MSw4Ni4yMjkgMCwxMjUuMTIxIDg3LjU0MywyMTIuNjYyIDIzNi45ODgsNjMuMjE3ICIvPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo='; @@ -8,13 +9,14 @@ function MultipleSelectionControls( editor ) { const signals = editor.signals; const strings = editor.strings; + const config = editor.config; const container = new UIPanel(); container.setId( 'multiple-selection-buttons' ); // Toggle Button const toggleIcon = document.createElement( 'img' ); - toggleIcon.title = strings.getKey( 'toolbar/toggle-multiple-selection' ); + toggleIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/toggle-multiple-selection' ), config.getKey( 'settings/shortcuts/multiple-selection' ) ); toggleIcon.src = toggleMultipleSelectionImg; const toggleBtn = new UIButton(); @@ -28,7 +30,7 @@ function MultipleSelectionControls( editor ) { // Cancel Button const cancelIcon = document.createElement( 'img' ); - cancelIcon.title = strings.getKey( 'toolbar/cancel-multiple-selection' ); + cancelIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/cancel-multiple-selection' ) ); cancelIcon.src = cancelMultipleSelectionImg; const cancelBtn = new UIButton(); @@ -43,7 +45,7 @@ function MultipleSelectionControls( editor ) { // Submit Button const submitIcon = document.createElement( 'img' ); - submitIcon.title = strings.getKey( 'toolbar/submit-multiple-selection' ); + submitIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/submit-multiple-selection' ) ); submitIcon.src = submitMultipleSelectionImg; const submitBtn = new UIButton(); diff --git a/editor/js/Strings.js b/editor/js/Strings.js index 46ea3d9a37bf3..50fbc9af1d8d5 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -332,9 +332,9 @@ function Strings( config ) { 'toolbar/rotate': 'Rotate', 'toolbar/scale': 'Scale', 'toolbar/local': 'Local', - 'toolbar/toggle-multiple-selection': 'Toggle multiple selection', - 'toolbar/submit-multiple-selection': 'Submit multiple selection', - 'toolbar/cancel-multiple-selection': 'Cancel multiple selection', + 'toolbar/toggle-multiple-selection': 'Toggle Multiple Selection', + 'toolbar/submit-multiple-selection': 'Submit Multiple Selection', + 'toolbar/cancel-multiple-selection': 'Cancel Multiple Selection', 'viewport/info/objects': 'Objects', 'viewport/info/vertices': 'Vertices', diff --git a/editor/js/Toolbar.js b/editor/js/Toolbar.js index 1ba7f90fd9a2f..e04034ed19f48 100644 --- a/editor/js/Toolbar.js +++ b/editor/js/Toolbar.js @@ -1,5 +1,6 @@ -import { UIPanel, UIButton, UICheckbox } from './libs/ui.js'; +import { UIButton, UICheckbox, UIPanel } from './libs/ui.js'; import { MultipleSelectionControls } from './MultipleSelectionControls.js'; +import { getToolbarBtnHintText } from './libs/getToolbarBtnHintText.js'; /* '../images/translate.svg' */ const translateImg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPHBhdGggZD0ibTI1NiAwYy0xLjI0NTIgMC0yLjQ1ODYgMC4xMjc5MS0zLjYzODcgMC4zNTE1Ni0wLjA2NTkgMC4wMTI1NjctMC4xMzM0OSAwLjAxODAwOC0wLjE5OTIyIDAuMDMxMjUtMC41Nzg5NCAwLjExNTk1LTEuMTQ2IDAuMjYzNTctMS43MDUxIDAuNDI5NjktMC4wNDcgMC4wMTM5OS0wLjA5NTcgMC4wMjI3NjctMC4xNDI1OCAwLjAzNzEwOS0xLjgxNTEgMC41NTQzNi0zLjUxNTkgMS4zNjgyLTUuMDYyNSAyLjM5NjUtMC4wMzEyIDAuMDIwNzAzLTAuMDY0NiAwLjAzNzcwNi0wLjA5NTcgMC4wNTg1OTQtMC4zMjU3NiAwLjIxOTMxLTAuNjMyMDEgMC40NjMwNy0wLjk0MzM2IDAuNzAxMTctMC43MDYwNSAwLjUzNzg3LTEuMzkwNiAxLjEwNTktMi4wMjM0IDEuNzQyMmwtNzUuMTggNzUuODI4Yy03LjU2MyA3LjYyOC03LjUwNDggMTkuOTM3IDAuMTE3MTggMjcuNSA3LjYyOCA3LjU1NyAxOS45NDEgNy41MDQ4IDI3LjQ5OC0wLjExNzE5bDQxLjkzMi00Mi4yOTF2MTY5Ljg5aC0xNjkuODhsNDIuMjk1LTQxLjkyNmM3LjYyMi03LjU2MyA3LjY3ODItMTkuODcgMC4xMTUyMy0yNy40OThzLTE5Ljg3Ni03LjY4MDItMjcuNDk4LTAuMTE3MTlsLTc1LjgyOCA3NS4xOGMtMC4wMDI5NyAzZS0zIC0wLjAwNDg1IDdlLTMgLTAuMDA3ODEgMC4wMS0yLjI0NjMgMi4yMzAyLTMuOTUwMSA1LjAwNDEtNC44OTg0IDguMTA5NC0wLjAwNDcwOCAwLjAxNTQtMC4wMDcwNDkgMC4wMzE1LTAuMDExNzE5IDAuMDQ2OS0wLjE3ODM5IDAuNTg5MzUtMC4zMzI2IDEuMTg5Mi0wLjQ1NTA4IDEuODAwOC0wLjAxMzI0OCAwLjA2NTctMC4wMTg2NzcgMC4xMzMzMi0wLjAzMTI1IDAuMTk5MjItMC4xMDY1NSAwLjU2MjIzLTAuMTk4ODMgMS4xMjg4LTAuMjU1ODYgMS43MDctMC4wNjI2NzEgMC42MzUyMi0wLjA5NTcwNiAxLjI3OTQtMC4wOTU3MDYgMS45MzE0czAuMDMzMDM1IDEuMjk2MiAwLjA5NTcwMyAxLjkzMTZjMC4wNTcwMjUgMC41NzgyNCAwLjE0OTMxIDEuMTQ0OCAwLjI1NTg2IDEuNzA3IDAuMDEyNTcyIDAuMDY1OSAwLjAxODAwMyAwLjEzMzQ5IDAuMDMxMjUgMC4xOTkyMiAwLjExNTk1IDAuNTc4OTQgMC4yNjM1NyAxLjE0NiAwLjQyOTY5IDEuNzA1MSAwLjAxNDc2MSAwLjA0OTYgMC4wMjM5MDkgMC4xMDA5MyAwLjAzOTA2MiAwLjE1MDM5IDAuNTY1MDMgMS44NDczIDEuMzk2IDMuNTc4MyAyLjQ1MTIgNS4xNDY1IDAuMzU1MTEgMC41Mjc3NSAwLjczMjkzIDEuMDM4MSAxLjEzNjcgMS41Mjc0IDAuMDAyNjUgM2UtMyAwLjAwNTE2IDdlLTMgMC4wMDc4MSAwLjAxIDAuMDY3MTU4IDAuMDgxNSAwLjE0NjI5IDAuMTUzOTEgMC4yMTQ4NCAwLjIzNDM4IDAuMzM4OTEgMC4zOTY4MSAwLjY4NTM1IDAuNzg4MDEgMS4wNTQ3IDEuMTU2MiAwLjAxMzc2IDAuMDEzNyAwLjAyNTI1NyAwLjAyOTMgMC4wMzkwNjMgMC4wNDNsNzUuODI2IDc1LjE4YzMuNzkxIDMuNzUzIDguNzM3NSA1LjYzMjggMTMuNjg5IDUuNjMyOCA1LjAwMyAwIDEwLjAwNy0xLjkxODkgMTMuODA1LTUuNzU1OSA3LjU2My03LjYyOCA3LjUwNDgtMTkuOTM1LTAuMTE3MTktMjcuNDk4bC00Mi4yODktNDEuOTI2aDE2OS44OXYxNjkuODlsLTQxLjkyNi00Mi4yODljLTcuNTU3LTcuNjM1LTE5Ljg3LTcuNjY3LTI3LjQ5OC0wLjEyMzA1LTcuNjIyIDcuNTYzLTcuNjgwMiAxOS44NzItMC4xMTcxOSAyNy41bDc1LjE4IDc1LjgyNmMzZS0zIDNlLTMgN2UtMyA1ZS0zIDAuMDEgOGUtMyAxLjM0NTggMS4zNTU2IDIuODg4NSAyLjUxNTggNC41ODQgMy40Mjk3IDAuMDYzNyAwLjAzNDMgMC4xMzEyOCAwLjA2MDIgMC4xOTUzMiAwLjA5MzcgMC41MDAwNiAwLjI2MjM5IDEuMDA4NiAwLjUwOTU4IDEuNTMzMiAwLjcyODUyIDAuMDI4NyAwLjAxMiAwLjA1OTEgMC4wMTk0IDAuMDg3OSAwLjAzMTIgMC41NTE0OCAwLjIyNzA2IDEuMTEzOSAwLjQzMjkyIDEuNjg5NCAwLjYwOTM3IDAuMTMwNTkgMC4wNDAxIDAuMjY1MDEgMC4wNjYyIDAuMzk2NDkgMC4xMDM1MiAwLjQ4NDU5IDAuMTM3NDEgMC45NzE0OSAwLjI2OTE2IDEuNDcwNyAwLjM2OTE0IDAuMDY1NyAwLjAxMzIgMC4xMzMzMiAwLjAxODcgMC4xOTkyMiAwLjAzMTIgMS4xNzk4IDAuMjIzNjEgMi4zOTMyIDAuMzUxNTIgMy42Mzg0IDAuMzUxNTIgMS44MTk0IDAgMy41NzItMC4yNjkwOSA1LjI0MjItMC43MzYzMyAwLjE1NTQzLTAuMDQzNSAwLjMxNDU0LTAuMDczOCAwLjQ2ODc1LTAuMTIxMDkgMS4xMDExLTAuMzM3OTIgMi4xNTM5LTAuNzgwMjUgMy4xNjIxLTEuMjk4OCAwLjExNDcyLTAuMDU4OCAwLjIzNDA3LTAuMTA2ODUgMC4zNDc2NS0wLjE2Nzk3IDAuMzcyNTktMC4yMDExMSAwLjcyODQ4LTAuNDI4MTIgMS4wODU5LTAuNjUyMzQgMC4xODY4LTAuMTE2NzYgMC4zODE0My0wLjIyMDUyIDAuNTY0NDUtMC4zNDM3NSAwLjEwNDY3LTAuMDcwNyAwLjE5OTUzLTAuMTUzODggMC4zMDI3NC0wLjIyNjU3IDAuOTM1NzEtMC42NTY3MyAxLjgyNzEtMS4zODU3IDIuNjQ0NS0yLjIwOWw3NS4xOC03NS44MjZjNy41NTYtNy42MjggNy41MDMtMTkuOTM3LTAuMTI1LTI3LjUtNy42MzUtNy41NTctMTkuOTQxLTcuNTA1LTI3LjQ5OCAwLjEyMzA1bC00MS45MzIgNDIuMjk5di0xNjkuOWgxNjkuODlsLTQyLjI5MyA0MS45MjZjLTcuNjI4IDcuNTYzLTcuNjggMTkuODctMC4xMjMwNSAyNy40OTggMy44MDQgMy44MzcgOC44MDc2IDUuNzU1OSAxMy44MTEgNS43NTU5IDQuOTQ1IDAgOS44OTg0LTEuODgwOCAxMy42ODktNS42MzI4bDc1LjgyNi03NS4xOGMwLjAxNDEtMC4wMTQgMC4wMjY5LTAuMDI4OSAwLjA0MS0wLjA0MyAwLjI1MTUtMC4yNTA4IDAuNDgxMjEtMC41MjI5MiAwLjcxODc1LTAuNzg3MTEgMC4xODQ0Ny0wLjIwNTM0IDAuMzgxNjgtMC40MDEwNSAwLjU1NjY0LTAuNjEzMjggMC40MDQtMC40ODk1NSAwLjc4MzM5LTAuOTk5MyAxLjEzODctMS41Mjc0IDAuMDI0OS0wLjAzNzEgMC4wNDM3LTAuMDc3OSAwLjA2ODQtMC4xMTUyMyAwLjMyNzEzLTAuNDkzNSAwLjYzODAyLTAuOTk5NzIgMC45MTk5Mi0xLjUyMzQgMC4wMzI0LTAuMDYwNCAwLjA1NjEtMC4xMjQ4NCAwLjA4NzktMC4xODU1NSAwLjI2MzA2LTAuNTAxMzMgMC41MTEwOS0xLjAxMTIgMC43MzA0Ny0xLjUzNzEgMC4wMTI1LTAuMDMwMSAwLjAyMDgtMC4wNjE3IDAuMDMzMi0wLjA5MTggMC4yMjQ5Ny0wLjU0NzA3IDAuNDI4MzQtMS4xMDUgMC42MDM1Mi0xLjY3NTggMC4wNDczLTAuMTU0MTkgMC4wNzc2LTAuMzEzMzQgMC4xMjEwOS0wLjQ2ODc1IDAuMTMwMTktMC40NjUzNyAwLjI1OTc0LTAuOTMxMzkgMC4zNTU0Ny0xLjQxMDIgMC4wMTI4LTAuMDYzNyAwLjAxNzEtMC4xMjk0OCAwLjAyOTMtMC4xOTMzNiAwLjIyMzYyLTEuMTgwMSAwLjM1MTUzLTIuMzkzNCAwLjM1MTUzLTMuNjM4NiAwLTEuMzEyNS0wLjEzMzAyLTIuNTkyNS0wLjM4MDg2LTMuODMyLTRlLTQgLTJlLTMgLTJlLTMgLTRlLTMgLTJlLTMgLTZlLTMgLTAuMDk1NS0wLjQ3Njc0LTAuMjIzODctMC45NDA4NS0wLjM1MzUyLTEuNDA0My0wLjA0MzUtMC4xNTU0MS0wLjA3MzgtMC4zMTQ1Ni0wLjEyMTA5LTAuNDY4NzUtMC4xODQ3OC0wLjYwMjA3LTAuMzk2NjMtMS4xOTItMC42MzY3Mi0xLjc2NzYtNS42ZS00IC0xZS0zIC0xZS0zIC0zZS0zIC0yZS0zIC00ZS0zIC0wLjI0NTQyLTAuNTg4MDEtMC41MTY1Ny0xLjE2MTctMC44MTY0MS0xLjcxODgtMmUtMyAtM2UtMyAtNGUtMyAtNmUtMyAtNmUtMyAtMC4wMS0wLjMwMTY1LTAuNTU5NjMtMC42MjkyMS0xLjEwMzktMC45ODI0Mi0xLjYyODktOGUtNCAtMWUtMyAtMWUtMyAtM2UtMyAtMmUtMyAtNGUtMyAtMC4zNTQ1OS0wLjUyNjc2LTAuNzMzNjQtMS4wMzUtMS4xMzY3LTEuNTIzNC0wLjE3NDk2LTAuMjEyMjMtMC4zNzIxNy0wLjQwNzk0LTAuNTU2NjQtMC42MTMyOC0wLjIzNzU0LTAuMjY0MTktMC40NjcyNS0wLjUzNjMxLTAuNzE4NzUtMC43ODcxMS0wLjAxNDEtMC4wMTQtMC4wMjY5LTAuMDI5LTAuMDQxLTAuMDQzbC03NS44MjYtNzUuMThjLTcuNjM1LTcuNTYzLTE5Ljk0My03LjUwNDgtMjcuNSAwLjExNzE4LTcuNTU3IDcuNjI4LTcuNTA1IDE5LjkzNSAwLjEyMzA1IDI3LjQ5OGw0Mi4yOTUgNDEuOTMyaC0xNjkuODl2LTE2OS44OWw0MS45MjYgNDIuMjg5YzMuODA0IDMuODM3IDguODA3NiA1Ljc1NTkgMTMuODExIDUuNzU1OSA0Ljk0NSAwIDkuODk1NS0xLjg3MzggMTMuNjg4LTUuNjMyOCA3LjYyOC03LjU2MyA3LjY4LTE5Ljg3MiAwLjEyMzA0LTI3LjVsLTc1LjE4LTc1LjgyNmMtMC4wMTM3LTAuMDEzODA1LTAuMDI5Mi0wLjAyNTMwMy0wLjA0My0wLjAzOTA2My0wLjQ0MTc1LTAuNDQzMDYtMC45MDQxMy0wLjg2NjYyLTEuMzg2Ny0xLjI2NTYtNWUtMyAtMC4wMDM4Mi05ZS0zIC0wLjAwNzktMC4wMTM3LTAuMDExNzE5LTMuMzYwOC0yLjc3MzUtNy42Njg4LTQuNDM5NS0xMi4zNjctNC40Mzk1eiIvPgo8L3N2Zz4K'; @@ -12,6 +13,7 @@ function Toolbar( editor ) { const signals = editor.signals; const strings = editor.strings; + const config = editor.config; const container = new UIPanel(); container.setId( 'toolbar' ); @@ -19,7 +21,7 @@ function Toolbar( editor ) { // translate / rotate / scale const translateIcon = document.createElement( 'img' ); - translateIcon.title = strings.getKey( 'toolbar/translate' ); + translateIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/translate' ), config.getKey( 'settings/shortcuts/translate' ) ); translateIcon.src = translateImg; const translate = new UIButton(); @@ -33,7 +35,7 @@ function Toolbar( editor ) { container.add( translate ); const rotateIcon = document.createElement( 'img' ); - rotateIcon.title = strings.getKey( 'toolbar/rotate' ); + rotateIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/rotate' ), config.getKey( 'settings/shortcuts/rotate' ) ); rotateIcon.src = rotateImg; const rotate = new UIButton(); @@ -46,7 +48,7 @@ function Toolbar( editor ) { container.add( rotate ); const scaleIcon = document.createElement( 'img' ); - scaleIcon.title = strings.getKey( 'toolbar/scale' ); + scaleIcon.title = getToolbarBtnHintText( strings.getKey( 'toolbar/scale' ), config.getKey( 'settings/shortcuts/scale' ) ); scaleIcon.src = scaleImg; const scale = new UIButton(); diff --git a/editor/js/libs/getToolbarBtnHintText.js b/editor/js/libs/getToolbarBtnHintText.js new file mode 100644 index 0000000000000..d9bee375c30a4 --- /dev/null +++ b/editor/js/libs/getToolbarBtnHintText.js @@ -0,0 +1,15 @@ +function getToolbarBtnHintText( optionText, shortcutText ) { + + let result = optionText; + + if ( shortcutText ) { + + result += ' ' + '(' + shortcutText.toUpperCase() + ')'; + + } + + return result; + +} + +export { getToolbarBtnHintText }; From e939741ebfb92b7a3cfba3eddc11dcf5254cbd9f Mon Sep 17 00:00:00 2001 From: Anton Slipchenko Date: Tue, 9 Aug 2022 01:10:28 +0300 Subject: [PATCH 14/15] added rotation functonallity --- editor/js/Viewport.js | 2 ++ .../AddMultipleSelectionGroupCommand.js | 14 +++++++++- .../RemoveMultipleSelectionGroupCommand.js | 7 +++++ examples/jsm/controls/ArcballControls.js | 2 +- examples/jsm/controls/TransformControls.js | 28 +++++++++++++------ examples/jsm/interactive/HTMLMesh.js | 4 +-- examples/jsm/nodes/core/InputNode.js | 2 +- examples/jsm/nodes/core/NodeUtils.js | 2 +- examples/jsm/nodes/lights/LightsNode.js | 6 ++-- examples/jsm/nodes/materials/Materials.js | 2 +- examples/jsm/nodes/shadernode/ShaderNode.js | 10 +++---- .../jsm/renderers/webgl/nodes/WebGLNodes.js | 2 +- examples/jsm/utils/BufferGeometryUtils.js | 2 +- 13 files changed, 58 insertions(+), 25 deletions(-) diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 6d6758bd1c61d..9c4e21cf4beed 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -98,6 +98,7 @@ function Viewport( editor ) { sceneHelpers.add( selectionBox ); const multipleSelection = new MultipleSelection( editor ); + editor.multipleSelection = multipleSelection; multipleSelection.addEventListener( 'pointerdown', () => { @@ -420,6 +421,7 @@ function Viewport( editor ) { signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); + render(); } ); diff --git a/editor/js/commands/AddMultipleSelectionGroupCommand.js b/editor/js/commands/AddMultipleSelectionGroupCommand.js index 2a5a7d198a196..20cf11cfa5f4b 100644 --- a/editor/js/commands/AddMultipleSelectionGroupCommand.js +++ b/editor/js/commands/AddMultipleSelectionGroupCommand.js @@ -1,6 +1,7 @@ import { Command } from '../Command.js'; import { AddObjectCommand } from './AddObjectCommand.js'; import { MultipleSelectionGroup } from '../objects/MultipleSelectionGroup.js'; +import { Group, Sphere, Vector3 } from 'three'; class AddMultipleSelectionGroupCommand extends Command { @@ -20,7 +21,18 @@ class AddMultipleSelectionGroupCommand extends Command { this.meshes.forEach( mesh => group.add( mesh ) ); - this.editor.execute( new AddObjectCommand( this.editor, group ) ); + const positions = this.meshes.map( ( { matrixWorld } ) => { + + return new Vector3().setFromMatrixPosition( matrixWorld ); + + } ); + const sphere = new Sphere().setFromPoints( positions ); + const pivotGroup = new Group(); + pivotGroup.name = 'Pivot Group'; + this.editor.execute( new AddObjectCommand( this.editor, pivotGroup ) ); + this.editor.execute( new AddObjectCommand( this.editor, group, pivotGroup ) ); + pivotGroup.position.set( sphere.center.x, sphere.center.y, sphere.center.z ); + group.position.set( - sphere.center.x, - sphere.center.y, - sphere.center.z ); } diff --git a/editor/js/commands/RemoveMultipleSelectionGroupCommand.js b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js index d09616526cc9f..250f7678915f6 100644 --- a/editor/js/commands/RemoveMultipleSelectionGroupCommand.js +++ b/editor/js/commands/RemoveMultipleSelectionGroupCommand.js @@ -14,6 +14,13 @@ class RemoveMultipleSelectionGroupCommand extends Command { execute() { const group = this.editor.scene.getObjectByProperty( 'type', 'MultipleSelectionGroup' ); + const pivotGroup = this.editor.scene.getObjectByProperty( 'name', 'Pivot Group' ); + + if ( pivotGroup ) { + + this.editor.execute( new RemoveObjectCommand( this.editor, pivotGroup ) ); + + } if ( group ) { diff --git a/examples/jsm/controls/ArcballControls.js b/examples/jsm/controls/ArcballControls.js index e7e57c7b017ab..dd08c5f5f6700 100644 --- a/examples/jsm/controls/ArcballControls.js +++ b/examples/jsm/controls/ArcballControls.js @@ -1040,7 +1040,7 @@ class ArcballControls extends EventDispatcher { } - this._v3_1.setFromMatrixPosition(this._gizmoMatrixState); + this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ); this.applyTransformMatrix( this.scale( size, this._v3_1 ) ); diff --git a/examples/jsm/controls/TransformControls.js b/examples/jsm/controls/TransformControls.js index 16fe1c105aef6..45f8caa61b0a4 100644 --- a/examples/jsm/controls/TransformControls.js +++ b/examples/jsm/controls/TransformControls.js @@ -17,8 +17,9 @@ import { Raycaster, SphereGeometry, TorusGeometry, - Vector3 + Vector3, } from 'three'; +import { MultipleSelectionGroup } from '../../../editor/js/objects/MultipleSelectionGroup.js'; const _raycaster = new Raycaster(); @@ -546,8 +547,19 @@ class TransformControls extends Object3D { // Set current object attach( object ) { - this.object = object; - this.visible = true; + if ( object instanceof MultipleSelectionGroup ) { + + this.object = object.parent; + console.log(this.object, this.mode); + console.log( 'this mode', this.mode ); + + } else { + + this.object = object; + this.visible = true; + + } + return this; @@ -598,7 +610,9 @@ class TransformControls extends Object3D { } setMode( mode ) { - + if (!this.visible) { + this.visible = true; + } this.mode = mode; } @@ -1130,7 +1144,6 @@ class TransformControlsGizmo extends Object3D { this.add( this.helper[ 'scale' ] = setupGizmo( helperScale ) ); // Pickers should be hidden always - this.picker[ 'translate' ].visible = false; this.picker[ 'rotate' ].visible = false; this.picker[ 'scale' ].visible = false; @@ -1146,7 +1159,7 @@ class TransformControlsGizmo extends Object3D { const quaternion = ( space === 'local' ) ? this.worldQuaternion : _identityQuaternion; // Show only gizmos for current transform mode - + //TODO: why do we need this logic if below in cycle we do the same??? this.gizmo[ 'translate' ].visible = this.mode === 'translate'; this.gizmo[ 'rotate' ].visible = this.mode === 'rotate'; this.gizmo[ 'scale' ].visible = this.mode === 'scale'; @@ -1378,7 +1391,6 @@ class TransformControlsGizmo extends Object3D { } else if ( this.mode === 'rotate' ) { // Align handles to current local or world rotation - _tempQuaternion2.copy( quaternion ); _alignVector.copy( this.eye ).applyQuaternion( _tempQuaternion.copy( quaternion ).invert() ); @@ -1528,7 +1540,7 @@ class TransformControlsPlane extends Mesh { case 'rotate': default: // special case for rotate - _dirVector.set( 0, 0, 0 ); + // _dirVector.set( 0, 0, 0 ); } diff --git a/examples/jsm/interactive/HTMLMesh.js b/examples/jsm/interactive/HTMLMesh.js index d9212e8f15ce1..84ed9b384f832 100644 --- a/examples/jsm/interactive/HTMLMesh.js +++ b/examples/jsm/interactive/HTMLMesh.js @@ -249,8 +249,8 @@ function html2canvas( element ) { context.save(); const dpr = window.devicePixelRatio; - context.scale(1/dpr, 1/dpr); - context.drawImage(element, 0, 0 ); + context.scale( 1 / dpr, 1 / dpr ); + context.drawImage( element, 0, 0 ); context.restore(); } else { diff --git a/examples/jsm/nodes/core/InputNode.js b/examples/jsm/nodes/core/InputNode.js index 01268edf9d6a7..5df1e845e26c1 100644 --- a/examples/jsm/nodes/core/InputNode.js +++ b/examples/jsm/nodes/core/InputNode.js @@ -51,7 +51,7 @@ class InputNode extends Node { generate( /*builder, output*/ ) { - console.warn('Abstract function.'); + console.warn( 'Abstract function.' ); } diff --git a/examples/jsm/nodes/core/NodeUtils.js b/examples/jsm/nodes/core/NodeUtils.js index efafa7d776346..42610b7487ce7 100644 --- a/examples/jsm/nodes/core/NodeUtils.js +++ b/examples/jsm/nodes/core/NodeUtils.js @@ -62,7 +62,7 @@ export const getValueType = ( value ) => { export const getValueFromType = ( type, ...params ) => { - const last4 = type?.slice( -4 ); + const last4 = type?.slice( - 4 ); if ( type === 'color' ) { diff --git a/examples/jsm/nodes/lights/LightsNode.js b/examples/jsm/nodes/lights/LightsNode.js index 9c59c5d453ba0..52ac6ebe4da1b 100644 --- a/examples/jsm/nodes/lights/LightsNode.js +++ b/examples/jsm/nodes/lights/LightsNode.js @@ -44,7 +44,7 @@ class LightsNode extends Node { if ( this._hash === null ) { let hash = ''; - + const lightNodes = this.lightNodes; for ( const lightNode of lightNodes ) { @@ -52,9 +52,9 @@ class LightsNode extends Node { hash += lightNode.light.uuid + ' '; } - + this._hash = hash; - + } return this._hash; diff --git a/examples/jsm/nodes/materials/Materials.js b/examples/jsm/nodes/materials/Materials.js index e787b52c793e5..f0ad731894014 100644 --- a/examples/jsm/nodes/materials/Materials.js +++ b/examples/jsm/nodes/materials/Materials.js @@ -47,7 +47,7 @@ NodeMaterial.fromMaterial = function ( material ) { const nodeMaterial = new materialLib[ type ]( material ); - for ( let key in material ) { + for ( const key in material ) { if ( nodeMaterial[ key ] === undefined ) { diff --git a/examples/jsm/nodes/shadernode/ShaderNode.js b/examples/jsm/nodes/shadernode/ShaderNode.js index 9256e7cdc8ac9..3636d64ff038b 100644 --- a/examples/jsm/nodes/shadernode/ShaderNode.js +++ b/examples/jsm/nodes/shadernode/ShaderNode.js @@ -187,17 +187,17 @@ const ints = [ - 1, - 2 ]; const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ]; const boolsCacheMap = new Map(); -for ( let bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); +for ( const bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); const uintsCacheMap = new Map(); -for ( let uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); +for ( const uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ); -for ( let int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); +for ( const int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ); -for ( let float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); -for ( let float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); +for ( const float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); +for ( const float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); export const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; diff --git a/examples/jsm/renderers/webgl/nodes/WebGLNodes.js b/examples/jsm/renderers/webgl/nodes/WebGLNodes.js index 9648f17e23f0d..830173b24a4e0 100644 --- a/examples/jsm/renderers/webgl/nodes/WebGLNodes.js +++ b/examples/jsm/renderers/webgl/nodes/WebGLNodes.js @@ -37,7 +37,7 @@ Material.prototype.onBeforeRender = function ( renderer, scene, camera, geometry nodeFrame.updateNode( node ); } - + } } diff --git a/examples/jsm/utils/BufferGeometryUtils.js b/examples/jsm/utils/BufferGeometryUtils.js index 16024e1d241ef..ce4da6b92f162 100644 --- a/examples/jsm/utils/BufferGeometryUtils.js +++ b/examples/jsm/utils/BufferGeometryUtils.js @@ -98,7 +98,7 @@ function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) { if ( geometry !== _geometry ) { - geometry.copy( _geometry ) + geometry.copy( _geometry ); } From ce2be578ef7c05dd0b8b458e64393ceca8eab940 Mon Sep 17 00:00:00 2001 From: Anton Slipchenko Date: Tue, 9 Aug 2022 01:12:24 +0300 Subject: [PATCH 15/15] resolve lint issues --- examples/jsm/controls/TransformControls.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/jsm/controls/TransformControls.js b/examples/jsm/controls/TransformControls.js index 45f8caa61b0a4..f3f5a5ee285ef 100644 --- a/examples/jsm/controls/TransformControls.js +++ b/examples/jsm/controls/TransformControls.js @@ -550,8 +550,6 @@ class TransformControls extends Object3D { if ( object instanceof MultipleSelectionGroup ) { this.object = object.parent; - console.log(this.object, this.mode); - console.log( 'this mode', this.mode ); } else { @@ -610,9 +608,13 @@ class TransformControls extends Object3D { } setMode( mode ) { - if (!this.visible) { + + if ( ! this.visible ) { + this.visible = true; + } + this.mode = mode; }