From 293ef241f1e4ef4e41b254e62b4d903012683308 Mon Sep 17 00:00:00 2001 From: "H. Utku Maden" Date: Mon, 7 Sep 2026 21:51:29 +0300 Subject: [PATCH] Begind creating new layout system. --- Dashboard.Common/Drawing/IImmediateMode.cs | 2 +- .../Layout/ContainerLayoutInfo.cs | 117 +++++ Dashboard.Common/Layout/ContainerMode.cs | 9 + Dashboard.Common/Layout/DisplayMode.cs | 11 + Dashboard.Common/Layout/FlowDirection.cs | 10 + Dashboard.Common/Layout/ILayoutItem.cs | 2 +- Dashboard.Common/Layout/LayoutBox.cs | 435 ------------------ Dashboard.Common/Layout/LayoutInfo.cs | 184 ++------ Dashboard.Common/Layout/LayoutSolution.cs | 364 --------------- Dashboard.Common/Layout/OverflowMode.cs | 11 + Dashboard.Common/LayoutExtensions.cs | 130 ++++++ Dashboard.OpenGL/Drawing/ImmediateMode.cs | 6 +- Dashboard/Controls/Container.cs | 7 +- Dashboard/Controls/Control.cs | 18 +- Dashboard/Controls/Form.cs | 21 +- Dashboard/Controls/Label.cs | 4 +- Dashboard/Controls/MessageBox.cs | 67 +-- tests/Dashboard.TestApplication/Program.cs | 46 +- 18 files changed, 410 insertions(+), 1034 deletions(-) create mode 100644 Dashboard.Common/Layout/ContainerLayoutInfo.cs create mode 100644 Dashboard.Common/Layout/ContainerMode.cs create mode 100644 Dashboard.Common/Layout/DisplayMode.cs create mode 100644 Dashboard.Common/Layout/FlowDirection.cs delete mode 100644 Dashboard.Common/Layout/LayoutBox.cs delete mode 100644 Dashboard.Common/Layout/LayoutSolution.cs create mode 100644 Dashboard.Common/Layout/OverflowMode.cs create mode 100644 Dashboard.Common/LayoutExtensions.cs diff --git a/Dashboard.Common/Drawing/IImmediateMode.cs b/Dashboard.Common/Drawing/IImmediateMode.cs index bb13af2..9cad8e7 100644 --- a/Dashboard.Common/Drawing/IImmediateMode.cs +++ b/Dashboard.Common/Drawing/IImmediateMode.cs @@ -7,7 +7,7 @@ using Dashboard.Pal; namespace Dashboard.Drawing { - public record struct RectangleDrawInfo(Vector2 Position, ComputedBox Box, Brush Fill, Brush? Border = null); + public record struct RectangleDrawInfo(Vector2 Position, Box2d Box, Brush Fill, Brush? Border = null); [StructLayout(LayoutKind.Explicit, Size = Size)] public struct ImmediateVertex() diff --git a/Dashboard.Common/Layout/ContainerLayoutInfo.cs b/Dashboard.Common/Layout/ContainerLayoutInfo.cs new file mode 100644 index 0000000..96f00ec --- /dev/null +++ b/Dashboard.Common/Layout/ContainerLayoutInfo.cs @@ -0,0 +1,117 @@ +using System.ComponentModel; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Dashboard.Layout +{ + public class ContainerLayoutInfo : INotifyPropertyChanged + { + public FlowDirection FlowDirection + { + get; + set => SetField(ref field, value); + } = FlowDirection.Row; + + public Extents Padding + { + get; + set => SetField(ref field, value); + } + + public event PropertyChangedEventHandler? PropertyChanged; + + public virtual void ValidateLayout(ILayoutContainer container) + { + if (container.Count == 0) + return; + + ItemSolution[] items = [.. container.Select(x => new ItemSolution(x))]; + + // TODO: is this the actual size budget available at draw time? + Vector2 budget = container.Layout.ComputedBox.Size - Padding.ExtentSize; + + IEnumerable growItems = items.Where(x => x.DisplayMode == DisplayMode.Grow); + + Vector2 denominator = growItems.Any() + ? growItems.Select(x => x.Layout.Size + x.Layout.Margin.ExtentSize) + .Aggregate((a, b) => a + b) + : Vector2.One; + + // TODO: The layout engine assumes row layout atm. Implement other layouts. + + for (int i = 0; i < items.Length; i++) + items[i].Measure(budget, budget/denominator); + + float fixedWidth = items + .Where(x => x.DisplayMode != DisplayMode.Grow) + .Sum(x => x.DesiredSize.X); + + float remaining = budget.X - fixedWidth; + float star = remaining / denominator.X; + + Vector2 pen = container.Layout.ComputedBox.Min + new Vector2(Padding.Left, Padding.Top); + for (int i = 0; i < items.Length; i++) + { + items[i].Measure(budget, new Vector2(star, budget.Y)); + items[i].Position = pen; + pen.X += items[i].DesiredSize.X; + + items[i].Finish(); + } + } + + private struct ItemSolution(ILayoutItem item) + { + public ILayoutItem Item { get; } = item; + public Vector2 InstrinsicSize { get; } = item.CalculateIntrinsicSize(); + public Vector2 DesiredSize { get; private set; } + + public readonly LayoutInfo Layout => Item.Layout; + public readonly DisplayMode DisplayMode => Item.Layout.DisplayMode; + + public Vector2 Position { get; set; } + + public void Measure(Vector2 budget, Vector2 coefficient) + { + switch (DisplayMode) + { + case DisplayMode.None: + DesiredSize = Vector2.Zero; + break; + case DisplayMode.Fit: + DesiredSize = InstrinsicSize; + break; + case DisplayMode.Fixed: + DesiredSize = Layout.Size; + break; + case DisplayMode.Grow: + DesiredSize = Layout.Size * coefficient; + break; + case DisplayMode.Relative: + DesiredSize = Layout.Size * budget; + break; + } + + DesiredSize = Vector2.Clamp(DesiredSize, Layout.MinimumSize, Layout.MaximumSize); + } + + public void Finish() + { + Layout.ComputedBox = new Box2d(Position, Position + DesiredSize); + } + } + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + OnPropertyChanged(propertyName); + return true; + } + } +} diff --git a/Dashboard.Common/Layout/ContainerMode.cs b/Dashboard.Common/Layout/ContainerMode.cs new file mode 100644 index 0000000..4fa0c4b --- /dev/null +++ b/Dashboard.Common/Layout/ContainerMode.cs @@ -0,0 +1,9 @@ +namespace Dashboard.Layout +{ + public enum ContainerMode + { + Basic, + Flex, + Grid, + } +} diff --git a/Dashboard.Common/Layout/DisplayMode.cs b/Dashboard.Common/Layout/DisplayMode.cs new file mode 100644 index 0000000..271eea4 --- /dev/null +++ b/Dashboard.Common/Layout/DisplayMode.cs @@ -0,0 +1,11 @@ +namespace Dashboard.Layout +{ + public enum DisplayMode + { + None, + Fit, + Grow, + Relative, + Fixed, + } +} diff --git a/Dashboard.Common/Layout/FlowDirection.cs b/Dashboard.Common/Layout/FlowDirection.cs new file mode 100644 index 0000000..edb27c0 --- /dev/null +++ b/Dashboard.Common/Layout/FlowDirection.cs @@ -0,0 +1,10 @@ +namespace Dashboard.Layout +{ + public enum FlowDirection + { + Row, + Column, + RowReverse, + ColumnReverse, + } +} diff --git a/Dashboard.Common/Layout/ILayoutItem.cs b/Dashboard.Common/Layout/ILayoutItem.cs index 253fa7c..b260b11 100644 --- a/Dashboard.Common/Layout/ILayoutItem.cs +++ b/Dashboard.Common/Layout/ILayoutItem.cs @@ -11,7 +11,7 @@ namespace Dashboard.Layout public Vector2 CalculateSize(Vector2 limits); } - public interface ILayoutContainer : ILayoutItem, IEnumerable + public interface ILayoutContainer : ILayoutItem, IReadOnlyList { public ContainerLayoutInfo ContainerLayout { get; } } diff --git a/Dashboard.Common/Layout/LayoutBox.cs b/Dashboard.Common/Layout/LayoutBox.cs deleted file mode 100644 index 2a5699b..0000000 --- a/Dashboard.Common/Layout/LayoutBox.cs +++ /dev/null @@ -1,435 +0,0 @@ -using System.ComponentModel; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace Dashboard.Layout -{ - public readonly record struct ComputedBox(Vector4 Margin, Vector4 Padding, Vector4 Border, Vector2 Size) - { - public float MarginLeft => Margin.X; - public float MarginTop => Margin.Y; - public float MarginRight => Margin.Z; - public float MarginBottom => Margin.W; - - public float PaddingLeft => Padding.X; - public float PaddingTop => Padding.Y; - public float PaddingRight => Padding.Z; - public float PaddingBottom => Padding.W; - - public float BorderLeft => Border.X; - public float BorderTop => Border.Y; - public float BorderRight => Border.Z; - public float BorderBottom => Border.W; - - public float Width => Size.X; - public float Height => Size.Y; - - public Vector2 BoundingSize => new Vector2( - MarginLeft + BorderLeft + Width + BorderRight + MarginRight, - MarginTop + BorderTop + Height + BorderBottom + MarginBottom); - - public Vector2 ContentSize => new Vector2( - Width - PaddingLeft - PaddingRight, - Height - PaddingTop - PaddingBottom); - - public Vector4 ContentExtents => new Vector4( - PaddingLeft, - PaddingTop, - PaddingLeft + PaddingRight + Width, - PaddingTop + PaddingBottom + Height); - - public Vector4 CornerRadii { get; init; } = Vector4.Zero; - } - - public class LayoutBox : INotifyPropertyChanged - { - private Vector4 _margin = Vector4.Zero; - private Vector4 _padding = Vector4.Zero; - private Vector4 _border = Vector4.Zero; - private Vector2 _size = Vector2.Zero; - private Vector2 _minimumSize = -Vector2.One; - private Vector2 _maximumSize = -Vector2.One; - private Vector4 _cornerRadii = Vector4.Zero; - - private LayoutUnit _marginLeftUnit = LayoutUnit.Pixel; - private LayoutUnit _marginTopUnit = LayoutUnit.Pixel; - private LayoutUnit _marginRightUnit = LayoutUnit.Pixel; - private LayoutUnit _marginBottomUnit = LayoutUnit.Pixel; - - private LayoutUnit _paddingLeftUnit = LayoutUnit.Pixel; - private LayoutUnit _paddingTopUnit = LayoutUnit.Pixel; - private LayoutUnit _paddingRightUnit = LayoutUnit.Pixel; - private LayoutUnit _paddingBottomUnit = LayoutUnit.Pixel; - - private LayoutUnit _borderLeftUnit = LayoutUnit.Pixel; - private LayoutUnit _borderTopUnit = LayoutUnit.Pixel; - private LayoutUnit _borderRightUnit = LayoutUnit.Pixel; - private LayoutUnit _borderBottomUnit = LayoutUnit.Pixel; - - private LayoutUnit _widthUnit = LayoutUnit.Pixel; - private LayoutUnit _heightUnit = LayoutUnit.Pixel; - - private LayoutUnit _minimumWidthUnit = LayoutUnit.Pixel; - private LayoutUnit _minimumHeightUnit = LayoutUnit.Pixel; - - private LayoutUnit _maximumWidthUnit = LayoutUnit.Pixel; - private LayoutUnit _maximumHeightUnit = LayoutUnit.Pixel; - - private LayoutUnit _cornerRadiusTopLeftUnit = LayoutUnit.Pixel; - private LayoutUnit _cornerRadiusBottomLeftUnit = LayoutUnit.Pixel; - private LayoutUnit _cornerRadiusBottomRightUnit = LayoutUnit.Pixel; - private LayoutUnit _cornerRadiusTopRightUnit = LayoutUnit.Pixel; - private ComputedBox _computedBox = new ComputedBox(); - - public bool UpdateRequired { get; private set; } = true; - - public Vector4 Margin - { - get => _margin; - set => SetField(ref _margin, value); - } - - public Vector4 Padding - { - get => _padding; - set => SetField(ref _padding, value); - } - - public Vector4 Border - { - get => _border; - set => SetField(ref _border, value); - } - - public Vector2 Size - { - get => _size; - set => SetField(ref _size, value); - } - - public Vector2 MinimumSize - { - get => _minimumSize; - set => SetField(ref _minimumSize, value); - } - - public Vector2 MaximumSize - { - get => _maximumSize; - set => SetField(ref _maximumSize, value); - } - - public Vector4 CornerRadii - { - get => _cornerRadii; - set => SetField(ref _cornerRadii, value); - } - - public float MarginLeft - { - get => Margin.X; - set => Margin = Margin with { X = value }; - } - - public float MarginTop - { - get => Margin.Y; - set => Margin = Margin with { Y = value }; - } - - public float MarginRight - { - get => Margin.Z; - set => Margin = Margin with { Z = value }; - } - - public float MarginBottom - { - get => Margin.W; - set => Margin = Margin with { W = value }; - } - - public float PaddingLeft - { - get => Padding.X; - set => Padding = Padding with { X = value }; - } - - public float PaddingTop - { - get => Padding.Y; - set => Padding = Padding with { Y = value }; - } - - public float PaddingRight - { - get => Padding.Z; - set => Padding = Padding with { Z = value }; - } - - public float PaddingBottom - { - get => Padding.W; - set => Padding = Padding with { W = value }; - } - - public float BorderLeft - { - get => Border.X; - set => Border = Border with { X = value }; - } - - public float BorderTop - { - get => Border.Y; - set => Border = Border with { Y = value }; - } - - public float BorderRight - { - get => Border.Z; - set => Border = Border with { Z = value }; - } - - public float BorderBottom - { - get => Border.W; - set => Border = Border with { W = value }; - } - - public float CornerRadiusTopLeft - { - get => CornerRadii.X; - set => CornerRadii = CornerRadii with { X = value }; - } - - public float CornerRadiusBottomLeft - { - get => CornerRadii.Y; - set => CornerRadii = CornerRadii with { Y = value }; - } - - public float CornerRadiusBottomRight - { - get => CornerRadii.Z; - set => CornerRadii = CornerRadii with { Z = value }; - } - - public float CornerRadiusTopRight - { - get => CornerRadii.W; - set => CornerRadii = CornerRadii with { W = value }; - } - - public LayoutUnit MarginLeftUnit - { - get => _marginLeftUnit; - set => SetField(ref _marginLeftUnit, value); - } - - public LayoutUnit MarginTopUnit - { - get => _marginTopUnit; - set => SetField(ref _marginTopUnit, value); - } - - public LayoutUnit MarginRightUnit - { - get => _marginRightUnit; - set => SetField(ref _marginRightUnit, value); - } - - public LayoutUnit MarginBottomUnit - { - get => _marginBottomUnit; - set => SetField(ref _marginBottomUnit, value); - } - - public LayoutUnit PaddingLeftUnit - { - get => _paddingLeftUnit; - set => SetField(ref _paddingLeftUnit, value); - } - - public LayoutUnit PaddingTopUnit - { - get => _paddingTopUnit; - set => SetField(ref _paddingTopUnit, value); - } - - public LayoutUnit PaddingRightUnit - { - get => _paddingRightUnit; - set => SetField(ref _paddingRightUnit, value); - } - - public LayoutUnit PaddingBottomUnit - { - get => _paddingBottomUnit; - set => SetField(ref _paddingBottomUnit, value); - } - - public LayoutUnit BorderLeftUnit - { - get => _borderLeftUnit; - set => SetField(ref _borderLeftUnit, value); - } - - public LayoutUnit BorderTopUnit - { - get => _borderTopUnit; - set => SetField(ref _borderTopUnit, value); - } - - public LayoutUnit BorderRightUnit - { - get => _borderRightUnit; - set => SetField(ref _borderRightUnit, value); - } - - public LayoutUnit BorderBottomUnit - { - get => _borderBottomUnit; - set => SetField(ref _borderBottomUnit, value); - } - - public LayoutUnit WidthUnit - { - get => _widthUnit; - set => SetField(ref _widthUnit, value); - } - - public LayoutUnit HeightUnit - { - get => _heightUnit; - set => SetField(ref _heightUnit, value); - } - - public LayoutUnit MinimumWidthUnit - { - get => _minimumWidthUnit; - set => SetField(ref _minimumWidthUnit, value); - } - - public LayoutUnit MinimumHeightUnit - { - get => _minimumHeightUnit; - set => SetField(ref _minimumHeightUnit, value); - } - - public LayoutUnit MaximumWidthUnit - { - get => _maximumWidthUnit; - set => SetField(ref _maximumWidthUnit, value); - } - - public LayoutUnit MaximumHeightUnit - { - get => _maximumHeightUnit; - set => SetField(ref _maximumHeightUnit, value); - } - - public LayoutUnit CornerRadiusTopLeftUnit - { - get => _cornerRadiusTopLeftUnit; - set => SetField(ref _cornerRadiusTopLeftUnit, value); - } - - public LayoutUnit CornerRadiusBottomLeftUnit - { - get => _cornerRadiusBottomLeftUnit; - set => SetField(ref _cornerRadiusBottomLeftUnit, value); - } - - public LayoutUnit CornerRadiusBottomRightUnit - { - get => _cornerRadiusBottomRightUnit; - set => SetField(ref _cornerRadiusBottomRightUnit, value); - } - - public LayoutUnit CornerRadiusTopRightUnit - { - get => _cornerRadiusTopRightUnit; - set => SetField(ref _cornerRadiusTopRightUnit, value); - } - - public ComputedBox ComputedBox - { - get => _computedBox; - private set => SetField(ref _computedBox, value, false); - } - - public event PropertyChangedEventHandler? PropertyChanged; - - public ComputedBox ComputeLayout(Vector2 intrinsic, Vector2 dpi, Vector2 area, Vector2 star) - { - // TODO: take intrinsic into account. - Vector4 margin = Compute(_margin, dpi, area, star, _marginLeftUnit, _marginTopUnit, _marginRightUnit, _marginBottomUnit); - Vector4 padding = Compute(_padding, dpi, area, star, _paddingLeftUnit, _paddingTopUnit, _paddingRightUnit, _paddingBottomUnit); - Vector4 border = Compute(_border, dpi, area, star, _borderLeftUnit, _borderTopUnit, _borderRightUnit, _borderBottomUnit); - - Vector2 size = Compute(_size, dpi, area, star, _widthUnit, _heightUnit); - Vector2 minimumSize = Compute(_minimumSize, dpi, area, star, _minimumWidthUnit, _minimumHeightUnit); - Vector2 maximumSize = Compute(_maximumSize, dpi, area, star, _maximumWidthUnit, _maximumHeightUnit); - Vector4 cornerRadii = Compute(_cornerRadii, dpi, area, star, _cornerRadiusTopLeftUnit, - _cornerRadiusBottomLeftUnit, _cornerRadiusBottomRightUnit, _cornerRadiusTopRightUnit); - - size = Vector2.Clamp(size, minimumSize, maximumSize); - - ComputedBox = new ComputedBox(margin, padding, border, size) - { - CornerRadii = cornerRadii, - }; - - UpdateRequired = false; - return ComputedBox; - } - - private static float Compute(float value, float dpi, float length, float star, LayoutUnit unit) - { - const float dpiToMm = 0f; - const float dpiToPt = 0f; - - return unit switch - { - LayoutUnit.Pixel => value, - LayoutUnit.Millimeter => value * dpi * dpiToMm, - LayoutUnit.Percent => value * length, - LayoutUnit.Point => value * dpi * dpiToPt, - LayoutUnit.Star => value * star, - _ => throw new ArgumentException(nameof(unit)), - }; - } - - private static Vector2 Compute(Vector2 value, Vector2 dpi, Vector2 size, Vector2 star, LayoutUnit xUnit, LayoutUnit yUnit) - { - return new Vector2( - Compute(value.X, dpi.X, size.X, star.X, xUnit), - Compute(value.Y, dpi.Y, size.Y, star.Y, yUnit)); - } - - private static Vector4 Compute(Vector4 value, Vector2 dpi, Vector2 size, Vector2 star, LayoutUnit xUnit, LayoutUnit yUnit, LayoutUnit zUnit, LayoutUnit wUnit) - { - return new Vector4( - Compute(value.X, dpi.X, size.X, star.X, xUnit), - Compute(value.Y, dpi.Y, size.Y, star.Y, yUnit), - Compute(value.Z, dpi.X, size.X, star.X, zUnit), - Compute(value.W, dpi.Y, size.Y, star.Y, wUnit)); - } - - - private void OnPropertyChanged([CallerMemberName] string? propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private bool SetField(ref T field, T value, bool updateRequired = true, [CallerMemberName] string? propertyName = null) - { - if (EqualityComparer.Default.Equals(field, value)) return false; - field = value; - UpdateRequired |= updateRequired; - OnPropertyChanged(propertyName); - return true; - } - } -} diff --git a/Dashboard.Common/Layout/LayoutInfo.cs b/Dashboard.Common/Layout/LayoutInfo.cs index 8b03efc..4757890 100644 --- a/Dashboard.Common/Layout/LayoutInfo.cs +++ b/Dashboard.Common/Layout/LayoutInfo.cs @@ -1,4 +1,3 @@ -using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Numerics; @@ -6,68 +5,54 @@ using System.Runtime.CompilerServices; namespace Dashboard.Layout { - public enum DisplayMode + public class LayoutInfo : INotifyPropertyChanged { - None, - Inline, - Block, - } - - public enum ContainerMode - { - Basic, - Flex, - Grid, - } - - public enum FlowDirection - { - Row, - Column, - RowReverse, - ColumnReverse, - } - - public enum PositionMode - { - Absolute, - Relative, - } - - public enum OverflowMode - { - Hidden, - Overflow, - ScrollHorizontal, - ScrollVertical, - ScrollBoth, - } - - public record struct TrackInfo(float Width, LayoutUnit Unit) - { - public static readonly TrackInfo Default = new TrackInfo(0, LayoutUnit.Auto); - } - - public class ContainerLayoutInfo : INotifyPropertyChanged - { - private ContainerMode _containerMode; - private FlowDirection _flowDirection = FlowDirection.Row; - - public ObservableCollection Rows { get; } = new ObservableCollection() { TrackInfo.Default }; - - public ObservableCollection Columns { get; } = - new ObservableCollection() { TrackInfo.Default }; - - public ContainerMode ContainerMode + /// + /// Changes the control display. + /// + public DisplayMode DisplayMode { - get => _containerMode; - set => SetField(ref _containerMode, value); + get; + set => SetField(ref field, value); + } = DisplayMode.Fit; + + /// + /// Changes how overflows are handled. + /// + public OverflowMode OverflowMode + { + get; + set => SetField(ref field, value); + } = OverflowMode.Hidden; + + public Vector2 Size + { + get; + set => SetField(ref field, value); } - public FlowDirection FlowDirection + public Vector2 MaximumSize { - get => _flowDirection; - set => SetField(ref _flowDirection, value); + get; + set => SetField(ref field, value); + } + + public Vector2 MinimumSize + { + get; + set => SetField(ref field, value); + } + + public Extents Margin + { + get; + set => SetField(ref field, value); + } + + public Box2d ComputedBox + { + get; + set => SetField(ref field, value); } public event PropertyChangedEventHandler? PropertyChanged; @@ -85,87 +70,4 @@ namespace Dashboard.Layout return true; } } - - public class LayoutInfo : INotifyPropertyChanged - { - private DisplayMode _displayMode = DisplayMode.Inline; - private PositionMode _positionMode = PositionMode.Relative; - private OverflowMode _overflowMode = OverflowMode.Overflow; - private int _row = 0; - private int _column = 0; - - /// - /// Changes the control display. - /// - public DisplayMode DisplayMode - { - get => _displayMode; - set => SetField(ref _displayMode, value); - } - - /// - /// Changes how the control is positioned. - /// - public PositionMode PositionMode - { - get => _positionMode; - set => SetField(ref _positionMode, value); - } - - /// - /// Changes how overflows are handled. - /// - public OverflowMode OverflowMode - { - get => _overflowMode; - set => SetField(ref _overflowMode, value); - } - - public LayoutBox Box { get; } = new LayoutBox(); - - /// - /// The row of the control in a grid container. - /// - public int Row - { - get => _row; - set => SetField(ref _row, value); - } - - /// - /// The column of the control in a grid container. - /// - public int Column - { - get => _column; - set => SetField(ref _column, value); - } - - public event PropertyChangedEventHandler? PropertyChanged; - - public LayoutInfo() - { - Box.PropertyChanged += BoxOnPropertyChanged; - // Rows.CollectionChanged += RowsChanged; - // Columns.CollectionChanged += ColumnsChanged; - } - - private void BoxOnPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - OnPropertyChanged(nameof(Box)); - } - - protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) - { - if (EqualityComparer.Default.Equals(field, value)) return false; - field = value; - OnPropertyChanged(propertyName); - return true; - } - } } diff --git a/Dashboard.Common/Layout/LayoutSolution.cs b/Dashboard.Common/Layout/LayoutSolution.cs deleted file mode 100644 index 19fe327..0000000 --- a/Dashboard.Common/Layout/LayoutSolution.cs +++ /dev/null @@ -1,364 +0,0 @@ -using System.Numerics; - -namespace Dashboard.Layout -{ - public record struct LayoutItemSolution(ILayoutItem Item, ComputedBox Solution); - - public class LayoutSolution - { - public ILayoutContainer Container { get; } - public IReadOnlyList Items { get; } - - private LayoutSolution(ILayoutContainer container, IEnumerable itemSolutions) - { - Container = container; - Items = itemSolutions.ToList().AsReadOnly(); - } - - public static LayoutSolution CalculateLayout(T1 container, Vector2 limits, int iterations = 3, float absTol = 0.001f, float relTol = 0.01f) - where T1 : ILayoutContainer - { - switch (container.ContainerLayout.ContainerMode) - { - default: - case ContainerMode.Basic: - return SolveForBasicLayout(container, limits, iterations, absTol, relTol); - case ContainerMode.Flex: - return SolveForFlex(container, limits, iterations, absTol, relTol); - case ContainerMode.Grid: - return SolveForGrid(container, limits, iterations, absTol, relTol); - } - } - - private static LayoutSolution SolveForGrid(T1 container, Vector2 limits, int iterations, float absTol, float relTol) where T1 : ILayoutContainer - { - throw new NotImplementedException(); - } - - private static LayoutSolution SolveForFlex(T1 container, Vector2 limits,int iterations, float absTol, float relTol) where T1 : ILayoutContainer - { - throw new NotImplementedException(); - } - - private static LayoutSolution SolveForBasicLayout(T1 container, Vector2 limits, int iterations, float absTol, float relTol) where T1 : ILayoutContainer - { - int count = container.Count(); - LayoutItemSolution[] items = new LayoutItemSolution[count]; - - int i = 0; - foreach (ILayoutItem item in container) - { - items[i++] = new LayoutItemSolution(item, default); - } - - bool limitX = limits.X > 0; - bool limitY = limits.Y > 0; - - while (iterations-- > 0) - { - Vector2 pen = Vector2.Zero; - - i = 0; - foreach (ILayoutItem item in container) - { - Vector2 size = item.CalculateIntrinsicSize(); - - } - } - - return new LayoutSolution(container, items); - } - - private record TrackSolution(TrackInfo Track) - { - public bool Auto => Track.Unit == LayoutUnit.Auto; - - public bool Absolute => Track.Unit.IsAbsolute(); - - public float Requested { get; private set; } - public float Value { get; private set; } - - public float Result { get; set; } = 0.0f; - public bool IsFrozen { get; set; } = false; - - public void CalculateRequested(float dpi, float rel, float star) - { - Requested = new Metric(Track.Unit, Track.Width).Compute(dpi, rel, star); - } - - public void Freeze() - { - if (IsFrozen) - return; - - IsFrozen = true; - Result = Value; - } - } - - private delegate float GetItemLength(float dpi, float rel, float star, T1 item) - where T1 : ILayoutItem; - - private TrackSolution[] SolveForGridTracks( - float limit, - T1 tracks, - T2 container, - int iterations, - float absTol, - float relTol, - Func getItemTrack, - GetItemLength getItemLength) - where T1 : IList - where T2 : ILayoutContainer - where T3 : ILayoutItem - { - int itemCount = container.Count(); - bool auto = limit < 0; - TrackSolution[] solution = new TrackSolution[tracks.Count]; - - foreach (TrackSolution track in solution) - { - if (track.Absolute) { - // FIXME: pass DPI here. - track.CalculateRequested(96f, limit, 0); - track.Freeze(); - } - } - - while (iterations-- > 0) - { - } - - for (int i = 0; i < tracks.Count; i++) - { - solution[i].Freeze(); - } - - return solution; - } - - // private static void GetIntrinsicGridSizes(Span cols, Span rows, T1 parent, T2 items) - // where T1 : ILayoutItem - // where T2 : IEnumerable - // { - // CopyToSpan(rows, parent.Layout.Rows); - // CopyToSpan(cols, parent.Layout.Columns); - // - // foreach (ILayoutItem item in items) - // { - // int col = Math.Clamp(item.Layout.Column, 0, cols.Length - 1); - // int row = Math.Clamp(item.Layout.Row, 0, rows.Length - 1); - // - // bool autoCols = parent.Layout.Columns[col] < 0; - // bool autoRows = parent.Layout.Rows[row] < 0; - // - // if (!autoRows && !autoCols) - // continue; - // - // Vector2 size = item.CalculateIntrinsicSize(); - // cols[col] = autoCols ? Math.Max(size.X, cols[col]) : cols[col]; - // rows[row] = autoRows ? Math.Max(size.Y, rows[row]) : rows[row]; - // } - // } - // - // public static Vector2 CalculateIntrinsicSize(T1 parent, T2 items) - // where T1 : ILayoutItem - // where T2 : IEnumerable - // { - // // Copy layout details. - // Span cols = stackalloc float[parent.Layout.Columns.Count]; - // Span rows = stackalloc float[parent.Layout.Rows.Count]; - // - // GetIntrinsicGridSizes(cols, rows, parent, items); - // - // float width = parent.Layout.Margin.X + parent.Layout.Margin.Z + parent.Layout.Padding.X + parent.Layout.Padding.Z + SumSpan(cols); - // float height = parent.Layout.Margin.Y + parent.Layout.Margin.W + parent.Layout.Padding.Y + parent.Layout.Padding.W + SumSpan(rows); - // - // return new Vector2(width, height); - // } - // - // public static GridResult Layout(T1 parent, T2 items, Vector2 limits, int iterations = 3, float abstol = 0.0001f, float reltol = 0.01f) - // where T1 : ILayoutItem - // where T2 : IEnumerable - // { - // Vector4 contentSpace = parent.Layout.Margin + parent.Layout.Padding; - // Vector2 contentLimits = new Vector2( - // limits.X > 0 ? limits.X - contentSpace.X - contentSpace.Z : -1, - // limits.Y > 0 ? limits.Y - contentSpace.Y - contentSpace.W : -1); - // - // // Get rows and columns for now. - // Span cols = stackalloc Track[parent.Layout.Columns.Count]; - // Span rows = stackalloc Track[parent.Layout.Rows.Count]; - // - // for (int i = 0; i < cols.Length; i++) - // { - // cols[i] = new Track(parent.Layout.Columns[i]); - // - // if (!cols[i].Auto) - // { - // cols[i].Freeze(); - // } - // } - // - // for (int i = 0; i < rows.Length; i++) - // { - // rows[i] = new Track(parent.Layout.Rows[i]); - // - // if (!rows[i].Auto) - // { - // rows[i].Freeze(); - // } - // } - // - // int freeRows = 0; - // int freeCols = 0; - // while (iterations-- > 0 && ((freeRows = CountFree(rows)) > 0 || (freeCols = CountFree(cols)) > 0)) - // { - // // Calculate the remaining size. - // Vector2 remaining = contentLimits; - // - // for (int i = 0; contentLimits.X > 0 && i < cols.Length; i++) - // { - // if (cols[i].IsFrozen) - // remaining.X -= cols[i].Value; - // } - // - // for (int i = 0; contentLimits.Y > 0 && i < rows.Length; i++) - // { - // if (rows[i].IsFrozen) - // remaining.Y -= rows[i].Value; - // } - // - // Vector2 childLimits = remaining / new Vector2(Math.Max(freeCols, 1), Math.Max(freeRows, 1)); - // - // - // // Calculate the size of each free track. - // foreach (ILayoutItem child in items) - // { - // int c = Math.Clamp(child.Layout.Column, 0, cols.Length - 1); - // int r = Math.Clamp(child.Layout.Row, 0, rows.Length - 1); - // - // bool autoRow = rows[r].Auto; - // bool autoCol = cols[c].Auto; - // - // if (!autoRow && !autoCol) - // continue; - // - // Vector2 childSize = child.CalculateSize(childLimits); - // - // if (autoCol) - // cols[c].Value = Math.Max(childLimits.X, childSize.X); - // - // if (autoRow) - // rows[r].Value = Math.Max(childLimits.Y, childSize.Y); - // } - // - // // Calculate for errors and decide to freeze them. - // - // for (int i = 0; limits.X > 0 && i < cols.Length; i++) - // { - // if (WithinTolerance(cols[i].Value, childLimits.X, abstol, reltol)) - // { - // cols[i].Freeze(); - // } - // } - // - // for (int i = 0; limits.Y > 0 && i < rows.Length; i++) - // { - // if (WithinTolerance(rows[i].Value, childLimits.Y, abstol, reltol)) - // { - // rows[i].Freeze(); - // } - // } - // } - // - // Vector2 size = new Vector2( - // parent.Layout.Margin.X + parent.Layout.Margin.Z + parent.Layout.Padding.X + parent.Layout.Padding.Z, - // parent.Layout.Margin.Y + parent.Layout.Margin.W + parent.Layout.Padding.Y + parent.Layout.Padding.W); - // - // foreach (ref Track col in cols) - // { - // col.Freeze(); - // size.X += col.Result; - // } - // - // foreach (ref Track row in rows) - // { - // row.Freeze(); - // size.Y += row.Result; - // } - // - // if (limits.X > 0) size.X = Math.Max(size.X, limits.X); - // if (limits.Y > 0) size.Y = Math.Max(size.Y, limits.Y); - // - // // Temporary solution - // return new GridResult(size, cols.ToArray().Select(x => x.Result).ToArray(), rows.ToArray().Select(x => x.Result).ToArray()); - // - // static int CountFree(Span tracks) - // { - // int i = 0; - // foreach (Track track in tracks) - // { - // if (!track.IsFrozen) - // i++; - // } - // - // return i; - // } - // } - // - // private static void CopyToSpan(Span span, T2 items) - // where T2 : IEnumerable - // { - // using IEnumerator iterator = items.GetEnumerator(); - // for (int i = 0; i < span.Length; i++) - // { - // if (!iterator.MoveNext()) - // break; - // - // span[i] = iterator.Current; - // } - // } - // - // private static T1 SumSpan(ReadOnlySpan span) - // where T1 : struct, INumber - // { - // T1 value = default; - // - // foreach (T1 item in span) - // { - // value += item; - // } - // - // return value; - // } - // - // private static bool WithinTolerance(T value, T limit, T abstol, T reltol) - // where T : INumber - // { - // T tol = T.Max(abstol, value * reltol); - // return T.Abs(value - limit) < tol; - // } - // - // public record GridResult(Vector2 Size, float[] Columns, float[] Rows) - // { - // - // } - // - // private record struct Track(float Request) - // { - // public bool Auto => Request < 0; - // - // public bool IsFrozen { get; private set; } = false; - // public float Value { get; set; } = Request; - // - // public float Result { get; private set; } - // - // public void Freeze() - // { - // Result = Value; - // IsFrozen = true; - // } - // } - } -} diff --git a/Dashboard.Common/Layout/OverflowMode.cs b/Dashboard.Common/Layout/OverflowMode.cs new file mode 100644 index 0000000..aeadf8d --- /dev/null +++ b/Dashboard.Common/Layout/OverflowMode.cs @@ -0,0 +1,11 @@ +namespace Dashboard.Layout +{ + public enum OverflowMode + { + Hidden, + Overflow, + ScrollHorizontal, + ScrollVertical, + ScrollBoth, + } +} diff --git a/Dashboard.Common/LayoutExtensions.cs b/Dashboard.Common/LayoutExtensions.cs new file mode 100644 index 0000000..7276eae --- /dev/null +++ b/Dashboard.Common/LayoutExtensions.cs @@ -0,0 +1,130 @@ +using System.Numerics; +using Dashboard.Layout; + +namespace Dashboard +{ + public static class LayoutExtensions + { + extension(T item) + where T : ILayoutItem + { + public DisplayMode DisplayMode + { + get => item.Layout.DisplayMode; + set => item.Layout.DisplayMode = value; + } + + public OverflowMode OverflowMode + { + get => item.Layout.OverflowMode; + set => item.Layout.OverflowMode = value; + } + + public Vector2 Size + { + get => item.Layout.Size; + set => item.Layout.Size = value; + } + + public float Width + { + get => item.Size.X; + set => item.Size = new Vector2(value, item.Size.Y); + } + + public float Height + { + get => item.Size.Y; + set => item.Size = new Vector2(item.Size.X, value); + } + + public Vector2 MaximumSize + { + get => item.Layout.MaximumSize; + set => item.Layout.MaximumSize = value; + } + + public float MaximumWidth + { + get => item.MaximumSize.X; + set => item.MaximumSize = new Vector2(value, item.MaximumSize.Y); + } + + public float MaximumHeight + { + get => item.MaximumSize.Y; + set => item.MaximumSize = new Vector2(item.MaximumSize.X, value); + } + + public Vector2 MinimumSize + { + get => item.Layout.MinimumSize; + set => item.Layout.MinimumSize = value; + } + + public float MinimumWidth + { + get => item.MinimumSize.X; + set => item.MinimumSize = new Vector2(value, item.MinimumSize.Y); + } + + public float MinimumHeight + { + get => item.MinimumSize.Y; + set => item.MinimumSize = new Vector2(item.MinimumSize.X, value); + } + + public Extents Margin + { + get => item.Layout.Margin; + set => item.Layout.Margin = value; + } + + public float MarginLeft + { + get => item.Layout.Margin.Left; + set => item.Layout.Margin = new Extents(value, item.MarginTop, item.MarginRight, item.MarginBottom); + } + + public float MarginTop + { + get => item.Layout.Margin.Top; + set => item.Layout.Margin = new Extents(item.MarginLeft, value, item.MarginRight, item.MarginBottom); + } + + public float MarginRight + { + get => item.Layout.Margin.Right; + set => item.Layout.Margin = new Extents(item.MarginLeft, item.MarginTop, value, item.MarginBottom); + } + + public float MarginBottom + { + get => item.Layout.Margin.Bottom; + set => item.Layout.Margin = new Extents(item.MarginLeft, item.MarginTop, item.MarginRight, value); + } + + public Box2d ComputedBox + { + get => item.Layout.ComputedBox; + set => item.Layout.ComputedBox = value; + } + } + + extension (T item) + where T : ILayoutContainer + { + public FlowDirection FlowDirection + { + get => item.ContainerLayout.FlowDirection; + set => item.ContainerLayout.FlowDirection = value; + } + + public Extents Padding + { + get => item.ContainerLayout.Padding; + set => item.ContainerLayout.Padding = value; + } + } + } +} diff --git a/Dashboard.OpenGL/Drawing/ImmediateMode.cs b/Dashboard.OpenGL/Drawing/ImmediateMode.cs index e0ddf55..00262c1 100644 --- a/Dashboard.OpenGL/Drawing/ImmediateMode.cs +++ b/Dashboard.OpenGL/Drawing/ImmediateMode.cs @@ -127,10 +127,8 @@ namespace Dashboard.OpenGL.Drawing int z = Context.ExtensionRequire().IncrementZ(); Color color = (rectangle.Fill as SolidColorBrush)?.Color ?? Color.LightGray; Vector4 colorV = new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); - Vector4 margin = rectangle.Box.Margin; - Vector4 border = rectangle.Box.Border; - Vector2 size = rectangle.Box.Size + new Vector2(border.X + border.Z, border.Y = border.W); - Box2d box = Box2d.FromPositionAndSize(rectangle.Position + new Vector2(margin.X + border.X, margin.Y + border.Y), size); + Vector2 size = rectangle.Box.Size; + Box2d box = Box2d.FromPositionAndSize(rectangle.Position, size); Rectangle(box, z, colorV); } diff --git a/Dashboard/Controls/Container.cs b/Dashboard/Controls/Container.cs index 01cbe5e..04ea2cf 100644 --- a/Dashboard/Controls/Container.cs +++ b/Dashboard/Controls/Container.cs @@ -18,6 +18,8 @@ namespace Dashboard.Controls public ContainerLayoutInfo ContainerLayout { get; } = new ContainerLayoutInfo(); + ILayoutItem IReadOnlyList.this[int index] => _controls[index]; + public event EventHandler? ChildAdded; public event EventHandler? ChildRemoved; @@ -33,7 +35,10 @@ namespace Dashboard.Controls if (!IsLayoutEnabled || IsLayoutValid) return; - // LayoutSolution solution = LayoutSolution.CalculateLayout(this, ClientArea.Size); + ContainerLayout.ValidateLayout(this); + + foreach (var child in this) + child.InvalidateLayout(); base.ValidateLayout(); } diff --git a/Dashboard/Controls/Control.cs b/Dashboard/Controls/Control.cs index 4f6db8f..e1fd9ce 100644 --- a/Dashboard/Controls/Control.cs +++ b/Dashboard/Controls/Control.cs @@ -1,8 +1,8 @@ using System; using System.ComponentModel; -using System.Diagnostics; using System.Drawing; using System.Numerics; +using System.Runtime.CompilerServices; using Dashboard.Drawing; using Dashboard.Events; using Dashboard.Layout; @@ -29,7 +29,7 @@ namespace Dashboard.Controls public Control? Parent { get; private set; } = null; public bool Disposed { get; private set; } - public virtual Box2d ClientArea { get; set; } + public virtual Box2d ClientArea => Layout.ComputedBox; public bool IsFocused => _owner?.FocusedControl == this; public Brush Background { get; set; } = new SolidColorBrush(Color.Transparent); @@ -39,6 +39,7 @@ namespace Dashboard.Controls public bool IsLayoutEnabled { get; private set; } = true; protected bool IsLayoutValid { get; set; } = false; + public event PropertyChangedEventHandler? PropertyChanged; public event EventHandler? Painting; public event EventHandler? AnimationTick; public event EventHandler? OwnerChanged; @@ -175,7 +176,18 @@ namespace Dashboard.Controls IsLayoutValid = false; } + protected void SetField(ref T field, T value, [CallerMemberName]string name = "") + { + field = value; + if (!string.IsNullOrEmpty(name)) + OnPropertyChanged(name); + } + + protected virtual void OnPropertyChanged(string name) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + protected static Exception NoOwnerException => new Exception("No form owns this control"); - public event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/Dashboard/Controls/Form.cs b/Dashboard/Controls/Form.cs index 1ff83e1..bcee628 100644 --- a/Dashboard/Controls/Form.cs +++ b/Dashboard/Controls/Form.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.Numerics; using Dashboard.Drawing; using Dashboard.Events; using Dashboard.Pal; @@ -23,13 +24,11 @@ namespace Dashboard.Controls Window.Title = _title ?? ""; } } - public Brush Background { get; set; } = new SolidColorBrush(Color.SlateGray); public Control? FocusedControl { get; private set; } = null; public override Box2d ClientArea { get => new Box2d(0, 0, Window.ClientSize.Width, Window.ClientSize.Height); - set { } } public event EventHandler? Closing; @@ -37,9 +36,18 @@ namespace Dashboard.Controls public Form(IWindow window) { Window = window; - window.Form = this; - + Window.Form = this; Window.Title = _title; + Window.EventRaised += WindowEventRaised; + Background = new SolidColorBrush(Color.SlateGray); + } + + private void WindowEventRaised(object? sender, EventArgs e) + { + if (e is ResizeEventArgs) + { + InvalidateLayout(); + } } public void Focus(Control control) @@ -65,6 +73,11 @@ namespace Dashboard.Controls if (Background is SolidColorBrush solidColorBrush) dcb.ClearColor(solidColorBrush.Color); + if (!IsLayoutValid) + { + ValidateLayout(); + } + foreach (Control child in this) child.SendEvent(this, new PaintEventArgs(dc)); diff --git a/Dashboard/Controls/Label.cs b/Dashboard/Controls/Label.cs index d57d191..5c0a7c2 100644 --- a/Dashboard/Controls/Label.cs +++ b/Dashboard/Controls/Label.cs @@ -29,9 +29,7 @@ namespace Dashboard.Controls protected void CalculateSize(DeviceContext dc) { Box2d box = dc.ExtensionRequire().MeasureText(Font.Base, TextSize, Text); - // _intrinsicSize = box.Size; - // Layout.Size = box.Size; - // ClientArea = new Box2d(ClientArea.Min, ClientArea.Min + Layout.Size); + _intrinsicSize = box.Size; } public override void OnPaint(DeviceContext dc) diff --git a/Dashboard/Controls/MessageBox.cs b/Dashboard/Controls/MessageBox.cs index 10f1e40..920cf27 100644 --- a/Dashboard/Controls/MessageBox.cs +++ b/Dashboard/Controls/MessageBox.cs @@ -2,8 +2,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; -using System.Collections.Specialized; +using System.Drawing; using System.IO; +using System.Numerics; using System.Reflection; using Dashboard.Drawing; using Dashboard.Windowing; @@ -36,12 +37,11 @@ namespace Dashboard.Controls /// public class MessageBox : Form { - private MessageBoxIcon _icon; private MessageBoxButtons _buttons; - private ImageBox _iconBox = new ImageBox(); - private Label _label = new Label(); - private Container _main = new Container(); - private Container _buttonsContainer = new Container(); + private readonly ImageBox _iconBox = new ImageBox(); + private readonly Label _label = new Label(); + private readonly Container _main = new Container(); + private readonly Container _buttonsContainer = new Container(); private Image? IconImage { @@ -51,7 +51,7 @@ namespace Dashboard.Controls public MessageBoxIcon Icon { - get => _icon; + get; set { IconImage = value switch @@ -63,7 +63,7 @@ namespace Dashboard.Controls _ => null, }; - _icon = value; + field = value; } } @@ -82,7 +82,7 @@ namespace Dashboard.Controls public string? Message { get => _label.Text; - set => _label.Text = value ?? String.Empty; + set => _label.Text = value ?? string.Empty; } public MessageBoxButtons Buttons @@ -99,21 +99,24 @@ namespace Dashboard.Controls public MessageBox(IWindow window) : base(window) { - // Layout.Rows.Clear(); - // Layout.Rows.Add(-1); - // Layout.Rows.Add(48); - // - // Add(_main); - // _main.Layout.Columns.Clear(); - // _main.Layout.Columns.Add(48); - // _main.Layout.Columns.Add(-1); + Add(_main); + _main.DisplayMode = Dashboard.Layout.DisplayMode.Grow; + _main.Size = Vector2.One; + _main.FlowDirection = Dashboard.Layout.FlowDirection.Row; + _main.Padding = new Extents(4f); _main.Add(_iconBox); + _iconBox.Size = new Vector2(72f); + _iconBox.Margin = new Extents(0f, 4f, 2f, 0f); + _iconBox.Background = new SolidColorBrush(Color.Purple); + _main.Add(_label); - _label.Layout.Column = 1; + _label.DisplayMode = Dashboard.Layout.DisplayMode.Fit; + _iconBox.Margin = new Extents(2f, 4f, 0f, 0f); + _iconBox.Background = new SolidColorBrush(Color.Black); Add(_buttonsContainer); - _buttonsContainer.Layout.Row = 1; + _buttonsContainer.Padding = new Extents(2f, 4f, 2f, 4f); CustomButtons.CollectionChanged += (sender, ea) => UpdateButtons(); @@ -139,19 +142,19 @@ namespace Dashboard.Controls _ => s_ok, }; - // _buttonsContainer.Clear(); - // _buttonsContainer.Layout.Columns.Clear(); - // for (int i = 0; i < list.Count; i++) - // { - // _buttonsContainer.Layout.Columns.Add(-1); - // string str = list[i]; - // - // Button button = new Button() { Text = str }; - // button.Clicked += (sender, ea) => ButtonClicked(sender, ea, i); - // button.Layout.Column = i; - // _buttonsContainer.Add(button); - // Add(button); - // } + _buttonsContainer.Clear(); + for (int i = 0; i < list.Count; i++) + { + string str = list[i]; + + Button button = new Button() { Text = str }; + button.Clicked += (sender, ea) => ButtonClicked(sender, ea, i); + button.Layout.Margin = new Extents(2f, 0f, 2f, 0f); + // button.Layout.Column = i; + _buttonsContainer.Add(button); + button.Background = new SolidColorBrush(Color.Red); + // Add(button); + } } private void ButtonClicked(object? sender, EventArgs ea, int i) diff --git a/tests/Dashboard.TestApplication/Program.cs b/tests/Dashboard.TestApplication/Program.cs index fddfc53..6a739ec 100644 --- a/tests/Dashboard.TestApplication/Program.cs +++ b/tests/Dashboard.TestApplication/Program.cs @@ -3,15 +3,14 @@ using Dashboard.BlurgText; using Dashboard.BlurgText.OpenGL; using Dashboard.Controls; using Dashboard.Drawing; -using Dashboard.Events; using Dashboard.OpenGL; using Dashboard.OpenTK.PAL2; using Dashboard.Pal; using Dashboard.StbImage; -using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; using OpenTK.Platform; using TK = OpenTK.Platform.Toolkit; + Application app = new Pal2Application(new ToolkitOptions() { ApplicationName = "DashTerm", @@ -57,59 +56,16 @@ window.Title = "DashTerm"; TK.Window.SetMinClientSize(window.WindowHandle, 300, 200); TK.Window.SetClientSize(window.WindowHandle, new Vector2i(320, 240)); TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder); -// TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f); GLDeviceContext context = (GLDeviceContext)window.DeviceContext; context.GLContext.MakeCurrent(); context.GLContext.SwapGroup.SwapInterval = 1; -GL.Disable(EnableCap.DepthTest); -GL.Enable(EnableCap.Blend); -GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); -GL.ColorMask(true, true, true, true); - TK.Window.SetMode(window.WindowHandle, WindowMode.Normal); window.DeviceContext.ExtensionRequire().ScaleOverride = 1.5f; -IDirectRendering direct = window.DeviceContext.ExtensionRequire(); -IImmediateMode imm = window.DeviceContext.ExtensionRequire(); -ImmediateVertex[] vertices = new ImmediateVertex[] -{ // x, y, z, r, g, b, a - new ImmediateVertex(new System.Numerics.Vector3(-0.5f, -0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(1, 0, 0, 1)), - new ImmediateVertex(new System.Numerics.Vector3(+0.5f, -0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(0, 1, 0, 1)), - new ImmediateVertex(new System.Numerics.Vector3(+0.0f, +0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(0, 0, 1, 1)), -}; - - -window.EventRaised += (sender, eventArgs) => -{ - if (eventArgs is not PaintEventArgs paint) - return; - - // window.DeviceContext.Begin(); - var dcb = window.DeviceContext.ExtensionRequire(); - dcb.ResetTransforms(); - dcb.ClearDepth(); - - imm.Rectangle( - new Dashboard.Box2d( - new System.Numerics.Vector2(30, 30), - new System.Numerics.Vector2(140, 110)), - 0.2f, - new System.Numerics.Vector4(1, 1, 0, 1)); - imm.Line( - new System.Numerics.Vector2(180, 40), - new System.Numerics.Vector2(290, 180), - 6, - 0.2f, - new System.Numerics.Vector4(0, 1, 1, 1)); - imm.DrawImmediate(new ImmediateDrawCall(MeshPrimitive.Triangle, vertices.AsMemory())); - - // window.DeviceContext.End(); -}; - app.Run(true, source.Token);