Merge branch 'v2_develop' of github.com:gui-cs/Terminal.Gui into v2_develop

This commit is contained in:
Tig
2025-02-27 13:19:18 -07:00
8 changed files with 345 additions and 174 deletions

View File

@@ -8,8 +8,13 @@ namespace Terminal.Gui;
/// <summary>
/// View is the base class all visible elements. View can render itself and
/// contains zero or more nested views, called SubViews. View provides basic functionality for layout, positioning, and
/// drawing. In addition, View provides keyboard and mouse event handling.
/// contains zero or more nested views, called SubViews. View provides basic functionality for layout, arrangement, and
/// drawing. In addition, View provides keyboard and mouse event handling. See the
/// <see href="../docs/view.html">
/// View
/// Deep Dive
/// </see>
/// for more.
/// </summary>
/// <remarks>
/// <list type="table">
@@ -27,73 +32,222 @@ namespace Terminal.Gui;
/// <item>
/// <term>SuperView</term><description>The View that is a container for SubViews.</description>
/// </item>
/// <item>
/// <term>Input</term>
/// <description>
/// <para>
/// Key Bindings is the preferred way of handling keyboard input in View implementations.
/// The View calls
/// <see cref="AddCommand(Terminal.Gui.Command,Terminal.Gui.View.CommandImplementation)"/> to declare
/// it supports a particular command and then uses <see cref="KeyBindings"/>
/// to indicate which key presses will invoke the command.
/// </para>
/// <para>
/// Mouse Bindings is the preferred way of handling mouse input in View implementations. The View calls
/// <see cref="AddCommand(Terminal.Gui.Command,Terminal.Gui.View.CommandImplementation)"/> to declare
/// it supports a
/// particular command and then uses <see cref="MouseBindings"/> to indicate which mouse events will
/// invoke the command.
/// </para>
/// <para>
/// See the
/// <see href="../docs/mouse.html">
/// Mouse
/// Deep Dive
/// </see>
/// and
/// <see href="../docs/keyboard.html">
/// Keyboard
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Layout</term>
/// <description>
/// <para>
/// Terminal.Gui provides a rich system for how View objects are laid out relative to each other. The
/// layout system also defines how coordinates are specified.
/// </para>
/// <para>
/// The <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties are
/// <see cref="Dim"/> and <see cref="Pos"/> objects that dynamically update the position of a view. The
/// X and Y properties are of type <see cref="Pos"/> and you can use either absolute positions,
/// percentages, or anchor points. The Width and Height properties are of type <see cref="Dim"/> and
/// can use absolute position, percentages, and anchors. These are useful as they will take care of
/// repositioning views when view's adornments are resized or if the terminal size changes.
/// </para>
/// <para>
/// See the
/// <see href="../docs/layout.html">
/// Layout
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Arrangement</term>
/// <description>
/// <para>
/// Complimenting the Layout system, <see cref="Arrangement"/> controls how the user can use the mouse
/// and keyboard to arrange views and enables either Tiled or Overlapped layouts.
/// </para>
/// <para>
/// See the
/// <see href="../docs/arrangement.html">
/// Arrangement
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Drawing</term>
/// <description>
/// <para>
/// Apps draw using the <see cref="Move"/> and <see cref="AddRune(Rune)"/> APIs. Move selects the
/// column and row of the Cell and AddRune places
/// the specified glyph in that cell using the <see cref="Attribute"/> that was most recently set via
/// <see cref="SetAttribute"/>.
/// The ConsoleDriver caches all changed Cells and efficiently outputs them to the terminal each
/// iteration of the Application. In other words, Terminal.Gui uses deferred rendering.
/// </para>
/// <para>
/// The View draw APIs all take coordinates specified in Viewport-Relative coordinates. That is,
/// <c>(0,0)</c> is the top-left cell visible to the user.
/// </para>
/// <para>
/// If a View need to redraw because something changed within it's Content Area it can call
/// <see cref="SetNeedsDraw()"/>.
/// </para>
/// <para>
/// Terminal.Gui supports the full range of Unicode/wide characters.
/// This includes emoji, CJK characters, and other wide characters. For Unicode characters that require
/// more than one cell,
/// AddRune and the ConsoleDriver automatically manage the cells. Extension methods to Rune are
/// provided to determine if a Rune is a wide character and to get the width of a Rune.
/// </para>
/// <para>
/// The <see cref="ColorScheme"/> provides consistent colors across all views. The
/// <see cref="ColorScheme"/> is inherited from the <see cref="SuperView"/>. The
/// <see cref="ColorScheme"/> is used to set the <see cref="Attribute"/> for drawing.
/// </para>
/// The <see cref="Color"/> class represents a color. It provides automatic mapping between the legacy
/// 4-bit (16-color) system and 24-bit colors. It contains properties for the red, green, and blue
/// components of the color.
/// The Color class also contains a static property for each of the 16 ANSI colors. Use
/// <see cref="SetAttribute"/> to change the colors used when drawing.</para>
/// <para>
/// </para>
/// <para>
/// Clipping enables better performance by ensuring on regions of the terminal that need to be drawn
/// actually get drawn by the ConsoleDriver. Terminal.Gui supports non-rectangular clip regions with
/// <see cref="Region"/>.
/// There is an <see cref="Application"/>-managed clip region. Developers cannot change this directly,
/// but can use <see cref="ClipFrame"/>, <see cref="ClipViewport"/>, and <see cref="SetClip"/> to
/// modify the clip region.
/// </para>
/// <para>
/// <see cref="LineCanvas"/> provides auto join, a smart TUI drawing system that automatically selects
/// the correct line/box drawing glyphs for intersections making drawing complex shapes easy.
/// </para>
/// <para>
/// A set of static properties are provided for the common glyphs used in TUI apps. See
/// <see cref="Glyphs"/>.
/// </para>
/// <para>
/// See the
/// <see href="../docs/drawing.html">
/// Drawing
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Text</term>
/// <description>
/// <para>
/// A rich text formatting engine is provided in <see cref="TextFormatter"/>. TextFormatter provides
/// methods for formatting text with horizontal and vertical alignment, word wrapping, and hotkeys.
/// </para>
/// <para>
/// See the
/// <see href="../docs/navigation.html">
/// Navigation
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Navigation</term>
/// <description>
/// <para>
/// Navigation refers to the user experience for moving focus between views in the application
/// view-hierarchy. Focus is a concept that is used to describe which View is currently receiving user
/// input. Only
/// Views that are
/// <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus. NOTE:
/// <see cref="CanFocus"/> is <see langword="false"/> by default.
/// </para>
/// <para>
/// Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor
/// is
/// placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it
/// can be
/// distracting to have the cursor left at the last focused view. So views should make sure that they
/// place the
/// cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/>
/// will place the
/// cursor at either the hotkey (if defined) or <c>0,0</c>.
/// </para>
/// <para>
/// See the
/// <see href="../docs/navigation.html">
/// Navigation
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// <item>
/// <term>Scrolling</term>
/// <description>
/// <para>
/// The ability to scroll content is built into View. The <see cref="Viewport"/> represents the
/// scrollable "viewport" into the View's Content Area (which is defined by the return value of
/// <see cref="GetContentSize"/>).
/// </para>
/// <para>
/// Terminal.Gui also provides the ability show a visual scroll bar that responds to mouse input. This
/// ability is not enabled by default given how precious TUI screen real estate is.
/// Use <see cref="VerticalScrollBar"/> and <see cref="HorizontalScrollBar"/> to enable this feature.
/// </para>
/// <para>
/// Use <see cref="ViewportSettings"/> to adjust the behavior of scrolling.
/// </para>
/// <para>
/// See the
/// <see href="../docs/scrolling.html">
/// Scrolling
/// Deep Dive
/// </see>
/// for more information.
/// </para>
/// </description>
/// </item>
/// </list>
/// <para>
/// Focus is a concept that is used to describe which View is currently receiving user input. Only Views that are
/// <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
/// </para>
/// <para>
/// Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor is
/// placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it can be
/// distracting to have the cursor left at the last focused view. So views should make sure that they place the
/// cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/> will place the
/// cursor at either the hotkey (if defined) or <c>0,0</c>.
/// </para>
/// <para>
/// The View defines the base functionality for user interface elements in Terminal.Gui. Views can contain one or
/// more subviews, can respond to user input and render themselves on the screen.
/// </para>
/// <para>
/// To create a View using Absolute layout, call a constructor that takes a Rect parameter to specify the
/// absolute position and size or simply set <see cref="View.Frame "/>). To create a View using Computed layout use
/// a constructor that does not take a Rect parameter and set the X, Y, Width and Height properties on the view to
/// non-absolute values. Both approaches use coordinates that are relative to the <see cref="Viewport"/> of the
/// <see cref="SuperView"/> the View is added to.
/// </para>
/// <para>
/// Computed layout is more flexible and supports dynamic console apps where controls adjust layout as the
/// terminal resizes or other Views change size or position. The <see cref="X"/>, <see cref="Y"/>,
/// <see cref="Width"/>, and <see cref="Height"/> properties are <see cref="Dim"/> and <see cref="Pos"/> objects
/// that dynamically update the position of a view. The X and Y properties are of type <see cref="Pos"/> and you
/// can use either absolute positions, percentages, or anchor points. The Width and Height properties are of type
/// <see cref="Dim"/> and can use absolute position, percentages, and anchors. These are useful as they will take
/// care of repositioning views when view's adornments are resized or if the terminal size changes.
/// </para>
/// <para>
/// Absolute layout requires specifying coordinates and sizes of Views explicitly, and the View will typically
/// stay in a fixed position and size. To change the position and size use the <see cref="Frame"/> property.
/// </para>
/// <para>
/// Subviews (child views) can be added to a View by calling the <see cref="Add(View)"/> method. The container of
/// a View can be accessed with the <see cref="SuperView"/> property.
/// </para>
/// <para>
/// To flag a region of the View's <see cref="Viewport"/> to be redrawn call
/// <see cref="SetNeedsDraw(System.Drawing.Rectangle)"/>
/// .
/// To flag the entire view for redraw call <see cref="SetNeedsDraw()"/>.
/// </para>
/// <para>
/// The <see cref="SetNeedsLayout"/> method is called when the size or layout of a view has changed. The
/// <see cref="MainLoop"/> will
/// cause <see cref="Layout()"/> to be called on the next <see cref="Application.Iteration"/> so there is normally
/// no reason to direclty call
/// see <see cref="Layout()"/>.
/// </para>
/// <para>
/// Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews should use for
/// rendering. This ensures that the views fit in the context where they are being used, and allows for themes to
/// be plugged in. For example, the default colors for windows and Toplevels uses a blue background, while it uses
/// a white background for dialog boxes and a red background for errors.
/// </para>
/// <para>
/// Subclasses should not rely on <see cref="ColorScheme"/> being set at construction time. If a
/// <see cref="ColorScheme"/> is not set on a view, the view will inherit the value from its
/// <see cref="SuperView"/> and the value might only be valid once a view has been added to a SuperView.
/// </para>
/// <para>By using <see cref="ColorScheme"/> applications will work both in color as well as black and white displays.</para>
/// <para>
/// Views can also opt-in to more sophisticated initialization by implementing overrides to
/// Views can opt in to more sophisticated initialization by implementing overrides to
/// <see cref="ISupportInitialize.BeginInit"/> and <see cref="ISupportInitialize.EndInit"/> which will be called
/// when the view is added to a <see cref="SuperView"/>.
/// </para>
@@ -369,6 +523,7 @@ public partial class View : IDisposable, ISupportInitializeNotification
SetNeedsLayout ();
SuperView?.SetNeedsLayout ();
SetNeedsDraw ();
if (SuperView is { })
{
SuperView?.SetNeedsDraw ();
@@ -576,7 +731,7 @@ public partial class View : IDisposable, ISupportInitializeNotification
}
/// <summary>
/// Riased when the <see cref="View"/> is being disposed.
/// Riased when the <see cref="View"/> is being disposed.
/// </summary>
public event EventHandler? Disposing;

