2020-12-05 16:42:21 +01:00
using System ;
2021-11-27 22:45:37 +01:00
using System.Collections.Generic ;
2019-08-10 21:37:10 +02:00
using Microsoft.Xna.Framework ;
using MLEM.Font ;
2019-12-26 19:30:17 +01:00
using MLEM.Formatting ;
2022-03-07 12:00:33 +01:00
using MLEM.Formatting.Codes ;
2024-07-19 20:02:28 +02:00
using MLEM.Maths ;
2020-03-21 00:49:43 +01:00
using MLEM.Misc ;
2022-08-20 11:39:28 +02:00
using MLEM.Sound ;
2019-08-10 21:37:10 +02:00
using MLEM.Textures ;
2020-05-22 17:02:24 +02:00
using MLEM.Ui.Elements ;
2019-08-10 21:37:10 +02:00
namespace MLEM.Ui.Style {
2020-05-22 17:02:24 +02:00
/// <summary>
/// The style settings for a <see cref="UiSystem"/>.
/// Each <see cref="Element"/> uses these style settings by default, however you can also change these settings per element using the elements' individual style settings.
2023-06-14 14:54:49 +02:00
/// Additional styles for built-in or custom element types can easily be added using <see cref="AddCustomStyle{T}"/>.
2020-05-22 17:02:24 +02:00
/// </summary>
2020-03-21 00:49:43 +01:00
public class UiStyle : GenericDataHolder {
2019-08-10 21:37:10 +02:00
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that is rendered on top of the <see cref="UiControls.SelectedElement"/>
/// </summary>
2019-08-28 18:27:17 +02:00
public NinePatch SelectionIndicator ;
2020-05-22 17:02:24 +02:00
/// <summary>
2023-06-14 14:54:49 +02:00
/// A <see cref="UiAnimation"/> that is played when the mouse enters an element.
/// </summary>
public UiAnimation MouseEnterAnimation ;
/// <summary>
/// A <see cref="UiAnimation"/> that is played when the mouse exists an element.
/// </summary>
public UiAnimation MouseExitAnimation ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="Button"/> element uses
/// </summary>
2019-08-10 21:37:10 +02:00
public NinePatch ButtonTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="Button"/> element uses when it is moused over (<see cref="Element.IsMouseOver"/>)
/// Note that, if you just want to change the button's color when hovered, use <see cref="ButtonHoveredColor"/>.
/// </summary>
2019-08-10 21:37:10 +02:00
public NinePatch ButtonHoveredTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="Button"/> element renders with when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2021-10-29 23:33:15 +02:00
public Color ButtonHoveredColor = Color . LightGray ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="Button"/> element uses when it <see cref="Button.IsDisabled"/>
/// </summary>
2020-01-15 17:05:28 +01:00
public NinePatch ButtonDisabledTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="Button"/> element uses when it <see cref="Button.IsDisabled"/>
/// </summary>
2021-10-29 23:33:15 +02:00
public Color ButtonDisabledColor = Color . Gray ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="Panel"/> element uses
/// </summary>
2019-08-10 21:37:10 +02:00
public NinePatch PanelTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
2023-06-14 14:54:49 +02:00
/// The color that the <see cref="Panel"/> element draws with.
/// </summary>
public Color PanelColor = Color . White ;
/// <summary>
2021-10-29 23:33:15 +02:00
/// The <see cref="Element.ChildPadding"/> to apply to a <see cref="Panel"/> by default
/// </summary>
public Padding PanelChildPadding = new Vector2 ( 5 ) ;
/// <summary>
/// The amount that a <see cref="Panel"/>'s scrollable area is moved per single movement of the scroll wheel
/// </summary>
public float PanelStepPerScroll = 10 ;
/// <summary>
/// The size of the scroller of a <see cref="Panel"/>'s scroll bar
/// </summary>
public Vector2 PanelScrollerSize = new Vector2 ( 5 , 10 ) ;
/// <summary>
2021-11-11 16:43:27 +01:00
/// The amount of pixels of room there should be between a <see cref="Panel"/>'s scroll bar and the rest of its content
/// </summary>
public float PanelScrollBarOffset = 1 ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="TextField"/> element uses
/// </summary>
2019-08-10 21:37:10 +02:00
public NinePatch TextFieldTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="TextField"/> element uses when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2019-08-10 21:37:10 +02:00
public NinePatch TextFieldHoveredTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="TextField"/> renders with when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2021-10-29 23:33:15 +02:00
public Color TextFieldHoveredColor = Color . LightGray ;
/// <summary>
/// The x position that a <see cref="TextField"/>'s text should start rendering at, based on the x position of the text field
/// </summary>
public float TextFieldTextOffsetX = 4 ;
/// <summary>
/// The width that a <see cref="TextField"/>'s caret should render with
/// </summary>
public float TextFieldCaretWidth = 0.5F ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The background texture that the <see cref="ScrollBar"/> element uses
/// </summary>
2019-08-12 19:44:16 +02:00
public NinePatch ScrollBarBackground ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the scroll indicator of the <see cref="ScrollBar"/> element uses
/// </summary>
2019-08-12 19:44:16 +02:00
public NinePatch ScrollBarScrollerTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
2021-10-29 23:33:15 +02:00
/// Whether or not a <see cref="ScrollBar"/> should use smooth scrolling
/// </summary>
public bool ScrollBarSmoothScrolling ;
/// <summary>
/// The factor with which a <see cref="ScrollBar"/>'s smooth scrolling happens
/// </summary>
public float ScrollBarSmoothScrollFactor = 0.75F ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="Checkbox"/> element uses
/// </summary>
2019-08-13 21:23:20 +02:00
public NinePatch CheckboxTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="Checkbox"/> element uses when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2019-08-13 21:23:20 +02:00
public NinePatch CheckboxHoveredTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="Checkbox"/> element renders with when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2021-10-29 23:33:15 +02:00
public Color CheckboxHoveredColor = Color . LightGray ;
2020-05-22 17:02:24 +02:00
/// <summary>
2021-12-24 12:10:04 +01:00
/// The texture that the <see cref="Checkbox"/> element uses when it <see cref="Checkbox.IsDisabled"/>.
/// </summary>
public NinePatch CheckboxDisabledTexture ;
/// <summary>
/// The color that the <see cref="Checkbox"/> element uses when it <see cref="Checkbox.IsDisabled"/>.
/// </summary>
public Color CheckboxDisabledColor = Color . Gray ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="Checkbox"/> element renders on top of its regular texture when it is <see cref="Checkbox.Checked"/>
/// </summary>
2019-08-13 21:23:20 +02:00
public TextureRegion CheckboxCheckmark ;
2020-05-22 17:02:24 +02:00
/// <summary>
2021-10-29 23:33:15 +02:00
/// The width of the space between a <see cref="Checkbox"/> and its <see cref="Checkbox.Label"/>
/// </summary>
public float CheckboxTextOffsetX = 2 ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="RadioButton"/> element uses
/// </summary>
2019-08-13 21:23:20 +02:00
public NinePatch RadioTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="RadioButton"/> element uses when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2019-08-13 21:23:20 +02:00
public NinePatch RadioHoveredTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="RadioButton"/> element renders with when it is moused over (<see cref="Element.IsMouseOver"/>)
/// </summary>
2021-10-29 23:33:15 +02:00
public Color RadioHoveredColor = Color . LightGray ;
2020-05-22 17:02:24 +02:00
/// <summary>
2020-10-06 20:14:57 +02:00
/// The texture that the <see cref="RadioButton"/> renders on top of its regular texture when it is <see cref="Checkbox.Checked"/>
2020-05-22 17:02:24 +02:00
/// </summary>
2019-08-13 21:23:20 +02:00
public TextureRegion RadioCheckmark ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="Tooltip"/> uses for its background
/// </summary>
2019-08-13 23:54:29 +02:00
public NinePatch TooltipBackground ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The offset of the <see cref="Tooltip"/> element's top left corner from the mouse position
/// </summary>
2021-10-29 23:33:15 +02:00
public Vector2 TooltipOffset = new Vector2 ( 8 , 16 ) ;
2020-05-22 17:02:24 +02:00
/// <summary>
2022-04-05 14:42:30 +02:00
/// The offset of the <see cref="Tooltip"/> element's top center coordinate from the bottom center of the element snapped to when <see cref="Tooltip.DisplayInAutoNavMode"/> is true.
/// </summary>
public Vector2 TooltipAutoNavOffset = new Vector2 ( 0 , 8 ) ;
2024-04-10 20:45:16 +02:00
/// <summary>
/// The auto-nav anchor that is used or tooltips by default.
/// </summary>
2024-04-10 17:58:01 +02:00
public Anchor TooltipAutoNavAnchor = Anchor . BottomCenter ;
2024-04-10 20:45:16 +02:00
/// <summary>
/// The mouse anchor that is used for tooltips by default.
/// </summary>
2024-04-10 17:58:01 +02:00
public Anchor TooltipMouseAnchor = Anchor . BottomRight ;
2024-04-10 20:45:16 +02:00
/// <summary>
/// Whether tooltips should use auto-nav rendering behavior for tooltips even when using a mouse by default.
/// </summary>
2024-04-10 17:58:01 +02:00
public bool TooltipUseAutoNavBehaviorForMouse ;
2022-04-05 14:42:30 +02:00
/// <summary>
2020-10-31 17:42:39 +01:00
/// The color that the text of a <see cref="Tooltip"/> should have
/// </summary>
2020-10-31 17:55:46 +01:00
public Color TooltipTextColor = Color . White ;
2020-10-31 17:42:39 +01:00
/// <summary>
2020-12-05 16:42:21 +01:00
/// The amount of time that the mouse has to be over an element with a <see cref="Tooltip"/> for the tooltip to appear
/// </summary>
public TimeSpan TooltipDelay = TimeSpan . Zero ;
/// <summary>
2021-10-29 23:33:15 +02:00
/// The width of a <see cref="Tooltip"/>'s default text <see cref="Paragraph"/>
/// </summary>
public float TooltipTextWidth = 50 ;
/// <summary>
/// The <see cref="Element.ChildPadding"/> to apply to a <see cref="Tooltip"/> by default
/// </summary>
public Padding TooltipChildPadding = new Vector2 ( 2 ) ;
/// <summary>
2020-05-22 17:02:24 +02:00
/// The texture that the <see cref="ProgressBar"/> element uses for its background
/// </summary>
2019-09-10 23:28:25 +02:00
public NinePatch ProgressBarTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="ProgressBar"/> element renders with
/// </summary>
2021-10-29 23:33:15 +02:00
public Color ProgressBarColor = Color . White ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The padding that the <see cref="ProgressBar"/> uses for its progress texture (<see cref="ProgressBarProgressTexture"/>)
/// </summary>
2021-10-29 23:33:15 +02:00
public Vector2 ProgressBarProgressPadding = new Vector2 ( 1 ) ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that the <see cref="ProgressBar"/> uses for displaying its progress
/// </summary>
2019-09-10 23:28:25 +02:00
public NinePatch ProgressBarProgressTexture ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color that the <see cref="ProgressBar"/> renders its progress texture with
/// </summary>
2021-10-29 23:33:15 +02:00
public Color ProgressBarProgressColor = Color . Red ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The font that <see cref="Paragraph"/> and other elements should use for rendering.
/// Note that, to specify a bold and italic font for <see cref="TextFormatter"/>, you should use <see cref="GenericFont.Bold"/> and <see cref="GenericFont.Italic"/>.
/// </summary>
2020-03-28 22:25:06 +01:00
public GenericFont Font ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The scale that text should be rendered with in <see cref="Paragraph"/> and other elements
/// </summary>
2019-08-10 21:37:10 +02:00
public float TextScale = 1 ;
2020-05-22 17:02:24 +02:00
/// <summary>
2020-09-13 18:00:19 +02:00
/// The color that the text of a <see cref="Paragraph"/> should have
/// </summary>
public Color TextColor = Color . White ;
/// <summary>
2022-01-22 22:54:47 +01:00
/// The <see cref="TextAlignment"/> that a <see cref="Paragraph"/> should use by default.
/// </summary>
public TextAlignment TextAlignment ;
/// <summary>
2020-06-22 13:59:33 +02:00
/// The <see cref="SoundEffectInfo"/> that should be played when an element's <see cref="Element.OnPressed"/> and <see cref="Element.OnSecondaryPressed"/> events are called.
2020-05-22 17:02:24 +02:00
/// Note that this sound is only played if the callbacks have any subscribers.
/// </summary>
2020-06-22 13:59:33 +02:00
public SoundEffectInfo ActionSound ;
2021-11-27 22:45:37 +01:00
/// <summary>
2022-03-07 12:00:33 +01:00
/// The color that a <see cref="Paragraph"/>'s <see cref="Paragraph.Link"/> codes should have.
/// This value is passed to <see cref="LinkCode"/>.
/// </summary>
2022-12-18 13:01:19 +01:00
public Color ? LinkColor = Color . CornflowerBlue ;
2022-03-07 12:00:33 +01:00
/// <summary>
2021-11-27 22:45:37 +01:00
/// A set of additional fonts that can be used for the <c><f FontName></c> formatting code
/// </summary>
public Dictionary < string , GenericFont > AdditionalFonts = new Dictionary < string , GenericFont > ( ) ;
2019-08-28 18:27:17 +02:00
2023-06-14 14:54:49 +02:00
private readonly Dictionary < Type , Action < Element > > elementStyles = new Dictionary < Type , Action < Element > > ( ) ;
2023-06-28 13:35:32 +02:00
/// <summary>
/// Creates a new set of style settings with the default values.
/// </summary>
public UiStyle ( ) { }
/// <summary>
/// Creates a new set of style settings with values inherited from the given <paramref name="original"/> style settings.
/// </summary>
/// <param name="original">The original style settings, to copy into the new instance.</param>
public UiStyle ( UiStyle original ) {
this . SelectionIndicator = original . SelectionIndicator ;
this . MouseEnterAnimation = original . MouseEnterAnimation ;
this . MouseExitAnimation = original . MouseExitAnimation ;
this . ButtonTexture = original . ButtonTexture ;
this . ButtonHoveredTexture = original . ButtonHoveredTexture ;
this . ButtonHoveredColor = original . ButtonHoveredColor ;
this . ButtonDisabledTexture = original . ButtonDisabledTexture ;
this . ButtonDisabledColor = original . ButtonDisabledColor ;
this . PanelTexture = original . PanelTexture ;
this . PanelColor = original . PanelColor ;
this . PanelChildPadding = original . PanelChildPadding ;
this . PanelStepPerScroll = original . PanelStepPerScroll ;
this . PanelScrollerSize = original . PanelScrollerSize ;
this . PanelScrollBarOffset = original . PanelScrollBarOffset ;
this . TextFieldTexture = original . TextFieldTexture ;
this . TextFieldHoveredTexture = original . TextFieldHoveredTexture ;
this . TextFieldHoveredColor = original . TextFieldHoveredColor ;
this . TextFieldTextOffsetX = original . TextFieldTextOffsetX ;
this . TextFieldCaretWidth = original . TextFieldCaretWidth ;
this . ScrollBarBackground = original . ScrollBarBackground ;
this . ScrollBarScrollerTexture = original . ScrollBarScrollerTexture ;
this . ScrollBarSmoothScrolling = original . ScrollBarSmoothScrolling ;
this . ScrollBarSmoothScrollFactor = original . ScrollBarSmoothScrollFactor ;
this . CheckboxTexture = original . CheckboxTexture ;
this . CheckboxHoveredTexture = original . CheckboxHoveredTexture ;
this . CheckboxHoveredColor = original . CheckboxHoveredColor ;
this . CheckboxDisabledTexture = original . CheckboxDisabledTexture ;
this . CheckboxDisabledColor = original . CheckboxDisabledColor ;
this . CheckboxCheckmark = original . CheckboxCheckmark ;
this . CheckboxTextOffsetX = original . CheckboxTextOffsetX ;
this . RadioTexture = original . RadioTexture ;
this . RadioHoveredTexture = original . RadioHoveredTexture ;
this . RadioHoveredColor = original . RadioHoveredColor ;
this . RadioCheckmark = original . RadioCheckmark ;
this . TooltipBackground = original . TooltipBackground ;
this . TooltipOffset = original . TooltipOffset ;
this . TooltipAutoNavOffset = original . TooltipAutoNavOffset ;
this . TooltipTextColor = original . TooltipTextColor ;
this . TooltipDelay = original . TooltipDelay ;
this . TooltipTextWidth = original . TooltipTextWidth ;
this . TooltipChildPadding = original . TooltipChildPadding ;
this . ProgressBarTexture = original . ProgressBarTexture ;
this . ProgressBarColor = original . ProgressBarColor ;
this . ProgressBarProgressPadding = original . ProgressBarProgressPadding ;
this . ProgressBarProgressTexture = original . ProgressBarProgressTexture ;
this . ProgressBarProgressColor = original . ProgressBarProgressColor ;
this . Font = original . Font ;
this . TextScale = original . TextScale ;
this . TextColor = original . TextColor ;
this . TextAlignment = original . TextAlignment ;
this . ActionSound = original . ActionSound ;
this . LinkColor = original . LinkColor ;
this . AdditionalFonts = new Dictionary < string , GenericFont > ( original . AdditionalFonts ) ;
this . elementStyles = new Dictionary < Type , Action < Element > > ( original . elementStyles ) ;
}
2023-06-14 14:54:49 +02:00
/// <summary>
/// Adds an action to the given <see cref="Element"/> type <typeparamref name="T"/> that allows applying any kind of custom styling or behavior to it.
/// Custom styles added in this manner can be applied to an element using <see cref="ApplyCustomStyle"/>.
/// </summary>
/// <param name="style">The style action to add.</param>
/// <param name="add">Whether the <paramref name="style"/> function should be added to the existing style settings rather than replacing them.</param>
/// <typeparam name="T">The <see cref="Element"/> type that the <paramref name="style"/> should apply to.</typeparam>
public void AddCustomStyle < T > ( Action < T > style , bool add = false ) where T : Element {
if ( add & & this . elementStyles . ContainsKey ( typeof ( T ) ) ) {
this . elementStyles [ typeof ( T ) ] + = Action ;
} else {
this . elementStyles [ typeof ( T ) ] = Action ;
}
void Action ( Element e ) {
style . Invoke ( ( T ) e ) ;
}
}
/// <summary>
/// Applies a set of custom styling actions to the given <paramref name="element"/> which were added through <see cref="AddCustomStyle{T}"/>.
/// This method is automatically invoked in <see cref="Element.InitStyle"/>.
/// </summary>
/// <param name="element">The element to apply custom styling to.</param>
/// <returns>Whether any custom styling exists for the given <paramref name="element"/>.</returns>
public bool ApplyCustomStyle ( Element element ) {
if ( this . elementStyles . TryGetValue ( element . GetType ( ) , out var style ) ) {
style ? . Invoke ( element ) ;
return true ;
}
return false ;
}
2019-08-10 21:37:10 +02:00
}
2022-06-17 18:23:47 +02:00
}