♻️ Refactoring craftsmans.

This commit is contained in:
Kolosov Alexandr 2024-03-08 14:41:29 +05:00
parent 2eb8fee7d4
commit 074365652d
15 changed files with 78 additions and 67 deletions

View File

@ -23,7 +23,7 @@ public class CellsComponentBase : ComponentBase, IComponent
var content = new StringBuilder(); var content = new StringBuilder();
foreach (var cell in _cells) foreach (var cell in _cells)
{ {
content.Append(Symbols.Space.Repeat(MaxCellWidth - cell.Width())); content.Append(Symbols.Space.Repeat(MaxCellWidth - cell.GetWidth()));
content.Append(cell); content.Append(cell);
} }

View File

@ -29,7 +29,7 @@ public class Dashboard : ComponentBase, IComponent
private static void RenderTopLine(StringBuilder dashboardBuilder, Size size, string title) 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; (int)Indentation.Default * 2) / 2;
dashboardBuilder.Append(Symbols.Angles.LeftTop); dashboardBuilder.Append(Symbols.Angles.LeftTop);
dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(halfWidth)); dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(halfWidth));

View File

@ -1,6 +1,8 @@
namespace TUI.Engine.Nodes.Attributes; 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}]"; public override string ToString() => $"W[{Width}] H[{Height}]";
} }

View File

@ -10,12 +10,12 @@ public sealed class Sketch : IEnumerable<string>
public IEnumerator<string> GetEnumerator() => ContentRows.GetEnumerator(); public IEnumerator<string> GetEnumerator() => ContentRows.GetEnumerator();
public IEnumerable<string> Rows(int maxWidth, int maxHeight) => public IEnumerable<string> Rows(Size maxSize) =>
ContentRows.Where(row => maxWidth >= row.Width()).Take(maxHeight).ToArray(); ContentRows.Where(row => maxSize.Width >= row.GetWidth()).Take(maxSize.Height).ToArray();
public Size GetSize() 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(); var height = ContentRows.Count();
return new Size(width, height); return new Size(width, height);
} }

View File

@ -2,5 +2,6 @@ namespace TUI.Engine.Nodes;
public record Position(int Left, int Top) public record Position(int Left, int Top)
{ {
public static readonly Position Default = new(0, 0);
public override string ToString() => $"L[{Left}] T[{Top}]"; public override string ToString() => $"L[{Left}] T[{Top}]";
} }

View File

@ -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);
}

View File

@ -1,4 +1,3 @@
using System.Diagnostics;
using TUI.Engine.Nodes; using TUI.Engine.Nodes;
using TUI.Engine.Nodes.Attributes; using TUI.Engine.Nodes.Attributes;
using TUI.Engine.Nodes.Components; using TUI.Engine.Nodes.Components;
@ -6,7 +5,7 @@ using TUI.Engine.Nodes.Containers;
namespace TUI.Engine.Rendering; namespace TUI.Engine.Rendering;
public sealed class ComponentCraftsman : IDrawable<IComponent> public sealed class ComponentCraftsman : CraftsmanBase, IDrawable<IComponent>
{ {
private readonly ICanvas _canvas; private readonly ICanvas _canvas;
@ -19,16 +18,10 @@ public sealed class ComponentCraftsman : IDrawable<IComponent>
{ {
var sketch = component.Draw(); var sketch = component.Draw();
var actualSize = sketch.GetSize(); var actualSize = sketch.GetSize();
var maxSize = _canvas.GetSize() - sketchPosition;
var maxWidth = _canvas.Width - sketchPosition.Left;
var maxHeight = _canvas.Height - sketchPosition.Top;
var pencilPosition = component.GetPosition(sketchPosition, allowableSize, actualSize); var pencilPosition = component.GetPosition(sketchPosition, allowableSize, actualSize);
Debugger.Log(0, "Render", $"{pencilPosition}{component.GetType().Name}.\n"); foreach (var row in sketch.Rows(maxSize))
Helper.ShowBackground(sketchPosition, allowableSize);
foreach (var row in sketch.Rows(maxWidth, maxHeight))
{ {
_canvas.SetPencil(pencilPosition.Left, pencilPosition.Top); _canvas.SetPencil(pencilPosition.Left, pencilPosition.Top);
_canvas.Paint(row); _canvas.Paint(row);
@ -36,6 +29,8 @@ public sealed class ComponentCraftsman : IDrawable<IComponent>
pencilPosition = pencilPosition with { Top = pencilPosition.Top + 1 }; pencilPosition = pencilPosition with { Top = pencilPosition.Top + 1 };
} }
Debug(pencilPosition, sketchPosition, allowableSize);
return actualSize; return actualSize;
} }
} }

