renderables)
{
- var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
+ var context = RenderOptions.Create(console, new EncoderCapabilities(ColorSystem.TrueColor));
var builder = new StringBuilder();
builder.Append("\n");
diff --git a/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs b/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
index ac2bc61..2570699 100644
--- a/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
+++ b/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
@@ -4,7 +4,7 @@ internal sealed class TextEncoder : IAnsiConsoleEncoder
{
public string Encode(IAnsiConsole console, IEnumerable renderables)
{
- var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
+ var context = RenderOptions.Create(console, new EncoderCapabilities(ColorSystem.TrueColor));
var builder = new StringBuilder();
foreach (var renderable in renderables)
diff --git a/src/Spectre.Console/Justify.cs b/src/Spectre.Console/Justify.cs
index dc81437..a4578de 100644
--- a/src/Spectre.Console/Justify.cs
+++ b/src/Spectre.Console/Justify.cs
@@ -6,12 +6,12 @@ namespace Spectre.Console;
public enum Justify
{
///
- /// Left aligned.
+ /// Left justified.
///
Left = 0,
///
- /// Right aligned.
+ /// Right justified.
///
Right = 1,
diff --git a/src/Spectre.Console/Live/LiveDisplayRenderer.cs b/src/Spectre.Console/Live/LiveDisplayRenderer.cs
index 3a95df1..a9a1a52 100644
--- a/src/Spectre.Console/Live/LiveDisplayRenderer.cs
+++ b/src/Spectre.Console/Live/LiveDisplayRenderer.cs
@@ -41,7 +41,7 @@ internal sealed class LiveDisplayRenderer : IRenderHook
}
}
- public IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_context.Lock)
{
diff --git a/src/Spectre.Console/Live/LiveRenderable.cs b/src/Spectre.Console/Live/LiveRenderable.cs
index 9152540..40107f9 100644
--- a/src/Spectre.Console/Live/LiveRenderable.cs
+++ b/src/Spectre.Console/Live/LiveRenderable.cs
@@ -67,7 +67,7 @@ internal sealed class LiveRenderable : Renderable
}
}
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
lock (_lock)
{
@@ -75,10 +75,10 @@ internal sealed class LiveRenderable : Renderable
if (_renderable != null)
{
- var segments = _renderable.Render(context, maxWidth);
+ var segments = _renderable.Render(options, maxWidth);
var lines = Segment.SplitLines(segments);
- var shape = SegmentShape.Calculate(context, lines);
+ var shape = SegmentShape.Calculate(options, lines);
if (shape.Height > _console.Profile.Height)
{
if (Overflow == VerticalOverflow.Crop)
@@ -97,12 +97,12 @@ internal sealed class LiveRenderable : Renderable
lines.RemoveRange(0, start);
}
- shape = SegmentShape.Calculate(context, lines);
+ shape = SegmentShape.Calculate(options, lines);
}
else if (Overflow == VerticalOverflow.Ellipsis)
{
var ellipsisText = _console.Profile.Capabilities.Unicode ? "…" : "...";
- var ellipsis = new SegmentLine(((IRenderable)new Markup($"[yellow]{ellipsisText}[/]")).Render(context, maxWidth));
+ var ellipsis = new SegmentLine(((IRenderable)new Markup($"[yellow]{ellipsisText}[/]")).Render(options, maxWidth));
if (OverflowCropping == VerticalOverflowCropping.Bottom)
{
@@ -120,14 +120,14 @@ internal sealed class LiveRenderable : Renderable
lines.Insert(0, ellipsis);
}
- shape = SegmentShape.Calculate(context, lines);
+ shape = SegmentShape.Calculate(options, lines);
}
DidOverflow = true;
}
_shape = _shape == null ? shape : _shape.Value.Inflate(shape);
- _shape.Value.Apply(context, ref lines);
+ _shape.Value.Apply(options, ref lines);
foreach (var (_, _, last, line) in lines.Enumerate())
{
diff --git a/src/Spectre.Console/Live/Progress/Columns/DownloadedColumn.cs b/src/Spectre.Console/Live/Progress/Columns/DownloadedColumn.cs
index fa8e496..6162986 100644
--- a/src/Spectre.Console/Live/Progress/Columns/DownloadedColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/DownloadedColumn.cs
@@ -11,7 +11,7 @@ public sealed class DownloadedColumn : ProgressColumn
public CultureInfo? Culture { get; set; }
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
var total = new FileSize(task.MaxValue);
diff --git a/src/Spectre.Console/Live/Progress/Columns/ElapsedTimeColumn.cs b/src/Spectre.Console/Live/Progress/Columns/ElapsedTimeColumn.cs
index a005be6..a29fdfb 100644
--- a/src/Spectre.Console/Live/Progress/Columns/ElapsedTimeColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/ElapsedTimeColumn.cs
@@ -14,7 +14,7 @@ public sealed class ElapsedTimeColumn : ProgressColumn
public Style Style { get; set; } = new Style(foreground: Color.Blue);
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
var elapsed = task.ElapsedTime;
if (elapsed == null)
@@ -31,7 +31,7 @@ public sealed class ElapsedTimeColumn : ProgressColumn
}
///
- public override int? GetColumnWidth(RenderContext context)
+ public override int? GetColumnWidth(RenderOptions options)
{
return 8;
}
diff --git a/src/Spectre.Console/Live/Progress/Columns/PercentageColumn.cs b/src/Spectre.Console/Live/Progress/Columns/PercentageColumn.cs
index f0bf597..0dbef1c 100644
--- a/src/Spectre.Console/Live/Progress/Columns/PercentageColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/PercentageColumn.cs
@@ -16,15 +16,15 @@ public sealed class PercentageColumn : ProgressColumn
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Green);
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
var percentage = (int)task.Percentage;
var style = percentage == 100 ? CompletedStyle : Style ?? Style.Plain;
- return new Text($"{percentage}%", style).RightAligned();
+ return new Text($"{percentage}%", style).RightJustified();
}
///
- public override int? GetColumnWidth(RenderContext context)
+ public override int? GetColumnWidth(RenderOptions options)
{
return 4;
}
diff --git a/src/Spectre.Console/Live/Progress/Columns/ProgressBarColumn.cs b/src/Spectre.Console/Live/Progress/Columns/ProgressBarColumn.cs
index 7b0b018..16c7c19 100644
--- a/src/Spectre.Console/Live/Progress/Columns/ProgressBarColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/ProgressBarColumn.cs
@@ -31,7 +31,7 @@ public sealed class ProgressBarColumn : ProgressColumn
public Style IndeterminateStyle { get; set; } = ProgressBar.DefaultPulseStyle;
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
return new ProgressBar
{
diff --git a/src/Spectre.Console/Live/Progress/Columns/RemainingTimeColumn.cs b/src/Spectre.Console/Live/Progress/Columns/RemainingTimeColumn.cs
index 49aeae5..3ce467a 100644
--- a/src/Spectre.Console/Live/Progress/Columns/RemainingTimeColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/RemainingTimeColumn.cs
@@ -14,7 +14,7 @@ public sealed class RemainingTimeColumn : ProgressColumn
public Style Style { get; set; } = new Style(foreground: Color.Blue);
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
var remaining = task.RemainingTime;
if (remaining == null)
@@ -31,7 +31,7 @@ public sealed class RemainingTimeColumn : ProgressColumn
}
///
- public override int? GetColumnWidth(RenderContext context)
+ public override int? GetColumnWidth(RenderOptions options)
{
return 8;
}
diff --git a/src/Spectre.Console/Live/Progress/Columns/SpinnerColumn.cs b/src/Spectre.Console/Live/Progress/Columns/SpinnerColumn.cs
index 429d484..425de14 100644
--- a/src/Spectre.Console/Live/Progress/Columns/SpinnerColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/SpinnerColumn.cs
@@ -95,9 +95,9 @@ public sealed class SpinnerColumn : ProgressColumn
}
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
- var useAscii = !context.Unicode && _spinner.IsUnicode;
+ var useAscii = !options.Unicode && _spinner.IsUnicode;
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
if (!task.IsStarted)
@@ -123,24 +123,24 @@ public sealed class SpinnerColumn : ProgressColumn
}
///
- public override int? GetColumnWidth(RenderContext context)
+ public override int? GetColumnWidth(RenderOptions options)
{
- return GetMaxWidth(context);
+ return GetMaxWidth(options);
}
- private int GetMaxWidth(RenderContext context)
+ private int GetMaxWidth(RenderOptions options)
{
lock (_lock)
{
if (_maxWidth == null)
{
- var useAscii = !context.Unicode && _spinner.IsUnicode;
+ var useAscii = !options.Unicode && _spinner.IsUnicode;
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
_maxWidth = Math.Max(
Math.Max(
- ((IRenderable)new Markup(PendingText ?? " ")).Measure(context, int.MaxValue).Max,
- ((IRenderable)new Markup(CompletedText ?? " ")).Measure(context, int.MaxValue).Max),
+ ((IRenderable)new Markup(PendingText ?? " ")).Measure(options, int.MaxValue).Max,
+ ((IRenderable)new Markup(CompletedText ?? " ")).Measure(options, int.MaxValue).Max),
spinner.Frames.Max(frame => Cell.GetCellLength(frame)));
}
diff --git a/src/Spectre.Console/Live/Progress/Columns/TaskDescriptionColumn.cs b/src/Spectre.Console/Live/Progress/Columns/TaskDescriptionColumn.cs
index b6ffb0d..4e3c39f 100644
--- a/src/Spectre.Console/Live/Progress/Columns/TaskDescriptionColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/TaskDescriptionColumn.cs
@@ -14,9 +14,9 @@ public sealed class TaskDescriptionColumn : ProgressColumn
public Justify Alignment { get; set; } = Justify.Right;
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
var text = task.Description?.RemoveNewLines()?.Trim();
- return new Markup(text ?? string.Empty).Overflow(Overflow.Ellipsis).Alignment(Alignment);
+ return new Markup(text ?? string.Empty).Overflow(Overflow.Ellipsis).Justify(Alignment);
}
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Live/Progress/Columns/TransferSpeedColumn.cs b/src/Spectre.Console/Live/Progress/Columns/TransferSpeedColumn.cs
index 7e6e783..84f2743 100644
--- a/src/Spectre.Console/Live/Progress/Columns/TransferSpeedColumn.cs
+++ b/src/Spectre.Console/Live/Progress/Columns/TransferSpeedColumn.cs
@@ -11,7 +11,7 @@ public sealed class TransferSpeedColumn : ProgressColumn
public CultureInfo? Culture { get; set; }
///
- public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
+ public override IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime)
{
if (task.Speed == null)
{
diff --git a/src/Spectre.Console/Live/Progress/ProgressColumn.cs b/src/Spectre.Console/Live/Progress/ProgressColumn.cs
index 2aa593d..c10538e 100644
--- a/src/Spectre.Console/Live/Progress/ProgressColumn.cs
+++ b/src/Spectre.Console/Live/Progress/ProgressColumn.cs
@@ -13,18 +13,18 @@ public abstract class ProgressColumn
///
/// Gets a renderable representing the column.
///
- /// The render context.
+ /// The render options.
/// The task.
/// The elapsed time since last call.
/// A renderable representing the column.
- public abstract IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime);
+ public abstract IRenderable Render(RenderOptions options, ProgressTask task, TimeSpan deltaTime);
///
/// Gets the width of the column.
///
- /// The context.
+ /// The render options.
/// The width of the column, or null to calculate.
- public virtual int? GetColumnWidth(RenderContext context)
+ public virtual int? GetColumnWidth(RenderOptions options)
{
return null;
}
diff --git a/src/Spectre.Console/Live/Progress/ProgressRenderer.cs b/src/Spectre.Console/Live/Progress/ProgressRenderer.cs
index 598ce5a..5840b20 100644
--- a/src/Spectre.Console/Live/Progress/ProgressRenderer.cs
+++ b/src/Spectre.Console/Live/Progress/ProgressRenderer.cs
@@ -13,5 +13,5 @@ internal abstract class ProgressRenderer : IRenderHook
}
public abstract void Update(ProgressContext context);
- public abstract IEnumerable Process(RenderContext context, IEnumerable renderables);
+ public abstract IEnumerable Process(RenderOptions options, IEnumerable renderables);
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs b/src/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs
index 9715402..8155751 100644
--- a/src/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs
+++ b/src/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs
@@ -64,7 +64,7 @@ internal sealed class DefaultProgressRenderer : ProgressRenderer
_stopwatch.Start();
}
- var renderContext = new RenderContext(_console.Profile.Capabilities);
+ var renderContext = RenderOptions.Create(_console, _console.Profile.Capabilities);
var delta = _stopwatch.Elapsed - _lastUpdate;
_lastUpdate = _stopwatch.Elapsed;
@@ -105,7 +105,7 @@ internal sealed class DefaultProgressRenderer : ProgressRenderer
}
}
- public override IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public override IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_lock)
{
diff --git a/src/Spectre.Console/Live/Progress/Renderers/FallbackProgressRenderer.cs b/src/Spectre.Console/Live/Progress/Renderers/FallbackProgressRenderer.cs
index 90c54b3..e40f54c 100644
--- a/src/Spectre.Console/Live/Progress/Renderers/FallbackProgressRenderer.cs
+++ b/src/Spectre.Console/Live/Progress/Renderers/FallbackProgressRenderer.cs
@@ -58,7 +58,7 @@ internal sealed class FallbackProgressRenderer : ProgressRenderer
}
}
- public override IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public override IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_lock)
{
diff --git a/src/Spectre.Console/Live/Progress/Renderers/FallbackStatusRenderer.cs b/src/Spectre.Console/Live/Progress/Renderers/FallbackStatusRenderer.cs
index f8f445e..69e025c 100644
--- a/src/Spectre.Console/Live/Progress/Renderers/FallbackStatusRenderer.cs
+++ b/src/Spectre.Console/Live/Progress/Renderers/FallbackStatusRenderer.cs
@@ -34,7 +34,7 @@ internal sealed class FallbackStatusRenderer : ProgressRenderer
}
}
- public override IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public override IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_lock)
{
diff --git a/src/Spectre.Console/Prompts/List/ListPromptRenderHook.cs b/src/Spectre.Console/Prompts/List/ListPromptRenderHook.cs
index 53fa21f..090a2f6 100644
--- a/src/Spectre.Console/Prompts/List/ListPromptRenderHook.cs
+++ b/src/Spectre.Console/Prompts/List/ListPromptRenderHook.cs
@@ -32,7 +32,7 @@ internal sealed class ListPromptRenderHook : IRenderHook
_console.Write(new ControlCode(string.Empty));
}
- public IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_lock)
{
diff --git a/src/Spectre.Console/Region.cs b/src/Spectre.Console/Region.cs
new file mode 100644
index 0000000..a5aeb05
--- /dev/null
+++ b/src/Spectre.Console/Region.cs
@@ -0,0 +1,43 @@
+namespace Spectre.Console;
+
+///
+/// Represents a region.
+///
+[DebuggerDisplay("[X={X,nq}, Y={Y,nq}, W={Width,nq}, H={Height,nq}]")]
+public struct Region
+{
+ ///
+ /// Gets the x-coordinate.
+ ///
+ public int X { get; }
+
+ ///
+ /// Gets the y-coordinate.
+ ///
+ public int Y { get; }
+
+ ///
+ /// Gets the width.
+ ///
+ public int Width { get; }
+
+ ///
+ /// Gets the height.
+ ///
+ public int Height { get; }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The x-coordinate.
+ /// The y-coordinate.
+ /// The width.
+ /// The height.
+ public Region(int x, int y, int width, int height)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ }
+}
\ No newline at end of file
diff --git a/src/Spectre.Console/Rendering/IRenderHook.cs b/src/Spectre.Console/Rendering/IRenderHook.cs
index 417a500..49c92d6 100644
--- a/src/Spectre.Console/Rendering/IRenderHook.cs
+++ b/src/Spectre.Console/Rendering/IRenderHook.cs
@@ -8,8 +8,8 @@ public interface IRenderHook
///
/// Processes the specified renderables.
///
- /// The render context.
+ /// The render options.
/// The renderables to process.
/// The processed renderables.
- IEnumerable Process(RenderContext context, IEnumerable renderables);
+ IEnumerable Process(RenderOptions options, IEnumerable renderables);
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Rendering/JustInTimeRenderable.cs b/src/Spectre.Console/Rendering/JustInTimeRenderable.cs
index dd85e40..f30b370 100644
--- a/src/Spectre.Console/Rendering/JustInTimeRenderable.cs
+++ b/src/Spectre.Console/Rendering/JustInTimeRenderable.cs
@@ -10,13 +10,13 @@ public abstract class JustInTimeRenderable : Renderable
private IRenderable? _rendered;
///
- protected sealed override Measurement Measure(RenderContext context, int maxWidth)
+ protected sealed override Measurement Measure(RenderOptions context, int maxWidth)
{
return GetInner().Measure(context, maxWidth);
}
///
- protected sealed override IEnumerable Render(RenderContext context, int width)
+ protected sealed override IEnumerable Render(RenderOptions context, int width)
{
return GetInner().Render(context, width);
}
diff --git a/src/Spectre.Console/Rendering/RenderContext.cs b/src/Spectre.Console/Rendering/RenderContext.cs
deleted file mode 100644
index c8d15f8..0000000
--- a/src/Spectre.Console/Rendering/RenderContext.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-namespace Spectre.Console.Rendering;
-
-///
-/// Represents a render context.
-///
-public sealed class RenderContext
-{
- private readonly IReadOnlyCapabilities _capabilities;
-
- ///
- /// Gets the current color system.
- ///
- public ColorSystem ColorSystem => _capabilities.ColorSystem;
-
- ///
- /// Gets a value indicating whether or not VT/Ansi codes are supported.
- ///
- public bool Ansi => _capabilities.Ansi;
-
- ///
- /// Gets a value indicating whether or not unicode is supported.
- ///
- public bool Unicode => _capabilities.Unicode;
-
- ///
- /// Gets the current justification.
- ///
- public Justify? Justification { get; }
-
- ///
- /// Gets a value indicating whether the context want items to render without
- /// line breaks and return a single line where applicable.
- ///
- internal bool SingleLine { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The capabilities.
- /// The justification.
- public RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null)
- : this(capabilities, justification, false)
- {
- }
-
- private RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false)
- {
- _capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities));
-
- Justification = justification;
- SingleLine = singleLine;
- }
-
- ///
- /// Creates a new context with the specified justification.
- ///
- /// The justification.
- /// A new instance.
- public RenderContext WithJustification(Justify? justification)
- {
- return new RenderContext(_capabilities, justification, SingleLine);
- }
-
- ///
- /// Creates a new context that tell instances
- /// to not care about splitting things in new lines. Whether or not to
- /// comply to the request is up to the item being rendered.
- ///
- ///
- /// Use with care since this has the potential to mess things up.
- /// Only use this kind of context with items that you know about.
- ///
- /// A new instance.
- internal RenderContext WithSingleLine()
- {
- return new RenderContext(_capabilities, Justification, true);
- }
-}
\ No newline at end of file
diff --git a/src/Spectre.Console/Rendering/RenderOptions.cs b/src/Spectre.Console/Rendering/RenderOptions.cs
new file mode 100644
index 0000000..3dcf04a
--- /dev/null
+++ b/src/Spectre.Console/Rendering/RenderOptions.cs
@@ -0,0 +1,63 @@
+namespace Spectre.Console.Rendering;
+
+///
+/// Represents render options.
+///
+/// The capabilities.
+/// The console size.
+public record class RenderOptions(IReadOnlyCapabilities Capabilities, Size ConsoleSize)
+{
+ ///
+ /// Gets the current color system.
+ ///
+ public ColorSystem ColorSystem => Capabilities.ColorSystem;
+
+ ///
+ /// Gets a value indicating whether or not VT/Ansi codes are supported.
+ ///
+ public bool Ansi => Capabilities.Ansi;
+
+ ///
+ /// Gets a value indicating whether or not unicode is supported.
+ ///
+ public bool Unicode => Capabilities.Unicode;
+
+ ///
+ /// Gets the current justification.
+ ///
+ public Justify? Justification { get; init; }
+
+ ///
+ /// Gets the requested height.
+ ///
+ public int? Height { get; init; }
+
+ ///
+ /// Gets a value indicating whether the context want items to render without
+ /// line breaks and return a single line where applicable.
+ ///
+ internal bool SingleLine { get; init; }
+
+ ///
+ /// Creates a instance from a .
+ ///
+ /// The console.
+ /// The capabilities, or null to use the provided console's capabilities.
+ /// A representing the provided .
+ public static RenderOptions Create(IAnsiConsole console, IReadOnlyCapabilities? capabilities = null)
+ {
+ if (console is null)
+ {
+ throw new ArgumentNullException(nameof(console));
+ }
+
+ return new RenderOptions(
+ capabilities ?? console.Profile.Capabilities,
+ new Size(console.Profile.Width, console.Profile.Height))
+ {
+ Justification = null,
+ Height = null,
+ SingleLine = false,
+ };
+ }
+}
diff --git a/src/Spectre.Console/Rendering/RenderPipeline.cs b/src/Spectre.Console/Rendering/RenderPipeline.cs
index 367fffd..6865c1b 100644
--- a/src/Spectre.Console/Rendering/RenderPipeline.cs
+++ b/src/Spectre.Console/Rendering/RenderPipeline.cs
@@ -44,17 +44,17 @@ public sealed class RenderPipeline
///
/// Processes the specified renderables.
///
- /// The render context.
+ /// The render options.
/// The renderables to process.
/// The processed renderables.
- public IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
lock (_lock)
{
var current = renderables;
for (var index = _hooks.Count - 1; index >= 0; index--)
{
- current = _hooks[index].Process(context, current);
+ current = _hooks[index].Process(options, current);
}
return current;
diff --git a/src/Spectre.Console/Rendering/Renderable.cs b/src/Spectre.Console/Rendering/Renderable.cs
index 2b22f5d..1234053 100644
--- a/src/Spectre.Console/Rendering/Renderable.cs
+++ b/src/Spectre.Console/Rendering/Renderable.cs
@@ -7,25 +7,25 @@ public abstract class Renderable : IRenderable
{
///
[DebuggerStepThrough]
- Measurement IRenderable.Measure(RenderContext context, int maxWidth)
+ Measurement IRenderable.Measure(RenderOptions options, int maxWidth)
{
- return Measure(context, maxWidth);
+ return Measure(options, maxWidth);
}
///
[DebuggerStepThrough]
- IEnumerable IRenderable.Render(RenderContext context, int maxWidth)
+ IEnumerable IRenderable.Render(RenderOptions options, int maxWidth)
{
- return Render(context, maxWidth);
+ return Render(options, maxWidth);
}
///
/// Measures the renderable object.
///
- /// The render context.
+ /// The render options.
/// The maximum allowed width.
/// The minimum and maximum width of the object.
- protected virtual Measurement Measure(RenderContext context, int maxWidth)
+ protected virtual Measurement Measure(RenderOptions options, int maxWidth)
{
return new Measurement(maxWidth, maxWidth);
}
@@ -33,8 +33,8 @@ public abstract class Renderable : IRenderable
///
/// Renders the object.
///
- /// The render context.
+ /// The render options.
/// The maximum allowed width.
/// A collection of segments.
- protected abstract IEnumerable Render(RenderContext context, int maxWidth);
+ protected abstract IEnumerable Render(RenderOptions options, int maxWidth);
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Rendering/Segment.cs b/src/Spectre.Console/Rendering/Segment.cs
index 53bd2f9..9f36a77 100644
--- a/src/Spectre.Console/Rendering/Segment.cs
+++ b/src/Spectre.Console/Rendering/Segment.cs
@@ -201,8 +201,9 @@ public class Segment
///
/// The segments to split into lines.
/// The maximum width.
+ /// The height (if any).
/// A list of lines.
- public static List SplitLines(IEnumerable segments, int maxWidth)
+ public static List SplitLines(IEnumerable segments, int maxWidth, int? height = null)
{
if (segments is null)
{
@@ -294,6 +295,25 @@ public class Segment
lines.Add(line);
}
+ // Got a height specified?
+ if (height != null)
+ {
+ if (lines.Count >= height)
+ {
+ // Remove lines
+ lines.RemoveRange(height.Value, lines.Count - height.Value);
+ }
+ else
+ {
+ // Add lines
+ var missing = height - lines.Count;
+ for (var i = 0; i < missing; i++)
+ {
+ lines.Add(new SegmentLine());
+ }
+ }
+ }
+
return lines;
}
@@ -549,6 +569,21 @@ public class Segment
return cells;
}
+ internal static List MakeWidth(int expectedWidth, List lines)
+ {
+ foreach (var line in lines)
+ {
+ var width = line.CellCount();
+ if (width < expectedWidth)
+ {
+ var diff = expectedWidth - width;
+ line.Add(new Segment(new string(' ', diff)));
+ }
+ }
+
+ return lines;
+ }
+
internal static List SplitSegment(string text, int maxCellLength)
{
var list = new List();
diff --git a/src/Spectre.Console/Rendering/SegmentShape.cs b/src/Spectre.Console/Rendering/SegmentShape.cs
index 6b45c38..fd8c7ff 100644
--- a/src/Spectre.Console/Rendering/SegmentShape.cs
+++ b/src/Spectre.Console/Rendering/SegmentShape.cs
@@ -11,13 +11,8 @@ internal readonly struct SegmentShape
Height = height;
}
- public static SegmentShape Calculate(RenderContext context, List lines)
+ public static SegmentShape Calculate(RenderOptions options, List lines)
{
- if (context is null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
if (lines is null)
{
throw new ArgumentNullException(nameof(lines));
@@ -36,7 +31,7 @@ internal readonly struct SegmentShape
Math.Max(Height, other.Height));
}
- public void Apply(RenderContext context, ref List lines)
+ public void Apply(RenderOptions options, ref List lines)
{
foreach (var line in lines)
{
diff --git a/src/Spectre.Console/Size.cs b/src/Spectre.Console/Size.cs
new file mode 100644
index 0000000..5a074c8
--- /dev/null
+++ b/src/Spectre.Console/Size.cs
@@ -0,0 +1,29 @@
+namespace Spectre.Console;
+
+///
+/// Represents a size.
+///
+[DebuggerDisplay("{Width,nq}x{Height,nq}")]
+public struct Size
+{
+ ///
+ /// Gets the width.
+ ///
+ public int Width { get; }
+
+ ///
+ /// Gets the height.
+ ///
+ public int Height { get; }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The width.
+ /// The height.
+ public Size(int width, int height)
+ {
+ Width = width;
+ Height = height;
+ }
+}
diff --git a/src/Spectre.Console/VerticalAlignment.cs b/src/Spectre.Console/VerticalAlignment.cs
new file mode 100644
index 0000000..dfffb77
--- /dev/null
+++ b/src/Spectre.Console/VerticalAlignment.cs
@@ -0,0 +1,22 @@
+namespace Spectre.Console;
+
+///
+/// Represents vertical alignment.
+///
+public enum VerticalAlignment
+{
+ ///
+ /// Top aligned.
+ ///
+ Top,
+
+ ///
+ /// Middle aligned.
+ ///
+ Middle,
+
+ ///
+ /// Bottom aligned.
+ ///
+ Bottom,
+}
diff --git a/src/Spectre.Console/Widgets/Align.cs b/src/Spectre.Console/Widgets/Align.cs
new file mode 100644
index 0000000..9da88b4
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Align.cs
@@ -0,0 +1,146 @@
+namespace Spectre.Console;
+
+///
+/// Represents a renderable used to align content.
+///
+public sealed class Align : Renderable
+{
+ private readonly IRenderable _renderable;
+
+ ///
+ /// Gets or sets the horizontal alignment.
+ ///
+ public HorizontalAlignment Horizontal { get; set; } = HorizontalAlignment.Left;
+
+ ///
+ /// Gets or sets the vertical alignment.
+ ///
+ public VerticalAlignment? Vertical { get; set; }
+
+ ///
+ /// Gets or sets the width.
+ ///
+ public int? Width { get; set; }
+
+ ///
+ /// Gets or sets the height.
+ ///
+ public int? Height { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The renderable to align.
+ /// The horizontal alignment.
+ /// The vertical alignment, or null if none.
+ public Align(IRenderable renderable, HorizontalAlignment horizontal, VerticalAlignment? vertical = null)
+ {
+ _renderable = renderable ?? throw new ArgumentNullException(nameof(renderable));
+
+ Horizontal = horizontal;
+ Vertical = vertical;
+ }
+
+ ///
+ /// Initializes a new instance of the class that is left aligned.
+ ///
+ /// The to align.
+ /// The vertical alignment, or null if none.
+ /// A new object.
+ public static Align Left(IRenderable renderable, VerticalAlignment? vertical = null)
+ {
+ return new Align(renderable, HorizontalAlignment.Left, vertical);
+ }
+
+ ///
+ /// Initializes a new instance of the class that is center aligned.
+ ///
+ /// The to align.
+ /// The vertical alignment, or null if none.
+ /// A new object.
+ public static Align Center(IRenderable renderable, VerticalAlignment? vertical = null)
+ {
+ return new Align(renderable, HorizontalAlignment.Center, vertical);
+ }
+
+ ///
+ /// Initializes a new instance of the class that is right aligned.
+ ///
+ /// The to align.
+ /// The vertical alignment, or null if none.
+ /// A new object.
+ public static Align Right(IRenderable renderable, VerticalAlignment? vertical = null)
+ {
+ return new Align(renderable, HorizontalAlignment.Right, vertical);
+ }
+
+ ///
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
+ {
+ var rendered = _renderable.Render(options with { Height = null }, maxWidth);
+ var lines = Segment.SplitLines(rendered);
+
+ var width = Math.Min(Width ?? maxWidth, maxWidth);
+ var height = Height ?? options.Height;
+
+ var blank = new SegmentLine(new[] { new Segment(new string(' ', width)) });
+
+ // Align vertically
+ if (Vertical != null && height != null)
+ {
+ switch (Vertical)
+ {
+ case VerticalAlignment.Top:
+ {
+ var diff = Height - lines.Count;
+ for (var i = 0; i < diff; i++)
+ {
+ lines.Add(blank);
+ }
+
+ break;
+ }
+
+ case VerticalAlignment.Middle:
+ {
+ var top = (height - lines.Count) / 2;
+ var bottom = height - top - lines.Count;
+
+ for (var i = 0; i < top; i++)
+ {
+ lines.Insert(0, blank);
+ }
+
+ for (var i = 0; i < bottom; i++)
+ {
+ lines.Add(blank);
+ }
+
+ break;
+ }
+
+ case VerticalAlignment.Bottom:
+ {
+ var diff = Height - lines.Count;
+ for (var i = 0; i < diff; i++)
+ {
+ lines.Insert(0, blank);
+ }
+
+ break;
+ }
+
+ default:
+ throw new NotSupportedException("Unknown vertical alignment");
+ }
+ }
+
+ // Align horizontally
+ foreach (var line in lines)
+ {
+ Aligner.AlignHorizontally(line, Horizontal, width);
+ }
+
+ return new SegmentLineEnumerator(lines);
+ }
+}
diff --git a/src/Spectre.Console/Widgets/Calendar.cs b/src/Spectre.Console/Widgets/Calendar.cs
index 3f4ece6..6e2bcd9 100644
--- a/src/Spectre.Console/Widgets/Calendar.cs
+++ b/src/Spectre.Console/Widgets/Calendar.cs
@@ -107,6 +107,7 @@ public sealed class Calendar : JustInTimeRenderable, IHasCulture, IHasTableBorde
}
///
+ [Obsolete("Use the Align widget instead. This property will be removed in a later release.")]
public Justify? Alignment
{
get => _alignment;
@@ -162,6 +163,7 @@ public sealed class Calendar : JustInTimeRenderable, IHasCulture, IHasTableBorde
{
var culture = Culture ?? CultureInfo.InvariantCulture;
+#pragma warning disable CS0618 // Type or member is obsolete
var table = new Table
{
Border = _border,
@@ -169,6 +171,7 @@ public sealed class Calendar : JustInTimeRenderable, IHasCulture, IHasTableBorde
BorderStyle = _borderStyle,
Alignment = _alignment,
};
+#pragma warning restore CS0618 // Type or member is obsolete
if (ShowHeader)
{
diff --git a/src/Spectre.Console/Widgets/Canvas.cs b/src/Spectre.Console/Widgets/Canvas.cs
index 2718a49..cdabca0 100644
--- a/src/Spectre.Console/Widgets/Canvas.cs
+++ b/src/Spectre.Console/Widgets/Canvas.cs
@@ -70,7 +70,7 @@ public sealed class Canvas : Renderable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
if (PixelWidth < 0)
{
@@ -88,7 +88,7 @@ public sealed class Canvas : Renderable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
if (PixelWidth < 0)
{
diff --git a/src/Spectre.Console/Widgets/Charts/BarChart.cs b/src/Spectre.Console/Widgets/Charts/BarChart.cs
index 457116b..b6367b7 100644
--- a/src/Spectre.Console/Widgets/Charts/BarChart.cs
+++ b/src/Spectre.Console/Widgets/Charts/BarChart.cs
@@ -52,14 +52,14 @@ public sealed class BarChart : Renderable, IHasCulture
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
return new Measurement(width, width);
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
var maxValue = Math.Max(MaxValue ?? 0d, Data.Max(item => item.Value));
@@ -72,7 +72,7 @@ public sealed class BarChart : Renderable, IHasCulture
if (!string.IsNullOrWhiteSpace(Label))
{
- grid.AddRow(Text.Empty, new Markup(Label).Alignment(LabelAlignment));
+ grid.AddRow(Text.Empty, new Markup(Label).Justify(LabelAlignment));
}
foreach (var item in Data)
@@ -93,6 +93,6 @@ public sealed class BarChart : Renderable, IHasCulture
});
}
- return ((IRenderable)grid).Render(context, width);
+ return ((IRenderable)grid).Render(options, width);
}
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Widgets/Charts/BreakdownBar.cs b/src/Spectre.Console/Widgets/Charts/BreakdownBar.cs
index 4db0bc4..fa1e5f9 100644
--- a/src/Spectre.Console/Widgets/Charts/BreakdownBar.cs
+++ b/src/Spectre.Console/Widgets/Charts/BreakdownBar.cs
@@ -11,13 +11,13 @@ internal sealed class BreakdownBar : Renderable
_data = data ?? throw new ArgumentNullException(nameof(data));
}
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
return new Measurement(width, width);
}
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
diff --git a/src/Spectre.Console/Widgets/Charts/BreakdownChart.cs b/src/Spectre.Console/Widgets/Charts/BreakdownChart.cs
index b7f973c..85067c9 100644
--- a/src/Spectre.Console/Widgets/Charts/BreakdownChart.cs
+++ b/src/Spectre.Console/Widgets/Charts/BreakdownChart.cs
@@ -3,7 +3,7 @@ namespace Spectre.Console;
///
/// A renderable breakdown chart.
///
-public sealed class BreakdownChart : Renderable, IHasCulture
+public sealed class BreakdownChart : Renderable, IHasCulture, IExpandable
{
///
/// Gets the breakdown chart data.
@@ -43,6 +43,13 @@ public sealed class BreakdownChart : Renderable, IHasCulture
/// Defaults to invariant culture.
public CultureInfo? Culture { get; set; }
+ ///
+ /// Gets or sets a value indicating whether or not the object should
+ /// expand to the available space. If false, the object's
+ /// width will be auto calculated.
+ ///
+ public bool Expand { get; set; } = true;
+
///
/// Initializes a new instance of the class.
///
@@ -53,14 +60,14 @@ public sealed class BreakdownChart : Renderable, IHasCulture
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
return new Measurement(width, width);
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
@@ -90,6 +97,11 @@ public sealed class BreakdownChart : Renderable, IHasCulture
});
}
- return ((IRenderable)grid).Render(context, width);
+ if (!Expand)
+ {
+ grid.Collapse();
+ }
+
+ return ((IRenderable)grid).Render(options, width);
}
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Widgets/Charts/BreakdownTags.cs b/src/Spectre.Console/Widgets/Charts/BreakdownTags.cs
index 669660a..a747345 100644
--- a/src/Spectre.Console/Widgets/Charts/BreakdownTags.cs
+++ b/src/Spectre.Console/Widgets/Charts/BreakdownTags.cs
@@ -14,13 +14,13 @@ internal sealed class BreakdownTags : Renderable
_data = data ?? throw new ArgumentNullException(nameof(data));
}
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
return new Measurement(width, width);
}
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var culture = Culture ?? CultureInfo.InvariantCulture;
@@ -29,13 +29,13 @@ internal sealed class BreakdownTags : Renderable
{
var panel = new Panel(GetTag(item, culture));
panel.Inline = true;
- panel.Padding = new Padding(0, 0);
+ panel.Padding = new Padding(0, 0, 2, 0);
panel.NoBorder();
panels.Add(panel);
}
- foreach (var segment in ((IRenderable)new Columns(panels).Padding(0, 0)).Render(context, maxWidth))
+ foreach (var segment in ((IRenderable)new Columns(panels).Padding(0, 0)).Render(options, maxWidth))
{
yield return segment;
}
diff --git a/src/Spectre.Console/Widgets/Columns.cs b/src/Spectre.Console/Widgets/Columns.cs
index d6bb8de..de20d35 100644
--- a/src/Spectre.Console/Widgets/Columns.cs
+++ b/src/Spectre.Console/Widgets/Columns.cs
@@ -55,11 +55,11 @@ public sealed class Columns : Renderable, IPaddable, IExpandable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var maxPadding = Math.Max(Padding.GetLeftSafe(), Padding.GetRightSafe());
- var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
+ var itemWidths = _items.Select(item => item.Measure(options, maxWidth).Max).ToArray();
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
if (columnCount == 0)
{
@@ -83,11 +83,11 @@ public sealed class Columns : Renderable, IPaddable, IExpandable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var maxPadding = Math.Max(Padding.GetLeftSafe(), Padding.GetRightSafe());
- var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
+ var itemWidths = _items.Select(item => item.Measure(options, maxWidth).Max).ToArray();
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
if (columnCount == 0)
{
@@ -121,7 +121,7 @@ public sealed class Columns : Renderable, IPaddable, IExpandable
table.AddRow(_items.Skip(start).Take(columnCount).ToArray());
}
- return ((IRenderable)table).Render(context, maxWidth);
+ return ((IRenderable)table).Render(options, maxWidth);
}
// Algorithm borrowed from https://github.com/willmcgugan/rich/blob/master/rich/columns.py
diff --git a/src/Spectre.Console/Widgets/ControlCode.cs b/src/Spectre.Console/Widgets/ControlCode.cs
index fa7b46e..b83d833 100644
--- a/src/Spectre.Console/Widgets/ControlCode.cs
+++ b/src/Spectre.Console/Widgets/ControlCode.cs
@@ -9,14 +9,14 @@ internal sealed class ControlCode : Renderable
_segment = Segment.Control(control);
}
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
return new Measurement(0, 0);
}
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- if (context.Ansi)
+ if (options.Ansi)
{
yield return _segment;
}
diff --git a/src/Spectre.Console/Widgets/Figlet/FigletText.cs b/src/Spectre.Console/Widgets/Figlet/FigletText.cs
index f17d6a5..be4ecde 100644
--- a/src/Spectre.Console/Widgets/Figlet/FigletText.cs
+++ b/src/Spectre.Console/Widgets/Figlet/FigletText.cs
@@ -3,7 +3,7 @@ namespace Spectre.Console;
///
/// Represents text rendered with a FIGlet font.
///
-public sealed class FigletText : Renderable, IAlignable
+public sealed class FigletText : Renderable, IHasJustification
{
private readonly FigletFont _font;
private readonly string _text;
@@ -14,7 +14,7 @@ public sealed class FigletText : Renderable, IAlignable
public Color? Color { get; set; }
///
- public Justify? Alignment { get; set; }
+ public Justify? Justification { get; set; }
///
/// Initializes a new instance of the class.
@@ -37,10 +37,10 @@ public sealed class FigletText : Renderable, IAlignable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var style = new Style(Color ?? Console.Color.Default);
- var alignment = Alignment ?? Justify.Left;
+ var alignment = Justification ?? Console.Justify.Left;
foreach (var row in GetRows(maxWidth))
{
@@ -49,7 +49,7 @@ public sealed class FigletText : Renderable, IAlignable
var line = new Segment(string.Concat(row.Select(x => x.Lines[index])), style);
var lineWidth = line.CellCount();
- if (alignment == Justify.Left)
+ if (alignment == Console.Justify.Left)
{
yield return line;
@@ -58,7 +58,7 @@ public sealed class FigletText : Renderable, IAlignable
yield return Segment.Padding(maxWidth - lineWidth);
}
}
- else if (alignment == Justify.Center)
+ else if (alignment == Console.Justify.Center)
{
var left = (maxWidth - lineWidth) / 2;
var right = left + ((maxWidth - lineWidth) % 2);
@@ -67,7 +67,7 @@ public sealed class FigletText : Renderable, IAlignable
yield return line;
yield return Segment.Padding(right);
}
- else if (alignment == Justify.Right)
+ else if (alignment == Console.Justify.Right)
{
if (lineWidth < maxWidth)
{
diff --git a/src/Spectre.Console/Widgets/Grid.cs b/src/Spectre.Console/Widgets/Grid.cs
index 448ef1b..7a14798 100644
--- a/src/Spectre.Console/Widgets/Grid.cs
+++ b/src/Spectre.Console/Widgets/Grid.cs
@@ -30,6 +30,7 @@ public sealed class Grid : JustInTimeRenderable, IExpandable, IAlignable
}
///
+ [Obsolete("Use the Align widget instead. This property will be removed in a later release.")]
public Justify? Alignment
{
get => _alignment;
diff --git a/src/Spectre.Console/Widgets/Layout/Layout.cs b/src/Spectre.Console/Widgets/Layout/Layout.cs
new file mode 100644
index 0000000..f3bc0c4
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Layout/Layout.cs
@@ -0,0 +1,311 @@
+namespace Spectre.Console;
+
+///
+/// Represents a renderable to divide a fixed height into rows or columns.
+///
+public sealed class Layout : Renderable, IRatioResolvable, IHasVisibility
+{
+ private LayoutSplitter _splitter;
+ private Layout[] _children;
+ private IRenderable _renderable;
+ private int _ratio;
+ private int _minimumSize;
+ private int? _size;
+
+ ///
+ /// Gets or sets the name.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Gets or sets the ratio.
+ ///
+ ///
+ /// Defaults to 1.
+ /// Must be greater than 0.
+ ///
+ public int Ratio
+ {
+ get => _ratio;
+ set
+ {
+ if (value < 1)
+ {
+ throw new InvalidOperationException("Ratio must be equal to or greater than 1");
+ }
+
+ _ratio = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the minimum width.
+ ///
+ ///
+ /// Defaults to 1.
+ /// Must be greater than 0.
+ ///
+ public int MinimumSize
+ {
+ get => _minimumSize;
+ set
+ {
+ if (value < 1)
+ {
+ throw new InvalidOperationException("Minimum size must be equal to or greater than 1");
+ }
+
+ _minimumSize = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the width.
+ ///
+ ///
+ /// Defaults to null.
+ /// Must be greater than 0.
+ ///
+ public int? Size
+ {
+ get => _size;
+ set
+ {
+ if (value < 1)
+ {
+ throw new InvalidOperationException("Size must be equal to or greater than 1");
+ }
+
+ _size = value;
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether or not the layout should
+ /// be visible or not.
+ ///
+ /// Defaults to true.
+ public bool IsVisible { get; set; } = true;
+
+ ///
+ /// Gets the splitter used for this layout.
+ ///
+ internal LayoutSplitter Splitter => _splitter;
+
+ ///
+ /// Gets the associated with this layout.
+ ///
+ internal IRenderable Renderable => _renderable;
+
+ ///
+ /// Gets a child layout by it's name.
+ ///
+ /// The layout name.
+ /// The specified child .
+ public Layout this[string name]
+ {
+ get => GetLayout(name);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The layout name.
+ public Layout(string name)
+ : this(name, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The renderable.
+ public Layout(IRenderable renderable)
+ : this(null, renderable)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The layout name.
+ /// The renderable.
+ public Layout(string? name = null, IRenderable? renderable = null)
+ {
+ _splitter = LayoutSplitter.Null;
+ _children = Array.Empty();
+ _renderable = renderable ?? new LayoutPlaceholder(this);
+ _ratio = 1;
+ _size = null;
+
+ Name = name;
+ }
+
+ ///
+ /// Gets a child layout by it's name.
+ ///
+ /// The layout name.
+ /// The specified child .
+ public Layout GetLayout(string name)
+ {
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new ArgumentException($"'{nameof(name)}' cannot be null or empty.", nameof(name));
+ }
+
+ var stack = new Stack();
+ stack.Push(this);
+
+ while (stack.Count > 0)
+ {
+ var current = stack.Pop();
+ if (name.Equals(current.Name, StringComparison.OrdinalIgnoreCase))
+ {
+ return current;
+ }
+
+ foreach (var layout in current.GetChildren())
+ {
+ stack.Push(layout);
+ }
+ }
+
+ throw new InvalidOperationException($"Could not find layout '{name}'");
+ }
+
+ ///
+ /// Splits the layout into rows.
+ ///
+ /// The layout to split into rows.
+ /// The same instance so that multiple calls can be chained.
+ public Layout SplitRows(params Layout[] children)
+ {
+ Split(LayoutSplitter.Row, children);
+ return this;
+ }
+
+ ///
+ /// Splits the layout into columns.
+ ///
+ /// The layout to split into columns.
+ /// The same instance so that multiple calls can be chained.
+ public Layout SplitColumns(params Layout[] children)
+ {
+ Split(LayoutSplitter.Column, children);
+ return this;
+ }
+
+ ///
+ /// Updates the containing .
+ ///
+ /// The renderable to use for this layout.
+ /// /// The same instance so that multiple calls can be chained.
+ public Layout Update(IRenderable renderable)
+ {
+ _renderable = renderable ?? new LayoutPlaceholder(this);
+ return this;
+ }
+
+ ///
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
+ {
+ var height = options.Height ?? options.ConsoleSize.Height;
+ var map = MakeRenderMap(options, maxWidth);
+
+ var layoutLines = new List();
+ layoutLines.AddRange(Enumerable.Range(0, height).Select(x => new SegmentLine()));
+
+ foreach (var (region, lines) in map.Values.Select(x => (x.Region, x.Render)))
+ {
+ foreach (var line in layoutLines
+ .Skip(region.Y)
+ .Take(region.Y + region.Height)
+ .Enumerate().Select(x => (Index: x.Index + region.Y, Line: x.Item))
+ .Zip(lines, (first, second) => (first.Index, Line: second)))
+ {
+ layoutLines[line.Index].AddRange(line.Line);
+ }
+ }
+
+ // Return all the segments in all the lines
+ foreach (var (_, _, last, line) in layoutLines.Enumerate())
+ {
+ foreach (var segment in line)
+ {
+ yield return segment;
+ }
+
+ if (!last)
+ {
+ yield return Segment.LineBreak;
+ }
+ }
+ }
+
+ private IEnumerable GetChildren(bool visibleOnly = false)
+ {
+ return visibleOnly ? _children.Where(c => c.IsVisible) : _children;
+ }
+
+ private bool HasChildren(bool visibleOnly = false)
+ {
+ return visibleOnly ? _children.Any(c => c.IsVisible) : _children.Any();
+ }
+
+ private void Split(LayoutSplitter splitter, Layout[] layouts)
+ {
+ if (_children.Length > 0)
+ {
+ throw new InvalidOperationException("Cannot split the same layout twice");
+ }
+
+ _splitter = splitter ?? throw new ArgumentNullException(nameof(splitter));
+ _children = layouts ?? throw new ArgumentNullException(nameof(layouts));
+ }
+
+ private Dictionary MakeRenderMap(RenderOptions options, int maxWidth)
+ {
+ var result = new Dictionary();
+
+ var renderWidth = maxWidth;
+ var renderHeight = options.Height ?? options.ConsoleSize.Height;
+ var regionMap = MakeRegionMap(maxWidth, renderHeight);
+
+ foreach (var (layout, region) in regionMap.Where(x => !x.Layout.HasChildren(visibleOnly: true)))
+ {
+ var segments = layout.Renderable.Render(options with { Height = region.Height }, region.Width);
+
+ var lines = Segment.SplitLines(segments, region.Width, region.Height);
+ lines = Segment.MakeWidth(region.Width, lines);
+
+ result[layout] = new LayoutRender(region, lines);
+ }
+
+ return result;
+ }
+
+ private IEnumerable<(Layout Layout, Region Region)> MakeRegionMap(int width, int height)
+ {
+ var stack = new Stack<(Layout Layout, Region Region)>();
+ stack.Push((this, new Region(0, 0, width, height)));
+
+ var result = new List<(Layout Layout, Region Region)>();
+
+ while (stack.Count > 0)
+ {
+ var current = stack.Pop();
+ result.Add(current);
+
+ if (current.Layout.HasChildren(visibleOnly: true))
+ {
+ foreach (var childAndRegion in current.Layout.Splitter
+ .Divide(current.Region, current.Layout.GetChildren(visibleOnly: true)))
+ {
+ stack.Push(childAndRegion);
+ }
+ }
+ }
+
+ return result.ReverseEnumerable();
+ }
+}
diff --git a/src/Spectre.Console/Widgets/Layout/LayoutPlaceholder.cs b/src/Spectre.Console/Widgets/Layout/LayoutPlaceholder.cs
new file mode 100644
index 0000000..46b959a
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Layout/LayoutPlaceholder.cs
@@ -0,0 +1,31 @@
+namespace Spectre.Console;
+
+internal sealed class LayoutPlaceholder : Renderable
+{
+ public Layout Layout { get; }
+
+ public LayoutPlaceholder(Layout layout)
+ {
+ Layout = layout ?? throw new ArgumentNullException(nameof(layout));
+ }
+
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
+ {
+ var width = maxWidth;
+ var height = options.Height ?? options.ConsoleSize.Height;
+ var title = Layout.Name != null
+ ? $"{Layout.Name} ({width} x {height})"
+ : $"{width} x {height}";
+
+ var panel = new Panel(
+ Align.Center(new Text("Placeholder"), VerticalAlignment.Middle))
+ {
+ Width = maxWidth,
+ Height = options.Height ?? options.ConsoleSize.Height,
+ Header = new PanelHeader(title),
+ Border = BoxBorder.Rounded,
+ };
+
+ return ((IRenderable)panel).Render(options, maxWidth);
+ }
+}
diff --git a/src/Spectre.Console/Widgets/Layout/LayoutRender.cs b/src/Spectre.Console/Widgets/Layout/LayoutRender.cs
new file mode 100644
index 0000000..a608be7
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Layout/LayoutRender.cs
@@ -0,0 +1,14 @@
+namespace Spectre.Console;
+
+[DebuggerDisplay("{Region,nq}")]
+internal sealed class LayoutRender
+{
+ public Region Region { get; }
+ public List Render { get; }
+
+ public LayoutRender(Region region, List render)
+ {
+ Region = region;
+ Render = render ?? throw new ArgumentNullException(nameof(render));
+ }
+}
\ No newline at end of file
diff --git a/src/Spectre.Console/Widgets/Layout/LayoutSplitter.cs b/src/Spectre.Console/Widgets/Layout/LayoutSplitter.cs
new file mode 100644
index 0000000..6be913c
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Layout/LayoutSplitter.cs
@@ -0,0 +1,48 @@
+namespace Spectre.Console;
+
+internal abstract class LayoutSplitter
+{
+ public static LayoutSplitter Column { get; } = new ColumnSplitter();
+ public static LayoutSplitter Row { get; } = new RowSplitter();
+ public static LayoutSplitter Null { get; } = new NullSplitter();
+
+ public abstract IEnumerable<(Layout Child, Region Region)> Divide(Region region, IEnumerable layouts);
+
+ private sealed class NullSplitter : LayoutSplitter
+ {
+ public override IEnumerable<(Layout Child, Region Region)> Divide(Region region, IEnumerable layouts)
+ {
+ yield break;
+ }
+ }
+
+ private sealed class ColumnSplitter : LayoutSplitter
+ {
+ public override IEnumerable<(Layout Child, Region Region)> Divide(Region region, IEnumerable children)
+ {
+ var widths = Ratio.Resolve(region.Width, children);
+ var offset = 0;
+
+ foreach (var (child, childWidth) in children.Zip(widths, (child, width) => (child, width)))
+ {
+ yield return (child, new Region(region.X + offset, region.Y, childWidth, region.Height));
+ offset += childWidth;
+ }
+ }
+ }
+
+ private sealed class RowSplitter : LayoutSplitter
+ {
+ public override IEnumerable<(Layout Child, Region Region)> Divide(Region region, IEnumerable children)
+ {
+ var heights = Ratio.Resolve(region.Height, children);
+ var offset = 0;
+
+ foreach (var (child, childHeight) in children.Zip(heights, (child, height) => (child, height)))
+ {
+ yield return (child, new Region(region.X, region.Y + offset, region.Width, childHeight));
+ offset += childHeight;
+ }
+ }
+ }
+}
diff --git a/src/Spectre.Console/Widgets/Markup.cs b/src/Spectre.Console/Widgets/Markup.cs
index 7b23376..5e43809 100644
--- a/src/Spectre.Console/Widgets/Markup.cs
+++ b/src/Spectre.Console/Widgets/Markup.cs
@@ -4,15 +4,15 @@ namespace Spectre.Console;
/// A renderable piece of markup text.
///
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
-public sealed class Markup : Renderable, IAlignable, IOverflowable
+public sealed class Markup : Renderable, IHasJustification, IOverflowable
{
private readonly Paragraph _paragraph;
///
- public Justify? Alignment
+ public Justify? Justification
{
- get => _paragraph.Alignment;
- set => _paragraph.Alignment = value;
+ get => _paragraph.Justification;
+ set => _paragraph.Justification = value;
}
///
@@ -43,15 +43,15 @@ public sealed class Markup : Renderable, IAlignable, IOverflowable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
- return ((IRenderable)_paragraph).Measure(context, maxWidth);
+ return ((IRenderable)_paragraph).Measure(options, maxWidth);
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- return ((IRenderable)_paragraph).Render(context, maxWidth);
+ return ((IRenderable)_paragraph).Render(options, maxWidth);
}
///
diff --git a/src/Spectre.Console/Widgets/Padder.cs b/src/Spectre.Console/Widgets/Padder.cs
index 9f2d376..eeecdf1 100644
--- a/src/Spectre.Console/Widgets/Padder.cs
+++ b/src/Spectre.Console/Widgets/Padder.cs
@@ -29,10 +29,10 @@ public sealed class Padder : Renderable, IPaddable, IExpandable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var paddingWidth = Padding?.GetWidth() ?? 0;
- var measurement = _child.Measure(context, maxWidth - paddingWidth);
+ var measurement = _child.Measure(options, maxWidth - paddingWidth);
return new Measurement(
measurement.Min + paddingWidth,
@@ -40,14 +40,14 @@ public sealed class Padder : Renderable, IPaddable, IExpandable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var paddingWidth = Padding?.GetWidth() ?? 0;
var childWidth = maxWidth - paddingWidth;
if (!Expand)
{
- var measurement = _child.Measure(context, maxWidth - paddingWidth);
+ var measurement = _child.Measure(options, maxWidth - paddingWidth);
childWidth = measurement.Max;
}
@@ -66,7 +66,7 @@ public sealed class Padder : Renderable, IPaddable, IExpandable
result.Add(Segment.LineBreak);
}
- var child = _child.Render(context, maxWidth - paddingWidth);
+ var child = _child.Render(options, maxWidth - paddingWidth);
foreach (var line in Segment.SplitLines(child))
{
// Left padding
diff --git a/src/Spectre.Console/Widgets/Panel.cs b/src/Spectre.Console/Widgets/Panel.cs
index 0c263cb..05d41d4 100644
--- a/src/Spectre.Console/Widgets/Panel.cs
+++ b/src/Spectre.Console/Widgets/Panel.cs
@@ -35,6 +35,16 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
///
public PanelHeader? Header { get; set; }
+ ///
+ /// Gets or sets the width of the panel.
+ ///
+ public int? Width { get; set; }
+
+ ///
+ /// Gets or sets the height of the panel.
+ ///
+ public int? Height { get; set; }
+
///
/// Gets or sets a value indicating whether or not the panel is inlined.
///
@@ -59,54 +69,73 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var child = new Padder(_child, Padding);
- var childWidth = ((IRenderable)child).Measure(context, maxWidth);
+ return Measure(options, maxWidth, child);
+ }
+
+ private Measurement Measure(RenderOptions options, int maxWidth, IRenderable child)
+ {
+ var edgeWidth = (options.GetSafeBorder(this) is not NoBoxBorder) ? EdgeWidth : 0;
+ var childWidth = child.Measure(options, maxWidth - edgeWidth);
+
+ if (Width != null)
+ {
+ var width = Width.Value - edgeWidth;
+ if (width > childWidth.Max)
+ {
+ childWidth = new Measurement(
+ childWidth.Min,
+ width);
+ }
+ }
+
return new Measurement(
- childWidth.Min + EdgeWidth,
- childWidth.Max + EdgeWidth);
+ childWidth.Min + edgeWidth,
+ childWidth.Max + edgeWidth);
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- var edgeWidth = EdgeWidth;
-
- var border = BoxExtensions.GetSafeBorder(Border, !context.Unicode && UseSafeBorder);
+ var border = options.GetSafeBorder(this);
var borderStyle = BorderStyle ?? Style.Plain;
- var showBorder = true;
- if (border is NoBoxBorder)
- {
- showBorder = false;
- edgeWidth = 0;
- }
+ var showBorder = border is not NoBoxBorder;
+ var edgeWidth = showBorder ? EdgeWidth : 0;
var child = new Padder(_child, Padding);
- var childWidth = maxWidth - edgeWidth;
+ var width = Measure(options, maxWidth, child);
+
+ var panelWidth = Math.Min(!Expand ? width.Max : maxWidth, maxWidth);
+ var innerWidth = panelWidth - edgeWidth;
+
+ var height = Height != null
+ ? Height - 2
+ : options.Height != null
+ ? options.Height - 2
+ : null;
if (!Expand)
{
- var measurement = ((IRenderable)child).Measure(context, maxWidth - edgeWidth);
- childWidth = measurement.Max;
+ // Set the height to the explicit height (or null)
+ // if the panel isn't expandable.
+ height = Height != null ? Height - 2 : null;
}
- var panelWidth = childWidth + edgeWidth;
- panelWidth = Math.Min(panelWidth, maxWidth);
- childWidth = panelWidth - edgeWidth;
-
+ // Start building the panel
var result = new List();
+ // Panel top
if (showBorder)
{
- // Panel top
- AddTopBorder(result, context, border, borderStyle, panelWidth);
+ AddTopBorder(result, options, border, borderStyle, panelWidth);
}
// Split the child segments into lines.
- var childSegments = ((IRenderable)child).Render(context, childWidth);
- foreach (var (_, _, last, line) in Segment.SplitLines(childSegments, childWidth).Enumerate())
+ var childSegments = ((IRenderable)child).Render(options with { Height = height }, innerWidth);
+ foreach (var (_, _, last, line) in Segment.SplitLines(childSegments, innerWidth, height).Enumerate())
{
if (line.Count == 1 && line[0].IsWhiteSpace)
{
@@ -125,9 +154,9 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
// Do we need to pad the panel?
var length = line.Sum(segment => segment.CellCount());
- if (length < childWidth)
+ if (length < innerWidth)
{
- var diff = childWidth - length;
+ var diff = innerWidth - length;
content.Add(Segment.Padding(diff));
}
@@ -170,7 +199,7 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
}
private void AddTopBorder(
- List result, RenderContext context, BoxBorder border,
+ List result, RenderOptions options, BoxBorder border,
Style borderStyle, int panelWidth)
{
var rule = new Rule
@@ -180,14 +209,14 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
TitlePadding = 1,
TitleSpacing = 0,
Title = Header?.Text,
- Alignment = Header?.Alignment ?? Justify.Left,
+ Justification = Header?.Justification ?? Justify.Left,
};
// Top left border
result.Add(new Segment(border.GetPart(BoxBorderPart.TopLeft), borderStyle));
// Top border (and header text if specified)
- result.AddRange(((IRenderable)rule).Render(context, panelWidth - 2).Where(x => !x.IsLineBreak));
+ result.AddRange(((IRenderable)rule).Render(options, panelWidth - 2).Where(x => !x.IsLineBreak));
// Top right border
result.Add(new Segment(border.GetPart(BoxBorderPart.TopRight), borderStyle));
diff --git a/src/Spectre.Console/Widgets/PanelHeader.cs b/src/Spectre.Console/Widgets/PanelHeader.cs
index 951dcbd..97cdd33 100644
--- a/src/Spectre.Console/Widgets/PanelHeader.cs
+++ b/src/Spectre.Console/Widgets/PanelHeader.cs
@@ -3,7 +3,7 @@ namespace Spectre.Console;
///
/// Represents a panel header.
///
-public sealed class PanelHeader : IAlignable
+public sealed class PanelHeader : IHasJustification
{
///
/// Gets the panel header text.
@@ -13,7 +13,7 @@ public sealed class PanelHeader : IAlignable
///
/// Gets or sets the panel header alignment.
///
- public Justify? Alignment { get; set; }
+ public Justify? Justification { get; set; }
///
/// Initializes a new instance of the class.
@@ -23,7 +23,7 @@ public sealed class PanelHeader : IAlignable
public PanelHeader(string text, Justify? alignment = null)
{
Text = text ?? throw new ArgumentNullException(nameof(text));
- Alignment = alignment;
+ Justification = alignment;
}
///
@@ -57,7 +57,7 @@ public sealed class PanelHeader : IAlignable
/// The same instance so that multiple calls can be chained.
public PanelHeader SetAlignment(Justify alignment)
{
- Alignment = alignment;
+ Justification = alignment;
return this;
}
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Widgets/Paragraph.cs b/src/Spectre.Console/Widgets/Paragraph.cs
index 5ac2f8e..96012d4 100644
--- a/src/Spectre.Console/Widgets/Paragraph.cs
+++ b/src/Spectre.Console/Widgets/Paragraph.cs
@@ -5,14 +5,14 @@ namespace Spectre.Console;
/// of the paragraph can have individual styling.
///
[DebuggerDisplay("{_text,nq}")]
-public sealed class Paragraph : Renderable, IAlignable, IOverflowable
+public sealed class Paragraph : Renderable, IHasJustification, IOverflowable
{
private readonly List _lines;
///
/// Gets or sets the alignment of the whole paragraph.
///
- public Justify? Alignment { get; set; }
+ public Justify? Justification { get; set; }
///
/// Gets or sets the text overflow strategy.
@@ -115,7 +115,7 @@ public sealed class Paragraph : Renderable, IAlignable, IOverflowable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
if (_lines.Count == 0)
{
@@ -129,11 +129,11 @@ public sealed class Paragraph : Renderable, IAlignable, IOverflowable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- if (context is null)
+ if (options is null)
{
- throw new ArgumentNullException(nameof(context));
+ throw new ArgumentNullException(nameof(options));
}
if (_lines.Count == 0)
@@ -141,13 +141,13 @@ public sealed class Paragraph : Renderable, IAlignable, IOverflowable
return Array.Empty();
}
- var lines = context.SingleLine
+ var lines = options.SingleLine
? new List(_lines)
: SplitLines(maxWidth);
// Justify lines
- var justification = context.Justification ?? Alignment ?? Justify.Left;
- if (justification != Justify.Left)
+ var justification = options.Justification ?? Justification ?? Console.Justify.Left;
+ if (justification != Console.Justify.Left)
{
foreach (var line in lines)
{
@@ -155,7 +155,7 @@ public sealed class Paragraph : Renderable, IAlignable, IOverflowable
}
}
- if (context.SingleLine)
+ if (options.SingleLine)
{
// Return the first line
return lines[0].Where(segment => !segment.IsLineBreak);
diff --git a/src/Spectre.Console/Widgets/ProgressBar.cs b/src/Spectre.Console/Widgets/ProgressBar.cs
index 67ef339..6b59a42 100644
--- a/src/Spectre.Console/Widgets/ProgressBar.cs
+++ b/src/Spectre.Console/Widgets/ProgressBar.cs
@@ -23,13 +23,13 @@ internal sealed class ProgressBar : Renderable, IHasCulture
internal static Style DefaultPulseStyle { get; } = new Style(foreground: Color.DodgerBlue1, background: Color.Grey23);
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
return new Measurement(4, width);
}
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var width = Math.Min(Width ?? maxWidth, maxWidth);
var completedBarCount = Math.Min(MaxValue, Math.Max(0, Value));
@@ -37,7 +37,7 @@ internal sealed class ProgressBar : Renderable, IHasCulture
if (IsIndeterminate && !isCompleted)
{
- foreach (var segment in RenderIndeterminate(context, width))
+ foreach (var segment in RenderIndeterminate(options, width))
{
yield return segment;
}
@@ -45,7 +45,7 @@ internal sealed class ProgressBar : Renderable, IHasCulture
yield break;
}
- var bar = !context.Unicode ? AsciiBar : UnicodeBar;
+ var bar = !options.Unicode ? AsciiBar : UnicodeBar;
var style = isCompleted ? FinishedStyle : CompletedStyle;
var barCount = Math.Max(0, (int)(width * (completedBarCount / MaxValue)));
@@ -84,29 +84,29 @@ internal sealed class ProgressBar : Renderable, IHasCulture
}
}
- var legacy = context.ColorSystem == ColorSystem.NoColors || context.ColorSystem == ColorSystem.Legacy;
+ var legacy = options.ColorSystem == ColorSystem.NoColors || options.ColorSystem == ColorSystem.Legacy;
var remainingToken = ShowRemaining && !legacy ? bar : ' ';
yield return new Segment(new string(remainingToken, diff), RemainingStyle);
}
}
- private IEnumerable RenderIndeterminate(RenderContext context, int width)
+ private IEnumerable RenderIndeterminate(RenderOptions options, int width)
{
- var bar = context.Unicode ? UnicodeBar.ToString() : AsciiBar.ToString();
+ var bar = options.Unicode ? UnicodeBar.ToString() : AsciiBar.ToString();
var style = IndeterminateStyle ?? DefaultPulseStyle;
IEnumerable GetPulseSegments()
{
// For 1-bit and 3-bit colors, fall back to
// a simpler versions with only two colors.
- if (context.ColorSystem == ColorSystem.NoColors ||
- context.ColorSystem == ColorSystem.Legacy)
+ if (options.ColorSystem == ColorSystem.NoColors ||
+ options.ColorSystem == ColorSystem.Legacy)
{
// First half of the pulse
var segments = Enumerable.Repeat(new Segment(bar, new Style(style.Foreground)), PULSESIZE / 2);
// Second half of the pulse
- var legacy = context.ColorSystem == ColorSystem.NoColors || context.ColorSystem == ColorSystem.Legacy;
+ var legacy = options.ColorSystem == ColorSystem.NoColors || options.ColorSystem == ColorSystem.Legacy;
var bar2 = legacy ? " " : bar;
segments = segments.Concat(Enumerable.Repeat(new Segment(bar2, new Style(style.Background)), PULSESIZE - (PULSESIZE / 2)));
diff --git a/src/Spectre.Console/Widgets/Rows.cs b/src/Spectre.Console/Widgets/Rows.cs
index 32f88cf..9539440 100644
--- a/src/Spectre.Console/Widgets/Rows.cs
+++ b/src/Spectre.Console/Widgets/Rows.cs
@@ -29,7 +29,7 @@ public sealed class Rows : Renderable, IExpandable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
if (Expand)
{
@@ -37,7 +37,7 @@ public sealed class Rows : Renderable, IExpandable
}
else
{
- var measurements = _children.Select(c => c.Measure(context, maxWidth));
+ var measurements = _children.Select(c => c.Measure(options, maxWidth));
return new Measurement(
measurements.Min(c => c.Min),
measurements.Min(c => c.Max));
@@ -45,13 +45,13 @@ public sealed class Rows : Renderable, IExpandable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var result = new List();
foreach (var child in _children)
{
- var segments = child.Render(context, maxWidth);
+ var segments = child.Render(options, maxWidth);
foreach (var (_, _, last, segment) in segments.Enumerate())
{
result.Add(segment);
diff --git a/src/Spectre.Console/Widgets/Rule.cs b/src/Spectre.Console/Widgets/Rule.cs
index 210318c..0bcef99 100644
--- a/src/Spectre.Console/Widgets/Rule.cs
+++ b/src/Spectre.Console/Widgets/Rule.cs
@@ -3,7 +3,7 @@ namespace Spectre.Console;
///
/// A renderable horizontal rule.
///
-public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
+public sealed class Rule : Renderable, IHasJustification, IHasBoxBorder
{
///
/// Gets or sets the rule title markup text.
@@ -16,9 +16,9 @@ public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
public Style? Style { get; set; }
///
- /// Gets or sets the rule's title alignment.
+ /// Gets or sets the rule's title justification.
///
- public Justify? Alignment { get; set; }
+ public Justify? Justification { get; set; }
///
public BoxBorder Border { get; set; } = BoxBorder.Square;
@@ -43,17 +43,17 @@ public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var extraLength = (2 * TitlePadding) + (2 * TitleSpacing);
if (Title == null || maxWidth <= extraLength)
{
- return GetLineWithoutTitle(context, maxWidth);
+ return GetLineWithoutTitle(options, maxWidth);
}
// Get the title and make sure it fits.
- var title = GetTitleSegments(context, Title, maxWidth - extraLength);
+ var title = GetTitleSegments(options, Title, maxWidth - extraLength);
if (Segment.CellCount(title) > maxWidth - extraLength)
{
// Truncate the title
@@ -61,11 +61,11 @@ public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
if (!title.Any())
{
// We couldn't fit the title at all.
- return GetLineWithoutTitle(context, maxWidth);
+ return GetLineWithoutTitle(options, maxWidth);
}
}
- var (left, right) = GetLineSegments(context, maxWidth, title);
+ var (left, right) = GetLineSegments(options, maxWidth, title);
var segments = new List();
segments.Add(left);
@@ -76,9 +76,9 @@ public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
return segments;
}
- private IEnumerable GetLineWithoutTitle(RenderContext context, int maxWidth)
+ private IEnumerable GetLineWithoutTitle(RenderOptions options, int maxWidth)
{
- var border = Border.GetSafeBorder(safe: !context.Unicode);
+ var border = Border.GetSafeBorder(safe: !options.Unicode);
var text = border.GetPart(BoxBorderPart.Top).Repeat(maxWidth);
return new[]
@@ -88,21 +88,21 @@ public sealed class Rule : Renderable, IAlignable, IHasBoxBorder
};
}
- private IEnumerable GetTitleSegments(RenderContext context, string title, int width)
+ private IEnumerable GetTitleSegments(RenderOptions options, string title, int width)
{
title = title.NormalizeNewLines().ReplaceExact("\n", " ").Trim();
var markup = new Markup(title, Style);
- return ((IRenderable)markup).Render(context.WithSingleLine(), width);
+ return ((IRenderable)markup).Render(options with { SingleLine = true }, width);
}
- private (Segment Left, Segment Right) GetLineSegments(RenderContext context, int width, IEnumerable title)
+ private (Segment Left, Segment Right) GetLineSegments(RenderOptions options, int width, IEnumerable title)
{
var titleLength = Segment.CellCount(title);
- var border = Border.GetSafeBorder(safe: !context.Unicode);
+ var border = Border.GetSafeBorder(safe: !options.Unicode);
var borderPart = border.GetPart(BoxBorderPart.Top);
- var alignment = Alignment ?? Justify.Center;
+ var alignment = Justification ?? Justify.Center;
if (alignment == Justify.Left)
{
var left = new Segment(borderPart.Repeat(TitlePadding) + new string(' ', TitleSpacing), Style ?? Style.Plain);
diff --git a/src/Spectre.Console/Widgets/Table/Table.cs b/src/Spectre.Console/Widgets/Table/Table.cs
index a22dd63..c0d83e1 100644
--- a/src/Spectre.Console/Widgets/Table/Table.cs
+++ b/src/Spectre.Console/Widgets/Table/Table.cs
@@ -59,6 +59,7 @@ public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
public TableTitle? Caption { get; set; }
///
+ [Obsolete("Use the Align widget instead. This property will be removed in a later release.")]
public Justify? Alignment { get; set; }
// Whether this is a grid or not.
@@ -100,14 +101,14 @@ public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
}
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
- if (context is null)
+ if (options is null)
{
- throw new ArgumentNullException(nameof(context));
+ throw new ArgumentNullException(nameof(options));
}
- var measurer = new TableMeasurer(this, context);
+ var measurer = new TableMeasurer(this, options);
// Calculate the total cell width
var totalCellWidth = measurer.CalculateTotalCellWidth(maxWidth);
@@ -120,14 +121,14 @@ public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- if (context is null)
+ if (options is null)
{
- throw new ArgumentNullException(nameof(context));
+ throw new ArgumentNullException(nameof(options));
}
- var measurer = new TableMeasurer(this, context);
+ var measurer = new TableMeasurer(this, options);
// Calculate the column and table width
var totalCellWidth = measurer.CalculateTotalCellWidth(maxWidth);
@@ -139,7 +140,7 @@ public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
// Render the table
return TableRenderer.Render(
- new TableRendererContext(this, context, rows, tableWidth, maxWidth),
+ new TableRendererContext(this, options, rows, tableWidth, maxWidth),
columnWidths);
}
diff --git a/src/Spectre.Console/Widgets/Table/TableAccessor.cs b/src/Spectre.Console/Widgets/Table/TableAccessor.cs
index 2979a0d..3dda3ee 100644
--- a/src/Spectre.Console/Widgets/Table/TableAccessor.cs
+++ b/src/Spectre.Console/Widgets/Table/TableAccessor.cs
@@ -4,12 +4,12 @@ internal abstract class TableAccessor
{
private readonly Table _table;
- public RenderContext Options { get; }
+ public RenderOptions Options { get; }
public IReadOnlyList Columns => _table.Columns;
public virtual IReadOnlyList Rows => _table.Rows;
public bool Expand => _table.Expand || _table.Width != null;
- protected TableAccessor(Table table, RenderContext options)
+ protected TableAccessor(Table table, RenderOptions options)
{
_table = table ?? throw new ArgumentNullException(nameof(table));
Options = options ?? throw new ArgumentNullException(nameof(options));
diff --git a/src/Spectre.Console/Widgets/Table/TableMeasurer.cs b/src/Spectre.Console/Widgets/Table/TableMeasurer.cs
index d7a26cd..d436a08 100644
--- a/src/Spectre.Console/Widgets/Table/TableMeasurer.cs
+++ b/src/Spectre.Console/Widgets/Table/TableMeasurer.cs
@@ -8,7 +8,7 @@ internal sealed class TableMeasurer : TableAccessor
private readonly TableBorder _border;
private readonly bool _padRightCell;
- public TableMeasurer(Table table, RenderContext options)
+ public TableMeasurer(Table table, RenderOptions options)
: base(table, options)
{
_explicitWidth = table.Width;
diff --git a/src/Spectre.Console/Widgets/Table/TableRenderer.cs b/src/Spectre.Console/Widgets/Table/TableRenderer.cs
index fadade9..467fe61 100644
--- a/src/Spectre.Console/Widgets/Table/TableRenderer.cs
+++ b/src/Spectre.Console/Widgets/Table/TableRenderer.cs
@@ -26,7 +26,7 @@ internal static class TableRenderer
foreach (var (columnIndex, _, _, (rowWidth, cell)) in columnWidths.Zip(row).Enumerate())
{
var justification = context.Columns[columnIndex].Alignment;
- var childContext = context.Options.WithJustification(justification);
+ var childContext = context.Options with { Justification = justification };
var lines = Segment.SplitLines(cell.Render(childContext, rowWidth));
cellHeight = Math.Max(cellHeight, lines.Count);
@@ -159,7 +159,7 @@ internal static class TableRenderer
}
var paragraph = new Markup(header.Text, header.Style ?? defaultStyle)
- .Alignment(Justify.Center)
+ .Justify(Justify.Center)
.Overflow(Overflow.Ellipsis);
// Render the paragraphs
diff --git a/src/Spectre.Console/Widgets/Table/TableRendererContext.cs b/src/Spectre.Console/Widgets/Table/TableRendererContext.cs
index 17e98c7..b549802 100644
--- a/src/Spectre.Console/Widgets/Table/TableRendererContext.cs
+++ b/src/Spectre.Console/Widgets/Table/TableRendererContext.cs
@@ -31,9 +31,12 @@ internal sealed class TableRendererContext : TableAccessor
public bool PadRightCell => _table.PadRightCell;
public TableTitle? Title => _table.Title;
public TableTitle? Caption => _table.Caption;
- public Justify? Alignment => _table.Alignment;
- public TableRendererContext(Table table, RenderContext options, IEnumerable rows, int tableWidth, int maxWidth)
+#pragma warning disable CS0618 // Type or member is obsolete
+ public Justify? Alignment => _table.Alignment;
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ public TableRendererContext(Table table, RenderOptions options, IEnumerable rows, int tableWidth, int maxWidth)
: base(table, options)
{
_table = table ?? throw new ArgumentNullException(nameof(table));
diff --git a/src/Spectre.Console/Widgets/Text.cs b/src/Spectre.Console/Widgets/Text.cs
index e84c2f3..d715730 100644
--- a/src/Spectre.Console/Widgets/Text.cs
+++ b/src/Spectre.Console/Widgets/Text.cs
@@ -5,7 +5,7 @@ namespace Spectre.Console;
///
[DebuggerDisplay("{_text,nq}")]
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
-public sealed class Text : Renderable, IAlignable, IOverflowable
+public sealed class Text : Renderable, IHasJustification, IOverflowable
{
private readonly Paragraph _paragraph;
@@ -32,10 +32,10 @@ public sealed class Text : Renderable, IAlignable, IOverflowable
///
/// Gets or sets the text alignment.
///
- public Justify? Alignment
+ public Justify? Justification
{
- get => _paragraph.Alignment;
- set => _paragraph.Alignment = value;
+ get => _paragraph.Justification;
+ set => _paragraph.Justification = value;
}
///
@@ -58,14 +58,14 @@ public sealed class Text : Renderable, IAlignable, IOverflowable
public int Lines => _paragraph.Lines;
///
- protected override Measurement Measure(RenderContext context, int maxWidth)
+ protected override Measurement Measure(RenderOptions options, int maxWidth)
{
- return ((IRenderable)_paragraph).Measure(context, maxWidth);
+ return ((IRenderable)_paragraph).Measure(options, maxWidth);
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
- return ((IRenderable)_paragraph).Render(context, maxWidth);
+ return ((IRenderable)_paragraph).Render(options, maxWidth);
}
}
\ No newline at end of file
diff --git a/src/Spectre.Console/Widgets/TextPath.cs b/src/Spectre.Console/Widgets/TextPath.cs
index 2d03e19..92c8471 100644
--- a/src/Spectre.Console/Widgets/TextPath.cs
+++ b/src/Spectre.Console/Widgets/TextPath.cs
@@ -3,7 +3,7 @@ namespace Spectre.Console;
///
/// Representation of a file system path.
///
-public sealed class TextPath : IRenderable, IAlignable
+public sealed class TextPath : IRenderable, IHasJustification
{
private const string Ellipsis = "...";
private const string UnicodeEllipsis = "…";
@@ -35,7 +35,7 @@ public sealed class TextPath : IRenderable, IAlignable
///
/// Gets or sets the alignment.
///
- public Justify? Alignment { get; set; }
+ public Justify? Justification { get; set; }
///
/// Initializes a new instance of the class.
@@ -66,9 +66,9 @@ public sealed class TextPath : IRenderable, IAlignable
}
///
- public Measurement Measure(RenderContext context, int maxWidth)
+ public Measurement Measure(RenderOptions options, int maxWidth)
{
- var fitted = Fit(context, maxWidth);
+ var fitted = Fit(options, maxWidth);
var separatorCount = fitted.Length - 1;
var length = fitted.Sum(f => f.Length) + separatorCount;
@@ -78,16 +78,14 @@ public sealed class TextPath : IRenderable, IAlignable
}
///
- public IEnumerable Render(RenderContext context, int maxWidth)
+ public IEnumerable Render(RenderOptions options, int maxWidth)
{
- var alignment = Alignment ?? Justify.Left;
-
var rootStyle = RootStyle ?? Style.Plain;
var separatorStyle = SeparatorStyle ?? Style.Plain;
var stemStyle = StemStyle ?? Style.Plain;
var leafStyle = LeafStyle ?? Style.Plain;
- var fitted = Fit(context, maxWidth);
+ var fitted = Fit(options, maxWidth);
var parts = new List();
foreach (var (_, first, last, item) in fitted.Enumerate())
{
@@ -119,7 +117,7 @@ public sealed class TextPath : IRenderable, IAlignable
}
// Align the result
- Aligner.Align(parts, Alignment, maxWidth);
+ Aligner.Align(parts, Justification, maxWidth);
// Insert a line break
parts.Add(Segment.LineBreak);
@@ -127,7 +125,7 @@ public sealed class TextPath : IRenderable, IAlignable
return parts;
}
- private string[] Fit(RenderContext context, int maxWidth)
+ private string[] Fit(RenderOptions options, int maxWidth)
{
// No parts?
if (_parts.Length == 0)
@@ -141,7 +139,7 @@ public sealed class TextPath : IRenderable, IAlignable
return _parts;
}
- var ellipsis = context.Unicode ? UnicodeEllipsis : Ellipsis;
+ var ellipsis = options.Unicode ? UnicodeEllipsis : Ellipsis;
var ellipsisLength = Cell.GetCellLength(ellipsis);
if (_parts.Length >= 2)
diff --git a/src/Spectre.Console/Widgets/Tree.cs b/src/Spectre.Console/Widgets/Tree.cs
index 9929a53..289884e 100644
--- a/src/Spectre.Console/Widgets/Tree.cs
+++ b/src/Spectre.Console/Widgets/Tree.cs
@@ -47,7 +47,7 @@ public sealed class Tree : Renderable, IHasTreeNodes
}
///
- protected override IEnumerable Render(RenderContext context, int maxWidth)
+ protected override IEnumerable Render(RenderOptions options, int maxWidth)
{
var result = new List();
var visitedNodes = new HashSet();
@@ -56,7 +56,7 @@ public sealed class Tree : Renderable, IHasTreeNodes
stack.Push(new Queue(new[] { _root }));
var levels = new List();
- levels.Add(GetGuide(context, TreeGuidePart.Continue));
+ levels.Add(GetGuide(options, TreeGuidePart.Continue));
while (stack.Count > 0)
{
@@ -66,7 +66,7 @@ public sealed class Tree : Renderable, IHasTreeNodes
levels.RemoveLast();
if (levels.Count > 0)
{
- levels.AddOrReplaceLast(GetGuide(context, TreeGuidePart.Fork));
+ levels.AddOrReplaceLast(GetGuide(options, TreeGuidePart.Fork));
}
continue;
@@ -83,11 +83,11 @@ public sealed class Tree : Renderable, IHasTreeNodes
if (isLastChild)
{
- levels.AddOrReplaceLast(GetGuide(context, TreeGuidePart.End));
+ levels.AddOrReplaceLast(GetGuide(options, TreeGuidePart.End));
}
var prefix = levels.Skip(1).ToList();
- var renderableLines = Segment.SplitLines(current.Renderable.Render(context, maxWidth - Segment.CellCount(prefix)));
+ var renderableLines = Segment.SplitLines(current.Renderable.Render(options, maxWidth - Segment.CellCount(prefix)));
foreach (var (_, isFirstLine, _, line) in renderableLines.Enumerate())
{
@@ -102,14 +102,14 @@ public sealed class Tree : Renderable, IHasTreeNodes
if (isFirstLine && prefix.Count > 0)
{
var part = isLastChild ? TreeGuidePart.Space : TreeGuidePart.Continue;
- prefix.AddOrReplaceLast(GetGuide(context, part));
+ prefix.AddOrReplaceLast(GetGuide(options, part));
}
}
if (current.Expanded && current.Nodes.Count > 0)
{
- levels.AddOrReplaceLast(GetGuide(context, isLastChild ? TreeGuidePart.Space : TreeGuidePart.Continue));
- levels.Add(GetGuide(context, current.Nodes.Count == 1 ? TreeGuidePart.End : TreeGuidePart.Fork));
+ levels.AddOrReplaceLast(GetGuide(options, isLastChild ? TreeGuidePart.Space : TreeGuidePart.Continue));
+ levels.Add(GetGuide(options, current.Nodes.Count == 1 ? TreeGuidePart.End : TreeGuidePart.Fork));
stack.Push(new Queue(current.Nodes));
}
@@ -118,9 +118,9 @@ public sealed class Tree : Renderable, IHasTreeNodes
return result;
}
- private Segment GetGuide(RenderContext context, TreeGuidePart part)
+ private Segment GetGuide(RenderOptions options, TreeGuidePart part)
{
- var guide = Guide.GetSafeTreeGuide(safe: !context.Unicode);
+ var guide = Guide.GetSafeTreeGuide(safe: !options.Unicode);
return new Segment(guide.GetPart(part), Style ?? Style.Plain);
}
}
\ No newline at end of file
diff --git a/test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj b/test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj
index 67f5874..6f68434 100644
--- a/test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj
+++ b/test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj
@@ -1,8 +1,7 @@
- net7.0;net48
- net7.0
+ net7.0
@@ -30,15 +29,4 @@
-
-
- $([System.String]::Copy('%(FileName)').Split('.')[0])
- %(ParentFile).cs
-
-
- $([System.String]::Copy('%(FileName)').Split('.')[0])
- %(ParentFile).cs
-
-
-
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Bottom.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Bottom.Output.verified.txt
new file mode 100644
index 0000000..74ab31e
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Bottom.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Middle.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Middle.Output.verified.txt
new file mode 100644
index 0000000..33cc191
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Middle.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Top.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Top.Output.verified.txt
new file mode 100644
index 0000000..7390030
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Center_Top.Output.verified.txt
@@ -0,0 +1,15 @@
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Bottom.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Bottom.Output.verified.txt
new file mode 100644
index 0000000..5c9e9c0
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Bottom.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+┌──────────────┐
+│ Hello World! │
+└──────────────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Middle.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Middle.Output.verified.txt
new file mode 100644
index 0000000..f7beea5
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Middle.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+┌──────────────┐
+│ Hello World! │
+└──────────────┘
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Top.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Top.Output.verified.txt
new file mode 100644
index 0000000..21d696c
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Left_Top.Output.verified.txt
@@ -0,0 +1,15 @@
+┌──────────────┐
+│ Hello World! │
+└──────────────┘
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Bottom.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Bottom.Output.verified.txt
new file mode 100644
index 0000000..d61cd86
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Bottom.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Middle.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Middle.Output.verified.txt
new file mode 100644
index 0000000..90a5884
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Middle.Output.verified.txt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Top.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Top.Output.verified.txt
new file mode 100644
index 0000000..a1742a8
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Align/Right_Top.Output.verified.txt
@@ -0,0 +1,15 @@
+ ┌──────────────┐
+ │ Hello World! │
+ └──────────────┘
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Empty_Layout.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Empty_Layout.Output.verified.txt
new file mode 100644
index 0000000..5caaedb
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Empty_Layout.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─40 x 15──────────────────────────────╮
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ Placeholder │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+╰──────────────────────────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Fallback_Layout.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Fallback_Layout.Output.verified.txt
new file mode 100644
index 0000000..0df2d79
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Fallback_Layout.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─T1 (40 x 7)──────────────────────────╮
+│ │
+│ │
+│ Placeholder │
+│ │
+│ │
+╰──────────────────────────────────────╯
+╭─T2 (40 x 8)──────────────────────────╮
+│ │
+│ │
+│ Placeholder │
+│ │
+│ │
+│ │
+╰──────────────────────────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout.Output.verified.txt
new file mode 100644
index 0000000..614b3a1
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout.Output.verified.txt
@@ -0,0 +1,15 @@
+╔══════════════════════════════════════╗
+║ Hello ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+║ ║
+╚══════════════════════════════════════╝
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Columns.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Columns.Output.verified.txt
new file mode 100644
index 0000000..5fea3f1
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Columns.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─Left (20 x 15)───╮╭─Right (20 x 15)──╮
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ Placeholder ││ Placeholder │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Columns.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Columns.Output.verified.txt
new file mode 100644
index 0000000..9c7084a
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Columns.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─L1…────╮╭─L2…────╮╭─R1…────╮╭─R2…────╮
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ Placeh ││ Placeh ││ Placeh ││ Placeh │
+│ older ││ older ││ older ││ older │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+│ ││ ││ ││ │
+╰────────╯╰────────╯╰────────╯╰────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows.Output.verified.txt
new file mode 100644
index 0000000..bb5f7d9
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─T1 (40 x 3)──────────────────────────╮
+│ Placeholder │
+╰──────────────────────────────────────╯
+╭─T2 (40 x 4)──────────────────────────╮
+│ Placeholder │
+│ │
+╰──────────────────────────────────────╯
+╭─B1 (40 x 4)──────────────────────────╮
+│ Placeholder │
+│ │
+╰──────────────────────────────────────╯
+╭─B2 (40 x 4)──────────────────────────╮
+│ Placeholder │
+│ │
+╰──────────────────────────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows_And_Columns.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows_And_Columns.Output.verified.txt
new file mode 100644
index 0000000..258288b
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Rows_And_Columns.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─A (20 x 3)───────╮╭─B (20 x 3)───────╮
+│ Placeholder ││ Placeholder │
+╰──────────────────╯╰──────────────────╯
+╭─C (20 x 4)───────╮╭─D (20 x 4)───────╮
+│ Placeholder ││ Placeholder │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
+╭─E (20 x 4)───────╮╭─F (20 x 4)───────╮
+│ Placeholder ││ Placeholder │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
+╭─G (20 x 4)───────╮╭─H (20 x 4)───────╮
+│ Placeholder ││ Placeholder │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Minimum_Size.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Minimum_Size.Output.verified.txt
new file mode 100644
index 0000000..5a21d74
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Minimum_Size.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─Left (30 x 15)─────────────╮╭─Right…─╮
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ Placeh │
+│ Placeholder ││ older │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+╰────────────────────────────╯╰────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Ratio.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Ratio.Output.verified.txt
new file mode 100644
index 0000000..5a21d74
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Ratio.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─Left (30 x 15)─────────────╮╭─Right…─╮
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ Placeh │
+│ Placeholder ││ older │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+╰────────────────────────────╯╰────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Size.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Size.Output.verified.txt
new file mode 100644
index 0000000..6ffd309
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Respect_To_Size.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─Left (28 x 15)───────────╮╭─Right…───╮
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ Placehol │
+│ Placeholder ││ der │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+│ ││ │
+╰──────────────────────────╯╰──────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Rows.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Rows.Output.verified.txt
new file mode 100644
index 0000000..12a6f9d
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Rows.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─Top (40 x 7)─────────────────────────╮
+│ │
+│ │
+│ Placeholder │
+│ │
+│ │
+╰──────────────────────────────────────╯
+╭─Bottom (40 x 8)──────────────────────╮
+│ │
+│ │
+│ Placeholder │
+│ │
+│ │
+│ │
+╰──────────────────────────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_Without_Invisible_Children.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_Without_Invisible_Children.Output.verified.txt
new file mode 100644
index 0000000..9468df9
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_Without_Invisible_Children.Output.verified.txt
@@ -0,0 +1,15 @@
+╭─B (40 x 3)───────────────────────────╮
+│ Placeholder │
+╰──────────────────────────────────────╯
+╭─C (20 x 4)───────╮╭─D (20 x 4)───────╮
+│ Placeholder ││ Placeholder │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
+╭─E (20 x 4)───────╮╭─F (20 x 4)───────╮
+│ Placeholder ││ Placeholder │
+│ ││ │
+╰──────────────────╯╰──────────────────╯
+╭─G (40 x 4)───────────────────────────╮
+│ Placeholder │
+│ │
+╰──────────────────────────────────────╯
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Height.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Height.Output.verified.txt
new file mode 100644
index 0000000..554308f
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Height.Output.verified.txt
@@ -0,0 +1,25 @@
+┌───────────────────┐
+│ Hello World │
+│ Hello Hello Hello │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└───────────────────┘
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width.Output.verified.txt
new file mode 100644
index 0000000..dc133c3
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width.Output.verified.txt
@@ -0,0 +1,3 @@
+┌───────────────────────┐
+│ Hello World │
+└───────────────────────┘
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_Height.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_Height.Output.verified.txt
new file mode 100644
index 0000000..2f85980
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_Height.Output.verified.txt
@@ -0,0 +1,25 @@
+┌────────────────────────────────────────────────┐
+│ Hello World │
+│ Hello Hello Hello │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────────────────────────────────┘
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_MaxWidth.Output.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_MaxWidth.Output.verified.txt
new file mode 100644
index 0000000..21ceda9
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Panel/Render_Width_MaxWidth.Output.verified.txt
@@ -0,0 +1,3 @@
+┌──────────────────┐
+│ Hello World │
+└──────────────────┘
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_Centered.Align_Widget.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_Centered.Align_Widget.verified.txt
new file mode 100644
index 0000000..62617a0
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_Centered.Align_Widget.verified.txt
@@ -0,0 +1,6 @@
+ ┌────────┬────────┬───────┐
+ │ Foo │ Bar │ Baz │
+ ├────────┼────────┼───────┤
+ │ Qux │ Corgi │ Waldo │
+ │ Grault │ Garply │ Fred │
+ └────────┴────────┴───────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_LeftAligned.Align_Widget.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_LeftAligned.Align_Widget.verified.txt
new file mode 100644
index 0000000..6edca8f
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_LeftAligned.Align_Widget.verified.txt
@@ -0,0 +1,6 @@
+┌────────┬────────┬───────┐
+│ Foo │ Bar │ Baz │
+├────────┼────────┼───────┤
+│ Qux │ Corgi │ Waldo │
+│ Grault │ Garply │ Fred │
+└────────┴────────┴───────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_RightAligned.Align_Widget.verified.txt b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_RightAligned.Align_Widget.verified.txt
new file mode 100644
index 0000000..72a459e
--- /dev/null
+++ b/test/Spectre.Console.Tests/Expectations/Widgets/Table/Render_RightAligned.Align_Widget.verified.txt
@@ -0,0 +1,6 @@
+ ┌────────┬────────┬───────┐
+ │ Foo │ Bar │ Baz │
+ ├────────┼────────┼───────┤
+ │ Qux │ Corgi │ Waldo │
+ │ Grault │ Garply │ Fred │
+ └────────┴────────┴───────┘
\ No newline at end of file
diff --git a/test/Spectre.Console.Tests/Spectre.Console.Tests.csproj b/test/Spectre.Console.Tests/Spectre.Console.Tests.csproj
index 0342253..4d74810 100644
--- a/test/Spectre.Console.Tests/Spectre.Console.Tests.csproj
+++ b/test/Spectre.Console.Tests/Spectre.Console.Tests.csproj
@@ -1,8 +1,7 @@
- net7.0;net48
- net7.0
+ net7.0
diff --git a/test/Spectre.Console.Tests/Unit/Live/Progress/ProgressColumnFixture.cs b/test/Spectre.Console.Tests/Unit/Live/Progress/ProgressColumnFixture.cs
index 4b10877..9a2fac2 100644
--- a/test/Spectre.Console.Tests/Unit/Live/Progress/ProgressColumnFixture.cs
+++ b/test/Spectre.Console.Tests/Unit/Live/Progress/ProgressColumnFixture.cs
@@ -16,7 +16,7 @@ public sealed class ProgressColumnFixture
public string Render()
{
var console = new TestConsole();
- var context = new RenderContext(console.Profile.Capabilities);
+ var context = RenderOptions.Create(console, console.Profile.Capabilities);
console.Write(Column.Render(context, Task, TimeSpan.Zero));
return console.Output;
}
diff --git a/test/Spectre.Console.Tests/Unit/Rendering/RenderHookTests.cs b/test/Spectre.Console.Tests/Unit/Rendering/RenderHookTests.cs
index 219a13d..6be28da 100644
--- a/test/Spectre.Console.Tests/Unit/Rendering/RenderHookTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Rendering/RenderHookTests.cs
@@ -4,7 +4,7 @@ public sealed class RenderHookTests
{
private sealed class HelloRenderHook : IRenderHook
{
- public IEnumerable Process(RenderContext context, IEnumerable renderables)
+ public IEnumerable Process(RenderOptions options, IEnumerable renderables)
{
return new IRenderable[] { new Text("Hello\n") }.Concat(renderables);
}
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs
new file mode 100644
index 0000000..e3f2923
--- /dev/null
+++ b/test/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs
@@ -0,0 +1,155 @@
+using Spectre.Console.Extensions;
+
+namespace Spectre.Console.Tests.Unit;
+
+[UsesVerify]
+[ExpectationPath("Widgets/Align")]
+public sealed class AlignTests
+{
+ [UsesVerify]
+ public sealed class Left
+ {
+ [Fact]
+ [Expectation("Left_Top")]
+ public Task Should_Render_Panel_Left_Aligned_At_Top()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Left(new Panel("Hello World!"), VerticalAlignment.Top).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Left_Middle")]
+ public Task Should_Render_Panel_Left_Aligned_At_Middle()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Left(new Panel("Hello World!"), VerticalAlignment.Middle).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Left_Bottom")]
+ public Task Should_Render_Panel_Left_Aligned_At_Bottom()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Left(new Panel("Hello World!"), VerticalAlignment.Bottom).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+ }
+
+ [UsesVerify]
+ public sealed class Center
+ {
+ [Fact]
+ [Expectation("Center_Top")]
+ public Task Should_Render_Panel_Center_Aligned_At_Top()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Center(new Panel("Hello World!"), VerticalAlignment.Top).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Center_Middle")]
+ public Task Should_Render_Panel_Center_Aligned_At_Middle()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Center(new Panel("Hello World!"), VerticalAlignment.Middle).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Center_Bottom")]
+ public Task Should_Render_Panel_Center_Aligned_At_Bottom()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Center(new Panel("Hello World!"), VerticalAlignment.Bottom).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+ }
+
+ [UsesVerify]
+ public sealed class Right
+ {
+ [Fact]
+ [Expectation("Right_Top")]
+ public Task Should_Render_Panel_Right_Aligned_At_Top()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Right(new Panel("Hello World!"), VerticalAlignment.Top).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Right_Middle")]
+ public Task Should_Render_Panel_Right_Aligned_At_Middle()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Right(new Panel("Hello World!"), VerticalAlignment.Middle).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Right_Bottom")]
+ public Task Should_Render_Panel_Right_Aligned_At_Bottom()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var align = Align.Right(new Panel("Hello World!"), VerticalAlignment.Bottom).Height(15);
+
+ // When
+ console.Write(align);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+ }
+}
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/FigletTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/FigletTests.cs
index 8453901..b283176 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/FigletTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/FigletTests.cs
@@ -60,7 +60,7 @@ public sealed class FigletTests
// Given
var console = new TestConsole().Width(120);
var text = new FigletText(FigletFont.Default, "Spectre.Console")
- .Alignment(Justify.Left);
+ .Justify(Justify.Left);
// When
console.Write(text);
@@ -76,7 +76,7 @@ public sealed class FigletTests
// Given
var console = new TestConsole().Width(120);
var text = new FigletText(FigletFont.Default, "Spectre.Console")
- .Alignment(Justify.Center);
+ .Justify(Justify.Center);
// When
console.Write(text);
@@ -92,7 +92,7 @@ public sealed class FigletTests
// Given
var console = new TestConsole().Width(120);
var text = new FigletText(FigletFont.Default, "Spectre.Console")
- .Alignment(Justify.Right);
+ .Justify(Justify.Right);
// When
console.Write(text);
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs
new file mode 100644
index 0000000..fc0017e
--- /dev/null
+++ b/test/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs
@@ -0,0 +1,268 @@
+namespace Spectre.Console.Tests.Unit;
+
+[UsesVerify]
+[ExpectationPath("Widgets/Layout")]
+public sealed class LayoutTests
+{
+ [Fact]
+ [Expectation("Render_Empty_Layout")]
+ public Task Should_Render_Empty_Layout()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout();
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout")]
+ public Task Should_Render_Empty_Layout_With_Renderable()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout().Update(new Panel("Hello").DoubleBorder().Expand());
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Columns")]
+ public Task Should_Render_Layout_With_Columns()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitColumns(
+ new Layout("Left"),
+ new Layout("Right"));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Rows")]
+ public Task Should_Render_Layout_With_Rows()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitRows(
+ new Layout("Top"),
+ new Layout("Bottom"));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Nested_Columns")]
+ public Task Should_Render_Layout_With_Nested_Columns()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitColumns(
+ new Layout("Left")
+ .SplitColumns(
+ new Layout("L1"),
+ new Layout("L2")),
+ new Layout("Right")
+ .SplitColumns(
+ new Layout("R1"),
+ new Layout("R2")));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Nested_Rows")]
+ public Task Should_Render_Layout_With_Nested_Rows()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitRows(
+ new Layout("Top")
+ .SplitRows(
+ new Layout("T1"),
+ new Layout("T2")),
+ new Layout("Bottom")
+ .SplitRows(
+ new Layout("B1"),
+ new Layout("B2")));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Nested_Rows_And_Columns")]
+ public Task Should_Render_Layout_With_Nested_Rows_And_Columns()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitRows(
+ new Layout("Top")
+ .SplitRows(
+ new Layout("T1")
+ .SplitColumns(
+ new Layout("A"),
+ new Layout("B")),
+ new Layout("T2")
+ .SplitColumns(
+ new Layout("C"),
+ new Layout("D"))),
+ new Layout("Bottom")
+ .SplitRows(
+ new Layout("B1")
+ .SplitColumns(
+ new Layout("E"),
+ new Layout("F")),
+ new Layout("B2")
+ .SplitColumns(
+ new Layout("G"),
+ new Layout("H"))));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_Without_Invisible_Children")]
+ public Task Should_Render_Layout_Without_Invisible_Children()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitRows(
+ new Layout("Top")
+ .SplitRows(
+ new Layout("T1")
+ .SplitColumns(
+ new Layout("A").Invisible(),
+ new Layout("B")),
+ new Layout("T2")
+ .SplitColumns(
+ new Layout("C"),
+ new Layout("D"))),
+ new Layout("Bottom")
+ .SplitRows(
+ new Layout("B1")
+ .SplitColumns(
+ new Layout("E"),
+ new Layout("F")),
+ new Layout("B2")
+ .SplitColumns(
+ new Layout("G"),
+ new Layout("H").Invisible())));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Respect_To_Ratio")]
+ public Task Should_Render_Layout_With_Respect_To_Ratio()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitColumns(
+ new Layout("Left").Ratio(3),
+ new Layout("Right"));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Respect_To_Size")]
+ public Task Should_Render_Layout_With_Respect_To_Size()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitColumns(
+ new Layout("Left").Size(28),
+ new Layout("Right"));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Layout_With_Respect_To_Minimum_Size")]
+ public Task Should_Render_Layout_With_Respect_To_Minimum_Size()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitColumns(
+ new Layout("Left").Size(28).MinimumSize(30),
+ new Layout("Right"));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Fallback_Layout")]
+ public Task Should_Fall_Back_To_Parent_Layout_If_All_Children_Are_Invisible()
+ {
+ // Given
+ var console = new TestConsole().Size(new Size(40, 15));
+ var layout = new Layout()
+ .SplitRows(
+ new Layout("T1").SplitColumns(
+ new Layout("A").Invisible(),
+ new Layout("B").Invisible()),
+ new Layout("T2").SplitColumns(
+ new Layout("C").Invisible(),
+ new Layout("D").Invisible()));
+
+ // When
+ console.Write(layout);
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+}
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/PanelTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/PanelTests.cs
index 73a2ca9..377c94f 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/PanelTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/PanelTests.cs
@@ -81,7 +81,7 @@ public sealed class PanelTests
// When
console.Write(new Panel("Hello World")
{
- Header = new PanelHeader("Greeting").LeftAligned(),
+ Header = new PanelHeader("Greeting").LeftJustified(),
Expand = true,
});
@@ -117,7 +117,7 @@ public sealed class PanelTests
// When
console.Write(new Panel("Hello World")
{
- Header = new PanelHeader("Greeting").RightAligned(),
+ Header = new PanelHeader("Greeting").RightJustified(),
Expand = true,
});
@@ -204,6 +204,76 @@ public sealed class PanelTests
return Verifier.Verify(console.Output);
}
+ [Fact]
+ [Expectation("Render_Width")]
+ public Task Should_Render_To_Specified_Width()
+ {
+ // Given
+ var console = new TestConsole();
+
+ // When
+ console.Write(new Panel(new Text("Hello World"))
+ {
+ Width = 25,
+ });
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Width_MaxWidth")]
+ public Task Should_Use_Max_Width_If_Specified_Width_Is_Too_Large()
+ {
+ // Given
+ var console = new TestConsole();
+ console.Profile.Width = 20;
+
+ // When
+ console.Write(new Panel(new Text("Hello World"))
+ {
+ Width = 25,
+ });
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Height")]
+ public Task Should_Render_To_Specified_Height()
+ {
+ // Given
+ var console = new TestConsole();
+
+ // When
+ console.Write(new Panel(new Text("Hello World\nHello Hello Hello"))
+ {
+ Height = 25,
+ });
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
+ [Fact]
+ [Expectation("Render_Width_Height")]
+ public Task Should_Render_To_Specified_Width_And_Height()
+ {
+ // Given
+ var console = new TestConsole();
+
+ // When
+ console.Write(new Panel("Hello World\nHello Hello Hello")
+ {
+ Width = 50,
+ Height = 25,
+ });
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
[Fact]
[Expectation("Render_Child_RightAligned")]
public Task Should_Justify_Child_To_Right_Correctly()
@@ -213,7 +283,7 @@ public sealed class PanelTests
// When
console.Write(
- new Panel(new Text("Hello World").RightAligned())
+ new Panel(new Text("Hello World").RightJustified())
{
Expand = true,
});
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/RuleTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/RuleTests.cs
index fbff7b5..fada3fd 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/RuleTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/RuleTests.cs
@@ -70,7 +70,7 @@ public sealed class RuleTests
// When
console.Write(new Rule("Hello World")
{
- Alignment = Justify.Left,
+ Justification = Justify.Left,
});
// Then
@@ -87,7 +87,7 @@ public sealed class RuleTests
// When
console.Write(new Rule("Hello World")
{
- Alignment = Justify.Right,
+ Justification = Justify.Right,
});
// Then
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/Table/TableTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/Table/TableTests.cs
index 2716fbb..a027658 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/Table/TableTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/Table/TableTests.cs
@@ -187,7 +187,9 @@ public sealed class TableTests
// Given
var console = new TestConsole();
var table = new Table();
+#pragma warning disable CS0618 // Type or member is obsolete
table.Alignment = Justify.Left;
+#pragma warning restore CS0618 // Type or member is obsolete
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -199,6 +201,24 @@ public sealed class TableTests
return Verifier.Verify(console.Output);
}
+ [Fact]
+ [Expectation("Render_LeftAligned", "Align_Widget")]
+ public Task Should_Left_Align_Table_Correctly_When_Wrapped_In_Align_Widget()
+ {
+ // Given
+ var console = new TestConsole();
+ var table = new Table();
+ table.AddColumns("Foo", "Bar", "Baz");
+ table.AddRow("Qux", "Corgi", "Waldo");
+ table.AddRow("Grault", "Garply", "Fred");
+
+ // When
+ console.Write(Align.Left(table));
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
[Fact]
[Expectation("Render_Centered")]
public Task Should_Center_Table_Correctly()
@@ -206,7 +226,9 @@ public sealed class TableTests
// Given
var console = new TestConsole();
var table = new Table();
+#pragma warning disable CS0618 // Type or member is obsolete
table.Alignment = Justify.Center;
+#pragma warning restore CS0618 // Type or member is obsolete
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -218,6 +240,24 @@ public sealed class TableTests
return Verifier.Verify(console.Output);
}
+ [Fact]
+ [Expectation("Render_Centered", "Align_Widget")]
+ public Task Should_Center_Table_Correctly_When_Wrapped_In_Align_Widget()
+ {
+ // Given
+ var console = new TestConsole();
+ var table = new Table();
+ table.AddColumns("Foo", "Bar", "Baz");
+ table.AddRow("Qux", "Corgi", "Waldo");
+ table.AddRow("Grault", "Garply", "Fred");
+
+ // When
+ console.Write(Align.Center(table));
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
[Fact]
[Expectation("Render_RightAligned")]
public Task Should_Right_Align_Table_Correctly()
@@ -225,7 +265,9 @@ public sealed class TableTests
// Given
var console = new TestConsole();
var table = new Table();
+#pragma warning disable CS0618 // Type or member is obsolete
table.Alignment = Justify.Right;
+#pragma warning restore CS0618 // Type or member is obsolete
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -237,6 +279,24 @@ public sealed class TableTests
return Verifier.Verify(console.Output);
}
+ [Fact]
+ [Expectation("Render_RightAligned", "Align_Widget")]
+ public Task Should_Right_Align_Table_Correctly_When_Wrapped_In_Align_Widget()
+ {
+ // Given
+ var console = new TestConsole();
+ var table = new Table();
+ table.AddColumns("Foo", "Bar", "Baz");
+ table.AddRow("Qux", "Corgi", "Waldo");
+ table.AddRow("Grault", "Garply", "Fred");
+
+ // When
+ console.Write(Align.Right(table));
+
+ // Then
+ return Verifier.Verify(console.Output);
+ }
+
[Fact]
[Expectation("Render_Nested")]
public Task Should_Render_Table_Nested_In_Panels_Correctly()
@@ -380,7 +440,7 @@ public sealed class TableTests
table.AddColumn(new TableColumn(new Panel("[u]DEF[/]").BorderColor(Color.Green)));
table.AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)));
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World[/]"), Text.Empty);
- table.AddRow(second, new Text("Whaat"), new Text("Lol").RightAligned());
+ table.AddRow(second, new Text("Whaat"), new Text("Lol").RightJustified());
table.AddRow(new Markup("[blue]Hej[/]"), new Markup("[yellow]Världen[/]"), Text.Empty);
// When
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/TextPathTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/TextPathTests.cs
index 0f984be..d7e5513 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/TextPathTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/TextPathTests.cs
@@ -77,7 +77,7 @@ public sealed class TextPathTests
var console = new TestConsole().Width(40);
// When
- console.Write(new TextPath("C:/My documents/Bar/Baz.txt").RightAligned());
+ console.Write(new TextPath("C:/My documents/Bar/Baz.txt").RightJustified());
// Then
console.Output.TrimEnd('\n')
diff --git a/test/Spectre.Console.Tests/Unit/Widgets/TextTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/TextTests.cs
index cf08e23..6b0bdfd 100644
--- a/test/Spectre.Console.Tests/Unit/Widgets/TextTests.cs
+++ b/test/Spectre.Console.Tests/Unit/Widgets/TextTests.cs
@@ -42,11 +42,13 @@ public sealed class TextTests
public void Should_Consider_The_Longest_Word_As_Minimum_Width()
{
// Given
+ var console = new TestConsole();
var caps = new TestCapabilities { Unicode = true };
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When
- var result = ((IRenderable)text).Measure(caps.CreateRenderContext(), 80);
+ var result = ((IRenderable)text).Measure(
+ caps.CreateRenderContext(console), 80);
// Then
result.Min.ShouldBe(6);
@@ -56,11 +58,13 @@ public sealed class TextTests
public void Should_Consider_The_Longest_Line_As_Maximum_Width()
{
// Given
+ var console = new TestConsole();
var caps = new TestCapabilities { Unicode = true };
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When
- var result = ((IRenderable)text).Measure(caps.CreateRenderContext(), 80);
+ var result = ((IRenderable)text).Measure(
+ caps.CreateRenderContext(console), 80);
// Then
result.Max.ShouldBe(11);