Console bugfixes
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TerminalUI.Extensions;
|
||||
using TerminalUI.Models;
|
||||
@@ -10,10 +9,18 @@ namespace TerminalUI.Controls;
|
||||
|
||||
public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChangeHandler
|
||||
{
|
||||
private readonly struct ColumnRowSizeCalculationResult(int usedWidth, int widthStars, int usedHeight, int heightStars)
|
||||
{
|
||||
public readonly int UsedWidth = usedWidth;
|
||||
public readonly int WidthStars = widthStars;
|
||||
public readonly int UsedHeight = usedHeight;
|
||||
public readonly int HeightStars = heightStars;
|
||||
}
|
||||
|
||||
private readonly List<IView> _forceRerenderChildren = new();
|
||||
private readonly object _forceRerenderChildrenLock = new();
|
||||
private List<RowDefinition> _rowDefinitions = new() {RowDefinition.Star(1)};
|
||||
private List<ColumnDefinition> _columnDefinitions = new() {ColumnDefinition.Star(1)};
|
||||
private List<RowDefinition> _rowDefinitions = new() { RowDefinition.Star(1) };
|
||||
private List<ColumnDefinition> _columnDefinitions = new() { ColumnDefinition.Star(1) };
|
||||
private ILogger<Grid<T>>? Logger => ApplicationContext?.LoggerFactory?.CreateLogger<Grid<T>>();
|
||||
|
||||
private delegate void WithSizes(in RenderContext renderContext, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights);
|
||||
@@ -30,7 +37,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
var nextValue = value;
|
||||
if (value.Count == 0)
|
||||
{
|
||||
nextValue = new List<RowDefinition> {RowDefinition.Star(1)};
|
||||
nextValue = new List<RowDefinition> { RowDefinition.Star(1) };
|
||||
}
|
||||
|
||||
var needUpdate = nextValue.Count != _rowDefinitions.Count;
|
||||
@@ -62,7 +69,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
var nextValue = value;
|
||||
if (value.Count == 0)
|
||||
{
|
||||
nextValue = new List<ColumnDefinition> {ColumnDefinition.Star(1)};
|
||||
nextValue = new List<ColumnDefinition> { ColumnDefinition.Star(1) };
|
||||
}
|
||||
|
||||
var needUpdate = nextValue.Count != _columnDefinitions.Count;
|
||||
@@ -238,12 +245,12 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
|
||||
if (renderPosition.X + width > gridPosition.X + gridSize.Width)
|
||||
{
|
||||
renderSize = renderSize with {Width = gridPosition.X + gridSize.Width - renderPosition.X};
|
||||
renderSize = renderSize with { Width = gridPosition.X + gridSize.Width - renderPosition.X };
|
||||
}
|
||||
|
||||
if (renderPosition.Y + height > gridPosition.Y + gridSize.Height)
|
||||
{
|
||||
renderSize = renderSize with {Height = gridPosition.Y + gridSize.Height - renderPosition.Y};
|
||||
renderSize = renderSize with { Height = gridPosition.Y + gridSize.Height - renderPosition.Y };
|
||||
}
|
||||
|
||||
if (renderSize.Width == 0 || renderSize.Height == 0) return false;
|
||||
@@ -257,7 +264,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
var updatedContext = context;
|
||||
if (needsRerender)
|
||||
{
|
||||
updatedContext = context with {ForceRerender = true};
|
||||
updatedContext = context with { ForceRerender = true };
|
||||
}
|
||||
|
||||
//This implies that children further back in the list will be rendered on top of children placed before in the list.
|
||||
@@ -267,7 +274,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
if (rendered && !needsRerender)
|
||||
{
|
||||
needsRerender = true;
|
||||
updatedContext = context with {ForceRerender = true};
|
||||
updatedContext = context with { ForceRerender = true };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +317,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
}
|
||||
else
|
||||
{
|
||||
viewsByPosition[(x, y)] = new List<IView> {child};
|
||||
viewsByPosition[(x, y)] = new List<IView> { child };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,9 +356,64 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
Debug.Assert(columns > 0, "Columns must contain at least one element");
|
||||
Debug.Assert(rows > 0, "Rows must contain at least one element");
|
||||
|
||||
|
||||
//Calculate the width and height for each column and row
|
||||
Span<int> columnWidths = stackalloc int[columns];
|
||||
Span<int> rowHeights = stackalloc int[rows];
|
||||
|
||||
var calculationResult = CalculateColumnAndRowSize(columns, rows, columnWidths, rowHeights, size);
|
||||
|
||||
//Calculate the width and height for each column and row with star value if size of the current grid is given
|
||||
if (size.IsSome)
|
||||
{
|
||||
var widthLeft = size.Value.Width - calculationResult.UsedWidth;
|
||||
var heightLeft = size.Value.Height - calculationResult.UsedHeight;
|
||||
|
||||
var widthPerStart = (int) Math.Floor((double) widthLeft / calculationResult.WidthStars);
|
||||
var heightPerStart = (int) Math.Floor((double) heightLeft / calculationResult.HeightStars);
|
||||
|
||||
for (var i = 0; i < columnWidths.Length; i++)
|
||||
{
|
||||
var column = ColumnDefinitions[i];
|
||||
if (column.Type == GridUnitType.Star)
|
||||
{
|
||||
columnWidths[i] = widthPerStart * column.Value;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < rowHeights.Length; i++)
|
||||
{
|
||||
var row = RowDefinitions[i];
|
||||
if (row.Type == GridUnitType.Star)
|
||||
{
|
||||
rowHeights[i] = heightPerStart * row.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actionWithSizes(renderContext, columnWidths, rowHeights);
|
||||
}
|
||||
|
||||
private ColumnRowSizeCalculationResult CalculateColumnAndRowSize(
|
||||
int columns,
|
||||
int rows,
|
||||
Span<int> columnWidths,
|
||||
Span<int> rowHeights,
|
||||
Option<Size> size)
|
||||
{
|
||||
Span<int> allWidth = stackalloc int[columns * rows];
|
||||
Span<int> allHeight = stackalloc int[columns * rows];
|
||||
|
||||
CalculateAllWidthAndHeight(allWidth, allHeight, columns, rows);
|
||||
|
||||
var (usedWidth, widthStars) = CalculateColumnWidth(columnWidths, size, columns, rows, allWidth);
|
||||
var (usedHeight, heightStars) = CalculateRowHeight(rowHeights, size, columns, allHeight);
|
||||
|
||||
return new ColumnRowSizeCalculationResult(usedWidth, widthStars, usedHeight, heightStars);
|
||||
}
|
||||
|
||||
private void CalculateAllWidthAndHeight(Span<int> allWidth, Span<int> allHeight, int columns, int rows)
|
||||
{
|
||||
//Store the largest width and height for a cell
|
||||
foreach (var child in Children)
|
||||
{
|
||||
@@ -371,11 +433,10 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
allHeight.SetToMatrix(childSize.Height, x, y, columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Calculate the width and height for each column and row
|
||||
Span<int> columnWidths = stackalloc int[columns];
|
||||
Span<int> rowHeights = stackalloc int[rows];
|
||||
|
||||
private (int usedWidth, int widthStars) CalculateColumnWidth(Span<int> columnWidths, Option<Size> size, int columns, int rows, Span<int> allWidth)
|
||||
{
|
||||
var usedWidth = 0;
|
||||
var widthStars = 0;
|
||||
for (var i = 0; i < columnWidths.Length; i++)
|
||||
@@ -404,6 +465,11 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
usedWidth += columnWidths[i];
|
||||
}
|
||||
|
||||
return (usedWidth, widthStars);
|
||||
}
|
||||
|
||||
private (int usedHeight, int heightStars) CalculateRowHeight(Span<int> rowHeights, Option<Size> size, int columns, Span<int> allHeight)
|
||||
{
|
||||
var usedHeight = 0;
|
||||
var heightStars = 0;
|
||||
for (var i = 0; i < rowHeights.Length; i++)
|
||||
@@ -432,35 +498,7 @@ public sealed class Grid<T> : ChildCollectionView<Grid<T>, T>, IVisibilityChange
|
||||
usedHeight += rowHeights[i];
|
||||
}
|
||||
|
||||
//Calculate the width and height for each column and row with star value if size of the current grid is given
|
||||
if (size.IsSome)
|
||||
{
|
||||
var widthLeft = size.Value.Width - usedWidth;
|
||||
var heightLeft = size.Value.Height - usedHeight;
|
||||
|
||||
var widthPerStart = (int) Math.Floor((double) widthLeft / widthStars);
|
||||
var heightPerStart = (int) Math.Floor((double) heightLeft / heightStars);
|
||||
|
||||
for (var i = 0; i < columnWidths.Length; i++)
|
||||
{
|
||||
var column = ColumnDefinitions[i];
|
||||
if (column.Type == GridUnitType.Star)
|
||||
{
|
||||
columnWidths[i] = widthPerStart * column.Value;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < rowHeights.Length; i++)
|
||||
{
|
||||
var row = RowDefinitions[i];
|
||||
if (row.Type == GridUnitType.Star)
|
||||
{
|
||||
rowHeights[i] = heightPerStart * row.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actionWithSizes(renderContext, columnWidths, rowHeights);
|
||||
return (usedHeight, heightStars);
|
||||
}
|
||||
|
||||
public void SetRowDefinitions(string value)
|
||||
|
||||
@@ -215,8 +215,13 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
||||
driver.ResetStyle();
|
||||
}
|
||||
|
||||
Span<char> placeHolder = stackalloc char[size.Width];
|
||||
placeHolder.Fill(ApplicationContext!.EmptyCharacter);
|
||||
/*Span<char> placeHolder = stackalloc char[size.Width];
|
||||
placeHolder.Fill(ApplicationContext!.EmptyCharacter);*/
|
||||
var placeHolder = new char[size.Width];
|
||||
for (var i = 0; i < size.Width; i++)
|
||||
{
|
||||
placeHolder[i] = ApplicationContext!.EmptyCharacter;
|
||||
}
|
||||
for (var i = 0; i < size.Height; i++)
|
||||
{
|
||||
driver.SetCursorPosition(position with {Y = position.Y + i});
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
public static class SpanExtensions
|
||||
{
|
||||
public static T GetFromMatrix<T>(this Span<T> span, int x, int y, int width) => span[y * width + x];
|
||||
public static void SetToMatrix<T>(this Span<T> span, T value, int x, int y, int width) => span[y * width + x] = value;
|
||||
public static T GetFromMatrix<T>(this in Span<T> span, int x, int y, int width) => span[y * width + x];
|
||||
public static void SetToMatrix<T>(this in Span<T> span, T value, int x, int y, int width) => span[y * width + x] = value;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using TerminalUI.Controls;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TerminalUI.Controls;
|
||||
using TerminalUI.Models;
|
||||
using TerminalUI.Styling;
|
||||
using TerminalUI.TextFormat;
|
||||
@@ -10,6 +11,7 @@ public class RenderEngine : IRenderEngine
|
||||
{
|
||||
private readonly IApplicationContext _applicationContext;
|
||||
private readonly IEventLoop _eventLoop;
|
||||
private readonly ILogger<RenderEngine> _logger;
|
||||
private readonly object _lock = new();
|
||||
private readonly List<IView> _permanentViewsToRender = new();
|
||||
private readonly List<IView> _forcedTemporaryViewsToRender = new();
|
||||
@@ -21,10 +23,11 @@ public class RenderEngine : IRenderEngine
|
||||
private bool[,]? _lastFilledCells;
|
||||
private ITheme? _lastTheme;
|
||||
|
||||
public RenderEngine(IApplicationContext applicationContext, IEventLoop eventLoop)
|
||||
public RenderEngine(IApplicationContext applicationContext, IEventLoop eventLoop, ILogger<RenderEngine> logger)
|
||||
{
|
||||
_applicationContext = applicationContext;
|
||||
_eventLoop = eventLoop;
|
||||
_logger = logger;
|
||||
|
||||
_eventLoop.AddToPermanentQueue(Render);
|
||||
_eventLoop.AddInitializer(() =>
|
||||
@@ -32,10 +35,7 @@ public class RenderEngine : IRenderEngine
|
||||
_applicationContext.ConsoleDriver.ThreadId = _eventLoop.ThreadId;
|
||||
_applicationContext.ConsoleDriver.EnterRestrictedMode();
|
||||
});
|
||||
_eventLoop.AddFinalizer(() =>
|
||||
{
|
||||
_applicationContext.ConsoleDriver.ExitRestrictedMode();
|
||||
});
|
||||
_eventLoop.AddFinalizer(() => { _applicationContext.ConsoleDriver.ExitRestrictedMode(); });
|
||||
}
|
||||
|
||||
public void RequestRerender(IView view) => RequestRerender();
|
||||
@@ -204,11 +204,18 @@ public class RenderEngine : IRenderEngine
|
||||
private void RenderViews(List<IView> views, in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
foreach (var view in views)
|
||||
{
|
||||
try
|
||||
{
|
||||
view.Attached = true;
|
||||
view.GetRequestedSize();
|
||||
view.Render(renderContext, position, size);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while rendering view");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearArray2D<T>(T[,] array, T defaultValue = default!)
|
||||
|
||||
Reference in New Issue
Block a user