diff --git a/MLEM.Ui/Elements/AutoScaledText.cs b/MLEM.Ui/Elements/AutoScaledText.cs index f13dcef..dcf00da 100644 --- a/MLEM.Ui/Elements/AutoScaledText.cs +++ b/MLEM.Ui/Elements/AutoScaledText.cs @@ -9,7 +9,7 @@ namespace MLEM.Ui.Elements { public class AutoScaledText : Element { private IGenericFont font; - private float scale; + private float textScale; private string text; public string Text { @@ -30,17 +30,17 @@ namespace MLEM.Ui.Elements { public override void ForceUpdateArea() { base.ForceUpdateArea(); - this.scale = 0; + this.textScale = 0; Vector2 measure; do { - this.scale += 0.1F; - measure = this.font.MeasureString(this.Text) * this.scale; - } while (measure.X <= this.DisplayArea.Size.X && measure.Y <= this.DisplayArea.Size.Y); + this.textScale += 0.1F; + measure = this.font.MeasureString(this.Text) * this.textScale; + } while (measure.X <= this.DisplayArea.Size.X / this.Scale && measure.Y <= this.DisplayArea.Size.Y / this.Scale); } public override void Draw(GameTime time, SpriteBatch batch, float alpha) { var pos = this.DisplayArea.Location.ToVector2() + this.DisplayArea.Size.ToVector2() / 2; - this.font.DrawCenteredString(batch, this.Text, pos, this.scale, this.Color * alpha, true, true); + this.font.DrawCenteredString(batch, this.Text, pos, this.textScale * this.Scale, this.Color * alpha, true, true); base.Draw(time, batch, alpha); } diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index aa85299..b1119df 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -15,6 +15,7 @@ namespace MLEM.Ui.Elements { private Vector2 size; private Point offset; public Point Padding; + public Point ScaledPadding => this.Padding.Multiply(this.Scale); private Point childPadding; public Anchor Anchor { get => this.anchor; @@ -34,6 +35,7 @@ namespace MLEM.Ui.Elements { this.SetDirty(); } } + public Vector2 ScaledSize => this.size * this.Scale; public Point PositionOffset { get => this.offset; set { @@ -43,6 +45,7 @@ namespace MLEM.Ui.Elements { this.SetDirty(); } } + public Point ScaledOffset => this.offset.Multiply(this.Scale); public Point ChildPadding { get => this.childPadding; set { @@ -52,6 +55,7 @@ namespace MLEM.Ui.Elements { this.SetDirty(); } } + public Point ScaledChildPadding => this.childPadding.Multiply(this.Scale); public MouseClickCallback OnClicked; public GenericCallback OnSelected; @@ -71,13 +75,8 @@ namespace MLEM.Ui.Elements { } protected InputHandler Input => this.System.InputHandler; public RootElement Root { get; private set; } - public Rectangle ScaledViewport { - get { - var bounds = this.System.GraphicsDevice.Viewport; - return new Rectangle(bounds.X, bounds.Y, (bounds.Width / this.Root.ActualScale).Ceil(), (bounds.Height / this.Root.ActualScale).Ceil()); - } - } - public Vector2 MousePos => this.Input.MousePosition.ToVector2() / this.Root.ActualScale; + public float Scale => this.Root.ActualScale; + public Vector2 MousePos => this.Input.MousePosition.ToVector2(); public Element Parent { get; private set; } public bool IsMouseOver { get; private set; } public bool IsSelected { get; private set; } @@ -106,12 +105,11 @@ namespace MLEM.Ui.Elements { public Rectangle DisplayArea { get { var padded = this.Area; - padded.Location += this.Padding; - padded.Width -= this.Padding.X * 2; - padded.Height -= this.Padding.Y * 2; + padded.Location += this.ScaledPadding; + padded.Width -= this.ScaledPadding.X * 2; + padded.Height -= this.ScaledPadding.Y * 2; return padded; } - } private bool areaDirty; @@ -177,11 +175,11 @@ namespace MLEM.Ui.Elements { Rectangle parentArea; if (this.Parent != null) { parentArea = this.Parent.area; - parentArea.Location += this.Parent.ChildPadding; - parentArea.Width -= this.Parent.ChildPadding.X * 2; - parentArea.Height -= this.Parent.ChildPadding.Y * 2; + parentArea.Location += this.Parent.ScaledChildPadding; + parentArea.Width -= this.Parent.ScaledChildPadding.X * 2; + parentArea.Height -= this.Parent.ScaledChildPadding.Y * 2; } else { - parentArea = this.ScaledViewport; + parentArea = this.system.GraphicsDevice.Viewport.Bounds; } var parentCenterX = parentArea.X + parentArea.Width / 2; var parentCenterY = parentArea.Y + parentArea.Height / 2; @@ -194,42 +192,42 @@ namespace MLEM.Ui.Elements { case Anchor.AutoLeft: case Anchor.AutoInline: case Anchor.AutoInlineIgnoreOverflow: - pos.X = parentArea.X + this.offset.X; - pos.Y = parentArea.Y + this.offset.Y; + pos.X = parentArea.X + this.ScaledOffset.X; + pos.Y = parentArea.Y + this.ScaledOffset.Y; break; case Anchor.TopCenter: case Anchor.AutoCenter: - pos.X = parentCenterX - actualSize.X / 2 + this.offset.X; - pos.Y = parentArea.Y + this.offset.Y; + pos.X = parentCenterX - actualSize.X / 2 + this.ScaledOffset.X; + pos.Y = parentArea.Y + this.ScaledOffset.Y; break; case Anchor.TopRight: case Anchor.AutoRight: - pos.X = parentArea.Right - actualSize.X - this.offset.X; - pos.Y = parentArea.Y + this.offset.Y; + pos.X = parentArea.Right - actualSize.X - this.ScaledOffset.X; + pos.Y = parentArea.Y + this.ScaledOffset.Y; break; case Anchor.CenterLeft: - pos.X = parentArea.X + this.offset.X; - pos.Y = parentCenterY - actualSize.Y / 2 + this.offset.Y; + pos.X = parentArea.X + this.ScaledOffset.X; + pos.Y = parentCenterY - actualSize.Y / 2 + this.ScaledOffset.Y; break; case Anchor.Center: - pos.X = parentCenterX - actualSize.X / 2 + this.offset.X; - pos.Y = parentCenterY - actualSize.Y / 2 + this.offset.Y; + pos.X = parentCenterX - actualSize.X / 2 + this.ScaledOffset.X; + pos.Y = parentCenterY - actualSize.Y / 2 + this.ScaledOffset.Y; break; case Anchor.CenterRight: - pos.X = parentArea.Right - actualSize.X - this.offset.X; - pos.Y = parentCenterY - actualSize.Y / 2 + this.offset.Y; + pos.X = parentArea.Right - actualSize.X - this.ScaledOffset.X; + pos.Y = parentCenterY - actualSize.Y / 2 + this.ScaledOffset.Y; break; case Anchor.BottomLeft: - pos.X = parentArea.X + this.offset.X; - pos.Y = parentArea.Bottom - actualSize.Y - this.offset.Y; + pos.X = parentArea.X + this.ScaledOffset.X; + pos.Y = parentArea.Bottom - actualSize.Y - this.ScaledOffset.Y; break; case Anchor.BottomCenter: - pos.X = parentCenterX - actualSize.X / 2 + this.offset.X; - pos.Y = parentArea.Bottom - actualSize.Y - this.offset.Y; + pos.X = parentCenterX - actualSize.X / 2 + this.ScaledOffset.X; + pos.Y = parentArea.Bottom - actualSize.Y - this.ScaledOffset.Y; break; case Anchor.BottomRight: - pos.X = parentArea.Right - actualSize.X - this.offset.X; - pos.Y = parentArea.Bottom - actualSize.Y - this.offset.Y; + pos.X = parentArea.Right - actualSize.X - this.ScaledOffset.X; + pos.Y = parentArea.Bottom - actualSize.Y - this.ScaledOffset.Y; break; } @@ -241,19 +239,19 @@ namespace MLEM.Ui.Elements { case Anchor.AutoLeft: case Anchor.AutoCenter: case Anchor.AutoRight: - pos.Y = prevArea.Bottom + this.PositionOffset.Y; + pos.Y = prevArea.Bottom + this.ScaledOffset.Y; break; case Anchor.AutoInline: - var newX = prevArea.Right + this.PositionOffset.X; + var newX = prevArea.Right + this.ScaledOffset.X; if (newX + actualSize.X <= parentArea.Right) { pos.X = newX; pos.Y = prevArea.Y; } else { - pos.Y = prevArea.Bottom + this.PositionOffset.Y; + pos.Y = prevArea.Bottom + this.ScaledOffset.Y; } break; case Anchor.AutoInlineIgnoreOverflow: - pos.X = prevArea.Right + this.PositionOffset.X; + pos.X = prevArea.Right + this.ScaledOffset.X; pos.Y = prevArea.Y; break; } @@ -271,7 +269,7 @@ namespace MLEM.Ui.Elements { height = child.area.Bottom; } - var newHeight = height - pos.Y + this.ChildPadding.Y; + var newHeight = (height - pos.Y + this.ScaledChildPadding.Y) / this.Scale; if (newHeight != this.size.Y) { this.size.Y = newHeight; this.ForceUpdateArea(); @@ -281,8 +279,8 @@ namespace MLEM.Ui.Elements { protected virtual Point CalcActualSize(Rectangle parentArea) { return new Point( - (this.size.X > 1 ? this.size.X : parentArea.Width * this.size.X).Floor(), - (this.size.Y > 1 ? this.size.Y : parentArea.Height * this.size.Y).Floor()); + (this.size.X > 1 ? this.ScaledSize.X : parentArea.Width * this.size.X).Floor(), + (this.size.Y > 1 ? this.ScaledSize.Y : parentArea.Height * this.size.Y).Floor()); } protected Element GetPreviousChild(bool hiddenAlso) { diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs index 721e9a5..69b3657 100644 --- a/MLEM.Ui/Elements/Paragraph.cs +++ b/MLEM.Ui/Elements/Paragraph.cs @@ -33,12 +33,12 @@ namespace MLEM.Ui.Elements { protected override Point CalcActualSize(Rectangle parentArea) { var size = base.CalcActualSize(parentArea); - this.splitText = this.font.SplitString(this.text, size.X, this.TextScale).ToArray(); + this.splitText = this.font.SplitString(this.text, size.X, this.TextScale * this.Scale).ToArray(); this.lineHeight = 0; var height = 0F; foreach (var strg in this.splitText) { - var strgHeight = this.font.MeasureString(strg).Y * this.TextScale; + var strgHeight = this.font.MeasureString(strg).Y * this.TextScale * this.Scale; height += strgHeight + 1; if (strgHeight > this.lineHeight) this.lineHeight = strgHeight; @@ -53,9 +53,9 @@ namespace MLEM.Ui.Elements { var offset = new Vector2(); foreach (var line in this.splitText) { if (this.centerText) { - this.font.DrawCenteredString(batch, line, pos + offset + new Vector2(this.DisplayArea.Width / 2, 0), this.TextScale, Color.White * alpha); + this.font.DrawCenteredString(batch, line, pos + offset + new Vector2(this.DisplayArea.Width / 2, 0), this.TextScale * this.Scale, Color.White * alpha); } else { - this.font.DrawString(batch, line, pos + offset, Color.White * alpha, 0, Vector2.Zero, this.TextScale, SpriteEffects.None, 0); + this.font.DrawString(batch, line, pos + offset, Color.White * alpha, 0, Vector2.Zero, this.TextScale * this.Scale, SpriteEffects.None, 0); } offset.Y += this.lineHeight + 1; } diff --git a/MLEM.Ui/Elements/TextField.cs b/MLEM.Ui/Elements/TextField.cs index 449283e..eee4f06 100644 --- a/MLEM.Ui/Elements/TextField.cs +++ b/MLEM.Ui/Elements/TextField.cs @@ -78,7 +78,7 @@ namespace MLEM.Ui.Elements { batch.Draw(tex, this.DisplayArea, color); var caret = this.IsSelected && this.caretBlinkTimer >= 0.5F ? "|" : ""; var text = this.Text.ToString(this.textStartIndex, this.Text.Length - this.textStartIndex) + caret; - this.font.DrawCenteredString(batch, text, this.DisplayArea.Location.ToVector2() + new Vector2(this.TextOffsetX, this.DisplayArea.Height / 2), this.TextScale, Color.White * alpha, false, true); + this.font.DrawCenteredString(batch, text, this.DisplayArea.Location.ToVector2() + new Vector2(this.TextOffsetX, this.DisplayArea.Height / 2), this.TextScale * this.Scale, Color.White * alpha, false, true); base.Draw(time, batch, alpha); } diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index aa83bff..184c315 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -94,7 +94,7 @@ namespace MLEM.Ui { foreach (var root in this.rootElements) { if (root.Element.IsHidden) continue; - batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState, transformMatrix: Matrix.CreateScale(root.ActualScale)); + batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState); root.Element.Draw(time, batch, this.DrawAlpha * root.Element.DrawAlpha); batch.End(); } diff --git a/MLEM/Extensions/NumberExtensions.cs b/MLEM/Extensions/NumberExtensions.cs index 05b92d0..73a842f 100644 --- a/MLEM/Extensions/NumberExtensions.cs +++ b/MLEM/Extensions/NumberExtensions.cs @@ -24,5 +24,9 @@ namespace MLEM.Extensions { return new Vector4(vec.X.Floor(), vec.Y.Floor(), vec.Z.Floor(), vec.W.Floor()); } + public static Point Multiply(this Point point, float f) { + return new Point((point.X * f).Floor(), (point.Y * f).Floor()); + } + } } \ No newline at end of file diff --git a/Tests/GameImpl.cs b/Tests/GameImpl.cs index 1b61243..0470fae 100644 --- a/Tests/GameImpl.cs +++ b/Tests/GameImpl.cs @@ -30,7 +30,7 @@ namespace Tests { var style = new UiStyle { Font = new GenericSpriteFont(LoadContent("Fonts/TestFont")), - TextScale = 0.8F, + TextScale = 0.2F, PanelTexture = this.testPatch, ButtonTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4), TextFieldTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4), @@ -39,20 +39,20 @@ namespace Tests { }; var untexturedStyle = this.UiSystem.Style; this.UiSystem.Style = style; - this.UiSystem.GlobalScale = 1.25F; + this.UiSystem.GlobalScale = 5; - var root = new Panel(Anchor.BottomLeft, new Vector2(300, 450), Point.Zero, true); + var root = new Panel(Anchor.BottomLeft, new Vector2(100, 120), Point.Zero, true); this.UiSystem.Add("Test", root); root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a test text that is hopefully long enough to cover at least a few lines, otherwise it would be very sad.")); - var image = root.AddChild(new Image(Anchor.AutoCenter, new Vector2(70, 70), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Point(10)}); - root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 40), "Test Button") { + var image = root.AddChild(new Image(Anchor.AutoCenter, new Vector2(20, 20), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true}); + root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 15), "Test Button") { OnClicked = (element, button) => { if (button == MouseButton.Left) image.IsHidden = !image.IsHidden; } }); - root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 40), "Change Style") { + root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 15), "Change Style") { OnClicked = (element, button) => { if (button == MouseButton.Left) this.UiSystem.Style = this.UiSystem.Style is UntexturedStyle ? style : untexturedStyle; @@ -61,21 +61,34 @@ namespace Tests { Texture = this.testPatch, HoveredColor = Color.LightGray }); - root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 40))); + root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 15))); root.AddChild(new VerticalSpace(3)); - root.AddChild(new Button(Anchor.AutoLeft, new Vector2(40), "+") { + root.AddChild(new Button(Anchor.AutoLeft, new Vector2(15), "+") { OnClicked = (element, button) => { if (element.Root.Scale < 2) element.Root.Scale += 0.1F; } }); - root.AddChild(new Button(Anchor.AutoInline, new Vector2(40), "-") { + root.AddChild(new Button(Anchor.AutoInline, new Vector2(15), "-") { OnClicked = (element, button) => { if (element.Root.Scale > 0.5F) element.Root.Scale -= 0.1F; } }); + root.AddChild(new Button(Anchor.AutoInline, new Vector2(30, 15), "Woop") { + OnClicked = (element, button) => CoroutineHandler.Start(Woop(element)) + }); + } + + private static IEnumerator Woop(Element element) { + var angle = 0; + var startScale = element.Root.Scale; + while (angle < 180) { + element.Root.Scale = startScale + (float) Math.Sin(MathHelper.ToRadians(angle)); + angle++; + yield return new WaitSeconds(0.01F); + } } protected override void Draw(GameTime gameTime) {