TextFormat
This commit is contained in:
@@ -8,6 +8,7 @@ using GeneralInputKey;
|
|||||||
using TerminalUI.Controls;
|
using TerminalUI.Controls;
|
||||||
using TerminalUI.Extensions;
|
using TerminalUI.Extensions;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
using TerminalUI.ViewExtensions;
|
using TerminalUI.ViewExtensions;
|
||||||
|
|
||||||
@@ -22,11 +23,26 @@ public class Dialogs
|
|||||||
|
|
||||||
private Action? _readInputChildHandlerUnSubscriber;
|
private Action? _readInputChildHandlerUnSubscriber;
|
||||||
|
|
||||||
|
|
||||||
|
private readonly ITextFormat _specialItemNamePartFormat;
|
||||||
|
|
||||||
public Dialogs(IRootViewModel rootViewModel, ITheme theme)
|
public Dialogs(IRootViewModel rootViewModel, ITheme theme)
|
||||||
{
|
{
|
||||||
_rootViewModel = rootViewModel;
|
_rootViewModel = rootViewModel;
|
||||||
_theme = theme;
|
_theme = theme;
|
||||||
|
|
||||||
|
_specialItemNamePartFormat = new OrFormat
|
||||||
|
{
|
||||||
|
Format1 = new AnsiFormat
|
||||||
|
{
|
||||||
|
IsUnderline = true
|
||||||
|
},
|
||||||
|
Format2 = new SimpleFormat
|
||||||
|
{
|
||||||
|
Foreground = _theme.DefaultForegroundAccentColor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
rootViewModel.FocusReadInputElement += element =>
|
rootViewModel.FocusReadInputElement += element =>
|
||||||
{
|
{
|
||||||
_inputElementToFocus = element;
|
_inputElementToFocus = element;
|
||||||
@@ -185,16 +201,15 @@ public class Dialogs
|
|||||||
ColumnDefinitionsObject = "* *",
|
ColumnDefinitionsObject = "* *",
|
||||||
ChildInitializer =
|
ChildInitializer =
|
||||||
{
|
{
|
||||||
new ItemsControl<IPreviewElement, ItemNamePart>()
|
new ItemsControl<IPreviewElement, ItemNamePart>
|
||||||
{
|
{
|
||||||
Orientation = Orientation.Horizontal,
|
Orientation = Orientation.Horizontal,
|
||||||
ItemTemplate = ItemNamePartItemTemplate
|
ItemTemplate = ItemNamePartItemTemplate
|
||||||
}.Setup(i => i.Bind(
|
}.Setup(i => i.Bind(
|
||||||
i,
|
i,
|
||||||
dc => ((DoubleItemNamePartListPreview) dc).ItemNameParts1,
|
dc => ((DoubleItemNamePartListPreview) dc).ItemNameParts1,
|
||||||
c => c.ItemsSource,
|
c => c.ItemsSource)),
|
||||||
v => v)),
|
new ItemsControl<IPreviewElement, ItemNamePart>
|
||||||
new ItemsControl<IPreviewElement, ItemNamePart>()
|
|
||||||
{
|
{
|
||||||
Orientation = Orientation.Horizontal,
|
Orientation = Orientation.Horizontal,
|
||||||
Extensions =
|
Extensions =
|
||||||
@@ -226,8 +241,8 @@ public class Dialogs
|
|||||||
);
|
);
|
||||||
textBlock.Bind(
|
textBlock.Bind(
|
||||||
textBlock,
|
textBlock,
|
||||||
dc => dc.IsSpecial ? _theme.DefaultForegroundAccentColor : null,
|
dc => dc.IsSpecial ? _specialItemNamePartFormat : null,
|
||||||
tb => tb.Foreground
|
tb => tb.TextFormat
|
||||||
);
|
);
|
||||||
|
|
||||||
return textBlock;
|
return textBlock;
|
||||||
@@ -327,8 +342,7 @@ public class Dialogs
|
|||||||
.Setup(t => t.Bind(
|
.Setup(t => t.Bind(
|
||||||
t,
|
t,
|
||||||
d => d.DialogService.ReadInput.Value.Inputs,
|
d => d.DialogService.ReadInput.Value.Inputs,
|
||||||
c => c.ItemsSource,
|
c => c.ItemsSource
|
||||||
v => v
|
|
||||||
));
|
));
|
||||||
|
|
||||||
readInputs.WithKeyHandler((_, e) =>
|
readInputs.WithKeyHandler((_, e) =>
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ public class Timeline
|
|||||||
.Setup(i => i.Bind(
|
.Setup(i => i.Bind(
|
||||||
i,
|
i,
|
||||||
dc => dc.TimelineViewModel.ParallelCommandsGroups[0].Commands,
|
dc => dc.TimelineViewModel.ParallelCommandsGroups[0].Commands,
|
||||||
i => i.ItemsSource,
|
i => i.ItemsSource))
|
||||||
v => v))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,30 @@ public class MainWindow
|
|||||||
},
|
},
|
||||||
ChildInitializer =
|
ChildInitializer =
|
||||||
{
|
{
|
||||||
|
new StackPanel<IRootViewModel>
|
||||||
|
{
|
||||||
|
Orientation = Orientation.Horizontal,
|
||||||
|
ChildInitializer =
|
||||||
|
{
|
||||||
|
new TextBlock<IRootViewModel>
|
||||||
|
{
|
||||||
|
Margin = "0 0 1 0",
|
||||||
|
}
|
||||||
|
.Setup(t => t.Bind(
|
||||||
|
t,
|
||||||
|
dc => dc.AppState.SelectedTab.Value.CurrentSelectedItem.Value.Attributes,
|
||||||
|
tb => tb.Text)),
|
||||||
|
new TextBlock<IRootViewModel>
|
||||||
|
{
|
||||||
|
Margin = "0 0 1 0",
|
||||||
|
}
|
||||||
|
.Setup(t => t.Bind(
|
||||||
|
t,
|
||||||
|
dc => dc.AppState.SelectedTab.Value.CurrentSelectedItem.Value.ModifiedAt,
|
||||||
|
tb => tb.Text,
|
||||||
|
v => v.ToString()))
|
||||||
|
}
|
||||||
|
},
|
||||||
new TextBlock<IRootViewModel>
|
new TextBlock<IRootViewModel>
|
||||||
{
|
{
|
||||||
Extensions = {new GridPositionExtension(1, 0)}
|
Extensions = {new GridPositionExtension(1, 0)}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public static class ColorSchema
|
|||||||
public static void PrintColorSchema(ITheme theme, IConsoleDriver consoleDriver)
|
public static void PrintColorSchema(ITheme theme, IConsoleDriver consoleDriver)
|
||||||
{
|
{
|
||||||
consoleDriver.Dispose();
|
consoleDriver.Dispose();
|
||||||
consoleDriver.ResetColor();
|
consoleDriver.ResetStyle();
|
||||||
PrintThemeColors(theme, consoleDriver);
|
PrintThemeColors(theme, consoleDriver);
|
||||||
|
|
||||||
if (theme is IColorSampleProvider colorSampleProvider)
|
if (theme is IColorSampleProvider colorSampleProvider)
|
||||||
@@ -46,7 +46,7 @@ public static class ColorSchema
|
|||||||
PrintColor(consoleDriver, colorProperty.Name, color, colorTextStartX);
|
PrintColor(consoleDriver, colorProperty.Name, color, colorTextStartX);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleDriver.ResetColor();
|
consoleDriver.ResetStyle();
|
||||||
consoleDriver.Write(Environment.NewLine);
|
consoleDriver.Write(Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@ public static class ColorSchema
|
|||||||
PrintColor(consoleDriver, key, value, colorTextStartX);
|
PrintColor(consoleDriver, key, value, colorTextStartX);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleDriver.ResetColor();
|
consoleDriver.ResetStyle();
|
||||||
consoleDriver.Write(Environment.NewLine);
|
consoleDriver.Write(Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintColor(IConsoleDriver consoleDriver, string name, IColor? color, int colorTextStartX)
|
private static void PrintColor(IConsoleDriver consoleDriver, string name, IColor? color, int colorTextStartX)
|
||||||
{
|
{
|
||||||
consoleDriver.ResetColor();
|
consoleDriver.ResetStyle();
|
||||||
consoleDriver.Write(name + ":");
|
consoleDriver.Write(name + ":");
|
||||||
var y = consoleDriver.GetCursorPosition().Y;
|
var y = consoleDriver.GetCursorPosition().Y;
|
||||||
consoleDriver.SetCursorPosition(new Position(colorTextStartX, y));
|
consoleDriver.SetCursorPosition(new Position(colorTextStartX, y));
|
||||||
@@ -124,7 +124,7 @@ public static class ColorSchema
|
|||||||
consoleDriver.Write("Sample text");
|
consoleDriver.Write("Sample text");
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleDriver.ResetColor();
|
consoleDriver.ResetStyle();
|
||||||
consoleDriver.Write(Environment.NewLine);
|
consoleDriver.Write(Environment.NewLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using TerminalUI.ConsoleDrivers;
|
using TerminalUI.ConsoleDrivers;
|
||||||
using TerminalUI.Controls;
|
using TerminalUI.Controls;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
|
|
||||||
namespace TerminalUI.Examples.Controls;
|
namespace TerminalUI.Examples.Controls;
|
||||||
|
|
||||||
@@ -56,7 +57,8 @@ public class ProgressBarExamples
|
|||||||
true,
|
true,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new()
|
new(),
|
||||||
|
new TextFormatContext(true)
|
||||||
);
|
);
|
||||||
progressBar.Render(renderContext, position, new Size(10, 1));
|
progressBar.Render(renderContext, position, new Size(10, 1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ namespace TerminalUI.ConsoleDrivers;
|
|||||||
|
|
||||||
public class DotnetDriver : IConsoleDriver
|
public class DotnetDriver : IConsoleDriver
|
||||||
{
|
{
|
||||||
|
public bool SupportsAnsiEscapeSequence { get; protected set; }
|
||||||
|
|
||||||
public virtual bool Init()
|
public virtual bool Init()
|
||||||
{
|
{
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
@@ -14,7 +16,8 @@ public class DotnetDriver : IConsoleDriver
|
|||||||
|
|
||||||
public void SetCursorPosition(Position position) => Console.SetCursorPosition(position.X, position.Y);
|
public void SetCursorPosition(Position position) => Console.SetCursorPosition(position.X, position.Y);
|
||||||
|
|
||||||
public void ResetColor() => Console.ResetColor();
|
public virtual void ResetColor() => Console.ResetColor();
|
||||||
|
public virtual void ResetStyle() => Console.ResetColor();
|
||||||
|
|
||||||
public Position GetCursorPosition()
|
public Position GetCursorPosition()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ namespace TerminalUI.ConsoleDrivers;
|
|||||||
|
|
||||||
public interface IConsoleDriver
|
public interface IConsoleDriver
|
||||||
{
|
{
|
||||||
|
bool SupportsAnsiEscapeSequence { get; }
|
||||||
bool Init();
|
bool Init();
|
||||||
void Dispose();
|
void Dispose();
|
||||||
void SetCursorPosition(Position position);
|
void SetCursorPosition(Position position);
|
||||||
void ResetColor();
|
void ResetColor();
|
||||||
|
void ResetStyle();
|
||||||
Position GetCursorPosition();
|
Position GetCursorPosition();
|
||||||
void Write(string text);
|
void Write(string text);
|
||||||
void Write(ReadOnlySpan<char> text);
|
void Write(ReadOnlySpan<char> text);
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ public sealed class XTermDriver : DotnetDriver
|
|||||||
{
|
{
|
||||||
private Position _initialCursorPosition;
|
private Position _initialCursorPosition;
|
||||||
|
|
||||||
|
public XTermDriver()
|
||||||
|
{
|
||||||
|
SupportsAnsiEscapeSequence = true;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Init()
|
public override bool Init()
|
||||||
{
|
{
|
||||||
_initialCursorPosition = GetCursorPosition();
|
_initialCursorPosition = GetCursorPosition();
|
||||||
@@ -27,6 +32,11 @@ public sealed class XTermDriver : DotnetDriver
|
|||||||
SetCursorPosition(_initialCursorPosition);
|
SetCursorPosition(_initialCursorPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void ResetStyle()
|
||||||
|
{
|
||||||
|
Write("\x1b[0m");
|
||||||
|
}
|
||||||
|
|
||||||
public override void SetBackgroundColor(IColor background)
|
public override void SetBackgroundColor(IColor background)
|
||||||
{
|
{
|
||||||
if (background == SpecialColor.None) return;
|
if (background == SpecialColor.None) return;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public sealed partial class Border<T> : ContentView<Border<T>, T>, IDisplayView
|
|||||||
if (contentRendered)
|
if (contentRendered)
|
||||||
{
|
{
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
driver.ResetColor();
|
driver.ResetStyle();
|
||||||
SetColorsForDriver(renderContext);
|
SetColorsForDriver(renderContext);
|
||||||
|
|
||||||
RenderTopBorder(renderContext, position, size);
|
RenderTopBorder(renderContext, position, size);
|
||||||
|
|||||||
@@ -170,13 +170,11 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
|
|||||||
_forceRerenderChildren.Clear();
|
_forceRerenderChildren.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
var childContext = new RenderContext(
|
var childContext = context with
|
||||||
context.ConsoleDriver,
|
{
|
||||||
context.ForceRerender,
|
Foreground = Foreground ?? context.Foreground,
|
||||||
Foreground ?? context.Foreground,
|
Background = Background ?? context.Background,
|
||||||
Background ?? context.Background,
|
};
|
||||||
context.Statistics
|
|
||||||
);
|
|
||||||
var viewsByPosition = GroupViewsByPosition(columnWidths.Length, rowHeights.Length);
|
var viewsByPosition = GroupViewsByPosition(columnWidths.Length, rowHeights.Length);
|
||||||
|
|
||||||
var anyRendered = false;
|
var anyRendered = false;
|
||||||
@@ -214,7 +212,6 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
|
|||||||
int row,
|
int row,
|
||||||
IReadOnlyList<IView> forceRerenderChildren)
|
IReadOnlyList<IView> forceRerenderChildren)
|
||||||
{
|
{
|
||||||
|
|
||||||
var width = columnWidths[column];
|
var width = columnWidths[column];
|
||||||
var height = rowHeights[row];
|
var height = rowHeights[row];
|
||||||
var renderSize = new Size(width, height);
|
var renderSize = new Size(width, height);
|
||||||
@@ -253,7 +250,8 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
|
|||||||
true,
|
true,
|
||||||
context.Foreground,
|
context.Foreground,
|
||||||
context.Background,
|
context.Background,
|
||||||
context.Statistics
|
context.Statistics,
|
||||||
|
context.TextFormat
|
||||||
);
|
);
|
||||||
RenderEmpty(context, renderPosition, renderSize);
|
RenderEmpty(context, renderPosition, renderSize);
|
||||||
}
|
}
|
||||||
@@ -270,7 +268,8 @@ public sealed class Grid<T> : ChildContainerView<Grid<T>, T>, IVisibilityChangeH
|
|||||||
true,
|
true,
|
||||||
context.Foreground,
|
context.Foreground,
|
||||||
context.Background,
|
context.Background,
|
||||||
context.Statistics
|
context.Statistics,
|
||||||
|
context.TextFormat
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ public sealed partial class ItemsControl<TDataContext, TItem>
|
|||||||
double width = 0;
|
double width = 0;
|
||||||
double height = 0;
|
double height = 0;
|
||||||
|
|
||||||
foreach (var child in _children)
|
var children = _children.ToList();
|
||||||
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
if (!child.IsVisible) continue;
|
if (!child.IsVisible) continue;
|
||||||
|
|
||||||
@@ -149,13 +150,7 @@ public sealed partial class ItemsControl<TDataContext, TItem>
|
|||||||
|
|
||||||
if (forceRerenderChildren.Contains(child))
|
if (forceRerenderChildren.Contains(child))
|
||||||
{
|
{
|
||||||
var rerenderContext = new RenderContext(
|
var rerenderContext = renderContext with {ForceRerender = true};
|
||||||
renderContext.ConsoleDriver,
|
|
||||||
true,
|
|
||||||
renderContext.Foreground,
|
|
||||||
renderContext.Background,
|
|
||||||
renderContext.Statistics
|
|
||||||
);
|
|
||||||
neededRerender = child.Render(rerenderContext, childPosition, childSize) || neededRerender;
|
neededRerender = child.Render(rerenderContext, childPosition, childSize) || neededRerender;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ public sealed partial class ListView<TDataContext, TItem> : View<ListView<TDataC
|
|||||||
|
|
||||||
var driver = ApplicationContext!.ConsoleDriver;
|
var driver = ApplicationContext!.ConsoleDriver;
|
||||||
var placeholder = new string(' ', size.Width);
|
var placeholder = new string(' ', size.Width);
|
||||||
driver.ResetColor();
|
driver.ResetStyle();
|
||||||
for (var i = deltaY; i < size.Height; i++)
|
for (var i = deltaY; i < size.Height; i++)
|
||||||
{
|
{
|
||||||
driver.SetCursorPosition(position with {Y = position.Y + i});
|
driver.SetCursorPosition(position with {Y = position.Y + i});
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SetColor(driver, foreground, background);
|
SetStyleColor(renderContext, foreground, background);
|
||||||
|
|
||||||
// Left border
|
// Left border
|
||||||
var textStartPosition = position;
|
var textStartPosition = position;
|
||||||
@@ -132,7 +132,7 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
// Transient character
|
// Transient character
|
||||||
if (progressQuotientWidth < progressAvailableSpace)
|
if (progressQuotientWidth < progressAvailableSpace)
|
||||||
{
|
{
|
||||||
SetColor(driver, foreground, unfilledBackground);
|
SetStyleColor(renderContext, foreground, unfilledBackground);
|
||||||
RenderText(
|
RenderText(
|
||||||
transientChar,
|
transientChar,
|
||||||
driver,
|
driver,
|
||||||
@@ -147,7 +147,7 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
Span<char> unfilledText = stackalloc char[progressRemainderWidth];
|
Span<char> unfilledText = stackalloc char[progressRemainderWidth];
|
||||||
unfilledText.Fill(unfilledCharacter);
|
unfilledText.Fill(unfilledCharacter);
|
||||||
|
|
||||||
SetColor(driver, unfilledForeground, unfilledBackground);
|
SetStyleColor(renderContext, unfilledForeground, unfilledBackground);
|
||||||
RenderText(
|
RenderText(
|
||||||
unfilledText,
|
unfilledText,
|
||||||
driver,
|
driver,
|
||||||
@@ -159,7 +159,7 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
// Right border
|
// Right border
|
||||||
if (rightCap.HasValue)
|
if (rightCap.HasValue)
|
||||||
{
|
{
|
||||||
SetColor(driver, foreground, background);
|
SetStyleColor(renderContext, foreground, background);
|
||||||
RenderText(
|
RenderText(
|
||||||
rightCap.Value,
|
rightCap.Value,
|
||||||
driver,
|
driver,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public sealed partial class Rectangle<T> : View<Rectangle<T>, T>, IDisplayView
|
|||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
|
|
||||||
var s = new string(' ', size.Width);
|
var s = new string(' ', size.Width);
|
||||||
driver.ResetColor();
|
driver.ResetStyle();
|
||||||
if (color is not null)
|
if (color is not null)
|
||||||
{
|
{
|
||||||
driver.SetBackgroundColor(color);
|
driver.SetBackgroundColor(color);
|
||||||
|
|||||||
@@ -80,13 +80,7 @@ public sealed partial class StackPanel<T> : ChildContainerView<StackPanel<T>, T>
|
|||||||
|
|
||||||
if (forceRerenderChildren.Contains(child))
|
if (forceRerenderChildren.Contains(child))
|
||||||
{
|
{
|
||||||
var rerenderContext = new RenderContext(
|
var rerenderContext = renderContext with {ForceRerender = true};
|
||||||
renderContext.ConsoleDriver,
|
|
||||||
true,
|
|
||||||
renderContext.Foreground,
|
|
||||||
renderContext.Background,
|
|
||||||
renderContext.Statistics
|
|
||||||
);
|
|
||||||
neededRerender = child.Render(rerenderContext, childPosition, childSize) || neededRerender;
|
neededRerender = child.Render(rerenderContext, childPosition, childSize) || neededRerender;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.Extensions;
|
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
|
|
||||||
namespace TerminalUI.Controls;
|
namespace TerminalUI.Controls;
|
||||||
@@ -16,7 +16,8 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
Size Size,
|
Size Size,
|
||||||
string? Text,
|
string? Text,
|
||||||
IColor? Foreground,
|
IColor? Foreground,
|
||||||
IColor? Background);
|
IColor? Background,
|
||||||
|
ITextFormat? TextFormat);
|
||||||
|
|
||||||
private RenderState? _lastRenderState;
|
private RenderState? _lastRenderState;
|
||||||
private string[]? _textLines;
|
private string[]? _textLines;
|
||||||
@@ -24,17 +25,13 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
|
|
||||||
[Notify] private string? _text = string.Empty;
|
[Notify] private string? _text = string.Empty;
|
||||||
[Notify] private TextAlignment _textAlignment = TextAlignment.Left;
|
[Notify] private TextAlignment _textAlignment = TextAlignment.Left;
|
||||||
|
[Notify] private ITextFormat? _textFormat;
|
||||||
|
|
||||||
public TextBlock()
|
public TextBlock()
|
||||||
{
|
{
|
||||||
/*this.Bind(
|
|
||||||
this,
|
|
||||||
dc => dc == null ? string.Empty : dc.ToString(),
|
|
||||||
tb => tb.Text
|
|
||||||
);*/
|
|
||||||
|
|
||||||
RerenderProperties.Add(nameof(Text));
|
RerenderProperties.Add(nameof(Text));
|
||||||
RerenderProperties.Add(nameof(TextAlignment));
|
RerenderProperties.Add(nameof(TextAlignment));
|
||||||
|
RerenderProperties.Add(nameof(TextFormat));
|
||||||
|
|
||||||
((INotifyPropertyChanged) this).PropertyChanged += (o, e) =>
|
((INotifyPropertyChanged) this).PropertyChanged += (o, e) =>
|
||||||
{
|
{
|
||||||
@@ -58,7 +55,8 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
size,
|
size,
|
||||||
Text,
|
Text,
|
||||||
foreground,
|
foreground,
|
||||||
background);
|
background,
|
||||||
|
_textFormat);
|
||||||
|
|
||||||
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
|
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
|
||||||
|
|
||||||
@@ -78,7 +76,7 @@ public sealed partial class TextBlock<T> : View<TextBlock<T>, T>, IDisplayView
|
|||||||
_placeholderRenderDone = false;
|
_placeholderRenderDone = false;
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
SetColor(driver, foreground, background);
|
SetStyleColor(renderContext, foreground, background, _textFormat);
|
||||||
|
|
||||||
RenderText(_textLines, driver, position, size, TransformText);
|
RenderText(_textLines, driver, position, size, TransformText);
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public sealed partial class TextBox<T> : View<TextBox<T>, T>, IFocusable, IDispl
|
|||||||
_lastRenderState = renderStatus;
|
_lastRenderState = renderStatus;
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
SetColor(driver, foreground, background);
|
SetStyleColor(renderContext, foreground, background);
|
||||||
|
|
||||||
RenderEmpty(renderContext, position, size);
|
RenderEmpty(renderContext, position, size);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using PropertyChanged.SourceGenerator;
|
|||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.ConsoleDrivers;
|
using TerminalUI.ConsoleDrivers;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
|
|
||||||
namespace TerminalUI.Controls;
|
namespace TerminalUI.Controls;
|
||||||
@@ -175,12 +176,12 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
bool renderResult;
|
bool renderResult;
|
||||||
if (Background != null || Foreground != null)
|
if (Background != null || Foreground != null)
|
||||||
{
|
{
|
||||||
var newRenderContext = new RenderContext(
|
var newRenderContext = renderContext with
|
||||||
renderContext.ConsoleDriver,
|
{
|
||||||
renderContext.ForceRerender,
|
Foreground = Foreground ?? renderContext.Foreground,
|
||||||
Foreground ?? renderContext.Foreground,
|
Background = Background ?? renderContext.Background
|
||||||
Background ?? renderContext.Background,
|
};
|
||||||
renderContext.Statistics);
|
|
||||||
renderResult = RenderMethod(newRenderContext, position, size);
|
renderResult = RenderMethod(newRenderContext, position, size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -202,7 +203,7 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
protected void RenderEmpty(in RenderContext renderContext, Position position, Size size)
|
protected void RenderEmpty(in RenderContext renderContext, Position position, Size size)
|
||||||
{
|
{
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
driver.ResetColor();
|
driver.ResetStyle();
|
||||||
|
|
||||||
var placeHolder = new string(ApplicationContext!.EmptyCharacter, size.Width);
|
var placeHolder = new string(ApplicationContext!.EmptyCharacter, size.Width);
|
||||||
for (var i = 0; i < size.Height; i++)
|
for (var i = 0; i < size.Height; i++)
|
||||||
@@ -309,13 +310,24 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
driver.Write(contentString);
|
driver.Write(contentString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected void SetColor(IConsoleDriver driver, IColor? foreground, IColor? background)
|
|
||||||
|
protected void SetStyleColor(
|
||||||
|
in RenderContext renderContext,
|
||||||
|
IColor? foreground = null,
|
||||||
|
IColor? background = null,
|
||||||
|
ITextFormat? textFormat = null)
|
||||||
{
|
{
|
||||||
|
var driver = renderContext.ConsoleDriver;
|
||||||
driver.ResetColor();
|
driver.ResetColor();
|
||||||
|
if (textFormat is { } t)
|
||||||
|
{
|
||||||
|
t.ApplyFormat(driver, renderContext.TextFormat);
|
||||||
|
}
|
||||||
if (foreground is not null)
|
if (foreground is not null)
|
||||||
{
|
{
|
||||||
driver.SetForegroundColor(foreground);
|
driver.SetForegroundColor(foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (background is not null)
|
if (background is not null)
|
||||||
{
|
{
|
||||||
driver.SetBackgroundColor(background);
|
driver.SetBackgroundColor(background);
|
||||||
@@ -324,11 +336,9 @@ public abstract partial class View<TConcrete, T> : IView<T> where TConcrete : Vi
|
|||||||
|
|
||||||
protected void SetColorsForDriver(in RenderContext renderContext)
|
protected void SetColorsForDriver(in RenderContext renderContext)
|
||||||
{
|
{
|
||||||
var driver = renderContext.ConsoleDriver;
|
|
||||||
|
|
||||||
var foreground = Foreground ?? renderContext.Foreground;
|
var foreground = Foreground ?? renderContext.Foreground;
|
||||||
var background = Background ?? renderContext.Background;
|
var background = Background ?? renderContext.Background;
|
||||||
SetColor(driver, foreground, background);
|
SetStyleColor(renderContext, foreground, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TChild CreateChild<TChild>() where TChild : IView<T>, new()
|
public TChild CreateChild<TChild>() where TChild : IView<T>, new()
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ namespace TerminalUI.ExpressionTrackers;
|
|||||||
public abstract class ExpressionTrackerBase : IExpressionTracker
|
public abstract class ExpressionTrackerBase : IExpressionTracker
|
||||||
{
|
{
|
||||||
private object? _currentValue;
|
private object? _currentValue;
|
||||||
public List<string> TrackedPropertyNames { get; } = new();
|
private readonly List<IExpressionTracker> _propertyProxyTrackers = new();
|
||||||
|
private readonly List<string> _trackedPropertyNames = new();
|
||||||
|
|
||||||
protected bool SubscribeToValueChanges { get; set; } = true;
|
protected bool SubscribeToValueChanges { get; set; } = true;
|
||||||
|
|
||||||
@@ -15,10 +16,22 @@ public abstract class ExpressionTrackerBase : IExpressionTracker
|
|||||||
public object? GetValue() => _currentValue;
|
public object? GetValue() => _currentValue;
|
||||||
protected abstract object? ComputeValue();
|
protected abstract object? ComputeValue();
|
||||||
|
|
||||||
protected void SubscribeToTracker(IExpressionTracker? expressionTracker)
|
protected void SubscribeToTracker(IExpressionTracker? expressionTracker, bool proxyPropertyChanged = false)
|
||||||
{
|
{
|
||||||
if (expressionTracker is null) return;
|
if (expressionTracker is null) return;
|
||||||
|
|
||||||
expressionTracker.Update += UpdateValueAndChangeTrackers;
|
expressionTracker.Update += UpdateValueAndChangeTrackers;
|
||||||
|
|
||||||
|
if (proxyPropertyChanged)
|
||||||
|
{
|
||||||
|
expressionTracker.PropertyChanged += OnPropertyChanged;
|
||||||
|
_propertyProxyTrackers.Add(expressionTracker);
|
||||||
|
|
||||||
|
foreach (var propertyName in _trackedPropertyNames)
|
||||||
|
{
|
||||||
|
expressionTracker.TrackProperty(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void UpdateValueAndChangeTrackers() => UpdateValueAndChangeTrackers(true);
|
protected void UpdateValueAndChangeTrackers() => UpdateValueAndChangeTrackers(true);
|
||||||
@@ -74,9 +87,24 @@ public abstract class ExpressionTrackerBase : IExpressionTracker
|
|||||||
{
|
{
|
||||||
if (e.PropertyName is null) return;
|
if (e.PropertyName is null) return;
|
||||||
|
|
||||||
if (TrackedPropertyNames.Contains(e.PropertyName))
|
if (_trackedPropertyNames.Contains(e.PropertyName))
|
||||||
{
|
{
|
||||||
PropertyChanged?.Invoke(e.PropertyName);
|
PropertyChanged?.Invoke(e.PropertyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(propertyName);
|
||||||
|
|
||||||
|
public void TrackProperty(string propertyName)
|
||||||
|
{
|
||||||
|
if (!_trackedPropertyNames.Contains(propertyName))
|
||||||
|
{
|
||||||
|
_trackedPropertyNames.Add(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var propertyProxyTracker in _propertyProxyTrackers)
|
||||||
|
{
|
||||||
|
propertyProxyTracker.TrackProperty(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
public interface IExpressionTracker
|
public interface IExpressionTracker
|
||||||
{
|
{
|
||||||
List<string> TrackedPropertyNames { get; }
|
|
||||||
event Action<string>? PropertyChanged;
|
event Action<string>? PropertyChanged;
|
||||||
event Action<bool>? Update;
|
event Action<bool>? Update;
|
||||||
object? GetValue();
|
object? GetValue();
|
||||||
|
void TrackProperty(string propertyName);
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public sealed class MemberTracker : ExpressionTrackerBase
|
|||||||
if (memberExpression.Member is PropertyInfo propertyInfo)
|
if (memberExpression.Member is PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
_memberName = propertyInfo.Name;
|
_memberName = propertyInfo.Name;
|
||||||
parentTracker?.TrackedPropertyNames.Add(propertyInfo.Name);
|
parentTracker?.TrackProperty(propertyInfo.Name);
|
||||||
|
|
||||||
if (propertyInfo.GetMethod is { } getMethod)
|
if (propertyInfo.GetMethod is { } getMethod)
|
||||||
{
|
{
|
||||||
@@ -44,7 +44,7 @@ public sealed class MemberTracker : ExpressionTrackerBase
|
|||||||
else if (memberExpression.Member is FieldInfo fieldInfo)
|
else if (memberExpression.Member is FieldInfo fieldInfo)
|
||||||
{
|
{
|
||||||
_memberName = fieldInfo.Name;
|
_memberName = fieldInfo.Name;
|
||||||
parentTracker?.TrackedPropertyNames.Add(fieldInfo.Name);
|
parentTracker?.TrackProperty(fieldInfo.Name);
|
||||||
|
|
||||||
_valueProvider = () => CallFieldInfo(fieldInfo);
|
_valueProvider = () => CallFieldInfo(fieldInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class UnaryTracker : ExpressionTrackerBase
|
|||||||
_ => throw new NotSupportedException($"Unary expression of type {unaryExpression.NodeType} is not supported.")
|
_ => throw new NotSupportedException($"Unary expression of type {unaryExpression.NodeType} is not supported.")
|
||||||
};
|
};
|
||||||
|
|
||||||
SubscribeToTracker(operandTracker);
|
SubscribeToTracker(operandTracker, true);
|
||||||
|
|
||||||
UpdateValueAndChangeTrackers();
|
UpdateValueAndChangeTrackers();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.ConsoleDrivers;
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
|
|
||||||
namespace TerminalUI.Models;
|
namespace TerminalUI.Models;
|
||||||
|
|
||||||
@@ -8,19 +9,21 @@ namespace TerminalUI.Models;
|
|||||||
public readonly ref struct RenderContext
|
public readonly ref struct RenderContext
|
||||||
{
|
{
|
||||||
private static int _renderId;
|
private static int _renderId;
|
||||||
public readonly int RenderId;
|
public int RenderId { get; init; }
|
||||||
public readonly IConsoleDriver ConsoleDriver;
|
public IConsoleDriver ConsoleDriver { get; init; }
|
||||||
public readonly bool ForceRerender;
|
public bool ForceRerender { get; init; }
|
||||||
public readonly IColor? Foreground;
|
public IColor? Foreground { get; init; }
|
||||||
public readonly IColor? Background;
|
public IColor? Background { get; init; }
|
||||||
public readonly RenderStatistics Statistics;
|
public RenderStatistics Statistics { get; init; }
|
||||||
|
public TextFormatContext TextFormat { get; init; }
|
||||||
|
|
||||||
public RenderContext(
|
public RenderContext(
|
||||||
IConsoleDriver consoleDriver,
|
IConsoleDriver consoleDriver,
|
||||||
bool forceRerender,
|
bool forceRerender,
|
||||||
IColor? foreground,
|
IColor? foreground,
|
||||||
IColor? background,
|
IColor? background,
|
||||||
RenderStatistics statistics)
|
RenderStatistics statistics,
|
||||||
|
TextFormatContext textFormat)
|
||||||
{
|
{
|
||||||
RenderId = _renderId++;
|
RenderId = _renderId++;
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@ public readonly ref struct RenderContext
|
|||||||
Foreground = foreground;
|
Foreground = foreground;
|
||||||
Background = background;
|
Background = background;
|
||||||
Statistics = statistics;
|
Statistics = statistics;
|
||||||
|
TextFormat = textFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RenderContext Empty =>
|
public static RenderContext Empty =>
|
||||||
@@ -37,6 +41,7 @@ public readonly ref struct RenderContext
|
|||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RenderStatistics()
|
new RenderStatistics(),
|
||||||
|
new TextFormatContext(false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using TerminalUI.Controls;
|
using TerminalUI.Controls;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
using TerminalUI.TextFormat;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
|
|
||||||
namespace TerminalUI;
|
namespace TerminalUI;
|
||||||
@@ -83,7 +84,8 @@ public class RenderEngine : IRenderEngine
|
|||||||
true,
|
true,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RenderStatistics()
|
new RenderStatistics(),
|
||||||
|
new TextFormatContext(driver.SupportsAnsiEscapeSequence)
|
||||||
),
|
),
|
||||||
initialPosition,
|
initialPosition,
|
||||||
size);
|
size);
|
||||||
@@ -95,7 +97,8 @@ public class RenderEngine : IRenderEngine
|
|||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RenderStatistics()
|
new RenderStatistics(),
|
||||||
|
new TextFormatContext(driver.SupportsAnsiEscapeSequence)
|
||||||
),
|
),
|
||||||
initialPosition,
|
initialPosition,
|
||||||
size);
|
size);
|
||||||
|
|||||||
25
src/Library/TerminalUI/TextFormat/AnsiFormat.cs
Normal file
25
src/Library/TerminalUI/TextFormat/AnsiFormat.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public class AnsiFormat : ITextFormat
|
||||||
|
{
|
||||||
|
public bool IsUnderline { get; set; }
|
||||||
|
public bool IsItalic { get; set; }
|
||||||
|
public bool IsBold { get; set; }
|
||||||
|
public bool CanApply(TextFormatContext context) => context.SupportsAnsi;
|
||||||
|
|
||||||
|
public void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context)
|
||||||
|
{
|
||||||
|
if (!context.SupportsAnsi) return;
|
||||||
|
|
||||||
|
if (IsUnderline)
|
||||||
|
consoleDriver.Write("\x01b[4m");
|
||||||
|
|
||||||
|
if (IsItalic)
|
||||||
|
consoleDriver.Write("\x01b[3m");
|
||||||
|
|
||||||
|
if (IsBold)
|
||||||
|
consoleDriver.Write("\x01b[1m");
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Library/TerminalUI/TextFormat/EmptyFormat.cs
Normal file
13
src/Library/TerminalUI/TextFormat/EmptyFormat.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public readonly struct EmptyFormat : ITextFormat
|
||||||
|
{
|
||||||
|
public static EmptyFormat Instance => new();
|
||||||
|
public bool CanApply(TextFormatContext context) => true;
|
||||||
|
|
||||||
|
public void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/Library/TerminalUI/TextFormat/FormatCollection.cs
Normal file
23
src/Library/TerminalUI/TextFormat/FormatCollection.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public class FormatCollection : ITextFormat
|
||||||
|
{
|
||||||
|
public List<ITextFormat> Formats { get; } = new();
|
||||||
|
|
||||||
|
public Func<IReadOnlyList<ITextFormat>, TextFormatContext, bool> CanApplyPredicate { get; set; } = DefaultCanApplyPredicate;
|
||||||
|
|
||||||
|
public bool CanApply(TextFormatContext context) => CanApplyPredicate(Formats, context);
|
||||||
|
|
||||||
|
public void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context)
|
||||||
|
{
|
||||||
|
foreach (var format in Formats)
|
||||||
|
{
|
||||||
|
format.ApplyFormat(consoleDriver, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DefaultCanApplyPredicate(IReadOnlyList<ITextFormat> formats, TextFormatContext context)
|
||||||
|
=> formats.Any(format => format.CanApply(context));
|
||||||
|
}
|
||||||
9
src/Library/TerminalUI/TextFormat/ITextFormat.cs
Normal file
9
src/Library/TerminalUI/TextFormat/ITextFormat.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public interface ITextFormat
|
||||||
|
{
|
||||||
|
bool CanApply(TextFormatContext context);
|
||||||
|
void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context);
|
||||||
|
}
|
||||||
23
src/Library/TerminalUI/TextFormat/OrFormat.cs
Normal file
23
src/Library/TerminalUI/TextFormat/OrFormat.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public class OrFormat : ITextFormat
|
||||||
|
{
|
||||||
|
public required ITextFormat Format1 { get; set; }
|
||||||
|
public required ITextFormat Format2 { get; set; }
|
||||||
|
|
||||||
|
public bool CanApply(TextFormatContext context) => true;
|
||||||
|
|
||||||
|
public void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context)
|
||||||
|
{
|
||||||
|
if (Format1.CanApply(context))
|
||||||
|
{
|
||||||
|
Format1.ApplyFormat(consoleDriver, context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Format2.ApplyFormat(consoleDriver, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Library/TerminalUI/TextFormat/SimpleFormat.cs
Normal file
20
src/Library/TerminalUI/TextFormat/SimpleFormat.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using TerminalUI.Color;
|
||||||
|
using TerminalUI.ConsoleDrivers;
|
||||||
|
|
||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public class SimpleFormat : ITextFormat
|
||||||
|
{
|
||||||
|
public IColor? Foreground { get; init; }
|
||||||
|
public IColor? Background { get; init; }
|
||||||
|
public bool CanApply(TextFormatContext context) => true;
|
||||||
|
|
||||||
|
public void ApplyFormat(IConsoleDriver consoleDriver, TextFormatContext context)
|
||||||
|
{
|
||||||
|
if (Foreground is not null)
|
||||||
|
consoleDriver.SetForegroundColor(Foreground);
|
||||||
|
|
||||||
|
if (Background is not null)
|
||||||
|
consoleDriver.SetBackgroundColor(Background);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Library/TerminalUI/TextFormat/TextFormatContext.cs
Normal file
11
src/Library/TerminalUI/TextFormat/TextFormatContext.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace TerminalUI.TextFormat;
|
||||||
|
|
||||||
|
public readonly struct TextFormatContext
|
||||||
|
{
|
||||||
|
public readonly bool SupportsAnsi;
|
||||||
|
|
||||||
|
public TextFormatContext(bool supportsAnsi)
|
||||||
|
{
|
||||||
|
SupportsAnsi = supportsAnsi;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user