/// <summary> /// Returns candidates for all ports at orange nodes in the graph, except /// for the current source node to avoid the creation of self-loops. /// </summary> public IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context) { List <IPortCandidate> result = new List <IPortCandidate>(); // add the current one as the default result.Add(new DefaultPortCandidate(edge.TargetPort)); var graph = context.GetGraph(); if (graph == null) { return(result); } foreach (INode node in graph.Nodes) { if (node != edge.SourcePort.Owner && Colors.Orange.Equals(node.Tag)) { // If available, use the candidates from the provider. Otherwise, add a default candidate. IPortCandidateProvider provider = node.Lookup <IPortCandidateProvider>(); if (provider != null) { result.AddRange(provider.GetTargetPortCandidates(context)); } else { result.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored)); } } } return(result); }
/// <summary> /// Returns a list that contains a port candidate for each of the node's /// ports. Each candidate has the same location as the port. If a port /// already has a connected edge, its port candidate is marked as invalid. /// </summary> /// <remarks> /// Note that the variants of getPortCandidates for target ports are all /// implemented by this class. Therefore, this method is only used for /// source ports. /// </remarks> protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context) { List <IPortCandidate> candidates = new List <IPortCandidate>(); bool hasValid = false; var graph = context.GetGraph(); if (graph != null) { // Create a port candidate for each port on the node foreach (IPort port in node.Ports) { DefaultPortCandidate portCandidate = new DefaultPortCandidate(port); bool valid = graph.OutDegree(port) == 0; hasValid |= valid; portCandidate.Validity = valid ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid; candidates.Add(portCandidate); } } // If no valid candidates have been created so far, use the ShapeGeometryPortCandidateProvider as fallback. // This provides a candidate in the middle of each of the four sides of the node. if (!hasValid) { candidates.AddRange(PortCandidateProviders.FromShapeGeometry(node).GetSourcePortCandidates(context)); } return(candidates); }
/// <summary> /// Returns a list that contains a port candidate for each of the node's /// ports. Each candidate has the same location as the port. If a port /// already has a connected edge, its port candidate is marked as invalid. /// </summary> /// <remarks> /// Note that the various variants of getPortCandidates of /// <see cref="PortCandidateProviderBase"/> delegate to this method. /// This can be used to provide the same candidates for all use-cases. /// </remarks> protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context) { List <IPortCandidate> candidates = new List <IPortCandidate>(); var graph = context.GetGraph(); // Create the candidate for each port if (graph != null) { foreach (IPort port in node.Ports) { DefaultPortCandidate portCandidate = new DefaultPortCandidate(port); portCandidate.Validity = graph.Degree(port) == 0 ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid; candidates.Add(portCandidate); } } // If no candidates have been created so far, create a single invalid candidate as fallback if (candidates.Count == 0) { DefaultPortCandidate item = new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored); item.Validity = PortCandidateValidity.Invalid; candidates.Add(item); } return(candidates); }
// a button has been hit: perform the action public void OnClicked(IInputModeContext context, PointD location) { var hitInfo = GetHitInfo(location); var classInfo = (ClassInfo)node.Tag; var graph = context.GetGraph(); switch (hitInfo) { case HitInfo.None: break; case HitInfo.ToggleAllDetails: classInfo.ShowDetails = !classInfo.ShowDetails; if (graph != null) { graph.AddUndoUnit("Toggle Details", "Toggle Details", () => classInfo.ShowDetails = !classInfo.ShowDetails, () => classInfo.ShowDetails = !classInfo.ShowDetails); } AdjustNodeBoundsCommand.Execute(node, context.CanvasControl); break; case HitInfo.TogglePropertyDetails: classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden; if (graph != null) { graph.AddUndoUnit("Toggle Property Details", "Toggle Property Details", () => classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden, () => classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden); } AdjustNodeBoundsCommand.Execute(node, context.CanvasControl); break; case HitInfo.ToggleMethodDetails: classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden; if (graph != null) { graph.AddUndoUnit("Toggle Method Details", "Toggle Method Details", () => classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden, () => classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden); } AdjustNodeBoundsCommand.Execute(node, context.CanvasControl); break; case HitInfo.ToggleFieldDetails: classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden; if (graph != null) { graph.AddUndoUnit("Toggle Field Details", "Toggle Field Details", () => classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden, () => classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden); } AdjustNodeBoundsCommand.Execute(node, context.CanvasControl); break; default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// The subtree is upon to be dragged. /// </summary> public void InitializeDrag(IInputModeContext context) { subtree = new Subtree(context.GetGraph(), node); layoutHelper = new RelocateSubtreeLayoutHelper((GraphControl)context.CanvasControl, subtree); layoutHelper.InitializeLayout(); compositeHandler = CreateCompositeHandler(subtree); compositeHandler.InitializeDrag(context); }
public void DragFinished([NotNull] IInputModeContext context, PointD originalLocation, PointD newLocation) { CancelDrag(context, originalLocation); var graph = context.GetGraph(); if (graph != null) { // assign the new size graph.SetLabelPreferredSize(label, dummyPreferredSize); } }
public override void InitializeDrag(IInputModeContext context) { var graph = context.GetGraph(); ZOrderSupport = graph.Lookup <ZOrderSupport>(); // store initial parent of the node... this.initialParent = graph.GetParent(node); this.currentParent = initialParent; this.dragging = true; base.InitializeDrag(context); }
/// <summary> /// Finishes the drag and updates the angle of the rotated node. /// </summary> public void DragFinished(IInputModeContext context, PointD originalLocation, PointD newLocation) { var vector = (newLocation - rotationCenter).Normalized; var angle = CalculateAngle(vector); if (ShouldSnap(context)) { angle = SnapAngle(context, angle); } SetAngle(context, angle); // Switch width / height for 'vertical' rotations // Note that other parts of the application need support for this feature, too. var graph = context.GetGraph(); if (graph == null) { return; } var portContext = new DelegatingContext(context); foreach (var portHandle in portHandles) { portHandle.DragFinished(portContext, originalLocation, newLocation); } portHandles.Clear(); // Workaround: if the OrthogonalEdgeEditingContext is used to keep the edges orthogonal, it is not allowed // to change that edges manually. Therefore, we explicitly finish the OrthogonalEdgeEditingContext here and // then call the edge router. var edgeEditingContext = context.Lookup <OrthogonalEdgeEditingContext>(); if (edgeEditingContext != null && edgeEditingContext.IsInitialized) { edgeEditingContext.DragFinished(); } if (reshapeHandler != null) { reshapeHandler.ReshapeFinished(context, node.Layout.ToRectD(), node.Layout.ToRectD()); } if (compoundEdit != null) { compoundEdit.Commit(); } nodeAngles = null; ClearSameAngleHighlights(context); }
/// <summary> /// Sets the angle to the node style if the style supports this. /// </summary> private void SetAngle(IInputModeContext context, double angle) { var wrapper = node.Style as RotatableNodeStyleDecorator; if (wrapper != null) { var oldAngle = wrapper.Angle; context.GetGraph().AddUndoUnit("Change Angle", "Change Angle", () => wrapper.Angle = oldAngle, () => wrapper.Angle = angle); wrapper.Angle = angle; } }
public override void HandleReshape(IInputModeContext context, RectD originalBounds, RectD newBounds) { base.HandleReshape(context, originalBounds, newBounds); // some reshaped nodes might got moved outside their parents bounds so enlarge the group node bounds if necessary var graph = context.GetGraph(); foreach (var node in ReshapeNodes) { if (graph.IsGroupNode(node)) { graph.GetGroupingSupport().EnlargeGroupNode(context, node, true); } } }
/// <summary> /// Returns port candidates for all existing ports at all nodes in the graph as alternatives. /// </summary> /// <param name="context">The context.</param> /// <returns>A sequence of all possible port candidates in <paramref name="context" />'s graph.</returns> private IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context) { var graph = context.GetGraph(); if (graph == null) { return(Enumerable.Empty <IPortCandidate>()); } return (from node in graph.Nodes from port in node.Ports select CreatePortCandidate(node, port)); }
public void DragFinished(IInputModeContext inputModeContext, PointD originalLocation, PointD newLocation) { // the value is already set. // we create an Undo unit, though, to make the edit undoable var clipboardBusinessObject = node.Tag as ClipboardBusinessObject; if (clipboardBusinessObject != null && clipboardBusinessObject.Value != originalValue) { var undoEngine = inputModeContext.GetGraph().GetUndoEngine(); if (undoEngine != null) { undoEngine.AddUnit(new BusinessValueUndoUnit(clipboardBusinessObject, originalValue)); } } }
/// <summary> /// Returns for each green node a candidate with a dynamic <see cref="FreeNodePortLocationModel"/>. /// When the Shift key is pressed, a port can be placed /// anywhere inside that node. /// </summary> public IEnumerable <IPortCandidate> GetSourcePortCandidates(IInputModeContext context) { var graph = context.GetGraph(); if (graph == null) { return(Enumerable.Empty <IPortCandidate>()); } else { return (from node in graph.Nodes where Equals(node.Tag, Colors.Green) select(IPortCandidate) new DefaultPortCandidate(node, FreeNodePortLocationModel.Instance)); } }
public void DragFinished(IInputModeContext context, PointD originalLocation, PointD newLocation) { var graph = context.GetGraph(); if (graph != null) { var model = label.LayoutParameter.Model; var finder = model.Lookup <ILabelModelParameterFinder>(); if (finder != null) { var param = finder.FindBestParameter(label, model, GetCurrentLabelLayout()); graph.SetLabelLayoutParameter(label, param); } } CancelDrag(context, originalLocation); }
/// <summary> /// Sets the original node bounds according to the given anchor location and size. /// </summary> private RectD SetNodeLocationAndSize(IInputModeContext inputModeContext, PointD anchor, SizeD size) { var graph = inputModeContext.GetGraph(); if (graph == null) { return(RectD.Empty); } var orientedRectangle = new OrientedRectangle(anchor.X, anchor.Y, size.Width, size.Height, initialLayout.UpX, initialLayout.UpY); var center = orientedRectangle.GetCenter(); var layout = RectD.FromCenter(center, size); graph.SetNodeLayout(node, layout); return(layout); }
public virtual void InitializeReshape(IInputModeContext context) { this.OriginalBounds = rectangle.TightRectangle; // register our CollectSnapResults callback var snapContext = context.Lookup <GraphSnapContext>(); if (snapContext != null) { snapContext.CollectSnapResults += CollectSnapResults; } // store original node layouts, reshape handlers and reshape snap result providers foreach (var node in ReshapeNodes) { originalNodeLayouts.Add(node, node.Layout.ToRectD()); // store reshape handler to change the shape of node var reshapeHandler = node.Lookup <IReshapeHandler>(); if (reshapeHandler != null) { reshapeHandler.InitializeReshape(context); reshapeHandlers.Add(node, reshapeHandler); } // store reshape snap result provider to collect snap results where node would snap to snaplines etc. var snapResultProvider = node.Lookup <INodeReshapeSnapResultProvider>(); if (snapContext != null && snapResultProvider != null) { reshapeSnapResultProviders.Add(node, snapResultProvider); } // store orthogonal edge drag handler that keeps edges at node orthogonal var orthogonalEdgeDragHandler = OrthogonalEdgeEditingContext.CreateOrthogonalEdgeDragHandler(context, node, false); if (orthogonalEdgeDragHandler != null) { orthogonalEdgeDragHandlers[node] = orthogonalEdgeDragHandler; } } // update the minimum/maximum size of the handle considering all initial node layouts Handle.MinimumSize = CalculateMinimumSize(); Handle.MaximumSize = CalculateMaximumSize(); // start a compound undo unit this.compoundEdit = context.GetGraph().BeginEdit("Undo Group Resize", "Redo Group Resize"); }
/// <summary> /// Returns all port candidates that apply for the provided opposite port candidate. /// </summary> /// <remarks> /// In this implementation only source ports with the same color and source ports of nodes /// with the same color as the target port are accepted. /// </remarks> public override IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context, IPortCandidate source) { List <IPortCandidate> candidates = new List <IPortCandidate>(); var graph = context.GetGraph(); if (graph != null) { foreach (IPort port in node.Ports) { DefaultPortCandidate portCandidate = new DefaultPortCandidate(port); var sourcePort = source.CreatePort(context); bool valid = port.Tag.Equals(source.Owner.Tag) || sourcePort != null && port.Tag.Equals(sourcePort.Tag); portCandidate.Validity = valid ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid; candidates.Add(portCandidate); } } return(candidates); }
/// <summary> /// Returns the suitable candidates based on the specified <see cref="EdgeDirection"/>. /// </summary> private IEnumerable <IPortCandidate> GetCandidatesForDirection(EdgeDirection direction, IInputModeContext context) { // If EdgeDirectionPolicy.DetermineFromPortCandidates is used, CreateEdgeInputMode queries GetSourcePortCandidates // as well as GetTargetPortCandidates to collect possible port candidates to start the edge creation. // In this case this method is called twice (with EdgeDirection.In and EdgeDirection.Out) so for each call we // should only return the *valid* port candidates of a port as otherwise for each port a valid as well as an invalid // candidate is returned. var provideAllCandidates = true; var ceim = context.ParentInputMode as CreateEdgeInputMode; if (ceim != null) { // check the edge direction policy as well as whether candidates are collected for starting or ending the edge creation provideAllCandidates = ceim.EdgeDirectionPolicy != EdgeDirectionPolicy.DetermineFromPortCandidates || ceim.IsCreationInProgress; } var candidates = new List <IPortCandidate>(); // iterate over all available ports foreach (var port in context.GetGraph().Ports) { // create a port candidate, invalidate it (so it is visible but not usable) var candidate = new DefaultPortCandidate(port) { Validity = PortCandidateValidity.Invalid }; // get the port descriptor var portDescriptor = port.Tag as PortDescriptor; // make the candidate valid if the direction is the same as the one supplied if (portDescriptor != null && portDescriptor.EdgeDirection == direction) { candidate.Validity = PortCandidateValidity.Valid; } // add the candidate to the list if (provideAllCandidates || candidate.Validity == PortCandidateValidity.Valid) { candidates.Add(candidate); } } // and return the list return(candidates); }
public void Uninstall(IInputModeContext context) { context.GetGraph().NodeLayoutChanged -= NodeLayoutChanged; var geim = context.ParentInputMode as GraphEditorInputMode; geim.MultiSelectionStarted -= MultiSelectionStarted; geim.MultiSelectionFinished -= MultiSelectionFinished; ((GraphControl)context.CanvasControl).Selection.ItemSelectionChanged -= ItemSelectionChanged; handleInputMode.DragStarted -= RegisterReshapedNodes; handleInputMode.DragStarting -= moveHandleOrthogonalHelper.Starting; handleInputMode.DragFinished -= moveHandleOrthogonalHelper.Finished; handleInputMode.DragCanceled -= moveHandleOrthogonalHelper.Canceled; handleInputMode.DragStarted -= moveHandleOrthogonalHelper.Started; RemoveRectangleVisualization(); handleInputMode.Uninstall(context); handleInputMode = null; InputModeContext = null; }
/// <summary> /// Creates an enumeration of possible port candidates, in this /// case one port candidate for each of the node's /// ports in the same location as the port. /// </summary> /// <remarks> /// This method is used to provide the same candidates for all /// use-cases. It is used as a fallback if methods <c>GetSourcePortCandidates()</c> /// and <c>GetTargetPortCandidates()</c> aren't implemented. /// </remarks> protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context) { List <IPortCandidate> candidates = new List <IPortCandidate>(); var graph = context.GetGraph(); if (graph != null) { foreach (IPort port in node.Ports) { DefaultPortCandidate portCandidate = new DefaultPortCandidate(port); candidates.Add(portCandidate); } } if (candidates.Count == 0) { DefaultPortCandidate item = new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored); item.Validity = PortCandidateValidity.Invalid; candidates.Add(item); } return(candidates); }
public void Install(IInputModeContext context, ConcurrencyController controller) { InputModeContext = context; var geim = context.ParentInputMode as GraphEditorInputMode; if (geim == null) { throw new InvalidOperationException("NodeGroupResizingInputMode must be installed as child mode of GraphEditorInputMode"); } // create own HandleInputMode for the handles handleInputMode = new HandleInputMode { Priority = 1 }; // notify the GraphSnapContext which nodes are resized and shouldn't provide SnapLines handleInputMode.DragStarted += RegisterReshapedNodes; // forward events to OrthogonalEdgeEditingContext so it can handle keeping edges at reshaped nodes orthogonal handleInputMode.DragStarting += moveHandleOrthogonalHelper.Starting; handleInputMode.DragStarted += moveHandleOrthogonalHelper.Started; handleInputMode.DragFinished += moveHandleOrthogonalHelper.Finished; handleInputMode.DragCanceled += moveHandleOrthogonalHelper.Canceled; handleInputMode.Install(context, controller); handleInputMode.Enabled = false; // update handles depending on the changed node selection geim.MultiSelectionStarted += MultiSelectionStarted; geim.MultiSelectionFinished += MultiSelectionFinished; ((GraphControl)context.CanvasControl).Selection.ItemSelectionChanged += ItemSelectionChanged; // add a NodeLayoutChanged listener so the reshape rect is updated when the nodes are moved (e.g. through // layout animations or MoveInputMode). context.GetGraph().NodeLayoutChanged += NodeLayoutChanged; }