// determines whether the button has been hit
            public bool IsHit(IInputModeContext context, PointD location)
            {
                // see if the button is visible at all
                IOrientedRectangle orientedRectangle = label.GetLayout();

                if (orientedRectangle.Contains(location, context.HitTestRadius))
                {
                    location = location - orientedRectangle.GetAnchorLocation();

                    double upX = orientedRectangle.UpX;
                    double upY = orientedRectangle.UpY;

                    double tx = location.X * -upY + location.Y * upX;
                    double ty = location.X * upX + location.Y * upY;

                    // consider auto flipping of the label contents
                    if (upY > 0)
                    {
                        return
                            (new RectD(inset, inset, 20, orientedRectangle.Height - 2 * inset).Contains(new PointD(tx, ty),
                                                                                                        context.HitTestRadius));
                    }
                    else
                    {
                        return
                            (new RectD(orientedRectangle.Width - (inset + buttonWidth), inset, buttonWidth,
                                       orientedRectangle.Height - 2 * inset).Contains(new PointD(tx, ty),
                                                                                      context.HitTestRadius));
                    }
                }
                else
                {
                    return(false);
                }
            }
예제 #2
0
 public static void Set(this OrientedRectangle mutable, IOrientedRectangle r)
 {
     mutable.AnchorX = r.AnchorX;
     mutable.AnchorY = r.AnchorY;
     mutable.Width   = r.Width;
     mutable.Height  = r.Height;
     mutable.UpX     = r.UpX;
     mutable.UpY     = r.UpY;
 }
예제 #3
0
        /// <summary>
        ///   Creates the geometry for the label's path.
        /// </summary>
        /// <param name="layout">The label's layout.</param>
        /// <param name="text">The label text.</param>
        /// <returns>The label path's geometry.</returns>
        /// <remarks>
        ///   The label's visualization is an approximation of its text where each word is represented by a line with a length
        ///   proportional to the word's length. In the vast majority of cases this approximates the position of spaces in the line
        ///   accurately enough that the switch from a text label to a fast label is almost imperceptible.
        /// </remarks>
        private StreamGeometry CreateGeometry(IOrientedRectangle layout, string text)
        {
            var origin = layout.GetAnchorLocation();
            var up     = layout.GetUp();
            var right  = new PointD(-up.Y, up.X);

            if (AutoFlip && up.Y > 0)
            {
                origin = origin + up * layout.Height + right * layout.Width;
                up     = -up;
                right  = -right;
            }

            var upperLeft = origin + up * layout.Height;

            // This part could be optimized a bit by not allocating new objects and thus reduce pressure on the garbage
            // collector. However, in practice it made not much of an impact.
            var lines             = text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            var longestLineLength = lines.Max(l => l.Length);
            var sizePerLetter     = layout.Width / longestLineLength;

            var geometry = new StreamGeometry();

            using (var ctx = geometry.Open()) {
                // Fill – only drawn when a brush was set
                if (BackgroundBrush != null)
                {
                    ctx.BeginFigure(origin, true, false);
                    ctx.PolyLineTo(new Point[]
                    {
                        origin + right * layout.Width,
                        origin + right * layout.Width + up * layout.Height,
                        origin + up * layout.Height
                    }, false, false);
                }

                // Lines
                for (int i = 0; i < lines.Length; i++)
                {
                    var line         = lines[i];
                    var words        = line.Split(' ', ' ');
                    var currentPoint = upperLeft - up * layout.Height / lines.Length * (i + 0.6);
                    // Words
                    foreach (var word in words)
                    {
                        var wordLength  = word.Length * sizePerLetter;
                        var targetPoint = currentPoint + right * wordLength;

                        ctx.BeginFigure(currentPoint, false, false);
                        ctx.LineTo(targetPoint, true, false);

                        currentPoint = targetPoint + right * sizePerLetter;
                    }
                }
            }
            return(geometry);
        }
예제 #4
0
        // Create an ImageVisual which represents the button
        private static ImageVisual CreateButton(IOrientedRectangle layout)
        {
            var imageVisual = new ImageVisual {
                Image     = Resources.edit_label,
                Rectangle = new RectD(layout.Width - (inset + buttonWidth), inset, buttonWidth, layout.Height - inset * 2)
            };

            return(imageVisual);
        }
 public ButtonVisual(ILabel label, Button button, ButtonIcon icon, Color backgroundColor, Color foregroundColor)
 {
     this.label           = label;
     this.labelLayout     = label.LayoutParameter.Model.GetGeometry(label, label.LayoutParameter);
     this.button          = button;
     this.icon            = icon;
     this.backgroundColor = backgroundColor;
     this.foregroundColor = foregroundColor;
 }
