123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- using System;
- using Avalonia;
- using Avalonia.Controls;
- using Avalonia.Input;
- using Avalonia.Utilities;
- namespace InABox.Avalonia.Components.ModuleGrid;
- public class AvaloniaModuleGridPanel : Panel, INavigableContainer
- {
- public static readonly StyledProperty<int> ItemsPerLineProperty =
- AvaloniaProperty.Register<AvaloniaModuleGridPanel, int>(nameof(ItemsPerLine), 3);
- static AvaloniaModuleGridPanel()
- {
- AffectsMeasure<AvaloniaModuleGridPanel>(ItemsPerLineProperty);
- }
-
- public int ItemsPerLine
- {
- get => GetValue(ItemsPerLineProperty);
- set => SetValue(ItemsPerLineProperty, value);
- }
- IInputElement INavigableContainer.GetControl(NavigationDirection direction, IInputElement? from, bool wrap)
- {
- var index = from is Control cFrom ? Children.IndexOf(cFrom) : -1;
- switch (direction)
- {
- case NavigationDirection.First:
- index = 0;
- break;
- case NavigationDirection.Last:
- index = Children.Count - 1;
- break;
- case NavigationDirection.Next:
- ++index;
- break;
- case NavigationDirection.Previous:
- --index;
- break;
- case NavigationDirection.Left:
- index -= 1;
- break;
- case NavigationDirection.Right:
- index += 1;
- break;
- case NavigationDirection.Up:
- index = -1;
- break;
- case NavigationDirection.Down:
- index = -1;
- break;
- }
- if (index >= 0 && index < Children.Count) return Children[index];
- return this;
- }
- protected override Size MeasureOverride(Size constraint)
- {
- var itemWidth = constraint.Width / ItemsPerLine;
- MutableSize currentLineSize = new();
- MutableSize panelSize = new();
- Size lineConstraint = new(constraint.Width, constraint.Height);
- Size childConstraint = new(itemWidth, constraint.Height);
- for (int i = 0, count = Children.Count; i < count; i++)
- {
- var child = Children[i];
- if (child is null) continue;
- child.Measure(childConstraint);
- Size childSize = new(itemWidth, child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(currentLineSize.Width + childSize.Width, lineConstraint.Width))
- {
- // Need to switch to another line
- panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
- panelSize.Height += currentLineSize.Height;
- currentLineSize = new MutableSize(childSize);
- }
- else
- {
- // Continue to accumulate a line
- currentLineSize.Width += childSize.Width;
- currentLineSize.Height = Math.Max(childSize.Height, currentLineSize.Height);
- }
- }
- // The last line size, if any should be added
- panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
- panelSize.Height += currentLineSize.Height;
- return panelSize.ToSize();
- }
- protected override Size ArrangeOverride(Size finalSize)
- {
- var itemWidth = finalSize.Width / ItemsPerLine;
- var firstInLine = 0;
- double accumulatedHeight = 0;
- var currentLineSize = new MutableSize();
- for (var i = 0; i < Children.Count; i++)
- {
- var child = Children[i];
- if (child == null) continue;
- MutableSize itemSize = new(itemWidth, child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(currentLineSize.Width + itemSize.Width, finalSize.Width))
- {
- // Need to switch to another line
- ArrangeLine(accumulatedHeight, currentLineSize.Height, firstInLine, i, itemWidth);
- accumulatedHeight += currentLineSize.Height;
- currentLineSize = itemSize;
- firstInLine = i;
- }
- else
- {
- // Continue to accumulate a line
- currentLineSize.Width += itemSize.Width;
- currentLineSize.Height = Math.Max(itemSize.Height, currentLineSize.Height);
- }
- }
- if (firstInLine < Children.Count)
- // Arrange the last line, if any
- ArrangeLine(accumulatedHeight, currentLineSize.Height, firstInLine, Children.Count, itemWidth);
- return finalSize;
- }
- private void ArrangeLine(double y, double height, int start, int end, double width)
- {
- double x = 0;
- for (var i = start; i < end; i++)
- {
- var child = Children[i];
- if (child == null) continue;
- child.Arrange(new Rect(x, y, width, height));
- x += width;
- }
- }
- private struct MutableSize
- {
- internal MutableSize(double width, double height)
- {
- Width = width;
- Height = height;
- }
- internal MutableSize(Size size)
- {
- Width = size.Width;
- Height = size.Height;
- }
- internal double Width;
- internal double Height;
- internal Size ToSize()
- {
- return new Size(Width, Height);
- }
- }
- }
|