FilePreview use ASCII only, force rerender when item disappears
This commit is contained in:
@@ -79,9 +79,11 @@ public class ItemPreviews
|
|||||||
.Setup(t => t.Bind(
|
.Setup(t => t.Bind(
|
||||||
t,
|
t,
|
||||||
dc => dc.TextContent,
|
dc => dc.TextContent,
|
||||||
t => t.Text)),
|
t => t.Text,
|
||||||
|
fallbackValue: string.Empty)),
|
||||||
new TextBlock<IElementPreviewViewModel>
|
new TextBlock<IElementPreviewViewModel>
|
||||||
{
|
{
|
||||||
|
Margin = "0 1 0 0",
|
||||||
Extensions = {new GridPositionExtension(0, 1)}
|
Extensions = {new GridPositionExtension(0, 1)}
|
||||||
}.Setup(t => t.Bind(
|
}.Setup(t => t.Bind(
|
||||||
t,
|
t,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using TerminalUI.Controls;
|
using TerminalUI.Controls;
|
||||||
using TerminalUI.ExpressionTrackers;
|
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
|
|
||||||
namespace TerminalUI;
|
namespace TerminalUI;
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ namespace TerminalUI.ConsoleDrivers;
|
|||||||
|
|
||||||
public class DotnetDriver : IConsoleDriver
|
public class DotnetDriver : IConsoleDriver
|
||||||
{
|
{
|
||||||
|
protected bool CheckThreadId;
|
||||||
public bool SupportsAnsiEscapeSequence { get; protected set; }
|
public bool SupportsAnsiEscapeSequence { get; protected set; }
|
||||||
|
public int ThreadId { get; set; }
|
||||||
|
|
||||||
|
public void EnterRestrictedMode() => CheckThreadId = true;
|
||||||
|
|
||||||
public virtual bool Init()
|
public virtual bool Init()
|
||||||
{
|
{
|
||||||
@@ -25,10 +29,31 @@ public class DotnetDriver : IConsoleDriver
|
|||||||
return new(x, y);
|
return new(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(string text) => Console.Out.Write(text);
|
public void Write(string text)
|
||||||
public void Write(ReadOnlySpan<char> text) => Console.Out.Write(text);
|
{
|
||||||
|
CheckThread();
|
||||||
|
Console.Out.Write(text);
|
||||||
|
}
|
||||||
|
|
||||||
public void Write(char text) => Console.Out.Write(text);
|
public void Write(ReadOnlySpan<char> text)
|
||||||
|
{
|
||||||
|
CheckThread();
|
||||||
|
Console.Out.Write(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(char text)
|
||||||
|
{
|
||||||
|
CheckThread();
|
||||||
|
Console.Out.Write(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckThread()
|
||||||
|
{
|
||||||
|
if (CheckThreadId && ThreadId != Thread.CurrentThread.ManagedThreadId)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cannot write to console from another thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Dispose() => Console.Clear();
|
public virtual void Dispose() => Console.Clear();
|
||||||
|
|
||||||
@@ -40,7 +65,7 @@ public class DotnetDriver : IConsoleDriver
|
|||||||
public virtual void SetForegroundColor(IColor foreground)
|
public virtual void SetForegroundColor(IColor foreground)
|
||||||
{
|
{
|
||||||
if (foreground == SpecialColor.None) return;
|
if (foreground == SpecialColor.None) return;
|
||||||
|
|
||||||
if (foreground is not ConsoleColor consoleColor) throw new NotSupportedException();
|
if (foreground is not ConsoleColor consoleColor) throw new NotSupportedException();
|
||||||
Console.ForegroundColor = consoleColor.Color;
|
Console.ForegroundColor = consoleColor.Color;
|
||||||
}
|
}
|
||||||
@@ -48,7 +73,7 @@ public class DotnetDriver : IConsoleDriver
|
|||||||
public virtual void SetBackgroundColor(IColor background)
|
public virtual void SetBackgroundColor(IColor background)
|
||||||
{
|
{
|
||||||
if (background == SpecialColor.None) return;
|
if (background == SpecialColor.None) return;
|
||||||
|
|
||||||
if (background is not ConsoleColor consoleColor) throw new NotSupportedException();
|
if (background is not ConsoleColor consoleColor) throw new NotSupportedException();
|
||||||
Console.BackgroundColor = consoleColor.Color;
|
Console.BackgroundColor = consoleColor.Color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace TerminalUI.ConsoleDrivers;
|
|||||||
public interface IConsoleDriver
|
public interface IConsoleDriver
|
||||||
{
|
{
|
||||||
bool SupportsAnsiEscapeSequence { get; }
|
bool SupportsAnsiEscapeSequence { get; }
|
||||||
|
int ThreadId { get; set; }
|
||||||
bool Init();
|
bool Init();
|
||||||
void Dispose();
|
void Dispose();
|
||||||
void SetCursorPosition(Position position);
|
void SetCursorPosition(Position position);
|
||||||
@@ -22,4 +23,5 @@ public interface IConsoleDriver
|
|||||||
void SetBackgroundColor(IColor background);
|
void SetBackgroundColor(IColor background);
|
||||||
Size GetWindowSize();
|
Size GetWindowSize();
|
||||||
void Clear();
|
void Clear();
|
||||||
|
void EnterRestrictedMode();
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ public sealed class XTermDriver : DotnetDriver
|
|||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
|
CheckThreadId = false;
|
||||||
Write("\x1b[?1047l");
|
Write("\x1b[?1047l");
|
||||||
SetCursorPosition(_initialCursorPosition);
|
SetCursorPosition(_initialCursorPosition);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace TerminalUI.Controls;
|
namespace TerminalUI.Controls;
|
||||||
|
|
||||||
|
|||||||
@@ -96,37 +96,6 @@ public sealed partial class StackPanel<T> : ChildCollectionView<StackPanel<T>, T
|
|||||||
: childSize.Width;
|
: childSize.Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Orientation == Orientation.Horizontal)
|
|
||||||
{
|
|
||||||
var leftWidth = size.Width - delta;
|
|
||||||
Span<char> text = stackalloc char[leftWidth];
|
|
||||||
text.Fill(ApplicationContext!.EmptyCharacter);
|
|
||||||
|
|
||||||
SetColorsForDriver(renderContext);
|
|
||||||
RenderText(
|
|
||||||
text,
|
|
||||||
renderContext,
|
|
||||||
position with {X = position.X + delta},
|
|
||||||
size with {Width = leftWidth},
|
|
||||||
!neededRerender
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var leftHeight = size.Height - delta;
|
|
||||||
Span<char> text = stackalloc char[size.Width];
|
|
||||||
text.Fill(ApplicationContext!.EmptyCharacter);
|
|
||||||
|
|
||||||
SetColorsForDriver(renderContext);
|
|
||||||
RenderText(
|
|
||||||
text,
|
|
||||||
renderContext,
|
|
||||||
position with {Y = position.Y + delta},
|
|
||||||
size with {Height = leftHeight},
|
|
||||||
!neededRerender
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return neededRerender;
|
return neededRerender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
|
|
||||||
private RenderState? _lastRenderState;
|
private RenderState? _lastRenderState;
|
||||||
private string[]? _textLines;
|
private string[]? _textLines;
|
||||||
private bool _placeholderRenderDone;
|
|
||||||
|
|
||||||
[Notify] private string? _text = string.Empty;
|
[Notify] private string? _text = string.Empty;
|
||||||
[Notify] private TextAlignment _textAlignment = TextAlignment.Left;
|
[Notify] private TextAlignment _textAlignment = TextAlignment.Left;
|
||||||
@@ -64,30 +63,22 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
|
|
||||||
_lastRenderState = renderState;
|
_lastRenderState = renderState;
|
||||||
|
|
||||||
if (_textLines is null)
|
var textLines = _textLines;
|
||||||
|
var textStartIndex = _textStartIndex;
|
||||||
|
if (textLines is null)
|
||||||
{
|
{
|
||||||
if (!_placeholderRenderDone)
|
|
||||||
{
|
|
||||||
_placeholderRenderDone = true;
|
|
||||||
RenderEmpty(renderContext, position, size, skipRender);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_placeholderRenderDone = false;
|
|
||||||
|
|
||||||
SetStyleColor(renderContext, foreground, background, _textFormat);
|
SetStyleColor(renderContext, foreground, background, _textFormat);
|
||||||
|
|
||||||
var textLines = _textLines;
|
if (textStartIndex < textLines.Length)
|
||||||
if (_textStartIndex < _textLines.Length)
|
|
||||||
{
|
{
|
||||||
textLines = _textLines[_textStartIndex..];
|
textLines = textLines[textStartIndex..];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_textStartIndex = _textLines.Length - size.Height;
|
_textStartIndex = textLines.Length - size.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderText(textLines, renderContext, position, size, skipRender, TransformText);
|
RenderText(textLines, renderContext, position, size, skipRender, TransformText);
|
||||||
@@ -99,7 +90,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
=> TextAlignment switch
|
=> TextAlignment switch
|
||||||
{
|
{
|
||||||
TextAlignment.Right => string.Format($"{{0,{size.Width}}}", text),
|
TextAlignment.Right => string.Format($"{{0,{size.Width}}}", text),
|
||||||
_ => string.Format($"{{0,{-size.Width}}}", text)
|
_ => text
|
||||||
};
|
};
|
||||||
|
|
||||||
private bool NeedsRerender(RenderState renderState)
|
private bool NeedsRerender(RenderState renderState)
|
||||||
|
|||||||
@@ -103,11 +103,8 @@ public sealed partial class TextBox<T> : View<TextBox<T>, T>, IFocusable, IDispl
|
|||||||
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderStatus);
|
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderStatus);
|
||||||
_lastRenderState = renderStatus;
|
_lastRenderState = renderStatus;
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
|
||||||
SetStyleColor(renderContext, foreground, background);
|
SetStyleColor(renderContext, foreground, background);
|
||||||
|
|
||||||
RenderEmpty(renderContext, position, size, skipRender);
|
|
||||||
|
|
||||||
if (PasswordChar is { } passwordChar && !char.IsControl(passwordChar))
|
if (PasswordChar is { } passwordChar && !char.IsControl(passwordChar))
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _textLines.Count; i++)
|
for (var i = 0; i < _textLines.Count; i++)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
}
|
}
|
||||||
else if (e.PropertyName == nameof(IsVisible))
|
else if (e.PropertyName == nameof(IsVisible))
|
||||||
{
|
{
|
||||||
ApplicationContext?.RenderEngine.VisibilityChanged(this);
|
ApplicationContext?.RenderEngine.VisibilityChanged(this, IsVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCells(bool[,] renderContextUpdatedCells, Position position, int sizeWidth, int sizeHeight)
|
private static void UpdateCells(bool[,] renderContextUpdatedCells, Position position, int sizeWidth, int sizeHeight)
|
||||||
{
|
{
|
||||||
for (var x = 0; x < sizeWidth; x++)
|
for (var x = 0; x < sizeWidth; x++)
|
||||||
{
|
{
|
||||||
@@ -235,14 +235,12 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
Position position,
|
Position position,
|
||||||
Size size,
|
Size size,
|
||||||
bool updateCellsOnly,
|
bool updateCellsOnly,
|
||||||
TextTransformer? textTransformer = null)
|
TextTransformer? textTransformer = null,
|
||||||
|
bool useAsciiOnly = true)
|
||||||
{
|
{
|
||||||
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
|
|
||||||
|
|
||||||
if (updateCellsOnly) return;
|
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
for (var i = 0; i < textLines.Count; i++)
|
var end = int.Min(textLines.Count, size.Height);
|
||||||
|
for (var i = 0; i < end; i++)
|
||||||
{
|
{
|
||||||
var currentPosition = position with {Y = position.Y + i};
|
var currentPosition = position with {Y = position.Y + i};
|
||||||
var text = textLines[i];
|
var text = textLines[i];
|
||||||
@@ -252,22 +250,40 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
text = textTransformer(text, currentPosition, size);
|
text = textTransformer(text, currentPosition, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.Length > size.Width)
|
if (useAsciiOnly)
|
||||||
{
|
{
|
||||||
text = text[..size.Width];
|
RenderTextAsciiOnly(
|
||||||
|
text,
|
||||||
|
renderContext,
|
||||||
|
currentPosition,
|
||||||
|
size.Width,
|
||||||
|
updateCellsOnly);
|
||||||
}
|
}
|
||||||
else if (text.Length < size.Width)
|
else
|
||||||
{
|
{
|
||||||
text = text.PadRight(size.Width);
|
if (text.Length > size.Width)
|
||||||
}
|
{
|
||||||
|
text = text[..size.Width];
|
||||||
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
foreach (var c in text)
|
||||||
driver.SetCursorPosition(currentPosition);
|
{
|
||||||
driver.Write(text);
|
if (char.IsControl(c))
|
||||||
}
|
throw new Exception("Control character");
|
||||||
catch
|
}
|
||||||
{
|
|
||||||
|
if (updateCellsOnly) continue;
|
||||||
|
UpdateCells(renderContext.UpdatedCells, currentPosition, text.Length, 1);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
driver.SetCursorPosition(currentPosition);
|
||||||
|
driver.Write(text);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,10 +295,6 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
Size size,
|
Size size,
|
||||||
bool updateCellsOnly)
|
bool updateCellsOnly)
|
||||||
{
|
{
|
||||||
UpdateCells(renderContext.UpdatedCells, position, size.Width, size.Height);
|
|
||||||
|
|
||||||
if (updateCellsOnly) return;
|
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
for (var i = 0; i < size.Height; i++)
|
for (var i = 0; i < size.Height; i++)
|
||||||
{
|
{
|
||||||
@@ -294,6 +306,9 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
finalText = finalText[..size.Width];
|
finalText = finalText[..size.Width];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateCells(renderContext.UpdatedCells, currentPosition, finalText.Length, 1);
|
||||||
|
if (updateCellsOnly) continue;
|
||||||
|
|
||||||
driver.SetCursorPosition(currentPosition);
|
driver.SetCursorPosition(currentPosition);
|
||||||
driver.Write(finalText);
|
driver.Write(finalText);
|
||||||
}
|
}
|
||||||
@@ -311,7 +326,8 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
if (updateCellsOnly) return;
|
if (updateCellsOnly) return;
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
var contentString = new string(content, size.Width);
|
Span<char> contentString = stackalloc char[size.Width];
|
||||||
|
contentString.Fill(content);
|
||||||
|
|
||||||
for (var i = 0; i < size.Height; i++)
|
for (var i = 0; i < size.Height; i++)
|
||||||
{
|
{
|
||||||
@@ -322,6 +338,37 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderTextAsciiOnly(
|
||||||
|
ReadOnlySpan<char> text,
|
||||||
|
in RenderContext renderContext,
|
||||||
|
Position position,
|
||||||
|
int width,
|
||||||
|
bool updateCellsOnly)
|
||||||
|
{
|
||||||
|
Span<char> finalText = stackalloc char[width];
|
||||||
|
|
||||||
|
var finalTextPosition = 0;
|
||||||
|
for (var i = 0; i < text.Length && finalTextPosition < width; i++)
|
||||||
|
{
|
||||||
|
var c = text[i];
|
||||||
|
if (c < 32 || c > 255) continue;
|
||||||
|
|
||||||
|
finalText[finalTextPosition] = c;
|
||||||
|
finalTextPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < finalTextPosition; i++)
|
||||||
|
{
|
||||||
|
renderContext.UpdatedCells[position.X + i, position.Y] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateCellsOnly) return;
|
||||||
|
|
||||||
|
var driver = renderContext.ConsoleDriver;
|
||||||
|
driver.SetCursorPosition(position);
|
||||||
|
driver.Write(finalText[..finalTextPosition]);
|
||||||
|
}
|
||||||
|
|
||||||
protected void SetStyleColor(
|
protected void SetStyleColor(
|
||||||
in RenderContext renderContext,
|
in RenderContext renderContext,
|
||||||
IColor? foreground = null,
|
IColor? foreground = null,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace TerminalUI;
|
namespace TerminalUI;
|
||||||
|
|
||||||
@@ -7,8 +6,11 @@ public class EventLoop : IEventLoop
|
|||||||
{
|
{
|
||||||
private readonly IApplicationContext _applicationContext;
|
private readonly IApplicationContext _applicationContext;
|
||||||
private readonly ILogger<EventLoop> _logger;
|
private readonly ILogger<EventLoop> _logger;
|
||||||
|
private readonly List<Action> _initializers = new();
|
||||||
private readonly List<Action> _permanentQueue = new();
|
private readonly List<Action> _permanentQueue = new();
|
||||||
|
|
||||||
|
public int ThreadId { get; set; } = -1;
|
||||||
|
|
||||||
public EventLoop(
|
public EventLoop(
|
||||||
IApplicationContext applicationContext,
|
IApplicationContext applicationContext,
|
||||||
ILogger<EventLoop> logger)
|
ILogger<EventLoop> logger)
|
||||||
@@ -18,15 +20,22 @@ public class EventLoop : IEventLoop
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void AddToPermanentQueue(Action action) => _permanentQueue.Add(action);
|
public void AddToPermanentQueue(Action action) => _permanentQueue.Add(action);
|
||||||
|
public void AddInitializer(Action action) => _initializers.Add(action);
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
_applicationContext.IsRunning = true;
|
_applicationContext.IsRunning = true;
|
||||||
|
ThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||||
|
foreach (var initializer in _initializers)
|
||||||
|
{
|
||||||
|
initializer();
|
||||||
|
}
|
||||||
while (_applicationContext.IsRunning)
|
while (_applicationContext.IsRunning)
|
||||||
{
|
{
|
||||||
ProcessQueues();
|
ProcessQueues();
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
|
ThreadId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessQueues()
|
private void ProcessQueues()
|
||||||
@@ -35,7 +44,7 @@ public class EventLoop : IEventLoop
|
|||||||
{
|
{
|
||||||
/*try
|
/*try
|
||||||
{*/
|
{*/
|
||||||
action();
|
action();
|
||||||
/*}
|
/*}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ public interface IEventLoop
|
|||||||
{
|
{
|
||||||
void Run();
|
void Run();
|
||||||
void AddToPermanentQueue(Action action);
|
void AddToPermanentQueue(Action action);
|
||||||
|
void AddInitializer(Action action);
|
||||||
|
int ThreadId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace TerminalUI;
|
|||||||
public interface IRenderEngine
|
public interface IRenderEngine
|
||||||
{
|
{
|
||||||
void RequestRerender(IView view);
|
void RequestRerender(IView view);
|
||||||
void VisibilityChanged(IView view);
|
void VisibilityChanged(IView view, bool newVisibility);
|
||||||
void AddViewToPermanentRenderGroup(IView view);
|
void AddViewToPermanentRenderGroup(IView view);
|
||||||
void Run();
|
void Run();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using TerminalUI.ConsoleDrivers;
|
using TerminalUI.Controls;
|
||||||
using TerminalUI.Controls;
|
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
using TerminalUI.TextFormat;
|
using TerminalUI.TextFormat;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
@@ -15,9 +14,11 @@ public class RenderEngine : IRenderEngine
|
|||||||
private readonly List<IView> _forcedTemporaryViewsToRender = new();
|
private readonly List<IView> _forcedTemporaryViewsToRender = new();
|
||||||
private bool _rerenderRequested = true;
|
private bool _rerenderRequested = true;
|
||||||
private bool _lastCursorVisible;
|
private bool _lastCursorVisible;
|
||||||
|
private bool _forceRerenderAll;
|
||||||
private bool[,]? _updatedCells;
|
private bool[,]? _updatedCells;
|
||||||
private bool[,]? _filledCells;
|
private bool[,]? _filledCells;
|
||||||
private bool[,]? _lastFilledCells;
|
private bool[,]? _lastFilledCells;
|
||||||
|
private DateTime _renderRequestDetected;
|
||||||
|
|
||||||
public RenderEngine(IApplicationContext applicationContext, IEventLoop eventLoop)
|
public RenderEngine(IApplicationContext applicationContext, IEventLoop eventLoop)
|
||||||
{
|
{
|
||||||
@@ -25,12 +26,23 @@ public class RenderEngine : IRenderEngine
|
|||||||
_eventLoop = eventLoop;
|
_eventLoop = eventLoop;
|
||||||
|
|
||||||
_eventLoop.AddToPermanentQueue(Render);
|
_eventLoop.AddToPermanentQueue(Render);
|
||||||
|
_eventLoop.AddInitializer(() =>
|
||||||
|
{
|
||||||
|
_applicationContext.ConsoleDriver.ThreadId = _eventLoop.ThreadId;
|
||||||
|
_applicationContext.ConsoleDriver.EnterRestrictedMode();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RequestRerender(IView view) => RequestRerender();
|
public void RequestRerender(IView view) => RequestRerender();
|
||||||
|
|
||||||
public void VisibilityChanged(IView view)
|
public void VisibilityChanged(IView view, bool newVisibility)
|
||||||
{
|
{
|
||||||
|
if (!newVisibility)
|
||||||
|
{
|
||||||
|
_forceRerenderAll = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IVisibilityChangeHandler? visibilityChangeHandler = null;
|
IVisibilityChangeHandler? visibilityChangeHandler = null;
|
||||||
var parent = view.VisualParent;
|
var parent = view.VisualParent;
|
||||||
while (parent?.VisualParent != null)
|
while (parent?.VisualParent != null)
|
||||||
@@ -46,12 +58,11 @@ public class RenderEngine : IRenderEngine
|
|||||||
|
|
||||||
if (visibilityChangeHandler is null)
|
if (visibilityChangeHandler is null)
|
||||||
{
|
{
|
||||||
AddViewToForcedTemporaryRenderGroup(parent ?? view);
|
//AddViewToForcedTemporaryRenderGroup(parent ?? view);
|
||||||
}
|
return;
|
||||||
else
|
|
||||||
{
|
|
||||||
visibilityChangeHandler.ChildVisibilityChanged(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visibilityChangeHandler.ChildVisibilityChanged(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run() => _eventLoop.Run();
|
public void Run() => _eventLoop.Run();
|
||||||
@@ -68,6 +79,7 @@ public class RenderEngine : IRenderEngine
|
|||||||
{
|
{
|
||||||
List<IView> permanentViewsToRender;
|
List<IView> permanentViewsToRender;
|
||||||
List<IView> forcedTemporaryViewsToRender;
|
List<IView> forcedTemporaryViewsToRender;
|
||||||
|
bool forceRerenderAll;
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_rerenderRequested) return;
|
if (!_rerenderRequested) return;
|
||||||
@@ -75,6 +87,9 @@ public class RenderEngine : IRenderEngine
|
|||||||
permanentViewsToRender = _permanentViewsToRender.ToList();
|
permanentViewsToRender = _permanentViewsToRender.ToList();
|
||||||
forcedTemporaryViewsToRender = _forcedTemporaryViewsToRender.ToList();
|
forcedTemporaryViewsToRender = _forcedTemporaryViewsToRender.ToList();
|
||||||
_forcedTemporaryViewsToRender.Clear();
|
_forcedTemporaryViewsToRender.Clear();
|
||||||
|
|
||||||
|
forceRerenderAll = _forceRerenderAll;
|
||||||
|
_forceRerenderAll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var driver = _applicationContext.ConsoleDriver;
|
var driver = _applicationContext.ConsoleDriver;
|
||||||
@@ -93,25 +108,28 @@ public class RenderEngine : IRenderEngine
|
|||||||
ClearArray2D(_updatedCells);
|
ClearArray2D(_updatedCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderViews(
|
if (!forceRerenderAll)
|
||||||
forcedTemporaryViewsToRender,
|
{
|
||||||
new RenderContext(
|
RenderViews(
|
||||||
driver,
|
forcedTemporaryViewsToRender,
|
||||||
true,
|
new RenderContext(
|
||||||
null,
|
driver,
|
||||||
null,
|
true,
|
||||||
new RenderStatistics(),
|
null,
|
||||||
new TextFormatContext(driver.SupportsAnsiEscapeSequence),
|
null,
|
||||||
_updatedCells
|
new RenderStatistics(),
|
||||||
),
|
new TextFormatContext(driver.SupportsAnsiEscapeSequence),
|
||||||
initialPosition,
|
_updatedCells
|
||||||
size);
|
),
|
||||||
|
initialPosition,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
RenderViews(
|
RenderViews(
|
||||||
permanentViewsToRender,
|
permanentViewsToRender,
|
||||||
new RenderContext(
|
new RenderContext(
|
||||||
driver,
|
driver,
|
||||||
false,
|
forceRerenderAll,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RenderStatistics(),
|
new RenderStatistics(),
|
||||||
|
|||||||
@@ -24,8 +24,4 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="KeyHandling\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user