瀏覽代碼

Fixes #1979. MessageBox.Query not wrapping since 1.7.1 (#1995)

* Added MaxWidthLine into the TextFormatter class.

* Some more test line to better verifying the mainloop idle handlers.

* Fixes #1979. MessageBox.Query not wrapping since 1.7.1

* Added MessageBox unit tests.

* States a button centered issue on a lower fixed size.

* Fixed the centered button issue 4d0a4b6.
BDisp 2 年之前
父節點
當前提交
ff1eb9bea1

+ 12 - 0
Terminal.Gui/Core/TextFormatter.cs

@@ -835,6 +835,18 @@ namespace Terminal.Gui {
 			return max;
 		}
 
+		/// <summary>
+		/// Determines the line with the highest width in the 
+		/// <paramref name="text"/> if it contains newlines.
+		/// </summary>
+		/// <param name="text">Text, may contain newlines.</param>
+		/// <returns>The highest line width.</returns>
+		public static int MaxWidthLine (ustring text)
+		{
+			var result = TextFormatter.SplitNewLine (text);
+			return result.Max (x => x.ConsoleWidth);
+		}
+
 		/// <summary>
 		/// Gets the total width of the passed text.
 		/// </summary>

+ 1 - 2
Terminal.Gui/Windows/Dialog.cs

@@ -160,7 +160,7 @@ namespace Terminal.Gui {
 			switch (ButtonAlignment) {
 			case ButtonAlignments.Center:
 				// Center Buttons
-				shiftLeft = Math.Max ((Bounds.Width - buttonsWidth - buttons.Count - 2) / 2 + 1, 0);
+				shiftLeft = (Bounds.Width - buttonsWidth - buttons.Count - 2) / 2 + 1;
 				for (int i = buttons.Count - 1; i >= 0; i--) {
 					Button button = buttons [i];
 					shiftLeft += button.Frame.Width + (i == buttons.Count - 1 ? 0 : 1);
@@ -231,6 +231,5 @@ namespace Terminal.Gui {
 			}
 			return base.ProcessKey (kb);
 		}
-
 	}
 }

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

@@ -1,7 +1,6 @@
 using NStack;
 using System;
 using System.Collections.Generic;
