/// <summary> /// Runs a layout algorithm which is configured to consider node rotations. /// </summary> public async Task ApplyLayout() { var graph = graphControl.Graph; // provide the rotated outline and layout for the layout algorithm graph.MapperRegistry.CreateDelegateMapper(RotatedNodeLayoutStage.RotatedNodeLayoutDpKey, node => { var style = node.Style; var outline = style.Renderer.GetShapeGeometry(node, style).GetOutline(); if (outline == null) { outline = new GeneralPath(4); outline.AppendRectangle(node.Layout.ToRectD(), false); } return(new RotatedNodeLayoutStage.RotatedNodeShape(outline, style is RotatableNodeStyleDecorator ? ((RotatableNodeStyleDecorator)style).GetRotatedLayout(node) : (IOrientedRectangle) new OrientedRectangle(node.Layout))); }); // get the selected layout algorithm var layout = GetLayoutAlgorithm(); // wrap the algorithm in RotatedNodeLayoutStage to make it aware of the node rotations var rotatedLayout = new RotatedNodeLayoutStage(layout) { EdgeRoutingMode = GetRoutingMode() }; // apply the layout await graphControl.MorphLayout(rotatedLayout, TimeSpan.FromMilliseconds(700)); // clean up mapper registry graph.MapperRegistry.RemoveMapper(RotatedNodeLayoutStage.RotatedNodeLayoutDpKey); }
/// <summary> /// Returns the outline of the node's rotated shape. /// </summary> protected override GeneralPath GetOutline(INode node) { var outline = Wrapped.Renderer.GetShapeGeometry(node, Wrapped).GetOutline(); if (outline == null) { outline = new GeneralPath(4); outline.AppendRectangle(node.Layout.ToRectD(), false); } else { outline = (GeneralPath)outline.Clone(); } outline.Transform(GetInverseRotationMatrix(node)); return(outline); }
/// <summary> /// Returns a slightly enlarged outline of the shape to ensure that ports that lie exactly on the shape's outline /// are always considered inside. /// </summary> private GeneralPath GetScaledOutline(INode node, IShapeGeometry nodeShapeGeometry) { var outline = nodeShapeGeometry.GetOutline(); if (outline == null) { outline = new GeneralPath(4); outline.AppendRectangle(node.Layout.ToRectD(), false); } const double factor = 1.001; var center = node.Layout.GetCenter(); var matrix = new Matrix2D(); matrix.Translate(new PointD(-center.X * (factor - 1), -center.Y * (factor - 1))); matrix.Scale(factor, factor); outline.Transform(matrix); return(outline); }
/// <summary> /// Adds the view modes that handle the resizing and movement of the export rectangle. /// </summary> /// <param name="inputMode"></param> private void AddExportRectInputModes(MultiplexingInputMode inputMode) { // create handles for interactivel resizing the export rectangle var rectangleHandles = new RectangleReshapeHandleProvider(exportRect) { MinimumSize = new SizeD(1, 1) }; // create a mode that deals with the handles var exportHandleInputMode = new HandleInputMode { Priority = 1 }; // add it to the graph editor mode inputMode.Add(exportHandleInputMode); // now the handles var inputModeContext = Contexts.CreateInputModeContext(exportHandleInputMode); exportHandleInputMode.Handles = new DefaultObservableCollection <IHandle> { rectangleHandles.GetHandle(inputModeContext, HandlePositions.NorthEast), rectangleHandles.GetHandle(inputModeContext, HandlePositions.NorthWest), rectangleHandles.GetHandle(inputModeContext, HandlePositions.SouthEast), rectangleHandles.GetHandle(inputModeContext, HandlePositions.SouthWest), }; // create a mode that allows for dragging the export rectangle at the sides var moveInputMode = new MoveInputMode { PositionHandler = new ExportRectanglePositionHandler(exportRect), HitTestable = HitTestables.Create( (context, location) => { var path = new GeneralPath(5); path.AppendRectangle(exportRect, false); return(path.PathContains(location, context.HitTestRadius)); }), Priority = 41 }; // add it to the edit mode inputMode.Add(moveInputMode); }