From ca89d03ca476ca928cdf945cd5d206c943197e77 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sat, 30 Oct 2021 15:33:38 +0200 Subject: [PATCH] Some more ui style improvements --- CHANGELOG.md | 2 ++ Demos/UiDemo.cs | 2 +- MLEM.Ui/Elements/Button.cs | 4 ++- MLEM.Ui/Elements/Element.cs | 49 ++++++++++++++++--------------- MLEM.Ui/Elements/ElementHelper.cs | 4 ++- MLEM.Ui/Elements/Panel.cs | 13 ++++---- MLEM.Ui/Elements/Tooltip.cs | 5 ++-- MLEM.Ui/Style/StyleProp.cs | 15 ++++++---- MLEM/Misc/Padding.cs | 8 +++++ Sandbox/GameImpl.cs | 2 +- Tests/UiTests.cs | 2 +- 11 files changed, 64 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 588e53c..b435f63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ Improvements - Exposed the epsilon value used by Element calculations - Made Image ScaleToImage take ui scale into account - Added style properties for a lot of hardcoded default element styles +- Allow style properties to set style values with a higher priority, which allows elements to style their default children +- Allow changing the entire ui style for a single element Fixes - Fixed VerticalSpace height parameter being an integer diff --git a/Demos/UiDemo.cs b/Demos/UiDemo.cs index bc85457..45feeb0 100644 --- a/Demos/UiDemo.cs +++ b/Demos/UiDemo.cs @@ -69,7 +69,7 @@ namespace Demos { this.UiRoot.AddChild(this.root); this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a small demo for MLEM.Ui, a user interface library that is part of the MLEM Library for Extending MonoGame.")); - var image = this.root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Vector2(3)}); + var image = this.root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Padding(3)}); // Setting the x or y coordinate of the size to 1 or a lower number causes the width or height to be a percentage of the parent's width or height // (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth) this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), "Toggle Grass Image", "This button shows a grass tile above it to show the automatic anchoring of objects.") { diff --git a/MLEM.Ui/Elements/Button.cs b/MLEM.Ui/Elements/Button.cs index ee7fdd5..ed1744c 100644 --- a/MLEM.Ui/Elements/Button.cs +++ b/MLEM.Ui/Elements/Button.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -81,7 +82,8 @@ namespace MLEM.Ui.Elements { /// The text that should be displayed in a when hovering over this button public Button(Anchor anchor, Vector2 size, string text = null, string tooltipText = null) : base(anchor, size) { if (text != null) { - this.Text = new Paragraph(Anchor.Center, 1, text, true) {Padding = new Vector2(1)}; + this.Text = new Paragraph(Anchor.Center, 1, text, true); + this.Text.Padding.SetFromStyle(new Padding(1), 1); this.AddChild(this.Text); } if (tooltipText != null) diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 4d9abf6..19bfa3a 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -32,8 +32,17 @@ namespace MLEM.Ui.Elements { internal set { this.system = value; this.Controls = value?.Controls; - if (this.system != null) - this.InitStyle(this.system.Style); + this.Style = value?.Style; + } + } + public UiStyle Style { + get => this.style; + set { + if (this.style != value) { + this.style = value; + if (value != null) + this.InitStyle(value); + } } } /// @@ -109,31 +118,13 @@ namespace MLEM.Ui.Elements { /// public Vector2 ScaledOffset => this.offset * this.Scale; /// - /// The padding that this element has. - /// The padding is subtracted from the element's , and it is an area that the element does not extend into. This means that this element's resulting does not include this padding. - /// - public Padding Padding; - /// /// The , but with applied. /// - public Padding ScaledPadding => this.Padding * this.Scale; - /// - /// The child padding that this element has. - /// The child padding moves any added to this element inwards by the given amount in each direction. - /// - public Padding ChildPadding { - get => this.childPadding; - set { - if (this.childPadding == value) - return; - this.childPadding = value; - this.SetAreaDirty(); - } - } + public Padding ScaledPadding => this.Padding.Value * this.Scale; /// /// The , but with applied. /// - public Padding ScaledChildPadding => this.childPadding * this.Scale; + public Padding ScaledChildPadding => this.ChildPadding.Value * this.Scale; /// /// This element's current , but with applied. /// @@ -260,6 +251,7 @@ namespace MLEM.Ui.Elements { /// Stores whether this element is its 's . /// public bool IsSelected { get; protected set; } + /// /// A style property that contains the selection indicator that is displayed on this element if it is the /// @@ -272,6 +264,17 @@ namespace MLEM.Ui.Elements { /// A style property that contains the sound effect that is played when this element's is called /// public StyleProp SecondActionSound; + /// + /// The padding that this element has. + /// The padding is subtracted from the element's , and it is an area that the element does not extend into. This means that this element's resulting does not include this padding. + /// + public StyleProp Padding; + /// + /// The child padding that this element has. + /// The child padding moves any added to this element inwards by the given amount in each direction. + /// When setting this style after this element has already been added to a ui, should be called. + /// + public StyleProp ChildPadding; /// /// Event that is called after this element is drawn, but before its children are drawn @@ -389,11 +392,11 @@ namespace MLEM.Ui.Elements { private Anchor anchor; private Vector2 size; private Vector2 offset; - private Padding childPadding; private RectangleF area; private bool areaDirty; private bool isHidden; private int priority; + private UiStyle style; /// /// Creates a new element with the given anchor and size and sets up some default event reactions. diff --git a/MLEM.Ui/Elements/ElementHelper.cs b/MLEM.Ui/Elements/ElementHelper.cs index 8a50c6c..b7755f1 100644 --- a/MLEM.Ui/Elements/ElementHelper.cs +++ b/MLEM.Ui/Elements/ElementHelper.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using Microsoft.Xna.Framework; using MLEM.Input; +using MLEM.Misc; using MLEM.Textures; namespace MLEM.Ui.Elements { @@ -22,7 +23,8 @@ namespace MLEM.Ui.Elements { /// An image button public static Button ImageButton(Anchor anchor, Vector2 size, TextureRegion texture, string text = null, string tooltipText = null, float imagePadding = 2) { var button = new Button(anchor, size, text, tooltipText); - var image = new Image(Anchor.CenterLeft, Vector2.One, texture) {Padding = new Vector2(imagePadding)}; + var image = new Image(Anchor.CenterLeft, Vector2.One, texture); + image.Padding.SetFromStyle(new Padding(imagePadding), 1); button.OnAreaUpdated += e => image.Size = new Vector2(e.Area.Height, e.Area.Height) / e.Scale; button.AddChild(image, 0); return button; diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 2428fcd..9c8d8dd 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -71,8 +71,12 @@ namespace MLEM.Ui.Elements { AutoHideWhenEmpty = autoHideScrollbar, IsHidden = autoHideScrollbar }; - if (autoHideScrollbar) - this.ScrollBar.OnAutoHide += e => this.ChildPadding += new Padding(0, this.ScrollerSize.Value.X, 0, 0) * (e.IsHidden ? -1 : 1); + if (autoHideScrollbar) { + this.ScrollBar.OnAutoHide += e => { + this.ChildPadding += new Padding(0, this.ScrollerSize.Value.X, 0, 0) * (e.IsHidden ? -1 : 1); + this.SetAreaDirty(); + }; + } // handle automatic element selection, the scroller needs to scroll to the right location this.OnSelectedElementChanged += (element, otherElement) => { @@ -216,8 +220,7 @@ namespace MLEM.Ui.Elements { this.Texture.SetFromStyle(style.PanelTexture); this.StepPerScroll.SetFromStyle(style.PanelStepPerScroll); this.ScrollerSize.SetFromStyle(style.PanelScrollerSize); - if (this.ChildPadding == default) - this.ChildPadding = style.PanelChildPadding; + this.ChildPadding.SetFromStyle(style.PanelChildPadding); this.SetScrollBarStyle(); } @@ -235,7 +238,7 @@ namespace MLEM.Ui.Elements { var lowestChild = this.GetLowestChild(c => c != this.ScrollBar && !c.IsHidden); // the max value of the scrollbar is the amount of non-scaled pixels taken up by overflowing components var childrenHeight = lowestChild.Area.Bottom - firstChild.Area.Top; - this.ScrollBar.MaxValue = (childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Height; + this.ScrollBar.MaxValue = (childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Value.Height; // update the render target var targetArea = (Rectangle) this.GetRenderTargetArea(); diff --git a/MLEM.Ui/Elements/Tooltip.cs b/MLEM.Ui/Elements/Tooltip.cs index 83c3c20..86ea485 100644 --- a/MLEM.Ui/Elements/Tooltip.cs +++ b/MLEM.Ui/Elements/Tooltip.cs @@ -79,10 +79,9 @@ namespace MLEM.Ui.Elements { this.Texture.SetFromStyle(style.TooltipBackground); this.MouseOffset.SetFromStyle(style.TooltipOffset); this.Delay.SetFromStyle(style.TooltipDelay); - this.ChildPadding = style.TooltipChildPadding; + this.ChildPadding.SetFromStyle(style.TooltipChildPadding); if (this.Paragraph != null) { - // we can't set from style here since it's a different element - this.Paragraph.TextColor.Set(style.TooltipTextColor); + this.Paragraph.TextColor.SetFromStyle(style.TooltipTextColor, 1); this.Paragraph.Size = new Vector2(style.TooltipTextWidth, 0); } } diff --git a/MLEM.Ui/Style/StyleProp.cs b/MLEM.Ui/Style/StyleProp.cs index 01fddee..02f6c4a 100644 --- a/MLEM.Ui/Style/StyleProp.cs +++ b/MLEM.Ui/Style/StyleProp.cs @@ -14,14 +14,14 @@ namespace MLEM.Ui.Style { /// The currently applied style /// public T Value { get; private set; } - private bool isCustom; + private byte lastSetPriority; /// /// Creates a new style property with the given custom style. /// /// The custom style to apply public StyleProp(T value) { - this.isCustom = true; + this.lastSetPriority = byte.MaxValue; this.Value = value; } @@ -30,9 +30,12 @@ namespace MLEM.Ui.Style { /// This allows this property to be overridden by custom style settings using . /// /// The style to apply - public void SetFromStyle(T value) { - if (!this.isCustom) + /// The priority that this style value has. Higher priority style values will override lower priority style values. + public void SetFromStyle(T value, byte priority = 0) { + if (priority >= this.lastSetPriority) { this.Value = value; + this.lastSetPriority = priority; + } } /// @@ -41,7 +44,7 @@ namespace MLEM.Ui.Style { /// /// public void Set(T value) { - this.isCustom = true; + this.lastSetPriority = byte.MaxValue; this.Value = value; } @@ -64,7 +67,7 @@ namespace MLEM.Ui.Style { /// public override string ToString() { - return $"{this.Value} (Custom: {this.isCustom})"; + return this.Value?.ToString(); } /// diff --git a/MLEM/Misc/Padding.cs b/MLEM/Misc/Padding.cs index e69f631..7586f03 100644 --- a/MLEM/Misc/Padding.cs +++ b/MLEM/Misc/Padding.cs @@ -52,6 +52,14 @@ namespace MLEM.Misc { this.Bottom = bottom; } + /// + /// Creates a new padding with the specified value, which will be applied to each edge. + /// + /// The padding to apply to each edge + public Padding(float value) : + this(value, value) { + } + /// /// Creates a new padding with the specified x and y values, applying them to both edges. /// diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 6167e28..70e4f18 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -224,7 +224,7 @@ namespace Sandbox { var button = loadPanel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1)) { SetHeightBasedOnChildren = true, Padding = new Padding(0, 0, 0, 1), - ChildPadding = new Vector2(3) + ChildPadding = new Padding(3) }); button.AddChild(new Group(Anchor.AutoLeft, new Vector2(0.5F, 30), false) { CanBeMoused = false diff --git a/Tests/UiTests.cs b/Tests/UiTests.cs index 90822be..ef70dad 100644 --- a/Tests/UiTests.cs +++ b/Tests/UiTests.cs @@ -49,7 +49,7 @@ namespace Tests { var button = panel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1)) { SetHeightBasedOnChildren = true, Padding = new Padding(0, 0, 0, 1), - ChildPadding = new Vector2(3) + ChildPadding = new Padding(3) }); button.AddChild(new Group(Anchor.AutoLeft, new Vector2(0.5F, 30), false) { CanBeMoused = false