private void UpdateControl(D2dAdaptableControl source, D2dAdaptableControl target, Point cpt) { target.Context = source.Context; if (target.Context == null) { return; } // transform current mouse point to graph space. var srcXform = source.As <ITransformAdapter>(); Matrix3x2F mtrx = Matrix3x2F.Invert(srcXform.Transform); var gpt = Matrix3x2F.TransformPoint(mtrx, cpt); var targetXform = target.As <ITransformAdapter>(); var csz = target.ClientSize; PointF translation = new PointF(csz.Width / 2 - gpt.X * targetXform.Scale.X, csz.Height / 2 - gpt.Y * targetXform.Scale.Y); targetXform.Translation = translation; var edgeEditor = source.As <D2dGraphEdgeEditAdapter <Module, Connection, ICircuitPin> >(); m_activeEdgeEditor = (edgeEditor != null && edgeEditor.IsDraggingEdge) ? edgeEditor : null; target.Invalidate(); }
protected override void OnMouseDown(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left || !IsContextValid()) { return; } var sourceControl = m_birdEyeView.m_sourceControl; var srcXformAdapter = sourceControl.Cast <ITransformAdapter>(); var srcInvXform = Matrix3x2F.Invert(srcXformAdapter.Transform); var grect = Matrix3x2F.Transform(srcInvXform, sourceControl.ClientRectangle); var inxXform = Matrix3x2F.Invert(m_transformAdapter.Transform); var gpt = Matrix3x2F.TransformPoint(inxXform, e.Location); if (!grect.Contains(gpt)) { var srcScale = srcXformAdapter.Scale; float gcx = grect.X + grect.Width / 2; float gcy = grect.Y + grect.Height / 2; grect.X += gpt.X - gcx; grect.Y += gpt.Y - gcy; float tx = -grect.X * srcScale.X; float ty = -grect.Y * srcScale.Y; srcXformAdapter.Translation = new PointF(tx, ty); } m_hitGpt.X = gpt.X - grect.X; m_hitGpt.Y = gpt.Y - grect.Y; base.OnMouseDown(sender, e); AdaptedControl.Capture = true; }
/// <summary> /// Performs hit testing for rectangle bounds, in client coordinates</summary> /// <param name="pickRect">Pick rectangle, in client coordinates</param> /// <returns>Items that overlap with the rectangle, in client coordinates</returns> public virtual IEnumerable <object> Pick(Rectangle pickRect) { Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform); RectangleF rect = D2dUtil.Transform(invXform, pickRect); return(m_renderer.Pick(m_graph, rect, m_d2dGraphics)); }
private void control_MouseWheel(object sender, MouseEventArgs e) { if (!AdaptedControl.ClientRectangle.Contains(e.Location)) { return; } if (e.Button != MouseButtons.None || !IsContextValid()) { return; } // apply transformation to source control. var sourceControl = m_birdEyeView.m_sourceControl; var srcXformAdapter = sourceControl.Cast <ITransformAdapter>(); var srcInvXform = Matrix3x2F.Invert(srcXformAdapter.Transform); var grect = Matrix3x2F.Transform(srcInvXform, sourceControl.ClientRectangle); var inxXform = Matrix3x2F.Invert(m_transformAdapter.Transform); var gpt = Matrix3x2F.TransformPoint(inxXform, e.Location); if (!grect.Contains(gpt)) { return; } // zoom at the center of the grect. gpt.X = grect.X + grect.Width / 2; gpt.Y = grect.Y + grect.Height / 2; // transform gpt to client space of sourcecontrol. var srcCpt = Matrix3x2F.TransformPoint(srcXformAdapter.Transform, gpt); PointF translation = srcXformAdapter.Translation; PointF scale = srcXformAdapter.Scale; PointF scaleCenterStart = new PointF( (srcCpt.X - translation.X) / scale.X, (srcCpt.Y - translation.Y) / scale.Y); float delta = 1.0f + e.Delta / 1200.0f; scale = new PointF( scale.X * delta, scale.Y * delta); // constrain scale before calculating translation to maintain scroll center position scale = srcXformAdapter.ConstrainScale(scale); translation = new PointF( srcCpt.X - scaleCenterStart.X * scale.X, srcCpt.Y - scaleCenterStart.Y * scale.Y); srcXformAdapter.SetTransform( scale.X, scale.Y, translation.X, translation.Y); }
/// <summary> /// Transforms point by inverse transform</summary> /// <param name="matrix">Matrix representing transform</param> /// <param name="p">Point</param> /// <returns>Inverse transformed point</returns> public static Point InverseTransform(Matrix3x2F matrix, Point p) { Matrix3x2F inverse = matrix; inverse.Invert(); s_tempPtsF[0] = p; s_tempPtsF[0] = Matrix3x2F.TransformPoint(inverse, s_tempPtsF[0]); return(new Point((int)s_tempPtsF[0].X, (int)s_tempPtsF[0].Y)); }
/// <summary> /// Performs hit testing for rectangle bounds, in client coordinates</summary> /// <param name="pickRect">Pick rectangle, in client coordinates</param> /// <returns>Items that overlap with the rectangle, in client coordinates</returns> public override IEnumerable <object> Pick(Rectangle pickRect) { #if CS_4 Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform); RectangleF rect = D2dUtil.Transform(invXform, pickRect); IEnumerable <object> pickedGraphNodes = base.Pick(pickRect); #else // workaround a C#3 compiler bug( CS1911 warning) Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform); RectangleF rect = D2dUtil.Transform(invXform, pickRect); List <object> pickedGraphNodes = new List <object>(); foreach (TNode node in m_graph.Nodes) { RectangleF nodeBounds = m_renderer.GetBounds(node, m_d2dGraphics); // in graph space if (nodeBounds.IntersectsWith(rect)) { pickedGraphNodes.Add(node); } } #endif foreach (var pickedGraphNode in pickedGraphNodes) { yield return(pickedGraphNode); } var pickedFloatingPins = new List <object>(); var circuiElement = m_graph.Cast <ICircuitElementType>(); foreach (var pin in circuiElement.Inputs) { var grpPIn = pin.Cast <ICircuitGroupPin <TNode> >(); RectangleF nodeBounds = m_renderer.GetBounds(grpPIn, true, m_d2dGraphics); if (nodeBounds.IntersectsWith(rect)) { pickedFloatingPins.Add(pin); } } foreach (var pin in circuiElement.Outputs) { var grpPIn = pin.Cast <ICircuitGroupPin <TNode> >(); RectangleF nodeBounds = m_renderer.GetBounds(grpPIn, false, m_d2dGraphics); if (nodeBounds.IntersectsWith(rect)) { pickedFloatingPins.Add(pin); } } foreach (var floatingPin in pickedFloatingPins) { yield return(floatingPin); } }
/// <summary> /// Performs hit test for a point, in client coordinates</summary> /// <param name="nodes">Nodes to test if hit</param> /// <param name="edges">Edges to test if hit</param> /// <param name="pickPoint">Pick point, in client coordinates</param> /// <returns>Hit record for a point, in client coordinates</returns> public GraphHitRecord <TNode, TEdge, TEdgeRoute> Pick(IEnumerable <TNode> nodes, IEnumerable <TEdge> edges, Point pickPoint) { Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform); PointF pt = Matrix3x2F.TransformPoint(invXform, pickPoint); TEdge priorityEdge = null; if (m_selectionContext != null) { priorityEdge = m_selectionContext.GetLastSelected <TEdge>(); } return(m_renderer.Pick(nodes, edges, priorityEdge, pt, m_d2dGraphics)); }
/// <summary> /// Performs hit test for a point, in client coordinates</summary> /// <param name="pickPoint">Pick point, in client coordinates</param> /// <returns>Hit record for a point, in client coordinates</returns> DiagramHitRecord IPickingAdapter2.Pick(Point pickPoint) { Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform); PointF pt = Matrix3x2F.TransformPoint(invXform, pickPoint); TEdge priorityEdge = null; if (m_selectionContext != null) { priorityEdge = m_selectionContext.GetLastSelected <TEdge>(); } return(m_renderer.Pick(m_graph, priorityEdge, pt, m_d2dGraphics)); }
private void PaintD2d(object sender, EventArgs e) { if (!IsContextValid()) { return; } var control = (D2dAdaptableControl)AdaptedControl; var sourceControl = m_birdEyeView.m_sourceControl; var srcXformAdapter = sourceControl.Cast <ITransformAdapter>(); D2dGraphics g = control.D2dGraphics; Matrix3x2F invXform = g.Transform; float scaleX = invXform.M11; invXform.Invert(); Point cpt = control.PointToClient(Control.MousePosition); var gpt = Matrix3x2F.TransformPoint(invXform, cpt); // transform client rect of source control to graph space. var srcInvXform = Matrix3x2F.Invert(srcXformAdapter.Transform); var grect = Matrix3x2F.Transform(srcInvXform, sourceControl.ClientRectangle); float strokeWidth = m_dragging || (grect.Contains(gpt) && control.Focused) ? 3.0f / scaleX : 1.5f / scaleX; g.DrawRectangle(grect, Color.Yellow, strokeWidth); Point srcCpt = sourceControl.PointToClient(Control.MousePosition); var srcGpt = Matrix3x2F.TransformPoint(srcInvXform, srcCpt); if (sourceControl.Focused && grect.Contains(srcGpt) && !control.ClientRectangle.Contains(cpt)) { float cursorSize = 7.0f / scaleX; RectangleF cursorRect = new RectangleF(srcGpt.X - cursorSize / 2, srcGpt.Y - cursorSize / 2, cursorSize, cursorSize); g.FillEllipse(cursorRect, Color.Yellow); } }
/// <summary> /// Frames the items in the current view</summary> /// <param name="items">Items to frame</param> public void Frame(IEnumerable <object> items) { if (ToggleFramingEnabled) { if (m_isUnframing) { m_isUnframing = false; m_transformAdapter.SetTransform(m_unframeMtrx.M11, m_unframeMtrx.M22, m_unframeMtrx.DX, m_unframeMtrx.DY); return; } m_isUnframing = true; m_unframeMtrx = m_transformAdapter.Transform; } var bounds = GetBounds(items); // transform bounds from client space to graph space. Matrix3x2F invXform = Matrix3x2F.Invert(m_transformAdapter.Transform); var gBounds = Matrix3x2F.Transform(invXform, bounds); var crect = AdaptedControl.ClientRectangle; crect.Inflate(-MarginSize.Width, -MarginSize.Height); if (crect.Width < 1 || crect.Height < 1) { return; } float sx = MathUtil.Clamp(crect.Width / gBounds.Width, m_transformAdapter.MinScale.X, m_transformAdapter.MaxScale.X); float sy = MathUtil.Clamp(crect.Height / gBounds.Height, m_transformAdapter.MinScale.Y, m_transformAdapter.MaxScale.Y); float scale = Math.Min(sx, sy); crect.X += (int)(crect.Width - gBounds.Width * scale) / 2; crect.Y += (int)(crect.Height - gBounds.Height * scale) / 2; float tx = crect.X - gBounds.X * scale; float ty = crect.Y - gBounds.Y * scale; m_transformAdapter.SetTransform(scale, scale, tx, ty); }
/// <summary> /// Renders entire graph</summary> protected override void OnRender() { D2dGraphics.AntialiasMode = D2dAntialiasMode.PerPrimitive; Matrix3x2F invMtrx = D2dGraphics.Transform; invMtrx.Invert(); RectangleF boundsGr = Matrix3x2F.Transform(invMtrx, this.AdaptedControl.ClientRectangle); // Draw normal nodes on top of edges foreach (StateBase node in Graph.Nodes) { RectangleF nodeBounds = Renderer.GetBounds(node, D2dGraphics); if (!boundsGr.IntersectsWith(nodeBounds)) { continue; } DiagramDrawingStyle style = GetStyle(node); Renderer.Draw(node, style, D2dGraphics); } // Draw edges last for now. Todo: draw in layers, with edges and then nodes for each layer foreach (Transition edge in Graph.Edges) { if (edge == HiddenEdge) { continue; } RectangleF edgeBounds = Renderer.GetBounds(edge, D2dGraphics); if (!boundsGr.IntersectsWith(edgeBounds)) { continue; } DiagramDrawingStyle style = GetStyle(edge); Renderer.Draw(edge, style, D2dGraphics); } }
protected override void OnDragging(MouseEventArgs e) { base.OnDragging(e); if (e.Button != MouseButtons.Left || !IsContextValid()) { return; } AdaptedControl.Capture = true; m_dragging = true; var sourceControl = m_birdEyeView.m_sourceControl; var srcXformAdapter = sourceControl.Cast <ITransformAdapter>(); var inxXform = Matrix3x2F.Invert(m_transformAdapter.Transform); var gpt = Matrix3x2F.TransformPoint(inxXform, e.Location); gpt.X -= m_hitGpt.X; gpt.Y -= m_hitGpt.Y; var srcScale = srcXformAdapter.Scale; srcXformAdapter.Translation = new PointF(-gpt.X * srcScale.X, -gpt.Y * srcScale.Y); }
private void UpdateGraphBounds() { if (m_targetControl == null || m_sourceControl == null || m_targetControl.Context != m_sourceControl.Context) { return; } m_currentGraphBounds = RectangleF.Empty; var vc = m_sourceControl.Context.Cast <ViewingContext>(); var bounds = vc.GetBounds(); if (m_sourceControl.ContextIs <Sce.Atf.Controls.Adaptable.Graphs.Group>()) { bounds.Inflate(m_editor.Theme.PinSize + CircuitGroupPinInfo.FloatingPinBoxWidth, 0); } var srcXform = m_sourceControl.As <ITransformAdapter>(); Matrix3x2F invXform = Matrix3x2F.Invert(srcXform.Transform); var gBounds = Matrix3x2F.Transform(invXform, bounds); m_currentGraphBounds = gBounds; Fit(m_targetControl, gBounds); }
/// <summary> /// Get currently dragging edge or null /// if currently no edige is being dragged.</summary> /// <returns></returns> public DragEdge GetDraggingEdge() { if (!m_isConnecting) { return(null); } var d2dControl = this.AdaptedControl as D2dAdaptableControl; D2dGraphics gfx = d2dControl.D2dGraphics; var invXform = Matrix3x2F.Invert(gfx.Transform); var edge = new DragEdge(); edge.FromNode = m_draggingContext.ActualFromNode(); edge.FromRoute = m_draggingContext.ActualFromRoute(edge.FromNode); edge.ToNode = m_draggingContext.ActualToNode(); edge.ToRoute = m_draggingContext.ActualToRoute(edge.ToNode); edge.Label = m_draggingContext.ExistingEdge != null ? m_draggingContext.ExistingEdge.Label : null; edge.StartPoint = edge.FromRoute == null?Matrix3x2F.TransformPoint(invXform, m_edgeDragPoint) : m_draggingContext.FromRoutePos; edge.EndPoint = edge.ToRoute == null?Matrix3x2F.TransformPoint(invXform, m_edgeDragPoint) : m_draggingContext.ToRoutePos; return(edge); }
/// <summary> /// Renders entire graph</summary> protected virtual void OnRender() { try { m_renderer.GetStyle = GetStyle; m_d2dGraphics.AntialiasMode = D2dAntialiasMode.PerPrimitive; Matrix3x2F invMtrx = m_d2dGraphics.Transform; invMtrx.Invert(); RectangleF boundsGr = Matrix3x2F.Transform(invMtrx, this.AdaptedControl.ClientRectangle); // Either draw (most) edges first or prepare multimaps for draw-as-we-go edges. if (EdgeRenderPolicy == DrawEdgePolicy.AllFirst) { foreach (var edge in m_graph.Edges) { if (edge == m_hiddenEdge) { continue; } RectangleF bounds = m_renderer.GetBounds(edge, m_d2dGraphics); if (!boundsGr.IntersectsWith(bounds)) { continue; } var group = edge.FromNode.As <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); if (group == null || !group.Expanded) { group = edge.ToNode.As <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); } if (group != null && group.Expanded) { m_edgesOnGroups.Add(edge); } else { DiagramDrawingStyle style = GetStyle(edge); m_renderer.Draw(edge, style, m_d2dGraphics); } } } else { // build node to edge maps foreach (TEdge edge in m_graph.Edges) { m_nodeEdges.Add(edge.FromNode, edge); m_nodeEdges.Add(edge.ToNode, edge); m_edgeNodeEncounter.Add(edge, 0); } } // Draw normal nodes first TNode containerOfSelectedNode = null; foreach (var node in m_graph.Nodes) { RectangleF nodeBounds = m_renderer.GetBounds(node, m_d2dGraphics); if (boundsGr.IntersectsWith(nodeBounds)) { DiagramDrawingStyle drawStyle = GetStyle(node); // Draw all dragged nodes (even expanded groups) last. if (drawStyle == DiagramDrawingStyle.DragSource) { m_draggingNodes.Add(node); } else { // Draw selected nodes after normal nodes. If the node // is hot, check if it's selected. if (drawStyle == DiagramDrawingStyle.Selected || drawStyle == DiagramDrawingStyle.LastSelected || (drawStyle == DiagramDrawingStyle.Hot && m_selectionContext != null && m_selectionContext.SelectionContains(node))) { m_selectedNodes.Add(node); } else { // Expanded groups are drawn after normal nodes. bool expandedGroup = false; var group = node.As <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); if (group != null) { group.Info.PickingPriority = 0; if (group.Expanded) { if (node == ActiveContainer()) { containerOfSelectedNode = node; } else { m_expandedGroups.Add(node); } expandedGroup = true; } } // Draw normal nodes and collapsed groups. if (!expandedGroup) { m_renderer.Draw(node, drawStyle, m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(node, boundsGr); } } } } } else if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(node, boundsGr); } } // Draw expanded groups on top of normal sibling nodes, so that normal nodes that overlap // these groups don't appear as if they are in the groups. int pickPriority = 0; foreach (var node in m_expandedGroups) { var group = node.Cast <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); group.Info.PickingPriority = pickPriority++; m_renderer.Draw(node, GetStyle(node), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(node, boundsGr); } } // Draw the expanded group that contains a selected or dragged child node, so that // if multiple expanded groups overlap, that the user can see the owning group. if (containerOfSelectedNode != null) { var group = containerOfSelectedNode.Cast <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); group.Info.PickingPriority = pickPriority++; m_renderer.Draw(containerOfSelectedNode, GetStyle(containerOfSelectedNode), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(containerOfSelectedNode, boundsGr); } } // Draw selected nodes. foreach (var node in m_selectedNodes) { var group = node.As <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); if (group != null) { group.Info.PickingPriority = pickPriority++; } m_renderer.Draw(node, GetStyle(node), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(node, boundsGr); } } // Draw dragging nodes last to ensure they are visible (necessary for container-crossing move operation) foreach (var node in m_draggingNodes) { m_renderer.Draw(node, DiagramDrawingStyle.DragSource, m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { DrawAssociatedEdges(node, boundsGr); } } // Draw "all first" edges that connect to expanded groups. foreach (var edge in m_edgesOnGroups) { DiagramDrawingStyle style = GetStyle(edge); m_renderer.Draw(edge, style, m_d2dGraphics); } } finally { m_nodeEdges.Clear(); m_edgeNodeEncounter.Clear(); m_draggingNodes.Clear(); m_selectedNodes.Clear(); m_expandedGroups.Clear(); m_edgesOnGroups.Clear(); } }
/// <summary> /// Renders entire graph</summary> protected virtual void OnRender() { m_d2dGraphics.AntialiasMode = D2dAntialiasMode.PerPrimitive; Matrix3x2F invMtrx = m_d2dGraphics.Transform; invMtrx.Invert(); RectangleF boundsGr = Matrix3x2F.Transform(invMtrx, this.AdaptedControl.ClientRectangle); if (EdgeRenderPolicy == DrawEdgePolicy.AllFirst) { foreach (var edge in m_graph.Edges) { DrawEdge(edge, boundsGr); } } else { // build node to edge maps m_fromNodeEdges.Clear(); m_toNodeEdges.Clear(); m_edgeNodeEncounter.Clear(); foreach (TEdge edge in m_graph.Edges) { m_fromNodeEdges.Add(edge.FromNode, edge); m_toNodeEdges.Add(edge.ToNode, edge); m_edgeNodeEncounter.Add(edge, 0); } } // Draw normal nodes first TNode selectedGroup = null; var draggingNodes = new List <TNode>(); var expandedGroupNodes = new List <TNode>(); foreach (var node in m_graph.Nodes) { RectangleF nodeBounds = m_renderer.GetBounds(node, m_d2dGraphics); if (boundsGr.IntersectsWith(nodeBounds)) { bool expandedGroup = false; if (node.Is <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >()) { var group = node.Cast <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); group.Info.PickingPriority = 0; if (group.Expanded) { if (node == ActiveContainer()) { selectedGroup = node; } else { expandedGroupNodes.Add(node); } expandedGroup = true; } } if (!expandedGroup) { if (m_renderer.GetCustomStyle(node) == DiagramDrawingStyle.DragSource) { draggingNodes.Add(node); } else { m_renderer.Draw(node, GetStyle(node), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { TryDrawAssociatedEdges(node, boundsGr); } } } } else if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { TryDrawAssociatedEdges(node, boundsGr); } } int pickPriority = 0; foreach (var node in expandedGroupNodes) { var group = node.Cast <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); group.Info.PickingPriority = pickPriority++; m_renderer.Draw(node, GetStyle(node), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { TryDrawAssociatedEdges(node, boundsGr); } } if (selectedGroup != null) { var group = selectedGroup.Cast <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >(); group.Info.PickingPriority = pickPriority++; m_renderer.Draw(selectedGroup, GetStyle(selectedGroup), m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { TryDrawAssociatedEdges(selectedGroup, boundsGr); } } // Draw dragging nodes last to ensure they are visible (necessary for container-crossing move operation) foreach (var node in draggingNodes) { m_renderer.Draw(node, DiagramDrawingStyle.DragSource, m_d2dGraphics); if (EdgeRenderPolicy == DrawEdgePolicy.Associated) { TryDrawAssociatedEdges(node, boundsGr); } } }
/// <summary> /// Transforms point by inverse transform</summary> /// <param name="matrix">Matrix representing transform</param> /// <param name="p">Point</param> /// <returns>Inverse transformed point</returns> public static Point InverseTransform(Matrix3x2F matrix, Point p) { Matrix3x2F inverse = Matrix3x2F.Invert(matrix); return(Point.Truncate(Matrix3x2F.TransformPoint(inverse, p))); }