using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text.Json.Serialization; #nullable enable 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 detemrine 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": "Brown", /// "Background": "Black" /// /// }, /// "HotFocus": { /// "Foreground": "Blue", /// "Background": "Cyan" /// }, /// "Disabled": { /// "Foreground": "DarkGray", /// "Background": "Black" /// /// } /// } /// } /// public class ThemeManager : IDictionary { private static readonly ThemeManager _instance = new ThemeManager (); static ThemeManager () { } // Make sure it's truly lazy private ThemeManager () { } // Prevent instantiation outside /// /// Class is a singleton... /// public static ThemeManager Instance { get { return _instance; } } private static string _theme = string.Empty; /// /// 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; set { var oldTheme = _theme; _theme = value; if (oldTheme != _theme && ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary themes && themes.ContainsKey (_theme)) { ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme; Instance.OnThemeChanged (oldTheme); } } } /// /// Gets or sets the currently selected theme. The value is persisted to the "Theme" /// property. /// [JsonIgnore] public string Theme { get => ThemeManager.SelectedTheme; set { ThemeManager.SelectedTheme = value; } } /// /// 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)); } /// /// Event fired he selected theme has changed. /// application. /// public event EventHandler? ThemeChanged; /// /// Holds the definitions. /// [JsonInclude, JsonConverter (typeof (DictionaryJsonConverter))] [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] public static Dictionary? Themes { get => ConfigurationManager.Settings? ["Themes"]?.PropertyValue as Dictionary; // themes ?? new Dictionary (); set { //if (themes == null || value == null) { // themes = value; //} else { // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; //} ConfigurationManager.Settings! ["Themes"].PropertyValue = value; } } internal static void Reset () { Debug.WriteLine ($"Themes.Reset()"); Themes?.Clear (); SelectedTheme = string.Empty; } internal static void GetHardCodedDefaults () { Debug.WriteLine ($"Themes.GetHardCodedDefaults()"); var theme = new ThemeScope (); theme.RetrieveValues (); Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; SelectedTheme = "Default"; } #region IDictionary #pragma warning disable 1591 public ICollection Keys => ((IDictionary)Themes!).Keys; public ICollection Values => ((IDictionary)Themes!).Values; public int Count => ((ICollection>)Themes!).Count; public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; public ThemeScope this [string key] { get => ((IDictionary)Themes!) [key]; set => ((IDictionary)Themes!) [key] = value; } public void Add (string key, ThemeScope value) { ((IDictionary)Themes!).Add (key, value); } public bool ContainsKey (string key) { return ((IDictionary)Themes!).ContainsKey (key); } public bool Remove (string key) { return ((IDictionary)Themes!).Remove (key); } public bool TryGetValue (string key, out ThemeScope value) { return ((IDictionary)Themes!).TryGetValue (key, out value!); } public void Add (KeyValuePair item) { ((ICollection>)Themes!).Add (item); } public void Clear () { ((ICollection>)Themes!).Clear (); } public bool Contains (KeyValuePair item) { return ((ICollection>)Themes!).Contains (item); } public void CopyTo (KeyValuePair [] array, int arrayIndex) { ((ICollection>)Themes!).CopyTo (array, arrayIndex); } public bool Remove (KeyValuePair item) { return ((ICollection>)Themes!).Remove (item); } public IEnumerator> GetEnumerator () { return ((IEnumerable>)Themes!).GetEnumerator (); } IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable)Themes!).GetEnumerator (); } #pragma warning restore 1591 #endregion }