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

better styling

This commit is contained in:
Ellpeck 2019-08-10 21:37:10 +02:00
parent 15081a8fe0
commit 0c8af5b9bf
13 changed files with 210 additions and 46 deletions

View file

@ -4,6 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using MLEM.Input; using MLEM.Input;
using MLEM.Ui; using MLEM.Ui;
using MLEM.Ui.Style;
using MonoGame.Extended; using MonoGame.Extended;
namespace MLEM.Startup { namespace MLEM.Startup {
@ -40,7 +41,7 @@ namespace MLEM.Startup {
protected override void LoadContent() { protected override void LoadContent() {
this.SpriteBatch = new SpriteBatch(this.GraphicsDevice); this.SpriteBatch = new SpriteBatch(this.GraphicsDevice);
this.InputHandler = new InputHandler(); this.InputHandler = new InputHandler();
this.UiSystem = new UiSystem(this.Window, this.GraphicsDevice, this.InputHandler); this.UiSystem = new UiSystem(this.Window, this.GraphicsDevice, new UntexturedStyle(this.SpriteBatch), this.InputHandler);
} }
protected override void Initialize() { protected override void Initialize() {

View file

@ -3,11 +3,12 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Font; using MLEM.Font;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public class AutoScaledText : Element { public class AutoScaledText : Element {
private readonly IGenericFont font; private IGenericFont font;
private float scale; private float scale;
private string text; private string text;
@ -22,7 +23,7 @@ namespace MLEM.Ui.Elements {
public AutoScaledText(Anchor anchor, Vector2 size, string text, IGenericFont font = null) : base(anchor, size) { public AutoScaledText(Anchor anchor, Vector2 size, string text, IGenericFont font = null) : base(anchor, size) {
this.Text = text; this.Text = text;
this.font = font ?? Paragraph.DefaultFont; this.font = font;
this.IgnoresMouse = true; this.IgnoresMouse = true;
} }
@ -43,5 +44,10 @@ namespace MLEM.Ui.Elements {
base.Draw(time, batch, alpha); base.Draw(time, batch, alpha);
} }
protected override void InitStyle(UiStyle style) {
base.InitStyle(style);
this.font = style.Font;
}
} }
} }

View file

@ -2,17 +2,14 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public class Button : Element { public class Button : Element {
public static NinePatch DefaultTexture; public NinePatch Texture;
public static NinePatch DefaultHoveredTexture; public NinePatch HoveredTexture;
public static Color DefaultHoveredColor = Color.LightGray; public Color HoveredColor;
public NinePatch Texture = DefaultTexture;
public NinePatch HoveredTexture = DefaultHoveredTexture;
public Color HoveredColor = DefaultHoveredColor;
public AutoScaledText Text; public AutoScaledText Text;
public Button(Anchor anchor, Vector2 size, string text = null) : base(anchor, size) { public Button(Anchor anchor, Vector2 size, string text = null) : base(anchor, size) {
@ -36,5 +33,12 @@ namespace MLEM.Ui.Elements {
base.Draw(time, batch, alpha); base.Draw(time, batch, alpha);
} }
protected override void InitStyle(UiStyle style) {
base.InitStyle(style);
this.Texture = style.ButtonTexture;
this.HoveredTexture = style.ButtonHoveredTexture;
this.HoveredColor = style.ButtonHoveredColor;
}
} }
} }

View file

@ -5,6 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Input; using MLEM.Input;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public abstract class Element { public abstract class Element {
@ -68,7 +69,15 @@ namespace MLEM.Ui.Elements {
public MouseCallback OnMouseExit; public MouseCallback OnMouseExit;
public TextInputCallback OnTextInput; public TextInputCallback OnTextInput;
public UiSystem System { get; private set; } private UiSystem system;
public UiSystem System {
get => this.system;
set {
this.system = value;
if (this.system != null && !this.HasCustomStyle)
this.InitStyle(this.system.Style);
}
}
protected InputHandler Input => this.System.InputHandler; protected InputHandler Input => this.System.InputHandler;
public Element Parent { get; private set; } public Element Parent { get; private set; }
public bool IsMouseOver { get; private set; } public bool IsMouseOver { get; private set; }
@ -85,6 +94,7 @@ namespace MLEM.Ui.Elements {
} }
public bool IgnoresMouse; public bool IgnoresMouse;
public float DrawAlpha = 1; public float DrawAlpha = 1;
public bool HasCustomStyle;
private Rectangle area; private Rectangle area;
public Rectangle Area { public Rectangle Area {
@ -122,7 +132,7 @@ namespace MLEM.Ui.Elements {
index = this.children.Count; index = this.children.Count;
this.children.Insert(index, element); this.children.Insert(index, element);
element.Parent = this; element.Parent = this;
element.System = this.System; element.PropagateUiSystem(this.System);
this.SetDirty(); this.SetDirty();
return element; return element;
} }
@ -130,7 +140,7 @@ namespace MLEM.Ui.Elements {
public void RemoveChild(Element element) { public void RemoveChild(Element element) {
this.children.Remove(element); this.children.Remove(element);
element.Parent = null; element.Parent = null;
element.System = null; element.PropagateUiSystem(this.System);
this.SetDirty(); this.SetDirty();
} }
@ -307,6 +317,9 @@ namespace MLEM.Ui.Elements {
return this; return this;
} }
protected virtual void InitStyle(UiStyle style) {
}
public delegate void MouseClickCallback(Element element, Vector2 mousePos, MouseButton button); public delegate void MouseClickCallback(Element element, Vector2 mousePos, MouseButton button);
public delegate void MouseCallback(Element element, Vector2 mousePos); public delegate void MouseCallback(Element element, Vector2 mousePos);
@ -315,10 +328,10 @@ namespace MLEM.Ui.Elements {
public delegate void GenericCallback(Element element); public delegate void GenericCallback(Element element);
internal void SetUiSystem(UiSystem system) { internal void PropagateUiSystem(UiSystem system) {
this.System = system; this.System = system;
foreach (var child in this.children) foreach (var child in this.children)
child.SetUiSystem(system); child.PropagateUiSystem(system);
} }
internal void PropagateInput(Keys key, char character) { internal void PropagateInput(Keys key, char character) {

View file

@ -1,24 +1,28 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public class Panel : Element { public class Panel : Element {
public static NinePatch DefaultTexture; public NinePatch Texture;
private readonly NinePatch texture;
public Panel(Anchor anchor, Vector2 size, Point positionOffset, NinePatch texture = null) : base(anchor, size) { public Panel(Anchor anchor, Vector2 size, Point positionOffset, NinePatch texture = null) : base(anchor, size) {
this.texture = texture ?? DefaultTexture; this.Texture = texture;
this.PositionOffset = positionOffset; this.PositionOffset = positionOffset;
this.ChildPadding = new Point(5); this.ChildPadding = new Point(5);
} }
public override void Draw(GameTime time, SpriteBatch batch, float alpha) { public override void Draw(GameTime time, SpriteBatch batch, float alpha) {
batch.Draw(this.texture, this.DisplayArea, Color.White * alpha); batch.Draw(this.Texture, this.DisplayArea, Color.White * alpha);
base.Draw(time, batch, alpha); base.Draw(time, batch, alpha);
} }
protected override void InitStyle(UiStyle style) {
base.InitStyle(style);
this.Texture = style.PanelTexture;
}
} }
} }

View file

@ -5,20 +5,18 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions; using MLEM.Extensions;
using MLEM.Font; using MLEM.Font;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public class Paragraph : Element { public class Paragraph : Element {
public static IGenericFont DefaultFont;
public static float DefaultTextScale = 1;
private string text; private string text;
private float lineHeight; private float lineHeight;
private string[] splitText; private string[] splitText;
private readonly IGenericFont font; private IGenericFont font;
private readonly bool centerText; private readonly bool centerText;
public float TextScale = DefaultTextScale; public float TextScale;
public string Text { public string Text {
get => this.text; get => this.text;
set { set {
@ -29,7 +27,7 @@ namespace MLEM.Ui.Elements {
public Paragraph(Anchor anchor, float width, string text, bool centerText = false, IGenericFont font = null) : base(anchor, new Vector2(width, 0)) { public Paragraph(Anchor anchor, float width, string text, bool centerText = false, IGenericFont font = null) : base(anchor, new Vector2(width, 0)) {
this.text = text; this.text = text;
this.font = font ?? DefaultFont; this.font = font;
this.centerText = centerText; this.centerText = centerText;
} }
@ -63,6 +61,12 @@ namespace MLEM.Ui.Elements {
} }
} }
protected override void InitStyle(UiStyle style) {
base.InitStyle(style);
this.TextScale = style.TextScale;
this.font = style.Font;
}
} }
} }

View file

@ -5,28 +5,24 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using MLEM.Font; using MLEM.Font;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui.Style;
namespace MLEM.Ui.Elements { namespace MLEM.Ui.Elements {
public class TextField : Element { public class TextField : Element {
public static NinePatch DefaultTexture; public NinePatch Texture;
public static NinePatch DefaultHoveredTexture; public NinePatch HoveredTexture;
public static Color DefaultHoveredColor = Color.LightGray; public Color HoveredColor;
public NinePatch Texture = DefaultTexture;
public NinePatch HoveredTexture = DefaultHoveredTexture;
public Color HoveredColor = DefaultHoveredColor;
public float TextScale; public float TextScale;
public readonly StringBuilder Text = new StringBuilder(); public readonly StringBuilder Text = new StringBuilder();
public TextChanged OnTextChange; public TextChanged OnTextChange;
public int MaxTextLength = int.MaxValue; public int MaxTextLength = int.MaxValue;
public float TextOffsetX = 4; public float TextOffsetX = 4;
private readonly IGenericFont font; private IGenericFont font;
private double caretBlinkTimer; private double caretBlinkTimer;
public TextField(Anchor anchor, Vector2 size, IGenericFont font = null) : base(anchor, size) { public TextField(Anchor anchor, Vector2 size, IGenericFont font = null) : base(anchor, size) {
this.font = font ?? Paragraph.DefaultFont; this.font = font;
this.TextScale = Paragraph.DefaultTextScale;
this.OnTextInput += (element, key, character) => { this.OnTextInput += (element, key, character) => {
if (!this.IsSelected) if (!this.IsSelected)
return; return;
@ -69,6 +65,15 @@ namespace MLEM.Ui.Elements {
base.Draw(time, batch, alpha); base.Draw(time, batch, alpha);
} }
protected override void InitStyle(UiStyle style) {
base.InitStyle(style);
this.TextScale = style.TextScale;
this.font = style.Font;
this.Texture = style.TextFieldTexture;
this.HoveredTexture = style.TextFieldHoveredTexture;
this.HoveredColor = style.TextFieldHoveredColor;
}
public delegate void TextChanged(TextField field, string text); public delegate void TextChanged(TextField field, string text);
} }

19
MLEM.Ui/Style/UiStyle.cs Normal file
View file

@ -0,0 +1,19 @@
using Microsoft.Xna.Framework;
using MLEM.Font;
using MLEM.Textures;
namespace MLEM.Ui.Style {
public class UiStyle {
public NinePatch ButtonTexture;
public NinePatch ButtonHoveredTexture;
public Color ButtonHoveredColor;
public NinePatch PanelTexture;
public NinePatch TextFieldTexture;
public NinePatch TextFieldHoveredTexture;
public Color TextFieldHoveredColor;
public IGenericFont Font;
public float TextScale = 1;
}
}

View file

@ -0,0 +1,74 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Font;
using MLEM.Textures;
namespace MLEM.Ui.Style {
public class UntexturedStyle : UiStyle {
public UntexturedStyle(SpriteBatch batch) {
this.ButtonTexture = GenerateTexture(batch, Color.CadetBlue);
this.ButtonHoveredColor = Color.LightGray;
this.PanelTexture = GenerateTexture(batch, Color.Gray);
this.TextFieldTexture = GenerateTexture(batch, Color.MediumBlue);
this.TextFieldHoveredColor = Color.LightGray;
this.Font = new EmptyFont();
}
private static NinePatch GenerateTexture(SpriteBatch batch, Color color) {
var tex = new Texture2D(batch.GraphicsDevice, 3, 3);
tex.SetData(new[] {
Color.Black, Color.Black, Color.Black,
Color.Black, color, Color.Black,
Color.Black, Color.Black, Color.Black
});
batch.Disposing += (sender, args) => {
if (tex != null) {
tex.Dispose();
tex = null;
}
};
return new NinePatch(tex, 1);
}
private class EmptyFont : IGenericFont {
public Vector2 MeasureString(string text) {
return Vector2.One;
}
public Vector2 MeasureString(StringBuilder text) {
return Vector2.One;
}
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color) {
}
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth) {
}
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
}
public void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color) {
}
public void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth) {
}
public void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
}
public void DrawCenteredString(SpriteBatch batch, string text, Vector2 position, float scale, Color color, bool horizontal = true, bool vertical = false, float addedScale = 0) {
}
public IEnumerable<string> SplitString(string text, float width, float scale) {
yield break;
}
}
}
}

View file

@ -6,6 +6,7 @@ using MLEM.Extensions;
using MLEM.Font; using MLEM.Font;
using MLEM.Input; using MLEM.Input;
using MLEM.Ui.Elements; using MLEM.Ui.Elements;
using MLEM.Ui.Style;
namespace MLEM.Ui { namespace MLEM.Ui {
public class UiSystem { public class UiSystem {
@ -33,14 +34,26 @@ namespace MLEM.Ui {
public Vector2 MousePos => this.InputHandler.MousePosition.ToVector2() / this.globalScale; public Vector2 MousePos => this.InputHandler.MousePosition.ToVector2() / this.globalScale;
public Element MousedElement { get; private set; } public Element MousedElement { get; private set; }
public Element SelectedElement { get; private set; } public Element SelectedElement { get; private set; }
private UiStyle style;
public UiStyle Style {
get => this.style;
set {
this.style = value;
foreach (var root in this.rootElements) {
root.Element.PropagateUiSystem(this);
root.Element.SetDirty();
}
}
}
public float DrawAlpha = 1; public float DrawAlpha = 1;
public BlendState BlendState; public BlendState BlendState;
public SamplerState SamplerState = SamplerState.PointClamp; public SamplerState SamplerState = SamplerState.PointClamp;
public UiSystem(GameWindow window, GraphicsDevice device, InputHandler inputHandler = null) { public UiSystem(GameWindow window, GraphicsDevice device, UiStyle style, InputHandler inputHandler = null) {
this.GraphicsDevice = device; this.GraphicsDevice = device;
this.InputHandler = inputHandler ?? new InputHandler(); this.InputHandler = inputHandler ?? new InputHandler();
this.isInputOurs = inputHandler == null; this.isInputOurs = inputHandler == null;
this.style = style;
window.ClientSizeChanged += (sender, args) => { window.ClientSizeChanged += (sender, args) => {
foreach (var root in this.rootElements) foreach (var root in this.rootElements)
@ -103,7 +116,7 @@ namespace MLEM.Ui {
throw new ArgumentException($"There is already a root element with name {name}"); throw new ArgumentException($"There is already a root element with name {name}");
this.rootElements.Add(new RootElement(name, root)); this.rootElements.Add(new RootElement(name, root));
root.SetUiSystem(this); root.PropagateUiSystem(this);
} }
public void Remove(string name) { public void Remove(string name) {

View file

@ -8,7 +8,7 @@ namespace MLEM.Extensions {
public static Texture2D GetBlankTexture(this SpriteBatch batch) { public static Texture2D GetBlankTexture(this SpriteBatch batch) {
if (blankTexture == null) { if (blankTexture == null) {
blankTexture = new Texture2D(batch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color); blankTexture = new Texture2D(batch.GraphicsDevice, 1, 1);
blankTexture.SetData(new[] {Color.White}); blankTexture.SetData(new[] {Color.White});
batch.Disposing += (sender, args) => { batch.Disposing += (sender, args) => {
if (blankTexture != null) { if (blankTexture != null) {

View file

@ -27,6 +27,9 @@ namespace MLEM.Textures {
this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom) { this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom) {
} }
public NinePatch(Texture2D texture, int padding) : this(new TextureRegion(texture), padding) {
}
public NinePatch(TextureRegion texture, int padding) : this(texture, padding, padding, padding, padding) { public NinePatch(TextureRegion texture, int padding) : this(texture, padding, padding, padding, padding) {
} }

View file

@ -9,6 +9,7 @@ using MLEM.Startup;
using MLEM.Textures; using MLEM.Textures;
using MLEM.Ui; using MLEM.Ui;
using MLEM.Ui.Elements; using MLEM.Ui.Elements;
using MLEM.Ui.Style;
namespace Tests { namespace Tests {
public class GameImpl : MlemGame { public class GameImpl : MlemGame {
@ -21,17 +22,26 @@ namespace Tests {
} }
protected override void LoadContent() { protected override void LoadContent() {
base.LoadContent();
this.testTexture = LoadContent<Texture2D>("Textures/Test"); this.testTexture = LoadContent<Texture2D>("Textures/Test");
this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8); this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8);
base.LoadContent();
Paragraph.DefaultFont = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont")); var style = new UiStyle {
Paragraph.DefaultTextScale = 0.2F; Font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont")),
Button.DefaultTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4); TextScale = 0.2F,
TextField.DefaultTexture = Button.DefaultTexture; 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),
ButtonHoveredColor = Color.LightGray,
TextFieldHoveredColor = Color.LightGray
};
var untexturedStyle = this.UiSystem.Style;
this.UiSystem.Style = style;
this.UiSystem.GlobalScale = 5; this.UiSystem.GlobalScale = 5;
var root = new Panel(Anchor.BottomLeft, new Vector2(100, 100), new Point(5, 5), this.testPatch); var root = new Panel(Anchor.BottomLeft, new Vector2(100, 120), new Point(5, 5));
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.")); 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}); 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") { root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 15), "Test Button") {
@ -40,8 +50,16 @@ namespace Tests {
image.IsHidden = !image.IsHidden; image.IsHidden = !image.IsHidden;
} }
}); });
root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 15), "Change Style") {
OnClicked = (element, pos, button) => {
if (button == MouseButton.Left)
this.UiSystem.Style = this.UiSystem.Style is UntexturedStyle ? style : untexturedStyle;
},
HasCustomStyle = true,
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, 15)));
this.UiSystem.Add("Test", root);
} }
protected override void Draw(GameTime gameTime) { protected override void Draw(GameTime gameTime) {