From dc309b1fd3a314efde0dd061155c007d525a2250 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 01:10:52 +0000 Subject: [PATCH 1/5] Initial plan From 892544842a134cf1708eaad57488da24e4f1e4e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 01:17:54 +0000 Subject: [PATCH 2/5] Move non-UICatalog examples out of Terminal.Gui repo Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/01a4446d-af40-4ac8-83d3-b36596f94b7f Co-authored-by: tig <585482+tig@users.noreply.github.com> --- .claude/tasks/build-app.md | 5 +- .claude/workflows/build-test-workflow.md | 9 +- .cursorrules | 2 +- .github/workflows/README.md | 2 - .github/workflows/build-validation.yml | 31 -- .windsurfrules | 2 +- AGENTS.md | 3 +- CONTRIBUTING.md | 13 +- .../CommunityToolkitExample.csproj | 14 - .../CommunityToolkitExample/LoginActions.cs | 8 - .../LoginView.Designer.cs | 64 ---- Examples/CommunityToolkitExample/LoginView.cs | 77 ----- .../CommunityToolkitExample/LoginViewModel.cs | 129 -------- Examples/CommunityToolkitExample/Message.cs | 5 - Examples/CommunityToolkitExample/Program.cs | 29 -- Examples/CommunityToolkitExample/README.md | 158 --------- Examples/Config/README.md | 90 ------ Examples/Config/example_config.json | 156 --------- Examples/Config/macos.json | 55 ---- Examples/Config/windows.json | 56 ---- Examples/DatePicker.ps1 | 53 --- Examples/Example/Example.cs | 94 ------ Examples/Example/Example.csproj | 10 - Examples/Example/README.md | 8 - Examples/FSharpExample/.editorconfig | 4 - Examples/FSharpExample/FSharpExample.fsproj | 19 -- Examples/FSharpExample/FSharpExample.sln | 31 -- Examples/FSharpExample/Program.fs | 48 --- Examples/FluentExample/FluentExample.csproj | 11 - Examples/FluentExample/Program.cs | 110 ------- Examples/InlineCLI/InlineCLI.cs | 212 ------------ Examples/InlineCLI/InlineCLI.csproj | 11 - Examples/InlineCLI/README.md | 38 --- .../InlineColorPicker.csproj | 10 - Examples/InlineColorPicker/Program.cs | 85 ----- Examples/InlineSelect/InlineSelect.csproj | 10 - Examples/InlineSelect/Program.cs | 151 --------- Examples/NativeAot/NativeAot.csproj | 34 -- Examples/NativeAot/Program.cs | 215 ------------- .../FolderProfile_net8.0_win-x64_Debug.pubxml | 18 -- ...olderProfile_net8.0_win-x64_Release.pubxml | 18 -- .../NativeAot/Properties/launchSettings.json | 13 - Examples/NativeAot/Publish_linux-x64_Debug.sh | 5 - .../NativeAot/Publish_linux-x64_Release.sh | 5 - Examples/NativeAot/Publish_osx-x64_Debug.sh | 5 - Examples/NativeAot/Publish_osx-x64_Release.sh | 5 - Examples/NativeAot/README.md | 42 --- Examples/PowershellExample.ps1 | 35 -- Examples/PromptExample/Program.cs | 302 ------------------ Examples/PromptExample/PromptExample.csproj | 19 -- Examples/README.md | 7 +- Examples/ReactiveExample/LoginView.cs | 162 ---------- Examples/ReactiveExample/LoginViewModel.cs | 81 ----- Examples/ReactiveExample/Program.cs | 24 -- Examples/ReactiveExample/README.md | 52 --- .../ReactiveExample/ReactiveExample.csproj | 13 - Examples/ReactiveExample/TerminalScheduler.cs | 67 ---- Examples/ReactiveExample/ViewExtensions.cs | 24 -- Examples/SelfContained/Program.cs | 123 ------- ...olderProfile_net8.0_linux-x64_Debug.pubxml | 16 - ...derProfile_net8.0_linux-x64_Release.pubxml | 16 - .../FolderProfile_net8.0_osx-x64_Debug.pubxml | 16 - ...olderProfile_net8.0_osx-x64_Release.pubxml | 16 - .../FolderProfile_net8.0_win-x64_Debug.pubxml | 17 - ...olderProfile_net8.0_win-x64_Release.pubxml | 17 - Examples/SelfContained/README.md | 35 -- Examples/SelfContained/SelfContained.csproj | 18 -- Examples/ShortcutTest/ShortcutTest.cs | 158 --------- Examples/ShortcutTest/ShortcutTest.csproj | 14 - Examples/Themes/code-dark.config.json | 25 -- Examples/WideCharRepro/BUG_REPORT_TEMPLATE.md | 121 ------- Examples/WideCharRepro/Program.cs | 154 --------- Examples/WideCharRepro/README.md | 59 ---- Examples/WideCharRepro/WideCharRepro.csproj | 10 - README.md | 2 +- Terminal.sln | 163 ---------- ai-v2-primer.md | 2 +- docfx/docs/application.md | 3 +- docfx/docs/config.md | 2 +- docfx/docs/getting-started.md | 28 +- docfx/docs/newinv2.md | 2 +- docfx/scripts/OutputView/OutputView.csproj | 1 - 82 files changed, 43 insertions(+), 3934 deletions(-) delete mode 100644 Examples/CommunityToolkitExample/CommunityToolkitExample.csproj delete mode 100644 Examples/CommunityToolkitExample/LoginActions.cs delete mode 100644 Examples/CommunityToolkitExample/LoginView.Designer.cs delete mode 100644 Examples/CommunityToolkitExample/LoginView.cs delete mode 100644 Examples/CommunityToolkitExample/LoginViewModel.cs delete mode 100644 Examples/CommunityToolkitExample/Message.cs delete mode 100644 Examples/CommunityToolkitExample/Program.cs delete mode 100644 Examples/CommunityToolkitExample/README.md delete mode 100644 Examples/Config/README.md delete mode 100644 Examples/Config/example_config.json delete mode 100644 Examples/Config/macos.json delete mode 100644 Examples/Config/windows.json delete mode 100644 Examples/DatePicker.ps1 delete mode 100644 Examples/Example/Example.cs delete mode 100644 Examples/Example/Example.csproj delete mode 100644 Examples/Example/README.md delete mode 100644 Examples/FSharpExample/.editorconfig delete mode 100644 Examples/FSharpExample/FSharpExample.fsproj delete mode 100644 Examples/FSharpExample/FSharpExample.sln delete mode 100644 Examples/FSharpExample/Program.fs delete mode 100644 Examples/FluentExample/FluentExample.csproj delete mode 100644 Examples/FluentExample/Program.cs delete mode 100644 Examples/InlineCLI/InlineCLI.cs delete mode 100644 Examples/InlineCLI/InlineCLI.csproj delete mode 100644 Examples/InlineCLI/README.md delete mode 100644 Examples/InlineColorPicker/InlineColorPicker.csproj delete mode 100644 Examples/InlineColorPicker/Program.cs delete mode 100644 Examples/InlineSelect/InlineSelect.csproj delete mode 100644 Examples/InlineSelect/Program.cs delete mode 100644 Examples/NativeAot/NativeAot.csproj delete mode 100644 Examples/NativeAot/Program.cs delete mode 100644 Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml delete mode 100644 Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml delete mode 100644 Examples/NativeAot/Properties/launchSettings.json delete mode 100644 Examples/NativeAot/Publish_linux-x64_Debug.sh delete mode 100644 Examples/NativeAot/Publish_linux-x64_Release.sh delete mode 100644 Examples/NativeAot/Publish_osx-x64_Debug.sh delete mode 100644 Examples/NativeAot/Publish_osx-x64_Release.sh delete mode 100644 Examples/NativeAot/README.md delete mode 100644 Examples/PowershellExample.ps1 delete mode 100644 Examples/PromptExample/Program.cs delete mode 100644 Examples/PromptExample/PromptExample.csproj delete mode 100644 Examples/ReactiveExample/LoginView.cs delete mode 100644 Examples/ReactiveExample/LoginViewModel.cs delete mode 100644 Examples/ReactiveExample/Program.cs delete mode 100644 Examples/ReactiveExample/README.md delete mode 100644 Examples/ReactiveExample/ReactiveExample.csproj delete mode 100644 Examples/ReactiveExample/TerminalScheduler.cs delete mode 100644 Examples/ReactiveExample/ViewExtensions.cs delete mode 100644 Examples/SelfContained/Program.cs delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Debug.pubxml delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Release.pubxml delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Debug.pubxml delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Release.pubxml delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml delete mode 100644 Examples/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml delete mode 100644 Examples/SelfContained/README.md delete mode 100644 Examples/SelfContained/SelfContained.csproj delete mode 100644 Examples/ShortcutTest/ShortcutTest.cs delete mode 100644 Examples/ShortcutTest/ShortcutTest.csproj delete mode 100644 Examples/Themes/code-dark.config.json delete mode 100644 Examples/WideCharRepro/BUG_REPORT_TEMPLATE.md delete mode 100644 Examples/WideCharRepro/Program.cs delete mode 100644 Examples/WideCharRepro/README.md delete mode 100644 Examples/WideCharRepro/WideCharRepro.csproj diff --git a/.claude/tasks/build-app.md b/.claude/tasks/build-app.md index d8850df6aa..0ba4512286 100644 --- a/.claude/tasks/build-app.md +++ b/.claude/tasks/build-app.md @@ -142,10 +142,9 @@ See `.claude/cookbook/common-patterns.md` for recipes including: | Example | Location | Description | |---------|----------|-------------| -| Hello World | `Examples/Example/` | Minimal login form | | All Controls | `Examples/UICatalog/` | Comprehensive demo app | -| MVVM | `Examples/CommunityToolkitExample/` | CommunityToolkit MVVM | -| Reactive | `Examples/ReactiveExample/` | ReactiveUI integration | +| Scenario automation | `Examples/ScenarioRunner/` | Run UICatalog scenarios from the CLI | +| Additional samples | `gui-cs/Examples` | Standalone example applications | ## Event Handling Patterns diff --git a/.claude/workflows/build-test-workflow.md b/.claude/workflows/build-test-workflow.md index 36b1a0ed2b..c34b9c4391 100644 --- a/.claude/workflows/build-test-workflow.md +++ b/.claude/workflows/build-test-workflow.md @@ -80,14 +80,9 @@ dotnet test --project Tests/UnitTests --no-build --verbosity normal && dotnet te ## Common Build Issues -### Issue: NativeAot/SelfContained Build Failures +### Issue: Restores fail after example repository split -**Solution:** Restore these projects explicitly: - -```bash -dotnet restore ./Examples/NativeAot/NativeAot.csproj -f -dotnet restore ./Examples/SelfContained/SelfContained.csproj -f -``` +**Solution:** Ensure your local clone does not reference removed in-repo example projects. ## Build Order Best Practice diff --git a/.cursorrules b/.cursorrules index bbd5679660..9e9ee1fd67 100644 --- a/.cursorrules +++ b/.cursorrules @@ -122,4 +122,4 @@ Input flows: Driver → `IInputProcessor` → `KeyBindings`/`MouseBindings` → | Common UI patterns | `.claude/cookbook/common-patterns.md` | | App building guide | `.claude/tasks/build-app.md` | | Deep-dive docs | `docfx/docs/` | -| Working examples | `Examples/Example/`, `Examples/UICatalog/` | +| Working examples | `Examples/UICatalog/`, `Examples/ScenarioRunner/`, `gui-cs/Examples` | diff --git a/.github/workflows/README.md b/.github/workflows/README.md index c08c42cb04..df171f39af 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -16,8 +16,6 @@ The repository uses multiple GitHub Actions workflows. What runs and when: - Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612` - Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612` - Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612` -- Restore NativeAot/SelfContained examples, then restore solution again -- Build Release for `Examples/NativeAot` and `Examples/SelfContained` - Build Release solution ### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`) diff --git a/.github/workflows/build-validation.yml b/.github/workflows/build-validation.yml index c5e29f4f3c..833b1930d5 100644 --- a/.github/workflows/build-validation.yml +++ b/.github/workflows/build-validation.yml @@ -50,36 +50,5 @@ jobs: - name: Pack Release Terminal.Gui run: dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612 - - name: Restore AOT and Self-Contained projects - run: | - dotnet restore ./Examples/NativeAot/NativeAot.csproj -f - dotnet restore ./Examples/SelfContained/SelfContained.csproj -f - - - name: Restore Solution Packages - run: dotnet restore - - - name: Build Release AOT and Self-Contained - run: | - dotnet build ./Examples/NativeAot/NativeAot.csproj --configuration Release -property:NoWarn=0618%3B0612 - dotnet build ./Examples/SelfContained/SelfContained.csproj --configuration Release -property:NoWarn=0618%3B0612 - - - name: AOT Publish (catches trimming and reflection errors) - run: dotnet publish ./Examples/NativeAot/NativeAot.csproj --configuration Release --output ./aot-publish -property:NoWarn=0618%3B0612 - - - name: AOT Smoke Test (run the published AOT binary on Linux) - if: runner.os == 'Linux' - env: - DisableRealDriverIO: "1" - run: | - chmod +x ./aot-publish/NativeAot - ./aot-publish/NativeAot --smoke-test - - - name: AOT Smoke Test (run the published AOT binary on Windows) - if: runner.os == 'Windows' - env: - DisableRealDriverIO: "1" - shell: pwsh - run: ./aot-publish/NativeAot.exe --smoke-test - - name: Build Release Solution run: dotnet build --configuration Release --no-restore -property:NoWarn=0618%3B0612 diff --git a/.windsurfrules b/.windsurfrules index 9a87984309..726e393bb3 100644 --- a/.windsurfrules +++ b/.windsurfrules @@ -122,4 +122,4 @@ Input flows: Driver → `IInputProcessor` → `KeyBindings`/`MouseBindings` → | Common UI patterns | `.claude/cookbook/common-patterns.md` | | App building guide | `.claude/tasks/build-app.md` | | Deep-dive docs | `docfx/docs/` | -| Working examples | `Examples/Example/`, `Examples/UICatalog/` | +| Working examples | `Examples/UICatalog/`, `Examples/ScenarioRunner/`, `gui-cs/Examples` | diff --git a/AGENTS.md b/AGENTS.md index 9654260ed0..d1a9fee611 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,7 +62,7 @@ dotnet run ### Key Resources - **App Building Guide**: [.claude/tasks/build-app.md](.claude/tasks/build-app.md) - **Common Patterns**: [.claude/cookbook/common-patterns.md](.claude/cookbook/common-patterns.md) -- **Examples**: `Examples/Example/` (minimal), `Examples/UICatalog/` (comprehensive) +- **Examples**: `Examples/UICatalog/`, `Examples/ScenarioRunner/`, and [gui-cs/Examples](https://github.com/gui-cs/Examples) ### API Reference (Compressed) | Namespace | Contents | @@ -547,6 +547,5 @@ Implementing `IValue` requires `ValueChanging`, `ValueChanged`, and `ValueCha - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5626a08e60..cd5ceae58d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -98,14 +98,6 @@ Welcome! This guide provides everything you need to know to contribute effective ### Common Build Issues -#### Issue: NativeAot/SelfContained Build - -- **Solution**: Restore these projects explicitly: - ```bash - dotnet restore ./Examples/NativeAot/NativeAot.csproj -f - dotnet restore ./Examples/SelfContained/SelfContained.csproj -f - ``` - ## Coding Conventions **⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code** @@ -318,9 +310,8 @@ foreach (Rune rune in text.EnumerateRunes ()) **`/Examples/`**: - `UICatalog/` - Comprehensive demo app for manual testing -- `Example/` - Basic example -- `NativeAot/`, `SelfContained/` - Deployment examples -- `ReactiveExample/`, `CommunityToolkitExample/` - Integration examples +- `ScenarioRunner/` - Scenario automation tool +- Additional examples live in [gui-cs/Examples](https://github.com/gui-cs/Examples) **`/docfx/`** - Documentation source: - `docs/` - Conceptual documentation (deep dives) diff --git a/Examples/CommunityToolkitExample/CommunityToolkitExample.csproj b/Examples/CommunityToolkitExample/CommunityToolkitExample.csproj deleted file mode 100644 index f01c030b97..0000000000 --- a/Examples/CommunityToolkitExample/CommunityToolkitExample.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - enable - - - - - - - - - diff --git a/Examples/CommunityToolkitExample/LoginActions.cs b/Examples/CommunityToolkitExample/LoginActions.cs deleted file mode 100644 index 3cbc6972cd..0000000000 --- a/Examples/CommunityToolkitExample/LoginActions.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace CommunityToolkitExample; - -internal enum LoginActions -{ - Clear, - Validation, - LoginProgress -} diff --git a/Examples/CommunityToolkitExample/LoginView.Designer.cs b/Examples/CommunityToolkitExample/LoginView.Designer.cs deleted file mode 100644 index 77b114a33b..0000000000 --- a/Examples/CommunityToolkitExample/LoginView.Designer.cs +++ /dev/null @@ -1,64 +0,0 @@ - -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; - -namespace CommunityToolkitExample; - -internal partial class LoginView : Window -{ - private Label titleLabel; - private Label usernameLengthLabel; - private TextField usernameInput; - private Label passwordLengthLabel; - private TextField passwordInput; - private Label validationLabel; - private Button loginButton; - private Button clearButton; - private Label loginProgressLabel; - - private void InitializeComponent () - { - titleLabel = new Label (); - titleLabel.Text = "Login Form"; - Add (titleLabel); - usernameLengthLabel = new Label (); - usernameLengthLabel.X = Pos.Left (titleLabel); - usernameLengthLabel.Y = Pos.Top (titleLabel) + 1; - Add (usernameLengthLabel); - usernameInput = new TextField (); - usernameInput.X = Pos.Right (usernameLengthLabel) + 1; - usernameInput.Y = Pos.Top (usernameLengthLabel); - usernameInput.Width = 40; - Add (usernameInput); - passwordLengthLabel = new Label (); - passwordLengthLabel.X = Pos.Left (usernameLengthLabel); - passwordLengthLabel.Y = Pos.Top (usernameLengthLabel) + 1; - Add (passwordLengthLabel); - passwordInput = new TextField (); - passwordInput.X = Pos.Right (passwordLengthLabel) + 1; - passwordInput.Y = Pos.Top (passwordLengthLabel); - passwordInput.Width = 40; - passwordInput.Secret = true; - Add (passwordInput); - validationLabel = new Label (); - validationLabel.X = Pos.Left (passwordInput); - validationLabel.Y = Pos.Top (passwordInput) + 1; - Add (validationLabel); - loginButton = new Button (); - loginButton.X = Pos.Left (validationLabel); - loginButton.Y = Pos.Top (validationLabel) + 1; - loginButton.Text = "_Login"; - Add (loginButton); - clearButton = new Button (); - clearButton.X = Pos.Left (loginButton); - clearButton.Y = Pos.Top (loginButton) + 1; - clearButton.Text = "_Clear"; - Add (clearButton); - loginProgressLabel = new Label (); - loginProgressLabel.X = Pos.Left (clearButton); - loginProgressLabel.Y = Pos.Top (clearButton) + 1; - loginProgressLabel.Width = 40; - loginProgressLabel.Height = 1; - Add (loginProgressLabel); - } -} diff --git a/Examples/CommunityToolkitExample/LoginView.cs b/Examples/CommunityToolkitExample/LoginView.cs deleted file mode 100644 index 97aec5da1b..0000000000 --- a/Examples/CommunityToolkitExample/LoginView.cs +++ /dev/null @@ -1,77 +0,0 @@ -using CommunityToolkit.Mvvm.Messaging; -using Terminal.Gui.App; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Input; - -namespace CommunityToolkitExample; - -internal partial class LoginView : IRecipient> -{ - public LoginView (LoginViewModel viewModel) - { - WeakReferenceMessenger.Default.Register (this); - Title = $"Community Toolkit MVVM Example - {Application.GetDefaultKey (Command.Quit)} to Exit"; - ViewModel = viewModel; - InitializeComponent (); - usernameInput.TextChanged += (_, _) => - { - ViewModel.Username = usernameInput.Text; - }; - passwordInput.TextChanged += (_, _) => - { - ViewModel.Password = passwordInput.Text; - }; - loginButton.Accepting += (_, e) => - { - if (!ViewModel.CanLogin) { return; } - ViewModel.LoginCommand.Execute (null); - // When Accepting is handled, set e.Handled to true to prevent further processing. - e.Handled = true; - }; - - clearButton.Accepting += (_, e) => - { - ViewModel.ClearCommand.Execute (null); - // When Accepting is handled, set e.Handled to true to prevent further processing. - e.Handled = true; - }; - - Initialized += (_, _) => { ViewModel.Initialized (); }; - } - - public LoginViewModel ViewModel { get; set; } - - public void Receive (Message message) - { - switch (message.Value) - { - case LoginActions.Clear: - { - loginProgressLabel.Text = ViewModel.LoginProgressMessage; - validationLabel.Text = ViewModel.ValidationMessage; - validationLabel.SetScheme (ViewModel.ValidationScheme); - break; - } - case LoginActions.LoginProgress: - { - loginProgressLabel.Text = ViewModel.LoginProgressMessage; - break; - } - case LoginActions.Validation: - { - validationLabel.Text = ViewModel.ValidationMessage; - validationLabel.SetScheme (ViewModel.ValidationScheme); - break; - } - } - SetText (); - } - - private void SetText () - { - usernameInput.Text = ViewModel.Username; - usernameLengthLabel.Text = ViewModel.UsernameLengthMessage; - passwordInput.Text = ViewModel.Password; - passwordLengthLabel.Text = ViewModel.PasswordLengthMessage; - } -} \ No newline at end of file diff --git a/Examples/CommunityToolkitExample/LoginViewModel.cs b/Examples/CommunityToolkitExample/LoginViewModel.cs deleted file mode 100644 index af7d594c36..0000000000 --- a/Examples/CommunityToolkitExample/LoginViewModel.cs +++ /dev/null @@ -1,129 +0,0 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using CommunityToolkit.Mvvm.Messaging; -using Terminal.Gui.Configuration; -using Terminal.Gui.Drawing; - -namespace CommunityToolkitExample; - -internal partial class LoginViewModel : ObservableObject -{ - private const string DEFAULT_LOGIN_PROGRESS_MESSAGE = "Press 'Login' to log in."; - private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password."; - private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in..."; - private const string VALID_LOGIN_MESSAGE = "The input is valid!"; - - [ObservableProperty] - private bool _canLogin; - - [ObservableProperty] - private string _loginProgressMessage; - - private string _password; - - [ObservableProperty] - private string _passwordLengthMessage; - - private string _username; - - [ObservableProperty] - private string _usernameLengthMessage; - - [ObservableProperty] - private Scheme? _validationScheme; - - [ObservableProperty] - private string _validationMessage; - public LoginViewModel () - { - _loginProgressMessage = string.Empty; - _password = string.Empty; - _passwordLengthMessage = string.Empty; - _username = string.Empty; - _usernameLengthMessage = string.Empty; - _validationMessage = string.Empty; - - Username = string.Empty; - Password = string.Empty; - - ClearCommand = new (Clear); - LoginCommand = new (Execute); - - Clear (); - - return; - - async void Execute () { await Login (); } - } - - public RelayCommand ClearCommand { get; } - - public RelayCommand LoginCommand { get; } - - public string Password - { - get => _password; - set - { - SetProperty (ref _password, value); - PasswordLengthMessage = $"_Password ({_password.Length} characters):"; - ValidateLogin (); - } - } - - public string Username - { - get => _username; - set - { - SetProperty (ref _username, value); - UsernameLengthMessage = $"_Username ({_username.Length} characters):"; - ValidateLogin (); - } - } - - public void Initialized () - { - Clear (); - } - - private void Clear () - { - Username = string.Empty; - Password = string.Empty; - SendMessage (LoginActions.Clear, DEFAULT_LOGIN_PROGRESS_MESSAGE); - } - - private async Task Login () - { - SendMessage (LoginActions.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE); - await Task.Delay (TimeSpan.FromSeconds (1)); - Clear (); - } - - private void SendMessage (LoginActions loginAction, string message = "") - { - switch (loginAction) - { - case LoginActions.Clear: - LoginProgressMessage = message; - ValidationMessage = INVALID_LOGIN_MESSAGE; - ValidationScheme = SchemeManager.GetScheme ("Error"); - break; - case LoginActions.LoginProgress: - LoginProgressMessage = message; - break; - case LoginActions.Validation: - ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE; - ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error"); - break; - } - WeakReferenceMessenger.Default.Send (new Message { Value = loginAction }); - } - - private void ValidateLogin () - { - CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password); - SendMessage (LoginActions.Validation); - } -} diff --git a/Examples/CommunityToolkitExample/Message.cs b/Examples/CommunityToolkitExample/Message.cs deleted file mode 100644 index fbd85604f3..0000000000 --- a/Examples/CommunityToolkitExample/Message.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace CommunityToolkitExample; -internal class Message -{ - public T? Value { get; set; } -} diff --git a/Examples/CommunityToolkitExample/Program.cs b/Examples/CommunityToolkitExample/Program.cs deleted file mode 100644 index 75ada56653..0000000000 --- a/Examples/CommunityToolkitExample/Program.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Terminal.Gui.App; -using Terminal.Gui.Configuration; - -namespace CommunityToolkitExample; - -public static class Program -{ - public static IServiceProvider? Services { get; private set; } - - private static void Main (string [] args) - { - ConfigurationManager.Enable (ConfigLocations.All); - Services = ConfigureServices (); - using IApplication app = Application.Create (); - app.Init (); - using var loginView = Services.GetRequiredService (); - app.Run (loginView); - } - - private static IServiceProvider ConfigureServices () - { - var services = new ServiceCollection (); - services.AddTransient (); - services.AddTransient (); - - return services.BuildServiceProvider (); - } -} diff --git a/Examples/CommunityToolkitExample/README.md b/Examples/CommunityToolkitExample/README.md deleted file mode 100644 index 1f7d5d8778..0000000000 --- a/Examples/CommunityToolkitExample/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# CommunityToolkit.MVVM Example - -This small demo gives an example of using the `CommunityToolkit.MVVM` framework's `ObservableObject`, `ObservableProperty`, and `IRecipient` in conjunction with `Microsoft.Extensions.DependencyInjection`. - -Right away we use IoC to load our views and view models. - -``` csharp -// As a public property for access further in the application if needed. -public static IServiceProvider? Services { get; private set; } -... -// In Main -ConfigurationManager.Enable (ConfigLocations.All); -Services = ConfigureServices (); -... -private static IServiceProvider ConfigureServices () -{ - var services = new ServiceCollection (); - services.AddTransient (); - services.AddTransient (); - return services.BuildServiceProvider (); -} -``` - -Now, we start the app using the modern Terminal.Gui model and get our main view. - -``` csharp -using IApplication app = Application.Create (); -app.Init (); -using var loginView = Services.GetRequiredService (); -app.Run (loginView); -``` - -Our view implements `IRecipient` to demonstrate the use of the `WeakReferenceMessenger`. The binding of the view events is then created. - -``` csharp -internal partial class LoginView : IRecipient> -{ - public LoginView (LoginViewModel viewModel) - { - // Initialize our Receive method - WeakReferenceMessenger.Default.Register (this); - ... - ViewModel = viewModel; - ... - passwordInput.TextChanged += (_, _) => - { - ViewModel.Password = passwordInput.Text; - }; - loginButton.Accepting += (_, e) => - { - if (!ViewModel.CanLogin) { return; } - ViewModel.LoginCommand.Execute (null); - // When Accepting is handled, set e.Handled to true to prevent further processing. - e.Handled = true; - }; - ... - // Let the view model know the view is initialized. - Initialized += (_, _) => { ViewModel.Initialized (); }; - } - ... -} -``` - -Momentarily slipping over to the view model, all bindable properties use some form of `ObservableProperty` with the class deriving from `ObservableObject`. Commands are of the `RelayCommand` type. The use of `ObservableProperty` generates the code for handling `INotifyPropertyChanged` and `INotifyPropertyChanging`. - -``` csharp -internal partial class LoginViewModel : ObservableObject -{ - ... - [ObservableProperty] - private bool _canLogin; - - private string _password; - ... - public LoginViewModel () - { - ... - Password = string.Empty; - ... - LoginCommand = new (Execute); - - Clear (); - - return; - - async void Execute () { await Login (); } - } - ... - public RelayCommand LoginCommand { get; } - - public string Password - { - get => _password; - set - { - SetProperty (ref _password, value); - PasswordLengthMessage = $"_Password ({_password.Length} characters):"; - ValidateLogin (); - } - } -``` - -The use of `WeakReferenceMessenger` provides one method of signaling the view from the view model. It's just one way to handle cross-thread messaging in this framework. - -``` csharp -... -private async Task Login () -{ - SendMessage (LoginActions.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE); - await Task.Delay (TimeSpan.FromSeconds (1)); - Clear (); -} - -private void SendMessage (LoginActions loginAction, string message = "") -{ - switch (loginAction) - { - case LoginActions.LoginProgress: - LoginProgressMessage = message; - break; - case LoginActions.Validation: - ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE; - ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error"); - break; - } - WeakReferenceMessenger.Default.Send (new Message { Value = loginAction }); -} - -private void ValidateLogin () -{ - CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password); - SendMessage (LoginActions.Validation); -} -... -``` - -The view's `Receive` function updates the UI based on messages from the view model. In the modern Terminal.Gui model, UI updates are automatically refreshed, so no manual `Application.Refresh()` call is needed. - -``` csharp -public void Receive (Message message) -{ - switch (message.Value) - { - case LoginActions.LoginProgress: - { - loginProgressLabel.Text = ViewModel.LoginProgressMessage; - break; - } - case LoginActions.Validation: - { - validationLabel.Text = ViewModel.ValidationMessage; - validationLabel.SetScheme (ViewModel.ValidationScheme); - break; - } - } - SetText (); -} -``` diff --git a/Examples/Config/README.md b/Examples/Config/README.md deleted file mode 100644 index e22877dc3c..0000000000 --- a/Examples/Config/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Terminal.Gui Key Binding Config Examples - -This folder contains example `config.json` files that override Terminal.Gui's default -key bindings to match platform conventions. - -## How to Use - -Copy the desired file to `~/.tui/config.json` (the global Terminal.Gui config location). - -| OS | Want macOS feel? | Want Windows feel? | -|----|------------------|--------------------| -| **Windows** | Copy `macos.json` → `~/.tui/config.json` | (already default) | -| **macOS** | (already default) | Copy `windows.json` → `~/.tui/config.json` | - -On Windows `~` expands to `C:\Users\`. -On macOS/Linux `~` expands to `/home/` (or `/Users/` on macOS). - -## What Each File Changes - -### `macos.json` — macOS-style bindings (for Windows users) - -Overrides Terminal.Gui's default key bindings to match macOS conventions: - -| What changes | Default (Windows) | With `macos.json` | -|---|---|---| -| Quit app | `Esc` | `Esc` or `Ctrl+Q` | -| Suspend app to background | *(not available)* | `Ctrl+Z` | -| Undo | `Ctrl+Z` | `Ctrl+Z` or `Ctrl+/` | -| Redo | `Ctrl+Y` | `Ctrl+Y` or `Ctrl+Shift+Z` | -| Delete char right | `Delete` | `Delete` or `Ctrl+D` | - -Note: Emacs navigation shortcuts (`Ctrl+B`/`Ctrl+F` for left/right in text fields, -`Ctrl+N`/`Ctrl+P` for up/down in text views and lists) are already available on all -platforms — no override needed. - -### `windows.json` — Windows-style bindings (for macOS users) - -Overrides Terminal.Gui's default key bindings to match Windows conventions: - -| What changes | Default (macOS) | With `windows.json` | -|---|---|---| -| Quit app | `Esc` or `Ctrl+Q` | `Esc` only | -| Suspend app to background | `Ctrl+Z` | *(disabled)* | -| Undo | `Ctrl+Z` or `Ctrl+/` | `Ctrl+Z` only | -| Redo | `Ctrl+Y` or `Ctrl+Shift+Z` | `Ctrl+Y` only | -| Delete char right | `Delete` or `Ctrl+D` | `Delete` only | - -**Limitation:** Emacs navigation shortcuts built into text views (`Ctrl+B`, `Ctrl+F`, -`Ctrl+N`, `Ctrl+P`, `Ctrl+K`, etc.) are set in C# code and cannot be removed via -`config.json`. They remain available alongside the standard keys. - -## How It Works - -Terminal.Gui's `ConfigurationManager` loads `~/.tui/config.json` and uses it to -replace the values of three key binding properties: - -- **`Application.DefaultKeyBindings`** — app-level commands (Quit, Suspend, Tab navigation) -- **`View.DefaultKeyBindings`** — shared commands across all views (navigation, clipboard, editing) -- **`View.ViewKeyBindings`** — per-view overrides (keyed by view type name, e.g. `"TextField"`) - -The JSON format maps command names to `PlatformKeyBinding` objects: - -```json -{ - "Application.DefaultKeyBindings": { - "Quit": { "All": ["Esc", "Ctrl+Q"] } - }, - "View.DefaultKeyBindings": { - "Undo": { "All": ["Ctrl+Z"], "Linux": ["Ctrl+/"], "Macos": ["Ctrl+/"] } - }, - "View.ViewKeyBindings": { - "TextField": { - "WordLeft": { "All": ["Ctrl+CursorLeft"] } - } - } -} -``` - -Each `PlatformKeyBinding` has four optional fields: - -| Field | Applies to | -|-------|-----------| -| `All` | Every platform | -| `Windows` | Windows only (added to `All`) | -| `Linux` | Linux only (added to `All`) | -| `Macos` | macOS only (added to `All`) | - -**Important:** When you override a property (e.g. `View.DefaultKeyBindings`), your -JSON replaces the entire default dictionary. Any command you omit reverts to -having no binding from that layer. Always include all commands you want active. diff --git a/Examples/Config/example_config.json b/Examples/Config/example_config.json deleted file mode 100644 index b47cb04a0d..0000000000 --- a/Examples/Config/example_config.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "$schema": "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", - "ConfigurationManager.ThrowOnJsonErrors": false, - "Application.DefaultKeyBindings": { - "Quit": { "All": ["Esc"] }, - "Suspend": { "Linux": ["Ctrl+Z"], "Macos": ["Ctrl+Z"] }, - "Arrange": { "All": ["Ctrl+F5"] }, - "NextTabStop": { "All": ["Tab"] }, - "PreviousTabStop": { "All": ["Shift+Tab"] }, - "NextTabGroup": { "All": ["F6"] }, - "PreviousTabGroup": { "All": ["Shift+F6"] }, - "Refresh": { "All": ["F5"] } - }, - "Driver.Force16Colors": false, - "Application.ForceDriver": "", - "Application.IsMouseDisabled": false, - "Key.Separator": "+", - "MenuBar.DefaultKey": "F10", - "PopoverMenu.DefaultKey": "Shift+F10", - "FileDialog.MaxSearchResults": 10000, - "FileDialogStyle.DefaultUseColors": false, - "FileDialogStyle.DefaultUseUnicodeCharacters": false, - "Theme": "Gruntled", - "Themes": [ - { - "Gruntled": { - "Glyphs": { - "CheckStateChecked": "✓" - }, - "Schemes": [ - { - "TopLevel": { - "Normal": { - "Foreground": "OrangeRed", - "Background": "AntiqueWhite" - }, - "Focus": { - "Foreground": "White", - "Background": "Maroon" - }, - "HotNormal": { - "Foreground": "DarkRed", - "Background": "AntiqueWhite" - }, - "HotFocus": { - "Foreground": "Yellow", - "Background": "Maroon" - }, - "Disabled": { - "Foreground": "LightPink", - "Background": "AntiqueWhite" - } - } - }, - { - "Base": { - "Normal": { - "Foreground": "White", - "Background": "OrangeRed" - }, - "Focus": { - "Foreground": "FireBrick", - "Background": "AntiqueWhite" - }, - "HotNormal": { - "Foreground": "Gold", - "Background": "OrangeRed" - }, - "HotFocus": { - "Foreground": "FireBrick", - "Background": "AntiqueWhite" - }, - "Disabled": { - "Foreground": "LightPink", - "Background": "OrangeRed" - } - } - }, - { - "Dialog": { - "Normal": { - "Foreground": "FireBrick", - "Background": "GhostWhite" - }, - "Focus": { - "Foreground": "DarkGray", - "Background": "LightGray" - }, - "HotNormal": { - "Foreground": "FireBrick", - "Background": "GhostWhite" - }, - "HotFocus": { - "Foreground": "FireBrick", - "Background": "GhostWhite" - }, - "Disabled": { - "Foreground": "Gray", - "Background": "DarkGray" - } - } - }, - { - "Menu": { - "Normal": { - "Foreground": "White", - "Background": "FireBrick" - }, - "Focus": { - "Foreground": "White", - "Background": "DarkRed" - }, - "HotNormal": { - "Foreground": "Yellow", - "Background": "FireBrick" - }, - "HotFocus": { - "Foreground": "Yellow", - "Background": "DarkRed" - }, - "Disabled": { - "Foreground": "Gray", - "Background": "DarkGray" - } - } - }, - { - "Error": { - "Normal": { - "Foreground": "Yellow", - "Background": "DarkRed" - }, - "Focus": { - "Foreground": "DarkSalmon", - "Background": "Brown" - }, - "HotNormal": { - "Foreground": "Black", - "Background": "DarkRed" - }, - "HotFocus": { - "Foreground": "FireBrick", - "Background": "Brown" - }, - "Disabled": { - "Foreground": "DarkGray", - "Background": "DarkRed" - } - } - } - ] - } - } - - ] -} \ No newline at end of file diff --git a/Examples/Config/macos.json b/Examples/Config/macos.json deleted file mode 100644 index 693dea0298..0000000000 --- a/Examples/Config/macos.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", - - "Application.DefaultKeyBindings": { - "Quit": { "All": ["Esc", "Ctrl+Q"] }, - "Suspend": { "All": ["Ctrl+Z"] }, - "Arrange": { "All": ["Ctrl+F5"] }, - "NextTabStop": { "All": ["Tab"] }, - "PreviousTabStop": { "All": ["Shift+Tab"] }, - "NextTabGroup": { "All": ["F6"] }, - "PreviousTabGroup":{ "All": ["Shift+F6"] }, - "Refresh": { "All": ["F5"] } - }, - - "View.DefaultKeyBindings": { - "Left": { "All": ["CursorLeft"] }, - "Right": { "All": ["CursorRight"] }, - "Up": { "All": ["CursorUp"] }, - "Down": { "All": ["CursorDown"] }, - "PageUp": { "All": ["PageUp"] }, - "PageDown": { "All": ["PageDown"] }, - "LeftStart": { "All": ["Home"] }, - "RightEnd": { "All": ["End"] }, - "Start": { "All": ["Ctrl+Home"] }, - "End": { "All": ["Ctrl+End"] }, - - "LeftExtend": { "All": ["Shift+CursorLeft"] }, - "RightExtend": { "All": ["Shift+CursorRight"] }, - "UpExtend": { "All": ["Shift+CursorUp"] }, - "DownExtend": { "All": ["Shift+CursorDown"] }, - "PageUpExtend": { "All": ["Shift+PageUp"] }, - "PageDownExtend": { "All": ["Shift+PageDown"] }, - "LeftStartExtend": { "All": ["Shift+Home"] }, - "RightEndExtend": { "All": ["Shift+End"] }, - "StartExtend": { "All": ["Ctrl+Shift+Home"] }, - "EndExtend": { "All": ["Ctrl+Shift+End"] }, - - "Copy": { "All": ["Ctrl+C"] }, - "Cut": { "All": ["Ctrl+X"] }, - "Paste": { "All": ["Ctrl+V"] }, - - "Undo": { "All": ["Ctrl+Z", "Ctrl+/"] }, - "Redo": { "All": ["Ctrl+Y", "Ctrl+Shift+Z"] }, - "SelectAll": { "All": ["Ctrl+A"] }, - "DeleteCharLeft": { "All": ["Backspace"] }, - "DeleteCharRight": { "All": ["Delete", "Ctrl+D"] } - }, - - "View.ViewKeyBindings": { - "TextField": { - "CutToEndOfLine": { "All": ["Ctrl+K"] }, - "KillWordRight": { "All": ["Ctrl+W"] } - } - } -} diff --git a/Examples/Config/windows.json b/Examples/Config/windows.json deleted file mode 100644 index b4d0085e70..0000000000 --- a/Examples/Config/windows.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "$schema": "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", - - "Application.DefaultKeyBindings": { - "Quit": { "All": ["Esc"] }, - "Arrange": { "All": ["Ctrl+F5"] }, - "NextTabStop": { "All": ["Tab"] }, - "PreviousTabStop": { "All": ["Shift+Tab"] }, - "NextTabGroup": { "All": ["F6"] }, - "PreviousTabGroup":{ "All": ["Shift+F6"] }, - "Refresh": { "All": ["F5"] } - }, - - "View.DefaultKeyBindings": { - "Left": { "All": ["CursorLeft"] }, - "Right": { "All": ["CursorRight"] }, - "Up": { "All": ["CursorUp"] }, - "Down": { "All": ["CursorDown"] }, - "PageUp": { "All": ["PageUp"] }, - "PageDown": { "All": ["PageDown"] }, - "LeftStart": { "All": ["Home"] }, - "RightEnd": { "All": ["End"] }, - "Start": { "All": ["Ctrl+Home"] }, - "End": { "All": ["Ctrl+End"] }, - - "LeftExtend": { "All": ["Shift+CursorLeft"] }, - "RightExtend": { "All": ["Shift+CursorRight"] }, - "UpExtend": { "All": ["Shift+CursorUp"] }, - "DownExtend": { "All": ["Shift+CursorDown"] }, - "PageUpExtend": { "All": ["Shift+PageUp"] }, - "PageDownExtend": { "All": ["Shift+PageDown"] }, - "LeftStartExtend": { "All": ["Shift+Home"] }, - "RightEndExtend": { "All": ["Shift+End"] }, - "StartExtend": { "All": ["Ctrl+Shift+Home"] }, - "EndExtend": { "All": ["Ctrl+Shift+End"] }, - - "Copy": { "All": ["Ctrl+C"] }, - "Cut": { "All": ["Ctrl+X"] }, - "Paste": { "All": ["Ctrl+V"] }, - - "Undo": { "All": ["Ctrl+Z"] }, - "Redo": { "All": ["Ctrl+Y"] }, - "SelectAll": { "All": ["Ctrl+A"] }, - "DeleteCharLeft": { "All": ["Backspace"] }, - "DeleteCharRight": { "All": ["Delete"] } - }, - - "View.ViewKeyBindings": { - "TextField": { - "WordLeft": { "All": ["Ctrl+CursorLeft"] }, - "WordRight": { "All": ["Ctrl+CursorRight"] }, - "WordLeftExtend": { "All": ["Ctrl+Shift+CursorLeft"] }, - "WordRightExtend":{ "All": ["Ctrl+Shift+CursorRight"] } - } - } -} diff --git a/Examples/DatePicker.ps1 b/Examples/DatePicker.ps1 deleted file mode 100644 index 4338f4643a..0000000000 --- a/Examples/DatePicker.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -using namespace Terminal.Gui.App -using namespace Terminal.Gui.ViewBase -using namespace Terminal.Gui.Views -# DatePicker.ps1 - Demonstrates Prompt API with DatePicker -# -# Usage: -# ./DatePicker.ps1 # Uses today's date -# ./DatePicker.ps1 '9/10/1966' # Uses specified date -# -# Prerequisites: -# dotnet build ..\Terminal.Gui -c Debug /p:CopyLocalLockFileAssemblies=true -# -# Returns: -# Selected date (yyyy-MM-dd format) if user accepts -# Nothing if user cancels - -param( - [string]$InitialDate = "" -) - - -$dllFolder = "Terminal.Gui\bin\Debug\net10.0" - -# Load all Terminal.Gui DLLs -Get-ChildItem $dllFolder -Filter *.dll | ForEach-Object { - Add-Type -Path $_.FullName -ErrorAction SilentlyContinue -} - -# Parse initial date or use today -$date = if ($InitialDate) { - [DateTime]::Parse($InitialDate) -} else { - [DateTime]::Now -} - -$app = [Application]::Create().Init() -$app.Init() - -try { - $datePicker = [DatePicker]::new($date) - - # Use the bool-returning overload (simpler for PowerShell) - # The generic Func<>-based overload requires complex delegate creation - $accepted = [Prompt]::Show($app, "Select Date", $datePicker) - - if ($accepted) { - Write-Output $datePicker.Date.ToString("yyyy-MM-dd") - } -} -finally { - if ($datePicker) { $datePicker.Dispose() } - $app.Dispose() -} diff --git a/Examples/Example/Example.cs b/Examples/Example/Example.cs deleted file mode 100644 index 7becbe1dd7..0000000000 --- a/Examples/Example/Example.cs +++ /dev/null @@ -1,94 +0,0 @@ -// A simple Terminal.Gui example in C# - using C# 9.0 Top-level statements - -// This is a simple example application. For the full range of functionality -// see the UICatalog project - -using Terminal.Gui.App; -using Terminal.Gui.Configuration; -using Terminal.Gui.Input; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; - -// Override the default configuration for the application to use the Amber Phosphor theme -ConfigurationManager.RuntimeConfig = """{ "Theme": "Amber Phosphor" }"""; -ConfigurationManager.Enable (ConfigLocations.All); - -IApplication app = Application.Create ().Init (); -var userName = app.Run ().GetResult (); -app.Dispose (); - -// To see this output on the screen it must be done after Dispose, -// which restores the previous screen. -if (string.IsNullOrEmpty (userName)) -{ - Console.WriteLine (@"Login cancelled"); -} -else -{ - Console.WriteLine ($@"Username: {userName}"); -} - -// Defines a top-level window with border and title -public sealed class ExampleWindow : Runnable -{ - public ExampleWindow () - { - Title = $"Example App ({Application.GetDefaultKey (Command.Quit)} to quit)"; - - // Create input components and labels - var usernameLabel = new Label { Text = "Username:" }; - - var userNameText = new TextField - { - // Position text field adjacent to the label - X = Pos.Right (usernameLabel) + 1, - - // Fill remaining horizontal space - Width = Dim.Fill () - }; - - var passwordLabel = new Label { Text = "Password:", X = Pos.Left (usernameLabel), Y = Pos.Bottom (usernameLabel) + 1 }; - - var passwordText = new TextField - { - Secret = true, - - // align with the text box above - X = Pos.Left (userNameText), - Y = Pos.Top (passwordLabel), - Width = Dim.Fill () - }; - - // Create login button - var btnLogin = new Button - { - Text = "Login", - Y = Pos.Bottom (passwordLabel) + 1, - - // center the login button horizontally - X = Pos.Center (), - IsDefault = true - }; - - // When login button is clicked display a message popup - btnLogin.Accepting += (s, e) => - { - if (userNameText.Text == "admin" && passwordText.Text == "password") - { - MessageBox.Query (App!, "Logging In", "Login Successful", "Ok"); - Result = userNameText.Text; - App!.RequestStop (); - } - else - { - MessageBox.ErrorQuery ((s as View)?.App!, "Logging In", "Incorrect username or password", "Ok"); - } - - // When Accepting is handled, set e.Handled to true to prevent further processing. - e.Handled = true; - }; - - // Add the views to the Window - Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin); - } -} diff --git a/Examples/Example/Example.csproj b/Examples/Example/Example.csproj deleted file mode 100644 index ed4cca28a1..0000000000 --- a/Examples/Example/Example.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - Exe - enable - latest - - - - - \ No newline at end of file diff --git a/Examples/Example/README.md b/Examples/Example/README.md deleted file mode 100644 index f1de23be54..0000000000 --- a/Examples/Example/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Terminal.Gui C# Example - -This example shows how to use the Terminal.Gui library to create a simple TUI application in C#. - -This is the same code found in the Terminal.Gui README.md file. - -To explore the full range of functionality in Terminal.Gui, see the [UICatalog](../UICatalog) project - diff --git a/Examples/FSharpExample/.editorconfig b/Examples/FSharpExample/.editorconfig deleted file mode 100644 index 924c8fe000..0000000000 --- a/Examples/FSharpExample/.editorconfig +++ /dev/null @@ -1,4 +0,0 @@ -[*.fs] -indent_style = space -indent_size = 4 -tab_width = 4 diff --git a/Examples/FSharpExample/FSharpExample.fsproj b/Examples/FSharpExample/FSharpExample.fsproj deleted file mode 100644 index 82b2802e5d..0000000000 --- a/Examples/FSharpExample/FSharpExample.fsproj +++ /dev/null @@ -1,19 +0,0 @@ - - - Exe - net8.0 - 1.6.2.0 - 1.6.2.0 - 1.6.2+Branch.main.Sha.b6eeb6321685af474ffc17b1390ff1d4894a90c5 - 1.6.2 - - - - - - - - - - - \ No newline at end of file diff --git a/Examples/FSharpExample/FSharpExample.sln b/Examples/FSharpExample/FSharpExample.sln deleted file mode 100644 index 90e5c5be25..0000000000 --- a/Examples/FSharpExample/FSharpExample.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpExample", "FSharpExample.fsproj", "{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "..\Terminal.Gui\Terminal.Gui.csproj", "{FA48E777-1308-489D-95A0-89DE46B65A93}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Release|Any CPU.Build.0 = Release|Any CPU - {FA48E777-1308-489D-95A0-89DE46B65A93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA48E777-1308-489D-95A0-89DE46B65A93}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA48E777-1308-489D-95A0-89DE46B65A93}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA48E777-1308-489D-95A0-89DE46B65A93}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A023D2E3-EF0F-4986-8E6C-323F967788B7} - EndGlobalSection -EndGlobal diff --git a/Examples/FSharpExample/Program.fs b/Examples/FSharpExample/Program.fs deleted file mode 100644 index 716f444faa..0000000000 --- a/Examples/FSharpExample/Program.fs +++ /dev/null @@ -1,48 +0,0 @@ -open Terminal.Gui - -type ExampleWindow() as this = - inherit Window() - - do - this.Title <- sprintf "Example App (%O to quit)" (Application.GetDefaultKey (Command.Quit)) - - // Create input components and labels - let usernameLabel = new Label(Text = "Username:") - - let userNameText = new TextField(X = Pos.Right(usernameLabel) + Pos.op_Implicit(1), Width = Dim.Fill()) - - let passwordLabel = new Label(Text = "Password:", X = Pos.Left(usernameLabel), Y = Pos.Bottom(usernameLabel) + Pos.op_Implicit(1)) - - let passwordText = new TextField(Secret = true, X = Pos.Left(userNameText), Y = Pos.Top(passwordLabel), Width = Dim.Fill()) - - // Create login button - let btnLogin = new Button(Text = "Login", Y = Pos.Bottom(passwordLabel) + Pos.op_Implicit(1), X = Pos.Center(), IsDefault = true) - - // When login button is clicked display a message popup - btnLogin.Accepting.Add(fun _ -> - if userNameText.Text = "admin" && passwordText.Text = "password" then - MessageBox.Query("Logging In", "Login Successful", "Ok") |> ignore - ExampleWindow.UserName <- userNameText.Text.ToString() - Application.RequestStop() - else - MessageBox.ErrorQuery("Logging In", "Incorrect username or password", "Ok") |> ignore - ) - - // Add the views to the Window - this.Add(usernameLabel, userNameText, passwordLabel, passwordText, btnLogin) - - static member val UserName = "" with get, set - -[] -let main argv = - Application.Init() - Application.Run().Dispose() - - // Before the application exits, reset Terminal.Gui for clean shutdown - Application.Shutdown() - - // To see this output on the screen it must be done after shutdown, - // which restores the previous screen. - printfn "Username: %s" ExampleWindow.UserName - - 0 // return an integer exit code diff --git a/Examples/FluentExample/FluentExample.csproj b/Examples/FluentExample/FluentExample.csproj deleted file mode 100644 index 4f6ca2449b..0000000000 --- a/Examples/FluentExample/FluentExample.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - net10.0 - preview - enable - - - - - diff --git a/Examples/FluentExample/Program.cs b/Examples/FluentExample/Program.cs deleted file mode 100644 index 3949bfd449..0000000000 --- a/Examples/FluentExample/Program.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Fluent API example demonstrating IRunnable with automatic disposal and result extraction - -using Terminal.Gui.App; -using Terminal.Gui.Drawing; -using Terminal.Gui.Resources; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; - -IApplication? app = Application.Create () - .Init () - .Run (); - -// Run the application with fluent API - automatically creates, runs, and disposes the runnable -Color? result = app.GetResult () as Color?; - -// Shut down the app with Dispose before we can use Console.WriteLine -app.Dispose (); - -if (result is { }) -{ - Console.WriteLine (@$"Selected Color: {result}"); -} -else -{ - Console.WriteLine (@"No color selected"); -} - -/// -/// A runnable view that allows the user to select a color. -/// Demonstrates the Runnable with type pattern with automatic disposal. -/// -public class ColorPickerView : Runnable -{ - public ColorPickerView () - { - Title = "Select a Color (Esc to quit)"; - BorderStyle = LineStyle.Single; - Height = Dim.Auto (); - Width = Dim.Auto (); - - // Add instructions - var instructions = new Label - { - Text = "Use arrow keys to select a color, Enter to accept", - X = Pos.Center (), - Y = 0 - }; - - // Create color picker - ColorPicker colorPicker = new () - { - X = Pos.Center (), - Y = Pos.Bottom (instructions), - Style = new ColorPickerStyle () - { - ShowColorName = true, - ShowTextFields = true - } - }; - colorPicker.ApplyStyleChanges (); - - // Create OK button - Button okButton = new () - { - Title = "_OK", - X = Pos.Align (Alignment.Center), - Y = Pos.AnchorEnd (), - IsDefault = true - }; - - okButton.Accepting += (s, e) => - { - // Extract result before stopping - Result = colorPicker.Value; - RequestStop (); - e.Handled = true; - }; - - // Create Cancel button - Button cancelButton = new () - { - Title = Strings.btnCancel, - X = Pos.Align (Alignment.Center), - Y = Pos.AnchorEnd () - }; - - cancelButton.Accepting += (s, e) => - { - // Don't set result - leave as null - RequestStop (); - e.Handled = true; - }; - - // Add views - Add (instructions, colorPicker, okButton, cancelButton); - } - - protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning) - { - // Alternative place to extract result before stopping - // This is called before the view is removed from the stack - if (!newIsRunning && Result is null) - { - // User pressed Esc - could extract current selection here - //Result = SelectedColor; - } - - return base.OnIsRunningChanging (oldIsRunning, newIsRunning); - } -} diff --git a/Examples/InlineCLI/InlineCLI.cs b/Examples/InlineCLI/InlineCLI.cs deleted file mode 100644 index a13c9129e0..0000000000 --- a/Examples/InlineCLI/InlineCLI.cs +++ /dev/null @@ -1,212 +0,0 @@ -// A simple Terminal.Gui example demonstrating Inline mode rendering. -// -// This example shows how to use AppModel.Inline to render UI inline within -// the primary (scrollback) terminal buffer, similar to how Claude Code CLI -// and GitHub Copilot CLI render their UI. -// -// The application renders below the current shell prompt without switching -// to the alternate screen buffer. On exit, the rendered content stays in -// scrollback history. - -using System.Collections.ObjectModel; -using System.Drawing; -using Terminal.Gui.App; -using Terminal.Gui.Drawing; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; -using UICatalog; -// ReSharper disable AccessToModifiedClosure - -// Set Inline mode BEFORE Init -Application.AppModel = AppModel.Inline; - -//Application.ForceInlinePosition = new Point (0, 3); - -IApplication app = Application.Create ().Init (); - -app.Run (); -app.Dispose (); - -/// -/// A simple inline prompt view that demonstrates the inline rendering mode. -/// Uses Height = Dim.Auto(minimumContentSize: 10) so the view sizes itself by content -/// with a minimum height. The framework automatically resizes Screen to the rows -/// available below the cursor and offsets rendering so the view appears at the cursor position. -/// -public sealed class InlinePromptView : Window -{ - private readonly Shortcut? _cursorShortcut; - private readonly Shortcut? _driverShortcut; - private readonly Shortcut? _screenShortcut; - private readonly Shortcut? _frameShortcut; - - public InlinePromptView () - { - Title = "Inline CLI Demo"; - - Border.Thickness = new Thickness (0, 3, 0, 0); - Border.LineStyle = LineStyle.Rounded; - - Arrangement = ViewArrangement.TopResizable; - - Width = Dim.Fill (); - Height = Dim.Auto (); - - StatusBar statusBar = new () { AlignmentModes = AlignmentModes.IgnoreFirstOrLast, SchemeName = SchemeName }; - Shortcut itemCountShortcut = new () { Title = "No items", MouseHighlightStates = MouseState.None, Enabled = false }; - - _cursorShortcut = new Shortcut { Text = "Cursor", MouseHighlightStates = MouseState.None, Enabled = false }; - _driverShortcut = new Shortcut { Text = "Driver", MouseHighlightStates = MouseState.None, Enabled = false }; - _screenShortcut = new Shortcut { Text = "Screen", MouseHighlightStates = MouseState.None, Enabled = false }; - _frameShortcut = new Shortcut { Text = "Frame", MouseHighlightStates = MouseState.None, Enabled = false }; - - Logo logo = new () { X = Pos.Center () }; - - Label infoLabel = new () - { - Text = "Demonstrates Inline Application Mode.\nType a message and press Enter. Press Esc to exit.", - Y = Pos.Bottom (logo), - TextAlignment = Alignment.Center, - Width = Dim.Fill (), - Enabled = false - }; - - ObservableCollection items = []; - - // Declared early so the local function can capture them. - ListView outputList = null!; - View inputIndicator = null!; - - outputList = new ListView - { - Y = Pos.Bottom (infoLabel), - Width = Dim.Fill (), - Height = Dim.Auto (minimumContentDim: 1, maximumContentDim: Dim.Func (_ => GetMaxListHeight ())), - BorderStyle = LineStyle.Dotted - }; - outputList.Border.Thickness = new Thickness (0, 0, 0, 1); - - outputList.SubViewsLaidOut += (_, _) => - { - if (outputList.Index is { }) - { - outputList.Viewport = outputList.Viewport with { Y = outputList.Index.Value }; - } - }; - - outputList.GettingAttributeForRole += (sender, args) => - { - var view = sender as View; - - if (args.Role != VisualRole.Active) - { - return; - } - args.Result = view?.GetAttributeForRole (VisualRole.Normal); - args.Handled = true; - }; - - outputList.SetSource (items); - - inputIndicator = new View - { - Text = $"{Glyphs.RightArrow}", - Y = Pos.Bottom (outputList), - Width = 2, - Height = 2, - Enabled = false, - BorderStyle = LineStyle.Dotted - }; - inputIndicator.Border.Thickness = new Thickness (0, 0, 0, 1); - - TextField inputField = new () - { - X = Pos.Right (inputIndicator), Y = Pos.Top (inputIndicator), Width = Dim.Fill (), BorderStyle = inputIndicator.BorderStyle - }; - inputField.Border.Thickness = new Thickness (0, 0, 0, 1); - - inputField.Accepted += (_, _) => - { - var text = $"{Glyphs.BlackCircle} {inputField.Text}"; - - items.Add (text); - outputList.MoveEnd (); - - inputField.Text = string.Empty; - itemCountShortcut.Title = $"{items.Count}"; - }; - - statusBar.Add (_cursorShortcut, _driverShortcut, _screenShortcut, _frameShortcut, itemCountShortcut); - - Add (logo, infoLabel, outputList, inputIndicator, inputField, statusBar); - inputField.SetFocus (); - - _cursorShortcut?.Title = $"{App?.Driver?.InlinePosition.Y}"; - _driverShortcut?.Title = $"{Format (App?.Driver?.Screen)}"; - _screenShortcut?.Title = $"{Format (App?.Screen)}"; - _frameShortcut?.Title = $"{Format (Frame)}"; - - return; - - // Returns the maximum content height for the outputList so it doesn't grow beyond what the - // terminal can display. Subtracts all sibling and adornment heights from App.Screen.Height. - int GetMaxListHeight () - { - int screenHeight = App?.Driver?.Screen.Height ?? 100; - - // Adornments of the containing InlinePromptView (this Window) - int windowAdornments = (Border?.Thickness.Vertical ?? 0) + (Margin?.Thickness.Vertical ?? 0) + (Padding?.Thickness.Vertical ?? 0); - - // Heights of sibling views (everything except the list itself) - int siblingHeight = (logo?.Frame.Height ?? 0) - + (infoLabel?.Frame.Height ?? 0) - + (inputIndicator?.Frame.Height ?? 0) - + (statusBar?.Frame.Height ?? 0); - - // The list's own adornment overhead (border bottom = 1) - int listAdornments = (outputList.Border?.Thickness.Vertical ?? 0) - + (outputList.Margin?.Thickness.Vertical ?? 0) - + (outputList.Padding?.Thickness.Vertical ?? 0); - - int maxContent = screenHeight - windowAdornments - siblingHeight - listAdornments; - - return Math.Max (1, maxContent); - } - } - - /// - protected override void OnIsRunningChanged (bool newIsRunning) - { - base.OnIsRunningChanged (newIsRunning); - - if (newIsRunning) - { - App?.ScreenChanged += AppOnScreenChanged; - App?.Driver?.SizeChanged += DriverOnSizeChanged; - } - else - { - App?.ScreenChanged -= AppOnScreenChanged; - App?.Driver?.SizeChanged -= DriverOnSizeChanged; - } - } - - private void AppOnScreenChanged (object? sender, EventArgs e) => _screenShortcut?.Title = $"{Format (e.Value)}"; - - private void DriverOnSizeChanged (object? sender, SizeChangedEventArgs e) => - _driverShortcut?.Title = $"{Format (new Rectangle (new Point (0, 0), e.Size!.Value))}"; - - /// - protected override void OnFrameChanged (in Rectangle frame) - { - base.OnFrameChanged (in frame); - - _cursorShortcut?.Title = $"{App?.Driver?.InlinePosition.Y}"; - _driverShortcut?.Title = $"{Format (App?.Driver?.Screen)}"; - _screenShortcut?.Title = $"{Format (App?.Screen)}"; - _frameShortcut?.Title = $"{Format (Frame)}"; - } - - private static string Format (Rectangle? rect) => - rect is null ? $"({Glyphs.Null})" : $"({rect.Value.X},{rect.Value.Y},{rect.Value.Width},{rect.Value.Height})"; -} diff --git a/Examples/InlineCLI/InlineCLI.csproj b/Examples/InlineCLI/InlineCLI.csproj deleted file mode 100644 index 963226eeae..0000000000 --- a/Examples/InlineCLI/InlineCLI.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - enable - latest - - - - - - diff --git a/Examples/InlineCLI/README.md b/Examples/InlineCLI/README.md deleted file mode 100644 index 417432b3d7..0000000000 --- a/Examples/InlineCLI/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# InlineCLI Example - -Demonstrates Terminal.Gui's **Inline** rendering mode, which renders UI inline within -the primary (scrollback) terminal buffer instead of switching to the alternate screen buffer. - -## How It Works - -Setting `Application.AppModel = AppModel.Inline` before calling `Init()` tells -Terminal.Gui to: - -1. **Skip the alternate screen buffer** — no `CSI ?1049h` is emitted. -2. **Render in the primary buffer** — output appears below the shell prompt. -3. **Exit cleanly** — no `CSI ?1049l` is emitted; the shell prompt appears - naturally below the rendered content, which stays in scrollback history. - -## Running - -```bash -dotnet run --project Examples/InlineCLI -``` - -## API - -```csharp -// Set Inline mode BEFORE Init -Application.AppModel = AppModel.Inline; - -IApplication app = Application.Create ().Init (); -app.Run (); -app.Dispose (); -``` - -## Inspiration - -This mode is inspired by tools like: -- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) -- [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) -- [Ink](https://github.com/vadimdemedes/ink) (React for terminals) diff --git a/Examples/InlineColorPicker/InlineColorPicker.csproj b/Examples/InlineColorPicker/InlineColorPicker.csproj deleted file mode 100644 index 46d92f7faf..0000000000 --- a/Examples/InlineColorPicker/InlineColorPicker.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - Exe - enable - latest - - - - - diff --git a/Examples/InlineColorPicker/Program.cs b/Examples/InlineColorPicker/Program.cs deleted file mode 100644 index 9f57db9a9f..0000000000 --- a/Examples/InlineColorPicker/Program.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Inline ColorPicker — demonstrates using RunnableWrapper in inline mode. -// -// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command -// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output, -// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike. -// -// Renders a ColorPicker inline in the terminal (primary buffer) without dialog buttons. -// If the user accepts (double-click), the selected color name is written to stdout. -// If the user cancels (Esc), nothing is output and exit code is 1. -// -// Usage: -// dotnet run --project Examples/InlineColorPicker -// dotnet run --project Examples/InlineColorPicker -- --initial "#FF0000" -// dotnet run --project Examples/InlineColorPicker -- --initial Red -// $color = dotnet run --project Examples/InlineColorPicker # capture in shell - -using Terminal.Gui.App; -using Terminal.Gui.Drawing; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; - -// Parse command-line arguments -string? initialValue = null; - -for (var i = 0; i < args.Length; i++) -{ - if (args [i] is "--initial" or "-i") - { - if (i + 1 < args.Length) - { - initialValue = args [++i]; - } - else - { - Console.Error.WriteLine ("Error: --initial requires a color value (e.g., \"#FF0000\" or \"Red\")."); - - return 1; - } - } -} - -// Enable inline mode before Init -Application.AppModel = AppModel.Inline; - -IApplication app = Application.Create ().Init (); - -// Wrap ColorPicker in a RunnableWrapper — no dialog buttons, just the picker. -// ColorPicker raises Command.Accept on double-click. -RunnableWrapper wrapper = new () { Title = "Select a Color (Double-click to accept, Esc to cancel)", ResultExtractor = cp => cp.Value }; - -// Enable color name display -wrapper.GetWrappedView ().Style.ShowColorName = true; -wrapper.GetWrappedView ().ApplyStyleChanges (); - -// Apply initial value via IValue.TrySetValueFromString if provided -if (initialValue is { }) -{ - if (!((IValue)wrapper.GetWrappedView ()).TrySetValueFromString (initialValue)) - { - Console.Error.WriteLine ($"Error: '{initialValue}' is not a valid color (use e.g., \"#FF0000\" or \"Red\")."); - app.Dispose (); - - return 1; - } -} - -// Run inline — blocks until user accepts or cancels -app.Run (wrapper); - -Color? result = wrapper.Result; - -app.Dispose (); - -if (result is { } selectedColor) -{ - StandardColorsNameResolver resolver = new (); - - string output = resolver.TryNameColor (selectedColor, out string? name) ? name : selectedColor.ToString (); - - Console.WriteLine (output); - - return 0; -} - -return 1; diff --git a/Examples/InlineSelect/InlineSelect.csproj b/Examples/InlineSelect/InlineSelect.csproj deleted file mode 100644 index 46d92f7faf..0000000000 --- a/Examples/InlineSelect/InlineSelect.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - Exe - enable - latest - - - - - diff --git a/Examples/InlineSelect/Program.cs b/Examples/InlineSelect/Program.cs deleted file mode 100644 index 4c34f8e4a4..0000000000 --- a/Examples/InlineSelect/Program.cs +++ /dev/null @@ -1,151 +0,0 @@ -// InlineSelect — demonstrates using RunnableWrapper in inline mode. -// -// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command -// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output, -// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike. -// -// Renders an OptionSelector inline in the terminal with options from the command line. -// Supports horizontal or vertical orientation via --horizontal / --vertical flags. -// Hot keys are auto-assigned from option text. -// Supports --timeout to auto-cancel via CancellationToken (demonstrates RunAsync). -// Supports --initial to pre-select an option via IValue.TrySetValueFromString. -// -// Usage: -// dotnet run --project Examples/InlineSelect -- Apple Banana Cherry -// dotnet run --project Examples/InlineSelect -- --horizontal Red Green Blue Yellow -// dotnet run --project Examples/InlineSelect -- --vertical One Two Three -// dotnet run --project Examples/InlineSelect -- --timeout 10 Apple Banana Cherry -// dotnet run --project Examples/InlineSelect -- --initial 1 Apple Banana Cherry - -using Terminal.Gui.App; -using Terminal.Gui.Drawing; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; -using Timeout = System.Threading.Timeout; - -// Parse command-line arguments -Orientation orientation = Orientation.Vertical; -List options = []; -int? timeoutSeconds = null; -string? initialValue = null; - -for (var i = 0; i < args.Length; i++) -{ - string arg = args [i]; - - switch (arg) - { - case "--horizontal" or "-h": orientation = Orientation.Horizontal; break; - - case "--vertical" or "-v": orientation = Orientation.Vertical; break; - - case "--timeout" or "-t" when i + 1 < args.Length && int.TryParse (args [i + 1], out int seconds): - timeoutSeconds = seconds; - i++; // skip the next arg (the number) - - break; - - case "--timeout" or "-t": - Console.Error.WriteLine ("Error: --timeout requires a number of seconds."); - - return 1; - - case "--initial" or "-i" when i + 1 < args.Length: initialValue = args [++i]; break; - - case "--initial" or "-i": - Console.Error.WriteLine ("Error: --initial requires an index value."); - - return 1; - - default: options.Add (arg); break; - } -} - -if (options.Count == 0) -{ - Console.Error.WriteLine ("Usage: InlineSelect [--horizontal|--vertical] [--timeout ] ..."); - - return 1; -} - -// Enable inline mode before Init -Application.AppModel = AppModel.Inline; - -IApplication app = Application.Create ().Init (); - -// Build the OptionSelector with command-line options -OptionSelector selector = new () { Labels = options, Orientation = orientation, AssignHotKeys = true }; - -// Wrap in RunnableWrapper — auto-extracts Value via IValue -RunnableWrapper wrapper = new (selector) -{ - Title = timeoutSeconds.HasValue - ? $"Select an option (Enter to accept, Esc to cancel, {timeoutSeconds}s timeout)" - : "Select an option (Enter to accept, Esc to cancel)", - Width = Dim.Fill (), - BorderStyle = LineStyle.Rounded -}; - -// Apply initial value if provided — match by label (case-insensitive) or by numeric index -if (initialValue is { }) -{ - // First try matching a label - int matchIndex = options.FindIndex (o => string.Equals (o, initialValue, StringComparison.OrdinalIgnoreCase)); - - if (matchIndex >= 0) - { - selector.Value = matchIndex; - } - else if (!((IValue)selector).TrySetValueFromString (initialValue)) - { - Console.Error.WriteLine ($"Error: '{initialValue}' does not match any option and is not a valid index."); - app.Dispose (); - - return 1; - } -} - -// Run with optional timeout via RunAsync + CancellationToken -if (timeoutSeconds.HasValue) -{ - // Use RunAsync with a CancellationToken for timeout-based cancellation - using CancellationTokenSource cts = new (TimeSpan.FromSeconds (timeoutSeconds.Value)); - - // Show terminal progress indicator counting down the timeout (OSC 9;4) - DateTime startTime = DateTime.UtcNow; - int totalMs = timeoutSeconds.Value * 1000; - - await using Timer progressTimer = new (_ => app.Invoke (_ => - { - var elapsedMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds; - int percent = Math.Min (elapsedMs * 100 / totalMs, 100); - app.Driver?.ProgressIndicator?.SetValue (percent); - }), - null, - 0, - 250); - - await app.RunAsync (wrapper, cts.Token); - - // Clear the progress indicator when done - progressTimer.Change (Timeout.Infinite, Timeout.Infinite); - app.Driver?.ProgressIndicator?.Clear (); -} -else -{ - // Run synchronously — blocks until user accepts or cancels - app.Run (wrapper); -} - -int? result = wrapper.Result; - -app.Dispose (); - -if (result is { } selectedIndex and >= 0 && selectedIndex < options.Count) -{ - Console.WriteLine (options [selectedIndex]); - - return 0; -} - -return 1; diff --git a/Examples/NativeAot/NativeAot.csproj b/Examples/NativeAot/NativeAot.csproj deleted file mode 100644 index ea28e087a6..0000000000 --- a/Examples/NativeAot/NativeAot.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - Exe - enable - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Examples/NativeAot/Program.cs b/Examples/NativeAot/Program.cs deleted file mode 100644 index 5b3675fe93..0000000000 --- a/Examples/NativeAot/Program.cs +++ /dev/null @@ -1,215 +0,0 @@ -// Native AOT test application for Terminal.Gui. -// -// This is an AOT-safe equivalent of UICatalog's AllViewsTester. It statically instantiates -// every IDesignable view and calls EnableForDesign() to populate demo data — exercising the -// config-property deep-cloning, JSON serialization, and dictionary construction paths that -// are most sensitive to AOT trimming. -// -// Unlike AllViewsView (which uses Activator.CreateInstance and MakeGenericType), this file -// constructs every view explicitly, making it safe for native AOT compilation. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using Terminal.Gui.Configuration; -using Terminal.Gui.Editor; -using UICatalog.Scenarios; - -namespace NativeAot; - -public static class Program -{ - private static async Task Main (string [] args) - { -#pragma warning disable IL2026, IL3050 - await RunAsync (args); -#pragma warning restore IL2026, IL3050 - } - - [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Init(IDriver, String)")] - [RequiresDynamicCode ("Calls Terminal.Gui.Application.Init(IDriver, String)")] - private static async Task RunAsync (string [] args) - { - bool smokeTest = args.Length > 0 && args [0] == "--smoke-test"; - - ConfigurationManager.Enable (ConfigLocations.All); - - IApplication app = Application.Create ().Init (); - - #region Localization sanity check - - if (Equals (Thread.CurrentThread.CurrentUICulture, CultureInfo.InvariantCulture) && Application.SupportedCultures!.Count == 0) - { - Debug.Assert (Application.SupportedCultures.Count == 0); - } - else - { - Debug.Assert (Application.SupportedCultures!.Count > 0); - Debug.Assert (Equals (CultureInfo.CurrentCulture, Thread.CurrentThread.CurrentUICulture)); - } - - #endregion - - if (smokeTest) - { - ExerciseDictionaryDeepCloning (); - - // CI smoke test: run the full app lifecycle with a timeout - using CancellationTokenSource cts = new (TimeSpan.FromSeconds (5)); - await app.RunAsync (cts.Token); - app.Dispose (); - Console.WriteLine ("AOT smoke test passed: full app lifecycle completed successfully."); - - return; - } - - app.Run (); - app.Dispose (); - } - - /// - /// To validate AOT compatibility of dictionary deep cloning, call DeepClone on key dictionaries. - /// - private static void ExerciseDictionaryDeepCloning () - { - _ = DeepCloner.DeepClone (Color.Colors16); - _ = DeepCloner.DeepClone (Application.DefaultKeyBindings); - _ = DeepCloner.DeepClone (View.DefaultKeyBindings); - _ = DeepCloner.DeepClone (View.ViewKeyBindings); - _ = DeepCloner.DeepClone (ThemeManager.Themes); - _ = DeepCloner.DeepClone (SchemeManager.Schemes); - } -} - -/// -/// AOT-safe mini AllViewsTester. Statically constructs every view -/// and calls to populate demo data, then displays -/// them in a scrollable list of titled frames. -/// -public sealed class AotAllViewsWindow : Runnable -{ - private const int MAX_HEIGHT = 12; - - public AotAllViewsWindow () - { - Title = $"AOT All Views ({Application.GetDefaultKey (Command.Quit)} to quit)"; - - // ── MenuBar (config host: MenuBar, Menu) ───────────────────── - MenuBar menuBar = new () - { - Menus = - [ - new MenuBarItem ("_File", [new MenuItem ("_Quit", "", () => App?.RequestStop ())]), - new MenuBarItem ("_Help", [new MenuItem ("_About", "", () => MessageBox.Query (App!, "About", "AOT All Views Tester", "OK"))]) - ] - }; - - // ── StatusBar (config host: StatusBar) ─────────────────────── - StatusBar statusBar = new (); - - // ── ViewPropertiesEditor (linked from UICatalog — no reflection, AOT-safe) ── - ViewPropertiesEditor propsEditor = new () - { - Title = "Properties", - Width = Dim.Percent (30), - Height = Dim.Fill (statusBar), - X = Pos.AnchorEnd (), - AutoSelectViewToEdit = true, - AutoSelectAdornments = false, - BorderStyle = LineStyle.Dotted - }; - - // ── Scrollable container for all views ─────────────────────── - View container = new () { Y = Pos.Bottom (menuBar), Width = Dim.Fill (propsEditor), Height = Dim.Fill (statusBar), CanFocus = true }; - - container.ViewportSettings |= ViewportSettingsFlags.HasVerticalScrollBar; - - container.ViewportChanged += (sender, _) => - { - if (sender is View sendingView) - { - sendingView.SetContentHeight (sendingView.GetHeightRequiredForSubViews ()); - } - }; - - // Scope auto-select to views within the container - propsEditor.AutoSelectSuperView = container; - - View? previous = null; - - foreach ((string name, View view) in CreateAllViews ()) - { - FrameView frame = new () - { - CanFocus = true, - Title = name, - Y = previous is { } ? Pos.Bottom (previous) : 0, - Width = Dim.Fill (), - Height = Dim.Auto (DimAutoStyle.Content, maximumContentDim: MAX_HEIGHT) - }; - - if (view.Width == Dim.Absolute (0)) - { - view.Width = Dim.Fill (); - } - - if (view.Height == Dim.Absolute (0)) - { - view.Height = MAX_HEIGHT - 2; - } - - frame.Add (view); - container.Add (frame); - previous = frame; - } - - Shortcut quitShortcut = new () { Text = "Quit", Key = Application.GetDefaultKey(Command.Quit), Action = RequestStop }; - - statusBar.Add (quitShortcut); - - Add (menuBar, container, propsEditor, statusBar); - } - - /// - /// Statically creates every view. No reflection, no - /// CreateInstance — fully AOT-safe. - /// - private static IEnumerable<(string Name, View View)> CreateAllViews () - { - // ── Core controls (IDesignable — EnableForDesign populates demo data) ── - yield return Design (new Button ()); - yield return Design (new ColorPicker ()); - yield return Design (new DropDownList ()); - yield return Design (new FlagSelector ()); - yield return Design (new GraphView ()); - yield return Design (new HexView ()); - yield return Design (new Link { Text = "Terminal.Gui on GitHub", Url = "https://github.com/gui-cs/Terminal.Gui" }); - yield return Design (new ListView ()); - yield return Design (new OptionSelector ()); - yield return Design (new ProgressBar ()); - yield return Design (new ScrollBar { Orientation = Orientation.Horizontal }); - yield return Design (new Shortcut ()); - yield return Design (new SpinnerView ()); - yield return Design (new Tabs ()); - yield return Design (new TextField ()); - yield return Design (new TextValidateField ()); - yield return Design (new Editor ()); - yield return Design (new TreeView ()); - - // ── Views without IDesignable (still AOT-relevant as config hosts or common views) ── - yield return (nameof (CharMap), new CharMap ()); - yield return (nameof (CheckBox), new CheckBox { Text = "Check me" }); - yield return (nameof (DatePicker), new DatePicker ()); - yield return (nameof (FrameView), new FrameView { Title = "FrameView", Text = "Content" }); - yield return (nameof (Label), new Label { Text = "This is a Label." }); - yield return (nameof (Line), new Line ()); - yield return (nameof (NumericUpDown), new NumericUpDown ()); - } - - private static (string Name, View View) Design (T view) where T : View, IDesignable - { - view.EnableForDesign (); - - return (typeof (T).Name, view); - } -} diff --git a/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml b/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml deleted file mode 100644 index c883267bf0..0000000000 --- a/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Debug - Any CPU - bin\Debug\net8.0\publish\win-x64\ - FileSystem - <_TargetId>Folder - net8.0 - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml b/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml deleted file mode 100644 index 79576fb52f..0000000000 --- a/Examples/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Release - Any CPU - bin\Release\net8.0\publish\win-x64\ - FileSystem - <_TargetId>Folder - net8.0 - win-x64 - true - false - false - - \ No newline at end of file diff --git a/Examples/NativeAot/Properties/launchSettings.json b/Examples/NativeAot/Properties/launchSettings.json deleted file mode 100644 index a7872f0012..0000000000 --- a/Examples/NativeAot/Properties/launchSettings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "profiles": { - "NativeAot": { - "commandName": "Project" - }, - "WSL : NativeAot": { - "commandName": "Executable", - "executablePath": "wsl", - "commandLineArgs": "dotnet NativeAot.dll", - "distributionName": "" - } - } -} \ No newline at end of file diff --git a/Examples/NativeAot/Publish_linux-x64_Debug.sh b/Examples/NativeAot/Publish_linux-x64_Debug.sh deleted file mode 100644 index 3b537fcf1c..0000000000 --- a/Examples/NativeAot/Publish_linux-x64_Debug.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -dotnet clean -c Debug -dotnet build -c Debug -dotnet publish -c Debug -r linux-x64 --self-contained diff --git a/Examples/NativeAot/Publish_linux-x64_Release.sh b/Examples/NativeAot/Publish_linux-x64_Release.sh deleted file mode 100644 index 5179907a8c..0000000000 --- a/Examples/NativeAot/Publish_linux-x64_Release.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -dotnet clean -c Release -dotnet build -c Release -dotnet publish -c Release -r linux-x64 --self-contained diff --git a/Examples/NativeAot/Publish_osx-x64_Debug.sh b/Examples/NativeAot/Publish_osx-x64_Debug.sh deleted file mode 100644 index 9470c7edff..0000000000 --- a/Examples/NativeAot/Publish_osx-x64_Debug.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -dotnet clean -c Debug -dotnet build -c Debug -dotnet publish -c Debug -r osx-x64 --self-contained diff --git a/Examples/NativeAot/Publish_osx-x64_Release.sh b/Examples/NativeAot/Publish_osx-x64_Release.sh deleted file mode 100644 index bfeaedf9cd..0000000000 --- a/Examples/NativeAot/Publish_osx-x64_Release.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -dotnet clean -c Release -dotnet build -c Release -dotnet publish -c Release -r osx-x64 --self-contained diff --git a/Examples/NativeAot/README.md b/Examples/NativeAot/README.md deleted file mode 100644 index 3b469a1738..0000000000 --- a/Examples/NativeAot/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Terminal.Gui Native AOT Example - -This project is an **AOT-safe mini AllViewsTester**. Unlike UICatalog's `AllViewsView` (which -uses `Activator.CreateInstance` and `MakeGenericType`), this example statically constructs every -`IDesignable` view and calls `EnableForDesign()` to populate demo data. - -## What it exercises - -Every view type that implements `IDesignable` is instantiated and displayed in a scrollable -list of titled frames. This exercises the full configuration initialization pipeline — -`ConfigurationManager.Initialize`, `DeepCloner`, `SourceGenerationContext`, and all -config-property-hosting types — under actual AOT trimming. - -A `ViewPropertiesEditor` panel (linked from UICatalog's `EditorsAndHelpers/` — no copy, -no reflection) lets you edit properties of the focused view. This proves the editor -infrastructure is also AOT-safe. - -Views tested: `Button`, `CheckBox`, `ColorPicker`, `DatePicker`, `DropDownList`, -`FlagSelector`, `GraphView`, `HexView`, `Label`, `Line`, `Link`, `ListView`, -`NumericUpDown`, `OptionSelector`, `ProgressBar`, `ScrollBar`, `Shortcut`, `SpinnerView`, -`Tabs`, `TextField`, `TextValidateField`, `Editor`, `TreeView`, `CharMap`, `FrameView`, -`MenuBar`, `Menu`, `StatusBar`, `MessageBox` (via dialog), `Dialog` (via `Wizard` base). - -## Publishing - -Native AOT publishing must target the same platform as the host. Cross-compilation is not -supported. - -```bash -# Linux -dotnet publish -c Release -r linux-x64 --self-contained - -# macOS -dotnet publish -c Release -r osx-x64 --self-contained - -# Windows -dotnet publish -c Release -r win-x64 --self-contained -``` - -## Debugging - -To debug the native AOT binary, attach to the process and select `Native Code`. \ No newline at end of file diff --git a/Examples/PowershellExample.ps1 b/Examples/PowershellExample.ps1 deleted file mode 100644 index ceb5fd52fa..0000000000 --- a/Examples/PowershellExample.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -using namespace Terminal.Gui.App -using namespace Terminal.Gui.ViewBase -using namespace Terminal.Gui.Views - -$dllFolder = "..\Terminal.Gui\bin\Debug\net8.0" - -# For this to work all dependent DLLs need to be in the $dllFolder folder -# Do this first: -# dotnet build -c Debug /p:CopyLocalLockFileAssemblies=true - -Get-ChildItem $dllFolder -Filter *.dll | ForEach-Object { - Add-Type -Path $_.FullName -ErrorAction SilentlyContinue -} - -$app = [Application]::Create() - -$app.Init() - -$win = [Window]@{ - Title = "Terminal.Gui in Powershell" - Width = [Dim]::Fill() - Height = [Dim]::Fill() -} - -$lbl = [Label]@{ - Text = "Hello from PowerShell + Terminal.Gui!`nPress ESC to quit" - X = [Pos]::Center() - Y = [Pos]::Center() -} -$win.Add($lbl) - -$app.Run($win) - -$win.Dispose() -$app.Dispose() diff --git a/Examples/PromptExample/Program.cs b/Examples/PromptExample/Program.cs deleted file mode 100644 index 3b0756066e..0000000000 --- a/Examples/PromptExample/Program.cs +++ /dev/null @@ -1,302 +0,0 @@ -// Example demonstrating the Prompt API for getting typed input from users -// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command -// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output, -// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike. - -using Terminal.Gui.App; -using Terminal.Gui.Configuration; -using Terminal.Gui.Drawing; -using Terminal.Gui.Drivers; -using Terminal.Gui.Editor; -using Terminal.Gui.Resources; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Views; -using Color = Terminal.Gui.Drawing.Color; - -// ReSharper disable AccessToDisposedClosure - -ConfigurationManager.Enable (ConfigLocations.All); -using IApplication app = Application.Create ().Init (DriverRegistry.Names.DOTNET); - -// Create a main window to host the prompts -using Window mainWindow = new (); -mainWindow.Title = "Prompt API Examples (Esc to quit)"; -mainWindow.Text = "This example demonstrates various uses of the Prompt API.\nPress the buttons to try different prompt types.\nPress Esc to quit."; -mainWindow.TextAlignment = Alignment.Center; - -// Initial Value TextField — entered text is applied to prompt views via IValue.TrySetValueFromString -TextField initialValueField = new () -{ - Title = "Initial _Value (TrySetValueFromString)", - X = 0, - Y = 0, - Width = Dim.Fill (), - BorderStyle = LineStyle.Dotted -}; -mainWindow.Add (initialValueField); - -var buttonY = 2; - -// Example 1: TextField with string result using auto-Text extraction -Button textFieldButton = new () { Title = "TextField (Auto-Text)", X = Pos.Center (), Y = buttonY++ }; - -textFieldButton.Accepting += (_, _) => - { - string? result = mainWindow.Prompt (beginInitHandler: prompt => - { - prompt.Title = textFieldButton.Title; - prompt.GetWrappedView ().Width = 40; - prompt.GetWrappedView ().Text = "Default name"; - - if (!string.IsNullOrEmpty (initialValueField.Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField.Text); - } - }); - - MessageBox.Query (app, textFieldButton.Title, result is { } ? $"You entered: {result}" : "Canceled", Strings.btnOk); - }; - -mainWindow.Add (textFieldButton); - -// Example 1: TextField with string result using auto-Text extraction -Button editorButton = new () { Title = "Editor (Auto-Text)", X = Pos.Center (), Y = buttonY++ }; - -editorButton.Accepting += (_, _) => - { - string? result = mainWindow.Prompt (beginInitHandler: prompt => - { - prompt.Title = editorButton.Title; - - prompt.GetWrappedView ().Text = "Some text\nis nice."; - prompt.GetWrappedView ().Width = Dim.Fill (0, 40); - prompt.GetWrappedView ().Height = Dim.Fill (0, 8); - - if (!string.IsNullOrEmpty (initialValueField.Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField.Text); - } - }); - - MessageBox.Query (app, editorButton.Title, result is { } ? $"You entered: {result}" : "Canceled", Strings.btnOk); - }; - -mainWindow.Add (editorButton); - -// Example 2: DatePicker with DateTime result -Button datePickerButton = new () { Title = "DatePicker (Typed Result)", X = Pos.Center (), Y = buttonY++ }; - -datePickerButton.Accepting += (_, _) => - { - DateTime? result = mainWindow.Prompt (resultExtractor: dp => dp.Value, - beginInitHandler: prompt => - { - prompt.Title = "Select a Date"; - prompt.GetWrappedView ().Value = DateTime.Now; - - if (!string.IsNullOrEmpty (initialValueField.Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField.Text); - } - }); - - if (result is { } selectedDate) - { - MessageBox.Query (app, datePickerButton.Title, $"You selected: {selectedDate:yyyy-MM-dd}", Strings.btnOk); - } - else - { - MessageBox.Query (app, datePickerButton.Title, "Canceled", Strings.btnOk); - } - }; - -mainWindow.Add (datePickerButton); - -// Example 3: ColorPicker with Color result -Button colorPickerButton = new () { Title = "ColorPicker (Typed Result)", X = Pos.Center (), Y = buttonY++ }; - -colorPickerButton.Accepting += (_, _) => - { - Color? result = mainWindow.Prompt (input: null, - beginInitHandler: prompt => - { - prompt.Title = "Pick a Color"; - - if (!string.IsNullOrEmpty (initialValueField.Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField.Text); - } - }); - - if (result is { } selectedColor) - { - MessageBox.Query (app, colorPickerButton.Title, $"You selected: {selectedColor}", Strings.btnOk); - } - else - { - MessageBox.Query (app, colorPickerButton.Title, "Canceled", Strings.btnOk); - } - }; - -mainWindow.Add (colorPickerButton); - -// Example 4: ColorPicker with auto-Text extraction -Button colorTextButton = new () { Title = "ColorPicker (Auto-Text)", X = Pos.Center (), Y = buttonY++ }; - -colorTextButton.Accepting += (_, _) => - { - string? result = mainWindow.Prompt (beginInitHandler: prompt => - { - prompt.Title = "Pick a Color (as text)"; - prompt.GetWrappedView ().SelectedColor = Color.Red; - - if (!string.IsNullOrEmpty (initialValueField.Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField.Text); - } - }); - - MessageBox.Query (app, colorTextButton.Title, result is { } ? $"Color as text: {result}" : "Canceled", Strings.btnOk); - }; - -mainWindow.Add (colorTextButton); - -// Example 5: Pre-created view -Button preCreatedButton = new () { Title = "Pre-Created TextField", X = Pos.Center (), Y = buttonY++ }; - -preCreatedButton.Accepting += (_, _) => - { - // Pre-create and configure the view - TextField textField = new () { Width = 50, Text = "Pre-configured text" }; - - string? result = mainWindow.Prompt (textField, - field => field.Text, - beginInitHandler: prompt => - { - prompt.Title = preCreatedButton.Title; - prompt.BorderStyle = LineStyle.Rounded; - }); - - if (result is { }) - { - MessageBox.Query (app, preCreatedButton.Title, $"You entered: {result}", Strings.btnOk); - } - }; - -mainWindow.Add (preCreatedButton); - -// Example 6: Custom form with complex result extraction -Button customFormButton = new () { Title = "Custom Form", X = Pos.Center (), Y = buttonY++ }; - -customFormButton.Accepting += (_, _) => - { - View formView = CreateCustomForm (); - - FormData? result = mainWindow.Prompt (formView, - ExtractFormData, - beginInitHandler: prompt => { prompt.Title = "User Information Form"; }); - - if (result is { }) - { - MessageBox.Query (app, - customFormButton.Title, - $"Name: {result.Name}\nAge: {result.Age}\nAgreed: {result.Agreed}", - Strings.btnOk); - } - else - { - MessageBox.Query (app, "Form canceled", Strings.btnOk); - } - }; - -mainWindow.Add (customFormButton); - -// Example 7: FlagSelector with enum result -Button flagSelectorButton = new () { Title = "FlagSelector (Enum Result)", X = Pos.Center (), Y = buttonY++ }; - -flagSelectorButton.Accepting += (_, _) => - { - SelectorStyles? result = - mainWindow.Prompt, SelectorStyles> (resultExtractor: fs => fs.Value!.Value, - beginInitHandler: prompt => - { - prompt.Title = "Choose Selector Styles"; - - if (!string.IsNullOrEmpty (initialValueField - .Text)) - { - ((IValue)prompt.GetWrappedView ()) - .TrySetValueFromString (initialValueField - .Text); - } - }); - - if (result is { } styles) - { - MessageBox.Query (app, flagSelectorButton.Title, $"Selected styles: {styles}", Strings.btnOk); - } - else - { - MessageBox.Query (app, flagSelectorButton.Title, "Canceled", Strings.btnOk); - } - }; - -mainWindow.Add (flagSelectorButton); - -// Add a quit button -Button quitButton = new () { Title = "Quit", X = Pos.Center (), Y = Pos.AnchorEnd () }; - -quitButton.Accepting += (_, _) => app.RequestStop (); -mainWindow.Add (quitButton); - -app.Run (mainWindow); - -return; - -// Helper method to create a custom form -View CreateCustomForm () -{ - View form = new () { Width = 50, Height = 10 }; - - TextField nameField = new () { Id = "nameField", X = 10, Y = 1, Width = 30 }; - - TextField ageField = new () { Id = "ageField", X = 10, Y = 3, Width = 10 }; - - CheckBox agreeCheckbox = new () { Id = "agreeCheckbox", Title = "I agree to terms", X = 10, Y = 5 }; - - form.Add (new Label { Text = "Name:", X = 2, Y = 1 }); - form.Add (nameField); - form.Add (new Label { Text = "Age:", X = 2, Y = 3 }); - form.Add (ageField); - form.Add (agreeCheckbox); - - return form; -} - -// Helper method to extract data from the custom form -FormData ExtractFormData (View form) -{ - var nameField = form.SubViews.FirstOrDefault (v => v.Id == "nameField") as TextField; - var ageField = form.SubViews.FirstOrDefault (v => v.Id == "ageField") as TextField; - var agreeCheckbox = form.SubViews.FirstOrDefault (v => v.Id == "agreeCheckbox") as CheckBox; - - return new FormData - { - Name = nameField?.Text ?? string.Empty, - Age = int.TryParse (ageField?.Text, out int age) ? age : 0, - Agreed = agreeCheckbox?.Value == CheckState.Checked - }; -} - -// Result type for custom form -internal record FormData -{ - public int Age { get; init; } - public bool Agreed { get; init; } - public string Name { get; init; } = string.Empty; -} diff --git a/Examples/PromptExample/PromptExample.csproj b/Examples/PromptExample/PromptExample.csproj deleted file mode 100644 index 6fa83eeabb..0000000000 --- a/Examples/PromptExample/PromptExample.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net10.0 - enable - enable - latest - - - - - - - - - - - diff --git a/Examples/README.md b/Examples/README.md index 0f6aa383ff..03b80054f6 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -1,3 +1,8 @@ # Terminal.Gui Examples -This directory contains example applications demonstrating Terminal.Gui. Each example has its own README with usage details and documentation. +This repository now keeps only: + +- `UICatalog` - the main demo app +- `ScenarioRunner` - scenario automation tool + +All other examples were moved to the [gui-cs/Examples](https://github.com/gui-cs/Examples) repository. diff --git a/Examples/ReactiveExample/LoginView.cs b/Examples/ReactiveExample/LoginView.cs deleted file mode 100644 index 9cceecde66..0000000000 --- a/Examples/ReactiveExample/LoginView.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System.Reactive.Disposables; -using System.Reactive.Disposables.Fluent; -using System.Reactive.Linq; -using ReactiveMarbles.ObservableEvents; -using ReactiveUI; -using Terminal.Gui.Configuration; -using Terminal.Gui.Views; -using Terminal.Gui.App; -using Terminal.Gui.ViewBase; -using Terminal.Gui.Input; - -namespace ReactiveExample; - -public class LoginView : Window, IViewFor -{ - private const string SuccessMessage = "The input is valid!"; - private const string ErrorMessage = "Please enter a valid user name and password."; - private const string ProgressMessage = "Logging in..."; - private const string IdleMessage = "Press 'Login' to log in."; - - private readonly CompositeDisposable _disposable = []; - - public LoginView (LoginViewModel viewModel) - { - Title = $"Reactive Extensions Example - {Application.GetDefaultKey (Command.Quit)} to Exit"; - ViewModel = viewModel; - var title = this.AddControl