diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs index 0789277bb..b3acc64a8 100644 --- a/Terminal.Gui/Core.cs +++ b/Terminal.Gui/Core.cs @@ -119,6 +119,24 @@ namespace Terminal.Gui { } } + /// + /// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the + /// value from the Frame will be used, if the value is Computer, then the Frame + /// will be updated from the X, Y Pos objets and the Width and Heigh Dim objects. + /// + public enum LayoutStyle { + /// + /// The position and size of the view are based on the Frame value. + /// + Absolute, + + /// + /// The position and size of the view will be computed based on the + /// X, Y, Width and Height properties and set on the Frame. + /// + Computed + } + /// /// View is the base class for all views on the screen and represents a visible element that can render itself and contains zero or more nested views. /// @@ -128,8 +146,26 @@ namespace Terminal.Gui { /// can contain one or more subviews, can respond to user input and render themselves on the screen. /// /// - /// Views are created with a specified rectangle region (the frame) that is relative to the container - /// that they are added into. + /// Views can either be created with an absolute position, by calling the constructor that takes a + /// Rect parameter to specify the absolute position and size (the Frame of the View) or by setting the + /// X, Y, Width and Height properties on the view. Both approaches use coordinates that are relative + /// to the container they are being added to. + /// + /// + /// When you do not specify a Rect frame you can use the more flexible + /// Dim and Pos objects that can dynamically update the position of a view. + /// The X and Y properties are of type + /// and you can use either absolute positions, percentages or anchor + /// points. The Width and Height properties are of type + /// and can use absolute position, + /// percentages and anchors. These are useful as they will take + /// care of repositioning your views if your view's frames are resized + /// or if the terminal size changes. + /// + /// + /// When you specify the Rect parameter to a view, you are setting the LayoutStyle to Absolute, and the + /// view will always stay in the position that you placed it. To change the position change the + /// Frame property to the new position. /// /// /// Subviews can be added to a View by calling the Add method. The container of a view is the @@ -163,6 +199,12 @@ namespace Terminal.Gui { /// the last focused view. So views should make sure that they place the cursor /// in a visually sensible place. /// + /// + /// The metnod LayoutSubviews is invoked when the size or layout of a view has + /// changed. The default processing system will keep the size and dimensions + /// for views that use the LayoutKind.Absolute, and will recompute the + /// frames for the vies that use LayoutKind.Computed. + /// /// public class View : Responder, IEnumerable { View container = null; @@ -207,7 +249,7 @@ namespace Terminal.Gui { /// Altering the Frame of a view will trigger the redrawing of the /// view as well as the redrawing of the affected regions in the superview. /// - public Rect Frame { + public virtual Rect Frame { get => frame; set { if (SuperView != null) { @@ -216,6 +258,7 @@ namespace Terminal.Gui { } frame = value; + SetNeedsLayout (); SetNeedsDisplay (frame); } } @@ -230,6 +273,22 @@ namespace Terminal.Gui { yield return v; } + LayoutStyle layoutStyle; + + /// + /// Controls how the view's Frame is computed during the LayoutSubviews method, if Absolute, then + /// LayoutSubviews does not change the Frame properties, otherwise the Frame is updated from the + /// values in X, Y, Width and Height properties. + /// + /// The layout style. + public LayoutStyle LayoutStyle { + get => layoutStyle; + set { + layoutStyle = value; + SetNeedsLayout (); + } + } + /// /// The bounds represent the View-relative rectangle used for this view. Updates to the Bounds update the Frame, and has the same side effects as updating the frame. /// @@ -241,6 +300,61 @@ namespace Terminal.Gui { } } + Pos x, y; + /// + /// Gets or sets the X position for the view (the column). This is only used when the LayoutStyle is Computed, if the + /// LayoutStyle is set to Absolute, this value is ignored. + /// + /// The X Position. + public Pos X { + get => x; + set { + x = value; + SetNeedsLayout (); + } + } + + /// + /// Gets or sets the Y position for the view (line). This is only used when the LayoutStyle is Computed, if the + /// LayoutStyle is set to Absolute, this value is ignored. + /// + /// The y position (line). + public Pos Y { + get => y; + set { + y = value; + SetNeedsLayout (); + } + } + + Dim width, height; + + /// + /// Gets or sets the width for the view. This is only used when the LayoutStyle is Computed, if the + /// LayoutStyle is set to Absolute, this value is ignored. + /// + /// The width. + public Dim Width { + get => width; + set { + width = value; + SetNeedsLayout (); + } + } + + /// + /// Gets or sets the height for the view. This is only used when the LayoutStyle is Computed, if the + /// LayoutStyle is set to Absolute, this value is ignored. + /// + /// The height. + public Dim Height { + get => height; + set { + height = value; + SetNeedsLayout (); + } + } + /// /// Returns the container for this view, or null if this view has not been added to a container. /// @@ -248,13 +362,27 @@ namespace Terminal.Gui { public View SuperView => container; /// - /// Initializes a new instance of the class with the specified frame. This is the default constructor. + /// Initializes a new instance of the class with the absolute + /// dimensions specified in the frame. If you want to have Views that can be positioned with + /// Pos and Dim properties on X, Y, Width and Height, use the empty constructor. /// /// The region covered by this view. public View (Rect frame) { this.Frame = frame; CanFocus = false; + LayoutStyle = LayoutStyle.Absolute; + } + + /// + /// Initializes a new instance of the class and sets the + /// view up for Computed layout, which will use the values in X, Y, Width and Height to + /// compute the View's Frame. + /// + public View () + { + CanFocus = false; + LayoutStyle = LayoutStyle.Computed; } /// @@ -266,6 +394,18 @@ namespace Terminal.Gui { SetNeedsDisplay (Bounds); } + bool layoutNeeded = true; + + internal void SetNeedsLayout () + { + if (layoutNeeded) + return; + layoutNeeded = true; + if (SuperView == null) + return; + SuperView.layoutNeeded = true; + } + /// /// Flags the specified rectangle region on this view as needing to be repainted. /// @@ -864,6 +1004,43 @@ namespace Terminal.Gui { return false; } + /// + /// Computes the RelativeLayout for the view, given the frame for its container. + /// + /// The Frame for the host. + internal void RelativeLayout (Rect hostFrame) + { + int w, h, _x, _y; + if (width == null) + w = hostFrame.Width; + else + w = width.Anchor (hostFrame.Width); + + if (x == null) + _x = 0; + else { + if (x is Pos.PosCenter) + _x = x.Anchor (hostFrame.Width - w); + else + _x = x.Anchor (hostFrame.Width); + } + if (height == null) + h = hostFrame.Height; + else + h = height.Anchor (hostFrame.Height); + + if (y == null) + _y = 0; + else { + if (y is Pos.PosCenter) + _y = y.Anchor (hostFrame.Height - h); + else + _y = y.Anchor (hostFrame.Height); + } + + Frame = new Rect (_x, _y, w, h); + } + /// /// This virtual method is invoked when a view starts executing or /// when the dimensions of the view have changed, for example in @@ -871,6 +1048,17 @@ namespace Terminal.Gui { /// public virtual void LayoutSubviews () { + if (!layoutNeeded) + return; + + foreach (var v in Subviews) { + if (v.LayoutStyle == LayoutStyle.Absolute) + continue; + + v.RelativeLayout (Frame); + v.layoutNeeded = false; + } + layoutNeeded = false; } /// @@ -908,7 +1096,7 @@ namespace Terminal.Gui { public bool Running; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class with the specified absolute layout. /// /// Frame. public Toplevel (Rect frame) : base (frame) @@ -916,6 +1104,16 @@ namespace Terminal.Gui { ColorScheme = Colors.Base; } + /// + /// Initializes a new instance of the class with Computed layout, defaulting to full screen. + /// + public Toplevel () : base () + { + ColorScheme = Colors.Base; + Width = Dim.Fill (); + Height = Dim.Fill (); + } + /// /// Convenience factory method that creates a new toplevel with the current terminal dimensions. /// @@ -1000,10 +1198,11 @@ namespace Terminal.Gui { class ContentView : View { public ContentView (Rect frame) : base (frame) { } + public ContentView () : base () { } } /// - /// Initializes a new instance of the class with an optioanl title + /// Initializes a new instance of the class with an optional title and a set frame. /// /// Frame. /// Title. @@ -1011,6 +1210,14 @@ namespace Terminal.Gui { { } + /// + /// Initializes a new instance of the class with an optional title. + /// + /// Title. + public Window (ustring title = null) : this (title, padding: 0) + { + } + int padding; /// /// Initializes a new instance of the with @@ -1030,6 +1237,27 @@ namespace Terminal.Gui { base.Add (contentView); } + /// + /// Initializes a new instance of the with + /// the specified frame for its location, with the specified border + /// an optional title. + /// + /// Number of characters to use for padding of the drawn frame. + /// Title. + public Window (ustring title = null, int padding = 0) : base () + { + this.Title = title; + int wb = 2 * (1 + padding); + this.padding = padding; + contentView = new ContentView () { + X = 1 + padding, + Y = 1 + padding, + Width = Dim.Fill (wb), + Height = Dim.Fill (wb) + }; + base.Add (contentView); + } + /// /// Enumerates the various views in the ContentView. /// @@ -1295,7 +1523,7 @@ namespace Terminal.Gui { internal Toplevel Toplevel; /// - /// Releases all resource used by the object. + /// Releases alTop = l resource used by the object. /// /// Call when you are finished using the . The /// method leaves the in an unusable state. After @@ -1448,6 +1676,8 @@ namespace Terminal.Gui { toplevels.Push (toplevel); Current = toplevel; Driver.PrepareToRun (MainLoop, ProcessKeyEvent, ProcessMouseEvent); + if (toplevel.LayoutStyle == LayoutStyle.Computed) + toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows)); toplevel.LayoutSubviews (); toplevel.FocusFirst (); Redraw (toplevel); diff --git a/Terminal.Gui/Dialogs/Dialog.cs b/Terminal.Gui/Dialogs/Dialog.cs index f578f15a4..934c51ee1 100644 --- a/Terminal.Gui/Dialogs/Dialog.cs +++ b/Terminal.Gui/Dialogs/Dialog.cs @@ -25,8 +25,12 @@ namespace Terminal.Gui { /// Width for the dialog. /// Height for the dialog. /// Optional buttons to lay out at the bottom of the dialog. - public Dialog (ustring title, int width, int height, params Button [] buttons) : base (Application.MakeCenteredRect (new Size (width, height)), title, padding: padding) + public Dialog (ustring title, int width, int height, params Button [] buttons) : base (title, padding: padding) { + X = Pos.Center (); + Y = Pos.Center (); + Width = width; + Height = height; ColorScheme = Colors.Dialog; if (buttons != null) { diff --git a/Terminal.Gui/MonoCurses/mainloop.cs b/Terminal.Gui/MonoCurses/mainloop.cs index 919f706ab..7af17db46 100644 --- a/Terminal.Gui/MonoCurses/mainloop.cs +++ b/Terminal.Gui/MonoCurses/mainloop.cs @@ -388,16 +388,18 @@ namespace Mono.Terminal { RunTimers (); if (useUnix) { - foreach (var p in pollmap) { - Watch watch; + if (pollmap != null) { + foreach (var p in pollmap) { + Watch watch; - if (p.revents == 0) - continue; + if (p.revents == 0) + continue; - if (!descriptorWatchers.TryGetValue (p.fd, out watch)) - continue; - if (!watch.Callback (this)) - descriptorWatchers.Remove (p.fd); + if (!descriptorWatchers.TryGetValue (p.fd, out watch)) + continue; + if (!watch.Callback (this)) + descriptorWatchers.Remove (p.fd); + } } } else { if (windowsKeyResult.HasValue) { diff --git a/Terminal.Gui/Types/PosDim.cs b/Terminal.Gui/Types/PosDim.cs new file mode 100644 index 000000000..46e1965fc --- /dev/null +++ b/Terminal.Gui/Types/PosDim.cs @@ -0,0 +1,351 @@ +// +// PosDim.cs: Pos and Dim objects for view dimensions. +// +// Authors: +// Miguel de Icaza (miguel@gnome.org) +// + +using System; +namespace Terminal.Gui { + /// + /// Describes a position which can be an absolute value, a percentage, centered, or + /// relative to the ending dimension. Integer values are implicitly convertible to + /// an absolute Pos. These objects are created using the static methods Percent, + /// AnchorEnd and Center. The Pos objects can be combined with the addition and + /// subtraction operators. + /// + /// + /// + /// Use the Pos objects on the X or Y properties of a view to control the position. + /// + /// + /// These can be used to set the absolute position, when merely assigning an + /// integer value (via the implicit integer to Pos conversion), and they can be combined + /// to produce more useful layouts, like: Pos.Center - 3, which would shift the postion + /// of the view 3 characters to the left after centering for example. + /// + /// + public class Pos { + internal virtual int Anchor (int width) + { + return 0; + } + + class PosFactor : Pos { + float factor; + + public PosFactor (float n) + { + this.factor = n; + } + + internal override int Anchor (int width) + { + return (int)(width * factor); + } + + public override string ToString () + { + return $"Pos.Factor({factor})"; + } + } + + /// + /// Creates a percentage Pos object + /// + /// The percent Pos object. + /// A value between 0 and 100 representing the percentage. + public static Pos Percent (float n) + { + if (n < 0 || n > 100) + throw new ArgumentException ("Percent value must be between 0 and 100"); + + return new PosFactor (n / 100); + } + + static PosAnchorEnd endNoMargin; + + class PosAnchorEnd : Pos { + int n; + + public PosAnchorEnd (int n) + { + this.n = n; + } + + internal override int Anchor (int width) + { + return width - n; + } + + public override string ToString () + { + return $"Pos.AnchorEnd(margin={n})"; + } + } + + /// + /// Creates a Pos object that is anchored to the end of the dimension, useful to flush + /// the layout from the end. + /// + /// The Pos object anchored to the end (the bottom or the right side). + /// Optional margin to set aside. + public static Pos AnchorEnd (int margin = 0) + { + if (margin < 0) + throw new ArgumentException ("Margin must be positive"); + + if (margin == 0) { + if (endNoMargin == null) + endNoMargin = new PosAnchorEnd (0); + return endNoMargin; + } + return new PosAnchorEnd (margin); + } + + internal class PosCenter : Pos { + internal override int Anchor (int width) + { + return width / 2; + } + + public override string ToString () + { + return "Pos.Center"; + } + } + + static PosCenter pCenter; + + /// + /// Returns a Pos object that can be used to center the views. + /// + /// The center Pos. + public static Pos Center () + { + if (pCenter == null) + pCenter = new PosCenter (); + return pCenter; + } + + class PosAbsolute : Pos { + int n; + public PosAbsolute (int n) { this.n = n; } + + public override string ToString () + { + return $"Pos.Absolute({n})"; + } + + internal override int Anchor (int width) + { + return n; + } + } + + /// + /// Creates an Absolute Pos from the specified integer value. + /// + /// The Absolute Pos. + /// The value to convert to the pos. + public static implicit operator Pos (int n) + { + return new PosAbsolute (n); + } + + class PosCombine : Pos { + Pos left, right; + bool add; + public PosCombine (bool add, Pos left, Pos right) + { + this.left = left; + this.right = right; + this.add = add; + } + + internal override int Anchor (int width) + { + var la = left.Anchor (width); + var ra = right.Anchor (width); + if (add) + return la + ra; + else + return la - ra; + } + } + + /// + /// Adds a to a , yielding a new . + /// + /// The first to add. + /// The second to add. + /// The that is the sum of the values of left and right. + public static Pos operator + (Pos left, Pos right) + { + return new PosCombine (true, left, right); + } + + /// + /// Subtracts a from a , yielding a new . + /// + /// The to subtract from (the minuend). + /// The to subtract (the subtrahend). + /// The that is the left minus right. + public static Pos operator - (Pos left, Pos right) + { + return new PosCombine (false, left, right); + } + } + + /// + /// + /// + /// + /// Use the Dim objects on the Width or Height properties of a view to control the position. + /// + /// + /// These can be used to set the absolute position, when merely assigning an + /// integer value (via the implicit integer to Pos conversion), and they can be combined + /// to produce more useful layouts, like: Pos.Center - 3, which would shift the postion + /// of the view 3 characters to the left after centering for example. + /// + /// + public class Dim { + internal virtual int Anchor (int width) + { + return 0; + } + + class DimFactor : Dim { + float factor; + + public DimFactor (float n) + { + this.factor = n; + } + + internal override int Anchor (int width) + { + return (int)(width * factor); + } + + public override string ToString () + { + return $"Dim.Factor({factor})"; + } + } + + /// + /// Creates a percentage Dim object + /// + /// The percent Dim object. + /// A value between 0 and 100 representing the percentage. + public static Dim Percent (float n) + { + if (n < 0 || n > 100) + throw new ArgumentException ("Percent value must be between 0 and 100"); + + return new DimFactor (n / 100); + } + + class DimAbsolute : Dim { + int n; + public DimAbsolute (int n) { this.n = n; } + + public override string ToString () + { + return $"Dim.Absolute({n})"; + } + + internal override int Anchor (int width) + { + return n; + } + } + + class DimFill : Dim { + int margin; + public DimFill (int margin) { this.margin = margin; } + + public override string ToString () + { + return $"Dim.Fill(margin={margin})"; + } + + internal override int Anchor (int width) + { + return width-margin; + } + } + + static DimFill zeroMargin; + + /// + /// Creates a Dim object that fills the dimension, but leaves the specified number of colums for a margin. + /// + /// The Fill dimension. + /// Margin to use. + public static Dim Fill (int margin = 0) + { + if (margin == 0) { + if (zeroMargin == null) + zeroMargin = new DimFill (0); + return zeroMargin; + } + return new DimFill (margin); + } + + /// + /// Creates an Absolute Pos from the specified integer value. + /// + /// The Absolute Pos. + /// The value to convert to the pos. + public static implicit operator Dim (int n) + { + return new DimAbsolute (n); + } + + class DimCombine : Dim { + Dim left, right; + bool add; + public DimCombine (bool add, Dim left, Dim right) + { + this.left = left; + this.right = right; + this.add = add; + } + + internal override int Anchor (int width) + { + var la = left.Anchor (width); + var ra = right.Anchor (width); + if (add) + return la + ra; + else + return la - ra; + } + } + + /// + /// Adds a to a , yielding a new . + /// + /// The first to add. + /// The second to add. + /// The that is the sum of the values of left and right. + public static Dim operator + (Dim left, Dim right) + { + return new DimCombine (true, left, right); + } + + /// + /// Subtracts a from a , yielding a new . + /// + /// The to subtract from (the minuend). + /// The to subtract (the subtrahend). + /// The that is the left minus right. + public static Dim operator - (Dim left, Dim right) + { + return new DimCombine (false, left, right); + } + } +} diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index cf1630b2e..f55ed4846 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -62,20 +62,13 @@ namespace Terminal.Gui { /// text length. This button is not a default button. /// /// The button's text - public Button (ustring text) : this (0, 0, text) { } - - /// - /// Public constructor, creates a button based on - /// the given text. - /// - /// - /// If the value for is_default is true, a special - /// decoration is used, and the enter key on a - /// dialog would implicitly activate this button. - /// - /// The button's text /// If set, this makes the button the default button in the current view, which means that if the user presses return on a view that does not handle return, it will be treated as if he had clicked on the button - public Button (ustring text, bool is_default) : this (0, 0, text, is_default) { } + public Button (ustring text, bool is_default = false) : base () + { + Text = text; + Width = text.Length + 4 + (is_default ? 2 : 0); + Height = 1; + } /// /// Public constructor, creates a button based on diff --git a/Terminal.Gui/Views/Checkbox.cs b/Terminal.Gui/Views/Checkbox.cs index 4e672200f..5ae8bb428 100644 --- a/Terminal.Gui/Views/Checkbox.cs +++ b/Terminal.Gui/Views/Checkbox.cs @@ -27,9 +27,23 @@ namespace Terminal.Gui { /// public event EventHandler Toggled; + /// + /// Public constructor, creates a CheckButton based on the given text, uses Computed layout and sets the height and width. + /// + /// S. + /// If set to true is checked. + public CheckBox (ustring s, bool is_checked = false) : base () + { + Checked = is_checked; + Text = s; + CanFocus = true; + Height = 1; + Width = s.Length + 4; + } + /// /// Public constructor, creates a CheckButton based on - /// the given text at the given position. + /// the given text at an absolute position. /// /// /// The size of CheckButton is computed based on the diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index 01aedd5fd..518a843b8 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -31,11 +31,12 @@ namespace Terminal.Gui { class ContentView : View { public ContentView (Rect frame) : base (frame) { } + public ContentView () : base () { } } /// /// Initializes a new instance of the class with - /// a title. + /// an absolute position and a title. /// /// Frame. /// Title. @@ -47,6 +48,24 @@ namespace Terminal.Gui { Title = title; } + /// + /// Initializes a new instance of the class with + /// a title and the result is suitable to have its X, Y, Width and Height properties computed. + /// + /// Title. + public FrameView (ustring title) + { + contentView = new ContentView () { + X = 1, + Y = 1, + Width = Dim.Fill (2), + Height = Dim.Fill (2) + }; + base.Add (contentView); + Title = title; + } + + void DrawFrame () { DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), 0, fill: true); diff --git a/Terminal.Gui/Views/Label.cs b/Terminal.Gui/Views/Label.cs index 0c276b9ad..db6a930e1 100644 --- a/Terminal.Gui/Views/Label.cs +++ b/Terminal.Gui/Views/Label.cs @@ -80,6 +80,18 @@ namespace Terminal.Gui { this.text = text; } + /// + /// Public constructor: creates a label and configures the default Width and Height based on the text, the result is suitable for Computed layout. + /// + /// Text. + public Label (ustring text) : base () + { + this.text = text; + var r = CalcRect (0, 0, text); + Width = r.Width; + Height = r.Height; + } + static char [] whitespace = new char [] { ' ', '\t' }; static ustring ClipAndJustify (ustring str, int width, TextAlignment talign) diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs index f58e1a07f..39412d4c3 100644 --- a/Terminal.Gui/Views/ListView.cs +++ b/Terminal.Gui/Views/ListView.cs @@ -233,7 +233,29 @@ namespace Terminal.Gui { } /// - /// Initializes a new ListView that will display the contents of the object implementing the IList interface. + /// Initializes a new ListView that will display the contents of the object implementing the IList interface, with relative positioning + /// + /// An IList data source, if the elements of the IList are strings or ustrings, the string is rendered, otherwise the ToString() method is invoked on the result. + public ListView (IList source) : this (MakeWrapper (source)) + { + ((ListWrapper)(Source)).Container = this; + ((ListWrapper)(Source)).Driver = Driver; + } + + /// + /// Initializes a new ListView that will display the provided data source, uses relative positioning. + /// + /// IListDataSource object that provides a mechanism to render the data. The number of elements on the collection should not change, if you must change, set the "Source" property to reset the internal settings of the ListView. + public ListView (IListDataSource source) : base () + { + if (source == null) + throw new ArgumentNullException (nameof (source)); + Source = source; + CanFocus = true; + } + + /// + /// Initializes a new ListView that will display the contents of the object implementing the IList interface with an absolute position. /// /// Frame for the listview. /// An IList data source, if the elements of the IList are strings or ustrings, the string is rendered, otherwise the ToString() method is invoked on the result. @@ -244,7 +266,7 @@ namespace Terminal.Gui { } /// - /// Initializes a new ListView that will display the provided data source. + /// Initializes a new ListView that will display the provided data source with an absolute position /// /// Frame for the listview. /// IListDataSource object that provides a mechanism to render the data. The number of elements on the collection should not change, if you must change, set the "Source" property to reset the internal settings of the ListView. diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 109548a5c..e71ed482c 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -275,8 +275,12 @@ namespace Terminal.Gui { /// Initializes a new instance of the class with the specified set of toplevel menu items. /// /// Menus. - public MenuBar (MenuBarItem [] menus) : base (new Rect (0, 0, Application.Driver.Cols, 1)) + public MenuBar (MenuBarItem [] menus) : base () { + X = 0; + Y = 0; + Width = Dim.Fill (); + Height = 1; Menus = menus; CanFocus = false; selected = -1; diff --git a/Terminal.Gui/Views/ProgressBar.cs b/Terminal.Gui/Views/ProgressBar.cs index 6de6f29bf..efe41d2ca 100644 --- a/Terminal.Gui/Views/ProgressBar.cs +++ b/Terminal.Gui/Views/ProgressBar.cs @@ -20,7 +20,7 @@ namespace Terminal.Gui { int activityPos, delta; /// - /// Initializes a new instance of the class, starts in percentage mode. + /// Initializes a new instance of the class, starts in percentage mode with an absolute position and size. /// /// Rect. public ProgressBar (Rect rect) : base (rect) @@ -29,6 +29,15 @@ namespace Terminal.Gui { fraction = 0; } + /// + /// Initializes a new instance of the class, starts in percentage mode and uses relative layout. + /// + public ProgressBar () : base () + { + CanFocus = false; + fraction = 0; + } + float fraction; /// diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index 3091cb646..6d0f411de 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/Terminal.Gui/Views/RadioGroup.cs @@ -8,7 +8,8 @@ namespace Terminal.Gui { /// /// Initializes a new instance of the class - /// setting up the initial set of radio labels and the item that should be selected. + /// setting up the initial set of radio labels and the item that should be selected and uses + /// an absolute layout for the result. /// /// Boundaries for the radio group. /// Radio labels, the strings can contain hotkeys using an undermine before the letter. @@ -20,6 +21,23 @@ namespace Terminal.Gui { CanFocus = true; } + /// + /// Initializes a new instance of the class + /// setting up the initial set of radio labels and the item that should be selected. + /// + /// Radio labels, the strings can contain hotkeys using an undermine before the letter. + /// The item to be selected, the value is clamped to the number of items. + public RadioGroup (string [] radioLabels, int selected = 0) : base () + { + var r = MakeRect (0, 0, radioLabels); + Width = r.Width; + Height = radioLabels.Length; + + this.selected = selected; + this.radioLabels = radioLabels; + CanFocus = true; + } + static Rect MakeRect (int x, int y, string [] radioLabels) { int width = 0; diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index c6ae784b0..20a865f7d 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -33,21 +33,46 @@ namespace Terminal.Gui { public event EventHandler Changed; /// - /// Public constructor. + /// Public constructor that creates a text field, with layout controlled with X, Y, Width and Height. /// - /// - /// - public TextField (int x, int y, int w, string s) : base (new Rect (x, y, w, 1)) + /// Initial text contents. + public TextField (ustring text) { - if (s == null) - s = ""; + if (text == null) + text = ""; - text = s; - point = s.Length; + this.text = text; + point = text.Length; + CanFocus = true; + } + + /// + /// Public constructor that creates a text field at an absolute position and size. + /// + /// The x coordinate. + /// The y coordinate. + /// The width. + /// Initial text contents. + public TextField (int x, int y, int w, ustring text) : base (new Rect (x, y, w, 1)) + { + if (text == null) + text = ""; + + this.text = text; + point = text.Length; first = point > w ? point - w : 0; CanFocus = true; } + public override Rect Frame { + get => base.Frame; + set { + base.Frame = value; + var w = base.Frame.Width; + first = point > w ? point - w : 0; + } + } + /// /// Sets or gets the text in the entry. /// diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index 4223a53c7..ec836ced4 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -276,7 +276,7 @@ namespace Terminal.Gui { public event EventHandler Changed; #endif /// - /// Public constructor, creates a view on the specfied area + /// Public constructor, creates a view on the specified area, with absolute position and size. /// /// /// @@ -285,6 +285,14 @@ namespace Terminal.Gui { CanFocus = true; } + /// + /// Public constructor, creates a view on the specified area, with dimensions controlled with the X, Y, Width and Height properties. + /// + public TextView () : base () + { + CanFocus = true; + } + void ResetPosition () { topRow = leftColumn = currentRow = currentColumn = 0;