Fill not render space (Render engine, Border)

This commit is contained in:
2023-08-17 15:55:00 +02:00
parent 92726f1af9
commit df4fe93c81
17 changed files with 373 additions and 146 deletions

View File

@@ -1,4 +1,5 @@
using PropertyChanged.SourceGenerator;
using TerminalUI.Color;
using TerminalUI.Models;
using TerminalUI.Traits;
@@ -16,6 +17,7 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
[Notify] private char _topRightChar = '┐';
[Notify] private char _bottomLeftChar = '└';
[Notify] private char _bottomRightChar = '┘';
[Notify] private IColor? _fill;
public Border()
{
@@ -25,6 +27,9 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
RerenderProperties.Add(nameof(LeftChar));
RerenderProperties.Add(nameof(RightChar));
RerenderProperties.Add(nameof(BottomChar));
RerenderProperties.Add(nameof(TopLeftChar));
RerenderProperties.Add(nameof(TopRightChar));
RerenderProperties.Add(nameof(Fill));
}
protected override Size CalculateSize()
@@ -51,12 +56,19 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
+ DataContext?.GetType().Name);
}
var backgroundColor = Background ?? renderContext.Background;
var foregroundColor = Foreground ?? renderContext.Foreground;
var fillColor = Fill ?? Background ?? renderContext.Background;
var childPosition = new Position(X: position.X + _borderThickness.Left, Y: position.Y + _borderThickness.Top);
var childSize = new Size(
Width: size.Width - _borderThickness.Left - _borderThickness.Right,
Height: size.Height - _borderThickness.Top - _borderThickness.Bottom
);
var childPositionWithoutPadding = childPosition;
var childSizeWithoutPadding = childSize;
if (_padding.Left > 0 || _padding.Top > 0 || _padding.Right > 0 || _padding.Bottom > 0)
{
childPosition = new Position(X: childPosition.X + _padding.Left, Y: childPosition.Y + _padding.Top);
@@ -66,85 +78,117 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
);
}
var contentRendered = ContentRendererMethod(renderContext, childPosition, childSize);
// Same size as the original.
// Although wasting memory, but we would have to delta the position when setting "updatedcells"
// It is easier and also covers the fact the children use a different array
var borderChildUpdatedCells = new bool[
renderContext.UpdatedCells.GetLength(0),
renderContext.UpdatedCells.GetLength(1)
];
var childRenderContext = renderContext with {UpdatedCells = borderChildUpdatedCells};
var contentRendered = ContentRendererMethod(childRenderContext, childPosition, childSize);
if (contentRendered)
{
var driver = renderContext.ConsoleDriver;
driver.ResetStyle();
SetColorsForDriver(renderContext);
SetStyleColor(renderContext, foregroundColor, backgroundColor);
}
RenderTopBorder(renderContext, position, size);
RenderBottomBorder(renderContext, position, size);
RenderLeftBorder(renderContext, position, size);
RenderRightBorder(renderContext, position, size);
var updateCellsOnly = !contentRendered;
RenderTopBorder(renderContext, position, size, updateCellsOnly);
RenderBottomBorder(renderContext, position, size, updateCellsOnly);
RenderLeftBorder(renderContext, position, size, updateCellsOnly);
RenderRightBorder(renderContext, position, size, updateCellsOnly);
RenderTopLeftCorner(renderContext, position);
RenderTopRightCorner(renderContext, position, size);
RenderBottomLeftCorner(renderContext, position, size);
RenderBottomRightCorner(renderContext, position, size);
RenderTopLeftCorner(renderContext, position, updateCellsOnly);
RenderTopRightCorner(renderContext, position, size, updateCellsOnly);
RenderBottomLeftCorner(renderContext, position, size, updateCellsOnly);
RenderBottomRightCorner(renderContext, position, size, updateCellsOnly);
//TODO render padding
if (fillColor != null)
{
SetStyleColor(renderContext, foregroundColor, fillColor);
// Use the same array that children use. Also use that area, so we working only inside the border
Array2DHelper.RenderEmpty(
renderContext.ConsoleDriver,
borderChildUpdatedCells,
borderChildUpdatedCells,
ApplicationContext!.EmptyCharacter,
childPositionWithoutPadding,
childSizeWithoutPadding
);
//Write back the changes to the original array
Array2DHelper.CombineArray2Ds(
renderContext.UpdatedCells,
borderChildUpdatedCells,
new Position(0, 0),
renderContext.UpdatedCells,
(a, b) => (a ?? false) || (b ?? false)
);
}
return contentRendered;
}
private void RenderTopBorder(in RenderContext renderContext, Position position, Size size)
private void RenderTopBorder(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
position = position with {X = position.X + _borderThickness.Left};
size = new Size(Width: size.Width - _borderThickness.Left - _borderThickness.Right, Height: _borderThickness.Top);
RenderText(_topChar, renderContext.ConsoleDriver, position, size);
RenderText(_topChar, renderContext, position, size, updateCellsOnly);
}
private void RenderBottomBorder(in RenderContext renderContext, Position position, Size size)
private void RenderBottomBorder(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
position = new Position(X: position.X + _borderThickness.Left, Y: position.Y + size.Height - _borderThickness.Bottom);
size = new Size(Width: size.Width - _borderThickness.Left - _borderThickness.Right, Height: _borderThickness.Bottom);
RenderText(_bottomChar, renderContext.ConsoleDriver, position, size);
RenderText(_bottomChar, renderContext, position, size, updateCellsOnly);
}
private void RenderLeftBorder(in RenderContext renderContext, Position position, Size size)
private void RenderLeftBorder(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
position = position with {Y = position.Y + _borderThickness.Top};
size = new Size(Width: _borderThickness.Left, Height: size.Height - _borderThickness.Top - _borderThickness.Bottom);
RenderText(_leftChar, renderContext.ConsoleDriver, position, size);
RenderText(_leftChar, renderContext, position, size, updateCellsOnly);
}
private void RenderRightBorder(in RenderContext renderContext, Position position, Size size)
private void RenderRightBorder(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
position = new Position(X: position.X + size.Width - _borderThickness.Right, Y: position.Y + _borderThickness.Top);
size = new Size(Width: _borderThickness.Right, Height: size.Height - _borderThickness.Top - _borderThickness.Bottom);
RenderText(_rightChar, renderContext.ConsoleDriver, position, size);
RenderText(_rightChar, renderContext, position, size, updateCellsOnly);
}
private void RenderTopLeftCorner(in RenderContext renderContext, Position position)
private void RenderTopLeftCorner(in RenderContext renderContext, Position position, bool updateCellsOnly)
{
if (_borderThickness.Left == 0 || _borderThickness.Top == 0) return;
var size = new Size(Width: _borderThickness.Left, Height: _borderThickness.Top);
RenderText(_topLeftChar, renderContext.ConsoleDriver, position, size);
RenderText(_topLeftChar, renderContext, position, size, updateCellsOnly);
}
private void RenderTopRightCorner(in RenderContext renderContext, Position position, Size size)
private void RenderTopRightCorner(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
if (_borderThickness.Right == 0 || _borderThickness.Top == 0) return;
position = position with {X = position.X + size.Width - _borderThickness.Right};
size = new Size(Width: _borderThickness.Right, Height: _borderThickness.Top);
RenderText(_topRightChar, renderContext.ConsoleDriver, position, size);
RenderText(_topRightChar, renderContext, position, size, updateCellsOnly);
}
private void RenderBottomLeftCorner(in RenderContext renderContext, Position position, Size size)
private void RenderBottomLeftCorner(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
if (_borderThickness.Left == 0 || _borderThickness.Bottom == 0) return;
position = position with {Y = position.Y + size.Height - _borderThickness.Bottom};
size = new Size(Width: _borderThickness.Left, Height: _borderThickness.Bottom);
RenderText(_bottomLeftChar, renderContext.ConsoleDriver, position, size);
RenderText(_bottomLeftChar, renderContext, position, size, updateCellsOnly);
}
private void RenderBottomRightCorner(in RenderContext renderContext, Position position, Size size)
private void RenderBottomRightCorner(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly)
{
if (_borderThickness.Right == 0 || _borderThickness.Bottom == 0) return;
@@ -153,6 +197,6 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
Y: position.Y + size.Height - _borderThickness.Bottom
);
size = new Size(Width: _borderThickness.Right, Height: _borderThickness.Bottom);
RenderText(_bottomRightChar, renderContext.ConsoleDriver, position, size);
RenderText(_bottomRightChar, renderContext, position, size, updateCellsOnly);
}
}

