View.Drawing.Attribute.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #nullable enable
  2. using System.ComponentModel;
  3. namespace Terminal.Gui.ViewBase;
  4. public partial class View
  5. {
  6. #region Get
  7. /// <summary>Gets the current <see cref="System.Attribute"/> used by <see cref="AddRune(System.Text.Rune)"/>.</summary>
  8. /// <returns>The current attribute.</returns>
  9. public Attribute GetCurrentAttribute () { return Driver?.GetAttribute () ?? Attribute.Default; }
  10. /// <summary>
  11. /// Gets the <see cref="Attribute"/> associated with a specified <see cref="VisualRole"/>
  12. /// from the <see cref="Scheme"/>.
  13. /// <para>
  14. /// Raises <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
  15. /// which can cancel the default behavior, and optionally change the attribute in the event args.
  16. /// </para>
  17. /// <para>
  18. /// If <see cref="Enabled"/> is <see langword="false"/>, <see cref="VisualRole.Disabled"/>
  19. /// will be used instead of <paramref name="role"></paramref>.
  20. /// To override this behavior use <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
  21. /// to cancel the method, and return a different attribute.
  22. /// </para>
  23. /// <para>
  24. /// If <see cref="HighlightStates"/> is not <see cref="MouseState.None"/> and <see cref="MouseState"/> is <see cref="MouseState.In"/>
  25. /// the <see cref="VisualRole.Highlight"/> will be used instead of <paramref name="role"/>.
  26. /// To override this behavior use <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
  27. /// to cancel the method, and return a different attribute.
  28. /// </para>
  29. /// </summary>
  30. /// <param name="role">The semantic <see cref="Drawing.VisualRole"/> describing the element being rendered.</param>
  31. /// <returns>The corresponding <see cref="Attribute"/> from the <see cref="Drawing.Scheme"/>.</returns>
  32. public Attribute GetAttributeForRole (VisualRole role)
  33. {
  34. // Get the base attribute
  35. // If this view doesn't have an explicit scheme or scheme name, defer to SuperView for attribute resolution.
  36. // This allows parent views to customize attribute resolution for their children via
  37. // OnGettingAttributeForRole/GettingAttributeForRole.
  38. // This matches the logic in GetScheme() where SchemeName takes precedence over SuperView inheritance.
  39. Attribute schemeAttribute;
  40. if (!HasScheme && string.IsNullOrEmpty (SchemeName) && SuperView is { })
  41. {
  42. schemeAttribute = SuperView.GetAttributeForRole (role);
  43. }
  44. else
  45. {
  46. schemeAttribute = GetScheme ()!.GetAttributeForRole (role);
  47. }
  48. if (OnGettingAttributeForRole (role, ref schemeAttribute))
  49. {
  50. // The implementation may have changed the attribute
  51. return schemeAttribute;
  52. }
  53. VisualRoleEventArgs args = new (role, result: schemeAttribute);
  54. GettingAttributeForRole?.Invoke (this, args);
  55. if (args is { Handled: true, Result: { } })
  56. {
  57. // A handler may have changed the attribute
  58. return args.Result.Value;
  59. }
  60. if (role != VisualRole.Disabled && HighlightStates != MouseState.None)
  61. {
  62. // The default behavior for HighlightStates of MouseState.Over is to use the Highlight role
  63. if (((HighlightStates.HasFlag (MouseState.In) && MouseState.HasFlag (MouseState.In))
  64. || (HighlightStates.HasFlag (MouseState.Pressed) && MouseState.HasFlag (MouseState.Pressed)))
  65. && role != VisualRole.Highlight && !HasFocus)
  66. {
  67. schemeAttribute = GetAttributeForRole (VisualRole.Highlight);
  68. }
  69. }
  70. return Enabled || role == VisualRole.Disabled ? schemeAttribute : GetAttributeForRole (VisualRole.Disabled);
  71. }
  72. /// <summary>
  73. /// Called when the Attribute for a <see cref="GetAttributeForRole(VisualRole)"/> is being retrieved.
  74. /// Implementations can
  75. /// return <see langword="true"/> to stop further processing and optionally set the <see cref="Attribute"/> in the
  76. /// event args to a different value.
  77. /// </summary>
  78. /// <param name="role"></param>
  79. /// <param name="currentAttribute">The current value of the Attribute for the VisualRole. This by-ref value can be changed</param>
  80. /// <returns></returns>
  81. protected virtual bool OnGettingAttributeForRole (in VisualRole role, ref Attribute currentAttribute) { return false; }
  82. /// <summary>
  83. /// Raised when the Attribute for a <see cref="GetAttributeForRole(VisualRole)"/> is being retrieved.
  84. /// Handlers should check if <see cref="CancelEventArgs.Cancel"/>
  85. /// has been set to <see langword="true"/> and do nothing if so. If Cancel is <see langword="false"/>
  86. /// a handler can set it to <see langword="true"/> to stop further processing optionally change the
  87. /// `CurrentValue` in the event args to a different value.
  88. /// </summary>
  89. public event EventHandler<VisualRoleEventArgs>? GettingAttributeForRole;
  90. #endregion Get
  91. #region Set
  92. /// <summary>
  93. /// Selects the specified Attribute
  94. /// as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr"/>.
  95. /// </summary>
  96. /// <param name="attribute">THe Attribute to set.</param>
  97. /// <returns>The previously set Attribute.</returns>
  98. public Attribute SetAttribute (Attribute attribute) { return Driver?.SetAttribute (attribute) ?? Attribute.Default; }
  99. /// <summary>
  100. /// Selects the Attribute associated with the specified <see cref="VisualRole"/>
  101. /// as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr"/>.
  102. /// <para>
  103. /// Calls <see cref="GetAttributeForRole"/> to get the Attribute associated with the specified role, which will
  104. /// raise <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>.
  105. /// </para>
  106. /// </summary>
  107. /// <param name="role">The semantic <see cref="VisualRole"/> describing the element being rendered.</param>
  108. /// <returns>The previously set Attribute.</returns>
  109. public Attribute? SetAttributeForRole (VisualRole role)
  110. {
  111. Attribute schemeAttribute = GetAttributeForRole (role);
  112. Attribute currentAttribute = GetCurrentAttribute ();
  113. return SetAttribute (schemeAttribute);
  114. }
  115. #endregion Set
  116. }