소스 검색

[scene] Add per prefab contextMenu items, meshSpray setToGround via ctx menu

Clément Espeute 6 달 전
부모
커밋
370a0af6c1
4개의 변경된 파일127개의 추가작업 그리고 34개의 파일을 삭제
  1. 43 2
      hide/comp/SceneEditor.hx
  2. 31 1
      hide/ui/View.hx
  3. 10 0
      hrt/prefab/Prefab.hx
  4. 43 31
      hrt/prefab/l3d/MeshSpray.hx

+ 43 - 2
hide/comp/SceneEditor.hx

@@ -1855,8 +1855,49 @@ class SceneEditor {
 					menuItems.push({ label : "Tag", menu: menu });
 					menuItems.push({ label : "Tag", menu: menu });
 			}
 			}
 
 
-			menuItems.push({ isSeparator : true, label : "" });
-			hide.comp.ContextMenu.createFromEvent(cast e, cast menuItems.concat(actionItems));
+			menuItems.push({ isSeparator : true, label : "Actions" });
+
+			menuItems = menuItems.concat(actionItems);
+
+			var customContextMenus: Map<String, Array<hide.comp.ContextMenu.MenuItem>> = [];
+			for (prefab in selectedPrefabs) {
+				var entries = prefab.editorOnContextMenu();
+				for (entry in entries) {
+					var subArray = MapUtils.getOrPut(customContextMenus, entry.label, []);
+					subArray.push(entry);
+				}
+			}
+
+			if (customContextMenus.iterator().hasNext()) {
+				menuItems.push({ isSeparator : true, label : "Prefabs" });
+
+
+
+					for (name => entries in customContextMenus) {
+						menuItems.push({label: name, click: () -> {
+
+							// Create a new undo stack so if the click handler handles
+							// undo/redo, we wrap all the undo/redos in a single operation
+							view.pushUndoStack();
+
+							try {
+								for (entry in entries) {
+									if (entry.click != null) {
+										entry.click();
+									}
+								}
+							} catch (e) {
+								// restore the undo stack in case of a exception returing us early
+								view.popUndoStack();
+								throw e;
+							}
+
+							view.popUndoStack();
+						}});
+					}
+			}
+
+			hide.comp.ContextMenu.createFromEvent(cast e, menuItems);
 		};
 		};
 
 
 		tree.element.parent().contextmenu(ctxMenu.bind(tree));
 		tree.element.parent().contextmenu(ctxMenu.bind(tree));

+ 31 - 1
hide/ui/View.hx

@@ -22,7 +22,14 @@ class View<T> extends hide.comp.Component {
 	var watches : Array<{ keep : Bool, path : String, callb : Void -> Void }> = [];
 	var watches : Array<{ keep : Bool, path : String, callb : Void -> Void }> = [];
 	public var keys(get,null) : Keys;
 	public var keys(get,null) : Keys;
 	public var state(default, null) : T;
 	public var state(default, null) : T;
-	public var undo(default, null) = new hide.ui.UndoHistory();
+	public var undo(get, null) = new hide.ui.UndoHistory();
+
+	function get_undo() : hide.ui.UndoHistory {
+		return undoStack[undoStack.length-1];
+	}
+
+	var undoStack: Array<UndoHistory> = [new hide.ui.UndoHistory()];
+
 	public var config(get, null) : Config;
 	public var config(get, null) : Config;
 	public var viewClass(get, never) : String;
 	public var viewClass(get, never) : String;
 	public var defaultOptions(get,never) : ViewOptions;
 	public var defaultOptions(get,never) : ViewOptions;
@@ -79,6 +86,29 @@ class View<T> extends hide.comp.Component {
 		return Type.getClassName(Type.getClass(this));
 		return Type.getClassName(Type.getClass(this));
 	}
 	}
 
 
