Пример #1
0
        private void CalculateLimits(CustomCanvas canvas, IEnumerable <ContentPresenter> items, out double minLeft,
                                     out double minTop,
                                     out double minDeltaHorizontal, out double minDeltaVertical,
                                     out double maxDeltaHorizontal, out double maxDeltaVertical)
        {
            minLeft            = double.MaxValue;
            minTop             = double.MaxValue;
            minDeltaHorizontal = double.MaxValue;
            minDeltaVertical   = double.MaxValue;
            maxDeltaHorizontal = double.MaxValue;
            maxDeltaVertical   = double.MaxValue;

            foreach (ContentPresenter item in items)
            {
                // resize delta should not go out of canvas bounds (top and left)
                // min distance to top and left among all elements
                double left = Canvas.GetLeft(item) - BorderThreshold;
                double top  = Canvas.GetTop(item) - BorderThreshold;
                minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
                minTop  = double.IsNaN(top) ? 0 : Math.Min(top, minTop);

                // resize delta should not go over item minimum height or width
                // min distance to element minimum heigth and width
                minDeltaVertical   = Math.Min(minDeltaVertical, item.ActualHeight - item.MinHeight);
                minDeltaHorizontal = Math.Min(minDeltaHorizontal, item.ActualWidth - item.MinWidth);

                // resize delta should not go out of canvas bounds (bottom and right)
                maxDeltaVertical   = Math.Min(maxDeltaVertical, canvas.ActualHeight - Canvas.GetTop(item) - item.ActualHeight - BorderThreshold);
                maxDeltaHorizontal = Math.Min(maxDeltaHorizontal, canvas.ActualWidth - Canvas.GetLeft(item) - item.ActualWidth - BorderThreshold);
            }
        }
