소스 검색

fixed frame drawing, buttons, dialogs, messageboxes and more

Charlie Kindel 5 년 전
부모
커밋
8e58434e72

+ 2 - 2
Terminal.Gui/Core/ConsoleDriver.cs

@@ -562,7 +562,7 @@ namespace Terminal.Gui {
 		const char bottomChar = clearChar;
 		const char bottomChar = clearChar;
 #endif
 #endif
 		/// <summary>
 		/// <summary>
-		/// Draws a frame for a window with padding aand n optional visible border inside the padding. 
+		/// Draws a frame for a window with padding and an optional visible border inside the padding. 
 		/// </summary>
 		/// </summary>
 		/// <param name="region">Screen relative region where the frame will be drawn.</param>
 		/// <param name="region">Screen relative region where the frame will be drawn.</param>
 		/// <param name="paddingLeft">Number of columns to pad on the left (if 0 the border will not appear on the left).</param>
 		/// <param name="paddingLeft">Number of columns to pad on the left (if 0 the border will not appear on the left).</param>
@@ -724,7 +724,7 @@ namespace Terminal.Gui {
 			// DrawFrame assumes the border is always at least one row/col thick
 			// DrawFrame assumes the border is always at least one row/col thick
 			// DrawWindowFrame assumes a padding of 0 means NO padding and no frame
 			// DrawWindowFrame assumes a padding of 0 means NO padding and no frame
 			DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height), 
 			DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height), 
-				padding + 1, padding + 1, padding + 1, padding + 1, fill: fill);
+				padding + 1, padding + 1, padding + 1, padding + 1, border: false, fill: fill);
 		}
 		}
 
 
 
 

+ 1 - 1
Terminal.Gui/Core/View.cs

@@ -714,7 +714,7 @@ namespace Terminal.Gui {
 		{
 		{
 			var scrRect = ViewToScreen (region);
 			var scrRect = ViewToScreen (region);
 			var savedClip = ClipToBounds ();
 			var savedClip = ClipToBounds ();
-			Driver.DrawFrame (scrRect, padding, fill);
+			Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: fill);
 			Driver.Clip = savedClip;
 			Driver.Clip = savedClip;
 		}
 		}
 
 

+ 2 - 2
Terminal.Gui/Core/Window.cs

@@ -164,7 +164,7 @@ namespace Terminal.Gui {
 			// BUGBUG: Why do we draw the frame twice? This call is here to clear the content area, I think. Why not just clear that area?
 			// BUGBUG: Why do we draw the frame twice? This call is here to clear the content area, I think. Why not just clear that area?
 			if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
 			if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
 				Driver.SetAttribute (ColorScheme.Normal);
 				Driver.SetAttribute (ColorScheme.Normal);
-				Driver.DrawFrame (scrRect, padding, true);
+				Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: true);
 			}
 			}
 
 
 			var savedClip = ClipToBounds ();
 			var savedClip = ClipToBounds ();
@@ -173,7 +173,7 @@ namespace Terminal.Gui {
 
 
 			ClearNeedsDisplay ();
 			ClearNeedsDisplay ();
 			Driver.SetAttribute (ColorScheme.Normal);
 			Driver.SetAttribute (ColorScheme.Normal);
-			Driver.DrawFrame (scrRect, padding, false);
+			Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: false);
 
 
 			if (HasFocus)
 			if (HasFocus)
 				Driver.SetAttribute (ColorScheme.HotNormal);
 				Driver.SetAttribute (ColorScheme.HotNormal);

+ 7 - 2
Terminal.Gui/Terminal.Gui.csproj

@@ -5,11 +5,12 @@
     <AssemblyName>Terminal.Gui</AssemblyName>
     <AssemblyName>Terminal.Gui</AssemblyName>
     <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
     <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
     <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
     <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
+    <AssemblyVersion>0.82.0.0</AssemblyVersion>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup>
   <PropertyGroup>
     <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
     <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
     <PackageId>Terminal.Gui</PackageId>
     <PackageId>Terminal.Gui</PackageId>
-    <PackageVersion>0.81</PackageVersion>
+    <PackageVersion>0.82</PackageVersion>
     <Authors>Miguel de Icaza</Authors>
     <Authors>Miguel de Icaza</Authors>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <PackageProjectUrl>https://github.com/migueldeicaza/gui.cs/</PackageProjectUrl>
     <PackageProjectUrl>https://github.com/migueldeicaza/gui.cs/</PackageProjectUrl>
@@ -18,8 +19,12 @@
     <Owners>Miguel de Icaza</Owners>
     <Owners>Miguel de Icaza</Owners>
     <Summary>Application framework for creating modern console applications using .NET </Summary>
     <Summary>Application framework for creating modern console applications using .NET </Summary>
     <Title>Gui.cs is a framework for creating console user interfaces</Title>
     <Title>Gui.cs is a framework for creating console user interfaces</Title>
-    <PackageReleaseNotes>0.81: Fix ncurses engine for macOS/Linux, it works again
+    <PackageReleaseNotes>
+0.82: Many fixes
+* ...
 
 
+0.81: 
+* Fix ncurses engine for macOS/Linux, it works again
 * Fixes an issue with referencing views that have not been allocated yet causing a stack overflow
 * Fixes an issue with referencing views that have not been allocated yet causing a stack overflow
 * New OnCloseMenu event on menus
 * New OnCloseMenu event on menus
 * Button cursor position looks better
 * Button cursor position looks better

+ 38 - 22
Terminal.Gui/Views/Button.cs

