mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-12-24 02:25:48 +08:00
Add Layout widget (#1041)
* Add width to panels * Add height to panels * Replace RenderContext with RenderOptions * Remove exclusivity from alternative buffer * Add Layout widget * Add Align widget
This commit is contained in:
@@ -89,4 +89,51 @@ internal static class Aligner
|
||||
throw new NotSupportedException("Unknown alignment");
|
||||
}
|
||||
}
|
||||
|
||||
public static void AlignHorizontally<T>(T segments, HorizontalAlignment alignment, int maxWidth)
|
||||
where T : List<Segment>
|
||||
{
|
||||
var width = Segment.CellCount(segments);
|
||||
if (width >= maxWidth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
{
|
||||
var diff = maxWidth - width;
|
||||
segments.Add(Segment.Padding(diff));
|
||||
break;
|
||||
}
|
||||
|
||||
case HorizontalAlignment.Right:
|
||||
{
|
||||
var diff = maxWidth - width;
|
||||
segments.Insert(0, Segment.Padding(diff));
|
||||
break;
|
||||
}
|
||||
|
||||
case HorizontalAlignment.Center:
|
||||
{
|
||||
// Left side.
|
||||
var diff = (maxWidth - width) / 2;
|
||||
segments.Insert(0, Segment.Padding(diff));
|
||||
|
||||
// Right side
|
||||
segments.Add(Segment.Padding(diff));
|
||||
var remainder = (maxWidth - width) % 2;
|
||||
if (remainder != 0)
|
||||
{
|
||||
segments.Add(Segment.Padding(remainder));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new NotSupportedException("Unknown alignment");
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/Spectre.Console/Internal/IRatioResolvable.cs
Normal file
22
src/Spectre.Console/Internal/IRatioResolvable.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Represents something that can be used to resolve ratios.
|
||||
/// </summary>
|
||||
internal interface IRatioResolvable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ratio.
|
||||
/// </summary>
|
||||
int Ratio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size.
|
||||
/// </summary>
|
||||
int? Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum size.
|
||||
/// </summary>
|
||||
int MinimumSize { get; }
|
||||
}
|
||||
15
src/Spectre.Console/Internal/Polyfill/IsExternalInit.cs
Normal file
15
src/Spectre.Console/Internal/Polyfill/IsExternalInit.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
#if NETSTANDARD2_0
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved to be used by the compiler for tracking metadata.
|
||||
/// This class should not be used by developers in source code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal static class IsExternalInit
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -5,6 +5,78 @@ namespace Spectre.Console;
|
||||
|
||||
internal static class Ratio
|
||||
{
|
||||
public static List<int> Resolve(int total, IEnumerable<IRatioResolvable> edges)
|
||||
{
|
||||
static (int Div, float Mod) DivMod(float x, float y)
|
||||
{
|
||||
return ((int)(x / y), x % y);
|
||||
}
|
||||
|
||||
static int? GetEdgeWidth(IRatioResolvable edge)
|
||||
{
|
||||
if (edge.Size != null && edge.Size < edge.MinimumSize)
|
||||
{
|
||||
return edge.MinimumSize;
|
||||
}
|
||||
|
||||
return edge.Size;
|
||||
}
|
||||
|
||||
var sizes = edges.Select(x => GetEdgeWidth(x)).ToArray();
|
||||
|
||||
while (sizes.Any(s => s == null))
|
||||
{
|
||||
// Get all edges and map them back to their index.
|
||||
// Ignore edges which have a explicit size.
|
||||
var flexibleEdges = sizes.Zip(edges, (a, b) => (Size: a, Edge: b))
|
||||
.Enumerate()
|
||||
.Select(x => (x.Index, x.Item.Size, x.Item.Edge))
|
||||
.Where(x => x.Size == null)
|
||||
.ToList();
|
||||
|
||||
// Get the remaining space
|
||||
var remaining = total - sizes.Select(size => size ?? 0).Sum();
|
||||
if (remaining <= 0)
|
||||
{
|
||||
// No more room for flexible edges.
|
||||
return sizes
|
||||
.Zip(edges, (size, edge) => (Size: size, Edge: edge))
|
||||
.Select(zip => zip.Size ?? zip.Edge.MinimumSize)
|
||||
.Select(size => size > 0 ? size : 1)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
var portion = (float)remaining / flexibleEdges.Sum(x => Math.Max(1, x.Edge.Ratio));
|
||||
|
||||
var invalidate = false;
|
||||
foreach (var (index, size, edge) in flexibleEdges)
|
||||
{
|
||||
if (portion * edge.Ratio <= edge.MinimumSize)
|
||||
{
|
||||
sizes[index] = edge.MinimumSize;
|
||||
|
||||
// New fixed size will invalidate calculations,
|
||||
// so we need to repeat the process
|
||||
invalidate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!invalidate)
|
||||
{
|
||||
var remainder = 0f;
|
||||
foreach (var flexibleEdge in flexibleEdges)
|
||||
{
|
||||
var (div, mod) = DivMod((portion * flexibleEdge.Edge.Ratio) + remainder, 1);
|
||||
remainder = mod;
|
||||
sizes[flexibleEdge.Index] = div;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sizes.Select(x => x ?? 1).ToList();
|
||||
}
|
||||
|
||||
public static List<int> Reduce(int total, List<int> ratios, List<int> maximums, List<int> values)
|
||||
{
|
||||
ratios = ratios.Zip(maximums, (a, b) => (ratio: a, max: b)).Select(a => a.max > 0 ? a.ratio : 0).ToList();
|
||||
|
||||
@@ -4,7 +4,7 @@ internal sealed class HtmlEncoder : IAnsiConsoleEncoder
|
||||
{
|
||||
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
|
||||
{
|
||||
var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
|
||||
var context = RenderOptions.Create(console, new EncoderCapabilities(ColorSystem.TrueColor));
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n");
|
||||
|
||||
@@ -4,7 +4,7 @@ internal sealed class TextEncoder : IAnsiConsoleEncoder
|
||||
{
|
||||
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> 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)
|
||||
|
||||
Reference in New Issue
Block a user