Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds IApplication #3872

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Terminal.Gui/Application/Application.Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ public static partial class Application // Driver abstractions
{
internal static bool _forceFakeConsole;



/// <summary>Gets the <see cref="IConsoleDriver"/> that has been selected. See also <see cref="ForceDriver"/>.</summary>
public static IConsoleDriver? Driver { get; internal set; }
public static IConsoleDriver? Driver
{
get => ApplicationImpl.Instance.Driver;
set => ApplicationImpl.Instance.Driver = value;
}

// BUGBUG: Force16Colors should be nullable.
/// <summary>
Expand Down
141 changes: 6 additions & 135 deletions Terminal.Gui/Application/Application.Initialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,140 +41,7 @@ public static partial class Application // Initialization (Init/Shutdown)

internal static int MainThreadId { get; set; } = -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<T>() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run<T>() 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 (
IConsoleDriver? 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 (ignoreDisposed: true);
}

Navigation = new ();

// For UnitTests
if (driver is { })
{
Driver = driver;

if (driver is FakeDriver)
{
// We're running unit tests. Disable loading config files other than default
if (Locations == ConfigLocations.All)
{
Locations = ConfigLocations.Default;
Reset ();
}
}
}

AddApplicationKeyBindings ();

// 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.
string previousTheme = Themes?.Theme ?? string.Empty;
Load ();
if (Themes is { } && !string.IsNullOrEmpty (previousTheme) && previousTheme != "Default")
{
ThemeManager.SelectedTheme = previousTheme;
}
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<Type?> drivers = GetDriverTypes ();
Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase));

if (driverType is { })
{
Driver = (IConsoleDriver)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 += Driver_SizeChanged;
Driver.KeyDown += Driver_KeyDown;
Driver.KeyUp += Driver_KeyUp;
Driver.MouseEvent += Driver_MouseEvent;

SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());

SupportedCultures = GetSupportedCultures ();
MainThreadId = Thread.CurrentThread.ManagedThreadId;
bool init = Initialized = true;
InitializedChanged?.Invoke (null, new (init));
}


private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { OnSizeChanging (e); }
private static void Driver_KeyDown (object? sender, Key e) { RaiseKeyDownEvent (e); }
Expand Down Expand Up @@ -233,7 +100,11 @@ public static void Shutdown ()
/// The <see cref="InitializedChanged"/> event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
/// </para>
/// </remarks>
public static bool Initialized { get; internal set; }
public static bool Initialized
{
get => ApplicationImpl.Instance.Initialized;
set => ApplicationImpl.Instance.Initialized = value;
}

/// <summary>
/// This event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
Expand Down
130 changes: 3 additions & 127 deletions Terminal.Gui/Application/Application.Keyboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,114 +155,12 @@ public static bool RaiseKeyUpEvent (Key key)

#region Application-scoped KeyBindings

static Application () { AddApplicationKeyBindings (); }

/// <summary>Gets the Application-scoped key bindings.</summary>
public static KeyBindings KeyBindings { get; internal set; } = new ();

internal static void AddApplicationKeyBindings ()
public static KeyBindings KeyBindings
{
CommandImplementations = new ();

// Things this view knows how to do
AddCommand (
Command.Quit,
static () =>
{
RequestStop ();

return true;
}
);

AddCommand (
Command.Suspend,
static () =>
{
Driver?.Suspend ();

return true;
}
);

AddCommand (
Command.NextTabStop,
static () => Navigation?.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop));

AddCommand (
Command.PreviousTabStop,
static () => Navigation?.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop));

AddCommand (
Command.NextTabGroup,
static () => Navigation?.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabGroup));

AddCommand (
Command.PreviousTabGroup,
static () => Navigation?.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabGroup));

AddCommand (
Command.Refresh,
static () =>
{
LayoutAndDraw (true);

return true;
}
);

AddCommand (
Command.Edit,
static () =>
{
View? viewToArrange = Navigation?.GetFocused ();

// Go up the superview hierarchy and find the first that is not ViewArrangement.Fixed
while (viewToArrange is { SuperView: { }, Arrangement: ViewArrangement.Fixed })
{
viewToArrange = viewToArrange.SuperView;
}

if (viewToArrange is { })
{
return viewToArrange.Border?.EnterArrangeMode (ViewArrangement.Fixed);
}

return false;
});

KeyBindings.Clear ();

// Resources/config.json overrides
NextTabKey = Key.Tab;
PrevTabKey = Key.Tab.WithShift;
NextTabGroupKey = Key.F6;
PrevTabGroupKey = Key.F6.WithShift;
QuitKey = Key.Esc;
ArrangeKey = Key.F5.WithCtrl;

KeyBindings.Add (QuitKey, KeyBindingScope.Application, Command.Quit);

KeyBindings.Add (Key.CursorRight, KeyBindingScope.Application, Command.NextTabStop);
KeyBindings.Add (Key.CursorDown, KeyBindingScope.Application, Command.NextTabStop);
KeyBindings.Add (Key.CursorLeft, KeyBindingScope.Application, Command.PreviousTabStop);
KeyBindings.Add (Key.CursorUp, KeyBindingScope.Application, Command.PreviousTabStop);
KeyBindings.Add (NextTabKey, KeyBindingScope.Application, Command.NextTabStop);
KeyBindings.Add (PrevTabKey, KeyBindingScope.Application, Command.PreviousTabStop);

KeyBindings.Add (NextTabGroupKey, KeyBindingScope.Application, Command.NextTabGroup);
KeyBindings.Add (PrevTabGroupKey, KeyBindingScope.Application, Command.PreviousTabGroup);

KeyBindings.Add (ArrangeKey, KeyBindingScope.Application, Command.Edit);

// TODO: Refresh Key should be configurable
KeyBindings.Add (Key.F5, KeyBindingScope.Application, Command.Refresh);

// TODO: Suspend Key should be configurable
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
KeyBindings.Add (Key.Z.WithCtrl, KeyBindingScope.Application, Command.Suspend);
}
get => ApplicationImpl.Instance.KeyBindings;
set => ApplicationImpl.Instance.KeyBindings = value;
}

/// <summary>
Expand Down Expand Up @@ -310,27 +208,5 @@ private static void ReplaceKey (Key oldKey, Key newKey)

#endregion Application-scoped KeyBindings

/// <summary>
/// <para>
/// Sets the function that will be invoked for a <see cref="Command"/>.
/// </para>
/// <para>
/// If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
/// replace the old one.
/// </para>
/// </summary>
/// <remarks>
/// <para>
/// This version of AddCommand is for commands that do not require a <see cref="CommandContext"/>.
/// </para>
/// </remarks>
/// <param name="command">The command.</param>
/// <param name="f">The function.</param>
private static void AddCommand (Command command, Func<bool?> f) { CommandImplementations! [command] = ctx => f (); }

/// <summary>
/// Commands for Application.
/// </summary>
private static Dictionary<Command, View.CommandImplementation>? CommandImplementations { get; set; }

}
4 changes: 3 additions & 1 deletion Terminal.Gui/Application/Application.Navigation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ public static partial class Application // Navigation stuff
/// <summary>
/// Gets the <see cref="ApplicationNavigation"/> instance for the current <see cref="Application"/>.
/// </summary>
public static ApplicationNavigation? Navigation { get; internal set; }
public static ApplicationNavigation? Navigation {
get=>ApplicationImpl.Instance.Navigation;
set => ApplicationImpl.Instance.Navigation = value;}

private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrides
private static Key _nextTabKey = Key.Tab; // Resources/config.json overrides
Expand Down
Loading
Loading