mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Merge branch 'copilot/add-fences-for-application-models' of tig:gui-cs/Terminal.Gui into copilot/add-fences-for-application-models
This commit is contained in:
@@ -13,38 +13,44 @@ public static partial class Application // Driver abstractions
|
||||
internal set => ApplicationImpl.Instance.Driver = value;
|
||||
}
|
||||
|
||||
private static bool _force16Colors = false; // Resources/config.json overrides
|
||||
|
||||
/// <inheritdoc cref="IApplication.Force16Colors"/>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static bool Force16Colors
|
||||
{
|
||||
get => ApplicationImpl.Instance.Force16Colors;
|
||||
set => ApplicationImpl.Instance.Force16Colors = value;
|
||||
get => _force16Colors;
|
||||
set
|
||||
{
|
||||
bool oldValue = _force16Colors;
|
||||
_force16Colors = value;
|
||||
Force16ColorsChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _force16Colors));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="Force16Colors"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<bool>>? Force16ColorsChanged;
|
||||
|
||||
private static string _forceDriver = string.Empty; // Resources/config.json overrides
|
||||
|
||||
/// <inheritdoc cref="IApplication.ForceDriver"/>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static string ForceDriver
|
||||
{
|
||||
get => ApplicationImpl.Instance.ForceDriver;
|
||||
get => _forceDriver;
|
||||
set
|
||||
{
|
||||
if (!string.IsNullOrEmpty (ApplicationImpl.Instance.ForceDriver) && value != Driver?.GetName ())
|
||||
{
|
||||
// ForceDriver cannot be changed if it has a valid value
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApplicationImpl.Instance.Initialized && value != Driver?.GetName ())
|
||||
{
|
||||
throw new InvalidOperationException ($"The {nameof (ForceDriver)} can only be set before initialized.");
|
||||
}
|
||||
|
||||
ApplicationImpl.Instance.ForceDriver = value;
|
||||
string oldValue = _forceDriver;
|
||||
_forceDriver = value;
|
||||
ForceDriverChanged?.Invoke (null, new ValueChangedEventArgs<string> (oldValue, _forceDriver));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="ForceDriver"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<string>>? ForceDriverChanged;
|
||||
|
||||
/// <inheritdoc cref="IApplication.Sixel"/>
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static List<SixelToRender> Sixel => ApplicationImpl.Instance.Sixel;
|
||||
|
||||
@@ -4,15 +4,25 @@ namespace Terminal.Gui.App;
|
||||
|
||||
public static partial class Application // Mouse handling
|
||||
{
|
||||
private static bool _isMouseDisabled = false; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Disable or enable the mouse. The mouse is enabled by default.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static bool IsMouseDisabled
|
||||
{
|
||||
get => Mouse.IsMouseDisabled;
|
||||
set => Mouse.IsMouseDisabled = value;
|
||||
get => _isMouseDisabled;
|
||||
set
|
||||
{
|
||||
bool oldValue = _isMouseDisabled;
|
||||
_isMouseDisabled = value;
|
||||
IsMouseDisabledChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _isMouseDisabled));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="IsMouseDisabled"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<bool>>? IsMouseDisabledChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMouse"/> instance that manages mouse event handling and state.
|
||||
/// </summary>
|
||||
|
||||
@@ -13,22 +13,43 @@ public static partial class Application // Navigation stuff
|
||||
internal set => ApplicationImpl.Instance.Navigation = value;
|
||||
}
|
||||
|
||||
private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
[Obsolete ("The legacy static Application object is going away.")]public static Key NextTabGroupKey
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static Key NextTabGroupKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.NextTabGroupKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.NextTabGroupKey = value;
|
||||
get => _nextTabGroupKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _nextTabGroupKey;
|
||||
_nextTabGroupKey = value;
|
||||
NextTabGroupKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _nextTabGroupKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="NextTabGroupKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? NextTabGroupKeyChanged;
|
||||
|
||||
private static Key _nextTabKey = Key.Tab; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Alternative key to navigate forwards through views. Tab is the primary key.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key NextTabKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.NextTabKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.NextTabKey = value;
|
||||
get => _nextTabKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _nextTabKey;
|
||||
_nextTabKey = value;
|
||||
NextTabKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _nextTabKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="NextTabKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? NextTabKeyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the user releases a key.
|
||||
/// <para>
|
||||
@@ -48,19 +69,39 @@ public static partial class Application // Navigation stuff
|
||||
remove => ApplicationImpl.Instance.Keyboard.KeyUp -= value;
|
||||
}
|
||||
|
||||
private static Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key PrevTabGroupKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.PrevTabGroupKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.PrevTabGroupKey = value;
|
||||
get => _prevTabGroupKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _prevTabGroupKey;
|
||||
_prevTabGroupKey = value;
|
||||
PrevTabGroupKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _prevTabGroupKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="PrevTabGroupKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? PrevTabGroupKeyChanged;
|
||||
|
||||
private static Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Alternative key to navigate backwards through views. Shift+Tab is the primary key.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key PrevTabKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.PrevTabKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.PrevTabKey = value;
|
||||
get => _prevTabKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _prevTabKey;
|
||||
_prevTabKey = value;
|
||||
PrevTabKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _prevTabKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="PrevTabKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? PrevTabKeyChanged;
|
||||
}
|
||||
|
||||
@@ -4,22 +4,42 @@ namespace Terminal.Gui.App;
|
||||
|
||||
public static partial class Application // Run (Begin -> Run -> Layout/Draw -> End -> Stop)
|
||||
{
|
||||
private static Key _quitKey = Key.Esc; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Gets or sets the key to quit the application.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key QuitKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.QuitKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.QuitKey = value;
|
||||
get => _quitKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _quitKey;
|
||||
_quitKey = value;
|
||||
QuitKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _quitKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="QuitKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? QuitKeyChanged;
|
||||
|
||||
private static Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
|
||||
|
||||
/// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
|
||||
[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key ArrangeKey
|
||||
{
|
||||
get => ApplicationImpl.Instance.Keyboard.ArrangeKey;
|
||||
set => ApplicationImpl.Instance.Keyboard.ArrangeKey = value;
|
||||
get => _arrangeKey;
|
||||
set
|
||||
{
|
||||
Key oldValue = _arrangeKey;
|
||||
_arrangeKey = value;
|
||||
ArrangeKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _arrangeKey));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Raised when <see cref="ArrangeKey"/> changes.</summary>
|
||||
public static event EventHandler<ValueChangedEventArgs<Key>>? ArrangeKeyChanged;
|
||||
|
||||
/// <inheritdoc cref="IApplication.Begin(IRunnable)"/>
|
||||
[Obsolete ("The legacy static Application object is going away.")]
|
||||
public static SessionToken Begin (Toplevel toplevel) => ApplicationImpl.Instance.Begin (toplevel);
|
||||
|
||||
@@ -254,6 +254,17 @@ public partial class ApplicationImpl
|
||||
ClearScreenNextIteration = false;
|
||||
|
||||
// === 6. Reset input systems ===
|
||||
// Dispose keyboard and mouse to unsubscribe from events
|
||||
if (_keyboard is IDisposable keyboardDisposable)
|
||||
{
|
||||
keyboardDisposable.Dispose ();
|
||||
}
|
||||
|
||||
if (_mouse is IDisposable mouseDisposable)
|
||||
{
|
||||
mouseDisposable.Dispose ();
|
||||
}
|
||||
|
||||
// Mouse and Keyboard will be lazy-initialized on next access
|
||||
_mouse = null;
|
||||
_keyboard = null;
|
||||
@@ -286,10 +297,33 @@ public partial class ApplicationImpl
|
||||
// gui.cs does no longer process any callbacks. See #1084 for more details:
|
||||
// (https://github.com/gui-cs/Terminal.Gui/issues/1084).
|
||||
SynchronizationContext.SetSynchronizationContext (null);
|
||||
|
||||
// === 12. Unsubscribe from Application static property change events ===
|
||||
UnsubscribeApplicationEvents ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="InitializedChanged"/> event.
|
||||
/// </summary>
|
||||
internal void RaiseInitializedChanged (object sender, EventArgs<bool> e) { InitializedChanged?.Invoke (sender, e); }
|
||||
|
||||
// Event handlers for Application static property changes
|
||||
private void OnForce16ColorsChanged (object? sender, ValueChangedEventArgs<bool> e)
|
||||
{
|
||||
Force16Colors = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnForceDriverChanged (object? sender, ValueChangedEventArgs<string> e)
|
||||
{
|
||||
ForceDriver = e.NewValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from Application static property change events.
|
||||
/// </summary>
|
||||
private void UnsubscribeApplicationEvents ()
|
||||
{
|
||||
Application.Force16ColorsChanged -= OnForce16ColorsChanged;
|
||||
Application.ForceDriverChanged -= OnForceDriverChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,27 @@ namespace Terminal.Gui.App;
|
||||
public partial class ApplicationImpl : IApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// INTERNAL: Creates a new instance of the Application backend.
|
||||
/// INTERNAL: Creates a new instance of the Application backend and subscribes to Application configuration property events.
|
||||
/// </summary>
|
||||
internal ApplicationImpl () { }
|
||||
internal ApplicationImpl ()
|
||||
{
|
||||
// Initialize from Application static properties (ConfigurationManager may have set these before we were created)
|
||||
Force16Colors = Application.Force16Colors;
|
||||
ForceDriver = Application.ForceDriver;
|
||||
|
||||
// Subscribe to Application static property change events
|
||||
Application.Force16ColorsChanged += OnForce16ColorsChanged;
|
||||
Application.ForceDriverChanged += OnForceDriverChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// INTERNAL: Creates a new instance of the Application backend.
|
||||
/// </summary>
|
||||
/// <param name="componentFactory"></param>
|
||||
internal ApplicationImpl (IComponentFactory componentFactory) { _componentFactory = componentFactory; }
|
||||
internal ApplicationImpl (IComponentFactory componentFactory) : this ()
|
||||
{
|
||||
_componentFactory = componentFactory;
|
||||
}
|
||||
|
||||
#region Singleton
|
||||
|
||||
@@ -108,6 +120,18 @@ public partial class ApplicationImpl : IApplication
|
||||
// If an instance exists, reset it
|
||||
_instance?.ResetState (ignoreDisposed);
|
||||
|
||||
// Reset Application static properties to their defaults
|
||||
// This ensures tests start with clean state
|
||||
Application.ForceDriver = string.Empty;
|
||||
Application.Force16Colors = false;
|
||||
Application.IsMouseDisabled = false;
|
||||
Application.QuitKey = Key.Esc;
|
||||
Application.ArrangeKey = Key.F5.WithCtrl;
|
||||
Application.NextTabGroupKey = Key.F6;
|
||||
Application.NextTabKey = Key.Tab;
|
||||
Application.PrevTabGroupKey = Key.F6.WithShift;
|
||||
Application.PrevTabKey = Key.Tab.WithShift;
|
||||
|
||||
// Always reset the model tracking to allow tests to use either model after reset
|
||||
ResetModelUsageTracking ();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Terminal.Gui.App;
|
||||
/// See <see cref="IKeyboard"/> for usage details.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
internal class KeyboardImpl : IKeyboard
|
||||
internal class KeyboardImpl : IKeyboard, IDisposable
|
||||
{
|
||||
private Key _quitKey = Key.Esc; // Resources/config.json overrides
|
||||
private Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
|
||||
@@ -103,10 +103,26 @@ internal class KeyboardImpl : IKeyboard
|
||||
public event EventHandler<Key>? KeyUp;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes keyboard bindings.
|
||||
/// Initializes keyboard bindings and subscribes to Application configuration property events.
|
||||
/// </summary>
|
||||
public KeyboardImpl ()
|
||||
{
|
||||
// Initialize from Application static properties (ConfigurationManager may have set these before we were created)
|
||||
_quitKey = Application.QuitKey;
|
||||
_arrangeKey = Application.ArrangeKey;
|
||||
_nextTabGroupKey = Application.NextTabGroupKey;
|
||||
_nextTabKey = Application.NextTabKey;
|
||||
_prevTabGroupKey = Application.PrevTabGroupKey;
|
||||
_prevTabKey = Application.PrevTabKey;
|
||||
|
||||
// Subscribe to Application static property change events
|
||||
Application.QuitKeyChanged += OnQuitKeyChanged;
|
||||
Application.ArrangeKeyChanged += OnArrangeKeyChanged;
|
||||
Application.NextTabGroupKeyChanged += OnNextTabGroupKeyChanged;
|
||||
Application.NextTabKeyChanged += OnNextTabKeyChanged;
|
||||
Application.PrevTabGroupKeyChanged += OnPrevTabGroupKeyChanged;
|
||||
Application.PrevTabKeyChanged += OnPrevTabKeyChanged;
|
||||
|
||||
AddKeyBindings ();
|
||||
}
|
||||
|
||||
@@ -378,4 +394,47 @@ internal class KeyboardImpl : IKeyboard
|
||||
KeyBindings.Add (Key.Z.WithCtrl, Command.Suspend);
|
||||
}
|
||||
}
|
||||
|
||||
// Event handlers for Application static property changes
|
||||
private void OnQuitKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
QuitKey = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnArrangeKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
ArrangeKey = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnNextTabGroupKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
NextTabGroupKey = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnNextTabKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
NextTabKey = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnPrevTabGroupKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
PrevTabGroupKey = e.NewValue;
|
||||
}
|
||||
|
||||
private void OnPrevTabKeyChanged (object? sender, ValueChangedEventArgs<Key> e)
|
||||
{
|
||||
PrevTabKey = e.NewValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose ()
|
||||
{
|
||||
// Unsubscribe from Application static property change events
|
||||
Application.QuitKeyChanged -= OnQuitKeyChanged;
|
||||
Application.ArrangeKeyChanged -= OnArrangeKeyChanged;
|
||||
Application.NextTabGroupKeyChanged -= OnNextTabGroupKeyChanged;
|
||||
Application.NextTabKeyChanged -= OnNextTabKeyChanged;
|
||||
Application.PrevTabGroupKeyChanged -= OnPrevTabGroupKeyChanged;
|
||||
Application.PrevTabKeyChanged -= OnPrevTabKeyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,19 @@ namespace Terminal.Gui.App;
|
||||
/// enabling better testability and parallel test execution.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
internal class MouseImpl : IMouse
|
||||
internal class MouseImpl : IMouse, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MouseImpl"/> class.
|
||||
/// Initializes a new instance of the <see cref="MouseImpl"/> class and subscribes to Application configuration property events.
|
||||
/// </summary>
|
||||
public MouseImpl () { }
|
||||
public MouseImpl ()
|
||||
{
|
||||
// Initialize from Application static property (ConfigurationManager may have set this before we were created)
|
||||
IsMouseDisabled = Application.IsMouseDisabled;
|
||||
|
||||
// Subscribe to Application static property change events
|
||||
Application.IsMouseDisabledChanged += OnIsMouseDisabledChanged;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IApplication? App { get; set; }
|
||||
@@ -391,4 +398,17 @@ internal class MouseImpl : IMouse
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event handler for Application static property changes
|
||||
private void OnIsMouseDisabledChanged (object? sender, ValueChangedEventArgs<bool> e)
|
||||
{
|
||||
IsMouseDisabled = e.NewValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose ()
|
||||
{
|
||||
// Unsubscribe from Application static property change events
|
||||
Application.IsMouseDisabledChanged -= OnIsMouseDisabledChanged;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user