View File

@@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
namespace TerminalUI.Controls;
public abstract class ChildContainerView<TConcrete, T>
public abstract class ChildCollectionView<TConcrete, T>
: View<TConcrete, T>, IChildContainer<T>
where TConcrete : View<TConcrete, T>
{
@@ -12,7 +12,7 @@ public abstract class ChildContainerView<TConcrete, T>
public ReadOnlyObservableCollection<IView> Children { get; }
public ChildInitializer<T> ChildInitializer { get; }
protected ChildContainerView()
protected ChildCollectionView()
{
ChildInitializer = new ChildInitializer<T>(this);
Children = new ReadOnlyObservableCollection<IView>(_children);

View File

@@ -48,7 +48,7 @@ public abstract partial class ContentView<TConcrete, T>
{
if (_placeholderRenderDone) return false;
_placeholderRenderDone = true;
RenderEmpty(renderContext, position, size);
RenderEmpty(renderContext, position, size, false);
return true;
}

View File

@@ -7,7 +7,7 @@ using TerminalUI.ViewExtensions;
namespace TerminalUI.Controls;
public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeHandler
public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChangeHandler
{
private readonly List<IView> _forceRerenderChildren = new();
private readonly object _forceRerenderChildrenLock = new();
@@ -202,7 +202,8 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
}
}
private bool RenderViewsByPosition(RenderContext context,
private bool RenderViewsByPosition(
in RenderContext context,
Position gridPosition,
Size gridSize,
ReadOnlySpan<int> columnWidths,
@@ -238,39 +239,26 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
if (!viewsByPosition.TryGetValue((column, row), out var children))
{
RenderEmpty(context, renderPosition, renderSize);
RenderEmpty(context, renderPosition, renderSize, false);
return true;
}
var needsRerender = children.Any(forceRerenderChildren.Contains);
var updatedContext = context;
if (needsRerender)
{
context = new RenderContext(
context.ConsoleDriver,
true,
context.Foreground,
context.Background,
context.Statistics,
context.TextFormat
);
RenderEmpty(context, renderPosition, renderSize);
updatedContext = context with {ForceRerender = true};
RenderEmpty(updatedContext, renderPosition, renderSize, false);
}
//This implies that children further back in the list will be rendered on top of children placed before in the list.
foreach (var child in children.Where(child => child.IsVisible))
foreach (var child in children)
{
var rendered = child.Render(context, renderPosition, renderSize);
var rendered = child.Render(updatedContext, renderPosition, renderSize);
if (rendered && !needsRerender)
{
needsRerender = true;
context = new RenderContext(
context.ConsoleDriver,
true,
context.Foreground,
context.Background,
context.Statistics,
context.TextFormat
);
updatedContext = context with {ForceRerender = true};
}
}

View File

@@ -162,6 +162,8 @@ public sealed partial class ItemsControl<TDataContext, TItem>
? childSize.Height
: childSize.Width;
}
// TODO: clean non used space
return neededRerender;
}

View File

@@ -232,6 +232,8 @@ public sealed partial class ListView<TDataContext, TItem> : View<ListView<TDataC
item.Render(renderContext, position with {X = position.X + deltaX}, size with {Width = width});
deltaX = nextDeltaX;
}
//TODO: render empty to remaining space
return true;
}
@@ -277,23 +279,20 @@ public sealed partial class ListView<TDataContext, TItem> : View<ListView<TDataC
if (lastItemIndex > listViewItems.Length)
lastItemIndex = listViewItems.Length;
var anyRendered = false;
for (var i = renderStartIndex; i < lastItemIndex; i++)
{
var item = listViewItems[i];
item.Render(renderContext, position with {Y = position.Y + deltaY}, requestedItemSize with {Width = size.Width});
anyRendered =
item.Render(renderContext, position with {Y = position.Y + deltaY}, requestedItemSize with {Width = size.Width})
|| anyRendered;
deltaY += requestedItemSize.Height;
}
var driver = ApplicationContext!.ConsoleDriver;
var placeholder = new string(' ', size.Width);
driver.ResetStyle();
for (var i = deltaY; i < size.Height; i++)
{
driver.SetCursorPosition(position with {Y = position.Y + i});
driver.Write(placeholder);
}
// TODO: this should only render if deltaY is changed compared to last render or if last render was a horizontal
RenderEmpty(renderContext, position with {Y = position.Y + deltaY}, size with {Height = size.Height - deltaY}, false);
return true;
return anyRendered;
}
private ReadOnlySpan<ListViewItem<TItem, TDataContext>> InstantiateItemViews()

