From db534ed1c17441e2697e1b03e51ca168444254f4 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Sun, 7 Jan 2018 22:11:23 -0500 Subject: [PATCH] Refresh works, Dialogs close --- Core.cs | 99 +++++++++++++++++++++++++++++++++------------ Driver.cs | 3 ++ TODO.md | 4 ++ Views/Button.cs | 2 +- Views/Checkbox.cs | 2 +- Views/Dialog.cs | 10 +++++ Views/Menu.cs | 2 +- Views/RadioGroup.cs | 4 +- 8 files changed, 95 insertions(+), 31 deletions(-) diff --git a/Core.cs b/Core.cs index 58b725b9b..1714588a6 100644 --- a/Core.cs +++ b/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. /// + /// + /// 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. + /// /// public virtual bool ProcessKey (KeyEvent kb) { @@ -439,6 +446,12 @@ namespace Terminal { Driver.AddCh (ch); } + protected void ClearNeedsDisplay () + { + NeedDisplay = Rect.Empty; + childNeedsDisplay = false; + } + /// /// Performs a redraw of this view and its subviews, only redraws the views that have been flagged for a re-display. /// @@ -462,8 +475,7 @@ namespace Terminal { } } } - NeedDisplay = Rect.Empty; - childNeedsDisplay = false; + ClearNeedsDisplay (); } /// @@ -669,6 +681,12 @@ namespace Terminal { /// /// Toplevel views can be modally executed. /// + /// + /// + /// Toplevels can be modally executing views, and they return control + /// to the caller when the "Running" property is set to false. + /// + /// 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 } /// - /// 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. /// public class Window : Toplevel, IEnumerable { View contentView; @@ -754,6 +761,11 @@ namespace Terminal { public ContentView (Rect frame) : base (frame) { } } + /// + /// Initializes a new instance of the class with an optioanl title + /// + /// Frame. + /// Title. public Window (Rect frame, string title = null) : base (frame) { this.Title = title; @@ -762,6 +774,10 @@ namespace Terminal { base.Add (contentView); } + /// + /// Enumerates the various views in the ContentView. + /// + /// The enumerator. public new IEnumerator GetEnumerator () { return contentView.GetEnumerator (); @@ -772,6 +788,10 @@ namespace Terminal { DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), true); } + /// + /// Add the specified view to the ContentView. + /// + /// View to add to the window. 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 (); } } + /// + /// The application driver for gui.cs + /// + /// + /// + /// You can hook up to the Iteration event to have your method + /// invoked on each iteration of the mainloop. + /// + /// + /// Creates a mainloop to process input events, handle timers and + /// other sources of data. It is accessible via the MainLoop property. + /// + /// + /// When invoked sets the SynchronizationContext to one that is tied + /// to the mainloop, allowing user code to use async/await. + /// + /// 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 toplevels = new Stack (); - static Responder focus; /// /// 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 (); } + /// + /// Triggers a refresh of the entire display. + /// 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. /// /// - /// This method is used to start processing events - /// for the main application, but it is also used to - /// run modal dialog boxes. + /// + /// This method is used to start processing events + /// for the main application, but it is also used to + /// run modal dialog boxes. + /// + /// + /// To make a toplevel stop execution, set the "Running" + /// property to false. + /// /// public static void Run (Toplevel view) { diff --git a/Driver.cs b/Driver.cs index f8f707f2d..b392c796a 100644 --- a/Driver.cs +++ b/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++; } diff --git a/TODO.md b/TODO.md index 6a24cd323..b9e3303ad 100644 --- a/TODO.md +++ b/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. diff --git a/Views/Button.cs b/Views/Button.cs index 3bcf522b0..6a302fc50 100644 --- a/Views/Button.cs +++ b/Views/Button.cs @@ -168,7 +168,7 @@ namespace Terminal { Clicked (this, EventArgs.Empty); return true; } - return false; + return base.ProcessKey (kb); } #if false diff --git a/Views/Checkbox.cs b/Views/Checkbox.cs index da1f7adb7..e95598bac 100644 --- a/Views/Checkbox.cs +++ b/Views/Checkbox.cs @@ -110,7 +110,7 @@ namespace Terminal { SetNeedsDisplay (); return true; } - return false; + return base.ProcessKey (kb); } #if false diff --git a/Views/Dialog.cs b/Views/Dialog.cs index 47b9973e5..3a50325ee 100644 --- a/Views/Dialog.cs +++ b/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); + } } } diff --git a/Views/Menu.cs b/Views/Menu.cs index 57f9fe9c3..3c4286046 100644 --- a/Views/Menu.cs +++ b/Views/Menu.cs @@ -190,7 +190,7 @@ namespace Terminal { } break; } - return false; + return base.ProcessKey (kb); } } diff --git a/Views/RadioGroup.cs b/Views/RadioGroup.cs index be138eb89..60c32e50b 100644 --- a/Views/RadioGroup.cs +++ b/Views/RadioGroup.cs @@ -134,10 +134,8 @@ namespace Terminal { case Key.Space: Selected = cursor; return true; - default: - - return false; } + return base.ProcessKey (kb); } } }