mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-25 22:18:34 +01:00
added formatted string truncation to tokenized strings and ui paragraphs
This commit is contained in:
parent
e916ddb7a8
commit
d385581c25
4 changed files with 92 additions and 41 deletions
|
@ -60,6 +60,17 @@ namespace MLEM.Ui.Elements {
|
|||
this.CanBeSelected = !value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether this button's <see cref="Text"/> should be truncated if it exceeds this button's width.
|
||||
/// Defaults to false.
|
||||
/// </summary>
|
||||
public bool TruncateTextIfLong {
|
||||
get => this.Text?.TruncateIfLong ?? false;
|
||||
set {
|
||||
if (this.Text != null)
|
||||
this.Text.TruncateIfLong = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new button with the given settings
|
||||
|
@ -71,7 +82,7 @@ namespace MLEM.Ui.Elements {
|
|||
/// <param name="tooltipWidth">The width of this button's <see cref="Tooltip"/>, or 50 by default</param>
|
||||
public Button(Anchor anchor, Vector2 size, string text = null, string tooltipText = null, float tooltipWidth = 50) : base(anchor, size) {
|
||||
if (text != null) {
|
||||
this.Text = new Paragraph(Anchor.Center, 1, text, true);
|
||||
this.Text = new Paragraph(Anchor.Center, 1, text, true) {Padding = new Vector2(1)};
|
||||
this.AddChild(this.Text);
|
||||
}
|
||||
if (tooltipText != null)
|
||||
|
|
|
@ -64,6 +64,16 @@ namespace MLEM.Ui.Elements {
|
|||
/// </summary>
|
||||
public bool AutoAdjustWidth;
|
||||
/// <summary>
|
||||
/// Whether this paragraph should be truncated instead of split if the displayed <see cref="Text"/>'s width exceeds the provided width.
|
||||
/// When the string is truncated, the <see cref="Ellipsis"/> is added to its end.
|
||||
/// </summary>
|
||||
public bool TruncateIfLong;
|
||||
/// <summary>
|
||||
/// The ellipsis characters to use if <see cref="TruncateIfLong"/> is enabled and the string is truncated.
|
||||
/// If this is set to an empty string, no ellipsis will be attached to the truncated string.
|
||||
/// </summary>
|
||||
public string Ellipsis = "...";
|
||||
/// <summary>
|
||||
/// An event that gets called when this paragraph's <see cref="Text"/> is queried.
|
||||
/// Use this event for setting this paragraph's text if it changes frequently.
|
||||
/// </summary>
|
||||
|
@ -142,7 +152,14 @@ namespace MLEM.Ui.Elements {
|
|||
foreach (var link in this.TokenizedText.Tokens.Where(t => t.AppliedCodes.Any(c => c is LinkCode)))
|
||||
this.AddChild(new Link(Anchor.TopLeft, link, this.TextScale * this.TextScaleMultiplier));
|
||||
}
|
||||
this.TokenizedText.Split(this.RegularFont, size.X - this.ScaledPadding.Width, this.TextScale * this.TextScaleMultiplier * this.Scale);
|
||||
|
||||
var width = size.X - this.ScaledPadding.Width;
|
||||
var scale = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
||||
if (this.TruncateIfLong) {
|
||||
this.TokenizedText.Truncate(this.RegularFont, width, scale, this.Ellipsis);
|
||||
} else {
|
||||
this.TokenizedText.Split(this.RegularFont, width, scale);
|
||||
}
|
||||
}
|
||||
|
||||
private void QueryTextCallback() {
|
||||
|
|
|
@ -29,15 +29,15 @@ namespace MLEM.Formatting {
|
|||
/// </summary>
|
||||
public readonly string Substring;
|
||||
/// <summary>
|
||||
/// The string that is displayed by this token. If the tokenized string has been split, this string will contain the newline characters.
|
||||
/// The string that is displayed by this token. If the tokenized string has been <see cref="TokenizedString.Split"/> or <see cref="TokenizedString.Truncate"/> has been used, this string will contain the newline characters.
|
||||
/// </summary>
|
||||
public string DisplayString => this.SplitSubstring ?? this.Substring;
|
||||
public string DisplayString => this.ModifiedSubstring ?? this.Substring;
|
||||
/// <summary>
|
||||
/// The substring that this token contains, without the formatting codes removed.
|
||||
/// </summary>
|
||||
public readonly string RawSubstring;
|
||||
internal RectangleF[] Area;
|
||||
internal string SplitSubstring;
|
||||
internal string ModifiedSubstring;
|
||||
|
||||
internal Token(Code[] appliedCodes, int index, int rawIndex, string substring, string rawSubstring) {
|
||||
this.AppliedCodes = appliedCodes;
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace MLEM.Formatting {
|
|||
public readonly string String;
|
||||
/// <summary>
|
||||
/// The string that is actually displayed by this tokenized string.
|
||||
/// If this string has been <see cref="Split"/>, this string will contain the newline characters.
|
||||
/// If this string has been <see cref="Split"/> or <see cref="Truncate"/> has been used, this string will contain the newline characters.
|
||||
/// </summary>
|
||||
public string DisplayString => this.splitString ?? this.String;
|
||||
public string DisplayString => this.modifiedString ?? this.String;
|
||||
/// <summary>
|
||||
/// The tokens that this tokenized string contains.
|
||||
/// </summary>
|
||||
|
@ -36,7 +36,7 @@ namespace MLEM.Formatting {
|
|||
/// Note that, to get a formatting code for a certain token, use <see cref="Token.AppliedCodes"/>
|
||||
/// </summary>
|
||||
public readonly Code[] AllCodes;
|
||||
private string splitString;
|
||||
private string modifiedString;
|
||||
|
||||
internal TokenizedString(GenericFont font, string rawString, string strg, Token[] tokens) {
|
||||
this.RawString = rawString;
|
||||
|
@ -49,44 +49,30 @@ namespace MLEM.Formatting {
|
|||
|
||||
/// <summary>
|
||||
/// Splits this tokenized string, inserting newline characters if the width of the string is bigger than the maximum width.
|
||||
/// Note that a tokenized string can be re-split without losing any of its actual data, as this operation merely modifies the <see cref="DisplayString"/>.
|
||||
/// <seealso cref="GenericFont.SplitString"/>
|
||||
/// </summary>
|
||||
/// <param name="font">The font to use for width calculations</param>
|
||||
/// <param name="width">The maximum width</param>
|
||||
/// <param name="scale">The scale to use fr width calculations</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>
|
||||
public void Split(GenericFont font, float width, float scale) {
|
||||
// a split string has the same character count as the input string
|
||||
// but with newline characters added
|
||||
this.splitString = font.SplitString(this.String, width, scale);
|
||||
// skip splitting logic for unformatted text
|
||||
if (this.Tokens.Length == 1) {
|
||||
this.Tokens[0].SplitSubstring = this.splitString;
|
||||
return;
|
||||
}
|
||||
// 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.StoreModifiedSubstrings(font);
|
||||
}
|
||||
|
||||
// this is basically a substring function that ignores newlines for indexing
|
||||
var index = 0;
|
||||
var currToken = 0;
|
||||
var splitIndex = 0;
|
||||
var ret = new StringBuilder();
|
||||
while (splitIndex < this.splitString.Length) {
|
||||
var token = this.Tokens[currToken];
|
||||
if (token.Substring.Length > 0) {
|
||||
ret.Append(this.splitString[splitIndex]);
|
||||
// if the current char is not an added newline, we simulate length increase
|
||||
if (this.splitString[splitIndex] != '\n' || this.String[index] == '\n')
|
||||
index++;
|
||||
splitIndex++;
|
||||
}
|
||||
// move on to the next token if we reached its end
|
||||
if (index >= token.Index + token.Substring.Length) {
|
||||
token.SplitSubstring = ret.ToString();
|
||||
ret.Clear();
|
||||
currToken++;
|
||||
}
|
||||
}
|
||||
|
||||
this.CalculateTokenAreas(font);
|
||||
/// <summary>
|
||||
/// Truncates this tokenized string, removing any additional characters that exceed the length from the displayed string.
|
||||
/// Note that a tokenized string can be re-truncated without losing any of its actual data, as this operation merely modifies the <see cref="DisplayString"/>.
|
||||
/// <seealso cref="GenericFont.TruncateString"/>
|
||||
/// </summary>
|
||||
/// <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="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>
|
||||
public void Truncate(GenericFont font, float width, float scale, string ellipsis = "") {
|
||||
this.modifiedString = font.TruncateString(this.String, width, scale, false, ellipsis);
|
||||
this.StoreModifiedSubstrings(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GenericFont.MeasureString(string)"/>
|
||||
|
@ -137,6 +123,43 @@ namespace MLEM.Formatting {
|
|||
}
|
||||
}
|
||||
|
||||
private void StoreModifiedSubstrings(GenericFont font) {
|
||||
// skip substring logic for unformatted text
|
||||
if (this.Tokens.Length == 1) {
|
||||
this.Tokens[0].ModifiedSubstring = this.modifiedString;
|
||||
return;
|
||||
}
|
||||
|
||||
// this is basically a substring function that ignores added newlines for indexing
|
||||
var index = 0;
|
||||
var currToken = 0;
|
||||
var splitIndex = 0;
|
||||
var ret = new StringBuilder();
|
||||
while (splitIndex < this.modifiedString.Length) {
|
||||
var token = this.Tokens[currToken];
|
||||
if (token.Substring.Length > 0) {
|
||||
ret.Append(this.modifiedString[splitIndex]);
|
||||
// if the current char is not an added newline, we simulate length increase
|
||||
if (this.modifiedString[splitIndex] != '\n' || this.String[index] == '\n')
|
||||
index++;
|
||||
splitIndex++;
|
||||
}
|
||||
// move on to the next token if we reached its end
|
||||
if (index >= token.Index + token.Substring.Length) {
|
||||
token.ModifiedSubstring = ret.ToString();
|
||||
ret.Clear();
|
||||
currToken++;
|
||||
}
|
||||
}
|
||||
// set additional token contents beyond our string in case we truncated
|
||||
if (ret.Length > 0)
|
||||
this.Tokens[currToken - 1].ModifiedSubstring += ret.ToString();
|
||||
while (currToken < this.Tokens.Length)
|
||||
this.Tokens[currToken++].ModifiedSubstring = string.Empty;
|
||||
|
||||
this.CalculateTokenAreas(font);
|
||||
}
|
||||
|
||||
private void CalculateTokenAreas(GenericFont font) {
|
||||
var innerOffset = new Vector2();
|
||||
foreach (var token in this.Tokens) {
|
||||
|
|
Loading…
Reference in a new issue