@@ -55,29 +55,32 @@ namespace Terminal.Gui {
 		public Action Clicked;
 		public Action Clicked;
 
 
 		/// <summary>
 		/// <summary>
-		///   Initializes a new instance of <see cref="Button"/> based on the given text at position 0,0
+		///   Initializes a new instance of <see cref="Button"/> using <see cref="LayoutStyle.Computed"/> layout.
 		/// </summary>
 		/// </summary>
 		/// <remarks>
 		/// <remarks>
-		///   The size of the <see cref="Button"/> is computed based on the
-		///   text length. 
+		///   The width of the <see cref="Button"/> is computed based on the
+		///   text length. The height will always be 1.
 		/// </remarks>
 		/// </remarks>
 		/// <param name="text">The button's text</param>
 		/// <param name="text">The button's text</param>
-		/// <param name="is_default">If set, this makes the button the default button in the current view. <seealso cref="IsDefault"/></param>
+		/// <param name="is_default">
+		///   If <c>true</c>, a special decoration is used, and the user pressing the enter key 
+		///   in a <see cref="Dialog"/> will implicitly activate this button.
+		/// </param>
 		public Button (ustring text, bool is_default = false) : base ()
 		public Button (ustring text, bool is_default = false) : base ()
 		{
 		{
 			CanFocus = true;
 			CanFocus = true;
 			Text = text ?? string.Empty;
 			Text = text ?? string.Empty;
 			this.IsDefault = is_default;
 			this.IsDefault = is_default;
 			int w = SetWidthHeight (text, is_default);
 			int w = SetWidthHeight (text, is_default);
-			Frame = new Rect (0, 0, w, 1);
+			Frame = new Rect (Frame.Location, new Size (w, 1));
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		///   Initializes a new instance of <see cref="Button"/> at the given coordinates, based on the given text
+		///   Initializes a new instance of <see cref="Button"/> using <see cref="LayoutStyle.Absolute"/> layout, based on the given text
 		/// </summary>
 		/// </summary>
 		/// <remarks>
 		/// <remarks>
-		///   The size of the <see cref="Button"/> is computed based on the
-		///   text length. 
+		///   The width of the <see cref="Button"/> is computed based on the
+		///   text length. The height will always be 1.
 		/// </remarks>
 		/// </remarks>
 		/// <param name="x">X position where the button will be shown.</param>
 		/// <param name="x">X position where the button will be shown.</param>
 		/// <param name="y">Y position where the button will be shown.</param>
 		/// <param name="y">Y position where the button will be shown.</param>
@@ -85,17 +88,19 @@ namespace Terminal.Gui {
 		public Button (int x, int y, ustring text) : this (x, y, text, false) { }
 		public Button (int x, int y, ustring text) : this (x, y, text, false) { }
 
 
 		/// <summary>
 		/// <summary>
-		///   Initializes a new instance of <see cref="Button"/> at the given coordinates, based on the given text, and with the specified <see cref="IsDefault"/> value
+		///   Initializes a new instance of <see cref="Button"/> using <see cref="LayoutStyle.Absolute"/> layout, based on the given text.
 		/// </summary>
 		/// </summary>
 		/// <remarks>
 		/// <remarks>
-		///   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 width of the <see cref="Button"/> is computed based on the
+		///   text length. The height will always be 1.
 		/// </remarks>
 		/// </remarks>
 		/// <param name="x">X position where the button will be shown.</param>
 		/// <param name="x">X position where the button will be shown.</param>
 		/// <param name="y">Y position where the button will be shown.</param>
 		/// <param name="y">Y position where the button will be shown.</param>
 		/// <param name="text">The button's text</param>
 		/// <param name="text">The button's text</param>
-		/// <param name="is_default">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</param>
+		/// <param name="is_default">
+		///   If <c>true</c>, a special decoration is used, and the user pressing the enter key 
+		///   in a <see cref="Dialog"/> will implicitly activate this button.
+		/// </param>
 		public Button (int x, int y, ustring text, bool is_default)
 		public Button (int x, int y, ustring text, bool is_default)
 		    : base (new Rect (x, y, text.Length + 4 + (is_default ? 2 : 0), 1))
 		    : base (new Rect (x, y, text.Length + 4 + (is_default ? 2 : 0), 1))
 		{
 		{
@@ -110,6 +115,7 @@ namespace Terminal.Gui {
 			int w = text.Length + 4 + (is_default ? 2 : 0);
 			int w = text.Length + 4 + (is_default ? 2 : 0);
 			Width = w;
 			Width = w;
 			Height = 1;
 			Height = 1;
+			Frame = new Rect (Frame.Location, new Size (w, 1));
 			return w;
 			return w;
 		}
 		}
 
 
@@ -137,17 +143,27 @@ namespace Terminal.Gui {
 			else
 			else
 				shown_text = "[ " + text + " ]";
 				shown_text = "[ " + text + " ]";
 
 
-			hot_pos = -1;
 			hot_key = (Rune)0;
 			hot_key = (Rune)0;
-			int i = 0;
-			foreach (Rune c in shown_text) {
-				if (Rune.IsUpper (c)) {
-					hot_key = c;
-					hot_pos = i;
-					break;
+			hot_pos = shown_text.IndexOf ('_');
+
+			if (hot_pos == -1) {
+				// Use first upper-case char
+				int i = 0;
+				foreach (Rune c in shown_text) {
+					if (Rune.IsUpper (c)) {
+						hot_key = c;
+						hot_pos = i;
+						break;
+					}
+					i++;
 				}
 				}
-				i++;
+			} else {
+				// Use char after '_'
+				var start = shown_text [0, hot_pos];
+				shown_text = start + shown_text [hot_pos + 1, shown_text.Length];
+				hot_key = Char.ToUpper((char)shown_text [hot_pos]);
 			}
 			}
+
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 		}
 		}
 
 
@@ -214,7 +230,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		///<inheritdoc cref="MouseEvent"/>
 		///<inheritdoc cref="MouseEvent"/>
-		public override bool MouseEvent(MouseEvent me)
+		public override bool MouseEvent (MouseEvent me)
 		{
 		{
 			if (me.Flags == MouseFlags.Button1Clicked) {
 			if (me.Flags == MouseFlags.Button1Clicked) {
 				SuperView.SetFocus (this);
 				SuperView.SetFocus (this);

+ 2 - 2
Terminal.Gui/Views/FrameView.cs

@@ -140,7 +140,7 @@ namespace Terminal.Gui {
 
 
 			if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
 			if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
 				Driver.SetAttribute (ColorScheme.Normal);
 				Driver.SetAttribute (ColorScheme.Normal);
-				Driver.DrawFrame (scrRect, padding, true);
+				Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: true);
 			}
 			}
 
 
 			var savedClip = ClipToBounds ();
 			var savedClip = ClipToBounds ();
@@ -149,7 +149,7 @@ namespace Terminal.Gui {
 
 
 			ClearNeedsDisplay ();
 			ClearNeedsDisplay ();
 			Driver.SetAttribute (ColorScheme.Normal);
 			Driver.SetAttribute (ColorScheme.Normal);
-			Driver.DrawFrame (scrRect, padding, false);
+			Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: false);
 
 
 			if (HasFocus)
 			if (HasFocus)
 				Driver.SetAttribute (ColorScheme.HotNormal);
 				Driver.SetAttribute (ColorScheme.HotNormal);

+ 53 - 23
Terminal.Gui/Windows/Dialog.cs

@@ -4,15 +4,15 @@
 // Authors:
 // Authors:
 //   Miguel de Icaza ([email protected])
 //   Miguel de Icaza ([email protected])
 //
 //
-
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Linq;
 using NStack;
 using NStack;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
 	/// The <see cref="Dialog"/> <see cref="View"/> is a <see cref="Window"/> that by default is centered and contains one 
 	/// The <see cref="Dialog"/> <see cref="View"/> is a <see cref="Window"/> that by default is centered and contains one 
-	/// or more <see cref="Button"/>. It defaults to the <see cref="Colors.Dialog"/> color scheme and has a 1 cell padding around the edges.
+	/// or more <see cref="Button"/>s. It defaults to the <see cref="Colors.Dialog"/> color scheme and has a 1 cell padding around the edges.
 	/// </summary>
 	/// </summary>
 	/// <remarks>
 	/// <remarks>
 	///  To run the <see cref="Dialog"/> modally, create the <see cref="Dialog"/>, and pass it to <see cref="Application.Run()"/>. 
 	///  To run the <see cref="Dialog"/> modally, create the <see cref="Dialog"/>, and pass it to <see cref="Application.Run()"/>. 
@@ -21,21 +21,37 @@ namespace Terminal.Gui {
 	/// </remarks>
 	/// </remarks>
 	public class Dialog : Window {
 	public class Dialog : Window {
 		List<Button> buttons = new List<Button> ();
 		List<Button> buttons = new List<Button> ();
-		const int padding = 1;
+		const int padding = 0;
 
 
 		/// <summary>
 		/// <summary>
-		/// Initializes a new instance of the <see cref="Dialog"/> class with an optional set of <see cref="Button"/>s to display
+		/// Initializes a new instance of the <see cref="Dialog"/> class using <see cref="LayoutStyle.Absolute"/> positioning 
+		/// and an optional set of <see cref="Button"/>s to display
 		/// </summary>
 		/// </summary>
 		/// <param name="title">Title for the dialog.</param>
 		/// <param name="title">Title for the dialog.</param>
 		/// <param name="width">Width for the dialog.</param>
 		/// <param name="width">Width for the dialog.</param>
 		/// <param name="height">Height for the dialog.</param>
 		/// <param name="height">Height for the dialog.</param>
 		/// <param name="buttons">Optional buttons to lay out at the bottom of the dialog.</param>
 		/// <param name="buttons">Optional buttons to lay out at the bottom of the dialog.</param>
+		/// <remarks>
+		/// if <c>width</c> and <c>height</c> are both 0, the Dialog will be vertically and horizontally centered in the
+		/// container and the size will be 85% of the container. 
+		/// After initialzation use <c>X</c>, <c>Y</c>, <c>Width</c>, and <c>Height</c> to override this with a location or size.
+		/// </remarks>
+		/// <remarks>
+		/// Use the constructor that does not take a <c>width</c> and <c>height</c> instead.
+		/// </remarks>
 		public Dialog (ustring title, int width, int height, params Button [] buttons) : base (title, padding: padding)
 		public Dialog (ustring title, int width, int height, params Button [] buttons) : base (title, padding: padding)
 		{
 		{
 			X = Pos.Center ();
 			X = Pos.Center ();
 			Y = Pos.Center ();
 			Y = Pos.Center ();
-			Width = width;
-			Height = height;
+
+			if (width == 0 & height == 0) {
+				Width = Dim.Percent (85);
+				Height = Dim.Percent (85);
+			} else {
+				Width = width;
+				Height = height;
+			}
+
 			ColorScheme = Colors.Dialog;
 			ColorScheme = Colors.Dialog;
 			Modal = true;
 			Modal = true;
 
 
@@ -47,6 +63,20 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Dialog"/> class using <see cref="LayoutStyle.Computed"/> positioning 
+		/// and with an optional set of <see cref="Button"/>s to display
+		/// </summary>
+		/// <param name="title">Title for the dialog.</param>
+		/// <param name="buttons">Optional buttons to lay out at the bottom of the dialog.</param>
+		/// <remarks>
+		/// if <c>width</c> and <c>height</c> are both 0, the Dialog will be vertically and horizontally centered in the
+		/// container and the size will be 85% of the container. 
+		/// After initialzation use <c>X</c>, <c>Y</c>, <c>Width</c>, and <c>Height</c> to override this with a location or size.
+		/// </remarks>
+		public Dialog (ustring title, params Button [] buttons) : this (title: title, width: 0, height: 0, buttons: buttons) { 
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Adds a <see cref="Button"/> to the <see cref="Dialog"/>, its layout will be controled by the <see cref="Dialog"/>
 		/// Adds a <see cref="Button"/> to the <see cref="Dialog"/>, its layout will be controled by the <see cref="Dialog"/>
 		/// </summary>
 		/// </summary>
@@ -58,31 +88,31 @@ namespace Terminal.Gui {
 
 
 			buttons.Add (button);
 			buttons.Add (button);
 			Add (button);
 			Add (button);
+			LayoutSubviews ();
+		}
+
+		internal int GetButtonsWidth ()
+		{
+			if (buttons.Count == 0) {
+				return 0;
+			}
+			return buttons.Select (b => b.Bounds.Width).Sum () + buttons.Count() - 1;
 		}
 		}
 
 
 		///<inheritdoc cref="LayoutSubviews"/>
 		///<inheritdoc cref="LayoutSubviews"/>
 		public override void LayoutSubviews ()
 		public override void LayoutSubviews ()
 		{
 		{
-			base.LayoutSubviews ();
+			int buttonsWidth = GetButtonsWidth ();
 
 
-			int buttonSpace = 0;
-			int maxHeight = 0;
-
-			foreach (var b in buttons) {
-				buttonSpace += b.Frame.Width + 1;
-				maxHeight = Math.Max (maxHeight, b.Frame.Height);
+			int shiftLeft = Math.Max((Bounds.Width - buttonsWidth) / 2 - 2, 0);
+			for (int i = buttons.Count - 1; i >= 0 ; i--) {
+				Button button = buttons [i];
+				shiftLeft += button.Frame.Width + 1;
+				button.X = Pos.AnchorEnd (shiftLeft);
+				button.Y = Pos.AnchorEnd (1);
 			}
 			}
-			const int borderWidth = 2;
-			var start = (Frame.Width-borderWidth - buttonSpace) / 2;
-
-			var y = Frame.Height - borderWidth  - maxHeight-1-padding;
-			foreach (var b in buttons) {
-				var bf = b.Frame;
-
-				b.Frame = new Rect (start, y, bf.Width, bf.Height);
 
 
-				start += bf.Width + 1;
-			}
+			base.LayoutSubviews ();
 		}
 		}
 
 
 		///<inheritdoc cref="ProcessKey"/>
 		///<inheritdoc cref="ProcessKey"/>

+ 95 - 15
Terminal.Gui/Windows/MessageBox.cs

@@ -1,18 +1,22 @@
 using System;
 using System;
+using System.Collections.Generic;
+using System.Linq;
+
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
 	/// MessageBox displays a modal message to the user, with a title, a message and a series of options that the user can choose from.
 	/// MessageBox displays a modal message to the user, with a title, a message and a series of options that the user can choose from.
 	/// </summary>
 	/// </summary>
 	/// <para>
 	/// <para>
-	///   The difference between the <see cref="Query"/> and <see cref="ErrorQuery"/> method is the default set of colors used for the message box.
+	///   The difference between the <see cref="Query(string, string, string[])"/> and <see cref="ErrorQuery(string, string, string[])"/> 
+	///   method is the default set of colors used for the message box.
 	/// </para>
 	/// </para>
 	/// <para>
 	/// <para>
-	/// The following example pops up a <see cref="MessageBox"/> with 50 columns, and 7 lines, with the specified title and text, plus two <see cref="Button"/>s.
+	/// The following example pops up a <see cref="MessageBox"/> with the specified title and text, plus two <see cref="Button"/>s.
 	/// The value -1 is returned when the user cancels the <see cref="MessageBox"/> by pressing the ESC key.
 	/// The value -1 is returned when the user cancels the <see cref="MessageBox"/> by pressing the ESC key.
 	/// </para>
 	/// </para>
 	/// <example>
 	/// <example>
 	/// <code lang="c#">
 	/// <code lang="c#">
-	/// var n = MessageBox.Query (50, 7, "Quit Demo", "Are you sure you want to quit this demo?", "Yes", "No");
+	/// var n = MessageBox.Query ("Quit Demo", "Are you sure you want to quit this demo?", "Yes", "No");
 	/// if (n == 0)
 	/// if (n == 0)
 	///    quit = true;
 	///    quit = true;
 	/// else
 	/// else
@@ -29,11 +33,30 @@ namespace Terminal.Gui {
 		/// <param name="title">Title for the query.</param>
 		/// <param name="title">Title for the query.</param>
 		/// <param name="message">Message to display, might contain multiple lines..</param>
 		/// <param name="message">Message to display, might contain multiple lines..</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
+		/// <remarks>
+		/// Use <see cref="Query(string, string, string[])"/> instead; it automatically sizes the MessageBox based on the contents.
+		/// </remarks>
 		public static int Query (int width, int height, string title, string message, params string [] buttons)
 		public static int Query (int width, int height, string title, string message, params string [] buttons)
 		{
 		{
 			return QueryFull (false, width, height, title, message, buttons);
 			return QueryFull (false, width, height, title, message, buttons);
 		}
 		}
 
 
+		/// <summary>
+		/// Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show to the user.
+		/// </summary>
+		/// <returns>The index of the selected button, or -1 if the user pressed ESC to close the dialog.</returns>
+		/// <param name="title">Title for the query.</param>
+		/// <param name="message">Message to display, might contain multiple lines.</param>
+		/// <param name="buttons">Array of buttons to add.</param>
+		/// <remarks>
+		/// The message box will be vertically and horizontally centered in the container and the size will be automatically determined
+		/// from the size of the message and buttons.
+		/// </remarks>
+		public static int Query (string title, string message, params string [] buttons)
+		{
+			return QueryFull (false, 0, 0, title, message, buttons);
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show to the user.
 		/// Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show to the user.
 		/// </summary>
 		/// </summary>
@@ -43,34 +66,91 @@ namespace Terminal.Gui {
 		/// <param name="title">Title for the query.</param>
 		/// <param name="title">Title for the query.</param>
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
+		/// <remarks>
+		/// Use <see cref="ErrorQuery(string, string, string[])"/> instead; it automatically sizes the MessageBox based on the contents.
+		/// </remarks>
 		public static int ErrorQuery (int width, int height, string title, string message, params string [] buttons)
 		public static int ErrorQuery (int width, int height, string title, string message, params string [] buttons)
 		{
 		{
 			return QueryFull (true, width, height, title, message, buttons);
 			return QueryFull (true, width, height, title, message, buttons);
 		}
 		}
 
 
+		/// <summary>
+		/// Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show to the user.
+		/// </summary>
+		/// <returns>The index of the selected button, or -1 if the user pressed ESC to close the dialog.</returns>
+		/// <param name="title">Title for the query.</param>
+		/// <param name="message">Message to display, might contain multiple lines.</param>
+		/// <param name="buttons">Array of buttons to add.</param>
+		/// <remarks>
+		/// The message box will be vertically and horizontally centered in the container and the size will be automatically determined
+		/// from the size of the title, message. and buttons.
+		/// </remarks>
+		public static int ErrorQuery (string title, string message, params string [] buttons)
+		{
+			return QueryFull (true, 0, 0, title, message, buttons);
+		}
+
+
 		static int QueryFull (bool useErrorColors, int width, int height, string title, string message, params string [] buttons)
 		static int QueryFull (bool useErrorColors, int width, int height, string title, string message, params string [] buttons)
 		{
 		{
+			const int defaultWidth = 30;
 			int textWidth = Label.MaxWidth (message, width);
 			int textWidth = Label.MaxWidth (message, width);
-			int clicked = -1, count = 0;
-
-			var d = new Dialog (title, Math.Max(width, textWidth) + 4, height);
-			if (useErrorColors)
-				d.ColorScheme = Colors.Error;
+			int textHeight = message.ToCharArray ().Count (c => c == '\n') + 1;
+			int msgboxHeight = Math.Max (1, textHeight) + 4; // textHeight + (top + top padding + buttons + bottom)
 
 
+			// Create button array for Dialog
+			int count = 0;
+			List<Button> buttonList = new List<Button> ();
 			foreach (var s in buttons) {
 			foreach (var s in buttons) {
-				int n = count++;
 				var b = new Button (s);
 				var b = new Button (s);
-				b.Clicked += delegate {
-					clicked = n;
-					d.Running = false;
-				};
-				d.AddButton (b);
+				if (count == 0) {
+					b.IsDefault = true;
+				}
+				buttonList.Add (b);
+				count++;
+			}
+
+			// Create Dialog (retain backwards compat by supporting specifying height/width)
+			Dialog d;
+			if (width == 0 & height == 0) {
+				d = new Dialog (title, buttonList.ToArray ());
+				d.Height = msgboxHeight;
+			} else {
+				d = new Dialog (title, Math.Max (width, textWidth) + 4, height, buttonList.ToArray ());
 			}
 			}
+
+			if (useErrorColors) {
+				d.ColorScheme = Colors.Error;
+			}
+
 			if (message != null) {
 			if (message != null) {
-				var l = new Label (textWidth > width ? 0 : (width - 4 - textWidth) / 2, 0, message);
+				var l = new Label (textWidth > width ? 0 : (width - 4 - textWidth) / 2, 1, message);
+				//l.ColorScheme = Colors.Menu;
+				if (true) { //width == 0 & height == 0) {
+					l.LayoutStyle = LayoutStyle.Computed;
+					l.TextAlignment = TextAlignment.Centered;
+					l.X = Pos.Center ();
+					l.Y = Pos.Center ();
+					l.Width = Dim.Fill (2);
+					l.Height = Dim.Fill (2);
+				}
 				d.Add (l);
 				d.Add (l);
 			}
 			}
 
 
+			// Dynamically size Width
+			int msgboxWidth = Math.Max (defaultWidth, Math.Max (title.Length + 8, Math.Max (textWidth + 4, d.GetButtonsWidth ()) + 8)); // textWidth + (left + padding + padding + right)
+			d.Width = msgboxWidth;
+
+			// Setup actions
+			int clicked = -1;
+			for (int n = 0; n < buttonList.Count; n++) {
+				int buttonId = n;
+				buttonList [n].Clicked += () => {
+					clicked = buttonId;
+					Application.RequestStop ();
+				};
+			}
+
 			Application.Run (d);
 			Application.Run (d);
 			return clicked;
 			return clicked;
 		}
 		}

+ 57 - 28
UICatalog/Scenarios/Buttons.cs

@@ -1,4 +1,6 @@
-using Terminal.Gui;
+using NStack;
+using System;
+using Terminal.Gui;
 
 
 namespace UICatalog {
 namespace UICatalog {
 	[ScenarioMetadata (Name: "Buttons", Description: "Demonstrates all sorts of Buttons")]
 	[ScenarioMetadata (Name: "Buttons", Description: "Demonstrates all sorts of Buttons")]
@@ -19,50 +21,58 @@ namespace UICatalog {
 
 
 			// This is the default button (IsDefault = true); if user presses ENTER in the TextField
 			// This is the default button (IsDefault = true); if user presses ENTER in the TextField
 			// the scenario will quit
 			// the scenario will quit
-			var defaultButton = new Button ("Quit") {
+			var defaultButton = new Button ("_Quit") {
 				X = Pos.Center (),
 				X = Pos.Center (),
 				//TODO: Change to use Pos.AnchorEnd()
 				//TODO: Change to use Pos.AnchorEnd()
-				Y= Pos.Bottom(Win) - 3,
+				Y = Pos.Bottom (Win) - 3,
 				IsDefault = true,
 				IsDefault = true,
 				Clicked = () => Application.RequestStop (),
 				Clicked = () => Application.RequestStop (),
 			};
 			};
 			Win.Add (defaultButton);
 			Win.Add (defaultButton);
 
 
+			static void DoMessage (Button button, ustring txt)
+			{
+				button.Clicked = () => {
+					var btnText = button.Text.ToString ();
+					MessageBox.Query (30, 7, "Message", $"Did you click {txt.ToString ()}?", "Yes", "No");
+				};
+			}
+
 			var y = 2;
 			var y = 2;
-			var button = new Button (10, y, "Base Color") {
+			var button = new Button (10, y, "Ba_se Color") {
 				ColorScheme = Colors.Base,
 				ColorScheme = Colors.Base,
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No") 
 			};
 			};
+			DoMessage (button, button.Text);
 			Win.Add (button);
 			Win.Add (button);
 
 
 			y += 2;
 			y += 2;
-			Win.Add (new Button (10, y, "Error Color") { 
+			Win.Add (button = new Button (10, y, "Error Color") {
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No") 
 			});
 			});
+			DoMessage (button, button.Text);
 
 
 			y += 2;
 			y += 2;
-			Win.Add (new Button (10, y, "Dialog Color") {
+			Win.Add (button = new Button (10, y, "Dialog Color") {
 				ColorScheme = Colors.Dialog,
 				ColorScheme = Colors.Dialog,
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No")
 			});
 			});
+			DoMessage (button, button.Text);
 
 
 			y += 2;
 			y += 2;
-			Win.Add (new Button (10, y, "Menu Color") {
+			Win.Add (button = new Button (10, y, "Menu Color") {
 				ColorScheme = Colors.Menu,
 				ColorScheme = Colors.Menu,
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No")
 			});
 			});
+			DoMessage (button, button.Text);
 
 
 			y += 2;
 			y += 2;
-			Win.Add (new Button (10, y, "TopLevel Color") {
+			Win.Add (button = new Button (10, y, "TopLevel Color") {
 				ColorScheme = Colors.TopLevel,
 				ColorScheme = Colors.TopLevel,
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No")
 			});
 			});
+			DoMessage (button, button.Text);
 
 
 			y += 2;
 			y += 2;
-			Win.Add (new Button (10, y, "A super long button that will probably expose a bug in clipping or wrapping of text. Will it?") {
-				Clicked = () => MessageBox.Query (30, 7, "Message", "Question?", "Yes", "No")
+			Win.Add (button = new Button (10, y, "A super long _Button that will probably expose a bug in clipping or wrapping of text. Will it?") {
 			});
 			});
+			DoMessage (button, button.Text);
 
 
 			y += 2;
 			y += 2;
 			// Note the 'N' in 'Newline' will be the hotkey
 			// Note the 'N' in 'Newline' will be the hotkey
@@ -73,13 +83,14 @@ namespace UICatalog {
 			y += 2;
 			y += 2;
 			// BUGBUG: Buttons don't support specifying hotkeys with _?!?
 			// BUGBUG: Buttons don't support specifying hotkeys with _?!?
 			Win.Add (button = new Button ("Te_xt Changer") {
 			Win.Add (button = new Button ("Te_xt Changer") {
-				X = 10, 
+				X = 10,
 				Y = y
 				Y = y
 			});
 			});
-			button.Clicked = () => button.Text += $"{y++}";
+
+			button.Clicked = () => button.Text += "!"; 
 
 
 			Win.Add (new Button ("Lets see if this will move as \"Text Changer\" grows") {
 			Win.Add (new Button ("Lets see if this will move as \"Text Changer\" grows") {
-				X = Pos.Right(button) + 10,
+				X = Pos.Right (button) + 10,
 				Y = y,
 				Y = y,
 			});
 			});
 
 
@@ -99,25 +110,43 @@ namespace UICatalog {
 
 
 			// Demonstrates how changing the View.Frame property can move Views
 			// Demonstrates how changing the View.Frame property can move Views
 			y += 2;
 			y += 2;
-			var moveBtn = new Button (10, y, "Move TextField via Frame") {
+			var moveBtn = new Button (10, y, "Move This Button via Frame") {
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
 			};
 			};
 			moveBtn.Clicked = () => {
 			moveBtn.Clicked = () => {
-				edit.Frame = new Rect (edit.Frame.X + 5, edit.Frame.Y, edit.Frame.Width, edit.Frame.Height);
+				moveBtn.Frame = new Rect (moveBtn.Frame.X + 5, moveBtn.Frame.Y, moveBtn.Frame.Width, moveBtn.Frame.Height);
 			};
 			};
 			Win.Add (moveBtn);
 			Win.Add (moveBtn);
 
 
-			// Demonstrates how changing the View.Frame property can NOT resize Views
+			// Demo changing hotkey
+			ustring MoveHotkey (ustring txt)
+			{
+				// Remove the '_'
+				var i = txt.IndexOf ('_');
+				var start = txt [0, i];
+				txt = start + txt [i + 1, txt.Length];
+
+				// Move over one or go to start
+				i++;
+				if (i >= txt.Length) {
+					i = 0;
+				}
+
+				// Slip in the '_'
+				start = txt [0, i];
+				txt = start + ustring.Make ('_') + txt [i, txt.Length];
+
+				return txt;
+			}
+
 			y += 2;
 			y += 2;
-			var sizeBtn = new Button (10, y, "Grow TextField via Frame") {
-				ColorScheme = Colors.Error,
+			var moveHotKeyBtn = new Button (10, y, "Click to Change th_is Button's Hotkey") {
+				ColorScheme = Colors.TopLevel,
 			};
 			};
-			sizeBtn.Clicked = () => {
-				edit.Frame = new Rect (edit.Frame.X, edit.Frame.Y, edit.Frame.Width + 2, edit.Frame.Height);
-				Win.LayoutSubviews ();
+			moveHotKeyBtn.Clicked = () => {
+				moveHotKeyBtn.Text = MoveHotkey (moveHotKeyBtn.Text);
 			};
 			};
-			Win.Add (sizeBtn);
-
+			Win.Add (moveHotKeyBtn);
 		}
 		}
 	}
 	}
 }
 }

+ 171 - 0
UICatalog/Scenarios/Dialogs.cs

@@ -0,0 +1,171 @@
+using NStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Terminal.Gui;
+
+namespace UICatalog {
+	[ScenarioMetadata (Name: "Dialogs", Description: "Demonstrates how to the Dialog class")]
+	[ScenarioCategory ("Controls")]
+	[ScenarioCategory ("Dialogs")]
+	class Dialogs : Scenario {
+		public override void Setup ()
+		{
+			var frame = new FrameView ("Dialog Options") {
+				X = Pos.Center(),
+				Y = 1,
+				Width = Dim.Percent(75),
+				Height = 10
+			};
+			Win.Add (frame);
+
+			var label = new Label ("width:") {
+				X = 0,
+				Y = 0,
+				Width = 15,
+				Height = 1,
+				TextAlignment = Terminal.Gui.TextAlignment.Right,
+			};
+			frame.Add (label);
+			var widthEdit = new TextField ("0") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 5,
+				Height = 1
+			};
+			frame.Add (widthEdit);
+
+			label = new Label ("height:") {
+				X = 0,
+				Y = Pos.Bottom (label),
+				Width = Dim.Width(label),
+				Height = 1,
+				TextAlignment = Terminal.Gui.TextAlignment.Right,
+			};
+			frame.Add (label);
+			var heightEdit = new TextField ("0") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 5,
+				Height = 1
+			};
+			frame.Add (heightEdit);
+
+			frame.Add (new Label ("If height & width are both 0,") {
+				X = Pos.Right (widthEdit) + 2,
+				Y = Pos.Top (widthEdit),
+			});
+			frame.Add (new Label ("the Dialog will size to 80% of container.") {
+				X = Pos.Right (heightEdit) + 2,
+				Y = Pos.Top (heightEdit),
+			});
+
+			label = new Label ("Title:") {
+				X = 0,
+				Y = Pos.Bottom (label),
+				Width = Dim.Width (label),
+				Height = 1,
+				TextAlignment = Terminal.Gui.TextAlignment.Right,
+			};
+			frame.Add (label);
+			var titleEdit = new TextField ("Title") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = Dim.Fill(),
+				Height = 1
+			};
+			frame.Add (titleEdit);
+
+			label = new Label ("Num Buttons:") {
+				X = 0,
+				Y = Pos.Bottom (titleEdit),
+				Width = Dim.Width (label),
+				Height = 1,
+				TextAlignment = Terminal.Gui.TextAlignment.Right,
+			};
+			frame.Add (label);
+			var numButtonsEdit = new TextField ("3") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 5,
+				Height = 1
+			};
+			frame.Add (numButtonsEdit);
+
+			frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) 
+				+ Dim.Height(numButtonsEdit) + 2;
+
+			label = new Label ("Button Pressed:") {
+				X = Pos.Center (),
+				Y = Pos.Bottom (frame) + 2,
+				Height = 1,
+				TextAlignment = Terminal.Gui.TextAlignment.Right,
+			};
+			Win.Add (label);
+			var buttonPressedLabel = new Label ("") {
+				X = Pos.Center (),
+				Y = Pos.Bottom (frame) + 4,
+				Width = 25,
+				Height = 1,
+				ColorScheme = Colors.Error,
+			};
+
+			var btnText = new [] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };
+			var showDialogButton = new Button ("Show Dialog") {
+				X = Pos.Center(),
+				Y = Pos.Bottom (frame) + 2			,
+				IsDefault = true,
+				Clicked = () => {
+					try {
+						int width = int.Parse (widthEdit.Text.ToString ());
+						int height = int.Parse (heightEdit.Text.ToString ());
+						int numButtons = int.Parse (numButtonsEdit.Text.ToString ());
+
+						var buttons = new List<Button> ();
+						var clicked = -1;
+						for (int i = 0; i < numButtons; i++) {
+							var buttonId = i;
+							var button = new Button (btnText [buttonId % 10], is_default: buttonId == 0) {
+								Clicked = () => {
+									clicked = buttonId;
+									Application.RequestStop ();
+								},
+							};
+							buttons.Add(button);
+						}
+
+						// This tests dynamically adding buttons; ensuring the dialog resizes if needed and 
+						// the buttons are laid out correctly
+						var dialog = new Dialog (titleEdit.Text, width, height, buttons.ToArray ());
+						var add = new Button ("Add a button") {
+							X = Pos.Center (),
+							Y = Pos.Center (),
+							Clicked = () => {
+								var buttonId = buttons.Count;
+								var button = new Button (btnText [buttonId % 10], is_default: buttonId == 0) {
+									Clicked = () => {
+										clicked = buttonId;
+										Application.RequestStop ();
+									},
+								};
+								buttons.Add (button);
+								dialog.AddButton (button);
+							},
+						};
+						dialog.Add (add);
+
+						Application.Run (dialog);
+						buttonPressedLabel.Text = $"{clicked}";
+
+					} catch (FormatException) {
+						buttonPressedLabel.Text = "Invalid Options";
+					}
+				},
+			};
+			Win.Add (showDialogButton);
+
+			Win.Add (buttonPressedLabel);
+		}
+	}
+}

+ 4 - 4
UICatalog/Scenarios/Editor.cs

@@ -76,7 +76,7 @@ namespace UICatalog {
 		private void LoadFile ()
 		private void LoadFile ()
 		{
 		{
 			if (!_saved) {
 			if (!_saved) {
-				MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+				MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 			}
 			}
 
 
 			if (_fileName != null) {
 			if (_fileName != null) {
@@ -90,17 +90,17 @@ namespace UICatalog {
 
 
 		private void Paste ()
 		private void Paste ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 		}
 		}
 
 
 		private void Cut ()
 		private void Cut ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 		}
 		}
 
 
 		private void Copy ()
 		private void Copy ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 			//if (_textView != null && _textView.SelectedLength != 0) {
 			//if (_textView != null && _textView.SelectedLength != 0) {
 			//	_textView.Copy ();
 			//	_textView.Copy ();
 			//}
 			//}

+ 4 - 4
UICatalog/Scenarios/HexEditor.cs

@@ -69,7 +69,7 @@ namespace UICatalog {
 		{
 		{
 			MemoryStream stream = null;
 			MemoryStream stream = null;
 			if (!_saved) {
 			if (!_saved) {
-				MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+				MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 			}
 			}
 
 
 			if (_fileName != null) {
 			if (_fileName != null) {
@@ -83,17 +83,17 @@ namespace UICatalog {
 
 
 		private void Paste ()
 		private void Paste ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 		}
 		}
 
 
 		private void Cut ()
 		private void Cut ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 		}
 		}
 
 
 		private void Copy ()
 		private void Copy ()
 		{
 		{
-			MessageBox.ErrorQuery (0, 10, "Not Implemented", "Functionality not yet implemented.", "Ok");
+			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
 			//if (_textView != null && _textView.SelectedLength != 0) {
 			//if (_textView != null && _textView.SelectedLength != 0) {
 			//	_textView.Copy ();
 			//	_textView.Copy ();
 			//}
 			//}

+ 24 - 9
UICatalog/Scenarios/MessageBoxes.cs

@@ -18,7 +18,7 @@ namespace UICatalog {
 			};
 			};
 			Win.Add (frame);
 			Win.Add (frame);
 
 
-			var label = new Label ("Width:") {
+			var label = new Label ("width:") {
 				X = 0,
 				X = 0,
 				Y = 0,
 				Y = 0,
 				Width = 15,
 				Width = 15,
@@ -26,7 +26,7 @@ namespace UICatalog {
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 			};
 			};
 			frame.Add (label);
 			frame.Add (label);
-			var widthEdit = new TextField ("50") {
+			var widthEdit = new TextField ("0") {
 				X = Pos.Right (label) + 1,
 				X = Pos.Right (label) + 1,
 				Y = Pos.Top (label),
 				Y = Pos.Top (label),
 				Width = 5,
 				Width = 5,
@@ -34,7 +34,7 @@ namespace UICatalog {
 			};
 			};
 			frame.Add (widthEdit);
 			frame.Add (widthEdit);
 
 
-			label = new Label ("Height:") {
+			label = new Label ("height:") {
 				X = 0,
 				X = 0,
 				Y = Pos.Bottom (label),
 				Y = Pos.Bottom (label),
 				Width = Dim.Width(label),
 				Width = Dim.Width(label),
@@ -42,7 +42,7 @@ namespace UICatalog {
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 			};
 			};
 			frame.Add (label);
 			frame.Add (label);
-			var heightEdit = new TextField ("6") {
+			var heightEdit = new TextField ("0") {
 				X = Pos.Right (label) + 1,
 				X = Pos.Right (label) + 1,
 				Y = Pos.Top (label),
 				Y = Pos.Top (label),
 				Width = 5,
 				Width = 5,
@@ -50,6 +50,15 @@ namespace UICatalog {
 			};
 			};
 			frame.Add (heightEdit);
 			frame.Add (heightEdit);
 
 
+			frame.Add (new Label ("If height & width are both 0,") {
+				X = Pos.Right (widthEdit) + 2,
+				Y = Pos.Top (widthEdit),
+			});
+			frame.Add (new Label ("the MessageBox will be sized automatically.") {
+				X = Pos.Right (heightEdit) + 2,
+				Y = Pos.Top (heightEdit),
+			});
+
 			label = new Label ("Title:") {
 			label = new Label ("Title:") {
 				X = 0,
 				X = 0,
 				Y = Pos.Bottom (label),
 				Y = Pos.Bottom (label),
@@ -74,17 +83,19 @@ namespace UICatalog {
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 			};
 			};
 			frame.Add (label);
 			frame.Add (label);
-			var messageEdit = new TextField ("Message") {
+			var messageEdit = new TextView () {
+				Text = "Message",
 				X = Pos.Right (label) + 1,
 				X = Pos.Right (label) + 1,
 				Y = Pos.Top (label),
 				Y = Pos.Top (label),
 				Width = Dim.Fill (),
 				Width = Dim.Fill (),
-				Height = 1
+				Height = 5,
+				ColorScheme = Colors.Dialog,
 			};
 			};
 			frame.Add (messageEdit);
 			frame.Add (messageEdit);
 
 
 			label = new Label ("Num Buttons:") {
 			label = new Label ("Num Buttons:") {
 				X = 0,
 				X = 0,
-				Y = Pos.Bottom (label),
+				Y = Pos.Bottom (messageEdit),
 				Width = Dim.Width (label),
 				Width = Dim.Width (label),
 				Height = 1,
 				Height = 1,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
@@ -130,6 +141,8 @@ namespace UICatalog {
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
 			};
 			};
 
 
+			var btnText = new [] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };
+
 			var showMessageBoxButton = new Button ("Show MessageBox") {
 			var showMessageBoxButton = new Button ("Show MessageBox") {
 				X = Pos.Center(),
 				X = Pos.Center(),
 				Y = Pos.Bottom (frame) + 2			,
 				Y = Pos.Bottom (frame) + 2			,
@@ -139,21 +152,23 @@ namespace UICatalog {
 						int width = int.Parse (widthEdit.Text.ToString ());
 						int width = int.Parse (widthEdit.Text.ToString ());
 						int height = int.Parse (heightEdit.Text.ToString ());
 						int height = int.Parse (heightEdit.Text.ToString ());
 						int numButtons = int.Parse (numButtonsEdit.Text.ToString ());
 						int numButtons = int.Parse (numButtonsEdit.Text.ToString ());
+
 						var btns = new List<string> ();
 						var btns = new List<string> ();
 						for (int i = 0; i < numButtons; i++) {
 						for (int i = 0; i < numButtons; i++) {
-							btns.Add($"Btn {i}");
+							btns.Add(btnText[i % 10]);
 						}
 						}
 						if (styleRadioGroup.Selected == 0) {
 						if (styleRadioGroup.Selected == 0) {
 							buttonPressedLabel.Text = $"{MessageBox.Query (width, height, titleEdit.Text.ToString (), messageEdit.Text.ToString (), btns.ToArray ())}";
 							buttonPressedLabel.Text = $"{MessageBox.Query (width, height, titleEdit.Text.ToString (), messageEdit.Text.ToString (), btns.ToArray ())}";
 						} else {
 						} else {
 							buttonPressedLabel.Text = $"{MessageBox.ErrorQuery (width, height, titleEdit.Text.ToString (), messageEdit.Text.ToString (), btns.ToArray ())}";
 							buttonPressedLabel.Text = $"{MessageBox.ErrorQuery (width, height, titleEdit.Text.ToString (), messageEdit.Text.ToString (), btns.ToArray ())}";
 						}
 						}
-					} catch {
+					} catch (FormatException) {
 						buttonPressedLabel.Text = "Invalid Options";
 						buttonPressedLabel.Text = "Invalid Options";
 					}
 					}
 				},
 				},
 			};
 			};
 			Win.Add (showMessageBoxButton);
 			Win.Add (showMessageBoxButton);
+
 			Win.Add (buttonPressedLabel);
 			Win.Add (buttonPressedLabel);
 		}
 		}
 	}
 	}

+ 13 - 14
UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -32,21 +32,20 @@ namespace UICatalog {
 		{
 		{
 			static int About ()
 			static int About ()
 			{
 			{
-				//return MessageBox.Query (50, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")
+				return MessageBox.Query ("About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok");
 
 
-				var about = new Window (new Rect (0, 0, 50, 10), "About UI catalog", 0) {
-					X = Pos.Center (),
-					Y = Pos.Center (),
-					Width = 50,
-					Height = 10,
-					LayoutStyle = LayoutStyle.Computed,
-					ColorScheme = Colors.Error,
+				//var about = new Window (new Rect (0, 0, 50, 10), "About UI catalog", 0) {
+				//	X = Pos.Center (),
+				//	Y = Pos.Center (),
+				//	Width = 50,
+				//	Height = 10,
+				//	LayoutStyle = LayoutStyle.Computed,
+				//	ColorScheme = Colors.Error,
 
 
-				};
-				//about.Add (new Label ("UI Catalog is a comprehensive sample library for Terminal.Gui"));
+				//};
 
 
-				Application.Run (about);
-				return 0;
+				//Application.Run (about);
+				//return 0;
 
 
 			}
 			}
 
 
@@ -88,7 +87,7 @@ namespace UICatalog {
 					X = Pos.Center (),
 					X = Pos.Center (),
 					Y = 0,
 					Y = 0,
 					ColorScheme = Colors.Error,
 					ColorScheme = Colors.Error,
-					Clicked = () => MessageBox.ErrorQuery (30, 10, win.Title.ToString (), "Neat?", "Yes", "No")
+					Clicked = () => MessageBox.ErrorQuery (win.Title.ToString (), "Neat?", "Yes", "No")
 				});
 				});
 				var subWin = new Window ("Sub Window") {
 				var subWin = new Window ("Sub Window") {
 					X = Pos.Percent (0),
 					X = Pos.Percent (0),
@@ -128,7 +127,7 @@ namespace UICatalog {
 				X = Pos.Center (),
 				X = Pos.Center (),
 				Y = 0,
 				Y = 0,
 				ColorScheme = Colors.Error,
 				ColorScheme = Colors.Error,
-				//Clicked = () => MessageBox.ErrorQuery (30, 10, frame.Title.ToString (), "Neat?", "Yes", "No")
+				//Clicked = () => MessageBox.ErrorQuery (frame.Title.ToString (), "Neat?", "Yes", "No")
 			});
 			});
 			var subWinofFV = new Window ("this is a Sub-Window") {
 			var subWinofFV = new Window ("this is a Sub-Window") {
 				X = Pos.Percent (0),
 				X = Pos.Percent (0),

+ 9 - 1
UICatalog/UICatalog.cs

@@ -5,7 +5,10 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
+using System.Reflection;
+using System.Text;
 using Terminal.Gui;
 using Terminal.Gui;
+using Rune = System.Rune;
 
 
 /// <remarks>
 /// <remarks>
 /// <para>
 /// <para>
@@ -88,11 +91,16 @@ namespace UICatalog {
 		/// </summary>
 		/// </summary>
 		private static void Setup ()
 		private static void Setup ()
 		{
 		{
+			StringBuilder aboutMessage = new StringBuilder ();
+			aboutMessage.AppendLine ("UI Catalog is a comprehensive sample library for Terminal.Gui\n");
+			aboutMessage.AppendLine ($"Version: {typeof(UICatalogApp).Assembly.GetName ().Version}");
+			aboutMessage.Append ($"Using Terminal.Gui Version: {typeof (Terminal.Gui.Application).Assembly.GetName ().Version}\n");
+
 			_menu = new MenuBar (new MenuBarItem [] {
 			_menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 				}),
 				}),
-				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query (50, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")),
+				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query ("About UI Catalog", aboutMessage.ToString(), "Ok")),
 			});
 			});
 
 
 			_leftPane = new Window ("Categories") {
 			_leftPane = new Window ("Categories") {

+ 1 - 0
UICatalog/UICatalog.csproj

@@ -4,6 +4,7 @@
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
+    <AssemblyVersion>1.0.0.1</AssemblyVersion>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>