diff --git a/Bonsai.Editor/GraphModel/GraphNode.cs b/Bonsai.Editor/GraphModel/GraphNode.cs index 949c26a7..7f572153 100644 --- a/Bonsai.Editor/GraphModel/GraphNode.cs +++ b/Bonsai.Editor/GraphModel/GraphNode.cs @@ -159,8 +159,7 @@ public bool Highlight public WorkflowElementStatus? Status { get; set; } - public int NotifyingCounter { get; set; } - + public int NotifyingCounter { get; set; } = -1; /// /// Returns a string that represents the value of this instance. diff --git a/Bonsai.Editor/GraphView/GraphViewControl.cs b/Bonsai.Editor/GraphView/GraphViewControl.cs index 77d08852..8a717d48 100644 --- a/Bonsai.Editor/GraphView/GraphViewControl.cs +++ b/Bonsai.Editor/GraphView/GraphViewControl.cs @@ -22,6 +22,7 @@ partial class GraphViewControl : UserControl, IGraphView const float DefaultNodeAirspace = 80; const float DefaultPortSize = 6; const float DefaultLabelTextOffset = 5; + static readonly float SpinnerRotation = (float)Math.Cos(Math.PI / 4); static readonly Color CursorLight = Color.White; static readonly Color CursorDark = Color.Black; static readonly Color NodeEdgeColor = Color.DarkGray; @@ -57,14 +58,17 @@ partial class GraphViewControl : UserControl, IGraphView float PenWidth; float NodeAirspace; float NodeSize; - float HalfSize; float PortSize; + float HalfNodeSize; + float HalfPortSize; + float HalfPenWidth; float LabelTextOffset; SizeF VectorTextOffset; SizeF EntryOffset; SizeF ExitOffset; SizeF InputPortOffset; SizeF OutputPortOffset; + SpinnerOffset[] SpinnerOffsets; Pen SolidPen; Pen DashPen; Font DefaultIconFont; @@ -401,14 +405,28 @@ protected override void ScaleControl(SizeF factor, BoundsSpecified specified) PenWidth = DefaultPenWidth * drawScale; NodeAirspace = DefaultNodeAirspace * drawScale; NodeSize = DefaultNodeSize * drawScale; - HalfSize = NodeSize / 2; PortSize = DefaultPortSize * drawScale; + HalfNodeSize = NodeSize / 2; + HalfPortSize = PortSize / 2; + HalfPenWidth = PenWidth / 2; LabelTextOffset = DefaultLabelTextOffset * drawScale; VectorTextOffset = new SizeF(0, 1.375f * drawScale); - EntryOffset = new SizeF(-2 * PenWidth, HalfSize); - ExitOffset = new SizeF(NodeSize + 2 * PenWidth, HalfSize); - InputPortOffset = new SizeF(-PortSize / 2, EntryOffset.Height - PortSize / 2); - OutputPortOffset = new SizeF(ExitOffset.Width - PortSize / 2, ExitOffset.Height - PortSize / 2); + EntryOffset = new SizeF(-2 * PenWidth, HalfNodeSize); + ExitOffset = new SizeF(NodeSize + 2 * PenWidth, HalfNodeSize); + InputPortOffset = new SizeF(-HalfPortSize, EntryOffset.Height - HalfPortSize); + OutputPortOffset = new SizeF(ExitOffset.Width - HalfPortSize, ExitOffset.Height - HalfPortSize); + + var spinnerTilt = (HalfPortSize - HalfPenWidth) * SpinnerRotation; + SpinnerOffsets = new SpinnerOffset[] + { + new(x1: HalfPortSize, y1: HalfPenWidth, x2: HalfPortSize, y2: PortSize - HalfPenWidth), + new(x1: HalfPortSize + spinnerTilt, y1: HalfPortSize - spinnerTilt, + x2: HalfPortSize - spinnerTilt, y2: HalfPortSize + spinnerTilt), + new(x1: HalfPenWidth, y1: HalfPortSize, x2: PortSize - HalfPenWidth, y2: HalfPortSize), + new(x1: HalfPortSize + spinnerTilt, y1: HalfPortSize + spinnerTilt, + x2: HalfPortSize - spinnerTilt, y2: HalfPortSize - spinnerTilt) + }; + SolidPen = new Pen(NodeEdgeColor, drawScale); DashPen = new Pen(NodeEdgeColor, drawScale) { DashPattern = new[] { 4f, 2f } }; DefaultIconFont = new Font(Font, FontStyle.Bold); @@ -578,7 +596,7 @@ IEnumerable GetRubberBandSelection(Rectangle rect) { if (layout.Node.Value != null) { - var selected = CircleIntersect(layout.Center, HalfSize, selectionRect); + var selected = CircleIntersect(layout.Center, HalfNodeSize, selectionRect); if (selected) { yield return layout.Node; @@ -719,7 +737,7 @@ public GraphNode GetNodeAt(Point point) { if (layout.Node.Value == null) continue; - if (CircleIntersect(layout.Center, HalfSize, point)) + if (CircleIntersect(layout.Center, HalfNodeSize, point)) { return layout.Node; } @@ -1162,10 +1180,11 @@ private void DrawNode( graphics.DrawEllipse(iconRendererState.StrokeStyle(edgeColor, PenWidth), outputPortRectangle); graphics.FillEllipse(outputPortBrush, outputPortRectangle); - if (active && layout.Node.NotifyingCounter != 0) + if (active && layout.Node.NotifyingCounter >= 0) { - var notify1 = new PointF(outputPortRectangle.X + PortSize / 2, outputPortRectangle.Top + PenWidth); - var notify2 = new PointF(outputPortRectangle.X + PortSize / 2, outputPortRectangle.Bottom - PenWidth); + var spinnerIndex = layout.Node.NotifyingCounter % SpinnerOffsets.Length; + var notify1 = outputPortRectangle.Location + SpinnerOffsets[spinnerIndex].Offset1; + var notify2 = outputPortRectangle.Location + SpinnerOffsets[spinnerIndex].Offset2; graphics.DrawLine(iconRendererState.StrokeStyle(CursorDark, PenWidth), notify1, notify2); } } @@ -1401,7 +1420,7 @@ public LayoutNode(GraphViewControl view, GraphNode node, PointF location) public PointF Center { - get { return PointF.Add(Location, new SizeF(View.HalfSize, View.HalfSize)); } + get { return PointF.Add(Location, new SizeF(View.HalfNodeSize, View.HalfNodeSize)); } } public PointF EntryPoint @@ -1430,7 +1449,7 @@ public RectangleF BoundingRectangle { return new RectangleF( InputPortLocation.X - View.PenWidth, Location.Y - View.PenWidth, - View.PortSize / 2 + View.NodeSize + 2 * View.PenWidth, View.NodeSize + 2 * View.PenWidth); + View.HalfPortSize + View.NodeSize + 2 * View.PenWidth, View.NodeSize + 2 * View.PenWidth); } } @@ -1474,5 +1493,17 @@ public void SetNodeLabel(string text, Font font, Graphics graphics) LabelRectangle = new RectangleF(labelLocation, labelSize); } } + + struct SpinnerOffset + { + public SpinnerOffset(float x1, float y1, float x2, float y2) + { + Offset1 = new SizeF(x1, y1); + Offset2 = new SizeF(x2, y2); + } + + public SizeF Offset1; + public SizeF Offset2; + } } } diff --git a/Bonsai.Editor/GraphView/WorkflowGraphView.cs b/Bonsai.Editor/GraphView/WorkflowGraphView.cs index 8dea220c..c3cf723e 100644 --- a/Bonsai.Editor/GraphView/WorkflowGraphView.cs +++ b/Bonsai.Editor/GraphView/WorkflowGraphView.cs @@ -107,17 +107,17 @@ private void WorkflowWatch_Tick(object sender, EventArgs e) node.Status = counter.GetStatus(); if (node.Status == WorkflowElementStatus.Notifying) { - node.NotifyingCounter = (node.NotifyingCounter + 1) % 2; + node.NotifyingCounter++; } else if (node.Status != WorkflowElementStatus.Active) { - node.NotifyingCounter = 0; + node.NotifyingCounter = -1; } } else { node.Status = null; - node.NotifyingCounter = 0; + node.NotifyingCounter = -1; } } }