diff --git a/MLEM.Ui/Elements/Button.cs b/MLEM.Ui/Elements/Button.cs
index aeea6ad..18c5871 100644
--- a/MLEM.Ui/Elements/Button.cs
+++ b/MLEM.Ui/Elements/Button.cs
@@ -60,6 +60,17 @@ namespace MLEM.Ui.Elements {
this.CanBeSelected = !value;
}
}
+ ///
+ /// Whether this button's should be truncated if it exceeds this button's width.
+ /// Defaults to false.
+ ///
+ public bool TruncateTextIfLong {
+ get => this.Text?.TruncateIfLong ?? false;
+ set {
+ if (this.Text != null)
+ this.Text.TruncateIfLong = value;
+ }
+ }
///
/// Creates a new button with the given settings
@@ -71,7 +82,7 @@ namespace MLEM.Ui.Elements {
/// The width of this button's , or 50 by default
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)
diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs
index ac2aba5..479fcd0 100644
--- a/MLEM.Ui/Elements/Paragraph.cs
+++ b/MLEM.Ui/Elements/Paragraph.cs
@@ -64,6 +64,16 @@ namespace MLEM.Ui.Elements {
///
public bool AutoAdjustWidth;
///
+ /// Whether this paragraph should be truncated instead of split if the displayed 's width exceeds the provided width.
+ /// When the string is truncated, the is added to its end.
+ ///
+ public bool TruncateIfLong;
+ ///
+ /// The ellipsis characters to use if is enabled and the string is truncated.
+ /// If this is set to an empty string, no ellipsis will be attached to the truncated string.
+ ///
+ public string Ellipsis = "...";
+ ///
/// An event that gets called when this paragraph's is queried.
/// Use this event for setting this paragraph's text if it changes frequently.
///
@@ -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() {
diff --git a/MLEM/Formatting/Token.cs b/MLEM/Formatting/Token.cs
index c35ec50..c51d956 100644
--- a/MLEM/Formatting/Token.cs
+++ b/MLEM/Formatting/Token.cs
@@ -29,15 +29,15 @@ namespace MLEM.Formatting {
///
public readonly string Substring;
///
- /// 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 or has been used, this string will contain the newline characters.
///
- public string DisplayString => this.SplitSubstring ?? this.Substring;
+ public string DisplayString => this.ModifiedSubstring ?? this.Substring;
///
/// The substring that this token contains, without the formatting codes removed.
///
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;
diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs
index 473b194..b016f01 100644
--- a/MLEM/Formatting/TokenizedString.cs
+++ b/MLEM/Formatting/TokenizedString.cs
@@ -24,9 +24,9 @@ namespace MLEM.Formatting {
public readonly string String;
///
/// The string that is actually displayed by this tokenized string.
- /// If this string has been , this string will contain the newline characters.
+ /// If this string has been or has been used, this string will contain the newline characters.
///
- public string DisplayString => this.splitString ?? this.String;
+ public string DisplayString => this.modifiedString ?? this.String;
///
/// The tokens that this tokenized string contains.
///
@@ -36,7 +36,7 @@ namespace MLEM.Formatting {
/// Note that, to get a formatting code for a certain token, use
///
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 {
///
/// 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 .
///
///
/// The font to use for width calculations
- /// The maximum width
- /// The scale to use fr width calculations
+ /// The maximum width, in display pixels based on the font and scale
+ /// The scale to use for width measurements
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);
+ ///
+ /// 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 .
+ ///
+ ///
+ /// The font to use for width calculations
+ /// The maximum width, in display pixels based on the font and scale
+ /// The scale to use for width measurements
+ /// The characters to add to the end of the string if it is too long
+ public void Truncate(GenericFont font, float width, float scale, string ellipsis = "") {
+ this.modifiedString = font.TruncateString(this.String, width, scale, false, ellipsis);
+ this.StoreModifiedSubstrings(font);
}
///
@@ -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) {