瀏覽代碼

[animgraph] Drag & drop & UI imrpovements

Clément Espeute 8 月之前
父節點
當前提交
e4f2407cd8
共有 3 個文件被更改,包括 97 次插入14 次删除
  1. 12 2
      bin/style.css
  2. 14 2
      bin/style.less
  3. 71 10
      hide/view/animgraph/BlendSpace2DEditor.hx

+ 12 - 2
bin/style.css

@@ -4407,6 +4407,7 @@ blend-space-2d-root main-panel preview-container .hide-toolbar2 {
 }
 }
 blend-space-2d-root main-panel graph-container {
 blend-space-2d-root main-panel graph-container {
   height: 40%;
   height: 40%;
+  position: relative;
   background-color: var(--bg-1);
   background-color: var(--bg-1);
   margin: 16px;
   margin: 16px;
 }
 }
@@ -4446,6 +4447,14 @@ blend-space-2d-root main-panel graph-container svg .preview-axis {
   stroke: #008a00;
   stroke: #008a00;
   stroke-width: 2;
   stroke-width: 2;
 }
 }
+blend-space-2d-root main-panel graph-container drag-handler {
+  z-index: 1;
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  top: 0;
+}
 blend-space-2d-root properties-container {
 blend-space-2d-root properties-container {
   padding: var(--basic-padding);
   padding: var(--basic-padding);
   display: flex;
   display: flex;
@@ -4470,14 +4479,15 @@ blend-space-2d-root properties-container .hide-properties input {
 blend-space-2d-root properties-container .hide-properties dl {
 blend-space-2d-root properties-container .hide-properties dl {
   display: grid;
   display: grid;
   grid-template-columns: 6em minmax(0, 1fr);
   grid-template-columns: 6em minmax(0, 1fr);
-  row-gap: 2px;
-  column-gap: 1em;
+  row-gap: 1px;
+  column-gap: 0.5em;
   width: 100%;
   width: 100%;
 }
 }
 blend-space-2d-root properties-container .hide-properties dl > div {
 blend-space-2d-root properties-container .hide-properties dl > div {
   display: grid;
   display: grid;
   grid-column: 1 / -1;
   grid-column: 1 / -1;
   grid-template-columns: subgrid;
   grid-template-columns: subgrid;
+  align-items: center;
 }
 }
 blend-space-2d-root properties-container .hide-properties dl > div > dt {
 blend-space-2d-root properties-container .hide-properties dl > div > dt {
   width: unset;
   width: unset;

+ 14 - 2
bin/style.less

@@ -5219,6 +5219,8 @@ blend-space-2d-root {
 		graph-container {
 		graph-container {
 			height: 40%;
 			height: 40%;
 
 
+			position: relative;
+
 			background-color: var(--bg-1);
 			background-color: var(--bg-1);
 			margin: 16px;
 			margin: 16px;
 
 
@@ -5267,6 +5269,15 @@ blend-space-2d-root {
 					stroke-width: 2;
 					stroke-width: 2;
 				}
 				}
 			}
 			}
+
+			drag-handler {
+				z-index: 1;
+				position: absolute;
+				left: 0;
+				bottom: 0;
+				right: 0;
+				top: 0;
+			}
 		}
 		}
 	}
 	}
 
 
@@ -5300,14 +5311,15 @@ blend-space-2d-root {
 			dl {
 			dl {
 				display: grid;
 				display: grid;
 				grid-template-columns: 6em minmax(0, 1fr);
 				grid-template-columns: 6em minmax(0, 1fr);
-				row-gap: 2px;
-				column-gap: 1em;
+				row-gap: 1px;
+				column-gap: 0.5em;
 				width: 100%;
 				width: 100%;
 
 
 				> div {
 				> div {
 					display: grid;
 					display: grid;
 					grid-column: 1 / -1;
 					grid-column: 1 / -1;
 					grid-template-columns: subgrid;
 					grid-template-columns: subgrid;
+					align-items: center;
 					> dt {
 					> dt {
 						width: unset;
 						width: unset;
 						text-align: right;
 						text-align: right;

+ 71 - 10
hide/view/animgraph/BlendSpace2DEditor.hx

@@ -92,7 +92,10 @@ class BlendSpace2DEditor extends hide.view.FileView {
 				var movingPreview = false;
 				var movingPreview = false;
 				var svg: js.html.svg.SVGElement = cast graph.element.get(0);
 				var svg: js.html.svg.SVGElement = cast graph.element.get(0);
 
 
-				svg.onpointerdown = (e:js.html.PointerEvent) -> {
+				// We use a div instead to catch the drag event instead of the svg because the svg getting repainted messes with the mouse cursor drag preview
+				var dragHandler = new Element("<drag-handler>").appendTo(graphContainer).get(0);
+
+				dragHandler.onpointerdown = (e:js.html.PointerEvent) -> {
 					if (e.button != 0)
 					if (e.button != 0)
 						return;
 						return;
 
 
@@ -115,11 +118,14 @@ class BlendSpace2DEditor extends hide.view.FileView {
 							return;
 							return;
 					}
 					}
 
 
-					svg.setPointerCapture(e.pointerId);
+					dragHandler.setPointerCapture(e.pointerId);
 					e.preventDefault();
 					e.preventDefault();
 				}
 				}
 
 
-				svg.onpointermove = (e:js.html.PointerEvent) -> {
+
+
+
+				dragHandler.onpointermove = (e:js.html.PointerEvent) -> {
 					if (movingPreview) {
 					if (movingPreview) {
 						var pt = getPointPos(e.clientX, e.clientY, false);
 						var pt = getPointPos(e.clientX, e.clientY, false);
 
 
@@ -161,7 +167,7 @@ class BlendSpace2DEditor extends hide.view.FileView {
 					refreshGraph();
 					refreshGraph();
 				}
 				}
 
 
-				svg.onpointerup = (e:js.html.PointerEvent) -> {
+				dragHandler.onpointerup = (e:js.html.PointerEvent) -> {
 					if (movingPreview) {
 					if (movingPreview) {
 						movingPreview = false;
 						movingPreview = false;
 						refreshPropertiesPannel();
 						refreshPropertiesPannel();
@@ -199,7 +205,7 @@ class BlendSpace2DEditor extends hide.view.FileView {
 					movedPoint = -1;
 					movedPoint = -1;
 				}
 				}
 
 
-				svg.oncontextmenu = (e:js.html.MouseEvent) -> {
+				dragHandler.oncontextmenu = (e:js.html.MouseEvent) -> {
 					e.preventDefault();
 					e.preventDefault();
 
 
 					var options : Array<hide.comp.ContextMenu.MenuItem> = [];
 					var options : Array<hide.comp.ContextMenu.MenuItem> = [];
@@ -238,18 +244,48 @@ class BlendSpace2DEditor extends hide.view.FileView {
 					hide.comp.ContextMenu.createFromEvent(e, options);
 					hide.comp.ContextMenu.createFromEvent(e, options);
 				}
 				}
 
 
-				svg.ondragover = (e:js.html.DragEvent) -> {
+				dragHandler.ondragover = (e:js.html.DragEvent) -> {
 					if (e.dataTransfer.types.contains(AnimList.dragEventKey)) {
 					if (e.dataTransfer.types.contains(AnimList.dragEventKey)) {
 						e.preventDefault();
 						e.preventDefault();
+
+						var mouse = inline new h2d.col.Point(e.clientX - cachedRect.x, e.clientY - cachedRect.y);
+
+						hoverPoint = -1;
+						for (id => point in blendSpace2D.points) {
+							var pt = inline new h2d.col.Point(localXToGraph(point.x), localYToGraph(point.y));
+							if (mouse.distanceSq(pt) < pointRadius * pointRadius) {
+								hoverPoint = id;
+								break;
+							}
+						}
+
+						refreshGraph();
 					}
 					}
 				}
 				}
 
 
-				svg.ondrop = (e:js.html.DragEvent) -> {
+				dragHandler.ondrop = (e:js.html.DragEvent) -> {
 					if (e.dataTransfer.types.contains(AnimList.dragEventKey)) {
 					if (e.dataTransfer.types.contains(AnimList.dragEventKey)) {
+
+						var path = e.dataTransfer.getData(AnimList.dragEventKey);
+						if (path.length <= 0)
+							return;
+
 						e.preventDefault();
 						e.preventDefault();
 
 
-							var pos = getPointPos(e.clientX, e.clientY, true);
-							addPoint({x: pos.x, y: pos.y, animPath: e.dataTransfer.getData(AnimList.dragEventKey)}, true);
+						if (hoverPoint >= 0) {
+							var old = blendSpace2D.points[hoverPoint].animPath;
+							blendSpace2D.points[hoverPoint].animPath = path;
+							undo.change(Field(blendSpace2D.points[hoverPoint], "animPath", old), () -> {
+								refreshPropertiesPannel();
+								refreshPreviewAnimation();
+							});
+							refreshPropertiesPannel();
+							refreshPreviewAnimation();
+						}
+						else {
+							var pos = getPointPos(e.clientX, e.clientY, false);
+							addPoint({x: pos.x, y: pos.y, animPath: path}, true);
+						}
 					}
 					}
 				}
 				}
 			}
 			}
@@ -390,12 +426,37 @@ class BlendSpace2DEditor extends hide.view.FileView {
 								blendSpace2D.points[selectedPoint].animPath = path;
 								blendSpace2D.points[selectedPoint].animPath = path;
 								undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
 								undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
 									button.label = blendSpace2D.points[selectedPoint].animPath;
 									button.label = blendSpace2D.points[selectedPoint].animPath;
+									refreshPreviewAnimation();
 								});
 								});
+								button.label = blendSpace2D.points[selectedPoint].animPath;
+								refreshPreviewAnimation();
 							}, true);
 							}, true);
 						}
 						}
 					}
 					}
 				], {search: Visible, autoWidth: true});
 				], {search: Visible, autoWidth: true});
 			};
 			};