-using System.Linq;
 
 namespace Terminal.Gui {
 	/// <summary>
@@ -240,7 +239,16 @@ namespace Terminal.Gui {
 			int defaultButton = 0, Border border = null, params ustring [] buttons)
 		{
 			const int defaultWidth = 50;
-			int textWidth = TextFormatter.MaxWidth (message, width == 0 ? defaultWidth : width);
+			int maxWidthLine = TextFormatter.MaxWidthLine (message);
+			if (maxWidthLine > Application.Driver.Cols) {
+				maxWidthLine = Application.Driver.Cols;
+			}
+			if (width == 0) {
+				maxWidthLine = Math.Max (maxWidthLine, defaultWidth);
+			} else {
+				maxWidthLine = width;
+			}
+			int textWidth = TextFormatter.MaxWidth (message, maxWidthLine);
 			int textHeight = TextFormatter.MaxLines (message, textWidth); // message.Count (ustring.Make ('\n')) + 1;
 			int msgboxHeight = Math.Max (1, textHeight) + 4; // textHeight + (top + top padding + buttons + bottom)
 
@@ -262,10 +270,11 @@ namespace Terminal.Gui {
 			// 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;
+				d = new Dialog (title, buttonList.ToArray ()) {
+					Height = msgboxHeight
+				};
 			} else {
-				d = new Dialog (title, Math.Max (width, textWidth) + 4, height, buttonList.ToArray ());
+				d = new Dialog (title, width, Math.Max (height, 4), buttonList.ToArray ());
 			}
 
 			if (border != null) {
@@ -277,19 +286,22 @@ namespace Terminal.Gui {
 			}
 
 			if (message != null) {
-				var l = new Label (textWidth > width ? 0 : (width - 4 - textWidth) / 2, 1, message);
-				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 (1);
+				var l = new Label (message) {
+					LayoutStyle = LayoutStyle.Computed,
+					TextAlignment = TextAlignment.Centered,
+					X = Pos.Center (),
+					Y = Pos.Center (),
+					Width = Dim.Fill (),
+					Height = Dim.Fill (1),
+					AutoSize = false
+				};
 				d.Add (l);
 			}
 
-			// Dynamically size Width
-			int msgboxWidth = Math.Max (defaultWidth, Math.Max (title.RuneCount + 8, Math.Max (textWidth + 4, d.GetButtonsWidth ()) + 8)); // textWidth + (left + padding + padding + right)
-			d.Width = msgboxWidth;
+			if (width == 0 & height == 0) {
+				// Dynamically size Width
+				d.Width = Math.Max (maxWidthLine, Math.Max (title.ConsoleWidth, Math.Max (textWidth + 2, d.GetButtonsWidth ()))); // textWidth + (left + padding + padding + right)
+			}
 
 			// Setup actions
 			Clicked = -1;

+ 22 - 2
UnitTests/MainLoopTests.cs

@@ -29,12 +29,18 @@ namespace Terminal.Gui.Core {
 		{
 			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 
-			Func<bool> fnTrue = () => { return true; };
-			Func<bool> fnFalse = () => { return false; };
+			Func<bool> fnTrue = () => true;
+			Func<bool> fnFalse = () => false;
+
 			ml.AddIdle (fnTrue);
 			ml.AddIdle (fnFalse);
 
+			Assert.Equal (2, ml.IdleHandlers.Count);
+			Assert.Equal (fnTrue, ml.IdleHandlers [0]);
+			Assert.NotEqual (fnFalse, ml.IdleHandlers [0]);
+
 			Assert.True (ml.RemoveIdle (fnTrue));
+			Assert.Single (ml.IdleHandlers);
 
 			// BUGBUG: This doesn't throw or indicate an error. Ideally RemoveIdle would either 
 			// throw an exception in this case, or return an error.
@@ -52,8 +58,19 @@ namespace Terminal.Gui.Core {
 			ml.AddIdle (fnTrue);
 			ml.AddIdle (fnTrue);
 
+			Assert.Equal (2, ml.IdleHandlers.Count);
+			Assert.Equal (fnTrue, ml.IdleHandlers [0]);
+			Assert.True (ml.IdleHandlers [0] ());
+			Assert.Equal (fnTrue, ml.IdleHandlers [1]);
+			Assert.True (ml.IdleHandlers [1] ());
+
 			Assert.True (ml.RemoveIdle (fnTrue));
+			Assert.Single (ml.IdleHandlers);
+			Assert.Equal (fnTrue, ml.IdleHandlers [0]);
+			Assert.NotEqual (fnFalse, ml.IdleHandlers [0]);
+
 			Assert.True (ml.RemoveIdle (fnTrue));
+			Assert.Empty (ml.IdleHandlers);
 
 			// BUGBUG: This doesn't throw an exception or indicate an error. Ideally RemoveIdle would either 
 			// throw an exception in this case, or return an error.
@@ -125,14 +142,17 @@ namespace Terminal.Gui.Core {
 			ml.AddIdle (fn);
 			ml.MainIteration ();
 			Assert.Equal (2, functionCalled);
+			Assert.Equal (2, ml.IdleHandlers.Count);
 
 			functionCalled = 0;
 			Assert.True (ml.RemoveIdle (fn));
+			Assert.Single (ml.IdleHandlers);
 			ml.MainIteration ();
 			Assert.Equal (1, functionCalled);
 
 			functionCalled = 0;
 			Assert.True (ml.RemoveIdle (fn));
+			Assert.Empty (ml.IdleHandlers);
 			ml.MainIteration ();
 			Assert.Equal (0, functionCalled);
 			Assert.False (ml.RemoveIdle (fn));

+ 158 - 0
UnitTests/MessageBoxTests.cs

@@ -0,0 +1,158 @@
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+using System.Text;
+
+namespace Terminal.Gui.Views {
+
+	public class MessageBoxTests {
+		readonly ITestOutputHelper output;
+
+		public MessageBoxTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
+		[Fact, AutoInitShutdown]
+		public void MessageBox_With_Empty_Size_Without_Buttons ()
+		{
+			var iterations = -1;
+			Application.Begin (Application.Top);
+
+			Application.Iteration += () => {
+				iterations++;
+
+				if (iterations == 0) {
+					MessageBox.Query ("Title", "Message");
+
+					Application.RequestStop ();
+
+				} else if (iterations == 1) {
+					Application.Top.Redraw (Application.Top.Bounds);
+					GraphViewTests.AssertDriverContentsWithFrameAre (@"
+               ┌ Title ─────────────────────────────────────────┐
+               │                    Message                     │
+               │                                                │
+               │                                                │
+               └────────────────────────────────────────────────┘
+", output);
+
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+		}
+
+		[Fact, AutoInitShutdown]
+		public void MessageBox_With_Empty_Size_With_Button ()
+		{
+			var iterations = -1;
+			Application.Begin (Application.Top);
+
+			Application.Iteration += () => {
+				iterations++;
+
+				if (iterations == 0) {
+					StringBuilder aboutMessage = new StringBuilder ();
+					aboutMessage.AppendLine (@"A comprehensive sample library for");
+					aboutMessage.AppendLine (@"");
+					aboutMessage.AppendLine (@"  _______                  _             _   _____       _  ");
+					aboutMessage.AppendLine (@" |__   __|                (_)           | | / ____|     (_) ");
+					aboutMessage.AppendLine (@"    | | ___ _ __ _ __ ___  _ _ __   __ _| || |  __ _   _ _  ");
+					aboutMessage.AppendLine (@"    | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | | ");
+					aboutMessage.AppendLine (@"    | |  __/ |  | | | | | | | | | | (_| | || |__| | |_| | | ");
+					aboutMessage.AppendLine (@"    |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_| ");
+					aboutMessage.AppendLine (@"");
+					aboutMessage.AppendLine (@"https://github.com/gui-cs/Terminal.Gui");
+
+					MessageBox.Query ("About UI Catalog", aboutMessage.ToString (), "_Ok");
+
+					Application.RequestStop ();
+				} else if (iterations == 1) {
+					Application.Top.Redraw (Application.Top.Bounds);
+					GraphViewTests.AssertDriverContentsWithFrameAre (@"
+         ┌ About UI Catalog ──────────────────────────────────────────┐
+         │             A comprehensive sample library for             │
+         │                                                            │
+         │  _______                  _             _   _____       _  │
+         │ |__   __|                (_)           | | / ____|     (_) │
+         │    | | ___ _ __ _ __ ___  _ _ __   __ _| || |  __ _   _ _  │
+         │    | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | | │
+         │    | |  __/ |  | | | | | | | | | | (_| | || |__| | |_| | | │
+         │    |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_| │
+         │                                                            │
+         │           https://github.com/gui-cs/Terminal.Gui           │
+         │                                                            │
+         │                          [◦ Ok ◦]                          │
+         └────────────────────────────────────────────────────────────┘
+", output);
+
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+		}
+
+		[Fact, AutoInitShutdown]
+		public void MessageBox_With_A_Lower_Fixed_Size ()
+		{
+			var iterations = -1;
+			Application.Begin (Application.Top);
+
+			Application.Iteration += () => {
+				iterations++;
+
+				if (iterations == 0) {
+					MessageBox.Query (7, 5, "Title", "Message", "_Ok");
+
+					Application.RequestStop ();
+				} else if (iterations == 1) {
+					Application.Top.Redraw (Application.Top.Bounds);
+					GraphViewTests.AssertDriverContentsWithFrameAre (@"
+                                    ┌─────┐
+                                    │Messa│
+                                    │ ge  │
+                                    │ Ok ◦│
+                                    └─────┘
+", output);
+
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+		}
+
+		[Fact, AutoInitShutdown]
+		public void MessageBox_With_A_Enough_Fixed_Size ()
+		{
+			var iterations = -1;
+			Application.Begin (Application.Top);
+
+			Application.Iteration += () => {
+				iterations++;
+
+				if (iterations == 0) {
+					MessageBox.Query (11, 5, "Title", "Message", "_Ok");
+
+					Application.RequestStop ();
+				} else if (iterations == 1) {
+					Application.Top.Redraw (Application.Top.Bounds);
+					GraphViewTests.AssertDriverContentsWithFrameAre (@"
+                                  ┌ Title ──┐
+                                  │ Message │
+                                  │         │
+                                  │[◦ Ok ◦] │
+                                  └─────────┘
+", output);
+
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+		}
+	}
+}

+ 10 - 0
UnitTests/TextFormatterTests.cs

@@ -4054,5 +4054,15 @@ e
 			Assert.Equal ("Third Line 界", splited [2]);
 			Assert.Equal ("", splited [^1]);
 		}
+
+		[Fact]
+		public void MaxWidthLine_With_And_Without_Newlines ()
+		{
+			var text = "Single Line 界";
+			Assert.Equal (14, TextFormatter.MaxWidthLine (text));
+
+			text = $"First Line 界\nSecond Line 界\nThird Line 界\n";
+			Assert.Equal (14, TextFormatter.MaxWidthLine (text));
+		}
 	}
 }