Console Binary file preview

This commit is contained in:
2023-08-20 07:37:28 +02:00
parent 570ecd3f83
commit 845a37050f
23 changed files with 391 additions and 23 deletions

View 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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}