Browse Source

Refresh works, Dialogs close

Miguel de Icaza 7 years ago
parent
commit
db534ed1c1
8 changed files with 95 additions and 31 deletions
  1. 74 25
      Core.cs
  2. 3 0
      Driver.cs
  3. 4 0
      TODO.md
  4. 1 1
      Views/Button.cs
  5. 1 1
      Views/Checkbox.cs
  6. 10 0
      Views/Dialog.cs
  7. 1 1
      Views/Menu.cs
  8. 1 3
      Views/RadioGroup.cs

+ 74 - 25
Core.cs

@@ -16,6 +16,7 @@ using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Threading;
+using System.Linq;
 
 namespace Terminal {
 
@@ -66,6 +67,12 @@ namespace Terminal {
 		///     keystroke will be passed using the ProcessColdKey
 		///     method to other views to process.
 		///   </para>
+		///   <para>
+		///     The View implementation does nothing but return false,
+		///     so it is not necessary to call base.ProcessKey if you 
+		///     derive directly from View, but you should if you derive
+		///     other View subclasses.
+		///   </para>
 		/// </remarks>
 		public virtual bool ProcessKey (KeyEvent kb)
 		{
@@ -439,6 +446,12 @@ namespace Terminal {
 			Driver.AddCh (ch);
 		}
 
+		protected void ClearNeedsDisplay ()
+		{
+			NeedDisplay = Rect.Empty;
+			childNeedsDisplay = false;
+		}
+
 		/// <summary>
 		/// Performs a redraw of this view and its subviews, only redraws the views that have been flagged for a re-display.
 		/// </summary>
@@ -462,8 +475,7 @@ namespace Terminal {
 					}
 				}
 			}
-			NeedDisplay = Rect.Empty;
-			childNeedsDisplay = false;
+			ClearNeedsDisplay ();
 		}
 
 		/// <summary>
@@ -669,6 +681,12 @@ namespace Terminal {
 	/// <summary>
 	/// Toplevel views can be modally executed.
 	/// </summary>
+	/// <remarks>
+	///   <para>
+	///     Toplevels can be modally executing views, and they return control
+	///     to the caller when the "Running" property is set to false.
+	///   </para>
+	/// </remarks>
 	public class Toplevel : View {
 		public bool Running;
 
@@ -708,7 +726,7 @@ namespace Terminal {
 				}
 				return true;
 			case Key.BackTab:
-			old = Focused;
+				old = Focused;
 				if (!FocusPrev ())
 					FocusPrev ();
 				if (old != Focused) {
@@ -717,26 +735,15 @@ namespace Terminal {
 				}
 				return true;
 			case Key.ControlL:
-				SetNeedsDisplay();
+				Application.Refresh ();
 				return true;
 			}
 			return false;
 		}
-
-#if false
-        public override void Redraw ()
-        {
-            base.Redraw ();
-            for (int i = 0; i < Driver.Cols; i++) {
-                Driver.Move (0, i);
-                Driver.AddStr ("Line: " + i);
-            }
-        }
-#endif
 	}
 
 	/// <summary>
-	/// A toplevel view that draws a frame around its region
+	/// A toplevel view that draws a frame around its region and has a "ContentView" subview where the contents are added.
 	/// </summary>
 	public class Window : Toplevel, IEnumerable {
 		View contentView;
@@ -754,6 +761,11 @@ namespace Terminal {
 			public ContentView (Rect frame) : base (frame) { }
 		}
 
+		/// <summary>
+		/// Initializes a new instance of the <see cref="T:Terminal.Window"/> class with an optioanl title
+		/// </summary>
+		/// <param name="frame">Frame.</param>
+		/// <param name="title">Title.</param>
 		public Window (Rect frame, string title = null) : base (frame)
 		{
 			this.Title = title;
@@ -762,6 +774,10 @@ namespace Terminal {
 			base.Add (contentView);
 		}
 
+		/// <summary>
+		/// Enumerates the various views in the ContentView.
+		/// </summary>
+		/// <returns>The enumerator.</returns>
 		public new IEnumerator GetEnumerator ()
 		{
 			return contentView.GetEnumerator ();
@@ -772,6 +788,10 @@ namespace Terminal {
 			DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), true);
 		}
 
+		/// <summary>
+		/// Add the specified view to the ContentView.
+		/// </summary>
+		/// <param name="view">View to add to the window.</param>
 		public override void Add (View view)
 		{
 			contentView.Add (view);
@@ -795,9 +815,27 @@ namespace Terminal {
 				Driver.SetAttribute (Colors.Dialog.Normal);
 			}
 			contentView.Redraw (contentView.Bounds);
+			ClearNeedsDisplay ();
 		}
 	}
 
