Пример #1
0
        public static bool ResizePopup(FrameworkElement itemsPresenter,
                                       Size minDropDownSize,
                                       bool canUserResizeHorizontally,
                                       bool canUserResizeVertically,
                                       bool isDropDownPositionedLeft,
                                       bool isDropDownPositionedAbove,
                                       Rect screenBounds,
                                       UIElement popupRoot,
                                       double horizontalDelta,
                                       double verticalDelta)
        {
            if (itemsPresenter != null)
            {
                verticalDelta   = isDropDownPositionedAbove ? (-verticalDelta) : verticalDelta;
                horizontalDelta = isDropDownPositionedLeft ? (-horizontalDelta) : horizontalDelta;

                Rect rootScreenBounds = new Rect(popupRoot.PointToScreen(new Point()),
                                                 popupRoot.PointToScreen(new Point(popupRoot.RenderSize.Width, popupRoot.RenderSize.Height)));

                // There is a bug in .net3.5 in PopupRoot. When a Popup reaches a screen edge its size is restricted in both dimensions,
                // regardless of which dimension is at the screen edge.
                // If Popup is at bottom screen edge and you try to increase width horizontally,
                // the contents increase in size but get clipped by the Popup. This has been fixed in 4.0.
                // To workaround this bug, we dont allow Popup to ever go beyond top/bottom screen edge via resizing
                // Note that Popup could still hit screen edge even before resizing, when Popup is opened for the first time.
                // This will cause clipping but we are not going to workaround this case.

                // Case 1: Popup is already at screen edge.
                // So we want to ignore the delta if trying to increase in direction of screen edge.
                bool isAtBottomScreenEdge = DoubleUtil.GreaterThanOrClose(rootScreenBounds.Bottom, screenBounds.Bottom);
                bool isAtTopScreenEdge    = DoubleUtil.LessThanOrClose(rootScreenBounds.Top, screenBounds.Top + TopScreenEdgeBuffer);
                bool isAtRightScreenEdge  = DoubleUtil.GreaterThanOrClose(rootScreenBounds.Right, screenBounds.Right);
                bool isAtLeftScreenEdge   = DoubleUtil.LessThanOrClose(rootScreenBounds.Left, screenBounds.Left);

                // Case 2: If applying the deltas will make popup go over the screen edge.
                // Truncate delta to whatever is remaining until the screen edge.
                bool isAlmostAtBottomScreenEdge = DoubleUtil.GreaterThanOrClose(rootScreenBounds.Bottom + verticalDelta, screenBounds.Bottom);
                bool isAlmostAtTopScreenEdge    = DoubleUtil.LessThanOrClose(rootScreenBounds.Top - verticalDelta, screenBounds.Top + TopScreenEdgeBuffer);
                bool isAlmostAtRightScreenEdge  = DoubleUtil.GreaterThanOrClose(rootScreenBounds.Right + horizontalDelta, screenBounds.Right);
                bool isAlmostAtLeftScreenEdge   = DoubleUtil.LessThanOrClose(rootScreenBounds.Left - horizontalDelta, screenBounds.Left);

                if (isDropDownPositionedAbove)
                {
                    if (isAtTopScreenEdge && DoubleUtil.GreaterThanOrClose(verticalDelta, 0))
                    {
                        verticalDelta = 0;
                    }
                    else if (isAlmostAtTopScreenEdge)
                    {
                        verticalDelta = rootScreenBounds.Top - TopScreenEdgeBuffer;
                    }
                }
                else if (!isDropDownPositionedAbove)
                {
                    if (isAtBottomScreenEdge && DoubleUtil.GreaterThanOrClose(verticalDelta, 0))
                    {
                        verticalDelta = 0;
                    }
                    else if (isAlmostAtBottomScreenEdge)
                    {
                        verticalDelta = screenBounds.Bottom - rootScreenBounds.Bottom;
                    }
                }

                // We need this check because WPF Popup's can render only on single monitor.
                // (i.e. wont extend to second monitor in multi-mon setup).
                if (isAtRightScreenEdge && DoubleUtil.GreaterThanOrClose(horizontalDelta, 0))
                {
                    horizontalDelta = 0;
                }
                else if (isAlmostAtRightScreenEdge)
                {
                    horizontalDelta = screenBounds.Right - rootScreenBounds.Right;
                }

                if (isAtLeftScreenEdge && DoubleUtil.GreaterThanOrClose(horizontalDelta, 0))
                {
                    horizontalDelta = 0;
                }
                else if (isAlmostAtLeftScreenEdge)
                {
                    horizontalDelta = rootScreenBounds.Left - screenBounds.Left;
                }

                double newWidth  = itemsPresenter.Width + horizontalDelta;
                double newHeight = itemsPresenter.Height + verticalDelta;
                return(ResizePopupActual(itemsPresenter, minDropDownSize, canUserResizeHorizontally, canUserResizeVertically, newWidth, newHeight));
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        ///   Measures all of the RibbonGroups, and asks them to resize themselves appropriately
        ///   to fit within the available room in the GroupsContainer.
        /// </summary>
        /// <param name="availableSize">The available size that this element can give to child elements.</param>
        /// <returns>
        ///   The size that the groups container determines it needs during layout, based
        ///   on its calculations of child element sizes.
        /// </returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            RibbonTab ribbonTab = ParentRibbonTab;

            double remainingSpace        = 0;
            Size   desiredSize           = BasicMeasure(availableSize, out remainingSpace);
            UIElementCollection children = InternalChildren;

            if (children.Count != _cachedChildCount)
            {
                ResetNextIncreaseGroupCache();
                _cachedChildCount = children.Count;
            }

            if (DoubleUtil.GreaterThan(remainingSpace, 0))
            {
                // nudging the positive remaining space by a pixel
                // protects against aggregation of double errors and
                // provides a better appreance.
                remainingSpace = Math.Max(0, remainingSpace - 1);
            }

            if ((DoubleUtil.GreaterThanOrClose(_cachedRemainingSpace, 0) && (DoubleUtil.LessThan(remainingSpace, 0) || DoubleUtil.GreaterThan(remainingSpace, _cachedRemainingSpace))) ||
                (DoubleUtil.LessThan(_cachedRemainingSpace, 0) && DoubleUtil.GreaterThan(remainingSpace, 0)))
            {
                if (ribbonTab != null)
                {
                    double?lastPreIncreaseRemainingSpace = null;
                    while (DoubleUtil.GreaterThan(remainingSpace, 0))
                    {
                        // When there is remaining space try to give it
                        // to stars, which qualify to increase before
                        // next group resize.
                        desiredSize = StarMeasure(availableSize,
                                                  desiredSize,
                                                  ribbonTab,
                                                  ref remainingSpace);

                        // When there is more remaining space, increase
                        // the size of the next group.
                        if (DoubleUtil.GreaterThan(remainingSpace, 0))
                        {
                            if (double.IsNaN(_nextGroupIncreaseWidth) ||
                                DoubleUtil.GreaterThanOrClose(remainingSpace, _nextGroupIncreaseWidth))
                            {
                                if (ribbonTab.IncreaseNextGroupSize())
                                {
                                    ResetNextIncreaseGroupCache();
                                    lastPreIncreaseRemainingSpace = remainingSpace;
                                    desiredSize = BasicMeasure(availableSize, out remainingSpace);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    double preDecreaseGroupRemainingSpace = remainingSpace;
                    while (DoubleUtil.LessThan(remainingSpace, 0))
                    {
                        // When the remaining space is negative decrease the
                        // next groups size.
                        if (ribbonTab.DecreaseNextGroupSize())
                        {
                            desiredSize = BasicMeasure(availableSize, out remainingSpace);
                            if (lastPreIncreaseRemainingSpace != null)
                            {
                                // Though in most of the cases we expect that the desired size of the
                                // entire subtree is up to date synchronously, there are some cases where desired
                                // size of subtree gets updated asynchronously(eg. where bindings
                                // impacting desired size resolve at a later time). To gaurd against infinite
                                // loops in such cases, if this decrease operation is to compensate any unnecessary
                                // increase operation performed above, then use the remaining space
                                // computed before such corresponding unnecessary increase operation, instead
                                // of the value computed post decrease which may be inaccurate due to some
                                // pending async updates. On the other hand if the group remains in
                                // same stage and when such async update happens at a later point of time,
                                // this measure would be executed again and hence fixing things.
                                remainingSpace = lastPreIncreaseRemainingSpace.Value;

                                // The remaining space needed to successfully perform the
                                // preceeding group increase without needing to do a compensating
                                // group decrease is cached to be used to optimize out the
                                // unsuccessful group size increases on further increase
                                // in remaining space.
                                _nextGroupIncreaseWidth       = lastPreIncreaseRemainingSpace.Value - preDecreaseGroupRemainingSpace;
                                lastPreIncreaseRemainingSpace = null;
                            }
                            else
                            {
                                ResetNextIncreaseGroupCache();
                            }
                            if (DoubleUtil.GreaterThan(remainingSpace, 0))
                            {
                                // Now if there is remaining space, give it to the
                                // qualified stars.
                                desiredSize = StarMeasure(availableSize,
                                                          desiredSize,
                                                          ribbonTab,
                                                          ref remainingSpace);
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            else if (DoubleUtil.GreaterThan(remainingSpace, 0))
            {
                desiredSize = StarMeasure(availableSize,
                                          desiredSize,
                                          ribbonTab,
                                          ref remainingSpace);
            }

            _cachedRemainingSpace = remainingSpace;

            //// Scroll if not enough space
            return(desiredSize);
        }
Пример #3
0
        /// <summary>
        /// This method implement the core algorithm to check whether a point is within a polygon
        /// that are formed by the lasso points.
        /// </summary>
        /// <param name="point"></param>
        /// <returns>true if the point is contained within the lasso; false otherwise </returns>
        internal bool Contains(Point point)
        {
            System.Diagnostics.Debug.Assert(_points != null);

            if (false == _bounds.Contains(point))
            {
                return(false);
            }

            bool isHigher = false;
            int  last     = _points.Count;

            while (--last >= 0)
            {
                if (!DoubleUtil.AreClose(_points[last].Y, point.Y))
                {
                    isHigher = (point.Y < _points[last].Y);
                    break;
                }
            }

            bool  isInside       = false;
            Point prevLassoPoint = _points[_points.Count - 1];

            for (int i = 0; i < _points.Count; i++)
            {
                Point lassoPoint = _points[i];
                if (DoubleUtil.AreClose(lassoPoint.Y, point.Y))
                {
                    if (DoubleUtil.AreClose(lassoPoint.X, point.X))
                    {
                        isInside = true;
                        break;
                    }
                    if ((0 != i) && DoubleUtil.AreClose(prevLassoPoint.Y, point.Y) &&
                        DoubleUtil.GreaterThanOrClose(point.X, Math.Min(prevLassoPoint.X, lassoPoint.X)) &&
                        DoubleUtil.LessThanOrClose(point.X, Math.Max(prevLassoPoint.X, lassoPoint.X)))
                    {
                        isInside = true;
                        break;
                    }
                }
                else if (isHigher != (point.Y < lassoPoint.Y))
                {
                    isHigher = !isHigher;
                    if (DoubleUtil.GreaterThanOrClose(point.X, Math.Max(prevLassoPoint.X, lassoPoint.X)))
                    {
                        // there certainly is an intersection on the left
                        isInside = !isInside;
                    }
                    else if (DoubleUtil.GreaterThanOrClose(point.X, Math.Min(prevLassoPoint.X, lassoPoint.X)))
                    {
                        // The X of the point lies within the x ranges for the segment.
                        // Calculate the x value of the point where the segment intersects with the line.
                        Vector lassoSegment = lassoPoint - prevLassoPoint;
                        System.Diagnostics.Debug.Assert(lassoSegment.Y != 0);
                        double x = prevLassoPoint.X + (lassoSegment.X / lassoSegment.Y) * (point.Y - prevLassoPoint.Y);
                        if (DoubleUtil.GreaterThanOrClose(point.X, x))
                        {
                            isInside = !isInside;
                        }
                    }
                }
                prevLassoPoint = lassoPoint;
            }
            return(isInside);
        }
Пример #4
0
        // ------------------------------------------------------------------
        // Arrange content of formatted line.
        //
        //      vc - Visual collection of the parent.
        //      lineOffset - Offset of the line.
        // ------------------------------------------------------------------
        internal override void Arrange(VisualCollection vc, Vector lineOffset)
        {
            // Arrange inline objects
            int runDcp = _dcp;
            IList <TextSpan <TextRun> > runs = _line.GetTextRunSpans();

            Debug.Assert(runs != null, "Cannot retrieve runs collection.");

            // Calculate offset shift due to trailing spaces
            double adjustedXOffset = lineOffset.X + CalculateXOffsetShift();

            foreach (TextSpan <TextRun> textSpan in runs)
            {
                TextRun run = textSpan.Value;
                if (run is InlineObject)
                {
                    InlineObject inlineObject = run as InlineObject;

                    // Disconnect visual from its old parent, if necessary.
                    Visual currentParent = VisualTreeHelper.GetParent(inlineObject.Element) as Visual;
                    if (currentParent != null)
                    {
                        ContainerVisual parent = currentParent as ContainerVisual;
                        Invariant.Assert(parent != null, "parent should always derives from ContainerVisual");
                        parent.Children.Remove(inlineObject.Element);
                    }

                    // Get position of inline object withing the text line.
                    FlowDirection flowDirection;
                    Rect          rect = GetBoundsFromPosition(runDcp, inlineObject.Length, out flowDirection);
                    Debug.Assert(DoubleUtil.GreaterThanOrClose(rect.Width, 0), "Negative inline object's width.");

                    ContainerVisual proxyVisual = new ContainerVisual();
                    if (inlineObject.Element is FrameworkElement)
                    {
                        FlowDirection parentFlowDirection = _owner.FlowDirection;
                        // Check parent's FlowDirection to determine if mirroring is needed

                        DependencyObject parent = ((FrameworkElement)inlineObject.Element).Parent;
                        if (parent != null)
                        {
                            parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty);
                        }

                        PtsHelper.UpdateMirroringTransform(_owner.FlowDirection, parentFlowDirection, proxyVisual, rect.Width);
                    }
                    vc.Add(proxyVisual);

                    if (_owner.UseLayoutRounding)
                    {
                        // If using layout rounding, check whether rounding needs to compensate for high DPI
                        DpiScale dpi = _owner.GetDpi();
                        proxyVisual.Offset = new Vector(UIElement.RoundLayoutValue(lineOffset.X + rect.Left, dpi.DpiScaleX),
                                                        UIElement.RoundLayoutValue(lineOffset.Y + rect.Top, dpi.DpiScaleY));
                    }
                    else
                    {
                        proxyVisual.Offset = new Vector(lineOffset.X + rect.Left, lineOffset.Y + rect.Top);
                    }
                    proxyVisual.Children.Add(inlineObject.Element);

                    // Combine text line offset (relative to the Text control) with inline object
                    // offset (relative to the line) and set transorm on the visual. Trailing spaces
                    // shift is not added here because it is returned by GetBoundsFromPosition
                    inlineObject.Element.Arrange(new Rect(inlineObject.Element.DesiredSize));
                }

                // Do not use TextRun.Length, because it gives total length of the run.
                // So, if the run is broken between lines, it gives incorrect value.
                // Use length of the TextSpan instead, which gives the correct length here.
                runDcp += textSpan.Length;
            }
        }
Пример #5
0
        // Token: 0x06006DAF RID: 28079 RVA: 0x001F81B4 File Offset: 0x001F63B4
        private bool Contains(Point point)
        {
            if (!this._boundingBox.Contains(point))
            {
                return(false);
            }
            bool flag = false;
            int  num  = this._lasso.Count;

            while (--num >= 0)
            {
                if (!DoubleUtil.AreClose(this._lasso[num].Y, point.Y))
                {
                    flag = (point.Y < this._lasso[num].Y);
                    break;
                }
            }
            bool  flag2  = false;
            bool  flag3  = false;
            Point point2 = this._lasso[this._lasso.Count - 1];

            for (int i = 0; i < this._lasso.Count; i++)
            {
                Point point3 = this._lasso[i];
                if (DoubleUtil.AreClose(point3.Y, point.Y))
                {
                    if (DoubleUtil.AreClose(point3.X, point.X))
                    {
                        flag2 = true;
                        break;
                    }
                    if (i != 0 && DoubleUtil.AreClose(point2.Y, point.Y) && DoubleUtil.GreaterThanOrClose(point.X, Math.Min(point2.X, point3.X)) && DoubleUtil.LessThanOrClose(point.X, Math.Max(point2.X, point3.X)))
                    {
                        flag2 = true;
                        break;
                    }
                }
                else if (flag != point.Y < point3.Y)
                {
                    flag = !flag;
                    if (DoubleUtil.GreaterThanOrClose(point.X, Math.Max(point2.X, point3.X)))
                    {
                        flag2 = !flag2;
                        if (i == 0 && DoubleUtil.AreClose(point.X, Math.Max(point2.X, point3.X)))
                        {
                            flag3 = true;
                        }
                    }
                    else if (DoubleUtil.GreaterThanOrClose(point.X, Math.Min(point2.X, point3.X)))
                    {
                        Vector vector = point3 - point2;
                        double value  = point2.X + vector.X / vector.Y * (point.Y - point2.Y);
                        if (DoubleUtil.GreaterThanOrClose(point.X, value))
                        {
                            flag2 = !flag2;
                            if (i == 0 && DoubleUtil.AreClose(point.X, value))
                            {
                                flag3 = true;
                            }
                        }
                    }
                }
                point2 = point3;
            }
            return(flag2 && !flag3);
        }
Пример #6
0
        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size();

            // Don't measure the child if tabs are not ready yet or Ribbon is collapsed.
            if (Ribbon != null && !Ribbon.IsCollapsed)
            {
                double remainingSpace    = availableSize.Width;
                bool   invalidateTHPanel = false;
                RibbonTabHeadersPanel tabHeadersPanel = null;
                if (Ribbon.RibbonTabHeaderItemsControl != null)
                {
                    tabHeadersPanel = Ribbon.RibbonTabHeaderItemsControl.InternalItemsHost as RibbonTabHeadersPanel;
                }
                double tabHeadersPanelSpaceAvailable = (tabHeadersPanel != null) ? tabHeadersPanel.SpaceAvailable : 0.0;

                foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren)
                {
                    double width = 0;
                    tabGroupHeader.ArrangeWidth      = 0;
                    tabGroupHeader.ArrangeX          = 0;
                    tabGroupHeader.IdealDesiredWidth = 0.0;

                    if (tabGroupHeader.Visibility == Visibility.Visible && tabGroupHeader.FirstVisibleTab != null && DoubleUtil.GreaterThanOrClose(remainingSpace, 0.0))
                    {
                        // Measure the maximum desired width
                        // TabHeaders should be padded up more if needed.
                        // Also we need to determine if we need to show the label tooltip
                        tabGroupHeader.Measure(new Size(double.PositiveInfinity, availableSize.Height));
                        tabGroupHeader.IdealDesiredWidth = tabGroupHeader.DesiredSize.Width;

                        // If TabHeadersPanel has space to expand, then invalidate it so that TabHeaders add extra Padding to themselves.
                        double desiredExtraPadding = tabGroupHeader.IdealDesiredWidth - tabGroupHeader.TabsDesiredWidth;
                        if (DoubleUtil.GreaterThan(desiredExtraPadding, 0.0) &&
                            DoubleUtil.GreaterThan(tabHeadersPanelSpaceAvailable, 0.0))
                        {
                            invalidateTHPanel = true;
                        }

                        width = tabGroupHeader.TabsDesiredWidth;
                        // If the difference between tabGroupHeader.TabsDesiredWidth and remainingSpace is less
                        // than 1e-10 then assume that both are same. This is because TextBlock is very sensitive to
                        // even a minute floating point difference and displays ellipsis even when sufficient
                        // space is available.
                        if (Math.Abs(tabGroupHeader.TabsDesiredWidth - remainingSpace) > _desiredWidthEpsilon)
                        {
                            // Clip on the  left side
                            width = Math.Min(tabGroupHeader.TabsDesiredWidth, remainingSpace);
                        }

                        tabGroupHeader.ArrangeWidth = width;
                        tabGroupHeader.Measure(new Size(width, availableSize.Height));

                        // If label is truncated - show the tooltip
                        tabGroupHeader.ShowLabelToolTip = DoubleUtil.GreaterThan(tabGroupHeader.IdealDesiredWidth, width);

                        remainingSpace = remainingSpace - width;
                    }

                    desiredSize.Width += width;
                    desiredSize.Height = Math.Max(desiredSize.Height, tabGroupHeader.DesiredSize.Height);
                }

                if (WaitingForMeasure || invalidateTHPanel)
                {
                    if (tabHeadersPanel != null)
                    {
                        tabHeadersPanel.InvalidateMeasure();
                    }
                }
            }

            return(desiredSize);
        }