mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-24 21:48:35 +01:00
Compare commits
No commits in common. "1377941f1ac4c13a4b7e0baf4a3958ebe450355a" and "d1ce9412a25affda8c92578810c24a70e30e8819" have entirely different histories.
1377941f1a
...
d1ce9412a2
8 changed files with 74 additions and 199 deletions
|
@ -6,7 +6,6 @@ using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
using MLEM.Font;
|
using MLEM.Font;
|
||||||
using MLEM.Formatting;
|
|
||||||
using MLEM.Formatting.Codes;
|
using MLEM.Formatting.Codes;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
using MLEM.Startup;
|
using MLEM.Startup;
|
||||||
|
@ -192,14 +191,6 @@ namespace Demos {
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
this.root.AddChild(new VerticalSpace(3));
|
||||||
this.root.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Disabled button", "This button can't be clicked or moved to using automatic navigation") {IsDisabled = true}).PositionOffset = new Vector2(0, 1);
|
this.root.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Disabled button", "This button can't be clicked or moved to using automatic navigation") {IsDisabled = true}).PositionOffset = new Vector2(0, 1);
|
||||||
|
|
||||||
const string alignText = "Paragraphs can have <c CornflowerBlue><l Left>left</l></c> aligned text, <c CornflowerBlue><l Right>right</l></c> aligned text and <c CornflowerBlue><l Center>center</l></c> aligned text.";
|
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
|
||||||
var alignPar = this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, alignText));
|
|
||||||
alignPar.LinkAction = (l, c) => {
|
|
||||||
if (Enum.TryParse<TextAlignment>(c.Match.Groups[1].Value, out var alignment))
|
|
||||||
alignPar.Alignment = alignment;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
this.root.AddChild(new VerticalSpace(3));
|
||||||
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "The code for this demo contains some examples for how to query element data. This is the output of that:"));
|
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "The code for this demo contains some examples for how to query element data. This is the output of that:"));
|
||||||
|
|
||||||
|
|
|
@ -257,12 +257,12 @@ namespace MLEM.Ui.Elements {
|
||||||
public bool CanAutoAnchorsAttach = true;
|
public bool CanAutoAnchorsAttach = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause this element's width to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
/// Set this field to true to cause this element's width to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||||
/// To use this element's <see cref="Size"/>'s X coordinate as a minimum or maximum width rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
/// To use this element's <see cref="Size"/>'s X coordinate as a minimum width rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> to true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SetWidthBasedOnChildren;
|
public bool SetWidthBasedOnChildren;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause this element's height to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
/// Set this field to true to cause this element's height to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||||
/// To use this element's <see cref="Size"/>'s Y coordinate as a minimum or maximum height rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
/// To use this element's <see cref="Size"/>'s Y coordinate as a minimum height rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> to true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SetHeightBasedOnChildren;
|
public bool SetHeightBasedOnChildren;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -272,11 +272,6 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TreatSizeAsMinimum;
|
public bool TreatSizeAsMinimum;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/>are enabled, the resulting width or height weill always be less than or equal to this element's <see cref="Size"/>.
|
|
||||||
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
|
||||||
/// </summary>
|
|
||||||
public bool TreatSizeAsMaximum;
|
|
||||||
/// <summary>
|
|
||||||
/// Set this field to true to cause this element's final display area to never exceed that of its <see cref="Parent"/>.
|
/// Set this field to true to cause this element's final display area to never exceed that of its <see cref="Parent"/>.
|
||||||
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
|
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
|
||||||
/// This can be useful if an element should fill the remaining area of a parent exactly.
|
/// This can be useful if an element should fill the remaining area of a parent exactly.
|
||||||
|
@ -666,12 +661,8 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.TreatSizeAsMinimum) {
|
if (this.TreatSizeAsMinimum)
|
||||||
autoSize = Vector2.Max(autoSize, actualSize);
|
autoSize = Vector2.Max(autoSize, actualSize);
|
||||||
} else if (this.TreatSizeAsMaximum) {
|
|
||||||
autoSize = Vector2.Min(autoSize, actualSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!autoSize.Equals(this.UnscrolledArea.Size, 0.01F)) {
|
if (!autoSize.Equals(this.UnscrolledArea.Size, 0.01F)) {
|
||||||
recursion++;
|
recursion++;
|
||||||
if (recursion >= 16) {
|
if (recursion >= 16) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Paragraph : Element {
|
public class Paragraph : Element {
|
||||||
|
|
||||||
|
private string text;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font that this paragraph draws text with.
|
/// The font that this paragraph draws text with.
|
||||||
/// To set its bold and italic font, use <see cref="GenericFont.Bold"/> and <see cref="GenericFont.Italic"/>.
|
/// To set its bold and italic font, use <see cref="GenericFont.Bold"/> and <see cref="GenericFont.Italic"/>.
|
||||||
|
@ -83,20 +84,6 @@ namespace MLEM.Ui.Elements {
|
||||||
/// By default, <see cref="MlemPlatform.OpenLinkOrFile"/> is executed.
|
/// By default, <see cref="MlemPlatform.OpenLinkOrFile"/> is executed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<Link, LinkCode> LinkAction;
|
public Action<Link, LinkCode> LinkAction;
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="TextAlignment"/> that this paragraph's text should be rendered with
|
|
||||||
/// </summary>
|
|
||||||
public TextAlignment Alignment {
|
|
||||||
get => this.alignment;
|
|
||||||
set {
|
|
||||||
this.alignment = value;
|
|
||||||
this.SetAreaDirty();
|
|
||||||
this.TokenizedText = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string text;
|
|
||||||
private TextAlignment alignment;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new paragraph with the given settings.
|
/// Creates a new paragraph with the given settings.
|
||||||
|
@ -141,10 +128,10 @@ namespace MLEM.Ui.Elements {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {
|
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {
|
||||||
var pos = this.DisplayArea.Location + new Vector2(GetAlignmentOffset(), 0);
|
var pos = this.DisplayArea.Location;
|
||||||
var sc = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
var sc = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
||||||
var color = this.TextColor.OrDefault(Color.White) * alpha;
|
var color = this.TextColor.OrDefault(Color.White) * alpha;
|
||||||
this.TokenizedText.Draw(time, batch, pos, this.RegularFont, color, sc, 0, this.Alignment);
|
this.TokenizedText.Draw(time, batch, pos, this.RegularFont, color, sc, 0);
|
||||||
base.Draw(time, batch, alpha, blendState, samplerState, matrix);
|
base.Draw(time, batch, alpha, blendState, samplerState, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +151,7 @@ namespace MLEM.Ui.Elements {
|
||||||
protected virtual void ParseText(Vector2 size) {
|
protected virtual void ParseText(Vector2 size) {
|
||||||
if (this.TokenizedText == null) {
|
if (this.TokenizedText == null) {
|
||||||
// tokenize the text
|
// tokenize the text
|
||||||
this.TokenizedText = this.System.TextFormatter.Tokenize(this.RegularFont, this.Text, this.Alignment);
|
this.TokenizedText = this.System.TextFormatter.Tokenize(this.RegularFont, this.Text);
|
||||||
|
|
||||||
// add links to the paragraph
|
// add links to the paragraph
|
||||||
this.RemoveChildren(c => c is Link);
|
this.RemoveChildren(c => c is Link);
|
||||||
|
@ -175,9 +162,9 @@ namespace MLEM.Ui.Elements {
|
||||||
var width = size.X - this.ScaledPadding.Width;
|
var width = size.X - this.ScaledPadding.Width;
|
||||||
var scale = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
var scale = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
||||||
if (this.TruncateIfLong) {
|
if (this.TruncateIfLong) {
|
||||||
this.TokenizedText.Truncate(this.RegularFont, width, scale, this.Ellipsis, this.Alignment);
|
this.TokenizedText.Truncate(this.RegularFont, width, scale, this.Ellipsis);
|
||||||
} else {
|
} else {
|
||||||
this.TokenizedText.Split(this.RegularFont, width, scale, this.Alignment);
|
this.TokenizedText.Split(this.RegularFont, width, scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,16 +173,6 @@ namespace MLEM.Ui.Elements {
|
||||||
this.Text = this.GetTextCallback(this);
|
this.Text = this.GetTextCallback(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetAlignmentOffset() {
|
|
||||||
switch (this.Alignment) {
|
|
||||||
case TextAlignment.Center:
|
|
||||||
return this.DisplayArea.Width / 2;
|
|
||||||
case TextAlignment.Right:
|
|
||||||
return this.DisplayArea.Width;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate method used for <see cref="Paragraph.GetTextCallback"/>
|
/// A delegate method used for <see cref="Paragraph.GetTextCallback"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -237,7 +214,7 @@ namespace MLEM.Ui.Elements {
|
||||||
public override void ForceUpdateArea() {
|
public override void ForceUpdateArea() {
|
||||||
// set the position offset and size to the token's first area
|
// set the position offset and size to the token's first area
|
||||||
var area = this.Token.GetArea(Vector2.Zero, this.textScale).First();
|
var area = this.Token.GetArea(Vector2.Zero, this.textScale).First();
|
||||||
this.PositionOffset = area.Location + new Vector2(((Paragraph) this.Parent).GetAlignmentOffset() / this.Parent.Scale, 0);
|
this.PositionOffset = area.Location;
|
||||||
this.Size = area.Size;
|
this.Size = area.Size;
|
||||||
base.ForceUpdateArea();
|
base.ForceUpdateArea();
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,13 +70,13 @@ namespace MLEM.Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
///<inheritdoc cref="SpriteFont.MeasureString(string)"/>
|
///<inheritdoc cref="SpriteFont.MeasureString(string)"/>
|
||||||
public Vector2 MeasureString(string text, bool ignoreTrailingSpaces = false) {
|
public Vector2 MeasureString(string text) {
|
||||||
var size = Vector2.Zero;
|
var size = Vector2.Zero;
|
||||||
if (text.Length <= 0)
|
if (text.Length <= 0)
|
||||||
return size;
|
return size;
|
||||||
var xOffset = 0F;
|
var xOffset = 0F;
|
||||||
for (var i = 0; i < text.Length; i++) {
|
foreach (var c in text) {
|
||||||
switch (text[i]) {
|
switch (c) {
|
||||||
case '\n':
|
case '\n':
|
||||||
xOffset = 0;
|
xOffset = 0;
|
||||||
size.Y += this.LineHeight;
|
size.Y += this.LineHeight;
|
||||||
|
@ -90,16 +90,8 @@ namespace MLEM.Font {
|
||||||
case Zwsp:
|
case Zwsp:
|
||||||
// don't add width for a zero-width space
|
// don't add width for a zero-width space
|
||||||
break;
|
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(' ').X;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
xOffset += this.MeasureChar(text[i]).X;
|
xOffset += this.MeasureChar(c).X;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// increase x size if this line is the longest
|
// increase x size if this line is the longest
|
||||||
|
@ -194,13 +186,5 @@ namespace MLEM.Font {
|
||||||
return ret.ToString();
|
return ret.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsTrailingSpace(string s, int index) {
|
|
||||||
for (var i = index + 1; i < s.Length; i++) {
|
|
||||||
if (s[i] != ' ')
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
namespace MLEM.Formatting {
|
|
||||||
/// <summary>
|
|
||||||
/// An enumeration that represents a set of alignment options for <see cref="TokenizedString"/> objects and MLEM.Ui paragraphs.
|
|
||||||
/// </summary>
|
|
||||||
public enum TextAlignment {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Left alignment, which is also the default value
|
|
||||||
/// </summary>
|
|
||||||
Left,
|
|
||||||
/// <summary>
|
|
||||||
/// Center alignment
|
|
||||||
/// </summary>
|
|
||||||
Center,
|
|
||||||
/// <summary>
|
|
||||||
/// Right alignment.
|
|
||||||
/// In this alignment option, trailing spaces are ignored to ensure that visual alignment is consistent.
|
|
||||||
/// </summary>
|
|
||||||
Right
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -67,9 +67,8 @@ namespace MLEM.Formatting {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="font">The font to use for tokenization. Note that this font needs to be the same that will later be used for splitting, measuring and/or drawing.</param>
|
/// <param name="font">The font to use for tokenization. Note that this font needs to be the same that will later be used for splitting, measuring and/or drawing.</param>
|
||||||
/// <param name="s">The string to tokenize</param>
|
/// <param name="s">The string to tokenize</param>
|
||||||
/// <param name="alignment">The text alignment that should be used. Note that this alignment needs to be the same that will later be used for splitting, measuring and/or drawing.</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public TokenizedString Tokenize(GenericFont font, string s, TextAlignment alignment = TextAlignment.Left) {
|
public TokenizedString Tokenize(GenericFont font, string s) {
|
||||||
// resolve macros
|
// resolve macros
|
||||||
s = this.ResolveMacros(s);
|
s = this.ResolveMacros(s);
|
||||||
var tokens = new List<Token>();
|
var tokens = new List<Token>();
|
||||||
|
@ -102,7 +101,7 @@ namespace MLEM.Formatting {
|
||||||
codes.RemoveAll(c => c.EndsHere(next));
|
codes.RemoveAll(c => c.EndsHere(next));
|
||||||
codes.Add(next);
|
codes.Add(next);
|
||||||
}
|
}
|
||||||
return new TokenizedString(font, alignment, s, StripFormatting(font, s, tokens.SelectMany(t => t.AppliedCodes)), tokens.ToArray());
|
return new TokenizedString(font, s, StripFormatting(font, s, tokens.SelectMany(t => t.AppliedCodes)), tokens.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -33,10 +33,6 @@ namespace MLEM.Formatting {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DisplayString => this.ModifiedSubstring ?? this.Substring;
|
public string DisplayString => this.ModifiedSubstring ?? this.Substring;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="DisplayString"/>, but split at newline characters
|
|
||||||
/// </summary>
|
|
||||||
public string[] SplitDisplayString { get; internal set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The substring that this token contains, without the formatting codes removed.
|
/// The substring that this token contains, without the formatting codes removed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string RawSubstring;
|
public readonly string RawSubstring;
|
||||||
|
|
|
@ -38,13 +38,13 @@ namespace MLEM.Formatting {
|
||||||
public readonly Code[] AllCodes;
|
public readonly Code[] AllCodes;
|
||||||
private string modifiedString;
|
private string modifiedString;
|
||||||
|
|
||||||
internal TokenizedString(GenericFont font, TextAlignment alignment, string rawString, string strg, Token[] tokens) {
|
internal TokenizedString(GenericFont font, string rawString, string strg, Token[] tokens) {
|
||||||
this.RawString = rawString;
|
this.RawString = rawString;
|
||||||
this.String = strg;
|
this.String = strg;
|
||||||
this.Tokens = tokens;
|
this.Tokens = tokens;
|
||||||
// since a code can be present in multiple tokens, we use Distinct here
|
// since a code can be present in multiple tokens, we use Distinct here
|
||||||
this.AllCodes = tokens.SelectMany(t => t.AppliedCodes).Distinct().ToArray();
|
this.AllCodes = tokens.SelectMany(t => t.AppliedCodes).Distinct().ToArray();
|
||||||
this.RecalculateTokenData(font, alignment);
|
this.CalculateTokenAreas(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -55,11 +55,10 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="font">The font to use for width calculations</param>
|
/// <param name="font">The font to use for width calculations</param>
|
||||||
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
||||||
/// <param name="scale">The scale to use for width measurements</param>
|
/// <param name="scale">The scale to use for width measurements</param>
|
||||||
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
public void Split(GenericFont font, float width, float scale) {
|
||||||
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
|
// 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 = font.SplitString(this.String, width, scale);
|
||||||
this.StoreModifiedSubstrings(font, alignment);
|
this.StoreModifiedSubstrings(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -71,13 +70,12 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
||||||
/// <param name="scale">The scale to use for width measurements</param>
|
/// <param name="scale">The scale to use for width measurements</param>
|
||||||
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
/// <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 = "") {
|
||||||
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 = font.TruncateString(this.String, width, scale, false, ellipsis);
|
||||||
this.StoreModifiedSubstrings(font, alignment);
|
this.StoreModifiedSubstrings(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GenericFont.MeasureString(string,bool)"/>
|
/// <inheritdoc cref="GenericFont.MeasureString(string)"/>
|
||||||
public Vector2 Measure(GenericFont font) {
|
public Vector2 Measure(GenericFont font) {
|
||||||
return font.MeasureString(this.DisplayString);
|
return font.MeasureString(this.DisplayString);
|
||||||
}
|
}
|
||||||
|
@ -104,37 +102,34 @@ namespace MLEM.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GenericFont.DrawString(SpriteBatch,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
/// <inheritdoc cref="GenericFont.DrawString(SpriteBatch,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
||||||
public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth, TextAlignment alignment = TextAlignment.Left) {
|
public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||||
var innerOffset = new Vector2(this.GetInnerOffsetX(font, 0, 0, scale, alignment), 0);
|
var innerOffset = new Vector2();
|
||||||
for (var t = 0; t < this.Tokens.Length; t++) {
|
foreach (var token in this.Tokens) {
|
||||||
var token = this.Tokens[t];
|
|
||||||
var drawFont = token.GetFont(font) ?? font;
|
var drawFont = token.GetFont(font) ?? font;
|
||||||
var drawColor = token.GetColor(color) ?? color;
|
var drawColor = token.GetColor(color) ?? color;
|
||||||
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
|
for (var i = 0; i < token.DisplayString.Length; i++) {
|
||||||
var line = token.SplitDisplayString[l];
|
var c = token.DisplayString[i];
|
||||||
for (var i = 0; i < line.Length; i++) {
|
if (c == '\n') {
|
||||||
var c = line[i];
|
innerOffset.X = 0;
|
||||||
if (l == 0 && i == 0)
|
innerOffset.Y += font.LineHeight * scale;
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
token.DrawSelf(time, batch, pos + innerOffset, font, color, scale, depth);
|
token.DrawSelf(time, batch, pos + innerOffset, font, color, scale, depth);
|
||||||
|
|
||||||
var cString = c.ToCachedString();
|
var cString = c.ToCachedString();
|
||||||
token.DrawCharacter(time, batch, c, cString, i, pos + innerOffset, drawFont, drawColor, scale, depth);
|
token.DrawCharacter(time, batch, c, cString, i, pos + innerOffset, drawFont, drawColor, scale, depth);
|
||||||
innerOffset.X += font.MeasureString(cString).X * scale;
|
innerOffset.X += font.MeasureString(cString).X * scale;
|
||||||
}
|
}
|
||||||
// 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.Y += font.LineHeight * scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StoreModifiedSubstrings(GenericFont font, TextAlignment alignment) {
|
private void StoreModifiedSubstrings(GenericFont font) {
|
||||||
if (this.Tokens.Length == 1) {
|
|
||||||
// skip substring logic for unformatted text
|
// skip substring logic for unformatted text
|
||||||
|
if (this.Tokens.Length == 1) {
|
||||||
this.Tokens[0].ModifiedSubstring = this.modifiedString;
|
this.Tokens[0].ModifiedSubstring = this.modifiedString;
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// this is basically a substring function that ignores added newlines for indexing
|
// this is basically a substring function that ignores added newlines for indexing
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var currToken = 0;
|
var currToken = 0;
|
||||||
|
@ -161,59 +156,23 @@ namespace MLEM.Formatting {
|
||||||
this.Tokens[currToken++].ModifiedSubstring = ret.ToString();
|
this.Tokens[currToken++].ModifiedSubstring = ret.ToString();
|
||||||
while (currToken < this.Tokens.Length)
|
while (currToken < this.Tokens.Length)
|
||||||
this.Tokens[currToken++].ModifiedSubstring = string.Empty;
|
this.Tokens[currToken++].ModifiedSubstring = string.Empty;
|
||||||
|
|
||||||
|
this.CalculateTokenAreas(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.RecalculateTokenData(font, alignment);
|
private void CalculateTokenAreas(GenericFont font) {
|
||||||
}
|
var innerOffset = new Vector2();
|
||||||
|
foreach (var token in this.Tokens) {
|
||||||
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);
|
|
||||||
for (var t = 0; t < this.Tokens.Length; t++) {
|
|
||||||
var token = this.Tokens[t];
|
|
||||||
var area = new List<RectangleF>();
|
var area = new List<RectangleF>();
|
||||||
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
|
var split = token.DisplayString.Split('\n');
|
||||||
var size = font.MeasureString(token.SplitDisplayString[l]);
|
for (var i = 0; i < split.Length; i++) {
|
||||||
|
var size = font.MeasureString(split[i]);
|
||||||
var rect = new RectangleF(innerOffset, size);
|
var rect = new RectangleF(innerOffset, size);
|
||||||
if (!rect.IsEmpty)
|
if (!rect.IsEmpty)
|
||||||
area.Add(rect);
|
area.Add(rect);
|
||||||
|
|
||||||
if (l < token.SplitDisplayString.Length - 1) {
|
if (i < split.Length - 1) {
|
||||||
innerOffset.X = this.GetInnerOffsetX(font, t, l + 1, 1, alignment);
|
innerOffset.X = 0;
|
||||||
innerOffset.Y += font.LineHeight;
|
innerOffset.Y += font.LineHeight;
|
||||||
} else {
|
} else {
|
||||||
innerOffset.X += size.X;
|
innerOffset.X += size.X;
|
||||||
|
|
Loading…
Reference in a new issue