View File

@@ -67,7 +67,7 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
unfilledForeground,
unfilledBackground);
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState);
var utf8Support = ApplicationContext!.SupportUtf8Output;
var unfilledCharacter = unfilledCharacterS.GetChar(utf8Support);
@@ -117,16 +117,17 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
var textStartPosition = position;
if (leftCap.HasValue)
{
RenderText(leftCap.Value, driver, position, size with {Width = 1});
RenderText(leftCap.Value, renderContext, position, size with {Width = 1}, skipRender);
textStartPosition = textStartPosition with {X = textStartPosition.X + 1};
}
// Filled
RenderText(
filledText,
driver,
renderContext,
textStartPosition,
size with {Width = progressQuotientWidth}
size with {Width = progressQuotientWidth},
skipRender
);
// Transient character
@@ -135,9 +136,10 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
SetStyleColor(renderContext, foreground, unfilledBackground);
RenderText(
transientChar,
driver,
renderContext,
textStartPosition with {X = textStartPosition.X + progressQuotientWidth},
size with {Width = 1}
size with {Width = 1},
skipRender
);
}
@@ -150,9 +152,10 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
SetStyleColor(renderContext, unfilledForeground, unfilledBackground);
RenderText(
unfilledText,
driver,
renderContext,
textStartPosition with {X = textStartPosition.X + progressQuotientWidth + 1},
size with {Width = progressRemainderWidth}
size with {Width = progressRemainderWidth},
skipRender
);
}
@@ -162,12 +165,13 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
SetStyleColor(renderContext, foreground, background);
RenderText(
rightCap.Value,
driver,
renderContext,
position with {X = position.X + size.Width - 1},
size with {Width = 1});
size with {Width = 1},
skipRender);
}
return true;
return !skipRender;
}
private bool NeedsRerender(RenderState renderState)

