#nullable enable using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace Terminal.Gui; /// Contains a dictionary of the s for a Terminal.Gui application. /// /// A Theme is a collection of settings that are named. The default theme is named "Default". /// The property is used to determine the currently active theme. /// /// /// is a singleton class. It is created when the first property /// is accessed. Accessing is the same as accessing /// . /// /// /// /// "Themes": [ /// { /// "Default": { /// "ColorSchemes": [ /// { /// "TopLevel": { /// "Normal": { /// "Foreground": "BrightGreen", /// "Background": "Black" /// }, /// "Focus": { /// "Foreground": "White", /// "Background": "Cyan" /// /// }, /// "HotNormal": { /// "Foreground": "Yellow", /// "Background": "Black" /// /// }, /// "HotFocus": { /// "Foreground": "Blue", /// "Background": "Cyan" /// }, /// "Disabled": { /// "Foreground": "DarkGray", /// "Background": "Black" /// /// } /// } /// } /// /// public class ThemeManager : IDictionary { private static string _theme = string.Empty; static ThemeManager () { } // Make sure it's truly lazy private ThemeManager () { } // Prevent instantiation outside /// Class is a singleton... public static ThemeManager Instance { get; } = new (); /// Gets or sets the currently selected theme. The value is persisted to the "Theme" property. [JsonIgnore] public string Theme { get => SelectedTheme; [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] set => SelectedTheme = value; } /// Holds the definitions. [JsonInclude] [JsonConverter (typeof (DictionaryJsonConverter))] [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] public static Dictionary? Themes { [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] get => Settings? ["Themes"] ?.PropertyValue as Dictionary; // themes ?? new Dictionary (); [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] set => //if (themes is null || value is null) { // themes = value; //} else { // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; //} Settings! ["Themes"].PropertyValue = value; } /// The currently selected theme. This is the internal version; see . [JsonInclude] [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] [JsonPropertyName ("Theme")] internal static string SelectedTheme { get => _theme; [RequiresUnreferencedCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] [RequiresDynamicCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] set { string oldTheme = _theme; _theme = value; if (oldTheme != _theme && Settings! ["Themes"]?.PropertyValue is Dictionary themes && themes.ContainsKey (_theme)) { Settings! ["Theme"].PropertyValue = _theme; Instance.OnThemeChanged (oldTheme); } } } /// Event fired he selected theme has changed. application. public event EventHandler? ThemeChanged; [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void GetHardCodedDefaults () { //Debug.WriteLine ("Themes.GetHardCodedDefaults()"); var theme = new ThemeScope (); theme.RetrieveValues (); Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; SelectedTheme = "Default"; } /// Called when the selected theme has changed. Fires the event. internal void OnThemeChanged (string theme) { //Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}"); ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); } [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void Reset () { Debug.WriteLine ("Themes.Reset()"); Colors.Reset (); Themes?.Clear (); SelectedTheme = string.Empty; } #region IDictionary #pragma warning disable 1591 [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Keys => ((IDictionary)Themes!).Keys; [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Values => ((IDictionary)Themes!).Values; [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public int Count => ((ICollection>)Themes!).Count; [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; public ThemeScope this [string key] { [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. get => ((IDictionary)Themes!) [key]; #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. set => ((IDictionary)Themes!) [key] = value; #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. } [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Add (string key, ThemeScope value) { ((IDictionary)Themes!).Add (key, value); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool ContainsKey (string key) { return ((IDictionary)Themes!).ContainsKey (key); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Remove (string key) { return ((IDictionary)Themes!).Remove (key); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool TryGetValue (string key, out ThemeScope value) { return ((IDictionary)Themes!).TryGetValue (key, out value!); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Add (KeyValuePair item) { ((ICollection>)Themes!).Add (item); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Clear () { ((ICollection>)Themes!).Clear (); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Contains (KeyValuePair item) { return ((ICollection>)Themes!).Contains (item); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void CopyTo (KeyValuePair [] array, int arrayIndex) #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. { ((ICollection>)Themes!).CopyTo (array, arrayIndex); } [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Remove (KeyValuePair item) { return ((ICollection>)Themes!).Remove (item); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public IEnumerator> GetEnumerator () { return ((IEnumerable>)Themes!).GetEnumerator (); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] #pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable)Themes!).GetEnumerator (); } #pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore 1591 #endregion }