mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-12-24 01:09:23 +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));
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue