1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-05-31 12:23:38 +02:00

simplify text rendering quite a bit after realizing that monogame deals with multiple lines on its own

This commit is contained in:
Ellpeck 2019-08-25 19:07:45 +02:00
parent 6766d769f4
commit 226640ef3a
8 changed files with 64 additions and 84 deletions

View file

@ -69,7 +69,7 @@ namespace Demos {
var root = new Panel(Anchor.Center, new Vector2(80, 100), Vector2.Zero, false, true, new Point(5, 10));
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)});
// 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)

View file

@ -1,25 +1,14 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MonoGame.Extended.BitmapFonts;
namespace MLEM.Extended.Extensions {
public static class BitmapFontExtensions {
public static IEnumerable<string> SplitString(this BitmapFont font, string text, float width, float scale) {
var builder = new StringBuilder();
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();
}
public static string SplitString(this BitmapFont font, string text, float width, float scale) {
return SpriteFontExtensions.SplitString(s => font.MeasureString(s).Width, text, width, scale);
}
}

View file

@ -10,6 +10,7 @@ namespace MLEM.Extended.Font {
public class GenericBitmapFont : IGenericFont {
public readonly BitmapFont Font;
public float LineHeight => this.Font.LineHeight;
public GenericBitmapFont(BitmapFont font) {
this.Font = font;
@ -55,7 +56,7 @@ namespace MLEM.Extended.Font {
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);
}

View file

@ -14,9 +14,7 @@ namespace MLEM.Ui.Elements {
public class Paragraph : Element {
private string text;
private float lineHeight;
private float longestLineLength;
private string[] splitText;
private string splitText;
private Dictionary<int, FormattingCode> codeLocations;
private IGenericFont regularFont;
private IGenericFont boldFont;
@ -37,7 +35,6 @@ namespace MLEM.Ui.Elements {
}
public bool AutoAdjustWidth;
public TextCallback GetTextCallback;
public float LineSpace = 1;
public Paragraph(Anchor anchor, float width, TextCallback textCallback, bool centerText = false)
: this(anchor, width, "", centerText) {
@ -53,21 +50,13 @@ namespace MLEM.Ui.Elements {
protected override Point CalcActualSize(Rectangle parentArea) {
var size = base.CalcActualSize(parentArea);
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.lineHeight = 0;
this.longestLineLength = 0;
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);
var textDims = this.regularFont.MeasureString(this.splitText) * sc;
return new Point(this.AutoAdjustWidth ? textDims.X.Ceil() + this.ScaledPadding.X * 2 : size.X, textDims.Y.Ceil() + this.ScaledPadding.Y * 2);
}
public override void Update(GameTime time) {
@ -86,51 +75,45 @@ namespace MLEM.Ui.Elements {
// if we don't have any formatting codes, then we don't need to do complex drawing
if (this.codeLocations.Count <= 0) {
foreach (var line in this.splitText) {
this.regularFont.DrawString(batch, line, pos + off, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
off.Y += this.lineHeight;
}
this.regularFont.DrawString(batch, this.splitText, pos + off, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
} else {
// if we have formatting codes, we need to go through each index and see how it should be drawn
var characterCounter = 0;
var currColor = this.TextColor;
var currFont = this.regularFont;
foreach (var line in this.splitText) {
var lineOffset = new Vector2();
foreach (var c in line) {
// check if the current character's index has a formatting code
this.codeLocations.TryGetValue(characterCounter, out var code);
if (code != null) {
// if so, apply it
if (code.IsColorCode) {
currColor = code.Color;
} else {
switch (code.Style) {
case TextStyle.Regular:
currFont = this.regularFont;
break;
case TextStyle.Bold:
currFont = this.boldFont;
break;
case TextStyle.Italic:
currFont = this.italicFont;
break;
}
var innerOffset = new Vector2();
foreach (var c in this.splitText) {
// check if the current character's index has a formatting code
this.codeLocations.TryGetValue(characterCounter, out var code);
if (code != null) {
// if so, apply it
if (code.IsColorCode) {
currColor = code.Color;
} else {
switch (code.Style) {
case TextStyle.Regular:
currFont = this.regularFont;
break;
case TextStyle.Bold:
currFont = this.boldFont;
break;
case TextStyle.Italic:
currFont = this.italicFont;
break;
}
}
var cSt = c.ToString();
currFont.DrawString(batch, cSt, pos + off + lineOffset, currColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
// get the width based on the regular font so that the split text doesn't overshoot the borders
// this is a bit of a hack, but bold fonts shouldn't be that much thicker so it won't look bad
lineOffset.X += this.regularFont.MeasureString(cSt).X * sc;
characterCounter++;
}
// spaces are replaced by newline characters, account for that
characterCounter++;
off.Y += this.lineHeight;
var cSt = c.ToString();
if (c == '\n') {
innerOffset.X = 0;
innerOffset.Y += this.regularFont.LineHeight * sc;
} else {
currFont.DrawString(batch, cSt, pos + off + innerOffset, currColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
innerOffset.X += this.regularFont.MeasureString(cSt).X * sc;
}
}
}
base.Draw(time, batch, alpha, offset);

View file

@ -45,6 +45,8 @@ namespace MLEM.Ui.Style {
private class EmptyFont : IGenericFont {
public float LineHeight => 1;
public Vector2 MeasureString(string text) {
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 IEnumerable<string> SplitString(string text, float width, float scale) {
yield break;
public string SplitString(string text, float width, float scale) {
return text;
}
}

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
@ -5,20 +6,25 @@ using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Extensions {
public static class SpriteFontExtensions {
public static IEnumerable<string> SplitString(this SpriteFont font, string text, float width, float scale) {
var builder = new StringBuilder();
public static string SplitString(this SpriteFont font, string text, float width, float scale) {
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')) {
var curr = new StringBuilder();
foreach (var word in line.Split(' ')) {
builder.Append(word).Append(' ');
if (font.MeasureString(builder).X * scale >= width) {
var len = builder.Length - word.Length - 1;
yield return builder.ToString(0, len - 1);
builder.Remove(0, len);
curr.Append(word).Append(' ');
if (widthFunc(curr) * scale >= width) {
var len = curr.Length - word.Length - 1;
total.Append(curr.ToString(0, len - 1)).Append('\n');
curr.Remove(0, len);
}
}
yield return builder.ToString(0, builder.Length - 1);
builder.Clear();
total.Append(curr.ToString(0, curr.Length - 1)).Append('\n');
}
return total.ToString(0, total.Length - 1);
}
}

View file

@ -8,15 +8,12 @@ namespace MLEM.Font {
public class GenericSpriteFont : IGenericFont {
public readonly SpriteFont Font;
public float LineHeight => this.Font.LineSpacing;
public GenericSpriteFont(SpriteFont font) {
this.Font = font;
}
public static implicit operator GenericSpriteFont(SpriteFont font) {
return new GenericSpriteFont(font);
}
public Vector2 MeasureString(string text) {
return this.Font.MeasureString(text);
}
@ -53,7 +50,7 @@ namespace MLEM.Font {
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);
}

View file

@ -6,6 +6,8 @@ using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Font {
public interface IGenericFont {
float LineHeight { get; }
Vector2 MeasureString(string 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);
IEnumerable<string> SplitString(string text, float width, float scale);
string SplitString(string text, float width, float scale);
}
}