diff --git a/TLD.sln b/TLD.sln index a779c60..be4f9f0 100644 --- a/TLD.sln +++ b/TLD.sln @@ -2,7 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI", "src\TUI\TUI.csproj", "{F92C03F7-2A65-4D0A-9736-13E749AF6903}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI.Tests", "tests\WIdgets\TUI.Tests\TUI.Tests.csproj", "{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI.Engine.Tests", "tests\TUI.Engine.Tests\TUI.Engine.Tests.csproj", "{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI.Engine", "src\TUI.Engine\TUI.Engine.csproj", "{38E7E2DD-40C1-4B7C-9A7A-E3677AD55431}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -22,5 +24,9 @@ Global {2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Release|Any CPU.Build.0 = Release|Any CPU + {38E7E2DD-40C1-4B7C-9A7A-E3677AD55431}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38E7E2DD-40C1-4B7C-9A7A-E3677AD55431}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38E7E2DD-40C1-4B7C-9A7A-E3677AD55431}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38E7E2DD-40C1-4B7C-9A7A-E3677AD55431}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Dashboard/Dashboard.csproj b/src/Dashboard/Dashboard.csproj deleted file mode 100644 index 2b14c81..0000000 --- a/src/Dashboard/Dashboard.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - net7.0 - enable - enable - - - diff --git a/src/Dashboard/Program.cs b/src/Dashboard/Program.cs deleted file mode 100644 index c462094..0000000 --- a/src/Dashboard/Program.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Dashboard; - -class Program -{ - static void Main(string[] args) - { - Console.WriteLine("Hello, World!"); - } -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Alignments/Alignment.cs b/src/TUI.Engine/Attributes/Alignments/Alignment.cs similarity index 55% rename from src/TUI/Engine/Nodes/Attributes/Alignments/Alignment.cs rename to src/TUI.Engine/Attributes/Alignments/Alignment.cs index 1ddb95c..ffa9430 100644 --- a/src/TUI/Engine/Nodes/Attributes/Alignments/Alignment.cs +++ b/src/TUI.Engine/Attributes/Alignments/Alignment.cs @@ -1,3 +1,3 @@ -namespace TUI.Engine.Nodes.Attributes.Alignments; +namespace TUI.Engine.Attributes.Alignments; public record Alignment(Horizontal Horizontal, Vertical Vertical); \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Alignments/Horizontal.cs b/src/TUI.Engine/Attributes/Alignments/Horizontal.cs similarity index 58% rename from src/TUI/Engine/Nodes/Attributes/Alignments/Horizontal.cs rename to src/TUI.Engine/Attributes/Alignments/Horizontal.cs index cbc839a..10e010d 100644 --- a/src/TUI/Engine/Nodes/Attributes/Alignments/Horizontal.cs +++ b/src/TUI.Engine/Attributes/Alignments/Horizontal.cs @@ -1,4 +1,4 @@ -namespace TUI.Engine.Nodes.Attributes.Alignments; +namespace TUI.Engine.Attributes.Alignments; public enum Horizontal { diff --git a/src/TUI.Engine/Attributes/Alignments/IWithAlignment.cs b/src/TUI.Engine/Attributes/Alignments/IWithAlignment.cs new file mode 100644 index 0000000..b8272e5 --- /dev/null +++ b/src/TUI.Engine/Attributes/Alignments/IWithAlignment.cs @@ -0,0 +1,10 @@ +namespace TUI.Engine.Attributes.Alignments; + +public interface IWithAlignment +{ + internal Alignment Alignment { get; } + + void SetAlignment(Vertical vertical); + + void SetAlignment(Horizontal horizontal); +} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Alignments/Vertical.cs b/src/TUI.Engine/Attributes/Alignments/Vertical.cs similarity index 52% rename from src/TUI/Engine/Nodes/Attributes/Alignments/Vertical.cs rename to src/TUI.Engine/Attributes/Alignments/Vertical.cs index f03c6fa..9c26c2d 100644 --- a/src/TUI/Engine/Nodes/Attributes/Alignments/Vertical.cs +++ b/src/TUI.Engine/Attributes/Alignments/Vertical.cs @@ -1,4 +1,4 @@ -namespace TUI.Engine.Nodes.Attributes.Alignments; +namespace TUI.Engine.Attributes.Alignments; public enum Vertical { diff --git a/src/TUI.Engine/Attributes/Orientations/IWithOrientation.cs b/src/TUI.Engine/Attributes/Orientations/IWithOrientation.cs new file mode 100644 index 0000000..1d6f5e9 --- /dev/null +++ b/src/TUI.Engine/Attributes/Orientations/IWithOrientation.cs @@ -0,0 +1,9 @@ +namespace TUI.Engine.Attributes.Orientations; + +public interface IWithOrientation +{ + internal Orientation Orientation { get; } + + public void SetOrientationHorizontal(); + public void SetOrientationVertical(); +} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Orientations/Orientation.cs b/src/TUI.Engine/Attributes/Orientations/Orientation.cs similarity index 51% rename from src/TUI/Engine/Nodes/Attributes/Orientations/Orientation.cs rename to src/TUI.Engine/Attributes/Orientations/Orientation.cs index 16b8b41..66f3a1f 100644 --- a/src/TUI/Engine/Nodes/Attributes/Orientations/Orientation.cs +++ b/src/TUI.Engine/Attributes/Orientations/Orientation.cs @@ -1,4 +1,4 @@ -namespace TUI.Engine.Nodes.Attributes.Orientations; +namespace TUI.Engine.Attributes.Orientations; public enum Orientation { diff --git a/src/TUI/Engine/Nodes/Attributes/Paddings/IPaddingable.cs b/src/TUI.Engine/Attributes/Paddings/IWithPadding.cs similarity index 75% rename from src/TUI/Engine/Nodes/Attributes/Paddings/IPaddingable.cs rename to src/TUI.Engine/Attributes/Paddings/IWithPadding.cs index b100181..453ea7e 100644 --- a/src/TUI/Engine/Nodes/Attributes/Paddings/IPaddingable.cs +++ b/src/TUI.Engine/Attributes/Paddings/IWithPadding.cs @@ -1,8 +1,8 @@ using TUI.Engine.Theme; -namespace TUI.Engine.Nodes.Attributes.Paddings; +namespace TUI.Engine.Attributes.Paddings; -public interface IPaddingable +public interface IWithPadding { Padding Padding { get; } diff --git a/src/TUI/Engine/Nodes/Attributes/Paddings/Padding.cs b/src/TUI.Engine/Attributes/Paddings/Padding.cs similarity index 85% rename from src/TUI/Engine/Nodes/Attributes/Paddings/Padding.cs rename to src/TUI.Engine/Attributes/Paddings/Padding.cs index 0efbea8..ac97f6e 100644 --- a/src/TUI/Engine/Nodes/Attributes/Paddings/Padding.cs +++ b/src/TUI.Engine/Attributes/Paddings/Padding.cs @@ -1,6 +1,6 @@ using TUI.Engine.Theme; -namespace TUI.Engine.Nodes.Attributes.Paddings; +namespace TUI.Engine.Attributes.Paddings; public record Padding( Level Left = Level.None, diff --git a/src/TUI.Engine/Attributes/Resizings/IResizable.cs b/src/TUI.Engine/Attributes/Resizings/IResizable.cs new file mode 100644 index 0000000..2e28b18 --- /dev/null +++ b/src/TUI.Engine/Attributes/Resizings/IResizable.cs @@ -0,0 +1,16 @@ +using TUI.Engine.Attributes.Orientations; + +namespace TUI.Engine.Attributes.Resizings; + +public interface IResizable +{ + internal Resizing ResizingHorizontal { get; } + + internal Resizing ResizingVertical { get; } + + internal Size GetFixedSize(); + + void SetAdaptive(Orientation orientation); + + void SetFixed(Orientation orientation, int value); +} \ No newline at end of file diff --git a/src/TUI.Engine/Attributes/Resizings/Resizing.cs b/src/TUI.Engine/Attributes/Resizings/Resizing.cs new file mode 100644 index 0000000..163ac95 --- /dev/null +++ b/src/TUI.Engine/Attributes/Resizings/Resizing.cs @@ -0,0 +1,7 @@ +namespace TUI.Engine.Attributes.Resizings; + +public enum Resizing +{ + Adaptive, + Fixed +} \ No newline at end of file diff --git a/src/TUI.Engine/Attributes/Resizings/ResizingExtensions.cs b/src/TUI.Engine/Attributes/Resizings/ResizingExtensions.cs new file mode 100644 index 0000000..e502342 --- /dev/null +++ b/src/TUI.Engine/Attributes/Resizings/ResizingExtensions.cs @@ -0,0 +1,58 @@ +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Containers; + +namespace TUI.Engine.Attributes.Resizings; + +internal static class ResizingExtensions +{ + internal static int GetHeight(this IResizable node, IContainer container, int maxHeight, int nodeIndex) + { + if (node.ResizingVertical == Resizing.Fixed) + { + return node.GetFixedSize().Height; + } + + if (container.Orientation == Orientation.Horizontal) + { + return maxHeight; + } + + var fixedNodes = container.GetFixedNodes().ToArray(); + + var fixedHeight = fixedNodes.Sum(s => s.GetFixedSize().Height); + var allowableHeight = maxHeight - fixedHeight; + + var allowableCount = container.GetNodes().Count - fixedNodes.Length; + var nodeHeight = (allowableHeight / allowableCount).Min(1); + var nodeNumber = nodeIndex + 1 - container.GetFixedNodes(nodeIndex).Sum(c => c.GetFixedSize().Height); + + if (allowableHeight - nodeNumber * nodeHeight < nodeHeight) + { + return allowableHeight + nodeHeight - nodeNumber * nodeHeight; + } + + return nodeHeight; + } + + internal static int GetWidth(this IResizable node, IContainer container, int maxWidth) + { + if (node.ResizingHorizontal == Resizing.Fixed) + { + return node.GetFixedSize().Width; + } + + if (container.Orientation == Orientation.Vertical) + { + return maxWidth; + } + + var fixedNodes = container + .GetNodes() + .Where(n => n.ResizingHorizontal == Resizing.Fixed).ToArray(); + + var allowableWidth = maxWidth - fixedNodes.Sum(s => s.GetFixedSize().Width); + var allowableCount = container.GetNodes().Count - fixedNodes.Length; + + return allowableWidth / allowableCount; + } +} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Size.cs b/src/TUI.Engine/Attributes/Size.cs similarity index 79% rename from src/TUI/Engine/Nodes/Attributes/Size.cs rename to src/TUI.Engine/Attributes/Size.cs index 4848283..6f74084 100644 --- a/src/TUI/Engine/Nodes/Attributes/Size.cs +++ b/src/TUI.Engine/Attributes/Size.cs @@ -1,4 +1,6 @@ -namespace TUI.Engine.Nodes.Attributes; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Attributes; public readonly record struct Size(int Width, int Height) { diff --git a/src/TUI.Engine/Components/ComponentAttribute.cs b/src/TUI.Engine/Components/ComponentAttribute.cs new file mode 100644 index 0000000..949c8cc --- /dev/null +++ b/src/TUI.Engine/Components/ComponentAttribute.cs @@ -0,0 +1,50 @@ +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Attributes.Paddings; +using TUI.Engine.Nodes; +using TUI.Engine.Theme; + +namespace TUI.Engine.Components; + +public abstract class ComponentAttribute : NodeBase, IComponent +{ + protected abstract Sketch DrawComponent(); + + Sketch IComponent.MakeSketch() => DrawComponent(); + + #region Alignments + + internal Alignment Alignment { get; private set; } = new(Defaults.HorizontalAlignment, Defaults.VerticalAlignment); + + Alignment IWithAlignment.Alignment => Alignment; + + public void SetAlignment(Vertical vertical) + { + Alignment = Alignment with { Vertical = vertical }; + } + + public void SetAlignment(Horizontal horizontal) + { + Alignment = Alignment with { Horizontal = horizontal }; + } + + #endregion + + #region Paddings + + internal Padding Padding { get; private set; } = new(Defaults.Padding); + + + Padding IWithPadding.Padding => Padding; + + public void SetPadding(Level level) => Padding = new Padding(level); + + public void SetPaddingTop(Level level) => Padding = Padding with { Top = level }; + + public void SetPaddingRight(Level level) => Padding = Padding with { Right = level }; + + public void SetPaddingBottom(Level level) => Padding = Padding with { Bottom = level }; + + public void SetPaddingLeft(Level level) => Padding = Padding with { Left = level }; + + #endregion +} \ No newline at end of file diff --git a/src/TUI.Engine/Components/ComponentExtensions.cs b/src/TUI.Engine/Components/ComponentExtensions.cs new file mode 100644 index 0000000..6c5e4ca --- /dev/null +++ b/src/TUI.Engine/Components/ComponentExtensions.cs @@ -0,0 +1,40 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Components; + +internal static class ComponentExtensions +{ + internal static Position CorrectContentPosition(this IComponent component, + Position pencil, + Size maxSize, + Size sketchSize) + { + var padding = component.Padding; + var alignment = component.Alignment; + var alignmentCompensationLeft = GetAlignmentCompensationLeft(alignment.Horizontal, maxSize, sketchSize); + var alignmentCompensationTop = GetAlignmentCompensationTop(alignment.Vertical, maxSize, sketchSize); + var left = pencil.Left + (int)padding.Left + alignmentCompensationLeft; + var top = pencil.Top + (int)padding.Top + alignmentCompensationTop; + return new Position(left, top); + } + + private static int GetAlignmentCompensationLeft(Horizontal alignment, Size maxSize, Size sketchSize) => + alignment switch + { + Horizontal.Left => 0, + Horizontal.Center => (maxSize.Width - sketchSize.Width) / 2, + Horizontal.Right => maxSize.Width - sketchSize.Width, + _ => 0 + }; + + private static int GetAlignmentCompensationTop(Vertical alignment, Size maxSize, Size sketchSize) => + alignment switch + { + Vertical.Top => 0, + Vertical.Center => (maxSize.Height - sketchSize.Height) / 2, + Vertical.Bottom => maxSize.Height - sketchSize.Height, + _ => 0 + }; +} \ No newline at end of file diff --git a/src/TUI.Engine/Components/IComponent.cs b/src/TUI.Engine/Components/IComponent.cs new file mode 100644 index 0000000..b990aca --- /dev/null +++ b/src/TUI.Engine/Components/IComponent.cs @@ -0,0 +1,10 @@ +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Attributes.Paddings; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Components; + +public interface IComponent : INode, IWithAlignment, IWithPadding +{ + internal Sketch MakeSketch(); +} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Components/Sketch.cs b/src/TUI.Engine/Components/Sketch.cs similarity index 92% rename from src/TUI/Engine/Nodes/Components/Sketch.cs rename to src/TUI.Engine/Components/Sketch.cs index d2c02a5..6cd7da4 100644 --- a/src/TUI/Engine/Nodes/Components/Sketch.cs +++ b/src/TUI.Engine/Components/Sketch.cs @@ -1,6 +1,6 @@ -using TUI.Engine.Nodes.Attributes; +using TUI.Engine.Attributes; -namespace TUI.Engine.Nodes.Components; +namespace TUI.Engine.Components; public sealed class Sketch : IEnumerable { diff --git a/src/TUI/Engine/Nodes/Components/ComponentStaticBase.cs b/src/TUI.Engine/Components/StaticComponentAttribute.cs similarity index 70% rename from src/TUI/Engine/Nodes/Components/ComponentStaticBase.cs rename to src/TUI.Engine/Components/StaticComponentAttribute.cs index 15cc414..50c4b24 100644 --- a/src/TUI/Engine/Nodes/Components/ComponentStaticBase.cs +++ b/src/TUI.Engine/Components/StaticComponentAttribute.cs @@ -1,14 +1,14 @@ using System.Text; -namespace TUI.Engine.Nodes.Components; +namespace TUI.Engine.Components; -public abstract class ComponentStaticBase : ComponentBase +public abstract class StaticComponentAttribute : ComponentAttribute { private Sketch? _cache; protected abstract void RenderWithCache(StringBuilder builder); - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { if (_cache is not null) { @@ -16,7 +16,9 @@ public abstract class ComponentStaticBase : ComponentBase } var builder = new StringBuilder(); + RenderWithCache(builder); + _cache = new Sketch(builder.ToString()); return _cache; diff --git a/src/TUI.Engine/Containers/ContainerBase.cs b/src/TUI.Engine/Containers/ContainerBase.cs new file mode 100644 index 0000000..e2b5141 --- /dev/null +++ b/src/TUI.Engine/Containers/ContainerBase.cs @@ -0,0 +1,24 @@ +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Nodes; +using TUI.Engine.Theme; + +namespace TUI.Engine.Containers; + +public abstract class ContainerBase : NodeBase, IContainer +{ + private Orientation _orientation = Defaults.Orientation; + + Orientation IWithOrientation.Orientation => _orientation; + + public void SetOrientationHorizontal() + { + _orientation = Orientation.Horizontal; + } + + public void SetOrientationVertical() + { + _orientation = Orientation.Vertical; + } + + public abstract Nodes.Nodes GetNodes(); +} \ No newline at end of file diff --git a/src/TUI.Engine/Containers/ContainerExtensions.cs b/src/TUI.Engine/Containers/ContainerExtensions.cs new file mode 100644 index 0000000..3b6eb36 --- /dev/null +++ b/src/TUI.Engine/Containers/ContainerExtensions.cs @@ -0,0 +1,22 @@ +using TUI.Engine.Attributes.Resizings; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Containers; + +internal static class ContainerExtensions +{ + internal static IEnumerable GetFixedNodes(this IContainer container, int? takeNodeNumber = null) + { + if (takeNodeNumber is not null) + { + return container + .GetNodes() + .Take(takeNodeNumber.Value + 1) + .Where(n => n.ResizingVertical == Resizing.Fixed); + } + + return container + .GetNodes() + .Where(n => n.ResizingVertical == Resizing.Fixed); + } +} \ No newline at end of file diff --git a/src/TUI.Engine/Containers/IContainer.cs b/src/TUI.Engine/Containers/IContainer.cs new file mode 100644 index 0000000..b195750 --- /dev/null +++ b/src/TUI.Engine/Containers/IContainer.cs @@ -0,0 +1,9 @@ +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Containers; + +public interface IContainer : INode, IWithOrientation +{ + public Nodes.Nodes GetNodes(); +} \ No newline at end of file diff --git a/src/TUI/Extensions.cs b/src/TUI.Engine/Extensions.cs similarity index 81% rename from src/TUI/Extensions.cs rename to src/TUI.Engine/Extensions.cs index 6da3e2f..b54b99b 100644 --- a/src/TUI/Extensions.cs +++ b/src/TUI.Engine/Extensions.cs @@ -1,11 +1,20 @@ using System.Globalization; using System.Text.RegularExpressions; - -namespace TUI; +namespace TUI.Engine; public static class Extensions { + public static int Max(this int value, int maxValue) + { + return value <= maxValue ? value : maxValue; + } + + public static int Min(this int value, int minValue) + { + return value > minValue ? value : minValue; + } + public static bool Have(this IEnumerable array, string findValue) { return array.Any(item => item == findValue); diff --git a/src/TUI/Engine/Helper.cs b/src/TUI.Engine/Helper.cs similarity index 89% rename from src/TUI/Engine/Helper.cs rename to src/TUI.Engine/Helper.cs index 2217059..8a73f30 100644 --- a/src/TUI/Engine/Helper.cs +++ b/src/TUI.Engine/Helper.cs @@ -1,6 +1,9 @@ +using System.Runtime.CompilerServices; using Pastel; +using TUI.Engine.Attributes; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; + +[assembly:InternalsVisibleTo("TUI.Engine.Tests", AllInternalsVisible = true)] namespace TUI.Engine; diff --git a/src/TUI/Engine/Nodes/INode.cs b/src/TUI.Engine/Nodes/INode.cs similarity index 60% rename from src/TUI/Engine/Nodes/INode.cs rename to src/TUI.Engine/Nodes/INode.cs index efbdfd7..6bdfb87 100644 --- a/src/TUI/Engine/Nodes/INode.cs +++ b/src/TUI.Engine/Nodes/INode.cs @@ -1,4 +1,4 @@ -using TUI.Engine.Nodes.Attributes.Resizing; +using TUI.Engine.Attributes.Resizings; namespace TUI.Engine.Nodes; diff --git a/src/TUI/Engine/Nodes/NodeBase.cs b/src/TUI.Engine/Nodes/NodeBase.cs similarity index 70% rename from src/TUI/Engine/Nodes/NodeBase.cs rename to src/TUI.Engine/Nodes/NodeBase.cs index ec121ef..bb28979 100644 --- a/src/TUI/Engine/Nodes/NodeBase.cs +++ b/src/TUI.Engine/Nodes/NodeBase.cs @@ -1,6 +1,7 @@ -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Nodes.Attributes.Resizing; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Attributes.Resizings; +using TUI.Engine.Theme; namespace TUI.Engine.Nodes; @@ -9,12 +10,17 @@ public abstract class NodeBase : INode private int _fixedWidth; private int _fixedHeight; - public Size GetFixedSize() => new(_fixedWidth, _fixedHeight); + Size IResizable.GetFixedSize() => new(_fixedWidth, _fixedHeight); #region Resizing - public Resizing ResizingHorizontal { get; private set; } = Resizing.Adaptive; - public Resizing ResizingVertical { get; private set; } = Resizing.Adaptive; + private Resizing ResizingHorizontal { get; set; } = Defaults.HorizontalResizing; + + Resizing IResizable.ResizingHorizontal => ResizingHorizontal; + + private Resizing ResizingVertical { get; set; } = Defaults.VerticalResizing; + + Resizing IResizable.ResizingVertical => ResizingVertical; public void SetAdaptive(Orientation orientation) { diff --git a/src/TUI.Engine/Nodes/NodeExtensions.cs b/src/TUI.Engine/Nodes/NodeExtensions.cs new file mode 100644 index 0000000..efdb506 --- /dev/null +++ b/src/TUI.Engine/Nodes/NodeExtensions.cs @@ -0,0 +1,15 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Resizings; +using TUI.Engine.Containers; + +namespace TUI.Engine.Nodes; + +internal static class NodeExtensions +{ + internal static Size GetSize(this INode node, IContainer parentContainer, int nodeNumber, Size allowableSize) + { + var width = node.GetWidth(parentContainer, allowableSize.Width); + var height = node.GetHeight(parentContainer, allowableSize.Height, nodeNumber); + return new Size(width, height); + } +} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Nodes.cs b/src/TUI.Engine/Nodes/Nodes.cs similarity index 100% rename from src/TUI/Engine/Nodes/Nodes.cs rename to src/TUI.Engine/Nodes/Nodes.cs diff --git a/src/TUI/Engine/Nodes/Position.cs b/src/TUI.Engine/Nodes/Position.cs similarity index 98% rename from src/TUI/Engine/Nodes/Position.cs rename to src/TUI.Engine/Nodes/Position.cs index edaa9d8..bc566d2 100644 --- a/src/TUI/Engine/Nodes/Position.cs +++ b/src/TUI.Engine/Nodes/Position.cs @@ -3,5 +3,6 @@ namespace TUI.Engine.Nodes; public record Position(int Left, int Top) { public static readonly Position Default = new(0, 0); + public override string ToString() => $"L[{Left}] T[{Top}]"; } \ No newline at end of file diff --git a/src/TUI.Engine/Rendering/Canvas/ConsoleCanvas.cs b/src/TUI.Engine/Rendering/Canvas/ConsoleCanvas.cs new file mode 100644 index 0000000..9313148 --- /dev/null +++ b/src/TUI.Engine/Rendering/Canvas/ConsoleCanvas.cs @@ -0,0 +1,35 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Rendering.Canvas; + +public class ConsoleCanvas : ICanvas +{ + private readonly DrawCraftsman _drawCraftsman; + + public Size Size { get; } = new(Console.WindowWidth, Console.WindowHeight); + + public ConsoleCanvas() + { + var componentCraftsman = new ComponentCraftsman(this); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + _drawCraftsman = new DrawCraftsman(componentCraftsman, containerCraftsman); + } + + public void SetPencil(Position pencilPosition) + { + Console.SetCursorPosition(pencilPosition.Left, pencilPosition.Top); + } + + public void Paint(string value) => Console.Write(value); + + public void Draw(INode node) + { + _drawCraftsman.Draw(node, Position.Default, Size); + } + + public void Draw(INode node, Position pencil, Size maxSize) + { + _drawCraftsman.Draw(node, pencil, maxSize); + } +} \ No newline at end of file diff --git a/src/TUI.Engine/Rendering/Canvas/ICanvas.cs b/src/TUI.Engine/Rendering/Canvas/ICanvas.cs new file mode 100644 index 0000000..efe3efe --- /dev/null +++ b/src/TUI.Engine/Rendering/Canvas/ICanvas.cs @@ -0,0 +1,17 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Rendering.Canvas; + +public interface ICanvas +{ + Size Size { get; } + + void SetPencil(Position pencilPosition); + + void Paint(string value); + + void Draw(INode node); + + void Draw(INode node, Position pencil, Size maxSize); +} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/ComponentCraftsman.cs b/src/TUI.Engine/Rendering/ComponentCraftsman.cs similarity index 64% rename from src/TUI/Engine/Rendering/ComponentCraftsman.cs rename to src/TUI.Engine/Rendering/ComponentCraftsman.cs index 27e293c..6d03a26 100644 --- a/src/TUI/Engine/Rendering/ComponentCraftsman.cs +++ b/src/TUI.Engine/Rendering/ComponentCraftsman.cs @@ -1,11 +1,11 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Components; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Nodes.Containers; +using TUI.Engine.Rendering.Canvas; namespace TUI.Engine.Rendering; -public sealed class ComponentCraftsman : CraftsmanBase, IDrawable +internal sealed class ComponentCraftsman : CraftsmanBase, IDrawable { private readonly ICanvas _canvas; @@ -19,13 +19,13 @@ public sealed class ComponentCraftsman : CraftsmanBase, IDrawable var sketch = component.MakeSketch(); var sketchSize = sketch.GetSize(); - var correctedPencil = component.CorrectPosition(pencil, maxSize, sketchSize); + var correctedPencil = component.CorrectContentPosition(pencil, maxSize, sketchSize); Debug(pencil, maxSize); foreach (var line in sketch.Crop(maxSize)) { - _canvas.SetPencil(correctedPencil.Left, correctedPencil.Top); + _canvas.SetPencil(correctedPencil); _canvas.Paint(line); correctedPencil = correctedPencil with { Top = correctedPencil.Top + 1 }; diff --git a/src/TUI/Engine/Rendering/ContainerCraftsman.cs b/src/TUI.Engine/Rendering/ContainerCraftsman.cs similarity index 90% rename from src/TUI/Engine/Rendering/ContainerCraftsman.cs rename to src/TUI.Engine/Rendering/ContainerCraftsman.cs index 7999ad0..22d139c 100644 --- a/src/TUI/Engine/Rendering/ContainerCraftsman.cs +++ b/src/TUI.Engine/Rendering/ContainerCraftsman.cs @@ -1,13 +1,13 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Attributes.Resizings; +using TUI.Engine.Components; +using TUI.Engine.Containers; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Nodes.Attributes.Resizing; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Nodes.Containers; namespace TUI.Engine.Rendering; -public sealed class ContainerCraftsman : CraftsmanBase, IDrawable +internal sealed class ContainerCraftsman : CraftsmanBase, IDrawable { private readonly IDrawable _componentCraftsman; diff --git a/src/TUI/Engine/Rendering/CraftsmanBase.cs b/src/TUI.Engine/Rendering/CraftsmanBase.cs similarity index 90% rename from src/TUI/Engine/Rendering/CraftsmanBase.cs rename to src/TUI.Engine/Rendering/CraftsmanBase.cs index 6c50bf9..a411d86 100644 --- a/src/TUI/Engine/Rendering/CraftsmanBase.cs +++ b/src/TUI.Engine/Rendering/CraftsmanBase.cs @@ -1,6 +1,6 @@ using System.Diagnostics; +using TUI.Engine.Attributes; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; namespace TUI.Engine.Rendering; diff --git a/src/TUI/Engine/Rendering/IDrawable.cs b/src/TUI.Engine/Rendering/IDrawable.cs similarity index 82% rename from src/TUI/Engine/Rendering/IDrawable.cs rename to src/TUI.Engine/Rendering/IDrawable.cs index 05ae2bc..dcf7ff0 100644 --- a/src/TUI/Engine/Rendering/IDrawable.cs +++ b/src/TUI.Engine/Rendering/IDrawable.cs @@ -1,5 +1,5 @@ +using TUI.Engine.Attributes; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; namespace TUI.Engine.Rendering; diff --git a/src/TUI/Engine/Rendering/NodeCraftsman.cs b/src/TUI.Engine/Rendering/NodeCraftsman.cs similarity index 77% rename from src/TUI/Engine/Rendering/NodeCraftsman.cs rename to src/TUI.Engine/Rendering/NodeCraftsman.cs index ec62349..ccce935 100644 --- a/src/TUI/Engine/Rendering/NodeCraftsman.cs +++ b/src/TUI.Engine/Rendering/NodeCraftsman.cs @@ -1,19 +1,16 @@ +using TUI.Engine.Attributes; +using TUI.Engine.Components; +using TUI.Engine.Containers; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Nodes.Containers; namespace TUI.Engine.Rendering; -/// -/// 🍀 -/// -public sealed class NodeCraftsman : IDrawable +internal sealed class DrawCraftsman : IDrawable { private readonly IDrawable _componentCraftsman; private readonly IDrawable _containerCraftsman; - public NodeCraftsman( + public DrawCraftsman( IDrawable componentCraftsman, IDrawable containerCraftsman) { diff --git a/src/TUI/Engine/Symbols.cs b/src/TUI.Engine/Symbols.cs similarity index 100% rename from src/TUI/Engine/Symbols.cs rename to src/TUI.Engine/Symbols.cs diff --git a/src/TUI.Engine/TUI.Engine.csproj b/src/TUI.Engine/TUI.Engine.csproj new file mode 100644 index 0000000..270ccf7 --- /dev/null +++ b/src/TUI.Engine/TUI.Engine.csproj @@ -0,0 +1,20 @@ + + + + net7.0 + enable + enable + + + + + + + <_Parameter1>$(MSBuildProjectName).Tests + + + <_Parameter1>Other.Assembly.Name + + + + diff --git a/src/TUI.Engine/Theme/Defaults.cs b/src/TUI.Engine/Theme/Defaults.cs new file mode 100644 index 0000000..b22e9d0 --- /dev/null +++ b/src/TUI.Engine/Theme/Defaults.cs @@ -0,0 +1,20 @@ +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Attributes.Resizings; + +namespace TUI.Engine.Theme; + +public static class Defaults +{ + public const Horizontal HorizontalAlignment = Horizontal.Center; + + public const Vertical VerticalAlignment = Vertical.Top; + + public const Level Padding = Level.None; + + public const Resizing HorizontalResizing = Resizing.Adaptive; + + public const Resizing VerticalResizing = Resizing.Adaptive; + + public const Orientation Orientation = TUI.Engine.Attributes.Orientations.Orientation.Horizontal; +} \ No newline at end of file diff --git a/src/TUI/Engine/Theme/Indentation.cs b/src/TUI.Engine/Theme/Indentation.cs similarity index 100% rename from src/TUI/Engine/Theme/Indentation.cs rename to src/TUI.Engine/Theme/Indentation.cs diff --git a/src/TUI/Engine/Theme/Level.cs b/src/TUI.Engine/Theme/Level.cs similarity index 100% rename from src/TUI/Engine/Theme/Level.cs rename to src/TUI.Engine/Theme/Level.cs diff --git a/src/TUI/Engine/Theme/Palette.cs b/src/TUI.Engine/Theme/Palette.cs similarity index 100% rename from src/TUI/Engine/Theme/Palette.cs rename to src/TUI.Engine/Theme/Palette.cs diff --git a/src/TUI/Components/Controls/CellsComponentBase.cs b/src/TUI/Components/Controls/CellsComponentAttribute.cs similarity index 68% rename from src/TUI/Components/Controls/CellsComponentBase.cs rename to src/TUI/Components/Controls/CellsComponentAttribute.cs index 86b26bc..de7f9b5 100644 --- a/src/TUI/Components/Controls/CellsComponentBase.cs +++ b/src/TUI/Components/Controls/CellsComponentAttribute.cs @@ -1,18 +1,18 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Components; namespace TUI.Components.Controls; -public class CellsComponentBase : ComponentBase, IComponent +public class CellsComponentAttribute : ComponentAttribute, IComponent { private const int MaxCellWidth = 10; private readonly IEnumerable _cells; - public CellsComponentBase(IEnumerable cells) + public CellsComponentAttribute(IEnumerable cells) { _cells = cells; } @@ -29,7 +29,7 @@ public class CellsComponentBase : ComponentBase, IComponent // base.Render(content, position, size); } - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { throw new NotImplementedException(); } diff --git a/src/TUI/Components/Controls/Copyright.cs b/src/TUI/Components/Controls/Copyright.cs index 0cd2d2a..c7d6e1b 100644 --- a/src/TUI/Components/Controls/Copyright.cs +++ b/src/TUI/Components/Controls/Copyright.cs @@ -1,11 +1,11 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; namespace TUI.Components.Controls; -public class Copyright : ComponentStaticBase +public class Copyright : StaticComponentAttribute { protected override void RenderWithCache(StringBuilder builder) { diff --git a/src/TUI/Components/Controls/Dashboard.cs b/src/TUI/Components/Controls/Dashboard.cs index 46f0dcf..b5eae7b 100644 --- a/src/TUI/Components/Controls/Dashboard.cs +++ b/src/TUI/Components/Controls/Dashboard.cs @@ -1,13 +1,13 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Components; using TUI.Engine.Theme; namespace TUI.Components.Controls; -public class Dashboard : ComponentBase, IComponent +public class Dashboard : ComponentAttribute, IComponent { private readonly string _title; @@ -61,7 +61,7 @@ public class Dashboard : ComponentBase, IComponent dashboardBuilder.Append(Symbols.Angles.RightBottom); } - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { throw new NotImplementedException(); } diff --git a/src/TUI/Components/Controls/HeaderContainer.cs b/src/TUI/Components/Controls/HeaderContainer.cs index 0a01794..cb8ceee 100644 --- a/src/TUI/Components/Controls/HeaderContainer.cs +++ b/src/TUI/Components/Controls/HeaderContainer.cs @@ -1,8 +1,8 @@ using TUI.Components.Controls.Statics; using TUI.Components.Controls.Statics.Hints; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Containers; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Containers; using TUI.Engine.Theme; namespace TUI.Components.Controls; diff --git a/src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs b/src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs index 31520d0..381defc 100644 --- a/src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs +++ b/src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs @@ -1,12 +1,12 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; using TUI.UserInterface; namespace TUI.Components.Controls.Statics.Hints; -public class AppTypeHints : ComponentStaticBase +public class AppTypeHints : StaticComponentAttribute { private readonly Dictionary _hints = new() { diff --git a/src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs b/src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs index 630177e..1d780b5 100644 --- a/src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs +++ b/src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs @@ -1,11 +1,11 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; namespace TUI.Components.Controls.Statics.Hints; -public class HotkeysHint : ComponentStaticBase +public class HotkeysHint : StaticComponentAttribute { private readonly Dictionary _hints = new() { diff --git a/src/TUI/Components/Controls/Statics/Hints/TagHints.cs b/src/TUI/Components/Controls/Statics/Hints/TagHints.cs index 54cb140..75680b7 100644 --- a/src/TUI/Components/Controls/Statics/Hints/TagHints.cs +++ b/src/TUI/Components/Controls/Statics/Hints/TagHints.cs @@ -1,12 +1,12 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; using TUI.UserInterface; namespace TUI.Components.Controls.Statics.Hints; -public class TagHints : ComponentStaticBase +public class TagHints : StaticComponentAttribute { private readonly Dictionary _hints = new() { diff --git a/src/TUI/Components/Controls/Statics/Hints/VersionHints.cs b/src/TUI/Components/Controls/Statics/Hints/VersionHints.cs index fa5f3fd..4237e18 100644 --- a/src/TUI/Components/Controls/Statics/Hints/VersionHints.cs +++ b/src/TUI/Components/Controls/Statics/Hints/VersionHints.cs @@ -1,11 +1,11 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; namespace TUI.Components.Controls.Statics.Hints; -public class VersionHints : ComponentStaticBase +public class VersionHints : StaticComponentAttribute { private readonly Dictionary _hints = new() { diff --git a/src/TUI/Components/Controls/Statics/Logo.cs b/src/TUI/Components/Controls/Statics/Logo.cs index 41c54b8..f63944e 100644 --- a/src/TUI/Components/Controls/Statics/Logo.cs +++ b/src/TUI/Components/Controls/Statics/Logo.cs @@ -1,11 +1,11 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; using TUI.Engine.Theme; namespace TUI.Components.Controls.Statics; -public class Logo : ComponentStaticBase +public class Logo : StaticComponentAttribute { protected override void RenderWithCache(StringBuilder builder) { diff --git a/src/TUI/Components/Controls/Tag.cs b/src/TUI/Components/Controls/Tag.cs index e7eca6e..8c8d443 100644 --- a/src/TUI/Components/Controls/Tag.cs +++ b/src/TUI/Components/Controls/Tag.cs @@ -1,23 +1,18 @@ using System.Text; using TUI.Engine; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Rendering; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Components; using TUI.Engine.Theme; using TUI.UserInterface; namespace TUI.Components.Controls; -public class Tag : ComponentBase +public class Tag : ComponentAttribute { private IEnumerable _tags; private string _gitType; - public Tag(NodeCraftsman drawEngine) - { - } - public void Bind(IEnumerable tags, string gitType) { _tags = tags; @@ -59,7 +54,7 @@ public class Tag : ComponentBase _ => Symbols.Git }; - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { throw new NotImplementedException(); } diff --git a/src/TUI/Components/Layouts/DashboardLayout.cs b/src/TUI/Components/Layouts/DashboardLayout.cs index b4fe8fc..0b1ff26 100644 --- a/src/TUI/Components/Layouts/DashboardLayout.cs +++ b/src/TUI/Components/Layouts/DashboardLayout.cs @@ -1,14 +1,18 @@ +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Components; +using TUI.Engine.Containers; using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Nodes.Attributes.Resizing; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Nodes.Containers; namespace TUI.Components.Layouts; public class DashboardLayout : ContainerBase, IContainer { - public new Orientation Orientation => Orientation.Vertical; + public DashboardLayout() + { + SetOrientationVertical(); + SetAdaptive(Orientation.Horizontal); + SetAdaptive(Orientation.Vertical); + } private INode _header; private INode _footer; @@ -35,8 +39,4 @@ public class DashboardLayout : ContainerBase, IContainer { throw new NotImplementedException(); } - - public Resizing ResizingHorizontal => Resizing.Adaptive; - - public Resizing ResizingVertical => Resizing.Adaptive; } \ No newline at end of file diff --git a/src/TUI/Components/Views/DependenciesView.cs b/src/TUI/Components/Views/DependenciesView.cs index 88c02b1..5ef6bdd 100644 --- a/src/TUI/Components/Views/DependenciesView.cs +++ b/src/TUI/Components/Views/DependenciesView.cs @@ -1,13 +1,13 @@ using TUI.Components.Controls; using TUI.Domain; using TUI.Engine; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Components; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Components; namespace TUI.Components.Views; -public class DependenciesView : ComponentBase, IComponent +public class DependenciesView : ComponentAttribute, IComponent { private const string ViewName = "Dependencies"; @@ -153,7 +153,7 @@ public class DependenciesView : ComponentBase, IComponent // { // _table.Previous(); // } - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { throw new NotImplementedException(); } diff --git a/src/TUI/Domain/Package.cs b/src/TUI/Domain/Package.cs index c56d4a3..b9d5519 100644 --- a/src/TUI/Domain/Package.cs +++ b/src/TUI/Domain/Package.cs @@ -1,5 +1,6 @@ using System.Text.Json.Nodes; using System.Text.Json.Serialization; +using TUI.Engine; namespace TUI.Domain; diff --git a/src/TUI/Engine/Nodes/Attributes/Alignments/IAlignable.cs b/src/TUI/Engine/Nodes/Attributes/Alignments/IAlignable.cs deleted file mode 100644 index 875408b..0000000 --- a/src/TUI/Engine/Nodes/Attributes/Alignments/IAlignable.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TUI.Engine.Nodes.Attributes.Alignments; - -public interface IAlignable -{ - Alignment Alignment { get; } - - void SetAlignment(Vertical vertical); - - void SetAlignment(Horizontal horizontal); -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Orientations/IWithOrientation.cs b/src/TUI/Engine/Nodes/Attributes/Orientations/IWithOrientation.cs deleted file mode 100644 index 2d5fda9..0000000 --- a/src/TUI/Engine/Nodes/Attributes/Orientations/IWithOrientation.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TUI.Engine.Nodes.Attributes.Orientations; - -public interface IWithOrientation -{ - public Orientation Orientation { get; } -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Resizing/IResizable.cs b/src/TUI/Engine/Nodes/Attributes/Resizing/IResizable.cs deleted file mode 100644 index 2773ce8..0000000 --- a/src/TUI/Engine/Nodes/Attributes/Resizing/IResizable.cs +++ /dev/null @@ -1,14 +0,0 @@ -using TUI.Engine.Nodes.Attributes.Orientations; - -namespace TUI.Engine.Nodes.Attributes.Resizing; - -public interface IResizable -{ - Resizing ResizingHorizontal { get; } - - Resizing ResizingVertical { get; } - - void SetAdaptive(Orientation orientation); - void SetFixed(Orientation orientation, int value); - Size GetFixedSize(); -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Attributes/Resizing/Resizing.cs b/src/TUI/Engine/Nodes/Attributes/Resizing/Resizing.cs deleted file mode 100644 index a213eb1..0000000 --- a/src/TUI/Engine/Nodes/Attributes/Resizing/Resizing.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TUI.Engine.Nodes.Attributes.Resizing; - -public enum Resizing -{ - Adaptive, - Fixed -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Components/ComponentBase.cs b/src/TUI/Engine/Nodes/Components/ComponentBase.cs deleted file mode 100644 index 862547e..0000000 --- a/src/TUI/Engine/Nodes/Components/ComponentBase.cs +++ /dev/null @@ -1,63 +0,0 @@ -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Attributes.Paddings; -using TUI.Engine.Nodes.Attributes.Resizing; -using TUI.Engine.Theme; - - -namespace TUI.Engine.Nodes.Components; - - -public abstract class ComponentBase : NodeBase, IComponent -{ - private Size _sketchSize; - - public abstract Sketch DrawComponent(); - - public Sketch MakeSketch() - { - var sketch = DrawComponent(); - _sketchSize = sketch.GetSize(); - return sketch; - } - - public Resizing ResizingHorizontal { get; } - - // protected override Size GetAllowableSize() => - // new( - // AllowableSize.Width <= _sketchSize.Width ? _sketchSize.Width : AllowableSize.Width, - // AllowableSize.Height <= _sketchSize.Height ? _sketchSize.Height : AllowableSize.Height - // ); - - #region Alignments - - public Alignment Alignment { get; private set; } = new(Horizontal.Center, Vertical.Top); - - public void SetAlignment(Vertical vertical) - { - Alignment = Alignment with { Vertical = vertical }; - } - - public void SetAlignment(Horizontal horizontal) - { - Alignment = Alignment with { Horizontal = horizontal }; - } - - #endregion - - #region Paddings - - public Padding Padding { get; private set; } = new(Level.None); - - public void SetPadding(Level level) => Padding = new Padding(level); - - public void SetPaddingTop(Level level) => Padding = Padding with { Top = level }; - - public void SetPaddingRight(Level level) => Padding = Padding with { Right = level }; - - public void SetPaddingBottom(Level level) => Padding = Padding with { Bottom = level }; - - public void SetPaddingLeft(Level level) => Padding = Padding with { Left = level }; - - #endregion -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Components/IComponent.cs b/src/TUI/Engine/Nodes/Components/IComponent.cs deleted file mode 100644 index a1bf772..0000000 --- a/src/TUI/Engine/Nodes/Components/IComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Attributes.Paddings; - -namespace TUI.Engine.Nodes.Components; - -public interface IComponent : INode, IAlignable, IPaddingable -{ - Sketch MakeSketch(); -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Containers/ContainerBase.cs b/src/TUI/Engine/Nodes/Containers/ContainerBase.cs deleted file mode 100644 index 416a5e9..0000000 --- a/src/TUI/Engine/Nodes/Containers/ContainerBase.cs +++ /dev/null @@ -1,16 +0,0 @@ -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Orientations; - -namespace TUI.Engine.Nodes.Containers; - -public abstract class ContainerBase : NodeBase, IContainer -{ - public Orientation Orientation => Orientation.Horizontal; - - public Size GetSketchSize() - { - throw new NotImplementedException(); - } - - public abstract Nodes GetNodes(); -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Containers/ContainerExtension.cs b/src/TUI/Engine/Nodes/Containers/ContainerExtension.cs deleted file mode 100644 index 02e9b83..0000000 --- a/src/TUI/Engine/Nodes/Containers/ContainerExtension.cs +++ /dev/null @@ -1,116 +0,0 @@ -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Nodes.Attributes.Resizing; -using TUI.Engine.Nodes.Components; -using TUI.Engine.Rendering; - -namespace TUI.Engine.Nodes.Containers; - -public static class ContainerExtension -{ - public static Size GetSize(this INode node, IContainer parentContainer, int nodeNumber, Size allowableSize) - { - var width = GetWidth(node, parentContainer, allowableSize.Width); - var height = GetHeight(node, parentContainer, allowableSize.Height, nodeNumber); - return new Size(width, height); - } - - private static IEnumerable GetFixedNodes(this IContainer container, int? takeNodeNumber = null) - { - if (takeNodeNumber is not null) - { - return container - .GetNodes() - .Take(takeNodeNumber.Value + 1) - .Where(n => n.ResizingVertical == Resizing.Fixed); - } - - return container - .GetNodes() - .Where(n => n.ResizingVertical == Resizing.Fixed); - } - - private static int GetHeight(IResizable node, IContainer container, int maxHeight, int nodeIndex) - { - if (node.ResizingVertical == Resizing.Fixed) - { - return node.GetFixedSize().Height; - } - - if (container.Orientation == Orientation.Horizontal) - { - return maxHeight; - } - - var fixedNodes = container.GetFixedNodes().ToArray(); - - var fixedHeight = fixedNodes.Sum(s => s.GetFixedSize().Height); - var allowableHeight = maxHeight - fixedHeight; - - var allowableCount = container.GetNodes().Count - fixedNodes.Length; - var nodeHeight = (allowableHeight / allowableCount).Min(1); - var nodeNumber = nodeIndex + 1 - container.GetFixedNodes(nodeIndex).Sum(c => c.GetFixedSize().Height); - - if (allowableHeight - nodeNumber * nodeHeight < nodeHeight) - { - return allowableHeight + nodeHeight - nodeNumber * nodeHeight; - } - - return nodeHeight; - } - - private static int GetWidth(IResizable node, IContainer container, int maxWidth) - { - if (node.ResizingHorizontal == Resizing.Fixed) - { - return node.GetFixedSize().Width; - } - - if (container.Orientation == Orientation.Vertical) - { - return maxWidth; - } - - var fixedNodes = container - .GetNodes() - .Where(n => n.ResizingHorizontal == Resizing.Fixed).ToArray(); - - var allowableWidth = maxWidth - fixedNodes.Sum(s => s.GetFixedSize().Width); - var allowableCount = container.GetNodes().Count - fixedNodes.Length; - - return allowableWidth / allowableCount; - } -} - -public static class ComponentExtensions -{ - public static Position CorrectPosition(this IComponent component, Position pencil, Size maxSize, Size sketchSize) - { - var padding = component.Padding; - var alignment = component.Alignment; - var alignmentCompensationLeft = GetAlignmentCompensationLeft(alignment.Horizontal, maxSize, sketchSize); - var alignmentCompensationTop = GetAlignmentCompensationTop(alignment.Vertical, maxSize, sketchSize); - var left = pencil.Left + (int)padding.Left + alignmentCompensationLeft; - var top = pencil.Top + (int)padding.Top + alignmentCompensationTop; - return new Position(left, top); - } - - private static int GetAlignmentCompensationLeft(Horizontal alignment, Size maxSize, Size sketchSize) => - alignment switch - { - Horizontal.Left => 0, - Horizontal.Center => (maxSize.Width - sketchSize.Width) / 2, - Horizontal.Right => maxSize.Width - sketchSize.Width, - _ => 0 - }; - - private static int GetAlignmentCompensationTop(Vertical alignment, Size maxSize, Size sketchSize) => - alignment switch - { - Vertical.Top => 0, - Vertical.Center => (maxSize.Height - sketchSize.Height) / 2, - Vertical.Bottom => maxSize.Height - sketchSize.Height, - _ => 0 - }; -} \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Containers/IContainer.cs b/src/TUI/Engine/Nodes/Containers/IContainer.cs deleted file mode 100644 index 85c2500..0000000 --- a/src/TUI/Engine/Nodes/Containers/IContainer.cs +++ /dev/null @@ -1,10 +0,0 @@ -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Orientations; - -namespace TUI.Engine.Nodes.Containers; - -public interface IContainer : INode, IWithOrientation -{ - Size GetSketchSize(); - Nodes GetNodes(); -} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/CanvasExtensions.cs b/src/TUI/Engine/Rendering/CanvasExtensions.cs deleted file mode 100644 index 5dfe4cf..0000000 --- a/src/TUI/Engine/Rendering/CanvasExtensions.cs +++ /dev/null @@ -1,8 +0,0 @@ -using TUI.Engine.Nodes.Attributes; - -namespace TUI.Engine.Rendering; - -public static class CanvasExtensions -{ - public static Size GetSize(this ICanvas canvas) => new(canvas.Width, canvas.Height); -} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/ConsoleCanvas.cs b/src/TUI/Engine/Rendering/ConsoleCanvas.cs deleted file mode 100644 index 18227c4..0000000 --- a/src/TUI/Engine/Rendering/ConsoleCanvas.cs +++ /dev/null @@ -1,13 +0,0 @@ -using TUI.Engine.Nodes.Attributes; - -namespace TUI.Engine.Rendering; - -public class ConsoleCanvas : ICanvas -{ - public int Width => Console.WindowWidth; - public int Height => Console.WindowHeight; - - public void SetPencil(int left, int top) => Console.SetCursorPosition(left, top); - public void Paint(string value) => Console.Write(value); - public Size GetSize() => new(Width, Height); -} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/ICanvas.cs b/src/TUI/Engine/Rendering/ICanvas.cs deleted file mode 100644 index 88781c1..0000000 --- a/src/TUI/Engine/Rendering/ICanvas.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TUI.Engine.Rendering; - -public interface ICanvas -{ - int Width { get; } - int Height { get; } - void SetPencil(int left, int top); - void Paint(string value); -} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/IntegerExtension.cs b/src/TUI/Engine/Rendering/IntegerExtension.cs deleted file mode 100644 index b142d85..0000000 --- a/src/TUI/Engine/Rendering/IntegerExtension.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TUI.Engine.Rendering; - -public static class IntegerExtension -{ - public static int Max(this int value, int maxValue) => value <= maxValue ? value : maxValue; - public static int Min(this int value, int minValue) => value > minValue ? value : minValue; -} \ No newline at end of file diff --git a/src/TUI/Pages/DependenciesPage.cs b/src/TUI/Pages/DependenciesPage.cs index 03a9713..ca97f42 100644 --- a/src/TUI/Pages/DependenciesPage.cs +++ b/src/TUI/Pages/DependenciesPage.cs @@ -1,10 +1,9 @@ using System.Diagnostics; using TUI.Components.Controls; using TUI.Components.Layouts; -using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Rendering; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Rendering.Canvas; using TUI.Engine.Theme; namespace TUI.Pages; @@ -15,11 +14,7 @@ public class DependenciesPage { Debugger.Log(0, "Event", "Open page dependencies\n"); - var canvas = new ConsoleCanvas(); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - var nodeCraftsman = new NodeCraftsman(componentCraftsman, containerCraftsman); + ICanvas canvas = new ConsoleCanvas(); var header = new HeaderContainer(); header.SetFixed(Orientation.Vertical, 6); @@ -33,7 +28,7 @@ public class DependenciesPage // CommandLine = new CommandLine(); // DependenciesView = new DependenciesView(); - nodeCraftsman.Draw(layout, Position.Default, canvas.GetSize()); + canvas.Draw(layout); } // private bool _commandLineInDisplay; diff --git a/src/TUI/Store/DependenciesStore.cs b/src/TUI/Store/DependenciesStore.cs index 141484f..82eb923 100644 --- a/src/TUI/Store/DependenciesStore.cs +++ b/src/TUI/Store/DependenciesStore.cs @@ -1,5 +1,6 @@ using System.Text.Json; using TUI.Domain; +using TUI.Engine; using TUI.Settings; namespace TUI.Store; diff --git a/src/TUI/TUI.csproj b/src/TUI/TUI.csproj index 8e11941..ee7b7f3 100644 --- a/src/TUI/TUI.csproj +++ b/src/TUI/TUI.csproj @@ -19,4 +19,8 @@ + + + + diff --git a/tests/WIdgets/TUI.Tests/ComponentBaseTests.cs b/tests/TUI.Engine.Tests/DrawTests/ComponentAttributeTests.cs similarity index 82% rename from tests/WIdgets/TUI.Tests/ComponentBaseTests.cs rename to tests/TUI.Engine.Tests/DrawTests/ComponentAttributeTests.cs index 0d657a5..06501fc 100644 --- a/tests/WIdgets/TUI.Tests/ComponentBaseTests.cs +++ b/tests/TUI.Engine.Tests/DrawTests/ComponentAttributeTests.cs @@ -1,16 +1,16 @@ using FluentAssertions; -using TUI.Components.Controls.Statics; -using TUI.Engine.Nodes.Attributes.Alignments; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Tests.Stubs; using TUI.Engine.Theme; -namespace Widgets.Tests; +namespace TUI.Engine.Tests.DrawTests; -public class ComponentBaseTests +public class ComponentAttributeTests { [Fact] public void WhenUseChainingSaveAllChange() { - var logo = new Logo(); + var logo = new TestComponent(); logo.SetPadding(Level.Normal); logo.SetAlignment(Vertical.Center); logo.SetAlignment(Horizontal.Center); @@ -26,7 +26,7 @@ public class ComponentBaseTests [Fact] public void WhenSetPaddingsSaveAllChange() { - var component = new Logo(); + var component = new TestComponent(); component.SetPadding(Level.Normal); @@ -42,7 +42,7 @@ public class ComponentBaseTests [InlineData(Vertical.Top)] public void WhenSetVerticalAlignSaveAllChange(Vertical alignment) { - var component = new Logo(); + var component = new TestComponent(); component.SetAlignment(alignment); @@ -55,7 +55,7 @@ public class ComponentBaseTests [InlineData(Horizontal.Right)] public void WhenSetHorizontalAlignSaveAllChange(Horizontal alignment) { - var component = new Logo(); + var component = new TestComponent(); component.SetAlignment(alignment); diff --git a/tests/TUI.Engine.Tests/DrawTests/DrawResizingTests.cs b/tests/TUI.Engine.Tests/DrawTests/DrawResizingTests.cs new file mode 100644 index 0000000..fbe3438 --- /dev/null +++ b/tests/TUI.Engine.Tests/DrawTests/DrawResizingTests.cs @@ -0,0 +1,55 @@ +using Moq; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Nodes; +using TUI.Engine.Rendering; +using TUI.Engine.Rendering.Canvas; +using TUI.Engine.Tests.Stubs; + +namespace TUI.Engine.Tests.DrawTests; + +public class DrawResizingTests +{ + private readonly ICanvas _canvas; + private readonly TestContainer _container; + private readonly ContainerCraftsman _craftsman; + private readonly TestContainer _root; + + public DrawResizingTests() + { + var component = Prepare.Component(); + _canvas = Mock.Of(w => w.Size == new Size(20, 2)); + _container = Prepare.Container(component); + + _root = Prepare.Container(_container, component); + _root.SetOrientationHorizontal(); + + var componentCraftsman = new ComponentCraftsman(_canvas); + _craftsman = new ContainerCraftsman(componentCraftsman); + } + + [Fact] + public void DrawResizingFixedContainer() + { + _container.SetFixed(Orientation.Horizontal, 6); + _container.SetFixed(Orientation.Vertical, 2); + + _craftsman.Draw(_root, Position.Default, _canvas.Size); + + Mock.Get(_canvas).VerifyPositionOnce(Position.Default); + Mock.Get(_canvas).VerifyPositionOnce(6, 0); + Mock.Get(_canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); + } + + [Fact] + public void DrawResizingAdaptiveContainer() + { + _container.SetAdaptive(Orientation.Horizontal); + + _craftsman.Draw(_root, Position.Default, _canvas.Size); + + Mock.Get(_canvas).VerifyPositionOnce(Position.Default); + Mock.Get(_canvas).VerifyPositionOnce(10, 0); + Mock.Get(_canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); + } +} \ No newline at end of file diff --git a/tests/TUI.Engine.Tests/DrawTests/DrawTests.cs b/tests/TUI.Engine.Tests/DrawTests/DrawTests.cs new file mode 100644 index 0000000..0ccd630 --- /dev/null +++ b/tests/TUI.Engine.Tests/DrawTests/DrawTests.cs @@ -0,0 +1,218 @@ +using Moq; +using TUI.Engine.Attributes; +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Attributes.Orientations; +using TUI.Engine.Containers; +using TUI.Engine.Nodes; +using TUI.Engine.Rendering; +using TUI.Engine.Rendering.Canvas; +using TUI.Engine.Tests.Stubs; + +namespace TUI.Engine.Tests.DrawTests; + +public class DrawCraftsmanTests +{ + public TestComponent _component; + + public DrawCraftsmanTests() + { + _component = Prepare.Component(); + } + + [Fact] + public void DrawSimple() + { + var canvas = Mock.Of(w => w.Size == new Size(9, 1)); + + var componentCraftsman = new ComponentCraftsman(canvas); + componentCraftsman.Draw(_component, Position.Default, canvas.Size); + + Mock.Get(canvas).Verify(w => w.SetPencil(Position.Default), Times.Once()); + Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once()); + } + + [Theory] + [InlineData(Horizontal.Left, "Lorem", 10, 0)] + [InlineData(Horizontal.Center, "Lorem", 10, 2)] + [InlineData(Horizontal.Center, "Lo", 10, 4)] + [InlineData(Horizontal.Center, "Lorem", 9, 2)] + [InlineData(Horizontal.Center, "Lorem", 11, 3)] + [InlineData(Horizontal.Right, "Lorem", 10, 5)] + [InlineData(Horizontal.Right, "Lo", 10, 8)] + public void DrawWithHorizontalAlignment(Horizontal alignment, string content, int canvasSize, + int expectedPosition) + { + var canvas = Mock.Of(w => w.Size == new Size(canvasSize, canvasSize)); + var component = Prepare.Component(); + component.SetContent(content); + component.SetAlignment(Vertical.Top); + component.SetAlignment(alignment); + + var componentCraftsman = new ComponentCraftsman(canvas); + componentCraftsman.Draw(component, Position.Default, canvas.Size); + + Mock.Get(canvas).Verify(w => w.Paint(content), Times.Once()); + Mock.Get(canvas).Verify(w => w.SetPencil(new Position(expectedPosition, 0)), Times.Once()); + } + + [Theory] + [InlineData(Vertical.Top, "v", 5, new[] { 0 })] + [InlineData(Vertical.Top, "v\nv", 5, new[] { 0, 1 })] + [InlineData(Vertical.Top, "v\nv\nv", 5, new[] { 0, 1, 2 })] + [InlineData(Vertical.Center, "v", 1, new[] { 0 })] + [InlineData(Vertical.Center, "v", 4, new[] { 1 })] + [InlineData(Vertical.Center, "v", 5, new[] { 2 })] + [InlineData(Vertical.Center, "v", 6, new[] { 2 })] + [InlineData(Vertical.Center, "v\nv", 4, new[] { 1, 2 })] + [InlineData(Vertical.Center, "v\nv", 5, new[] { 1, 2 })] + [InlineData(Vertical.Center, "v\nv", 6, new[] { 2, 3 })] + [InlineData(Vertical.Bottom, "v", 5, new[] { 4 })] + [InlineData(Vertical.Bottom, "v\nv", 2, new[] { 0, 1 })] + [InlineData(Vertical.Bottom, "v\nv", 3, new[] { 1, 2 })] + [InlineData(Vertical.Bottom, "v\nv\nv\nv", 5, new[] { 1, 2, 3, 4 })] + public void DrawWithVerticalAlignment(Vertical alignment, string content, int canvasSize, int[] expectedPositions) + { + var canvas = Mock.Of(w => w.Size == new Size(canvasSize, canvasSize)); + _component.SetContent(content); + _component.SetAlignment(Horizontal.Left); + _component.SetAlignment(alignment); + + var componentCraftsman = new ComponentCraftsman(canvas); + componentCraftsman.Draw(_component, Position.Default, canvas.Size); + + foreach (var expectedPencilPosition in expectedPositions) + { + Mock.Get(canvas).VerifyPositionOnce(0, expectedPencilPosition); + } + } + + [Theory] + [InlineData(Horizontal.Left, Vertical.Top, 0, 0)] + [InlineData(Horizontal.Left, Vertical.Center, 0, 2)] + [InlineData(Horizontal.Left, Vertical.Bottom, 0, 4)] + [InlineData(Horizontal.Center, Vertical.Top, 2, 0)] + [InlineData(Horizontal.Center, Vertical.Center, 2, 2)] + [InlineData(Horizontal.Center, Vertical.Bottom, 2, 4)] + [InlineData(Horizontal.Right, Vertical.Top, 4, 0)] + [InlineData(Horizontal.Right, Vertical.Center, 4, 2)] + [InlineData(Horizontal.Right, Vertical.Bottom, 4, 4)] + public void DrawWithAlignment(Horizontal horizontal, Vertical vertical, int expectedLeft, + int expectedTop) + { + var canvas = Mock.Of(w => w.Size == new Size(6, 5)); + _component.SetContent("VV"); + _component.SetAlignment(horizontal); + _component.SetAlignment(vertical); + + var componentCraftsman = new ComponentCraftsman(canvas); + componentCraftsman.Draw(_component, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(expectedLeft, expectedTop); + } + + [Theory] + [InlineData(Orientation.Horizontal, 9, 1)] + public void DrawWithOverloadHorizontal(Orientation orientation, int rootWidth, int rootHeight) + { + var canvas = Mock.Of(w => w.Size == new Size(rootWidth, rootHeight)); + var root = Prepare.Container(_component, _component); + root.SetOrientationHorizontal(); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + containerCraftsman.Draw(root, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(Position.Default); + Mock.Get(canvas).VerifyPositionOnce(4, 0); + Mock.Get(canvas).Verify(w => w.Paint("Lore"), Times.Exactly(2)); + } + + + [Theory] + [InlineData(4, 4, new[] { 0, 1, 2, 3 })] + public void DrawWithOverloadVertical(int rootWidth, int rootHeight, int[] expectedTopPositions) + { + var canvas = Mock.Of(w => w.Size == new Size(rootWidth, rootHeight)); + _component.SetContent("Lorem\nLorem\nLorem"); + var root = Prepare.Container(_component, _component); + root.SetOrientationVertical(); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + containerCraftsman.Draw(root, Position.Default, canvas.Size); + + foreach (var expectedTopPosition in expectedTopPositions) + { + Mock.Get(canvas).VerifyPositionOnce(0, expectedTopPosition); + } + + Mock.Get(canvas).Verify(w => w.Paint("Lore"), Times.Exactly(rootHeight)); + } + + [Fact] + public void DrawVerticalWithDoubleComponent() + { + var canvas = Mock.Of(w => w.Size == new Size(10, 2)); + var root = Prepare.Container(_component, _component); + root.SetOrientationVertical(); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + new DrawCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(Position.Default); + Mock.Get(canvas).VerifyPositionOnce(0, 1); + Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); + } + + [Fact] + public void DrawHorizontalWithDoubleComponent() + { + var canvas = Mock.Of(w => w.Size == new Size(10, 1)); + var nodes = new Nodes.Nodes { _component, _component }; + var container = Mock.Of(g => g.GetNodes() == nodes); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + new DrawCraftsman(componentCraftsman, containerCraftsman).Draw(container, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(Position.Default); + Mock.Get(canvas).VerifyPositionOnce(5, 0); + Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); + } + + [Fact] + public void DrawWithMultipleComponent() + { + var canvas = Mock.Of(w => w.Size == new Size(24, 1)); + var root = Prepare.Container(_component, _component, _component, _component); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + containerCraftsman.Draw(root, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(Position.Default); + Mock.Get(canvas).VerifyPositionOnce(6, 0); + Mock.Get(canvas).VerifyPositionOnce(12, 0); + Mock.Get(canvas).VerifyPositionOnce(18, 0); + Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(4)); + } + + [Fact] + public void DrawWithContainerAndComponent() + { + var canvas = Mock.Of(w => w.Size == new Size(10, 2)); + var container = Prepare.Container(_component); + var root = Prepare.Container(container, _component); + root.SetAdaptive(Orientation.Vertical); + root.SetOrientationVertical(); + + var componentCraftsman = new ComponentCraftsman(canvas); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + containerCraftsman.Draw(root, Position.Default, canvas.Size); + + Mock.Get(canvas).VerifyPositionOnce(Position.Default); + Mock.Get(canvas).VerifyPositionOnce(0, 1); + Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); + } +} \ No newline at end of file diff --git a/tests/TUI.Engine.Tests/DrawTests/IntegerTests.cs b/tests/TUI.Engine.Tests/DrawTests/IntegerTests.cs new file mode 100644 index 0000000..f2f7608 --- /dev/null +++ b/tests/TUI.Engine.Tests/DrawTests/IntegerTests.cs @@ -0,0 +1,26 @@ +using FluentAssertions; + +namespace TUI.Engine.Tests.DrawTests; + +public class IntegerTests +{ + [Theory] + [InlineData(5, 10, 5)] + [InlineData(5, 5, 5)] + [InlineData(5, 3, 3)] + public void Max(int value, int max, int expected) + { + var result = value.Max(max); + result.Should().Be(expected); + } + + [Theory] + [InlineData(5, 10, 10)] + [InlineData(5, 5, 5)] + [InlineData(5, 3, 5)] + public void Min(int value, int min, int expected) + { + var result = value.Min(min); + result.Should().Be(expected); + } +} \ No newline at end of file diff --git a/tests/TUI.Engine.Tests/MockExtensions.cs b/tests/TUI.Engine.Tests/MockExtensions.cs new file mode 100644 index 0000000..3322533 --- /dev/null +++ b/tests/TUI.Engine.Tests/MockExtensions.cs @@ -0,0 +1,18 @@ +using Moq; +using TUI.Engine.Nodes; +using TUI.Engine.Rendering.Canvas; + +namespace TUI.Engine.Tests; + +public static class MockExtensions +{ + public static void VerifyPositionOnce(this Mock mock, int left, int top) where T : class, ICanvas + { + mock.Verify(w => w.SetPencil(new Position(left, top)), Times.Exactly(1)); + } + + public static void VerifyPositionOnce(this Mock mock, Position position) where T : class, ICanvas + { + mock.Verify(w => w.SetPencil(position), Times.Exactly(1)); + } +} \ No newline at end of file diff --git a/tests/TUI.Engine.Tests/Stubs/Prepare.cs b/tests/TUI.Engine.Tests/Stubs/Prepare.cs new file mode 100644 index 0000000..428dff2 --- /dev/null +++ b/tests/TUI.Engine.Tests/Stubs/Prepare.cs @@ -0,0 +1,22 @@ +using TUI.Engine.Attributes.Alignments; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Tests.Stubs; + +public static class Prepare +{ + public static TestComponent Component() + { + var testComponent = new TestComponent(); + testComponent.SetAlignment(Horizontal.Left); + testComponent.SetAlignment(Vertical.Top); + return testComponent; + } + + public static TestContainer Container(params INode[] nodes) + { + var testContainer = new TestContainer(); + testContainer.SetNodes(nodes); + return testContainer; + } +} \ No newline at end of file diff --git a/tests/WIdgets/TUI.Tests/TestComponent.cs b/tests/TUI.Engine.Tests/Stubs/TestComponent.cs similarity index 52% rename from tests/WIdgets/TUI.Tests/TestComponent.cs rename to tests/TUI.Engine.Tests/Stubs/TestComponent.cs index d018319..1d4be6c 100644 --- a/tests/WIdgets/TUI.Tests/TestComponent.cs +++ b/tests/TUI.Engine.Tests/Stubs/TestComponent.cs @@ -1,8 +1,8 @@ -using TUI.Engine.Nodes.Components; +using TUI.Engine.Components; -namespace Widgets.Tests; +namespace TUI.Engine.Tests.Stubs; -internal class TestComponent : ComponentBase +public class TestComponent : ComponentAttribute { private string _content = "Lorem"; @@ -11,7 +11,7 @@ internal class TestComponent : ComponentBase _content = content; } - public override Sketch DrawComponent() + protected override Sketch DrawComponent() { return new Sketch(_content); } diff --git a/tests/TUI.Engine.Tests/Stubs/TestContainer.cs b/tests/TUI.Engine.Tests/Stubs/TestContainer.cs new file mode 100644 index 0000000..f34d65b --- /dev/null +++ b/tests/TUI.Engine.Tests/Stubs/TestContainer.cs @@ -0,0 +1,20 @@ +using TUI.Engine.Containers; +using TUI.Engine.Nodes; + +namespace TUI.Engine.Tests.Stubs; + +public class TestContainer : ContainerBase +{ + private Nodes.Nodes _nodes = new(); + + public override Nodes.Nodes GetNodes() + { + return _nodes; + } + + public TestContainer SetNodes(params INode[] nodes) + { + _nodes.AddRange(nodes); + return this; + } +} \ No newline at end of file diff --git a/tests/WIdgets/TUI.Tests/TUI.Tests.csproj b/tests/TUI.Engine.Tests/TUI.Engine.Tests.csproj similarity index 86% rename from tests/WIdgets/TUI.Tests/TUI.Tests.csproj rename to tests/TUI.Engine.Tests/TUI.Engine.Tests.csproj index 5f8628f..ba7433b 100644 --- a/tests/WIdgets/TUI.Tests/TUI.Tests.csproj +++ b/tests/TUI.Engine.Tests/TUI.Engine.Tests.csproj @@ -7,7 +7,8 @@ false true - Widgets.Tests + TUI.Engine.Tests + TUI.Engine.Tests @@ -26,7 +27,7 @@ - + diff --git a/tests/WIdgets/TUI.Tests/Usings.cs b/tests/TUI.Engine.Tests/Usings.cs similarity index 100% rename from tests/WIdgets/TUI.Tests/Usings.cs rename to tests/TUI.Engine.Tests/Usings.cs diff --git a/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs b/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs deleted file mode 100644 index b8c969b..0000000 --- a/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs +++ /dev/null @@ -1,240 +0,0 @@ -using Moq; -using TUI.Engine.Nodes; -using TUI.Engine.Nodes.Attributes; -using TUI.Engine.Nodes.Attributes.Alignments; -using TUI.Engine.Nodes.Attributes.Orientations; -using TUI.Engine.Nodes.Attributes.Resizing; -using TUI.Engine.Nodes.Containers; -using TUI.Engine.Rendering; - -namespace Widgets.Tests; - -public class NodeCraftsmanTests -{ - private readonly TestComponent _component; - - public NodeCraftsmanTests() - { - _component = new TestComponent(); - _component.SetAlignment(Horizontal.Left); - _component.SetAlignment(Vertical.Top); - } - - [Fact] - public void DrawSimple() - { - var canvas = Mock.Of(w => w.Width == 9 && w.Height == 1); - - var componentCraftsman = new ComponentCraftsman(canvas); - componentCraftsman.Draw(_component, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Once()); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once()); - } - - [Theory] - [InlineData(Horizontal.Left, "Lorem", 10, 0)] - [InlineData(Horizontal.Center, "Lorem", 10, 2)] - [InlineData(Horizontal.Center, "Lo", 10, 4)] - [InlineData(Horizontal.Center, "Lorem", 9, 2)] - [InlineData(Horizontal.Center, "Lorem", 11, 3)] - [InlineData(Horizontal.Right, "Lorem", 10, 5)] - [InlineData(Horizontal.Right, "Lo", 10, 8)] - public void DrawWithHorizontalAlignment(Horizontal alignment, string content, int canvasSize, - int expectedPosition) - { - var canvas = Mock.Of(w => w.Width == canvasSize && w.Height == canvasSize); - _component.SetContent(content); - _component.SetAlignment(Vertical.Top); - _component.SetAlignment(alignment); - - var componentCraftsman = new ComponentCraftsman(canvas); - componentCraftsman.Draw(_component, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.Paint(content), Times.Once()); - Mock.Get(canvas).Verify(w => w.SetPencil(expectedPosition, 0), Times.Once()); - } - - [Theory] - [InlineData(Vertical.Top, "v", 5, new[] { 0 })] - [InlineData(Vertical.Top, "v\nv", 5, new[] { 0, 1 })] - [InlineData(Vertical.Top, "v\nv\nv", 5, new[] { 0, 1, 2 })] - [InlineData(Vertical.Center, "v", 1, new[] { 0 })] - [InlineData(Vertical.Center, "v", 4, new[] { 1 })] - [InlineData(Vertical.Center, "v", 5, new[] { 2 })] - [InlineData(Vertical.Center, "v", 6, new[] { 2 })] - [InlineData(Vertical.Center, "v\nv", 4, new[] { 1, 2 })] - [InlineData(Vertical.Center, "v\nv", 5, new[] { 1, 2 })] - [InlineData(Vertical.Center, "v\nv", 6, new[] { 2, 3 })] - [InlineData(Vertical.Bottom, "v", 5, new[] { 4 })] - [InlineData(Vertical.Bottom, "v\nv", 2, new[] { 0, 1 })] - [InlineData(Vertical.Bottom, "v\nv", 3, new[] { 1, 2 })] - [InlineData(Vertical.Bottom, "v\nv\nv\nv", 5, new[] { 1, 2, 3, 4 })] - public void DrawWithVerticalAlignment(Vertical alignment, string content, int canvasSize, int[] expectedPositions) - { - var canvas = Mock.Of(w => w.Width == canvasSize && w.Height == canvasSize); - _component.SetContent(content); - _component.SetAlignment(Horizontal.Left); - _component.SetAlignment(alignment); - - var componentCraftsman = new ComponentCraftsman(canvas); - componentCraftsman.Draw(_component, Position.Default, canvas.GetSize()); - - foreach (var expectedCursorPosition in expectedPositions) - { - Mock.Get(canvas).Verify(w => w.SetPencil(0, expectedCursorPosition), Times.Once()); - } - } - - [Theory] - [InlineData(Horizontal.Left, Vertical.Top, 0, 0)] - [InlineData(Horizontal.Left, Vertical.Center, 0, 2)] - [InlineData(Horizontal.Left, Vertical.Bottom, 0, 4)] - [InlineData(Horizontal.Center, Vertical.Top, 2, 0)] - [InlineData(Horizontal.Center, Vertical.Center, 2, 2)] - [InlineData(Horizontal.Center, Vertical.Bottom, 2, 4)] - [InlineData(Horizontal.Right, Vertical.Top, 4, 0)] - [InlineData(Horizontal.Right, Vertical.Center, 4, 2)] - [InlineData(Horizontal.Right, Vertical.Bottom, 4, 4)] - public void DrawWithAlignment(Horizontal horizontal, Vertical vertical, int expectedLeft, - int expectedTop) - { - var canvas = Mock.Of(w => w.Width == 6 && w.Height == 5); - _component.SetContent("VV"); - _component.SetAlignment(horizontal); - _component.SetAlignment(vertical); - - var componentCraftsman = new ComponentCraftsman(canvas); - componentCraftsman.Draw(_component, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(expectedLeft, expectedTop), Times.Once()); - } - - [Theory] - [InlineData(Orientation.Horizontal, 9, 1)] - public void DrawWithOverloadHorizontal(Orientation orientation, int rootWidth, int rootHeight) - { - var canvas = Mock.Of(w => w.Width == rootWidth && w.Height == rootHeight); - var nodes = new Nodes { _component, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == orientation); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - containerCraftsman.Draw(root, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Once()); - Mock.Get(canvas).Verify(w => w.SetPencil(4, 0), Times.Once()); - Mock.Get(canvas).Verify(w => w.Paint("Lore"), Times.Exactly(2)); - } - - - [Theory] - [InlineData(4, 4, new[] { 0, 1, 2, 3 })] - public void DrawWithOverloadVertical(int rootWidth, int rootHeight, int[] expectedTopPositions) - { - var canvas = Mock.Of(w => w.Width == rootWidth && w.Height == rootHeight); - _component.SetContent("Lorem\nLorem\nLorem"); - var nodes = new Nodes { _component, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - containerCraftsman.Draw(root, Position.Default, canvas.GetSize()); - - foreach (var expectedTopPosition in expectedTopPositions) - { - Mock.Get(canvas).Verify(w => w.SetPencil(0, expectedTopPosition), Times.Once()); - } - - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(rootHeight)); - } - - [Fact] - public void DrawVerticalWithDoubleComponent() - { - var canvas = Mock.Of(w => w.Height == 2 && w.Width == 10); - var nodes = new Nodes { _component, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Once()); - Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), Times.Once()); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); - } - - [Fact] - public void DrawHorizontalWithDoubleComponent() - { - var canvas = Mock.Of(w => w.Width == 10 && w.Height == 1); - var nodes = new Nodes { _component, _component }; - var container = Mock.Of(g => g.GetNodes() == nodes); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(container, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(5, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); - } - - [Fact] - public void DrawWithMultipleComponent() - { - var canvas = Mock.Of(w => w.Width == 24 && w.Height == 1); - var nodes = new Nodes { _component, _component, _component, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - containerCraftsman.Draw(root, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(6, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(12, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(18, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(4)); - } - - [Fact] - public void DrawWithContainerAndComponent() - { - var canvas = Mock.Of(w => w.Width == 10 && w.Height == 2); - var container = Mock.Of(c => c.GetNodes() == new Nodes { _component }); - var nodes = new Nodes { container, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - containerCraftsman.Draw(root, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); - } - - [Theory] - [InlineData(Resizing.Fixed, 6)] - [InlineData(Resizing.Adaptive, 10)] - public void DrawResizingContainer(Resizing resizing, int expectedCursorPosition) - { - var canvas = Mock.Of(w => w.Width == 20 && w.Height == 2); - var container = - Mock.Of(c => - c.GetNodes() == new Nodes { _component } && c.ResizingHorizontal == resizing && - c.GetFixedSize() == new Size(6, 2)); - var nodes = new Nodes { container, _component }; - var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Horizontal); - - var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(componentCraftsman); - containerCraftsman.Draw(root, Position.Default, canvas.GetSize()); - - Mock.Get(canvas).Verify(w => w.SetPencil(0, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.SetPencil(expectedCursorPosition, 0), Times.Exactly(1)); - Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Exactly(2)); - } -} \ No newline at end of file diff --git a/tests/WIdgets/TUI.Tests/Controls/LogoTests.cs b/tests/WIdgets/TUI.Tests/Controls/LogoTests.cs deleted file mode 100644 index 9455f0f..0000000 --- a/tests/WIdgets/TUI.Tests/Controls/LogoTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using TUI.Components.Controls.Statics; - -namespace Widgets.Tests.Controls; - -public class LogoTests -{ - [Fact] - public void Simple() - { - var logo = new Logo(); - - var render = logo.MakeSketch().ToString(); - - Assert.Equal( - " \u001b[38;2;132;186;100m\u256d\u2501\u2501\u2501\u2501\u2533\u256e\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u256d\u2501\u2501\u2501\u256e\u001b[0m\n \u001b[38;2;132;186;100m\u2503\u256d\u256e\u256d\u256e\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u256e\u256d\u256e\u2503\u001b[0m\n \u001b[38;2;132;186;100m\u2570\u256f\u2503\u2503\u2570\u252b\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u2503\u2503\u001b[0m\n \u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u256d\u256e\u2503\u2503\u2503\u2503\u001b[0m\n \u001b[38;2;113;121;126m\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2570\u2501\u256f\u2523\u256f\u2570\u256f\u2503\u001b[0m\n\u001b[38;2;113;121;126m\u2571\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u256f\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u2501\u2501\u2501\u253b\u2501\u2501\u2501\u256f\u001b[0m\n", - render); - } -} \ No newline at end of file diff --git a/tests/WIdgets/TUI.Tests/IntegerTests.cs b/tests/WIdgets/TUI.Tests/IntegerTests.cs deleted file mode 100644 index 71e9e7e..0000000 --- a/tests/WIdgets/TUI.Tests/IntegerTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using FluentAssertions; -using TUI.Engine.Rendering; - -namespace Widgets.Tests; - -public class IntegerTests -{ - [Fact] - public void IntegerGreaterMax() - { - var result = 5.Max(10); - - result.Should().Be(5); - } - [Fact] - public void IntegerLessMax() - { - var result = 5.Max(3); - - result.Should().Be(3); - } -} \ No newline at end of file