|
@@ -1,380 +1,970 @@
|
|
|
-# Configuration Management
|
|
|
|
|
|
|
+# Configuration Management Deep Dive
|
|
|
|
|
|
|
|
-Terminal.Gui provides persistent configuration settings via the [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) class.
|
|
|
|
|
|
|
+Terminal.Gui provides a comprehensive configuration system that allows users and developers to customize application behavior and appearance through JSON configuration files. The [ConfigurationManager](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) enables persistent settings, themes, and application-specific preferences.
|
|
|
|
|
|
|
|
-## Configuration Lexicon and Taxonomy
|
|
|
|
|
|
|
+## Table of Contents
|
|
|
|
|
|
|
|
-[!INCLUDE [Config Lexicon](~/includes/config-lexicon.md)]
|
|
|
|
|
|
|
+- [Overview](#overview)
|
|
|
|
|
+- [Getting Started](#getting-started)
|
|
|
|
|
+- [Configuration Scopes](#configuration-scopes)
|
|
|
|
|
+- [Configuration Locations and Precedence](#configuration-locations-and-precedence)
|
|
|
|
|
+- [Themes and Schemes](#themes-and-schemes)
|
|
|
|
|
+- [Defining Configuration Properties](#defining-configuration-properties)
|
|
|
|
|
+- [Loading and Applying Configuration](#loading-and-applying-configuration)
|
|
|
|
|
+- [Events](#events)
|
|
|
|
|
+- [What Can Be Configured](#what-can-be-configured)
|
|
|
|
|
+- [Configuration File Format](#configuration-file-format)
|
|
|
|
|
+- [Best Practices](#best-practices)
|
|
|
|
|
|
|
|
-# Fundamentals
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-The `ConfigurationManager` class provides a way to store and retrieve configuration settings for an application. The configuration is stored in JSON documents, which can be located in the user's home directory, the current working directory, in memory, or as a resource within the application's main assembly.
|
|
|
|
|
|
|
+## Overview
|
|
|
|
|
|
|
|
-Settings are defined in JSON format, according to this schema: https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json.
|
|
|
|
|
|
|
+The [ConfigurationManager](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) provides:
|
|
|
|
|
|
|
|
-Terminal.Gui library developers can define settings in code and set the default values in the Terminal.Gui assembly's resources (e.g. `Terminal.Gui.Resources.config.json`).
|
|
|
|
|
|
|
+- **Persistent Settings** - User preferences stored in JSON files
|
|
|
|
|
+- **Theme System** - Named collections of visual settings
|
|
|
|
|
+- **Scheme Management** - Color and text style definitions
|
|
|
|
|
+- **Configuration Precedence** - Layered configuration from multiple sources
|
|
|
|
|
+- **Runtime Configuration** - In-memory configuration without files
|
|
|
|
|
+- **AOT Compatible** - Works with Native AOT compilation
|
|
|
|
|
|
|
|
-Terminal.Gui application developers can define settings in their apps' code and set the default values in their apps' resources (e.g. `Resources/config.json`) or by setting @Terminal.Gui.Configuration.ConfigurationManager.RuntimeConfig to string containing JSON.
|
|
|
|
|
|
|
+### Key Features
|
|
|
|
|
|
|
|
-Users can change settings on a global or per-application basis by providing JSON formatted configuration files. The configuration files can be placed in at .tui folder in the user's home directory (e.g. `C:/Users/username/.tui`, or `/usr/username/.tui`) or the folder where the Terminal.Gui application was launched from (e.g. `./.tui`).
|
|
|
|
|
|
|
+- JSON-based configuration with schema validation
|
|
|
|
|
+- Multiple configuration locations (user home, app directory, resources)
|
|
|
|
|
+- Process-wide settings using static properties
|
|
|
|
|
+- Built-in themes (Default, Dark, Light, etc.)
|
|
|
|
|
+- Custom glyphs and Unicode characters
|
|
|
|
|
+- Event-driven configuration changes
|
|
|
|
|
|
|
|
-## CM is Disabled by Default
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-The `ConfigurationManager` must be enabled explicitly by calling @Terminal.Gui.Configuration.ConfigurationManager.Enable(Terminal.Gui.Configuration.ConfigLocations) in an application's `Main` method.
|
|
|
|
|
|
|
+## Getting Started
|
|
|
|
|
|
|
|
-```csharp
|
|
|
|
|
-// Enable configuration with all sources
|
|
|
|
|
-ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
-```
|
|
|
|
|
|
|
+### Enabling Configuration
|
|
|
|
|
|
|
|
-If `ConfigurationManager.Enable()` is not called (`ConfigurationManager.IsEnabled` is 'false'), all configuration settings are ignored and ConfigurationManager will effectively be a no-op. All `[ConfigurationProperty]` properties will initially be their hard-coded default values.
|
|
|
|
|
|
|
+**ConfigurationManager is disabled by default** and must be explicitly enabled:
|
|
|
|
|
|
|
|
-Other than that, no other ConfigurationManager APIs will have any effect.
|
|
|
|
|
-
|
|
|
|
|
-## Loading and Applying Configuration
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+using Terminal.Gui.Configuration;
|
|
|
|
|
|
|
|
-Optionally, developers can more granularly control the loading and applying of configuration by calling the `Load` and `Apply` methods directly.
|
|
|
|
|
|
|
+class Program
|
|
|
|
|
+{
|
|
|
|
|
+ static void Main()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Enable configuration with all sources
|
|
|
|
|
+ ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+
|
|
|
|
|
+ Application.Init();
|
|
|
|
|
+ // ... rest of app
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-When a configuration has been loaded, the @Terminal.Gui.Configuration.ConfigurationManager.Apply method must be called to apply the settings to the application. This method uses reflection to find all static fields decorated with the `[ConfigurationProperty]` attribute and applies the settings to the corresponding properties.
|
|
|
|
|
|
|
+### Quick Example
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-// Load the configuration from just the users home directory.
|
|
|
|
|
-ConfigurationManager.Enable(ConfigLocations.HardCoded);
|
|
|
|
|
-ConfigurationManager.Load(ConfigLocations.GlobalHome);
|
|
|
|
|
|
|
+// Enable configuration
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+
|
|
|
|
|
+// Listen for configuration changes
|
|
|
|
|
+ConfigurationManager.Applied += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ Console.WriteLine("Configuration applied!");
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// Switch themes
|
|
|
|
|
+ThemeManager.Theme = "Dark";
|
|
|
ConfigurationManager.Apply();
|
|
ConfigurationManager.Apply();
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-> [!IMPORTANT]
|
|
|
|
|
-> Configuration Settings Apply at the Process Level.
|
|
|
|
|
-> Configuration settings are applied at the process level, which means that they are applied to all applications that are part of the same process. This is due to the fact that configuration properties are defined as static fields, which are static for the process.
|
|
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Configuration Scopes
|
|
|
|
|
|
|
|
-## Configuration Types and Scopes
|
|
|
|
|
|
|
+Terminal.Gui uses three configuration scopes, each serving a different purpose:
|
|
|
|
|
|
|
|
-Terminal.Gui supports three main configuration scopes. See the section below titled [What Can Be Configured](#what-can-be-configured) for more details.
|
|
|
|
|
|
|
+### 1. SettingsScope
|
|
|
|
|
|
|
|
-### SettingsScope
|
|
|
|
|
|
|
+System-level settings that affect Terminal.Gui behavior. Only Terminal.Gui library developers can define [SettingsScope](~/api/Terminal.Gui.Configuration.SettingsScope.yml) properties.
|
|
|
|
|
|
|
|
-System-level settings that affect Terminal.Gui behavior:
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-[ConfigurationProperty (Scope = typeof (SettingsScope))]
|
|
|
|
|
-public static int MaxSearchResults { get; set; } = 10000;
|
|
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(SettingsScope))]
|
|
|
|
|
+public static bool Force16Colors { get; set; } = false;
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### ThemeScope
|
|
|
|
|
-Visual appearance settings that can be themed:
|
|
|
|
|
|
|
+**Examples:**
|
|
|
|
|
+- `Application.QuitKey` - Default key to quit applications
|
|
|
|
|
+- `Application.Force16Colors` - Force 16-color mode
|
|
|
|
|
+- `Key.Separator` - Character separating keys in key combinations
|
|
|
|
|
+
|
|
|
|
|
+### 2. ThemeScope
|
|
|
|
|
+
|
|
|
|
|
+Visual appearance settings that can be themed. Only Terminal.Gui library developers can define [ThemeScope](~/api/Terminal.Gui.Configuration.ThemeScope.yml) properties.
|
|
|
|
|
+
|
|
|
```csharp
|
|
```csharp
|
|
|
- [ConfigurationProperty (Scope = typeof (ThemeScope))]
|
|
|
|
|
- public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
|
|
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(ThemeScope))]
|
|
|
|
|
+public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### AppSettingsScope (default)
|
|
|
|
|
-Application-specific settings:
|
|
|
|
|
|
|
+**Examples:**
|
|
|
|
|
+- `Window.DefaultBorderStyle` - Default border style for windows
|
|
|
|
|
+- `Dialog.DefaultShadow` - Default shadow style for dialogs
|
|
|
|
|
+- `Schemes` - Color schemes for the theme
|
|
|
|
|
+
|
|
|
|
|
+### 3. AppSettingsScope (Default)
|
|
|
|
|
+
|
|
|
|
|
+Application-specific settings. Application developers can define [AppSettingsScope](~/api/Terminal.Gui.Configuration.AppSettingsScope.yml) properties for their apps.
|
|
|
|
|
+
|
|
|
```csharp
|
|
```csharp
|
|
|
[ConfigurationProperty] // AppSettingsScope is default
|
|
[ConfigurationProperty] // AppSettingsScope is default
|
|
|
-public static string MyAppSetting { get; set; } = "default";
|
|
|
|
|
|
|
+public static string MyAppSetting { get; set; } = "default value";
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Configuration Precedence
|
|
|
|
|
|
|
+**Important:**
|
|
|
|
|
+- App developers **cannot** define `SettingsScope` or `ThemeScope` properties
|
|
|
|
|
+- AppSettings property names must be globally unique (automatically prefixed with class name)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Configuration Locations and Precedence
|
|
|
|
|
+
|
|
|
|
|
+Configuration is loaded from multiple locations with increasing precedence (higher numbers override lower):
|
|
|
|
|
+
|
|
|
|
|
+### ConfigLocations Enum
|
|
|
|
|
+
|
|
|
|
|
+[ConfigLocations](~/api/Terminal.Gui.Configuration.ConfigLocations.yml) specifies where configuration can be loaded from:
|
|
|
|
|
+
|
|
|
|
|
+1. **[ConfigLocations.HardCoded](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)** (Lowest Precedence)
|
|
|
|
|
+ - Default values in code (static property initializers)
|
|
|
|
|
+ - Always available, even when ConfigurationManager is disabled
|
|
|
|
|
+
|
|
|
|
|
+2. **[ConfigLocations.LibraryResources](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - Settings in `Terminal.Gui.dll` resources (`Terminal.Gui.Resources.config.json`)
|
|
|
|
|
+ - Defines default themes and settings for the library
|
|
|
|
|
+
|
|
|
|
|
+3. **[ConfigLocations.Runtime](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - Settings in [ConfigurationManager.RuntimeConfig](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml#Terminal_Gui_Configuration_ConfigurationManager_RuntimeConfig) string property
|
|
|
|
|
+ - In-memory configuration without files
|
|
|
|
|
+
|
|
|
|
|
+4. **[ConfigLocations.AppResources](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - App-specific resources (`MyApp.Resources.config.json` or `Resources/config.json`)
|
|
|
|
|
+ - Embedded in the application assembly
|
|
|
|
|
+
|
|
|
|
|
+5. **[ConfigLocations.AppHome](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - App-specific file in user's home directory (`~/.tui/MyApp.config.json`)
|
|
|
|
|
+
|
|
|
|
|
+6. **[ConfigLocations.AppCurrent](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - App-specific file in current directory (`./.tui/MyApp.config.json`)
|
|
|
|
|
+
|
|
|
|
|
+7. **[ConfigLocations.GlobalHome](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)**
|
|
|
|
|
+ - Global file in user's home directory (`~/.tui/config.json`)
|
|
|
|
|
+
|
|
|
|
|
+8. **[ConfigLocations.GlobalCurrent](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)** (Highest Precedence)
|
|
|
|
|
+ - Global file in current directory (`./.tui/config.json`)
|
|
|
|
|
+
|
|
|
|
|
+### Precedence Diagram
|
|
|
|
|
|
|
|
```mermaid
|
|
```mermaid
|
|
|
graph TD
|
|
graph TD
|
|
|
- A[Hard-coded Defaults] --> B[Terminal.Gui Defaults]
|
|
|
|
|
- B --> C[Runtime Config]
|
|
|
|
|
- C --> D[App Resources]
|
|
|
|
|
- D --> E[App Home Directory]
|
|
|
|
|
- E --> F[App Current Directory]
|
|
|
|
|
- F --> G[Global Home Directory]
|
|
|
|
|
- G --> H[Global Current Directory]
|
|
|
|
|
|
|
+ A[1. Hard-coded Defaults] --> B[2. Library Resources]
|
|
|
|
|
+ B --> C[3. Runtime Config]
|
|
|
|
|
+ C --> D[4. App Resources]
|
|
|
|
|
+ D --> E[5. App Home Directory]
|
|
|
|
|
+ E --> F[6. App Current Directory]
|
|
|
|
|
+ F --> G[7. Global Home Directory]
|
|
|
|
|
+ G --> H[8. Global Current Directory]
|
|
|
|
|
+
|
|
|
|
|
+ style A fill:#f9f9f9
|
|
|
|
|
+ style H fill:#90EE90
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Settings are applied using the following precedence (higher precedence settings overwrite lower precedence settings):
|
|
|
|
|
|
|
+### File Locations
|
|
|
|
|
|
|
|
-1. @Terminal.Gui.Configuration.ConfigLocations.HardCoded Hard-coded default values in any static property decorated with the `[ConfigurationProperty]` attribute.
|
|
|
|
|
|
|
+**Global Settings** (`config.json`):
|
|
|
|
|
+- Windows: `C:\Users\username\.tui\config.json`
|
|
|
|
|
+- macOS/Linux: `~/.tui/config.json` or `./.tui/config.json`
|
|
|
|
|
|
|
|
-2. @Terminal.Gui.Configuration.ConfigLocations.LibraryResources - Default settings in the Terminal.Gui assembly -- Lowest precedence.
|
|
|
|
|
|
|
+**App-Specific Settings** (`AppName.config.json`):
|
|
|
|
|
+- Windows: `C:\Users\username\.tui\UICatalog.config.json`
|
|
|
|
|
+- macOS/Linux: `~/.tui/UICatalog.config.json` or `./.tui/UICatalog.config.json`
|
|
|
|
|
|
|
|
-3. @Terminal.Gui.Configuration.ConfigLocations.Runtime - Settings stored in the @Terminal.Gui.Configuration.ConfigurationManager.RuntimeConfig static property.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-4. @Terminal.Gui.Configuration.ConfigLocations.AppResources - App settings in app resources (`Resources/config.json`).
|
|
|
|
|
|
|
+## Themes and Schemes
|
|
|
|
|
|
|
|
-5. @Terminal.Gui.Configuration.ConfigLocations.AppHome - App-specific settings in the users's home directory (`~/.tui/appname.config.json`).
|
|
|
|
|
|
|
+### Theme System
|
|
|
|
|
|
|
|
-6. @Terminal.Gui.Configuration.ConfigLocations.AppCurrent - App-specific settings in the directory the app was launched from (`./.tui/appname.config.json`).
|
|
|
|
|
|
|
+A **Theme** is a named collection of visual settings bundled together. Terminal.Gui includes several built-in themes.
|
|
|
|
|
|
|
|
-7. @Terminal.Gui.Configuration.ConfigLocations.GlobalHome - Global settings in the the user's home directory (`~/.tui/config.json`).
|
|
|
|
|
|
|
+#### Built-in Themes
|
|
|
|
|
|
|
|
-8. @Terminal.Gui.Configuration.ConfigLocations.GlobalCurrent - Global settings in the directory the app was launched from (`./.tui/config.json`) --- Hightest precedence.
|
|
|
|
|
|
|
+- **Default** - The default Terminal.Gui theme (matches hard-coded defaults)
|
|
|
|
|
+- **Dark** - Dark color scheme with heavy borders
|
|
|
|
|
+- **Light** - Light color scheme
|
|
|
|
|
+- **TurboPascal 5** - Classic Turbo Pascal IDE colors
|
|
|
|
|
+- **And more** - See `Terminal.Gui/Resources/config.json` for all built-in themes
|
|
|
|
|
|
|
|
|
|
+#### Using Themes
|
|
|
|
|
|
|
|
-The [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) will look for configuration files in the `.tui` folder in the user's home directory (e.g. `C:/Users/username/.tui` or `/usr/username/.tui`), the folder where the Terminal.Gui application was launched from (e.g. `./.tui`), or as a resource within the Terminal.Gui application's main assembly.
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Get current theme
|
|
|
|
|
+ThemeScope currentTheme = ThemeManager.GetCurrentTheme();
|
|
|
|
|
|
|
|
-Settings that will apply to all applications (global settings) reside in files named `config.json`. Settings that will apply to a specific Terminal.Gui application reside in files named `appname.config.json`, where *appname* is the assembly name of the application (e.g. `UICatalog.config.json`).
|
|
|
|
|
|
|
+// Get all available themes
|
|
|
|
|
+Dictionary<string, ThemeScope> themes = ThemeManager.GetThemes();
|
|
|
|
|
+
|
|
|
|
|
+// Get theme names
|
|
|
|
|
+ImmutableList<string> themeNames = ThemeManager.GetThemeNames();
|
|
|
|
|
|
|
|
|
|
+// Switch themes
|
|
|
|
|
+ThemeManager.Theme = "Dark";
|
|
|
|
|
+ConfigurationManager.Apply();
|
|
|
|
|
|
|
|
-## Configuration Events
|
|
|
|
|
|
|
+// Listen for theme changes
|
|
|
|
|
+ThemeManager.ThemeChanged += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Update UI based on new theme
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-The ConfigurationManager provides several events to track configuration changes:
|
|
|
|
|
|
|
+### Scheme System
|
|
|
|
|
+
|
|
|
|
|
+A **Scheme** defines the colors and text styles for a specific UI context (e.g., Dialog, Menu, TopLevel).
|
|
|
|
|
+
|
|
|
|
|
+See the [Scheme Deep Dive](scheme.md) for complete details on the scheme system.
|
|
|
|
|
+
|
|
|
|
|
+#### Built-in Schemes
|
|
|
|
|
+
|
|
|
|
|
+[Schemes](~/api/Terminal.Gui.Drawing.Schemes.yml) enum defines the standard schemes:
|
|
|
|
|
+
|
|
|
|
|
+- **TopLevel** - Top-level application windows
|
|
|
|
|
+- **Base** - Default for most views
|
|
|
|
|
+- **Dialog** - Dialogs and message boxes
|
|
|
|
|
+- **Menu** - Menus and status bars
|
|
|
|
|
+- **Error** - Error messages and dialogs
|
|
|
|
|
+
|
|
|
|
|
+#### Working with Schemes
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-// Called after configuration is applied
|
|
|
|
|
-ConfigurationManager.Applied += (sender, e) => {
|
|
|
|
|
- // Handle configuration changes
|
|
|
|
|
-};
|
|
|
|
|
|
|
+// Get all schemes for current theme
|
|
|
|
|
+Dictionary<string, Scheme> schemes = SchemeManager.GetCurrentSchemes();
|
|
|
|
|
+
|
|
|
|
|
+// Get specific scheme
|
|
|
|
|
+Scheme dialogScheme = SchemeManager.GetScheme(Schemes.Dialog);
|
|
|
|
|
|
|
|
-// Called when the active theme changes
|
|
|
|
|
-ConfigurationManager.ThemeChanged += (sender, e) => {
|
|
|
|
|
- // Handle theme changes
|
|
|
|
|
|
|
+// Get scheme names
|
|
|
|
|
+ImmutableList<string> schemeNames = SchemeManager.GetSchemeNames();
|
|
|
|
|
+
|
|
|
|
|
+// Add custom scheme
|
|
|
|
|
+SchemeManager.AddScheme("MyScheme", new Scheme
|
|
|
|
|
+{
|
|
|
|
|
+ Normal = new Attribute(Color.White, Color.Blue),
|
|
|
|
|
+ Focus = new Attribute(Color.Black, Color.Cyan)
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// Listen for scheme changes
|
|
|
|
|
+SchemeManager.CollectionChanged += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Handle scheme changes
|
|
|
};
|
|
};
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+#### Scheme Structure
|
|
|
|
|
|
|
|
-## How Settings are Defined
|
|
|
|
|
|
|
+Each [Scheme](~/api/Terminal.Gui.Drawing.Scheme.yml) maps [VisualRole](~/api/Terminal.Gui.Drawing.VisualRole.yml) to [Attribute](~/api/Terminal.Gui.Drawing.Attribute.yml):
|
|
|
|
|
|
|
|
-Application developers define settings by decorating static properties with the `[ConfigurationProperty]` attribute.
|
|
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "TopLevel": {
|
|
|
|
|
+ "Normal": {
|
|
|
|
|
+ "Foreground": "BrightGreen",
|
|
|
|
|
+ "Background": "Black",
|
|
|
|
|
+ "Style": "None"
|
|
|
|
|
+ },
|
|
|
|
|
+ "Focus": {
|
|
|
|
|
+ "Foreground": "White",
|
|
|
|
|
+ "Background": "Cyan",
|
|
|
|
|
+ "Style": "Bold"
|
|
|
|
|
+ },
|
|
|
|
|
+ "HotNormal": {
|
|
|
|
|
+ "Foreground": "Yellow",
|
|
|
|
|
+ "Background": "Black"
|
|
|
|
|
+ },
|
|
|
|
|
+ "HotFocus": {
|
|
|
|
|
+ "Foreground": "Blue",
|
|
|
|
|
+ "Background": "Cyan",
|
|
|
|
|
+ "Style": "Underline"
|
|
|
|
|
+ },
|
|
|
|
|
+ "Disabled": {
|
|
|
|
|
+ "Foreground": "DarkGray",
|
|
|
|
|
+ "Background": "Black",
|
|
|
|
|
+ "Style": "Faint"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Defining Configuration Properties
|
|
|
|
|
+
|
|
|
|
|
+### Basic Property Definition
|
|
|
|
|
+
|
|
|
|
|
+Application developers define settings using the [ConfigurationPropertyAttribute](~/api/Terminal.Gui.Configuration.ConfigurationPropertyAttribute.yml):
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-class MyApp
|
|
|
|
|
|
|
+public class MyApp
|
|
|
{
|
|
{
|
|
|
[ConfigurationProperty]
|
|
[ConfigurationProperty]
|
|
|
public static string MySetting { get; set; } = "Default Value";
|
|
public static string MySetting { get; set; } = "Default Value";
|
|
|
|
|
+
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static int MaxItems { get; set; } = 100;
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Configuration Properties must be `public` or `internal` `static` properties.
|
|
|
|
|
|
|
+**Requirements:**
|
|
|
|
|
+- Must be `public` or `internal`
|
|
|
|
|
+- Must be `static`
|
|
|
|
|
+- Must be a property (not a field)
|
|
|
|
|
+- Must have a default value
|
|
|
|
|
|
|
|
-The above example will define a configuration property in the `AppSettings` scope. The name of the property will be `MyApp.MySetting` and will appear in JSON as:
|
|
|
|
|
|
|
+### Property Naming
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
|
|
+AppSettings properties are automatically prefixed with the class name to ensure global uniqueness:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Code
|
|
|
|
|
+public class MyApp
|
|
|
{
|
|
{
|
|
|
- "AppSettings": {
|
|
|
|
|
- "MyApp.MySetting": "Default Value"
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static string MySetting { get; set; } = "value";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// JSON
|
|
|
|
|
+{
|
|
|
|
|
+ "AppSettings": {
|
|
|
|
|
+ "MyApp.MySetting": "value"
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-`AppSettings` property names must be globally unique. To ensure this, the name of the AppSettings property is the name of the property prefixed with a period and the full name of the class that holds it. In the example above, the AppSettings property is named `MyApp.MySetting`.
|
|
|
|
|
|
|
+### Scope Specification
|
|
|
|
|
+
|
|
|
|
|
+Use the `Scope` parameter to specify non-default scopes (Terminal.Gui library only):
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+// SettingsScope - Library-wide settings
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(SettingsScope))]
|
|
|
|
|
+public static bool Force16Colors { get; set; } = false;
|
|
|
|
|
+
|
|
|
|
|
+// ThemeScope - Visual settings
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(ThemeScope))]
|
|
|
|
|
+public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
|
|
|
|
|
|
|
|
-Terminal.Gui library developers can use the `SettingsScope` and `ThemeScope` attributes to define settings and themes for the terminal.Gui library.
|
|
|
|
|
|
|
+// AppSettingsScope - Application settings (default)
|
|
|
|
|
+[ConfigurationProperty] // or explicitly: Scope = typeof(AppSettingsScope)
|
|
|
|
|
+public static string MyAppSetting { get; set; } = "default";
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Omit Class Name (Advanced)
|
|
|
|
|
|
|
|
-> [!IMPORTANT]
|
|
|
|
|
-App developers cannot define `SettingScope` or `ThemeScope` properties.
|
|
|
|
|
|
|
+For library developers only, use `OmitClassName = true` for cleaner JSON:
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
- /// <summary>
|
|
|
|
|
- /// Gets or sets whether <see cref="Button"/>s are shown with a shadow effect by default.
|
|
|
|
|
- /// </summary>
|
|
|
|
|
- [ConfigurationProperty (Scope = typeof (ThemeScope))]
|
|
|
|
|
- public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
|
|
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(ThemeScope), OmitClassName = true)]
|
|
|
|
|
+public static Dictionary<string, Scheme> Schemes { get; set; } = new();
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-# Sample Code
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-The `UICatalog` application provides an example of how to use the [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) class to load and save configuration files.
|
|
|
|
|
|
|
+## Loading and Applying Configuration
|
|
|
|
|
|
|
|
-The `Configuration Editor` Scenario provides an editor that allows users to edit the configuration files. UI Catalog also uses a file system watcher to detect changes to the configuration files to tell [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) to reload them; allowing users to change settings without having to restart the application.
|
|
|
|
|
|
|
+### Enable with Load and Apply
|
|
|
|
|
|
|
|
-The `Themes` Scenario in the UI Catalog provides a viewer for the themes defined in the configuration files.
|
|
|
|
|
|
|
+The simplest approach - enable and load in one call:
|
|
|
|
|
|
|
|
-# What Can Be Configured
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-`ConfigurationManager` provides the following features:
|
|
|
|
|
|
|
+This:
|
|
|
|
|
+1. Enables ConfigurationManager
|
|
|
|
|
+2. Loads configuration from all locations
|
|
|
|
|
+3. Applies settings to the application
|
|
|
|
|
|
|
|
-1) **Settings**. Settings are applied to the [`Application`](~/api/Terminal.Gui.App.Application.yml) class. Settings are accessed via the `Settings` property of [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml). E.g. `Settings["Application.QuitKey"]`
|
|
|
|
|
-2) **Themes**. Themes are a named collection of settings impacting how applications look. The default theme is named "Default". Two other built-in themes are provided: "Dark", and "Light". Additional themes can be defined in the configuration files. `Settings ["Themes"]` is a dictionary of theme names to theme settings.
|
|
|
|
|
-3) **AppSettings**. Applications can use the [`ConfigurationManager`](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml) to store and retrieve application-specific settings.
|
|
|
|
|
|
|
+### Granular Control
|
|
|
|
|
|
|
|
-Methods for discovering what can be configured are available in the `ConfigurationManager` class:
|
|
|
|
|
|
|
+For more control, use [Load](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml#Terminal_Gui_Configuration_ConfigurationManager_Load_Terminal_Gui_Configuration_ConfigLocations_) and [Apply](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml#Terminal_Gui_Configuration_ConfigurationManager_Apply) separately:
|
|
|
|
|
|
|
|
-- Call @Terminal.Gui.Configuration.ConfigurationManager.GetHardCodedConfig()
|
|
|
|
|
-- Search the source code for `[ConfigurationProperty]`
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Enable without loading
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.None);
|
|
|
|
|
|
|
|
-For complete schema details and examples, refer to:
|
|
|
|
|
-- Schema: https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json
|
|
|
|
|
-- Default configuration: Terminal.Gui/Resources/config.json
|
|
|
|
|
|
|
+// Load from specific locations
|
|
|
|
|
+ConfigurationManager.Load(ConfigLocations.GlobalHome | ConfigLocations.AppResources);
|
|
|
|
|
|
|
|
-## Themes
|
|
|
|
|
|
|
+// Apply settings
|
|
|
|
|
+ConfigurationManager.Apply();
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-A Theme is a named collection of settings that impact the visual style of Terminal.Gui applications. The default theme is named "Default". The built-in configuration within the Terminal.Gui library defines two more themes: "Dark", and "Light". Additional themes can be defined in the configuration files. The JSON property `Theme` defines the name of the theme that will be used. If the theme is not found, the default theme will be used.
|
|
|
|
|
|
|
+### Runtime Configuration
|
|
|
|
|
|
|
|
-Themes support defining Schemes (a set of colors and styles that define the appearance of views) as well as various default settings for Views. Both the default color schemes and user-defined color schemes can be configured. See [Schemes](~/api/Terminal.Gui.Drawing.Schemes.yml) for more information.
|
|
|
|
|
|
|
+Set configuration directly in code without files:
|
|
|
|
|
|
|
|
-### Theme Configuration
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.RuntimeConfig = @"
|
|
|
|
|
+{
|
|
|
|
|
+ ""Application.QuitKey"": ""Ctrl+Q"",
|
|
|
|
|
+ ""Application.Force16Colors"": true
|
|
|
|
|
+}";
|
|
|
|
|
|
|
|
-Themes provide a way to bundle visual settings together. When @Terminal.Gui.Configuration.ConfigurationManager.Apply is called, the theme settings are applied to the application.
|
|
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.Runtime);
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
-// ...
|
|
|
|
|
- "Dark": {
|
|
|
|
|
- "Dialog.DefaultButtonAlignment": "End",
|
|
|
|
|
- "Dialog.DefaultButtonAlignmentModes": "AddSpaceBetweenItems",
|
|
|
|
|
- "Dialog.DefaultBorderStyle": "Heavy",
|
|
|
|
|
- "Dialog.DefaultShadow": "Transparent",
|
|
|
|
|
- "FrameView.DefaultBorderStyle": "Single",
|
|
|
|
|
- "Window.DefaultBorderStyle": "Single",
|
|
|
|
|
- "MessageBox.DefaultButtonAlignment": "Center",
|
|
|
|
|
- "MessageBox.DefaultBorderStyle": "Heavy",
|
|
|
|
|
- "Button.DefaultShadow": "Opaque",
|
|
|
|
|
- "Schemes": [
|
|
|
|
|
- {
|
|
|
|
|
- "TopLevel": {
|
|
|
|
|
- "Normal": {
|
|
|
|
|
- "Foreground": "LightGray",
|
|
|
|
|
- "Background": "Black",
|
|
|
|
|
- "Style": "None"
|
|
|
|
|
- },
|
|
|
|
|
-// etc...
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-Only properties that are defined in the theme will be applied, meaning that themes can be used to override the a previously applied theme.
|
|
|
|
|
-
|
|
|
|
|
-To ensure a theme inherits from the default theme, first apply the default theme, then apply the new theme, like this:
|
|
|
|
|
-
|
|
|
|
|
-```csharp
|
|
|
|
|
-// Apply the default theme
|
|
|
|
|
- ThemeManager.Theme = "Default";
|
|
|
|
|
-ConfigurationManager.Apply();
|
|
|
|
|
|
|
+### Reset to Defaults
|
|
|
|
|
|
|
|
-// Apply the new theme
|
|
|
|
|
-ThemeManager.Theme = "MyCustomTheme";
|
|
|
|
|
-ConfigurationManager.Apply();
|
|
|
|
|
|
|
+Reset all settings to hard-coded defaults:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.ResetToHardCodedDefaults();
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### Glyphs
|
|
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Events
|
|
|
|
|
+
|
|
|
|
|
+The ConfigurationManager provides events to track configuration changes:
|
|
|
|
|
+
|
|
|
|
|
+### Applied Event
|
|
|
|
|
+
|
|
|
|
|
+Raised after configuration is applied to the application:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.Applied += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Configuration has been applied
|
|
|
|
|
+ // Update UI or refresh views
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-Themes support changing the standard set of glyphs used by views (e.g. the default indicator for [Button](~/api/Terminal.Gui.Views.Button.yml)) and line drawing (e.g. [LineCanvas](~/api/Terminal.Gui.Drawing.LineCanvas.yml)).
|
|
|
|
|
|
|
+### ThemeChanged Event
|
|
|
|
|
|
|
|
|
|
+Raised when the active theme changes:
|
|
|
|
|
|
|
|
-The value can be either a decimal number or a string. The string may be:
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+ThemeManager.ThemeChanged += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Theme has changed
|
|
|
|
|
+ // Refresh all views to use new theme
|
|
|
|
|
+ Application.Top?.SetNeedsDraw();
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### CollectionChanged Event
|
|
|
|
|
+
|
|
|
|
|
+Raised when schemes collection changes:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+SchemeManager.CollectionChanged += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Schemes have changed
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## What Can Be Configured
|
|
|
|
|
+
|
|
|
|
|
+### Application Settings
|
|
|
|
|
+
|
|
|
|
|
+System-wide settings from [SettingsScope](~/api/Terminal.Gui.Configuration.SettingsScope.yml):
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "Application.QuitKey": "Esc",
|
|
|
|
|
+ "Application.Force16Colors": false,
|
|
|
|
|
+ "Application.IsMouseDisabled": false,
|
|
|
|
|
+ "Application.ArrangeKey": "Ctrl+F5",
|
|
|
|
|
+ "Application.NextTabKey": "Tab",
|
|
|
|
|
+ "Application.PrevTabKey": "Shift+Tab",
|
|
|
|
|
+ "Application.NextTabGroupKey": "F6",
|
|
|
|
|
+ "Application.PrevTabGroupKey": "Shift+F6",
|
|
|
|
|
+ "Key.Separator": "+"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### View-Specific Settings
|
|
|
|
|
+
|
|
|
|
|
+Settings for individual View types from [ThemeScope](~/api/Terminal.Gui.Configuration.ThemeScope.yml):
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "Window.DefaultBorderStyle": "Single",
|
|
|
|
|
+ "Window.DefaultShadow": "None",
|
|
|
|
|
+ "Dialog.DefaultBorderStyle": "Heavy",
|
|
|
|
|
+ "Dialog.DefaultShadow": "Transparent",
|
|
|
|
|
+ "Dialog.DefaultButtonAlignment": "End",
|
|
|
|
|
+ "FrameView.DefaultBorderStyle": "Rounded",
|
|
|
|
|
+ "Button.DefaultShadow": "None",
|
|
|
|
|
+ "PopoverMenu.DefaultKey": "Shift+F10",
|
|
|
|
|
+ "FileDialog.MaxSearchResults": 10000
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Glyphs
|
|
|
|
|
|
|
|
-- A Unicode char (e.g. "☑")
|
|
|
|
|
-- A hex value in U+ format (e.g. "U+2611")
|
|
|
|
|
-- A hex value in UTF-16 format (e.g. "\\u2611")
|
|
|
|
|
|
|
+Customize the Unicode characters used for drawing:
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
|
|
+{
|
|
|
"Glyphs.RightArrow": "►",
|
|
"Glyphs.RightArrow": "►",
|
|
|
"Glyphs.LeftArrow": "U+25C4",
|
|
"Glyphs.LeftArrow": "U+25C4",
|
|
|
"Glyphs.DownArrow": "\\u25BC",
|
|
"Glyphs.DownArrow": "\\u25BC",
|
|
|
- "Glyphs.UpArrow": 965010
|
|
|
|
|
|
|
+ "Glyphs.UpArrow": 965010,
|
|
|
|
|
+ "Glyphs.LeftBracket": "[",
|
|
|
|
|
+ "Glyphs.RightBracket": "]",
|
|
|
|
|
+ "Glyphs.Checked": "☑",
|
|
|
|
|
+ "Glyphs.UnChecked": "☐",
|
|
|
|
|
+ "Glyphs.Selected": "◉",
|
|
|
|
|
+ "Glyphs.UnSelected": "○"
|
|
|
|
|
+}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-The `UI Catalog` application defines a `UICatalog` Theme. Look at the UI Catalog's `./Resources/config.json` file to see how to define a theme.
|
|
|
|
|
-
|
|
|
|
|
-### Theme and Scheme Management
|
|
|
|
|
|
|
+Glyphs can be specified as:
|
|
|
|
|
+- Unicode character: `"►"`
|
|
|
|
|
+- U+ format: `"U+25C4"`
|
|
|
|
|
+- UTF-16 format: `"\\u25BC"`
|
|
|
|
|
+- Decimal codepoint: `965010`
|
|
|
|
|
|
|
|
-Terminal.Gui provides two key managers for handling visual themes and schemes:
|
|
|
|
|
|
|
+### Discovering Configuration Properties
|
|
|
|
|
|
|
|
-The ThemeManager provides convenient methods for working with themes:
|
|
|
|
|
|
|
+To find all available configuration properties:
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-// Get the currently active theme
|
|
|
|
|
-ThemeScope currentTheme = ThemeManager.GetCurrentTheme();
|
|
|
|
|
|
|
+// Get hard-coded configuration
|
|
|
|
|
+SettingsScope hardCoded = ConfigurationManager.GetHardCodedConfig();
|
|
|
|
|
|
|
|
-// Get all available themes
|
|
|
|
|
-Dictionary<string, ThemeScope> themes = ThemeManager.GetThemes();
|
|
|
|
|
|
|
+// Iterate through all properties
|
|
|
|
|
+foreach (var property in hardCoded)
|
|
|
|
|
+{
|
|
|
|
|
+ Console.WriteLine($"{property.Key} = {property.Value}");
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-// Get list of theme names
|
|
|
|
|
-ImmutableList<string> themeNames = ThemeManager.GetThemeNames();
|
|
|
|
|
|
|
+Or search the source code for `[ConfigurationProperty]` attributes.
|
|
|
|
|
|
|
|
-// Get/Set current theme name
|
|
|
|
|
-string currentThemeName = ThemeManager.GetCurrentThemeName();
|
|
|
|
|
-ThemeManager.Theme = "Dark"; // Switch themes
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-// Listen for theme changes
|
|
|
|
|
-ThemeManager.ThemeChanged += (sender, e) => {
|
|
|
|
|
- // Handle theme changes
|
|
|
|
|
-};
|
|
|
|
|
|
|
+## Themes and Schemes
|
|
|
|
|
+
|
|
|
|
|
+### Theme Structure
|
|
|
|
|
+
|
|
|
|
|
+A theme is a named collection bundling visual settings and schemes:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "Themes": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "Dark": {
|
|
|
|
|
+ "Dialog.DefaultBorderStyle": "Heavy",
|
|
|
|
|
+ "Dialog.DefaultShadow": "Transparent",
|
|
|
|
|
+ "Window.DefaultBorderStyle": "Single",
|
|
|
|
|
+ "Button.DefaultShadow": "Opaque",
|
|
|
|
|
+ "Schemes": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "TopLevel": {
|
|
|
|
|
+ "Normal": { "Foreground": "BrightGreen", "Background": "Black" },
|
|
|
|
|
+ "Focus": { "Foreground": "White", "Background": "Cyan" }
|
|
|
|
|
+ },
|
|
|
|
|
+ "Dialog": {
|
|
|
|
|
+ "Normal": { "Foreground": "Black", "Background": "Gray" }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### SchemeManager
|
|
|
|
|
|
|
+### Creating Custom Themes
|
|
|
|
|
|
|
|
-The SchemeManager handles schemes within themes. Each theme contains multiple schemes for different UI contexts:
|
|
|
|
|
|
|
+Custom themes can be defined in configuration files:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "Themes": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "MyCustomTheme": {
|
|
|
|
|
+ "Window.DefaultBorderStyle": "Double",
|
|
|
|
|
+ "Dialog.DefaultShadow": "Opaque",
|
|
|
|
|
+ "Schemes": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "Base": {
|
|
|
|
|
+ "Normal": {
|
|
|
|
|
+ "Foreground": "Cyan",
|
|
|
|
|
+ "Background": "Black",
|
|
|
|
|
+ "Style": "Bold"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Then activate the theme:
|
|
|
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
-// Get current schemes
|
|
|
|
|
-Dictionary<string, Scheme> schemes = SchemeManager.GetCurrentSchemes();
|
|
|
|
|
|
|
+ThemeManager.Theme = "MyCustomTheme";
|
|
|
|
|
+ConfigurationManager.Apply();
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-// Get list of scheme names
|
|
|
|
|
-ImmutableList<string> schemeNames = SchemeManager.GetSchemeNames();
|
|
|
|
|
|
|
+### Theme Inheritance
|
|
|
|
|
|
|
|
-// Access specific schemes
|
|
|
|
|
-Scheme topLevelScheme = SchemeManager.GetScheme("TopLevel");
|
|
|
|
|
|
|
+Themes only override specified properties. To build on an existing theme:
|
|
|
|
|
|
|
|
-// Listen for scheme changes
|
|
|
|
|
-SchemeManager.CollectionChanged += (sender, e) => {
|
|
|
|
|
- // Handle scheme changes
|
|
|
|
|
-};
|
|
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Start with default theme
|
|
|
|
|
+ThemeManager.Theme = "Default";
|
|
|
|
|
+ConfigurationManager.Apply();
|
|
|
|
|
+
|
|
|
|
|
+// Apply custom theme (overrides only what's specified)
|
|
|
|
|
+ThemeManager.Theme = "MyCustomTheme";
|
|
|
|
|
+ConfigurationManager.Apply();
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### Built-in Schemes
|
|
|
|
|
|
|
+### TextStyle in Schemes
|
|
|
|
|
|
|
|
-The following Schemes are available by default:
|
|
|
|
|
|
|
+Each [Attribute](~/api/Terminal.Gui.Drawing.Attribute.yml) in a scheme now includes [TextStyle](~/api/Terminal.Gui.Drawing.TextStyle.yml):
|
|
|
|
|
|
|
|
-- **TopLevel**: Used for the application's top-level windows
|
|
|
|
|
-- **Base**: Default scheme for most views
|
|
|
|
|
-- **Dialog**: Used for dialogs and message boxes
|
|
|
|
|
-- **Menu**: Used for menus and status bars
|
|
|
|
|
-- **Error**: Used for error messages and dialogs
|
|
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "Normal": {
|
|
|
|
|
+ "Foreground": "White",
|
|
|
|
|
+ "Background": "Blue",
|
|
|
|
|
+ "Style": "Bold, Underline"
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Available styles (combinable):
|
|
|
|
|
+- `None`
|
|
|
|
|
+- `Bold`
|
|
|
|
|
+- `Faint`
|
|
|
|
|
+- `Italic`
|
|
|
|
|
+- `Underline`
|
|
|
|
|
+- `Blink`
|
|
|
|
|
+- `Reverse`
|
|
|
|
|
+- `Strikethrough`
|
|
|
|
|
|
|
|
-Each Scheme defines the attributes for different VisualRoles.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-## Application Settings
|
|
|
|
|
|
|
+## Configuration File Format
|
|
|
|
|
|
|
|
-Terminal.Gui provides several top-level application settings:
|
|
|
|
|
|
|
+### Schema
|
|
|
|
|
+
|
|
|
|
|
+All configuration files must conform to the JSON schema:
|
|
|
|
|
+
|
|
|
|
|
+**Schema URL:** https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json
|
|
|
|
|
+
|
|
|
|
|
+### Root Structure
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
{
|
|
{
|
|
|
- "Key.Separator": "+",
|
|
|
|
|
- "Application.ArrangeKey": "Ctrl+F5",
|
|
|
|
|
|
|
+ "$schema": "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json",
|
|
|
|
|
+
|
|
|
|
|
+ // SettingsScope properties
|
|
|
|
|
+ "Application.QuitKey": "Esc",
|
|
|
"Application.Force16Colors": false,
|
|
"Application.Force16Colors": false,
|
|
|
- "Application.IsMouseDisabled": false,
|
|
|
|
|
- "Application.NextTabGroupKey": "F6",
|
|
|
|
|
- "Application.NextTabKey": "Tab",
|
|
|
|
|
- "Application.PrevTabGroupKey": "Shift+F6",
|
|
|
|
|
- "Application.PrevTabKey": "Shift+Tab",
|
|
|
|
|
- "Application.QuitKey": "Esc"
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Current theme name
|
|
|
|
|
+ "Theme": "Dark",
|
|
|
|
|
+
|
|
|
|
|
+ // Theme definitions
|
|
|
|
|
+ "Themes": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "Dark": {
|
|
|
|
|
+ // ThemeScope properties
|
|
|
|
|
+ "Window.DefaultBorderStyle": "Single",
|
|
|
|
|
+ // Schemes
|
|
|
|
|
+ "Schemes": [ ... ]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+
|
|
|
|
|
+ // AppSettings
|
|
|
|
|
+ "AppSettings": {
|
|
|
|
|
+ "MyApp.MySetting": "value"
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### View-Specific Settings
|
|
|
|
|
|
|
+### Complete Example
|
|
|
|
|
|
|
|
-Examples of settings that control specific view behaviors:
|
|
|
|
|
|
|
+See the default configuration file:
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
|
|
+[!code-json[config.json](../../Terminal.Gui/Resources/config.json)]
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Best Practices
|
|
|
|
|
+
|
|
|
|
|
+### For Application Developers
|
|
|
|
|
+
|
|
|
|
|
+**1. Enable Early**
|
|
|
|
|
+
|
|
|
|
|
+Enable ConfigurationManager at the start of `Main()`, before `Application.Init()`:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+static void Main()
|
|
|
{
|
|
{
|
|
|
- "PopoverMenu.DefaultKey": "Shift+F10",
|
|
|
|
|
- "FileDialog.MaxSearchResults": 10000,
|
|
|
|
|
- "FileDialogStyle.DefaultUseColors": false,
|
|
|
|
|
- "FileDialogStyle.DefaultUseUnicodeCharacters": false
|
|
|
|
|
|
|
+ ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+ Application.Init();
|
|
|
|
|
+ // ...
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### Key Bindings
|
|
|
|
|
|
|
+**2. Use AppSettings for App Configuration**
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+public class MyApp
|
|
|
|
|
+{
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static bool ShowWelcomeMessage { get; set; } = true;
|
|
|
|
|
+
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static string DefaultDirectory { get; set; } = "";
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**3. Ship Default Configuration as Resource**
|
|
|
|
|
+
|
|
|
|
|
+Include a `Resources/config.json` file in your app:
|
|
|
|
|
+
|
|
|
|
|
+```xml
|
|
|
|
|
+<ItemGroup>
|
|
|
|
|
+ <EmbeddedResource Include="Resources\config.json" />
|
|
|
|
|
+</ItemGroup>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**4. Handle Configuration Changes**
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.Applied += (sender, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ // Refresh UI when configuration changes
|
|
|
|
|
+ RefreshAllViews();
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### For Library Developers
|
|
|
|
|
+
|
|
|
|
|
+**1. Use Appropriate Scopes**
|
|
|
|
|
+
|
|
|
|
|
+- `SettingsScope` - For system-wide behavior
|
|
|
|
|
+- `ThemeScope` - For visual appearance that should be themeable
|
|
|
|
|
+- Don't use `AppSettingsScope` in library code
|
|
|
|
|
+
|
|
|
|
|
+**2. Provide Meaningful Defaults**
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(ThemeScope))]
|
|
|
|
|
+public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**3. Document Configuration Properties**
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+/// <summary>
|
|
|
|
|
+/// Gets or sets the default border style for all Windows.
|
|
|
|
|
+/// </summary>
|
|
|
|
|
+[ConfigurationProperty(Scope = typeof(ThemeScope))]
|
|
|
|
|
+public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Process-Wide Settings
|
|
|
|
|
+
|
|
|
|
|
+> [!IMPORTANT]
|
|
|
|
|
+> Configuration settings are applied at the **process level**.
|
|
|
|
|
+>
|
|
|
|
|
+> Since configuration properties are static, changes affect all applications in the same process. This is typically not an issue for normal applications, but can affect scenarios with:
|
|
|
|
|
+> - Multiple Terminal.Gui apps in the same process
|
|
|
|
|
+> - Unit tests running in parallel
|
|
|
|
|
+> - Hot reload scenarios
|
|
|
|
|
|
|
|
-> [!WARNING]
|
|
|
|
|
-> Configuration Manager support for key bindings is not yet implemented.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-Key bindings are defined in the `KeyBindings` property of the configuration file. The value is an array of objects, each object defining a key binding. The key binding object has the following properties:
|
|
|
|
|
|
|
+## Advanced Topics
|
|
|
|
|
|
|
|
-- `Key`: The key to bind to. The format is a string describing the key (e.g. "q", "Q, "Ctrl+Q"). Function keys are specified as "F1", "F2", etc.
|
|
|
|
|
|
|
+### JSON Error Handling
|
|
|
|
|
|
|
|
-# Error Handling
|
|
|
|
|
|
|
+Control how JSON parsing errors are handled:
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
{
|
|
{
|
|
|
- "ConfigurationManager.ThrowOnJsonErrors": false
|
|
|
|
|
|
|
+ "ConfigurationManager.ThrowOnJsonErrors": true
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Set to `true` to throw exceptions on JSON parsing errors instead of silent failures.
|
|
|
|
|
|
|
+- `false` (default) - Silent failures, errors logged
|
|
|
|
|
+- `true` - Throws exceptions on JSON parsing errors
|
|
|
|
|
+
|
|
|
|
|
+### Manually Trigger Updates
|
|
|
|
|
+
|
|
|
|
|
+Update ConfigurationManager to reflect current static property values:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Change a setting programmatically
|
|
|
|
|
+Application.QuitKey = Key.Q.WithCtrl;
|
|
|
|
|
+
|
|
|
|
|
+// Update ConfigurationManager to reflect the change
|
|
|
|
|
+ConfigurationManager.UpdateToCurrentValues();
|
|
|
|
|
+
|
|
|
|
|
+// Save to file (if needed)
|
|
|
|
|
+string json = ConfigurationManager.Serialize();
|
|
|
|
|
+File.WriteAllText("my-config.json", json);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Disable ConfigurationManager
|
|
|
|
|
+
|
|
|
|
|
+Disable and optionally reset to defaults:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+// Disable but keep current settings
|
|
|
|
|
+ConfigurationManager.Disable(resetToHardCodedDefaults: false);
|
|
|
|
|
+
|
|
|
|
|
+// Disable and reset to hard-coded defaults
|
|
|
|
|
+ConfigurationManager.Disable(resetToHardCodedDefaults: true);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### File System Watching
|
|
|
|
|
+
|
|
|
|
|
+Watch for configuration file changes:
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+var watcher = new FileSystemWatcher(
|
|
|
|
|
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".tui"));
|
|
|
|
|
+watcher.Filter = "*.json";
|
|
|
|
|
+watcher.Changed += (s, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ ConfigurationManager.Load(ConfigLocations.GlobalHome);
|
|
|
|
|
+ ConfigurationManager.Apply();
|
|
|
|
|
+};
|
|
|
|
|
+watcher.EnableRaisingEvents = true;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+See UICatalog's `ConfigurationEditor` scenario for a complete example.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Examples
|
|
|
|
|
+
|
|
|
|
|
+### Example 1: Simple Theme Switching
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+using Terminal.Gui;
|
|
|
|
|
+using Terminal.Gui.Configuration;
|
|
|
|
|
+
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+Application.Init();
|
|
|
|
|
+
|
|
|
|
|
+var themeSelector = new ComboBox
|
|
|
|
|
+{
|
|
|
|
|
+ X = 1,
|
|
|
|
|
+ Y = 1,
|
|
|
|
|
+ Width = 20
|
|
|
|
|
+};
|
|
|
|
|
+themeSelector.SetSource(ThemeManager.GetThemeNames());
|
|
|
|
|
+themeSelector.SelectedItemChanged += (s, e) =>
|
|
|
|
|
+{
|
|
|
|
|
+ ThemeManager.Theme = e.Value.ToString();
|
|
|
|
|
+ ConfigurationManager.Apply();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+Application.Run(new Window { Title = "Theme Demo" }).Add(themeSelector);
|
|
|
|
|
+Application.Shutdown();
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Example 2: Custom Application Settings
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+public class MyApp
|
|
|
|
|
+{
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static string LastOpenedFile { get; set; } = "";
|
|
|
|
|
+
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static int WindowWidth { get; set; } = 80;
|
|
|
|
|
+
|
|
|
|
|
+ [ConfigurationProperty]
|
|
|
|
|
+ public static int WindowHeight { get; set; } = 25;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Enable and use
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.All);
|
|
|
|
|
+
|
|
|
|
|
+// Settings are automatically loaded and applied
|
|
|
|
|
+var window = new Window
|
|
|
|
|
+{
|
|
|
|
|
+ Width = MyApp.WindowWidth,
|
|
|
|
|
+ Height = MyApp.WindowHeight
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// Later, save updated settings
|
|
|
|
|
+MyApp.WindowWidth = 100;
|
|
|
|
|
+ConfigurationManager.UpdateToCurrentValues();
|
|
|
|
|
+// Could save to file here
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Example 3: Runtime Configuration
|
|
|
|
|
+
|
|
|
|
|
+```csharp
|
|
|
|
|
+ConfigurationManager.RuntimeConfig = @"
|
|
|
|
|
+{
|
|
|
|
|
+ ""Application.QuitKey"": ""Ctrl+Q"",
|
|
|
|
|
+ ""Application.Force16Colors"": true,
|
|
|
|
|
+ ""Theme"": ""Dark""
|
|
|
|
|
+}";
|
|
|
|
|
+
|
|
|
|
|
+ConfigurationManager.Enable(ConfigLocations.Runtime);
|
|
|
|
|
+
|
|
|
|
|
+// Settings are now applied
|
|
|
|
|
+// QuitKey is Ctrl+Q
|
|
|
|
|
+// 16-color mode is forced
|
|
|
|
|
+// Dark theme is active
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## See Also
|
|
|
|
|
|
|
|
-# Configuration File Schema
|
|
|
|
|
|
|
+- **[Scheme Deep Dive](scheme.md)** - Color scheme details
|
|
|
|
|
+- **[Drawing Deep Dive](drawing.md)** - Color and attribute system
|
|
|
|
|
+- **[View Deep Dive](View.md)** - View configuration properties
|
|
|
|
|
+- **[Theme Schema](https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json)** - JSON schema for validation
|
|
|
|
|
+- **[Default Config](../../Terminal.Gui/Resources/config.json)** - Complete default configuration
|
|
|
|
|
|
|
|
-Settings are defined in JSON format, according to the schema found here:
|
|
|
|
|
|
|
+### UICatalog Examples
|
|
|
|
|
|
|
|
-https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json
|
|
|
|
|
|
|
+The UICatalog application demonstrates configuration management:
|
|
|
|
|
|
|
|
-## The Default Config File
|
|
|
|
|
|
|
+- **Configuration Editor** - Interactive editor for configuration files
|
|
|
|
|
+- **Themes** - Theme viewer and selector
|
|
|
|
|
+- **File System Watcher** - Automatic reload on configuration file changes
|
|
|
|
|
|
|
|
-To illustrate the syntax, the below is the `config.json` file found in `Terminal.Gui.dll`:
|
|
|
|
|
|
|
+### API Reference
|
|
|
|
|
|
|
|
-[!code-json[config.json](../../Terminal.Gui/Resources/config.json)]
|
|
|
|
|
|
|
+- [ConfigurationManager](~/api/Terminal.Gui.Configuration.ConfigurationManager.yml)
|
|
|
|
|
+- [ConfigLocations](~/api/Terminal.Gui.Configuration.ConfigLocations.yml)
|
|
|
|
|
+- [SettingsScope](~/api/Terminal.Gui.Configuration.SettingsScope.yml)
|
|
|
|
|
+- [ThemeScope](~/api/Terminal.Gui.Configuration.ThemeScope.yml)
|
|
|
|
|
+- [AppSettingsScope](~/api/Terminal.Gui.Configuration.AppSettingsScope.yml)
|
|
|
|
|
+- [ThemeManager](~/api/Terminal.Gui.Configuration.ThemeManager.yml)
|
|
|
|
|
+- [SchemeManager](~/api/Terminal.Gui.Configuration.SchemeManager.yml)
|
|
|
|
|
+- [ConfigurationPropertyAttribute](~/api/Terminal.Gui.Configuration.ConfigurationPropertyAttribute.yml)
|