mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-22 04:53:29 +01:00
Made TextFormatter string size based on the currently active font and added a formatting code to allow for inline font changes
This commit is contained in:
parent
ad1d6a864e
commit
53b93a34f8
11 changed files with 179 additions and 72 deletions
|
@ -23,6 +23,7 @@ Improvements
|
|||
- Added Padding.Empty
|
||||
- Throw an exception when text formatter macros resolve recursively too many times
|
||||
- Allow using StaticSpriteBatch for AutoTiling
|
||||
- Made TextFormatter string size based on the currently active font rather than the default one
|
||||
|
||||
Fixes
|
||||
- Fixed some end-of-line inconsistencies when using the Right text alignment
|
||||
|
@ -31,6 +32,7 @@ Fixes
|
|||
Additions
|
||||
- Allow specifying a maximum amount of characters for a TextField
|
||||
- Added a multiline editing mode to TextField
|
||||
- Added a formatting code to allow for inline font changes
|
||||
|
||||
Improvements
|
||||
- *Made Image ScaleToImage take ui scale into account*
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
/processorParam:TextureFormat=Compressed
|
||||
/build:Fonts/TestFontItalic.spritefont
|
||||
|
||||
#begin Fonts/MonospacedFont.spritefont
|
||||
/importer:FontDescriptionImporter
|
||||
/processor:FontDescriptionProcessor
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:TextureFormat=Compressed
|
||||
/build:Fonts/MonospacedFont.spritefont
|
||||
|
||||
#begin Textures/Anim.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
|
|
BIN
Demos/Content/Fonts/JetBrainsMono-Regular.ttf
Normal file
BIN
Demos/Content/Fonts/JetBrainsMono-Regular.ttf
Normal file
Binary file not shown.
60
Demos/Content/Fonts/MonospacedFont.spritefont
Normal file
60
Demos/Content/Fonts/MonospacedFont.spritefont
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file contains an xml description of a font, and will be read by the XNA
|
||||
Framework Content Pipeline. Follow the comments to customize the appearance
|
||||
of the font in your game, and to change the characters which are available to draw
|
||||
with.
|
||||
-->
|
||||
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
|
||||
<Asset Type="Graphics:FontDescription">
|
||||
|
||||
<!--
|
||||
Modify this string to change the font that will be imported.
|
||||
-->
|
||||
<FontName>JetBrainsMono-Regular.ttf</FontName>
|
||||
|
||||
<!--
|
||||
Size is a float value, measured in points. Modify this value to change
|
||||
the size of the font.
|
||||
-->
|
||||
<Size>32</Size>
|
||||
|
||||
<!--
|
||||
Spacing is a float value, measured in pixels. Modify this value to change
|
||||
the amount of spacing in between characters.
|
||||
-->
|
||||
<Spacing>0</Spacing>
|
||||
|
||||
<!--
|
||||
UseKerning controls the layout of the font. If this value is true, kerning information
|
||||
will be used when placing characters.
|
||||
-->
|
||||
<UseKerning>true</UseKerning>
|
||||
|
||||
<!--
|
||||
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
|
||||
and "Bold, Italic", and are case sensitive.
|
||||
-->
|
||||
<Style>Regular</Style>
|
||||
|
||||
<!--
|
||||
If you uncomment this line, the default character will be substituted if you draw
|
||||
or measure text that contains characters which were not included in the font.
|
||||
-->
|
||||
<DefaultCharacter>*</DefaultCharacter>
|
||||
|
||||
<!--
|
||||
CharacterRegions control what letters are available in the font. Every
|
||||
character from Start to End will be built and made available for drawing. The
|
||||
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
|
||||
character set. The characters are ordered according to the Unicode standard.
|
||||
See the documentation for more information.
|
||||
-->
|
||||
<CharacterRegions>
|
||||
<CharacterRegion>
|
||||
<Start> </Start>
|
||||
<End>ɏ</End>
|
||||
</CharacterRegion>
|
||||
</CharacterRegions>
|
||||
</Asset>
|
||||
</XnaContent>
|
|
@ -47,7 +47,8 @@ namespace Demos {
|
|||
CheckboxTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4),
|
||||
CheckboxCheckmark = new TextureRegion(this.testTexture, 24, 0, 8, 8),
|
||||
RadioTexture = new NinePatch(new TextureRegion(this.testTexture, 16, 0, 8, 8), 3),
|
||||
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8)
|
||||
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8),
|
||||
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/MonospacedFont"))}}
|
||||
};
|
||||
var untexturedStyle = new UntexturedStyle(this.SpriteBatch) {
|
||||
TextScale = style.TextScale,
|
||||
|
@ -87,7 +88,7 @@ namespace Demos {
|
|||
this.root.AddChild(new VerticalSpace(3));
|
||||
|
||||
// a paragraph with formatting codes. To see them all or to add more, check the TextFormatting class
|
||||
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain <c Blue>formatting codes</c>, including colors and <i>text styles</i>. The names of all <c Orange>MonoGame Colors</c> can be used, as well as the codes <i>Italic</i>, <b>Bold</b>, <s>Drop Shadow'd</s> and <s><c Pink>mixed formatting</s></c>. \n<i>Even <c #ff611f82>inline custom colors</c> work!</i>"));
|
||||
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain <c Blue>formatting codes</c>, including colors and <i>text styles</i>. The names of all <c Orange>MonoGame Colors</c> can be used, as well as the codes <i>Italic</i>, <b>Bold</b>, <s>Drop Shadow'd</s> and <s><c Pink>mixed formatting</s></c>. You can also add additional fonts for things like\n<f Monospaced>void Code() {\n // Code\n}</f>\n<i>Even <c #ff611f82>inline custom colors</c> work!</i>"));
|
||||
|
||||
// adding some custom image formatting codes
|
||||
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Additionally, you can create custom formatting codes that contain <i Grass> images and more!"));
|
||||
|
|
|
@ -4,7 +4,7 @@ The **MLEM** package contains a simple text formatting system that supports colo
|
|||
|
||||
Text formatting makes use of [generic fonts](font_extensions.md).
|
||||
|
||||
It should also be noted that [MLEM.Ui](ui.md)'s `Paragraph`s support text formatting out of the box.
|
||||
It should also be noted that [MLEM.Ui](ui.md)'s `Paragraph` supports text formatting out of the box.
|
||||
|
||||
## Formatting codes
|
||||
To format your text, you can insert *formatting codes* into it. Almost all of these codes are single letters surrounded by `<>`, and some formatting codes can accept additional parameters after their letter representation.
|
||||
|
@ -16,6 +16,10 @@ By default, the following formatting options are available:
|
|||
- Underlined and strikethrough text using `<u>` and `<st>`, respectively. Reset using `</u>` and `</st>`.
|
||||
- A wobbly sine wave animation using `<a wobbly>`. Optional parameters for the wobble's intensity and height are accepted: `<a wobbly 10 0.25>`. Reset using `</a>`.
|
||||
|
||||
When using [MLEM.Ui](ui.md)'s `Paragraph`, these additional formatting options are available by default:
|
||||
- Hoverable and clickable links using `<l Url>`. Note that this code does not automatically change the color of the text. Reset using `</l>`.
|
||||
- Inline font changes using `<f FontName>`, with custom fonts gathered from `UiStyle.AdditionalFonts`. Reset using `</f>`.
|
||||
|
||||
## Getting your text ready
|
||||
To get your text ready for rendering with formatting codes, it has to be tokenized. For that, you need to create a new text formatter first. Additionally, you need to have a [generic font](font_extensions.md) ready:
|
||||
```cs
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MLEM.Font;
|
||||
using MLEM.Formatting;
|
||||
|
@ -194,6 +195,10 @@ namespace MLEM.Ui.Style {
|
|||
/// Note that this sound is only played if the callbacks have any subscribers.
|
||||
/// </summary>
|
||||
public SoundEffectInfo ActionSound;
|
||||
/// <summary>
|
||||
/// A set of additional fonts that can be used for the <c><f FontName></c> formatting code
|
||||
/// </summary>
|
||||
public Dictionary<string, GenericFont> AdditionalFonts = new Dictionary<string, GenericFont>();
|
||||
|
||||
}
|
||||
}
|
|
@ -223,6 +223,8 @@ namespace MLEM.Ui {
|
|||
this.TextFormatter = new TextFormatter();
|
||||
this.TextFormatter.Codes.Add(new Regex("<l(?: ([^>]+))?>"), (f, m, r) => new LinkCode(m, r, 1 / 16F, 0.85F,
|
||||
t => this.Controls.MousedElement is Paragraph.Link l1 && l1.Token == t || this.Controls.TouchedElement is Paragraph.Link l2 && l2.Token == t));
|
||||
this.TextFormatter.Codes.Add(new Regex("<f ([^>]+)>"), (_, m, r) => new FontCode(m, r,
|
||||
f => this.Style.AdditionalFonts != null && this.Style.AdditionalFonts.TryGetValue(m.Groups[1].Value, out var c) ? c : f));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
@ -88,44 +89,7 @@ namespace MLEM.Font {
|
|||
/// <param name="ignoreTrailingSpaces">Whether trailing whitespace should be ignored in the returned size, causing the end of each line to be effectively trimmed</param>
|
||||
/// <returns>The size of the string when drawn with this font</returns>
|
||||
public Vector2 MeasureString(string text, bool ignoreTrailingSpaces = false) {
|
||||
var size = Vector2.Zero;
|
||||
if (text.Length <= 0)
|
||||
return size;
|
||||
var xOffset = 0F;
|
||||
for (var i = 0; i < text.Length; i++) {
|
||||
switch (text[i]) {
|
||||
case '\n':
|
||||
xOffset = 0;
|
||||
size.Y += this.LineHeight;
|
||||
break;
|
||||
case OneEmSpace:
|
||||
xOffset += this.LineHeight;
|
||||
break;
|
||||
case Nbsp:
|
||||
xOffset += this.MeasureChar(' ');
|
||||
break;
|
||||
case Zwsp:
|
||||
// don't add width for a zero-width space
|
||||
break;
|
||||
case ' ':
|
||||
if (ignoreTrailingSpaces && IsTrailingSpace(text, i)) {
|
||||
// if this is a trailing space, we can skip remaining spaces too
|
||||
i = text.Length - 1;
|
||||
break;
|
||||
}
|
||||
xOffset += this.MeasureChar(' ');
|
||||
break;
|
||||
default:
|
||||
xOffset += this.MeasureChar(text[i]);
|
||||
break;
|
||||
}
|
||||
// increase x size if this line is the longest
|
||||
if (xOffset > size.X)
|
||||
size.X = xOffset;
|
||||
}
|
||||
// include the last line's height too!
|
||||
size.Y += this.LineHeight;
|
||||
return size;
|
||||
return MeasureString(i => this, text, ignoreTrailingSpaces);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -139,24 +103,7 @@ namespace MLEM.Font {
|
|||
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
||||
/// <returns>The truncated string, or the same string if it is shorter than the maximum width</returns>
|
||||
public string TruncateString(string text, float width, float scale, bool fromBack = false, string ellipsis = "") {
|
||||
var total = new StringBuilder();
|
||||
var ellipsisWidth = this.MeasureString(ellipsis).X * scale;
|
||||
for (var i = 0; i < text.Length; i++) {
|
||||
if (fromBack) {
|
||||
total.Insert(0, text[text.Length - 1 - i]);
|
||||
} else {
|
||||
total.Append(text[i]);
|
||||
}
|
||||
|
||||
if (this.MeasureString(total.ToString()).X * scale + ellipsisWidth >= width) {
|
||||
if (fromBack) {
|
||||
return total.Remove(0, 1).Insert(0, ellipsis).ToString();
|
||||
} else {
|
||||
return total.Remove(total.Length - 1, 1).Append(ellipsis).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return total.ToString();
|
||||
return TruncateString(i => this, text, width, scale, fromBack, ellipsis);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -182,6 +129,72 @@ namespace MLEM.Font {
|
|||
/// <param name="scale">The scale to use for width measurements</param>
|
||||
/// <returns>The split string as an enumerable of split sections</returns>
|
||||
public IEnumerable<string> SplitStringSeparate(string text, float width, float scale) {
|
||||
return SplitStringSeparate(i => this, text, width, scale);
|
||||
}
|
||||
|
||||
internal static Vector2 MeasureString(Func<int, GenericFont> fontFunction, string text, bool ignoreTrailingSpaces) {
|
||||
var size = Vector2.Zero;
|
||||
if (text.Length <= 0)
|
||||
return size;
|
||||
var xOffset = 0F;
|
||||
for (var i = 0; i < text.Length; i++) {
|
||||
var font = fontFunction(i);
|
||||
switch (text[i]) {
|
||||
case '\n':
|
||||
xOffset = 0;
|
||||
size.Y += font.LineHeight;
|
||||
break;
|
||||
case OneEmSpace:
|
||||
xOffset += font.LineHeight;
|
||||
break;
|
||||
case Nbsp:
|
||||
xOffset += font.MeasureChar(' ');
|
||||
break;
|
||||
case Zwsp:
|
||||
// don't add width for a zero-width space
|
||||
break;
|
||||
case ' ':
|
||||
if (ignoreTrailingSpaces && IsTrailingSpace(text, i)) {
|
||||
// if this is a trailing space, we can skip remaining spaces too
|
||||
i = text.Length - 1;
|
||||
break;
|
||||
}
|
||||
xOffset += font.MeasureChar(' ');
|
||||
break;
|
||||
default:
|
||||
xOffset += font.MeasureChar(text[i]);
|
||||
break;
|
||||
}
|
||||
// increase x size if this line is the longest
|
||||
if (xOffset > size.X)
|
||||
size.X = xOffset;
|
||||
}
|
||||
// include the last line's height too!
|
||||
size.Y += fontFunction(text.Length - 1).LineHeight;
|
||||
return size;
|
||||
}
|
||||
|
||||
internal static string TruncateString(Func<int, GenericFont> fontFunction, string text, float width, float scale, bool fromBack, string ellipsis) {
|
||||
var total = new StringBuilder();
|
||||
for (var i = 0; i < text.Length; i++) {
|
||||
if (fromBack) {
|
||||
total.Insert(0, text[text.Length - 1 - i]);
|
||||
} else {
|
||||
total.Append(text[i]);
|
||||
}
|
||||
|
||||
if (fontFunction(i).MeasureString(total + ellipsis).X * scale >= width) {
|
||||
if (fromBack) {
|
||||
return total.Remove(0, 1).Insert(0, ellipsis).ToString();
|
||||
} else {
|
||||
return total.Remove(total.Length - 1, 1).Append(ellipsis).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return total.ToString();
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> SplitStringSeparate(Func<int, GenericFont> fontFunction, string text, float width, float scale) {
|
||||
var currWidth = 0F;
|
||||
var lastSpaceIndex = -1;
|
||||
var widthSinceLastSpace = 0F;
|
||||
|
@ -195,7 +208,7 @@ namespace MLEM.Font {
|
|||
widthSinceLastSpace = 0;
|
||||
currWidth = 0;
|
||||
} else {
|
||||
var cWidth = this.MeasureString(c.ToCachedString()).X * scale;
|
||||
var cWidth = fontFunction(i).MeasureString(c.ToCachedString()).X * scale;
|
||||
if (c == ' ' || c == OneEmSpace || c == Zwsp) {
|
||||
// remember the location of this (breaking!) space
|
||||
lastSpaceIndex = curr.Length;
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace MLEM.Formatting {
|
|||
this.Codes.Add(new Regex("<u>"), (f, m, r) => new UnderlineCode(m, r, 1 / 16F, 0.85F));
|
||||
this.Codes.Add(new Regex("<st>"), (f, m, r) => new UnderlineCode(m, r, 1 / 16F, 0.55F));
|
||||
this.Codes.Add(new Regex("</(s|u|st|l)>"), (f, m, r) => new ResetFormattingCode(m, r));
|
||||
this.Codes.Add(new Regex("</(b|i)>"), (f, m, r) => new FontCode(m, r, null));
|
||||
this.Codes.Add(new Regex("</(b|i|f)>"), (f, m, r) => new FontCode(m, r, null));
|
||||
|
||||
// color codes
|
||||
foreach (var c in typeof(Color).GetProperties()) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -59,7 +60,7 @@ namespace MLEM.Formatting {
|
|||
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
||||
public void Split(GenericFont font, float width, float scale, TextAlignment alignment = TextAlignment.Left) {
|
||||
// a split string has the same character count as the input string but with newline characters added
|
||||
this.modifiedString = font.SplitString(this.String, width, scale);
|
||||
this.modifiedString = string.Join("\n", GenericFont.SplitStringSeparate(i => this.GetFontForIndex(font, i), this.String, width, scale));
|
||||
this.StoreModifiedSubstrings(font, alignment);
|
||||
}
|
||||
|
||||
|
@ -74,13 +75,13 @@ namespace MLEM.Formatting {
|
|||
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
||||
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
||||
public void Truncate(GenericFont font, float width, float scale, string ellipsis = "", TextAlignment alignment = TextAlignment.Left) {
|
||||
this.modifiedString = font.TruncateString(this.String, width, scale, false, ellipsis);
|
||||
this.modifiedString = GenericFont.TruncateString(i => this.GetFontForIndex(font, i), this.String, width, scale, false, ellipsis);
|
||||
this.StoreModifiedSubstrings(font, alignment);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GenericFont.MeasureString(string,bool)"/>
|
||||
public Vector2 Measure(GenericFont font) {
|
||||
return font.MeasureString(this.DisplayString);
|
||||
return GenericFont.MeasureString(i => this.GetFontForIndex(font, i), this.DisplayString, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -122,11 +123,11 @@ namespace MLEM.Formatting {
|
|||
for (var i = 0; i < line.Length; i++) {
|
||||
var c = line[i];
|
||||
if (l == 0 && i == 0)
|
||||
token.DrawSelf(time, batch, pos + innerOffset, font, color, scale, depth);
|
||||
token.DrawSelf(time, batch, pos + innerOffset, drawFont, color, scale, depth);
|
||||
|
||||
var cString = c.ToCachedString();
|
||||
token.DrawCharacter(time, batch, c, cString, i, pos + innerOffset, drawFont, drawColor, scale, depth);
|
||||
innerOffset.X += font.MeasureString(cString).X * scale;
|
||||
innerOffset.X += drawFont.MeasureString(cString).X * scale;
|
||||
}
|
||||
// only split at a new line, not between tokens!
|
||||
if (l < token.SplitDisplayString.Length - 1) {
|
||||
|
@ -183,17 +184,18 @@ namespace MLEM.Formatting {
|
|||
var innerOffset = new Vector2(this.initialInnerOffset, 0);
|
||||
for (var t = 0; t < this.Tokens.Length; t++) {
|
||||
var token = this.Tokens[t];
|
||||
var tokenFont = token.GetFont(font) ?? font;
|
||||
token.InnerOffsets = new float[token.SplitDisplayString.Length - 1];
|
||||
var area = new List<RectangleF>();
|
||||
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
|
||||
var size = font.MeasureString(token.SplitDisplayString[l]);
|
||||
var size = tokenFont.MeasureString(token.SplitDisplayString[l]);
|
||||
var rect = new RectangleF(innerOffset, size);
|
||||
if (!rect.IsEmpty)
|
||||
area.Add(rect);
|
||||
|
||||
if (l < token.SplitDisplayString.Length - 1) {
|
||||
innerOffset.X = token.InnerOffsets[l] = this.GetInnerOffsetX(font, t, l + 1, alignment);
|
||||
innerOffset.Y += font.LineHeight;
|
||||
innerOffset.Y += tokenFont.LineHeight;
|
||||
} else {
|
||||
innerOffset.X += size.X;
|
||||
}
|
||||
|
@ -202,24 +204,26 @@ namespace MLEM.Formatting {
|
|||
}
|
||||
}
|
||||
|
||||
private float GetInnerOffsetX(GenericFont font, int tokenIndex, int lineIndex, TextAlignment alignment) {
|
||||
private float GetInnerOffsetX(GenericFont defaultFont, int tokenIndex, int lineIndex, TextAlignment alignment) {
|
||||
if (alignment > TextAlignment.Left) {
|
||||
var token = this.Tokens[tokenIndex];
|
||||
var tokenFont = token.GetFont(defaultFont) ?? defaultFont;
|
||||
// if we're the last line in our line array, then we don't contain a line split, so the line ends in a later token
|
||||
var endsLater = lineIndex >= token.SplitDisplayString.Length - 1;
|
||||
// if the line ends in our token, we should ignore trailing white space
|
||||
var restOfLine = font.MeasureString(token.SplitDisplayString[lineIndex], !endsLater).X;
|
||||
var restOfLine = tokenFont.MeasureString(token.SplitDisplayString[lineIndex], !endsLater).X;
|
||||
if (endsLater) {
|
||||
for (var i = tokenIndex + 1; i < this.Tokens.Length; i++) {
|
||||
var other = this.Tokens[i];
|
||||
var otherFont = other.GetFont(defaultFont) ?? defaultFont;
|
||||
if (other.SplitDisplayString.Length > 1) {
|
||||
// the line ends in this token (so we also ignore trailing whitespaces)
|
||||
restOfLine += font.MeasureString(other.SplitDisplayString[0], true).X;
|
||||
restOfLine += otherFont.MeasureString(other.SplitDisplayString[0], true).X;
|
||||
break;
|
||||
} else {
|
||||
// the line doesn't end in this token (or it's the last token), so add it fully
|
||||
var lastToken = i >= this.Tokens.Length - 1;
|
||||
restOfLine += font.MeasureString(other.DisplayString, lastToken).X;
|
||||
restOfLine += otherFont.MeasureString(other.DisplayString, lastToken).X;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,5 +234,14 @@ namespace MLEM.Formatting {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private GenericFont GetFontForIndex(GenericFont font, int index) {
|
||||
foreach (var token in this.Tokens) {
|
||||
index -= token.Substring.Length;
|
||||
if (index <= 0)
|
||||
return token.GetFont(font) ?? font;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue