mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +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:
106
src/Spectre.Console/Extensions/AlignExtensions.cs
Normal file
106
src/Spectre.Console/Extensions/AlignExtensions.cs
Normal file
@ -0,0 +1,106 @@
|
||||
namespace Spectre.Console.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Align"/>.
|
||||
/// </summary>
|
||||
public static class AlignExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the width.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <param name="width">The width, or <c>null</c> for no explicit width.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align Width(this Align align, int? width)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Width = width;
|
||||
return align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the height.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <param name="height">The height, or <c>null</c> for no explicit height.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align Height(this Align align, int? height)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Height = height;
|
||||
return align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the vertical alignment.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <param name="vertical">The vertical alignment, or <c>null</c> for no vertical alignment.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align VerticalAlignment(this Align align, VerticalAlignment? vertical)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Vertical = vertical;
|
||||
return align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Align"/> object to be top aligned.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align TopAligned(this Align align)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Vertical = Console.VerticalAlignment.Top;
|
||||
return align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Align"/> object to be middle aligned.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align MiddleAligned(this Align align)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Vertical = Console.VerticalAlignment.Middle;
|
||||
return align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Align"/> object to be bottom aligned.
|
||||
/// </summary>
|
||||
/// <param name="align">The <see cref="Align"/> object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Align BottomAligned(this Align align)
|
||||
{
|
||||
if (align is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(align));
|
||||
}
|
||||
|
||||
align.Vertical = Console.VerticalAlignment.Bottom;
|
||||
return align;
|
||||
}
|
||||
}
|
@ -77,4 +77,4 @@ public static class AlignableExtensions
|
||||
obj.Alignment = Justify.Right;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,19 +27,18 @@ public static partial class AnsiConsoleExtensions
|
||||
throw new NotSupportedException("Alternate buffers are not supported by your terminal.");
|
||||
}
|
||||
|
||||
console.ExclusivityMode.Run<object?>(() =>
|
||||
{
|
||||
// Switch to alternate screen
|
||||
console.Write(new ControlCode("\u001b[?1049h\u001b[H"));
|
||||
// Switch to alternate screen
|
||||
console.Write(new ControlCode("\u001b[?1049h\u001b[H"));
|
||||
|
||||
try
|
||||
{
|
||||
// Execute custom action
|
||||
action();
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Switch back to primary screen
|
||||
console.Write(new ControlCode("\u001b[?1049l"));
|
||||
|
||||
// Dummy result
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
80
src/Spectre.Console/Extensions/HasJustificationExtensions.cs
Normal file
80
src/Spectre.Console/Extensions/HasJustificationExtensions.cs
Normal file
@ -0,0 +1,80 @@
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IHasJustification"/>.
|
||||
/// </summary>
|
||||
public static class HasJustificationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the justification for an <see cref="IHasJustification"/> object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that can be justified.</typeparam>
|
||||
/// <param name="obj">The alignable object.</param>
|
||||
/// <param name="alignment">The alignment.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Justify<T>(this T obj, Justify? alignment)
|
||||
where T : class, IHasJustification
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Justification = alignment;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IHasJustification"/> object to be left justified.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that can be justified.</typeparam>
|
||||
/// <param name="obj">The alignable object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T LeftJustified<T>(this T obj)
|
||||
where T : class, IHasJustification
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Justification = Console.Justify.Left;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IHasJustification"/> object to be centered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that can be justified.</typeparam>
|
||||
/// <param name="obj">The alignable object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Centered<T>(this T obj)
|
||||
where T : class, IHasJustification
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Justification = Console.Justify.Center;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IHasJustification"/> object to be right justified.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that can be justified.</typeparam>
|
||||
/// <param name="obj">The alignable object.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T RightJustified<T>(this T obj)
|
||||
where T : class, IHasJustification
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Justification = Console.Justify.Right;
|
||||
return obj;
|
||||
}
|
||||
}
|
58
src/Spectre.Console/Extensions/LayoutExtensions.cs
Normal file
58
src/Spectre.Console/Extensions/LayoutExtensions.cs
Normal file
@ -0,0 +1,58 @@
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Layout"/>.
|
||||
/// </summary>
|
||||
public static class LayoutExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the ratio of the layout.
|
||||
/// </summary>
|
||||
/// <param name="layout">The layout.</param>
|
||||
/// <param name="ratio">The ratio.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Layout Ratio(this Layout layout, int ratio)
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(layout));
|
||||
}
|
||||
|
||||
layout.Ratio = ratio;
|
||||
return layout;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the size of the layout.
|
||||
/// </summary>
|
||||
/// <param name="layout">The layout.</param>
|
||||
/// <param name="size">The size.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Layout Size(this Layout layout, int size)
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(layout));
|
||||
}
|
||||
|
||||
layout.Size = size;
|
||||
return layout;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the minimum width of the layout.
|
||||
/// </summary>
|
||||
/// <param name="layout">The layout.</param>
|
||||
/// <param name="size">The size.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Layout MinimumSize(this Layout layout, int size)
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(layout));
|
||||
}
|
||||
|
||||
layout.MinimumSize = size;
|
||||
return layout;
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ public static class PanelExtensions
|
||||
throw new ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
alignment ??= panel.Header?.Alignment;
|
||||
alignment ??= panel.Header?.Justification;
|
||||
return Header(panel, new PanelHeader(text, alignment));
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public static class PanelExtensions
|
||||
if (panel.Header != null)
|
||||
{
|
||||
// Update existing style
|
||||
panel.Header.Alignment = alignment;
|
||||
panel.Header.Justification = alignment;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
10
src/Spectre.Console/Extensions/RenderOptionsExtensions.cs
Normal file
10
src/Spectre.Console/Extensions/RenderOptionsExtensions.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Spectre.Console;
|
||||
|
||||
internal static class RenderOptionsExtensions
|
||||
{
|
||||
public static BoxBorder GetSafeBorder<T>(this RenderOptions options, T border)
|
||||
where T : IHasBoxBorder, IHasBorder
|
||||
{
|
||||
return BoxExtensions.GetSafeBorder(border.Border, !options.Unicode && border.UseSafeBorder);
|
||||
}
|
||||
}
|
@ -23,13 +23,13 @@ public static class RenderableExtensions
|
||||
throw new ArgumentNullException(nameof(renderable));
|
||||
}
|
||||
|
||||
var context = new RenderContext(console.Profile.Capabilities);
|
||||
var context = RenderOptions.Create(console, console.Profile.Capabilities);
|
||||
var renderables = console.Pipeline.Process(context, new[] { renderable });
|
||||
|
||||
return GetSegments(console, context, renderables);
|
||||
}
|
||||
|
||||
private static IEnumerable<Segment> GetSegments(IAnsiConsole console, RenderContext options, IEnumerable<IRenderable> renderables)
|
||||
private static IEnumerable<Segment> GetSegments(IAnsiConsole console, RenderOptions options, IEnumerable<IRenderable> renderables)
|
||||
{
|
||||
var result = new List<Segment>();
|
||||
foreach (var renderable in renderables)
|
||||
|
43
src/Spectre.Console/Extensions/VisibilityExtensions.cs
Normal file
43
src/Spectre.Console/Extensions/VisibilityExtensions.cs
Normal file
@ -0,0 +1,43 @@
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IHasVisibility"/>.
|
||||
/// </summary>
|
||||
public static class VisibilityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks the specified object as being invisible.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IHasVisibility"/>.</typeparam>
|
||||
/// <param name="obj">The object to hide.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Invisible<T>(this T obj)
|
||||
where T : class, IHasVisibility
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.IsVisible = false;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the specified object as being visible.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IHasVisibility"/>.</typeparam>
|
||||
/// <param name="obj">The object to show.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Visible<T>(this T obj)
|
||||
where T : class, IHasVisibility
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.IsVisible = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user