diff --git a/MLEM.Extended/Extensions/TextureExtensions.cs b/MLEM.Extended/Extensions/TextureExtensions.cs index c65606d..87f3132 100644 --- a/MLEM.Extended/Extensions/TextureExtensions.cs +++ b/MLEM.Extended/Extensions/TextureExtensions.cs @@ -1,3 +1,4 @@ +using MLEM.Extensions; using MLEM.Textures; using MonoGame.Extended.TextureAtlases; @@ -5,7 +6,7 @@ namespace MLEM.Extended.Extensions { public static class TextureExtensions { public static NinePatchRegion2D ToExtended(this NinePatch patch) { - return new NinePatchRegion2D(patch.Region.ToExtended(), patch.PaddingLeft, patch.PaddingTop, patch.PaddingRight, patch.PaddingBottom); + return new NinePatchRegion2D(patch.Region.ToExtended(), patch.Padding.Left.Floor(), patch.Padding.Top.Floor(), patch.Padding.Right.Floor(), patch.Padding.Bottom.Floor()); } public static TextureRegion2D ToExtended(this TextureRegion region) { diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 534f9bc..b19fa0b 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -25,9 +25,8 @@ namespace MLEM.Ui.Elements { private Anchor anchor; private Vector2 size; private Vector2 offset; - public Vector2 Padding; - public Vector2 ScaledPadding => this.Padding * this.Scale; - private Vector2 childPadding; + public Padding Padding; + public Padding ScaledPadding => this.Padding * this.Scale; public Anchor Anchor { get => this.anchor; set { @@ -56,8 +55,9 @@ namespace MLEM.Ui.Elements { this.SetAreaDirty(); } } - public Vector2 ScaledOffset => (this.offset * this.Scale); - public Vector2 ChildPadding { + public Vector2 ScaledOffset => this.offset * this.Scale; + private Padding childPadding; + public Padding ChildPadding { get => this.childPadding; set { if (this.childPadding == value) @@ -67,7 +67,7 @@ namespace MLEM.Ui.Elements { } } public RectangleF ChildPaddedArea => this.UnscrolledArea.Shrink(this.ScaledChildPadding); - public Vector2 ScaledChildPadding => this.childPadding * this.Scale; + public Padding ScaledChildPadding => this.childPadding * this.Scale; public DrawCallback OnDrawn; public TimeCallback OnUpdated; @@ -319,7 +319,7 @@ namespace MLEM.Ui.Elements { if (this.SetHeightBasedOnChildren) { var lowest = this.GetLowestChild(e => !e.IsHidden); if (lowest != null) { - var newHeight = (lowest.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Y) / this.Scale; + var newHeight = (lowest.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Bottom) / this.Scale; if ((int) newHeight != (int) this.size.Y) { this.size.Y = newHeight; this.ForceUpdateArea(); @@ -328,7 +328,7 @@ namespace MLEM.Ui.Elements { } else if (this.SetWidthBasedOnChildren) { var rightmost = this.GetRightmostChild(e => !e.IsHidden); if (rightmost != null) { - var newWidth = (rightmost.UnscrolledArea.Right - pos.X + this.ScaledChildPadding.X) / this.Scale; + var newWidth = (rightmost.UnscrolledArea.Right - pos.X + this.ScaledChildPadding.Right) / this.Scale; if ((int) newWidth != (int) this.size.X) { this.size.X = newWidth; this.ForceUpdateArea(); diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 1fb08c3..10300fa 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -32,13 +32,13 @@ namespace MLEM.Ui.Elements { StepPerScroll = 10, OnValueChanged = (element, value) => this.ScrollChildren(), CanAutoAnchorsAttach = false, - AutoHideWhenEmpty = true + AutoHideWhenEmpty = true, + IsHidden = true }; - this.AddChild(this.ScrollBar); // modify the padding so that the scroll bar isn't over top of something else this.ScrollBar.PositionOffset -= new Vector2(scrollSize.X + 1, 0); - this.ChildPadding += new Vector2(scrollSize.X, 0); + this.ScrollBar.OnAutoHide += e => this.ChildPadding += new Padding(0, scrollSize.X, 0, 0) * (e.IsHidden ? -1 : 1); // handle automatic element selection, the scroller needs to scroll to the right location this.OnSelectedElementChanged += (element, otherElement) => { @@ -48,6 +48,7 @@ namespace MLEM.Ui.Elements { return; this.ScrollBar.CurrentValue = (otherElement.Area.Bottom - this.Children[1].Area.Top - this.Area.Height / 2) / this.Scale; }; + this.AddChild(this.ScrollBar); } } @@ -76,7 +77,7 @@ namespace MLEM.Ui.Elements { var lowestChild = this.GetLowestChild(e => !e.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.Y * 2; + this.ScrollBar.MaxValue = (childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Height; // update the render target var targetArea = (Rectangle) this.GetRenderTargetArea(); diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs index b3f97ea..986ee2d 100644 --- a/MLEM.Ui/Elements/Paragraph.cs +++ b/MLEM.Ui/Elements/Paragraph.cs @@ -60,11 +60,11 @@ namespace MLEM.Ui.Elements { var size = base.CalcActualSize(parentArea); var sc = this.TextScale * this.Scale; - this.splitText = this.RegularFont.Value.SplitString(this.text.RemoveFormatting(), size.X - this.ScaledPadding.X * 2, sc); + this.splitText = this.RegularFont.Value.SplitString(this.text.RemoveFormatting(), size.X - this.ScaledPadding.Width, sc); this.codeLocations = this.text.GetFormattingCodes(); var textDims = this.RegularFont.Value.MeasureString(this.splitText) * sc; - return new Vector2(this.AutoAdjustWidth ? textDims.X + this.ScaledPadding.X * 2 : size.X, textDims.Y + this.ScaledPadding.Y * 2); + return new Vector2(this.AutoAdjustWidth ? textDims.X + this.ScaledPadding.Width : size.X, textDims.Y + this.ScaledPadding.Height); } public override void Update(GameTime time) { diff --git a/MLEM.Ui/Elements/ProgressBar.cs b/MLEM.Ui/Elements/ProgressBar.cs index d36f4b3..3b236d0 100644 --- a/MLEM.Ui/Elements/ProgressBar.cs +++ b/MLEM.Ui/Elements/ProgressBar.cs @@ -37,8 +37,8 @@ namespace MLEM.Ui.Elements { var percentage = this.CurrentValue / this.MaxValue; var tex = this.ProgressTexture.Value; - var padHor = tex != null ? (tex.PaddingLeft + tex.PaddingRight) * this.Scale : 0; - var padVer = tex != null ? (tex.PaddingTop + tex.PaddingBottom) * this.Scale : 0; + var padHor = tex != null ? tex.Padding.Width * this.Scale : 0; + var padVer = tex != null ? tex.Padding.Height * this.Scale : 0; var width = percentage * (this.DisplayArea.Width - padHor) + padHor; var height = percentage * (this.DisplayArea.Height - padVer) + padVer; RectangleF progressArea; diff --git a/MLEM.Ui/Elements/ScrollBar.cs b/MLEM.Ui/Elements/ScrollBar.cs index 3a4971a..262add8 100644 --- a/MLEM.Ui/Elements/ScrollBar.cs +++ b/MLEM.Ui/Elements/ScrollBar.cs @@ -23,8 +23,10 @@ namespace MLEM.Ui.Elements { this.maxValue = Math.Max(0, value); // force current value to be clamped this.CurrentValue = this.currValue; - if (this.AutoHideWhenEmpty) + if (this.AutoHideWhenEmpty && this.IsHidden != this.maxValue <= 0) { this.IsHidden = this.maxValue <= 0; + this.OnAutoHide?.Invoke(this); + } } } private float currValue; @@ -41,6 +43,7 @@ namespace MLEM.Ui.Elements { public readonly bool Horizontal; public float StepPerScroll = 1; public ValueChanged OnValueChanged; + public GenericCallback OnAutoHide; private bool isMouseHeld; private bool isDragging; private bool isTouchHeld; diff --git a/MLEM/Extensions/NumberExtensions.cs b/MLEM/Extensions/NumberExtensions.cs index 63ec928..57f170e 100644 --- a/MLEM/Extensions/NumberExtensions.cs +++ b/MLEM/Extensions/NumberExtensions.cs @@ -67,5 +67,13 @@ namespace MLEM.Extensions { return rect; } + public static RectangleF Shrink(this RectangleF rect, Padding padding) { + rect.X += padding.Left; + rect.Y += padding.Left; + rect.Width -= padding.Width; + rect.Height -= padding.Height; + return rect; + } + } } \ No newline at end of file diff --git a/MLEM/Misc/Padding.cs b/MLEM/Misc/Padding.cs new file mode 100644 index 0000000..a1b202c --- /dev/null +++ b/MLEM/Misc/Padding.cs @@ -0,0 +1,61 @@ +using Microsoft.Xna.Framework; + +namespace MLEM.Misc { + public struct Padding { + + public float Left; + public float Right; + public float Top; + public float Bottom; + public float Width => this.Left + this.Right; + public float Height => this.Top + this.Bottom; + + public Padding(float left, float right, float top, float bottom) { + this.Left = left; + this.Right = right; + this.Top = top; + this.Bottom = bottom; + } + + public static implicit operator Padding(Vector2 vec) { + return new Padding(vec.X, vec.X, vec.Y, vec.Y); + } + + public static Padding operator *(Padding p, float scale) { + return new Padding(p.Left * scale, p.Right * scale, p.Top * scale, p.Bottom * scale); + } + + public static Padding operator +(Padding left, Padding right) { + return new Padding(left.Left + right.Left, left.Right + right.Right, left.Top + right.Top, left.Bottom + right.Bottom); + } + + public static Padding operator -(Padding left, Padding right) { + return new Padding(left.Left - right.Left, left.Right - right.Right, left.Top - right.Top, left.Bottom - right.Bottom); + } + + public static bool operator ==(Padding left, Padding right) { + return left.Equals(right); + } + + public static bool operator !=(Padding left, Padding right) { + return !(left == right); + } + + public bool Equals(Padding other) { + return this.Left.Equals(other.Left) && this.Right.Equals(other.Right) && this.Top.Equals(other.Top) && this.Bottom.Equals(other.Bottom); + } + + public override bool Equals(object obj) { + return obj is Padding other && this.Equals(other); + } + + public override int GetHashCode() { + var hashCode = this.Left.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Right.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Top.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Bottom.GetHashCode(); + return hashCode; + } + + } +} \ No newline at end of file diff --git a/MLEM/Textures/NinePatch.cs b/MLEM/Textures/NinePatch.cs index a475f50..dcb15fb 100644 --- a/MLEM/Textures/NinePatch.cs +++ b/MLEM/Textures/NinePatch.cs @@ -9,22 +9,19 @@ namespace MLEM.Textures { public class NinePatch { public readonly TextureRegion Region; - public readonly int PaddingLeft; - public readonly int PaddingRight; - public readonly int PaddingTop; - public readonly int PaddingBottom; - + public readonly Padding Padding; public readonly Rectangle[] SourceRectangles; - public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) { + public NinePatch(TextureRegion texture, Padding padding) { this.Region = texture; - this.PaddingLeft = paddingLeft; - this.PaddingRight = paddingRight; - this.PaddingTop = paddingTop; - this.PaddingBottom = paddingBottom; + this.Padding = padding; this.SourceRectangles = this.CreateRectangles(this.Region.Area).ToArray(); } + public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) : + this(texture, new Padding(paddingLeft, paddingRight, paddingTop, paddingBottom)) { + } + public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) : this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom) { } @@ -40,10 +37,10 @@ namespace MLEM.Textures { } public IEnumerable CreateRectangles(RectangleF area, float patchScale = 1) { - var pl = (int) (this.PaddingLeft * patchScale); - var pr = (int) (this.PaddingRight * patchScale); - var pt = (int) (this.PaddingTop * patchScale); - var pb = (int) (this.PaddingBottom * patchScale); + var pl = (int) (this.Padding.Left * patchScale); + var pr = (int) (this.Padding.Right * patchScale); + var pt = (int) (this.Padding.Top * patchScale); + var pb = (int) (this.Padding.Bottom * patchScale); var centerW = area.Width - pl - pr; var centerH = area.Height - pt - pb;