From 32c8147a4c55a2a962d0e946d95f469203872605 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sat, 2 Nov 2019 14:53:59 +0100 Subject: [PATCH] added a rectanglef class which allows mlem to use decimal coordinates --- MLEM.Extended/Extensions/NumberExtensions.cs | 15 ++ .../Extensions/SpriteBatchExtensions.cs | 15 ++ MLEM.Ui/Elements/Checkbox.cs | 5 +- MLEM.Ui/Elements/Element.cs | 36 ++--- MLEM.Ui/Elements/Image.cs | 11 +- MLEM.Ui/Elements/Panel.cs | 10 +- MLEM.Ui/Elements/Paragraph.cs | 7 +- MLEM.Ui/Elements/ProgressBar.cs | 18 +-- MLEM.Ui/Elements/ScrollBar.cs | 19 +-- MLEM.Ui/Elements/TextField.cs | 16 +- MLEM.Ui/Style/UiStyle.cs | 2 +- MLEM.Ui/Style/UntexturedStyle.cs | 2 +- MLEM.Ui/UiControls.cs | 16 +- MLEM/Extensions/NumberExtensions.cs | 15 ++ MLEM/Extensions/SpriteBatchExtensions.cs | 15 ++ MLEM/Misc/RectangleF.cs | 142 ++++++++++++++++++ MLEM/Textures/NinePatch.cs | 33 ++-- MLEM/Textures/TextureRegion.cs | 10 ++ Sandbox/GameImpl.cs | 2 +- 19 files changed, 310 insertions(+), 79 deletions(-) create mode 100644 MLEM.Extended/Extensions/NumberExtensions.cs create mode 100644 MLEM/Misc/RectangleF.cs diff --git a/MLEM.Extended/Extensions/NumberExtensions.cs b/MLEM.Extended/Extensions/NumberExtensions.cs new file mode 100644 index 0000000..b13d160 --- /dev/null +++ b/MLEM.Extended/Extensions/NumberExtensions.cs @@ -0,0 +1,15 @@ +using MonoGame.Extended; + +namespace MLEM.Extended.Extensions { + public static class NumberExtensions { + + public static RectangleF ToExtended(this Misc.RectangleF rect) { + return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height); + } + + public static Misc.RectangleF ToMlem(this RectangleF rect) { + return new Misc.RectangleF(rect.X, rect.Y, rect.Width, rect.Height); + } + + } +} \ No newline at end of file diff --git a/MLEM.Extended/Extensions/SpriteBatchExtensions.cs b/MLEM.Extended/Extensions/SpriteBatchExtensions.cs index 1965d76..4d24346 100644 --- a/MLEM.Extended/Extensions/SpriteBatchExtensions.cs +++ b/MLEM.Extended/Extensions/SpriteBatchExtensions.cs @@ -1,5 +1,8 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Extensions; +using MLEM.Textures; +using MonoGame.Extended; using MonoGame.Extended.BitmapFonts; namespace MLEM.Extended.Extensions { @@ -15,6 +18,18 @@ namespace MLEM.Extended.Extensions { color, 0, size / 2, scale + addedScale, SpriteEffects.None, 0); } + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth) { + batch.Draw(texture, destinationRectangle.ToMlem(), sourceRectangle, color, rotation, origin, effects, layerDepth); + } + + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color) { + batch.Draw(texture, destinationRectangle, sourceRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); + } + + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Color color) { + batch.Draw(texture, destinationRectangle, null, color); + } + } } \ No newline at end of file diff --git a/MLEM.Ui/Elements/Checkbox.cs b/MLEM.Ui/Elements/Checkbox.cs index 7e4ddfa..2fe0055 100644 --- a/MLEM.Ui/Elements/Checkbox.cs +++ b/MLEM.Ui/Elements/Checkbox.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; using MLEM.Input; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -37,7 +38,7 @@ namespace MLEM.Ui.Elements { } } - protected override Point CalcActualSize(Rectangle parentArea) { + protected override Vector2 CalcActualSize(RectangleF parentArea) { var size = base.CalcActualSize(parentArea); if (this.Label != null) { this.Label.Size = new Vector2((size.X - size.Y) / this.Scale - this.TextOffsetX, 1); @@ -55,7 +56,7 @@ namespace MLEM.Ui.Elements { color = (Color) this.HoveredColor * alpha; } - var boxDisplayArea = new Rectangle(this.DisplayArea.Location, new Point(this.DisplayArea.Height)); + var boxDisplayArea = new RectangleF(this.DisplayArea.Location, new Vector2(this.DisplayArea.Height)); batch.Draw(tex, boxDisplayArea, color, this.Scale); if (this.Checked) batch.Draw(this.Checkmark, boxDisplayArea, Color.White * alpha); diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 8cfcb32..176a4da 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -26,7 +26,7 @@ namespace MLEM.Ui.Elements { private Vector2 size; private Vector2 offset; public Vector2 Padding; - public Point ScaledPadding => (this.Padding * this.Scale).ToPoint(); + public Vector2 ScaledPadding => this.Padding * this.Scale; private Vector2 childPadding; public Anchor Anchor { get => this.anchor; @@ -56,7 +56,7 @@ namespace MLEM.Ui.Elements { this.SetAreaDirty(); } } - public Point ScaledOffset => (this.offset * this.Scale).ToPoint(); + public Vector2 ScaledOffset => (this.offset * this.Scale); public Vector2 ChildPadding { get => this.childPadding; set { @@ -66,8 +66,8 @@ namespace MLEM.Ui.Elements { this.SetAreaDirty(); } } - public Rectangle ChildPaddedArea => this.UnscrolledArea.Shrink(this.ScaledChildPadding); - public Point ScaledChildPadding => (this.childPadding * this.Scale).ToPoint(); + public RectangleF ChildPaddedArea => this.UnscrolledArea.Shrink(this.ScaledChildPadding); + public Vector2 ScaledChildPadding => this.childPadding * this.Scale; public DrawCallback OnDrawn; public TimeCallback OnUpdated; @@ -116,17 +116,17 @@ namespace MLEM.Ui.Elements { public bool SetHeightBasedOnChildren; public bool CanAutoAnchorsAttach = true; - private Rectangle area; - public Rectangle UnscrolledArea { + private RectangleF area; + public RectangleF UnscrolledArea { get { this.UpdateAreaIfDirty(); return this.area; } } - public Rectangle Area => this.UnscrolledArea.OffsetCopy(this.ScaledScrollOffset); + public RectangleF Area => this.UnscrolledArea.OffsetCopy(this.ScaledScrollOffset); public Vector2 ScrollOffset; - public Point ScaledScrollOffset => (this.ScrollOffset * this.Scale).ToPoint(); - public Rectangle DisplayArea => this.Area.Shrink(this.ScaledPadding); + public Vector2 ScaledScrollOffset => this.ScrollOffset * this.Scale; + public RectangleF DisplayArea => this.Area.Shrink(this.ScaledPadding); private int priority; public int Priority { get => this.priority; @@ -218,12 +218,12 @@ namespace MLEM.Ui.Elements { if (this.IsHidden) return; - var parentArea = this.Parent != null ? this.Parent.ChildPaddedArea : this.system.Viewport; + var parentArea = this.Parent != null ? this.Parent.ChildPaddedArea : (RectangleF) this.system.Viewport; var parentCenterX = parentArea.X + parentArea.Width / 2; var parentCenterY = parentArea.Y + parentArea.Height / 2; var actualSize = this.CalcActualSize(parentArea); - var pos = new Point(); + var pos = new Vector2(); switch (this.anchor) { case Anchor.TopLeft: @@ -301,7 +301,7 @@ namespace MLEM.Ui.Elements { } } - this.area = new Rectangle(pos, actualSize); + this.area = new RectangleF(pos, actualSize); this.System.OnElementAreaUpdated?.Invoke(this); foreach (var child in this.Children) @@ -319,13 +319,13 @@ namespace MLEM.Ui.Elements { } } - protected virtual Point CalcActualSize(Rectangle parentArea) { - return new Point( - (this.size.X > 1 ? this.ScaledSize.X : parentArea.Width * this.size.X).Ceil(), - (this.size.Y > 1 ? this.ScaledSize.Y : parentArea.Height * this.size.Y).Ceil()); + protected virtual Vector2 CalcActualSize(RectangleF parentArea) { + return new Vector2( + this.size.X > 1 ? this.ScaledSize.X : parentArea.Width * this.size.X, + this.size.Y > 1 ? this.ScaledSize.Y : parentArea.Height * this.size.Y); } - protected virtual Rectangle GetAreaForAutoAnchors() { + protected virtual RectangleF GetAreaForAutoAnchors() { return this.UnscrolledArea; } @@ -443,7 +443,7 @@ namespace MLEM.Ui.Elements { } } - public virtual Element GetElementUnderPos(Point position) { + public virtual Element GetElementUnderPos(Vector2 position) { if (this.IsHidden) return null; var children = this.GetRelevantChildren(); diff --git a/MLEM.Ui/Elements/Image.cs b/MLEM.Ui/Elements/Image.cs index e3aed62..6bfba42 100644 --- a/MLEM.Ui/Elements/Image.cs +++ b/MLEM.Ui/Elements/Image.cs @@ -1,6 +1,7 @@ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -51,8 +52,8 @@ namespace MLEM.Ui.Elements { this.CanBeMoused = false; } - protected override Point CalcActualSize(Rectangle parentArea) { - return this.texture != null && this.scaleToImage ? this.texture.Size : base.CalcActualSize(parentArea); + protected override Vector2 CalcActualSize(RectangleF parentArea) { + return this.texture != null && this.scaleToImage ? this.texture.Size.ToVector2() : base.CalcActualSize(parentArea); } public override void Update(GameTime time) { @@ -69,10 +70,10 @@ namespace MLEM.Ui.Elements { if (this.MaintainImageAspect) { var scale = Math.Min(this.DisplayArea.Width / (float) this.texture.Width, this.DisplayArea.Height / (float) this.texture.Height); var imageOffset = new Vector2(this.DisplayArea.Width / 2F - this.texture.Width * scale / 2, this.DisplayArea.Height / 2F - this.texture.Height * scale / 2); - batch.Draw(this.texture, this.DisplayArea.Location.ToVector2() + center * scale + imageOffset, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); + batch.Draw(this.texture, this.DisplayArea.Location + center * scale + imageOffset, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); } else { - var scale = new Vector2(1F / this.texture.Width, 1F / this.texture.Height) * this.DisplayArea.Size.ToVector2(); - batch.Draw(this.texture, this.DisplayArea.Location.ToVector2() + center * scale, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); + var scale = new Vector2(1F / this.texture.Width, 1F / this.texture.Height) * this.DisplayArea.Size; + batch.Draw(this.texture, this.DisplayArea.Location + center * scale, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); } base.Draw(time, batch, alpha, blendState, samplerState, matrix); } diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 34205c2..e95afd6 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -82,8 +83,7 @@ namespace MLEM.Ui.Elements { if (this.renderTarget == null || targetArea.Width != this.renderTarget.Width || targetArea.Height != this.renderTarget.Height) { if (this.renderTarget != null) this.renderTarget.Dispose(); - var empty = targetArea.Width <= 0 || targetArea.Height <= 0; - this.renderTarget = empty ? null : new RenderTarget2D(this.System.GraphicsDevice, targetArea.Width, targetArea.Height); + this.renderTarget = targetArea.IsEmpty ? null : new RenderTarget2D(this.System.GraphicsDevice, targetArea.Width.Ceil(), targetArea.Height.Ceil()); } } } @@ -91,7 +91,7 @@ namespace MLEM.Ui.Elements { private void ScrollChildren() { if (!this.scrollOverflow) return; - var offset = -this.ScrollBar.CurrentValue.Floor(); + var offset = -this.ScrollBar.CurrentValue; foreach (var child in this.GetChildren(c => c != this.ScrollBar, true)) child.ScrollOffset = new Vector2(0, offset); this.relevantChildrenDirty = true; @@ -154,14 +154,14 @@ namespace MLEM.Ui.Elements { } } - public override Element GetElementUnderPos(Point position) { + public override Element GetElementUnderPos(Vector2 position) { // if overflow is handled, don't propagate mouse checks to hidden children if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(position)) return null; return base.GetElementUnderPos(position); } - private Rectangle GetRenderTargetArea() { + private RectangleF GetRenderTargetArea() { var area = this.ChildPaddedArea; area.X = this.DisplayArea.X; area.Width = this.DisplayArea.Width; diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs index 5cd1f1e..5ac2394 100644 --- a/MLEM.Ui/Elements/Paragraph.cs +++ b/MLEM.Ui/Elements/Paragraph.cs @@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; using MLEM.Font; using MLEM.Formatting; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -55,7 +56,7 @@ namespace MLEM.Ui.Elements { this.CanBeMoused = false; } - protected override Point CalcActualSize(Rectangle parentArea) { + protected override Vector2 CalcActualSize(RectangleF parentArea) { var size = base.CalcActualSize(parentArea); var sc = this.TextScale * this.Scale; @@ -63,7 +64,7 @@ namespace MLEM.Ui.Elements { this.codeLocations = this.text.GetFormattingCodes(); var textDims = this.RegularFont.Value.MeasureString(this.splitText) * sc; - return new Point(this.AutoAdjustWidth ? textDims.X.Ceil() + this.ScaledPadding.X * 2 : size.X, textDims.Y.Ceil() + this.ScaledPadding.Y * 2); + return new Vector2(this.AutoAdjustWidth ? textDims.X + this.ScaledPadding.X * 2 : size.X, textDims.Y + this.ScaledPadding.Y * 2); } public override void Update(GameTime time) { @@ -77,7 +78,7 @@ namespace MLEM.Ui.Elements { if (this.Background.Value != null) batch.Draw(this.Background, this.Area, (Color) this.BackgroundColor * alpha); - var pos = this.DisplayArea.Location.ToVector2(); + var pos = this.DisplayArea.Location; var sc = this.TextScale * this.Scale; var color = (this.TextColor.Value != default ? this.TextColor : Color.White) * alpha; diff --git a/MLEM.Ui/Elements/ProgressBar.cs b/MLEM.Ui/Elements/ProgressBar.cs index 67efd59..d36f4b3 100644 --- a/MLEM.Ui/Elements/ProgressBar.cs +++ b/MLEM.Ui/Elements/ProgressBar.cs @@ -11,7 +11,7 @@ namespace MLEM.Ui.Elements { public StyleProp Texture; public StyleProp Color; - public StyleProp ProgressPadding; + public StyleProp ProgressPadding; public StyleProp ProgressTexture; public StyleProp ProgressColor; @@ -39,28 +39,28 @@ namespace MLEM.Ui.Elements { 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 width = (percentage * (this.DisplayArea.Width - padHor) + padHor).Floor(); - var height = (percentage * (this.DisplayArea.Height - padVer) + padVer).Floor(); - Rectangle progressArea; + var width = percentage * (this.DisplayArea.Width - padHor) + padHor; + var height = percentage * (this.DisplayArea.Height - padVer) + padVer; + RectangleF progressArea; switch (this.Direction) { case Direction2.Up: - progressArea = new Rectangle(this.DisplayArea.X, + progressArea = new RectangleF(this.DisplayArea.X, this.DisplayArea.Y + (this.DisplayArea.Height - height), this.DisplayArea.Width, height); break; case Direction2.Down: - progressArea = new Rectangle(this.DisplayArea.Location, new Point(this.DisplayArea.Width, height)); + progressArea = new RectangleF(this.DisplayArea.Location, new Vector2(this.DisplayArea.Width, height)); break; case Direction2.Left: - progressArea = new Rectangle( + progressArea = new RectangleF( this.DisplayArea.X + (this.DisplayArea.Width - width), this.DisplayArea.Y, width, this.DisplayArea.Height); break; default: // Right - progressArea = new Rectangle(this.DisplayArea.Location, new Point(width, this.DisplayArea.Height)); + progressArea = new RectangleF(this.DisplayArea.Location, new Vector2(width, this.DisplayArea.Height)); break; } - var offsetArea = progressArea.Shrink(this.ProgressPadding.Value.Multiply(this.Scale)); + var offsetArea = progressArea.Shrink(this.ProgressPadding.Value * this.Scale); if (this.ProgressTexture.Value != null) { batch.Draw(this.ProgressTexture, offsetArea, (Color) this.ProgressColor * alpha, this.Scale); } else { diff --git a/MLEM.Ui/Elements/ScrollBar.cs b/MLEM.Ui/Elements/ScrollBar.cs index 4769a4a..81f981b 100644 --- a/MLEM.Ui/Elements/ScrollBar.cs +++ b/MLEM.Ui/Elements/ScrollBar.cs @@ -5,6 +5,7 @@ using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input.Touch; using MLEM.Extensions; using MLEM.Input; +using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; @@ -13,8 +14,8 @@ namespace MLEM.Ui.Elements { public StyleProp Background; public StyleProp ScrollerTexture; - public Point ScrollerOffset; - public Point ScrollerSize; + public Vector2 ScrollerOffset; + public Vector2 ScrollerSize; private float maxValue; public float MaxValue { get => this.maxValue; @@ -52,7 +53,7 @@ namespace MLEM.Ui.Elements { public ScrollBar(Anchor anchor, Vector2 size, int scrollerSize, float maxValue, bool horizontal = false) : base(anchor, size) { this.maxValue = maxValue; this.Horizontal = horizontal; - this.ScrollerSize = new Point(horizontal ? scrollerSize : size.X.Floor(), !horizontal ? scrollerSize : size.Y.Floor()); + this.ScrollerSize = new Vector2(horizontal ? scrollerSize : size.X, !horizontal ? scrollerSize : size.Y); this.CanBeSelected = false; } @@ -79,7 +80,7 @@ namespace MLEM.Ui.Elements { // are we dragging on top of the panel? if (this.Input.GetGesture(GestureType.VerticalDrag, out var drag)) { // if the element under the drag's start position is on top of the panel, start dragging - var touched = this.Parent.GetElementUnderPos(drag.Position.ToPoint().Transform(this.Root.InvTransform)); + var touched = this.Parent.GetElementUnderPos(Vector2.Transform(drag.Position, this.Root.InvTransform)); if (touched != null && touched != this) this.isDragging = true; @@ -121,11 +122,11 @@ namespace MLEM.Ui.Elements { public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) { batch.Draw(this.Background, this.DisplayArea, Color.White * alpha, this.Scale); - var scrollerPos = new Point(this.DisplayArea.X + this.ScrollerOffset.X, this.DisplayArea.Y + this.ScrollerOffset.Y); - var scrollerOffset = new Point( - !this.Horizontal ? 0 : (this.currValue / this.maxValue * (this.DisplayArea.Width - this.ScrollerSize.X * this.Scale)).Floor(), - this.Horizontal ? 0 : (this.currValue / this.maxValue * (this.DisplayArea.Height - this.ScrollerSize.Y * this.Scale)).Floor()); - var scrollerRect = new Rectangle(scrollerPos + scrollerOffset, new Point((this.ScrollerSize.X * this.Scale).Ceil(), (this.ScrollerSize.Y * this.Scale).Ceil())); + var scrollerPos = new Vector2(this.DisplayArea.X + this.ScrollerOffset.X, this.DisplayArea.Y + this.ScrollerOffset.Y); + var scrollerOffset = new Vector2( + !this.Horizontal ? 0 : this.currValue / this.maxValue * (this.DisplayArea.Width - this.ScrollerSize.X * this.Scale), + this.Horizontal ? 0 : this.currValue / this.maxValue * (this.DisplayArea.Height - this.ScrollerSize.Y * this.Scale)); + var scrollerRect = new RectangleF(scrollerPos + scrollerOffset, new Vector2((this.ScrollerSize.X * this.Scale).Ceil(), (this.ScrollerSize.Y * this.Scale).Ceil())); batch.Draw(this.ScrollerTexture, scrollerRect, Color.White * alpha, this.Scale); base.Draw(time, batch, alpha, blendState, samplerState, matrix); } diff --git a/MLEM.Ui/Elements/TextField.cs b/MLEM.Ui/Elements/TextField.cs index 20bf0bb..b916e80 100644 --- a/MLEM.Ui/Elements/TextField.cs +++ b/MLEM.Ui/Elements/TextField.cs @@ -143,13 +143,15 @@ namespace MLEM.Ui.Elements { } batch.Draw(tex, this.DisplayArea, color, this.Scale); - var textPos = this.DisplayArea.Location.ToVector2() + new Vector2(this.TextOffsetX * this.Scale, this.DisplayArea.Height / 2); - if (this.text.Length > 0 || this.IsSelected) { - var caret = this.IsSelected ? this.caretBlinkTimer >= 0.5F ? "|" : " " : ""; - var display = this.displayedText.Insert(this.CaretPos - this.textOffset, caret); - this.Font.Value.DrawCenteredString(batch, display, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true); - } else if (this.PlaceholderText != null) { - this.Font.Value.DrawCenteredString(batch, this.PlaceholderText, textPos, this.TextScale * this.Scale, Color.Gray * alpha, false, true); + if (this.displayedText != null) { + var textPos = this.DisplayArea.Location + new Vector2(this.TextOffsetX * this.Scale, this.DisplayArea.Height / 2); + if (this.text.Length > 0 || this.IsSelected) { + var caret = this.IsSelected ? this.caretBlinkTimer >= 0.5F ? "|" : " " : ""; + var display = this.displayedText.Insert(this.CaretPos - this.textOffset, caret); + this.Font.Value.DrawCenteredString(batch, display, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true); + } else if (this.PlaceholderText != null) { + this.Font.Value.DrawCenteredString(batch, this.PlaceholderText, textPos, this.TextScale * this.Scale, Color.Gray * alpha, false, true); + } } base.Draw(time, batch, alpha, blendState, samplerState, matrix); } diff --git a/MLEM.Ui/Style/UiStyle.cs b/MLEM.Ui/Style/UiStyle.cs index 1ed6438..9c4748e 100644 --- a/MLEM.Ui/Style/UiStyle.cs +++ b/MLEM.Ui/Style/UiStyle.cs @@ -27,7 +27,7 @@ namespace MLEM.Ui.Style { public Color TooltipBackgroundColor; public NinePatch ProgressBarTexture; public Color ProgressBarColor; - public Point ProgressBarProgressPadding; + public Vector2 ProgressBarProgressPadding; public NinePatch ProgressBarProgressTexture; public Color ProgressBarProgressColor; public IGenericFont Font; diff --git a/MLEM.Ui/Style/UntexturedStyle.cs b/MLEM.Ui/Style/UntexturedStyle.cs index 9d49954..2a63ded 100644 --- a/MLEM.Ui/Style/UntexturedStyle.cs +++ b/MLEM.Ui/Style/UntexturedStyle.cs @@ -27,7 +27,7 @@ namespace MLEM.Ui.Style { this.TooltipBackgroundColor = new Color(Color.Black, 0.65F); this.ProgressBarTexture = GenerateTexture(batch, Color.RoyalBlue); this.ProgressBarColor = Color.White; - this.ProgressBarProgressPadding = new Point(1); + this.ProgressBarProgressPadding = new Vector2(1); this.ProgressBarProgressColor = Color.Red; this.Font = new EmptyFont(); } diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs index 110fe5d..6e84b14 100644 --- a/MLEM.Ui/UiControls.cs +++ b/MLEM.Ui/UiControls.cs @@ -45,7 +45,7 @@ namespace MLEM.Ui { this.ActiveRoot = this.System.GetRootElements().FirstOrDefault(root => root.CanSelectContent); // MOUSE INPUT - var mousedNow = this.GetElementUnderPos(this.Input.MousePosition); + var mousedNow = this.GetElementUnderPos(this.Input.MousePosition.ToVector2()); if (mousedNow != this.MousedElement) { if (this.MousedElement != null) this.System.OnElementMouseExit?.Invoke(this.MousedElement); @@ -92,13 +92,13 @@ namespace MLEM.Ui { // TOUCH INPUT else if (this.Input.GetGesture(GestureType.Tap, out var tap)) { this.IsAutoNavMode = false; - var tapped = this.GetElementUnderPos(tap.Position.ToPoint()); + var tapped = this.GetElementUnderPos(tap.Position); this.ActiveRoot?.SelectElement(tapped); if (tapped != null) this.System.OnElementPressed?.Invoke(tapped); } else if (this.Input.GetGesture(GestureType.Hold, out var hold)) { this.IsAutoNavMode = false; - var held = this.GetElementUnderPos(hold.Position.ToPoint()); + var held = this.GetElementUnderPos(hold.Position); this.ActiveRoot?.SelectElement(held); if (held != null) this.System.OnElementSecondaryPressed?.Invoke(held); @@ -124,9 +124,9 @@ namespace MLEM.Ui { } } - public virtual Element GetElementUnderPos(Point position, bool transform = true) { + public virtual Element GetElementUnderPos(Vector2 position, bool transform = true) { foreach (var root in this.System.GetRootElements()) { - var pos = transform ? position.Transform(root.InvTransform) : position; + var pos = transform ? Vector2.Transform(position, root.InvTransform) : position; var moused = root.Element.GetElementUnderPos(pos); if (moused != null) return moused; @@ -162,7 +162,7 @@ namespace MLEM.Ui { } } - protected virtual Element GetGamepadNextElement(Rectangle searchArea) { + protected virtual Element GetGamepadNextElement(RectangleF searchArea) { if (this.ActiveRoot == null) return null; var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element); @@ -174,7 +174,7 @@ namespace MLEM.Ui { foreach (var child in children) { if (!child.CanBeSelected || child == this.SelectedElement || !searchArea.Intersects(child.Area)) continue; - var dist = Vector2.Distance(child.Area.Center.ToVector2(), this.SelectedElement.Area.Center.ToVector2()); + var dist = Vector2.Distance(child.Area.Center, this.SelectedElement.Area.Center); if (closest == null || dist < closestDist) { closest = child; closestDist = dist; @@ -190,7 +190,7 @@ namespace MLEM.Ui { private void HandleGamepadNextElement(Direction2 dir) { this.IsAutoNavMode = true; - Rectangle searchArea = default; + RectangleF searchArea = default; if (this.SelectedElement?.Root != null) { searchArea = this.SelectedElement.Area; var (_, _, width, height) = this.System.Viewport; diff --git a/MLEM/Extensions/NumberExtensions.cs b/MLEM/Extensions/NumberExtensions.cs index a3b9132..63ec928 100644 --- a/MLEM/Extensions/NumberExtensions.cs +++ b/MLEM/Extensions/NumberExtensions.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Xna.Framework; +using MLEM.Misc; namespace MLEM.Extensions { public static class NumberExtensions { @@ -44,6 +45,12 @@ namespace MLEM.Extensions { return rect; } + public static RectangleF OffsetCopy(this RectangleF rect, Vector2 offset) { + rect.X += offset.X; + rect.Y += offset.Y; + return rect; + } + public static Rectangle Shrink(this Rectangle rect, Point padding) { rect.X += padding.X; rect.Y += padding.Y; @@ -52,5 +59,13 @@ namespace MLEM.Extensions { return rect; } + public static RectangleF Shrink(this RectangleF rect, Vector2 padding) { + rect.X += padding.X; + rect.Y += padding.Y; + rect.Width -= padding.X * 2; + rect.Height -= padding.Y * 2; + return rect; + } + } } \ No newline at end of file diff --git a/MLEM/Extensions/SpriteBatchExtensions.cs b/MLEM/Extensions/SpriteBatchExtensions.cs index d79c94a..3cb34d4 100644 --- a/MLEM/Extensions/SpriteBatchExtensions.cs +++ b/MLEM/Extensions/SpriteBatchExtensions.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Misc; namespace MLEM.Extensions { public static class SpriteBatchExtensions { @@ -30,5 +31,19 @@ namespace MLEM.Extensions { color, 0, size / 2, scale + addedScale, SpriteEffects.None, 0); } + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth) { + var source = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height); + var scale = new Vector2(1F / source.Width, 1F / source.Height) * destinationRectangle.Size; + batch.Draw(texture, destinationRectangle.Location, sourceRectangle, color, rotation, origin, scale, effects, layerDepth); + } + + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color) { + batch.Draw(texture, destinationRectangle, sourceRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); + } + + public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Color color) { + batch.Draw(texture, destinationRectangle, null, color); + } + } } \ No newline at end of file diff --git a/MLEM/Misc/RectangleF.cs b/MLEM/Misc/RectangleF.cs new file mode 100644 index 0000000..ccf67a8 --- /dev/null +++ b/MLEM/Misc/RectangleF.cs @@ -0,0 +1,142 @@ +using System; +using Microsoft.Xna.Framework; +using MLEM.Extensions; + +namespace MLEM.Misc { + public struct RectangleF : IEquatable { + + public static RectangleF Empty => default; + + public float X; + public float Y; + public float Width; + public float Height; + + public float Left => this.X; + public float Right => this.X + this.Width; + public float Top => this.Y; + public float Bottom => this.Y + this.Height; + public bool IsEmpty => this.Width <= 0 || this.Height <= 0; + + public Vector2 Location { + get => new Vector2(this.X, this.Y); + set { + this.X = value.X; + this.Y = value.Y; + } + } + public Vector2 Size { + get => new Vector2(this.Width, this.Height); + set { + this.Width = value.X; + this.Height = value.Y; + } + } + public Vector2 Center => new Vector2(this.X + this.Width / 2, this.Y + this.Height / 2); + + public RectangleF(float x, float y, float width, float height) { + this.X = x; + this.Y = y; + this.Width = width; + this.Height = height; + } + + public RectangleF(Vector2 location, Vector2 size) { + this.X = location.X; + this.Y = location.Y; + this.Width = size.X; + this.Height = size.Y; + } + + public static explicit operator Rectangle(RectangleF rect) { + return new Rectangle(rect.X.Floor(), rect.Y.Floor(), rect.Width.Floor(), rect.Height.Floor()); + } + + public static explicit operator RectangleF(Rectangle rect) { + return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height); + } + + public static bool operator ==(RectangleF a, RectangleF b) { + return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height; + } + + public static bool operator !=(RectangleF a, RectangleF b) { + return !(a == b); + } + + public bool Contains(float x, float y) { + return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height; + } + + public bool Contains(Vector2 value) { + return this.Contains(value.X, value.Y); + } + + public bool Contains(RectangleF value) { + return this.X <= value.X && value.X + value.Width <= this.X + this.Width && this.Y <= value.Y && value.Y + value.Height <= this.Y + this.Height; + } + + public override bool Equals(object obj) { + return obj is RectangleF f && this == f; + } + + public bool Equals(RectangleF other) { + return this == other; + } + + public override int GetHashCode() { + return (((17 * 23 + this.X.GetHashCode()) * 23 + this.Y.GetHashCode()) * 23 + this.Width.GetHashCode()) * 23 + this.Height.GetHashCode(); + } + + public void Inflate(float horizontalAmount, float verticalAmount) { + this.X -= horizontalAmount; + this.Y -= verticalAmount; + this.Width += horizontalAmount * 2; + this.Height += verticalAmount * 2; + } + + public bool Intersects(RectangleF value) { + return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom; + } + + public static RectangleF Intersect(RectangleF value1, RectangleF value2) { + if (value1.Intersects(value2)) { + var num1 = Math.Min(value1.X + value1.Width, value2.X + value2.Width); + var x = Math.Max(value1.X, value2.X); + var y = Math.Max(value1.Y, value2.Y); + var num2 = Math.Min(value1.Y + value1.Height, value2.Y + value2.Height); + return new RectangleF(x, y, num1 - x, num2 - y); + } else { + return Empty; + } + } + + public void Offset(float offsetX, float offsetY) { + this.X += offsetX; + this.Y += offsetY; + } + + public void Offset(Vector2 amount) { + this.X += amount.X; + this.Y += amount.Y; + } + + public override string ToString() { + return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}"; + } + + public static RectangleF Union(RectangleF value1, RectangleF value2) { + var x = Math.Min(value1.X, value2.X); + var y = Math.Min(value1.Y, value2.Y); + return new RectangleF(x, y, Math.Max(value1.Right, value2.Right) - x, Math.Max(value1.Bottom, value2.Bottom) - y); + } + + public void Deconstruct(out float x, out float y, out float width, out float height) { + x = this.X; + y = this.Y; + width = this.Width; + height = this.Height; + } + + } +} \ No newline at end of file diff --git a/MLEM/Textures/NinePatch.cs b/MLEM/Textures/NinePatch.cs index 584a380..a475f50 100644 --- a/MLEM/Textures/NinePatch.cs +++ b/MLEM/Textures/NinePatch.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; +using MLEM.Misc; namespace MLEM.Textures { public class NinePatch { @@ -35,6 +36,10 @@ namespace MLEM.Textures { } public IEnumerable CreateRectangles(Rectangle area, float patchScale = 1) { + return this.CreateRectangles((RectangleF) area, patchScale).Select(r => (Rectangle) r); + } + + 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); @@ -47,22 +52,22 @@ namespace MLEM.Textures { var topY = area.Y + pt; var bottomY = area.Y + area.Height - pb; - yield return new Rectangle(area.X, area.Y, pl, pt); - yield return new Rectangle(leftX, area.Y, centerW, pt); - yield return new Rectangle(rightX, area.Y, pr, pt); - yield return new Rectangle(area.X, topY, pl, centerH); - yield return new Rectangle(leftX, topY, centerW, centerH); - yield return new Rectangle(rightX, topY, pr, centerH); - yield return new Rectangle(area.X, bottomY, pl, pb); - yield return new Rectangle(leftX, bottomY, centerW, pb); - yield return new Rectangle(rightX, bottomY, pr, pb); + yield return new RectangleF(area.X, area.Y, pl, pt); + yield return new RectangleF(leftX, area.Y, centerW, pt); + yield return new RectangleF(rightX, area.Y, pr, pt); + yield return new RectangleF(area.X, topY, pl, centerH); + yield return new RectangleF(leftX, topY, centerW, centerH); + yield return new RectangleF(rightX, topY, pr, centerH); + yield return new RectangleF(area.X, bottomY, pl, pb); + yield return new RectangleF(leftX, bottomY, centerW, pb); + yield return new RectangleF(rightX, bottomY, pr, pb); } } public static class NinePatchExtensions { - public static void Draw(this SpriteBatch batch, NinePatch texture, Rectangle destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, float patchScale = 1) { + public static void Draw(this SpriteBatch batch, NinePatch texture, RectangleF destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, float patchScale = 1) { var dest = texture.CreateRectangles(destinationRectangle, patchScale); var count = 0; foreach (var rect in dest) { @@ -72,6 +77,14 @@ namespace MLEM.Textures { } } + public static void Draw(this SpriteBatch batch, NinePatch texture, Rectangle destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, float patchScale = 1) { + batch.Draw(texture, (RectangleF) destinationRectangle, color, rotation, origin, effects, layerDepth, patchScale); + } + + public static void Draw(this SpriteBatch batch, NinePatch texture, RectangleF destinationRectangle, Color color, float patchScale = 1) { + batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0, patchScale); + } + public static void Draw(this SpriteBatch batch, NinePatch texture, Rectangle destinationRectangle, Color color, float patchScale = 1) { batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0, patchScale); } diff --git a/MLEM/Textures/TextureRegion.cs b/MLEM/Textures/TextureRegion.cs index d02b34e..d730e23 100644 --- a/MLEM/Textures/TextureRegion.cs +++ b/MLEM/Textures/TextureRegion.cs @@ -1,6 +1,8 @@ using System.Diagnostics.Tracing; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Extensions; +using MLEM.Misc; namespace MLEM.Textures { public class TextureRegion { @@ -44,6 +46,10 @@ namespace MLEM.Textures { batch.Draw(texture.Texture, destinationRectangle, texture.Area, color, rotation, origin, effects, layerDepth); } + public static void Draw(this SpriteBatch batch, TextureRegion texture, RectangleF destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth) { + batch.Draw(texture.Texture, destinationRectangle, texture.Area, color, rotation, origin, effects, layerDepth); + } + public static void Draw(this SpriteBatch batch, TextureRegion texture, Vector2 position, Color color) { batch.Draw(texture, position, color, 0, Vector2.Zero, Vector2.One, SpriteEffects.None, 0); } @@ -52,5 +58,9 @@ namespace MLEM.Textures { batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); } + public static void Draw(this SpriteBatch batch, TextureRegion texture, RectangleF destinationRectangle, Color color) { + batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); + } + } } \ No newline at end of file diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index a50e016..0b5fa61 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -54,7 +54,7 @@ namespace Sandbox { var show = screen.IsHidden; screen.IsHidden = false; var time = 0; - const float total = 200; + const float total = 20; while (time <= total) { yield return new WaitEvent(CoroutineEvents.Update); var percent = show ? time / total : 1 - time / total;