View File

@ -1,9 +1,13 @@
using TUI.Engine.Nodes.Attributes;
namespace TUI.Engine.Rendering; namespace TUI.Engine.Rendering;
public class ConsoleCanvas : ICanvas public class ConsoleCanvas : ICanvas
{ {
public int Width => Console.WindowWidth; public int Width => Console.WindowWidth;
public int Height => Console.WindowHeight; public int Height => Console.WindowHeight;
public void SetPencil(int left, int top) => Console.SetCursorPosition(left, top); public void SetPencil(int left, int top) => Console.SetCursorPosition(left, top);
public void Paint(string value) => Console.Write(value); public void Paint(string value) => Console.Write(value);
public Size GetSize() => new(Width, Height);
} }

View File

@ -7,16 +7,12 @@ using TUI.Engine.Nodes.Containers;
namespace TUI.Engine.Rendering; namespace TUI.Engine.Rendering;
public sealed class ContainerCraftsman : IDrawable<IContainer> public sealed class ContainerCraftsman : CraftsmanBase, IDrawable<IContainer>
{ {
private readonly ICanvas _canvas;
private readonly IDrawable<IComponent> _componentCraftsman; private readonly IDrawable<IComponent> _componentCraftsman;
public ContainerCraftsman( public ContainerCraftsman(IDrawable<IComponent> componentCraftsman)
ICanvas canvas,
IDrawable<IComponent> componentCraftsman)
{ {
_canvas = canvas;
_componentCraftsman = componentCraftsman; _componentCraftsman = componentCraftsman;
} }
@ -25,9 +21,6 @@ public sealed class ContainerCraftsman : IDrawable<IContainer>
{ {
var sketchSize = container.GetSize(allowableSize); var sketchSize = container.GetSize(allowableSize);
Debugger.Log(0, "Render", $"{sketchPosition} {allowableSize} {container.GetType().Name}\n");
Helper.ShowBackground(sketchPosition, allowableSize);
var controlNumber = 0; var controlNumber = 0;
while (controlNumber < container.GetNodes().Count) while (controlNumber < container.GetNodes().Count)
@ -38,6 +31,7 @@ public sealed class ContainerCraftsman : IDrawable<IContainer>
controlNumber++; controlNumber++;
} }
Debug(sketchPosition, sketchPosition, allowableSize);
return sketchSize; return sketchSize;
} }

View File

@ -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);
}
}

View File

@ -1,3 +1,5 @@
using TUI.Engine.Nodes.Attributes;
namespace TUI.Engine.Rendering; namespace TUI.Engine.Rendering;
public interface ICanvas public interface ICanvas

View File

@ -5,35 +5,24 @@ using TUI.Engine.Nodes.Containers;
namespace TUI.Engine.Rendering; namespace TUI.Engine.Rendering;
public sealed class NodeCraftsman public sealed class NodeCraftsman : IDrawable<INode>
{ {
private readonly ICanvas _canvas;
private readonly IDrawable<IComponent> _componentCraftsman; private readonly IDrawable<IComponent> _componentCraftsman;
private readonly IDrawable<IContainer> _containerCraftsman; private readonly IDrawable<IContainer> _containerCraftsman;
public NodeCraftsman( public NodeCraftsman(
ICanvas canvas,
IDrawable<IComponent> componentCraftsman, IDrawable<IComponent> componentCraftsman,
IDrawable<IContainer> containerCraftsman) IDrawable<IContainer> containerCraftsman)
{ {
_canvas = canvas;
_componentCraftsman = componentCraftsman; _componentCraftsman = componentCraftsman;
_containerCraftsman = containerCraftsman; _containerCraftsman = containerCraftsman;
} }
public void Draw(INode node) public Size Draw(INode node, Position sketchPosition, Size allowableSize) =>
{ node switch
var windowSize = new Size(_canvas.Width, _canvas.Height);
var defaultPosition = new Position(0, 0);
switch (node)
{ {
case IContainer container: IContainer container => _containerCraftsman.Draw(container, sketchPosition, allowableSize),
_containerCraftsman.Draw(container, defaultPosition, windowSize); IComponent component => _componentCraftsman.Draw(component, sketchPosition, allowableSize),
break; _ => throw new InvalidCastException("Unknown node type.")
case IComponent component: };
_componentCraftsman.Draw(component, defaultPosition, windowSize);
break;
}
}
} }