+	/**
+		Push a new "UndoStack", that will collect all the new undo.change until
+		popUndoStack is called
+	**/
+	public function pushUndoStack() {
+		undoStack.push(new UndoHistory());
+	}
+
+	/**
+		Pop the last pushUndoStack operation, creating a unique undo operation that contains all the changes were
+		recorded in the undo buffer if any were created
+	**/
+	public function popUndoStack() {
+		if (undoStack.length <= 1) {
+			throw "trying to pop while there is only one or less undoes on the stack";
+		}
+		var top = undoStack.pop();
+
+		@:privateAccess if (undo.undoElts.length > 0) {
+			undo.change(top.toElement());
+		}
+	}
+
 	#if !hl
 	#if !hl
 	public function setClipboard( v : Dynamic, ?type : String, ?opts : {} ) {
 	public function setClipboard( v : Dynamic, ?type : String, ?opts : {} ) {
 		nw.Clipboard.get().set(ide.toJSON({ type : type == null ? viewClass : type, value : v, opts : opts }));
 		nw.Clipboard.get().set(ide.toJSON({ type : type == null ? viewClass : type, value : v, opts : opts }));

+ 10 - 0
hrt/prefab/Prefab.hx

@@ -610,6 +610,16 @@ class Prefab {
 		dispose();
 		dispose();
 	}
 	}
 
 
+	/**
+		Return an array of entries to add to the scene context menu. Items with the same
+		name are grouped and executed together (when multiple prefabs are selected for example).
+		At the moment only click is supported for the menuItem.
+		See SceneEditor.onSceneReady.ctxMenu to add more features
+	**/
+	function editorOnContextMenu() : Array<hide.comp.ContextMenu.MenuItem> {
+		return [];
+	}
+
 
 
 	/**
 	/**
 		Called by the editor to remove the objects created by this prefab but not its children.
 		Called by the editor to remove the objects created by this prefab but not its children.

+ 43 - 31
hrt/prefab/l3d/MeshSpray.hx

@@ -629,6 +629,48 @@ class MeshSpray extends Spray {
 		};
 		};
 	}
 	}
 
 
+	override function editorOnContextMenu(): Array<hide.comp.ContextMenu.MenuItem> {
+		var items = super.editorOnContextMenu();
+		items.push({
+			label: "Set To Ground",
+			click: setToGround,
+		});
+		return items;
+	}
+
+	function setToGround() {
+		var mso = cast(local3d,MeshSprayObject);
+		var undo = undo;
+		undo.change(Custom(function(undo) {
+		}));
+		for( c in this.children ) {
+			var obj = c.to(Object3D);
+			if( obj == null ) continue;
+			setGroundPos(obj);
+			obj.applyTransform();
+			wasEdited = true;
+		}
+		if ( this.binaryMeshes != null ) {
+			var pos = new h3d.col.Point(0,0,0);
+			for ( bm in this.binaryMeshes ) {
+				var pivot = mso.getAbsPos();
+				pos.x = bm.x + pivot.tx;
+				pos.y = bm.y + pivot.ty;
+				pos.z = bm.z + pivot.tz;
+				var ground = setGroundPos(null, pos);
+				bm.z += ground.mz;
+				bm.rotX = ground.rotX;
+				bm.rotY = ground.rotY;
+				bm.rotZ = ground.rotZ;
+			}
+			if ( this.binaryMeshes.length > 0) {
+				wasEdited = true;
+				binaryChanged = true;
+			}
+		}
+		mso.redraw();
+	}
+
 	override function edit( ectx : hide.prefab.EditContext ) {
 	override function edit( ectx : hide.prefab.EditContext ) {
 		invParent = getAbsPos().clone();
 		invParent = getAbsPos().clone();
 		invParent.invert();
 		invParent.invert();
@@ -909,37 +951,7 @@ class MeshSpray extends Spray {
 			});
 			});
 		});
 		});
 
 
-		options.find("#toground").click(function(_) {
-			var mso = cast(local3d,MeshSprayObject);
-			undo.change(Custom(function(undo) {
-			}));
-			for( c in this.children ) {
-				var obj = c.to(Object3D);
-				if( obj == null ) continue;
-				setGroundPos(obj);
-				obj.applyTransform();
-				wasEdited = true;
-			}
-			if ( this.binaryMeshes != null ) {
-				var pos = new h3d.col.Point(0,0,0);
-				for ( bm in this.binaryMeshes ) {
-					var pivot = mso.getAbsPos();
-					pos.x = bm.x + pivot.tx;
-					pos.y = bm.y + pivot.ty;
-					pos.z = bm.z + pivot.tz;
-					var ground = setGroundPos(null, pos);
-					bm.z += ground.mz;
-					bm.rotX = ground.rotX;
-					bm.rotY = ground.rotY;
-					bm.rotZ = ground.rotZ;
-				}
-				if ( this.binaryMeshes.length > 0) {
-					wasEdited = true;
-					binaryChanged = true;
-				}
-			}
-			mso.redraw();
-		});
+		options.find("#toground").click((e) -> setToGround);
 
 
 		options.find("#remove").click(function(_) {
 		options.find("#remove").click(function(_) {
 			var options = selectElement.children().elements();
 			var options = selectElement.children().elements();