private static void AddEdgeLabelPlacementDescriptors(LayoutGraphAdapter adapter)
        {
            var atSourceDescriptor = new PreferredPlacementDescriptor {
                PlaceAlongEdge = LabelPlacements.AtSourcePort,
                SideOfEdge     = LabelPlacements.LeftOfEdge | LabelPlacements.RightOfEdge,
            };

            adapter.AddDataProvider(LayoutGraphAdapter.EdgeLabelLayoutPreferredPlacementDescriptorDpKey,
                                    Mappers.FromDelegate((ILabel label) => {
                var edgeType = ((BpmnEdgeStyle)((IEdge)label.Owner).Style).Type;
                if (edgeType == EdgeType.SequenceFlow || edgeType == EdgeType.DefaultFlow || edgeType == EdgeType.ConditionalFlow)
                {
                    // labels on sequence, default and conditional flow edges should be placed at the source side.
                    return(atSourceDescriptor);
                }
                return(null);
            }));
        }
        protected override void Apply(LayoutGraphAdapter adapter, ILayoutAlgorithm layout, CopiedLayoutGraph layoutGraph)
        {
            var graph = adapter.AdaptedGraph;

            // check if only selected elements should be laid out
            var layoutOnlySelection = layout is BpmnLayout && ((BpmnLayout)layout).Scope == Scope.SelectedElements;

            // mark 'flow' edges, i.e. sequence flows, default flows and conditional flows
            adapter.AddDataProvider(BpmnLayout.SequenceFlowEdgesDpKey, Mappers.FromDelegate <IEdge, bool>(IsSequenceFlow));

            // mark boundary interrupting edges for the BalancingPortOptimizer
            adapter.AddDataProvider(BpmnLayout.BoundaryInterruptingEdgesDpKey, Mappers.FromDelegate((IEdge edge) => edge.SourcePort.Style is EventPortStyle));

            // mark conversations, events and gateways so their port locations are adjusted
            adapter.AddDataProvider(PortLocationAdjuster.AffectedNodesDpKey,
                                    Mappers.FromDelegate((INode node) => (node.Style is ConversationNodeStyle || node.Style is EventNodeStyle || node.Style is GatewayNodeStyle)));

            // add NodeHalos around nodes with event ports or specific exterior labels so the layout keeps space for the event ports and labels as well
            AddNodeHalos(adapter, graph, layoutOnlySelection);

            // add PreferredPlacementDescriptors for labels on sequence, default or conditional flows to place them at source side
            AddEdgeLabelPlacementDescriptors(adapter);

            // mark nodes, edges and labels as either fixed or affected by the layout and configure port constraints and incremental hints
            MarkFixedAndAffectedItems(adapter, layoutOnlySelection);

            // mark associations and message flows as undirected so they have less impact on layering
            EdgeDirectedness.Delegate = edge => (IsMessageFlow(edge) || IsAssociation(edge)) ? 0 : 1;

            // add layer constraints for start events, sub processes and message flows
            AddLayerConstraints(graph);

            // add EdgeLayoutDescriptor to specify minimum edge length for edges
            AddMinimumEdgeLength(MinimumEdgeLength);

            base.Apply(adapter, layout, layoutGraph);
        }
 private async void StartAnimation()
 {
     // animates the nodes in random fashion
     Random r = new Random(DateTime.Now.TimeOfDay.Milliseconds);
     await animator.Animate(Animations.CreateGraphAnimation(graphControl.Graph, Mappers.FromDelegate <INode, IRectangle>(node => new RectD(r.NextDouble() * 800, r.NextDouble() * 800, node.Layout.Width, node.Layout.Height)), null, null, null, TimeSpan.FromSeconds(5)));
 }
        private void MarkFixedAndAffectedItems(LayoutGraphAdapter adapter, bool layoutOnlySelection)
        {
            if (layoutOnlySelection)
            {
                var affectedEdges = Mappers.FromDelegate((IEdge edge) =>
                                                         adapter.SelectionModel.IsSelected(edge) ||
                                                         adapter.SelectionModel.IsSelected(edge.GetSourceNode()) ||
                                                         adapter.SelectionModel.IsSelected(edge.GetTargetNode()));
                adapter.AddDataProvider(LayoutKeys.AffectedEdgesDpKey, affectedEdges);

                // fix ports of unselected edges and edges at event ports
                adapter.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, Mappers.FromDelegate <IEdge, PortConstraint>(
                                            edge =>
                                            (!affectedEdges[edge] || edge.SourcePort.Style is EventPortStyle)
              ? PortConstraint.Create(GetSide(edge, true))
              : null));
                adapter.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, Mappers.FromDelegate <IEdge, PortConstraint>(
                                            edge => !affectedEdges[edge] ? PortConstraint.Create(GetSide(edge, false)) : null));

                // give core layout hints that selected nodes and edges should be incremental
                IncrementalHints.ContextDelegate = (item, factory) => {
                    if (item is INode && adapter.SelectionModel.IsSelected(item))
                    {
                        return(factory.CreateLayerIncrementallyHint(item));
                    }
                    else if (item is IEdge && affectedEdges[(IEdge)item])
                    {
                        return(factory.CreateSequenceIncrementallyHint(item));
                    }
                    return(null);
                };
                adapter.AddDataProvider(BpmnLayout.AffectedLabelsDpKey, Mappers.FromDelegate <ILabel, bool>(label => {
                    var edge = label.Owner as IEdge;
                    if (edge != null)
                    {
                        return(affectedEdges[edge]);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var isInnerLabel    = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography && adapter.SelectionModel.IsSelected(node));
                    }
                    return(false);
                }));
            }
            else
            {
                // fix source port of edges at event ports
                adapter.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, Mappers.FromDelegate <IEdge, PortConstraint>(
                                            edge => edge.SourcePort.Style is EventPortStyle ? PortConstraint.Create(GetSide(edge, true)) : null));

                adapter.AddDataProvider(BpmnLayout.AffectedLabelsDpKey, Mappers.FromDelegate <ILabel, bool>(label => {
                    if (label.Owner is IEdge)
                    {
                        return(true);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var isInnerLabel    = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography);
                    }
                    return(false);
                }));
            }
        }
        private static void MarkFixedAndAffectedItems(GenericLayoutData data, HierarchicLayoutData hierarchicLayoutData, ISelectionModel <IModelItem> graphSelection,
                                                      bool layoutOnlySelection)
        {
            if (layoutOnlySelection)
            {
                var affectedEdges = Mappers.FromDelegate((IEdge edge) =>
                                                         graphSelection.IsSelected(edge) ||
                                                         graphSelection.IsSelected(edge.GetSourceNode()) ||
                                                         graphSelection.IsSelected(edge.GetTargetNode()));
                data.AddItemCollection(LayoutKeys.AffectedEdgesDpKey).Mapper = affectedEdges;

                // fix ports of unselected edges and edges at event ports
                data.AddItemMapping(PortConstraintKeys.SourcePortConstraintDpKey).Delegate =
                    edge =>
                    (!affectedEdges[edge] || edge.SourcePort.Style is EventPortStyle)
              ? PortConstraint.Create(GetSide(edge, true))
              : null;
                data.AddItemMapping(PortConstraintKeys.TargetPortConstraintDpKey).Delegate =
                    edge => !affectedEdges[edge] ? PortConstraint.Create(GetSide(edge, false)) : null;

                // give core layout hints that selected nodes and edges should be incremental
                hierarchicLayoutData.IncrementalHints.ContextDelegate = (item, factory) => {
                    if (item is INode && graphSelection.IsSelected(item))
                    {
                        return(factory.CreateLayerIncrementallyHint(item));
                    }
                    else if (item is IEdge && affectedEdges[(IEdge)item])
                    {
                        return(factory.CreateSequenceIncrementallyHint(item));
                    }
                    return(null);
                };
                data.AddItemCollection(BpmnLayout.AffectedLabelsDpKey).Delegate = label => {
                    var edge = label.Owner as IEdge;
                    if (edge != null)
                    {
                        return(affectedEdges[edge]);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var  isInnerLabel   = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography && graphSelection.IsSelected(node));
                    }
                    return(false);
                };
            }
            else
            {
                // fix source port of edges at event ports
                data.AddItemMapping(PortConstraintKeys.SourcePortConstraintDpKey).Delegate =
                    edge => edge.SourcePort.Style is EventPortStyle?PortConstraint.Create(GetSide(edge, true)) : null;

                data.AddItemCollection(BpmnLayout.AffectedLabelsDpKey).Delegate = label => {
                    if (label.Owner is IEdge)
                    {
                        return(true);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var  isInnerLabel   = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography);
                    }
                    return(false);
                };
            }
        }