diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs
index 50906cfb9..4a030f433 100644
--- a/Terminal.Gui/Core/Application.cs
+++ b/Terminal.Gui/Core/Application.cs
@@ -223,19 +223,28 @@ namespace Terminal.Gui {
public static bool ExitRunLoopAfterFirstIteration { get; set; } = false;
///
- /// Notify that a new token was created,
- /// used if is true.
+ /// Notify that a new was created ( was called). The token is created in
+ /// and this event will be fired before that function exits.
///
+ ///
+ /// If is callers to
+ /// must also subscribe to
+ /// and manually dispose of the token when the application is done.
+ ///
public static event Action NotifyNewRunState;
///
- /// Notify that a existent token is stopping,
- /// used if is true.
+ /// Notify that a existent is stopping ( was called).
///
+ ///
+ /// If is callers to
+ /// must also subscribe to
+ /// and manually dispose of the token when the application is done.
+ ///
public static event Action NotifyStopRunState;
///
- /// This event is raised on each iteration of the
+ /// This event is raised on each iteration of the .
///
///
/// See also
@@ -315,8 +324,10 @@ namespace Terminal.Gui {
/// returned) to ensure resources are cleaned up and terminal settings restored.
///
///
- /// The function combines and
- /// into a single call. An applciation cam use without explicitly calling .
+ /// The function
+ /// combines and
+ /// into a single call. An applciation cam use
+ /// without explicitly calling .
///
///
/// Note, due to Issue #520, if Init is called and is not called, the
@@ -326,7 +337,7 @@ namespace Terminal.Gui {
/// The to use. If not specified the default driver for the
/// platform will be used (see , , and ).
/// Specifies the to use.
- public static void Init (ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) => Init (() => Toplevel.Create (), driver, mainLoopDriver);
+ public static void Init (ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) => Init (() => Toplevel.Create (), driver, mainLoopDriver, resetState: true);
internal static bool _initialized = false;
internal static int _mainThreadId = -1;
@@ -341,12 +352,16 @@ namespace Terminal.Gui {
/// The to use. If not specified the default driver for the
/// platform will be used (see , , and ).
/// Specifies the to use.
- static void Init (Func topLevelFactory, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null)
+ /// If (default) all state will be reset.
+ /// Set to to not reset the state (for when this function is called via
+ /// when
+ /// has not already been called. f
+ internal static void Init (Func topLevelFactory, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null, bool resetState = true)
{
if (_initialized && driver == null) return;
if (_initialized) {
- throw new InvalidOperationException ("Init must be bracketed by Shutdown");
+ throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown.");
}
// Used only for start debugging on Unix.
@@ -358,7 +373,9 @@ namespace Terminal.Gui {
//#endif
// Reset all class variables (Application is a singleton).
- ResetState ();
+ if (resetState) {
+ ResetState ();
+ }
// This supports Unit Tests and the passing of a mock driver/loopdriver
if (driver != null) {
@@ -366,9 +383,6 @@ namespace Terminal.Gui {
throw new ArgumentNullException ("mainLoopDriver cannot be null if driver is provided.");
}
Driver = driver;
- Driver.Init (TerminalResized);
- MainLoop = new MainLoop (mainLoopDriver);
- SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
}
if (Driver == null) {
@@ -383,10 +397,12 @@ namespace Terminal.Gui {
mainLoopDriver = new UnixMainLoop ();
Driver = new CursesDriver ();
}
- Driver.Init (TerminalResized);
- MainLoop = new MainLoop (mainLoopDriver);
- SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
}
+ MainLoop = new MainLoop (mainLoopDriver);
+
+ Driver.Init (TerminalResized);
+ SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
+
Top = topLevelFactory ();
Current = Top;
supportedCultures = GetSupportedCultures ();
@@ -395,7 +411,7 @@ namespace Terminal.Gui {
}
///
- /// Captures the execution state for the provided view.
+ /// Captures the execution state for the provided view.
///
public class RunState : IDisposable {
///
@@ -411,31 +427,61 @@ namespace Terminal.Gui {
///
public Toplevel Toplevel { get; internal set; }
+#if DEBUG_IDISPOSABLE
///
- /// Releases alTop = l resource used by the object.
+ /// For debug purposes to verify objects are being disposed properly
///
- /// Call when you are finished using the . The
+ public bool WasDisposed = false;
+ ///
+ /// For debug purposes to verify objects are being disposed properly
+ ///
+ public int DisposedCount = 0;
+ ///
+ /// For debug purposes
+ ///
+ public static List Instances = new List ();
+ ///
+ /// For debug purposes
+ ///
+ public RunState ()
+ {
+ Instances.Add (this);
+ }
+#endif
+
+ ///
+ /// Releases all resource used by the object.
+ ///
+ ///
+ /// Call when you are finished using the .
+ ///
+ ///
/// method leaves the in an unusable state. After
/// calling , you must release all references to the
/// so the garbage collector can reclaim the memory that the
- /// was occupying.
+ /// was occupying.
+ ///
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
+#if DEBUG_IDISPOSABLE
+ WasDisposed = true;
+#endif
}
///
- /// Dispose the specified disposing.
+ /// Releases all resource used by the object.
///
- /// The dispose.
- /// If set to true disposing.
+ /// If set to we are disposing and should dispose held objects.
protected virtual void Dispose (bool disposing)
{
if (Toplevel != null && disposing) {
- End (Toplevel);
- Toplevel.Dispose ();
- Toplevel = null;
+ throw new InvalidOperationException ("You must clean up (Dispose) the Toplevel before calling Application.RunState.Dispose");
+ // BUGBUG: It's insidious that we call EndFirstTopLevel here so I moved it to End.
+ //EndFirstTopLevel (Toplevel);
+ //Toplevel.Dispose ();
+ //Toplevel = null;
}
}
}
@@ -841,7 +887,6 @@ namespace Terminal.Gui {
}
var rs = new RunState (toplevel);
-
Init ();
if (toplevel is ISupportInitializeNotification initializableNotification &&
!initializableNotification.IsInitialized) {
@@ -913,6 +958,7 @@ namespace Terminal.Gui {
Driver.Refresh ();
}
+ NotifyNewRunState?.Invoke (rs);
return rs;
}
@@ -930,6 +976,42 @@ namespace Terminal.Gui {
} else {
runState.Toplevel.OnUnloaded ();
}
+
+ // End the RunState.Toplevel
+ // First, take it off the toplevel Stack
+ if (toplevels.Count > 0) {
+ if (toplevels.Peek () != runState.Toplevel) {
+ // If there the top of the stack is not the RunState.Toplevel then
+ // this call to End is not balanced with the call to Begin that started the RunState
+ throw new ArgumentException ("End must be balanced with calls to Begin");
+ }
+ toplevels.Pop ();
+ }
+
+ // Notify that it is closing
+ runState.Toplevel?.OnClosed (runState.Toplevel);
+
+ // If there is a MdiTop that is not the RunState.Toplevel then runstate.TopLevel
+ // is a child of MidTop and we should notify the MdiTop that it is closing
+ if (MdiTop != null && !(runState.Toplevel).Modal && runState.Toplevel != MdiTop) {
+ MdiTop.OnChildClosed (runState.Toplevel);
+ }
+
+ // Set Current and Top to the next TopLevel on the stack
+ if (toplevels.Count == 0) {
+ Current = null;
+ } else {
+ Current = toplevels.Peek ();
+ if (toplevels.Count == 1 && Current == MdiTop) {
+ MdiTop.OnAllChildClosed ();
+ } else {
+ SetCurrentAsTop ();
+ }
+ Refresh ();
+ }
+
+ runState.Toplevel?.Dispose ();
+ runState.Toplevel = null;
runState.Dispose ();
}
@@ -937,7 +1019,7 @@ namespace Terminal.Gui {
/// Shutdown an application initialized with .
///
///
- /// Shutdown must be called for every call to or
+ /// Shutdown must be called for every call to or
/// to ensure all resources are cleaned up (Disposed) and terminal settings are restored.
///
public static void Shutdown ()
@@ -1014,40 +1096,17 @@ namespace Terminal.Gui {
Driver.Refresh ();
}
- internal static void End (View view)
- {
- if (toplevels.Peek () != view)
- throw new ArgumentException ("The view that you end with must be balanced");
- toplevels.Pop ();
- (view as Toplevel)?.OnClosed ((Toplevel)view);
-
- if (MdiTop != null && !((Toplevel)view).Modal && view != MdiTop) {
- MdiTop.OnChildClosed (view as Toplevel);
- }
-
- if (toplevels.Count == 0) {
- Current = null;
- } else {
- Current = toplevels.Peek ();
- if (toplevels.Count == 1 && Current == MdiTop) {
- MdiTop.OnAllChildClosed ();
- } else {
- SetCurrentAsTop ();
- }
- Refresh ();
- }
- }
///
- /// Building block API: Runs the main loop for the created dialog.
+ /// Building block API: Runs the for the created .
///
///
- /// Use the wait parameter to control whether this is a
- /// blocking or non-blocking call.
+ /// Use the parameter to control whether this is a blocking or non-blocking call.
///
- /// The state returned by the Begin method.
- /// By default this is true which will execute the runloop waiting for events, if you pass false, you can use this method to run a single iteration of the events.
+ /// The state returned by the method.
+ /// By default this is which will execute the runloop waiting for events,
+ /// if set to , a single iteration will execute.
public static void RunLoop (RunState state, bool wait = true)
{
if (state == null)
@@ -1057,8 +1116,9 @@ namespace Terminal.Gui {
bool firstIteration = true;
for (state.Toplevel.Running = true; state.Toplevel.Running;) {
- if (ExitRunLoopAfterFirstIteration && !firstIteration)
+ if (ExitRunLoopAfterFirstIteration && !firstIteration) {
return;
+ }
RunMainLoopIteration (ref state, wait, ref firstIteration);
}
}
@@ -1186,17 +1246,21 @@ namespace Terminal.Gui {
/// with a new instance of the specified -derived class.
///
/// If has not arleady been called, this function will
- /// call .
+ /// call .
///
///
- /// must be called when the application is closing (typically after has
+ /// must be called when the application is closing (typically after Run> has
/// returned) to ensure resources are cleaned up and terminal settings restored.
///
///
///
/// See for more details.
///
- public static void Run (Func errorHandler = null) where T : Toplevel, new()
+ ///
+ /// The to use. If not specified the default driver for the
+ /// platform will be used (see , , and ).
+ /// Specifies the to use.
+ public static void Run (Func errorHandler = null, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) where T : Toplevel, new()
{
if (_initialized && Driver != null) {
var top = new T ();
@@ -1207,9 +1271,11 @@ namespace Terminal.Gui {
if (type != typeof (Toplevel)) {
throw new ArgumentException ($"{top.GetType ().Name} must be derived from TopLevel");
}
+ // Run() will eventually cause Application.Top to be set, via Begin() and SetCurrentAsTop()
Run (top, errorHandler);
} else {
- Init (() => new T ());
+ // Note in this case, we don't verify the type of the Toplevel created by new T().
+ Init (() => new T (), Driver == null ? driver : Driver, Driver == null ? mainLoopDriver : null, resetState: false);
Run (Top, errorHandler);
}
}
@@ -1255,13 +1321,12 @@ namespace Terminal.Gui {
#endif
resume = false;
var runToken = Begin (view);
+ // If ExitRunLoopAfterFirstIteration is true then the user must dispose of the runToken
+ // by using NotifyStopRunState event.
RunLoop (runToken);
- if (!ExitRunLoopAfterFirstIteration)
+ if (!ExitRunLoopAfterFirstIteration) {
End (runToken);
- else
- // If ExitRunLoopAfterFirstIteration is true then the user must deal his disposing when it ends
- // by using NotifyStopRunState event.
- NotifyNewRunState?.Invoke (runToken);
+ }
#if !DEBUG
}
catch (Exception error)
@@ -1354,8 +1419,9 @@ namespace Terminal.Gui {
static void OnNotifyStopRunState (Toplevel top)
{
- if (ExitRunLoopAfterFirstIteration)
+ if (ExitRunLoopAfterFirstIteration) {
NotifyStopRunState?.Invoke (top);
+ }
}
///
diff --git a/Terminal.Gui/Core/MainLoop.cs b/Terminal.Gui/Core/MainLoop.cs
index e71367646..9b6492fe0 100644
--- a/Terminal.Gui/Core/MainLoop.cs
+++ b/Terminal.Gui/Core/MainLoop.cs
@@ -94,8 +94,8 @@ namespace Terminal.Gui {
public IMainLoopDriver Driver { get; }
///
- /// Invoked when a new timeout is added to be used on the case
- /// if is true,
+ /// Invoked when a new timeout is added. To be used in the case
+ /// when is .
///
public event Action TimeoutAdded;
diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs
index a922f729d..707a3e0a5 100644
--- a/Terminal.Gui/Core/Toplevel.cs
+++ b/Terminal.Gui/Core/Toplevel.cs
@@ -44,7 +44,7 @@ namespace Terminal.Gui {
public bool Running { get; set; }
///
- /// Invoked when the Toplevel has begin loaded.
+ /// Invoked when the Toplevel has begun to be loaded.
/// A Loaded event handler is a good place to finalize initialization before calling
/// .
///
@@ -77,13 +77,13 @@ namespace Terminal.Gui {
///
/// Invoked when a child of the Toplevel is closed by
- /// .
+ /// .
///
public event Action ChildClosed;
///
/// Invoked when the last child of the Toplevel is closed from
- /// by .
+ /// by .
///
public event Action AllChildClosed;
@@ -94,7 +94,7 @@ namespace Terminal.Gui {
public event Action Closing;
///
- /// Invoked when the Toplevel's is closed by .
+ /// Invoked when the Toplevel's is closed by .
///
public event Action Closed;
diff --git a/UICatalog/Properties/launchSettings.json b/UICatalog/Properties/launchSettings.json
index a519b2cb4..b621c2df5 100644
--- a/UICatalog/Properties/launchSettings.json
+++ b/UICatalog/Properties/launchSettings.json
@@ -48,6 +48,10 @@
"WSL": {
"commandName": "WSL2",
"distributionName": ""
+ },
+ "All Views Tester": {
+ "commandName": "Project",
+ "commandLineArgs": "\"All Views Tester\""
}
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenario.cs b/UICatalog/Scenario.cs
index 30767e190..e26ce2911 100644
--- a/UICatalog/Scenario.cs
+++ b/UICatalog/Scenario.cs
@@ -48,12 +48,7 @@ namespace UICatalog {
private bool _disposedValue;
///
- /// The Top level for the . This should be set to in most cases.
- ///
- public Toplevel Top { get; set; }
-
- ///
- /// The Window for the . This should be set within the in most cases.
+ /// The Window for the . This should be set to in most cases.
///
public Window Win { get; set; }
@@ -63,22 +58,21 @@ namespace UICatalog {
/// the Scenario picker UI.
/// Override to provide any behavior needed.
///
- /// The Toplevel created by the UI Catalog host.
/// The colorscheme to use.
///
///
- /// The base implementation calls , sets to the passed in , creates a for and adds it to .
+ /// The base implementation calls and creates a for
+ /// and adds it to .
///
///
- /// Overrides that do not call the base. , must call before creating any views or calling other Terminal.Gui APIs.
+ /// Overrides that do not call the base. , must call
+ /// before creating any views or calling other Terminal.Gui APIs.
///
///
- public virtual void Init (Toplevel top, ColorScheme colorScheme)
+ public virtual void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = top != null ? top : Application.Top;
-
Win = new Window ($"CTRL-Q to Close - Scenario: {GetName ()}") {
X = 0,
Y = 0,
@@ -86,7 +80,7 @@ namespace UICatalog {
Height = Dim.Fill (),
ColorScheme = colorScheme,
};
- Top.Add (Win);
+ Application.Top.Add (Win);
}
///
@@ -201,7 +195,7 @@ namespace UICatalog {
public virtual void Run ()
{
// Must explicit call Application.Shutdown method to shutdown.
- Application.Run (Top);
+ Application.Run (Application.Top);
}
///
diff --git a/UICatalog/Scenarios/AllViewsTester.cs b/UICatalog/Scenarios/AllViewsTester.cs
index 945b25df8..7e346f02d 100644
--- a/UICatalog/Scenarios/AllViewsTester.cs
+++ b/UICatalog/Scenarios/AllViewsTester.cs
@@ -14,7 +14,7 @@ namespace UICatalog.Scenarios {
[ScenarioCategory ("Tests")]
[ScenarioCategory ("Top Level Windows")]
public class AllViewsTester : Scenario {
- Window _leftPane;
+ FrameView _leftPane;
ListView _classListView;
FrameView _hostPane;
@@ -40,42 +40,33 @@ namespace UICatalog.Scenarios {
TextField _hText;
int _hVal = 0;
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
-
- Top = top != null ? top : Application.Top;
-
- //Win = new Window ($"CTRL-Q to Close - Scenario: {GetName ()}") {
- // X = 0,
- // Y = 0,
- // Width = Dim.Fill (),
- // Height = Dim.Fill ()
- //};
- //Top.Add (Win);
+ // Don't create a sub-win; just use Applicatiion.Top
}
-
+
public override void Setup ()
{
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
new StatusItem(Key.F2, "~F2~ Toggle Frame Ruler", () => {
ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FrameRuler;
- Top.SetNeedsDisplay ();
+ Application.Top.SetNeedsDisplay ();
}),
new StatusItem(Key.F3, "~F3~ Toggle Frame Padding", () => {
ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FramePadding;
- Top.SetNeedsDisplay ();
+ Application.Top.SetNeedsDisplay ();
}),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
_viewClasses = GetAllViewClassesCollection ()
.OrderBy (t => t.Name)
.Select (t => new KeyValuePair (t.Name, t))
.ToDictionary (t => t.Key, t => t.Value);
- _leftPane = new Window ("Classes") {
+ _leftPane = new FrameView ("Classes") {
X = 0,
Y = 0,
Width = 15,
@@ -241,9 +232,9 @@ namespace UICatalog.Scenarios {
ColorScheme = Colors.Dialog,
};
- Top.Add (_leftPane, _settingsPane, _hostPane);
+ Application.Top.Add (_leftPane, _settingsPane, _hostPane);
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
_curView = CreateClass (_viewClasses.First ().Value);
}
@@ -438,11 +429,6 @@ namespace UICatalog.Scenarios {
UpdateTitle (_curView);
}
- public override void Run ()
- {
- base.Run ();
- }
-
private void Quit ()
{
Application.RequestStop ();
diff --git a/UICatalog/Scenarios/BackgroundWorkerCollection.cs b/UICatalog/Scenarios/BackgroundWorkerCollection.cs
index 07eceb5f7..ec73bcf76 100644
--- a/UICatalog/Scenarios/BackgroundWorkerCollection.cs
+++ b/UICatalog/Scenarios/BackgroundWorkerCollection.cs
@@ -12,6 +12,11 @@ namespace UICatalog.Scenarios {
[ScenarioCategory ("Dialogs")]
[ScenarioCategory ("Controls")]
public class BackgroundWorkerCollection : Scenario {
+ public override void Init (ColorScheme colorScheme)
+ {
+ // Do not call Init as Application.Run will do it
+ }
+
public override void Run ()
{
// BUGBUG: work around Issue #520: Ensuring the `Toplevel` created by `Init` gets Disposed...
diff --git a/UICatalog/Scenarios/BordersComparisons.cs b/UICatalog/Scenarios/BordersComparisons.cs
index 9ea462f52..1aac4dca5 100644
--- a/UICatalog/Scenarios/BordersComparisons.cs
+++ b/UICatalog/Scenarios/BordersComparisons.cs
@@ -5,12 +5,10 @@ namespace UICatalog.Scenarios {
[ScenarioCategory ("Layout")]
[ScenarioCategory ("Borders")]
public class BordersComparisons : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- top = Application.Top;
-
var borderStyle = BorderStyle.Double;
var drawMarginFrame = false;
var borderThickness = new Thickness (1, 2, 3, 4);
@@ -53,7 +51,7 @@ namespace UICatalog.Scenarios {
Width = 10
};
win.Add (tf1, button, label, tv, tf2);
- top.Add (win);
+ Application.Top.Add (win);
var top2 = new Border.ToplevelContainer (new Rect (50, 5, 40, 20),
new Border () {
@@ -92,7 +90,7 @@ namespace UICatalog.Scenarios {
Width = 10
};
top2.Add (tf3, button2, label2, tv2, tf4);
- top.Add (top2);
+ Application.Top.Add (top2);
var frm = new FrameView (new Rect (95, 5, 40, 20), "Test3", null,
new Border () {
@@ -128,7 +126,7 @@ namespace UICatalog.Scenarios {
Width = 10
};
frm.Add (tf5, button3, label3, tv3, tf6);
- top.Add (frm);
+ Application.Top.Add (frm);
Application.Run ();
}
diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs
index f66849d9e..7269d53d3 100644
--- a/UICatalog/Scenarios/Buttons.cs
+++ b/UICatalog/Scenarios/Buttons.cs
@@ -56,7 +56,7 @@ namespace UICatalog.Scenarios {
//View prev = colorButtonsLabel;
- //With this method there is no need to call Top.Ready += () => Top.Redraw (Top.Bounds);
+ //With this method there is no need to call Application.TopReady += () => Application.TopRedraw (Top.Bounds);
var x = Pos.Right (colorButtonsLabel) + 2;
foreach (var colorScheme in Colors.ColorSchemes) {
var colorButton = new Button ($"{colorScheme.Key}") {
@@ -272,7 +272,7 @@ namespace UICatalog.Scenarios {
}
};
- Top.Ready += () => radioGroup.Refresh ();
+ Application.Top.Ready += () => radioGroup.Refresh ();
}
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenarios/ClassExplorer.cs b/UICatalog/Scenarios/ClassExplorer.cs
index c7b5798bd..3b96b18e0 100644
--- a/UICatalog/Scenarios/ClassExplorer.cs
+++ b/UICatalog/Scenarios/ClassExplorer.cs
@@ -58,7 +58,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
@@ -73,7 +73,7 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Expand All", "", () => treeView.ExpandAll()),
new MenuItem ("_Collapse All", "", () => treeView.CollapseAll()) }),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
treeView = new TreeView () {
X = 0,
diff --git a/UICatalog/Scenarios/Clipping.cs b/UICatalog/Scenarios/Clipping.cs
index 9c137f03e..0d68229a9 100644
--- a/UICatalog/Scenarios/Clipping.cs
+++ b/UICatalog/Scenarios/Clipping.cs
@@ -7,13 +7,10 @@ namespace UICatalog.Scenarios {
public class Clipping : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
-
- Top = top != null ? top : Application.Top;
-
- Top.ColorScheme = Colors.Base;
+ Application.Top.ColorScheme = Colors.Base;
}
public override void Setup ()
@@ -26,7 +23,7 @@ namespace UICatalog.Scenarios {
X = 0, Y = 0,
//ColorScheme = Colors.Dialog
};
- Top.Add (label);
+ Application.Top.Add (label);
var scrollView = new ScrollView (new Rect (3, 3, 50, 20));
scrollView.ColorScheme = Colors.Menu;
@@ -69,7 +66,7 @@ namespace UICatalog.Scenarios {
scrollView.Add (embedded1);
- Top.Add (scrollView);
+ Application.Top.Add (scrollView);
}
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenarios/CollectionNavigatorTester.cs b/UICatalog/Scenarios/CollectionNavigatorTester.cs
index d97f6890c..8d444ff08 100644
--- a/UICatalog/Scenarios/CollectionNavigatorTester.cs
+++ b/UICatalog/Scenarios/CollectionNavigatorTester.cs
@@ -15,11 +15,10 @@ namespace UICatalog.Scenarios {
public class CollectionNavigatorTester : Scenario {
// Don't create a Window, just return the top-level view
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = top != null ? top : Application.Top;
- Top.ColorScheme = Colors.Base;
+ Application.Top.ColorScheme = Colors.Base;
}
System.Collections.Generic.List _items = new string [] {
@@ -103,7 +102,7 @@ namespace UICatalog.Scenarios {
new MenuBarItem("_Quit", "CTRL-Q", () => Quit()),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
_items.Sort (StringComparer.OrdinalIgnoreCase);
@@ -113,7 +112,7 @@ namespace UICatalog.Scenarios {
Y = 1,
Height = Dim.Fill ()
};
- Top.Add (vsep);
+ Application.Top.Add (vsep);
CreateTreeView ();
}
@@ -129,7 +128,7 @@ namespace UICatalog.Scenarios {
Width = Dim.Percent (50),
Height = 1,
};
- Top.Add (label);
+ Application.Top.Add (label);
_listView = new ListView () {
X = 0,
@@ -140,7 +139,7 @@ namespace UICatalog.Scenarios {
AllowsMultipleSelection = false,
ColorScheme = Colors.TopLevel
};
- Top.Add (_listView);
+ Application.Top.Add (_listView);
_listView.SetSource (_items);
@@ -161,7 +160,7 @@ namespace UICatalog.Scenarios {
Width = Dim.Percent (50),
Height = 1,
};
- Top.Add (label);
+ Application.Top.Add (label);
_treeView = new TreeView () {
X = Pos.Right (_listView) + 1,
@@ -170,7 +169,7 @@ namespace UICatalog.Scenarios {
Height = Dim.Fill (),
ColorScheme = Colors.TopLevel
};
- Top.Add (_treeView);
+ Application.Top.Add (_treeView);
var root = new TreeNode ("IsLetterOrDigit examples");
root.Children = _items.Where (i => char.IsLetterOrDigit (i [0])).Select (i => new TreeNode (i)).Cast ().ToList ();
diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs
index 38300482f..af7d3ba28 100644
--- a/UICatalog/Scenarios/ComputedLayout.cs
+++ b/UICatalog/Scenarios/ComputedLayout.cs
@@ -25,12 +25,12 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Quit", "", () => Quit()),
}),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
//Top.LayoutStyle = LayoutStyle.Computed;
// Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width
diff --git a/UICatalog/Scenarios/ContextMenus.cs b/UICatalog/Scenarios/ContextMenus.cs
index a9e9223d3..897f75acc 100644
--- a/UICatalog/Scenarios/ContextMenus.cs
+++ b/UICatalog/Scenarios/ContextMenus.cs
@@ -81,7 +81,7 @@ namespace UICatalog.Scenarios {
Win.WantMousePositionReports = true;
- Top.Closed += (_) => {
+ Application.Top.Closed += (_) => {
Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
Application.RootMouseEvent -= Application_RootMouseEvent;
};
diff --git a/UICatalog/Scenarios/CsvEditor.cs b/UICatalog/Scenarios/CsvEditor.cs
index ab83b487d..f57d13e37 100644
--- a/UICatalog/Scenarios/CsvEditor.cs
+++ b/UICatalog/Scenarios/CsvEditor.cs
@@ -34,7 +34,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
this.tableView = new TableView () {
X = 0,
@@ -70,14 +70,14 @@ namespace UICatalog.Scenarios {
miCentered = new MenuItem ("_Set Format Pattern", "", () => SetFormat()),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.O, "~^O~ Open", () => Open()),
new StatusItem(Key.CtrlMask | Key.S, "~^S~ Save", () => Save()),
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
Win.Add (tableView);
diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs
index c3aac85a4..f8a680046 100644
--- a/UICatalog/Scenarios/Dialogs.cs
+++ b/UICatalog/Scenarios/Dialogs.cs
@@ -116,9 +116,9 @@ namespace UICatalog.Scenarios {
{
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit)
+ Dim.Height (numButtonsEdit) + Dim.Height (styleRadioGroup) + Dim.Height(glyphsNotWords) + 2;
- Top.Loaded -= Top_Loaded;
+ Application.Top.Loaded -= Top_Loaded;
}
- Top.Loaded += Top_Loaded;
+ Application.Top.Loaded += Top_Loaded;
label = new Label ("Button Pressed:") {
X = Pos.Center (),
diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs
index 82309b965..2ba8c3a07 100644
--- a/UICatalog/Scenarios/DynamicMenuBar.cs
+++ b/UICatalog/Scenarios/DynamicMenuBar.cs
@@ -13,11 +13,10 @@ namespace UICatalog.Scenarios {
[ScenarioCategory ("Top Level Windows")]
[ScenarioCategory ("Menus")]
public class DynamicMenuBar : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = Application.Top;
- Top.Add (new DynamicMenuBarSample ($"CTRL-Q to Close - Scenario: {GetName ()}"));
+ Application.Top.Add (new DynamicMenuBarSample ($"CTRL-Q to Close - Scenario: {GetName ()}"));
}
public class DynamicMenuItemList {
diff --git a/UICatalog/Scenarios/DynamicStatusBar.cs b/UICatalog/Scenarios/DynamicStatusBar.cs
index 5583afbcb..a61f366c0 100644
--- a/UICatalog/Scenarios/DynamicStatusBar.cs
+++ b/UICatalog/Scenarios/DynamicStatusBar.cs
@@ -12,11 +12,10 @@ namespace UICatalog.Scenarios {
[ScenarioMetadata (Name: "Dynamic StatusBar", Description: "Demonstrates how to add and remove a StatusBar and change items dynamically.")]
[ScenarioCategory ("Top Level Windows")]
public class DynamicStatusBar : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = Application.Top;
- Top.Add (new DynamicStatusBarSample ($"CTRL-Q to Close - Scenario: {GetName ()}"));
+ Application.Top.Add (new DynamicStatusBarSample ($"CTRL-Q to Close - Scenario: {GetName ()}"));
}
public class DynamicStatusItemList {
diff --git a/UICatalog/Scenarios/Editor.cs b/UICatalog/Scenarios/Editor.cs
index c14922d50..8bc930389 100644
--- a/UICatalog/Scenarios/Editor.cs
+++ b/UICatalog/Scenarios/Editor.cs
@@ -32,11 +32,10 @@ namespace UICatalog.Scenarios {
private bool _forceMinimumPosToZero = true;
private List _cultureInfos;
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
_cultureInfos = Application.SupportedCultures;
- Top = top != null ? top : Application.Top;
Win = new Window (_fileName ?? "Untitled") {
X = 0,
@@ -45,7 +44,7 @@ namespace UICatalog.Scenarios {
Height = Dim.Fill (),
ColorScheme = colorScheme,
};
- Top.Add (Win);
+ Application.Top.Add (Win);
_textView = new TextView () {
X = 0,
@@ -115,7 +114,7 @@ namespace UICatalog.Scenarios {
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
siCursorPosition,
@@ -125,7 +124,7 @@ namespace UICatalog.Scenarios {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
new StatusItem(Key.Null, $"OS Clipboard IsSupported : {Clipboard.IsSupported}", null)
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
_scrollBar = new ScrollBarView (_textView, true);
@@ -197,7 +196,7 @@ namespace UICatalog.Scenarios {
}
};
- Top.Closed += (_) => Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
+ Application.Top.Closed += (_) => Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
}
private void DisposeWinDialog ()
diff --git a/UICatalog/Scenarios/GraphViewExample.cs b/UICatalog/Scenarios/GraphViewExample.cs
index 8404f044b..e8f806046 100644
--- a/UICatalog/Scenarios/GraphViewExample.cs
+++ b/UICatalog/Scenarios/GraphViewExample.cs
@@ -23,7 +23,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
graphs = new Action [] {
()=>SetupPeriodicTableScatterPlot(), //0
@@ -59,7 +59,7 @@ namespace UICatalog.Scenarios {
}),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
graphView = new GraphView () {
X = 1,
@@ -92,7 +92,7 @@ namespace UICatalog.Scenarios {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
new StatusItem(Key.CtrlMask | Key.G, "~^G~ Next", ()=>graphs[currentGraph++%graphs.Length]()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
private void MultiBarGraph ()
diff --git a/UICatalog/Scenarios/HexEditor.cs b/UICatalog/Scenarios/HexEditor.cs
index 52d02b2ef..c83408ada 100644
--- a/UICatalog/Scenarios/HexEditor.cs
+++ b/UICatalog/Scenarios/HexEditor.cs
@@ -52,7 +52,7 @@ namespace UICatalog.Scenarios {
miAllowEdits = new MenuItem ("_AllowEdits", "", () => ToggleAllowEdits ()){Checked = _hexView.AllowEdits, CheckType = MenuItemCheckStyle.Checked}
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.F2, "~F2~ Open", () => Open()),
@@ -61,7 +61,7 @@ namespace UICatalog.Scenarios {
siPositionChanged = new StatusItem(Key.Null,
$"Position: {_hexView.Position} Line: {_hexView.CursorPosition.Y} Col: {_hexView.CursorPosition.X} Line length: {_hexView.BytesPerLine}", () => {})
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
private void _hexView_PositionChanged (HexView.HexViewEventArgs obj)
diff --git a/UICatalog/Scenarios/InteractiveTree.cs b/UICatalog/Scenarios/InteractiveTree.cs
index b3d63578d..f51f10238 100644
--- a/UICatalog/Scenarios/InteractiveTree.cs
+++ b/UICatalog/Scenarios/InteractiveTree.cs
@@ -20,14 +20,14 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Quit", "", () => Quit()),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
treeView = new TreeView () {
X = 0,
@@ -45,7 +45,7 @@ namespace UICatalog.Scenarios {
new StatusItem(Key.CtrlMask | Key.T, "~^T~ Add Root", () => AddRootNode()),
new StatusItem(Key.CtrlMask | Key.R, "~^R~ Rename Node", () => RenameNode()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
diff --git a/UICatalog/Scenarios/Keys.cs b/UICatalog/Scenarios/Keys.cs
index 35cafbc21..21b567f6d 100644
--- a/UICatalog/Scenarios/Keys.cs
+++ b/UICatalog/Scenarios/Keys.cs
@@ -48,10 +48,9 @@ namespace UICatalog.Scenarios {
}
}
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = top != null ? top : Application.Top;
Win = new TestWindow ($"CTRL-Q to Close - Scenario: {GetName ()}") {
X = 0,
@@ -60,7 +59,7 @@ namespace UICatalog.Scenarios {
Height = Dim.Fill (),
ColorScheme = colorScheme,
};
- Top.Add (Win);
+ Application.Top.Add (Win);
}
public override void Setup ()
@@ -107,7 +106,7 @@ namespace UICatalog.Scenarios {
Shift = true
});
var maxLogEntry = $"Key{"",-5}: {fakeKeyPress}".Length;
- var yOffset = (Top == Application.Top ? 1 : 6);
+ var yOffset = (Application.Top == Application.Top ? 1 : 6);
var keyStrokelist = new List ();
var keyStrokeListView = new ListView (keyStrokelist) {
X = 0,
@@ -126,7 +125,7 @@ namespace UICatalog.Scenarios {
Win.Add (processKeyLogLabel);
maxLogEntry = $"{fakeKeyPress}".Length;
- yOffset = (Top == Application.Top ? 1 : 6);
+ yOffset = (Application.Top == Application.Top ? 1 : 6);
var processKeyListView = new ListView (((TestWindow)Win)._processKeyList) {
X = Pos.Left (processKeyLogLabel),
Y = Pos.Top (processKeyLogLabel) + yOffset,
@@ -144,7 +143,7 @@ namespace UICatalog.Scenarios {
};
Win.Add (processHotKeyLogLabel);
- yOffset = (Top == Application.Top ? 1 : 6);
+ yOffset = (Application.Top == Application.Top ? 1 : 6);
var processHotKeyListView = new ListView (((TestWindow)Win)._processHotKeyList) {
X = Pos.Left (processHotKeyLogLabel),
Y = Pos.Top (processHotKeyLogLabel) + yOffset,
@@ -162,7 +161,7 @@ namespace UICatalog.Scenarios {
};
Win.Add (processColdKeyLogLabel);
- yOffset = (Top == Application.Top ? 1 : 6);
+ yOffset = (Application.Top == Application.Top ? 1 : 6);
var processColdKeyListView = new ListView (((TestWindow)Win)._processColdKeyList) {
X = Pos.Left (processColdKeyLogLabel),
Y = Pos.Top (processColdKeyLogLabel) + yOffset,
diff --git a/UICatalog/Scenarios/LabelsAsButtons.cs b/UICatalog/Scenarios/LabelsAsButtons.cs
index 395a042ec..29c2b98af 100644
--- a/UICatalog/Scenarios/LabelsAsButtons.cs
+++ b/UICatalog/Scenarios/LabelsAsButtons.cs
@@ -59,7 +59,7 @@ namespace UICatalog.Scenarios {
};
Win.Add (colorLabelsLabel);
- //With this method there is no need to call Top.Ready += () => Top.Redraw (Top.Bounds);
+ //With this method there is no need to call Application.TopReady += () => Application.TopRedraw (Top.Bounds);
var x = Pos.Right (colorLabelsLabel) + 2;
foreach (var colorScheme in Colors.ColorSchemes) {
var colorLabel = new Label ($"{colorScheme.Key}") {
@@ -73,7 +73,7 @@ namespace UICatalog.Scenarios {
Win.Add (colorLabel);
x += colorLabel.Text.Length + 2;
}
- Top.Ready += () => Top.Redraw (Top.Bounds);
+ Application.Top.Ready += () => Application.Top.Redraw (Application.Top.Bounds);
Label Label;
Win.Add (Label = new Label ("A super long _Label that will probably expose a bug in clipping or wrapping of text. Will it?") {
@@ -306,7 +306,7 @@ namespace UICatalog.Scenarios {
}
};
- Top.Ready += () => radioGroup.Refresh ();
+ Application.Top.Ready += () => radioGroup.Refresh ();
}
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenarios/LineViewExample.cs b/UICatalog/Scenarios/LineViewExample.cs
index 4a8c4002a..cf537d952 100644
--- a/UICatalog/Scenarios/LineViewExample.cs
+++ b/UICatalog/Scenarios/LineViewExample.cs
@@ -17,14 +17,14 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Quit", "", () => Quit()),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
Win.Add (new Label ("Regular Line") { Y = 0 });
@@ -94,7 +94,7 @@ namespace UICatalog.Scenarios {
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit())
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
diff --git a/UICatalog/Scenarios/MessageBoxes.cs b/UICatalog/Scenarios/MessageBoxes.cs
index 0b9aaa702..b0fe23109 100644
--- a/UICatalog/Scenarios/MessageBoxes.cs
+++ b/UICatalog/Scenarios/MessageBoxes.cs
@@ -156,9 +156,9 @@ namespace UICatalog.Scenarios {
{
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + Dim.Height (messageEdit)
+ Dim.Height (numButtonsEdit) + Dim.Height (defaultButtonEdit) + Dim.Height (styleRadioGroup) + 2 + Dim.Height (ckbEffect3D);
- Top.Loaded -= Top_Loaded;
+ Application.Top.Loaded -= Top_Loaded;
}
- Top.Loaded += Top_Loaded;
+ Application.Top.Loaded += Top_Loaded;
label = new Label ("Button Pressed:") {
X = Pos.Center (),
diff --git a/UICatalog/Scenarios/MultiColouredTable.cs b/UICatalog/Scenarios/MultiColouredTable.cs
index da772b0ec..d1d9b4059 100644
--- a/UICatalog/Scenarios/MultiColouredTable.cs
+++ b/UICatalog/Scenarios/MultiColouredTable.cs
@@ -16,7 +16,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
this.tableView = new TableViewColors () {
X = 0,
@@ -30,12 +30,12 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Quit", "", () => Quit()),
}),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
Win.Add (tableView);
diff --git a/UICatalog/Scenarios/Notepad.cs b/UICatalog/Scenarios/Notepad.cs
index d9d760175..a4fe1992e 100644
--- a/UICatalog/Scenarios/Notepad.cs
+++ b/UICatalog/Scenarios/Notepad.cs
@@ -11,11 +11,10 @@ namespace UICatalog.Scenarios {
private int numbeOfNewTabs = 1;
// Don't create a Window, just return the top-level view
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
- Top = top != null ? top : Application.Top;
- Top.ColorScheme = Colors.Base;
+ Application.Top.ColorScheme = Colors.Base;
}
public override void Setup ()
@@ -30,7 +29,7 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Quit", "", () => Quit()),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
tabView = new TabView () {
X = 0,
@@ -42,7 +41,7 @@ namespace UICatalog.Scenarios {
tabView.Style.ShowBorder = true;
tabView.ApplyStyleChanges ();
- Top.Add (tabView);
+ Application.Top.Add (tabView);
var lenStatusItem = new StatusItem (Key.CharMask, "Len: ", null);
var statusBar = new StatusBar (new StatusItem [] {
@@ -59,7 +58,7 @@ namespace UICatalog.Scenarios {
tabView.SelectedTabChanged += (s, e) => lenStatusItem.Title = $"Len:{(e.NewTab?.View?.Text?.Length ?? 0)}";
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
New ();
}
diff --git a/UICatalog/Scenarios/ProgressBarStyles.cs b/UICatalog/Scenarios/ProgressBarStyles.cs
index 0b8ee4bfe..d35949b5c 100644
--- a/UICatalog/Scenarios/ProgressBarStyles.cs
+++ b/UICatalog/Scenarios/ProgressBarStyles.cs
@@ -131,7 +131,7 @@ namespace UICatalog.Scenarios {
Application.MainLoop.Driver.Wakeup ();
}, null, 0, 300);
- Top.Unloaded += Top_Unloaded;
+ Application.Top.Unloaded += Top_Unloaded;
void Top_Unloaded ()
{
@@ -143,7 +143,7 @@ namespace UICatalog.Scenarios {
_pulseTimer.Dispose ();
_pulseTimer = null;
}
- Top.Unloaded -= Top_Unloaded;
+ Application.Top.Unloaded -= Top_Unloaded;
}
}
}
diff --git a/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs b/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
index a6bd140f0..4d7ddfa44 100644
--- a/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
+++ b/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
@@ -16,7 +16,7 @@ namespace UICatalog.Scenarios {
private Window _win;
private string _lastRunesUsed;
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
Application.Init ();
diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs
index a1b82282a..de28406ae 100644
--- a/UICatalog/Scenarios/Scrolling.cs
+++ b/UICatalog/Scenarios/Scrolling.cs
@@ -156,9 +156,9 @@ namespace UICatalog.Scenarios {
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)];
- Top.Loaded -= Top_Loaded;
+ Application.Top.Loaded -= Top_Loaded;
}
- Top.Loaded += Top_Loaded;
+ Application.Top.Loaded += Top_Loaded;
var pressMeButton = new Button ("Press me!") {
X = 3,
@@ -313,9 +313,9 @@ namespace UICatalog.Scenarios {
void Top_Unloaded ()
{
pulsing = false;
- Top.Unloaded -= Top_Unloaded;
+ Application.Top.Unloaded -= Top_Unloaded;
}
- Top.Unloaded += Top_Unloaded;
+ Application.Top.Unloaded += Top_Unloaded;
}
}
}
\ No newline at end of file
diff --git a/UICatalog/Scenarios/SingleBackgroundWorker.cs b/UICatalog/Scenarios/SingleBackgroundWorker.cs
index a2705500c..e0268ab41 100644
--- a/UICatalog/Scenarios/SingleBackgroundWorker.cs
+++ b/UICatalog/Scenarios/SingleBackgroundWorker.cs
@@ -11,11 +11,11 @@ namespace UICatalog.Scenarios {
public class SingleBackgroundWorker : Scenario {
public override void Run ()
{
- Top.Dispose ();
+ Application.Top.Dispose ();
Application.Run ();
- Top.Dispose ();
+ Application.Top.Dispose ();
}
public class MainApp : Toplevel {
diff --git a/UICatalog/Scenarios/SyntaxHighlighting.cs b/UICatalog/Scenarios/SyntaxHighlighting.cs
index cd3436341..3a696b14c 100644
--- a/UICatalog/Scenarios/SyntaxHighlighting.cs
+++ b/UICatalog/Scenarios/SyntaxHighlighting.cs
@@ -21,7 +21,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
@@ -29,7 +29,7 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Quit", "", () => Quit()),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
textView = new SqlTextView () {
X = 0,
@@ -49,7 +49,7 @@ namespace UICatalog.Scenarios {
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
private void WordWrap ()
diff --git a/UICatalog/Scenarios/TabViewExample.cs b/UICatalog/Scenarios/TabViewExample.cs
index 73e27ad69..2bab75e70 100644
--- a/UICatalog/Scenarios/TabViewExample.cs
+++ b/UICatalog/Scenarios/TabViewExample.cs
@@ -24,7 +24,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
@@ -50,7 +50,7 @@ namespace UICatalog.Scenarios {
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
tabView = new TabView () {
X = 0,
@@ -85,7 +85,6 @@ namespace UICatalog.Scenarios {
Height = Dim.Fill (),
};
-
frameRight.Add (new TextView () {
Text = "This demos the tabs control\nSwitch between tabs using cursor keys",
Width = Dim.Fill (),
@@ -94,8 +93,6 @@ namespace UICatalog.Scenarios {
Win.Add (frameRight);
-
-
var frameBelow = new FrameView ("Bottom Frame") {
X = 0,
Y = Pos.Bottom (tabView),
@@ -103,7 +100,6 @@ namespace UICatalog.Scenarios {
Height = Dim.Fill (),
};
-
frameBelow.Add (new TextView () {
Text = "This frame exists to check you can still tab here\nand that the tab control doesn't overspill it's bounds",
Width = Dim.Fill (),
@@ -115,7 +111,7 @@ namespace UICatalog.Scenarios {
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
}
private void AddBlankTab ()
diff --git a/UICatalog/Scenarios/TableEditor.cs b/UICatalog/Scenarios/TableEditor.cs
index e3da3c964..2f71e30ae 100644
--- a/UICatalog/Scenarios/TableEditor.cs
+++ b/UICatalog/Scenarios/TableEditor.cs
@@ -38,7 +38,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
this.tableView = new TableView () {
X = 0,
@@ -78,9 +78,9 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Set All MinAcceptableWidth=1", "",SetMinAcceptableWidthToOne),
}),
});
-
- Top.Add (menu);
+
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.F2, "~F2~ OpenExample", () => OpenExample(true)),
@@ -88,7 +88,7 @@ namespace UICatalog.Scenarios {
new StatusItem(Key.F4, "~F4~ OpenSimple", () => OpenSimple(true)),
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
Win.Add (tableView);
diff --git a/UICatalog/Scenarios/TextFormatterDemo.cs b/UICatalog/Scenarios/TextFormatterDemo.cs
index fb5187673..bf18ed506 100644
--- a/UICatalog/Scenarios/TextFormatterDemo.cs
+++ b/UICatalog/Scenarios/TextFormatterDemo.cs
@@ -42,7 +42,7 @@ namespace UICatalog.Scenarios {
blockText.Text = ustring.Make (block.ToString ()); // .Replace(" ", "\u00A0"); // \u00A0 is 'non-breaking space
Win.Add (blockText);
- var unicodeCheckBox = new CheckBox ("Unicode", Top.HotKeySpecifier == (Rune)' ') {
+ var unicodeCheckBox = new CheckBox ("Unicode", Application.Top.HotKeySpecifier == (Rune)' ') {
X = 0,
Y = Pos.Bottom (blockText) + 1,
};
diff --git a/UICatalog/Scenarios/TextViewAutocompletePopup.cs b/UICatalog/Scenarios/TextViewAutocompletePopup.cs
index a9518586f..5907a6a25 100644
--- a/UICatalog/Scenarios/TextViewAutocompletePopup.cs
+++ b/UICatalog/Scenarios/TextViewAutocompletePopup.cs
@@ -33,7 +33,7 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Quit", "", () => Quit())
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
textViewTopLeft = new TextView () {
Width = width,
@@ -89,7 +89,7 @@ namespace UICatalog.Scenarios {
siMultiline = new StatusItem(Key.Null, "", null),
siWrap = new StatusItem(Key.Null, "", null)
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
Win.LayoutStarted += Win_LayoutStarted;
}
diff --git a/UICatalog/Scenarios/Threading.cs b/UICatalog/Scenarios/Threading.cs
index 99ff09b10..6bd159497 100644
--- a/UICatalog/Scenarios/Threading.cs
+++ b/UICatalog/Scenarios/Threading.cs
@@ -96,9 +96,9 @@ namespace UICatalog.Scenarios {
void Top_Loaded ()
{
_btnActionCancel.SetFocus ();
- Top.Loaded -= Top_Loaded;
+ Application.Top.Loaded -= Top_Loaded;
}
- Top.Loaded += Top_Loaded;
+ Application.Top.Loaded += Top_Loaded;
}
private async void LoadData ()
diff --git a/UICatalog/Scenarios/TreeUseCases.cs b/UICatalog/Scenarios/TreeUseCases.cs
index 4a63c25aa..aa1626c8d 100644
--- a/UICatalog/Scenarios/TreeUseCases.cs
+++ b/UICatalog/Scenarios/TreeUseCases.cs
@@ -17,7 +17,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
@@ -31,13 +31,13 @@ namespace UICatalog.Scenarios {
}),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
// Start with the most basic use case
LoadSimpleNodes ();
diff --git a/UICatalog/Scenarios/TreeViewFileSystem.cs b/UICatalog/Scenarios/TreeViewFileSystem.cs
index 57fa181c7..e2c1c905b 100644
--- a/UICatalog/Scenarios/TreeViewFileSystem.cs
+++ b/UICatalog/Scenarios/TreeViewFileSystem.cs
@@ -35,7 +35,7 @@ namespace UICatalog.Scenarios {
Win.Title = this.GetName ();
Win.Y = 1; // menu
Win.Height = Dim.Fill (1); // status bar
- Top.LayoutSubviews ();
+ Application.Top.LayoutSubviews ();
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
@@ -60,12 +60,12 @@ namespace UICatalog.Scenarios {
miMultiSelect = new MenuItem ("_MultiSelect", "", () => SetMultiSelect()){Checked = true, CheckType = MenuItemCheckStyle.Checked},
}),
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
var lblFiles = new Label ("File Tree:") {
X = 0,
diff --git a/UICatalog/Scenarios/Unicode.cs b/UICatalog/Scenarios/Unicode.cs
index 29779c4ac..c2813a0f5 100644
--- a/UICatalog/Scenarios/Unicode.cs
+++ b/UICatalog/Scenarios/Unicode.cs
@@ -34,14 +34,14 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Paste", "", null)
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem (Key.CtrlMask | Key.Q, "~^Q~ Выход", () => Application.RequestStop()),
new StatusItem (Key.Unknown, "~F2~ Создать", null),
new StatusItem(Key.Unknown, "~F3~ Со_хранить", null),
});
- Top.Add (statusBar);
+ Application.Top.Add (statusBar);
var label = new Label ("Label:") { X = 0, Y = 1 };
Win.Add (label);
diff --git a/UICatalog/Scenarios/WindowsAndFrameViews.cs b/UICatalog/Scenarios/WindowsAndFrameViews.cs
index ca3f613ef..616c20fca 100644
--- a/UICatalog/Scenarios/WindowsAndFrameViews.cs
+++ b/UICatalog/Scenarios/WindowsAndFrameViews.cs
@@ -6,13 +6,6 @@ namespace UICatalog.Scenarios {
[ScenarioMetadata (Name: "Windows & FrameViews", Description: "Shows Windows, sub-Windows, and FrameViews.")]
[ScenarioCategory ("Layout")]
public class WindowsAndFrameViews : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
- {
- Application.Init ();
-
- Top = top != null ? top : Application.Top;
- }
-
public override void RequestStop ()
{
base.RequestStop ();
@@ -67,7 +60,7 @@ namespace UICatalog.Scenarios {
Y = Pos.AnchorEnd (1),
ColorScheme = Colors.Error
});
- Top.Add (Win);
+ Application.Top.Add (Win);
listWin.Add (Win);
for (var i = 0; i < 3; i++) {
@@ -114,11 +107,10 @@ namespace UICatalog.Scenarios {
});
win.Add (frameView);
- Top.Add (win);
+ Application.Top.Add (win);
listWin.Add (win);
}
-
FrameView frame = null;
frame = new FrameView ($"This is a FrameView") {
X = margin,
@@ -176,7 +168,7 @@ namespace UICatalog.Scenarios {
frame.Add (subFrameViewofFV);
- Top.Add (frame);
+ Application.Top.Add (frame);
listWin.Add (frame);
}
}
diff --git a/UICatalog/Scenarios/WizardAsView.cs b/UICatalog/Scenarios/WizardAsView.cs
index a53067885..af2239285 100644
--- a/UICatalog/Scenarios/WizardAsView.cs
+++ b/UICatalog/Scenarios/WizardAsView.cs
@@ -10,10 +10,8 @@ namespace UICatalog.Scenarios {
[ScenarioCategory ("Wizards")]
public class WizardAsView : Scenario {
- public override void Init (Toplevel top, ColorScheme colorScheme)
+ public override void Init (ColorScheme colorScheme)
{
- Top = Application.Top;
-
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Restart Configuration...", "", () => MessageBox.Query ("Wizaard", "Are you sure you want to reset the Wizard and start over?", "Ok", "Cancel")),
@@ -21,7 +19,7 @@ namespace UICatalog.Scenarios {
new MenuItem ("_Shutdown Server...", "", () => MessageBox.Query ("Wizaard", "Are you sure you want to cancel setup and shutdown?", "Ok", "Cancel")),
})
});
- Top.Add (menu);
+ Application.Top.Add (menu);
// No need for a Title because the border is disabled
var wizard = new Wizard () {
@@ -93,8 +91,8 @@ namespace UICatalog.Scenarios {
wizard.AddStep (lastStep);
lastStep.HelpText = "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing Esc will cancel.";
- Top.Add (wizard);
- Application.Run (Top);
+ Application.Top.Add (wizard);
+ Application.Run (Application.Top);
}
public override void Run ()
diff --git a/UICatalog/Scenarios/Wizards.cs b/UICatalog/Scenarios/Wizards.cs
index e5f503414..268d9a422 100644
--- a/UICatalog/Scenarios/Wizards.cs
+++ b/UICatalog/Scenarios/Wizards.cs
@@ -73,9 +73,9 @@ namespace UICatalog.Scenarios {
void Top_Loaded ()
{
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + 2;
- Top.Loaded -= Top_Loaded;
+ Application.Top.Loaded -= Top_Loaded;
}
- Top.Loaded += Top_Loaded;
+ Application.Top.Loaded += Top_Loaded;
label = new Label ("Action:") {
X = Pos.Center (),
diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs
index 33f69f321..c5f896b77 100644
--- a/UICatalog/UICatalog.cs
+++ b/UICatalog/UICatalog.cs
@@ -44,35 +44,7 @@ namespace UICatalog {
///
/// UI Catalog is a comprehensive sample app and scenario library for
///
- public class UICatalogApp {
- private static int _nameColumnWidth;
- private static FrameView _leftPane;
- private static List _categories;
- private static ListView _categoryListView;
- private static FrameView _rightPane;
- private static List _scenarios;
- private static ListView _scenarioListView;
- private static StatusBar _statusBar;
- private static StatusItem _capslock;
- private static StatusItem _numlock;
- private static StatusItem _scrolllock;
-
- // If set, holds the scenario the user selected
- private static Scenario _selectedScenario = null;
-
- private static bool _useSystemConsole = false;
- private static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
- private static bool _heightAsBuffer = false;
- private static bool _isFirstRunning = true;
-
- // When a scenario is run, the main app is killed. These items
- // are therefore cached so that when the scenario exits the
- // main app UI can be restored to previous state
- private static int _cachedScenarioIndex = 0;
- private static int _cachedCategoryIndex = 0;
-
- private static StringBuilder _aboutMessage;
-
+ class UICatalogApp {
static void Main (string [] args)
{
Console.OutputEncoding = Encoding.Default;
@@ -82,17 +54,22 @@ namespace UICatalog {
}
_scenarios = Scenario.GetScenarios ();
+ _categories = Scenario.GetAllCategories ();
+ _nameColumnWidth = _scenarios.OrderByDescending (s => s.GetName ().Length).FirstOrDefault ().GetName ().Length;
if (args.Length > 0 && args.Contains ("-usc")) {
_useSystemConsole = true;
args = args.Where (val => val != "-usc").ToArray ();
}
+
+ // If a Scenario name has been provided on the commandline
+ // run it and exit when done.
if (args.Length > 0) {
var item = _scenarios.FindIndex (s => s.GetName ().Equals (args [0], StringComparison.OrdinalIgnoreCase));
_selectedScenario = (Scenario)Activator.CreateInstance (_scenarios [item].GetType ());
Application.UseSystemConsole = _useSystemConsole;
Application.Init ();
- _selectedScenario.Init (Application.Top, _colorScheme);
+ _selectedScenario.Init (_colorScheme);
_selectedScenario.Setup ();
_selectedScenario.Run ();
_selectedScenario = null;
@@ -114,17 +91,8 @@ namespace UICatalog {
Scenario scenario;
while ((scenario = SelectScenario ()) != null) {
-#if DEBUG_IDISPOSABLE
- // Validate there are no outstanding Responder-based instances
- // after a scenario was selected to run. This proves the main UI Catalog
- // 'app' closed cleanly.
- foreach (var inst in Responder.Instances) {
- Debug.Assert (inst.WasDisposed);
- }
- Responder.Instances.Clear ();
-#endif
-
- scenario.Init (Application.Top, _colorScheme);
+ VerifyObjectsWereDisposed ();
+ scenario.Init (_colorScheme);
scenario.Setup ();
scenario.Run ();
@@ -132,23 +100,436 @@ namespace UICatalog {
// made by Scenario.Init()
Application.Shutdown ();
-#if DEBUG_IDISPOSABLE
- // After the scenario runs, validate all Responder-based instances
- // were disposed. This proves the scenario 'app' closed cleanly.
- foreach (var inst in Responder.Instances) {
- Debug.Assert (inst.WasDisposed);
- }
- Responder.Instances.Clear ();
-#endif
+ VerifyObjectsWereDisposed ();
+ }
+ VerifyObjectsWereDisposed ();
+ }
+
+ static List _scenarios;
+ static List _categories;
+ static int _nameColumnWidth;
+ // When a scenario is run, the main app is killed. These items
+ // are therefore cached so that when the scenario exits the
+ // main app UI can be restored to previous state
+ static int _cachedScenarioIndex = 0;
+ static int _cachedCategoryIndex = 0;
+ static StringBuilder _aboutMessage;
+
+ // If set, holds the scenario the user selected
+ static Scenario _selectedScenario = null;
+
+ static bool _useSystemConsole = false;
+ static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
+ static bool _heightAsBuffer = false;
+ static bool _isFirstRunning = true;
+ static ColorScheme _colorScheme;
+
+ ///
+ /// This is the main UI Catalog app view. It is run fresh when the app loads (if a Scenario has not been passed on
+ /// the command line) and each time a Scenario ends.
+ ///
+ class UICatalogTopLevel : Toplevel {
+ public MenuItem miIsMouseDisabled;
+ public MenuItem miHeightAsBuffer;
+
+ public FrameView LeftPane;
+ public ListView CategoryListView;
+ public FrameView RightPane;
+ public ListView ScenarioListView;
+
+ public StatusItem Capslock;
+ public StatusItem Numlock;
+ public StatusItem Scrolllock;
+ public StatusItem DriverName;
+
+ public UICatalogTopLevel ()
+ {
+ ColorScheme = _colorScheme;
+ MenuBar = new MenuBar (new MenuBarItem [] {
+ new MenuBarItem ("_File", new MenuItem [] {
+ new MenuItem ("_Quit", "Quit UI Catalog", () => RequestStop(), null, null, Key.Q | Key.CtrlMask)
+ }),
+ new MenuBarItem ("_Color Scheme", CreateColorSchemeMenuItems()),
+ new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems()),
+ new MenuBarItem ("_Help", new MenuItem [] {
+ new MenuItem ("_gui.cs API Overview", "", () => OpenUrl ("https://gui-cs.github.io/Terminal.Gui/articles/overview.html"), null, null, Key.F1),
+ new MenuItem ("gui.cs _README", "", () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"), null, null, Key.F2),
+ new MenuItem ("_About...",
+ "About UI Catalog", () => MessageBox.Query ("About UI Catalog", _aboutMessage.ToString(), "_Ok"), null, null, Key.CtrlMask | Key.A),
+ }),
+ });
+
+ Capslock = new StatusItem (Key.CharMask, "Caps", null);
+ Numlock = new StatusItem (Key.CharMask, "Num", null);
+ Scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
+ DriverName = new StatusItem (Key.CharMask, "Driver:", null);
+
+ StatusBar = new StatusBar () {
+ Visible = true,
+ };
+ StatusBar.Items = new StatusItem [] {
+ Capslock,
+ Numlock,
+ Scrolllock,
+ new StatusItem(Key.Q | Key.CtrlMask, "~CTRL-Q~ Quit", () => {
+ if (_selectedScenario is null){
+ // This causes GetScenarioToRun to return null
+ _selectedScenario = null;
+ RequestStop();
+ } else {
+ _selectedScenario.RequestStop();
+ }
+ }),
+ new StatusItem(Key.F10, "~F10~ Hide/Show Status Bar", () => {
+ StatusBar.Visible = !StatusBar.Visible;
+ LeftPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
+ RightPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
+ LayoutSubviews();
+ SetChildNeedsDisplay();
+ }),
+ DriverName,
+ };
+
+ LeftPane = new FrameView ("Categories") {
+ X = 0,
+ Y = 1, // for menu
+ Width = 25,
+ Height = Dim.Fill (1),
+ CanFocus = true,
+ Shortcut = Key.CtrlMask | Key.C
+ };
+ LeftPane.Title = $"{LeftPane.Title} ({LeftPane.ShortcutTag})";
+ LeftPane.ShortcutAction = () => LeftPane.SetFocus ();
+
+ CategoryListView = new ListView (_categories) {
+ X = 0,
+ Y = 0,
+ Width = Dim.Fill (0),
+ Height = Dim.Fill (0),
+ AllowsMarking = false,
+ CanFocus = true,
+ };
+ CategoryListView.OpenSelectedItem += (a) => {
+ RightPane.SetFocus ();
+ };
+ CategoryListView.SelectedItemChanged += CategoryListView_SelectedChanged;
+ LeftPane.Add (CategoryListView);
+
+ RightPane = new FrameView ("Scenarios") {
+ X = 25,
+ Y = 1, // for menu
+ Width = Dim.Fill (),
+ Height = Dim.Fill (1),
+ CanFocus = true,
+ Shortcut = Key.CtrlMask | Key.S
+ };
+ RightPane.Title = $"{RightPane.Title} ({RightPane.ShortcutTag})";
+ RightPane.ShortcutAction = () => RightPane.SetFocus ();
+
+ ScenarioListView = new ListView () {
+ X = 0,
+ Y = 0,
+ Width = Dim.Fill (0),
+ Height = Dim.Fill (0),
+ AllowsMarking = false,
+ CanFocus = true,
+ };
+
+ ScenarioListView.OpenSelectedItem += ScenarioListView_OpenSelectedItem;
+ RightPane.Add (ScenarioListView);
+
+ KeyDown += KeyDownHandler;
+ Add (MenuBar);
+ Add (LeftPane);
+ Add (RightPane);
+ Add (StatusBar);
+
+ Loaded += LoadedHandler;
+
+ // Restore previous selections
+ CategoryListView.SelectedItem = _cachedCategoryIndex;
+ ScenarioListView.SelectedItem = _cachedScenarioIndex;
}
+ void LoadedHandler ()
+ {
+ Application.HeightAsBuffer = _heightAsBuffer;
+
+ if (_colorScheme == null) {
+ ColorScheme = _colorScheme = Colors.Base;
+ }
+
+ miIsMouseDisabled.Checked = Application.IsMouseDisabled;
+ miHeightAsBuffer.Checked = Application.HeightAsBuffer;
+ DriverName.Title = $"Driver: {Driver.GetType ().Name}";
+
+ if (_selectedScenario != null) {
+ _selectedScenario = null;
+ _isFirstRunning = false;
+ }
+ if (!_isFirstRunning) {
+ RightPane.SetFocus ();
+ }
+ Loaded -= LoadedHandler;
+ }
+
+ ///
+ /// Launches the selected scenario, setting the global _selectedScenario
+ ///
+ ///
+ void ScenarioListView_OpenSelectedItem (EventArgs e)
+ {
+ if (_selectedScenario is null) {
+ // Save selected item state
+ _cachedCategoryIndex = CategoryListView.SelectedItem;
+ _cachedScenarioIndex = ScenarioListView.SelectedItem;
+ // Create new instance of scenario (even though Scenarios contains instances)
+ _selectedScenario = (Scenario)Activator.CreateInstance (ScenarioListView.Source.ToList () [ScenarioListView.SelectedItem].GetType ());
+
+ // Tell the main app to stop
+ Application.RequestStop ();
+ }
+ }
+
+ List CreateDiagnosticMenuItems ()
+ {
+ List menuItems = new List ();
+ menuItems.Add (CreateDiagnosticFlagsMenuItems ());
+ menuItems.Add (new MenuItem [] { null });
+ menuItems.Add (CreateHeightAsBufferMenuItems ());
+ menuItems.Add (CreateDisabledEnabledMouseItems ());
+ menuItems.Add (CreateKeybindingsMenuItems ());
+ return menuItems;
+ }
+
+ MenuItem [] CreateDisabledEnabledMouseItems ()
+ {
+ List menuItems = new List ();
+ miIsMouseDisabled = new MenuItem ();
+ miIsMouseDisabled.Title = "_Disable Mouse";
+ miIsMouseDisabled.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miIsMouseDisabled.Title.ToString ().Substring (1, 1) [0];
+ miIsMouseDisabled.CheckType |= MenuItemCheckStyle.Checked;
+ miIsMouseDisabled.Action += () => {
+ miIsMouseDisabled.Checked = Application.IsMouseDisabled = !miIsMouseDisabled.Checked;
+ };
+ menuItems.Add (miIsMouseDisabled);
+
+ return menuItems.ToArray ();
+ }
+
+ MenuItem [] CreateKeybindingsMenuItems ()
+ {
+ List menuItems = new List ();
+ var item = new MenuItem ();
+ item.Title = "_Key Bindings";
+ item.Help = "Change which keys do what";
+ item.Action += () => {
+ var dlg = new KeyBindingsDialog ();
+ Application.Run (dlg);
+ };
+
+ menuItems.Add (null);
+ menuItems.Add (item);
+
+ return menuItems.ToArray ();
+ }
+
+ MenuItem [] CreateHeightAsBufferMenuItems ()
+ {
+ List menuItems = new List ();
+ miHeightAsBuffer = new MenuItem ();
+ miHeightAsBuffer.Title = "_Height As Buffer";
+ miHeightAsBuffer.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miHeightAsBuffer.Title.ToString ().Substring (1, 1) [0];
+ miHeightAsBuffer.CheckType |= MenuItemCheckStyle.Checked;
+ miHeightAsBuffer.Action += () => {
+ miHeightAsBuffer.Checked = !miHeightAsBuffer.Checked;
+ Application.HeightAsBuffer = miHeightAsBuffer.Checked;
+ };
+ menuItems.Add (miHeightAsBuffer);
+
+ return menuItems.ToArray ();
+ }
+
+ MenuItem [] CreateDiagnosticFlagsMenuItems ()
+ {
+ const string OFF = "Diagnostics: _Off";
+ const string FRAME_RULER = "Diagnostics: Frame _Ruler";
+ const string FRAME_PADDING = "Diagnostics: _Frame Padding";
+ var index = 0;
+
+ List menuItems = new List ();
+ foreach (Enum diag in Enum.GetValues (_diagnosticFlags.GetType ())) {
+ var item = new MenuItem ();
+ item.Title = GetDiagnosticsTitle (diag);
+ item.Shortcut = Key.AltMask + index.ToString () [0];
+ index++;
+ item.CheckType |= MenuItemCheckStyle.Checked;
+ if (GetDiagnosticsTitle (ConsoleDriver.DiagnosticFlags.Off) == item.Title) {
+ item.Checked = (_diagnosticFlags & (ConsoleDriver.DiagnosticFlags.FramePadding
+ | ConsoleDriver.DiagnosticFlags.FrameRuler)) == 0;
+ } else {
+ item.Checked = _diagnosticFlags.HasFlag (diag);
+ }
+ item.Action += () => {
+ var t = GetDiagnosticsTitle (ConsoleDriver.DiagnosticFlags.Off);
+ if (item.Title == t && !item.Checked) {
+ _diagnosticFlags &= ~(ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler);
+ item.Checked = true;
+ } else if (item.Title == t && item.Checked) {
+ _diagnosticFlags |= (ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler);
+ item.Checked = false;
+ } else {
+ var f = GetDiagnosticsEnumValue (item.Title);
+ if (_diagnosticFlags.HasFlag (f)) {
+ SetDiagnosticsFlag (f, false);
+ } else {
+ SetDiagnosticsFlag (f, true);
+ }
+ }
+ foreach (var menuItem in menuItems) {
+ if (menuItem.Title == t) {
+ menuItem.Checked = !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FrameRuler)
+ && !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FramePadding);
+ } else if (menuItem.Title != t) {
+ menuItem.Checked = _diagnosticFlags.HasFlag (GetDiagnosticsEnumValue (menuItem.Title));
+ }
+ }
+ ConsoleDriver.Diagnostics = _diagnosticFlags;
+ Application.Top.SetNeedsDisplay ();
+ };
+ menuItems.Add (item);
+ }
+ return menuItems.ToArray ();
+
+ string GetDiagnosticsTitle (Enum diag)
+ {
+ switch (Enum.GetName (_diagnosticFlags.GetType (), diag)) {
+ case "Off":
+ return OFF;
+ case "FrameRuler":
+ return FRAME_RULER;
+ case "FramePadding":
+ return FRAME_PADDING;
+ }
+ return "";
+ }
+
+ Enum GetDiagnosticsEnumValue (ustring title)
+ {
+ switch (title.ToString ()) {
+ case FRAME_RULER:
+ return ConsoleDriver.DiagnosticFlags.FrameRuler;
+ case FRAME_PADDING:
+ return ConsoleDriver.DiagnosticFlags.FramePadding;
+ }
+ return null;
+ }
+
+ void SetDiagnosticsFlag (Enum diag, bool add)
+ {
+ switch (diag) {
+ case ConsoleDriver.DiagnosticFlags.FrameRuler:
+ if (add) {
+ _diagnosticFlags |= ConsoleDriver.DiagnosticFlags.FrameRuler;
+ } else {
+ _diagnosticFlags &= ~ConsoleDriver.DiagnosticFlags.FrameRuler;
+ }
+ break;
+ case ConsoleDriver.DiagnosticFlags.FramePadding:
+ if (add) {
+ _diagnosticFlags |= ConsoleDriver.DiagnosticFlags.FramePadding;
+ } else {
+ _diagnosticFlags &= ~ConsoleDriver.DiagnosticFlags.FramePadding;
+ }
+ break;
+ default:
+ _diagnosticFlags = default;
+ break;
+ }
+ }
+ }
+
+ MenuItem [] CreateColorSchemeMenuItems ()
+ {
+ List menuItems = new List ();
+ foreach (var sc in Colors.ColorSchemes) {
+ var item = new MenuItem ();
+ item.Title = $"_{sc.Key}";
+ item.Shortcut = Key.AltMask | (Key)sc.Key.Substring (0, 1) [0];
+ item.CheckType |= MenuItemCheckStyle.Radio;
+ item.Checked = sc.Value == _colorScheme;
+ item.Action += () => {
+ ColorScheme = _colorScheme = sc.Value;
+ SetNeedsDisplay ();
+ foreach (var menuItem in menuItems) {
+ menuItem.Checked = menuItem.Title.Equals ($"_{sc.Key}") && sc.Value == _colorScheme;
+ }
+ };
+ menuItems.Add (item);
+ }
+ return menuItems.ToArray ();
+ }
+
+ void KeyDownHandler (View.KeyEventEventArgs a)
+ {
+ if (a.KeyEvent.IsCapslock) {
+ Capslock.Title = "Caps: On";
+ StatusBar.SetNeedsDisplay ();
+ } else {
+ Capslock.Title = "Caps: Off";
+ StatusBar.SetNeedsDisplay ();
+ }
+
+ if (a.KeyEvent.IsNumlock) {
+ Numlock.Title = "Num: On";
+ StatusBar.SetNeedsDisplay ();
+ } else {
+ Numlock.Title = "Num: Off";
+ StatusBar.SetNeedsDisplay ();
+ }
+
+ if (a.KeyEvent.IsScrolllock) {
+ Scrolllock.Title = "Scroll: On";
+ StatusBar.SetNeedsDisplay ();
+ } else {
+ Scrolllock.Title = "Scroll: Off";
+ StatusBar.SetNeedsDisplay ();
+ }
+ }
+
+ void CategoryListView_SelectedChanged (ListViewItemEventArgs e)
+ {
+ var item = _categories [e.Item];
+ List newlist;
+ if (e.Item == 0) {
+ // First category is "All"
+ newlist = _scenarios;
+
+ } else {
+ newlist = _scenarios.Where (s => s.GetCategories ().Contains (item)).ToList ();
+ }
+ ScenarioListView.SetSource (newlist.ToList ());
+ }
+ }
+
+ static void VerifyObjectsWereDisposed ()
+ {
#if DEBUG_IDISPOSABLE
- // This proves that when the user exited the UI Catalog app
- // it cleaned up properly.
+ // Validate there are no outstanding Responder-based instances
+ // after a scenario was selected to run. This proves the main UI Catalog
+ // 'app' closed cleanly.
foreach (var inst in Responder.Instances) {
Debug.Assert (inst.WasDisposed);
}
Responder.Instances.Clear ();
+
+ // Validate there are no outstanding Application.RunState-based instances
+ // after a scenario was selected to run. This proves the main UI Catalog
+ // 'app' closed cleanly.
+ foreach (var inst in Application.RunState.Instances) {
+ Debug.Assert (inst.WasDisposed);
+ }
+ Application.RunState.Instances.Clear ();
#endif
}
@@ -158,389 +539,20 @@ namespace UICatalog {
/// When the Scenario exits, this function exits.
///
///
- private static Scenario SelectScenario ()
+ static Scenario SelectScenario ()
{
Application.UseSystemConsole = _useSystemConsole;
- Application.Init ();
- if (_colorScheme == null) {
- // `Colors` is not initilized until the ConsoleDriver is loaded by
- // Application.Init. Set it only the first time though so it is
- // preserved between running multiple Scenarios
- _colorScheme = Colors.Base;
- }
- Application.HeightAsBuffer = _heightAsBuffer;
-
- var menu = new MenuBar (new MenuBarItem [] {
- new MenuBarItem ("_File", new MenuItem [] {
- new MenuItem ("_Quit", "Quit UI Catalog", () => Application.RequestStop(), null, null, Key.Q | Key.CtrlMask)
- }),
- new MenuBarItem ("_Color Scheme", CreateColorSchemeMenuItems()),
- new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems()),
- new MenuBarItem ("_Help", new MenuItem [] {
- new MenuItem ("_gui.cs API Overview", "", () => OpenUrl ("https://gui-cs.github.io/Terminal.Gui/articles/overview.html"), null, null, Key.F1),
- new MenuItem ("gui.cs _README", "", () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"), null, null, Key.F2),
- new MenuItem ("_About...",
- "About UI Catalog", () => MessageBox.Query ("About UI Catalog", _aboutMessage.ToString(), "_Ok"), null, null, Key.CtrlMask | Key.A),
- }),
- });
-
- _leftPane = new FrameView ("Categories") {
- X = 0,
- Y = 1, // for menu
- Width = 25,
- Height = Dim.Fill (1),
- CanFocus = true,
- Shortcut = Key.CtrlMask | Key.C
- };
- _leftPane.Title = $"{_leftPane.Title} ({_leftPane.ShortcutTag})";
- _leftPane.ShortcutAction = () => _leftPane.SetFocus ();
-
- _categories = Scenario.GetAllCategories ();
- _categoryListView = new ListView (_categories) {
- X = 0,
- Y = 0,
- Width = Dim.Fill (0),
- Height = Dim.Fill (0),
- AllowsMarking = false,
- CanFocus = true,
- };
- _categoryListView.OpenSelectedItem += (a) => {
- _rightPane.SetFocus ();
- };
- _categoryListView.SelectedItemChanged += CategoryListView_SelectedChanged;
- _leftPane.Add (_categoryListView);
-
- _rightPane = new FrameView ("Scenarios") {
- X = 25,
- Y = 1, // for menu
- Width = Dim.Fill (),
- Height = Dim.Fill (1),
- CanFocus = true,
- Shortcut = Key.CtrlMask | Key.S
- };
- _rightPane.Title = $"{_rightPane.Title} ({_rightPane.ShortcutTag})";
- _rightPane.ShortcutAction = () => _rightPane.SetFocus ();
-
- _nameColumnWidth = _scenarios.OrderByDescending (s => s.GetName ().Length).FirstOrDefault ().GetName ().Length;
-
- _scenarioListView = new ListView () {
- X = 0,
- Y = 0,
- Width = Dim.Fill (0),
- Height = Dim.Fill (0),
- AllowsMarking = false,
- CanFocus = true,
- };
-
- _scenarioListView.OpenSelectedItem += _scenarioListView_OpenSelectedItem;
- _rightPane.Add (_scenarioListView);
-
- _capslock = new StatusItem (Key.CharMask, "Caps", null);
- _numlock = new StatusItem (Key.CharMask, "Num", null);
- _scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
-
- _statusBar = new StatusBar () {
- Visible = true,
- };
- _statusBar.Items = new StatusItem [] {
- _capslock,
- _numlock,
- _scrolllock,
- new StatusItem(Key.Q | Key.CtrlMask, "~CTRL-Q~ Quit", () => {
- if (_selectedScenario is null){
- // This causes GetScenarioToRun to return null
- _selectedScenario = null;
- Application.RequestStop();
- } else {
- _selectedScenario.RequestStop();
- }
- }),
- new StatusItem(Key.F10, "~F10~ Hide/Show Status Bar", () => {
- _statusBar.Visible = !_statusBar.Visible;
- _leftPane.Height = Dim.Fill(_statusBar.Visible ? 1 : 0);
- _rightPane.Height = Dim.Fill(_statusBar.Visible ? 1 : 0);
- Application.Top.LayoutSubviews();
- Application.Top.SetChildNeedsDisplay();
- }),
- new StatusItem (Key.CharMask, Application.Driver.GetType ().Name, null),
- };
-
- Application.Top.ColorScheme = _colorScheme;
- Application.Top.KeyDown += KeyDownHandler;
- Application.Top.Add (menu);
- Application.Top.Add (_leftPane);
- Application.Top.Add (_rightPane);
- Application.Top.Add (_statusBar);
-
- void TopHandler ()
- {
- if (_selectedScenario != null) {
- _selectedScenario = null;
- _isFirstRunning = false;
- }
- if (!_isFirstRunning) {
- _rightPane.SetFocus ();
- }
- Application.Top.Loaded -= TopHandler;
- }
- Application.Top.Loaded += TopHandler;
-
- // Restore previous selections
- _categoryListView.SelectedItem = _cachedCategoryIndex;
- _scenarioListView.SelectedItem = _cachedScenarioIndex;
+ //var top = new UICatalogTopLevel ();
// Run UI Catalog UI. When it exits, if _selectedScenario is != null then
// a Scenario was selected. Otherwise, the user wants to exit UI Catalog.
- Application.Run (Application.Top);
+ Application.Run ();
Application.Shutdown ();
return _selectedScenario;
}
-
- ///
- /// Launches the selected scenario, setting the global _selectedScenario
- ///
- ///
- private static void _scenarioListView_OpenSelectedItem (EventArgs e)
- {
- if (_selectedScenario is null) {
- // Save selected item state
- _cachedCategoryIndex = _categoryListView.SelectedItem;
- _cachedScenarioIndex = _scenarioListView.SelectedItem;
- // Create new instance of scenario (even though Scenarios contains instances)
- _selectedScenario = (Scenario)Activator.CreateInstance (_scenarioListView.Source.ToList () [_scenarioListView.SelectedItem].GetType ());
-
- // Tell the main app to stop
- Application.RequestStop ();
- }
- }
-
- static List CreateDiagnosticMenuItems ()
- {
- List menuItems = new List ();
- menuItems.Add (CreateDiagnosticFlagsMenuItems ());
- menuItems.Add (new MenuItem [] { null });
- menuItems.Add (CreateSizeStyle ());
- menuItems.Add (CreateDisabledEnabledMouse ());
- menuItems.Add (CreateKeybindings ());
- return menuItems;
- }
-
- private static MenuItem [] CreateDisabledEnabledMouse ()
- {
- List menuItems = new List ();
- var item = new MenuItem ();
- item.Title = "_Disable Mouse";
- item.Shortcut = Key.CtrlMask | Key.AltMask | (Key)item.Title.ToString ().Substring (1, 1) [0];
- item.CheckType |= MenuItemCheckStyle.Checked;
- item.Checked = Application.IsMouseDisabled;
- item.Action += () => {
- item.Checked = Application.IsMouseDisabled = !item.Checked;
- };
- menuItems.Add (item);
-
- return menuItems.ToArray ();
- }
- private static MenuItem [] CreateKeybindings ()
- {
-
- List menuItems = new List ();
- var item = new MenuItem ();
- item.Title = "_Key Bindings";
- item.Help = "Change which keys do what";
- item.Action += () => {
- var dlg = new KeyBindingsDialog ();
- Application.Run (dlg);
- };
-
- menuItems.Add (null);
- menuItems.Add (item);
-
- return menuItems.ToArray ();
- }
-
- static MenuItem [] CreateSizeStyle ()
- {
- List menuItems = new List ();
- var item = new MenuItem ();
- item.Title = "_Height As Buffer";
- item.Shortcut = Key.CtrlMask | Key.AltMask | (Key)item.Title.ToString ().Substring (1, 1) [0];
- item.CheckType |= MenuItemCheckStyle.Checked;
- item.Checked = Application.HeightAsBuffer;
- item.Action += () => {
- item.Checked = !item.Checked;
- _heightAsBuffer = item.Checked;
- Application.HeightAsBuffer = _heightAsBuffer;
- };
- menuItems.Add (item);
-
- return menuItems.ToArray ();
- }
-
- static MenuItem [] CreateDiagnosticFlagsMenuItems ()
- {
- const string OFF = "Diagnostics: _Off";
- const string FRAME_RULER = "Diagnostics: Frame _Ruler";
- const string FRAME_PADDING = "Diagnostics: _Frame Padding";
- var index = 0;
-
- List menuItems = new List ();
- foreach (Enum diag in Enum.GetValues (_diagnosticFlags.GetType ())) {
- var item = new MenuItem ();
- item.Title = GetDiagnosticsTitle (diag);
- item.Shortcut = Key.AltMask + index.ToString () [0];
- index++;
- item.CheckType |= MenuItemCheckStyle.Checked;
- if (GetDiagnosticsTitle (ConsoleDriver.DiagnosticFlags.Off) == item.Title) {
- item.Checked = (_diagnosticFlags & (ConsoleDriver.DiagnosticFlags.FramePadding
- | ConsoleDriver.DiagnosticFlags.FrameRuler)) == 0;
- } else {
- item.Checked = _diagnosticFlags.HasFlag (diag);
- }
- item.Action += () => {
- var t = GetDiagnosticsTitle (ConsoleDriver.DiagnosticFlags.Off);
- if (item.Title == t && !item.Checked) {
- _diagnosticFlags &= ~(ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler);
- item.Checked = true;
- } else if (item.Title == t && item.Checked) {
- _diagnosticFlags |= (ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler);
- item.Checked = false;
- } else {
- var f = GetDiagnosticsEnumValue (item.Title);
- if (_diagnosticFlags.HasFlag (f)) {
- SetDiagnosticsFlag (f, false);
- } else {
- SetDiagnosticsFlag (f, true);
- }
- }
- foreach (var menuItem in menuItems) {
- if (menuItem.Title == t) {
- menuItem.Checked = !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FrameRuler)
- && !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FramePadding);
- } else if (menuItem.Title != t) {
- menuItem.Checked = _diagnosticFlags.HasFlag (GetDiagnosticsEnumValue (menuItem.Title));
- }
- }
- ConsoleDriver.Diagnostics = _diagnosticFlags;
- Application.Top.SetNeedsDisplay ();
- };
- menuItems.Add (item);
- }
- return menuItems.ToArray ();
-
- string GetDiagnosticsTitle (Enum diag)
- {
- switch (Enum.GetName (_diagnosticFlags.GetType (), diag)) {
- case "Off":
- return OFF;
- case "FrameRuler":
- return FRAME_RULER;
- case "FramePadding":
- return FRAME_PADDING;
- }
- return "";
- }
-
- Enum GetDiagnosticsEnumValue (ustring title)
- {
- switch (title.ToString ()) {
- case FRAME_RULER:
- return ConsoleDriver.DiagnosticFlags.FrameRuler;
- case FRAME_PADDING:
- return ConsoleDriver.DiagnosticFlags.FramePadding;
- }
- return null;
- }
-
- void SetDiagnosticsFlag (Enum diag, bool add)
- {
- switch (diag) {
- case ConsoleDriver.DiagnosticFlags.FrameRuler:
- if (add) {
- _diagnosticFlags |= ConsoleDriver.DiagnosticFlags.FrameRuler;
- } else {
- _diagnosticFlags &= ~ConsoleDriver.DiagnosticFlags.FrameRuler;
- }
- break;
- case ConsoleDriver.DiagnosticFlags.FramePadding:
- if (add) {
- _diagnosticFlags |= ConsoleDriver.DiagnosticFlags.FramePadding;
- } else {
- _diagnosticFlags &= ~ConsoleDriver.DiagnosticFlags.FramePadding;
- }
- break;
- default:
- _diagnosticFlags = default;
- break;
- }
- }
- }
-
- static ColorScheme _colorScheme;
- static MenuItem [] CreateColorSchemeMenuItems ()
- {
- List menuItems = new List ();
- foreach (var sc in Colors.ColorSchemes) {
- var item = new MenuItem ();
- item.Title = $"_{sc.Key}";
- item.Shortcut = Key.AltMask | (Key)sc.Key.Substring (0, 1) [0];
- item.CheckType |= MenuItemCheckStyle.Radio;
- item.Checked = sc.Value == _colorScheme;
- item.Action += () => {
- Application.Top.ColorScheme = _colorScheme = sc.Value;
- Application.Top?.SetNeedsDisplay ();
- foreach (var menuItem in menuItems) {
- menuItem.Checked = menuItem.Title.Equals ($"_{sc.Key}") && sc.Value == _colorScheme;
- }
- };
- menuItems.Add (item);
- }
- return menuItems.ToArray ();
- }
-
- private static void KeyDownHandler (View.KeyEventEventArgs a)
- {
- if (a.KeyEvent.IsCapslock) {
- _capslock.Title = "Caps: On";
- _statusBar.SetNeedsDisplay ();
- } else {
- _capslock.Title = "Caps: Off";
- _statusBar.SetNeedsDisplay ();
- }
-
- if (a.KeyEvent.IsNumlock) {
- _numlock.Title = "Num: On";
- _statusBar.SetNeedsDisplay ();
- } else {
- _numlock.Title = "Num: Off";
- _statusBar.SetNeedsDisplay ();
- }
-
- if (a.KeyEvent.IsScrolllock) {
- _scrolllock.Title = "Scroll: On";
- _statusBar.SetNeedsDisplay ();
- } else {
- _scrolllock.Title = "Scroll: Off";
- _statusBar.SetNeedsDisplay ();
- }
- }
-
- private static void CategoryListView_SelectedChanged (ListViewItemEventArgs e)
- {
- var item = _categories [e.Item];
- List newlist;
- if (e.Item == 0) {
- // First category is "All"
- newlist = _scenarios;
-
- } else {
- newlist = _scenarios.Where (s => s.GetCategories ().Contains (item)).ToList ();
- }
- _scenarioListView.SetSource (newlist.ToList ());
- }
-
- private static void OpenUrl (string url)
+ static void OpenUrl (string url)
{
try {
if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs
index 597534c74..c10aaf211 100644
--- a/UnitTests/ApplicationTests.cs
+++ b/UnitTests/ApplicationTests.cs
@@ -14,9 +14,47 @@ namespace Terminal.Gui.Core {
{
#if DEBUG_IDISPOSABLE
Responder.Instances.Clear ();
+ Application.RunState.Instances.Clear ();
#endif
}
+ void Pre_Init_State ()
+ {
+ Assert.Null (Application.Driver);
+ Assert.Null (Application.Top);
+ Assert.Null (Application.Current);
+ Assert.Throws (() => Application.HeightAsBuffer == true);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Iteration);
+ Assert.Null (Application.RootMouseEvent);
+ Assert.Null (Application.Resized);
+ }
+
+ void Post_Init_State ()
+ {
+ Assert.NotNull (Application.Driver);
+ Assert.NotNull (Application.Top);
+ Assert.NotNull (Application.Current);
+ Assert.False (Application.HeightAsBuffer);
+ Assert.NotNull (Application.MainLoop);
+ Assert.Null (Application.Iteration);
+ Assert.Null (Application.RootMouseEvent);
+ Assert.Null (Application.Resized);
+ }
+
+ void Init ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+ Assert.NotNull (Application.Driver);
+ Assert.NotNull (Application.MainLoop);
+ Assert.NotNull (SynchronizationContext.Current);
+ }
+
+ void Shutdown ()
+ {
+ Application.Shutdown ();
+ }
+
[Fact]
public void Init_Shutdown_Cleans_Up ()
{
@@ -40,7 +78,7 @@ namespace Terminal.Gui.Core {
// Verify state is back to initial
Pre_Init_State ();
-
+
// Validate there are no outstanding Responder-based instances
// after a scenario was selected to run. This proves the main UI Catalog
// 'app' closed cleanly.
@@ -48,75 +86,69 @@ namespace Terminal.Gui.Core {
Assert.True (inst.WasDisposed);
}
}
-
- void Pre_Init_State ()
- {
- Assert.Null (Application.Driver);
- Assert.Null (Application.Top);
- Assert.Null (Application.Current);
- Assert.Throws (() => Application.HeightAsBuffer == true);
- Assert.Null (Application.MainLoop);
- Assert.Null (Application.Iteration);
- Assert.Null (Application.RootMouseEvent);
- Assert.Null (Application.Resized);
- }
-
- void Post_Init_State ()
- {
- Assert.NotNull (Application.Driver);
- Assert.NotNull (Application.Top);
- Assert.NotNull (Application.Current);
- Assert.False (Application.HeightAsBuffer);
- Assert.NotNull (Application.MainLoop);
- Assert.Null (Application.Iteration);
- Assert.Null (Application.RootMouseEvent);
- Assert.Null (Application.Resized);
- }
[Fact]
- public void RunState_Dispose_Cleans_Up ()
- {
- var rs = new Application.RunState (null);
- Assert.NotNull (rs);
-
- // Should not throw because Toplevel was null
- rs.Dispose ();
-
- var top = new Toplevel ();
- rs = new Application.RunState (top);
- Assert.NotNull (rs);
-
- // Should throw because there's no stack
- Assert.Throws (() => rs.Dispose ());
- }
-
- void Init ()
+ public void Init_Unbalanced_Throwss ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
- Assert.NotNull (Application.Driver);
- Assert.NotNull (Application.MainLoop);
- Assert.NotNull (SynchronizationContext.Current);
+
+ Toplevel topLevel = null;
+ Assert.Throws (() => Application.Init (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))));
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+
+ // Now try the other way
+ topLevel = null;
+ Application.Init (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ Assert.Throws (() => Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))));
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+
+ class TestToplevel : Toplevel {
+ public TestToplevel ()
+ {
+ IsMdiContainer = false;
+ }
}
- void Shutdown ()
- {
- Application.Shutdown ();
- }
-
[Fact]
- public void Begin_End_Cleans_Up ()
+ public void Init_Begin_End_Cleans_Up ()
{
- // Setup Mock driver
Init ();
+
+ // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
+ // if we don't stop
+ Application.Iteration = () => {
+ Application.RequestStop ();
+ };
- // Test null Toplevel
- Assert.Throws (() => Application.Begin (null));
+ Application.RunState runstate = null;
+ Action NewRunStateFn = (rs) => {
+ Assert.NotNull (rs);
+ runstate = rs;
+ };
+ Application.NotifyNewRunState += NewRunStateFn;
- var top = new Toplevel ();
- var rs = Application.Begin (top);
+ Toplevel topLevel = new Toplevel();
+ var rs = Application.Begin (topLevel);
Assert.NotNull (rs);
- Assert.Equal (top, Application.Current);
- Application.End (rs);
+ Assert.NotNull (runstate);
+ Assert.Equal (rs, runstate);
+
+ Assert.Equal (topLevel, Application.Top);
+ Assert.Equal (topLevel, Application.Current);
+
+ Application.NotifyNewRunState -= NewRunStateFn;
+ Application.End (runstate);
Assert.Null (Application.Current);
Assert.NotNull (Application.Top);
@@ -131,7 +163,141 @@ namespace Terminal.Gui.Core {
}
[Fact]
- public void RequestStop_Stops ()
+ public void InitWithTopLevelFactory_Begin_End_Cleans_Up ()
+ {
+ // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
+ // if we don't stop
+ Application.Iteration = () => {
+ Application.RequestStop ();
+ };
+
+ // NOTE: Run, when called after Init has been called behaves differently than
+ // when called if Init has not been called.
+ Toplevel topLevel = null;
+ Application.Init (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ Application.RunState runstate = null;
+ Action NewRunStateFn = (rs) => {
+ Assert.NotNull (rs);
+ runstate = rs;
+ };
+ Application.NotifyNewRunState += NewRunStateFn;
+
+ var rs = Application.Begin (topLevel);
+ Assert.NotNull (rs);
+ Assert.NotNull (runstate);
+ Assert.Equal (rs, runstate);
+
+ Assert.Equal (topLevel, Application.Top);
+ Assert.Equal (topLevel, Application.Current);
+
+ Application.NotifyNewRunState -= NewRunStateFn;
+ Application.End (runstate);
+
+ Assert.Null (Application.Current);
+ Assert.NotNull (Application.Top);
+ Assert.NotNull (Application.MainLoop);
+ Assert.NotNull (Application.Driver);
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ [Fact]
+ public void Begin_Null_Toplevel_Throws ()
+ {
+ // Setup Mock driver
+ Init ();
+
+ // Test null Toplevel
+ Assert.Throws (() => Application.Begin (null));
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ #region RunTests
+
+ [Fact]
+ public void Run_T_InitWithDriver_Throws_with_TopLevel ()
+ {
+ // Setup Mock driver
+ Init ();
+
+ // Run when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
+ Assert.Throws (() => Application.Run (errorHandler: null));
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ [Fact]
+ public void Run_T_InitWithDriver_Works_with_TestTopLevel ()
+ {
+ // Setup Mock driver
+ Init ();
+
+ Application.Iteration = () => {
+ Application.RequestStop ();
+ };
+
+ // Run when already initialized with a Driver will work
+ Application.Run (errorHandler: null);
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ [Fact]
+ public void Run_T_NoInit_ThrowsInDefaultDriver ()
+ {
+ Application.Iteration = () => {
+ Application.RequestStop ();
+ };
+
+ // Note that Init has NOT been called and we're passing no driver
+ // The platform-default driver will be selected and it will barf
+ Assert.ThrowsAny (() => Application.Run (errorHandler: null, driver: null, mainLoopDriver: null));
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ [Fact]
+ public void Run_T_NoInit_Works_WithFakeDriver ()
+ {
+ Application.Iteration = () => {
+ Application.RequestStop ();
+ };
+
+ // Note that Init has NOT been called and we're passing no driver
+ // The platform-default driver will be selected and it will barf
+ Application.Run (errorHandler: null, new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ Shutdown ();
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+
+ [Fact]
+ public void Run_RequestStop_Stops ()
{
// Setup Mock driver
Init ();
@@ -155,7 +321,7 @@ namespace Terminal.Gui.Core {
}
[Fact]
- public void RunningFalse_Stops ()
+ public void Run_RunningFalse_Stops ()
{
// Setup Mock driver
Init ();
@@ -178,7 +344,139 @@ namespace Terminal.Gui.Core {
Assert.Null (Application.Driver);
}
+ [Fact]
+ public void Run_Loaded_Ready_Unlodaded_Events ()
+ {
+ Init ();
+ var top = Application.Top;
+ var count = 0;
+ top.Loaded += () => count++;
+ top.Ready += () => count++;
+ top.Unloaded += () => count++;
+ Application.Iteration = () => Application.RequestStop ();
+ Application.Run ();
+ Application.Shutdown ();
+ Assert.Equal (3, count);
+ }
+ #endregion
+ #region ShutdownTests
+ [Fact]
+ public void Shutdown_Allows_Async ()
+ {
+ static async Task TaskWithAsyncContinuation ()
+ {
+ await Task.Yield ();
+ await Task.Yield ();
+ }
+
+ Init ();
+ Application.Shutdown ();
+
+ var task = TaskWithAsyncContinuation ();
+ Thread.Sleep (20);
+ Assert.True (task.IsCompletedSuccessfully);
+ }
+
+ [Fact]
+ public void Shutdown_Resets_SyncContext ()
+ {
+ Init ();
+ Application.Shutdown ();
+ Assert.Null (SynchronizationContext.Current);
+ }
+ #endregion
+
+ [Fact]
+ [AutoInitShutdown]
+ public void SetCurrentAsTop_Run_A_Not_Modal_Toplevel_Make_It_The_Current_Application_Top ()
+ {
+ var t1 = new Toplevel ();
+ var t2 = new Toplevel ();
+ var t3 = new Toplevel ();
+ var d = new Dialog ();
+ var t4 = new Toplevel ();
+
+ // t1, t2, t3, d, t4
+ var iterations = 5;
+
+ t1.Ready += () => {
+ Assert.Equal (t1, Application.Top);
+ Application.Run (t2);
+ };
+ t2.Ready += () => {
+ Assert.Equal (t2, Application.Top);
+ Application.Run (t3);
+ };
+ t3.Ready += () => {
+ Assert.Equal (t3, Application.Top);
+ Application.Run (d);
+ };
+ d.Ready += () => {
+ Assert.Equal (t3, Application.Top);
+ Application.Run (t4);
+ };
+ t4.Ready += () => {
+ Assert.Equal (t4, Application.Top);
+ t4.RequestStop ();
+ d.RequestStop ();
+ t3.RequestStop ();
+ t2.RequestStop ();
+ };
+ // Now this will close the MdiContainer when all MdiChildes was closed
+ t2.Closed += (_) => {
+ t1.RequestStop ();
+ };
+ Application.Iteration += () => {
+ if (iterations == 5) {
+ // The Current still is t4 because Current.Running is false.
+ Assert.Equal (t4, Application.Current);
+ Assert.False (Application.Current.Running);
+ Assert.Equal (t4, Application.Top);
+ } else if (iterations == 4) {
+ // The Current is d and Current.Running is false.
+ Assert.Equal (d, Application.Current);
+ Assert.False (Application.Current.Running);
+ Assert.Equal (t4, Application.Top);
+ } else if (iterations == 3) {
+ // The Current is t3 and Current.Running is false.
+ Assert.Equal (t3, Application.Current);
+ Assert.False (Application.Current.Running);
+ Assert.Equal (t3, Application.Top);
+ } else if (iterations == 2) {
+ // The Current is t2 and Current.Running is false.
+ Assert.Equal (t2, Application.Current);
+ Assert.False (Application.Current.Running);
+ Assert.Equal (t2, Application.Top);
+ } else {
+ // The Current is t1.
+ Assert.Equal (t1, Application.Current);
+ Assert.False (Application.Current.Running);
+ Assert.Equal (t1, Application.Top);
+ }
+ iterations--;
+ };
+
+ Application.Run (t1);
+
+ Assert.Equal (t1, Application.Top);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void Internal_Properties_Correct ()
+ {
+ Assert.True (Application._initialized);
+ Assert.NotNull (Application.Top);
+ var rs = Application.Begin (Application.Top);
+ Assert.Equal (Application.Top, rs.Toplevel);
+ Assert.Null (Application.MouseGrabView); // public
+ Assert.Null (Application.WantContinuousButtonPressedView); // public
+ Assert.False (Application.DebugDrawBounds);
+ Assert.False (Application.ShowChild (Application.Top));
+ }
+
+ #region KeyboardTests
[Fact]
public void KeyUp_Event ()
{
@@ -239,46 +537,6 @@ namespace Terminal.Gui.Core {
Assert.Null (Application.Driver);
}
- [Fact]
- public void Loaded_Ready_Unlodaded_Events ()
- {
- Init ();
- var top = Application.Top;
- var count = 0;
- top.Loaded += () => count++;
- top.Ready += () => count++;
- top.Unloaded += () => count++;
- Application.Iteration = () => Application.RequestStop ();
- Application.Run ();
- Application.Shutdown ();
- Assert.Equal (3, count);
- }
-
- [Fact]
- public void Shutdown_Allows_Async ()
- {
- static async Task TaskWithAsyncContinuation ()
- {
- await Task.Yield ();
- await Task.Yield ();
- }
-
- Init ();
- Application.Shutdown ();
-
- var task = TaskWithAsyncContinuation ();
- Thread.Sleep (20);
- Assert.True (task.IsCompletedSuccessfully);
- }
-
- [Fact]
- public void Shutdown_Resets_SyncContext ()
- {
- Init ();
- Application.Shutdown ();
- Assert.Null (SynchronizationContext.Current);
- }
-
[Fact]
public void AlternateForwardKey_AlternateBackwardKey_Tests ()
{
@@ -392,776 +650,6 @@ namespace Terminal.Gui.Core {
Application.Shutdown ();
}
- [Fact]
- public void Application_RequestStop_With_Params_On_A_Not_MdiContainer_Always_Use_The_Application_Current ()
- {
- Init ();
-
- var top1 = new Toplevel ();
- var top2 = new Toplevel ();
- var top3 = new Window ();
- var top4 = new Window ();
- var d = new Dialog ();
-
- // top1, top2, top3, d1 = 4
- var iterations = 4;
-
- top1.Ready += () => {
- Assert.Null (Application.MdiChildes);
- Application.Run (top2);
- };
- top2.Ready += () => {
- Assert.Null (Application.MdiChildes);
- Application.Run (top3);
- };
- top3.Ready += () => {
- Assert.Null (Application.MdiChildes);
- Application.Run (top4);
- };
- top4.Ready += () => {
- Assert.Null (Application.MdiChildes);
- Application.Run (d);
- };
-
- d.Ready += () => {
- Assert.Null (Application.MdiChildes);
- // This will close the d because on a not MdiContainer the Application.Current it always used.
- Application.RequestStop (top1);
- Assert.True (Application.Current == d);
- };
-
- d.Closed += (e) => Application.RequestStop (top1);
-
- Application.Iteration += () => {
- Assert.Null (Application.MdiChildes);
- if (iterations == 4) {
- Assert.True (Application.Current == d);
- } else if (iterations == 3) {
- Assert.True (Application.Current == top4);
- } else if (iterations == 2) {
- Assert.True (Application.Current == top3);
- } else if (iterations == 1) {
- Assert.True (Application.Current == top2);
- } else {
- Assert.True (Application.Current == top1);
- }
- Application.RequestStop (top1);
- iterations--;
- };
-
- Application.Run (top1);
-
- Assert.Null (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- class Mdi : Toplevel {
- public Mdi ()
- {
- IsMdiContainer = true;
- }
- }
-
- [Fact]
- public void MdiContainer_With_Toplevel_RequestStop_Balanced ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d = new Dialog ();
-
- // MdiChild = c1, c2, c3
- // d1 = 1
- var iterations = 4;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d);
- };
-
- // More easy because the Mdi Container handles all at once
- d.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- // This will not close the MdiContainer because d is a modal toplevel and will be closed.
- mdi.RequestStop ();
- };
-
- // Now this will close the MdiContainer propagating through the MdiChildes.
- d.Closed += (e) => {
- mdi.RequestStop ();
- };
-
- Application.Iteration += () => {
- if (iterations == 4) {
- // The Dialog was not closed before and will be closed now.
- Assert.True (Application.Current == d);
- Assert.False (d.Running);
- } else {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- for (int i = 0; i < iterations; i++) {
- Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
- }
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void MdiContainer_With_Application_RequestStop_MdiTop_With_Params ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d = new Dialog ();
-
- // MdiChild = c1, c2, c3
- // d1 = 1
- var iterations = 4;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d);
- };
-
- // Also easy because the Mdi Container handles all at once
- d.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- // This will not close the MdiContainer because d is a modal toplevel
- Application.RequestStop (mdi);
- };
-
- // Now this will close the MdiContainer propagating through the MdiChildes.
- d.Closed += (e) => Application.RequestStop (mdi);
-
- Application.Iteration += () => {
- if (iterations == 4) {
- // The Dialog was not closed before and will be closed now.
- Assert.True (Application.Current == d);
- Assert.False (d.Running);
- } else {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- for (int i = 0; i < iterations; i++) {
- Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
- }
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void MdiContainer_With_Application_RequestStop_MdiTop_Without_Params ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d = new Dialog ();
-
- // MdiChild = c1, c2, c3 = 3
- // d1 = 1
- var iterations = 4;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d);
- };
-
- //More harder because it's sequential.
- d.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- // Close the Dialog
- Application.RequestStop ();
- };
-
- // Now this will close the MdiContainer propagating through the MdiChildes.
- d.Closed += (e) => Application.RequestStop (mdi);
-
- Application.Iteration += () => {
- if (iterations == 4) {
- // The Dialog still is the current top and we can't request stop to MdiContainer
- // because we are not using parameter calls.
- Assert.True (Application.Current == d);
- Assert.False (d.Running);
- } else {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- for (int i = 0; i < iterations; i++) {
- Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
- }
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void IsMdiChild_Testing ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d = new Dialog ();
-
- Application.Iteration += () => {
- Assert.False (mdi.IsMdiChild);
- Assert.True (c1.IsMdiChild);
- Assert.True (c2.IsMdiChild);
- Assert.True (c3.IsMdiChild);
- Assert.False (d.IsMdiChild);
-
- mdi.RequestStop ();
- };
-
- Application.Run (mdi);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d1 = new Dialog ();
- var d2 = new Dialog ();
-
- // MdiChild = c1, c2, c3 = 3
- // d1, d2 = 2
- var iterations = 5;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d1);
- };
- d1.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d2);
- };
-
- d2.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Assert.True (Application.Current == d2);
- Assert.True (Application.Current.Running);
- // Trying to close the Dialog1
- d1.RequestStop ();
- };
-
- // Now this will close the MdiContainer propagating through the MdiChildes.
- d1.Closed += (e) => {
- Assert.True (Application.Current == d1);
- Assert.False (Application.Current.Running);
- mdi.RequestStop ();
- };
-
- Application.Iteration += () => {
- if (iterations == 5) {
- // The Dialog2 still is the current top and we can't request stop to MdiContainer
- // because Dialog2 and Dialog1 must be closed first.
- // Dialog2 will be closed in this iteration.
- Assert.True (Application.Current == d2);
- Assert.False (Application.Current.Running);
- Assert.False (d1.Running);
- } else if (iterations == 4) {
- // Dialog1 will be closed in this iteration.
- Assert.True (Application.Current == d1);
- Assert.False (Application.Current.Running);
- } else {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- for (int i = 0; i < iterations; i++) {
- Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
- }
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
- var d1 = new Dialog ();
- var c4 = new Toplevel ();
-
- // MdiChild = c1, c2, c3, c4 = 4
- // d1 = 1
- var iterations = 5;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (d1);
- };
- d1.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- Application.Run (c4);
- };
-
- c4.Ready += () => {
- Assert.Equal (4, Application.MdiChildes.Count);
- // Trying to close the Dialog1
- d1.RequestStop ();
- };
-
- // Now this will close the MdiContainer propagating through the MdiChildes.
- d1.Closed += (e) => {
- mdi.RequestStop ();
- };
-
- Application.Iteration += () => {
- if (iterations == 5) {
- // The Dialog2 still is the current top and we can't request stop to MdiContainer
- // because Dialog2 and Dialog1 must be closed first.
- // Using request stop here will call the Dialog again without need
- Assert.True (Application.Current == d1);
- Assert.False (Application.Current.Running);
- Assert.True (c4.Running);
- } else {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- for (int i = 0; i < iterations; i++) {
- Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
- Application.MdiChildes [i].Id);
- }
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
-
- // MdiChild = c1, c2, c3
- var iterations = 3;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- c3.RequestStop ();
- c1.RequestStop ();
- };
- // Now this will close the MdiContainer propagating through the MdiChildes.
- c1.Closed += (e) => {
- mdi.RequestStop ();
- };
- Application.Iteration += () => {
- if (iterations == 3) {
- // The Current still is c3 because Current.Running is false.
- Assert.True (Application.Current == c3);
- Assert.False (Application.Current.Running);
- // But the childes order were reorder by Running = false
- Assert.True (Application.MdiChildes [0] == c3);
- Assert.True (Application.MdiChildes [1] == c1);
- Assert.True (Application.MdiChildes [^1] == c2);
- } else if (iterations == 2) {
- // The Current is c1 and Current.Running is false.
- Assert.True (Application.Current == c1);
- Assert.False (Application.Current.Running);
- Assert.True (Application.MdiChildes [0] == c1);
- Assert.True (Application.MdiChildes [^1] == c2);
- } else if (iterations == 1) {
- // The Current is c2 and Current.Running is false.
- Assert.True (Application.Current == c2);
- Assert.False (Application.Current.Running);
- Assert.True (Application.MdiChildes [^1] == c2);
- } else {
- // The Current is mdi.
- Assert.True (Application.Current == mdi);
- Assert.Empty (Application.MdiChildes);
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void MdiContainer_Throws_If_More_Than_One ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var mdi2 = new Mdi ();
-
- mdi.Ready += () => {
- Assert.Throws (() => Application.Run (mdi2));
- mdi.RequestStop ();
- };
-
- Application.Run (mdi);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void MdiContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var logger = new Toplevel ();
-
- var iterations = 1; // The logger
- var running = true;
- var stageCompleted = true;
- var allStageClosed = false;
- var mdiRequestStop = false;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (logger);
- };
-
- logger.Ready += () => Assert.Single (Application.MdiChildes);
-
- Application.Iteration += () => {
- if (stageCompleted && running) {
- stageCompleted = false;
- var stage = new Window () { Modal = true };
-
- stage.Ready += () => {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- stage.RequestStop ();
- };
-
- stage.Closed += (_) => {
- if (iterations == 11) {
- allStageClosed = true;
- }
- Assert.Equal (iterations, Application.MdiChildes.Count);
- if (running) {
- stageCompleted = true;
-
- var rpt = new Window ();
-
- rpt.Ready += () => {
- iterations++;
- Assert.Equal (iterations, Application.MdiChildes.Count);
- };
-
- Application.Run (rpt);
- }
- };
-
- Application.Run (stage);
-
- } else if (iterations == 11 && running) {
- running = false;
- Assert.Equal (iterations, Application.MdiChildes.Count);
-
- } else if (!mdiRequestStop && running && !allStageClosed) {
- Assert.Equal (iterations, Application.MdiChildes.Count);
-
- } else if (!mdiRequestStop && !running && allStageClosed) {
- Assert.Equal (iterations, Application.MdiChildes.Count);
- mdiRequestStop = true;
- mdi.RequestStop ();
- } else {
- Assert.Empty (Application.MdiChildes);
- }
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void AllChildClosed_Event_Test ()
- {
- Init ();
-
- var mdi = new Mdi ();
- var c1 = new Toplevel ();
- var c2 = new Window ();
- var c3 = new Window ();
-
- // MdiChild = c1, c2, c3
- var iterations = 3;
-
- mdi.Ready += () => {
- Assert.Empty (Application.MdiChildes);
- Application.Run (c1);
- };
- c1.Ready += () => {
- Assert.Single (Application.MdiChildes);
- Application.Run (c2);
- };
- c2.Ready += () => {
- Assert.Equal (2, Application.MdiChildes.Count);
- Application.Run (c3);
- };
- c3.Ready += () => {
- Assert.Equal (3, Application.MdiChildes.Count);
- c3.RequestStop ();
- c2.RequestStop ();
- c1.RequestStop ();
- };
- // Now this will close the MdiContainer when all MdiChildes was closed
- mdi.AllChildClosed += () => {
- mdi.RequestStop ();
- };
- Application.Iteration += () => {
- if (iterations == 3) {
- // The Current still is c3 because Current.Running is false.
- Assert.True (Application.Current == c3);
- Assert.False (Application.Current.Running);
- // But the childes order were reorder by Running = false
- Assert.True (Application.MdiChildes [0] == c3);
- Assert.True (Application.MdiChildes [1] == c2);
- Assert.True (Application.MdiChildes [^1] == c1);
- } else if (iterations == 2) {
- // The Current is c2 and Current.Running is false.
- Assert.True (Application.Current == c2);
- Assert.False (Application.Current.Running);
- Assert.True (Application.MdiChildes [0] == c2);
- Assert.True (Application.MdiChildes [^1] == c1);
- } else if (iterations == 1) {
- // The Current is c1 and Current.Running is false.
- Assert.True (Application.Current == c1);
- Assert.False (Application.Current.Running);
- Assert.True (Application.MdiChildes [^1] == c1);
- } else {
- // The Current is mdi.
- Assert.True (Application.Current == mdi);
- Assert.False (Application.Current.Running);
- Assert.Empty (Application.MdiChildes);
- }
- iterations--;
- };
-
- Application.Run (mdi);
-
- Assert.Empty (Application.MdiChildes);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void SetCurrentAsTop_Run_A_Not_Modal_Toplevel_Make_It_The_Current_Application_Top ()
- {
- Init ();
-
- var t1 = new Toplevel ();
- var t2 = new Toplevel ();
- var t3 = new Toplevel ();
- var d = new Dialog ();
- var t4 = new Toplevel ();
-
- // t1, t2, t3, d, t4
- var iterations = 5;
-
- t1.Ready += () => {
- Assert.Equal (t1, Application.Top);
- Application.Run (t2);
- };
- t2.Ready += () => {
- Assert.Equal (t2, Application.Top);
- Application.Run (t3);
- };
- t3.Ready += () => {
- Assert.Equal (t3, Application.Top);
- Application.Run (d);
- };
- d.Ready += () => {
- Assert.Equal (t3, Application.Top);
- Application.Run (t4);
- };
- t4.Ready += () => {
- Assert.Equal (t4, Application.Top);
- t4.RequestStop ();
- d.RequestStop ();
- t3.RequestStop ();
- t2.RequestStop ();
- };
- // Now this will close the MdiContainer when all MdiChildes was closed
- t2.Closed += (_) => {
- t1.RequestStop ();
- };
- Application.Iteration += () => {
- if (iterations == 5) {
- // The Current still is t4 because Current.Running is false.
- Assert.Equal (t4, Application.Current);
- Assert.False (Application.Current.Running);
- Assert.Equal (t4, Application.Top);
- } else if (iterations == 4) {
- // The Current is d and Current.Running is false.
- Assert.Equal (d, Application.Current);
- Assert.False (Application.Current.Running);
- Assert.Equal (t4, Application.Top);
- } else if (iterations == 3) {
- // The Current is t3 and Current.Running is false.
- Assert.Equal (t3, Application.Current);
- Assert.False (Application.Current.Running);
- Assert.Equal (t3, Application.Top);
- } else if (iterations == 2) {
- // The Current is t2 and Current.Running is false.
- Assert.Equal (t2, Application.Current);
- Assert.False (Application.Current.Running);
- Assert.Equal (t2, Application.Top);
- } else {
- // The Current is t1.
- Assert.Equal (t1, Application.Current);
- Assert.False (Application.Current.Running);
- Assert.Equal (t1, Application.Top);
- }
- iterations--;
- };
-
- Application.Run (t1);
-
- Assert.Equal (t1, Application.Top);
-
- Application.Shutdown ();
-
- Assert.Null (Application.Top);
- }
-
- [Fact]
- [AutoInitShutdown]
- public void Internal_Tests ()
- {
- Assert.True (Application._initialized);
- Assert.NotNull (Application.Top);
- var rs = Application.Begin (Application.Top);
- Assert.Equal (Application.Top, rs.Toplevel);
- Assert.Null (Application.MouseGrabView);
- Assert.Null (Application.WantContinuousButtonPressedView);
- Assert.False (Application.DebugDrawBounds);
- Assert.False (Application.ShowChild (Application.Top));
- Application.End (Application.Top);
- }
-
[Fact]
[AutoInitShutdown]
public void QuitKey_Getter_Setter ()
@@ -1290,6 +778,8 @@ namespace Terminal.Gui.Core {
Assert.Null (Toplevel.dragPosition);
}
+ #endregion
+
[Fact, AutoInitShutdown]
public void GetSupportedCultures_Method ()
{
@@ -1297,129 +787,7 @@ namespace Terminal.Gui.Core {
Assert.Equal (cultures.Count, Application.SupportedCultures.Count);
}
- [Fact, AutoInitShutdown]
- public void TestAddManyTimeouts ()
- {
- int delegatesRun = 0;
- int numberOfThreads = 100;
- int numberOfTimeoutsPerThread = 100;
-
-
- lock (Application.Top) {
- // start lots of threads
- for (int i = 0; i < numberOfThreads; i++) {
-
- var myi = i;
-
- Task.Run (() => {
- Thread.Sleep (100);
-
- // each thread registers lots of 1s timeouts
- for (int j = 0; j < numberOfTimeoutsPerThread; j++) {
-
- Application.MainLoop.AddTimeout (TimeSpan.FromSeconds (1), (s) => {
-
- // each timeout delegate increments delegatesRun count by 1 every second
- Interlocked.Increment (ref delegatesRun);
- return true;
- });
- }
-
- // if this is the first Thread created
- if (myi == 0) {
-
- // let the timeouts run for a bit
- Thread.Sleep (10000);
-
- // then tell the application to quit
- Application.MainLoop.Invoke (() => Application.RequestStop ());
- }
- });
- }
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
-
- // undershoot a bit to be on the safe side. The 5000 ms wait allows the timeouts to run
- // a lot but all those timeout delegates could end up going slowly on a slow machine perhaps
- // so the final number of delegatesRun might vary by computer. So for this assert we say
- // that it should have run at least 2 seconds worth of delegates
- Assert.True (delegatesRun >= numberOfThreads * numberOfTimeoutsPerThread * 2);
- }
- }
-
- [Fact]
- public void SynchronizationContext_Post ()
- {
- Init ();
- var context = SynchronizationContext.Current;
-
- var success = false;
- Task.Run (() => {
- Thread.Sleep (1_000);
-
- // non blocking
- context.Post (
- delegate (object o) {
- success = true;
-
- // then tell the application to quit
- Application.MainLoop.Invoke (() => Application.RequestStop ());
- }, null);
- Assert.False (success);
- });
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
- Assert.True (success);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void SynchronizationContext_Send ()
- {
- Init ();
- var context = SynchronizationContext.Current;
-
- var success = false;
- Task.Run (() => {
- Thread.Sleep (1_000);
-
- // blocking
- context.Send (
- delegate (object o) {
- success = true;
-
- // then tell the application to quit
- Application.MainLoop.Invoke (() => Application.RequestStop ());
- }, null);
- Assert.True (success);
- });
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
- Assert.True (success);
-
- Application.Shutdown ();
- }
-
- [Fact]
- public void SynchronizationContext_CreateCopy ()
- {
- Init ();
-
- var context = SynchronizationContext.Current;
- Assert.NotNull (context);
-
- var contextCopy = context.CreateCopy ();
- Assert.NotNull (contextCopy);
-
- Assert.NotEqual (context, contextCopy);
-
- Application.Shutdown ();
- }
-
+ #region mousegrabtests
[Fact, AutoInitShutdown]
public void MouseGrabView_WithNullMouseEventView ()
{
@@ -1564,5 +932,6 @@ namespace Terminal.Gui.Core {
Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
}
}
+ #endregion
}
}
diff --git a/UnitTests/MainLoopTests.cs b/UnitTests/MainLoopTests.cs
index 01ba22316..57b1e8f1e 100644
--- a/UnitTests/MainLoopTests.cs
+++ b/UnitTests/MainLoopTests.cs
@@ -591,5 +591,57 @@ namespace Terminal.Gui.Core {
Assert.Equal ((numIncrements * numPasses), tbCounter);
}
+
+
+ [Fact, AutoInitShutdown]
+ public void TestAddManyTimeouts ()
+ {
+ int delegatesRun = 0;
+ int numberOfThreads = 100;
+ int numberOfTimeoutsPerThread = 100;
+
+
+ lock (Application.Top) {
+ // start lots of threads
+ for (int i = 0; i < numberOfThreads; i++) {
+
+ var myi = i;
+
+ Task.Run (() => {
+ Thread.Sleep (100);
+
+ // each thread registers lots of 1s timeouts
+ for (int j = 0; j < numberOfTimeoutsPerThread; j++) {
+
+ Application.MainLoop.AddTimeout (TimeSpan.FromSeconds (1), (s) => {
+
+ // each timeout delegate increments delegatesRun count by 1 every second
+ Interlocked.Increment (ref delegatesRun);
+ return true;
+ });
+ }
+
+ // if this is the first Thread created
+ if (myi == 0) {
+
+ // let the timeouts run for a bit
+ Thread.Sleep (10000);
+
+ // then tell the application to quit
+ Application.MainLoop.Invoke (() => Application.RequestStop ());
+ }
+ });
+ }
+
+ // blocks here until the RequestStop is processed at the end of the test
+ Application.Run ();
+
+ // undershoot a bit to be on the safe side. The 5000 ms wait allows the timeouts to run
+ // a lot but all those timeout delegates could end up going slowly on a slow machine perhaps
+ // so the final number of delegatesRun might vary by computer. So for this assert we say
+ // that it should have run at least 2 seconds worth of delegates
+ Assert.True (delegatesRun >= numberOfThreads * numberOfTimeoutsPerThread * 2);
+ }
+ }
}
}
diff --git a/UnitTests/MdiTests.cs b/UnitTests/MdiTests.cs
new file mode 100644
index 000000000..4f4f13e11
--- /dev/null
+++ b/UnitTests/MdiTests.cs
@@ -0,0 +1,662 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.Core {
+ public class MdiTests {
+ public MdiTests ()
+ {
+#if DEBUG_IDISPOSABLE
+ Responder.Instances.Clear ();
+ Application.RunState.Instances.Clear ();
+#endif
+ }
+
+ [Fact, AutoInitShutdown]
+ public void Application_RequestStop_With_Params_On_A_Not_MdiContainer_Always_Use_Application_Current ()
+ {
+ var top1 = new Toplevel ();
+ var top2 = new Toplevel ();
+ var top3 = new Window ();
+ var top4 = new Window ();
+ var d = new Dialog ();
+
+ // top1, top2, top3, d1 = 4
+ var iterations = 4;
+
+ top1.Ready += () => {
+ Assert.Null (Application.MdiChildes);
+ Application.Run (top2);
+ };
+ top2.Ready += () => {
+ Assert.Null (Application.MdiChildes);
+ Application.Run (top3);
+ };
+ top3.Ready += () => {
+ Assert.Null (Application.MdiChildes);
+ Application.Run (top4);
+ };
+ top4.Ready += () => {
+ Assert.Null (Application.MdiChildes);
+ Application.Run (d);
+ };
+
+ d.Ready += () => {
+ Assert.Null (Application.MdiChildes);
+ // This will close the d because on a not MdiContainer the Application.Current it always used.
+ Application.RequestStop (top1);
+ Assert.True (Application.Current == d);
+ };
+
+ d.Closed += (e) => Application.RequestStop (top1);
+
+ Application.Iteration += () => {
+ Assert.Null (Application.MdiChildes);
+ if (iterations == 4) {
+ Assert.True (Application.Current == d);
+ } else if (iterations == 3) {
+ Assert.True (Application.Current == top4);
+ } else if (iterations == 2) {
+ Assert.True (Application.Current == top3);
+ } else if (iterations == 1) {
+ Assert.True (Application.Current == top2);
+ } else {
+ Assert.True (Application.Current == top1);
+ }
+ Application.RequestStop (top1);
+ iterations--;
+ };
+
+ Application.Run (top1);
+
+ Assert.Null (Application.MdiChildes);
+ }
+
+ class Mdi : Toplevel {
+ public Mdi ()
+ {
+ IsMdiContainer = true;
+ }
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MdiContainer_With_Toplevel_RequestStop_Balanced ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d = new Dialog ();
+
+ // MdiChild = c1, c2, c3
+ // d1 = 1
+ var iterations = 4;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d);
+ };
+
+ // More easy because the Mdi Container handles all at once
+ d.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ // This will not close the MdiContainer because d is a modal toplevel and will be closed.
+ mdi.RequestStop ();
+ };
+
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ d.Closed += (e) => {
+ mdi.RequestStop ();
+ };
+
+ Application.Iteration += () => {
+ if (iterations == 4) {
+ // The Dialog was not closed before and will be closed now.
+ Assert.True (Application.Current == d);
+ Assert.False (d.Running);
+ } else {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ for (int i = 0; i < iterations; i++) {
+ Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
+ }
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MdiContainer_With_Application_RequestStop_MdiTop_With_Params ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d = new Dialog ();
+
+ // MdiChild = c1, c2, c3
+ // d1 = 1
+ var iterations = 4;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d);
+ };
+
+ // Also easy because the Mdi Container handles all at once
+ d.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ // This will not close the MdiContainer because d is a modal toplevel
+ Application.RequestStop (mdi);
+ };
+
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ d.Closed += (e) => Application.RequestStop (mdi);
+
+ Application.Iteration += () => {
+ if (iterations == 4) {
+ // The Dialog was not closed before and will be closed now.
+ Assert.True (Application.Current == d);
+ Assert.False (d.Running);
+ } else {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ for (int i = 0; i < iterations; i++) {
+ Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
+ }
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MdiContainer_With_Application_RequestStop_MdiTop_Without_Params ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d = new Dialog ();
+
+ // MdiChild = c1, c2, c3 = 3
+ // d1 = 1
+ var iterations = 4;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d);
+ };
+
+ //More harder because it's sequential.
+ d.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ // Close the Dialog
+ Application.RequestStop ();
+ };
+
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ d.Closed += (e) => Application.RequestStop (mdi);
+
+ Application.Iteration += () => {
+ if (iterations == 4) {
+ // The Dialog still is the current top and we can't request stop to MdiContainer
+ // because we are not using parameter calls.
+ Assert.True (Application.Current == d);
+ Assert.False (d.Running);
+ } else {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ for (int i = 0; i < iterations; i++) {
+ Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
+ }
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void IsMdiChild_Testing ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d = new Dialog ();
+
+ Application.Iteration += () => {
+ Assert.False (mdi.IsMdiChild);
+ Assert.True (c1.IsMdiChild);
+ Assert.True (c2.IsMdiChild);
+ Assert.True (c3.IsMdiChild);
+ Assert.False (d.IsMdiChild);
+
+ mdi.RequestStop ();
+ };
+
+ Application.Run (mdi);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d1 = new Dialog ();
+ var d2 = new Dialog ();
+
+ // MdiChild = c1, c2, c3 = 3
+ // d1, d2 = 2
+ var iterations = 5;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d1);
+ };
+ d1.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d2);
+ };
+
+ d2.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Assert.True (Application.Current == d2);
+ Assert.True (Application.Current.Running);
+ // Trying to close the Dialog1
+ d1.RequestStop ();
+ };
+
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ d1.Closed += (e) => {
+ Assert.True (Application.Current == d1);
+ Assert.False (Application.Current.Running);
+ mdi.RequestStop ();
+ };
+
+ Application.Iteration += () => {
+ if (iterations == 5) {
+ // The Dialog2 still is the current top and we can't request stop to MdiContainer
+ // because Dialog2 and Dialog1 must be closed first.
+ // Dialog2 will be closed in this iteration.
+ Assert.True (Application.Current == d2);
+ Assert.False (Application.Current.Running);
+ Assert.False (d1.Running);
+ } else if (iterations == 4) {
+ // Dialog1 will be closed in this iteration.
+ Assert.True (Application.Current == d1);
+ Assert.False (Application.Current.Running);
+ } else {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ for (int i = 0; i < iterations; i++) {
+ Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
+ }
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+ var d1 = new Dialog ();
+ var c4 = new Toplevel ();
+
+ // MdiChild = c1, c2, c3, c4 = 4
+ // d1 = 1
+ var iterations = 5;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (d1);
+ };
+ d1.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ Application.Run (c4);
+ };
+
+ c4.Ready += () => {
+ Assert.Equal (4, Application.MdiChildes.Count);
+ // Trying to close the Dialog1
+ d1.RequestStop ();
+ };
+
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ d1.Closed += (e) => {
+ mdi.RequestStop ();
+ };
+
+ Application.Iteration += () => {
+ if (iterations == 5) {
+ // The Dialog2 still is the current top and we can't request stop to MdiContainer
+ // because Dialog2 and Dialog1 must be closed first.
+ // Using request stop here will call the Dialog again without need
+ Assert.True (Application.Current == d1);
+ Assert.False (Application.Current.Running);
+ Assert.True (c4.Running);
+ } else {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ for (int i = 0; i < iterations; i++) {
+ Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
+ Application.MdiChildes [i].Id);
+ }
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+
+ // MdiChild = c1, c2, c3
+ var iterations = 3;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ c3.RequestStop ();
+ c1.RequestStop ();
+ };
+ // Now this will close the MdiContainer propagating through the MdiChildes.
+ c1.Closed += (e) => {
+ mdi.RequestStop ();
+ };
+ Application.Iteration += () => {
+ if (iterations == 3) {
+ // The Current still is c3 because Current.Running is false.
+ Assert.True (Application.Current == c3);
+ Assert.False (Application.Current.Running);
+ // But the childes order were reorder by Running = false
+ Assert.True (Application.MdiChildes [0] == c3);
+ Assert.True (Application.MdiChildes [1] == c1);
+ Assert.True (Application.MdiChildes [^1] == c2);
+ } else if (iterations == 2) {
+ // The Current is c1 and Current.Running is false.
+ Assert.True (Application.Current == c1);
+ Assert.False (Application.Current.Running);
+ Assert.True (Application.MdiChildes [0] == c1);
+ Assert.True (Application.MdiChildes [^1] == c2);
+ } else if (iterations == 1) {
+ // The Current is c2 and Current.Running is false.
+ Assert.True (Application.Current == c2);
+ Assert.False (Application.Current.Running);
+ Assert.True (Application.MdiChildes [^1] == c2);
+ } else {
+ // The Current is mdi.
+ Assert.True (Application.Current == mdi);
+ Assert.Empty (Application.MdiChildes);
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MdiContainer_Throws_If_More_Than_One ()
+ {
+ var mdi = new Mdi ();
+ var mdi2 = new Mdi ();
+
+ mdi.Ready += () => {
+ Assert.Throws (() => Application.Run (mdi2));
+ mdi.RequestStop ();
+ };
+
+ Application.Run (mdi);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void MdiContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
+ {
+ var mdi = new Mdi ();
+ var logger = new Toplevel ();
+
+ var iterations = 1; // The logger
+ var running = true;
+ var stageCompleted = true;
+ var allStageClosed = false;
+ var mdiRequestStop = false;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (logger);
+ };
+
+ logger.Ready += () => Assert.Single (Application.MdiChildes);
+
+ Application.Iteration += () => {
+ if (stageCompleted && running) {
+ stageCompleted = false;
+ var stage = new Window () { Modal = true };
+
+ stage.Ready += () => {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ stage.RequestStop ();
+ };
+
+ stage.Closed += (_) => {
+ if (iterations == 11) {
+ allStageClosed = true;
+ }
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ if (running) {
+ stageCompleted = true;
+
+ var rpt = new Window ();
+
+ rpt.Ready += () => {
+ iterations++;
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ };
+
+ Application.Run (rpt);
+ }
+ };
+
+ Application.Run (stage);
+
+ } else if (iterations == 11 && running) {
+ running = false;
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+
+ } else if (!mdiRequestStop && running && !allStageClosed) {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+
+ } else if (!mdiRequestStop && !running && allStageClosed) {
+ Assert.Equal (iterations, Application.MdiChildes.Count);
+ mdiRequestStop = true;
+ mdi.RequestStop ();
+ } else {
+ Assert.Empty (Application.MdiChildes);
+ }
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void AllChildClosed_Event_Test ()
+ {
+ var mdi = new Mdi ();
+ var c1 = new Toplevel ();
+ var c2 = new Window ();
+ var c3 = new Window ();
+
+ // MdiChild = c1, c2, c3
+ var iterations = 3;
+
+ mdi.Ready += () => {
+ Assert.Empty (Application.MdiChildes);
+ Application.Run (c1);
+ };
+ c1.Ready += () => {
+ Assert.Single (Application.MdiChildes);
+ Application.Run (c2);
+ };
+ c2.Ready += () => {
+ Assert.Equal (2, Application.MdiChildes.Count);
+ Application.Run (c3);
+ };
+ c3.Ready += () => {
+ Assert.Equal (3, Application.MdiChildes.Count);
+ c3.RequestStop ();
+ c2.RequestStop ();
+ c1.RequestStop ();
+ };
+ // Now this will close the MdiContainer when all MdiChildes was closed
+ mdi.AllChildClosed += () => {
+ mdi.RequestStop ();
+ };
+ Application.Iteration += () => {
+ if (iterations == 3) {
+ // The Current still is c3 because Current.Running is false.
+ Assert.True (Application.Current == c3);
+ Assert.False (Application.Current.Running);
+ // But the childes order were reorder by Running = false
+ Assert.True (Application.MdiChildes [0] == c3);
+ Assert.True (Application.MdiChildes [1] == c2);
+ Assert.True (Application.MdiChildes [^1] == c1);
+ } else if (iterations == 2) {
+ // The Current is c2 and Current.Running is false.
+ Assert.True (Application.Current == c2);
+ Assert.False (Application.Current.Running);
+ Assert.True (Application.MdiChildes [0] == c2);
+ Assert.True (Application.MdiChildes [^1] == c1);
+ } else if (iterations == 1) {
+ // The Current is c1 and Current.Running is false.
+ Assert.True (Application.Current == c1);
+ Assert.False (Application.Current.Running);
+ Assert.True (Application.MdiChildes [^1] == c1);
+ } else {
+ // The Current is mdi.
+ Assert.True (Application.Current == mdi);
+ Assert.False (Application.Current.Running);
+ Assert.Empty (Application.MdiChildes);
+ }
+ iterations--;
+ };
+
+ Application.Run (mdi);
+
+ Assert.Empty (Application.MdiChildes);
+ }
+ }
+}
diff --git a/UnitTests/RunStateTests.cs b/UnitTests/RunStateTests.cs
new file mode 100644
index 000000000..afe6886df
--- /dev/null
+++ b/UnitTests/RunStateTests.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.Core {
+ ///
+ /// These tests focus on Application.RunState and the various ways it can be changed.
+ ///
+ public class RunStateTests {
+ public RunStateTests ()
+ {
+#if DEBUG_IDISPOSABLE
+ Responder.Instances.Clear ();
+ Application.RunState.Instances.Clear ();
+#endif
+ }
+
+ [Fact]
+ public void New_Creates_RunState ()
+ {
+ var rs = new Application.RunState (null);
+ Assert.Null (rs.Toplevel);
+
+ var top = new Toplevel ();
+ rs = new Application.RunState (top);
+ Assert.Equal (top, rs.Toplevel);
+ }
+
+ [Fact]
+ public void Dispose_Cleans_Up_RunState ()
+ {
+ var rs = new Application.RunState (null);
+ Assert.NotNull (rs);
+
+ // Should not throw because Toplevel was null
+ rs.Dispose ();
+ Assert.True (rs.WasDisposed);
+
+ var top = new Toplevel ();
+ rs = new Application.RunState (top);
+ Assert.NotNull (rs);
+
+ // Should throw because Toplevel was not cleaned up
+ Assert.Throws (() => rs.Dispose ());
+
+ rs.Toplevel.Dispose ();
+ rs.Toplevel = null;
+ rs.Dispose ();
+ Assert.True (rs.WasDisposed);
+ Assert.True (top.WasDisposed);
+ }
+
+ void Init ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+ Assert.NotNull (Application.Driver);
+ Assert.NotNull (Application.MainLoop);
+ Assert.NotNull (SynchronizationContext.Current);
+ }
+
+ void Shutdown ()
+ {
+ Application.Shutdown ();
+ // Validate there are no outstanding RunState-based instances left
+ foreach (var inst in Application.RunState.Instances) {
+ Assert.True (inst.WasDisposed);
+ }
+ }
+
+ [Fact]
+ public void Begin_End_Cleans_Up_RunState ()
+ {
+ // Setup Mock driver
+ Init ();
+
+ // Test null Toplevel
+ Assert.Throws (() => Application.Begin (null));
+
+ var top = new Toplevel ();
+ var rs = Application.Begin (top);
+ Assert.NotNull (rs);
+ Assert.Equal (top, Application.Current);
+ Application.End (rs);
+
+ Assert.Null (Application.Current);
+ Assert.NotNull (Application.Top);
+ Assert.NotNull (Application.MainLoop);
+ Assert.NotNull (Application.Driver);
+
+ Shutdown ();
+
+ Assert.True (rs.WasDisposed);
+
+ Assert.Null (Application.Top);
+ Assert.Null (Application.MainLoop);
+ Assert.Null (Application.Driver);
+ }
+ }
+}
diff --git a/UnitTests/ScenarioTests.cs b/UnitTests/ScenarioTests.cs
index c2dbb6bdc..f5f1dc57b 100644
--- a/UnitTests/ScenarioTests.cs
+++ b/UnitTests/ScenarioTests.cs
@@ -66,7 +66,7 @@ namespace UICatalog {
// Close after a short period of time
var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), closeCallback);
- scenario.Init (Application.Top, Colors.Base);
+ scenario.Init (Colors.Base);
scenario.Setup ();
scenario.Run ();
Application.Shutdown ();
@@ -121,7 +121,7 @@ namespace UICatalog {
Assert.Equal (Key.CtrlMask | Key.Q, args.KeyEvent.Key);
};
- generic.Init (Application.Top, Colors.Base);
+ generic.Init (Colors.Base);
generic.Setup ();
// There is no need to call Application.Begin because Init already creates the Application.Top
// If Application.RunState is used then the Application.RunLoop must also be used instead Application.Run.
diff --git a/UnitTests/SynchronizatonContextTests.cs b/UnitTests/SynchronizatonContextTests.cs
new file mode 100644
index 000000000..fe492c386
--- /dev/null
+++ b/UnitTests/SynchronizatonContextTests.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.InteropServices.ComTypes;
+using System.Threading;
+using System.Threading.Tasks;
+using Terminal.Gui;
+using Xunit;
+using Xunit.Sdk;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.Core {
+ public class SyncrhonizationContextTests {
+
+ [Fact, AutoInitShutdown]
+ public void SynchronizationContext_Post ()
+ {
+ var context = SynchronizationContext.Current;
+
+ var success = false;
+ Task.Run (() => {
+ Thread.Sleep (1_000);
+
+ // non blocking
+ context.Post (
+ delegate (object o) {
+ success = true;
+
+ // then tell the application to quit
+ Application.MainLoop.Invoke (() => Application.RequestStop ());
+ }, null);
+ Assert.False (success);
+ });
+
+ // blocks here until the RequestStop is processed at the end of the test
+ Application.Run ();
+ Assert.True (success);
+ }
+
+ [Fact, AutoInitShutdown]
+ public void SynchronizationContext_Send ()
+ {
+ var context = SynchronizationContext.Current;
+
+ var success = false;
+ Task.Run (() => {
+ Thread.Sleep (1_000);
+
+ // blocking
+ context.Send (
+ delegate (object o) {
+ success = true;
+
+ // then tell the application to quit
+ Application.MainLoop.Invoke (() => Application.RequestStop ());
+ }, null);
+ Assert.True (success);
+ });
+
+ // blocks here until the RequestStop is processed at the end of the test
+ Application.Run ();
+ Assert.True (success);
+
+ }
+
+ [Fact, AutoInitShutdown]
+ public void SynchronizationContext_CreateCopy ()
+ {
+ var context = SynchronizationContext.Current;
+ Assert.NotNull (context);
+
+ var contextCopy = context.CreateCopy ();
+ Assert.NotNull (contextCopy);
+
+ Assert.NotEqual (context, contextCopy);
+ }
+
+ }
+}