/// <summary> /// Adds a mapper with a <see cref="PreferredPlacementDescriptor"/> that matches the given settings to the mapper /// registry of the given graph. In addition, sets the label model of all edge labels to free since that model /// can realizes any label placement calculated by a layout algorithm. /// </summary> public LayoutData CreateLabelingLayoutData( IGraph graph, EnumLabelPlacementAlongEdge placeAlongEdge, EnumLabelPlacementSideOfEdge sideOfEdge, EnumLabelPlacementOrientation orientation, double distanceToEdge) { var descriptor = CreatePreferredPlacementDescriptor( placeAlongEdge, sideOfEdge, orientation, distanceToEdge ); // change to a free edge label model to support integrated edge labeling var model = new FreeEdgeLabelModel(); foreach (var label in graph.GetEdgeLabels()) { if (!(label.LayoutParameter.Model is FreeEdgeLabelModel)) { graph.SetLabelLayoutParameter(label, model.FindBestParameter(label, model, label.GetLayout())); } } var layoutData = new GenericLayoutData(); layoutData.AddItemMapping(LayoutGraphAdapter.EdgeLabelLayoutPreferredPlacementDescriptorDpKey, new ItemMapping <ILabel, PreferredPlacementDescriptor>(label => descriptor)); return(layoutData); }
private static void AddNodeHalos(GenericLayoutData data, IGraph graph, ISelectionModel <IModelItem> selection, bool layoutOnlySelection) { var nodeHalos = new DictionaryMapper <INode, NodeHalo>(); foreach (var node in graph.Nodes) { var top = 0.0; var left = 0.0; var bottom = 0.0; var right = 0.0; // for each port with an EventPortStyle extend the node halo to cover the ports render size foreach (var port in node.Ports) { var eventPortStyle = port.Style as EventPortStyle; if (eventPortStyle != null) { var renderSize = eventPortStyle.RenderSize; var location = port.GetLocation(); top = Math.Max(top, node.Layout.Y - location.Y - renderSize.Height / 2); left = Math.Max(left, node.Layout.X - location.X - renderSize.Width / 2); bottom = Math.Max(bottom, location.Y + renderSize.Height / 2 - node.Layout.GetMaxY()); right = Math.Max(right, location.X + renderSize.Width / 2 - node.Layout.GetMaxX()); } } // for each node without incoming or outgoing edges reserve space for laid out exterior labels if (graph.InDegree(node) == 0 || graph.OutDegree(node) == 0) { foreach (var label in node.Labels) { if (IsNodeLabelAffected(graph, selection, label, layoutOnlySelection)) { var labelBounds = label.GetLayout().GetBounds(); if (graph.InDegree(node) == 0) { left = Math.Max(left, labelBounds.Width); top = Math.Max(top, labelBounds.Height); } if (graph.OutDegree(node) == 0) { right = Math.Max(right, labelBounds.Width); bottom = Math.Max(bottom, labelBounds.Height); } } } } nodeHalos[node] = NodeHalo.Create(top, left, bottom, right); } data.AddItemMapping(NodeHalo.NodeHaloDpKey).Mapper = nodeHalos; }
private static void AddEdgeLabelPlacementDescriptors(GenericLayoutData data) { var atSourceDescriptor = new PreferredPlacementDescriptor { PlaceAlongEdge = LabelPlacements.AtSourcePort, SideOfEdge = LabelPlacements.LeftOfEdge | LabelPlacements.RightOfEdge, }; data.AddItemMapping(LayoutGraphAdapter.EdgeLabelLayoutPreferredPlacementDescriptorDpKey).Delegate = 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); }; }
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); }; } }