浏览代码

[hide] Allow clickables submenus in context menu

Clément Espeute 9 月之前
父节点
当前提交
b8bc608bcc
共有 6 个文件被更改,包括 166 次插入19 次删除
  1. 10 3
      bin/style.css
  2. 13 3
      bin/style.less
  3. 38 0
      hide/comp/Button.hx
  4. 48 12
      hide/comp/ContextMenu.hx
  5. 5 1
      hide/view/animgraph/AnimGraphEditor.hx
  6. 52 0
      hrt/animgraph/nodes/BlendPerBone.hx

+ 10 - 3
bin/style.css

@@ -3943,6 +3943,7 @@ hide-popover hide-content {
 .context-menu2 menu li {
   text-align: left;
   --level: 0;
+  --menu-level: 0;
   --base-padding: 0.2em;
   padding: calc(0.2em);
   padding-left: calc(var(--base-padding) + var(--level) * 0.5em);
@@ -4150,6 +4151,14 @@ hide-popover hide-content {
   --bg-1: #111;
   --bg-2: #222;
 }
+button-2 {
+  min-height: 16px;
+  display: flex;
+  border: var(--basic-border);
+  border-radius: var(--basic-border-radius);
+  padding: var(--basic-padding);
+  background-color: var(--bg-2);
+}
 /** GenericGraphEditor**/
 graph-editor-root {
   width: 100%;
@@ -4230,9 +4239,6 @@ graph-editor-root properties-container {
 graph-editor-root properties-container graph-parameters {
   display: flex;
   flex-direction: column;
-  border: var(--basic-border);
-  border-radius: var(--basic-border-radius);
-  padding: var(--basic-padding);
 }
 graph-editor-root properties-container graph-parameters h1 {
   font-size: 1.2em;
@@ -4243,6 +4249,7 @@ graph-editor-root properties-container graph-parameters > ul {
   flex-direction: column;
   list-style: none;
   align-items: stretch;
+  gap: 2px;
 }
 graph-editor-root properties-container graph-parameters > ul graph-parameter {
   display: flex;

+ 13 - 3
bin/style.less

@@ -4631,9 +4631,11 @@ hide-popover {
 			background-color: #555555;
 		}
 
+
 		li {
 			text-align: left;
 			--level: 0;
+			--menu-level: 0;
 			--base-padding: 0.2em;
 			padding: calc(0.2em);
 			padding-left: calc(var(--base-padding) + var(--level) * 0.5em);
@@ -4907,6 +4909,15 @@ hide-popover {
 	--bg-2: #222;
 }
 
+button-2 {
+	min-height: 16px;
+	display: flex;
+	border: var(--basic-border);
+	border-radius: var(--basic-border-radius);
+	padding: var(--basic-padding);
+	background-color: var(--bg-2);
+}
+
 /** GenericGraphEditor**/
 
 graph-editor-root {
@@ -5007,9 +5018,6 @@ graph-editor-root {
 			display: flex;
 			flex-direction: column;
 
-			border: var(--basic-border);
-			border-radius: var(--basic-border-radius);
-			padding: var(--basic-padding);
 
 			h1 {
 				font-size: 1.2em;
@@ -5021,6 +5029,8 @@ graph-editor-root {
 				flex-direction: column;
 				list-style: none;
 				align-items: stretch;
+
+				gap: 2px;
 				graph-parameter {
 					display: flex;
 					flex-direction: column;

+ 38 - 0
hide/comp/Button.hx

@@ -0,0 +1,38 @@
+package hide.comp;
+
+
+typedef Options = {
+	?hasDropdown: Bool,
+}
+
+/**
+	Dropdown that uses a ContextMenu for it's dropdown element
+**/
+class Button extends hide.comp.Component {
+	public var label(default, set) : String;
+
+	var labelElem : hide.Element;
+	function set_label(newLabel: String) : String {
+		label = newLabel;
+		labelElem.text(label);
+		return label;
+	}
+
+	public function new(parent: hide.Element = null, ?label: String, ?options: Options) {
+		options ??= {};
+		super(parent, new Element("<button-2></button-2>"));
+		labelElem = new Element("<value></value>").appendTo(element);
+
+		this.label = label;
+
+		if (options.hasDropdown) {
+			new Element('<div class="ico ico-chevron-down"></div>').appendTo(element);
+		}
+
+		element.click((e) -> onClick());
+	}
+
+	public dynamic function onClick() {
+
+	}
+}

+ 48 - 12
hide/comp/ContextMenu.hx

@@ -285,12 +285,13 @@ class ContextMenu {
         else if (e.key == "Enter") {
             e.preventDefault();
             if (selected >= 0 && flatItems != null) {
-                if (flatItems[selected].menuItem.menu != null) {
+                if (flatItems[selected].menuItem.click != null) {
+                    flatItems[selected].menuItem.click();
+                }
+                else if (flatItems[selected].menuItem.menu != null) {
                     currentSubmenuItemId = flatItems[selected].index;
                     refreshSubmenu();
                     currentSubmenu.updateSelection(0);
-                } else {
-                    flatItems[selected].elem.click();
                 }
             }
             return true;
@@ -364,7 +365,7 @@ class ContextMenu {
                     if (item.menu != null) {
                         var subItems = filterElements(item.menu, match);
                         if (subItems.length > 0) {
-                            filteredItems.push({label: item.label, menu: subItems});
+                            filteredItems.push({label: item.label, menu: subItems, click: item.click});
                         }
                     }
                     else {
@@ -399,13 +400,30 @@ class ContextMenu {
 
                 var item = top.next();
                 if (item.menu != null) {
-                    var li = js.Browser.document.createLIElement();
-                    menu.appendChild(li);
-                    li.style.setProperty("--level", '${submenuStack.length-1}');
-                    li.innerText = item.label;
-                    li.classList.add("submenu-inline-header");
-                    lastSeparator = null;
-                    submenuStack.push(item.menu.iterator());
+                    if (item.click != null) {
+                        var newItem = {label: item.label, click: item.click, enabled: item.enabled};
+                        var li = createItem(newItem, flatItems.length);
+
+                        menu.appendChild(li);
+                        li.style.setProperty("--level", '${submenuStack.length-1}');
+                        if (item.enabled == null || item.enabled == true) {
+                            flatItems.push({menuItem: item, elem: li, index: flatItems.length});
+                        }
+                        lastSeparator = null;
+                        //li.classList.add("submenu-inline-header");
+
+                        submenuStack.push(item.menu.iterator());
+                    }
+                    else {
+                        var li = js.Browser.document.createLIElement();
+                        menu.appendChild(li);
+                        li.style.setProperty("--level", '${submenuStack.length-1}');
+                        li.style.setProperty("--menu-level", '${submenuStack.length}');
+                        li.innerText = item.label;
+                        li.classList.add("submenu-inline-header");
+                        lastSeparator = null;
+                        submenuStack.push(item.menu.iterator());
+                    }
                 }
                 else {
                     var li = createItem(item, flatItems.length);
@@ -424,6 +442,8 @@ class ContextMenu {
                 lastSeparator.remove();
             }
         }
+
+        refreshPos();
     }
 
     function close() {
@@ -562,7 +582,23 @@ class ContextMenu {
         else {
             selected = newIndex;
             flatItems[selected].elem.classList.add("highlight");
-            flatItems[selected].elem.scrollIntoView({block: cast "nearest"});
+
+            var pos = flatItems[selected].elem.offsetTop;
+            var itemHeight = flatItems[selected].elem.getBoundingClientRect().height;
+
+            var top = menu.scrollTop;
+            var bot = menu.scrollTop + menu.clientHeight;
+
+            trace(pos, top, bot);
+
+
+            if (pos < top + 60) {
+                menu.scrollTo(0, pos - 60);
+            }
+            else if (pos + itemHeight > bot) {
+                menu.scrollTo(0,pos - (bot - top));
+            }
+
         }
     }
 

+ 5 - 1
hide/view/animgraph/AnimGraphEditor.hx

@@ -9,7 +9,7 @@ import hrt.animgraph.*;
 class AnimGraphEditor extends GenericGraphEditor {
 
     var animGraph : hrt.animgraph.AnimGraph;
-    var previewModel : h3d.scene.Object;
+    public var previewModel : h3d.scene.Object;
 
     var parametersList : hide.Element;
     var previewAnimation : AnimGraphInstance = null;
@@ -60,6 +60,10 @@ class AnimGraphEditor extends GenericGraphEditor {
         });
     }
 
+    public function refreshPreview() {
+        setPreview(previewNode);
+    }
+
     public function setPreview(newOutput: hrt.animgraph.nodes.AnimNode) {
         previewNode = newOutput;
 

+ 52 - 0
hrt/animgraph/nodes/BlendPerBone.hx

@@ -48,4 +48,56 @@ class BlendPerBone extends AnimNode {
 			break;
 		}
 	}
+
+	#if editor
+	override function getPropertiesHTML(width:Float):Array<hide.Element> {
+		var arr =  super.getPropertiesHTML(width);
+
+		var button = new hide.comp.Button({hasDropdown: true});
+		button.label = targetBone;
+
+		button.onClick = () -> {
+			var model = getAnimEditor().previewModel;
+			if (model == null)
+				return;
+
+			var skins = model.findAll((o) -> Std.downcast(o, h3d.scene.Skin));
+
+			var menu : Array<hide.comp.ContextMenu.MenuItem> = [];
+
+			function gatherJoints(joint: h3d.anim.Skin.Joint, arr: Array<hide.comp.ContextMenu.MenuItem>) {
+				var subList : Array<hide.comp.ContextMenu.MenuItem> = [];
+				for (sub in joint.subs) {
+					gatherJoints(sub, subList);
+				}
+				arr.push({
+					label: joint.name,
+					menu: subList.length > 0 ? subList : null,
+					click: () -> {targetBone = joint.name; getAnimEditor().refreshPreview(); editor.refreshBox(this.id);},
+				});
+			}
+
+			for (skin in skins) {
+				var item : hide.comp.ContextMenu.MenuItem = {label: skin.name};
+
+				var skinData =skin.getSkinData();
+				var sub : Array<hide.comp.ContextMenu.MenuItem> = [];
+				for (root in skinData.rootJoints) {
+					gatherJoints(root, sub);
+				}
+
+				menu.push({
+					label: skin.name,
+					menu: sub,
+				});
+			}
+
+			hide.comp.ContextMenu.createDropdown(button.element.get(0), menu);
+		};
+
+		button.element.height(16);
+		arr.push(button.element);
+		return arr;
+	}
+	#end
 }