View File

@ -21,7 +21,7 @@ public static class Extensions
return Regex.Replace(text, @"\S\[(\d{0,3}[;m]_?){0,5}", ""); 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; if (string.IsNullOrEmpty(text)) return 0;

View File

@ -1,6 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using TUI.Components.Controls; using TUI.Components.Controls;
using TUI.Components.Layouts; using TUI.Components.Layouts;
using TUI.Engine.Nodes;
using TUI.Engine.Nodes.Attributes.Alignments; using TUI.Engine.Nodes.Attributes.Alignments;
using TUI.Engine.Rendering; using TUI.Engine.Rendering;
using TUI.Engine.Theme; using TUI.Engine.Theme;
@ -16,8 +17,8 @@ public class DependenciesPage
var canvas = new ConsoleCanvas(); var canvas = new ConsoleCanvas();
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
var nodeCraftsman = new NodeCraftsman(canvas, componentCraftsman, containerCraftsman); var nodeCraftsman = new NodeCraftsman(componentCraftsman, containerCraftsman);
var header = new HeaderContainer(); var header = new HeaderContainer();
var copyright = new Copyright() var copyright = new Copyright()
@ -27,7 +28,8 @@ public class DependenciesPage
var layout = new DashboardLayout().AddHeader(header).AddFooter(copyright); var layout = new DashboardLayout().AddHeader(header).AddFooter(copyright);
// CommandLine = new CommandLine(); // CommandLine = new CommandLine();
// DependenciesView = new DependenciesView(); // DependenciesView = new DependenciesView();
nodeCraftsman.Draw(layout);
nodeCraftsman.Draw(layout, Position.Default, canvas.GetSize());
} }
// private bool _commandLineInDisplay; // private bool _commandLineInDisplay;

View File

@ -28,8 +28,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Once());
Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once()); Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once());
@ -53,8 +53,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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.Paint(content), Times.Once());
Mock.Get(canvas).Verify(w => w.SetPencil(expectedPosition, 0), Times.Once()); Mock.Get(canvas).Verify(w => w.SetPencil(expectedPosition, 0), Times.Once());
@ -84,8 +84,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.GetSize());
foreach (var expectedCursorPosition in expectedPositions) foreach (var expectedCursorPosition in expectedPositions)
{ {
@ -113,8 +113,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); new NodeCraftsman(componentCraftsman, containerCraftsman).Draw(root, Position.Default, canvas.GetSize());
Mock.Get(canvas).Verify(w => w.SetPencil(expectedLeft, expectedTop), Times.Once()); Mock.Get(canvas).Verify(w => w.SetPencil(expectedLeft, expectedTop), Times.Once());
} }
@ -129,8 +129,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == orientation); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == orientation);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Once());
Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once()); Mock.Get(canvas).Verify(w => w.Paint("Lorem"), Times.Once());
@ -144,8 +144,8 @@ public class NodeCraftsmanTests
var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Once());
Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), Times.Once()); Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), Times.Once());
@ -160,8 +160,8 @@ public class NodeCraftsmanTests
var container = Mock.Of<IContainer>(g => g.GetNodes() == nodes); var container = Mock.Of<IContainer>(g => g.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(container); 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(0, 0), Times.Exactly(1));
Mock.Get(canvas).Verify(w => w.SetPencil(5, 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<IContainer>(r => r.GetNodes() == nodes); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Exactly(1));
Mock.Get(canvas).Verify(w => w.SetPencil(6, 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<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Vertical);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Exactly(1));
Mock.Get(canvas).Verify(w => w.SetPencil(0, 1), 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<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Horizontal); var root = Mock.Of<IContainer>(r => r.GetNodes() == nodes && r.Orientation == Orientation.Horizontal);
var componentCraftsman = new ComponentCraftsman(canvas); var componentCraftsman = new ComponentCraftsman(canvas);
var containerCraftsman = new ContainerCraftsman(canvas, componentCraftsman); var containerCraftsman = new ContainerCraftsman(componentCraftsman);
new NodeCraftsman(canvas, componentCraftsman, containerCraftsman).Draw(root); 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, 0), Times.Exactly(1));
Mock.Get(canvas).Verify(w => w.SetPencil(expectedCursorPosition, 0), Times.Exactly(1)); Mock.Get(canvas).Verify(w => w.SetPencil(expectedCursorPosition, 0), Times.Exactly(1));