예제 #6
0
 /// <summary>
 ///   Helper method to determine whether two <see cref="IOrientedRectangle" />s are equal.
 /// </summary>
 /// <param name="rect1">The first rectangle to compare.</param>
 /// <param name="rect2">The second rectangle to compare.</param>
 /// <returns><see langword="true" /> if both rectangles are equal, <see langword="false" /> otherwise.</returns>
 /// <remarks>
 ///   Two oriented rectangles are considered equal if their anchor location, up vector, width, and height are equal.
 /// </remarks>
 private static bool AreEqual(IOrientedRectangle rect1, IOrientedRectangle rect2)
 {
     // ReSharper disable CompareOfFloatsByEqualityOperator
     return(rect1.AnchorX == rect2.AnchorX ||
            rect1.AnchorY == rect2.AnchorY ||
            rect1.UpX == rect2.UpX ||
            rect1.UpY == rect2.UpY ||
            rect1.Width == rect2.Width ||
            rect1.Height == rect2.Height);
     // ReSharper restore CompareOfFloatsByEqualityOperator
 }
예제 #7
0
        public Visual CreateSelectionVisual(IRenderContext context, IOrientedRectangle layout)
        {
            var template         = context.CanvasControl.TryFindResource(OrientedRectangleIndicatorInstaller.SelectionTemplateKey) as DataTemplate;
            var container        = new VisualGroup();
            var frameworkElement = template != null ? (template.LoadContent() as FrameworkElement) : null;

            if (frameworkElement != null)
            {
                container.Children.Add(frameworkElement);
                return(UpdateSelectionVisual(context, container, layout));
            }
            return(null);
        }
예제 #8
0
        /// <summary>
        /// Gets the location that is specified by the given ratios.
        /// </summary>
        private static PointD GetLocation(IOrientedRectangle rectangle, double ratioWidth, double ratioHeight)
        {
            var x1 = rectangle.AnchorX;
            var y1 = rectangle.AnchorY;

            var upX = rectangle.UpX;
            var upY = rectangle.UpY;

            var w  = rectangle.Width * ratioWidth;
            var h  = rectangle.Height * ratioHeight;
            var x2 = x1 + upX * h - upY * w;
            var y2 = y1 + upY * h + upX * w;

            return(new PointD(x2, y2));
        }
        ILabelModelParameter ILabelModelParameterFinder.FindBestParameter(ILabel label, ILabelModel model,
                                                                          IOrientedRectangle labelLayout)
        {
            var    leftParam    = ((ILabelModelParameterFinder)leftModel).FindBestParameter(label, leftModel, labelLayout);
            var    rightParam   = ((ILabelModelParameterFinder)rightModel).FindBestParameter(label, rightModel, labelLayout);
            var    leftGeom     = ((ILabelModel)leftModel).GetGeometry(label, leftParam);
            var    rightGeom    = ((ILabelModel)rightModel).GetGeometry(label, rightParam);
            var    layoutCenter = labelLayout.GetCenter();
            double leftDist     = leftGeom.GetCenter().DistanceTo(layoutCenter);
            double rightDist    = rightGeom.GetCenter().DistanceTo(layoutCenter);

            return(leftDist < rightDist
        ? new RotatedSideSliderParameter(leftParam, this)
        : new RotatedSideSliderParameter(rightParam, this));
        }
예제 #10
0
        /// <summary>
        ///   Creates the geometry for the selection rectangle.
        /// </summary>
        /// <param name="layout">The label's layout.</param>
        /// <returns>The selection rectangle geometry.</returns>
        private Geometry CreateGeometry(IOrientedRectangle layout)
        {
            var up     = layout.GetUp();
            var anchor = layout.GetAnchorLocation();
            var right  = new PointD(-up.Y, up.X);

            var g = new StreamGeometry();

            using (var ctx = g.Open()) {
                ctx.BeginFigure(anchor, Fill != null, true);
                ctx.LineTo(anchor + right * layout.Width, true, false);
                ctx.LineTo(anchor + right * layout.Width + up * layout.Height, true, false);
                ctx.LineTo(anchor + up * layout.Height, true, false);
                ctx.LineTo(anchor, true, false);
            }
            return(g);
        }
