mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Add live display support
This commit also adds functionality to LiveRenderable that should fix some problems related to vertical overflow. Closes #316 Closes #415
This commit is contained in:

committed by
Phil Scott

parent
5d68020abb
commit
3dea412785
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static Spectre.Console.AnsiSequences;
|
||||
|
||||
namespace Spectre.Console.Rendering
|
||||
@ -6,12 +8,33 @@ namespace Spectre.Console.Rendering
|
||||
internal sealed class LiveRenderable : Renderable
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
private readonly IAnsiConsole _console;
|
||||
private IRenderable? _renderable;
|
||||
private SegmentShape? _shape;
|
||||
|
||||
public bool HasRenderable => _renderable != null;
|
||||
public IRenderable? Target => _renderable;
|
||||
public bool DidOverflow { get; private set; }
|
||||
|
||||
public void SetRenderable(IRenderable renderable)
|
||||
[MemberNotNullWhen(true, nameof(Target))]
|
||||
public bool HasRenderable => _renderable != null;
|
||||
public VerticalOverflow Overflow { get; set; }
|
||||
public VerticalOverflowCropping OverflowCropping { get; set; }
|
||||
|
||||
public LiveRenderable(IAnsiConsole console)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
|
||||
Overflow = VerticalOverflow.Ellipsis;
|
||||
OverflowCropping = VerticalOverflowCropping.Top;
|
||||
}
|
||||
|
||||
public LiveRenderable(IAnsiConsole console, IRenderable renderable)
|
||||
: this(console)
|
||||
{
|
||||
_renderable = renderable ?? throw new ArgumentNullException(nameof(renderable));
|
||||
}
|
||||
|
||||
public void SetRenderable(IRenderable? renderable)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
@ -51,12 +74,61 @@ namespace Spectre.Console.Rendering
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
DidOverflow = false;
|
||||
|
||||
if (_renderable != null)
|
||||
{
|
||||
var segments = _renderable.Render(context, maxWidth);
|
||||
var lines = Segment.SplitLines(segments);
|
||||
|
||||
var shape = SegmentShape.Calculate(context, lines);
|
||||
if (shape.Height > _console.Profile.Height)
|
||||
{
|
||||
if (Overflow == VerticalOverflow.Crop)
|
||||
{
|
||||
if (OverflowCropping == VerticalOverflowCropping.Bottom)
|
||||
{
|
||||
// Remove bottom lines
|
||||
var index = Math.Min(_console.Profile.Height, lines.Count);
|
||||
var count = lines.Count - index;
|
||||
lines.RemoveRange(index, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove top lines
|
||||
var start = lines.Count - _console.Profile.Height;
|
||||
lines.RemoveRange(0, start);
|
||||
}
|
||||
|
||||
shape = SegmentShape.Calculate(context, lines);
|
||||
}
|
||||
else if (Overflow == VerticalOverflow.Ellipsis)
|
||||
{
|
||||
var ellipsisText = _console.Profile.Capabilities.Unicode ? "…" : "...";
|
||||
var ellipsis = new SegmentLine(((IRenderable)new Markup($"[yellow]{ellipsisText}[/]")).Render(context, maxWidth));
|
||||
|
||||
if (OverflowCropping == VerticalOverflowCropping.Bottom)
|
||||
{
|
||||
// Remove bottom lines
|
||||
var index = Math.Min(_console.Profile.Height - 1, lines.Count);
|
||||
var count = lines.Count - index;
|
||||
lines.RemoveRange(index, count);
|
||||
lines.Add(ellipsis);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove top lines
|
||||
var start = lines.Count - _console.Profile.Height;
|
||||
lines.RemoveRange(0, start + 1);
|
||||
lines.Insert(0, ellipsis);
|
||||
}
|
||||
|
||||
shape = SegmentShape.Calculate(context, lines);
|
||||
}
|
||||
|
||||
DidOverflow = true;
|
||||
}
|
||||
|
||||
_shape = _shape == null ? shape : _shape.Value.Inflate(shape);
|
||||
_shape.Value.Apply(context, ref lines);
|
||||
|
||||
|
@ -13,6 +13,22 @@ namespace Spectre.Console.Rendering
|
||||
/// </summary>
|
||||
public int Length => this.Sum(line => line.Text.Length);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SegmentLine"/> class.
|
||||
/// </summary>
|
||||
public SegmentLine()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SegmentLine"/> class.
|
||||
/// </summary>
|
||||
/// <param name="segments">The segments.</param>
|
||||
public SegmentLine(IEnumerable<Segment> segments)
|
||||
: base(segments)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of cells the segment line occupies.
|
||||
/// </summary>
|
||||
|
Reference in New Issue
Block a user