+	/// <summary>
+	/// The application driver for gui.cs
+	/// </summary>
+	/// <remarks>
+	///   <para>
+	///     You can hook up to the Iteration event to have your method 
+	///     invoked on each iteration of the mainloop.
+	///   </para>
+	///   <para>
+	///     Creates a mainloop to process input events, handle timers and
+	///     other sources of data.   It is accessible via the MainLoop property.
+	///   </para>
+	///   <para>
+	///     When invoked sets the SynchronizationContext to one that is tied
+	///     to the mainloop, allowing user code to use async/await.
+	///   </para>
+	/// </remarks>
 	public class Application {
 		public static ConsoleDriver Driver = new CursesDriver ();
 		public static Toplevel Top { get; private set; }
@@ -805,7 +843,6 @@ namespace Terminal {
 		public static Mono.Terminal.MainLoop MainLoop { get; private set; }
 
 		static Stack<View> toplevels = new Stack<View> ();
-		static Responder focus;
 
 		/// <summary>
 		///   This event is raised on each iteration of the
@@ -826,6 +863,10 @@ namespace Terminal {
 			return new Rect (new Point ((Driver.Cols - size.Width) / 2, (Driver.Rows - size.Height) / 2), size);
 		}
 
+		//
+		// provides the sync context set while executing code in gui.cs, to let
+		// users use async/await on their code
+		//
 		class MainLoopSyncContext : SynchronizationContext {
 			Mono.Terminal.MainLoop mainLoop;
 
@@ -868,7 +909,6 @@ namespace Terminal {
 			SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
 			Top = Toplevel.Create ();
 			Current = Top;
-			focus = Top;
 		}
 
 		public class RunState : IDisposable {
@@ -906,7 +946,6 @@ namespace Terminal {
 				return;
 		}
 
-
 		static public RunState Begin (Toplevel toplevel)
 		{
 			if (toplevel == null)
@@ -930,6 +969,7 @@ namespace Terminal {
 		{
 			if (rs == null)
 				throw new ArgumentNullException (nameof (rs));
+
 			rs.Dispose ();
 		}
 
@@ -950,16 +990,19 @@ namespace Terminal {
 			Driver.Refresh ();
 		}
 
+		/// <summary>
+		/// Triggers a refresh of the entire display.
+		/// </summary>
 		public static void Refresh ()
 		{
 			Driver.RedrawTop ();
 			View last = null;
-			foreach (var v in toplevels) {
+			foreach (var v in toplevels.Reverse ()) {
+				v.SetNeedsDisplay ();
 				v.Redraw (v.Bounds);
 				last = v;
 			}
-			if (last != null)
-				last.PositionCursor ();
+			last?.PositionCursor ();
 			Driver.Refresh ();
 		}
 
@@ -1014,9 +1057,15 @@ namespace Terminal {
 		///   Runs the main loop on the given container.
 		/// </summary>
 		/// <remarks>
-		///   This method is used to start processing events
-		///   for the main application, but it is also used to
-		///   run modal dialog boxes.
+		///   <para>
+		///     This method is used to start processing events
+		///     for the main application, but it is also used to
+		///     run modal dialog boxes.
+		///   </para>
+		///   <para>
+		///     To make a toplevel stop execution, set the "Running"
+		///     property to false.
+		///   </para>
 		/// </remarks>
 		public static void Run (Toplevel view)
 		{

+ 3 - 0
Driver.cs

@@ -124,6 +124,7 @@ namespace Terminal {
 			}
 		}
 
+		static bool sync;
 		public override void AddCh (int ch)
 		{
 			if (Clip.Contains (ccol, crow)) {
@@ -134,6 +135,8 @@ namespace Terminal {
 				Curses.addch (ch);
 			} else
 				needMove = true;
+			if (sync)
+				Application.Driver.Refresh ();
 			ccol++;
 		}
 

+ 4 - 0
TODO.md

@@ -33,6 +33,10 @@ Widgets should not use Colors.Base or Colors.Dialog, they should likely use
 the colors defined in the toplevel container, so that the Dialog vs Toplevel
 colors are set there only.
 
+## Focus
+
+Use left/right/up/down to switch focus as well when nothing handles the event
+
 ## Views
 
 Checkbox, ListView, Menu.

+ 1 - 1
Views/Button.cs

@@ -168,7 +168,7 @@ namespace Terminal {
 					Clicked (this, EventArgs.Empty);
 				return true;
 			}
-			return false;
+			return base.ProcessKey (kb);
 		}
 
 #if false

+ 1 - 1
Views/Checkbox.cs

@@ -110,7 +110,7 @@ namespace Terminal {
 				SetNeedsDisplay ();
 				return true;
 			}
-			return false;
+			return base.ProcessKey (kb);
 		}
 
 #if false

+ 10 - 0
Views/Dialog.cs

@@ -47,5 +47,15 @@ namespace Terminal {
 				start += bf.Width + 1;
 			}
 		}
+
+		public override bool ProcessKey (KeyEvent kb)
+		{
+			switch (kb.Key) {
+			case Key.Esc:
+				Running = false;
+				return true;
+			}
+			return base.ProcessKey (kb);
+		}
 	}
 }

+ 1 - 1
Views/Menu.cs

@@ -190,7 +190,7 @@ namespace Terminal {
 				}
 				break;
 			}
-			return false;
+			return base.ProcessKey (kb);
 		}
 	}
 

+ 1 - 3
Views/RadioGroup.cs

@@ -134,10 +134,8 @@ namespace Terminal {
 			case Key.Space:
 				Selected = cursor;
 				return true;
-			default:
-				
-				return false;
 			}
+			return base.ProcessKey (kb);
 		}
 	}
 }