ColorScheme.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #nullable enable
  2. using System.Globalization;
  3. using System.Text.Json.Serialization;
  4. namespace Terminal.Gui;
  5. /// <summary>Defines a standard set of <see cref="Attribute"/>s for common visible elements in a <see cref="View"/>.</summary>
  6. /// <remarks>
  7. /// <para>
  8. /// ColorScheme objects are immutable. Once constructed, the properties cannot be changed. To change a
  9. /// ColorScheme, create a new one with the desired values, using the <see cref="ColorScheme(ColorScheme)"/>
  10. /// constructor.
  11. /// </para>
  12. /// </remarks>
  13. [JsonConverter (typeof (ColorSchemeJsonConverter))]
  14. public class ColorScheme : IEquatable<ColorScheme>
  15. {
  16. private readonly Attribute _disabled;
  17. private readonly Attribute _focus;
  18. private readonly Attribute _hotFocus;
  19. private readonly Attribute _hotNormal;
  20. private readonly Attribute _normal;
  21. /// <summary>Creates a new instance set to the default colors (see <see cref="Attribute.Default"/>).</summary>
  22. public ColorScheme () : this (Attribute.Default) { }
  23. /// <summary>Creates a new instance, initialized with the values from <paramref name="scheme"/>.</summary>
  24. /// <param name="scheme">The scheme to initialize the new instance with.</param>
  25. public ColorScheme (ColorScheme scheme)
  26. {
  27. if (scheme is null)
  28. {
  29. throw new ArgumentNullException (nameof (scheme));
  30. }
  31. _normal = scheme.Normal;
  32. _focus = scheme.Focus;
  33. _hotNormal = scheme.HotNormal;
  34. _disabled = scheme.Disabled;
  35. _hotFocus = scheme.HotFocus;
  36. }
  37. /// <summary>Creates a new instance, initialized with the values from <paramref name="attribute"/>.</summary>
  38. /// <param name="attribute">The attribute to initialize the new instance with.</param>
  39. public ColorScheme (Attribute attribute)
  40. {
  41. _normal = attribute;
  42. _focus = attribute;
  43. _hotNormal = attribute;
  44. _disabled = attribute;
  45. _hotFocus = attribute;
  46. }
  47. /// <summary>The default foreground and background color for text when the view is disabled.</summary>
  48. public Attribute Disabled
  49. {
  50. get => _disabled;
  51. init => _disabled = value;
  52. }
  53. /// <summary>The foreground and background color for text when the view has the focus.</summary>
  54. public Attribute Focus
  55. {
  56. get => _focus;
  57. init => _focus = value;
  58. }
  59. /// <summary>The foreground and background color for for text in a focused view that indicates a <see cref="View.HotKey"/>.</summary>
  60. public Attribute HotFocus
  61. {
  62. get => _hotFocus;
  63. init => _hotFocus = value;
  64. }
  65. /// <summary>The foreground and background color for text in a non-focused view that indicates a <see cref="View.HotKey"/>.</summary>
  66. public Attribute HotNormal
  67. {
  68. get => _hotNormal;
  69. init => _hotNormal = value;
  70. }
  71. /// <summary>The foreground and background color for text when the view is not focused, hot, or disabled.</summary>
  72. public Attribute Normal
  73. {
  74. get => _normal;
  75. init => _normal = value;
  76. }
  77. /// <summary>Compares two <see cref="ColorScheme"/> objects for equality.</summary>
  78. /// <param name="other"></param>
  79. /// <returns>true if the two objects are equal</returns>
  80. public bool Equals (ColorScheme? other)
  81. {
  82. return other is { }
  83. && EqualityComparer<Attribute>.Default.Equals (_normal, other._normal)
  84. && EqualityComparer<Attribute>.Default.Equals (_focus, other._focus)
  85. && EqualityComparer<Attribute>.Default.Equals (_hotNormal, other._hotNormal)
  86. && EqualityComparer<Attribute>.Default.Equals (_hotFocus, other._hotFocus)
  87. && EqualityComparer<Attribute>.Default.Equals (_disabled, other._disabled);
  88. }
  89. /// <summary>Compares two <see cref="ColorScheme"/> objects for equality.</summary>
  90. /// <param name="obj"></param>
  91. /// <returns>true if the two objects are equal</returns>
  92. public override bool Equals (object? obj) { return Equals (obj as ColorScheme); }
  93. /// <summary>Returns a hashcode for this instance.</summary>
  94. /// <returns>hashcode for this instance</returns>
  95. public override int GetHashCode ()
  96. {
  97. int hashCode = -1242460230;
  98. hashCode = hashCode * -1521134295 + _normal.GetHashCode ();
  99. hashCode = hashCode * -1521134295 + _focus.GetHashCode ();
  100. hashCode = hashCode * -1521134295 + _hotNormal.GetHashCode ();
  101. hashCode = hashCode * -1521134295 + _hotFocus.GetHashCode ();
  102. hashCode = hashCode * -1521134295 + _disabled.GetHashCode ();
  103. return hashCode;
  104. }
  105. /// <summary>Compares two <see cref="ColorScheme"/> objects for equality.</summary>
  106. /// <param name="left"></param>
  107. /// <param name="right"></param>
  108. /// <returns><c>true</c> if the two objects are equivalent</returns>
  109. public static bool operator == (ColorScheme left, ColorScheme right) { return EqualityComparer<ColorScheme>.Default.Equals (left, right); }
  110. /// <summary>Compares two <see cref="ColorScheme"/> objects for inequality.</summary>
  111. /// <param name="left"></param>
  112. /// <param name="right"></param>
  113. /// <returns><c>true</c> if the two objects are not equivalent</returns>
  114. public static bool operator != (ColorScheme left, ColorScheme right) { return !(left == right); }
  115. /// <inheritdoc/>
  116. public override string ToString () { return $"Normal: {Normal}; Focus: {Focus}; HotNormal: {HotNormal}; HotFocus: {HotFocus}; Disabled: {Disabled}"; }
  117. }
  118. /// <summary>
  119. /// Holds the <see cref="ColorScheme"/>s that define the <see cref="Attribute"/>s that are used by views to render
  120. /// themselves.
  121. /// </summary>
  122. public static class Colors
  123. {
  124. static Colors () { Reset (); }
  125. /// <summary>Gets a dictionary of defined <see cref="ColorScheme"/> objects.</summary>
  126. /// <remarks>
  127. /// <para>
  128. /// The <see cref="ColorSchemes"/> dictionary includes the following keys, by default:
  129. /// <list type="table">
  130. /// <listheader>
  131. /// <term>Built-in Color Scheme</term> <description>Description</description>
  132. /// </listheader>
  133. /// <item>
  134. /// <term>Base</term> <description>The base color scheme used for most Views.</description>
  135. /// </item>
  136. /// <item>
  137. /// <term>TopLevel</term>
  138. /// <description>The application Toplevel color scheme; used for the <see cref="Toplevel"/> View.</description>
  139. /// </item>
  140. /// <item>
  141. /// <term>Dialog</term>
  142. /// <description>
  143. /// The dialog color scheme; used for <see cref="Dialog"/>, <see cref="MessageBox"/>, and
  144. /// other views dialog-like views.
  145. /// </description>
  146. /// </item>
  147. /// <item>
  148. /// <term>Menu</term>
  149. /// <description>
  150. /// The menu color scheme; used for <see cref="MenuBar"/>, <see cref="ContextMenu"/>, and
  151. /// <see cref="StatusBar"/>.
  152. /// </description>
  153. /// </item>
  154. /// <item>
  155. /// <term>Error</term>
  156. /// <description>
  157. /// The color scheme for showing errors, such as in
  158. /// <see cref="MessageBox.ErrorQuery(string, string, string[])"/>.
  159. /// </description>
  160. /// </item>
  161. /// </list>
  162. /// </para>
  163. /// <para>Changing the values of an entry in this dictionary will affect all views that use the scheme.</para>
  164. /// <para>
  165. /// <see cref="ConfigurationManager"/> can be used to override the default values for these schemes and add
  166. /// additional schemes. See <see cref="ConfigurationManager.Themes"/>.
  167. /// </para>
  168. /// </remarks>
  169. [SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
  170. [JsonConverter (typeof (DictionaryJsonConverter<ColorScheme>))]
  171. public static Dictionary<string, ColorScheme>
  172. ColorSchemes { get; private set; } // Serialization requires this to have a setter (private set;)
  173. /// <summary>Resets the <see cref="ColorSchemes"/> dictionary to the default values.</summary>
  174. public static Dictionary<string, ColorScheme> Reset ()
  175. {
  176. ColorSchemes ??= new Dictionary<string, ColorScheme> (
  177. 5,
  178. CultureInfo.InvariantCulture.CompareInfo
  179. .GetStringComparer (
  180. CompareOptions.IgnoreCase
  181. )
  182. );
  183. ColorSchemes.Clear ();
  184. ColorSchemes.Add ("TopLevel", new ColorScheme ());
  185. ColorSchemes.Add ("Base", new ColorScheme ());
  186. ColorSchemes.Add ("Dialog", new ColorScheme ());
  187. ColorSchemes.Add ("Menu", new ColorScheme ());
  188. ColorSchemes.Add ("Error", new ColorScheme ());
  189. return ColorSchemes;
  190. }
  191. private class SchemeNameComparerIgnoreCase : IEqualityComparer<string>
  192. {
  193. public bool Equals (string x, string y)
  194. {
  195. if (x != null && y != null)
  196. {
  197. return string.Equals (x, y, StringComparison.InvariantCultureIgnoreCase);
  198. }
  199. return false;
  200. }
  201. public int GetHashCode (string obj) { return obj.ToLowerInvariant ().GetHashCode (); }
  202. }
  203. }