Browse Source

merge from master

Charlie Kindel 5 years ago
parent
commit
a1efbb8ed3

+ 5 - 3
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -243,7 +243,7 @@ namespace Terminal.Gui {
 								break;
 							if (IsButtonPressed && LastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
 								mouseHandler (me);
-								mainLoop.Driver.Wakeup ();
+								//mainLoop.Driver.Wakeup ();
 							}
 						}
 					});
@@ -368,7 +368,7 @@ namespace Terminal.Gui {
 			};
 		}
 
-		void ProcessInput (Action<KeyEvent> keyHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
+		void ProcessInput (Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		{
 			int wch;
 			var code = Curses.get_wch (out wch);
@@ -421,8 +421,10 @@ namespace Terminal.Gui {
 					keyHandler (new KeyEvent (Key.Esc));
 				}
 			} else if (wch == Curses.KeyTab) {
+				keyDownHandler (new KeyEvent (MapCursesKey (wch)));
 				keyHandler (new KeyEvent (MapCursesKey (wch)));
 			} else {
+				keyDownHandler (new KeyEvent ((Key)wch));
 				keyHandler (new KeyEvent ((Key)wch));
 			}
 			// Cause OnKeyUp and OnKeyPressed. Note that the special handling for ESC above 
@@ -445,7 +447,7 @@ namespace Terminal.Gui {
 			this.mainLoop = mainLoop;
 
 			(mainLoop.Driver as  UnixMainLoop).AddWatch (0,  UnixMainLoop.Condition.PollIn, x => {
-				ProcessInput (keyHandler, keyUpHandler, mouseHandler);
+				ProcessInput (keyHandler, keyDownHandler, keyUpHandler, mouseHandler);
 				return true;
 			});
 

+ 1 - 1
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -189,7 +189,7 @@ namespace Terminal.Gui {
 					pollTimeout = 0;
 				}
 				n = poll (pollmap, (uint)pollmap.Length, pollTimeout);
-				if (pollmap != null) {
+				if (n > 0) {
 					break;
 				}
 				if (mainLoop.timeouts.Count > 0 || mainLoop.idleHandlers.Count > 0) {

+ 27 - 20
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -541,40 +541,29 @@ namespace Terminal.Gui {
 
 		void IMainLoopDriver.Wakeup ()
 		{
-			//tokenSource.Cancel ();
-			eventReady.Reset ();
-			eventReady.Set ();
+			tokenSource.Cancel ();
+			//eventReady.Reset ();
+			//eventReady.Set ();
 		}
 
 		bool IMainLoopDriver.EventsPending (bool wait)
 		{
-			long now = DateTime.UtcNow.Ticks;
-
-			int waitTimeout;
-			if (mainLoop.timeouts.Count > 0) {
-				waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
-				if (waitTimeout < 0)
-					return true;
-			} else
-				waitTimeout = -1;
+			int waitTimeout = 0;
 
-			if (!wait)
-				waitTimeout = 0;
+			if (CkeckTimeout (wait, ref waitTimeout))
+				return true;
 
 			result = null;
 			waitForProbe.Set ();
 
 			try {
 				while (result == null) {
-					if (wait && waitTimeout == -1) {
-						waitTimeout = 0;
-					}
 					if (!tokenSource.IsCancellationRequested)
-						eventReady.Wait (waitTimeout, tokenSource.Token);
+						eventReady.Wait (0, tokenSource.Token);
 					if (result != null) {
 						break;
 					}
-					if (mainLoop.timeouts.Count > 0 || mainLoop.idleHandlers.Count > 0) {
+					if (mainLoop.idleHandlers.Count > 0 || CkeckTimeout (wait, ref waitTimeout)) {
 						return true;
 					}
 				}
@@ -592,6 +581,24 @@ namespace Terminal.Gui {
 			return true;
 		}
 
+		bool CkeckTimeout (bool wait, ref int waitTimeout)
+		{
+			long now = DateTime.UtcNow.Ticks;
+
+			if (mainLoop.timeouts.Count > 0) {
+				waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
+				if (waitTimeout < 0)
+					return true;
+			} else {
+				waitTimeout = -1;
+			}
+
+			if (!wait)
+				waitTimeout = 0;
+
+			return false;
+		}
+
 		Action<KeyEvent> keyHandler;
 		Action<KeyEvent> keyDownHandler;
 		Action<KeyEvent> keyUpHandler;
@@ -780,7 +787,7 @@ namespace Terminal.Gui {
 								break;
 							if (IsButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
 								mouseHandler (me);
-								mainLoop.Driver.Wakeup ();
+								//mainLoop.Driver.Wakeup ();
 							}
 						}
 					});

+ 4 - 2
Terminal.Gui/Views/TextField.cs

@@ -36,8 +36,10 @@ namespace Terminal.Gui {
 		///   Changed event, raised when the text has clicked.
 		/// </summary>
 		/// <remarks>
-		///   Client code can hook up to this event, it is
-		///   raised when the text in the entry changes.
+		///   This event is raised when the <see cref="Text"/> changes. 
+		/// </remarks>
+		/// <remarks>
+		///   The passed <see cref="EventArgs"/> is a <see cref="ustring"/> containing the old value. 
 		/// </remarks>
 		public event EventHandler<ustring> Changed;
 

+ 19 - 6
UICatalog/Scenarios/Mouse.cs

@@ -7,20 +7,33 @@ namespace UICatalog {
 	[ScenarioMetadata (Name: "Mouse", Description: "Demonstrates how to capture mouse events")]
 	[ScenarioCategory ("Input")]
 	class Mouse : Scenario {
-		public override void Setup () {
+		public override void Setup ()
+		{
 			Label ml;
 			int count = 0;
 			ml = new Label (new Rect (1, 1, 50, 1), "Mouse: ");
-			Application.RootMouseEvent += delegate (MouseEvent me) {
-				ml.TextColor = Colors.TopLevel.Normal;
-				ml.Text = $"Mouse: ({me.X},{me.Y}) - {me.Flags} {count++}";
-			};
-
+			List<string> rme = new List<string> ();
 
 			var test = new Label (1, 2, "Se iniciará el análisis");
 			Win.Add (test);
 			Win.Add (ml);
 
+			var rmeList = new ListView (rme) {
+				X = Pos.Right (test) + 25,
+				Y = Pos.Top (test) + 1,
+				Width = Dim.Fill () - 1,
+				Height = Dim.Fill (),
+				ColorScheme = Colors.TopLevel
+			};
+			Win.Add (rmeList);
+
+			Application.RootMouseEvent += delegate (MouseEvent me) {
+				ml.TextColor = Colors.TopLevel.Normal;
+				ml.Text = $"Mouse: ({me.X},{me.Y}) - {me.Flags} {count}";
+				rme.Add ($"({me.X},{me.Y}) - {me.Flags} {count++}");
+				rmeList.MoveDown ();
+			};
+
 			// I have no idea what this was intended to show off in demo.c
 			var drag = new Label ("Drag: ") { X = 1, Y = 4 };
 			var dragText = new TextField ("") {

+ 208 - 73
UICatalog/Scenarios/Progress.cs

@@ -1,6 +1,8 @@
-using System;
+using NStack;
+using System;
 using System.Threading;
 using Terminal.Gui;
+using System.Linq;
 
 namespace UICatalog {
 	// 
@@ -8,102 +10,235 @@ namespace UICatalog {
 	//
 	[ScenarioMetadata (Name: "Progress", Description: "Shows off ProgressBar and Threading")]
 	[ScenarioCategory ("Controls")]
+	[ScenarioCategory ("MainLoop")]
 	[ScenarioCategory ("Threading")]
 	class Progress : Scenario {
 
-		private ProgressBar _activityProgressBar;
-		private ProgressBar _pulseProgressBar;
-		private Timer _timer;
-		private object _timeoutToken = null;
+		class ProgressDemo : FrameView {
+			const int _verticalSpace = 1;
+
+			internal FrameView LeftFrame { get; private set; }
+			internal TextField Speed { get; private set; }
+			internal ProgressBar ActivityProgressBar { get; private set; }
+			internal ProgressBar PulseProgressBar { get; private set; }
+			internal Action StartBtnClick;
+			internal Action StopBtnClick;
+			internal Action PulseBtnClick;
+			private Label _startedLabel;
+			internal bool Started { 
+				get { 
+					return _startedLabel.Text == "Started";
+				} 
+				private set {
+					_startedLabel.Text = value ? "Started" : "Stopped";
+				} 
+			}
+
+			internal ProgressDemo (ustring title) : base (title)
+			{
+				ColorScheme = Colors.Dialog;
+
+				LeftFrame = new FrameView ("Settings") {
+					X = 0,
+					Y = 0,
+					Height = Dim.Percent (100) + 1, // BUGBUG: This +1 should not be needed
+					Width = Dim.Percent (25)
+				};
+				var lbl = new Label (1, 1, "Tick every (ms):");
+				LeftFrame.Add (lbl);
+				Speed = new TextField ("") {
+					X = Pos.Right (lbl) + 1,
+					Y = Pos.Y (lbl),
+					Width = 7,
+				};
+				LeftFrame.Add (Speed);
+
+				Add (LeftFrame);
+
+				var startButton = new Button ("Start Timer") {
+					X = Pos.Right (LeftFrame) + 1,
+					Y = 0,
+					Clicked = () => Start()
+				};
+				var pulseButton = new Button ("Pulse") {
+					X = Pos.Right (startButton) + 2,
+					Y = Pos.Y (startButton),
+					Clicked = () => PulseBtnClick.Invoke ()
+				};
+				var stopbutton = new Button ("Stop Timer") {
+					X = Pos.Right (pulseButton) + 2,
+					Y = Pos.Top (pulseButton),
+					Clicked = () => Stop()
+				};
+
+				Add (startButton);
+				Add (pulseButton);
+				Add (stopbutton);
+
+				ActivityProgressBar = new ProgressBar () {
+					X = Pos.Right (LeftFrame) + 1,
+					Y = Pos.Bottom (startButton) + 1,
+					Width = Dim.Fill (),
+					Height = 1,
+					Fraction = 0.25F,
+					ColorScheme = Colors.Error
+				};
+				Add (ActivityProgressBar);
+
+				PulseProgressBar = new ProgressBar () {
+					X = Pos.Right (LeftFrame) + 1,
+					Y = Pos.Bottom (ActivityProgressBar) + 1,
+					Width = Dim.Fill (),
+					Height = 1,
+					ColorScheme = Colors.Error
+				};
+				Add (PulseProgressBar);
+
+				_startedLabel = new Label ("Stopped") {
+					X = Pos.Right (LeftFrame) + 1,
+					Y = Pos.Bottom (PulseProgressBar),
+				};
+				Add (_startedLabel);
+
+
+				// Set height to height of controls + spacing + frame
+				Height = 2 + _verticalSpace + Dim.Height (startButton) + _verticalSpace + Dim.Height (ActivityProgressBar) + _verticalSpace + Dim.Height (PulseProgressBar) + _verticalSpace;
+			}
+
+			internal void Start ()
+			{
+				Started = true;
+				StartBtnClick?.Invoke ();
+			}
 
+			internal void Stop ()
+			{
+				Started = false;
+				StopBtnClick?.Invoke ();
+			}
+
+			internal void Pulse ()
+			{
+				if (PulseBtnClick != null) {
+					PulseBtnClick?.Invoke ();
+
+				} else {
+					if (ActivityProgressBar.Fraction + 0.01F >= 1) {
+						ActivityProgressBar.Fraction = 0F;
+					} else {
+						ActivityProgressBar.Fraction += 0.01F;
+					}
+					PulseProgressBar.Pulse ();
+				}
+			}
+		}
+
+		private Timer _systemTimer = null;
+		private uint _systemTimerTick = 1000; // ms
+		private object _mainLoopTimeout = null;
+		private uint _mainLooopTimeoutTick = 1000; // ms
 		public override void Setup ()
 		{
-			var pulseButton = new Button ("Pulse") {
-				X = Pos.Center (),
-				Y = Pos.Center () - 3,
-				Clicked = () => Pulse ()
+			// Demo #1 - Use System.Timer (and threading)
+			var systemTimerDemo = new ProgressDemo ("System.Timer (threads)") {
+				X = 0,
+				Y = 0,
+				Width = Dim.Percent (100),
 			};
+			systemTimerDemo.StartBtnClick = () => {
+				_systemTimer?.Dispose ();
+				_systemTimer = null;
+
+				systemTimerDemo.ActivityProgressBar.Fraction = 0F;
+				systemTimerDemo.PulseProgressBar.Fraction = 0F;
+
+				_systemTimer = new Timer ((o) => {
+					// Note the check for Mainloop being valid. System.Timers can run after they are Disposed.
+					// This code must be defensive for that. 
+					Application.MainLoop?.Invoke (() => systemTimerDemo.Pulse ());
+				}, null, 0, _systemTimerTick);
+			};
+
+			systemTimerDemo.StopBtnClick = () => {
+				_systemTimer?.Dispose ();
+				_systemTimer = null;
 
-			var startButton = new Button ("Start Timer") {
-				Y = Pos.Y(pulseButton),
-				Clicked = () => Start ()
+				systemTimerDemo.ActivityProgressBar.Fraction = 1F;
+				systemTimerDemo.PulseProgressBar.Fraction = 1F;
 			};
+			systemTimerDemo.Speed.Text = $"{_systemTimerTick}";
+			systemTimerDemo.Speed.Changed += (sender, a) => {
+				uint result;
+				if (uint.TryParse (systemTimerDemo.Speed.Text.ToString(), out result)) {
+					_systemTimerTick = result;
+					System.Diagnostics.Debug.WriteLine ($"{_systemTimerTick}");
+					if (systemTimerDemo.Started) {
+						systemTimerDemo.Start ();
+					}
+
+				} else {
+					System.Diagnostics.Debug.WriteLine ("bad entry");
+				}
+			};
+			Win.Add (systemTimerDemo);
 
-			var stopbutton = new Button ("Stop Timer") {
-				Y = Pos.Y (pulseButton),
-				Clicked = () => Stop()
+			// Demo #2 - Use Application.MainLoop.AddTimeout (no threads)
+			var mainLoopTimeoutDemo = new ProgressDemo ("Application.AddTimer (no threads)") {
+				X = 0,
+				Y = Pos.Bottom (systemTimerDemo),
+				Width = Dim.Percent (100),
 			};
+			mainLoopTimeoutDemo.StartBtnClick = () => {
+				mainLoopTimeoutDemo.StopBtnClick ();
 
-			// Center three buttons with 5 spaces between them
-			// TODO: Use Pos.Width instead of (Right-Left) when implemented (#502)
-			startButton.X = Pos.Left (pulseButton) - (Pos.Right (startButton) - Pos.Left (startButton)) - 5;
-			stopbutton.X = Pos.Right (pulseButton) + 5;
+				mainLoopTimeoutDemo.ActivityProgressBar.Fraction = 0F;
+				mainLoopTimeoutDemo.PulseProgressBar.Fraction = 0F;
 
-			Win.Add (startButton);
-			Win.Add (pulseButton);
-			Win.Add (stopbutton);
+				_mainLoopTimeout = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (_mainLooopTimeoutTick), (loop) => {
+					mainLoopTimeoutDemo.Pulse ();
+					return true;
+				});
+			};
+			mainLoopTimeoutDemo.StopBtnClick = () => {
+				if (_mainLoopTimeout != null) {
+					Application.MainLoop.RemoveTimeout (_mainLoopTimeout);
+					_mainLoopTimeout = null;
+				}
+
+				mainLoopTimeoutDemo.ActivityProgressBar.Fraction = 1F;
+				mainLoopTimeoutDemo.PulseProgressBar.Fraction = 1F;
+			};
 
-			_activityProgressBar = new ProgressBar () {
-				X = Pos.Center (),
-				// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
-				Y = Pos.Center ()+1,
-				Width = 30,
-				Fraction = 0.25F,
+			mainLoopTimeoutDemo.Speed.Text = $"{_mainLooopTimeoutTick}";
+			mainLoopTimeoutDemo.Speed.Changed += (sender, a) => {
+				uint result;
+				if (uint.TryParse (mainLoopTimeoutDemo.Speed.Text.ToString (), out result)) {
+					_mainLooopTimeoutTick = result;
+					if (mainLoopTimeoutDemo.Started) {
+						mainLoopTimeoutDemo.Start ();
+					}
+				}
 			};
-			Win.Add (_activityProgressBar);
+			Win.Add (mainLoopTimeoutDemo);
 
-			_pulseProgressBar = new ProgressBar () {
+			var startBoth = new Button ("Start Both") {
 				X = Pos.Center (),
-				// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
-				Y = Pos.Center () + 3,
-				Width = 30,
+				Y = Pos.AnchorEnd () - 1,
 			};
-			Win.Add (_pulseProgressBar);
+			startBoth.Clicked = () => {
+				systemTimerDemo.Start ();
+				mainLoopTimeoutDemo.Start ();
+			};
+			Win.Add (startBoth);
+
 		}
 
 		protected override void Dispose (bool disposing)
 		{
-			_timer?.Dispose ();
-			_timer = null;
-			if (_timeoutToken != null) {
-				Application.MainLoop.RemoveTimeout (_timeoutToken);
+			foreach (var v in Win.Subviews.OfType<ProgressDemo>()) {
+				v?.StopBtnClick ();
 			}
 			base.Dispose (disposing);
 		}
-
-		private void Pulse ()
-		{
-			if (_activityProgressBar.Fraction + 0.01F >= 1) {
-				_activityProgressBar.Fraction = 0F;
-			} else {
-				_activityProgressBar.Fraction += 0.01F;
-			}
-			_pulseProgressBar.Pulse ();
-		}
-
-		private void Start ()
-		{
-			_timer?.Dispose ();
-			_timer = null;
-
-			_activityProgressBar.Fraction = 0F;
-			_pulseProgressBar.Fraction = 0F;
-
-			_timer = new Timer ((o) => {
-				Application.MainLoop.Invoke (() => Pulse ());
-			}, null, 0, 20);
-		}
-
-		private void Stop ()
-		{
-			_timer?.Dispose ();
-			_timer = null;
-			if (_timeoutToken != null) {
-				Application.MainLoop.RemoveTimeout (_timeoutToken);
-			}
-
-			_activityProgressBar.Fraction = 1F;
-			_pulseProgressBar.Fraction = 1F;
-		}
 	}
 }

+ 16 - 7
UICatalog/Scenarios/Threading.cs

@@ -44,23 +44,34 @@ namespace UICatalog {
 				_itemsList.SetSource (items);
 			};
 
-			Application.Init ();
 
 			_btnActionCancel = new Button (1, 1, "Cancelable Load Items");
 			_btnActionCancel.Clicked += () => Application.MainLoop.Invoke (CallLoadItemsAsync);
 
-			_itemsList = new ListView {
+			Win.Add (new Label ("Data Items:") {
 				X = Pos.X (_btnActionCancel),
 				Y = Pos.Y (_btnActionCancel) + 4,
+			});
+
+			_itemsList = new ListView {
+				X = Pos.X (_btnActionCancel),
+				Y = Pos.Y (_btnActionCancel) + 6,
 				Width = 10,
-				Height = 10
+				Height = 10,
+				ColorScheme = Colors.TopLevel
 			};
 
+			Win.Add (new Label ("Task Logs:") {
+				X = Pos.Right (_itemsList) + 10,
+				Y = Pos.Y (_btnActionCancel) + 4,
+			});
+
 			_logJob = new ListView (log) {
 				X = Pos.Right (_itemsList) + 10,
 				Y = Pos.Y (_itemsList),
 				Width = 50,
-				Height = Dim.Fill ()
+				Height = Dim.Fill (),
+				ColorScheme = Colors.TopLevel
 			};
 
 			var text = new TextField (1, 3, 100, "Type anything after press the button");
@@ -76,13 +87,11 @@ namespace UICatalog {
 			var _btnMethod = new Button (80, 18, "Load Data Method");
 			_btnMethod.Clicked += async () => await MethodAsync ();
 			var _btnClearData = new Button (80, 20, "Clear Data");
-				_btnClearData.Clicked += () => { _itemsList.Source = null; LogJob ("Cleaning Data"); };
+			_btnClearData.Clicked += () => { _itemsList.Source = null; LogJob ("Cleaning Data"); };
 			var _btnQuit = new Button (80, 22, "Quit");
 			_btnQuit.Clicked += Application.RequestStop;
 
 			Win.Add (_itemsList, _btnActionCancel, _logJob, text, _btnAction, _btnLambda, _btnHandler, _btnSync, _btnMethod, _btnClearData, _btnQuit);
-			Application.Top.Add (Win);
-			Application.Run ();
 
 		}
 

+ 2 - 2
UICatalog/UICatalog.cs

@@ -177,7 +177,7 @@ namespace UICatalog {
 
 			_top = Application.Top;
 
-			_top.KeyUp += KeyUpHandler;
+			_top.KeyDown += KeyDownHandler;
 
 			_top.Add (_menu);
 			_top.Add (_leftPane);
@@ -271,7 +271,7 @@ namespace UICatalog {
 		/// to not be impacted. Same as for tabs.
 		/// </summary>
 		/// <param name="ke"></param>
-		private static void KeyUpHandler (object sender, View.KeyEventEventArgs a)
+		private static void KeyDownHandler (object sender, View.KeyEventEventArgs a)
 		{
 			if (_runningScenario != null) {
 				//switch (ke.Key) {