Browse Source

Merge branch 'mondo_onlayoutcomplete_clip_msgboxdlg' of tig:tig/gui.cs

Charlie Kindel 5 years ago
parent
commit
3e02b9e1ef

+ 1 - 1
Example/demo.cs

@@ -638,7 +638,7 @@ static class Demo {
 		var bottom2 = new Label ("This should go on the bottom of another top-level!");
 		top.Add (bottom2);
 
-		Application.Loaded += (sender, e) => {
+		top.LayoutComplete += (sender, e) => {
 			bottom.X = win.X;
 			bottom.Y = Pos.Bottom (win) - Pos.Top (win) - margin;
 			bottom2.X = Pos.Left (win);

+ 1 - 0
Terminal.Gui/Core/Application.cs

@@ -481,6 +481,7 @@ namespace Terminal.Gui {
 			if (closeDriver) {
 				MainLoop = null;
 				Driver.End ();
+				Driver = null;
 			}
 
 			_initialized = false;

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

@@ -264,7 +264,7 @@ namespace Terminal.Gui {
 			if (IsCurrentTop || this == Application.Top) {
 				if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
 					Driver.SetAttribute (Colors.TopLevel.Normal);
-					Clear (bounds);
+					Clear (Frame);
 					Driver.SetAttribute (Colors.Base.Normal);
 				}
 				foreach (var view in Subviews) {

+ 38 - 3
Terminal.Gui/Core/View.cs

@@ -911,9 +911,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Redraws this view and its subviews; only redraws the views that have been flagged for a re-display.
 		/// </summary>
-		/// <param name="bounds">The view-relative region to redraw.</param>
+		/// <param name="bounds">The bounds (view-relative region) to redraw.</param>
 		/// <remarks>
 		/// <para>
+		///    Always use <see cref="Bounds"/> (view-relative) when calling <see cref="Redraw(Rect)"/>, NOT <see cref="Frame"/> (superview-relative).
+		/// </para>
+		/// <para>
 		///    Views should set the color that they want to use on entry, as otherwise this will inherit
 		///    the last color that was set globaly on the driver.
 		/// </para>
@@ -1318,15 +1321,45 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Invoked when a view starts executing or
-		/// when the dimensions of the view have changed, for example in
+		/// Event arguments for the <see cref="LayoutComplete"/> event.
+		/// </summary>
+		public class LayoutEventArgs : EventArgs {
+			/// <summary>
+			/// The view-relative bounds of the <see cref="View"/> before it was laid out.
+			/// </summary>
+			public Rect OldBounds { get; set; }
+		}
+
+		/// <summary>
+		/// Fired after the Views's <see cref="LayoutSubviews"/> method has completed. 
+		/// </summary>
+		/// <remarks>
+		/// Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has otherwise changed.
+		/// </remarks>
+		public event EventHandler<LayoutEventArgs> LayoutComplete;
+
+		/// <summary>
+		/// Raises the <see cref="LayoutComplete"/> event. Called from  <see cref="LayoutSubviews"/> after all sub-views have been laid out.
+		/// </summary>
+		internal virtual void OnLayoutComplete (LayoutEventArgs args)
+		{
+			LayoutComplete?.Invoke (this, args);
+		}
+
+		/// <summary>
+		/// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
 		/// response to the container view or terminal resizing.
 		/// </summary>
+		/// <remarks>
+		/// Calls <see cref="OnLayoutComplete"/> (which raises the <see cref="LayoutComplete"/> event) before it returns.
+		/// </remarks>
 		public virtual void LayoutSubviews ()
 		{
 			if (!layoutNeeded)
 				return;
 
+			Rect oldBounds = Bounds;
+
 			// Sort out the dependencies of the X, Y, Width, Height properties
 			var nodes = new HashSet<View> ();
 			var edges = new HashSet<(View, View)> ();
@@ -1363,6 +1396,8 @@ namespace Terminal.Gui {
 			}
 
 			layoutNeeded = false;
+
+			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 		}
 
 		/// <inheritdoc cref="ToString"/>

+ 1 - 1
Terminal.Gui/Views/ComboBox.cs

@@ -58,7 +58,7 @@ namespace Terminal.Gui {
 					SetValue (searchset [listview.SelectedItem]);
 			};
 
-			Application.Loaded += (object sender, Application.ResizedEventArgs e) => {
+			LayoutComplete += (sender, a) => {
 				// Determine if this view is hosted inside a dialog
 				for (View view = this.SuperView; view != null; view = view.SuperView) {
 					if (view is Dialog) {

+ 2 - 0
Terminal.Gui/Views/Label.cs

@@ -99,6 +99,8 @@ namespace Terminal.Gui {
 
 		static ustring ClipAndJustify (ustring str, int width, TextAlignment talign)
 		{
+			// Get rid of any '\r' added by Windows
+			str = str.Replace ("\r", ustring.Empty);
 			int slen = str.RuneCount;
 			if (slen > width){
 				var uints = str.ToRunes (width);

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

@@ -120,7 +120,7 @@ namespace Terminal.Gui {
 			Width = Dim.Fill ();
 			Height = 1;
 
-			Application.Loaded += (sender, e) => {
+			LayoutComplete += (sender, e) => {
 				X = 0;
 				Height = 1;
 #if SNAP_TO_TOP
@@ -132,7 +132,7 @@ namespace Terminal.Gui {
 				case StatusBarStyle.SnapToBottom:
 #endif
 					if (Parent == null) {
-						Y = e.Rows - 1; 
+						Y = Driver.Rows - 1; 
 					} else {
 						Y = Pos.Bottom (Parent);
 					}

+ 4 - 3
Terminal.Gui/Windows/Dialog.cs

@@ -61,6 +61,8 @@ namespace Terminal.Gui {
 					Add (b);
 				}
 			}
+
+			//LayoutComplete += (sender, a) => AdjustButtonLayout ();
 		}
 
 		/// <summary>
@@ -98,14 +100,13 @@ namespace Terminal.Gui {
 			}
 			return buttons.Select (b => b.Bounds.Width).Sum () + buttons.Count() - 1;
 		}
-
 		///<inheritdoc cref="LayoutSubviews"/>
 		public override void LayoutSubviews ()
 		{
 			int buttonsWidth = GetButtonsWidth ();
 
-			int shiftLeft = Math.Max((Bounds.Width - buttonsWidth) / 2 - 2, 0);
-			for (int i = buttons.Count - 1; i >= 0 ; i--) {
+			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);

+ 7 - 11
Terminal.Gui/Windows/MessageBox.cs

@@ -91,12 +91,11 @@ namespace Terminal.Gui {
 			return QueryFull (true, 0, 0, title, message, buttons);
 		}
 
-
 		static int QueryFull (bool useErrorColors, int width, int height, ustring title, ustring message, params ustring [] buttons)
 		{
 			const int defaultWidth = 30;
 			int textWidth = Label.MaxWidth (message, width);
-			int textHeight = message.Count(ustring.Make('\n')) + 1;
+			int textHeight = message.Count (ustring.Make ('\n')) + 1;
 			int msgboxHeight = Math.Max (1, textHeight) + 4; // textHeight + (top + top padding + buttons + bottom)
 
 			// Create button array for Dialog
@@ -126,15 +125,12 @@ namespace Terminal.Gui {
 
 			if (message != null) {
 				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);
-				}
+				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);
 			}
 

+ 1 - 1
UICatalog/Scenarios/ComputedLayout.cs

@@ -42,7 +42,7 @@ namespace UICatalog {
 				ColorScheme = Colors.Error
 			};
 
-			Application.Resized += (sender, a) => {
+			Win.LayoutComplete += (sender, a) => {
 				horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
 				verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height*2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height*2)];
 			};

+ 3 - 2
UICatalog/Scenarios/Scrolling.cs

@@ -121,8 +121,9 @@ namespace UICatalog {
 			};
 			scrollView.Add (verticalRuler);
 
-			Application.Resized += (sender, a) => {
-				horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
+			Win.LayoutComplete += (sender, a) => {
+				horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)] +
+				"\n" + "|         ".Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
 				verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height * 2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height * 2)];
 			};
 

+ 1 - 0
UICatalog/Scenarios/SystemConsole.cs

@@ -14,6 +14,7 @@ namespace UICatalog {
 		public override void RequestStop ()
 		{
 			base.RequestStop ();
+			Application.UseSystemConsole = false;
 		}
 
 		public override void Run ()

+ 61 - 74
UICatalog/UICatalog.cs

@@ -58,6 +58,8 @@ namespace UICatalog {
 		private static StatusItem _scrolllock;
 
 		private static Scenario _runningScenario = null;
+		private static bool _useSystemConsole = false;
+		private static MenuItem _sysConsoleMenu;
 
 		static void Main (string [] args)
 		{
@@ -79,6 +81,7 @@ namespace UICatalog {
 
 			Scenario scenario = GetScenarioToRun ();
 			while (scenario != null) {
+				Application.UseSystemConsole = _useSystemConsole;
 				Application.Init ();
 				scenario.Init (Application.Top);
 				scenario.Setup ();
@@ -89,20 +92,65 @@ namespace UICatalog {
 			Application.Shutdown ();
 		}
 
+		/// <summary>
+		/// This shows the selection UI. Each time it is run, it calls Application.Init to reset everything.
+		/// </summary>
+		/// <returns></returns>
+		private static Scenario GetScenarioToRun ()
+		{
+			Application.UseSystemConsole = false;
+			Application.Init ();
+
+			if (_menu == null) {
+				Setup ();
+			}
+
+			_top = Application.Top;
+
+			_top.KeyDown += KeyDownHandler;
+
+			_top.Add (_menu);
+			_top.Add (_leftPane);
+			_top.Add (_rightPane);
+			_top.Add (_statusBar);
+
+			_top.Ready += (o, a) => {
+				if (_runningScenario != null) {
+					_top.SetFocus (_rightPane);
+					_runningScenario = null;
+				}
+			};
+
+			Application.Run (_top, false);
+			Application.Shutdown ();
+			return _runningScenario;
+		}
+
+
 		/// <summary>
 		/// Create all controls. This gets called once and the controls remain with their state between Sceanrio runs.
 		/// </summary>
 		private static void Setup ()
 		{
 			StringBuilder aboutMessage = new StringBuilder ();
-			aboutMessage.AppendLine ("UI Catalog is a comprehensive sample library for Terminal.Gui\n");
+			aboutMessage.AppendLine ("UI Catalog is a comprehensive sample library for Terminal.Gui");
+			aboutMessage.AppendLine ("");
 			aboutMessage.AppendLine ($"Version: {typeof(UICatalogApp).Assembly.GetName ().Version}");
-			aboutMessage.Append ($"Using Terminal.Gui Version: {typeof (Terminal.Gui.Application).Assembly.GetName ().Version}\n");
+			aboutMessage.AppendLine ($"Using Terminal.Gui Version: {typeof (Terminal.Gui.Application).Assembly.GetName ().Version}");
+			aboutMessage.AppendLine ("");
+
+			void HandleSysConsoleMenuChange ()
+			{
+				_useSystemConsole = !_useSystemConsole;
+				_sysConsoleMenu.Title = $"[{(_useSystemConsole ? 'x' : ' ')}] _Use System Console";
+			}
+			_sysConsoleMenu = new MenuItem ($"[{(_useSystemConsole ? 'x' : ' ')}] _Use System Console", "", () => HandleSysConsoleMenuChange ());
 
 			_menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 				}),
+				new MenuBarItem ("_Settings", new MenuItem [] { _sysConsoleMenu }),
 				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query ("About UI Catalog", aboutMessage.ToString(), "Ok")),
 			});
 
@@ -150,24 +198,17 @@ namespace UICatalog {
 				CanFocus = true,
 			};
 
-			//_scenarioListView.OnKeyPress += (KeyEvent ke) => {
-			//	if (_top.MostFocused == _scenarioListView && ke.Key == Key.Enter) {
-			//		_scenarioListView_OpenSelectedItem (null, null);
-			//	}
-			//};
-
 			_scenarioListView.OpenSelectedItem += _scenarioListView_OpenSelectedItem;
 			_rightPane.Add (_scenarioListView);
 
 			_categoryListView.SelectedItem = 0;
 			_categoryListView.OnSelectedChanged ();
 
-			_capslock = new StatusItem (Key.CharMask, "CapslockOff", null);
-			_numlock = new StatusItem (Key.CharMask, "NumlockOff", null);
-			_scrolllock = new StatusItem (Key.CharMask, "ScrolllockOff", null);
+			_capslock = new StatusItem (Key.CharMask, "Capslock", null);
+			_numlock = new StatusItem (Key.CharMask, "Numlock", null);
+			_scrolllock = new StatusItem (Key.CharMask, "Scrolllock", null);
 
 			_statusBar = new StatusBar (new StatusItem [] {
-				//new StatusItem(Key.F1, "~F1~ Help", () => Help()),
 				new StatusItem(Key.ControlQ, "~CTRL-Q~ Quit", () => {
 					if (_runningScenario is null){
 						// This causes GetScenarioToRun to return null
@@ -183,51 +224,6 @@ namespace UICatalog {
 			});
 		}
 
-		/// <summary>
-		/// This shows the selection UI. Each time it is run, it calls Application.Init to reset everything.
-		/// </summary>
-		/// <returns></returns>
-		private static Scenario GetScenarioToRun ()
-		{
-			Application.Init ();
-
-			if (_menu == null) {
-				Setup ();
-			}
-
-			_top = Application.Top;
-
-			_top.KeyDown += KeyDownHandler;
-
-			_top.Add (_menu);
-			_top.Add (_leftPane);
-			_top.Add (_rightPane);
-			_top.Add (_statusBar);
-
-			// HACK: There is no other way to SetFocus before Application.Run. See Issue #445
-#if false
-			if (_runningScenario != null)
-				Application.Iteration += Application_Iteration;
-#else
-			_top.Ready += (o, a) => {
-				if (_runningScenario != null) {
-					_top.SetFocus (_rightPane);
-					_runningScenario = null;
-				}
-			};
-#endif
-			
-			Application.Run (_top, false);
-			return _runningScenario;
-		}
-
-#if false
-		private static void Application_Iteration (object sender, EventArgs e)
-		{
-			Application.Iteration -= Application_Iteration;
-			_top.SetFocus (_rightPane);
-		}
-#endif
 		private static void _scenarioListView_OpenSelectedItem (object sender, EventArgs e)
 		{
 			if (_runningScenario is null) {
@@ -240,7 +236,7 @@ namespace UICatalog {
 		internal class ScenarioListDataSource : IListDataSource {
 			public List<Type> Scenarios { get; set; }
 
-			public bool IsMarked (int item) => false;//  Scenarios [item].IsMarked;
+			public bool IsMarked (int item) => false;
 
 			public int Count => Scenarios.Count;
 
@@ -282,7 +278,6 @@ namespace UICatalog {
 			{
 				return Scenarios;
 			}
-
 		}
 
 		/// <summary>
@@ -293,15 +288,7 @@ namespace UICatalog {
 		/// <param name="ke"></param>
 		private static void KeyDownHandler (object sender, View.KeyEventEventArgs a)
 		{
-			if (_runningScenario != null) {
-				//switch (ke.Key) {
-				//case Key.Esc:
-				//	//_runningScenario.RequestStop ();
-				//	break;
-				//case Key.Enter:
-				//	break;
-				//}<
-			} else if (a.KeyEvent.Key == Key.Tab || a.KeyEvent.Key == Key.BackTab) {
+			if (a.KeyEvent.Key == Key.Tab || a.KeyEvent.Key == Key.BackTab) {
 				// BUGBUG: Work around Issue #434 by implementing our own TAB navigation
 				if (_top.MostFocused == _categoryListView)
 					_top.SetFocus (_rightPane);
@@ -310,26 +297,26 @@ namespace UICatalog {
 			}
 
 			if (a.KeyEvent.IsCapslock) {
-				_capslock.Title = "CapslockOn";
+				_capslock.Title = "Capslock: On";
 				_statusBar.SetNeedsDisplay ();
 			} else {
-				_capslock.Title = "CapslockOff";
+				_capslock.Title = "Capslock: Off";
 				_statusBar.SetNeedsDisplay ();
 			}
 
 			if (a.KeyEvent.IsNumlock) {
-				_numlock.Title = "NumlockOn";
+				_numlock.Title = "Numlock: On";
 				_statusBar.SetNeedsDisplay ();
 			} else {
-				_numlock.Title = "NumlockOff";
+				_numlock.Title = "Numlock: Off";
 				_statusBar.SetNeedsDisplay ();
 			}
 
 			if (a.KeyEvent.IsScrolllock) {
-				_scrolllock.Title = "ScrolllockOn";
+				_scrolllock.Title = "Scrolllock: On";
 				_statusBar.SetNeedsDisplay ();
 			} else {
-				_scrolllock.Title = "ScrolllockOff";
+				_scrolllock.Title = "Scrolllock: Off";
 				_statusBar.SetNeedsDisplay ();
 			}
 		}