MParser/MApplication/DisplayTextViewPort.cs

265 lines
9.5 KiB
C#

using System;
namespace MApplication
{
internal class DisplayTextViewPort
{
public DisplayTextViewPort(
DisplayText text,
int width,
int height,
int startingColumn = 0,
int startingLine = 0,
int cursorAbsoluteColumn = 0,
int cursorAbsoluteLine = 0,
int virtualCursorAbsoluteColumn = 0)
{
Text = text;
Width = width;
Height = height;
StartingColumn = startingColumn;
StartingLine = startingLine;
CursorAbsoluteColumn = cursorAbsoluteColumn;
CursorAbsoluteLine = cursorAbsoluteLine;
VirtualCursorAbsoluteColumn = virtualCursorAbsoluteColumn;
}
public DisplayText Text { get; }
public int Width { get; }
public int Height { get; }
public int StartingColumn { get; }
public int StartingLine { get; }
public int CursorRelativeColumn => CursorAbsoluteColumn - StartingColumn;
public int CursorRelativeLine => CursorAbsoluteLine - StartingLine;
public int CursorAbsoluteColumn { get; }
public int CursorAbsoluteLine { get; }
public int VirtualCursorAbsoluteColumn { get; }
public int CurrentLineWidth => Text.Lines[CursorAbsoluteLine].Width;
public DisplayTextViewPort CursorLeft(out bool needsRedraw)
{
var newCursorAbsoluteColumn = Math.Max(CursorAbsoluteColumn - 1, 0);
if (CursorRelativeColumn == 0)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn,
startingColumn: Math.Max(StartingColumn - 1, 0));
}
else
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn);
}
}
public DisplayTextViewPort CursorRight(out bool needsRedraw)
{
var newCursorAbsoluteColumn = Math.Min(CursorAbsoluteColumn + 1, CurrentLineWidth);
if (CursorRelativeColumn == Width - 1)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn,
startingColumn: StartingColumn + 1);
}
else
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn);
}
}
private DisplayTextViewPort SnapToLine(out bool needsRedraw)
{
var cursorAbsoluteColumn = Math.Min(VirtualCursorAbsoluteColumn, CurrentLineWidth);
if (cursorAbsoluteColumn < StartingColumn)
{
return With(
out needsRedraw,
startingColumn: cursorAbsoluteColumn,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
if (cursorAbsoluteColumn > StartingColumn + Width - 1)
{
return With(
out needsRedraw,
startingColumn: cursorAbsoluteColumn - Width + 1,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
return With(
out needsRedraw,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
public DisplayTextViewPort CursorUp(out bool needsRedraw)
{
bool changed1;
var result1 = CursorRelativeLine switch
{
0 => With(
out changed1,
startingLine: Math.Max(StartingLine - 1, 0),
cursorAbsoluteLine: Math.Max(StartingLine - 1, 0)),
_ => With(out changed1, cursorAbsoluteLine: CursorAbsoluteLine - 1),
};
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
public DisplayTextViewPort CursorDown(out bool needsRedraw)
{
bool changed1;
var result1 = CursorRelativeLine switch
{
_ when CursorRelativeLine == Height - 1 =>
With(
out changed1,
startingLine: Math.Min(CursorAbsoluteLine + 1, Text.Lines.Count) - Height + 1,
cursorAbsoluteLine: Math.Min(CursorAbsoluteLine + 1, Text.Lines.Count)),
_ => With(
out changed1,
cursorAbsoluteLine: CursorAbsoluteLine + 1),
};
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
public DisplayTextViewPort CursorHome(out bool needsRedraw)
{
return With(
out needsRedraw,
startingColumn: 0,
cursorAbsoluteColumn: 0,
virtualCursorAbsoluteColumn: 0);
}
public DisplayTextViewPort CursorEnd(out bool needsRedraw)
{
var lineWidth = Text.Lines[CursorAbsoluteLine].Width;
var toAdd = lineWidth - CursorAbsoluteColumn;
if (toAdd == 0)
{
needsRedraw = false;
return this;
}
if (CursorRelativeColumn + toAdd < Width)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: CursorAbsoluteColumn + toAdd,
virtualCursorAbsoluteColumn: CursorAbsoluteColumn + toAdd);
}
return With(
out needsRedraw,
startingColumn: lineWidth - Width + 1,
cursorAbsoluteColumn: lineWidth,
virtualCursorAbsoluteColumn: lineWidth);
}
public void RenderTo(IOutputView view)
{
view.HideCursor();
for (var lineNumber = StartingLine; lineNumber < StartingLine + Height; lineNumber++)
{
view.MoveCursorTo(0, lineNumber - StartingLine);
if (lineNumber >= Text.Lines.Count)
{
view.WriteText(new string(' ', Width));
continue;
}
var line = Text.Lines[lineNumber];
var startsIn = StartingColumn;
foreach (var chunk in line.Chunks)
{
var left = Math.Max(0, startsIn);
var right = Math.Min(chunk.Width, startsIn + Width);
if (left < right)
{
view.SetStyle(chunk.Style);
view.WriteText(chunk.Text[left..right].ToString());
}
startsIn -= chunk.Width;
if (startsIn + Width <= 0)
{
break;
}
}
if (startsIn + Width > 0)
{
var numberOfSpaces = Math.Min(startsIn + Width, Width);
view.WriteText(new string(' ', numberOfSpaces));
}
}
view.MoveCursorTo(column: CursorRelativeColumn, line: CursorRelativeLine);
view.ShowCursor();
}
public DisplayTextViewPort With(
out bool changed,
int? width = null,
int? height = null,
int? startingColumn = null,
int? startingLine = null,
int? cursorAbsoluteColumn = null,
int? cursorAbsoluteLine = null,
int? virtualCursorAbsoluteColumn = null)
{
var widthValue = width ?? Width;
var heightValue = height ?? Height;
var startingColumnValue = startingColumn ?? StartingColumn;
var startingLineValue = startingLine ?? StartingLine;
var cursorAbsoluteColumnValue = cursorAbsoluteColumn ?? CursorAbsoluteColumn;
var cursorAbsoluteLineValue = cursorAbsoluteLine ?? CursorAbsoluteLine;
var virtualCursorAbsoluteColumnValue = virtualCursorAbsoluteColumn ?? VirtualCursorAbsoluteColumn;
if (widthValue == Width &&
heightValue == Height &&
startingColumnValue == StartingColumn &&
startingLineValue == StartingLine &&
cursorAbsoluteColumnValue == CursorAbsoluteColumn &&
cursorAbsoluteLineValue == CursorAbsoluteLine &&
virtualCursorAbsoluteColumnValue == VirtualCursorAbsoluteColumn)
{
changed = false;
return this;
}
changed = true;
return new DisplayTextViewPort(
text: Text,
width: widthValue,
height: heightValue,
startingColumn: startingColumnValue,
startingLine: startingLineValue,
cursorAbsoluteColumn: cursorAbsoluteColumnValue,
cursorAbsoluteLine: cursorAbsoluteLineValue,
virtualCursorAbsoluteColumn: virtualCursorAbsoluteColumnValue);
}
}
}