View File

@@ -1,9 +1,21 @@
namespace Terminal.Gui;
#nullable enable
namespace Terminal.Gui;
// TODO: FrameView is mis-named, really. It's far more about it being a TabGroup than a frame.
/// <summary>
/// The FrameView is a container View with a border around it.
/// A non-overlapped container for other views with a border and optional title.
/// </summary>
/// <remarks>
/// <para>
/// FrameView has <see cref="View.BorderStyle"/> set to <see cref="LineStyle.Single"/> and
/// inherits it's color scheme from the <see cref="SuperView"/>.
/// </para>
/// <para>
///
/// </para>
/// </remarks>
/// <seealso cref="Window"/>
public class FrameView : View
{
/// <summary>
@@ -14,21 +26,9 @@ public class FrameView : View
{
CanFocus = true;
TabStop = TabBehavior.TabGroup;
Border.Thickness = new Thickness (1);
Border.LineStyle = DefaultBorderStyle;
//Border.ColorScheme = ColorScheme;
Border.Data = "Border";
MouseClick += FrameView_MouseClick;
BorderStyle = DefaultBorderStyle;
}
private void FrameView_MouseClick (object sender, MouseEventArgs e)
{
// base sets focus on HotKey
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new ([Command.HotKey], this, this)) == true;
}
/// <summary>
/// The default <see cref="LineStyle"/> for <see cref="FrameView"/>'s border. The default is
/// <see cref="LineStyle.Single"/>.