View File

@@ -13,32 +13,40 @@ public sealed partial class Rectangle<T> : View<Rectangle<T>, T>, IDisplayView
IColor? Color);
private RenderState? _lastRenderState;
[Notify] private IColor? _fill;
public Rectangle()
{
RerenderProperties.Add(nameof(Fill));
}
protected override Size CalculateSize() => new(Width ?? 0, Height ?? 0);
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
{
var color = Background ?? renderContext.Background;
var renderState = new RenderState(position, size, color);
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
var fillColor = Fill ?? Background ?? renderContext.Background;
var renderState = new RenderState(position, size, fillColor);
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState);
_lastRenderState = renderState;
var driver = renderContext.ConsoleDriver;
var s = new string(' ', size.Width);
driver.ResetStyle();
if (color is not null)
if (fillColor is not null)
{
driver.SetBackgroundColor(color);
driver.SetBackgroundColor(fillColor);
}
var height = size.Height;
for (var i = 0; i < height; i++)
{
driver.SetCursorPosition(position with {Y = position.Y + i});
driver.Write(s);
}
RenderEmpty(
renderContext,
position,
size,
skipRender,
false
);
return true;
return !skipRender;
}
private bool NeedsRerender(RenderState renderState)

View File

@@ -4,7 +4,7 @@ using TerminalUI.Traits;
namespace TerminalUI.Controls;
public sealed partial class StackPanel<T> : ChildContainerView<StackPanel<T>, T>, IVisibilityChangeHandler
public sealed partial class StackPanel<T> : ChildCollectionView<StackPanel<T>, T>, IVisibilityChangeHandler
{
private readonly List<IView> _forceRerenderChildren = new();
private readonly object _forceRerenderChildrenLock = new();
@@ -39,7 +39,10 @@ public sealed partial class StackPanel<T> : ChildContainerView<StackPanel<T>, T>
return new Size(width, height);
}
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
protected override bool DefaultRenderer(
in RenderContext renderContext,
Position position,
Size size)
{
var neededRerender = false;
IReadOnlyList<IView> forceRerenderChildren;
@@ -102,9 +105,10 @@ public sealed partial class StackPanel<T> : ChildContainerView<StackPanel<T>, T>
SetColorsForDriver(renderContext);
RenderText(
text,
renderContext.ConsoleDriver,
renderContext,
position with {X = position.X + delta},
size with {Width = leftWidth}
size with {Width = leftWidth},
!neededRerender
);
}
else
@@ -116,9 +120,10 @@ public sealed partial class StackPanel<T> : ChildContainerView<StackPanel<T>, T>
SetColorsForDriver(renderContext);
RenderText(
text,
renderContext.ConsoleDriver,
renderContext,
position with {Y = position.Y + delta},
size with {Height = leftHeight}
size with {Height = leftHeight},
!neededRerender
);
}