Пример #2
0
        private List <ContentPresenter> GetChildElements(ContentPresenter element)
        {
            CustomCanvas elementCanvas = element.FindChild <CustomCanvas>(string.Empty);
            var          childs        = elementCanvas?.Children.Cast <ContentPresenter>().ToList();

            return(childs);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RubberbandAdorner"/> class
        /// </summary>
        /// <param name="canvas">Parent canvas</param>
        /// <param name="dragStartPoint">Dragging start point</param>
        /// <param name="mode">Mode of selection rectangle</param>
        public RubberbandAdorner(CustomCanvas canvas, Point?dragStartPoint, SelectionRectnagleModes mode) : base(canvas)
        {
            this.canvas     = canvas;
            this.startPoint = dragStartPoint;

            // choose color and selection behaviour based on mode
            switch (mode)
            {
            case SelectionRectnagleModes.Selection:
            {
                this.rubberandBrush = (Brush)Application.Current.FindResource("SelectionBrush");
                this.toSelect       = true;
                break;
            }

            case SelectionRectnagleModes.ChoiceBox:
            {
                this.rubberandBrush = (Brush)Application.Current.FindResource("MainItemsBrush");
                this.toSelect       = false;
                break;
            }

            case SelectionRectnagleModes.Grid:
            {
                this.rubberandBrush = (Brush)Application.Current.FindResource("MainItemsBrush");
                this.toSelect       = false;
                break;
            }
            }

            this.rubberbandPen           = new Pen(this.rubberandBrush, 1);
            this.rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
        }
        /// <summary>
        /// Handle thumb drag
        /// </summary>
        private void MoveThumbDragDelta(object sender, DragDeltaEventArgs e)
        {
            // dragging content - question or bubble
            DependencyObject content;

            // find dragging content - layout different for question and bubbles
            Adorner adorner = VisualTreeHelper.GetParent(this) as Adorner;

            if (adorner != null)
            {
                content = adorner.AdornedElement;
            }
            else
            {
                var grid = VisualTreeHelper.GetParent(this);
                content = VisualTreeHelper.GetParent(grid);
            }

            // presenter that holds omr item
            ContentPresenter presenter = (ContentPresenter)VisualTreeHelper.GetParent(content);

            // parent canvas
            CustomCanvas canvas = (CustomCanvas)VisualTreeHelper.GetParent(presenter);

            // get all selected elements
            List <ContentPresenter> presenters = ControlHelper.GetSelectedChildPresenters(canvas);

            double deltaHorizontal = e.HorizontalChange;
            double deltaVertical   = e.VerticalChange;

            // check out of bounds for each item
            for (int i = 0; i < presenters.Count; i++)
            {
                if (Canvas.GetLeft(presenters[i]) + deltaHorizontal > canvas.ActualWidth - presenters[i].ActualWidth - BorderThreshold
                    ||
                    Canvas.GetLeft(presenters[i]) + deltaHorizontal < BorderThreshold)
                {
                    deltaHorizontal = 0;
                }

                if (Canvas.GetTop(presenters[i]) + deltaVertical > canvas.ActualHeight - presenters[i].ActualHeight - BorderThreshold
                    ||
                    Canvas.GetTop(presenters[i]) + deltaVertical < BorderThreshold)
                {
                    deltaVertical = 0;
                }
            }

            // apply change for each item
            for (int i = 0; i < presenters.Count; i++)
            {
                Canvas.SetLeft(presenters[i], Canvas.GetLeft(presenters[i]) + deltaHorizontal);
                Canvas.SetTop(presenters[i], Canvas.GetTop(presenters[i]) + deltaVertical);
            }

            // canvas.InvalidateMeasure();
            e.Handled = true;
        }
Пример #5
0
        /// <summary>
        /// Find canvas childs as content presenters list
        /// </summary>
        /// <param name="canvas">Searched canvas</param>
        /// <returns>List of content presenters</returns>
        public static List <ContentPresenter> GetChildPresenters(CustomCanvas canvas)
        {
            List <ContentPresenter> presenters = new List <ContentPresenter>();
            int childsCount = VisualTreeHelper.GetChildrenCount(canvas);

            for (int i = 0; i < childsCount; i++)
            {
                presenters.Add(VisualTreeHelper.GetChild(canvas, i) as ContentPresenter);
            }

            return(presenters);
        }
Пример #6
0
        /// <summary>
        /// Finds all selected base omr elements inside canvas
        /// </summary>
        /// <param name="canvas">Canvas containing searched items</param>
        /// <returns>List of content presenters with selected items</returns>
        public static List <ContentPresenter> GetSelectedChildPresenters(CustomCanvas canvas)
        {
            List <ContentPresenter> presenters = new List <ContentPresenter>();
            int childsCount = VisualTreeHelper.GetChildrenCount(canvas);

            for (int i = 0; i < childsCount; i++)
            {
                ContentPresenter childPresenter = (ContentPresenter)VisualTreeHelper.GetChild(canvas, i);
                BaseOmrElement   childOmrItem   = (BaseOmrElement)VisualTreeHelper.GetChild(childPresenter, 0);

                if (childOmrItem.IsSelected)
                {
                    presenters.Add(childPresenter);
                }
            }

            return(presenters);
        }
Пример #7
0
        /// <summary>
        /// Snap single element to close elements on canvas
        /// </summary>
        /// <param name="movedItem">Item to snap</param>
        /// <param name="canvas">Main canvas holding all items</param>
        private void SnapElement(ContentPresenter movedItem, CustomCanvas canvas)
        {
            double            itemLeft = Canvas.GetLeft(movedItem);
            double            itemTop  = Canvas.GetTop(movedItem);
            TemplateViewModel context  = (TemplateViewModel)canvas.DataContext;

            // get list of close items according to snapDeltaPixels value
            List <ContentPresenter> presenters  = ControlHelper.GetUnselectedChildPresenters(canvas).ToList();
            List <ContentPresenter> closeByLeft = presenters.Where(x => Math.Abs(Canvas.GetLeft(x) - itemLeft) <= snapDeltaPixels).ToList();
            List <ContentPresenter> closeByTop  = presenters.Where(x => Math.Abs(Canvas.GetTop(x) - itemTop) <= snapDeltaPixels).ToList();

            List <Line> resultingSnapLines = new List <Line>();

            if (closeByLeft.Count > 0)
            {
                // closest by left position and then by top
                ContentPresenter closest = closeByLeft.OrderBy(x => Math.Abs(Canvas.GetLeft(x) - itemLeft))
                                           .ThenBy(x => Math.Abs(Canvas.GetTop(x) - itemTop)).First();

                // move snapped item to desired position
                double targetLeft = Canvas.GetLeft(closest);
                double targetTop  = Canvas.GetTop(closest);
                Canvas.SetLeft(movedItem, targetLeft);

                // add lowest item height to the line length
                double itemHeight = targetTop > itemTop ? closest.Height : movedItem.Height;

                // draw snap line and add to the list
                Line line = new Line();
                line.X1 = line.X2 = targetLeft;
                line.Y1 = Math.Max(Math.Min(itemTop, targetTop) - snapLineTail, 0);
                line.Y2 = Math.Max(itemTop, targetTop) + itemHeight + snapLineTail;

                resultingSnapLines.Add(line);
            }

            if (closeByTop.Count > 0)
            {
                // closes by top position and then by left
                ContentPresenter closest = closeByTop.OrderBy(x => Math.Abs(Canvas.GetTop(x) - itemTop))
                                           .ThenBy(x => Math.Abs(Canvas.GetLeft(x) - itemLeft)).First();

                // move snapped item to desired position
                double targetLeft = Canvas.GetLeft(closest);
                double targetTop  = Canvas.GetTop(closest);
                Canvas.SetTop(movedItem, targetTop);

                double itemWidth = targetLeft > itemLeft ? closest.Width : movedItem.Width;

                // draw snap line and add to the list
                Line line = new Line();
                line.Y1 = line.Y2 = targetTop;
                line.X1 = Math.Max(Math.Min(itemLeft, targetLeft) - snapLineTail, 0);
                line.X2 = Math.Max(itemLeft, targetLeft) + itemWidth + snapLineTail;

                resultingSnapLines.Add(line);
            }

            if (context.GotSnapLines)
            {
                context.CleanSnapLines();
            }

            // draw snap lines
            foreach (Line snapLine in resultingSnapLines)
            {
                context.AddLine(snapLine);
            }
        }
Пример #8
0
        /// <summary>
        /// Snap group of elements
        /// </summary>
        /// <param name="movedGroup">Group of elements to snap</param>
        /// <param name="canvas">Main canvas holding all items</param>
        private void SnapGroup(List <ContentPresenter> movedGroup, CustomCanvas canvas)
        {
            // get bounding box Rect of snap group
            Rect boundingBox = GetBoundingBox(movedGroup);

            TemplateViewModel       context     = (TemplateViewModel)canvas.DataContext;
            List <ContentPresenter> canvasItems = ControlHelper.GetUnselectedChildPresenters(canvas).ToList();

            // get list of close items according to snapDeltaPixels value
            List <Line>             resultingSnapLines = new List <Line>();
            List <ContentPresenter> closeByLeft        = canvasItems.Where(x => Math.Abs(Canvas.GetLeft(x) - boundingBox.Left) <= snapDeltaPixels).ToList();
            List <ContentPresenter> closeByTop         = canvasItems.Where(x => Math.Abs(Canvas.GetTop(x) - boundingBox.Top) <= snapDeltaPixels).ToList();

            if (closeByLeft.Count > 0)
            {
                // closes by left position and then by top
                ContentPresenter closest = closeByLeft.OrderBy(x => Math.Abs(Canvas.GetLeft(x) - boundingBox.Left))
                                           .ThenBy(x => Math.Abs(Canvas.GetTop(x) - boundingBox.Top)).First();

                double targetLeft = Canvas.GetLeft(closest);
                double targetTop  = Canvas.GetTop(closest);

                // snap each item of the group according to calculated distance to the target
                double moveDelta = boundingBox.Left - targetLeft;
                movedGroup.ForEach(x => Canvas.SetLeft(x, Canvas.GetLeft(x) - moveDelta));

                // add lowest item height to the line length
                double itemHeight = targetTop > boundingBox.Top ? closest.Height : boundingBox.Height;

                // draw snap line and add to the list
                Line line = new Line();
                line.X1 = line.X2 = targetLeft;
                line.Y1 = Math.Max(Math.Min(boundingBox.Top, targetTop) - snapLineTail, 0);
                line.Y2 = Math.Max(boundingBox.Top, targetTop) + itemHeight + snapLineTail;

                resultingSnapLines.Add(line);
            }

            if (closeByTop.Count > 0)
            {
                // closes by top position and then by left
                ContentPresenter closest = closeByTop.OrderBy(x => Math.Abs(Canvas.GetTop(x) - boundingBox.Top))
                                           .ThenBy(x => Math.Abs(Canvas.GetLeft(x) - boundingBox.Left)).First();

                double targetLeft = Canvas.GetLeft(closest);
                double targetTop  = Canvas.GetTop(closest);

                // snap each item of the group according to calculated distance to the target
                double moveDelta = boundingBox.Top - targetTop;
                movedGroup.ForEach(x => Canvas.SetTop(x, Canvas.GetTop(x) - moveDelta));

                double itemWidth = targetLeft > boundingBox.Left ? closest.Width : boundingBox.Width;

                // draw snap line and add to the list
                Line line = new Line();
                line.Y1 = line.Y2 = targetTop;
                line.X1 = Math.Max(Math.Min(boundingBox.Left, targetLeft) - snapLineTail, 0);
                line.X2 = Math.Max(boundingBox.Left, targetLeft) + itemWidth + snapLineTail;

                resultingSnapLines.Add(line);
            }

            if (context.GotSnapLines)
            {
                context.CleanSnapLines();
            }

            // draw snap lines
            foreach (Line snapLine in resultingSnapLines)
            {
                context.AddLine(snapLine);
            }
        }
Пример #9
0
        /// <summary>
        /// Occurs as the mouse changes position when a Thumb control has logical focus and mouse capture
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The event args</param>
        private void ResizeDragDelta(object sender, DragDeltaEventArgs e)
        {
            // get to resized element
            Grid        thumbsGrid  = (Grid)VisualTreeHelper.GetParent(this);
            ResizeThumb parentThumb = (ResizeThumb)VisualTreeHelper.GetParent(thumbsGrid);
            Adorner     adorner     = (Adorner)VisualTreeHelper.GetParent(parentThumb);

            // presenter that holds dragged item
            ContentPresenter presenter = (ContentPresenter)VisualTreeHelper.GetParent(adorner.AdornedElement);

            // parent canvas
            CustomCanvas canvas = (CustomCanvas)VisualTreeHelper.GetParent(presenter);

            // prepare items for resize depending on item level (question or bubble)
            List <ContentPresenter> presenters;

            if (canvas.Name.Equals(Properties.Resources.RootCanvasName))
            {
                // here we resize questions (e.g. choicebox), so take selected items
                presenters = ControlHelper.GetSelectedChildPresenters(canvas);
            }
            else
            {
                // here we resize bubbles, so get neighbor bubbles inside question (always resize bubbles equally)
                presenters = ControlHelper.GetChildPresenters(canvas);
            }

            double minLeft, minTop, minDeltaHorizontal, minDeltaVertical;
            double maxDeltaVertical, maxDeltaHorizontal;

            double maxHorizontalDeltaToChild = double.MaxValue;
            double maxVerticalDeltaToChild   = double.MaxValue;

            this.CalculateLimits(canvas, presenters, out minLeft, out minTop, out minDeltaHorizontal, out minDeltaVertical,
                                 out maxDeltaHorizontal, out maxDeltaVertical);

            minDeltaVertical   = Math.Min(minDeltaVertical, maxVerticalDeltaToChild);
            minDeltaHorizontal = Math.Min(minDeltaHorizontal, maxHorizontalDeltaToChild);

            foreach (ContentPresenter element in presenters)
            {
                double newHeight = element.ActualHeight;
                double newWidth  = element.ActualWidth;

                double newTop  = Canvas.GetTop(element);
                double newLeft = Canvas.GetLeft(element);

                double scale, dragDeltaVertical;
                switch (this.VerticalAlignment)
                {
                case VerticalAlignment.Bottom:
                    dragDeltaVertical = Math.Max(Math.Min(-e.VerticalChange, minDeltaVertical), -maxDeltaVertical);
                    newHeight         = element.ActualHeight - dragDeltaVertical;
                    break;

                case VerticalAlignment.Top:
                    dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical);
                    scale             = (element.ActualHeight - dragDeltaVertical) / element.ActualHeight;

                    newTop    = newTop - element.Height * (scale - 1);
                    newHeight = element.ActualHeight - dragDeltaVertical;
                    break;
                }

                double dragDeltaHorizontal;
                switch (this.HorizontalAlignment)
                {
                case HorizontalAlignment.Left:
                    dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal);
                    scale = (element.ActualWidth - dragDeltaHorizontal) / element.ActualWidth;

                    newLeft  = Canvas.GetLeft(element) - element.Width * (scale - 1);
                    newWidth = element.ActualWidth * scale;
                    break;

                case HorizontalAlignment.Right:
                    dragDeltaHorizontal = Math.Max(Math.Min(-e.HorizontalChange, minDeltaHorizontal), -maxDeltaHorizontal);
                    newWidth            = element.ActualWidth - dragDeltaHorizontal;
                    break;
                }

                var childs = this.GetChildElements(element);
                if (childs == null)
                {
                    element.Width  = newWidth;
                    element.Height = newHeight;
                    Canvas.SetTop(element, newTop);
                    Canvas.SetLeft(element, newLeft);
                }
                else
                {
                    double scaleH = newHeight / element.ActualHeight;
                    double scaleW = newWidth / element.ActualWidth;

                    if (this.CanTransformChildsRecursive(childs, scaleH, scaleW))
                    {
                        this.TransformChildsRecursive(childs, scaleH, scaleW);

                        element.Width  = newWidth;
                        element.Height = newHeight;
                        Canvas.SetTop(element, newTop);
                        Canvas.SetLeft(element, newLeft);
                    }
                }
            }

            e.Handled = true;
        }