diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0bcbdc..4f571f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,9 @@ Jump to version:
## 5.2.0 (Unreleased)
### MLEM.Ui
+Improvements
+- Cache TokenizedString inner offsets for non-Left text alignments to improve performance
+
Fixes
- Fixed VerticalSpace height parameter being an integer
diff --git a/MLEM/Formatting/Token.cs b/MLEM/Formatting/Token.cs
index 460e05f..8d0d8c6 100644
--- a/MLEM/Formatting/Token.cs
+++ b/MLEM/Formatting/Token.cs
@@ -42,6 +42,7 @@ namespace MLEM.Formatting {
public readonly string RawSubstring;
internal RectangleF[] Area;
internal string ModifiedSubstring;
+ internal float[] InnerOffsets;
internal Token(Code[] appliedCodes, int index, int rawIndex, string substring, string rawSubstring) {
this.AppliedCodes = appliedCodes;
diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs
index 9d60731..4ef054c 100644
--- a/MLEM/Formatting/TokenizedString.cs
+++ b/MLEM/Formatting/TokenizedString.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -37,6 +38,7 @@ namespace MLEM.Formatting {
///
public readonly Code[] AllCodes;
private string modifiedString;
+ private float initialInnerOffset;
internal TokenizedString(GenericFont font, TextAlignment alignment, string rawString, string strg, Token[] tokens) {
this.RawString = rawString;
@@ -111,7 +113,7 @@ namespace MLEM.Formatting {
///
public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth, TextAlignment alignment = TextAlignment.Left) {
- var innerOffset = new Vector2(this.GetInnerOffsetX(font, 0, 0, scale, alignment), 0);
+ var innerOffset = new Vector2(this.initialInnerOffset * scale, 0);
for (var t = 0; t < this.Tokens.Length; t++) {
var token = this.Tokens[t];
var drawFont = token.GetFont(font) ?? font;
@@ -129,7 +131,7 @@ namespace MLEM.Formatting {
}
// only split at a new line, not between tokens!
if (l < token.SplitDisplayString.Length - 1) {
- innerOffset.X = this.GetInnerOffsetX(font, t, l + 1, scale, alignment);
+ innerOffset.X = token.InnerOffsets[l] * scale;
innerOffset.Y += font.LineHeight * scale;
}
}
@@ -172,45 +174,17 @@ namespace MLEM.Formatting {
this.RecalculateTokenData(font, alignment);
}
- private float GetInnerOffsetX(GenericFont font, int tokenIndex, int lineIndex, float scale, TextAlignment alignment) {
- if (alignment > TextAlignment.Left) {
- var rest = this.GetRestOfLineLength(font, tokenIndex, lineIndex) * scale;
- if (alignment == TextAlignment.Center)
- rest /= 2;
- return -rest;
- }
- return 0;
- }
-
- private float GetRestOfLineLength(GenericFont font, int tokenIndex, int lineIndex) {
- var token = this.Tokens[tokenIndex];
- var ret = font.MeasureString(token.SplitDisplayString[lineIndex], true).X;
- if (lineIndex >= token.SplitDisplayString.Length - 1) {
- // the line ends somewhere in or after the next token
- for (var i = tokenIndex + 1; i < this.Tokens.Length; i++) {
- var other = this.Tokens[i];
- if (other.SplitDisplayString.Length > 1) {
- // the line ends in this token
- ret += font.MeasureString(other.SplitDisplayString[0]).X;
- break;
- } else {
- // the line doesn't end in this token, so add it fully
- ret += font.MeasureString(other.DisplayString).X;
- }
- }
- }
- return ret;
- }
-
private void RecalculateTokenData(GenericFont font, TextAlignment alignment) {
// split display strings
foreach (var token in this.Tokens)
token.SplitDisplayString = token.DisplayString.Split('\n');
// token areas
- var innerOffset = new Vector2(this.GetInnerOffsetX(font, 0, 0, 1, alignment), 0);
+ this.initialInnerOffset = this.GetInnerOffsetX(font, 0, 0, alignment);
+ var innerOffset = new Vector2(this.initialInnerOffset, 0);
for (var t = 0; t < this.Tokens.Length; t++) {
var token = this.Tokens[t];
+ token.InnerOffsets = new float[token.SplitDisplayString.Length - 1];
var area = new List();
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
var size = font.MeasureString(token.SplitDisplayString[l]);
@@ -219,7 +193,7 @@ namespace MLEM.Formatting {
area.Add(rect);
if (l < token.SplitDisplayString.Length - 1) {
- innerOffset.X = this.GetInnerOffsetX(font, t, l + 1, 1, alignment);
+ innerOffset.X = token.InnerOffsets[l] = this.GetInnerOffsetX(font, t, l + 1, alignment);
innerOffset.Y += font.LineHeight;
} else {
innerOffset.X += size.X;
@@ -229,5 +203,30 @@ namespace MLEM.Formatting {
}
}
+ private float GetInnerOffsetX(GenericFont font, int tokenIndex, int lineIndex, TextAlignment alignment) {
+ if (alignment > TextAlignment.Left) {
+ var token = this.Tokens[tokenIndex];
+ var restOfLine = font.MeasureString(token.SplitDisplayString[lineIndex], true).X;
+ if (lineIndex >= token.SplitDisplayString.Length - 1) {
+ // the line ends somewhere in or after the next token
+ for (var i = tokenIndex + 1; i < this.Tokens.Length; i++) {
+ var other = this.Tokens[i];
+ if (other.SplitDisplayString.Length > 1) {
+ // the line ends in this token
+ restOfLine += font.MeasureString(other.SplitDisplayString[0]).X;
+ break;
+ } else {
+ // the line doesn't end in this token, so add it fully
+ restOfLine += font.MeasureString(other.DisplayString).X;
+ }
+ }
+ }
+ if (alignment == TextAlignment.Center)
+ restOfLine /= 2;
+ return -restOfLine;
+ }
+ return 0;
+ }
+
}
}
\ No newline at end of file