2
0
Эх сурвалжийг харах

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

Clément Espeute 6 сар өмнө
parent
commit
370a0af6c1

+ 43 - 2
hide/comp/SceneEditor.hx

@@ -1855,8 +1855,49 @@ class SceneEditor {
 					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));

+ 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 }> = [];
 	public var keys(get,null) : Keys;
 	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 viewClass(get, never) : String;
 	public var defaultOptions(get,never) : ViewOptions;
@@ -79,6 +86,29 @@ class View<T> extends hide.comp.Component {
 		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
 	public function setClipboard( v : Dynamic, ?type : String, ?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();
 	}
 
+	/**
+		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.

+ 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 ) {
 		invParent = getAbsPos().clone();
 		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(_) {
 			var options = selectElement.children().elements();