protected override Size MeasureOverride(Size availableSize) { // Measure each child with the same available size as the parent, in the direction of the panel. foreach (var element in Elements) element.Measure(CreateSize(GetStackLength(availableSize), GetStretchLength(availableSize))); var groups = GetGroups(availableSize); // Find the tallest and longest group lengths. double stackLength = 0, stretchLength = 0; foreach (var group in groups) { double groupStackLength = 0, groupStretchLength = 0; foreach (var child in group.Elements) { groupStackLength += GetStackLength(child.DesiredSize); groupStretchLength = Math.Max(groupStretchLength, GetStretchLength(child.DesiredSize)); // Group with largest child. } stackLength = Math.Max(stackLength, groupStackLength); // Largest group based on total size. stretchLength += groupStretchLength; } return CreateSize(stackLength, stretchLength); }
protected override Size ArrangeOverride(Size finalSize) { double maxStackLength = 0; double stretchLength = 0; var groups = GetGroups(finalSize); foreach (var group in groups) { // Find max size of child to be the max width/height of the row/column. var groupMaxLength = group.Elements.Select(child => GetStretchLength(child.DesiredSize)).Max(); double groupLength = 0; foreach (var child in group.Elements) { var childStackLength = GetStackLength(child.DesiredSize); var rect = Orientation == Orientation.Horizontal ? new Rectangle(groupLength, stretchLength, childStackLength, groupMaxLength) : new Rectangle(stretchLength, groupLength, groupMaxLength, childStackLength); child.Arrange(rect); groupLength += childStackLength; //The next element will be position below/to the right of this one. } maxStackLength = Math.Max(maxStackLength, groupLength); // Move the x/y over by the max length to start a new row or column. stretchLength += groupMaxLength; } return finalSize; }
protected override Size ArrangeOverride(Size finalSize) { var stretchLength = GetStretchSize(finalSize); double stackLength = 0; for (var i = 0; i < Elements.Count; i++) { var child = Elements[i]; // Get the size in the stacking direction of the child. var childStackLength = GetStackSize(child.DesiredSize); var point = CreatePoint(stackLength, 0); // Create a rectangle from the point and length of the stretch and stack lengths. var rect = Orientation == Orientation.Vertical ? new Rectangle(point, stretchLength, childStackLength) : new Rectangle(point, childStackLength, stretchLength); child.Arrange(rect); stackLength += childStackLength; } return CreateSize(GetStackSize(finalSize), stretchLength); }
protected override Size ArrangeOverride(Size finalSize) { var remainingWidth = finalSize.Width; var remainingHeight = finalSize.Height; double left = 0, top = 0; for (var i = 0; i < Elements.Count; i++) { var child = Elements[i]; var dock = GetDock(child); var orientation = GetOrientation(dock); // If this is the last child and LastChildFill is true, fill the child to the available size. var fill = LastChildFill && i == Elements.Count - 1; // If the orientation is vertical, fill the width, and if it is horizontal, will the height. var cellWidth = orientation == Orientation.Vertical || fill ? remainingWidth : child.DesiredSize.Width; var cellHeight = orientation == Orientation.Horizontal || fill ? remainingHeight : child.DesiredSize.Height; // If to the right or bottom, use the remaining size - the cell size. double cellLeft = 0, cellTop = 0; if (dock == Dock.Right) cellLeft = remainingWidth - cellWidth; else if (dock == Dock.Bottom) cellTop = remainingHeight - cellHeight; child.Arrange(new Rectangle(left + cellLeft, top + cellTop, cellWidth, cellHeight)); // Add to the left or top if from the left or top. if (orientation == Orientation.Horizontal) { remainingWidth -= cellWidth; if (dock == Dock.Left) left += cellWidth; } else { remainingHeight -= cellHeight; if (dock == Dock.Top) top += cellHeight; } } return finalSize; }
protected override Size MeasureOverride(Size availableSize) { double stackLength = 0, stretchLength = 0; for (var i = 0; i < Elements.Count; i++) { var child = Elements[i]; // Measure each child with the container size in the stack direction and an infinite size in the other. child.Measure(CreateSize(double.PositiveInfinity, GetStretchSize(availableSize))); // Add to the stack length so far, and use the largest size in the stretch directorion to set the size of the stack panel. stackLength += GetStackSize(child.DesiredSize); stretchLength = Math.Max(stretchLength, GetStretchSize(child.DesiredSize)); } return CreateSize(stackLength, stretchLength); }
protected override Size ArrangeOverride(Size finalSize) { foreach (var child in Elements) { // By default, position them in the top left corner. var x = 0d; var y = 0d; var left = GetLeft(child); var top = GetTop(child); // X axis if (!double.IsNaN(left)) x = left; // If left is defined, use that for the x position. else // If it is not, use the right position. { // Arrange with right. var right = GetRight(child); if (!double.IsNaN(right)) x = finalSize.Width - child.DesiredSize.Width - right; } // Y axis if (!double.IsNaN(top)) y = top; else { var elementBottom = GetBottom(child); if (!double.IsNaN(elementBottom)) y = finalSize.Height - child.DesiredSize.Height - elementBottom; } child.Arrange(new Rectangle(new Point(x, y), child.DesiredSize)); } return finalSize; }
/// <summary> /// Clamp the size between a lower and upper bound. /// </summary> public Size Clamp(Size min, Size max) { if (min.Width > max.Width || min.Height > max.Height) throw new ArgumentException("Minimum must be less than maximum."); return Max(min).Min(max); }
/// <summary> /// Retuns an offset to the elements position according to its size, container size, and alignment. /// </summary> private Point Align(Rectangle container, Size size) { if (!double.IsInfinity(size.Width)) // Infinite sizes will be handled elsewhere. { switch (HorizontalAlignment) { case HorizontalAlignment.Stretch: case HorizontalAlignment.Center: container.X = container.Left + (container.Width - size.Width) / 2; break; case HorizontalAlignment.Right: container.X = container.Left + container.Width - size.Width; break; } } if (!double.IsInfinity(size.Height)) { switch (VerticalAlignment) { case VerticalAlignment.Stretch: case VerticalAlignment.Center: container.Y = container.Top + (container.Height - size.Height) / 2; break; case VerticalAlignment.Bottom: container.Y = container.Top + container.Height - size.Height; break; } } return container.Point; }
protected override Size MeasureOverride(Size availableSize) { var remainingWidth = availableSize.Width; var remainingHeight = availableSize.Height; foreach (var child in Elements) { // Measure the child with the remaining area. child.Measure(new Size(remainingWidth, remainingHeight)); // Subtract from the remaining area depending on the orientation. if (GetOrientation(GetDock(child)) == Orientation.Horizontal) remainingWidth -= child.DesiredSize.Width; else remainingHeight -= child.DesiredSize.Height; } double totalWidth = 0; double totalHeight = 0; foreach (var child in Elements) { if (GetOrientation(GetDock(child)) == Orientation.Horizontal) { totalWidth += child.DesiredSize.Width; totalHeight = Math.Max(totalHeight, child.DesiredSize.Height); } else { totalHeight += child.DesiredSize.Height; totalWidth = Math.Max(totalWidth, child.DesiredSize.Width); } } return new Size(totalWidth, totalHeight); }
public override void Measure(Size availableSize) { // If visibility is collapsed, do not account for the element's size. if (Visibility == Visibility.Collapsed) { Manager.Layout.RemoveMeasure(this); DesiredSize = Size.Zero; return; } base.Measure(availableSize); }
/// <summary> /// Measures the size of all child elements in a specific layout pattern. /// By default, returns the size of the largest child element. /// </summary> protected virtual Size MeasureOverride(Size availableSize) { // By default, return the size of the largest child element. var desired = Size.Zero; foreach (var child in Elements) { child.Measure(availableSize); desired = desired.Max(child.DesiredSize); } return desired; }
private double GetStretchLength(Size size) { return Orientation == Orientation.Horizontal ? size.Height : size.Width; }
/// <summary> /// Determines if the size is equal to another size within margin of error (because of floating point precision). /// </summary> public bool IsClose(Size size) => Width.IsClose(size.Width) && Height.IsClose(size.Height);
// Force derived panels to implement their own layout logic. protected abstract override Size ArrangeOverride(Size finalSize);
public Rectangle(Size size) : this(Point.Zero, size) { }
public Rectangle(Point location, Size size) : this(location.X, location.Y, size.Width, size.Height) { }
/// <summary> /// Extend the rectangle dimensions by the specified size. /// </summary> /// <param name="size"></param> /// <returns></returns> public Rectangle Extend(Size size) => new Rectangle(X, Y, Width + size.Width, Height + size.Height);
protected override Size MeasureOverride(Size availableSize) { // Give each child infinite size. foreach (var child in Elements) { // Idea: Give each child the available size of the container, minus their position? //child.Measure(availableSize - new Size(child.Position.X, child.Position.Y)); child.Measure(Size.Infinity); } return Size.Zero; }
/// <summary> /// Return the larger size of this size and the specified size. /// </summary> public Size Max(Size size) { var width = size.IsWidthEmpty ? Width : Math.Max(Width, size.Width); var height = size.IsHeightEmpty ? Height : Math.Max(Height, size.Height); return new Size(width, height); }
private Point AlignText(Size textsize) { // Calculate center for each axis. var center = new Point((Bounds.Width / 2) - (textsize.Width / 2), (Bounds.Height / 2) - (textsize.Height / 2)); var x = 0d; var y = 0d; switch (TextAlignment) { // Top. case Alignment.TopLeft: break; case Alignment.TopRight: x = Bounds.Width - textsize.Width; break; // Bottom. case Alignment.BottomLeft: y = Bounds.Height - textsize.Height; break; case Alignment.BottomRight: y = Bounds.Height - textsize.Height; x = Bounds.Width - textsize.Width; break; // Center. case Alignment.TopCenter: x = center.X; break; case Alignment.BottomCenter: y = Bounds.Height - textsize.Height; x = center.X; break; case Alignment.LeftCenter: y = center.Y; break; case Alignment.RightCenter: y = center.Y; x = Bounds.Width - textsize.Width; break; case Alignment.Center: y = center.Y; x = center.X; break; } return new Point(x, y); }
public bool Equals(Size other) => Width.Equals(other.Width) && Height.Equals(other.Height);
protected override Size ArrangeOverride(Size finalSize) { Child?.Arrange(new Rectangle(BorderThickness + Padding, finalSize.Remove(BorderThickness).Remove(Padding))); return finalSize; }
/// <summary> /// If the width or height is NaN or 0, fall back to another value. /// </summary> public Size Fallback(Size fallback) { return new Size( double.IsNaN(Width) || Width.IsClose(0) ? fallback.Width : Width, double.IsNaN(Height) || Height.IsClose(0) ? fallback.Height : Height); }
/// <summary> /// Create or gets the groups of elements that will form rows/colums. /// </summary> // ReSharper disable once ReturnTypeCanBeEnumerable.Local private List<WrapGroup> GetGroups(Size size) { if (!groupsInvalidated) return groupCache; var maxLength = GetStackLength(size); // Size of one row/column var groups = new List<WrapGroup>(); var group = new WrapGroup(); for (var i = 0; i < Elements.Count; i++) { var child = Elements[i]; var childSize = GetStackLength(child.DesiredSize); // If the group length + this child is more than the column/row length, start a new group. if (group.Length + childSize > maxLength) { groups.Add(group); group = new WrapGroup(); } group.AddElement(child); group.Length += childSize; } groups.Add(group); groupsInvalidated = false; groupCache = groups; return groups; }
protected abstract override Size MeasureOverride(Size availableSize);
private double GetStackSize(Size size) => Orientation == Orientation.Vertical ? size.Height : size.Width;
protected override Size MeasureCore(Size availableSize) { if (textSizeInvalidated) { textSize = Manager.Renderer.MeasureText(Text, FontSize, FontStyle); textSizeInvalidated = false; } return textSize.Max(Size); }
private double GetStretchSize(Size size) => Orientation == Orientation.Vertical ? size.Width : size.Height;
protected override Size MeasureOverride(Size availableSize) { // Remove the border and padding, measure the element, and then add them back, as they must be ignored. availableSize = availableSize.Remove(BorderThickness).Remove(Padding); var size = base.MeasureOverride(availableSize) + BorderThickness + Padding; return size; }
/// <summary> /// Measures the element. /// </summary> protected virtual Size MeasureCore(Size availableSize) { // Remove the margin from the size, as it should be ignored for now. availableSize = availableSize.Remove(Margin); // If the width or height is NaN or 0, fall back to the available size, and clamp it within the min and max sizes. availableSize = Size.Fallback(availableSize).Clamp(MinSize, MaxSize); // Measure the size of child elements. var measuredSize = MeasureOverride(availableSize); measuredSize = Size.Fallback(measuredSize).Clamp(MinSize, MaxSize); measuredSize = measuredSize.Add(Margin); return measuredSize; }