Console Binary file preview
This commit is contained in:
@@ -8,6 +8,10 @@ public class MockRenderEngine : IRenderEngine
|
||||
{
|
||||
}
|
||||
|
||||
public void VisibilityChanged(IView view, bool newVisibility)
|
||||
{
|
||||
}
|
||||
|
||||
public void VisibilityChanged(IView view)
|
||||
{
|
||||
}
|
||||
|
||||
126
src/Library/TerminalUI/Controls/BinaryView.cs
Normal file
126
src/Library/TerminalUI/Controls/BinaryView.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System.Reflection.Metadata;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using TerminalUI.Color;
|
||||
using TerminalUI.Models;
|
||||
using TerminalUI.Traits;
|
||||
|
||||
namespace TerminalUI.Controls;
|
||||
|
||||
public partial class BinaryView<T> : View<BinaryView<T>, T>, IDisplayView
|
||||
{
|
||||
private record RenderState(
|
||||
byte[]? Data,
|
||||
int BytesPerLine,
|
||||
Position Position,
|
||||
Size Size,
|
||||
IColor? Foreground,
|
||||
IColor? Background);
|
||||
|
||||
private RenderState? _lastRenderState;
|
||||
|
||||
[Notify] private byte[]? _data;
|
||||
[Notify] private int _bytesPerLine = 16;
|
||||
|
||||
public BinaryView()
|
||||
{
|
||||
RerenderProperties.Add(nameof(Data));
|
||||
RerenderProperties.Add(nameof(BytesPerLine));
|
||||
}
|
||||
|
||||
protected override Size CalculateSize()
|
||||
{
|
||||
if (_data is null) return new(0, 0);
|
||||
if (_data.Length < _bytesPerLine) return new Size(_data.Length, 1);
|
||||
|
||||
var completeLines = (int) Math.Floor((double) _data.Length / _bytesPerLine);
|
||||
var remaining = completeLines * _bytesPerLine - completeLines;
|
||||
|
||||
var lines = remaining > 0 ? completeLines + 1 : completeLines;
|
||||
|
||||
return new Size(_bytesPerLine * 3 - 1, lines);
|
||||
}
|
||||
|
||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||
{
|
||||
if (size.Width < 2 || size.Height == 0) return false;
|
||||
|
||||
var data = _data;
|
||||
var bytesPerLine = _bytesPerLine;
|
||||
if (size.Width < _bytesPerLine * 3 - 1)
|
||||
{
|
||||
bytesPerLine = (int) Math.Floor((double) (size.Width + 1) / 3);
|
||||
}
|
||||
|
||||
var foreground = Foreground ?? renderContext.Foreground;
|
||||
var background = Background ?? renderContext.Background;
|
||||
|
||||
var renderState = new RenderState(
|
||||
data,
|
||||
bytesPerLine,
|
||||
position,
|
||||
size,
|
||||
foreground,
|
||||
background);
|
||||
|
||||
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState);
|
||||
_lastRenderState = renderState;
|
||||
|
||||
if (data is null) return false;
|
||||
|
||||
var lineI = 0;
|
||||
var textSize = size with {Height = 1};
|
||||
for (var i = 0; i < data.Length; i += bytesPerLine, lineI++)
|
||||
{
|
||||
if (lineI > size.Height) break;
|
||||
RenderLine(
|
||||
renderContext,
|
||||
data,
|
||||
i,
|
||||
i + bytesPerLine,
|
||||
position with {Y = position.Y + lineI},
|
||||
textSize,
|
||||
skipRender);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RenderLine(
|
||||
in RenderContext renderContext,
|
||||
byte[] data,
|
||||
int startIndex,
|
||||
int maxEndIndex,
|
||||
Position position,
|
||||
Size size,
|
||||
bool updateCellsOnly
|
||||
)
|
||||
{
|
||||
Span<char> text = stackalloc char[(maxEndIndex - startIndex) * 3 - 1];
|
||||
var textI = 0;
|
||||
for (var i = startIndex; i < maxEndIndex && i < data.Length; i++, textI += 3)
|
||||
{
|
||||
var b = data[i];
|
||||
var b1 = (byte) (b >> 4);
|
||||
var b2 = (byte) (b & 0x0F);
|
||||
|
||||
var c1 = b1 < 10 ? (char) (b1 + '0') : (char) (b1 - 10 + 'A');
|
||||
var c2 = b2 < 10 ? (char) (b2 + '0') : (char) (b2 - 10 + 'A');
|
||||
text[textI] = c1;
|
||||
text[textI + 1] = c2;
|
||||
|
||||
if (textI + 2 < text.Length)
|
||||
text[textI + 2] = ' ';
|
||||
}
|
||||
|
||||
RenderText(
|
||||
text,
|
||||
renderContext,
|
||||
position,
|
||||
size,
|
||||
updateCellsOnly
|
||||
);
|
||||
}
|
||||
|
||||
private bool NeedsRerender(RenderState renderState)
|
||||
=> _lastRenderState is null || _lastRenderState != renderState;
|
||||
}
|
||||
@@ -17,7 +17,8 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
||||
string? Text,
|
||||
IColor? Foreground,
|
||||
IColor? Background,
|
||||
ITextFormat? TextFormat);
|
||||
ITextFormat? TextFormat,
|
||||
bool AsciiOnly);
|
||||
|
||||
private RenderState? _lastRenderState;
|
||||
private string[]? _textLines;
|
||||
@@ -26,6 +27,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
||||
[Notify] private TextAlignment _textAlignment = TextAlignment.Left;
|
||||
[Notify] private ITextFormat? _textFormat;
|
||||
[Notify] private int _textStartIndex;
|
||||
[Notify] private bool _asciiOnly = true;
|
||||
|
||||
public TextBlock()
|
||||
{
|
||||
@@ -33,6 +35,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
||||
RerenderProperties.Add(nameof(TextAlignment));
|
||||
RerenderProperties.Add(nameof(TextFormat));
|
||||
RerenderProperties.Add(nameof(TextStartIndex));
|
||||
RerenderProperties.Add(nameof(AsciiOnly));
|
||||
|
||||
((INotifyPropertyChanged) this).PropertyChanged += (o, e) =>
|
||||
{
|
||||
@@ -51,19 +54,23 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
||||
|
||||
var foreground = Foreground ?? renderContext.Foreground;
|
||||
var background = Background ?? renderContext.Background;
|
||||
var text = Text;
|
||||
var textLines = _textLines;
|
||||
var asciiOnly = _asciiOnly;
|
||||
|
||||
var renderState = new RenderState(
|
||||
position,
|
||||
size,
|
||||
Text,
|
||||
text,
|
||||
foreground,
|
||||
background,
|
||||
_textFormat);
|
||||
_textFormat,
|
||||
asciiOnly);
|
||||
|
||||
var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState);
|
||||
|
||||
_lastRenderState = renderState;
|
||||
|
||||
var textLines = _textLines;
|
||||
var textStartIndex = _textStartIndex;
|
||||
if (textLines is null)
|
||||
{
|
||||
@@ -81,7 +88,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
||||
_textStartIndex = textLines.Length - size.Height;
|
||||
}
|
||||
|
||||
RenderText(textLines, renderContext, position, size, skipRender, TransformText);
|
||||
RenderText(textLines, renderContext, position, size, skipRender, TransformText, asciiOnly);
|
||||
|
||||
return !skipRender;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Buffers;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
@@ -220,10 +220,13 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
||||
|
||||
private static void UpdateCells(bool[,] renderContextUpdatedCells, Position position, int sizeWidth, int sizeHeight)
|
||||
{
|
||||
var xLen = renderContextUpdatedCells.GetLength(0);
|
||||
var yLen = renderContextUpdatedCells.GetLength(1);
|
||||
for (var x = 0; x < sizeWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < sizeHeight; y++)
|
||||
{
|
||||
if (position.X + x >= xLen || position.Y + y >= yLen) continue;
|
||||
renderContextUpdatedCells[position.X + x, position.Y + y] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user