diff --git a/src/TUI/Components/Controls/CellsComponentBase.cs b/src/TUI/Components/Controls/CellsComponentBase.cs index dff5c6b..28a1188 100644 --- a/src/TUI/Components/Controls/CellsComponentBase.cs +++ b/src/TUI/Components/Controls/CellsComponentBase.cs @@ -23,7 +23,7 @@ public class CellsComponentBase : ComponentBase, IComponent var content = new StringBuilder(); foreach (var cell in _cells) { - content.Append(Symbols.Space.Repeat(MaxCellWidth - cell.Width())); + content.Append(Symbols.Space.Repeat(MaxCellWidth - cell.GetWidth())); content.Append(cell); } diff --git a/src/TUI/Components/Controls/Dashboard.cs b/src/TUI/Components/Controls/Dashboard.cs index 55f10e4..969fd25 100644 --- a/src/TUI/Components/Controls/Dashboard.cs +++ b/src/TUI/Components/Controls/Dashboard.cs @@ -29,7 +29,7 @@ public class Dashboard : ComponentBase, IComponent private static void RenderTopLine(StringBuilder dashboardBuilder, Size size, string title) { - var halfWidth = (size.Width - title.Width() - (int)Indentation.BorderWidth * 2 - + var halfWidth = (size.Width - title.GetWidth() - (int)Indentation.BorderWidth * 2 - (int)Indentation.Default * 2) / 2; dashboardBuilder.Append(Symbols.Angles.LeftTop); dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(halfWidth)); diff --git a/src/TUI/Engine/Nodes/Attributes/Size.cs b/src/TUI/Engine/Nodes/Attributes/Size.cs index d0c7689..4848283 100644 --- a/src/TUI/Engine/Nodes/Attributes/Size.cs +++ b/src/TUI/Engine/Nodes/Attributes/Size.cs @@ -1,6 +1,8 @@ namespace TUI.Engine.Nodes.Attributes; -public record Size(int Width, int Height) +public readonly record struct Size(int Width, int Height) { + public static Size operator -(Size a, Position b) => new(a.Width - b.Left, a.Height - b.Top); + public override string ToString() => $"W[{Width}] H[{Height}]"; } \ No newline at end of file diff --git a/src/TUI/Engine/Nodes/Components/Sketch.cs b/src/TUI/Engine/Nodes/Components/Sketch.cs index 583aea8..f5c8768 100644 --- a/src/TUI/Engine/Nodes/Components/Sketch.cs +++ b/src/TUI/Engine/Nodes/Components/Sketch.cs @@ -10,12 +10,12 @@ public sealed class Sketch : IEnumerable public IEnumerator GetEnumerator() => ContentRows.GetEnumerator(); - public IEnumerable Rows(int maxWidth, int maxHeight) => - ContentRows.Where(row => maxWidth >= row.Width()).Take(maxHeight).ToArray(); + public IEnumerable Rows(Size maxSize) => + ContentRows.Where(row => maxSize.Width >= row.GetWidth()).Take(maxSize.Height).ToArray(); public Size GetSize() { - var width = ContentRows.Select(row => row.Width()).DefaultIfEmpty(0).Max(); + var width = ContentRows.Select(row => row.GetWidth()).DefaultIfEmpty(0).Max(); var height = ContentRows.Count(); return new Size(width, height); } diff --git a/src/TUI/Engine/Nodes/Position.cs b/src/TUI/Engine/Nodes/Position.cs index 55600d3..edaa9d8 100644 --- a/src/TUI/Engine/Nodes/Position.cs +++ b/src/TUI/Engine/Nodes/Position.cs @@ -2,5 +2,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/CanvasExtensions.cs b/src/TUI/Engine/Rendering/CanvasExtensions.cs new file mode 100644 index 0000000..5dfe4cf --- /dev/null +++ b/src/TUI/Engine/Rendering/CanvasExtensions.cs @@ -0,0 +1,8 @@ +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/ComponentCraftsman.cs b/src/TUI/Engine/Rendering/ComponentCraftsman.cs index 65f5547..577eed5 100644 --- a/src/TUI/Engine/Rendering/ComponentCraftsman.cs +++ b/src/TUI/Engine/Rendering/ComponentCraftsman.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using TUI.Engine.Nodes; using TUI.Engine.Nodes.Attributes; using TUI.Engine.Nodes.Components; @@ -6,7 +5,7 @@ using TUI.Engine.Nodes.Containers; namespace TUI.Engine.Rendering; -public sealed class ComponentCraftsman : IDrawable +public sealed class ComponentCraftsman : CraftsmanBase, IDrawable { private readonly ICanvas _canvas; @@ -19,16 +18,10 @@ public sealed class ComponentCraftsman : IDrawable { var sketch = component.Draw(); var actualSize = sketch.GetSize(); - - var maxWidth = _canvas.Width - sketchPosition.Left; - var maxHeight = _canvas.Height - sketchPosition.Top; - + var maxSize = _canvas.GetSize() - sketchPosition; var pencilPosition = component.GetPosition(sketchPosition, allowableSize, actualSize); - Debugger.Log(0, "Render", $"{pencilPosition}{component.GetType().Name}.\n"); - Helper.ShowBackground(sketchPosition, allowableSize); - - foreach (var row in sketch.Rows(maxWidth, maxHeight)) + foreach (var row in sketch.Rows(maxSize)) { _canvas.SetPencil(pencilPosition.Left, pencilPosition.Top); _canvas.Paint(row); @@ -36,6 +29,8 @@ public sealed class ComponentCraftsman : IDrawable pencilPosition = pencilPosition with { Top = pencilPosition.Top + 1 }; } + Debug(pencilPosition, sketchPosition, allowableSize); + return actualSize; } } \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/ConsoleCanvas.cs b/src/TUI/Engine/Rendering/ConsoleCanvas.cs index 9636c3b..18227c4 100644 --- a/src/TUI/Engine/Rendering/ConsoleCanvas.cs +++ b/src/TUI/Engine/Rendering/ConsoleCanvas.cs @@ -1,9 +1,13 @@ +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/ConsoleDrawNode.cs b/src/TUI/Engine/Rendering/ContainerCraftsman.cs similarity index 85% rename from src/TUI/Engine/Rendering/ConsoleDrawNode.cs rename to src/TUI/Engine/Rendering/ContainerCraftsman.cs index dc01b01..42eda37 100644 --- a/src/TUI/Engine/Rendering/ConsoleDrawNode.cs +++ b/src/TUI/Engine/Rendering/ContainerCraftsman.cs @@ -7,16 +7,12 @@ using TUI.Engine.Nodes.Containers; namespace TUI.Engine.Rendering; -public sealed class ContainerCraftsman : IDrawable +public sealed class ContainerCraftsman : CraftsmanBase, IDrawable { - private readonly ICanvas _canvas; private readonly IDrawable _componentCraftsman; - public ContainerCraftsman( - ICanvas canvas, - IDrawable componentCraftsman) + public ContainerCraftsman(IDrawable componentCraftsman) { - _canvas = canvas; _componentCraftsman = componentCraftsman; } @@ -25,9 +21,6 @@ public sealed class ContainerCraftsman : IDrawable { var sketchSize = container.GetSize(allowableSize); - Debugger.Log(0, "Render", $"{sketchPosition} {allowableSize} {container.GetType().Name}\n"); - Helper.ShowBackground(sketchPosition, allowableSize); - var controlNumber = 0; while (controlNumber < container.GetNodes().Count) @@ -38,6 +31,7 @@ public sealed class ContainerCraftsman : IDrawable controlNumber++; } + Debug(sketchPosition, sketchPosition, allowableSize); return sketchSize; } diff --git a/src/TUI/Engine/Rendering/CraftsmanBase.cs b/src/TUI/Engine/Rendering/CraftsmanBase.cs new file mode 100644 index 0000000..20d8ad6 --- /dev/null +++ b/src/TUI/Engine/Rendering/CraftsmanBase.cs @@ -0,0 +1,14 @@ +using System.Diagnostics; +using TUI.Engine.Nodes; +using TUI.Engine.Nodes.Attributes; + +namespace TUI.Engine.Rendering; + +public abstract class CraftsmanBase +{ + protected void Debug(Position pencilPosition, Position sketchPosition, Size allowableSize) + { + Debugger.Log(0, "Draw", $"{pencilPosition}{GetType().Name}.\n"); + Helper.ShowBackground(sketchPosition, allowableSize); + } +} \ No newline at end of file diff --git a/src/TUI/Engine/Rendering/ICanvas.cs b/src/TUI/Engine/Rendering/ICanvas.cs index 88781c1..ef1e82c 100644 --- a/src/TUI/Engine/Rendering/ICanvas.cs +++ b/src/TUI/Engine/Rendering/ICanvas.cs @@ -1,3 +1,5 @@ +using TUI.Engine.Nodes.Attributes; + namespace TUI.Engine.Rendering; public interface ICanvas diff --git a/src/TUI/Engine/Rendering/NodeCraftsman.cs b/src/TUI/Engine/Rendering/NodeCraftsman.cs index a124c27..a73c939 100644 --- a/src/TUI/Engine/Rendering/NodeCraftsman.cs +++ b/src/TUI/Engine/Rendering/NodeCraftsman.cs @@ -5,35 +5,24 @@ using TUI.Engine.Nodes.Containers; namespace TUI.Engine.Rendering; -public sealed class NodeCraftsman +public sealed class NodeCraftsman : IDrawable { - private readonly ICanvas _canvas; private readonly IDrawable _componentCraftsman; private readonly IDrawable _containerCraftsman; public NodeCraftsman( - ICanvas canvas, IDrawable componentCraftsman, IDrawable containerCraftsman) { - _canvas = canvas; _componentCraftsman = componentCraftsman; _containerCraftsman = containerCraftsman; } - public void Draw(INode node) - { - var windowSize = new Size(_canvas.Width, _canvas.Height); - var defaultPosition = new Position(0, 0); - - switch (node) + public Size Draw(INode node, Position sketchPosition, Size allowableSize) => + node switch { - case IContainer container: - _containerCraftsman.Draw(container, defaultPosition, windowSize); - break; - case IComponent component: - _componentCraftsman.Draw(component, defaultPosition, windowSize); - break; - } - } + IContainer container => _containerCraftsman.Draw(container, sketchPosition, allowableSize), + IComponent component => _componentCraftsman.Draw(component, sketchPosition, allowableSize), + _ => throw new InvalidCastException("Unknown node type.") + }; } \ No newline at end of file diff --git a/src/TUI/Extensions.cs b/src/TUI/Extensions.cs index 63945e3..6da3e2f 100644 --- a/src/TUI/Extensions.cs +++ b/src/TUI/Extensions.cs @@ -21,7 +21,7 @@ public static class Extensions return Regex.Replace(text, @"\S\[(\d{0,3}[;m]_?){0,5}", ""); } - public static int Width(this string text) + public static int GetWidth(this string text) { if (string.IsNullOrEmpty(text)) return 0; diff --git a/src/TUI/Pages/DependenciesPage.cs b/src/TUI/Pages/DependenciesPage.cs index e465e23..7742452 100644 --- a/src/TUI/Pages/DependenciesPage.cs +++ b/src/TUI/Pages/DependenciesPage.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using TUI.Components.Controls; using TUI.Components.Layouts; +using TUI.Engine.Nodes; using TUI.Engine.Nodes.Attributes.Alignments; using TUI.Engine.Rendering; using TUI.Engine.Theme; @@ -16,8 +17,8 @@ public class DependenciesPage var canvas = new ConsoleCanvas(); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - var nodeCraftsman = new NodeCraftsman(canvas, componentCraftsman, containerCraftsman); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + var nodeCraftsman = new NodeCraftsman(componentCraftsman, containerCraftsman); var header = new HeaderContainer(); var copyright = new Copyright() @@ -27,7 +28,8 @@ public class DependenciesPage var layout = new DashboardLayout().AddHeader(header).AddFooter(copyright); // CommandLine = new CommandLine(); // DependenciesView = new DependenciesView(); - nodeCraftsman.Draw(layout); + + nodeCraftsman.Draw(layout, Position.Default, canvas.GetSize()); } // private bool _commandLineInDisplay; diff --git a/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs b/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs index b90e7e4..e4c1f87 100644 --- a/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs +++ b/tests/WIdgets/TUI.Tests/ConsoleDrawNodeTests.cs @@ -28,8 +28,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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.Paint("Lorem"), Times.Once()); @@ -53,8 +53,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, 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()); @@ -84,8 +84,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.GetSize()); foreach (var expectedCursorPosition in expectedPositions) { @@ -113,8 +113,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + var containerCraftsman = new ContainerCraftsman(componentCraftsman); + new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.GetSize()); Mock.Get(canvas).Verify(w => w.SetPencil(expectedLeft, expectedTop), Times.Once()); } @@ -129,8 +129,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == orientation); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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.Paint("Lorem"), Times.Once()); @@ -144,8 +144,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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()); @@ -160,8 +160,8 @@ public class NodeCraftsmanTests var container = Mock.Of(g => g.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(container); + 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)); @@ -176,8 +176,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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.Exactly(1)); Mock.Get(canvas).Verify(w => w.SetPencil(6, 0), Times.Exactly(1)); @@ -195,8 +195,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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.Exactly(1)); Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), Times.Exactly(1)); @@ -216,8 +216,8 @@ public class NodeCraftsmanTests var root = Mock.Of(r => r.GetNodes() == nodes && r.Orientation == Orientation.Horizontal); var componentCraftsman = new ComponentCraftsman(canvas); - var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); - new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); + 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.Exactly(1)); Mock.Get(canvas).Verify(w => w.SetPencil(expectedCursorPosition, 0), Times.Exactly(1));