View File

@@ -58,7 +58,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
background,
_textFormat);
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState);
_lastRenderState = renderState;
@@ -67,7 +67,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
if (_placeholderRenderDone)
{
_placeholderRenderDone = true;
RenderEmpty(renderContext, position, size);
RenderEmpty(renderContext, position, size, skipRender);
}
return false;
@@ -75,12 +75,11 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
_placeholderRenderDone = false;
var driver = renderContext.ConsoleDriver;
SetStyleColor(renderContext, foreground, background, _textFormat);
RenderText(_textLines, driver, position, size, TransformText);
RenderText(_textLines, renderContext, position, size, skipRender, TransformText);
return true;
return !skipRender;
}
private string TransformText(string text, Position position, Size size)

View File

@@ -100,38 +100,39 @@ public sealed partial class TextBox<T> : View<TextBox<T>, T>, IFocusable, IDispl
foreground,
background);
if (!renderContext.ForceRerender && !NeedsRerender(renderStatus)) return false;
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderStatus);
_lastRenderState = renderStatus;
var driver = renderContext.ConsoleDriver;
SetStyleColor(renderContext, foreground, background);
RenderEmpty(renderContext, position, size);
RenderEmpty(renderContext, position, size, skipRender);
if (PasswordChar is { } passwordChar && !char.IsControl(passwordChar))
{
for (var i = 0; i < _textLines.Count; i++)
{
var pos = position with {Y = position.Y + i};
RenderPasswordTextLine(_textLines[i], passwordChar, driver, pos, size);
RenderPasswordTextLine(_textLines[i], passwordChar, renderContext, pos, size, skipRender);
}
}
else
{
RenderText(_textLines, driver, position, size);
RenderText(_textLines, renderContext, position, size, skipRender);
}
_cursorPosition = position + _relativeCursorPosition;
return true;
return !skipRender;
}
private void RenderPasswordTextLine(
string sourceText,
char passwordChar,
IConsoleDriver driver,
in RenderContext renderContext,
Position position,
Size size)
Size size,
bool updateCellsOnly)
{
Span<char> text = stackalloc char[sourceText.Length];
for (var j = 0; j < text.Length; j++)
@@ -139,7 +140,7 @@ public sealed partial class TextBox<T> : View<TextBox<T>, T>, IFocusable, IDispl
text[j] = passwordChar;
}
RenderText(text, driver, position, size);
RenderText(text, renderContext, position, size, updateCellsOnly);
}
private bool NeedsRerender(RenderState renderState)

