Example #1
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);
        }