Browse Source

Merge pull request #19642 from mrdoob/editor

Editor: Implemented collapsable outliner items
Mr.doob 5 years ago
parent
commit
0a66ba5f84
3 changed files with 100 additions and 17 deletions
  1. 23 4
      editor/css/main.css
  2. 71 7
      editor/js/Sidebar.Scene.js
  3. 6 6
      editor/js/libs/ui.three.js

+ 23 - 4
editor/css/main.css

@@ -135,9 +135,27 @@ textarea, input { outline: none; } /* osx */
 
 /* outliner */
 
+#outliner .opener {
+	display: inline-block;
+	width: 14px;
+	height: 14px;
+	margin: 0px 4px;
+	vertical-align: top;
+	text-align: center;
+}
+
+	#outliner .opener.open:after {
+		content: '−';
+	}
+
+	#outliner .opener.closed:after {
+		content: '+';
+	}
+
 #outliner .option {
 
 	border: 1px solid transparent;
+
 }
 
 #outliner .option.drag {
@@ -159,14 +177,15 @@ textarea, input { outline: none; } /* osx */
 }
 
 #outliner .type {
-	position:relative;
-	top:-2px;
-	padding: 0 2px;
+	display: inline-block;
+	width: 14px;
+	height: 14px;
 	color: #ddd;
+	text-align: center;
 }
 
 #outliner .type:after {
-	content: '';
+	content: '';
 }
 
 #outliner .Scene {

+ 71 - 7
editor/js/Sidebar.Scene.js

@@ -16,6 +16,8 @@ function SidebarScene( editor ) {
 
 	// outliner
 
+	var nodeStates = new WeakMap();
+
 	function buildOption( object, draggable ) {
 
 		var option = document.createElement( 'div' );
@@ -23,6 +25,32 @@ function SidebarScene( editor ) {
 		option.innerHTML = buildHTML( object );
 		option.value = object.id;
 
+		// opener
+
+		if ( nodeStates.has( object ) ) {
+
+			var state = nodeStates.get( object );
+
+			var opener = document.createElement( 'span' );
+			opener.classList.add( 'opener' );
+
+			if ( object.children.length > 0 ) {
+
+				opener.classList.add( state ? 'open' : 'closed' );
+
+			}
+
+			opener.addEventListener( 'click', function () {
+
+				nodeStates.set( object, nodeStates.get( object ) === false ); // toggle
+				refreshUI();
+
+			}, false );
+
+			option.insertBefore( opener, option.firstChild );
+
+		}
+
 		return option;
 
 	}
@@ -60,15 +88,15 @@ function SidebarScene( editor ) {
 
 	function buildHTML( object ) {
 
-		var html = '<span class="type ' + object.type + '"></span> ' + escapeHTML( object.name );
+		var html = `<span class="type ${ object.type }"></span> ${ escapeHTML( object.name ) }`;
 
 		if ( object.isMesh ) {
 
 			var geometry = object.geometry;
 			var material = object.material;
 
-			html += ' <span class="type ' + geometry.type + '"></span> ' + escapeHTML( geometry.name );
-			html += ' <span class="type ' + material.type + '"></span> ' + escapeHTML( getMaterialName( material ) );
+			html += ` <span class="type ${ geometry.type }"></span> ${ escapeHTML( geometry.name ) }`;
+			html += ` <span class="type ${ material.type }"></span> ${ escapeHTML( getMaterialName( material ) ) }`;
 
 		}
 
@@ -300,15 +328,25 @@ function SidebarScene( editor ) {
 
 				var object = objects[ i ];
 
+				if ( nodeStates.has( object ) === false ) {
+
+					nodeStates.set( object, false );
+
+				}
+
 				var option = buildOption( object, true );
-				option.style.paddingLeft = ( pad * 10 ) + 'px';
+				option.style.paddingLeft = ( pad * 18 ) + 'px';
 				options.push( option );
 
-				addObjects( object.children, pad + 1 );
+				if ( nodeStates.get( object ) === true ) {
+
+					addObjects( object.children, pad + 1 );
+
+				}
 
 			}
 
-		} )( scene.children, 1 );
+		} )( scene.children, 0 );
 
 		outliner.setOptions( options );
 
@@ -421,7 +459,33 @@ function SidebarScene( editor ) {
 
 		if ( ignoreObjectSelectedSignal === true ) return;
 
-		outliner.setValue( object !== null ? object.id : null );
+		if ( object !== null ) {
+
+			let needsRefresh = false;
+			let parent = object.parent;
+
+			while ( parent !== editor.scene ) {
+
+				if ( nodeStates.get( parent ) !== true ) {
+
+					nodeStates.set( parent, true );
+					needsRefresh = true;
+
+				}
+
+				parent = parent.parent;
+
+			}
+
+			if ( needsRefresh ) refreshUI();
+
+			outliner.setValue( object.id );
+
+		} else {
+
+			outliner.setValue( null );
+
+		}
 
 	} );
 

+ 6 - 6
editor/js/libs/ui.three.js

@@ -584,16 +584,16 @@ UIOutliner.prototype.setOptions = function ( options ) {
 
 		scope.options.push( div );
 
-		div.addEventListener( 'click', onClick, false );
+		div.addEventListener( 'click', onClick );
 
 		if ( div.draggable === true ) {
 
-			div.addEventListener( 'drag', onDrag, false );
-			div.addEventListener( 'dragstart', onDragStart, false ); // Firefox needs this
+			div.addEventListener( 'drag', onDrag );
+			div.addEventListener( 'dragstart', onDragStart ); // Firefox needs this
 
-			div.addEventListener( 'dragover', onDragOver, false );
-			div.addEventListener( 'dragleave', onDragLeave, false );
-			div.addEventListener( 'drop', onDrop, false );
+			div.addEventListener( 'dragover', onDragOver );
+			div.addEventListener( 'dragleave', onDragLeave );
+			div.addEventListener( 'drop', onDrop );
 
 		}