/// <summary> /// Initializes a new instance of the FlowChart class. /// </summary> public FlowChart() { license = LicenseManager.Validate(typeof(FlowChart), this); measureUnit = GraphicsUnit.Millimeter; // set control styles for flicker-free redraw SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.Opaque, true); SetStyle(ControlStyles.ResizeRedraw, true); // we want to process keyboard input SetStyle(ControlStyles.Selectable, true); // init static objects lock (syncRoot) { Arrow.initHeadTemplates(); CustomCursors.Init(new ResourceManager( "MindFusion.FlowChartX.Cursors", typeof(ChartObject).Assembly)); } mouseMoved = false; boxFillColor = Color.FromArgb(220, 220, 255); boxFrameColor = Color.Black; arrowColor = Color.Black; arrowTextStyle = ArrowTextStyle.Center; arrowFillColor = Color.FromArgb(120, 220, 255); tableFrameColor = Color.Black; tableFillColor = Color.FromArgb(180, 160, 160); penDashStyle = DashStyle.Solid; penWidth = 0; BackColor = Color.FromArgb(170, 170, 200); // grid properties alignToGrid = true; showGrid = false; gridColor = Color.FromArgb(140, 140, 150); gridSizeX = 4; gridSizeY = 4; gridStyle = GridStyle.Points; // shadows properties shadowOffsetX = 1; shadowOffsetY = 1; shadowColor = Color.FromArgb(110, 110, 140); shadowsStyle = ShadowsStyle.OneLevel; activeMnpColor = Color.White; selMnpColor = Color.FromArgb(170, 170, 170); disabledMnpColor = Color.FromArgb(200, 0, 0); textFormat = new StringFormat(); textFormat.Alignment = StringAlignment.Center; textFormat.LineAlignment = StringAlignment.Center; // Set some flags, because otherwise the serializer // generates noncompilable code textFormat.FormatFlags = StringFormatFlags.NoFontFallback; imagePos = ImageAlign.Document; boxStyle = BoxStyle.RoundedRectangle; tableStyle = TableStyle.Rectangle; boxPen = new Pen(boxFrameColor, penWidth); boxBrush = new SolidBrush(boxFillColor); boxBrush.AddRef(); arrowPen = new Pen(arrowColor, penWidth); arrowBrush = new SolidBrush(arrowFillColor); arrowBrush.AddRef(); tablePen = new Pen(tableFrameColor, penWidth); tableBrush = new SolidBrush(tableFillColor); tableBrush.AddRef(); exteriorBrush = null; brush = new SolidBrush(BackColor); brush.AddRef(); boxes = new BoxCollection(); controlHosts = new ControlHostCollection(); tables = new TableCollection(); arrows = new ArrowCollection(); selection = new Selection(this); selectionOnTop = true; groups = new GroupCollection(); zOrder = new ChartObjectCollection(); textColor = Color.Black; arrowStyle = MindFusion.FlowChartX.ArrowStyle.Polyline; arrowSegments = 1; activeObject = null; modificationStart = ModificationStyle.SelectedOnly; autoHandlesObj = null; autoAnchorsObj = null; interaction = null; scrollX = scrollY = 0; zoomFactor = 100.0f; allowRefLinks = true; Behavior = BehaviorType.FlowChart; arrowEndsMovable = true; selectAfterCreate = true; // init default custom draw properties boxCustomDraw = CustomDraw.None; tableCustomDraw = CustomDraw.None; cellCustomDraw = CustomDraw.None; arrowCustomDraw = CustomDraw.None; restrObjsToDoc = RestrictToDoc.Intersection; dynamicArrows = false; arrowsSnapToBorders = false; arrowsRetainForm = false; arrowCascadeOrientation = Orientation.Auto; curPointer = Cursors.Arrow; curCannotCreate = Cursors.No; curModify = Cursors.SizeAll; curArrowStart = Cursors.Hand; curArrowEnd = Cursors.Hand; curArrowCannotCreate = Cursors.No; curHorzResize = Cursors.SizeWE; curVertResize = Cursors.SizeNS; curMainDgnlResize = Cursors.SizeNWSE; curSecDgnlResize = Cursors.SizeNESW; curRotateShape = CustomCursors.Rotate; panCursor = Cursors.NoMove2D; tableRowsCount = 4; tableColumnsCount = 2; tableRowHeight = 6; tableColWidth = 18; tableCaptionHeight = 5; tableCaption = "Table"; tableCellBorders = CellFrameStyle.System3D; selHandleSize = 2; showDisabledHandles = true; arrowSelStyle = HandlesStyle.SquareHandles; boxSelStyle = HandlesStyle.SquareHandles; chostSelStyle = HandlesStyle.HatchHandles; tableSelStyle = HandlesStyle.DashFrame; recursiveExpand = false; expandOnIncoming = false; boxesExpandable = false; tablesScrollable = false; tablesExpandable = false; controlHostsExpandable = false; arrowHead = ArrowHead.Arrow; arrowBase = ArrowHead.None; arrowInterm = ArrowHead.None; arrowHeadSize = 5; arrowBaseSize = 5; arrowIntermSize = 5; ShowScrollbars = true; DocExtents = new RectangleF(0, 0, 210, 297); autoScroll = true; autoScrDX = autoScrDY = 0; dirty = false; antiAlias = SmoothingMode.None; textRendering = TextRenderingHint.SystemDefault; sortGroupsByZ = false; // tooltips showToolTips = true; toolTip = ""; toolTipCtrl = new ToolTip(); toolTipCtrl.Active = showToolTips; shapeRotation = 0; DefaultShape = ShapeTemplate.FromId("Cylinder"); inplaceEditAllowed = false; inplaceObject = null; nowEditing = false; inplaceEditFont = (Font)Font.Clone(); inplaceAcceptOnEnter = false; inplaceCancelOnEsc = true; allowSplitArrows = false; printOptions = new PrintOptions(this); printOptions.EnableBackground = false; printOptions.EnableBackgroundImage = false; printOptions.PaintControls = true; displayOptions = new PrintOptions(this); renderOptions = displayOptions; previewOptions = new PreviewOptions(); allowLinksRepeat = true; showAnchors = ShowAnchors.Auto; snapToAnchor = SnapToAnchor.OnCreate; beginPrintHandler = new PrintEventHandler(this.BeginPrint); printPageHandler = new PrintPageEventHandler(this.PrintPage); printRect = new RectangleF(0, 0, 1, 1); usePolyTextLt = false; userAction = false; tableLinkStyle = TableLinkStyle.Rows; undoManager = new UndoManager(this); defaultControlType = typeof(System.Windows.Forms.Button); hostedCtrlMouseAction = HostMouseAction.SelectHost; dummy = new DummyNode(this); allowUnconnectedArrows = false; allowUnanchoredArrows = true; autoSizeDoc = MindFusion.FlowChartX.AutoSize.None; panMode = false; enableStyledText = false; expandBtnPos = ExpandButtonPosition.OuterRight; focusLost = false; hitTestPriority = HitTestPriority.NodesBeforeArrows; boxText = arrowText = ""; // arrow crossings arrowCrossings = ArrowCrossings.Straight; crossRadius = 1.5f; redrawNonModified = false; roundRectFactor = 1; scriptHelper = new ScriptHelper(this); // link routing options routingOptions = new RoutingOptions(this); routingGrid = new RoutingGrid(this); routeArrows = false; dontRouteForAwhile = false; validityChecks = true; _modifierKeyActions = new ModifierKeyActions(); middleButtonAction = MouseButtonAction.None; forceCacheRedraw = false; showHandlesOnDrag = true; mergeThreshold = 0; expandButtonAction = ExpandButtonAction.ExpandTreeBranch; }
/// <summary> /// mark obstacles and costs in the routing grid. /// </summary> private void markObstacles(RectangleF bounds, Arrow arrow, int cols, int rows) { RoutingOptions rop = flowChart.RoutingOptions; float gridSize = rop.GridSize; byte ccost = rop.CrossingCost; foreach (ChartObject obj in flowChart.Objects) { // if there is a crossing cost assigned, mark arrows in the route grid if (obj is Arrow && ccost > 0) { if (obj == arrow) { continue; } Arrow link = obj as Arrow; // at this time we handle only asPerpendicular links if (link.Style == ArrowStyle.Cascading) { PointF cp1 = link.ControlPoints[0]; Point gp1 = new Point( (int)((cp1.X - bounds.Left) / gridSize), (int)((cp1.Y - bounds.Top) / gridSize)); // iterate over all segments for (int i = 0; i < link.ControlPoints.Count - 1; ++i) { PointF cp2 = link.ControlPoints[i + 1]; Point gp2 = new Point( (int)((cp2.X - bounds.Left) / gridSize), (int)((cp2.Y - bounds.Top) / gridSize)); if (!gp1.Equals(gp2)) { if (gp1.X == gp2.X) { // vertical segment if (gp1.X >= 0 && gp1.X < cols) { int miny = Math.Min(gp1.Y, gp2.Y); miny = Math.Max(0, miny); int maxy = Math.Max(gp1.Y, gp2.Y); maxy = Math.Min(rows - 1, maxy); for (int y = miny; y <= maxy; ++y) { if (costGrid[gp1.X, y] < ccost) { costGrid[gp1.X, y] = ccost; } } } } else { // horizontal segment if (gp1.Y >= 0 && gp1.Y < rows) { int minx = Math.Min(gp1.X, gp2.X); minx = Math.Max(0, minx); int maxx = Math.Max(gp1.X, gp2.X); maxx = Math.Min(cols - 1, maxx); for (int x = minx; x <= maxx; ++x) { if (costGrid[x, gp1.Y] < ccost) { costGrid[x, gp1.Y] = ccost; } } } } } gp1 = gp2; } } continue; } if (!(obj is Node)) { continue; } Node node = obj as Node; if (!node.Obstacle) { continue; } if (node.MasterGroup != null && node.MasterGroup.MainObject == arrow) { continue; } RectangleF nodeRect = node.getRotatedBounds(); if (bounds.IntersectsWith(nodeRect)) { RectangleF intrRect = bounds; intrRect.Intersect(nodeRect); Point ptStart = new Point( (int)((intrRect.Left - bounds.Left) / gridSize), (int)((intrRect.Top - bounds.Top) / gridSize)); Point ptEnd = new Point( (int)((intrRect.Right - bounds.Left) / gridSize), (int)((intrRect.Bottom - bounds.Top) / gridSize)); if (ptStart.X < 0) { ptStart.X = 0; } if (ptStart.Y < 0) { ptStart.Y = 0; } if (ptEnd.X >= cols) { ptEnd.X = cols - 1; } if (ptEnd.Y >= rows) { ptEnd.Y = rows - 1; } // mark node interior as obstacle for (int c = ptStart.X; c <= ptEnd.X; ++c) { for (int r = ptStart.Y; r <= ptEnd.Y; ++r) { costGrid[c, r] = 255; } } // mark surrounding area with any cost assigned // going lineary down to the outside directions if (rop.NodeVicinityCost == 0) { continue; } for (int i = 1; i <= rop.NodeVicinitySize / gridSize; ++i) { byte cost = (byte)(rop.NodeVicinityCost / i); int minc = Math.Max(0, ptStart.X - i); int maxc = Math.Min(cols - 1, ptEnd.X + i); int minr = Math.Max(0, ptStart.Y - i); int maxr = Math.Min(rows - 1, ptEnd.Y + i); // top side int r = ptStart.Y - i; if (r >= 0) { for (int c = minc; c <= maxc; ++c) { if (costGrid[c, r] < cost) { costGrid[c, r] = cost; } } } // bottom side r = ptEnd.Y + i; if (r <= maxr) { for (int c = minc; c <= maxc; ++c) { if (costGrid[c, r] < cost) { costGrid[c, r] = cost; } } } // left side int cc = ptStart.X - i; if (cc >= 0) { for (r = minr; r <= maxr; ++r) { if (costGrid[cc, r] < cost) { costGrid[cc, r] = cost; } } } // right side cc = ptEnd.X + i; if (cc <= maxc) { for (r = minr; r <= maxr; ++r) { if (costGrid[cc, r] < cost) { costGrid[cc, r] = cost; } } } } } } }