docfx/docs/scheme.md
See Drawing for an overview of the drawing system and Configuration for an overview of the configuration system.
[!INCLUDE Scheme Overview]
A xref:Terminal.Gui.Drawing.Scheme enables consistent, semantic theming of UI elements by associating each visual state with a specific style. Each property (e.g., Normal or Focus) is an xref:Terminal.Gui.Drawing.Attribute.
Only Normal is required. If other properties are not explicitly set, its value is derived from other roles (typically Normal) using well-defined inheritance rules. See the source code for the xref:Terminal.Gui.Drawing.Scheme class for more details.
When a xref:Terminal.Gui.Drawing.Scheme uses Color.None for foreground or background (e.g., the default Base scheme), the derivation algorithm resolves these to concrete colors before performing any color math. The Accent scheme uses Color.None as a sentinel but is derived to opaque colors at draw time via Scheme.DeriveAccent. The resolution uses:
IDriver.DefaultAttribute.The derivation algorithm is also dark/light background aware. Roles that use Color.GetBrighterColor or Color.GetDimmerColor (Active, Highlight, Editable, ReadOnly, Disabled) determine whether the relevant background is dark or light via Color.IsDarkColor() and pass this context to the color math methods:
This ensures the built-in themes produce readable, visually correct results on both dark and light terminal backgrounds.
Terminal.Gui.ViewA xref:Terminal.Gui.ViewBase.View's appearance is primarily determined by its xref:Terminal.Gui.Drawing.Scheme, which maps semantic VisualRoles (like Normal, Focus, Disabled) to specific xref:Terminal.Gui.Drawing.Attributes (foreground color, background color, and text style). Terminal.Gui provides a flexible system for managing these schemes:
Scheme Inheritance (Default Behavior):
SuperView (its parent in the view hierarchy).SuperView has a scheme, (e.g., if the view is a top-level view), it ultimately falls back to the "Base" scheme defined in SchemeManager.GetCurrentSchemes().GetScheme() method implements this logic:
_scheme field (see point 2).SchemeName is set, it tries to resolve the scheme by name from SchemeManager.SuperView.GetScheme().SchemeManager.GetCurrentSchemes()["Base"].Explicit Scheme Assignment:
View.Scheme property (which calls SetScheme(value)). This overrides any inherited scheme. The HasScheme property will then return true.View.SchemeName property to the name of a scheme registered in SchemeManager. If xref:Terminal.Gui.Drawing.Scheme itself hasn't been directly set, GetScheme() will use SchemeName to look up the scheme. This is useful for declarative configurations (e.g., from a JSON file).SetScheme(Scheme? scheme) method updates the internal _scheme field. If the new scheme is different from the current one, it marks the view for redraw (SetNeedsDraw()) to reflect the visual change. It also handles a special case for xref:Terminal.Gui.ViewBase.Border to ensure its scheme is updated if it HasScheme.Event-Driven Customization: The scheme resolution and application process includes events that allow for fine-grained control and customization:
GettingScheme Event (View.Scheme.cs):
GetScheme() before the default logic (inheritance, SchemeName lookup, or explicit _scheme usage) fully determines the scheme.SuperView, a SubView, or any other interested component) can handle this event.args.NewScheme to a different xref:Terminal.Gui.Drawing.Scheme object.args.Cancel = true. If canceled, the xref:Terminal.Gui.Drawing.Scheme provided in args.NewScheme (which might have been modified by the handler) is returned directly by GetScheme().OnGettingScheme(out Scheme? scheme) virtual method is called first, allowing derived classes to provide a scheme directly.SettingScheme Event (View.Scheme.cs):
SetScheme(Scheme? scheme) before the _scheme field is actually updated.args.Cancel = true in the event handler.OnSettingScheme(in Scheme? scheme) virtual method is called first, allowing derived classes to prevent the scheme from being set.Retrieving and Applying Attributes for Visual Roles (View.Attribute.cs):
Once a xref:Terminal.Gui.ViewBase.View has determined its active xref:Terminal.Gui.Drawing.Scheme (via GetScheme()), it uses this scheme to get specific xref:Terminal.Gui.Drawing.Attributes for rendering different parts of itself based on their VisualRole.
GetAttributeForRole(VisualRole role):
role from the xref:Terminal.Gui.ViewBase.View's current xref:Terminal.Gui.Drawing.Scheme (GetScheme()!.GetAttributeForRole(role)).GettingAttributeForRole event (and calls the OnGettingAttributeForRole virtual method).GettingAttributeForRole can:
args.NewValue (which is passed by ref as schemeAttribute to the event).args.Cancel = true. The (potentially modified) args.NewValue is then returned.Enabled == false and the requested role is not VisualRole.Disabled, this method will recursively call itself to get the xref:Terminal.Gui.Drawing.Attribute for VisualRole.Disabled. This ensures disabled views use their designated disabled appearance.SetAttributeForRole(VisualRole role):
ConsoleDriver which xref:Terminal.Gui.Drawing.Attribute to use for subsequent drawing operations (like AddRune or AddStr).role from the current xref:Terminal.Gui.Drawing.Scheme by calling GetAttributeForRole.SetAttribute(Attribute attribute):
SetAttributeForRole to maintain consistency with the xref:Terminal.Gui.Drawing.Scheme.SuperView Influence: A SuperView can subscribe to its SubView's GettingScheme or GettingAttributeForRole events. This would allow a SuperView to dynamically alter how its children determine their schemes or specific attributes, perhaps based on the SuperView's state or other application logic. For example, a container view might want all its children to adopt a slightly modified version of its own scheme under certain conditions.
SubView Influence (Less Common for Scheme of Parent): While a SubView could subscribe to its SuperView's scheme events, this is less typical for influencing the SuperView's own scheme. It's more common for a SubView to react to changes in its SuperView's scheme if needed, or to manage its own scheme independently.
General Event Usage: These events are powerful for scenarios where:
On... methods.In summary, Terminal.Gui offers a layered approach to scheme management: straightforward inheritance and explicit setting for common cases, and a robust event system for advanced customization and dynamic control over how views derive and apply their visual attributes. This allows developers to achieve a wide range of visual styles and behaviors.