+
+			button.element.get(0).ondragover = (e:js.html.DragEvent) -> {
+				if (e.dataTransfer.types.contains(AnimList.dragEventKey))
+					e.preventDefault();
+			};
+
+			button.element.get(0).ondrop = (e:js.html.DragEvent) -> {
+				var data = e.dataTransfer.getData(AnimList.dragEventKey);
+				if (data.length == 0)
+					return;
+				e.preventDefault();
+
+				var old = blendSpace2D.points[selectedPoint].animPath;
+				blendSpace2D.points[selectedPoint].animPath = data;
+				undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
+					button.label = blendSpace2D.points[selectedPoint].animPath;
+					refreshPreviewAnimation();
+				});
+
+				button.label = blendSpace2D.points[selectedPoint].animPath;
+				refreshPreviewAnimation();
+			};
 		}
 		}
 
 
 		propsEditor.add(new hide.Element('
 		propsEditor.add(new hide.Element('
@@ -474,7 +535,7 @@ class BlendSpace2DEditor extends hide.view.FileView {
 			} else {
 			} else {
 				blendSpace2D.points.splice(index, 1);
 				blendSpace2D.points.splice(index, 1);
 				blendSpace2D.triangulate();
 				blendSpace2D.triangulate();
-				if (select)
+				if (select || selectedPoint == index)
 					setSelection(prevSelection);
 					setSelection(prevSelection);
 			}
 			}
 			refreshGraph();
 			refreshGraph();