1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-06-26 14:41:41 +02:00

added a rectanglef class which allows mlem to use decimal coordinates

This commit is contained in:
Ellpeck 2019-11-02 14:53:59 +01:00
parent cb7abbbbef
commit 32c8147a4c
19 changed files with 310 additions and 79 deletions

View file

@ -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);
}
}
}

View file

@ -1,5 +1,8 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Textures;
using MonoGame.Extended;
using MonoGame.Extended.BitmapFonts; using MonoGame.Extended.BitmapFonts;
namespace MLEM.Extended.Extensions { namespace MLEM.Extended.Extensions {
@ -15,6 +18,18 @@ namespace MLEM.Extended.Extensions {
color, 0, size / 2, scale + addedScale, SpriteEffects.None, 0); 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);
}
} }
} }

View file

@ -2,6 +2,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Input; using MLEM.Input;
using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style; 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); var size = base.CalcActualSize(parentArea);
if (this.Label != null) { if (this.Label != null) {
this.Label.Size = new Vector2((size.X - size.Y) / this.Scale - this.TextOffsetX, 1); 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; 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); batch.Draw(tex, boxDisplayArea, color, this.Scale);
if (this.Checked) if (this.Checked)
batch.Draw(this.Checkmark, boxDisplayArea, Color.White * alpha); batch.Draw(this.Checkmark, boxDisplayArea, Color.White * alpha);

View file

@ -26,7 +26,7 @@ namespace MLEM.Ui.Elements {
private Vector2 size; private Vector2 size;
private Vector2 offset; private Vector2 offset;
public Vector2 Padding; public Vector2 Padding;
public Point ScaledPadding => (this.Padding * this.Scale).ToPoint(); public Vector2 ScaledPadding => this.Padding * this.Scale;
private Vector2 childPadding; private Vector2 childPadding;
public Anchor Anchor { public Anchor Anchor {
get => this.anchor; get => this.anchor;
@ -56,7 +56,7 @@ namespace MLEM.Ui.Elements {
this.SetAreaDirty(); this.SetAreaDirty();
} }
} }
public Point ScaledOffset => (this.offset * this.Scale).ToPoint(); public Vector2 ScaledOffset => (this.offset * this.Scale);
public Vector2 ChildPadding { public Vector2 ChildPadding {
get => this.childPadding; get => this.childPadding;
set { set {
@ -66,8 +66,8 @@ namespace MLEM.Ui.Elements {
this.SetAreaDirty(); this.SetAreaDirty();
} }
} }
public Rectangle ChildPaddedArea => this.UnscrolledArea.Shrink(this.ScaledChildPadding); public RectangleF ChildPaddedArea => this.UnscrolledArea.Shrink(this.ScaledChildPadding);
public Point ScaledChildPadding => (this.childPadding * this.Scale).ToPoint(); public Vector2 ScaledChildPadding => this.childPadding * this.Scale;
public DrawCallback OnDrawn; public DrawCallback OnDrawn;
public TimeCallback OnUpdated; public TimeCallback OnUpdated;
@ -116,17 +116,17 @@ namespace MLEM.Ui.Elements {
public bool SetHeightBasedOnChildren; public bool SetHeightBasedOnChildren;
public bool CanAutoAnchorsAttach = true; public bool CanAutoAnchorsAttach = true;
private Rectangle area; private RectangleF area;
public Rectangle UnscrolledArea { public RectangleF UnscrolledArea {
get { get {
this.UpdateAreaIfDirty(); this.UpdateAreaIfDirty();
return this.area; return this.area;
} }
} }
public Rectangle Area => this.UnscrolledArea.OffsetCopy(this.ScaledScrollOffset); public RectangleF Area => this.UnscrolledArea.OffsetCopy(this.ScaledScrollOffset);
public Vector2 ScrollOffset; public Vector2 ScrollOffset;
public Point ScaledScrollOffset => (this.ScrollOffset * this.Scale).ToPoint(); public Vector2 ScaledScrollOffset => this.ScrollOffset * this.Scale;
public Rectangle DisplayArea => this.Area.Shrink(this.ScaledPadding); public RectangleF DisplayArea => this.Area.Shrink(this.ScaledPadding);
private int priority; private int priority;
public int Priority { public int Priority {
get => this.priority; get => this.priority;
@ -218,12 +218,12 @@ namespace MLEM.Ui.Elements {
if (this.IsHidden) if (this.IsHidden)
return; 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 parentCenterX = parentArea.X + parentArea.Width / 2;
var parentCenterY = parentArea.Y + parentArea.Height / 2; var parentCenterY = parentArea.Y + parentArea.Height / 2;
var actualSize = this.CalcActualSize(parentArea); var actualSize = this.CalcActualSize(parentArea);
var pos = new Point(); var pos = new Vector2();
switch (this.anchor) { switch (this.anchor) {
case Anchor.TopLeft: 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); this.System.OnElementAreaUpdated?.Invoke(this);
foreach (var child in this.Children) foreach (var child in this.Children)
@ -319,13 +319,13 @@ namespace MLEM.Ui.Elements {
} }
} }
protected virtual Point CalcActualSize(Rectangle parentArea) { protected virtual Vector2 CalcActualSize(RectangleF parentArea) {
return new Point( return new Vector2(
(this.size.X > 1 ? this.ScaledSize.X : parentArea.Width * this.size.X).Ceil(), this.size.X > 1 ? this.ScaledSize.X : parentArea.Width * this.size.X,
(this.size.Y > 1 ? this.ScaledSize.Y : parentArea.Height * this.size.Y).Ceil()); this.size.Y > 1 ? this.ScaledSize.Y : parentArea.Height * this.size.Y);
} }
protected virtual Rectangle GetAreaForAutoAnchors() { protected virtual RectangleF GetAreaForAutoAnchors() {
return this.UnscrolledArea; 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) if (this.IsHidden)
return null; return null;
var children = this.GetRelevantChildren(); var children = this.GetRelevantChildren();

View file

@ -1,6 +1,7 @@
using System; using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style; using MLEM.Ui.Style;
@ -51,8 +52,8 @@ namespace MLEM.Ui.Elements {
this.CanBeMoused = false; this.CanBeMoused = false;
} }
protected override Point CalcActualSize(Rectangle parentArea) { protected override Vector2 CalcActualSize(RectangleF parentArea) {
return this.texture != null && this.scaleToImage ? this.texture.Size : base.CalcActualSize(parentArea); return this.texture != null && this.scaleToImage ? this.texture.Size.ToVector2() : base.CalcActualSize(parentArea);
} }
public override void Update(GameTime time) { public override void Update(GameTime time) {
@ -69,10 +70,10 @@ namespace MLEM.Ui.Elements {
if (this.MaintainImageAspect) { if (this.MaintainImageAspect) {
var scale = Math.Min(this.DisplayArea.Width / (float) this.texture.Width, this.DisplayArea.Height / (float) this.texture.Height); 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); 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 { } else {
var scale = new Vector2(1F / this.texture.Width, 1F / this.texture.Height) * this.DisplayArea.Size.ToVector2(); var scale = new Vector2(1F / this.texture.Width, 1F / this.texture.Height) * this.DisplayArea.Size;
batch.Draw(this.texture, this.DisplayArea.Location.ToVector2() + center * scale, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); 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); base.Draw(time, batch, alpha, blendState, samplerState, matrix);
} }

View file

@ -5,6 +5,7 @@ using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style; 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 || targetArea.Width != this.renderTarget.Width || targetArea.Height != this.renderTarget.Height) {
if (this.renderTarget != null) if (this.renderTarget != null)
this.renderTarget.Dispose(); this.renderTarget.Dispose();
var empty = targetArea.Width <= 0 || targetArea.Height <= 0; this.renderTarget = targetArea.IsEmpty ? null : new RenderTarget2D(this.System.GraphicsDevice, targetArea.Width.Ceil(), targetArea.Height.Ceil());
this.renderTarget = empty ? null : new RenderTarget2D(this.System.GraphicsDevice, targetArea.Width, targetArea.Height);
} }
} }
} }
@ -91,7 +91,7 @@ namespace MLEM.Ui.Elements {
private void ScrollChildren() { private void ScrollChildren() {
if (!this.scrollOverflow) if (!this.scrollOverflow)
return; return;
var offset = -this.ScrollBar.CurrentValue.Floor(); var offset = -this.ScrollBar.CurrentValue;
foreach (var child in this.GetChildren(c => c != this.ScrollBar, true)) foreach (var child in this.GetChildren(c => c != this.ScrollBar, true))
child.ScrollOffset = new Vector2(0, offset); child.ScrollOffset = new Vector2(0, offset);
this.relevantChildrenDirty = true; 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 overflow is handled, don't propagate mouse checks to hidden children
if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(position)) if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(position))
return null; return null;
return base.GetElementUnderPos(position); return base.GetElementUnderPos(position);
} }
private Rectangle GetRenderTargetArea() { private RectangleF GetRenderTargetArea() {
var area = this.ChildPaddedArea; var area = this.ChildPaddedArea;
area.X = this.DisplayArea.X; area.X = this.DisplayArea.X;
area.Width = this.DisplayArea.Width; area.Width = this.DisplayArea.Width;

View file

@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Font; using MLEM.Font;
using MLEM.Formatting; using MLEM.Formatting;
using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style; using MLEM.Ui.Style;
@ -55,7 +56,7 @@ namespace MLEM.Ui.Elements {
this.CanBeMoused = false; this.CanBeMoused = false;
} }
protected override Point CalcActualSize(Rectangle parentArea) { protected override Vector2 CalcActualSize(RectangleF parentArea) {
var size = base.CalcActualSize(parentArea); var size = base.CalcActualSize(parentArea);
var sc = this.TextScale * this.Scale; var sc = this.TextScale * this.Scale;
@ -63,7 +64,7 @@ namespace MLEM.Ui.Elements {
this.codeLocations = this.text.GetFormattingCodes(); this.codeLocations = this.text.GetFormattingCodes();
var textDims = this.RegularFont.Value.MeasureString(this.splitText) * sc; 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) { public override void Update(GameTime time) {
@ -77,7 +78,7 @@ namespace MLEM.Ui.Elements {
if (this.Background.Value != null) if (this.Background.Value != null)
batch.Draw(this.Background, this.Area, (Color) this.BackgroundColor * alpha); 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 sc = this.TextScale * this.Scale;
var color = (this.TextColor.Value != default ? this.TextColor : Color.White) * alpha; var color = (this.TextColor.Value != default ? this.TextColor : Color.White) * alpha;

View file

@ -11,7 +11,7 @@ namespace MLEM.Ui.Elements {
public StyleProp<NinePatch> Texture; public StyleProp<NinePatch> Texture;
public StyleProp<Color> Color; public StyleProp<Color> Color;
public StyleProp<Point> ProgressPadding; public StyleProp<Vector2> ProgressPadding;
public StyleProp<NinePatch> ProgressTexture; public StyleProp<NinePatch> ProgressTexture;
public StyleProp<Color> ProgressColor; public StyleProp<Color> ProgressColor;
@ -39,28 +39,28 @@ namespace MLEM.Ui.Elements {
var tex = this.ProgressTexture.Value; var tex = this.ProgressTexture.Value;
var padHor = tex != null ? (tex.PaddingLeft + tex.PaddingRight) * this.Scale : 0; var padHor = tex != null ? (tex.PaddingLeft + tex.PaddingRight) * this.Scale : 0;
var padVer = tex != null ? (tex.PaddingTop + tex.PaddingBottom) * this.Scale : 0; var padVer = tex != null ? (tex.PaddingTop + tex.PaddingBottom) * this.Scale : 0;
var width = (percentage * (this.DisplayArea.Width - padHor) + padHor).Floor(); var width = percentage * (this.DisplayArea.Width - padHor) + padHor;
var height = (percentage * (this.DisplayArea.Height - padVer) + padVer).Floor(); var height = percentage * (this.DisplayArea.Height - padVer) + padVer;
Rectangle progressArea; RectangleF progressArea;
switch (this.Direction) { switch (this.Direction) {
case Direction2.Up: case Direction2.Up:
progressArea = new Rectangle(this.DisplayArea.X, progressArea = new RectangleF(this.DisplayArea.X,
this.DisplayArea.Y + (this.DisplayArea.Height - height), this.DisplayArea.Y + (this.DisplayArea.Height - height),
this.DisplayArea.Width, height); this.DisplayArea.Width, height);
break; break;
case Direction2.Down: 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; break;
case Direction2.Left: case Direction2.Left:
progressArea = new Rectangle( progressArea = new RectangleF(
this.DisplayArea.X + (this.DisplayArea.Width - width), this.DisplayArea.X + (this.DisplayArea.Width - width),
this.DisplayArea.Y, width, this.DisplayArea.Height); this.DisplayArea.Y, width, this.DisplayArea.Height);
break; break;
default: // Right 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; 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) { if (this.ProgressTexture.Value != null) {
batch.Draw(this.ProgressTexture, offsetArea, (Color) this.ProgressColor * alpha, this.Scale); batch.Draw(this.ProgressTexture, offsetArea, (Color) this.ProgressColor * alpha, this.Scale);
} else { } else {

View file

@ -5,6 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Xna.Framework.Input.Touch;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Input; using MLEM.Input;
using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style; using MLEM.Ui.Style;
@ -13,8 +14,8 @@ namespace MLEM.Ui.Elements {
public StyleProp<NinePatch> Background; public StyleProp<NinePatch> Background;
public StyleProp<NinePatch> ScrollerTexture; public StyleProp<NinePatch> ScrollerTexture;
public Point ScrollerOffset; public Vector2 ScrollerOffset;
public Point ScrollerSize; public Vector2 ScrollerSize;
private float maxValue; private float maxValue;
public float MaxValue { public float MaxValue {
get => this.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) { public ScrollBar(Anchor anchor, Vector2 size, int scrollerSize, float maxValue, bool horizontal = false) : base(anchor, size) {
this.maxValue = maxValue; this.maxValue = maxValue;
this.Horizontal = horizontal; 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; this.CanBeSelected = false;
} }
@ -79,7 +80,7 @@ namespace MLEM.Ui.Elements {
// are we dragging on top of the panel? // are we dragging on top of the panel?
if (this.Input.GetGesture(GestureType.VerticalDrag, out var drag)) { 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 // 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) if (touched != null && touched != this)
this.isDragging = true; 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) { 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); 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 scrollerPos = new Vector2(this.DisplayArea.X + this.ScrollerOffset.X, this.DisplayArea.Y + this.ScrollerOffset.Y);
var scrollerOffset = new Point( var scrollerOffset = new Vector2(
!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.Width - this.ScrollerSize.X * this.Scale),
this.Horizontal ? 0 : (this.currValue / this.maxValue * (this.DisplayArea.Height - this.ScrollerSize.Y * this.Scale)).Floor()); this.Horizontal ? 0 : this.currValue / this.maxValue * (this.DisplayArea.Height - this.ScrollerSize.Y * this.Scale));
var scrollerRect = new Rectangle(scrollerPos + scrollerOffset, new Point((this.ScrollerSize.X * this.Scale).Ceil(), (this.ScrollerSize.Y * this.Scale).Ceil())); 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); batch.Draw(this.ScrollerTexture, scrollerRect, Color.White * alpha, this.Scale);
base.Draw(time, batch, alpha, blendState, samplerState, matrix); base.Draw(time, batch, alpha, blendState, samplerState, matrix);
} }

View file

@ -143,13 +143,15 @@ namespace MLEM.Ui.Elements {
} }
batch.Draw(tex, this.DisplayArea, color, this.Scale); 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.displayedText != null) {
if (this.text.Length > 0 || this.IsSelected) { var textPos = this.DisplayArea.Location + new Vector2(this.TextOffsetX * this.Scale, this.DisplayArea.Height / 2);
var caret = this.IsSelected ? this.caretBlinkTimer >= 0.5F ? "|" : " " : ""; if (this.text.Length > 0 || this.IsSelected) {
var display = this.displayedText.Insert(this.CaretPos - this.textOffset, caret); var caret = this.IsSelected ? this.caretBlinkTimer >= 0.5F ? "|" : " " : "";
this.Font.Value.DrawCenteredString(batch, display, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true); var display = this.displayedText.Insert(this.CaretPos - this.textOffset, caret);
} else if (this.PlaceholderText != null) { this.Font.Value.DrawCenteredString(batch, display, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true);
this.Font.Value.DrawCenteredString(batch, this.PlaceholderText, textPos, this.TextScale * this.Scale, Color.Gray * 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); base.Draw(time, batch, alpha, blendState, samplerState, matrix);
} }

View file

@ -27,7 +27,7 @@ namespace MLEM.Ui.Style {
public Color TooltipBackgroundColor; public Color TooltipBackgroundColor;
public NinePatch ProgressBarTexture; public NinePatch ProgressBarTexture;
public Color ProgressBarColor; public Color ProgressBarColor;
public Point ProgressBarProgressPadding; public Vector2 ProgressBarProgressPadding;
public NinePatch ProgressBarProgressTexture; public NinePatch ProgressBarProgressTexture;
public Color ProgressBarProgressColor; public Color ProgressBarProgressColor;
public IGenericFont Font; public IGenericFont Font;

View file

@ -27,7 +27,7 @@ namespace MLEM.Ui.Style {
this.TooltipBackgroundColor = new Color(Color.Black, 0.65F); this.TooltipBackgroundColor = new Color(Color.Black, 0.65F);
this.ProgressBarTexture = GenerateTexture(batch, Color.RoyalBlue); this.ProgressBarTexture = GenerateTexture(batch, Color.RoyalBlue);
this.ProgressBarColor = Color.White; this.ProgressBarColor = Color.White;
this.ProgressBarProgressPadding = new Point(1); this.ProgressBarProgressPadding = new Vector2(1);
this.ProgressBarProgressColor = Color.Red; this.ProgressBarProgressColor = Color.Red;
this.Font = new EmptyFont(); this.Font = new EmptyFont();
} }

View file

@ -45,7 +45,7 @@ namespace MLEM.Ui {
this.ActiveRoot = this.System.GetRootElements().FirstOrDefault(root => root.CanSelectContent); this.ActiveRoot = this.System.GetRootElements().FirstOrDefault(root => root.CanSelectContent);
// MOUSE INPUT // MOUSE INPUT
var mousedNow = this.GetElementUnderPos(this.Input.MousePosition); var mousedNow = this.GetElementUnderPos(this.Input.MousePosition.ToVector2());
if (mousedNow != this.MousedElement) { if (mousedNow != this.MousedElement) {
if (this.MousedElement != null) if (this.MousedElement != null)
this.System.OnElementMouseExit?.Invoke(this.MousedElement); this.System.OnElementMouseExit?.Invoke(this.MousedElement);
@ -92,13 +92,13 @@ namespace MLEM.Ui {
// TOUCH INPUT // TOUCH INPUT
else if (this.Input.GetGesture(GestureType.Tap, out var tap)) { else if (this.Input.GetGesture(GestureType.Tap, out var tap)) {
this.IsAutoNavMode = false; this.IsAutoNavMode = false;
var tapped = this.GetElementUnderPos(tap.Position.ToPoint()); var tapped = this.GetElementUnderPos(tap.Position);
this.ActiveRoot?.SelectElement(tapped); this.ActiveRoot?.SelectElement(tapped);
if (tapped != null) if (tapped != null)
this.System.OnElementPressed?.Invoke(tapped); this.System.OnElementPressed?.Invoke(tapped);
} else if (this.Input.GetGesture(GestureType.Hold, out var hold)) { } else if (this.Input.GetGesture(GestureType.Hold, out var hold)) {
this.IsAutoNavMode = false; this.IsAutoNavMode = false;
var held = this.GetElementUnderPos(hold.Position.ToPoint()); var held = this.GetElementUnderPos(hold.Position);
this.ActiveRoot?.SelectElement(held); this.ActiveRoot?.SelectElement(held);
if (held != null) if (held != null)
this.System.OnElementSecondaryPressed?.Invoke(held); 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()) { 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); var moused = root.Element.GetElementUnderPos(pos);
if (moused != null) if (moused != null)
return moused; 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) if (this.ActiveRoot == null)
return null; return null;
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element); 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) { foreach (var child in children) {
if (!child.CanBeSelected || child == this.SelectedElement || !searchArea.Intersects(child.Area)) if (!child.CanBeSelected || child == this.SelectedElement || !searchArea.Intersects(child.Area))
continue; 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) { if (closest == null || dist < closestDist) {
closest = child; closest = child;
closestDist = dist; closestDist = dist;
@ -190,7 +190,7 @@ namespace MLEM.Ui {
private void HandleGamepadNextElement(Direction2 dir) { private void HandleGamepadNextElement(Direction2 dir) {
this.IsAutoNavMode = true; this.IsAutoNavMode = true;
Rectangle searchArea = default; RectangleF searchArea = default;
if (this.SelectedElement?.Root != null) { if (this.SelectedElement?.Root != null) {
searchArea = this.SelectedElement.Area; searchArea = this.SelectedElement.Area;
var (_, _, width, height) = this.System.Viewport; var (_, _, width, height) = this.System.Viewport;

View file

@ -1,5 +1,6 @@
using System; using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using MLEM.Misc;
namespace MLEM.Extensions { namespace MLEM.Extensions {
public static class NumberExtensions { public static class NumberExtensions {
@ -44,6 +45,12 @@ namespace MLEM.Extensions {
return rect; 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) { public static Rectangle Shrink(this Rectangle rect, Point padding) {
rect.X += padding.X; rect.X += padding.X;
rect.Y += padding.Y; rect.Y += padding.Y;
@ -52,5 +59,13 @@ namespace MLEM.Extensions {
return rect; 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;
}
} }
} }

View file

@ -1,5 +1,6 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Misc;
namespace MLEM.Extensions { namespace MLEM.Extensions {
public static class SpriteBatchExtensions { public static class SpriteBatchExtensions {
@ -30,5 +31,19 @@ namespace MLEM.Extensions {
color, 0, size / 2, scale + addedScale, SpriteEffects.None, 0); 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);
}
} }
} }

142
MLEM/Misc/RectangleF.cs Normal file
View file

@ -0,0 +1,142 @@
using System;
using Microsoft.Xna.Framework;
using MLEM.Extensions;
namespace MLEM.Misc {
public struct RectangleF : IEquatable<RectangleF> {
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;
}
}
}

View file

@ -3,6 +3,7 @@ using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Misc;
namespace MLEM.Textures { namespace MLEM.Textures {
public class NinePatch { public class NinePatch {
@ -35,6 +36,10 @@ namespace MLEM.Textures {
} }
public IEnumerable<Rectangle> CreateRectangles(Rectangle area, float patchScale = 1) { public IEnumerable<Rectangle> CreateRectangles(Rectangle area, float patchScale = 1) {
return this.CreateRectangles((RectangleF) area, patchScale).Select(r => (Rectangle) r);
}
public IEnumerable<RectangleF> CreateRectangles(RectangleF area, float patchScale = 1) {
var pl = (int) (this.PaddingLeft * patchScale); var pl = (int) (this.PaddingLeft * patchScale);
var pr = (int) (this.PaddingRight * patchScale); var pr = (int) (this.PaddingRight * patchScale);
var pt = (int) (this.PaddingTop * patchScale); var pt = (int) (this.PaddingTop * patchScale);
@ -47,22 +52,22 @@ namespace MLEM.Textures {
var topY = area.Y + pt; var topY = area.Y + pt;
var bottomY = area.Y + area.Height - pb; var bottomY = area.Y + area.Height - pb;
yield return new Rectangle(area.X, area.Y, pl, pt); yield return new RectangleF(area.X, area.Y, pl, pt);
yield return new Rectangle(leftX, area.Y, centerW, pt); yield return new RectangleF(leftX, area.Y, centerW, pt);
yield return new Rectangle(rightX, area.Y, pr, pt); yield return new RectangleF(rightX, area.Y, pr, pt);
yield return new Rectangle(area.X, topY, pl, centerH); yield return new RectangleF(area.X, topY, pl, centerH);
yield return new Rectangle(leftX, topY, centerW, centerH); yield return new RectangleF(leftX, topY, centerW, centerH);
yield return new Rectangle(rightX, topY, pr, centerH); yield return new RectangleF(rightX, topY, pr, centerH);
yield return new Rectangle(area.X, bottomY, pl, pb); yield return new RectangleF(area.X, bottomY, pl, pb);
yield return new Rectangle(leftX, bottomY, centerW, pb); yield return new RectangleF(leftX, bottomY, centerW, pb);
yield return new Rectangle(rightX, bottomY, pr, pb); yield return new RectangleF(rightX, bottomY, pr, pb);
} }
} }
public static class NinePatchExtensions { 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 dest = texture.CreateRectangles(destinationRectangle, patchScale);
var count = 0; var count = 0;
foreach (var rect in dest) { 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) { 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); batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0, patchScale);
} }

View file

@ -1,6 +1,8 @@
using System.Diagnostics.Tracing; using System.Diagnostics.Tracing;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Misc;
namespace MLEM.Textures { namespace MLEM.Textures {
public class TextureRegion { public class TextureRegion {
@ -44,6 +46,10 @@ namespace MLEM.Textures {
batch.Draw(texture.Texture, destinationRectangle, texture.Area, color, rotation, origin, effects, layerDepth); 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) { 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); 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); 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);
}
} }
} }

View file

@ -54,7 +54,7 @@ namespace Sandbox {
var show = screen.IsHidden; var show = screen.IsHidden;
screen.IsHidden = false; screen.IsHidden = false;
var time = 0; var time = 0;
const float total = 200; const float total = 20;
while (time <= total) { while (time <= total) {
yield return new WaitEvent(CoroutineEvents.Update); yield return new WaitEvent(CoroutineEvents.Update);
var percent = show ? time / total : 1 - time / total; var percent = show ? time / total : 1 - time / total;