View File

@@ -6,7 +6,6 @@ using System.Runtime.CompilerServices;
using GeneralInputKey;
using PropertyChanged.SourceGenerator;
using TerminalUI.Color;
using TerminalUI.ConsoleDrivers;
using TerminalUI.Models;
using TerminalUI.TextFormat;
using TerminalUI.Traits;
@@ -200,12 +199,18 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
return renderResult;
}
protected void RenderEmpty(in RenderContext renderContext, Position position, Size size)
protected void RenderEmpty(in RenderContext renderContext, Position position, Size size, bool updateCellsOnly, bool resetStyle = true)
{
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
if (updateCellsOnly) return;
var driver = renderContext.ConsoleDriver;
driver.ResetStyle();
if (resetStyle)
{
driver.ResetStyle();
}
var placeHolder = new string(ApplicationContext!.EmptyCharacter, size.Width);
Span<char> placeHolder = stackalloc char[size.Width];
placeHolder.Fill(ApplicationContext!.EmptyCharacter);
for (var i = 0; i < size.Height; i++)
{
driver.SetCursorPosition(position with {Y = position.Y + i});
@@ -213,13 +218,30 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
}
}
private void UpdateCells(bool[,] renderContextUpdatedCells, Position position, int sizeWidth, int sizeHeight)
{
for (var x = 0; x < sizeWidth; x++)
{
for (var y = 0; y < sizeHeight; y++)
{
renderContextUpdatedCells[position.X + x, position.Y + y] = true;
}
}
}
protected void RenderText(
IList<string> textLines,
IConsoleDriver driver,
in RenderContext renderContext,
Position position,
Size size,
bool updateCellsOnly,
TextTransformer? textTransformer = null)
{
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
if (updateCellsOnly) return;
var driver = renderContext.ConsoleDriver;
for (var i = 0; i < textLines.Count; i++)
{
var currentPosition = position with {Y = position.Y + i};
@@ -234,6 +256,10 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
{
text = text[..size.Width];
}
else if (text.Length < size.Width)
{
text = text.PadRight(size.Width);
}
try
{
@@ -247,38 +273,17 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
}
protected void RenderText(
string text,
IConsoleDriver driver,
in ReadOnlySpan<char> text,
in RenderContext renderContext,
Position position,
Size size,
TextTransformer? textTransformer = null)
bool updateCellsOnly)
{
for (var i = 0; i < size.Height; i++)
{
var currentPosition = position with {Y = position.Y + i};
var finalText = text;
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
if (textTransformer is not null)
{
finalText = textTransformer(finalText, currentPosition, size);
}
if (updateCellsOnly) return;
if (finalText.Length > size.Width)
{
finalText = finalText[..size.Width];
}
driver.SetCursorPosition(currentPosition);
driver.Write(finalText);
}
}
protected void RenderText(
in ReadOnlySpan<char> text,
IConsoleDriver driver,
Position position,
Size size)
{
var driver = renderContext.ConsoleDriver;
for (var i = 0; i < size.Height; i++)
{
var currentPosition = position with {Y = position.Y + i};
@@ -296,10 +301,16 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
protected void RenderText(
char content,
IConsoleDriver driver,
in RenderContext renderContext,
Position position,
Size size)
Size size,
bool updateCellsOnly)
{
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
if (updateCellsOnly) return;
var driver = renderContext.ConsoleDriver;
var contentString = new string(content, size.Width);
for (var i = 0; i < size.Height; i++)
@@ -323,6 +334,7 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
{
t.ApplyFormat(driver, renderContext.TextFormat);
}
if (foreground is not null)
{
driver.SetForegroundColor(foreground);