/// <inheritdoc /> protected override Size ArrangeOverride(Size finalSize) { if (Children.Count > 0) { var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top); var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom); var position = new UvMeasure(Orientation, Padding.Left, Padding.Top); double currentV = 0; void Arrange(UIElement child, bool isLast = false) { var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); if (desiredMeasure.U == 0) { return; // if an item is collapsed, avoid adding the spacing } if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U) { // next row! position.U = paddingStart.U; position.V += currentV + spacingMeasure.V; currentV = 0; } // Stretch the last item to fill the available space if (isLast) { desiredMeasure.U = parentMeasure.U - position.U; } // place the item if (Orientation == Orientation.Horizontal) { child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V)); } else { child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U)); } // adjust the location for the next items position.U += desiredMeasure.U + spacingMeasure.U; currentV = Math.Max(desiredMeasure.V, currentV); } var lastIndex = Children.Count - 1; for (var i = 0; i < lastIndex; i++) { Arrange(Children[i]); } Arrange(Children[lastIndex], StretchChild == StretchChild.Last); } return(finalSize); }
/// <inheritdoc /> protected override Size ArrangeOverride(Size finalSize) { var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); var position = UvMeasure.Zero; double currentV = 0; foreach (var child in Children) { var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); if ((desiredMeasure.U + position.U) > parentMeasure.U) { // next row! position.U = 0; position.V += currentV; currentV = 0; } // Place the item if (Orientation == Orientation.Horizontal) { child.Arrange(new Rect(position.U, position.V, child.DesiredSize.Width, child.DesiredSize.Height)); } else { child.Arrange(new Rect(position.V, position.U, child.DesiredSize.Width, child.DesiredSize.Height)); } // adjust the location for the next items position.U += desiredMeasure.U; currentV = Math.Max(desiredMeasure.V, currentV); } return(finalSize); }
/// <inheritdoc /> protected override Size MeasureOverride(Size availableSize) { availableSize.Width = availableSize.Width - Padding.Left - Padding.Right; availableSize.Height = availableSize.Height - Padding.Top - Padding.Bottom; var totalMeasure = UvMeasure.Zero; var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var lineMeasure = UvMeasure.Zero; foreach (var child in Children) { child.Measure(availableSize); var currentMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); if (parentMeasure.U >= currentMeasure.U + lineMeasure.U + spacingMeasure.U) { lineMeasure.U += currentMeasure.U + spacingMeasure.U; lineMeasure.V = Math.Max(lineMeasure.V, currentMeasure.V); } else { // new line should be added // to get the max U to provide it correctly to ui width ex: ---| or -----| totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U); totalMeasure.V += lineMeasure.V + spacingMeasure.V; // if the next new row still can handle more controls if (parentMeasure.U > currentMeasure.U) { // set lineMeasure initial values to the currentMeasure to be calculated later on the new loop lineMeasure = currentMeasure; } // the control will take one row alone else { // validate the new control measures totalMeasure.U = Math.Max(currentMeasure.U, totalMeasure.U); totalMeasure.V += currentMeasure.V; // add new empty line lineMeasure = UvMeasure.Zero; } } } // update value with the last line // if the the last loop is(parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here // for the last condition it is zeros so adding it will make no difference // this way is faster than an if condition in every loop for checking the last item totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U); totalMeasure.V += lineMeasure.V; totalMeasure.U = Math.Ceiling(totalMeasure.U); return(Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U)); }
public void Add(UvMeasure position, UvMeasure size) { ChildrenRects.Add(new UvRect { Position = position, Size = size }); Size = new UvMeasure { U = position.U + size.U, V = Math.Max(Size.V, size.V), }; }
internal void SetOrientation(Orientation orientation) { foreach (var item in _items.Where(i => i.Measure.HasValue)) { UvMeasure measure = item.Measure.Value; double v = measure.V; measure.V = measure.U; measure.U = v; item.Measure = measure; item.Position = null; } Orientation = orientation; AvailableU = 0; }
/// <inheritdoc /> protected override Size ArrangeOverride(Size finalSize) { var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top); var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom); var position = new UvMeasure(Orientation, Padding.Left, Padding.Top); double currentV = 0; foreach (var child in Children) { var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); if (desiredMeasure.U == 0) { continue; // if an item is collapsed, avoid adding the spacing } if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U) { // next row! position.U = paddingStart.U; position.V += currentV + spacingMeasure.V; currentV = 0; } // place the item if (Orientation == Orientation.Horizontal) { child.Arrange(new Rect(position.U, position.V, child.DesiredSize.Width, child.DesiredSize.Height)); } else { child.Arrange(new Rect(position.V, position.U, child.DesiredSize.Width, child.DesiredSize.Height)); } // adjust the location for the next items position.U += desiredMeasure.U + spacingMeasure.U; currentV = Math.Max(desiredMeasure.V, currentV); } return(finalSize); }
public Row(List <UvRect> childrenRects, UvMeasure size) { ChildrenRects = childrenRects; Size = size; }
public UvMeasure Add(UvMeasure measure) => Add(measure.U, measure.V);
private Size UpdateRows(Size availableSize) { _rows.Clear(); var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top); var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom); if (Children.Count == 0) { var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation); return(emptySize); } var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var position = new UvMeasure(Orientation, Padding.Left, Padding.Top); var currentRow = new Row(new List <UvRect>(), default); var finalMeasure = new UvMeasure(Orientation, width: 0.0, height: 0.0); void Arrange(UIElement child, bool isLast = false) { if (child.Visibility == Visibility.Collapsed) { return; // if an item is collapsed, avoid adding the spacing } var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize); if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U) { // next row! position.U = paddingStart.U; position.V += currentRow.Size.V + spacingMeasure.V; _rows.Add(currentRow); currentRow = new Row(new List <UvRect>(), default); } // Stretch the last item to fill the available space if (isLast) { desiredMeasure.U = parentMeasure.U - position.U; } currentRow.Add(position, desiredMeasure); // adjust the location for the next items position.U += desiredMeasure.U + spacingMeasure.U; finalMeasure.U = Math.Max(finalMeasure.U, position.U); } var lastIndex = Children.Count - 1; for (var i = 0; i < lastIndex; i++) { Arrange(Children[i]); } Arrange(Children[lastIndex], StretchChild == StretchChild.Last); if (currentRow.ChildrenRects.Count > 0) { _rows.Add(currentRow); } if (_rows.Count == 0) { var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation); return(emptySize); } // Get max V here before computing final rect var lastRowRect = _rows.Last().Rect; finalMeasure.V = lastRowRect.Position.V + lastRowRect.Size.V; var finalRect = finalMeasure.Add(paddingEnd).ToSize(Orientation); return(finalRect); }
/// <inheritdoc /> protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { if (context.ItemCount > 0) { var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var realizationBounds = new UvBounds(Orientation, context.RealizationRect); var state = (WrapLayoutState)context.LayoutState; bool Arrange(WrapItem item, bool isLast = false) { if (item.Measure.HasValue == false) { return(false); } if (item.Position == null) { return(false); } var desiredMeasure = item.Measure.Value; if (desiredMeasure.U == 0) { return(true); // if an item is collapsed, avoid adding the spacing } UvMeasure position = item.Position.Value; // Stretch the last item to fill the available space if (isLast) { desiredMeasure.U = parentMeasure.U - position.U; } if (((position.V + desiredMeasure.V) >= realizationBounds.VMin) && (position.V <= realizationBounds.VMax)) { // place the item UIElement child = context.GetOrCreateElementAt(item.Index); if (Orientation == Orientation.Horizontal) { child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V)); } else { child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U)); } } else if (position.V > realizationBounds.VMax) { return(false); } return(true); } for (var i = 0; i < context.ItemCount; i++) { bool continueArranging = Arrange(state.GetItemAt(i)); if (continueArranging == false) { break; } } } return(finalSize); }
/// <inheritdoc /> protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { var totalMeasure = UvMeasure.Zero; var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var realizationBounds = new UvBounds(Orientation, context.RealizationRect); var position = UvMeasure.Zero; var state = (WrapLayoutState)context.LayoutState; if (state.Orientation != Orientation) { state.SetOrientation(Orientation); } if (spacingMeasure.Equals(state.Spacing) == false) { state.ClearPositions(); state.Spacing = spacingMeasure; } if (state.AvailableU != parentMeasure.U) { state.ClearPositions(); state.AvailableU = parentMeasure.U; } double currentV = 0; for (int i = 0; i < context.ItemCount; i++) { bool measured = false; WrapItem item = state.GetItemAt(i); if (item.Measure == null) { item.Element = context.GetOrCreateElementAt(i); item.Element.Measure(availableSize); item.Measure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height); measured = true; } UvMeasure currentMeasure = item.Measure.Value; if (currentMeasure.U == 0) { continue; // ignore collapsed items } if (item.Position == null) { if (parentMeasure.U < position.U + currentMeasure.U) { // New Row position.U = 0; position.V += currentV + spacingMeasure.V; currentV = 0; } item.Position = position; } position = item.Position.Value; double vEnd = position.V + currentMeasure.V; if (vEnd < realizationBounds.VMin) { // Item is "above" the bounds if (item.Element != null) { context.RecycleElement(item.Element); item.Element = null; } } else if (position.V > realizationBounds.VMax) { // Item is "below" the bounds. if (item.Element != null) { context.RecycleElement(item.Element); item.Element = null; } // We don't need to measure anything below the bounds break; } else if (measured == false) { // Always measure elements that are within the bounds item.Element = context.GetOrCreateElementAt(i); item.Element.Measure(availableSize); currentMeasure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height); if (currentMeasure.Equals(item.Measure) == false) { // this item changed size; we need to recalculate layout for everything after this state.RemoveFromIndex(i + 1); item.Measure = currentMeasure; // did the change make it go into the new row? if (parentMeasure.U < position.U + currentMeasure.U) { // New Row position.U = 0; position.V += currentV + spacingMeasure.V; currentV = 0; } item.Position = position; } } position.U += currentMeasure.U + spacingMeasure.U; currentV = Math.Max(currentMeasure.V, currentV); } // update value with the last line // if the the last loop is(parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here // for the last condition it is zeros so adding it will make no difference // this way is faster than an if condition in every loop for checking the last item totalMeasure.U = parentMeasure.U; // Propagating an infinite size causes a crash. This can happen if the parent is scrollable and infinite in the opposite // axis to the panel. Clearing to zero prevents the crash. // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that wont crash. if (double.IsInfinity(totalMeasure.U)) { totalMeasure.U = 0.0; } totalMeasure.V = state.GetHeight(); totalMeasure.U = Math.Ceiling(totalMeasure.U); return(Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U)); }