From cb5594badac259f9683c2dbad469d6fe488714df Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sat, 24 Aug 2019 12:40:20 +0200 Subject: [PATCH] added ElementHelper and did some textfield changes --- Demos/UiDemo.cs | 8 ++- MLEM.Ui/Elements/Element.cs | 3 ++ MLEM.Ui/Elements/ElementHelper.cs | 42 ++++++++++++++++ MLEM.Ui/Elements/TextField.cs | 81 +++++++++++++++++++------------ 4 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 MLEM.Ui/Elements/ElementHelper.cs diff --git a/Demos/UiDemo.cs b/Demos/UiDemo.cs index 53ad0e1..fbfa64f 100644 --- a/Demos/UiDemo.cs +++ b/Demos/UiDemo.cs @@ -79,7 +79,7 @@ namespace Demos { image.IsHidden = !image.IsHidden; } }); - + root.AddChild(new VerticalSpace(3)); root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Note that the default style does not contain any textures or font files and, as such, is quite bland. However, the default style is quite easy to override.")); root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), "Change Style") { @@ -97,7 +97,7 @@ namespace Demos { root.AddChild(new VerticalSpace(3)); // a paragraph with formatting codes. To see them all or to add more, check the TextFormatting class - root.AddChild(new Paragraph(Anchor.AutoLeft, 1,"Paragraphs can also contain [Blue]formatting codes[White], including colors and [Italic]text styles[Regular]. The names of all [Orange]MonoGame Colors[White] can be used, as well as the codes [Italic]Italic[Regular] and [Bold]Bold[Regular]. \n[Italic]Even [CornflowerBlue]Cornflower Blue[White] works!")); + root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain [Blue]formatting codes[White], including colors and [Italic]text styles[Regular]. The names of all [Orange]MonoGame Colors[White] can be used, as well as the codes [Italic]Italic[Regular] and [Bold]Bold[Regular]. \n[Italic]Even [CornflowerBlue]Cornflower Blue[White] works!")); root.AddChild(new VerticalSpace(3)); root.AddChild(new Paragraph(Anchor.AutoCenter, 1, "Text input:", true)); @@ -155,6 +155,10 @@ namespace Demos { PositionOffset = new Vector2(0, 1) }); + root.AddChild(new VerticalSpace(3)); + root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "There are also some additional \"components\" which are created as combinations of other components. You can find all of them in the ElementHelper class. Here are some examples:")); + root.AddChild(ElementHelper.NumberField(Anchor.AutoLeft, new Vector2(1, 10))).PositionOffset = new Vector2(0, 1); + // Below are some querying examples that help you find certain elements easily var children = root.GetChildren(); diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 61a810c..007e0de 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -85,6 +85,7 @@ namespace MLEM.Ui.Elements { public MouseCallback OnMouseEnter; public MouseCallback OnMouseExit; public TextInputCallback OnTextInput; + public GenericCallback OnAreaUpdated; private UiSystem system; public UiSystem System { @@ -289,6 +290,8 @@ namespace MLEM.Ui.Elements { } this.area = new Rectangle(pos, actualSize); + this.OnAreaUpdated?.Invoke(this); + foreach (var child in this.Children) child.ForceUpdateArea(); diff --git a/MLEM.Ui/Elements/ElementHelper.cs b/MLEM.Ui/Elements/ElementHelper.cs new file mode 100644 index 0000000..20cbf42 --- /dev/null +++ b/MLEM.Ui/Elements/ElementHelper.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using MLEM.Input; + +namespace MLEM.Ui.Elements { + public static class ElementHelper { + + public static Group NumberField(Anchor anchor, Vector2 size, int defaultValue = 0, int stepPerClick = 1, TextField.Rule rule = null, TextField.TextChanged onTextChange = null) { + var group = new Group(anchor, size, false); + + var field = new TextField(Anchor.TopLeft, Vector2.One, rule ?? TextField.OnlyNumbers); + field.OnTextChange = onTextChange; + field.AppendText(defaultValue.ToString()); + group.AddChild(field); + group.OnAreaUpdated += e => field.Size = new Vector2((e.Area.Width - e.Area.Height / 2) / e.Scale, 1); + + var upButton = new Button(Anchor.TopRight, Vector2.One, "+") { + OnClicked = (element, button) => { + if (button == MouseButton.Left) { + var text = field.Text.ToString(); + field.SetText(int.Parse(text) + stepPerClick); + } + } + }; + group.AddChild(upButton); + group.OnAreaUpdated += e => upButton.Size = new Vector2(e.Area.Height / 2 / e.Scale); + + var downButton = new Button(Anchor.BottomRight, Vector2.One, "-") { + OnClicked = (element, button) => { + if (button == MouseButton.Left) { + var text = field.Text.ToString(); + field.SetText(int.Parse(text) - stepPerClick); + } + } + }; + group.AddChild(downButton); + group.OnAreaUpdated += e => downButton.Size = new Vector2(e.Area.Height / 2 / e.Scale); + + return group; + } + + } +} \ No newline at end of file diff --git a/MLEM.Ui/Elements/TextField.cs b/MLEM.Ui/Elements/TextField.cs index 62e6b7f..9f9bda2 100644 --- a/MLEM.Ui/Elements/TextField.cs +++ b/MLEM.Ui/Elements/TextField.cs @@ -21,10 +21,10 @@ namespace MLEM.Ui.Elements { public NinePatch HoveredTexture; public Color HoveredColor; public float TextScale; - public readonly StringBuilder Text = new StringBuilder(); + private readonly StringBuilder text = new StringBuilder(); + public string Text => this.text.ToString(); public string PlaceholderText; public TextChanged OnTextChange; - public int MaxTextLength = int.MaxValue; public float TextOffsetX = 4; private IGenericFont font; private double caretBlinkTimer; @@ -37,38 +37,37 @@ namespace MLEM.Ui.Elements { this.OnTextInput += (element, key, character) => { if (!this.IsSelected) return; - var textChanged = false; if (key == Keys.Back) { - if (this.Text.Length > 0) { - this.Text.Remove(this.Text.Length - 1, 1); - textChanged = true; + if (this.text.Length > 0) { + this.RemoveText(this.text.Length - 1, 1); } - } else if (this.InputRule(this, character.ToString())) { - if (this.Text.Length < this.MaxTextLength) { - this.Text.Append(character); - textChanged = true; - } - } - if (textChanged) { - var length = this.font.MeasureString(this.Text).X * this.TextScale; - var maxWidth = this.DisplayArea.Width / this.Scale - this.TextOffsetX * 2; - if (length > maxWidth) { - for (var i = 0; i < this.Text.Length; i++) { - var substring = this.Text.ToString(i, this.Text.Length - i); - if (this.font.MeasureString(substring).X * this.TextScale <= maxWidth) { - this.textStartIndex = i; - break; - } - } - } else { - this.textStartIndex = 0; - } - - this.OnTextChange?.Invoke(this, this.Text.ToString()); + } else { + this.AppendText(character); } }; } + private void HandleTextChange() { + // not initialized yet + if (this.font == null) + return; + var length = this.font.MeasureString(this.text).X * this.TextScale; + var maxWidth = this.DisplayArea.Width / this.Scale - this.TextOffsetX * 2; + if (length > maxWidth) { + for (var i = 0; i < this.text.Length; i++) { + var substring = this.text.ToString(i, this.text.Length - i); + if (this.font.MeasureString(substring).X * this.TextScale <= maxWidth) { + this.textStartIndex = i; + break; + } + } + } else { + this.textStartIndex = 0; + } + + this.OnTextChange?.Invoke(this, this.text.ToString()); + } + public override void Update(GameTime time) { base.Update(time); @@ -88,16 +87,36 @@ namespace MLEM.Ui.Elements { batch.Draw(tex, this.DisplayArea.OffsetCopy(offset), color, this.Scale); var textPos = this.DisplayArea.Location.ToVector2() + new Vector2(offset.X + this.TextOffsetX * this.Scale, offset.Y + this.DisplayArea.Height / 2); - if (this.Text.Length > 0 || this.IsSelected) { + if (this.text.Length > 0 || this.IsSelected) { 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, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true); + var display = this.text.ToString(this.textStartIndex, this.text.Length - this.textStartIndex) + caret; + this.font.DrawCenteredString(batch, display, textPos, this.TextScale * this.Scale, Color.White * alpha, false, true); } else if (this.PlaceholderText != null) { this.font.DrawCenteredString(batch, this.PlaceholderText, textPos, this.TextScale * this.Scale, Color.Gray * alpha, false, true); } base.Draw(time, batch, alpha, offset); } + public void SetText(object text) { + if (!this.InputRule(this, text.ToString())) + return; + this.text.Clear(); + this.text.Append(text); + this.HandleTextChange(); + } + + public void AppendText(object text) { + if (!this.InputRule(this, text.ToString())) + return; + this.text.Append(text); + this.HandleTextChange(); + } + + public void RemoveText(int index, int length) { + this.text.Remove(index, length); + this.HandleTextChange(); + } + protected override void InitStyle(UiStyle style) { base.InitStyle(style); this.TextScale = style.TextScale;