From 44ce74a5c0e2debadb3771e24ca6452018850771 Mon Sep 17 00:00:00 2001 From: Tig Date: Mon, 22 Jul 2024 16:52:02 -0600 Subject: [PATCH] Refactored Application into smaller files. Made Application #nullable enable --- .../Application/Application.Driver.cs | 29 + .../Application/Application.Initialization.cs | 209 +++ ...ionKeyboard.cs => Application.Keyboard.cs} | 2 +- ...plicationMouse.cs => Application.Mouse.cs} | 4 +- Terminal.Gui/Application/Application.Run.cs | 863 +++++++++++++ Terminal.Gui/Application/Application.cs | 1117 +---------------- Terminal.Gui/Clipboard/Clipboard.cs | 33 +- Terminal.Gui/Drawing/LineCanvas.cs | 6 +- Terminal.Gui/Drawing/Ruler.cs | 8 +- Terminal.Gui/Drawing/Thickness.cs | 14 +- .../Text/Autocomplete/AppendAutocomplete.cs | 4 +- .../Text/Autocomplete/PopupAutocomplete.cs | 6 +- Terminal.Gui/View/Layout/Dim.cs | 4 +- Terminal.Gui/View/Layout/DimView.cs | 4 +- Terminal.Gui/View/Layout/Pos.cs | 12 +- Terminal.Gui/View/Layout/PosView.cs | 4 +- Terminal.Gui/View/Layout/ViewLayout.cs | 4 +- Terminal.Gui/View/ViewDrawing.cs | 8 +- Terminal.Gui/Views/GraphView/Annotations.cs | 6 +- Terminal.Gui/Views/GraphView/Axis.cs | 14 +- Terminal.Gui/Views/GraphView/Series.cs | 4 +- Terminal.Gui/Views/Menu/ContextMenu.cs | 2 +- Terminal.Gui/Views/RadioGroup.cs | 12 +- UICatalog/Scenarios/CombiningMarks.cs | 28 +- UICatalog/Scenarios/Images.cs | 4 +- UICatalog/Scenarios/SendKeys.cs | 2 +- UICatalog/Scenarios/TextEffectsScenario.cs | 2 +- UICatalog/Scenarios/TrueColors.cs | 4 +- UICatalog/Scenarios/VkeyPacketSimulator.cs | 2 +- UICatalog/UICatalog.cs | 4 +- UnitTests/Application/ApplicationTests.cs | 14 +- UnitTests/Application/CursorTests.cs | 7 +- UnitTests/Clipboard/ClipboardTests.cs | 4 +- UnitTests/ConsoleDrivers/ClipRegionTests.cs | 8 +- .../ConsoleDrivers/ConsoleDriverTests.cs | 2 +- .../ConsoleDrivers/ConsoleKeyMappingTests.cs | 2 +- UnitTests/Dialogs/MessageBoxTests.cs | 20 +- UnitTests/Drawing/RulerTests.cs | 10 +- UnitTests/Drawing/ThicknessTests.cs | 20 +- UnitTests/FileServices/FileDialogTests.cs | 4 +- UnitTests/Text/TextFormatterTests.cs | 4 +- UnitTests/View/Adornment/BorderTests.cs | 16 +- UnitTests/View/Adornment/MarginTests.cs | 2 +- UnitTests/View/Adornment/PaddingTests.cs | 2 +- UnitTests/View/DrawTests.cs | 46 +- UnitTests/View/Layout/Dim.FillTests.cs | 2 +- UnitTests/View/Layout/Pos.AnchorEndTests.cs | 2 +- UnitTests/View/Layout/Pos.CenterTests.cs | 4 +- UnitTests/View/Layout/ViewportTests.cs | 2 +- UnitTests/View/NavigationTests.cs | 14 +- UnitTests/View/TextTests.cs | 20 +- UnitTests/View/ViewTests.cs | 30 +- UnitTests/Views/AppendAutocompleteTests.cs | 36 +- UnitTests/Views/ButtonTests.cs | 6 +- UnitTests/Views/CheckBoxTests.cs | 8 +- UnitTests/Views/ContextMenuTests.cs | 18 +- UnitTests/Views/FrameViewTests.cs | 2 +- UnitTests/Views/LabelTests.cs | 26 +- UnitTests/Views/ListViewTests.cs | 4 +- UnitTests/Views/MenuBarTests.cs | 28 +- UnitTests/Views/OverlappedTests.cs | 2 +- UnitTests/Views/RadioGroupTests.cs | 2 +- UnitTests/Views/ScrollBarViewTests.cs | 12 +- UnitTests/Views/ScrollViewTests.cs | 2 +- UnitTests/Views/TableViewTests.cs | 2 +- UnitTests/Views/TextFieldTests.cs | 14 +- UnitTests/Views/TextViewTests.cs | 18 +- UnitTests/Views/ToplevelTests.cs | 48 +- UnitTests/Views/TreeTableSourceTests.cs | 4 +- UnitTests/Views/TreeViewTests.cs | 2 +- UnitTests/Views/WindowTests.cs | 6 +- 71 files changed, 1449 insertions(+), 1441 deletions(-) create mode 100644 Terminal.Gui/Application/Application.Driver.cs create mode 100644 Terminal.Gui/Application/Application.Initialization.cs rename Terminal.Gui/Application/{ApplicationKeyboard.cs => Application.Keyboard.cs} (99%) rename Terminal.Gui/Application/{ApplicationMouse.cs => Application.Mouse.cs} (98%) create mode 100644 Terminal.Gui/Application/Application.Run.cs diff --git a/Terminal.Gui/Application/Application.Driver.cs b/Terminal.Gui/Application/Application.Driver.cs new file mode 100644 index 000000000..f15bd8053 --- /dev/null +++ b/Terminal.Gui/Application/Application.Driver.cs @@ -0,0 +1,29 @@ +#nullable enable +namespace Terminal.Gui; + +public static partial class Application // Driver abstractions +{ + internal static bool _forceFakeConsole; + + /// Gets the that has been selected. See also . + public static ConsoleDriver? Driver { get; internal set; } + + /// + /// Gets or sets whether will be forced to output only the 16 colors defined in + /// . The default is , meaning 24-bit (TrueColor) colors will be output + /// as long as the selected supports TrueColor. + /// + [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] + public static bool Force16Colors { get; set; } + + /// + /// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not + /// specified, the driver is selected based on the platform. + /// + /// + /// Note, will override this configuration setting if called + /// with either `driver` or `driverName` specified. + /// + [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] + public static string ForceDriver { get; set; } = string.Empty; +} diff --git a/Terminal.Gui/Application/Application.Initialization.cs b/Terminal.Gui/Application/Application.Initialization.cs new file mode 100644 index 000000000..a971850e3 --- /dev/null +++ b/Terminal.Gui/Application/Application.Initialization.cs @@ -0,0 +1,209 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace Terminal.Gui; + +public static partial class Application // Initialization (Init/Shutdown) +{ + /// Initializes a new instance of Application. + /// Call this method once per instance (or after has been called). + /// + /// This function loads the right for the platform, Creates a . and + /// assigns it to + /// + /// + /// must be called when the application is closing (typically after + /// has returned) to ensure resources are cleaned up and + /// terminal settings + /// restored. + /// + /// + /// The function combines + /// and + /// into a single + /// call. An application cam use without explicitly calling + /// . + /// + /// + /// The to use. If neither or + /// are specified the default driver for the platform will be used. + /// + /// + /// The short name (e.g. "net", "windows", "ansi", "fake", or "curses") of the + /// to use. If neither or are + /// specified the default driver for the platform will be used. + /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] + public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (driver, driverName); } + + internal static bool _initialized; + internal static int _mainThreadId = -1; + + + // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop. + // + // Called from: + // + // Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset. + // Run() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run() to be called without calling Init first. + // Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset. + // + // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] + internal static void InternalInit ( + ConsoleDriver driver = null, + string driverName = null, + bool calledViaRunT = false + ) + { + if (_initialized && driver is null) + { + return; + } + + if (_initialized) + { + throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); + } + + if (!calledViaRunT) + { + // Reset all class variables (Application is a singleton). + ResetState (); + } + + // For UnitTests + if (driver is { }) + { + Driver = driver; + } + + // Start the process of configuration management. + // Note that we end up calling LoadConfigurationFromAllSources + // multiple times. We need to do this because some settings are only + // valid after a Driver is loaded. In this case we need just + // `Settings` so we can determine which driver to use. + // Don't reset, so we can inherit the theme from the previous run. + Load (); + Apply (); + + // Ignore Configuration for ForceDriver if driverName is specified + if (!string.IsNullOrEmpty (driverName)) + { + ForceDriver = driverName; + } + + if (Driver is null) + { + PlatformID p = Environment.OSVersion.Platform; + + if (string.IsNullOrEmpty (ForceDriver)) + { + if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) + { + Driver = new WindowsDriver (); + } + else + { + Driver = new CursesDriver (); + } + } + else + { + List drivers = GetDriverTypes (); + Type driverType = drivers.FirstOrDefault (t => t.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase)); + + if (driverType is { }) + { + Driver = (ConsoleDriver)Activator.CreateInstance (driverType); + } + else + { + throw new ArgumentException ( + $"Invalid driver name: {ForceDriver}. Valid names are {string.Join (", ", drivers.Select (t => t.Name))}" + ); + } + } + } + + try + { + MainLoop = Driver.Init (); + } + catch (InvalidOperationException ex) + { + // This is a case where the driver is unable to initialize the console. + // This can happen if the console is already in use by another process or + // if running in unit tests. + // In this case, we want to throw a more specific exception. + throw new InvalidOperationException ( + "Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", + ex + ); + } + + Driver.SizeChanged += (s, args) => OnSizeChanging (args); + Driver.KeyDown += (s, args) => OnKeyDown (args); + Driver.KeyUp += (s, args) => OnKeyUp (args); + Driver.MouseEvent += (s, args) => OnMouseEvent (args); + + SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ()); + + SupportedCultures = GetSupportedCultures (); + _mainThreadId = Thread.CurrentThread.ManagedThreadId; + _initialized = true; + InitializedChanged?.Invoke (null, new (in _initialized)); + } + + private static void Driver_SizeChanged (object sender, SizeChangedEventArgs e) { OnSizeChanging (e); } + private static void Driver_KeyDown (object sender, Key e) { OnKeyDown (e); } + private static void Driver_KeyUp (object sender, Key e) { OnKeyUp (e); } + private static void Driver_MouseEvent (object sender, MouseEvent e) { OnMouseEvent (e); } + + /// Gets of list of types that are available. + /// + [RequiresUnreferencedCode ("AOT")] + public static List GetDriverTypes () + { + // use reflection to get the list of drivers + List driverTypes = new (); + + foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) + { + foreach (Type type in asm.GetTypes ()) + { + if (type.IsSubclassOf (typeof (ConsoleDriver)) && !type.IsAbstract) + { + driverTypes.Add (type); + } + } + } + + return driverTypes; + } + + /// Shutdown an application initialized with . + /// + /// 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 () + { + // TODO: Throw an exception if Init hasn't been called. + ResetState (); + PrintJsonErrors (); + InitializedChanged?.Invoke (null, new (in _initialized)); + } + + /// + /// This event is raised after the and methods have been called. + /// + /// + /// Intended to support unit tests that need to know when the application has been initialized. + /// + public static event EventHandler> InitializedChanged; +} diff --git a/Terminal.Gui/Application/ApplicationKeyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs similarity index 99% rename from Terminal.Gui/Application/ApplicationKeyboard.cs rename to Terminal.Gui/Application/Application.Keyboard.cs index be737968f..e8d698286 100644 --- a/Terminal.Gui/Application/ApplicationKeyboard.cs +++ b/Terminal.Gui/Application/Application.Keyboard.cs @@ -2,7 +2,7 @@ namespace Terminal.Gui; -partial class Application +public static partial class Application // Keyboard handling { private static Key _alternateForwardKey = Key.Empty; // Defined in config.json diff --git a/Terminal.Gui/Application/ApplicationMouse.cs b/Terminal.Gui/Application/Application.Mouse.cs similarity index 98% rename from Terminal.Gui/Application/ApplicationMouse.cs rename to Terminal.Gui/Application/Application.Mouse.cs index 9f2a95339..4d3fb6129 100644 --- a/Terminal.Gui/Application/ApplicationMouse.cs +++ b/Terminal.Gui/Application/Application.Mouse.cs @@ -1,6 +1,6 @@ namespace Terminal.Gui; -partial class Application +public static partial class Application // Mouse handling { #region Mouse handling @@ -272,7 +272,7 @@ partial class Application if (view is Adornment adornmentView) { - view = adornmentView.Parent.SuperView; + view = adornmentView.Parent!.SuperView; } else { diff --git a/Terminal.Gui/Application/Application.Run.cs b/Terminal.Gui/Application/Application.Run.cs new file mode 100644 index 000000000..34189d9fc --- /dev/null +++ b/Terminal.Gui/Application/Application.Run.cs @@ -0,0 +1,863 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Terminal.Gui; + +public static partial class Application // Run (Begin, Run, End, Stop) +{ + private static Toplevel _cachedRunStateToplevel; + + /// + /// 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 EventHandler NotifyNewRunState; + + /// Notify that an 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 EventHandler NotifyStopRunState; + + /// Building block API: Prepares the provided for execution. + /// + /// The handle that needs to be passed to the method upon + /// completion. + /// + /// The to prepare execution for. + /// + /// This method prepares the provided for running with the focus, it adds this to the list + /// of s, lays out the Subviews, focuses the first element, and draws the + /// in the screen. This is usually followed by executing the method, and then the + /// method upon termination which will undo these changes. + /// + public static RunState Begin (Toplevel toplevel) + { + ArgumentNullException.ThrowIfNull (toplevel); + +#if DEBUG_IDISPOSABLE + Debug.Assert (!toplevel.WasDisposed); + + if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel) + { + Debug.Assert (_cachedRunStateToplevel.WasDisposed); + } +#endif + + if (toplevel.IsOverlappedContainer && OverlappedTop != toplevel && OverlappedTop is { }) + { + throw new InvalidOperationException ("Only one Overlapped Container is allowed."); + } + + // Ensure the mouse is ungrabbed. + MouseGrabView = null; + + var rs = new RunState (toplevel); + + // View implements ISupportInitializeNotification which is derived from ISupportInitialize + if (!toplevel.IsInitialized) + { + toplevel.BeginInit (); + toplevel.EndInit (); + } + +#if DEBUG_IDISPOSABLE + if (Top is { } && toplevel != Top && !_topLevels.Contains (Top)) + { + // This assertion confirm if the Top was already disposed + Debug.Assert (Top.WasDisposed); + Debug.Assert (Top == _cachedRunStateToplevel); + } +#endif + + lock (_topLevels) + { + if (Top is { } && toplevel != Top && !_topLevels.Contains (Top)) + { + // If Top was already disposed and isn't on the Toplevels Stack, + // clean it up here if is the same as _cachedRunStateToplevel + if (Top == _cachedRunStateToplevel) + { + Top = null; + } + else + { + // Probably this will never hit + throw new ObjectDisposedException (Top.GetType ().FullName); + } + } + else if (OverlappedTop is { } && toplevel != Top && _topLevels.Contains (Top)) + { + Top.OnLeave (toplevel); + } + + // BUGBUG: We should not depend on `Id` internally. + // BUGBUG: It is super unclear what this code does anyway. + if (string.IsNullOrEmpty (toplevel.Id)) + { + var count = 1; + var id = (_topLevels.Count + count).ToString (); + + while (_topLevels.Count > 0 && _topLevels.FirstOrDefault (x => x.Id == id) is { }) + { + count++; + id = (_topLevels.Count + count).ToString (); + } + + toplevel.Id = (_topLevels.Count + count).ToString (); + + _topLevels.Push (toplevel); + } + else + { + Toplevel dup = _topLevels.FirstOrDefault (x => x.Id == toplevel.Id); + + if (dup is null) + { + _topLevels.Push (toplevel); + } + } + + if (_topLevels.FindDuplicates (new ToplevelEqualityComparer ()).Count > 0) + { + throw new ArgumentException ("There are duplicates Toplevel IDs"); + } + } + + if (Top is null || toplevel.IsOverlappedContainer) + { + Top = toplevel; + } + + var refreshDriver = true; + + if (OverlappedTop is null + || toplevel.IsOverlappedContainer + || (Current?.Modal == false && toplevel.Modal) + || (Current?.Modal == false && !toplevel.Modal) + || (Current?.Modal == true && toplevel.Modal)) + { + if (toplevel.Visible) + { + Current?.OnDeactivate (toplevel); + Toplevel previousCurrent = Current; + Current = toplevel; + Current.OnActivate (previousCurrent); + + SetCurrentOverlappedAsTop (); + } + else + { + refreshDriver = false; + } + } + else if ((OverlappedTop != null + && toplevel != OverlappedTop + && Current?.Modal == true + && !_topLevels.Peek ().Modal) + || (OverlappedTop is { } && toplevel != OverlappedTop && Current?.Running == false)) + { + refreshDriver = false; + MoveCurrent (toplevel); + } + else + { + refreshDriver = false; + MoveCurrent (Current); + } + + toplevel.SetRelativeLayout (Driver.Screen.Size); + + toplevel.LayoutSubviews (); + toplevel.PositionToplevels (); + toplevel.FocusFirst (); + BringOverlappedTopToFront (); + + if (refreshDriver) + { + OverlappedTop?.OnChildLoaded (toplevel); + toplevel.OnLoaded (); + toplevel.SetNeedsDisplay (); + toplevel.Draw (); + Driver.UpdateScreen (); + + if (PositionCursor (toplevel)) + { + Driver.UpdateCursor (); + } + } + + NotifyNewRunState?.Invoke (toplevel, new (rs)); + + return rs; + } + + /// + /// Calls on the most focused view in the view starting with . + /// + /// + /// Does nothing if is or if the most focused view is not visible or + /// enabled. + /// + /// If the most focused view is not visible within it's superview, the cursor will be hidden. + /// + /// + /// if a view positioned the cursor and the position is visible. + internal static bool PositionCursor (View view) + { + // Find the most focused view and position the cursor there. + View mostFocused = view?.MostFocused; + + if (mostFocused is null) + { + if (view is { HasFocus: true }) + { + mostFocused = view; + } + else + { + return false; + } + } + + // If the view is not visible or enabled, don't position the cursor + if (!mostFocused.Visible || !mostFocused.Enabled) + { + Driver.GetCursorVisibility (out CursorVisibility current); + + if (current != CursorVisibility.Invisible) + { + Driver.SetCursorVisibility (CursorVisibility.Invisible); + } + + return false; + } + + // If the view is not visible within it's superview, don't position the cursor + Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty }); + Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen; + + if (!superViewViewport.IntersectsWith (mostFocusedViewport)) + { + return false; + } + + Point? cursor = mostFocused.PositionCursor (); + + Driver.GetCursorVisibility (out CursorVisibility currentCursorVisibility); + + if (cursor is { }) + { + // Convert cursor to screen coords + cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location; + + // If the cursor is not in a visible location in the SuperView, hide it + if (!superViewViewport.Contains (cursor.Value)) + { + if (currentCursorVisibility != CursorVisibility.Invisible) + { + Driver.SetCursorVisibility (CursorVisibility.Invisible); + } + + return false; + } + + // Show it + if (currentCursorVisibility == CursorVisibility.Invisible) + { + Driver.SetCursorVisibility (mostFocused.CursorVisibility); + } + + return true; + } + + if (currentCursorVisibility != CursorVisibility.Invisible) + { + Driver.SetCursorVisibility (CursorVisibility.Invisible); + } + + return false; + } + + /// + /// Runs the application by creating a object and calling + /// . + /// + /// + /// Calling first is not needed as this function will initialize the application. + /// + /// must be called when the application is closing (typically after Run> has returned) to + /// ensure resources are cleaned up and terminal settings restored. + /// + /// + /// The caller is responsible for disposing the object returned by this method. + /// + /// + /// The created object. The caller is responsible for disposing this object. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] + public static Toplevel Run (Func errorHandler = null, ConsoleDriver driver = null) { return Run (errorHandler, driver); } + + /// + /// Runs the application by creating a -derived object of type T and calling + /// . + /// + /// + /// Calling first is not needed as this function will initialize the application. + /// + /// must be called when the application is closing (typically after Run> has returned) to + /// ensure resources are cleaned up and terminal settings restored. + /// + /// + /// The caller is responsible for disposing the object returned by this method. + /// + /// + /// + /// + /// The to use. If not specified the default driver for the platform will + /// be used ( , , or ). Must be + /// if has already been called. + /// + /// The created T object. The caller is responsible for disposing this object. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] + public static T Run (Func errorHandler = null, ConsoleDriver driver = null) + where T : Toplevel, new () + { + if (!_initialized) + { + // Init() has NOT been called. + InternalInit (driver, null, true); + } + + var top = new T (); + + Run (top, errorHandler); + + return top; + } + + /// Runs the Application using the provided view. + /// + /// + /// This method is used to start processing events for the main application, but it is also used to run other + /// modal s such as boxes. + /// + /// + /// To make a stop execution, call + /// . + /// + /// + /// Calling is equivalent to calling + /// , followed by , and then calling + /// . + /// + /// + /// Alternatively, to have a program control the main loop and process events manually, call + /// to set things up manually and then repeatedly call + /// with the wait parameter set to false. By doing this the + /// method will only process any pending events, timers, idle handlers and then + /// return control immediately. + /// + /// When using or + /// + /// will be called automatically. + /// + /// + /// RELEASE builds only: When is any exceptions will be + /// rethrown. Otherwise, if will be called. If + /// returns the will resume; otherwise this method will + /// exit. + /// + /// + /// The to run as a modal. + /// + /// RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true, + /// rethrows when null). + /// + public static void Run (Toplevel view, Func errorHandler = null) + { + ArgumentNullException.ThrowIfNull (view); + + if (_initialized) + { + if (Driver is null) + { + // Disposing before throwing + view.Dispose (); + + // This code path should be impossible because Init(null, null) will select the platform default driver + throw new InvalidOperationException ( + "Init() completed without a driver being set (this should be impossible); Run() cannot be called." + ); + } + } + else + { + // Init() has NOT been called. + throw new InvalidOperationException ( + "Init() has not been called. Only Run() or Run() can be used without calling Init()." + ); + } + + var resume = true; + + while (resume) + { +#if !DEBUG + try + { +#endif + resume = false; + RunState runState = Begin (view); + + // If EndAfterFirstIteration is true then the user must dispose of the runToken + // by using NotifyStopRunState event. + RunLoop (runState); + + if (runState.Toplevel is null) + { +#if DEBUG_IDISPOSABLE + Debug.Assert (_topLevels.Count == 0); +#endif + runState.Dispose (); + + return; + } + + if (!EndAfterFirstIteration) + { + End (runState); + } +#if !DEBUG + } + catch (Exception error) + { + if (errorHandler is null) + { + throw; + } + + resume = errorHandler (error); + } +#endif + } + } + + /// Adds a timeout to the application. + /// + /// When time specified passes, the callback will be invoked. If the callback returns true, the timeout will be + /// reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a + /// token that can be used to stop the timeout by calling . + /// + public static object AddTimeout (TimeSpan time, Func callback) { return MainLoop?.AddTimeout (time, callback); } + + /// Removes a previously scheduled timeout + /// The token parameter is the value returned by . + /// Returns + /// true + /// if the timeout is successfully removed; otherwise, + /// false + /// . + /// This method also returns + /// false + /// if the timeout is not found. + public static bool RemoveTimeout (object token) { return MainLoop?.RemoveTimeout (token) ?? false; } + + /// Runs on the thread that is processing events + /// the action to be invoked on the main processing thread. + public static void Invoke (Action action) + { + MainLoop?.AddIdle ( + () => + { + action (); + + return false; + } + ); + } + + /// Wakes up the running application that might be waiting on input. + public static void Wakeup () { MainLoop?.Wakeup (); } + + /// Triggers a refresh of the entire display. + public static void Refresh () + { + // TODO: Figure out how to remove this call to ClearContents. Refresh should just repaint damaged areas, not clear + Driver.ClearContents (); + View last = null; + + foreach (Toplevel v in _topLevels.Reverse ()) + { + if (v.Visible) + { + v.SetNeedsDisplay (); + v.SetSubViewNeedsDisplay (); + v.Draw (); + } + + last = v; + } + + Driver.Refresh (); + } + + /// This event is raised on each iteration of the main loop. + /// See also + public static event EventHandler Iteration; + + /// The driver for the application + /// The main loop. + internal static MainLoop MainLoop { get; private set; } + + /// + /// Set to true to cause to be called after the first iteration. Set to false (the default) to + /// cause the application to continue running until Application.RequestStop () is called. + /// + public static bool EndAfterFirstIteration { get; set; } + + /// Building block API: Runs the main loop for the created . + /// The state returned by the method. + public static void RunLoop (RunState state) + { + ArgumentNullException.ThrowIfNull (state); + ObjectDisposedException.ThrowIf (state.Toplevel is null, "state"); + + var firstIteration = true; + + for (state.Toplevel.Running = true; state.Toplevel?.Running == true;) + { + MainLoop.Running = true; + + if (EndAfterFirstIteration && !firstIteration) + { + return; + } + + RunIteration (ref state, ref firstIteration); + } + + MainLoop.Running = false; + + // Run one last iteration to consume any outstanding input events from Driver + // This is important for remaining OnKeyUp events. + RunIteration (ref state, ref firstIteration); + } + + /// Run one application iteration. + /// The state returned by . + /// + /// Set to if this is the first run loop iteration. Upon return, it + /// will be set to if at least one iteration happened. + /// + public static void RunIteration (ref RunState state, ref bool firstIteration) + { + if (MainLoop.Running && MainLoop.EventsPending ()) + { + // Notify Toplevel it's ready + if (firstIteration) + { + state.Toplevel.OnReady (); + } + + MainLoop.RunIteration (); + Iteration?.Invoke (null, new ()); + EnsureModalOrVisibleAlwaysOnTop (state.Toplevel); + + if (state.Toplevel != Current) + { + OverlappedTop?.OnDeactivate (state.Toplevel); + state.Toplevel = Current; + OverlappedTop?.OnActivate (state.Toplevel); + Top.SetSubViewNeedsDisplay (); + Refresh (); + } + } + + firstIteration = false; + + if (Current == null) + { + return; + } + + if (state.Toplevel != Top && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded)) + { + state.Toplevel.SetNeedsDisplay (state.Toplevel.Frame); + Top.Draw (); + + foreach (Toplevel top in _topLevels.Reverse ()) + { + if (top != Top && top != state.Toplevel) + { + top.SetNeedsDisplay (); + top.SetSubViewNeedsDisplay (); + top.Draw (); + } + } + } + + if (_topLevels.Count == 1 + && state.Toplevel == Top + && (Driver.Cols != state.Toplevel.Frame.Width + || Driver.Rows != state.Toplevel.Frame.Height) + && (state.Toplevel.NeedsDisplay + || state.Toplevel.SubViewNeedsDisplay + || state.Toplevel.LayoutNeeded)) + { + Driver.ClearContents (); + } + + if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ()) + { + state.Toplevel.SetNeedsDisplay (); + state.Toplevel.Draw (); + Driver.UpdateScreen (); + + //Driver.UpdateCursor (); + } + + if (PositionCursor (state.Toplevel)) + { + Driver.UpdateCursor (); + } + + // else + { + //if (PositionCursor (state.Toplevel)) + //{ + // Driver.Refresh (); + //} + //Driver.UpdateCursor (); + } + + if (state.Toplevel != Top && !state.Toplevel.Modal && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded)) + { + Top.Draw (); + } + } + + /// Stops the provided , causing or the if provided. + /// The to stop. + /// + /// This will cause to return. + /// + /// Calling is equivalent to setting the + /// property on the currently running to false. + /// + /// + public static void RequestStop (Toplevel top = null) + { + if (OverlappedTop is null || top is null || (OverlappedTop is null && top is { })) + { + top = Current; + } + + if (OverlappedTop != null + && top.IsOverlappedContainer + && top?.Running == true + && (Current?.Modal == false || (Current?.Modal == true && Current?.Running == false))) + { + OverlappedTop.RequestStop (); + } + else if (OverlappedTop != null + && top != Current + && Current?.Running == true + && Current?.Modal == true + && top.Modal + && top.Running) + { + var ev = new ToplevelClosingEventArgs (Current); + Current.OnClosing (ev); + + if (ev.Cancel) + { + return; + } + + ev = new (top); + top.OnClosing (ev); + + if (ev.Cancel) + { + return; + } + + Current.Running = false; + OnNotifyStopRunState (Current); + top.Running = false; + OnNotifyStopRunState (top); + } + else if ((OverlappedTop != null + && top != OverlappedTop + && top != Current + && Current?.Modal == false + && Current?.Running == true + && !top.Running) + || (OverlappedTop != null + && top != OverlappedTop + && top != Current + && Current?.Modal == false + && Current?.Running == false + && !top.Running + && _topLevels.ToArray () [1].Running)) + { + MoveCurrent (top); + } + else if (OverlappedTop != null + && Current != top + && Current?.Running == true + && !top.Running + && Current?.Modal == true + && top.Modal) + { + // The Current and the top are both modal so needed to set the Current.Running to false too. + Current.Running = false; + OnNotifyStopRunState (Current); + } + else if (OverlappedTop != null + && Current == top + && OverlappedTop?.Running == true + && Current?.Running == true + && top.Running + && Current?.Modal == true + && top.Modal) + { + // The OverlappedTop was requested to stop inside a modal Toplevel which is the Current and top, + // both are the same, so needed to set the Current.Running to false too. + Current.Running = false; + OnNotifyStopRunState (Current); + } + else + { + Toplevel currentTop; + + if (top == Current || (Current?.Modal == true && !top.Modal)) + { + currentTop = Current; + } + else + { + currentTop = top; + } + + if (!currentTop.Running) + { + return; + } + + var ev = new ToplevelClosingEventArgs (currentTop); + currentTop.OnClosing (ev); + + if (ev.Cancel) + { + return; + } + + currentTop.Running = false; + OnNotifyStopRunState (currentTop); + } + } + + private static void OnNotifyStopRunState (Toplevel top) + { + if (EndAfterFirstIteration) + { + NotifyStopRunState?.Invoke (top, new (top)); + } + } + + /// + /// Building block API: completes the execution of a that was started with + /// . + /// + /// The returned by the method. + public static void End (RunState runState) + { + ArgumentNullException.ThrowIfNull (runState); + + if (OverlappedTop is { }) + { + OverlappedTop.OnChildUnloaded (runState.Toplevel); + } + 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 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 OverlappedTop that is not the RunState.Toplevel then RunState.Toplevel + // is a child of MidTop, and we should notify the OverlappedTop that it is closing + if (OverlappedTop is { } && !runState.Toplevel.Modal && runState.Toplevel != OverlappedTop) + { + OverlappedTop.OnChildClosed (runState.Toplevel); + } + + // Set Current and Top to the next TopLevel on the stack + if (_topLevels.Count == 0) + { + Current = null; + } + else + { + if (_topLevels.Count > 1 && _topLevels.Peek () == OverlappedTop && OverlappedChildren.Any (t => t.Visible) is { }) + { + OverlappedMoveNext (); + } + + Current = _topLevels.Peek (); + + if (_topLevels.Count == 1 && Current == OverlappedTop) + { + OverlappedTop.OnAllChildClosed (); + } + else + { + SetCurrentOverlappedAsTop (); + runState.Toplevel.OnLeave (Current); + Current.OnEnter (runState.Toplevel); + } + + Refresh (); + } + + // Don't dispose runState.Toplevel. It's up to caller dispose it + // If it's not the same as the current in the RunIteration, + // it will be fixed later in the next RunIteration. + if (OverlappedTop is { } && !_topLevels.Contains (OverlappedTop)) + { + _cachedRunStateToplevel = OverlappedTop; + } + else + { + _cachedRunStateToplevel = runState.Toplevel; + } + + runState.Toplevel = null; + runState.Dispose (); + } +} diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 9c981b743..1561413e9 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -1,5 +1,5 @@ +#nullable enable using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; @@ -18,31 +18,6 @@ namespace Terminal.Gui; /// TODO: Flush this out. public static partial class Application { - // For Unit testing - ignores UseSystemConsole - internal static bool _forceFakeConsole; - - /// Gets the that has been selected. See also . - public static ConsoleDriver Driver { get; internal set; } - - /// - /// Gets or sets whether will be forced to output only the 16 colors defined in - /// . The default is , meaning 24-bit (TrueColor) colors will be output - /// as long as the selected supports TrueColor. - /// - [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] - public static bool Force16Colors { get; set; } - - /// - /// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not - /// specified, the driver is selected based on the platform. - /// - /// - /// Note, will override this configuration setting if called - /// with either `driver` or `driverName` specified. - /// - [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] - public static string ForceDriver { get; set; } = string.Empty; - /// Gets all cultures supported by the application without the invariant language. public static List SupportedCultures { get; private set; } @@ -68,10 +43,6 @@ public static partial class Application .ToList (); } - // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`. - // This variable is set in `End` in this case so that `Begin` correctly sets `Top`. - private static Toplevel _cachedRunStateToplevel; - // IMPORTANT: Ensure all property/fields are reset here. See Init_ResetState_Resets_Properties unit test. // Encapsulate all setting of initial state for Application; Having // this in a function like this ensures we don't make mistakes in @@ -82,9 +53,9 @@ public static partial class Application // Shutdown is the bookend for Init. As such it needs to clean up all resources // Init created. Apps that do any threading will need to code defensively for this. // e.g. see Issue #537 - foreach (Toplevel t in _topLevels) + foreach (Toplevel? t in _topLevels) { - t.Running = false; + t!.Running = false; } _topLevels.Clear (); @@ -163,1072 +134,11 @@ public static partial class Application SynchronizationContext.SetSynchronizationContext (null); } - #region Initialization (Init/Shutdown) - - /// Initializes a new instance of Application. - /// Call this method once per instance (or after has been called). - /// - /// This function loads the right for the platform, Creates a . and - /// assigns it to - /// - /// - /// must be called when the application is closing (typically after - /// has returned) to ensure resources are cleaned up and - /// terminal settings - /// restored. - /// - /// - /// The function combines - /// and - /// into a single - /// call. An application cam use without explicitly calling - /// . - /// - /// - /// The to use. If neither or - /// are specified the default driver for the platform will be used. - /// - /// - /// The short name (e.g. "net", "windows", "ansi", "fake", or "curses") of the - /// to use. If neither or are - /// specified the default driver for the platform will be used. - /// - [RequiresUnreferencedCode ("AOT")] - [RequiresDynamicCode ("AOT")] - public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (driver, driverName); } - - internal static bool _initialized; - internal static int _mainThreadId = -1; - - // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop. - // - // Called from: - // - // Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset. - // Run() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run() to be called without calling Init first. - // Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset. - // - // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset. - [RequiresUnreferencedCode ("AOT")] - [RequiresDynamicCode ("AOT")] - internal static void InternalInit ( - ConsoleDriver driver = null, - string driverName = null, - bool calledViaRunT = false - ) - { - if (_initialized && driver is null) - { - return; - } - - if (_initialized) - { - throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); - } - - if (!calledViaRunT) - { - // Reset all class variables (Application is a singleton). - ResetState (); - } - - // For UnitTests - if (driver is { }) - { - Driver = driver; - } - - // Start the process of configuration management. - // Note that we end up calling LoadConfigurationFromAllSources - // multiple times. We need to do this because some settings are only - // valid after a Driver is loaded. In this case we need just - // `Settings` so we can determine which driver to use. - // Don't reset, so we can inherit the theme from the previous run. - Load (); - Apply (); - - // Ignore Configuration for ForceDriver if driverName is specified - if (!string.IsNullOrEmpty (driverName)) - { - ForceDriver = driverName; - } - - if (Driver is null) - { - PlatformID p = Environment.OSVersion.Platform; - - if (string.IsNullOrEmpty (ForceDriver)) - { - if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) - { - Driver = new WindowsDriver (); - } - else - { - Driver = new CursesDriver (); - } - } - else - { - List drivers = GetDriverTypes (); - Type driverType = drivers.FirstOrDefault (t => t.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase)); - - if (driverType is { }) - { - Driver = (ConsoleDriver)Activator.CreateInstance (driverType); - } - else - { - throw new ArgumentException ( - $"Invalid driver name: {ForceDriver}. Valid names are {string.Join (", ", drivers.Select (t => t.Name))}" - ); - } - } - } - - try - { - MainLoop = Driver.Init (); - } - catch (InvalidOperationException ex) - { - // This is a case where the driver is unable to initialize the console. - // This can happen if the console is already in use by another process or - // if running in unit tests. - // In this case, we want to throw a more specific exception. - throw new InvalidOperationException ( - "Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", - ex - ); - } - - Driver.SizeChanged += (s, args) => OnSizeChanging (args); - Driver.KeyDown += (s, args) => OnKeyDown (args); - Driver.KeyUp += (s, args) => OnKeyUp (args); - Driver.MouseEvent += (s, args) => OnMouseEvent (args); - - SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ()); - - SupportedCultures = GetSupportedCultures (); - _mainThreadId = Thread.CurrentThread.ManagedThreadId; - _initialized = true; - InitializedChanged?.Invoke (null, new (in _initialized)); - } - - private static void Driver_SizeChanged (object sender, SizeChangedEventArgs e) { OnSizeChanging (e); } - private static void Driver_KeyDown (object sender, Key e) { OnKeyDown (e); } - private static void Driver_KeyUp (object sender, Key e) { OnKeyUp (e); } - private static void Driver_MouseEvent (object sender, MouseEvent e) { OnMouseEvent (e); } - - /// Gets of list of types that are available. - /// - [RequiresUnreferencedCode ("AOT")] - public static List GetDriverTypes () - { - // use reflection to get the list of drivers - List driverTypes = new (); - - foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) - { - foreach (Type type in asm.GetTypes ()) - { - if (type.IsSubclassOf (typeof (ConsoleDriver)) && !type.IsAbstract) - { - driverTypes.Add (type); - } - } - } - - return driverTypes; - } - - /// Shutdown an application initialized with . - /// - /// 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 () - { - // TODO: Throw an exception if Init hasn't been called. - ResetState (); - PrintJsonErrors (); - InitializedChanged?.Invoke (null, new (in _initialized)); - } - -#nullable enable - /// - /// This event is raised after the and methods have been called. - /// - /// - /// Intended to support unit tests that need to know when the application has been initialized. - /// - public static event EventHandler>? InitializedChanged; -#nullable restore - - #endregion Initialization (Init/Shutdown) - - #region Run (Begin, Run, End, Stop) - - /// - /// 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 EventHandler NotifyNewRunState; - - /// Notify that an 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 EventHandler NotifyStopRunState; - - /// Building block API: Prepares the provided for execution. - /// - /// The handle that needs to be passed to the method upon - /// completion. - /// - /// The to prepare execution for. - /// - /// This method prepares the provided for running with the focus, it adds this to the list - /// of s, lays out the Subviews, focuses the first element, and draws the - /// in the screen. This is usually followed by executing the method, and then the - /// method upon termination which will undo these changes. - /// - public static RunState Begin (Toplevel toplevel) - { - ArgumentNullException.ThrowIfNull (toplevel); - -#if DEBUG_IDISPOSABLE - Debug.Assert (!toplevel.WasDisposed); - - if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel) - { - Debug.Assert (_cachedRunStateToplevel.WasDisposed); - } -#endif - - if (toplevel.IsOverlappedContainer && OverlappedTop != toplevel && OverlappedTop is { }) - { - throw new InvalidOperationException ("Only one Overlapped Container is allowed."); - } - - // Ensure the mouse is ungrabbed. - MouseGrabView = null; - - var rs = new RunState (toplevel); - - // View implements ISupportInitializeNotification which is derived from ISupportInitialize - if (!toplevel.IsInitialized) - { - toplevel.BeginInit (); - toplevel.EndInit (); - } - -#if DEBUG_IDISPOSABLE - if (Top is { } && toplevel != Top && !_topLevels.Contains (Top)) - { - // This assertion confirm if the Top was already disposed - Debug.Assert (Top.WasDisposed); - Debug.Assert (Top == _cachedRunStateToplevel); - } -#endif - - lock (_topLevels) - { - if (Top is { } && toplevel != Top && !_topLevels.Contains (Top)) - { - // If Top was already disposed and isn't on the Toplevels Stack, - // clean it up here if is the same as _cachedRunStateToplevel - if (Top == _cachedRunStateToplevel) - { - Top = null; - } - else - { - // Probably this will never hit - throw new ObjectDisposedException (Top.GetType ().FullName); - } - } - else if (OverlappedTop is { } && toplevel != Top && _topLevels.Contains (Top)) - { - Top.OnLeave (toplevel); - } - - // BUGBUG: We should not depend on `Id` internally. - // BUGBUG: It is super unclear what this code does anyway. - if (string.IsNullOrEmpty (toplevel.Id)) - { - var count = 1; - var id = (_topLevels.Count + count).ToString (); - - while (_topLevels.Count > 0 && _topLevels.FirstOrDefault (x => x.Id == id) is { }) - { - count++; - id = (_topLevels.Count + count).ToString (); - } - - toplevel.Id = (_topLevels.Count + count).ToString (); - - _topLevels.Push (toplevel); - } - else - { - Toplevel dup = _topLevels.FirstOrDefault (x => x.Id == toplevel.Id); - - if (dup is null) - { - _topLevels.Push (toplevel); - } - } - - if (_topLevels.FindDuplicates (new ToplevelEqualityComparer ()).Count > 0) - { - throw new ArgumentException ("There are duplicates Toplevel IDs"); - } - } - - if (Top is null || toplevel.IsOverlappedContainer) - { - Top = toplevel; - } - - var refreshDriver = true; - - if (OverlappedTop is null - || toplevel.IsOverlappedContainer - || (Current?.Modal == false && toplevel.Modal) - || (Current?.Modal == false && !toplevel.Modal) - || (Current?.Modal == true && toplevel.Modal)) - { - if (toplevel.Visible) - { - Current?.OnDeactivate (toplevel); - Toplevel previousCurrent = Current; - Current = toplevel; - Current.OnActivate (previousCurrent); - - SetCurrentOverlappedAsTop (); - } - else - { - refreshDriver = false; - } - } - else if ((OverlappedTop != null - && toplevel != OverlappedTop - && Current?.Modal == true - && !_topLevels.Peek ().Modal) - || (OverlappedTop is { } && toplevel != OverlappedTop && Current?.Running == false)) - { - refreshDriver = false; - MoveCurrent (toplevel); - } - else - { - refreshDriver = false; - MoveCurrent (Current); - } - - toplevel.SetRelativeLayout (Driver.Screen.Size); - - toplevel.LayoutSubviews (); - toplevel.PositionToplevels (); - toplevel.FocusFirst (); - BringOverlappedTopToFront (); - - if (refreshDriver) - { - OverlappedTop?.OnChildLoaded (toplevel); - toplevel.OnLoaded (); - toplevel.SetNeedsDisplay (); - toplevel.Draw (); - Driver.UpdateScreen (); - - if (PositionCursor (toplevel)) - { - Driver.UpdateCursor (); - } - } - - NotifyNewRunState?.Invoke (toplevel, new (rs)); - - return rs; - } - - /// - /// Calls on the most focused view in the view starting with . - /// - /// - /// Does nothing if is or if the most focused view is not visible or - /// enabled. - /// - /// If the most focused view is not visible within it's superview, the cursor will be hidden. - /// - /// - /// if a view positioned the cursor and the position is visible. - internal static bool PositionCursor (View view) - { - // Find the most focused view and position the cursor there. - View mostFocused = view?.MostFocused; - - if (mostFocused is null) - { - if (view is { HasFocus: true }) - { - mostFocused = view; - } - else - { - return false; - } - } - - // If the view is not visible or enabled, don't position the cursor - if (!mostFocused.Visible || !mostFocused.Enabled) - { - Driver.GetCursorVisibility (out CursorVisibility current); - - if (current != CursorVisibility.Invisible) - { - Driver.SetCursorVisibility (CursorVisibility.Invisible); - } - - return false; - } - - // If the view is not visible within it's superview, don't position the cursor - Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty }); - Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen; - - if (!superViewViewport.IntersectsWith (mostFocusedViewport)) - { - return false; - } - - Point? cursor = mostFocused.PositionCursor (); - - Driver.GetCursorVisibility (out CursorVisibility currentCursorVisibility); - - if (cursor is { }) - { - // Convert cursor to screen coords - cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location; - - // If the cursor is not in a visible location in the SuperView, hide it - if (!superViewViewport.Contains (cursor.Value)) - { - if (currentCursorVisibility != CursorVisibility.Invisible) - { - Driver.SetCursorVisibility (CursorVisibility.Invisible); - } - - return false; - } - - // Show it - if (currentCursorVisibility == CursorVisibility.Invisible) - { - Driver.SetCursorVisibility (mostFocused.CursorVisibility); - } - - return true; - } - - if (currentCursorVisibility != CursorVisibility.Invisible) - { - Driver.SetCursorVisibility (CursorVisibility.Invisible); - } - - return false; - } - - /// - /// Runs the application by creating a object and calling - /// . - /// - /// - /// Calling first is not needed as this function will initialize the application. - /// - /// must be called when the application is closing (typically after Run> has returned) to - /// ensure resources are cleaned up and terminal settings restored. - /// - /// - /// The caller is responsible for disposing the object returned by this method. - /// - /// - /// The created object. The caller is responsible for disposing this object. - [RequiresUnreferencedCode ("AOT")] - [RequiresDynamicCode ("AOT")] - public static Toplevel Run (Func errorHandler = null, ConsoleDriver driver = null) { return Run (errorHandler, driver); } - - /// - /// Runs the application by creating a -derived object of type T and calling - /// . - /// - /// - /// Calling first is not needed as this function will initialize the application. - /// - /// must be called when the application is closing (typically after Run> has returned) to - /// ensure resources are cleaned up and terminal settings restored. - /// - /// - /// The caller is responsible for disposing the object returned by this method. - /// - /// - /// - /// - /// The to use. If not specified the default driver for the platform will - /// be used ( , , or ). Must be - /// if has already been called. - /// - /// The created T object. The caller is responsible for disposing this object. - [RequiresUnreferencedCode ("AOT")] - [RequiresDynamicCode ("AOT")] - public static T Run (Func errorHandler = null, ConsoleDriver driver = null) - where T : Toplevel, new() - { - if (!_initialized) - { - // Init() has NOT been called. - InternalInit (driver, null, true); - } - - var top = new T (); - - Run (top, errorHandler); - - return top; - } - - /// Runs the Application using the provided view. - /// - /// - /// This method is used to start processing events for the main application, but it is also used to run other - /// modal s such as boxes. - /// - /// - /// To make a stop execution, call - /// . - /// - /// - /// Calling is equivalent to calling - /// , followed by , and then calling - /// . - /// - /// - /// Alternatively, to have a program control the main loop and process events manually, call - /// to set things up manually and then repeatedly call - /// with the wait parameter set to false. By doing this the - /// method will only process any pending events, timers, idle handlers and then - /// return control immediately. - /// - /// When using or - /// - /// will be called automatically. - /// - /// - /// RELEASE builds only: When is any exceptions will be - /// rethrown. Otherwise, if will be called. If - /// returns the will resume; otherwise this method will - /// exit. - /// - /// - /// The to run as a modal. - /// - /// RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true, - /// rethrows when null). - /// - public static void Run (Toplevel view, Func errorHandler = null) - { - ArgumentNullException.ThrowIfNull (view); - - if (_initialized) - { - if (Driver is null) - { - // Disposing before throwing - view.Dispose (); - - // This code path should be impossible because Init(null, null) will select the platform default driver - throw new InvalidOperationException ( - "Init() completed without a driver being set (this should be impossible); Run() cannot be called." - ); - } - } - else - { - // Init() has NOT been called. - throw new InvalidOperationException ( - "Init() has not been called. Only Run() or Run() can be used without calling Init()." - ); - } - - var resume = true; - - while (resume) - { -#if !DEBUG - try - { -#endif - resume = false; - RunState runState = Begin (view); - - // If EndAfterFirstIteration is true then the user must dispose of the runToken - // by using NotifyStopRunState event. - RunLoop (runState); - - if (runState.Toplevel is null) - { -#if DEBUG_IDISPOSABLE - Debug.Assert (_topLevels.Count == 0); -#endif - runState.Dispose (); - - return; - } - - if (!EndAfterFirstIteration) - { - End (runState); - } -#if !DEBUG - } - catch (Exception error) - { - if (errorHandler is null) - { - throw; - } - - resume = errorHandler (error); - } -#endif - } - } - - /// Adds a timeout to the application. - /// - /// When time specified passes, the callback will be invoked. If the callback returns true, the timeout will be - /// reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a - /// token that can be used to stop the timeout by calling . - /// - public static object AddTimeout (TimeSpan time, Func callback) { return MainLoop?.AddTimeout (time, callback); } - - /// Removes a previously scheduled timeout - /// The token parameter is the value returned by . - /// Returns - /// true - /// if the timeout is successfully removed; otherwise, - /// false - /// . - /// This method also returns - /// false - /// if the timeout is not found. - public static bool RemoveTimeout (object token) { return MainLoop?.RemoveTimeout (token) ?? false; } - - /// Runs on the thread that is processing events - /// the action to be invoked on the main processing thread. - public static void Invoke (Action action) - { - MainLoop?.AddIdle ( - () => - { - action (); - - return false; - } - ); - } + // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`. + // This field is set in `End` in this case so that `Begin` correctly sets `Top`. // TODO: Determine if this is really needed. The only code that calls WakeUp I can find // is ProgressBarStyles, and it's not clear it needs to. - /// Wakes up the running application that might be waiting on input. - public static void Wakeup () { MainLoop?.Wakeup (); } - - /// Triggers a refresh of the entire display. - public static void Refresh () - { - // TODO: Figure out how to remove this call to ClearContents. Refresh should just repaint damaged areas, not clear - Driver.ClearContents (); - View last = null; - - foreach (Toplevel v in _topLevels.Reverse ()) - { - if (v.Visible) - { - v.SetNeedsDisplay (); - v.SetSubViewNeedsDisplay (); - v.Draw (); - } - - last = v; - } - - Driver.Refresh (); - } - - /// This event is raised on each iteration of the main loop. - /// See also - public static event EventHandler Iteration; - - /// The driver for the application - /// The main loop. - internal static MainLoop MainLoop { get; private set; } - - /// - /// Set to true to cause to be called after the first iteration. Set to false (the default) to - /// cause the application to continue running until Application.RequestStop () is called. - /// - public static bool EndAfterFirstIteration { get; set; } - - /// Building block API: Runs the main loop for the created . - /// The state returned by the method. - public static void RunLoop (RunState state) - { - ArgumentNullException.ThrowIfNull (state); - ObjectDisposedException.ThrowIf (state.Toplevel is null, "state"); - - var firstIteration = true; - - for (state.Toplevel.Running = true; state.Toplevel?.Running == true;) - { - MainLoop.Running = true; - - if (EndAfterFirstIteration && !firstIteration) - { - return; - } - - RunIteration (ref state, ref firstIteration); - } - - MainLoop.Running = false; - - // Run one last iteration to consume any outstanding input events from Driver - // This is important for remaining OnKeyUp events. - RunIteration (ref state, ref firstIteration); - } - - /// Run one application iteration. - /// The state returned by . - /// - /// Set to if this is the first run loop iteration. Upon return, it - /// will be set to if at least one iteration happened. - /// - public static void RunIteration (ref RunState state, ref bool firstIteration) - { - if (MainLoop.Running && MainLoop.EventsPending ()) - { - // Notify Toplevel it's ready - if (firstIteration) - { - state.Toplevel.OnReady (); - } - - MainLoop.RunIteration (); - Iteration?.Invoke (null, new ()); - EnsureModalOrVisibleAlwaysOnTop (state.Toplevel); - - if (state.Toplevel != Current) - { - OverlappedTop?.OnDeactivate (state.Toplevel); - state.Toplevel = Current; - OverlappedTop?.OnActivate (state.Toplevel); - Top.SetSubViewNeedsDisplay (); - Refresh (); - } - } - - firstIteration = false; - - if (Current == null) - { - return; - } - - if (state.Toplevel != Top && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded)) - { - state.Toplevel.SetNeedsDisplay (state.Toplevel.Frame); - Top.Draw (); - - foreach (Toplevel top in _topLevels.Reverse ()) - { - if (top != Top && top != state.Toplevel) - { - top.SetNeedsDisplay (); - top.SetSubViewNeedsDisplay (); - top.Draw (); - } - } - } - - if (_topLevels.Count == 1 - && state.Toplevel == Top - && (Driver.Cols != state.Toplevel.Frame.Width - || Driver.Rows != state.Toplevel.Frame.Height) - && (state.Toplevel.NeedsDisplay - || state.Toplevel.SubViewNeedsDisplay - || state.Toplevel.LayoutNeeded)) - { - Driver.ClearContents (); - } - - if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ()) - { - state.Toplevel.SetNeedsDisplay (); - state.Toplevel.Draw (); - Driver.UpdateScreen (); - - //Driver.UpdateCursor (); - } - - if (PositionCursor (state.Toplevel)) - { - Driver.UpdateCursor (); - } - - // else - { - //if (PositionCursor (state.Toplevel)) - //{ - // Driver.Refresh (); - //} - //Driver.UpdateCursor (); - } - - if (state.Toplevel != Top && !state.Toplevel.Modal && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded)) - { - Top.Draw (); - } - } - - /// Stops the provided , causing or the if provided. - /// The to stop. - /// - /// This will cause to return. - /// - /// Calling is equivalent to setting the - /// property on the currently running to false. - /// - /// - public static void RequestStop (Toplevel top = null) - { - if (OverlappedTop is null || top is null || (OverlappedTop is null && top is { })) - { - top = Current; - } - - if (OverlappedTop != null - && top.IsOverlappedContainer - && top?.Running == true - && (Current?.Modal == false || (Current?.Modal == true && Current?.Running == false))) - { - OverlappedTop.RequestStop (); - } - else if (OverlappedTop != null - && top != Current - && Current?.Running == true - && Current?.Modal == true - && top.Modal - && top.Running) - { - var ev = new ToplevelClosingEventArgs (Current); - Current.OnClosing (ev); - - if (ev.Cancel) - { - return; - } - - ev = new (top); - top.OnClosing (ev); - - if (ev.Cancel) - { - return; - } - - Current.Running = false; - OnNotifyStopRunState (Current); - top.Running = false; - OnNotifyStopRunState (top); - } - else if ((OverlappedTop != null - && top != OverlappedTop - && top != Current - && Current?.Modal == false - && Current?.Running == true - && !top.Running) - || (OverlappedTop != null - && top != OverlappedTop - && top != Current - && Current?.Modal == false - && Current?.Running == false - && !top.Running - && _topLevels.ToArray () [1].Running)) - { - MoveCurrent (top); - } - else if (OverlappedTop != null - && Current != top - && Current?.Running == true - && !top.Running - && Current?.Modal == true - && top.Modal) - { - // The Current and the top are both modal so needed to set the Current.Running to false too. - Current.Running = false; - OnNotifyStopRunState (Current); - } - else if (OverlappedTop != null - && Current == top - && OverlappedTop?.Running == true - && Current?.Running == true - && top.Running - && Current?.Modal == true - && top.Modal) - { - // The OverlappedTop was requested to stop inside a modal Toplevel which is the Current and top, - // both are the same, so needed to set the Current.Running to false too. - Current.Running = false; - OnNotifyStopRunState (Current); - } - else - { - Toplevel currentTop; - - if (top == Current || (Current?.Modal == true && !top.Modal)) - { - currentTop = Current; - } - else - { - currentTop = top; - } - - if (!currentTop.Running) - { - return; - } - - var ev = new ToplevelClosingEventArgs (currentTop); - currentTop.OnClosing (ev); - - if (ev.Cancel) - { - return; - } - - currentTop.Running = false; - OnNotifyStopRunState (currentTop); - } - } - - private static void OnNotifyStopRunState (Toplevel top) - { - if (EndAfterFirstIteration) - { - NotifyStopRunState?.Invoke (top, new (top)); - } - } - - /// - /// Building block API: completes the execution of a that was started with - /// . - /// - /// The returned by the method. - public static void End (RunState runState) - { - ArgumentNullException.ThrowIfNull (runState); - - if (OverlappedTop is { }) - { - OverlappedTop.OnChildUnloaded (runState.Toplevel); - } - 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 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 OverlappedTop that is not the RunState.Toplevel then RunState.Toplevel - // is a child of MidTop, and we should notify the OverlappedTop that it is closing - if (OverlappedTop is { } && !runState.Toplevel.Modal && runState.Toplevel != OverlappedTop) - { - OverlappedTop.OnChildClosed (runState.Toplevel); - } - - // Set Current and Top to the next TopLevel on the stack - if (_topLevels.Count == 0) - { - Current = null; - } - else - { - if (_topLevels.Count > 1 && _topLevels.Peek () == OverlappedTop && OverlappedChildren.Any (t => t.Visible) is { }) - { - OverlappedMoveNext (); - } - - Current = _topLevels.Peek (); - - if (_topLevels.Count == 1 && Current == OverlappedTop) - { - OverlappedTop.OnAllChildClosed (); - } - else - { - SetCurrentOverlappedAsTop (); - runState.Toplevel.OnLeave (Current); - Current.OnEnter (runState.Toplevel); - } - - Refresh (); - } - - // Don't dispose runState.Toplevel. It's up to caller dispose it - // If it's not the same as the current in the RunIteration, - // it will be fixed later in the next RunIteration. - if (OverlappedTop is { } && !_topLevels.Contains (OverlappedTop)) - { - _cachedRunStateToplevel = OverlappedTop; - } - else - { - _cachedRunStateToplevel = runState.Toplevel; - } - - runState.Toplevel = null; - runState.Dispose (); - } - - #endregion Run (Begin, Run, End) #region Toplevel handling @@ -1240,7 +150,7 @@ public static partial class Application /// The object used for the application on startup () /// The top. - public static Toplevel Top { get; private set; } + public static Toplevel? Top { get; private set; } /// /// The current object. This is updated in enters and leaves to @@ -1251,7 +161,7 @@ public static partial class Application /// Only relevant in scenarios where is . /// /// The current. - public static Toplevel Current { get; private set; } + public static Toplevel? Current { get; private set; } private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel topLevel) { @@ -1263,7 +173,7 @@ public static partial class Application return; } - foreach (Toplevel top in _topLevels.Reverse ()) + foreach (Toplevel? top in _topLevels.Reverse ()) { if (top.Modal && top != Current) { @@ -1292,7 +202,7 @@ public static partial class Application int rx = location.X - start.Frame.X; int ry = location.Y - start.Frame.Y; - foreach (Toplevel t in _topLevels) + foreach (Toplevel? t in _topLevels) { if (t != Current) { @@ -1327,7 +237,7 @@ public static partial class Application #nullable enable // Only return true if the Current has changed. - private static bool MoveCurrent (Toplevel? top) + private static bool MoveCurrent (Toplevel top) { // The Current is modal and the top is not modal Toplevel then // the Current must be moved above the first not modal Toplevel. @@ -1343,9 +253,9 @@ public static partial class Application } var index = 0; - Toplevel [] savedToplevels = _topLevels.ToArray (); + Toplevel? [] savedToplevels = _topLevels.ToArray (); - foreach (Toplevel t in savedToplevels) + foreach (Toplevel? t in savedToplevels) { if (!t.Modal && t != Current && t != top && t != savedToplevels [index]) { @@ -1376,7 +286,7 @@ public static partial class Application var index = 0; - foreach (Toplevel t in _topLevels.ToArray ()) + foreach (Toplevel? t in _topLevels.ToArray ()) { if (!t.Running && t != Current && index > 0) { @@ -1505,6 +415,7 @@ public static partial class Application sb.AppendLine (); } + return sb.ToString (); } } diff --git a/Terminal.Gui/Clipboard/Clipboard.cs b/Terminal.Gui/Clipboard/Clipboard.cs index 63c1cc40a..5dccea0a4 100644 --- a/Terminal.Gui/Clipboard/Clipboard.cs +++ b/Terminal.Gui/Clipboard/Clipboard.cs @@ -31,11 +31,11 @@ public static class Clipboard { if (IsSupported) { - string clipData = Application.Driver.Clipboard.GetClipboardData (); + string clipData = Application.Driver?.Clipboard.GetClipboardData (); if (clipData is null) { - // throw new InvalidOperationException ($"{Application.Driver.GetType ().Name}.GetClipboardData returned null instead of string.Empty"); + // throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty"); clipData = string.Empty; } @@ -60,7 +60,7 @@ public static class Clipboard value = string.Empty; } - Application.Driver.Clipboard.SetClipboardData (value); + Application.Driver?.Clipboard.SetClipboardData (value); } _contents = value; @@ -74,19 +74,16 @@ public static class Clipboard /// Returns true if the environmental dependencies are in place to interact with the OS clipboard. /// - public static bool IsSupported => Application.Driver.Clipboard.IsSupported; + public static bool IsSupported => Application.Driver?.Clipboard.IsSupported ?? false; /// Copies the _contents of the OS clipboard to if possible. /// The _contents of the OS clipboard if successful, if not. /// the OS clipboard was retrieved, otherwise. public static bool TryGetClipboardData (out string result) { - if (IsSupported && Application.Driver.Clipboard.TryGetClipboardData (out result)) + if (IsSupported && Application.Driver!.Clipboard.TryGetClipboardData (out result)) { - if (_contents != result) - { - _contents = result; - } + _contents = result; return true; } @@ -101,7 +98,7 @@ public static class Clipboard /// the OS clipboard was set, otherwise. public static bool TrySetClipboardData (string text) { - if (IsSupported && Application.Driver.Clipboard.TrySetClipboardData (text)) + if (IsSupported && Application.Driver!.Clipboard.TrySetClipboardData (text)) { _contents = text; @@ -155,7 +152,7 @@ internal static class ClipboardProcessRunner using (var process = new Process { - StartInfo = new ProcessStartInfo + StartInfo = new() { FileName = cmd, Arguments = arguments, @@ -191,17 +188,9 @@ internal static class ClipboardProcessRunner if (process.ExitCode > 0) { - output = $@"Process failed to run. Command line: { - cmd - } { - arguments - }. - Output: { - output - } - Error: { - process.StandardError.ReadToEnd () - }"; + output = $@"Process failed to run. Command line: {cmd} {arguments}. + Output: {output} + Error: {process.StandardError.ReadToEnd ()}"; } return (process.ExitCode, output); diff --git a/Terminal.Gui/Drawing/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas.cs index 4b5119a82..9a7365f26 100644 --- a/Terminal.Gui/Drawing/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas.cs @@ -336,7 +336,7 @@ public class LineCanvas : IDisposable return Fill != null ? Fill.GetAttribute (intersects [0]!.Point) : intersects [0]!.Line.Attribute; } - private Cell? GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition? [] intersects) + private Cell? GetCellForIntersects (ConsoleDriver? driver, IntersectionDefinition? [] intersects) { if (!intersects.Any ()) { @@ -356,7 +356,7 @@ public class LineCanvas : IDisposable return cell; } - private Rune? GetRuneForIntersects (ConsoleDriver driver, IntersectionDefinition? [] intersects) + private Rune? GetRuneForIntersects (ConsoleDriver? driver, IntersectionDefinition? [] intersects) { if (!intersects.Any ()) { @@ -679,7 +679,7 @@ public class LineCanvas : IDisposable internal Rune _thickV; public IntersectionRuneResolver () { SetGlyphs (); } - public Rune? GetRuneForIntersects (ConsoleDriver driver, IntersectionDefinition? [] intersects) + public Rune? GetRuneForIntersects (ConsoleDriver? driver, IntersectionDefinition? [] intersects) { bool useRounded = intersects.Any ( i => i?.Line.Length != 0 diff --git a/Terminal.Gui/Drawing/Ruler.cs b/Terminal.Gui/Drawing/Ruler.cs index 348036c84..d2551101d 100644 --- a/Terminal.Gui/Drawing/Ruler.cs +++ b/Terminal.Gui/Drawing/Ruler.cs @@ -39,8 +39,8 @@ public class Ruler _hTemplate.Repeat ((int)Math.Ceiling (Length + 2 / (double)_hTemplate.Length)) [start..(Length + start)]; // Top - Application.Driver.Move (location.X, location.Y); - Application.Driver.AddStr (hrule); + Application.Driver?.Move (location.X, location.Y); + Application.Driver?.AddStr (hrule); } else { @@ -50,8 +50,8 @@ public class Ruler for (int r = location.Y; r < location.Y + Length; r++) { - Application.Driver.Move (location.X, r); - Application.Driver.AddRune ((Rune)vrule [r - location.Y]); + Application.Driver?.Move (location.X, r); + Application.Driver?.AddRune ((Rune)vrule [r - location.Y]); } } } diff --git a/Terminal.Gui/Drawing/Thickness.cs b/Terminal.Gui/Drawing/Thickness.cs index 532c0af8a..ac6cc6cd6 100644 --- a/Terminal.Gui/Drawing/Thickness.cs +++ b/Terminal.Gui/Drawing/Thickness.cs @@ -119,20 +119,20 @@ public record struct Thickness // Draw the Top side if (Top > 0) { - Application.Driver.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar); + Application.Driver?.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar); } // Draw the Left side // Draw the Left side if (Left > 0) { - Application.Driver.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar); + Application.Driver?.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar); } // Draw the Right side if (Right > 0) { - Application.Driver.FillRect ( + Application.Driver?.FillRect ( rect with { X = Math.Max (0, rect.X + rect.Width - Right), @@ -145,7 +145,7 @@ public record struct Thickness // Draw the Bottom side if (Bottom > 0) { - Application.Driver.FillRect ( + Application.Driver?.FillRect ( rect with { Y = rect.Y + Math.Max (0, rect.Height - Bottom), @@ -197,7 +197,11 @@ public record struct Thickness VerticalAlignment = Alignment.End, AutoSize = true }; - tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect); + + if (Application.Driver?.CurrentAttribute is { }) + { + tf.Draw (rect, Application.Driver!.CurrentAttribute, Application.Driver!.CurrentAttribute, rect); + } } return GetInside (rect); diff --git a/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs b/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs index f5f7190e6..2fa920e70 100644 --- a/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs +++ b/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs @@ -106,7 +106,7 @@ public class AppendAutocomplete : AutocompleteBase } // draw it like it's selected, even though it's not - Application.Driver.SetAttribute ( + Application.Driver?.SetAttribute ( new Attribute ( ColorScheme.Normal.Foreground, textField.ColorScheme.Focus.Background @@ -128,7 +128,7 @@ public class AppendAutocomplete : AutocompleteBase ); } - Application.Driver.AddStr (fragment); + Application.Driver?.AddStr (fragment); } /// diff --git a/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs index 93e32b12e..4dfeb8a95 100644 --- a/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs +++ b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs @@ -376,18 +376,18 @@ public abstract partial class PopupAutocomplete : AutocompleteBase { if (i == SelectedIdx - ScrollOffset) { - Application.Driver.SetAttribute (ColorScheme.Focus); + Application.Driver?.SetAttribute (ColorScheme.Focus); } else { - Application.Driver.SetAttribute (ColorScheme.Normal); + Application.Driver?.SetAttribute (ColorScheme.Normal); } popup.Move (0, i); string text = TextFormatter.ClipOrPad (toRender [i].Title, width); - Application.Driver.AddStr (text); + Application.Driver?.AddStr (text); } } diff --git a/Terminal.Gui/View/Layout/Dim.cs b/Terminal.Gui/View/Layout/Dim.cs index e765414cb..7dfc6eb2e 100644 --- a/Terminal.Gui/View/Layout/Dim.cs +++ b/Terminal.Gui/View/Layout/Dim.cs @@ -139,7 +139,7 @@ public abstract class Dim /// Creates a object that tracks the Height of the specified . /// The height of the other . /// The view that will be tracked. - public static Dim Height (View view) { return new DimView (view, Dimension.Height); } + public static Dim Height (View? view) { return new DimView (view, Dimension.Height); } /// Creates a percentage object that is a percentage of the width or height of the SuperView. /// The percent object. @@ -171,7 +171,7 @@ public abstract class Dim /// Creates a object that tracks the Width of the specified . /// The width of the other . /// The view that will be tracked. - public static Dim Width (View view) { return new DimView (view, Dimension.Width); } + public static Dim Width (View? view) { return new DimView (view, Dimension.Width); } #endregion static Dim creation methods diff --git a/Terminal.Gui/View/Layout/DimView.cs b/Terminal.Gui/View/Layout/DimView.cs index 22c0d1f70..09ea96800 100644 --- a/Terminal.Gui/View/Layout/DimView.cs +++ b/Terminal.Gui/View/Layout/DimView.cs @@ -15,7 +15,7 @@ public class DimView : Dim /// /// The view the dimension is anchored to. /// Indicates which dimension is tracked. - public DimView (View view, Dimension dimension) + public DimView (View? view, Dimension dimension) { Target = view; Dimension = dimension; @@ -35,7 +35,7 @@ public class DimView : Dim /// /// Gets the View the dimension is anchored to. /// - public View Target { get; init; } + public View? Target { get; init; } /// public override string ToString () diff --git a/Terminal.Gui/View/Layout/Pos.cs b/Terminal.Gui/View/Layout/Pos.cs index 2213524ae..853bfa0ab 100644 --- a/Terminal.Gui/View/Layout/Pos.cs +++ b/Terminal.Gui/View/Layout/Pos.cs @@ -257,22 +257,22 @@ public abstract class Pos /// Creates a object that tracks the Top (Y) position of the specified . /// The that depends on the other view. /// The that will be tracked. - public static Pos Top (View view) { return new PosView (view, Side.Top); } + public static Pos Top (View? view) { return new PosView (view, Side.Top); } /// Creates a object that tracks the Top (Y) position of the specified . /// The that depends on the other view. /// The that will be tracked. - public static Pos Y (View view) { return new PosView (view, Side.Top); } + public static Pos Y (View? view) { return new PosView (view, Side.Top); } /// Creates a object that tracks the Left (X) position of the specified . /// The that depends on the other view. /// The that will be tracked. - public static Pos Left (View view) { return new PosView (view, Side.Left); } + public static Pos Left (View? view) { return new PosView (view, Side.Left); } /// Creates a object that tracks the Left (X) position of the specified . /// The that depends on the other view. /// The that will be tracked. - public static Pos X (View view) { return new PosView (view, Side.Left); } + public static Pos X (View? view) { return new PosView (view, Side.Left); } /// /// Creates a object that tracks the Bottom (Y+Height) coordinate of the specified @@ -280,7 +280,7 @@ public abstract class Pos /// /// The that depends on the other view. /// The that will be tracked. - public static Pos Bottom (View view) { return new PosView (view, Side.Bottom); } + public static Pos Bottom (View? view) { return new PosView (view, Side.Bottom); } /// /// Creates a object that tracks the Right (X+Width) coordinate of the specified @@ -288,7 +288,7 @@ public abstract class Pos /// /// The that depends on the other view. /// The that will be tracked. - public static Pos Right (View view) { return new PosView (view, Side.Right); } + public static Pos Right (View? view) { return new PosView (view, Side.Right); } #endregion static Pos creation methods diff --git a/Terminal.Gui/View/Layout/PosView.cs b/Terminal.Gui/View/Layout/PosView.cs index b48613307..fdf5bf784 100644 --- a/Terminal.Gui/View/Layout/PosView.cs +++ b/Terminal.Gui/View/Layout/PosView.cs @@ -12,12 +12,12 @@ namespace Terminal.Gui; /// /// The View the position is anchored to. /// The side of the View the position is anchored to. -public class PosView (View view, Side side) : Pos +public class PosView (View? view, Side side) : Pos { /// /// Gets the View the position is anchored to. /// - public View Target { get; } = view; + public View? Target { get; } = view; /// /// Gets the side of the View the position is anchored to. diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index fa0983993..637d1f0ca 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -398,7 +398,7 @@ public partial class View /// Either (if does not have a Super View) or /// 's SuperView. This can be used to ensure LayoutSubviews is called on the correct View. /// - internal static View GetLocationEnsuringFullVisibility ( + internal static View? GetLocationEnsuringFullVisibility ( View viewToMove, int targetX, int targetY, @@ -408,7 +408,7 @@ public partial class View ) { int maxDimension; - View superView; + View? superView; statusBar = null!; if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top) diff --git a/Terminal.Gui/View/ViewDrawing.cs b/Terminal.Gui/View/ViewDrawing.cs index 67778536f..73fa5d550 100644 --- a/Terminal.Gui/View/ViewDrawing.cs +++ b/Terminal.Gui/View/ViewDrawing.cs @@ -288,19 +288,19 @@ public partial class View public void DrawHotString (string text, Attribute hotColor, Attribute normalColor) { Rune hotkeySpec = HotKeySpecifier == (Rune)0xffff ? (Rune)'_' : HotKeySpecifier; - Application.Driver.SetAttribute (normalColor); + Application.Driver?.SetAttribute (normalColor); foreach (Rune rune in text.EnumerateRunes ()) { if (rune == new Rune (hotkeySpec.Value)) { - Application.Driver.SetAttribute (hotColor); + Application.Driver?.SetAttribute (hotColor); continue; } - Application.Driver.AddRune (rune); - Application.Driver.SetAttribute (normalColor); + Application.Driver?.AddRune (rune); + Application.Driver?.SetAttribute (normalColor); } } diff --git a/Terminal.Gui/Views/GraphView/Annotations.cs b/Terminal.Gui/Views/GraphView/Annotations.cs index 30247d4a6..7dbc8836e 100644 --- a/Terminal.Gui/Views/GraphView/Annotations.cs +++ b/Terminal.Gui/Views/GraphView/Annotations.cs @@ -133,7 +133,7 @@ public class LegendAnnotation : View, IAnnotation { if (!IsInitialized) { - ColorScheme = new ColorScheme { Normal = Application.Driver.GetAttribute () }; + ColorScheme = new ColorScheme { Normal = Application.Driver?.GetAttribute () ?? Attribute.Default}; graph.Add (this); } @@ -149,7 +149,7 @@ public class LegendAnnotation : View, IAnnotation { if (entry.Item1.Color.HasValue) { - Application.Driver.SetAttribute (entry.Item1.Color.Value); + Application.Driver?.SetAttribute (entry.Item1.Color.Value); } else { @@ -166,7 +166,7 @@ public class LegendAnnotation : View, IAnnotation Move (1, linesDrawn); string str = TextFormatter.ClipOrPad (entry.Item2, Viewport.Width - 1); - Application.Driver.AddStr (str); + Application.Driver?.AddStr (str); linesDrawn++; diff --git a/Terminal.Gui/Views/GraphView/Axis.cs b/Terminal.Gui/Views/GraphView/Axis.cs index efff79ce9..c46938890 100644 --- a/Terminal.Gui/Views/GraphView/Axis.cs +++ b/Terminal.Gui/Views/GraphView/Axis.cs @@ -103,7 +103,7 @@ public class HorizontalAxis : Axis graph.Move (screenPosition, y); // draw the tick on the axis - Application.Driver.AddRune (Glyphs.TopTee); + Application.Driver?.AddRune (Glyphs.TopTee); // and the label text if (!string.IsNullOrWhiteSpace (text)) @@ -161,7 +161,7 @@ public class HorizontalAxis : Axis } graph.Move (graph.Viewport.Width / 2 - toRender.Length / 2, graph.Viewport.Height - 1); - Application.Driver.AddStr (toRender); + Application.Driver?.AddStr (toRender); } } @@ -222,7 +222,7 @@ public class HorizontalAxis : Axis protected override void DrawAxisLine (GraphView graph, int x, int y) { graph.Move (x, y); - Application.Driver.AddRune (Glyphs.HLine); + Application.Driver?.AddRune (Glyphs.HLine); } private IEnumerable GetLabels (GraphView graph, Rectangle viewport) @@ -298,13 +298,13 @@ public class VerticalAxis : Axis graph.Move (x, screenPosition); // draw the tick on the axis - Application.Driver.AddRune (Glyphs.RightTee); + Application.Driver?.AddRune (Glyphs.RightTee); // and the label text if (!string.IsNullOrWhiteSpace (text)) { graph.Move (Math.Max (0, x - labelThickness), screenPosition); - Application.Driver.AddStr (text); + Application.Driver?.AddStr (text); } } @@ -342,7 +342,7 @@ public class VerticalAxis : Axis for (var i = 0; i < toRender.Length; i++) { graph.Move (0, startDrawingAtY + i); - Application.Driver.AddRune ((Rune)toRender [i]); + Application.Driver?.AddRune ((Rune)toRender [i]); } } } @@ -395,7 +395,7 @@ public class VerticalAxis : Axis protected override void DrawAxisLine (GraphView graph, int x, int y) { graph.Move (x, y); - Application.Driver.AddRune (Glyphs.VLine); + Application.Driver?.AddRune (Glyphs.VLine); } private int GetAxisYEnd (GraphView graph) diff --git a/Terminal.Gui/Views/GraphView/Series.cs b/Terminal.Gui/Views/GraphView/Series.cs index f0974556c..f7c02e174 100644 --- a/Terminal.Gui/Views/GraphView/Series.cs +++ b/Terminal.Gui/Views/GraphView/Series.cs @@ -33,7 +33,7 @@ public class ScatterSeries : ISeries { if (Fill.Color.HasValue) { - Application.Driver.SetAttribute (Fill.Color.Value); + Application.Driver?.SetAttribute (Fill.Color.Value); } foreach (PointF p in Points.Where (p => graphBounds.Contains (p))) @@ -261,7 +261,7 @@ public class BarSeries : ISeries if (adjusted.Color.HasValue) { - Application.Driver.SetAttribute (adjusted.Color.Value); + Application.Driver?.SetAttribute (adjusted.Color.Value); } graph.DrawLine (start, end, adjusted.Rune); diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs index 8bcbc076a..f35cbdf34 100644 --- a/Terminal.Gui/Views/Menu/ContextMenu.cs +++ b/Terminal.Gui/Views/Menu/ContextMenu.cs @@ -144,7 +144,7 @@ public sealed class ContextMenu : IDisposable _container = Application.Current; _container.Closing += Container_Closing; _container.Deactivate += Container_Deactivate; - Rectangle frame = Application.Driver.Screen; + Rectangle frame = Application.Driver?.Screen ?? Rectangle.Empty; Point position = Position; if (Host is { }) diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index f0dc5174b..bb2996ba4 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/Terminal.Gui/Views/RadioGroup.cs @@ -278,7 +278,7 @@ public class RadioGroup : View, IDesignable if (j == hotPos && i == _cursor) { - Application.Driver.SetAttribute ( + Application.Driver?.SetAttribute ( HasFocus ? ColorScheme.HotFocus : GetHotNormalColor () @@ -286,11 +286,11 @@ public class RadioGroup : View, IDesignable } else if (j == hotPos && i != _cursor) { - Application.Driver.SetAttribute (GetHotNormalColor ()); + Application.Driver?.SetAttribute (GetHotNormalColor ()); } else if (HasFocus && i == _cursor) { - Application.Driver.SetAttribute (ColorScheme.Focus); + Application.Driver?.SetAttribute (ColorScheme.Focus); } if (rune == HotKeySpecifier && j + 1 < rlRunes.Length) @@ -300,7 +300,7 @@ public class RadioGroup : View, IDesignable if (i == _cursor) { - Application.Driver.SetAttribute ( + Application.Driver?.SetAttribute ( HasFocus ? ColorScheme.HotFocus : GetHotNormalColor () @@ -308,11 +308,11 @@ public class RadioGroup : View, IDesignable } else if (i != _cursor) { - Application.Driver.SetAttribute (GetHotNormalColor ()); + Application.Driver?.SetAttribute (GetHotNormalColor ()); } } - Application.Driver.AddRune (rune); + Application.Driver?.AddRune (rune); Driver.SetAttribute (GetNormalColor ()); } } diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index b61ebb09f..78455eeca 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -15,20 +15,20 @@ public class CombiningMarks : Scenario top.DrawContentComplete += (s, e) => { - Application.Driver.Move (0, 0); - Application.Driver.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); - Application.Driver.Move (0, 2); - Application.Driver.AddStr ("\u0301\u0301\u0328<- \"\\u301\\u301\\u328]\" using AddStr."); - Application.Driver.Move (0, 3); - Application.Driver.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u301\\u301\\u328]\" using AddStr."); - Application.Driver.Move (0, 4); - Application.Driver.AddRune ('['); - Application.Driver.AddRune ('a'); - Application.Driver.AddRune ('\u0301'); - Application.Driver.AddRune ('\u0301'); - Application.Driver.AddRune ('\u0328'); - Application.Driver.AddRune (']'); - Application.Driver.AddStr ("<- \"[a\\u301\\u301\\u328]\" using AddRune for each."); + Application.Driver?.Move (0, 0); + Application.Driver?.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); + Application.Driver?.Move (0, 2); + Application.Driver?.AddStr ("\u0301\u0301\u0328<- \"\\u301\\u301\\u328]\" using AddStr."); + Application.Driver?.Move (0, 3); + Application.Driver?.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u301\\u301\\u328]\" using AddStr."); + Application.Driver?.Move (0, 4); + Application.Driver?.AddRune ('['); + Application.Driver?.AddRune ('a'); + Application.Driver?.AddRune ('\u0301'); + Application.Driver?.AddRune ('\u0301'); + Application.Driver?.AddRune ('\u0328'); + Application.Driver?.AddRune (']'); + Application.Driver?.AddStr ("<- \"[a\\u301\\u301\\u328]\" using AddRune for each."); }; Application.Run (top); diff --git a/UICatalog/Scenarios/Images.cs b/UICatalog/Scenarios/Images.cs index d31eae9cc..f17246742 100644 --- a/UICatalog/Scenarios/Images.cs +++ b/UICatalog/Scenarios/Images.cs @@ -20,9 +20,9 @@ public class Images : Scenario Application.Init (); var win = new Window { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName()}" }; - bool canTrueColor = Application.Driver.SupportsTrueColor; + bool canTrueColor = Application.Driver?.SupportsTrueColor ?? false; - var lblDriverName = new Label { X = 0, Y = 0, Text = $"Driver is {Application.Driver.GetType ().Name}" }; + var lblDriverName = new Label { X = 0, Y = 0, Text = $"Driver is {Application.Driver?.GetType ().Name}" }; win.Add (lblDriverName); var cbSupportsTrueColor = new CheckBox diff --git a/UICatalog/Scenarios/SendKeys.cs b/UICatalog/Scenarios/SendKeys.cs index a27a80232..6dc4a3bdf 100644 --- a/UICatalog/Scenarios/SendKeys.cs +++ b/UICatalog/Scenarios/SendKeys.cs @@ -86,7 +86,7 @@ public class SendKeys : Scenario ? (ConsoleKey)char.ToUpper (r) : (ConsoleKey)r; - Application.Driver.SendKeys ( + Application.Driver?.SendKeys ( r, ck, ckbShift.State == CheckState.Checked, diff --git a/UICatalog/Scenarios/TextEffectsScenario.cs b/UICatalog/Scenarios/TextEffectsScenario.cs index 17f6a6e5c..7d5d0e156 100644 --- a/UICatalog/Scenarios/TextEffectsScenario.cs +++ b/UICatalog/Scenarios/TextEffectsScenario.cs @@ -260,5 +260,5 @@ internal class GradientsView : View } } - private static void SetColor (Color color) { Application.Driver.SetAttribute (new (color, color)); } + private static void SetColor (Color color) { Application.Driver?.SetAttribute (new (color, color)); } } diff --git a/UICatalog/Scenarios/TrueColors.cs b/UICatalog/Scenarios/TrueColors.cs index 19e00187d..d08d9685a 100644 --- a/UICatalog/Scenarios/TrueColors.cs +++ b/UICatalog/Scenarios/TrueColors.cs @@ -19,11 +19,11 @@ public class TrueColors : Scenario var x = 2; var y = 1; - bool canTrueColor = Application.Driver.SupportsTrueColor; + bool canTrueColor = Application.Driver?.SupportsTrueColor ?? false; var lblDriverName = new Label { - X = x, Y = y++, Text = $"Current driver is {Application.Driver.GetType ().Name}" + X = x, Y = y++, Text = $"Current driver is {Application.Driver?.GetType ().Name}" }; app.Add (lblDriverName); y++; diff --git a/UICatalog/Scenarios/VkeyPacketSimulator.cs b/UICatalog/Scenarios/VkeyPacketSimulator.cs index 50ce09b71..975775f45 100644 --- a/UICatalog/Scenarios/VkeyPacketSimulator.cs +++ b/UICatalog/Scenarios/VkeyPacketSimulator.cs @@ -198,7 +198,7 @@ public class VkeyPacketSimulator : Scenario char keyChar = ConsoleKeyMapping.EncodeKeyCharForVKPacket (consoleKeyInfo); - Application.Driver.SendKeys ( + Application.Driver?.SendKeys ( keyChar, ConsoleKey.Packet, consoleKeyInfo.Modifiers.HasFlag (ConsoleModifiers.Shift), diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index ddb4c656f..dd4184cb4 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -369,7 +369,7 @@ internal class UICatalogApp /// public class UICatalogTopLevel : Toplevel { - public ListView CategoryList; + public ListView? CategoryList; public MenuItem? MiForce16Colors; public MenuItem? MiIsMenuBorderDisabled; public MenuItem? MiIsMouseDisabled; @@ -999,7 +999,7 @@ internal class UICatalogApp Title = "Force _16 Colors", Shortcut = (KeyCode)Key.F6, Checked = Application.Force16Colors, - CanExecute = () => Application.Driver.SupportsTrueColor + CanExecute = () => Application.Driver?.SupportsTrueColor ?? false }; MiForce16Colors.CheckType |= MenuItemCheckStyle.Checked; diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index a7c1fc64a..6363233a9 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -44,7 +44,7 @@ public class ApplicationTests Toplevel top = new (); Application.Begin (top); Assert.Equal (new (0, 0, 80, 25), Application.Top.Frame); - ((FakeDriver)Application.Driver).SetBufferSize (5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, 5); Assert.Equal (new (0, 0, 5, 5), Application.Top.Frame); top.Dispose (); } @@ -134,7 +134,7 @@ public class ApplicationTests Application.Init (driverName: driverType.Name); Assert.NotNull (Application.Driver); Assert.NotEqual (driver, Application.Driver); - Assert.Equal (driverType, Application.Driver.GetType ()); + Assert.Equal (driverType, Application.Driver?.GetType ()); Shutdown (); } @@ -565,8 +565,8 @@ public class ApplicationTests Assert.NotNull (Application.MainLoop); // FakeDriver is always 80x25 - Assert.Equal (80, Application.Driver.Cols); - Assert.Equal (25, Application.Driver.Rows); + Assert.Equal (80, Application.Driver!.Cols); + Assert.Equal (25, Application.Driver!.Rows); } private void Pre_Init_State () @@ -695,7 +695,7 @@ public class ApplicationTests Application.ForceDriver = "FakeDriver"; Application.Init (); - Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ()); + Assert.Equal (typeof (FakeDriver), Application.Driver?.GetType ()); Application.Iteration += (s, a) => { Application.RequestStop (); }; @@ -737,7 +737,7 @@ public class ApplicationTests Application.Iteration += (s, a) => { Application.RequestStop (); }; Application.Run (); - Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ()); + Assert.Equal (typeof (FakeDriver), Application.Driver?.GetType ()); Application.Top.Dispose (); Shutdown (); @@ -888,7 +888,7 @@ public class ApplicationTests Width = 5, Height = 5, Arrangement = ViewArrangement.Movable }; - ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 10); RunState rs = Application.Begin (w); // Don't use visuals to test as style of border can change over time. diff --git a/UnitTests/Application/CursorTests.cs b/UnitTests/Application/CursorTests.cs index 337003b0f..87999a9d2 100644 --- a/UnitTests/Application/CursorTests.cs +++ b/UnitTests/Application/CursorTests.cs @@ -141,7 +141,10 @@ public class CursorTests Assert.True (view.HasFocus); Assert.False (Application.PositionCursor (view)); - Application.Driver.GetCursorVisibility (out CursorVisibility cursor); - Assert.Equal (CursorVisibility.Invisible, cursor); + + if (Application.Driver?.GetCursorVisibility (out CursorVisibility cursor) ?? false) + { + Assert.Equal (CursorVisibility.Invisible, cursor); + } } } diff --git a/UnitTests/Clipboard/ClipboardTests.cs b/UnitTests/Clipboard/ClipboardTests.cs index 65c2e7707..e2c0ac11f 100644 --- a/UnitTests/Clipboard/ClipboardTests.cs +++ b/UnitTests/Clipboard/ClipboardTests.cs @@ -9,14 +9,14 @@ public class ClipboardTests [Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)] public void IClipboard_GetClipBoardData_Throws_NotSupportedException () { - var iclip = Application.Driver.Clipboard; + var iclip = Application.Driver?.Clipboard; Assert.Throws (() => iclip.GetClipboardData ()); } [Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)] public void IClipboard_SetClipBoardData_Throws_NotSupportedException () { - var iclip = Application.Driver.Clipboard; + var iclip = Application.Driver?.Clipboard; Assert.Throws (() => iclip.SetClipboardData ("foo")); } diff --git a/UnitTests/ConsoleDrivers/ClipRegionTests.cs b/UnitTests/ConsoleDrivers/ClipRegionTests.cs index 0d27f91c1..8a90f2e4d 100644 --- a/UnitTests/ConsoleDrivers/ClipRegionTests.cs +++ b/UnitTests/ConsoleDrivers/ClipRegionTests.cs @@ -26,8 +26,8 @@ public class ClipRegionTests { var driver = (ConsoleDriver)Activator.CreateInstance (driverType); Application.Init (driver); - Application.Driver.Rows = 25; - Application.Driver.Cols = 80; + Application.Driver!.Rows = 25; + Application.Driver!.Cols = 80; driver.Move (0, 0); driver.AddRune ('x'); @@ -94,8 +94,8 @@ public class ClipRegionTests { var driver = (ConsoleDriver)Activator.CreateInstance (driverType); Application.Init (driver); - Application.Driver.Rows = 10; - Application.Driver.Cols = 10; + Application.Driver!.Rows = 10; + Application.Driver!.Cols = 10; // positive Assert.True (driver.IsValidLocation (0, 0)); diff --git a/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs b/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs index afbf20d96..8ecc97807 100644 --- a/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs +++ b/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs @@ -234,7 +234,7 @@ public class ConsoleDriverTests // { // var win = new Window (); // Application.Begin (win); - // ((FakeDriver)Application.Driver).SetBufferSize (20, 8); + // ((FakeDriver)Application.Driver!).SetBufferSize (20, 8); // System.Threading.Tasks.Task.Run (() => { // System.Threading.Tasks.Task.Delay (500).Wait (); diff --git a/UnitTests/ConsoleDrivers/ConsoleKeyMappingTests.cs b/UnitTests/ConsoleDrivers/ConsoleKeyMappingTests.cs index de05b868f..1ea984b3d 100644 --- a/UnitTests/ConsoleDrivers/ConsoleKeyMappingTests.cs +++ b/UnitTests/ConsoleDrivers/ConsoleKeyMappingTests.cs @@ -123,7 +123,7 @@ public class ConsoleKeyMappingTests if (iterations == 0) { var keyChar = ConsoleKeyMapping.EncodeKeyCharForVKPacket (consoleKeyInfo); - Application.Driver.SendKeys (keyChar, ConsoleKey.Packet, shift, alt, control); + Application.Driver?.SendKeys (keyChar, ConsoleKey.Packet, shift, alt, control); } }; Application.Run (); diff --git a/UnitTests/Dialogs/MessageBoxTests.cs b/UnitTests/Dialogs/MessageBoxTests.cs index f32f7074a..8715eea2c 100644 --- a/UnitTests/Dialogs/MessageBoxTests.cs +++ b/UnitTests/Dialogs/MessageBoxTests.cs @@ -125,7 +125,7 @@ public class MessageBoxTests public void Location_Default () { int iterations = -1; - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); Application.Iteration += (s, a) => { @@ -243,7 +243,7 @@ public class MessageBoxTests int iterations = -1; var top = new Toplevel (); top.BorderStyle = LineStyle.None; - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var btn = $"{ @@ -319,7 +319,7 @@ public class MessageBoxTests int iterations = -1; var top = new Toplevel (); top.BorderStyle = LineStyle.None; - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var btn = $"{ @@ -396,7 +396,7 @@ ffffffffffffffffffff int iterations = -1; var top = new Toplevel(); top.BorderStyle = LineStyle.None; - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var btn = $"{ @@ -477,7 +477,7 @@ ffffffffffffffffffff int iterations = -1; var top = new Toplevel(); top.BorderStyle = LineStyle.None; - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var btn = $"{ @@ -547,7 +547,7 @@ ffffffffffffffffffff public void Size_Default () { int iterations = -1; - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); Application.Iteration += (s, a) => { @@ -650,7 +650,7 @@ ffffffffffffffffffff CM.Glyphs.RightBracket }"; - ((FakeDriver)Application.Driver).SetBufferSize (40 + 4, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (40 + 4, 8); Application.Iteration += (s, a) => { @@ -737,7 +737,7 @@ ffffffffffffffffffff public void Size_Not_Default_Message (int height, int width, string message) { int iterations = -1; - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); Application.Iteration += (s, a) => { @@ -774,7 +774,7 @@ ffffffffffffffffffff public void Size_Not_Default_Message_Button (int height, int width, string message) { int iterations = -1; - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); Application.Iteration += (s, a) => { @@ -807,7 +807,7 @@ ffffffffffffffffffff public void Size_Not_Default_No_Message (int height, int width) { int iterations = -1; - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); Application.Iteration += (s, a) => { diff --git a/UnitTests/Drawing/RulerTests.cs b/UnitTests/Drawing/RulerTests.cs index 0fdbfd7e2..d43ea327f 100644 --- a/UnitTests/Drawing/RulerTests.cs +++ b/UnitTests/Drawing/RulerTests.cs @@ -29,7 +29,7 @@ public class RulerTests [AutoInitShutdown] public void Draw_Default () { - ((FakeDriver)Application.Driver).SetBufferSize (25, 25); + ((FakeDriver)Application.Driver!).SetBufferSize (25, 25); var r = new Ruler (); r.Draw (Point.Empty); @@ -47,7 +47,7 @@ public class RulerTests var top = new Toplevel (); top.Add (f); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (len + 5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (len + 5, 5); Assert.Equal (new (0, 0, len + 5, 5), f.Frame); var r = new Ruler (); @@ -121,7 +121,7 @@ public class RulerTests var top = new Toplevel (); top.Add (f); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (len + 5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (len + 5, 5); Assert.Equal (new (0, 0, len + 5, 5), f.Frame); var r = new Ruler (); @@ -168,7 +168,7 @@ public class RulerTests var top = new Toplevel (); top.Add (f); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (5, len + 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, len + 5); Assert.Equal (new (0, 0, 5, len + 5), f.Frame); var r = new Ruler (); @@ -302,7 +302,7 @@ public class RulerTests var top = new Toplevel (); top.Add (f); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (5, len + 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, len + 5); Assert.Equal (new (0, 0, 5, len + 5), f.Frame); var r = new Ruler (); diff --git a/UnitTests/Drawing/ThicknessTests.cs b/UnitTests/Drawing/ThicknessTests.cs index 8215f8148..c71135722 100644 --- a/UnitTests/Drawing/ThicknessTests.cs +++ b/UnitTests/Drawing/ThicknessTests.cs @@ -51,13 +51,13 @@ public class ThicknessTests (ITestOutputHelper output) [AutoInitShutdown] public void DrawTests () { - ((FakeDriver)Application.Driver).SetBufferSize (60, 60); + ((FakeDriver)Application.Driver!).SetBufferSize (60, 60); var t = new Thickness (0, 0, 0, 0); var r = new Rectangle (5, 5, 40, 15); View.Diagnostics |= ViewDiagnosticFlags.Padding; - Application.Driver.FillRect ( - new Rectangle (0, 0, Application.Driver.Cols, Application.Driver.Rows), + Application.Driver?.FillRect ( + new Rectangle (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), (Rune)' ' ); t.Draw (r, "Test"); @@ -73,8 +73,8 @@ public class ThicknessTests (ITestOutputHelper output) r = new Rectangle (5, 5, 40, 15); View.Diagnostics |= ViewDiagnosticFlags.Padding; - Application.Driver.FillRect ( - new Rectangle (0, 0, Application.Driver.Cols, Application.Driver.Rows), + Application.Driver?.FillRect ( + new Rectangle (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), (Rune)' ' ); t.Draw (r, "Test"); @@ -104,8 +104,8 @@ public class ThicknessTests (ITestOutputHelper output) r = new Rectangle (5, 5, 40, 15); View.Diagnostics |= ViewDiagnosticFlags.Padding; - Application.Driver.FillRect ( - new Rectangle (0, 0, Application.Driver.Cols, Application.Driver.Rows), + Application.Driver?.FillRect ( + new Rectangle (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), (Rune)' ' ); t.Draw (r, "Test"); @@ -135,8 +135,8 @@ public class ThicknessTests (ITestOutputHelper output) r = new Rectangle (5, 5, 40, 15); View.Diagnostics |= ViewDiagnosticFlags.Padding; - Application.Driver.FillRect ( - new Rectangle (0, 0, Application.Driver.Cols, Application.Driver.Rows), + Application.Driver?.FillRect ( + new Rectangle (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), (Rune)' ' ); t.Draw (r, "Test"); @@ -174,7 +174,7 @@ public class ThicknessTests (ITestOutputHelper output) top.Add (f); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (45, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (45, 20); var t = new Thickness (0, 0, 0, 0); var r = new Rectangle (2, 2, 40, 15); Application.Refresh (); diff --git a/UnitTests/FileServices/FileDialogTests.cs b/UnitTests/FileServices/FileDialogTests.cs index 1395543ee..1488a75f0 100644 --- a/UnitTests/FileServices/FileDialogTests.cs +++ b/UnitTests/FileServices/FileDialogTests.cs @@ -701,14 +701,14 @@ public class FileDialogTests (ITestOutputHelper output) private void Send (char ch, ConsoleKey ck, bool shift = false, bool alt = false, bool control = false) { - Application.Driver.SendKeys (ch, ck, shift, alt, control); + Application.Driver?.SendKeys (ch, ck, shift, alt, control); } private void Send (string chars) { foreach (char ch in chars) { - Application.Driver.SendKeys (ch, ConsoleKey.NoName, false, false, false); + Application.Driver?.SendKeys (ch, ConsoleKey.NoName, false, false, false); } } diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index 6746f8ad7..f821d504b 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -451,7 +451,7 @@ ssb [SetupFakeDriver] public void FillRemaining_True_False () { - ((FakeDriver)Application.Driver).SetBufferSize (22, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (22, 5); Attribute [] attrs = { @@ -6041,7 +6041,7 @@ B")] Text = text }; - Application.Driver.FillRect (new Rectangle (0, 0, 7, 7), (Rune)'*'); + Application.Driver?.FillRect (new Rectangle (0, 0, 7, 7), (Rune)'*'); tf.Draw (new Rectangle (0, 0, 7, 7), Attribute.Default, Attribute.Default); TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output); } diff --git a/UnitTests/View/Adornment/BorderTests.cs b/UnitTests/View/Adornment/BorderTests.cs index 387844dbe..cae90f708 100644 --- a/UnitTests/View/Adornment/BorderTests.cs +++ b/UnitTests/View/Adornment/BorderTests.cs @@ -95,7 +95,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (width, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (width, 5); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -229,7 +229,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (width, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (width, 4); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -363,7 +363,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (width, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (width, 4); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -486,7 +486,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (20, height); + ((FakeDriver)Application.Driver!).SetBufferSize (20, height); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -548,7 +548,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (width, 3); + ((FakeDriver)Application.Driver!).SetBufferSize (width, 3); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -728,7 +728,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (top); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, 5); Application.RunIteration (ref rs, ref firstIteration); var expected = @" @@ -756,7 +756,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (top); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); Application.RunIteration (ref rs, ref firstIteration); var expected = @" @@ -779,7 +779,7 @@ public class BorderTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (3, 3); + ((FakeDriver)Application.Driver!).SetBufferSize (3, 3); Application.RunIteration (ref rs, ref firstIteration); var expected = @" diff --git a/UnitTests/View/Adornment/MarginTests.cs b/UnitTests/View/Adornment/MarginTests.cs index 1cfe6f0d1..736a720b1 100644 --- a/UnitTests/View/Adornment/MarginTests.cs +++ b/UnitTests/View/Adornment/MarginTests.cs @@ -8,7 +8,7 @@ public class MarginTests (ITestOutputHelper output) [SetupFakeDriver] public void Margin_Uses_SuperView_ColorScheme () { - ((FakeDriver)Application.Driver).SetBufferSize (5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, 5); var view = new View { Height = 3, Width = 3 }; view.Margin.Thickness = new (1); diff --git a/UnitTests/View/Adornment/PaddingTests.cs b/UnitTests/View/Adornment/PaddingTests.cs index 4f7bffb20..2c917572f 100644 --- a/UnitTests/View/Adornment/PaddingTests.cs +++ b/UnitTests/View/Adornment/PaddingTests.cs @@ -8,7 +8,7 @@ public class PaddingTests (ITestOutputHelper output) [SetupFakeDriver] public void Padding_Uses_Parent_ColorScheme () { - ((FakeDriver)Application.Driver).SetBufferSize (5, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (5, 5); var view = new View { Height = 3, Width = 3 }; view.Padding.Thickness = new (1); diff --git a/UnitTests/View/DrawTests.cs b/UnitTests/View/DrawTests.cs index 46c791ab4..52b4659f8 100644 --- a/UnitTests/View/DrawTests.cs +++ b/UnitTests/View/DrawTests.cs @@ -22,13 +22,13 @@ public class DrawTests (ITestOutputHelper _output) // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen) view.Move (0, 0); - Assert.Equal (new Point (2, 2), new Point (Application.Driver.Col, Application.Driver.Row)); + Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row)); view.Move (-1, -1); - Assert.Equal (new Point (2, 2), new Point (Application.Driver.Col, Application.Driver.Row)); + Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row)); view.Move (1, 1); - Assert.Equal (new Point (2, 2), new Point (Application.Driver.Col, Application.Driver.Row)); + Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row)); } [Fact] @@ -48,16 +48,16 @@ public class DrawTests (ITestOutputHelper _output) view.Draw (); // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen) - Assert.Equal ((Rune)' ', Application.Driver.Contents [2, 2].Rune); + Assert.Equal ((Rune)' ', Application.Driver?.Contents [2, 2].Rune); view.AddRune (0, 0, Rune.ReplacementChar); - Assert.Equal (Rune.ReplacementChar, Application.Driver.Contents [2, 2].Rune); + Assert.Equal (Rune.ReplacementChar, Application.Driver?.Contents [2, 2].Rune); view.AddRune (-1, -1, Rune.ReplacementChar); - Assert.Equal ((Rune)'M', Application.Driver.Contents [1, 1].Rune); + Assert.Equal ((Rune)'M', Application.Driver?.Contents [1, 1].Rune); view.AddRune (1, 1, Rune.ReplacementChar); - Assert.Equal ((Rune)'M', Application.Driver.Contents [3, 3].Rune); + Assert.Equal ((Rune)'M', Application.Driver?.Contents [3, 3].Rune); View.Diagnostics = ViewDiagnosticFlags.Off; } @@ -250,7 +250,7 @@ public class DrawTests (ITestOutputHelper _output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); const string expectedOutput = """ @@ -301,7 +301,7 @@ public class DrawTests (ITestOutputHelper _output) dg.Add (view); RunState rsTop = Application.Begin (top); RunState rsDiag = Application.Begin (dg); - ((FakeDriver)Application.Driver).SetBufferSize (30, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 10); const string expectedOutput = """ @@ -354,7 +354,7 @@ public class DrawTests (ITestOutputHelper _output) top.Add (viewRight, viewBottom); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (7, 7); + ((FakeDriver)Application.Driver!).SetBufferSize (7, 7); TestHelpers.AssertDriverContentsWithFrameAre ( """ @@ -394,7 +394,7 @@ public class DrawTests (ITestOutputHelper _output) var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single }; view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 2, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -419,7 +419,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1, 1, 1, 0); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 2, 1), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -437,7 +437,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (0, 1, 1, 1); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 1, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -462,7 +462,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1, 1, 0, 1); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 1, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -488,7 +488,7 @@ public class DrawTests (ITestOutputHelper _output) view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 2, 1), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -561,7 +561,7 @@ public class DrawTests (ITestOutputHelper _output) container.Add (content); Toplevel top = new (); top.Add (container); - Application.Driver.Clip = container.Frame; + Application.Driver!.Clip = container.Frame; Application.Begin (top); TestHelpers.AssertDriverContentsWithFrameAre ( @@ -727,7 +727,7 @@ public class DrawTests (ITestOutputHelper _output) return; - void Top_LayoutComplete (object? sender, LayoutEventArgs e) { Application.Driver.Clip = container.Frame; } + void Top_LayoutComplete (object? sender, LayoutEventArgs e) { Application.Driver!.Clip = container.Frame; } } [Fact] @@ -767,7 +767,7 @@ public class DrawTests (ITestOutputHelper _output) container.Add (content); Toplevel top = new (); top.Add (container); - Application.Driver.Clip = container.Frame; + Application.Driver!.Clip = container.Frame; Application.Begin (top); TestHelpers.AssertDriverContentsWithFrameAre ( @@ -889,7 +889,7 @@ public class DrawTests (ITestOutputHelper _output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); var expected = """ @@ -928,13 +928,13 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1); view.BeginInit (); view.EndInit (); - Assert.Equal (view.Frame, Application.Driver.Clip); + Assert.Equal (view.Frame, Application.Driver?.Clip); // Act view.SetClip (); // Assert - Assert.Equal (expectedClip, Application.Driver.Clip); + Assert.Equal (expectedClip, Application.Driver?.Clip); view.Dispose (); } @@ -960,14 +960,14 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1); view.BeginInit (); view.EndInit (); - Assert.Equal (view.Frame, Application.Driver.Clip); + Assert.Equal (view.Frame, Application.Driver?.Clip); view.Viewport = view.Viewport with { X = 1, Y = 1 }; // Act view.SetClip (); // Assert - Assert.Equal (expectedClip, Application.Driver.Clip); + Assert.Equal (expectedClip, Application.Driver?.Clip); view.Dispose (); } diff --git a/UnitTests/View/Layout/Dim.FillTests.cs b/UnitTests/View/Layout/Dim.FillTests.cs index c4b4ebacf..cdda3088d 100644 --- a/UnitTests/View/Layout/Dim.FillTests.cs +++ b/UnitTests/View/Layout/Dim.FillTests.cs @@ -14,7 +14,7 @@ public class DimFillTests (ITestOutputHelper output) var top = new Toplevel (); top.Add (view); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (32, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (32, 5); //view.SetNeedsLayout (); top.LayoutSubviews (); diff --git a/UnitTests/View/Layout/Pos.AnchorEndTests.cs b/UnitTests/View/Layout/Pos.AnchorEndTests.cs index 4309ee858..ddd3c62af 100644 --- a/UnitTests/View/Layout/Pos.AnchorEndTests.cs +++ b/UnitTests/View/Layout/Pos.AnchorEndTests.cs @@ -184,7 +184,7 @@ public class PosAnchorEndTests (ITestOutputHelper output) [SetupFakeDriver] public void PosAnchorEnd_View_And_Button () { - ((FakeDriver)Application.Driver).SetBufferSize (20, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 5); var b = $"{CM.Glyphs.LeftBracket} Ok {CM.Glyphs.RightBracket}"; diff --git a/UnitTests/View/Layout/Pos.CenterTests.cs b/UnitTests/View/Layout/Pos.CenterTests.cs index a17b1132a..e713c07b6 100644 --- a/UnitTests/View/Layout/Pos.CenterTests.cs +++ b/UnitTests/View/Layout/Pos.CenterTests.cs @@ -85,7 +85,7 @@ public class PosCenterTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (20, height); + ((FakeDriver)Application.Driver!).SetBufferSize (20, height); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; @@ -232,7 +232,7 @@ public class PosCenterTests (ITestOutputHelper output) RunState rs = Application.Begin (win); var firstIteration = false; - ((FakeDriver)Application.Driver).SetBufferSize (width, 7); + ((FakeDriver)Application.Driver!).SetBufferSize (width, 7); Application.RunIteration (ref rs, ref firstIteration); var expected = string.Empty; diff --git a/UnitTests/View/Layout/ViewportTests.cs b/UnitTests/View/Layout/ViewportTests.cs index f5bc9212d..f0d30f118 100644 --- a/UnitTests/View/Layout/ViewportTests.cs +++ b/UnitTests/View/Layout/ViewportTests.cs @@ -472,7 +472,7 @@ public class ViewportTests (ITestOutputHelper output) //[InlineData (5, 5, false)] //public void IsVisibleInSuperView_With_Driver (int x, int y, bool expected) //{ - // ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + // ((FakeDriver)Application.Driver!).SetBufferSize (10, 10); // var view = new View { X = 1, Y = 1, Width = 5, Height = 5 }; // var top = new Toplevel (); diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index 05dc30a1f..5a7019c19 100644 --- a/UnitTests/View/NavigationTests.cs +++ b/UnitTests/View/NavigationTests.cs @@ -669,7 +669,7 @@ public class NavigationTests (ITestOutputHelper output) // Assert.False (tfQuiting); // Assert.False (topQuiting); -// Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true); +// Application.Driver?.SendKeys ('Q', ConsoleKey.Q, false, false, true); // Assert.False (sbQuiting); // Assert.True (tfQuiting); // Assert.False (topQuiting); @@ -677,7 +677,7 @@ public class NavigationTests (ITestOutputHelper output) //#if BROKE_WITH_2927 // tf.KeyPressed -= Tf_KeyPress; // tfQuiting = false; -// Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true); +// Application.Driver?.SendKeys ('q', ConsoleKey.Q, false, false, true); // Application.MainLoop.RunIteration (); // Assert.True (sbQuiting); // Assert.False (tfQuiting); @@ -685,7 +685,7 @@ public class NavigationTests (ITestOutputHelper output) // sb.RemoveItem (0); // sbQuiting = false; -// Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true); +// Application.Driver?.SendKeys ('q', ConsoleKey.Q, false, false, true); // Application.MainLoop.RunIteration (); // Assert.False (sbQuiting); // Assert.False (tfQuiting); @@ -733,13 +733,13 @@ public class NavigationTests (ITestOutputHelper output) // Assert.False (sbQuiting); // Assert.False (tfQuiting); -// Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true); +// Application.Driver?.SendKeys ('Q', ConsoleKey.Q, false, false, true); // Assert.False (sbQuiting); // Assert.True (tfQuiting); // tf.KeyDown -= Tf_KeyPressed; // tfQuiting = false; -// Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true); +// Application.Driver?.SendKeys ('Q', ConsoleKey.Q, false, false, true); // Application.MainLoop.RunIteration (); //#if BROKE_WITH_2927 // Assert.True (sbQuiting); @@ -834,7 +834,7 @@ public class NavigationTests (ITestOutputHelper output) Assert.Equal (new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rectangle (0, 0, 80, 25), top.Frame); - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); Assert.Equal (new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rectangle (0, 0, 20, 10), top.Frame); @@ -984,7 +984,7 @@ public class NavigationTests (ITestOutputHelper output) Assert.NotEqual (new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rectangle (3, 2, 20, 10), top.Frame); - ((FakeDriver)Application.Driver).SetBufferSize (30, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 20); Assert.Equal (new Rectangle (0, 0, 30, 20), new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows)); Assert.NotEqual (new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rectangle (3, 2, 20, 10), top.Frame); diff --git a/UnitTests/View/TextTests.cs b/UnitTests/View/TextTests.cs index 3bd6cfb23..f0cb43091 100644 --- a/UnitTests/View/TextTests.cs +++ b/UnitTests/View/TextTests.cs @@ -148,7 +148,7 @@ Y top.Add (win); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (15, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (15, 15); Assert.Equal (new (0, 0, 15, 15), win.Frame); Assert.Equal (new (0, 0, 15, 15), win.Margin.Frame); @@ -416,7 +416,7 @@ Y var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (4, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (4, 10); Assert.Equal (5, text.Length); @@ -489,7 +489,7 @@ Y var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (4, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (4, 10); Assert.Equal (5, text.Length); Assert.Equal (new (0, 0, 2, 5), view.Frame); @@ -584,7 +584,7 @@ Y var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 20); Assert.Equal (new (0, 0, 11, 2), horizontalView.Frame); Assert.Equal (new (0, 3, 2, 11), verticalView.Frame); @@ -672,7 +672,7 @@ Y var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (22, 22); + ((FakeDriver)Application.Driver!).SetBufferSize (22, 22); Assert.Equal (new (text.GetColumns (), 1), horizontalView.TextFormatter.Size); Assert.Equal (new (2, 8), verticalView.TextFormatter.Size); @@ -769,7 +769,7 @@ Y for (var i = 0; i < 4; i++) { - text += Application.Driver.Contents [0, i].Rune; + text += Application.Driver?.Contents [0, i].Rune; } return text; @@ -804,7 +804,7 @@ Y var top = new Toplevel (); top.Add (horizontalView, verticalView); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (50, 50); + ((FakeDriver)Application.Driver!).SetBufferSize (50, 50); Assert.Equal (new (0, 0, 12, 1), horizontalView.Frame); Assert.Equal (new (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ()); @@ -900,7 +900,7 @@ Y var top = new Toplevel (); top.Add (frame); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (width + 2, 6); + ((FakeDriver)Application.Driver!).SetBufferSize (width + 2, 6); if (autoSize) { @@ -1028,7 +1028,7 @@ Y var top = new Toplevel (); top.Add (frame); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (9, height + 2); + ((FakeDriver)Application.Driver!).SetBufferSize (9, height + 2); if (autoSize) { @@ -1272,7 +1272,7 @@ Y [SetupFakeDriver] public void Narrow_Wide_Runes () { - ((FakeDriver)Application.Driver).SetBufferSize (32, 32); + ((FakeDriver)Application.Driver!).SetBufferSize (32, 32); var top = new View { Width = 32, Height = 32 }; var text = $"First line{Environment.NewLine}Second line"; diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs index 4044507f1..d545cdc1d 100644 --- a/UnitTests/View/ViewTests.cs +++ b/UnitTests/View/ViewTests.cs @@ -14,26 +14,26 @@ public class ViewTests (ITestOutputHelper output) view.DrawContent += (s, e) => { - Rectangle savedClip = Application.Driver.Clip; - Application.Driver.Clip = new (1, 1, view.Viewport.Width, view.Viewport.Height); + Rectangle savedClip = Application.Driver!.Clip; + Application.Driver!.Clip = new (1, 1, view.Viewport.Width, view.Viewport.Height); for (var row = 0; row < view.Viewport.Height; row++) { - Application.Driver.Move (1, row + 1); + Application.Driver?.Move (1, row + 1); for (var col = 0; col < view.Viewport.Width; col++) { - Application.Driver.AddStr ($"{col}"); + Application.Driver?.AddStr ($"{col}"); } } - Application.Driver.Clip = savedClip; + Application.Driver!.Clip = savedClip; e.Cancel = true; }; var top = new Toplevel (); top.Add (view); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var expected = @" ┌──────────────────┐ @@ -78,26 +78,26 @@ public class ViewTests (ITestOutputHelper output) view.DrawContent += (s, e) => { - Rectangle savedClip = Application.Driver.Clip; - Application.Driver.Clip = new (1, 1, view.Viewport.Width, view.Viewport.Height); + Rectangle savedClip = Application.Driver!.Clip; + Application.Driver!.Clip = new (1, 1, view.Viewport.Width, view.Viewport.Height); for (var row = 0; row < view.Viewport.Height; row++) { - Application.Driver.Move (1, row + 1); + Application.Driver?.Move (1, row + 1); for (var col = 0; col < view.Viewport.Width; col++) { - Application.Driver.AddStr ($"{col}"); + Application.Driver?.AddStr ($"{col}"); } } - Application.Driver.Clip = savedClip; + Application.Driver!.Clip = savedClip; e.Cancel = true; }; var top = new Toplevel (); top.Add (view); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); var expected = @" ┌──────────────────┐ @@ -1016,7 +1016,7 @@ At 0,0 view.Height = Dim.Auto (); Assert.Equal ("Testing visibility.".Length, view.Frame.Width); Assert.True (view.Visible); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); TestHelpers.AssertDriverContentsWithFrameAre ( @" @@ -1107,9 +1107,9 @@ At 0,0 Cell [,] contents = ((FakeDriver)Application.Driver).Contents; var runesCount = 0; - for (var i = 0; i < Application.Driver.Rows; i++) + for (var i = 0; i < Application.Driver!.Rows; i++) { - for (var j = 0; j < Application.Driver.Cols; j++) + for (var j = 0; j < Application.Driver!.Cols; j++) { if (contents [i, j].Rune != (Rune)' ') { diff --git a/UnitTests/Views/AppendAutocompleteTests.cs b/UnitTests/Views/AppendAutocompleteTests.cs index fab9ca750..eaabc43a6 100644 --- a/UnitTests/Views/AppendAutocompleteTests.cs +++ b/UnitTests/Views/AppendAutocompleteTests.cs @@ -11,14 +11,14 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting ("fish"); // f is typed and suggestion is "fish" - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); // When cancelling autocomplete - Application.Driver.SendKeys ('e', ConsoleKey.Escape, false, false, false); + Application.Driver?.SendKeys ('e', ConsoleKey.Escape, false, false, false); // Suggestion should disappear tf.Draw (); @@ -29,7 +29,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) Assert.Same (tf, Application.Top.Focused); // But can tab away - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); Assert.NotSame (tf, Application.Top.Focused); Application.Top.Dispose (); } @@ -41,14 +41,14 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting ("fish"); // f is typed and suggestion is "fish" - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); // When cancelling autocomplete - Application.Driver.SendKeys ('\0', ConsoleKey.Escape, false, false, false); + Application.Driver?.SendKeys ('\0', ConsoleKey.Escape, false, false, false); // Suggestion should disappear tf.Draw (); @@ -56,7 +56,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) Assert.Equal ("f", tf.Text); // Should reappear when you press next letter - Application.Driver.SendKeys ('i', ConsoleKey.I, false, false, false); + Application.Driver?.SendKeys ('i', ConsoleKey.I, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); @@ -73,14 +73,14 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting ("fish", "friend"); // f is typed and suggestion is "fish" - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); // When cycling autocomplete - Application.Driver.SendKeys (' ', cycleKey, false, false, false); + Application.Driver?.SendKeys (' ', cycleKey, false, false, false); tf.Draw (); tf.PositionCursor (); @@ -88,7 +88,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) Assert.Equal ("f", tf.Text); // Should be able to cycle in circles endlessly - Application.Driver.SendKeys (' ', cycleKey, false, false, false); + Application.Driver?.SendKeys (' ', cycleKey, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); @@ -103,15 +103,15 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting ("fish"); // f is typed and suggestion is "fish" - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); // add a space then go back 1 - Application.Driver.SendKeys (' ', ConsoleKey.Spacebar, false, false, false); - Application.Driver.SendKeys ('<', ConsoleKey.LeftArrow, false, false, false); + Application.Driver?.SendKeys (' ', ConsoleKey.Spacebar, false, false, false); + Application.Driver?.SendKeys ('<', ConsoleKey.LeftArrow, false, false, false); tf.Draw (); TestHelpers.AssertDriverContentsAre ("f", output); @@ -126,14 +126,14 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting ("fish"); // f is typed and suggestion is "fish" - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); // x is typed and suggestion should disappear - Application.Driver.SendKeys ('x', ConsoleKey.X, false, false, false); + Application.Driver?.SendKeys ('x', ConsoleKey.X, false, false, false); tf.Draw (); TestHelpers.AssertDriverContentsAre ("fx", output); Assert.Equal ("fx", tf.Text); @@ -166,7 +166,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) Assert.Equal ("my f", tf.Text); // When tab completing the case of the whole suggestion should be applied - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); tf.Draw (); TestHelpers.AssertDriverContentsAre ("my FISH", output); Assert.Equal ("my FISH", tf.Text); @@ -194,7 +194,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TestHelpers.AssertDriverContentsAre ("fish", output); Assert.Equal ("f", tf.Text); - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); tf.Draw (); TestHelpers.AssertDriverContentsAre ("fish", output); @@ -204,7 +204,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) Assert.Same (tf, Application.Top.Focused); // Second tab should move focus (nothing to autocomplete) - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); Assert.NotSame (tf, Application.Top.Focused); Application.Top.Dispose (); } @@ -219,7 +219,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output) TextField tf = GetTextFieldsInViewSuggesting (overspillUsing); // f is typed we should only see 'f' up to size of View (10) - Application.Driver.SendKeys ('f', ConsoleKey.F, false, false, false); + Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false); tf.Draw (); tf.PositionCursor (); TestHelpers.AssertDriverContentsAre (expectRender, output); diff --git a/UnitTests/Views/ButtonTests.cs b/UnitTests/Views/ButtonTests.cs index 4ef86d387..d5bc04e07 100644 --- a/UnitTests/Views/ButtonTests.cs +++ b/UnitTests/Views/ButtonTests.cs @@ -224,7 +224,7 @@ public class ButtonTests (ITestOutputHelper output) Assert.Equal ('_', btn.HotKeySpecifier.Value); Assert.True (btn.CanFocus); - Application.Driver.ClearContents (); + Application.Driver?.ClearContents (); btn.Draw (); expected = @$" @@ -563,7 +563,7 @@ public class ButtonTests (ITestOutputHelper output) Assert.False (btn.IsInitialized); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.True (btn.IsInitialized); Assert.Equal ("Say Hello 你", btn.Text); @@ -597,7 +597,7 @@ public class ButtonTests (ITestOutputHelper output) Assert.False (btn.IsInitialized); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.True (btn.IsInitialized); Assert.Equal ("Say Hello 你", btn.Text); diff --git a/UnitTests/Views/CheckBoxTests.cs b/UnitTests/Views/CheckBoxTests.cs index c7739272d..da41ec55a 100644 --- a/UnitTests/Views/CheckBoxTests.cs +++ b/UnitTests/Views/CheckBoxTests.cs @@ -254,7 +254,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.Equal (Alignment.Center, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); @@ -314,7 +314,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 6); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 6); Assert.Equal (Alignment.Fill, checkBox1.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox1.Frame); @@ -372,7 +372,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.Equal (Alignment.Start, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); @@ -423,7 +423,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.Equal (Alignment.End, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index 6d42add38..efeb709fb 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -117,9 +117,9 @@ public class ContextMenuTests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_A_ContextMenu_Over_A_Borderless_Top () { - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); - Assert.Equal (new Rectangle (0, 0, 20, 15), Application.Driver.Clip); + Assert.Equal (new Rectangle (0, 0, 20, 15), Application.Driver?.Clip); TestHelpers.AssertDriverContentsWithFrameAre ("", output); var top = new Toplevel { X = 2, Y = 2, Width = 15, Height = 4 }; @@ -167,7 +167,7 @@ public class ContextMenuTests (ITestOutputHelper output) var win = new Window (); top.Add (win); RunState rsTop = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); Assert.Equal (new Rectangle (0, 0, 20, 15), win.Frame); @@ -252,9 +252,9 @@ public class ContextMenuTests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_A_ContextMenu_Over_A_Top_Dialog () { - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); - Assert.Equal (new Rectangle (0, 0, 20, 15), Application.Driver.Clip); + Assert.Equal (new Rectangle (0, 0, 20, 15), Application.Driver?.Clip); TestHelpers.AssertDriverContentsWithFrameAre ("", output); // Don't use Dialog here as it has more layout logic. Use Window instead. @@ -542,7 +542,7 @@ public class ContextMenuTests (ITestOutputHelper output) output ); - ((FakeDriver)Application.Driver).SetBufferSize (40, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 20); cm.Position = new Point (41, -2); cm.Show (); Application.Refresh (); @@ -677,7 +677,7 @@ public class ContextMenuTests (ITestOutputHelper output) output ); - ((FakeDriver)Application.Driver).SetBufferSize (18, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (18, 8); cm.Position = new Point (19, 10); cm.Show (); Application.Refresh (); @@ -891,7 +891,7 @@ public class ContextMenuTests (ITestOutputHelper output) [AutoInitShutdown] public void Show_Display_At_Zero_If_The_Toplevel_Height_Is_Less_Than_The_Menu_Height () { - ((FakeDriver)Application.Driver).SetBufferSize (80, 3); + ((FakeDriver)Application.Driver!).SetBufferSize (80, 3); var cm = new ContextMenu { @@ -929,7 +929,7 @@ public class ContextMenuTests (ITestOutputHelper output) [AutoInitShutdown] public void Show_Display_At_Zero_If_The_Toplevel_Width_Is_Less_Than_The_Menu_Width () { - ((FakeDriver)Application.Driver).SetBufferSize (5, 25); + ((FakeDriver)Application.Driver!).SetBufferSize (5, 25); var cm = new ContextMenu { diff --git a/UnitTests/Views/FrameViewTests.cs b/UnitTests/Views/FrameViewTests.cs index 056b45747..88a5c786c 100644 --- a/UnitTests/Views/FrameViewTests.cs +++ b/UnitTests/Views/FrameViewTests.cs @@ -37,7 +37,7 @@ public class FrameViewTests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_Defaults () { - ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 10); var fv = new FrameView (); Assert.Equal (string.Empty, fv.Title); Assert.Equal (string.Empty, fv.Text); diff --git a/UnitTests/Views/LabelTests.cs b/UnitTests/Views/LabelTests.cs index 24a19c77d..78ed678a8 100644 --- a/UnitTests/Views/LabelTests.cs +++ b/UnitTests/Views/LabelTests.cs @@ -97,7 +97,7 @@ public class LabelTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); var expected = @" ┌────────────────────────────┐ @@ -137,7 +137,7 @@ public class LabelTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); var expected = @" ┌────────────────────────────┐ @@ -179,7 +179,7 @@ public class LabelTests (ITestOutputHelper output) label.Text = "Say Hello 你"; Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); var expected = @" ┌────────────────────────────┐ @@ -414,7 +414,7 @@ e Assert.False (label.IsInitialized); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.True (label.IsInitialized); Assert.Equal ("Say Hello 你", label.Text); @@ -446,7 +446,7 @@ e Assert.False (label.IsInitialized); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.True (label.IsInitialized); Assert.Equal ("Say Hello 你", label.Text); @@ -473,7 +473,7 @@ e var label = new Label { BorderStyle = LineStyle.Single, Text = "Test" }; label.BeginInit (); label.EndInit (); - label.SetRelativeLayout (Application.Driver.Screen.Size); + label.SetRelativeLayout (Application.Driver!.Screen.Size); Assert.Equal (new (0, 0, 4, 1), label.Viewport); Assert.Equal (new (0, 0, 6, 3), label.Frame); @@ -881,7 +881,7 @@ e Toplevel top = new (); top.Add (win); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (40, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 10); Assert.Equal (29, label.Text.Length); Assert.Equal (new (0, 0, 40, 10), top.Frame); @@ -931,7 +931,7 @@ e Toplevel top = new (); top.Add (win); RunState rs = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (40, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 10); Assert.Equal (new (0, 0, 40, 10), top.Frame); Assert.Equal (new (0, 0, 40, 10), win.Frame); @@ -1071,7 +1071,7 @@ e { if (k.KeyCode == KeyCode.Enter) { - ((FakeDriver)Application.Driver).SetBufferSize (22, count + 4); + ((FakeDriver)Application.Driver!).SetBufferSize (22, count + 4); Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], output); Assert.Equal (new (0, 0, 22, count + 4), pos); @@ -1135,7 +1135,7 @@ e [SetupFakeDriver] public void Label_Height_Zero_Stays_Zero () { - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); var text = "Label"; var label = new Label @@ -1223,7 +1223,7 @@ e { if (k.KeyCode == KeyCode.Enter) { - ((FakeDriver)Application.Driver).SetBufferSize (22, count + 4); + ((FakeDriver)Application.Driver!).SetBufferSize (22, count + 4); Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], output); Assert.Equal (new (0, 0, 22, count + 4), pos); @@ -1299,7 +1299,7 @@ e var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); Assert.Equal (5, text.Length); Assert.Equal (new (0, 0, 5, 1), label.Frame); @@ -1358,7 +1358,7 @@ e var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (10, 4); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 4); Assert.Equal (5, text.Length); Assert.Equal (new (0, 0, 5, 1), label.Frame); diff --git a/UnitTests/Views/ListViewTests.cs b/UnitTests/Views/ListViewTests.cs index 2682fb677..049c5f7e1 100644 --- a/UnitTests/Views/ListViewTests.cs +++ b/UnitTests/Views/ListViewTests.cs @@ -55,7 +55,7 @@ public class ListViewTests (ITestOutputHelper output) var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (12, 12); + ((FakeDriver)Application.Driver!).SetBufferSize (12, 12); Application.Refresh (); Assert.Equal (-1, lv.SelectedItem); @@ -357,7 +357,7 @@ Item 6", for (var i = 0; i < 7; i++) { - item += Application.Driver.Contents [line, i].Rune; + item += Application.Driver?.Contents [line, i].Rune; } return item; diff --git a/UnitTests/Views/MenuBarTests.cs b/UnitTests/Views/MenuBarTests.cs index f7804dd42..35d08beff 100644 --- a/UnitTests/Views/MenuBarTests.cs +++ b/UnitTests/Views/MenuBarTests.cs @@ -366,7 +366,7 @@ public class MenuBarTests (ITestOutputHelper output) var win = new Window (); top.Add (win); RunState rsTop = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (40, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 15); Assert.Equal (new (0, 0, 40, 15), win.Frame); @@ -556,7 +556,7 @@ public class MenuBarTests (ITestOutputHelper output) Assert.Equal (items [i], menu.Menus [0].Title); } - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); menu.OpenMenu (); firstIteration = false; Application.RunIteration (ref rsDialog, ref firstIteration); @@ -590,9 +590,9 @@ public class MenuBarTests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_A_Menu_Over_A_Top_Dialog () { - ((FakeDriver)Application.Driver).SetBufferSize (40, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 15); - Assert.Equal (new (0, 0, 40, 15), Application.Driver.Clip); + Assert.Equal (new (0, 0, 40, 15), Application.Driver?.Clip); TestHelpers.AssertDriverContentsWithFrameAre (@"", output); List items = new () @@ -734,7 +734,7 @@ public class MenuBarTests (ITestOutputHelper output) Assert.Equal (items [i], menu.Menus [0].Title); } - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); menu.OpenMenu (); firstIteration = false; Application.RunIteration (ref rs, ref firstIteration); @@ -805,7 +805,7 @@ public class MenuBarTests (ITestOutputHelper output) menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - ((FakeDriver)Application.Driver).SetBufferSize (7, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (7, 5); menu.OpenMenu (); Application.Refresh (); @@ -821,7 +821,7 @@ public class MenuBarTests (ITestOutputHelper output) menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - ((FakeDriver)Application.Driver).SetBufferSize (7, 3); + ((FakeDriver)Application.Driver!).SetBufferSize (7, 3); menu.OpenMenu (); Application.Refresh (); @@ -878,7 +878,7 @@ wo menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - ((FakeDriver)Application.Driver).SetBufferSize (3, 2); + ((FakeDriver)Application.Driver!).SetBufferSize (3, 2); menu.OpenMenu (); Application.Refresh (); @@ -891,7 +891,7 @@ wo menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - ((FakeDriver)Application.Driver).SetBufferSize (3, 1); + ((FakeDriver)Application.Driver!).SetBufferSize (3, 1); menu.OpenMenu (); Application.Refresh (); @@ -1519,7 +1519,7 @@ wo Toplevel top = new (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 8); TestHelpers.AssertDriverContentsWithFrameAre ( @" @@ -1630,7 +1630,7 @@ wo Application.Iteration += (s, a) => { - ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 8); TestHelpers.AssertDriverContentsWithFrameAre ( @" @@ -1741,7 +1741,7 @@ wo ] }; win.Add (menu); - ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 8); Application.Begin (win); TestHelpers.AssertDriverContentsWithFrameAre ( @@ -1827,7 +1827,7 @@ wo [AutoInitShutdown] public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () { - ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 8); Application.Iteration += (s, a) => { @@ -2758,7 +2758,7 @@ Edit output ); - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 15); firstIteration = false; Application.RunIteration (ref rs, ref firstIteration); diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs index 9c7202d68..5ca0fc566 100644 --- a/UnitTests/Views/OverlappedTests.cs +++ b/UnitTests/Views/OverlappedTests.cs @@ -881,7 +881,7 @@ public class OverlappedTests var overlapped = new Overlapped (); var win1 = new Window { Width = 5, Height = 5, Visible = false }; var win2 = new Window { X = 1, Y = 1, Width = 5, Height = 5 }; - ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 10); RunState rsOverlapped = Application.Begin (overlapped); // Need to fool MainLoop into thinking it's running diff --git a/UnitTests/Views/RadioGroupTests.cs b/UnitTests/Views/RadioGroupTests.cs index 75aab7b18..4c828f2c1 100644 --- a/UnitTests/Views/RadioGroupTests.cs +++ b/UnitTests/Views/RadioGroupTests.cs @@ -219,7 +219,7 @@ public class RadioGroupTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 5); Assert.Equal (Orientation.Vertical, rg.Orientation); Assert.Equal (2, rg.RadioLabels.Length); diff --git a/UnitTests/Views/ScrollBarViewTests.cs b/UnitTests/Views/ScrollBarViewTests.cs index f3f9f7c24..15c463d78 100644 --- a/UnitTests/Views/ScrollBarViewTests.cs +++ b/UnitTests/Views/ScrollBarViewTests.cs @@ -173,7 +173,7 @@ public class ScrollBarViewTests super.Add (vert); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (width, height); + ((FakeDriver)Application.Driver!).SetBufferSize (width, height); var expected = @" ┌─┐ @@ -703,7 +703,7 @@ This is a test var sbv = new ScrollBarView { Id = "sbv", Size = width * 2, ShowScrollIndicator = true }; super.Add (sbv); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (width, height); + ((FakeDriver)Application.Driver!).SetBufferSize (width, height); var expected = @" ┌──────────────────────────────────────┐ @@ -829,7 +829,7 @@ This is a test top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (45, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (45, 20); Assert.True (scrollBar.AutoHideScrollBars); Assert.False (scrollBar.ShowScrollIndicator); @@ -867,7 +867,7 @@ This is a test Assert.Equal (new Rectangle (0, 0, 45, 20), pos); textView.WordWrap = true; - ((FakeDriver)Application.Driver).SetBufferSize (26, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (26, 20); Application.Refresh (); Assert.True (textView.WordWrap); @@ -904,7 +904,7 @@ This is a test pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output); Assert.Equal (new Rectangle (0, 0, 26, 20), pos); - ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (10, 10); Application.Refresh (); Assert.True (textView.WordWrap); @@ -1229,7 +1229,7 @@ This is a test ", super.Add (sbv); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (width, height); + ((FakeDriver)Application.Driver!).SetBufferSize (width, height); var expected = @" ┌─┐ diff --git a/UnitTests/Views/ScrollViewTests.cs b/UnitTests/Views/ScrollViewTests.cs index ceab4e63a..c4d14c235 100644 --- a/UnitTests/Views/ScrollViewTests.cs +++ b/UnitTests/Views/ScrollViewTests.cs @@ -362,7 +362,7 @@ public class ScrollViewTests (ITestOutputHelper output) [SetupFakeDriver] public void ContentBottomRightCorner_Draw () { - ((FakeDriver)Application.Driver).SetBufferSize (30, 30); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 30); var top = new View { Width = 30, Height = 30, ColorScheme = new() { Normal = Attribute.Default } }; diff --git a/UnitTests/Views/TableViewTests.cs b/UnitTests/Views/TableViewTests.cs index 515e3f8bd..6740120f6 100644 --- a/UnitTests/Views/TableViewTests.cs +++ b/UnitTests/Views/TableViewTests.cs @@ -2196,7 +2196,7 @@ public class TableViewTests (ITestOutputHelper output) [SetupFakeDriver] public void TestEnumerableDataSource_BasicTypes () { - ((FakeDriver)Application.Driver).SetBufferSize(100,100); + ((FakeDriver)Application.Driver!).SetBufferSize(100,100); var tv = new TableView (); tv.ColorScheme = Colors.ColorSchemes ["TopLevel"]; tv.Viewport = new (0, 0, 50, 6); diff --git a/UnitTests/Views/TextFieldTests.cs b/UnitTests/Views/TextFieldTests.cs index e50617933..ed3a35775 100644 --- a/UnitTests/Views/TextFieldTests.cs +++ b/UnitTests/Views/TextFieldTests.cs @@ -67,7 +67,7 @@ public class TextFieldTests (ITestOutputHelper output) for (var i = 0; i < 16; i++) { - item += Application.Driver.Contents [0, i].Rune; + item += Application.Driver?.Contents [0, i].Rune; } return item; @@ -164,7 +164,7 @@ public class TextFieldTests (ITestOutputHelper output) // Caption has no effect when focused tf.Caption = caption; - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); Assert.False (tf.HasFocus); tf.Draw (); @@ -184,7 +184,7 @@ public class TextFieldTests (ITestOutputHelper output) TextField tf = GetTextFieldsInView (); tf.Caption = caption; - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); Assert.False (tf.HasFocus); tf.Draw (); @@ -205,7 +205,7 @@ public class TextFieldTests (ITestOutputHelper output) TestHelpers.AssertDriverContentsAre ("", output); tf.Caption = "Enter txt"; - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); // Caption should appear when not focused and no text Assert.False (tf.HasFocus); @@ -234,7 +234,7 @@ public class TextFieldTests (ITestOutputHelper output) tf.Draw (); TestHelpers.AssertDriverContentsAre ("", output); - Application.Driver.SendKeys ('\t', ConsoleKey.Tab, false, false, false); + Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false); Assert.False (tf.HasFocus); tf.Draw (); @@ -347,7 +347,7 @@ public class TextFieldTests (ITestOutputHelper output) Assert.Equal ( "TextField with some more test text. Unicode shouldn't 𝔹Aℝ𝔽!", - Application.Driver.Clipboard.GetClipboardData () + Application.Driver?.Clipboard.GetClipboardData () ); Assert.Equal (string.Empty, _textField.Text); _textField.Paste (); @@ -374,7 +374,7 @@ public class TextFieldTests (ITestOutputHelper output) Assert.Equal (32, _textField.CursorPosition); _textField.SelectAll (); _textField.Cut (); - Assert.Equal ("TAB to jump between text fields.", Application.Driver.Clipboard.GetClipboardData ()); + Assert.Equal ("TAB to jump between text fields.", Application.Driver?.Clipboard.GetClipboardData ()); Assert.Equal (string.Empty, _textField.Text); Assert.Equal (0, _textField.CursorPosition); _textField.Paste (); diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs index f260dd162..f9ff520dd 100644 --- a/UnitTests/Views/TextViewTests.cs +++ b/UnitTests/Views/TextViewTests.cs @@ -609,7 +609,7 @@ public class TextViewTests Assert.Equal ( "TextView with some more test text. Unicode shouldn't 𝔹Aℝ𝔽!", - Application.Driver.Clipboard.GetClipboardData () + Application.Driver?.Clipboard.GetClipboardData () ); Assert.Equal (string.Empty, _textView.Text); _textView.Paste (); @@ -1018,7 +1018,7 @@ This is the second line. tv.NewMouseEvent (new MouseEvent { Flags = MouseFlags.WheeledRight }); Assert.Equal (Math.Min (i + 1, 11), tv.LeftColumn); Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out CursorVisibility cursorVisibility); + Application.Driver!.GetCursorVisibility (out CursorVisibility cursorVisibility); Assert.Equal (CursorVisibility.Invisible, cursorVisibility); } @@ -1028,7 +1028,7 @@ This is the second line. Assert.Equal (i - 1, tv.LeftColumn); Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out CursorVisibility cursorVisibility); + Application.Driver!.GetCursorVisibility (out CursorVisibility cursorVisibility); if (i - 1 == 0) { @@ -1070,7 +1070,7 @@ This is the second line. tv.NewMouseEvent (new MouseEvent { Flags = MouseFlags.WheeledDown }); Application.PositionCursor (top); Assert.Equal (i + 1, tv.TopRow); - Application.Driver.GetCursorVisibility (out CursorVisibility cursorVisibility); + Application.Driver!.GetCursorVisibility (out CursorVisibility cursorVisibility); Assert.Equal (CursorVisibility.Invisible, cursorVisibility); } @@ -1081,7 +1081,7 @@ This is the second line. Assert.Equal (i - 1, tv.TopRow); Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out CursorVisibility cursorVisibility); + Application.Driver!.GetCursorVisibility (out CursorVisibility cursorVisibility); if (i - 1 == 0) { @@ -6697,7 +6697,7 @@ TAB to jump between text field", var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (15, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (15, 15); Application.Refresh (); //this passes @@ -6774,7 +6774,7 @@ TAB to jump between text field", var top = new Toplevel (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (15, 15); + ((FakeDriver)Application.Driver!).SetBufferSize (15, 15); Application.Refresh (); //this passes @@ -6899,8 +6899,8 @@ This is the second line. _output ); - ((FakeDriver)Application.Driver).SetBufferSize (6, 25); - tv.SetRelativeLayout (Application.Driver.Screen.Size); + ((FakeDriver)Application.Driver!).SetBufferSize (6, 25); + tv.SetRelativeLayout (Application.Driver!.Screen.Size); tv.Draw (); Assert.Equal (new Point (4, 2), tv.CursorPosition); Assert.Equal (new Point (12, 0), cp); diff --git a/UnitTests/Views/ToplevelTests.cs b/UnitTests/Views/ToplevelTests.cs index abbfdeb59..c19c72bb1 100644 --- a/UnitTests/Views/ToplevelTests.cs +++ b/UnitTests/Views/ToplevelTests.cs @@ -44,8 +44,8 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal ("Top1", Application.Top.Text); Assert.Equal (0, Application.Top.Frame.X); Assert.Equal (0, Application.Top.Frame.Y); - Assert.Equal (Application.Driver.Cols, Application.Top.Frame.Width); - Assert.Equal (Application.Driver.Rows, Application.Top.Frame.Height); + Assert.Equal (Application.Driver!.Cols, Application.Top.Frame.Width); + Assert.Equal (Application.Driver!.Rows, Application.Top.Frame.Height); Application.OnKeyPressed (new (Key.CtrlMask | Key.R)); @@ -54,8 +54,8 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal ("Top2", Application.Top.Text); Assert.Equal (0, Application.Top.Frame.X); Assert.Equal (0, Application.Top.Frame.Y); - Assert.Equal (Application.Driver.Cols, Application.Top.Frame.Width); - Assert.Equal (Application.Driver.Rows, Application.Top.Frame.Height); + Assert.Equal (Application.Driver!.Cols, Application.Top.Frame.Width); + Assert.Equal (Application.Driver!.Rows, Application.Top.Frame.Height); Application.OnKeyPressed (new (Key.CtrlMask | Key.C)); @@ -64,8 +64,8 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal ("Top1", Application.Top.Text); Assert.Equal (0, Application.Top.Frame.X); Assert.Equal (0, Application.Top.Frame.Y); - Assert.Equal (Application.Driver.Cols, Application.Top.Frame.Width); - Assert.Equal (Application.Driver.Rows, Application.Top.Frame.Height); + Assert.Equal (Application.Driver!.Cols, Application.Top.Frame.Width); + Assert.Equal (Application.Driver!.Rows, Application.Top.Frame.Height); Application.OnKeyPressed (new (Key.CtrlMask | Key.R)); @@ -74,8 +74,8 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal ("Top2", Application.Top.Text); Assert.Equal (0, Application.Top.Frame.X); Assert.Equal (0, Application.Top.Frame.Y); - Assert.Equal (Application.Driver.Cols, Application.Top.Frame.Width); - Assert.Equal (Application.Driver.Rows, Application.Top.Frame.Height); + Assert.Equal (Application.Driver!.Cols, Application.Top.Frame.Width); + Assert.Equal (Application.Driver!.Rows, Application.Top.Frame.Height); Application.OnKeyPressed (new (Key.CtrlMask | Key.C)); @@ -84,8 +84,8 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal ("Top1", Application.Top.Text); Assert.Equal (0, Application.Top.Frame.X); Assert.Equal (0, Application.Top.Frame.Y); - Assert.Equal (Application.Driver.Cols, Application.Top.Frame.Width); - Assert.Equal (Application.Driver.Rows, Application.Top.Frame.Height); + Assert.Equal (Application.Driver!.Cols, Application.Top.Frame.Width); + Assert.Equal (Application.Driver!.Rows, Application.Top.Frame.Height); Application.OnKeyPressed (new (Key.CtrlMask | Key.Q)); @@ -675,7 +675,7 @@ public partial class ToplevelTests (ITestOutputHelper output) if (iterations == 0) { - ((FakeDriver)Application.Driver).SetBufferSize (15, 7); + ((FakeDriver)Application.Driver!).SetBufferSize (15, 7); // Don't use MessageBox here; it's too complicated for this unit test; just use Window testWindow = new () @@ -794,7 +794,7 @@ public partial class ToplevelTests (ITestOutputHelper output) if (iterations == 0) { - ((FakeDriver)Application.Driver).SetBufferSize (30, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (30, 10); } else if (iterations == 1) { @@ -896,10 +896,10 @@ public partial class ToplevelTests (ITestOutputHelper output) top.BeginInit (); top.EndInit (); - Exception exception = Record.Exception (() => ((FakeDriver)Application.Driver).SetBufferSize (0, 10)); + Exception exception = Record.Exception (() => ((FakeDriver)Application.Driver!).SetBufferSize (0, 10)); Assert.Null (exception); - exception = Record.Exception (() => ((FakeDriver)Application.Driver).SetBufferSize (10, 0)); + exception = Record.Exception (() => ((FakeDriver)Application.Driver!).SetBufferSize (10, 0)); Assert.Null (exception); } @@ -1085,13 +1085,13 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.True (tf.HasFocus); Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out CursorVisibility cursor); + Application.Driver!.GetCursorVisibility (out CursorVisibility cursor); Assert.Equal (CursorVisibility.Default, cursor); view.Enabled = false; Assert.False (tf.HasFocus); Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out cursor); + Application.Driver!.GetCursorVisibility (out cursor); Assert.Equal (CursorVisibility.Invisible, cursor); top.Dispose (); } @@ -1209,7 +1209,7 @@ public partial class ToplevelTests (ITestOutputHelper output) Toplevel top = new (); var window = new Window { Width = 20, Height = 3, Arrangement = ViewArrangement.Movable }; RunState rsTop = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (40, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 10); RunState rsWindow = Application.Begin (window); Application.Refresh (); Assert.Equal (new (0, 0, 40, 10), top.Frame); @@ -1232,7 +1232,7 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal (new (0, 0, 20, 3), window.Frame); // Changes Top size to same size as Dialog more menu and scroll bar - ((FakeDriver)Application.Driver).SetBufferSize (20, 3); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 3); Application.OnMouseEvent ( new () @@ -1245,7 +1245,7 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Equal (new (0, 0, 20, 3), window.Frame); // Changes Top size smaller than Dialog size - ((FakeDriver)Application.Driver).SetBufferSize (19, 2); + ((FakeDriver)Application.Driver!).SetBufferSize (19, 2); Application.OnMouseEvent ( new () @@ -1338,7 +1338,7 @@ public partial class ToplevelTests (ITestOutputHelper output) { Toplevel top = new (); RunState rsTop = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 20); var testWindow = new Window { X = 2, Y = 1, Width = 15, Height = 10 }; Assert.Equal (new (2, 1, 15, 10), testWindow.Frame); @@ -1360,7 +1360,7 @@ public partial class ToplevelTests (ITestOutputHelper output) var win = new Window (); top.Add (win); RunState rsTop = Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 20); Assert.Equal (new (0, 0, 20, 20), win.Frame); @@ -1389,8 +1389,8 @@ public partial class ToplevelTests (ITestOutputHelper output) { Assert.Equal (new (1, 3, 18, 16), viewAddedToTop.Frame); - Rectangle savedClip = Application.Driver.Clip; - Application.Driver.Clip = top.Frame; + Rectangle savedClip = Application.Driver!.Clip; + Application.Driver!.Clip = top.Frame; viewAddedToTop.Draw (); top.Move (2, 15); View.Driver.AddStr ("One"); @@ -1398,7 +1398,7 @@ public partial class ToplevelTests (ITestOutputHelper output) View.Driver.AddStr ("Two"); top.Move (2, 17); View.Driver.AddStr ("Three"); - Application.Driver.Clip = savedClip; + Application.Driver!.Clip = savedClip; Application.Current.DrawContentComplete -= OnDrawContentComplete; } diff --git a/UnitTests/Views/TreeTableSourceTests.cs b/UnitTests/Views/TreeTableSourceTests.cs index 0b54be84d..39e18327b 100644 --- a/UnitTests/Views/TreeTableSourceTests.cs +++ b/UnitTests/Views/TreeTableSourceTests.cs @@ -29,7 +29,7 @@ public class TreeTableSourceTests : IDisposable [SetupFakeDriver] public void TestTreeTableSource_BasicExpanding_WithKeyboard () { - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); TableView tv = GetTreeTable (out _); tv.Style.GetOrCreateColumnStyle (1).MinAcceptableWidth = 1; @@ -88,7 +88,7 @@ public class TreeTableSourceTests : IDisposable [SetupFakeDriver] public void TestTreeTableSource_BasicExpanding_WithMouse () { - ((FakeDriver)Application.Driver).SetBufferSize (100, 100); + ((FakeDriver)Application.Driver!).SetBufferSize (100, 100); TableView tv = GetTreeTable (out _); diff --git a/UnitTests/Views/TreeViewTests.cs b/UnitTests/Views/TreeViewTests.cs index 11d85acdb..a770d1d9d 100644 --- a/UnitTests/Views/TreeViewTests.cs +++ b/UnitTests/Views/TreeViewTests.cs @@ -114,7 +114,7 @@ public class TreeViewTests tv.SelectAll (); tv.CursorVisibility = CursorVisibility.Default; Application.PositionCursor (top); - Application.Driver.GetCursorVisibility (out CursorVisibility visibility); + Application.Driver!.GetCursorVisibility (out CursorVisibility visibility); Assert.Equal (CursorVisibility.Default, tv.CursorVisibility); Assert.Equal (CursorVisibility.Default, visibility); top.Dispose (); diff --git a/UnitTests/Views/WindowTests.cs b/UnitTests/Views/WindowTests.cs index 24ea77876..6df5361e3 100644 --- a/UnitTests/Views/WindowTests.cs +++ b/UnitTests/Views/WindowTests.cs @@ -53,7 +53,7 @@ public class WindowTests Toplevel top = new (); top.Add (win); Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); TestHelpers.AssertDriverContentsWithFrameAre ( @" @@ -70,7 +70,7 @@ public class WindowTests _output ); - ((FakeDriver)Application.Driver).SetBufferSize (40, 20); + ((FakeDriver)Application.Driver!).SetBufferSize (40, 20); TestHelpers.AssertDriverContentsWithFrameAre ( @" @@ -97,7 +97,7 @@ public class WindowTests _output ); - ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + ((FakeDriver)Application.Driver!).SetBufferSize (20, 10); TestHelpers.AssertDriverContentsWithFrameAre ( @"