mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Add padder widget
This commit adds a padder can be use to pad other IRenderable objects such as tables, panels, grids, text, etc.
This commit is contained in:

committed by
Patrik Svensson

parent
314456ca17
commit
7d6104ace4
@ -12,9 +12,9 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
|
||||
/// <param name="obj">The paddable object instance.</param>
|
||||
/// <param name="padding">The left padding to apply.</param>
|
||||
/// <param name="left">The left padding.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T PadLeft<T>(this T obj, int padding)
|
||||
public static T PadLeft<T>(this T obj, int left)
|
||||
where T : class, IPaddable
|
||||
{
|
||||
if (obj is null)
|
||||
@ -22,7 +22,25 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetPadding(obj, new Padding(padding, obj.Padding.Right));
|
||||
return SetPadding(obj, new Padding(left, obj.Padding.Top, obj.Padding.Right, obj.Padding.Bottom));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the top padding.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
|
||||
/// <param name="obj">The paddable object instance.</param>
|
||||
/// <param name="top">The top padding.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T PadTop<T>(this T obj, int top)
|
||||
where T : class, IPaddable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetPadding(obj, new Padding(obj.Padding.Left, top, obj.Padding.Right, obj.Padding.Bottom));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -30,9 +48,9 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
|
||||
/// <param name="obj">The paddable object instance.</param>
|
||||
/// <param name="padding">The right padding to apply.</param>
|
||||
/// <param name="right">The right padding.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T PadRight<T>(this T obj, int padding)
|
||||
public static T PadRight<T>(this T obj, int right)
|
||||
where T : class, IPaddable
|
||||
{
|
||||
if (obj is null)
|
||||
@ -40,7 +58,25 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetPadding(obj, new Padding(obj.Padding.Left, padding));
|
||||
return SetPadding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, right, obj.Padding.Bottom));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the bottom padding.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
|
||||
/// <param name="obj">The paddable object instance.</param>
|
||||
/// <param name="bottom">The bottom padding.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T PadBottom<T>(this T obj, int bottom)
|
||||
where T : class, IPaddable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetPadding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, obj.Padding.Right, bottom));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -49,12 +85,14 @@ namespace Spectre.Console
|
||||
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
|
||||
/// <param name="obj">The paddable object instance.</param>
|
||||
/// <param name="left">The left padding to apply.</param>
|
||||
/// <param name="top">The top padding to apply.</param>
|
||||
/// <param name="right">The right padding to apply.</param>
|
||||
/// <param name="bottom">The bottom padding to apply.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetPadding<T>(this T obj, int left, int right)
|
||||
public static T SetPadding<T>(this T obj, int left, int top, int right, int bottom)
|
||||
where T : class, IPaddable
|
||||
{
|
||||
return SetPadding(obj, new Padding(left, right));
|
||||
return SetPadding(obj, new Padding(left, top, right, bottom));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,7 +3,7 @@ using System;
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a measurement.
|
||||
/// Represents padding.
|
||||
/// </summary>
|
||||
public struct Padding : IEquatable<Padding>
|
||||
{
|
||||
@ -12,20 +12,53 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public int Left { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top padding.
|
||||
/// </summary>
|
||||
public int Top { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right padding.
|
||||
/// </summary>
|
||||
public int Right { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bottom padding.
|
||||
/// </summary>
|
||||
public int Bottom { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Padding"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="size">The padding for all sides.</param>
|
||||
public Padding(int size)
|
||||
: this(size, size, size, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Padding"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="horizontal">The left and right padding.</param>
|
||||
/// <param name="vertical">The top and bottom padding.</param>
|
||||
public Padding(int horizontal, int vertical)
|
||||
: this(horizontal, vertical, horizontal, vertical)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Padding"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="left">The left padding.</param>
|
||||
/// <param name="top">The top padding.</param>
|
||||
/// <param name="right">The right padding.</param>
|
||||
public Padding(int left, int right)
|
||||
/// <param name="bottom">The bottom padding.</param>
|
||||
public Padding(int left, int top, int right, int bottom)
|
||||
{
|
||||
Left = left;
|
||||
Top = top;
|
||||
Right = right;
|
||||
Bottom = bottom;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -41,7 +74,9 @@ namespace Spectre.Console
|
||||
{
|
||||
var hash = (int)2166136261;
|
||||
hash = (hash * 16777619) ^ Left.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Top.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Right.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Bottom.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@ -49,7 +84,10 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Padding other)
|
||||
{
|
||||
return Left == other.Left && Right == other.Right;
|
||||
return Left == other.Left
|
||||
&& Top == other.Top
|
||||
&& Right == other.Right
|
||||
&& Bottom == other.Bottom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -75,12 +113,21 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal padding.
|
||||
/// Gets the padding width.
|
||||
/// </summary>
|
||||
/// <returns>The horizontal padding.</returns>
|
||||
public int GetHorizontalPadding()
|
||||
/// <returns>The padding width.</returns>
|
||||
public int GetWidth()
|
||||
{
|
||||
return Left + Right;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the padding height.
|
||||
/// </summary>
|
||||
/// <returns>The padding height.</returns>
|
||||
public int GetHeight()
|
||||
{
|
||||
return Top + Bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\stylecop.json" Link="stylecop.json" />
|
||||
<AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
|
||||
<None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Spectre.Console
|
||||
private readonly List<IRenderable> _items;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Padding Padding { get; set; } = new Padding(0, 1);
|
||||
public Padding Padding { get; set; } = new Padding(0, 0, 1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the columns should
|
||||
|
@ -21,6 +21,7 @@ namespace Spectre.Console
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding of the column.
|
||||
/// Vertical padding (top and bottom) is ignored.
|
||||
/// </summary>
|
||||
public Padding Padding
|
||||
{
|
||||
@ -48,7 +49,7 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public GridColumn()
|
||||
{
|
||||
_padding = new Padding(0, 2);
|
||||
_padding = new Padding(0, 0, 2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
106
src/Spectre.Console/Widgets/Padder.cs
Normal file
106
src/Spectre.Console/Widgets/Padder.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents padding around a <see cref="IRenderable"/> object.
|
||||
/// </summary>
|
||||
public sealed class Padder : Renderable, IPaddable, IExpandable
|
||||
{
|
||||
private readonly IRenderable _child;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Padding Padding { get; set; } = new Padding(1, 1, 1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the padding should
|
||||
/// fit the available space. If <c>false</c>, the padding width will be
|
||||
/// auto calculated. Defaults to <c>false</c>.
|
||||
/// </summary>
|
||||
public bool Expand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Padder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="child">The thing to pad.</param>
|
||||
/// <param name="padding">The padding. Defaults to <c>1,1,1,1</c> if null.</param>
|
||||
public Padder(IRenderable child, Padding? padding = null)
|
||||
{
|
||||
_child = child;
|
||||
Padding = padding ?? Padding;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
var paddingWidth = Padding.GetWidth();
|
||||
var measurement = _child.Measure(context, maxWidth - paddingWidth);
|
||||
|
||||
return new Measurement(
|
||||
measurement.Min + paddingWidth,
|
||||
measurement.Max + paddingWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
var paddingWidth = Padding.GetWidth();
|
||||
var childWidth = maxWidth - paddingWidth;
|
||||
|
||||
if (!Expand)
|
||||
{
|
||||
var measurement = _child.Measure(context, maxWidth - paddingWidth);
|
||||
childWidth = measurement.Max;
|
||||
}
|
||||
|
||||
var width = childWidth + paddingWidth;
|
||||
var result = new List<Segment>();
|
||||
|
||||
// Top padding
|
||||
for (var i = 0; i < Padding.Top; i++)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', width)));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
||||
var child = _child.Render(context, maxWidth - paddingWidth);
|
||||
foreach (var (_, _, _, line) in Segment.SplitLines(child).Enumerate())
|
||||
{
|
||||
// Left padding
|
||||
if (Padding.Left != 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Left)));
|
||||
}
|
||||
|
||||
result.AddRange(line);
|
||||
|
||||
// Right padding
|
||||
if (Padding.Right != 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Right)));
|
||||
}
|
||||
|
||||
// Missing space on right side?
|
||||
var lineWidth = line.CellWidth(context.Encoding);
|
||||
var diff = width - lineWidth - Padding.Left - Padding.Right;
|
||||
if (diff > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', diff)));
|
||||
}
|
||||
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
||||
// Bottom padding
|
||||
for (var i = 0; i < Padding.Bottom; i++)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', width)));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Gets or sets the padding.
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; } = new Padding(1, 1);
|
||||
public Padding Padding { get; set; } = new Padding(1, 0, 1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header.
|
||||
@ -61,10 +61,11 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
var childWidth = _child.Measure(context, maxWidth);
|
||||
var child = new Padder(_child, Padding);
|
||||
var childWidth = ((IRenderable)child).Measure(context, maxWidth);
|
||||
return new Measurement(
|
||||
childWidth.Min + EdgeWidth + Padding.GetHorizontalPadding(),
|
||||
childWidth.Max + EdgeWidth + Padding.GetHorizontalPadding());
|
||||
childWidth.Min + EdgeWidth,
|
||||
childWidth.Max + EdgeWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -73,16 +74,16 @@ namespace Spectre.Console
|
||||
var border = Border.GetSafeBorder((context.LegacyConsole || !context.Unicode) && UseSafeBorder);
|
||||
var borderStyle = BorderStyle ?? Style.Plain;
|
||||
|
||||
var paddingWidth = Padding.GetHorizontalPadding();
|
||||
var childWidth = maxWidth - EdgeWidth - paddingWidth;
|
||||
var child = new Padder(_child, Padding);
|
||||
var childWidth = maxWidth - EdgeWidth;
|
||||
|
||||
if (!Expand)
|
||||
{
|
||||
var measurement = _child.Measure(context, maxWidth - EdgeWidth - paddingWidth);
|
||||
var measurement = ((IRenderable)child).Measure(context, maxWidth - EdgeWidth);
|
||||
childWidth = measurement.Max;
|
||||
}
|
||||
|
||||
var panelWidth = childWidth + EdgeWidth + paddingWidth;
|
||||
var panelWidth = childWidth + EdgeWidth;
|
||||
panelWidth = Math.Min(panelWidth, maxWidth);
|
||||
|
||||
var result = new List<Segment>();
|
||||
@ -91,17 +92,11 @@ namespace Spectre.Console
|
||||
AddTopBorder(result, context, border, borderStyle, panelWidth);
|
||||
|
||||
// Split the child segments into lines.
|
||||
var childSegments = _child.Render(context, childWidth);
|
||||
var childSegments = ((IRenderable)child).Render(context, childWidth);
|
||||
foreach (var line in Segment.SplitLines(childSegments, panelWidth))
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellLeft), borderStyle));
|
||||
|
||||
// Left padding
|
||||
if (Padding.Left > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Left)));
|
||||
}
|
||||
|
||||
var content = new List<Segment>();
|
||||
content.AddRange(line);
|
||||
|
||||
@ -115,12 +110,6 @@ namespace Spectre.Console
|
||||
|
||||
result.AddRange(content);
|
||||
|
||||
// Right padding
|
||||
if (Padding.Right > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Right)));
|
||||
}
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellRight), borderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
@ -221,12 +221,12 @@ namespace Spectre.Console
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
||||
// Make cells the same shape
|
||||
cells = Segment.MakeSameHeight(cellHeight, cells);
|
||||
|
||||
// Iterate through each cell row
|
||||
foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
|
||||
{
|
||||
// Make cells the same shape
|
||||
cells = Segment.MakeSameHeight(cellHeight, cells);
|
||||
|
||||
foreach (var (cellIndex, firstCell, lastCell, cell) in cells.Enumerate())
|
||||
{
|
||||
if (firstCell && showBorder)
|
||||
@ -403,7 +403,7 @@ namespace Spectre.Console
|
||||
|
||||
private (int Min, int Max) MeasureColumn(TableColumn column, RenderContext options, int maxWidth)
|
||||
{
|
||||
var padding = column.Padding.GetHorizontalPadding();
|
||||
var padding = column.Padding.GetWidth();
|
||||
|
||||
// Predetermined width?
|
||||
if (column.Width != null)
|
||||
@ -438,7 +438,7 @@ namespace Spectre.Console
|
||||
var hideBorder = !Border.Visible;
|
||||
var separators = hideBorder ? 0 : _columns.Count - 1;
|
||||
var edges = hideBorder ? 0 : EdgeCount;
|
||||
var padding = includePadding ? _columns.Select(x => x.Padding.GetHorizontalPadding()).Sum() : 0;
|
||||
var padding = includePadding ? _columns.Select(x => x.Padding.GetWidth()).Sum() : 0;
|
||||
|
||||
if (!PadRightCell)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@ namespace Spectre.Console
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding of the column.
|
||||
/// Vertical padding (top and bottom) is ignored.
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; }
|
||||
|
||||
@ -52,7 +53,7 @@ namespace Spectre.Console
|
||||
{
|
||||
Text = renderable ?? throw new ArgumentNullException(nameof(renderable));
|
||||
Width = null;
|
||||
Padding = new Padding(1, 1);
|
||||
Padding = new Padding(1, 0, 1, 0);
|
||||
NoWrap = false;
|
||||
Alignment = null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user