Files
Terminal.Gui/Examples/UICatalog/Scenarios/KeyBindings.cs
Tig 0f72cf8a74 Fixes #4425 - ApplicationImpl internal (#4426)
* Pulled from v2_release

* Refactor migration guide for Terminal.Gui v2

Restructured and expanded the migration guide to provide a comprehensive resource for transitioning from Terminal.Gui v1 to v2. Key updates include:

- Added a Table of Contents for easier navigation.
- Summarized major architectural changes in v2, including the instance-based application model, IRunnable architecture, and 24-bit TrueColor support.
- Updated examples to reflect new patterns, such as initializers replacing constructors and explicit disposal using `IDisposable`.
- Documented changes to the layout system, including the removal of `Absolute`/`Computed` styles and the introduction of `Viewport`.
- Standardized event patterns to use `object sender, EventArgs args`.
- Detailed updates to the Keyboard, Mouse, and Navigation APIs, including configurable key bindings and viewport-relative mouse coordinates.
- Replaced legacy components like `ScrollView` and `ContextMenu` with built-in scrolling and `PopoverMenu`.
- Clarified disposal rules and introduced best practices for resource management.
- Provided a complete migration example and a summary of breaking changes.

This update aims to simplify the migration process by addressing breaking changes, introducing new features, and aligning with modern .NET conventions.

* Refactor to use Application.Instance for lifecycle management

Replaced all occurrences of `ApplicationImpl.Instance` with the new `Application.Instance` property across the codebase to align with the updated application lifecycle model.

Encapsulated the `ApplicationImpl` class by making it `internal`, ensuring it is no longer directly accessible outside its assembly. Introduced the `[Obsolete]` `Application.Instance` property as a backward-compatible singleton for the legacy static `Application` model, while encouraging the use of `Application.Create()` for new code.

Updated `MessageBox` methods to use `Application.Instance` for consistent modal dialog management. Improved documentation to reflect these changes and emphasize the transition to the instance-based application model.

Performed code cleanup in multiple classes to ensure consistency and maintainability. These changes maintain backward compatibility while preparing the codebase for the eventual removal of the legacy `ApplicationImpl` class.

* Fix doc bug

* - Removed obsolete `.cd` class diagram files.
- Introduced `IRunnable` interface for decoupling component execution.
- Added fluent API for running dialogs and retrieving results.
- Enhanced `View` with `App` and `Driver` properties for better decoupling.
- Improved testability with support for mock and real applications.
- Implemented `IDisposable` for proper resource cleanup.
- Replaced `RunnableSessionStack` with `SessionStack` for session management.
- Updated driver architecture to align with the new model.
- Scoped `IKeyboard` to application contexts for modularity.
- Updated documentation with migration strategies and best practices.

These changes modernize the library, improve maintainability, and align with current development practices.
2025-12-01 14:40:31 -07:00

