"In" modifier for ref readonly struct, StackPanel force rerender fix
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using TerminalUI.Models;
|
||||
|
||||
namespace TerminalUI.Controls;
|
||||
@@ -38,7 +38,7 @@ public partial class Border<T> : ContentView<T>
|
||||
return new Size(contentSize.Width + size.Width, contentSize.Height + size.Height);
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (ContentRendererMethod is null)
|
||||
{
|
||||
@@ -89,35 +89,35 @@ public partial class Border<T> : ContentView<T>
|
||||
return contentRendered;
|
||||
}
|
||||
|
||||
private void RenderTopBorder(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderTopBorder(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void RenderBottomBorder(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderBottomBorder(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void RenderLeftBorder(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderLeftBorder(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void RenderRightBorder(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderRightBorder(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void RenderTopLeftCorner(RenderContext renderContext, Position position)
|
||||
private void RenderTopLeftCorner(in RenderContext renderContext, Position position)
|
||||
{
|
||||
if (_borderThickness.Left == 0 || _borderThickness.Top == 0) return;
|
||||
|
||||
@@ -125,7 +125,7 @@ public partial class Border<T> : ContentView<T>
|
||||
RenderText(_topLeftChar, renderContext.ConsoleDriver, position, size);
|
||||
}
|
||||
|
||||
private void RenderTopRightCorner(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderTopRightCorner(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (_borderThickness.Right == 0 || _borderThickness.Top == 0) return;
|
||||
|
||||
@@ -134,7 +134,7 @@ public partial class Border<T> : ContentView<T>
|
||||
RenderText(_topRightChar, renderContext.ConsoleDriver, position, size);
|
||||
}
|
||||
|
||||
private void RenderBottomLeftCorner(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderBottomLeftCorner(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (_borderThickness.Left == 0 || _borderThickness.Bottom == 0) return;
|
||||
|
||||
@@ -143,7 +143,7 @@ public partial class Border<T> : ContentView<T>
|
||||
RenderText(_bottomLeftChar, renderContext.ConsoleDriver, position, size);
|
||||
}
|
||||
|
||||
private void RenderBottomRightCorner(RenderContext renderContext, Position position, Size size)
|
||||
private void RenderBottomRightCorner(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (_borderThickness.Right == 0 || _borderThickness.Bottom == 0) return;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract partial class ContentView<T> : View<T>, IContentRenderer<T>
|
||||
RerenderProperties.Add(nameof(ContentRendererMethod));
|
||||
}
|
||||
|
||||
private bool DefaultContentRender(RenderContext renderContext, Position position, Size size)
|
||||
private bool DefaultContentRender(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (Content is null || !Content.IsVisible)
|
||||
{
|
||||
|
||||
@@ -15,9 +15,9 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
private List<ColumnDefinition> _columnDefinitions = new() {ColumnDefinition.Star(1)};
|
||||
private ILogger<Grid<T>>? Logger => ApplicationContext?.LoggerFactory?.CreateLogger<Grid<T>>();
|
||||
|
||||
private delegate void WithSizes(RenderContext renderContext, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights);
|
||||
private delegate void WithSizes(in RenderContext renderContext, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights);
|
||||
|
||||
private delegate TResult WithSizes<TResult>(RenderContext renderContext, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights);
|
||||
private delegate TResult WithSizes<out TResult>(in RenderContext renderContext, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights);
|
||||
|
||||
private const int ToBeCalculated = -1;
|
||||
|
||||
@@ -126,10 +126,13 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
}
|
||||
|
||||
protected override Size CalculateSize()
|
||||
=> WithCalculatedSize(
|
||||
{
|
||||
return WithCalculatedSize(
|
||||
RenderContext.Empty,
|
||||
new Option<Size>(new Size(0, 0), false),
|
||||
(_, columnWidths, rowHeights) =>
|
||||
CalculateSizeInternal);
|
||||
|
||||
Size CalculateSizeInternal(in RenderContext _, ReadOnlySpan<int> columnWidths, ReadOnlySpan<int> rowHeights)
|
||||
{
|
||||
var width = 0;
|
||||
var height = 0;
|
||||
@@ -145,13 +148,18 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
}
|
||||
|
||||
return new Size(width, height);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
=> WithCalculatedSize(
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
return WithCalculatedSize(
|
||||
renderContext,
|
||||
new Option<Size>(size, true),
|
||||
(context, columnWidths, rowHeights) =>
|
||||
DefaultRendererInternal
|
||||
);
|
||||
|
||||
bool DefaultRendererInternal(in RenderContext context, ReadOnlySpan<int> columnWidths, ReadOnlySpan<int> rowHeights)
|
||||
{
|
||||
IReadOnlyList<IView> forceRerenderChildren;
|
||||
lock (_forceRerenderChildrenLock)
|
||||
@@ -160,11 +168,12 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
_forceRerenderChildren.Clear();
|
||||
}
|
||||
|
||||
context = new RenderContext(
|
||||
var childContext = new RenderContext(
|
||||
context.ConsoleDriver,
|
||||
context.ForceRerender,
|
||||
Foreground ?? context.Foreground,
|
||||
Background ?? context.Background
|
||||
Background ?? context.Background,
|
||||
context.Statistics
|
||||
);
|
||||
var viewsByPosition = GroupViewsByPosition(columnWidths.Length, rowHeights.Length);
|
||||
|
||||
@@ -173,7 +182,7 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
for (var row = 0; row < rowHeights.Length; row++)
|
||||
{
|
||||
RenderViewsByPosition(
|
||||
context,
|
||||
childContext,
|
||||
position,
|
||||
columnWidths,
|
||||
rowHeights,
|
||||
@@ -186,7 +195,8 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderViewsByPosition(RenderContext context,
|
||||
Position gridPosition,
|
||||
@@ -218,7 +228,8 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
context.ConsoleDriver,
|
||||
true,
|
||||
context.Foreground,
|
||||
context.Background
|
||||
context.Background,
|
||||
context.Statistics
|
||||
);
|
||||
RenderEmpty(context, renderPosition, renderSize);
|
||||
}
|
||||
@@ -234,7 +245,8 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
context.ConsoleDriver,
|
||||
true,
|
||||
context.Foreground,
|
||||
context.Background
|
||||
context.Background,
|
||||
context.Statistics
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -304,18 +316,18 @@ public class Grid<T> : ChildContainerView<T>, IVisibilityChangeHandler
|
||||
return (x, y);
|
||||
}
|
||||
|
||||
private void WithCalculatedSize(RenderContext renderContext, Option<Size> size, WithSizes actionWithSizes)
|
||||
private void WithCalculatedSize(in RenderContext renderContext, Option<Size> size, WithSizes actionWithSizes)
|
||||
{
|
||||
WithCalculatedSize(renderContext, size, Helper);
|
||||
|
||||
object? Helper(RenderContext renderContext1, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights)
|
||||
object? Helper(in RenderContext renderContext1, ReadOnlySpan<int> widths, ReadOnlySpan<int> heights)
|
||||
{
|
||||
actionWithSizes(renderContext1, widths, heights);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TResult WithCalculatedSize<TResult>(RenderContext renderContext, Option<Size> size, WithSizes<TResult> actionWithSizes)
|
||||
private TResult WithCalculatedSize<TResult>(in RenderContext renderContext, Option<Size> size, WithSizes<TResult> actionWithSizes)
|
||||
{
|
||||
//TODO: Optimize it, dont calculate all of these, only if there is Auto value(s)
|
||||
var columns = ColumnDefinitions.Count;
|
||||
|
||||
@@ -5,7 +5,7 @@ using TerminalUI.Traits;
|
||||
|
||||
namespace TerminalUI.Controls;
|
||||
|
||||
public delegate bool RenderMethod(RenderContext renderContext, Position position, Size size);
|
||||
public delegate bool RenderMethod(in RenderContext renderContext, Position position, Size size);
|
||||
|
||||
public interface IView : INotifyPropertyChanged, IDisposableCollection
|
||||
{
|
||||
@@ -31,7 +31,7 @@ public interface IView : INotifyPropertyChanged, IDisposableCollection
|
||||
event Action<IView> Disposed;
|
||||
|
||||
Size GetRequestedSize();
|
||||
bool Render(RenderContext renderContext, Position position, Size size);
|
||||
bool Render(in RenderContext renderContext, Position position, Size size);
|
||||
}
|
||||
|
||||
public interface IView<T> : IView
|
||||
|
||||
@@ -162,12 +162,12 @@ public partial class ListView<TDataContext, TItem> : View<TDataContext>
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
=> Orientation == Orientation.Vertical
|
||||
? RenderVertical(renderContext, position, size)
|
||||
: RenderHorizontal(renderContext, position, size);
|
||||
|
||||
private bool RenderHorizontal(RenderContext renderContext, Position position, Size size)
|
||||
private bool RenderHorizontal(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
//Note: no support for same width elements
|
||||
var listViewItems = InstantiateItemViews();
|
||||
@@ -236,7 +236,7 @@ public partial class ListView<TDataContext, TItem> : View<TDataContext>
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RenderVertical(RenderContext renderContext, Position position, Size size)
|
||||
private bool RenderVertical(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
//Note: only same height is supported
|
||||
var requestedItemSize = _requestedItemSize;
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class ListViewItem<T, TParentDataContext> : ContentView<T>
|
||||
return Content.GetRequestedSize();
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (ContentRendererMethod is null)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ public partial class Rectangle<T> : View<T>
|
||||
[Notify] private IColor? _fill;
|
||||
protected override Size CalculateSize() => new(Width ?? 0, Height ?? 0);
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
var renderState = new RenderState(position, size, Fill);
|
||||
if ((!renderContext.ForceRerender && !NeedsRerender(renderState)) || Fill is null) return false;
|
||||
|
||||
@@ -39,7 +39,7 @@ public partial class StackPanel<T> : ChildContainerView<T>, IVisibilityChangeHan
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
var delta = 0;
|
||||
var neededRerender = false;
|
||||
@@ -56,15 +56,6 @@ public partial class StackPanel<T> : ChildContainerView<T>, IVisibilityChangeHan
|
||||
|
||||
if (!_requestedSizes.TryGetValue(child, out var childSize)) throw new Exception("Child size not found");
|
||||
|
||||
if (forceRerenderChildren.Contains(child))
|
||||
{
|
||||
renderContext = new RenderContext(
|
||||
renderContext.ConsoleDriver,
|
||||
true,
|
||||
renderContext.Foreground,
|
||||
renderContext.Background
|
||||
);
|
||||
}
|
||||
|
||||
var childPosition = Orientation == Orientation.Vertical
|
||||
? position with {Y = position.Y + delta}
|
||||
@@ -84,7 +75,21 @@ public partial class StackPanel<T> : ChildContainerView<T>, IVisibilityChangeHan
|
||||
childSize = childSize with {Height = endY - childPosition.Y};
|
||||
}
|
||||
|
||||
if (forceRerenderChildren.Contains(child))
|
||||
{
|
||||
var rerenderContext = new RenderContext(
|
||||
renderContext.ConsoleDriver,
|
||||
true,
|
||||
renderContext.Foreground,
|
||||
renderContext.Background,
|
||||
renderContext.Statistics
|
||||
);
|
||||
neededRerender = child.Render(rerenderContext, childPosition, childSize) || neededRerender;
|
||||
}
|
||||
else
|
||||
{
|
||||
neededRerender = child.Render(renderContext, childPosition, childSize) || neededRerender;
|
||||
}
|
||||
|
||||
delta += Orientation == Orientation.Vertical
|
||||
? childSize.Height
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using TerminalUI.Color;
|
||||
@@ -46,7 +46,7 @@ public partial class TextBlock<T> : View<T>
|
||||
|
||||
protected override Size CalculateSize() => new(_textLines?.Max(l => l.Length) ?? 0, _textLines?.Length ?? 0);
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (size.Width == 0 || size.Height == 0) return false;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using GeneralInputKey;
|
||||
using GeneralInputKey;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using TerminalUI.Color;
|
||||
using TerminalUI.ConsoleDrivers;
|
||||
@@ -71,7 +71,7 @@ public partial class TextBox<T> : View<T>, IFocusable
|
||||
|
||||
protected override Size CalculateSize() => new(Width ?? 10, Height ?? 1);
|
||||
|
||||
protected override bool DefaultRenderer(RenderContext renderContext, Position position, Size size)
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
var foreground = Foreground ?? renderContext.Foreground;
|
||||
var background = Background ?? renderContext.Background;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Buffers;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -114,9 +114,9 @@ public abstract partial class View<T> : IView<T>
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool DefaultRenderer(RenderContext renderContext, Position position, Size size);
|
||||
protected abstract bool DefaultRenderer(in RenderContext renderContext, Position position, Size size);
|
||||
|
||||
public bool Render(RenderContext renderContext, Position position, Size size)
|
||||
public bool Render(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (!Attached)
|
||||
throw new InvalidOperationException("Cannot render unattached view");
|
||||
@@ -152,7 +152,7 @@ public abstract partial class View<T> : IView<T>
|
||||
return RenderMethod(renderContext, position, size);
|
||||
}
|
||||
|
||||
protected void RenderEmpty(RenderContext renderContext, Position position, Size size)
|
||||
protected void RenderEmpty(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
var driver = renderContext.ConsoleDriver;
|
||||
driver.ResetColor();
|
||||
@@ -236,7 +236,7 @@ public abstract partial class View<T> : IView<T>
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetColorsForDriver(RenderContext renderContext)
|
||||
protected void SetColorsForDriver(in RenderContext renderContext)
|
||||
{
|
||||
var driver = renderContext.ConsoleDriver;
|
||||
|
||||
@@ -316,7 +316,7 @@ public abstract partial class View<T> : IView<T>
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using TerminalUI.Controls;
|
||||
using TerminalUI.Controls;
|
||||
using TerminalUI.Models;
|
||||
using TerminalUI.Traits;
|
||||
|
||||
@@ -114,7 +114,7 @@ public class RenderEngine : IRenderEngine
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderViews(List<IView> views, RenderContext renderContext, Position position, Size size)
|
||||
private void RenderViews(List<IView> views, in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
foreach (var view in views)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||
<PackageReference Include="PropertyChanged.SourceGenerator" Version="1.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
Reference in New Issue
Block a user