예제 #11
0
        private static GeneralPath CreatePath(IOrientedRectangle layout)
        {
            GeneralPath gp   = new GeneralPath(10);
            double      xRad = layout.Width / 4;
            double      yRad = layout.Height / 10;

            gp.MoveTo(0, yRad);
            gp.QuadTo(0, 0, xRad, 0);
            gp.LineTo(layout.Width - xRad, 0);
            gp.QuadTo(layout.Width, 0, layout.Width, yRad);
            gp.LineTo(layout.Width, layout.Height - yRad);
            gp.QuadTo(layout.Width, layout.Height, layout.Width - xRad, layout.Height);
            gp.LineTo(xRad, layout.Height);
            gp.QuadTo(0, layout.Height, 0, layout.Height - yRad);
            gp.Close();
            return(gp);
        }
예제 #12
0
        /// <summary>
        /// Returns the location of the specified position on the border of the oriented rectangle.
        /// </summary>
        private PointD GetLocation(IOrientedRectangle layout, HandlePositions position)
        {
            if (layout == null)
            {
                return(node.Layout.ToPointD());
            }
            switch (position)
            {
            case HandlePositions.NorthWest:
                return(GetLocation(layout, 0.0, 1.0));

            case HandlePositions.North:
                return(GetLocation(layout, 0.5, 1.0));

            case HandlePositions.NorthEast:
                return(GetLocation(layout, 1.0, 1.0));

            case HandlePositions.East:
                return(GetLocation(layout, 1.0, 0.5));

            case HandlePositions.SouthEast:
                return(GetLocation(layout, 1.0, 0.0));

            case HandlePositions.South:
                return(GetLocation(layout, 0.5, 0.0));

            case HandlePositions.SouthWest:
                return(layout.GetAnchorLocation());

            case HandlePositions.West:
                return(GetLocation(layout, 0.0, 0.5));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Tries to find a parameter that best matches the given layout for the
        /// provided label instance.
        /// </summary>
        /// <remarks>By default, this method is only called when <b>no discrete</b> candidates are specified (i.e. here for <see cref="CandidateCount"/> = 0.
        /// This implementation just calculates the rotation angle for the center of <paramref name="labelLayout"/>
        /// and creates a parameter for exactly this angle which <see cref="CreateParameter"/>.</remarks>
        ILabelModelParameter ILabelModelParameterFinder.FindBestParameter(ILabel label, ILabelModel model, IOrientedRectangle labelLayout)
        {
            var labelModel = model as MyNodeLabelModel;
            var node       = label.Owner as INode;

            if (labelModel != null && node != null)
            {
                var    direction = (labelLayout.GetCenter() - node.Layout.GetCenter()).Normalized;
                double ratio     = Math.Atan2(direction.Y, -direction.X) / (Math.PI * 2.0d);
                return(labelModel.CreateParameter(ratio));
            }
            else
            {
                return(DefaultLabelModelParameterFinder.Instance.FindBestParameter(label, model, labelLayout));
            }
        }
예제 #14
0
 /// <summary>
 /// Creates a new instance.
 /// </summary>
 public RotatedNodeShape(GeneralPath outline, IOrientedRectangle orientedLayout)
 {
     Outline        = outline;
     OrientedLayout = orientedLayout;
 }
        /// <summary>
        /// Creates the visual appearance of a label
        /// </summary>
        private void Render(IRenderContext context, ILabel label, VisualGroup container, IOrientedRectangle labelLayout, RenderDataCache cache)
        {
            // store information with the visual on how we created it
            container.SetRenderDataCache(cache);

            // background rectangle
            System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle
            {
                Width           = labelLayout.Width,
                Height          = labelLayout.Height,
                RadiusX         = labelLayout.Width / 10,
                RadiusY         = labelLayout.Height / 10,
                Stroke          = Brushes.SkyBlue,
                Fill            = fillBrush,
                StrokeThickness = 1
            };
            container.Add(rect);

            // TextBlock with label text
            TextBlock textBlock = new TextBlock
            {
                Text        = cache.LabelText,
                FontFamily  = cache.Typeface.FontFamily,
                FontStretch = cache.Typeface.Stretch,
                FontStyle   = cache.Typeface.Style,
                FontWeight  = cache.Typeface.Weight,
                Foreground  = Brushes.Black,
            };

            textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            double textPositionLeft = (labelLayout.Width - textBlock.DesiredSize.Width) / 2;

            textBlock.SetCanvasArrangeRect(new Rect(textPositionLeft,
                                                    (labelLayout.Height - textBlock.DesiredSize.Height) / 2,
                                                    textBlock.DesiredSize.Width,
                                                    textBlock.DesiredSize.Height
                                                    ));
            container.Add(textBlock);
        }
예제 #16
0
            /// <summary>
            /// Finds the label model parameter that describes the given label layout best.
            /// </summary>
            /// <remarks>
            /// Sometimes the layout cannot be met exactly, then the nearest location is used.
            /// </remarks>
            public ILabelModelParameter FindBestParameter(ILabel label, ILabelModel model, IOrientedRectangle labelLayout)
            {
                var wrapperModel = model as RotatableNodeLabelModelDecorator;
                var styleWrapper = wrapperModel.GetNodeStyleWrapper(label);

                if (!wrapperModel.UseNodeRotation || styleWrapper == null || styleWrapper.Angle == 0)
                {
                    return
                        (wrapperModel.CreateWrappingParameter(wrappedFinder.FindBestParameter(label, wrapperModel.Wrapped,
                                                                                              labelLayout)));
                }

                var node          = label.Owner as INode;
                var rotatedCenter = styleWrapper.GetRotatedPoint(labelLayout.GetCenter(), node, false);
                var rotatedLayout = styleWrapper.GetRotatedLayout(node);

                var rectangle = new OrientedRectangle(labelLayout);

                rectangle.Angle -= rotatedLayout.GetRadians();
                rectangle.SetCenter(rotatedCenter);

                return
                    (wrapperModel.CreateWrappingParameter(wrappedFinder.FindBestParameter(label, wrapperModel.Wrapped, rectangle)));
            }
예제 #17
0
        /// <summary>
        /// Creates the visual appearance of a label
        /// </summary>
        private void Render(IRenderContext context, ILabel label, VisualGroup container, IOrientedRectangle labelLayout, RenderDataCache cache)
        {
            // store information with the visual on how we created it
            container.SetRenderDataCache(cache);

            // background rectangle
            System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle
            {
                Width           = labelLayout.Width,
                Height          = labelLayout.Height,
                RadiusX         = labelLayout.Width / 10,
                RadiusY         = labelLayout.Height / 10,
                Stroke          = Brushes.SkyBlue,
                Fill            = fillBrush,
                StrokeThickness = 1
            };
            container.Add(rect);

            // TextBlock with label text
            TextBlock textBlock = new TextBlock
            {
                Text        = cache.LabelText,
                FontFamily  = cache.Typeface.FontFamily,
                FontStretch = cache.Typeface.Stretch,
                FontStyle   = cache.Typeface.Style,
                FontWeight  = cache.Typeface.Weight,
                Foreground  = Brushes.Black,
            };

            textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // if edit button is visible align left, otherwise center
            double textPositionLeft = cache.ButtonVisibility == Visibility.Visible
                                  ? HorizontalInset
                                  : (labelLayout.Width - textBlock.DesiredSize.Width) / 2;

            textBlock.SetCanvasArrangeRect(new Rect(textPositionLeft,
                                                    (labelLayout.Height - textBlock.DesiredSize.Height) / 2,
                                                    textBlock.DesiredSize.Width,
                                                    textBlock.DesiredSize.Height
                                                    ));
            container.Add(textBlock);

            ////////////////////////////////////////////////////
            //////////////// New in this sample ////////////////
            ////////////////////////////////////////////////////

            if (cache.ButtonVisibility == Visibility.Visible)
            {
                // get style for edit button from XAML resources

                // create edit button
                Button editLabelButton = new Button
                {
                    Style = editButtonStyle
                };
                editLabelButton.SetCanvasArrangeRect(new Rect(labelLayout.Width - HorizontalInset - ButtonSize, VerticalInset, ButtonSize, ButtonSize));

                // set button command
                editLabelButton.Command          = GraphCommands.EditLabel;
                editLabelButton.CommandParameter = label;
                editLabelButton.CommandTarget    = context.CanvasControl;

                container.Add(editLabelButton);
            }

            ////////////////////////////////////////////////////
        }
예제 #18
0
        public Visual UpdateSelectionVisual(IRenderContext context, Visual oldVisual, IOrientedRectangle layout)
        {
            var container = oldVisual as VisualGroup;

            if (container != null && container.Children.Count == 1)
            {
                var visual = container.Children[0] as FrameworkElement;
                if (visual != null)
                {
                    Transform transform = context.IntermediateTransform;
                    container.Transform = transform;
                    var anchor      = layout.GetAnchorLocation();
                    var anchorAndUp = anchor + layout.GetUp();
                    anchor      = context.WorldToIntermediateCoordinates(anchor);
                    anchorAndUp = context.WorldToIntermediateCoordinates(anchorAndUp);

                    var or = new OrientedRectangle();
                    or.SetUpVector((anchorAndUp - anchor).Normalized);
                    or.SetAnchor(anchor);
                    or.Width      = layout.Width * context.Zoom;
                    or.Height     = layout.Height * context.Zoom;
                    visual.Width  = or.Width;
                    visual.Height = or.Height;
                    visual.SetCanvasArrangeRect(new Rect(0, 0, or.Width, or.Height));
                    ArrangeByLayout(context, visual, or, false);

                    if (!container.IsMeasureValid)
                    {
                        container.Arrange(new Rect(0, 0, or.Width, or.Height));
                    }

                    return(container);
                }
            }
            return(CreateSelectionVisual(context, layout));
        }
예제 #19
0
 public static SizeD ToSize(this IOrientedRectangle rect)
 {
     return(rect.ToSizeD());
 }
예제 #20
0
        /// <summary>
        /// Creates the visual appearance of a label
        /// </summary>
        private void Render(IRenderContext context, ILabel label, VisualGroup container, IOrientedRectangle labelLayout)
        {
            // background rectangle
            System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle
            {
                Width           = labelLayout.Width,
                Height          = labelLayout.Height,
                RadiusX         = labelLayout.Width / 10,
                RadiusY         = labelLayout.Height / 10,
                Stroke          = Brushes.SkyBlue,
                Fill            = fillBrush,
                StrokeThickness = 1
            };
            container.Add(rect);

            // TextBlock with label text
            TextBlock textBlock = new TextBlock
            {
                Text        = label.Text,
                FontFamily  = Typeface.FontFamily,
                FontStretch = Typeface.Stretch,
                FontStyle   = Typeface.Style,
                FontWeight  = Typeface.Weight,
                Foreground  = Brushes.Black,
            };

            textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // if edit button is visible align left, otherwise center
            double textPositionLeft = (labelLayout.Width - textBlock.DesiredSize.Width) / 2;

            textBlock.SetCanvasArrangeRect(new Rect(textPositionLeft,
                                                    (labelLayout.Height - textBlock.DesiredSize.Height) / 2,
                                                    textBlock.DesiredSize.Width,
                                                    textBlock.DesiredSize.Height
                                                    ));
            container.Add(textBlock);
        }
        /// <summary>
        /// Creates the visual appearance of a label
        /// </summary>
        private void Render(IRenderContext context, ILabel label, VisualGroup container, IOrientedRectangle labelLayout, RenderDataCache cache)
        {
            // store information with the visual on how we created it
            container.SetRenderDataCache(cache);

            // background rectangle
            System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle
            {
                Width           = labelLayout.Width,
                Height          = labelLayout.Height,
                RadiusX         = labelLayout.Width / 10,
                RadiusY         = labelLayout.Height / 10,
                Stroke          = Brushes.SkyBlue,
                Fill            = fillBrush,
                StrokeThickness = 1
            };
            container.Add(rect);

            // TextBlock with label text
            TextBlock textBlock = new TextBlock
            {
                Text        = cache.LabelText,
                FontFamily  = cache.Typeface.FontFamily,
                FontStretch = cache.Typeface.Stretch,
                FontStyle   = cache.Typeface.Style,
                FontWeight  = cache.Typeface.Weight,
                Foreground  = Brushes.Black,
            };

            textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // text is left aligned
            double textPositionLeft = HorizontalInset;

            textBlock.SetCanvasArrangeRect(new Rect(textPositionLeft,
                                                    (labelLayout.Height - textBlock.DesiredSize.Height) / 2,
                                                    textBlock.DesiredSize.Width,
                                                    textBlock.DesiredSize.Height
                                                    ));
            container.Add(textBlock);

            ////////////////////////////////////////////////////
            //////////////// New in this sample ////////////////
            ////////////////////////////////////////////////////

            // create edit button
            Button editLabelButton = new Button
            {
                Style = editButtonStyle
            };

            editLabelButton.SetCanvasArrangeRect(new Rect(labelLayout.Width - HorizontalInset - ButtonSize, VerticalInset,
                                                          ButtonSize, ButtonSize));

            // let the button edit the label
            editLabelButton.Click += (sender, args) => ((GraphEditorInputMode)context.CanvasControl.InputMode).EditLabel(label);

            container.Add(editLabelButton);

            ////////////////////////////////////////////////////
        }