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; }
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); }
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); } }
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> /// 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> /// 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> /// Transforms rectangle</summary> /// <param name="matrix">Matrix representing transform</param> /// <param name="r">Rectangle</param> /// <returns>Transformed rectangle</returns> public static RectangleF Transform(Matrix3x2F matrix, RectangleF r) { return(Matrix3x2F.Transform(matrix, r)); }