199 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("KeyBindings", "Illustrates the KeyBindings API.")]
[ScenarioCategory ("Mouse and Keyboard")]
public sealed class KeyBindings : Scenario
{
private readonly ObservableCollection<string> _focusedBindings = [];
private ListView _focusedBindingsListView;
public override void Main ()
{
// Init
Application.Init ();
// Setup - Create a top-level application window and configure it.
Window appWindow = new ()
{
Title = GetQuitKeyAndName (),
SuperViewRendersLineCanvas = true,
};
Label label = new ()
{
Title = "_Label:",
};
TextField textField = new ()
{
X = Pos.Right (label),
Y = Pos.Top (label),
Width = 20,
};
appWindow.Add (label, textField);
Button button = new ()
{
X = Pos.Right (textField) + 1,
Y = Pos.Top (label),
Text = "_Button",
};
appWindow.Add (button);
KeyBindingsDemo keyBindingsDemo = new ()
{
X = Pos.Right (button) + 1,
Width = Dim.Auto (DimAutoStyle.Text),
Height = Dim.Auto (DimAutoStyle.Text),
HotKeySpecifier = (Rune)'_',
Title = "_KeyBindingsDemo",
Text = $"""
These keys will cause this view to show a message box:
- Hotkey: k, K, Alt-K, Alt-Shift-K
- Focused: F3
- Application: F4
Pressing Esc or {Application.QuitKey} will cause it to quit the app.
""",
BorderStyle = LineStyle.Dashed
};
appWindow.Add (keyBindingsDemo);
ObservableCollection<string> appBindings = new ();
ListView appBindingsListView = new ()
{
Title = "_Application Bindings",
BorderStyle = LineStyle.Single,
X = -1,
Y = Pos.Bottom (keyBindingsDemo) + 1,
Width = Dim.Auto (),
Height = Dim.Fill () + 1,
CanFocus = true,
Source = new ListWrapper<string> (appBindings),
SuperViewRendersLineCanvas = true
};
appWindow.Add (appBindingsListView);
foreach (Key key in Application.KeyBindings.GetBindings().ToDictionary().Keys)
{
var binding = Application.KeyBindings.Get (key);
appBindings.Add ($"{key} -> {binding.Target?.GetType ().Name} - {binding.Commands [0]}");
}
ObservableCollection<string> hotkeyBindings = new ();
ListView hotkeyBindingsListView = new ()
{
Title = "_Hotkey Bindings",
BorderStyle = LineStyle.Single,
X = Pos.Right (appBindingsListView) - 1,
Y = Pos.Bottom (keyBindingsDemo) + 1,
Width = Dim.Auto (),
Height = Dim.Fill () + 1,
CanFocus = true,
Source = new ListWrapper<string> (hotkeyBindings),
SuperViewRendersLineCanvas = true
};
appWindow.Add (hotkeyBindingsListView);
foreach (var subview in appWindow.SubViews)
{
foreach (KeyValuePair<Key, KeyBinding> binding in subview.HotKeyBindings.GetBindings ())
{
hotkeyBindings.Add ($"{binding.Key} -> {subview.GetType ().Name} - {binding.Value.Commands [0]}");
}
}
_focusedBindingsListView = new ()
{
Title = "_Focused Bindings",
BorderStyle = LineStyle.Single,
X = Pos.Right (hotkeyBindingsListView) - 1,
Y = Pos.Bottom (keyBindingsDemo) + 1,
Width = Dim.Auto (),
Height = Dim.Fill () + 1,
CanFocus = true,
Source = new ListWrapper<string> (_focusedBindings),
SuperViewRendersLineCanvas = true
};
appWindow.Add (_focusedBindingsListView);
Application.Navigation!.FocusedChanged += Application_HasFocusChanged;
// Run - Start the application.
Application.Run (appWindow);
Application.Navigation!.FocusedChanged -= Application_HasFocusChanged;
appWindow.Dispose ();
// Shutdown - Calling Application.Shutdown is required.
Application.Shutdown ();
}
private void Application_HasFocusChanged (object sender, EventArgs e)
{
View focused = Application.Navigation!.GetFocused ();
if (focused == null)
{
return;
}
_focusedBindingsListView.Title = $"_Focused ({focused?.GetType ().Name}) Bindings";
_focusedBindings.Clear ();
foreach (var binding in focused?.KeyBindings!.GetBindings ())
{
_focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}");
}
}
}
public class KeyBindingsDemo : View
{
public KeyBindingsDemo ()
{
CanFocus = true;
AddCommand (Command.Save, ctx =>
{
MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
return true;
});
AddCommand (Command.New, ctx =>
{
MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
return true;
});
AddCommand (Command.HotKey, ctx =>
{
MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
SetFocus ();
return true;
});
KeyBindings.Add (Key.F2, Command.Save);
KeyBindings.Add (Key.F3, Command.New); // same as specifying KeyBindingScope.Focused
Application.KeyBindings.Add (Key.F4, this, Command.New);
AddCommand (Command.Quit, ctx =>
{
if (ctx is not CommandContext<KeyBinding> keyCommandContext)
{
return false;
}
MessageBox.Query (Application.Instance, $"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
Application.RequestStop ();
return true;
});
Application.KeyBindings.Add (Key.Q.WithAlt, this, Command.Quit);
}
}