mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-30 01:38:01 +01:00
578 lines
26 KiB
C#
578 lines
26 KiB
C#
#nullable enable
|
|
using System.Collections.Immutable;
|
|
using System.Numerics;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Terminal.Gui.Drawing;
|
|
|
|
/// <summary>
|
|
/// Represents a theme definition that maps each <see cref="VisualRole"/> (such as <see cref="VisualRole.Focus"/>,
|
|
/// <see cref="VisualRole.Disabled"/>, etc.)
|
|
/// to an <see cref="Attribute"/> describing its foreground color, background color, and text style.
|
|
/// <para>
|
|
/// A <see cref="Scheme"/> enables consistent, semantic theming of UI elements by associating each visual state
|
|
/// with a specific style.
|
|
/// Each property (e.g., <see cref="Normal"/>, <see cref="Focus"/>, <see cref="Disabled"/>) is an
|
|
/// <see cref="Attribute"/>.
|
|
/// If a property is not explicitly set, its value is derived from other roles (typically <see cref="Normal"/>)
|
|
/// using well-defined inheritance rules.
|
|
/// </para>
|
|
/// <para>
|
|
/// <see cref="Scheme"/> objects are immutable. To update a scheme, create a new instance with the desired values.
|
|
/// Use <see cref="SchemeManager"/> to manage available schemes and apply them to views.
|
|
/// </para>
|
|
/// <para>
|
|
/// See <see href="https://gui-cs.github.io/Terminal.Gui/docs/drawing.html"/> for more information.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <b>Immutability:</b> Scheme objects are immutable. Once constructed, their properties cannot be changed. To
|
|
/// modify a Scheme,
|
|
/// create a new instance with the desired values (e.g., using the <see cref="Scheme(Scheme)"/> constructor).
|
|
/// </para>
|
|
/// <para>
|
|
/// <b>Attribute Resolution Algorithm:</b>
|
|
/// <br/>
|
|
/// Each <see cref="Scheme"/> property corresponds to a <see cref="VisualRole"/> and is an <see cref="Attribute"/>.
|
|
/// The <see cref="Normal"/> attribute must always be set.
|
|
/// All other attributes are optional. If an attribute for a given <see cref="VisualRole"/> is not explicitly set,
|
|
/// its value is derived using the following rules:
|
|
/// <list type="number">
|
|
/// <item>
|
|
/// <description><b>Normal:</b> Must always be explicitly set.</description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>Focus:</b> If not set, derived from <see cref="Normal"/> by swapping foreground and background
|
|
/// colors.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>Active:</b> If not set, derived from <see cref="Focus"/> by:
|
|
/// <list type="bullet">
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Foreground</c> to <see cref="Focus"/>'s foreground with
|
|
/// <c>GetHighlightColor()</c>.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Background</c> to <see cref="Focus"/>'s background with
|
|
/// <c>GetDimColor()</c>.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>Adding <see cref="TextStyle.Bold"/> to the style.</description>
|
|
/// </item>
|
|
/// </list>
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>Highlight:</b> If not set, derived from <see cref="Normal"/> by:
|
|
/// <list type="bullet">
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Foreground</c> to <see cref="Normal"/>'s background with
|
|
/// <c>GetHighlightColor()</c>.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>Setting <c>Background</c> to <see cref="Normal"/>'s background.</description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Style</c> to <see cref="Editable"/>'s style with
|
|
/// <see cref="TextStyle.Italic"/> added.
|
|
/// </description>
|
|
/// </item>
|
|
/// </list>
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>Editable:</b> If not set, derived from <see cref="Normal"/> by:
|
|
/// <list type="bullet">
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Foreground</c> to <see cref="Normal"/>'s background with
|
|
/// <c>GetHighlightColor()</c>.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// Setting <c>Background</c> to <see cref="Normal"/>'s background with
|
|
/// <c>GetDimColor()</c>.
|
|
/// </description>
|
|
/// </item>
|
|
/// </list>
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>ReadOnly:</b> If not set, derived from <see cref="Editable"/> by adding
|
|
/// <see cref="TextStyle.Faint"/> to the style.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>Disabled:</b> If not set, derived from <see cref="Normal"/> by adding
|
|
/// <see cref="TextStyle.Faint"/> to the style.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>HotNormal:</b> If not set, derived from <see cref="Normal"/> by adding
|
|
/// <see cref="TextStyle.Underline"/> to the style.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>HotFocus:</b> If not set, derived from <see cref="Focus"/> by adding
|
|
/// <see cref="TextStyle.Underline"/> to the style.
|
|
/// </description>
|
|
/// </item>
|
|
/// <item>
|
|
/// <description>
|
|
/// <b>HotActive:</b> If not set, derived from <see cref="Active"/> by adding
|
|
/// <see cref="TextStyle.Underline"/> to the style.
|
|
/// </description>
|
|
/// </item>
|
|
/// </list>
|
|
/// This algorithm ensures that every <see cref="VisualRole"/> always resolves to a valid <see cref="Attribute"/>,
|
|
/// either explicitly set or derived.
|
|
/// </para>
|
|
/// </remarks>
|
|
[JsonConverter (typeof (SchemeJsonConverter))]
|
|
public record Scheme : IEqualityOperators<Scheme, Scheme, bool>
|
|
{
|
|
/// <summary>
|
|
/// INTERNAL: Gets the hard-coded set of <see cref="Scheme"/>s. Used for generating the built-in config.json and for
|
|
/// unit tests that don't depend on ConfigurationManager.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
internal static ImmutableSortedDictionary<string, Scheme> GetHardCodedSchemes ()
|
|
{
|
|
return ImmutableSortedDictionary.CreateRange (
|
|
StringComparer.InvariantCultureIgnoreCase,
|
|
[
|
|
new KeyValuePair<string, Scheme> (SchemeManager.SchemesToSchemeName (Schemes.Base)!, CreateBase ()),
|
|
new (SchemeManager.SchemesToSchemeName (Schemes.Dialog)!, CreateDialog ()),
|
|
new (SchemeManager.SchemesToSchemeName (Schemes.Error)!, CreateError ()),
|
|
new (SchemeManager.SchemesToSchemeName (Schemes.Menu)!, CreateMenu ()),
|
|
new (SchemeManager.SchemesToSchemeName (Schemes.Toplevel)!, CreateToplevel ()),
|
|
]
|
|
);
|
|
|
|
Scheme CreateBase ()
|
|
{
|
|
return new ()
|
|
{
|
|
Normal = new (StandardColor.LightBlue, StandardColor.RaisinBlack)
|
|
};
|
|
}
|
|
|
|
Scheme CreateError ()
|
|
{
|
|
return new ()
|
|
{
|
|
Normal = new (StandardColor.IndianRed, StandardColor.RaisinBlack)
|
|
};
|
|
}
|
|
|
|
Scheme CreateDialog ()
|
|
{
|
|
return new ()
|
|
{
|
|
Normal = new (StandardColor.LightSkyBlue, StandardColor.OuterSpace)
|
|
};
|
|
}
|
|
|
|
Scheme CreateMenu ()
|
|
{
|
|
return new ()
|
|
{
|
|
Normal = new (StandardColor.Charcoal, StandardColor.LightBlue, TextStyle.Bold)
|
|
};
|
|
}
|
|
|
|
Scheme CreateToplevel ()
|
|
{
|
|
return new ()
|
|
{
|
|
Normal = new (StandardColor.CadetBlue, StandardColor.Charcoal)
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>Creates a new instance set to the default attributes (see <see cref="Attribute.Default"/>).</summary>
|
|
public Scheme () : this (Attribute.Default) { }
|
|
|
|
/// <summary>Creates a new instance, initialized with the values from <paramref name="scheme"/>.</summary>
|
|
/// <param name="scheme">The scheme to initialize the new instance with.</param>
|
|
public Scheme (Scheme? scheme)
|
|
{
|
|
ArgumentNullException.ThrowIfNull (scheme);
|
|
|
|
Normal = scheme.Normal;
|
|
|
|
_hotNormal = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.HotNormal, out Attribute? hotNormal) ? hotNormal : null;
|
|
_focus = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.Focus, out Attribute? focus) ? focus : null;
|
|
_hotFocus = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.HotFocus, out Attribute? hotFocus) ? hotFocus : null;
|
|
_active = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.Active, out Attribute? active) ? active : null;
|
|
_hotActive = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.HotActive, out Attribute? hotActive) ? hotActive : null;
|
|
_highlight = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.Highlight, out Attribute? highlight) ? highlight : null;
|
|
_editable = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.Editable, out Attribute? editable) ? editable : null;
|
|
_readOnly = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.ReadOnly, out Attribute? readOnly) ? readOnly : null;
|
|
_disabled = scheme.TryGetExplicitlySetAttributeForRole (VisualRole.Disabled, out Attribute? disabled) ? disabled : null;
|
|
}
|
|
|
|
/// <summary>Creates a new instance, initialized with the values from <paramref name="attribute"/>.</summary>
|
|
/// <param name="attribute">The attribute to initialize the new instance with.</param>
|
|
public Scheme (Attribute attribute)
|
|
{
|
|
// Only set Normal as explicitly set
|
|
Normal = attribute;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Attribute"/> associated with a specified <see cref="VisualRole"/>,
|
|
/// applying inheritance rules for attributes not explicitly set.
|
|
/// </summary>
|
|
/// <param name="role">The semantic <see cref="VisualRole"/> describing the element being rendered.</param>
|
|
/// <returns>
|
|
/// The corresponding <see cref="Attribute"/> from the <see cref="Scheme"/>, possibly derived if not explicitly
|
|
/// set.
|
|
/// </returns>
|
|
public Attribute GetAttributeForRole (VisualRole role)
|
|
{
|
|
// Use a HashSet to guard against recursion cycles
|
|
return GetAttributeForRoleCore (role, []);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to get the <see cref="Attribute"/> associated with a specified <see cref="VisualRole"/>. If the
|
|
/// role is not explicitly set, it will return false and the out parameter will be null.
|
|
/// </summary>
|
|
/// <param name="role"></param>
|
|
/// <param name="attribute"></param>
|
|
/// <returns></returns>
|
|
public bool TryGetExplicitlySetAttributeForRole (VisualRole role, out Attribute? attribute)
|
|
{
|
|
// Use a HashSet to guard against recursion cycles
|
|
attribute = role switch
|
|
{
|
|
VisualRole.Normal => _normal,
|
|
VisualRole.HotNormal => _hotNormal,
|
|
VisualRole.Focus => _focus,
|
|
VisualRole.HotFocus => _hotFocus,
|
|
VisualRole.Active => _active,
|
|
VisualRole.HotActive => _hotActive,
|
|
VisualRole.Highlight => _highlight,
|
|
VisualRole.Editable => _editable,
|
|
VisualRole.ReadOnly => _readOnly,
|
|
VisualRole.Disabled => _disabled,
|
|
_ => null
|
|
};
|
|
|
|
return attribute is { };
|
|
}
|
|
|
|
// TODO: Provide a CWP-based API that lets devs override this algo?
|
|
|
|
private Attribute GetAttributeForRoleCore (VisualRole role, HashSet<VisualRole> stack)
|
|
{
|
|
// Prevent infinite recursion
|
|
if (!stack.Add (role))
|
|
{
|
|
return Normal; // fallback
|
|
}
|
|
|
|
Attribute? attr = Normal;
|
|
if (role == VisualRole.Normal || TryGetExplicitlySetAttributeForRole (role, out attr))
|
|
{
|
|
return attr!.Value;
|
|
}
|
|
|
|
// TODO: Provide an API that lets devs override this algo?
|
|
|
|
// Derivation algorithm as documented
|
|
Attribute result = role switch
|
|
{
|
|
VisualRole.Focus =>
|
|
GetAttributeForRoleCore (VisualRole.Normal, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Background,
|
|
Background = GetAttributeForRoleCore (VisualRole.Normal, stack).Foreground
|
|
},
|
|
|
|
VisualRole.Active =>
|
|
GetAttributeForRoleCore (VisualRole.Focus, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Focus, stack).Foreground.GetBrighterColor (),
|
|
Background = GetAttributeForRoleCore (VisualRole.Focus, stack).Background.GetDimColor (),
|
|
Style = GetAttributeForRoleCore (VisualRole.Focus, stack).Style | TextStyle.Bold
|
|
},
|
|
|
|
VisualRole.Highlight =>
|
|
GetAttributeForRoleCore (VisualRole.Normal, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Background.GetBrighterColor (),
|
|
Background = GetAttributeForRoleCore (VisualRole.Normal, stack).Background,
|
|
Style = GetAttributeForRoleCore (VisualRole.Editable, stack).Style | TextStyle.Italic
|
|
},
|
|
|
|
VisualRole.Editable =>
|
|
GetAttributeForRoleCore (VisualRole.Normal, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Foreground,
|
|
Background = GetAttributeForRoleCore (VisualRole.Normal, stack).Foreground.GetDimColor (0.5)
|
|
},
|
|
|
|
VisualRole.ReadOnly =>
|
|
GetAttributeForRoleCore (VisualRole.Editable, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Editable, stack).Foreground.GetDimColor (0.05),
|
|
},
|
|
|
|
VisualRole.Disabled =>
|
|
GetAttributeForRoleCore (VisualRole.Normal, stack) with
|
|
{
|
|
Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Foreground.GetDimColor (0.05),
|
|
},
|
|
|
|
VisualRole.HotNormal =>
|
|
GetAttributeForRoleCore (VisualRole.Normal, stack) with
|
|
{
|
|
Style = GetAttributeForRoleCore (VisualRole.Normal, stack).Style | TextStyle.Underline
|
|
},
|
|
|
|
VisualRole.HotFocus =>
|
|
GetAttributeForRoleCore (VisualRole.Focus, stack) with
|
|
{
|
|
Style = GetAttributeForRoleCore (VisualRole.Focus, stack).Style | TextStyle.Underline
|
|
},
|
|
|
|
VisualRole.HotActive =>
|
|
GetAttributeForRoleCore (VisualRole.Active, stack) with
|
|
{
|
|
Style = GetAttributeForRoleCore (VisualRole.Active, stack).Style | TextStyle.Underline
|
|
},
|
|
|
|
_ => GetAttributeForRoleCore (VisualRole.Normal, stack)
|
|
};
|
|
|
|
stack.Remove (role);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Attribute"/> associated with a specified <see cref="VisualRole"/> string.
|
|
/// </summary>
|
|
/// <param name="roleName">The name of the <see cref="VisualRole"/> describing the element being rendered.</param>
|
|
/// <returns>The corresponding <see cref="Attribute"/> from the <see cref="Scheme"/>.</returns>
|
|
public Attribute GetAttributeForRole (string roleName)
|
|
{
|
|
if (Enum.TryParse (roleName, true, out VisualRole role))
|
|
{
|
|
return GetAttributeForRole (role);
|
|
}
|
|
|
|
// If the string does not match any VisualRole, return the default Normal attribute
|
|
return Normal;
|
|
}
|
|
|
|
// Helper method for property _get implementation
|
|
private Attribute GetAttributeForRoleProperty (Attribute? explicitValue, VisualRole role)
|
|
{
|
|
if (explicitValue is { })
|
|
{
|
|
return explicitValue.Value;
|
|
}
|
|
|
|
return GetAttributeForRoleCore (role, []);
|
|
}
|
|
|
|
// Helper method for property _set implementation
|
|
private Attribute? SetAttributeForRoleProperty (Attribute value, VisualRole role)
|
|
{
|
|
// If value is the same as the algorithm value, use null
|
|
if (GetAttributeForRoleCore (role, []) == value)
|
|
{
|
|
return null;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private readonly Attribute? _normal;
|
|
|
|
/// <summary>
|
|
/// The default visual role for unfocused, unselected, enabled elements.
|
|
/// The Normal attribute must always be set. All other attributes are optional, and if not explicitly
|
|
/// set, will be automatically generated. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Normal
|
|
{
|
|
get => _normal!.Value;
|
|
init => _normal = value;
|
|
}
|
|
|
|
private readonly Attribute? _hotNormal;
|
|
|
|
/// <summary>
|
|
/// The visual role for <see cref="Normal"/> elements with a <see cref="View.HotKey"/> indicator.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute HotNormal
|
|
{
|
|
get => GetAttributeForRoleProperty (_hotNormal, VisualRole.HotNormal);
|
|
init => _hotNormal = SetAttributeForRoleProperty (value, VisualRole.HotNormal);
|
|
}
|
|
|
|
private readonly Attribute? _focus;
|
|
|
|
/// <summary>
|
|
/// The visual role when the element is focused.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Focus
|
|
{
|
|
get => GetAttributeForRoleProperty (_focus, VisualRole.Focus);
|
|
init => _focus = SetAttributeForRoleProperty (value, VisualRole.Focus);
|
|
}
|
|
|
|
private readonly Attribute? _hotFocus;
|
|
|
|
/// <summary>
|
|
/// The visual role for <see cref="Focus"/> elements with a <see cref="View.HotKey"/> indicator.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute HotFocus
|
|
{
|
|
get => GetAttributeForRoleProperty (_hotFocus, VisualRole.HotFocus);
|
|
init => _hotFocus = SetAttributeForRoleProperty (value, VisualRole.HotFocus);
|
|
}
|
|
|
|
private readonly Attribute? _active;
|
|
|
|
/// <summary>
|
|
/// The visual role for elements that are active or selected (e.g., selected item in a <see cref="ListView"/>). Also
|
|
/// used
|
|
/// for headers in, <see cref="HexView"/>, <see cref="CharMap"/> and <see cref="TabView"/>.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Active
|
|
{
|
|
get => GetAttributeForRoleProperty (_active, VisualRole.Active);
|
|
init => _active = SetAttributeForRoleProperty (value, VisualRole.Active);
|
|
}
|
|
|
|
private readonly Attribute? _hotActive;
|
|
|
|
/// <summary>
|
|
/// The visual role for <see cref="Active"/> elements with a <see cref="View.HotKey"/> indicator.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute HotActive
|
|
{
|
|
get => GetAttributeForRoleProperty (_hotActive, VisualRole.HotActive);
|
|
init => _hotActive = SetAttributeForRoleProperty (value, VisualRole.HotActive);
|
|
}
|
|
|
|
private readonly Attribute? _highlight;
|
|
|
|
/// <summary>
|
|
/// The visual role for elements that are highlighted (e.g., when the mouse is inside a <see cref="Button"/>).
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Highlight
|
|
{
|
|
get => GetAttributeForRoleProperty (_highlight, VisualRole.Highlight);
|
|
init => _highlight = SetAttributeForRoleProperty (value, VisualRole.Highlight);
|
|
}
|
|
|
|
private readonly Attribute? _editable;
|
|
|
|
/// <summary>
|
|
/// The visual role for elements that are editable (e.g., <see cref="TextField"/> and <see cref="TextView"/>).
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Editable
|
|
{
|
|
get => GetAttributeForRoleProperty (_editable, VisualRole.Editable);
|
|
init => _editable = SetAttributeForRoleProperty (value, VisualRole.Editable);
|
|
}
|
|
|
|
private readonly Attribute? _readOnly;
|
|
|
|
/// <summary>
|
|
/// The visual role for elements that are normally editable but currently read-only.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute ReadOnly
|
|
{
|
|
get => GetAttributeForRoleProperty (_readOnly, VisualRole.ReadOnly);
|
|
init => _readOnly = SetAttributeForRoleProperty (value, VisualRole.ReadOnly);
|
|
}
|
|
|
|
private readonly Attribute? _disabled;
|
|
|
|
/// <summary>
|
|
/// The visual role for elements that are disabled and not interactable.
|
|
/// If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
|
|
/// algorithm used.
|
|
/// </summary>
|
|
public Attribute Disabled
|
|
{
|
|
get => GetAttributeForRoleProperty (_disabled, VisualRole.Disabled);
|
|
init => _disabled = SetAttributeForRoleProperty (value, VisualRole.Disabled);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public virtual bool Equals (Scheme? other)
|
|
{
|
|
return other is { }
|
|
&& EqualityComparer<Attribute>.Default.Equals (Normal, other.Normal)
|
|
&& EqualityComparer<Attribute>.Default.Equals (HotNormal, other.HotNormal)
|
|
&& EqualityComparer<Attribute>.Default.Equals (Focus, other.Focus)
|
|
&& EqualityComparer<Attribute>.Default.Equals (HotFocus, other.HotFocus)
|
|
&& EqualityComparer<Attribute>.Default.Equals (Active, other.Active)
|
|
&& EqualityComparer<Attribute>.Default.Equals (HotActive, other.HotActive)
|
|
&& EqualityComparer<Attribute>.Default.Equals (Highlight, other.Highlight)
|
|
&& EqualityComparer<Attribute>.Default.Equals (Editable, other.Editable)
|
|
&& EqualityComparer<Attribute>.Default.Equals (ReadOnly, other.ReadOnly)
|
|
&& EqualityComparer<Attribute>.Default.Equals (Disabled, other.Disabled);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode ()
|
|
{
|
|
return HashCode.Combine (
|
|
HashCode.Combine (Normal, HotNormal, Focus, HotFocus, Active, HotActive, Highlight, Editable),
|
|
HashCode.Combine (ReadOnly, Disabled)
|
|
);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override string ToString ()
|
|
{
|
|
return $"Normal: {Normal}; HotNormal: {HotNormal}; Focus: {Focus}; HotFocus: {HotFocus}; "
|
|
+ $"Active: {Active}; HotActive: {HotActive}; Highlight: {Highlight}; Editable: {Editable}; "
|
|
+ $"ReadOnly: {ReadOnly}; Disabled: {Disabled}";
|
|
}
|
|
}
|