diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index da969a5..3175623 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -79,6 +79,14 @@ 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 Element Parent { get; private set; } public bool IsMouseOver { get; private set; } public bool IsSelected { get; private set; } @@ -119,8 +127,8 @@ namespace MLEM.Ui.Elements { this.anchor = anchor; this.size = size; - this.OnMouseEnter += (element, mousePos) => this.IsMouseOver = true; - this.OnMouseExit += (element, mousePos) => this.IsMouseOver = false; + this.OnMouseEnter += element => this.IsMouseOver = true; + this.OnMouseExit += element => this.IsMouseOver = false; this.OnSelected += element => this.IsSelected = true; this.OnDeselected += element => this.IsSelected = false; @@ -132,6 +140,7 @@ namespace MLEM.Ui.Elements { index = this.children.Count; this.children.Insert(index, element); element.Parent = this; + element.PropagateRoot(this.Root); element.PropagateUiSystem(this.System); this.SetDirty(); return element; @@ -140,6 +149,7 @@ namespace MLEM.Ui.Elements { public void RemoveChild(Element element) { this.children.Remove(element); element.Parent = null; + element.PropagateRoot(null); element.PropagateUiSystem(null); this.SetDirty(); } @@ -179,7 +189,7 @@ namespace MLEM.Ui.Elements { parentArea.Width -= this.Parent.ChildPadding.X * 2; parentArea.Height -= this.Parent.ChildPadding.Y * 2; } else { - parentArea = this.System.ScaledViewport; + parentArea = this.ScaledViewport; } var parentCenterX = parentArea.X + parentArea.Width / 2; var parentCenterY = parentArea.Y + parentArea.Height / 2; @@ -297,20 +307,20 @@ namespace MLEM.Ui.Elements { } } - public virtual void DrawUnbound(GameTime time, SpriteBatch batch, float alpha, BlendState blendState = null, SamplerState samplerState = null) { + public virtual void DrawUnbound(GameTime time, SpriteBatch batch, float alpha, float scale, BlendState blendState = null, SamplerState samplerState = null) { foreach (var child in this.children) { if (!child.IsHidden) - child.DrawUnbound(time, batch, alpha * child.DrawAlpha, blendState, samplerState); + child.DrawUnbound(time, batch, alpha * child.DrawAlpha, scale, blendState, samplerState); } } - public Element GetMousedElement(Vector2 mousePos) { + public Element GetMousedElement() { if (this.IsHidden || this.IgnoresMouse) return null; - if (!this.Area.Contains(mousePos)) + if (!this.Area.Contains(this.MousePos)) return null; for (var i = this.children.Count - 1; i >= 0; i--) { - var element = this.children[i].GetMousedElement(mousePos); + var element = this.children[i].GetMousedElement(); if (element != null) return element; } @@ -320,9 +330,9 @@ namespace MLEM.Ui.Elements { protected virtual void InitStyle(UiStyle style) { } - public delegate void MouseClickCallback(Element element, Vector2 mousePos, MouseButton button); + public delegate void MouseClickCallback(Element element, MouseButton button); - public delegate void MouseCallback(Element element, Vector2 mousePos); + public delegate void MouseCallback(Element element); public delegate void TextInputCallback(Element element, Keys key, char character); @@ -334,6 +344,12 @@ namespace MLEM.Ui.Elements { child.PropagateUiSystem(system); } + internal void PropagateRoot(RootElement root) { + this.Root = root; + foreach (var child in this.children) + child.PropagateRoot(root); + } + internal void PropagateInput(Keys key, char character) { this.OnTextInput?.Invoke(this, key, character); foreach (var child in this.children) diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index ec5b371..aa83bff 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -16,7 +16,7 @@ namespace MLEM.Ui { public readonly InputHandler InputHandler; private readonly bool isInputOurs; - private float globalScale; + private float globalScale = 1; public float GlobalScale { get => this.globalScale; set { @@ -25,13 +25,6 @@ namespace MLEM.Ui { root.Element.ForceUpdateArea(); } } - public Rectangle ScaledViewport { - get { - var bounds = this.GraphicsDevice.Viewport.Bounds; - return new Rectangle(bounds.X, bounds.Y, (bounds.Width / this.globalScale).Floor(), (bounds.Height / this.globalScale).Floor()); - } - } - public Vector2 MousePos => this.InputHandler.MousePosition.ToVector2() / this.globalScale; public Element MousedElement { get; private set; } public Element SelectedElement { get; private set; } private UiStyle style; @@ -72,9 +65,9 @@ namespace MLEM.Ui { var mousedNow = this.GetMousedElement(); if (mousedNow != this.MousedElement) { if (this.MousedElement != null) - this.MousedElement.OnMouseExit?.Invoke(this.MousedElement, this.MousePos); + this.MousedElement.OnMouseExit?.Invoke(this.MousedElement); if (mousedNow != null) - mousedNow.OnMouseEnter?.Invoke(mousedNow, this.MousePos); + mousedNow.OnMouseEnter?.Invoke(mousedNow); this.MousedElement = mousedNow; } @@ -89,7 +82,7 @@ namespace MLEM.Ui { if (mousedNow?.OnClicked != null) { foreach (var button in InputHandler.MouseButtons) { if (this.InputHandler.IsMouseButtonPressed(button)) - mousedNow.OnClicked(mousedNow, this.MousePos, button); + mousedNow.OnClicked(mousedNow, button); } } @@ -98,25 +91,29 @@ namespace MLEM.Ui { } public void Draw(GameTime time, SpriteBatch batch) { - batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState, transformMatrix: Matrix.CreateScale(this.globalScale)); foreach (var root in this.rootElements) { - if (!root.Element.IsHidden) - root.Element.Draw(time, batch, this.DrawAlpha * root.Element.DrawAlpha); + if (root.Element.IsHidden) + continue; + batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState, transformMatrix: Matrix.CreateScale(root.ActualScale)); + root.Element.Draw(time, batch, this.DrawAlpha * root.Element.DrawAlpha); + batch.End(); } - batch.End(); foreach (var root in this.rootElements) { if (!root.Element.IsHidden) - root.Element.DrawUnbound(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState); + root.Element.DrawUnbound(time, batch, this.DrawAlpha * root.Element.DrawAlpha, root.ActualScale, this.BlendState, this.SamplerState); } } - public void Add(string name, Element root) { + public RootElement Add(string name, Element root) { if (this.IndexOf(name) >= 0) throw new ArgumentException($"There is already a root element with name {name}"); - this.rootElements.Add(new RootElement(name, root)); + var rootInst = new RootElement(name, root, this); + this.rootElements.Add(rootInst); + root.PropagateRoot(rootInst); root.PropagateUiSystem(this); + return rootInst; } public void Remove(string name) { @@ -126,9 +123,9 @@ namespace MLEM.Ui { this.rootElements.RemoveAt(index); } - public Element Get(string name) { + public RootElement Get(string name) { var index = this.IndexOf(name); - return index < 0 ? null : this.rootElements[index].Element; + return index < 0 ? null : this.rootElements[index]; } private int IndexOf(string name) { @@ -137,7 +134,7 @@ namespace MLEM.Ui { private Element GetMousedElement() { foreach (var root in this.rootElements) { - var moused = root.Element.GetMousedElement(this.MousePos); + var moused = root.Element.GetMousedElement(); if (moused != null) return moused; } @@ -146,14 +143,27 @@ namespace MLEM.Ui { } - public struct RootElement { + public class RootElement { public readonly string Name; public readonly Element Element; + public readonly UiSystem System; + private float scale = 1; + public float Scale { + get => this.scale; + set { + if (this.scale == value) + return; + this.scale = value; + this.Element.ForceUpdateArea(); + } + } + public float ActualScale => this.System.GlobalScale * this.Scale; - public RootElement(string name, Element element) { + public RootElement(string name, Element element, UiSystem system) { this.Name = name; this.Element = element; + this.System = system; } } diff --git a/Tests/GameImpl.cs b/Tests/GameImpl.cs index 72a29b4..2ce4366 100644 --- a/Tests/GameImpl.cs +++ b/Tests/GameImpl.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using Coroutine; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -28,7 +30,7 @@ namespace Tests { var style = new UiStyle { Font = new GenericSpriteFont(LoadContent("Fonts/TestFont")), - TextScale = 0.2F, + TextScale = 0.8F, 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), @@ -37,21 +39,21 @@ namespace Tests { }; var untexturedStyle = this.UiSystem.Style; this.UiSystem.Style = style; - this.UiSystem.GlobalScale = 5; + this.UiSystem.GlobalScale = 1.25F; - var root = new Panel(Anchor.BottomLeft, new Vector2(100, 120), new Point(5, 5)); + var root = new Panel(Anchor.Center, new Vector2(300, 450), Point.Zero); 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(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, pos, button) => { + var image = root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true}); + root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 40), "Test Button") { + OnClicked = (element, button) => { if (button == MouseButton.Left) image.IsHidden = !image.IsHidden; } }); - root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 15), "Change Style") { - OnClicked = (element, pos, button) => { + root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 40), "Change Style") { + OnClicked = (element, button) => { if (button == MouseButton.Left) this.UiSystem.Style = this.UiSystem.Style is UntexturedStyle ? style : untexturedStyle; }, @@ -59,7 +61,21 @@ namespace Tests { Texture = this.testPatch, HoveredColor = Color.LightGray }); - root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 15))); + root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 40))); + + root.AddChild(new VerticalSpace(3)); + root.AddChild(new Button(Anchor.AutoLeft, new Vector2(40), "+") { + OnClicked = (element, button) => { + if (element.Root.Scale < 2) + element.Root.Scale += 0.1F; + } + }); + root.AddChild(new Button(Anchor.AutoInline, new Vector2(40), "-") { + OnClicked = (element, button) => { + if (element.Root.Scale > 0.5F) + element.Root.Scale -= 0.1F; + } + }); } protected override void Draw(GameTime gameTime) {