View File

@@ -1,25 +1,22 @@
namespace Terminal.Gui;
#nullable enable
namespace Terminal.Gui;
/// <summary>
/// A <see cref="Toplevel"/> <see cref="View"/> with <see cref="View.BorderStyle"/> set to
/// <see cref="LineStyle.Single"/>. Provides a container for other views.
/// An overlapped container for other views with a border and optional title.
/// </summary>
/// <remarks>
/// <para>
/// If any subview is a button and the <see cref="Button.IsDefault"/> property is set to true, the Enter key will
/// invoke the <see cref="Command.Accept"/> command on that subview.
/// Window has <see cref="View.BorderStyle"/> set to <see cref="LineStyle.Single"/>, <see cref="View.Arrangement"/>
/// set to <see cref="ViewArrangement.Overlapped"/>, and
/// uses the Base <see cref="Colors.ColorSchemes"/> color scheme by default.
/// </para>
/// <para>
/// To enable Window to be sized and moved by the user, adjust <see cref="View.Arrangement"/>.
/// </para>
/// </remarks>
/// <seealso cref="FrameView"/>
public class Window : Toplevel
{
/// <summary>
/// Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
/// </summary>
[SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
/// <summary>
/// Initializes a new instance of the <see cref="Window"/> class.
/// </summary>
@@ -27,12 +24,18 @@ public class Window : Toplevel
{
CanFocus = true;
TabStop = TabBehavior.TabGroup;
Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped | ViewArrangement.Resizable;
ColorScheme = Colors.ColorSchemes ["Base"]; // TODO: make this a theme property
Arrangement = ViewArrangement.Overlapped;
base.ColorScheme = Colors.ColorSchemes ["Base"]; // TODO: make this a theme property
BorderStyle = DefaultBorderStyle;
ShadowStyle = DefaultShadow;
base.ShadowStyle = DefaultShadow;
}
/// <summary>
/// Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
/// </summary>
[SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
// TODO: enable this
///// <summary>
///// The default <see cref="LineStyle"/> for <see cref="Window"/>'s border. The default is <see cref="LineStyle.Single"/>.

View File

@@ -34,7 +34,7 @@ public class Adornments : Scenario
var window = new Window
{
Title = "The _Window",
Arrangement = ViewArrangement.Movable,
Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable,
Width = Dim.Fill (Dim.Func (() => editor.Frame.Width )),
Height = Dim.Fill ()

View File

@@ -2,12 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
using static Terminal.Gui.Dialog;
namespace UICatalog.Scenarios;
/// <summary>
/// This Scenario demonstrates how to use Terminal.Gui's Dim and Pos Layout System.
/// This Scenario demonstrates how to use Terminal.Gui's Dim and Pos Layout System.
/// </summary>
[ScenarioMetadata ("Computed Layout", "Demonstrates the Computed (Dim and Pos) Layout System.")]
[ScenarioCategory ("Layout")]
@@ -19,7 +18,7 @@ public class ComputedLayout : Scenario
Window app = new ()
{
Title = GetQuitKeyAndName (),
Title = GetQuitKeyAndName ()
};
// Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width
@@ -51,19 +50,20 @@ public class ComputedLayout : Scenario
};
app.SubviewsLaidOut += (s, a) =>
{
if (horizontalRuler.Viewport.Width == 0 || horizontalRuler.Viewport.Height == 0)
{
return;
}
horizontalRuler.Text =
rule.Repeat ((int)Math.Ceiling (horizontalRuler.Viewport.Width / (double)rule.Length)) [
..horizontalRuler.Viewport.Width];
{
if (horizontalRuler.Viewport.Width == 0 || horizontalRuler.Viewport.Height == 0)
{
return;
}
verticalRuler.Text =
vrule.Repeat ((int)Math.Ceiling (verticalRuler.Viewport.Height * 2 / (double)rule.Length))
[..(verticalRuler.Viewport.Height * 2)];
};
horizontalRuler.Text =
rule.Repeat ((int)Math.Ceiling (horizontalRuler.Viewport.Width / (double)rule.Length)) [
..horizontalRuler.Viewport.Width];
verticalRuler.Text =
vrule.Repeat ((int)Math.Ceiling (verticalRuler.Viewport.Height * 2 / (double)rule.Length))
[..(verticalRuler.Viewport.Height * 2)];
};
app.Add (verticalRuler);
@@ -77,7 +77,12 @@ public class ComputedLayout : Scenario
// Demonstrate using Dim to create a window that fills the parent with a margin
var margin = 10;
var subWin = new Window { X = Pos.Center (), Y = 2, Width = Dim.Fill (margin), Height = 7 };
var subWin = new Window
{
X = Pos.Center (), Y = 2, Width = Dim.Fill (margin), Height = 7,
Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable | ViewArrangement.Overlapped
};
subWin.Initialized += (s, a) =>
{
@@ -89,10 +94,10 @@ public class ComputedLayout : Scenario
var i = 1;
var txt = "Resize the terminal to see computed layout in action.";
List<Label> labelList = new ();
labelList.Add (new Label { Text = "The lines below show different alignment" });
labelList.Add (new() { Text = "The lines below show different alignment" });
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Start,
Width = Dim.Fill (),
@@ -104,7 +109,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.End,
Width = Dim.Fill (),
@@ -116,7 +121,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Center,
Width = Dim.Fill (),
@@ -128,7 +133,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Fill,
Width = Dim.Fill (),
@@ -150,11 +155,11 @@ public class ComputedLayout : Scenario
$"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
};
i = 1;
labelList = new List<Label> ();
labelList.Add (new Label { Text = "The lines below show different alignment" });
labelList = new ();
labelList.Add (new() { Text = "The lines below show different alignment" });
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Start,
Width = Dim.Fill (),
@@ -166,7 +171,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.End,
Width = Dim.Fill (),
@@ -178,7 +183,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Center,
Width = Dim.Fill (),
@@ -190,7 +195,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Fill,
Width = Dim.Fill (),
@@ -203,7 +208,7 @@ public class ComputedLayout : Scenario
frameView.Add (labelList.ToArray ());
app.Add (frameView);
frameView = new FrameView
frameView = new()
{
X = Pos.Right (frameView), Y = Pos.Top (frameView), Width = Dim.Fill (), Height = 7
};
@@ -216,11 +221,11 @@ public class ComputedLayout : Scenario
$"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
};
labelList = new List<Label> ();
labelList.Add (new Label { Text = "The lines below show different alignment" });
labelList = new ();
labelList.Add (new() { Text = "The lines below show different alignment" });
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Start,
Width = Dim.Fill (),
@@ -232,7 +237,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.End,
Width = Dim.Fill (),
@@ -244,7 +249,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Center,
Width = Dim.Fill (),
@@ -256,7 +261,7 @@ public class ComputedLayout : Scenario
);
labelList.Add (
new Label
new()
{
TextAlignment = Alignment.Fill,
Width = Dim.Fill (),
@@ -296,24 +301,24 @@ public class ComputedLayout : Scenario
// Demonstrate odd-ball Combine scenarios
// Until https://github.com/gui-cs/Terminal.Gui/issues/2358 is fixed these won't work right
oddballButton = new Button { Text = "Center + 0", X = Pos.Center () + 0, Y = Pos.Bottom (oddballButton) };
oddballButton = new() { Text = "Center + 0", X = Pos.Center () + 0, Y = Pos.Bottom (oddballButton) };
app.Add (oddballButton);
oddballButton = new Button { Text = "Center + 1", X = Pos.Center () + 1, Y = Pos.Bottom (oddballButton) };
oddballButton = new() { Text = "Center + 1", X = Pos.Center () + 1, Y = Pos.Bottom (oddballButton) };
app.Add (oddballButton);
oddballButton = new Button { Text = "0 + Center", X = 0 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
oddballButton = new() { Text = "0 + Center", X = 0 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
app.Add (oddballButton);
oddballButton = new Button { Text = "1 + Center", X = 1 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
oddballButton = new() { Text = "1 + Center", X = 1 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
app.Add (oddballButton);
oddballButton = new Button { Text = "Center - 1", X = Pos.Center () - 1, Y = Pos.Bottom (oddballButton) };
oddballButton = new() { Text = "Center - 1", X = Pos.Center () - 1, Y = Pos.Bottom (oddballButton) };
app.Add (oddballButton);
// This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
// The `- Pos.Percent(5)` is there so at least something is visible
oddballButton = new Button
oddballButton = new()
{
Text = "Center + Center - Percent(50)",
X = Pos.Center () + Pos.Center () - Pos.Percent (50),
@@ -323,7 +328,7 @@ public class ComputedLayout : Scenario
// This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
// The `- Pos.Percent(5)` is there so at least something is visible
oddballButton = new Button
oddballButton = new()
{
Text = "Percent(50) + Center - Percent(50)",
X = Pos.Percent (50) + Pos.Center () - Pos.Percent (50),
@@ -333,7 +338,7 @@ public class ComputedLayout : Scenario
// This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
// The `- Pos.Percent(5)` is there so at least something is visible
oddballButton = new Button
oddballButton = new()
{
Text = "Center + Percent(50) - Percent(50)",
X = Pos.Center () + Pos.Percent (50) - Pos.Percent (50),
@@ -344,7 +349,7 @@ public class ComputedLayout : Scenario
#endregion
// This demonstrates nonsense: Same as At(0)
oddballButton = new Button
oddballButton = new()
{
Text = "Center - Center - Percent(50)",
X = Pos.Center () + Pos.Center () - Pos.Percent (50),
@@ -353,7 +358,7 @@ public class ComputedLayout : Scenario
app.Add (oddballButton);
// This demonstrates combining Percents)
oddballButton = new Button
oddballButton = new()
{
Text = "Percent(40) + Percent(10)", X = Pos.Percent (40) + Pos.Percent (10), Y = Pos.Bottom (oddballButton)
};
@@ -364,13 +369,13 @@ public class ComputedLayout : Scenario
anchorButton.X = Pos.AnchorEnd ();
anchorButton.Accepting += (s, e) =>
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
// The call to app.LayoutSubviews causes the Computed layout to
// get updated.
anchorButton.Text += "!";
};
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
// The call to app.LayoutSubviews causes the Computed layout to
// get updated.
anchorButton.Text += "!";
};
app.Add (anchorButton);
// Demonstrate AnchorEnd(n)
@@ -411,26 +416,26 @@ public class ComputedLayout : Scenario
};
leftButton.Accepting += (s, e) =>
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
leftButton.Text += "!";
};
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
leftButton.Text += "!";
};
// show positioning vertically using Pos.AnchorEnd
var centerButton = new Button
{
Text = "Center",
X = Pos.Align (Alignment.Center),
Y = Pos.AnchorEnd (2),
Y = Pos.AnchorEnd (2)
};
centerButton.Accepting += (s, e) =>
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
centerButton.Text += "!";
};
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
centerButton.Text += "!";
};
// show positioning vertically using another window and Pos.Bottom
var rightButton = new Button
@@ -441,11 +446,11 @@ public class ComputedLayout : Scenario
};
rightButton.Accepting += (s, e) =>
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
rightButton.Text += "!";
};
{
// This demonstrates how to have a dynamically sized button
// Each time the button is clicked the button's text gets longer
rightButton.Text += "!";
};
View [] buttons = { leftButton, centerButton, rightButton };
app.Add (leftButton);

View File

@@ -40,7 +40,8 @@ public class WindowsAndFrameViews : Scenario
Y = 1,
Width = Dim.Fill (15),
Height = 10,
ColorScheme = Colors.ColorSchemes ["Dialog"]
ColorScheme = Colors.ColorSchemes ["Dialog"],
Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable
};
win.Padding.Thickness = new (padding);
win.Margin.Thickness = new (margin);
@@ -86,7 +87,8 @@ public class WindowsAndFrameViews : Scenario
X = margin,
Y = Pos.Bottom (listWin.Last ()) + margin,
Width = Dim.Fill (margin),
Height = contentHeight + pad * 2 + 2
Height = contentHeight + pad * 2 + 2,
Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable
};
loopWin.Padding.Thickness = new (pad);
@@ -94,7 +96,7 @@ public class WindowsAndFrameViews : Scenario
var pressMeButton = new Button
{
X = Pos.Center (), Y = 0, ColorScheme = Colors.ColorSchemes ["Error"], Text = "Press me! (Y = 0)"
X = Pos.Center (), Y = 0, ColorScheme = Colors.ColorSchemes ["Error"], Text = "Press me! (Y = 0)",
};
pressMeButton.Accepting += (s, e) =>
@@ -109,7 +111,9 @@ public class WindowsAndFrameViews : Scenario
Width = Dim.Percent (50),
Height = 5,
ColorScheme = Colors.ColorSchemes ["Base"],
Text = "The Text in the Window"
Text = "The Text in the Window",
Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable
};
subWin.Add (
@@ -164,7 +168,9 @@ public class WindowsAndFrameViews : Scenario
Width = Dim.Percent (50),
Height = Dim.Fill () - 1,
ColorScheme = Colors.ColorSchemes ["Base"],
Text = "The Text in the Window"
Text = "The Text in the Window",
Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable
};
subWinofFV.Add (

View File

@@ -147,6 +147,8 @@ public class WindowTests
Assert.Null (defaultWindow.MostFocused);
Assert.Equal (TextDirection.LeftRight_TopBottom, defaultWindow.TextDirection);
Assert.Equal (ViewArrangement.Overlapped, defaultWindow.Arrangement);
// Empty Rect
using var windowWithFrameRectEmpty = new Window { Frame = Rectangle.Empty, Title = "title" };
windowWithFrameRectEmpty.Layout ();

View File

@@ -24,7 +24,7 @@ Scrolling with the mouse and keyboard are enabled by:
1) Making the [View.Viewport](~/api/Terminal.Gui.View.Viewport.yml) size smaller than the size returned by [View.GetContentSize()](~/api/Terminal.Gui.View.GetContentSize.yml).
2) Creating key bindings for the appropriate directional keys (e.g. [Key.CursorDown](~/api/Terminal.Gui.Key)), and calling [View.ScrollHorizontal()](~/api/Terminal.Gui.View.ScrollHorizontal.yml)/[ScrollVertical()](~/api/Terminal.Gui.View.ScrollVertical.yml) as needed.
3) Subscribing to [View.MouseEvent](~/api/Terminal.Gui.View.MouseEvent.yml) and calling calling [View.ScrollHorizontal()](~/api/Terminal.Gui.View.ScrollHorizontal.yml)/[ScrollVertical()](~/api/Terminal.Gui.View.ScrollVertical.yml) as needed.
4) Enabling the [ScrollBar](~/api/Terminal.Gui.ScrollBar.yml)s built into View ([View.HorizontalScrollBar/VerticalScrollBar](~/api/Terminal.Gui.View.HorizontalScrollBar.yml)) by either enabling automatic show/hide behavior (@Terminal.Gui.ScrollBar.AutoShow) or explicitly making them visible (@Terminal.Gui.View.Visible).
4) Enabling the [ScrollBar](~/api/Terminal.Gui.ScrollBar.yml)s built into View ([View.HorizontalScrollBar/VerticalScrollBar](~/api/Terminal.Gui.View.HorizontalScrollBar.yml)) by either enabling automatic show/hide behavior (see @Terminal.Gui.ScrollBar.AutoShow) or explicitly making them visible (see @Terminal.Gui.View.Visible).
While *[ScrollBar](~/api/Terminal.Gui.ScrollBar.yml)* can be used in a standalone manner to provide proportional scrolling, it is typically enabled automatically via the [View.HorizontalScrollBar](~/api/Terminal.Gui.View.HorizontalScrollBar.yml) and [View.VerticalScrollBar](~/api/Terminal.Gui.View.VerticalScrollBar.yml) properties.
@@ -40,7 +40,7 @@ These Scenarios illustrate Terminal.Gui scrolling:
## [Viewport Settings](~/api/Terminal.Gui.ViewportSettings.yml)
Use @Terminal.Gui.ViewporSettings to adjust the behavior of scrolling.
Use @Terminal.Gui.ViewportSettings to adjust the behavior of scrolling.
* `AllowNegativeX/Y` - If set, Viewport.Size can be set to negative coordinates enabling scrolling beyond the top-left of the content area.