mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-22 20:58:34 +01:00
simplify text rendering quite a bit after realizing that monogame deals with multiple lines on its own
This commit is contained in:
parent
6766d769f4
commit
226640ef3a
8 changed files with 64 additions and 84 deletions
|
@ -69,7 +69,7 @@ namespace Demos {
|
||||||
var root = new Panel(Anchor.Center, new Vector2(80, 100), Vector2.Zero, false, true, new Point(5, 10));
|
var root = new Panel(Anchor.Center, new Vector2(80, 100), Vector2.Zero, false, true, new Point(5, 10));
|
||||||
this.UiSystem.Add("Test", root);
|
this.UiSystem.Add("Test", root);
|
||||||
|
|
||||||
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a small demo for MLEM.Ui, a user interface library that is part of (M)LEM (L)ibrary by (E)llpeck for (M)onoGame.") {LineSpace = 1.5F});
|
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a small demo for MLEM.Ui, a user interface library that is part of (M)LEM (L)ibrary by (E)llpeck for (M)onoGame."));
|
||||||
var image = root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Point(3)});
|
var image = root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Point(3)});
|
||||||
// Setting the x or y coordinate of the size to 1 or a lower number causes the width or height to be a percentage of the parent's width or height
|
// Setting the x or y coordinate of the size to 1 or a lower number causes the width or height to be a percentage of the parent's width or height
|
||||||
// (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth)
|
// (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth)
|
||||||
|
|
|
@ -1,25 +1,14 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using MLEM.Extensions;
|
||||||
using MonoGame.Extended.BitmapFonts;
|
using MonoGame.Extended.BitmapFonts;
|
||||||
|
|
||||||
namespace MLEM.Extended.Extensions {
|
namespace MLEM.Extended.Extensions {
|
||||||
public static class BitmapFontExtensions {
|
public static class BitmapFontExtensions {
|
||||||
|
|
||||||
public static IEnumerable<string> SplitString(this BitmapFont font, string text, float width, float scale) {
|
public static string SplitString(this BitmapFont font, string text, float width, float scale) {
|
||||||
var builder = new StringBuilder();
|
return SpriteFontExtensions.SplitString(s => font.MeasureString(s).Width, text, width, scale);
|
||||||
foreach (var line in text.Split('\n')) {
|
|
||||||
foreach (var word in line.Split(' ')) {
|
|
||||||
builder.Append(word).Append(' ');
|
|
||||||
if (font.MeasureString(builder).Width * scale >= width) {
|
|
||||||
var len = builder.Length - word.Length - 1;
|
|
||||||
yield return builder.ToString(0, len - 1);
|
|
||||||
builder.Remove(0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yield return builder.ToString(0, builder.Length - 1);
|
|
||||||
builder.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace MLEM.Extended.Font {
|
||||||
public class GenericBitmapFont : IGenericFont {
|
public class GenericBitmapFont : IGenericFont {
|
||||||
|
|
||||||
public readonly BitmapFont Font;
|
public readonly BitmapFont Font;
|
||||||
|
public float LineHeight => this.Font.LineHeight;
|
||||||
|
|
||||||
public GenericBitmapFont(BitmapFont font) {
|
public GenericBitmapFont(BitmapFont font) {
|
||||||
this.Font = font;
|
this.Font = font;
|
||||||
|
@ -55,7 +56,7 @@ namespace MLEM.Extended.Font {
|
||||||
batch.DrawCenteredString(this.Font, text, position, scale, color, horizontal, vertical, addedScale);
|
batch.DrawCenteredString(this.Font, text, position, scale, color, horizontal, vertical, addedScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> SplitString(string text, float width, float scale) {
|
public string SplitString(string text, float width, float scale) {
|
||||||
return this.Font.SplitString(text, width, scale);
|
return this.Font.SplitString(text, width, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,7 @@ namespace MLEM.Ui.Elements {
|
||||||
public class Paragraph : Element {
|
public class Paragraph : Element {
|
||||||
|
|
||||||
private string text;
|
private string text;
|
||||||
private float lineHeight;
|
private string splitText;
|
||||||
private float longestLineLength;
|
|
||||||
private string[] splitText;
|
|
||||||
private Dictionary<int, FormattingCode> codeLocations;
|
private Dictionary<int, FormattingCode> codeLocations;
|
||||||
private IGenericFont regularFont;
|
private IGenericFont regularFont;
|
||||||
private IGenericFont boldFont;
|
private IGenericFont boldFont;
|
||||||
|
@ -37,7 +35,6 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
public bool AutoAdjustWidth;
|
public bool AutoAdjustWidth;
|
||||||
public TextCallback GetTextCallback;
|
public TextCallback GetTextCallback;
|
||||||
public float LineSpace = 1;
|
|
||||||
|
|
||||||
public Paragraph(Anchor anchor, float width, TextCallback textCallback, bool centerText = false)
|
public Paragraph(Anchor anchor, float width, TextCallback textCallback, bool centerText = false)
|
||||||
: this(anchor, width, "", centerText) {
|
: this(anchor, width, "", centerText) {
|
||||||
|
@ -53,21 +50,13 @@ namespace MLEM.Ui.Elements {
|
||||||
|
|
||||||
protected override Point CalcActualSize(Rectangle parentArea) {
|
protected override Point CalcActualSize(Rectangle parentArea) {
|
||||||
var size = base.CalcActualSize(parentArea);
|
var size = base.CalcActualSize(parentArea);
|
||||||
|
|
||||||
var sc = this.TextScale * this.Scale;
|
var sc = this.TextScale * this.Scale;
|
||||||
this.splitText = this.regularFont.SplitString(this.text.RemoveFormatting(), size.X - this.ScaledPadding.X * 2, sc).ToArray();
|
this.splitText = this.regularFont.SplitString(this.text.RemoveFormatting(), size.X - this.ScaledPadding.X * 2, sc);
|
||||||
this.codeLocations = this.text.GetFormattingCodes();
|
this.codeLocations = this.text.GetFormattingCodes();
|
||||||
|
|
||||||
this.lineHeight = 0;
|
var textDims = this.regularFont.MeasureString(this.splitText) * sc;
|
||||||
this.longestLineLength = 0;
|
return new Point(this.AutoAdjustWidth ? textDims.X.Ceil() + this.ScaledPadding.X * 2 : size.X, textDims.Y.Ceil() + this.ScaledPadding.Y * 2);
|
||||||
foreach (var strg in this.splitText) {
|
|
||||||
var strgScale = this.regularFont.MeasureString(strg) * sc;
|
|
||||||
if (strgScale.Y + 1 > this.lineHeight)
|
|
||||||
this.lineHeight = strgScale.Y + 1;
|
|
||||||
if (strgScale.X > this.longestLineLength)
|
|
||||||
this.longestLineLength = strgScale.X;
|
|
||||||
}
|
|
||||||
this.lineHeight *= this.LineSpace;
|
|
||||||
return new Point(this.AutoAdjustWidth ? this.longestLineLength.Ceil() + this.ScaledPadding.X * 2 : size.X, (this.lineHeight * this.splitText.Length).Ceil() + this.ScaledPadding.Y * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(GameTime time) {
|
public override void Update(GameTime time) {
|
||||||
|
@ -86,19 +75,15 @@ namespace MLEM.Ui.Elements {
|
||||||
|
|
||||||
// if we don't have any formatting codes, then we don't need to do complex drawing
|
// if we don't have any formatting codes, then we don't need to do complex drawing
|
||||||
if (this.codeLocations.Count <= 0) {
|
if (this.codeLocations.Count <= 0) {
|
||||||
foreach (var line in this.splitText) {
|
this.regularFont.DrawString(batch, this.splitText, pos + off, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
||||||
this.regularFont.DrawString(batch, line, pos + off, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
|
||||||
off.Y += this.lineHeight;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// if we have formatting codes, we need to go through each index and see how it should be drawn
|
// if we have formatting codes, we need to go through each index and see how it should be drawn
|
||||||
var characterCounter = 0;
|
var characterCounter = 0;
|
||||||
var currColor = this.TextColor;
|
var currColor = this.TextColor;
|
||||||
var currFont = this.regularFont;
|
var currFont = this.regularFont;
|
||||||
|
|
||||||
foreach (var line in this.splitText) {
|
var innerOffset = new Vector2();
|
||||||
var lineOffset = new Vector2();
|
foreach (var c in this.splitText) {
|
||||||
foreach (var c in line) {
|
|
||||||
// check if the current character's index has a formatting code
|
// check if the current character's index has a formatting code
|
||||||
this.codeLocations.TryGetValue(characterCounter, out var code);
|
this.codeLocations.TryGetValue(characterCounter, out var code);
|
||||||
if (code != null) {
|
if (code != null) {
|
||||||
|
@ -119,18 +104,16 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
characterCounter++;
|
||||||
|
|
||||||
var cSt = c.ToString();
|
var cSt = c.ToString();
|
||||||
currFont.DrawString(batch, cSt, pos + off + lineOffset, currColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
if (c == '\n') {
|
||||||
|
innerOffset.X = 0;
|
||||||
// get the width based on the regular font so that the split text doesn't overshoot the borders
|
innerOffset.Y += this.regularFont.LineHeight * sc;
|
||||||
// this is a bit of a hack, but bold fonts shouldn't be that much thicker so it won't look bad
|
} else {
|
||||||
lineOffset.X += this.regularFont.MeasureString(cSt).X * sc;
|
currFont.DrawString(batch, cSt, pos + off + innerOffset, currColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
||||||
characterCounter++;
|
innerOffset.X += this.regularFont.MeasureString(cSt).X * sc;
|
||||||
}
|
}
|
||||||
// spaces are replaced by newline characters, account for that
|
|
||||||
characterCounter++;
|
|
||||||
off.Y += this.lineHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.Draw(time, batch, alpha, offset);
|
base.Draw(time, batch, alpha, offset);
|
||||||
|
|
|
@ -45,6 +45,8 @@ namespace MLEM.Ui.Style {
|
||||||
|
|
||||||
private class EmptyFont : IGenericFont {
|
private class EmptyFont : IGenericFont {
|
||||||
|
|
||||||
|
public float LineHeight => 1;
|
||||||
|
|
||||||
public Vector2 MeasureString(string text) {
|
public Vector2 MeasureString(string text) {
|
||||||
return Vector2.One;
|
return Vector2.One;
|
||||||
}
|
}
|
||||||
|
@ -74,8 +76,8 @@ namespace MLEM.Ui.Style {
|
||||||
public void DrawCenteredString(SpriteBatch batch, string text, Vector2 position, float scale, Color color, bool horizontal = true, bool vertical = false, float addedScale = 0) {
|
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) {
|
public string SplitString(string text, float width, float scale) {
|
||||||
yield break;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
@ -5,20 +6,25 @@ using Microsoft.Xna.Framework.Graphics;
|
||||||
namespace MLEM.Extensions {
|
namespace MLEM.Extensions {
|
||||||
public static class SpriteFontExtensions {
|
public static class SpriteFontExtensions {
|
||||||
|
|
||||||
public static IEnumerable<string> SplitString(this SpriteFont font, string text, float width, float scale) {
|
public static string SplitString(this SpriteFont font, string text, float width, float scale) {
|
||||||
var builder = new StringBuilder();
|
return SplitString(s => font.MeasureString(s).X, text, width, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SplitString(Func<StringBuilder, float> widthFunc, string text, float width, float scale) {
|
||||||
|
var total = new StringBuilder();
|
||||||
foreach (var line in text.Split('\n')) {
|
foreach (var line in text.Split('\n')) {
|
||||||
|
var curr = new StringBuilder();
|
||||||
foreach (var word in line.Split(' ')) {
|
foreach (var word in line.Split(' ')) {
|
||||||
builder.Append(word).Append(' ');
|
curr.Append(word).Append(' ');
|
||||||
if (font.MeasureString(builder).X * scale >= width) {
|
if (widthFunc(curr) * scale >= width) {
|
||||||
var len = builder.Length - word.Length - 1;
|
var len = curr.Length - word.Length - 1;
|
||||||
yield return builder.ToString(0, len - 1);
|
total.Append(curr.ToString(0, len - 1)).Append('\n');
|
||||||
builder.Remove(0, len);
|
curr.Remove(0, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield return builder.ToString(0, builder.Length - 1);
|
total.Append(curr.ToString(0, curr.Length - 1)).Append('\n');
|
||||||
builder.Clear();
|
|
||||||
}
|
}
|
||||||
|
return total.ToString(0, total.Length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,12 @@ namespace MLEM.Font {
|
||||||
public class GenericSpriteFont : IGenericFont {
|
public class GenericSpriteFont : IGenericFont {
|
||||||
|
|
||||||
public readonly SpriteFont Font;
|
public readonly SpriteFont Font;
|
||||||
|
public float LineHeight => this.Font.LineSpacing;
|
||||||
|
|
||||||
public GenericSpriteFont(SpriteFont font) {
|
public GenericSpriteFont(SpriteFont font) {
|
||||||
this.Font = font;
|
this.Font = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator GenericSpriteFont(SpriteFont font) {
|
|
||||||
return new GenericSpriteFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 MeasureString(string text) {
|
public Vector2 MeasureString(string text) {
|
||||||
return this.Font.MeasureString(text);
|
return this.Font.MeasureString(text);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +50,7 @@ namespace MLEM.Font {
|
||||||
batch.DrawCenteredString(this.Font, text, position, scale, color, horizontal, vertical, addedScale);
|
batch.DrawCenteredString(this.Font, text, position, scale, color, horizontal, vertical, addedScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> SplitString(string text, float width, float scale) {
|
public string SplitString(string text, float width, float scale) {
|
||||||
return this.Font.SplitString(text, width, scale);
|
return this.Font.SplitString(text, width, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ using Microsoft.Xna.Framework.Graphics;
|
||||||
namespace MLEM.Font {
|
namespace MLEM.Font {
|
||||||
public interface IGenericFont {
|
public interface IGenericFont {
|
||||||
|
|
||||||
|
float LineHeight { get; }
|
||||||
|
|
||||||
Vector2 MeasureString(string text);
|
Vector2 MeasureString(string text);
|
||||||
|
|
||||||
Vector2 MeasureString(StringBuilder text);
|
Vector2 MeasureString(StringBuilder text);
|
||||||
|
@ -24,7 +26,7 @@ namespace MLEM.Font {
|
||||||
|
|
||||||
void DrawCenteredString(SpriteBatch batch, string text, Vector2 position, float scale, Color color, bool horizontal = true, bool vertical = false, float addedScale = 0);
|
void DrawCenteredString(SpriteBatch batch, string text, Vector2 position, float scale, Color color, bool horizontal = true, bool vertical = false, float addedScale = 0);
|
||||||
|
|
||||||
IEnumerable<string> SplitString(string text, float width, float scale);
|
string SplitString(string text, float width, float scale);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue