Exemplo n.º 1
0
        /// <summary>
        /// Draws grid lines corresponding to a vertical scale using GDI+</summary>
        /// <param name="transform">Transform from graph (world) to Window's client (screen) transform</param>
        /// <param name="graphRect">Graph rectangle</param>
        /// <param name="majorSpacing">Spacing, in pixels, between major tick marks</param>
        /// <param name="linePen">Grid line pen</param>
        /// <param name="g">Graphics GDI+ drawing surface</param>
        public static void DrawVerticalScaleGrid(
            Matrix transform,
            RectangleF graphRect,
            int majorSpacing,
            Pen linePen,
            System.Drawing.Graphics g)
        {
            double     xScale     = transform.Elements[0];
            RectangleF clientRect = GdiUtil.Transform(transform, graphRect);

            double min        = Math.Min(graphRect.Left, graphRect.Right);
            double max        = Math.Max(graphRect.Left, graphRect.Right);
            double tickAnchor = D2dUtil.CalculateTickAnchor(min, max);
            double step       = D2dUtil.CalculateStep(min, max, Math.Abs(clientRect.Right - clientRect.Left), majorSpacing, 0.0);

            if (step > 0)
            {
                double offset = tickAnchor - min;
                offset = offset - MathUtil.Remainder(offset, step) + step;
                for (double x = tickAnchor - offset; x <= max; x += step)
                {
                    double cx = (x - graphRect.Left) * xScale + clientRect.Left;
                    g.DrawLine(linePen, (float)cx, clientRect.Top, (float)cx, clientRect.Bottom);
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Gets a bounding rectangle for the items, in client coordinates</summary>
        /// <param name="items">Items to bound</param>
        /// <returns>Bounding rectangle for the items, in client coordinates</returns>
        public virtual Rectangle GetBounds(IEnumerable <object> items)
        {
            RectangleF bounds = m_renderer.GetBounds(items.AsIEnumerable <TNode>(), m_d2dGraphics);

            bounds = D2dUtil.Transform(m_d2dGraphics.Transform, bounds);
            return(Rectangle.Truncate(bounds));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Draws grid lines corresponding to a horizontal scale using GDI+</summary>
        /// <param name="transform">Transform from graph (world) to Window's client (screen) transform</param>
        /// <param name="graphRect">Graph rectangle</param>
        /// <param name="majorSpacing">Spacing, in pixels, between major tick marks</param>
        /// <param name="linePen">Grid line pen</param>
        /// <param name="g">Graphics GDI+ drawing surface</param>
        public static void DrawHorizontalScaleGrid(
            Matrix transform,
            RectangleF graphRect,
            int majorSpacing,
            Pen linePen,
            System.Drawing.Graphics g)
        {
            double     yScale     = transform.Elements[3];
            RectangleF clientRect = GdiUtil.Transform(transform, graphRect);

            double min        = Math.Min(graphRect.Top, graphRect.Bottom);
            double max        = Math.Max(graphRect.Top, graphRect.Bottom);
            double tickAnchor = D2dUtil.CalculateTickAnchor(min, max);
            double step       = D2dUtil.CalculateStep(min, max, Math.Abs(clientRect.Bottom - clientRect.Top), majorSpacing, 0.0);

            if (step > 0)
            {
                double offset = tickAnchor - min;
                offset = offset - MathUtil.Remainder(offset, step) + step;
                for (double y = tickAnchor - offset; y <= max; y += step)
                {
                    double cy;
                    if (yScale > 0)
                    {
                        cy = (y - min) * yScale + clientRect.Top;
                    }
                    else
                    {
                        cy = (y - max) * yScale + clientRect.Top;
                    }

                    g.DrawLine(linePen, clientRect.Left, (float)cy, clientRect.Right, (float)cy);
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Performs hit testing for rectangle bounds, in client coordinates</summary>
        /// <param name="pickRect">Pick rectangle, in client coordinates</param>
        /// <returns>Items that overlap with the rectangle, in client coordinates</returns>
        public virtual IEnumerable <object> Pick(Rectangle pickRect)
        {
            Matrix3x2F invXform = Matrix3x2F.Invert(m_d2dGraphics.Transform);
            RectangleF rect     = D2dUtil.Transform(invXform, pickRect);

            return(m_renderer.Pick(m_graph, rect, m_d2dGraphics));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Performs hit testing for rectangle bounds, in client coordinates</summary>
        /// <param name="pickRect">Pick rectangle, in client coordinates</param>
        /// <returns>Items that overlap with the rectangle, in client coordinates</returns>
        public override IEnumerable <object> Pick(Rectangle pickRect)
        {
#if CS_4
            Matrix3x2F           invXform         = Matrix3x2F.Invert(m_d2dGraphics.Transform);
            RectangleF           rect             = D2dUtil.Transform(invXform, pickRect);
            IEnumerable <object> pickedGraphNodes = base.Pick(pickRect);
#else
            // workaround a C#3 compiler bug( CS1911 warning)
            Matrix3x2F    invXform         = Matrix3x2F.Invert(m_d2dGraphics.Transform);
            RectangleF    rect             = D2dUtil.Transform(invXform, pickRect);
            List <object> pickedGraphNodes = new List <object>();
            foreach (TNode node in m_graph.Nodes)
            {
                RectangleF nodeBounds = m_renderer.GetBounds(node, m_d2dGraphics); // in graph space
                if (nodeBounds.IntersectsWith(rect))
                {
                    pickedGraphNodes.Add(node);
                }
            }
#endif
            foreach (var pickedGraphNode in pickedGraphNodes)
            {
                yield return(pickedGraphNode);
            }

            var pickedFloatingPins = new List <object>();
            var circuiElement      = m_graph.Cast <ICircuitElementType>();
            foreach (var pin in circuiElement.Inputs)
            {
                var        grpPIn     = pin.Cast <ICircuitGroupPin <TNode> >();
                RectangleF nodeBounds = m_renderer.GetBounds(grpPIn, true, m_d2dGraphics);
                if (nodeBounds.IntersectsWith(rect))
                {
                    pickedFloatingPins.Add(pin);
                }
            }

            foreach (var pin in circuiElement.Outputs)
            {
                var        grpPIn     = pin.Cast <ICircuitGroupPin <TNode> >();
                RectangleF nodeBounds = m_renderer.GetBounds(grpPIn, false, m_d2dGraphics);
                if (nodeBounds.IntersectsWith(rect))
                {
                    pickedFloatingPins.Add(pin);
                }
            }

            foreach (var floatingPin in pickedFloatingPins)
            {
                yield return(floatingPin);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Gets a bounding rectangle for the items, in client coordinates</summary>
        /// <param name="items">Items to bound</param>
        /// <returns>Bounding rectangle for the items, in client coordinates</returns>
        public override Rectangle GetBounds(IEnumerable <object> items)
        {
            var bounds = base.GetBounds(items);
            // include group pins y range
            var group = m_graph.As <ICircuitGroupType <TNode, TEdge, TEdgeRoute> >();

            if (group != null)
            {
                int yMin = int.MaxValue;
                int yMax = int.MinValue;

                foreach (var pin in group.Inputs.Concat(group.Info.HiddenInputPins))
                {
                    var grpPin = pin.Cast <ICircuitGroupPin <TNode> >();
                    if (grpPin.Bounds.Location.Y < yMin)
                    {
                        yMin = grpPin.Bounds.Location.Y;
                    }
                    if (grpPin.Bounds.Location.Y > yMax)
                    {
                        yMax = grpPin.Bounds.Location.Y;
                    }
                }

                foreach (var pin in group.Outputs.Concat(group.Info.HiddenOutputPins))
                {
                    var grpPin = pin.Cast <ICircuitGroupPin <TNode> >();
                    if (grpPin.Bounds.Location.Y < yMin)
                    {
                        yMin = grpPin.Bounds.Location.Y;
                    }
                    if (grpPin.Bounds.Location.Y > yMax)
                    {
                        yMax = grpPin.Bounds.Location.Y;
                    }
                }

                // transform y range to client space
                if (yMin != int.MaxValue && yMax != int.MinValue)
                {
                    var yRange = D2dUtil.TransformVector(m_d2dGraphics.Transform, new PointF(yMin, yMax));
                    yMin = (int)Math.Min(yRange.X, yRange.Y);
                    yMax = (int)Math.Max(yRange.X, yRange.Y);
                    int width  = bounds.Width;
                    int height = yMax - yMin + 1;
                    bounds = Rectangle.Union(bounds, new Rectangle(bounds.Location.X, yMin, width, height));
                }
            }
            return(bounds);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Draws a vertical chart scale using GDI+</summary>
        /// <param name="transform">Transform from graph (world) to Window's client (screen) transform</param>
        /// <param name="graphRect">Graph rectangle</param>
        /// <param name="left">Scale left</param>
        /// <param name="majorSpacing">Spacing, in pixels, between major tick marks</param>
        /// <param name="minimumGraphStep">Minimum spacing, in graph (world) space, between ticks.
        /// For example, 1.0 would limit ticks to being drawn on whole integers.</param>
        /// <param name="linePen">Scale line pen</param>
        /// <param name="font">Scale font</param>
        /// <param name="textBrush">Text brush</param>
        /// <param name="g">Graphics GDI+ drawing surface</param>
        public static void DrawVerticalScale(
            Matrix transform,
            RectangleF graphRect,
            bool left,
            int majorSpacing,
            float minimumGraphStep,
            Pen linePen,
            Font font,
            Brush textBrush,
            System.Drawing.Graphics g)
        {
            double     yScale     = transform.Elements[3];
            RectangleF clientRect = GdiUtil.Transform(transform, graphRect);

            double tickEnd, minorTickStart, textStart;

            Matrix temp     = g.Transform.Clone();
            Matrix vertical = g.Transform;

            vertical.Translate(clientRect.Right, clientRect.Bottom);
            vertical.Rotate(90);
            vertical.Translate(-clientRect.Left, -clientRect.Top);
            g.Transform = vertical;
            if (left)
            {
                tickEnd        = clientRect.Right - clientRect.X;
                minorTickStart = tickEnd - 6;
                textStart      = tickEnd - 19;
            }
            else
            {
                tickEnd        = clientRect.Left + 1;
                minorTickStart = tickEnd + 6;
                textStart      = tickEnd + 8;
            }

            double min = Math.Min(graphRect.Top, graphRect.Bottom);
            double max = Math.Max(graphRect.Top, graphRect.Bottom);

            double tickAnchor     = D2dUtil.CalculateTickAnchor(min, max);
            double majorGraphStep = D2dUtil.CalculateStep(
                min, max, Math.Abs(clientRect.Bottom - clientRect.Top), majorSpacing, minimumGraphStep);
            int    numMinorTicks = D2dUtil.CalculateNumMinorTicks(majorGraphStep, minimumGraphStep, 5);
            double cMinorStep    = (majorGraphStep / numMinorTicks) * yScale;

            if (majorGraphStep > 0)
            {
                double offset = tickAnchor - min;
                offset = offset - MathUtil.Remainder(offset, majorGraphStep) + majorGraphStep;
                for (double x = tickAnchor - offset; x <= max; x += majorGraphStep)
                {
                    double cx = (x - min) * yScale + clientRect.Left;
                    //g.DrawLine(linePen, (float)cx, (float)majorTickStart, (float)cx, (float)tickEnd);
                    // draw minor ticks
                    double cmx = cx;
                    for (int i = 0; i < numMinorTicks; i++)
                    {
                        cmx += cMinorStep;
                        g.DrawLine(linePen, (float)cmx, (float)minorTickStart, (float)cmx, (float)tickEnd);
                    }
                    string xString = String.Format("{0:G8}", Math.Round(x, 6));
                    g.DrawString(xString, font, textBrush, (float)cx + 2, (float)textStart);
                }
            }
            g.Transform = temp;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Draws a horizontal chart scale using GDI+</summary>
        /// <param name="transform">Graph (world) to Window's client (screen) transform</param>
        /// <param name="graphRect">Graph rectangle</param>
        /// <param name="top">Whether the scale should be aligned along the top of the rectangle</param>
        /// <param name="majorSpacing">Spacing, in pixels, between major tick marks</param>
        /// <param name="minimumGraphStep">Minimum spacing, in graph (world) space, between ticks.
        /// For example, 1.0 would limit ticks to being drawn on whole integers.</param>
        /// <param name="linePen">Scale line pen</param>
        /// <param name="font">Scale font</param>
        /// <param name="textBrush">Text brush</param>
        /// <param name="g">Graphics GDI+ drawing surface</param>
        public static void DrawHorizontalScale(
            Matrix transform,
            RectangleF graphRect,
            bool top,
            int majorSpacing,
            float minimumGraphStep,
            Pen linePen,
            Font font,
            Brush textBrush,
            System.Drawing.Graphics g)
        {
            double     xScale     = transform.Elements[0];
            RectangleF clientRect = GdiUtil.Transform(transform, graphRect);

            double tickEnd, majorTickStart, minorTickStart, textStart;

            if (top)
            {
                tickEnd        = clientRect.Top + 1;
                majorTickStart = tickEnd + 12;
                minorTickStart = tickEnd + 6;
                textStart      = tickEnd + 8;
            }
            else
            {
                tickEnd        = clientRect.Bottom - 1;
                majorTickStart = tickEnd - 12;
                minorTickStart = tickEnd - 6;
                textStart      = tickEnd - 19;
            }

            double min = Math.Min(graphRect.Left, graphRect.Right);
            double max = Math.Max(graphRect.Left, graphRect.Right);

            double tickAnchor     = D2dUtil.CalculateTickAnchor(min, max);
            double majorGraphStep = D2dUtil.CalculateStep(
                min, max, Math.Abs(clientRect.Right - clientRect.Left), majorSpacing, minimumGraphStep);
            int    numMinorTicks = D2dUtil.CalculateNumMinorTicks(majorGraphStep, minimumGraphStep, 5);
            double cMinorStep    = (majorGraphStep / numMinorTicks) * xScale;

            if (majorGraphStep > 0)
            {
                double offset = tickAnchor - min;
                offset = offset - MathUtil.Remainder(offset, majorGraphStep);

                // draw leading minor ticks
                double cmx;
                cmx = ((tickAnchor - (offset + majorGraphStep)) - min) * xScale + clientRect.Left + cMinorStep;
                for (int i = 0; i < numMinorTicks - 1 && cmx < clientRect.Right; i++)
                {
                    // cull minor ticks outside of the view
                    if (cmx > clientRect.Left)
                    {
                        g.DrawLine(linePen, (float)cmx, (float)minorTickStart, (float)cmx, (float)tickEnd);
                    }
                    cmx += cMinorStep;
                }

                for (double x = tickAnchor - offset; x < max; x += majorGraphStep)
                {
                    double cx = (x - min) * xScale + clientRect.Left;
                    g.DrawLine(linePen, (float)cx, (float)majorTickStart, (float)cx, (float)tickEnd);
                    string xString = String.Format("{0:G8}", Math.Round(x, 6));
                    g.DrawString(xString, font, textBrush, (float)cx + 1, (float)textStart);

                    // draw minor ticks
                    cmx = cx + cMinorStep;
                    for (int i = 0; i < numMinorTicks - 1 && cmx < clientRect.Right; i++)
                    {
                        g.DrawLine(linePen, (float)cmx, (float)minorTickStart, (float)cmx, (float)tickEnd);
                        cmx += cMinorStep;
                    }
                }
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Draws floating group pin</summary>
        /// <param name="grpPin">Group pin</param>
        /// <param name="inputSide">True for input pin, false for output pin</param>
        /// <param name="style">DiagramDrawingStyle</param>
        /// <param name="g">Graphics object</param>
        public void DrawFloatingGroupPin(ICircuitGroupPin <TElement> grpPin, bool inputSide, DiagramDrawingStyle style, D2dGraphics g)
        {
            SizeF  pinNameSize = g.MeasureText(grpPin.Name, Theme.TextFormat);
            PointF p;

            if (inputSide)
            {
                p = GetGroupPinLocation(grpPin, true);

                RectangleF pinRect = new RectangleF(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth - Theme.PinSize,
                                                    grpPin.Bounds.Location.Y + Theme.PinMargin + Theme.PinOffset,
                                                    Theme.PinSize, Theme.PinSize);
                // draw output pin for input floating pins
                g.DrawRectangle(pinRect, m_subGraphPinPen);
                if (grpPin.Info.Pinned)
                {
                    D2dUtil.DrawPin((int)(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth), (int)p.Y, true, true, m_pinBrush, g);
                }
                else
                {
                    D2dUtil.DrawPin((int)(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth), (int)p.Y + Theme.PinSize / 2, false, true, m_pinBrush, g);
                }

                RectangleF bounds    = new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight);
                RectangleF alignRect = new RectangleF(
                    bounds.Left, bounds.Bottom + Theme.PinMargin, pinNameSize.Width, Theme.RowSpacing);
                var textAlignment = Theme.TextFormat.TextAlignment;
                Theme.TextFormat.TextAlignment = D2dTextAlignment.Leading;
                g.DrawText(grpPin.Name, Theme.TextFormat, alignRect.Location, Theme.TextBrush);
                Theme.TextFormat.TextAlignment = textAlignment;
            }
            else
            {
                // assume vertical scroll bar width = 16
                p = GetGroupPinLocation(grpPin, false);

                RectangleF pinRect = new RectangleF(p.X + 1, grpPin.Bounds.Location.Y + Theme.PinMargin + Theme.PinOffset,
                                                    Theme.PinSize, Theme.PinSize);
                // draw input pin for output floating pins
                g.DrawRectangle(pinRect, m_subGraphPinPen);
                // draw pin icon
                if (grpPin.Info.Pinned)
                {
                    D2dUtil.DrawPin((int)p.X, (int)p.Y, true, false, m_pinBrush, g);
                }
                else
                {
                    D2dUtil.DrawPin((int)p.X, (int)p.Y + Theme.PinSize / 2, false, false, m_pinBrush, g);
                }

                // draw label
                RectangleF bounds     = new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight);
                RectangleF alignRectF = new RectangleF(bounds.Right - pinNameSize.Width, bounds.Bottom + Theme.PinMargin,
                                                       pinNameSize.Width, Theme.RowSpacing);

                var textAlignment = Theme.TextFormat.TextAlignment;
                Theme.TextFormat.TextAlignment = D2dTextAlignment.Trailing;
                g.DrawText(grpPin.Name, Theme.TextFormat, alignRectF, Theme.TextBrush);
                Theme.TextFormat.TextAlignment = textAlignment;
            }

            // draw the fake pin node itself
            float savedStrokeWidth = Theme.StrokeWidth;

            Theme.StrokeWidth = 2.0f;
            if (style == DiagramDrawingStyle.Normal)
            {
                g.DrawRectangle(new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight), m_subGraphPinNodePen);
            }
            else
            {
                g.DrawRectangle(new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight), Theme.HotBrush);
            }
            Theme.StrokeWidth = savedStrokeWidth;


            if (!grpPin.Info.ExternalConnected)
            {
                RectangleF eyeRect = GetVisibilityCheckRect(grpPin, inputSide);
                g.DrawEyeIcon(eyeRect, grpPin.Info.Visible ? m_visiblePinBrush : m_hiddrenPinBrush, 1.0f);
            }

            // draw fake edge that connects group pin fake node
            DrawGroupPinNodeFakeEdge(grpPin, p, inputSide, style, g);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Gets the bounding rectangle of all circuit items in client coordinates</summary>
        /// <returns>Bounding rectangle of all circuit items in client coordinates</returns>
        public Rectangle GetBounds()
        {
            var items = new List <object>();

            if (m_graphContainer != null)
            {
                items.AddRange(m_graphContainer.Elements.AsIEnumerable <object>());
                if (m_graphContainer.Annotations != null)
                {
                    items.AddRange(m_graphContainer.Annotations.AsIEnumerable <object>());
                }
            }
            else
            {
                if (m_graph != null)
                {
                    items.AddRange(m_graph.Nodes.AsIEnumerable <IGraphNode>().AsIEnumerable <object>());
                }
                //TODO: including Annotations
            }

            Rectangle bounds = GetBounds(items);

            if (DomNode.Is <Group>()) // the view is associated with a group editor
            {
                // include group pins y range
                var group = DomNode.Cast <Group>();

                int yMin = int.MaxValue;
                int yMax = int.MinValue;

                foreach (var pin in group.InputGroupPins)
                {
                    var grpPin = pin.Cast <GroupPin>();
                    if (grpPin.Bounds.Location.Y < yMin)
                    {
                        yMin = grpPin.Bounds.Location.Y;
                    }
                    if (grpPin.Bounds.Location.Y > yMax)
                    {
                        yMax = grpPin.Bounds.Location.Y;
                    }
                }

                foreach (var pin in group.OutputGroupPins)
                {
                    var grpPin = pin.Cast <GroupPin>();
                    if (grpPin.Bounds.Location.Y < yMin)
                    {
                        yMin = grpPin.Bounds.Location.Y;
                    }
                    if (grpPin.Bounds.Location.Y > yMax)
                    {
                        yMax = grpPin.Bounds.Location.Y;
                    }
                }

                // transform y range to client space
                if (yMin != int.MaxValue && yMax != int.MinValue)
                {
                    var transformAdapter = m_control.Cast <ITransformAdapter>();
                    var yRange           = D2dUtil.TransformVector(transformAdapter.Transform, new PointF(yMin, yMax));
                    yMin = (int)Math.Min(yRange.X, yRange.Y);
                    yMax = (int)Math.Max(yRange.X, yRange.Y);
                    int width  = bounds.Width;
                    int height = yMax - yMin + 1;
                    bounds = Rectangle.Union(bounds, new Rectangle(bounds.Location.X, yMin, width, height));
                }
            }
            return(bounds);
        }