//public static OrientedSize ArrangeStackLine(this Panel panel, Orientation orientation, Range<int> line, double lineOffset, double itemOffset, double? fixedLineSize, double? fixedItemSize) //{ // return ArrangeStackLine(panel.Children.Cast<UIElement>().Skip(line.Minimum).Take(line.Maximum - line.Minimum), orientation, lineOffset, itemOffset, fixedLineSize, fixedItemSize); //} public static OrientedSize ArrangeStackLine(IEnumerable <UIElement> elements, Orientation orientation, double lineOffset, double itemOffset, double?fixedLineSize, double?fixedItemSize) { var isHorizontal = orientation.IsHorizontal(); var orientedSize = new OrientedSize(orientation); foreach (var element in elements) { var elementSize = element.DesiredSize.AsOriented(orientation); var itemSize = fixedItemSize ?? elementSize.Direct; var lineSize = fixedLineSize ?? elementSize.Indirect; var bounds = isHorizontal ? new Rect(itemOffset, lineOffset, itemSize, lineSize) : new Rect(lineOffset, itemOffset, lineSize, itemSize); //bounds = bounds.LayoutRoundToEven(); element.Arrange(bounds); itemOffset += itemSize; //itemOffset = itemOffset.LayoutRoundMidPointFromZero(orientation); orientedSize = orientedSize.StackSize(elementSize); } return(orientedSize); }
//public static OrientedSize MeasureStackLine(this Panel panel, Orientation orientation, Range<int> line, double lineOffset, double itemOffset, double? fixedLineSize, double? fixedItemSize) //{ // return MeasureStackLine(panel.Children.Cast<UIElement>().Skip(line.Minimum).Take(line.Length()), orientation, null, null, fixedLineSize, fixedItemSize); //} public static OrientedSize MeasureStackLine(IEnumerable <UIElement> elements, OrientedSize availableSize, OrientedSize minimumSize, double?fixedLineSize, double?fixedItemSize) { var orientation = availableSize.Orientation; var orientedSize = new OrientedSize(orientation); foreach (var element in elements) { var currentConstraint = new OrientedSize(orientation) { Direct = (availableSize.Direct - orientedSize.Direct).Clamp(minimumSize.Direct, double.PositiveInfinity), Indirect = availableSize.Indirect.Clamp(minimumSize.Indirect, double.PositiveInfinity) }; var measureSize = new OrientedSize(orientation) { Direct = Math.Min(currentConstraint.Direct, fixedItemSize ?? double.PositiveInfinity), Indirect = Math.Min(currentConstraint.Indirect, fixedLineSize ?? double.PositiveInfinity) }; element.Measure(measureSize.Size); var desired = element.DesiredSize.AsOriented(orientation); orientedSize = orientedSize.StackSize(desired); } return(orientedSize); }
private void EnsureSizePart(TGridLineModel model, Size availableSize, Orientation orientation, bool expandCross) { var horizontal = orientation.IsHorizontal(); var orientedSize = new OrientedSize(orientation, availableSize); var currentOrientedSize = new OrientedSize(orientation, _size); var gridLines = model.GridLines; var sortedDefinitions = gridLines.SortedLines; var fillSize = orientedSize.Direct + MaxGridStep; var lineSize = orientedSize.Indirect + (expandCross ? MaxGridStep : 0); var lineCount = horizontal ? _lineCountX : _lineCountY; if (lineSize.IsGreaterThan(currentOrientedSize.Indirect)) { for (var i = 0; i < sortedDefinitions.Count; i++) { var pathFigureCollection = _pathFigures[i].Figures; var iLine = 0; foreach (var figure in pathFigureCollection) { var line = (LineSegment)figure.Segments[0]; var lineOrientation = figure.StartPoint.X.Equals(line.Point.X) ? Orientation.Horizontal : Orientation.Vertical; if (orientation != lineOrientation) { continue; } var orientedPoint = new OrientedPoint(orientation, figure.StartPoint); var iStep = gridLines.GetSortedDefinitionIndex(iLine); var lineDefinition = sortedDefinitions[iStep]; UpdateLineFigure(figure, lineDefinition, orientation, orientedPoint.Direct, orientedPoint.Indirect, lineSize); iLine++; } } } for (var offset = lineCount * GridStep; offset < fillSize; offset += GridStep) { var snapOffset = offset.LayoutRound(orientation, RoundingMode.MidPointFromZero) + 0.5; var iStep = gridLines.GetSortedDefinitionIndex(lineCount); var lineDefinition = sortedDefinitions[iStep]; var pathFigureCollection = _pathFigures[iStep].Figures; pathFigureCollection.Add(CreateLineFigure(lineDefinition, orientation, snapOffset, 0, lineSize)); lineCount++; } if (horizontal) { _lineCountX = lineCount; } else { _lineCountY = lineCount; } }
public static OrientedSize ExpandTo(OrientedSize size, OrientedSize another) { var clone = size; clone.Size = clone.Size.ExpandTo(another.Size); return(clone); }
internal static OrientedSize ConstraintSize(this OrientedSize desiredSize, OrientedSize availableSize) { if (desiredSize.Orientation != availableSize.Orientation) { throw new InvalidOperationException(); } return(new OrientedSize(desiredSize.Orientation, desiredSize.Size.ConstraintSize(availableSize.Size))); }
private static OrientedSize GetFinalMeasureSize(OrientedSize availableSize, OrientedSize desiredSize, OrientedSize visibleSize) { var finalSize = availableSize; // Indirect finalSize.Indirect = finalSize.Indirect.IsInfinity() ? desiredSize.Indirect : visibleSize.Indirect; // Direct finalSize.Direct = finalSize.Direct.IsInfinity() ? desiredSize.Direct : visibleSize.Direct; return(finalSize.ConstraintSize(availableSize)); }
public static Size Arrange(IWrapPanel panel, Size finalSize) { var orientation = panel.Orientation; var lineSize = new OrientedSize(orientation); var maximumSize = new OrientedSize(orientation, finalSize); var itemWidth = panel.ItemWidth.IsNaN() ? (double?)null : panel.ItemWidth; var itemHeight = panel.ItemHeight.IsNaN() ? (double?)null : panel.ItemHeight; var lineOffset = 0.0; var fixedItemSize = orientation.IsHorizontal() ? itemWidth : itemHeight; var children = panel.Elements; var count = children.Count; var lineStart = 0; for (var lineEnd = 0; lineEnd < count; lineEnd++) { var element = children[lineEnd]; var elementSize = element.GetDesiredOrientedSize(orientation, itemWidth, itemHeight); if (maximumSize.Direct.IsLessThan(lineSize.Direct + elementSize.Direct, XamlConstants.LayoutComparisonPrecision)) { panel.ArrangeStackLine(orientation, Zaaml.Core.Range.Create(lineStart, lineEnd), lineOffset, 0, lineSize.Indirect, fixedItemSize); lineOffset += lineSize.Indirect; lineSize = elementSize; if (maximumSize.Direct.IsLessThan(elementSize.Direct, XamlConstants.LayoutComparisonPrecision)) { panel.ArrangeStackLine(orientation, Zaaml.Core.Range.Create(lineStart, ++lineEnd), lineOffset, 0, lineSize.Indirect, fixedItemSize); lineOffset += lineSize.Indirect; lineSize = new OrientedSize(orientation); } lineStart = lineEnd; } else { lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } if (lineStart < count) { panel.ArrangeStackLine(orientation, Zaaml.Core.Range.Create(lineStart, count), lineOffset, 0, lineSize.Indirect, fixedItemSize); } return(finalSize); }
internal static OrientedSize Clamp(this OrientedSize self, OrientedSize min, OrientedSize max) { if (self.Orientation != min.Orientation || min.Orientation != max.Orientation) { throw new InvalidOperationException(); } return(new OrientedSize(self.Orientation) { Direct = self.Direct.Clamp(min.Direct, max.Direct), Indirect = self.Indirect.Clamp(min.Indirect, max.Indirect), }); }
protected override Size ArrangeOverride(Size finalSize) { Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, finalSize.Width, finalSize.Height); double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !double.IsNaN(itemWidth); bool hasFixedHeight = !double.IsNaN(itemHeight); double indirectOffset = 0; double? directDelta = (o == Orientation.Horizontal) ? (hasFixedWidth ? (double?)itemWidth : null) : (hasFixedHeight ? (double?)itemHeight : null); UIElementCollection children = Children; int count = children.Count; int lineStart = 0; for (int lineEnd = 0; lineEnd < count; lineEnd++) { UIElement element = children[lineEnd]; OrientedSize elementSize = new OrientedSize(o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); if (IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { ArrangeLine(lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect); indirectOffset += lineSize.Indirect; lineSize = elementSize; if (IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { ArrangeLine(lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect); indirectOffset += lineSize.Indirect; lineSize = new OrientedSize(o); } lineStart = lineEnd; } else { lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } if (lineStart < count) { ArrangeLine(lineStart, count, directDelta, indirectOffset, lineSize.Indirect); } return(finalSize); }
private static OrientedSize GetChildConstraint(FlexElement flexElement, OrientedSize autoConstraint, OrientedSize starConstraint) { var flexLength = flexElement.Length; if (flexLength.IsStar) { starConstraint.Direct *= flexLength.Value; return(starConstraint); } if (flexLength.IsAbsolute) { autoConstraint.Direct = flexLength.Value; return(autoConstraint); } return(autoConstraint); }
private void ArrangeLine(int lineStart, int lineEnd, double?directDelta, double indirectOffset, double indirectGrowth) { double directOffset = 0.0; Orientation o = Orientation; bool isHorizontal = o == Orientation.Horizontal; UIElementCollection children = Children; for (int index = lineStart; index < lineEnd; index++) { UIElement element = children[index]; OrientedSize elementSize = new OrientedSize(o, element.DesiredSize.Width, element.DesiredSize.Height); double directGrowth = directDelta != null ? directDelta.Value : elementSize.Direct; Rect bounds = isHorizontal ? new Rect(directOffset, indirectOffset, directGrowth, indirectGrowth) : new Rect(indirectOffset, directOffset, indirectGrowth, directGrowth); element.Arrange(bounds); directOffset += directGrowth; } }
protected override Size MeasureOverride(Size constraint) { Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize totalSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, constraint.Width, constraint.Height); double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !double.IsNaN(itemWidth); bool hasFixedHeight = !double.IsNaN(itemHeight); Size itemSize = new Size(hasFixedWidth ? itemWidth : constraint.Width, hasFixedHeight ? itemHeight : constraint.Height); foreach (UIElement element in Children) { element.Measure(itemSize); OrientedSize elementSize = new OrientedSize(o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); if (IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; lineSize = elementSize; if (IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { totalSize.Direct = Math.Max(elementSize.Direct, totalSize.Direct); totalSize.Indirect += elementSize.Indirect; lineSize = new OrientedSize(o); } } else { lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; return(new Size(totalSize.Width, totalSize.Height)); }
public static Size Measure(IWrapPanel panel, Size availableSize) { var orientation = panel.Orientation; var result = new OrientedSize(orientation); var lineSize = new OrientedSize(orientation); var orientedConstraint = new OrientedSize(orientation, availableSize); var itemWidth = panel.ItemWidth.IsNaN() ? (double?)null : panel.ItemWidth; var itemHeight = panel.ItemHeight.IsNaN() ? (double?)null : panel.ItemHeight; var itemConstraintSize = new Size(itemWidth ?? availableSize.Width, itemHeight ?? availableSize.Height); foreach (var element in panel.Elements) { element.Measure(itemConstraintSize); var elementSize = element.GetDesiredOrientedSize(orientation, itemWidth, itemHeight); if (orientedConstraint.Direct.IsLessThan(lineSize.Direct + elementSize.Direct, XamlConstants.LayoutComparisonPrecision)) { result = result.WrapSize(lineSize); lineSize = elementSize; if (!orientedConstraint.Direct.IsLessThan(elementSize.Direct, XamlConstants.LayoutComparisonPrecision)) { continue; } result = result.WrapSize(elementSize); lineSize = new OrientedSize(orientation); } else { lineSize = lineSize.StackSize(elementSize); } } return(result.WrapSize(lineSize).Size); }
protected override Size MeasureOverrideCore(Size availableSize) { Children.Add(_phantomGroup); _phantomGroup.BeginMeasurePass(); _phantomGroup.Invalidate(); _phantomGroup.Measure(new Size(0, double.PositiveInfinity)); _phantomGroup.EndMeasurePass(); var largeItemDesiredSize = _phantomGroup.DesiredSize; Children.Remove(_phantomGroup); if (Children.Count == 0) { return(new Size(0, largeItemDesiredSize.Height)); } var reductionOrder = ActualGroupSizeReductionOrder.ToList(); OddMeasure = false; try { foreach (var ribbonGroup in Groups) { ribbonGroup.BeginMeasurePass(); } var nextReduceGroupIndex = 0; OrientedSize finalSize; var reductionLevel = 0; do { finalSize = new OrientedSize(Orientation.Horizontal); var measureItemSize = new Size(double.PositiveInfinity, largeItemDesiredSize.Height); if (OddMeasure) { measureItemSize.Height += 1; } foreach (var ribbonGroup in Groups) { ribbonGroup.InvalidateInt(this); finalSize = finalSize.StackSize(ribbonGroup.MeasureInt(measureItemSize, false)); } OddMeasure = !OddMeasure; if (finalSize.Direct.IsLessThanOrClose(availableSize.Width, XamlConstants.LayoutComparisonPrecision)) { return(GetFinalSize(availableSize, new Size(finalSize.Width, largeItemDesiredSize.Height))); } foreach (var ribbonGroup in ActualGroupSizeReductionOrder) { var shrink = ribbonGroup.Shrink(finalSize.Direct - availableSize.Width); if (shrink.IsZero(XamlConstants.LayoutComparisonPrecision)) { continue; } finalSize.Direct -= shrink; if (finalSize.Direct.IsLessThanOrClose(availableSize.Width, XamlConstants.LayoutComparisonPrecision)) { return(GetFinalSize(availableSize, new Size(finalSize.Width, largeItemDesiredSize.Height))); } } reductionLevel++; } while (ReduceNextGroup(reductionOrder, ref nextReduceGroupIndex)); return(GetFinalSize(availableSize, new Size(finalSize.Width, largeItemDesiredSize.Height))); } finally { for (var i = 0; i < (OddMeasure ? 2 : 1); i++) { var measureItemSize = new Size(double.PositiveInfinity, largeItemDesiredSize.Height); if (OddMeasure) { measureItemSize.Height += 1; } OddMeasure = !OddMeasure; foreach (var ribbonGroup in Groups) { ribbonGroup.InvalidateInt(this); ribbonGroup.MeasureInt(measureItemSize, true); } } foreach (var ribbonGroup in Groups) { ribbonGroup.EndMeasurePass(); } } }
/// <summary> /// Arrange a sequence of elements in a single line. /// </summary> /// <param name="lineStart"> /// Index of the first element in the sequence to arrange. /// </param> /// <param name="lineEnd"> /// Index of the last+1 element in the sequence to arrange. /// </param> /// <param name="directDelta"> /// Optional fixed growth in the primary direction. /// </param> /// <param name="directMaximum"> /// Maximum length in the direct direction. /// </param> /// <param name="indirectOffset"> /// Offset of the line in the indirect direction. /// </param> /// <param name="indirectGrowth"> /// Shared indirect growth of the elements on this line. /// </param> private void ArrangeLine(int lineStart, int lineEnd, double?directDelta, double directMaximum, double indirectOffset, double indirectGrowth) { Orientation o = Orientation; bool isHorizontal = o == Orientation.Horizontal; UIElementCollection children = Children; double directLength = 0.0; double itemCount = 0.0; double itemLength = isHorizontal ? ItemWidth : ItemHeight; if (AlignLastItems && !itemLength.IsNaN()) { // Length is easy to calculate in this case itemCount = Math.Floor(directMaximum / itemLength); directLength = itemCount * itemLength; } else { // Make first pass to calculate the slack space itemCount = lineEnd - lineStart; for (int index = lineStart; index < lineEnd; index++) { // Get the size of the element UIElement element = children[index]; OrientedSize elementSize = new OrientedSize(o, element.DesiredSize.Width, element.DesiredSize.Height); // Determine if we should use the element's desired size or the // fixed item width or height double directGrowth = directDelta != null ? directDelta.Value : elementSize.Direct; // Update total length directLength += directGrowth; } } // Determine slack double directSlack = directMaximum - directLength; double directSlackSlice = directSlack / (itemCount + 1.0); double directOffset = directSlackSlice; // Make second pass to arrange items for (int index = lineStart; index < lineEnd; index++) { // Get the size of the element UIElement element = children[index]; OrientedSize elementSize = new OrientedSize(o, element.DesiredSize.Width, element.DesiredSize.Height); // Determine if we should use the element's desired size or the // fixed item width or height double directGrowth = directDelta != null ? directDelta.Value : elementSize.Direct; // Arrange the element Rect bounds = isHorizontal ? new Rect(directOffset, indirectOffset, directGrowth, indirectGrowth) : new Rect(indirectOffset, directOffset, indirectGrowth, directGrowth); element.Arrange(bounds); // Update offset for next time directOffset += directGrowth + directSlackSlice; } }
public static OrientedSize ExpandTo(this OrientedSize size, OrientedSize value) { return(SizeUtils.ExpandTo(size, value)); }
public static double HalfIndirect(this OrientedSize orientedSize) { return(SizeUtils.HalfIndirect(orientedSize)); }
protected override Size MeasureOverride(Size constraint) { // Variables tracking the size of the current line, the total size // measured so far, and the maximum size available to fill. Note // that the line might represent a row or a column depending on the // orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize totalSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, constraint.Width, constraint.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); Size itemSize = new Size( hasFixedWidth ? itemWidth : constraint.Width, hasFixedHeight ? itemHeight : constraint.Height); // Measure each of the Children foreach (UIElement element in Children) { // Determine the size of the element element.Measure(itemSize); OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Update the total size with the direct and indirect growth // for the current line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Move the element to a new line lineSize = elementSize; // If the current element is larger than the maximum size, // place it on a line by itself if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Update the total size for the line occupied by this // single element totalSize.Direct = Math.Max(elementSize.Direct, totalSize.Direct); totalSize.Indirect += elementSize.Indirect; // Move to a new line lineSize = new OrientedSize(o); } } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Update the total size with the elements on the last line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Return the total size required as an un-oriented quantity return(new Size(totalSize.Width, totalSize.Height)); }
/// <summary> /// Arranges and sizes the /// <see cref="T:System.Windows.Controls.WrapPanel" /> control and its /// child elements. /// </summary> /// <param name="finalSize"> /// The area within the parent that the /// <see cref="T:System.Windows.Controls.WrapPanel" /> should use /// arrange itself and its children. /// </param> /// <returns> /// The actual size used by the /// <see cref="T:System.Windows.Controls.WrapPanel" />. /// </returns> protected override Size ArrangeOverride(Size finalSize) { // Variables tracking the size of the current line, and the maximum // size available to fill. Note that the line might represent a row // or a column depending on the orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, finalSize.Width, finalSize.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); double indirectOffset = 0; double?directDelta = (o == Orientation.Horizontal) ? (hasFixedWidth ? (double?)itemWidth : null) : (hasFixedHeight ? (double?)itemHeight : null); // Measure each of the Children. We will process the elements one // line at a time, just like during measure, but we will wait until // we've completed an entire line of elements before arranging them. // The lineStart and lineEnd variables track the size of the // currently arranged line. UIElementCollection children = Children; int count = children.Count; int lineStart = 0; for (int lineEnd = 0; lineEnd < count; lineEnd++) { UIElement element = children[lineEnd]; // Get the size of the element OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Then we just completed a line and we should arrange it ArrangeLine(lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect); // Move the current element to a new line indirectOffset += lineSize.Indirect; lineSize = elementSize; // If the current element is larger than the maximum size if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Arrange the element as a single line ArrangeLine(lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect); // Move to a new line indirectOffset += lineSize.Indirect; lineSize = new OrientedSize(o); } // Advance the start index to a new line after arranging lineStart = lineEnd; } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Arrange any elements on the last line if (lineStart < count) { ArrangeLine(lineStart, count, directDelta, indirectOffset, lineSize.Indirect); } return(finalSize); }
public static double GetIndirect(Size size, Orientation orientation) { return(OrientedSize.GetIndirect(size, orientation)); }
public static double HalfIndirect(OrientedSize orientedSize) { return(orientedSize.Indirect / 2.0); }
protected override Size MeasureOverride(Size constraint) { // Variables tracking the size of the current line, the total size // measured so far, and the maximum size available to fill. Note // that the line might represent a row or a column depending on the // orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize totalSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, constraint.Width, constraint.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); Size itemSize = new Size( hasFixedWidth ? itemWidth : constraint.Width, hasFixedHeight ? itemHeight : constraint.Height); // Measure each of the Children foreach (UIElement element in Children) { // Determine the size of the element element.Measure(itemSize); OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Update the total size with the direct and indirect growth // for the current line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Move the element to a new line lineSize = elementSize; // If the current element is larger than the maximum size, // place it on a line by itself if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Update the total size for the line occupied by this // single element totalSize.Direct = Math.Max(elementSize.Direct, totalSize.Direct); totalSize.Indirect += elementSize.Indirect; // Move to a new line lineSize = new OrientedSize(o); } } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Update the total size with the elements on the last line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Return the total size required as an un-oriented quantity return new Size(totalSize.Width, totalSize.Height); }
/// <summary> /// Arranges the child elements of the panel. /// </summary> /// <param name="finalSize"> /// The final size. /// </param> /// <returns> /// Returns the size required by the panel. /// </returns> protected override Size ArrangeOverride(Size finalSize) { var o = this.Orientation; var lineSize = new OrientedSize(o); var maximumSize = new OrientedSize(o, finalSize.Width, finalSize.Height); // Determine the constraints for individual items double itemWidth = this.ItemWidth; double itemHeight = this.ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); double indirectOffset = 0; var directDelta = (o == Orientation.Horizontal) ? (hasFixedWidth ? (double?)itemWidth : null) : (hasFixedHeight ? (double?)itemHeight : null); var children = this.Children; int count = children.Count; int lineStart = 0; for (var lineEnd = 0; lineEnd < count; lineEnd++) { var element = children[lineEnd]; // Get the size of the element var elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (MathHelper.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Then we just completed a line and we should arrange it this.ArrangeLine(lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect); // Move the current element to a new line indirectOffset += lineSize.Indirect; lineSize = elementSize; // If the current element is larger than the maximum size if (MathHelper.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Arrange the element as a single line this.ArrangeLine(lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect); // Move to a new line indirectOffset += lineSize.Indirect; lineSize = new OrientedSize(o); } // Advance the start index to a new line after arranging lineStart = lineEnd; } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Arrange any elements on the last line if (lineStart < count) { this.ArrangeLine(lineStart, count, directDelta, indirectOffset, lineSize.Indirect); } return(finalSize); }
private static OrientedSize MeasureChild(UIElement child, OrientedSize childConstraint) { child.Measure(childConstraint.Size); return(child.DesiredSize.AsOriented(childConstraint.Orientation)); }
public static OrientedSize WrapSize(this OrientedSize self, Size itemSize) { return(self.WrapSize(itemSize.AsOriented(self.Orientation))); }
private OrientedSize ProcessSpacingAndOverflow(double spacing, OrientedSize desiredOriented, OrientedSize availableOriented, out bool isHiddenChanged) { var childrenCount = Panel.Elements.Count; var orientation = Panel.Orientation; var target = availableOriented.Direct; isHiddenChanged = false; // Current length is greater than available and we have no possibility to stretch down -> mark elements as hidden var current = 0.0; var visible = 0.0; var hasHiddenChildren = false; var visibleChildrenCount = 0; if (desiredOriented.Direct.IsGreaterThan(availableOriented.Direct)) { var stretchOverflow = FlexElementCollection.Mount(FlexElements.Capacity); try { // Process Pinned Flexible for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; if (CanPinStretch(flexElement) == false) { continue; } flexElement.StretchDirection = FlexStretchDirection.Shrink; stretchOverflow.Add(flexElement); Panel.SetIsHidden(Panel.Elements[index], false); } // Process Pinned for (var index = 0; index < childrenCount; index++) { var child = Panel.Elements[index]; if (child.Visibility == Visibility.Collapsed) { continue; } var flexElement = FlexElements[index]; if (CanPin(flexElement) == false) { continue; } current += flexElement.ActualLength; current += spacing; visible = current; Panel.SetIsHidden(Panel.Elements[index], false); } // Process Hide for (var index = 0; index < childrenCount; index++) { var child = Panel.Elements[index]; if (child.Visibility == Visibility.Collapsed) { continue; } visibleChildrenCount++; var flexElement = FlexElements[index]; if (CanPin(flexElement)) { continue; } current += flexElement.ActualLength; if (CanHide(flexElement) == false) { isHiddenChanged |= Panel.GetIsHidden(child); Panel.SetIsHidden(child, false); current += spacing; visible = current; continue; } var isOverflowed = current.IsGreaterThan(target, XamlConstants.LayoutComparisonPrecision); current += spacing; if (isOverflowed == false) { visible = current; } isHiddenChanged |= Panel.GetIsHidden(child) != isOverflowed; hasHiddenChildren |= isOverflowed; Panel.SetIsHidden(child, isOverflowed); } if (visibleChildrenCount > 0) { visible = visible - spacing; } Panel.HasHiddenChildren = hasHiddenChildren; // Stretch Pinned if (visible.IsGreaterThan(availableOriented.Direct) && stretchOverflow.Count > 0) { var currentPinStretch = stretchOverflow.Actual; var pinStretchTarget = (currentPinStretch - (visible - availableOriented.Direct)).Clamp(0, availableOriented.Direct); var pinStretchDesired = stretchOverflow.Stretch(FlexStretch.Fill, pinStretchTarget, FlexDistributor.Equalizer); if (pinStretchDesired < currentPinStretch) { var pinStretchIndex = 0; for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; if (CanPinStretch(flexElement)) { FlexElements[index] = stretchOverflow[pinStretchIndex++].WithStretchDirection(FlexStretchDirection.Shrink).WithMaxLength(flexElement.ActualLength); } else { FlexElements[index] = FlexElements[index].WithStretchDirection(FlexStretchDirection.Shrink).WithShrinkPriority(short.MaxValue); } } FinalMeasureItems(availableOriented, spacing, true); return(OrientedSize.Create(orientation, availableOriented.Direct, desiredOriented.Indirect)); } } } finally { FlexElementCollection.Release(stretchOverflow); } return(OrientedSize.Create(orientation, visible.Clamp(0, availableOriented.Direct), desiredOriented.Indirect)); } for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; var child = Panel.Elements[index]; if (child.Visibility == Visibility.Collapsed) { continue; } visibleChildrenCount++; current += flexElement.ActualLength; current += spacing; Panel.SetIsHidden(Panel.Elements[index], false); } Panel.HasHiddenChildren = false; visible = Math.Max(0, current); if (visibleChildrenCount > 0) { visible = visible - spacing; } return(OrientedSize.Create(orientation, visible.Clamp(0, availableOriented.Direct), desiredOriented.Indirect)); }
private Size ArrangeCoreImpl(Size finalSize) { var flexPanel = Panel; var flexPanelEx = Panel as IFlexPanelEx; var allowMeasure = flexPanelEx?.AllowMeasureInArrange ?? false; var orientation = flexPanel.Orientation; var useLayoutRounding = flexPanel.UseLayoutRounding; var spacing = GetRoundSpacing(flexPanel.Spacing, useLayoutRounding); for (var index = 0; index < flexPanel.Elements.Count; index++) { FlexElements[index] = FlexElements[index].WithUIElement(flexPanel.Elements[index], orientation); } var currentFlexElements = FlexElementCollection.Mount(FlexElements.Capacity); try { FlexElements.CopyTo(currentFlexElements); while (true) { var nextArrangePass = false; var size = new OrientedSize(orientation); var spacingDelta = 0.0; var finalOriented = finalSize.AsOriented(orientation); var finalIndirect = finalOriented.Indirect; var currentPoint = new OrientedPoint(orientation); var childFinalOriented = new OrientedSize(orientation); // Stretch Stretch(currentFlexElements, spacing, finalOriented.Direct, true); for (var index = 0; index < flexPanel.Elements.Count; index++) { var child = flexPanel.Elements[index]; var flexElement = currentFlexElements[index]; if (child.Visibility == Visibility.Collapsed) { continue; } if (flexPanel.GetIsHidden(child)) { child.Arrange(XamlConstants.ZeroRect); flexElement.ActualLength = 0.0; currentFlexElements[index] = flexElement; continue; } var desiredOriented = child.DesiredSize.AsOriented(orientation); childFinalOriented.Direct = flexElement.ActualLength; childFinalOriented.Indirect = Math.Max(finalIndirect, desiredOriented.Indirect); // Arrange Child var rect = new Rect(XamlConstants.ZeroPoint, childFinalOriented.Size).Offset(currentPoint); if (useLayoutRounding) { rect = rect.LayoutRound(RoundingMode.MidPointFromZero); } if (_measureInfinite && allowMeasure && desiredOriented.Direct.IsGreaterThan(childFinalOriented.Direct)) { var remeasureOriented = desiredOriented; remeasureOriented.ChangeDirect(childFinalOriented.Direct); child.Measure(remeasureOriented.Size); } child.Arrange(rect); var arrangeSize = GetActualArrangeSize(child); if (arrangeSize.IsEmpty == false) { rect.Width = arrangeSize.Width; rect.Height = arrangeSize.Height; } var finalChildDirect = rect.Size().AsOriented(orientation).Direct; if (IsArrangeFixed(flexElement) == false && finalChildDirect.IsLessThan(childFinalOriented.Direct)) { var length = finalChildDirect; flexElement.SetLengths(length, length, length, length); currentFlexElements[index] = flexElement; nextArrangePass = true; break; } if (useLayoutRounding) { var rectSize = rect.Size().AsOriented(orientation); flexElement.ActualLength = rectSize.Direct; currentPoint.Direct = Math.Max(0, (currentPoint.Direct + rectSize.Direct + spacing).LayoutRound(orientation, RoundingMode.MidPointFromZero)); } else { var rectSize = rect.Size().AsOriented(orientation); flexElement.ActualLength = rectSize.Direct; currentPoint.Direct = Math.Max(0, currentPoint.Direct + rectSize.Direct + spacing); } currentFlexElements[index] = flexElement; spacingDelta += spacing; size = size.StackSize(childFinalOriented); } if (nextArrangePass) { continue; } if (spacingDelta.Equals(0.0) == false) { size.Direct = Math.Max(0, size.Direct + spacingDelta - spacing); } var result = finalSize; if (orientation == Orientation.Horizontal) { result.Width = flexPanel.ShouldFill(Orientation.Horizontal) ? finalSize.Width : Math.Min(finalSize.Width, size.Width); } else { result.Height = flexPanel.ShouldFill(Orientation.Vertical) ? finalSize.Height : Math.Min(finalSize.Height, size.Height); } return(result); } } finally { FlexElementCollection.Release(currentFlexElements); } }
private OrientedSize MeasureItems(Size availableSize, out OrientedSize fixedSize, out OrientedSize flexibleSize) { var stretch = Panel.Stretch; var orientation = Panel.Orientation; var children = Panel.Elements; var childrenCount = children.Count; var oriented = availableSize.AsOriented(orientation); var fixedChildConstraint = oriented.Clone.ChangeDirect(double.PositiveInfinity); var starChildConstraint = oriented.Clone.ChangeDirect(0); var fixedResult = new OrientedSize(orientation); var starValue = 0.0; FlexElements.EnsureCount(childrenCount); for (var index = 0; index < childrenCount; index++) { var flexElement = Panel.GetFlexElement(children[index]).WithOrientation(orientation); if (flexElement.IsStar) { starValue += flexElement.Length.Value; } FlexElements[index] = flexElement; } // None Stretch if (stretch == FlexStretch.None) { for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; var child = children[index]; var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint); // Stack child size var size = MeasureChild(child, childConstraint); flexElement = flexElement.WithUIElement(child, orientation); size.Direct = flexElement.DesiredLength; fixedResult = fixedResult.StackSize(size); FlexElements[index] = flexElement; } fixedSize = fixedResult; flexibleSize = new OrientedSize(orientation); return(fixedResult); } // Fixed size children for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; if (flexElement.IsStar) { continue; } var child = children[index]; var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint); // Stack child size var size = MeasureChild(child, childConstraint); flexElement = flexElement.WithUIElement(child, orientation); size.Direct = flexElement.DesiredLength; fixedResult = fixedResult.StackSize(size); FlexElements[index] = flexElement; } fixedSize = fixedResult; flexibleSize = new OrientedSize(orientation); starChildConstraint.ChangeDirect(FlexUtils.CalcStarValue(oriented.Direct, fixedResult.Direct, starValue)); // Star size children var flexibleResult = new OrientedSize(orientation); for (var index = 0; index < childrenCount; index++) { var flexElement = FlexElements[index]; if (flexElement.IsFixed) { continue; } var child = children[index]; var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint); // Stack child size var size = MeasureChild(child, childConstraint); flexElement = flexElement.WithUIElement(child, orientation); size.Direct = flexElement.DesiredLength; flexibleResult = flexibleResult.StackSize(size); FlexElements[index] = flexElement.WithUIElement(child, orientation); } flexibleSize = flexibleResult; return(fixedResult.StackSize(flexibleResult)); }
/// <summary> /// Arranges the content of a WrapPanel element. /// </summary> /// <param name="finalSize"> /// The Size that this element should use to arrange its child elements. /// </param> /// <returns> /// The arranged size of this WrapPanel element and its children. /// </returns> protected override Size ArrangeOverride(Size finalSize) { // Variables tracking the size of the current line, and the maximum // size available to fill. Note that the line might represent a row // or a column depending on the orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, finalSize.Width, finalSize.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); double indirectOffset = 0; double? directDelta = (o == Orientation.Horizontal) ? (hasFixedWidth ? (double?) itemWidth : null) : (hasFixedHeight ? (double?) itemHeight : null); // Measure each of the Children. We will process the elements one // line at a time, just like during measure, but we will wait until // we've completed an entire line of elements before arranging them. // The lineStart and lineEnd variables track the size of the // currently arranged line. UIElementCollection children = Children; int count = children.Count; int lineStart = 0; for (int lineEnd = 0; lineEnd < count; lineEnd++) { UIElement element = children[lineEnd]; // Get the size of the element OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Then we just completed a line and we should arrange it ArrangeLine(lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect); // Move the current element to a new line indirectOffset += lineSize.Indirect; lineSize = elementSize; // If the current element is larger than the maximum size if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Arrange the element as a single line ArrangeLine(lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect); // Move to a new line indirectOffset += lineSize.Indirect; lineSize = new OrientedSize(o); } // Advance the start index to a new line after arranging lineStart = lineEnd; } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Arrange any elements on the last line if (lineStart < count) { ArrangeLine(lineStart, count, directDelta, indirectOffset, lineSize.Indirect); } return finalSize; }
public static OrientedSize WrapSize(this OrientedSize self, OrientedSize itemSize) { self.Direct = Math.Max(itemSize.Direct, self.Direct); self.Indirect += itemSize.Indirect; return(self); }
/// <summary> /// Arrange a sequence of elements in a single line. /// </summary> /// <param name="lineStart"> /// Index of the first element in the sequence to arrange. /// </param> /// <param name="lineEnd"> /// Index of the last element in the sequence to arrange. /// </param> /// <param name="directDelta"> /// Optional fixed growth in the primary direction. /// </param> /// <param name="indirectOffset"> /// Offset of the line in the indirect direction. /// </param> /// <param name="indirectGrowth"> /// Shared indirect growth of the elements on this line. /// </param> private void ArrangeLine(int lineStart, int lineEnd, double? directDelta, double indirectOffset, double indirectGrowth) { double directOffset = 0.0; Orientation o = Orientation; bool isHorizontal = o == Orientation.Horizontal; UIElementCollection children = Children; for (int index = lineStart; index < lineEnd; index++) { // Get the size of the element UIElement element = children[index]; OrientedSize elementSize = new OrientedSize(o, element.DesiredSize.Width, element.DesiredSize.Height); // Determine if we should use the element's desired size or the // fixed item width or height double directGrowth = directDelta != null ? directDelta.Value : elementSize.Direct; // Arrange the element Rect bounds = isHorizontal ? new Rect(directOffset, indirectOffset, directGrowth, indirectGrowth) : new Rect(indirectOffset, directOffset, indirectGrowth, directGrowth); element.Arrange(bounds); directOffset += directGrowth; } }
/// <summary> /// Measures the child elements of the panel. /// </summary> /// <param name="constraint"> /// The size available for child elements. /// </param> /// <returns> /// Returns the size required by the panel. /// </returns> protected override Size MeasureOverride(Size constraint) { var o = this.Orientation; var lineSize = new OrientedSize(o); var totalSize = new OrientedSize(o); var maximumSize = new OrientedSize(o, constraint.Width, constraint.Height); // Determine the constraints for individual items double itemWidth = this.ItemWidth; double itemHeight = this.ItemHeight; bool hasFixedWidth = !double.IsNaN(itemWidth); bool hasFixedHeight = !double.IsNaN(itemHeight); var itemSize = new Size( hasFixedWidth ? itemWidth : constraint.Width, hasFixedHeight ? itemHeight : constraint.Height); // Measure each of the children foreach (var element in this.Children) { // Determine the size of the element element.Measure(itemSize); var elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (MathHelper.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Update the total size with the direct and indirect growth for the current line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Move the element to a new line lineSize = elementSize; // If the current element is larger than the maximum size, place it on a line by itself if (MathHelper.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Update the total size for the line occupied by this single element totalSize.Direct = Math.Max(elementSize.Direct, totalSize.Direct); totalSize.Indirect += elementSize.Indirect; // Move to a new line lineSize = new OrientedSize(o); } } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Update the total size with the elements on the last line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Return the total size required as an un-oriented quantity return(new Size(totalSize.Width, totalSize.Height)); }