mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-29 15:58:33 +01:00
Compare commits
3 commits
73abfb2dc3
...
f5ff96d348
Author | SHA1 | Date | |
---|---|---|---|
f5ff96d348 | |||
ee62554fee | |||
f8567cfc99 |
2 changed files with 58 additions and 49 deletions
|
@ -68,6 +68,7 @@ Improvements
|
||||||
- Ensure paragraphs display up-to-date versions of their text callbacks
|
- Ensure paragraphs display up-to-date versions of their text callbacks
|
||||||
- Set cornflower blue as the default link color
|
- Set cornflower blue as the default link color
|
||||||
- Added TextField.OnCopyPasteException to allow handling exceptions thrown by TextCopy
|
- Added TextField.OnCopyPasteException to allow handling exceptions thrown by TextCopy
|
||||||
|
- Avoid paragraphs splitting or truncating their text unnecessarily
|
||||||
|
|
||||||
Fixes
|
Fixes
|
||||||
- Fixed parents of elements that prevent spill not being notified properly
|
- Fixed parents of elements that prevent spill not being notified properly
|
||||||
|
|
|
@ -32,7 +32,13 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tokenized version of the <see cref="Text"/>
|
/// The tokenized version of the <see cref="Text"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TokenizedString TokenizedText { get; private set; }
|
public TokenizedString TokenizedText {
|
||||||
|
get {
|
||||||
|
this.CheckTextChange();
|
||||||
|
this.TokenizeIfNecessary();
|
||||||
|
return this.tokenizedText;
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The color that the text will be rendered with
|
/// The color that the text will be rendered with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -53,14 +59,10 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Text {
|
public string Text {
|
||||||
get {
|
get {
|
||||||
var ret = this.GetTextCallback?.Invoke(this) ?? this.text;
|
this.CheckTextChange();
|
||||||
this.CheckTextChange(ret);
|
return this.displayedText;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
this.text = value;
|
|
||||||
this.CheckTextChange(value);
|
|
||||||
}
|
}
|
||||||
|
set => this.explicitlySetText = value;
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this paragraph should automatically adjust its width based on the width of the text within it
|
/// If this paragraph should automatically adjust its width based on the width of the text within it
|
||||||
|
@ -100,10 +102,13 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool IsHidden => base.IsHidden || string.IsNullOrWhiteSpace(this.Text);
|
public override bool IsHidden => base.IsHidden || string.IsNullOrWhiteSpace(this.Text);
|
||||||
|
|
||||||
private string text;
|
private string displayedText;
|
||||||
private string lastText;
|
private string explicitlySetText;
|
||||||
private StyleProp<TextAlignment> alignment;
|
private StyleProp<TextAlignment> alignment;
|
||||||
private StyleProp<GenericFont> regularFont;
|
private StyleProp<GenericFont> regularFont;
|
||||||
|
private TokenizedString tokenizedText;
|
||||||
|
private float? lastAlignSplitWidth;
|
||||||
|
private float? lastAlignSplitScale;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new paragraph with the given settings.
|
/// Creates a new paragraph with the given settings.
|
||||||
|
@ -127,16 +132,16 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Vector2 CalcActualSize(RectangleF parentArea) {
|
protected override Vector2 CalcActualSize(RectangleF parentArea) {
|
||||||
var size = base.CalcActualSize(parentArea);
|
var size = base.CalcActualSize(parentArea);
|
||||||
this.ParseText(size);
|
this.TokenizeIfNecessary();
|
||||||
var textSize = this.TokenizedText.GetArea(Vector2.Zero, this.TextScale * this.TextScaleMultiplier * this.Scale).Size;
|
this.AlignAndSplitIfNecessary(size);
|
||||||
|
var textSize = this.tokenizedText.GetArea(Vector2.Zero, this.TextScale * this.TextScaleMultiplier * this.Scale).Size;
|
||||||
return new Vector2(this.AutoAdjustWidth ? textSize.X + this.ScaledPadding.Width : size.X, textSize.Y + this.ScaledPadding.Height);
|
return new Vector2(this.AutoAdjustWidth ? textSize.X + this.ScaledPadding.Width : size.X, textSize.Y + this.ScaledPadding.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(GameTime time) {
|
public override void Update(GameTime time) {
|
||||||
base.Update(time);
|
base.Update(time);
|
||||||
if (this.TokenizedText != null)
|
this.TokenizedText?.Update(time);
|
||||||
this.TokenizedText.Update(time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -157,47 +162,19 @@ namespace MLEM.Ui.Elements {
|
||||||
this.Alignment = this.Alignment.OrStyle(style.TextAlignment);
|
this.Alignment = this.Alignment.OrStyle(style.TextAlignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void SetTextDirty() {
|
||||||
/// Parses this paragraph's <see cref="Text"/> into <see cref="TokenizedText"/>.
|
this.tokenizedText = null;
|
||||||
/// Additionally, this method adds any <see cref="Link"/> elements for tokenized links in the text.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="size">The paragraph's default size</param>
|
|
||||||
protected virtual void ParseText(Vector2 size) {
|
|
||||||
if (this.TokenizedText == null) {
|
|
||||||
// tokenize the text
|
|
||||||
this.TokenizedText = this.System.TextFormatter.Tokenize(this.RegularFont, this.Text, this.Alignment);
|
|
||||||
|
|
||||||
// add links to the paragraph
|
|
||||||
this.RemoveChildren(c => c is Link);
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
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, this.Alignment);
|
|
||||||
} else {
|
|
||||||
this.TokenizedText.Split(this.RegularFont, width, scale, this.Alignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A helper method that causes the <see cref="TokenizedText"/> to be reset.
|
|
||||||
/// Additionally, <see cref="Element.SetAreaDirty"/> if this paragraph's area has changed enough to warrant it, or if it has any <see cref="Link"/> children.
|
|
||||||
/// </summary>
|
|
||||||
protected void SetTextDirty() {
|
|
||||||
this.TokenizedText = null;
|
|
||||||
// only set our area dirty if our size changed as a result of this action
|
// only set our area dirty if our size changed as a result of this action
|
||||||
if (!this.AreaDirty && !this.CalcActualSize(this.ParentArea).Equals(this.DisplayArea.Size, Element.Epsilon))
|
if (!this.AreaDirty && !this.CalcActualSize(this.ParentArea).Equals(this.DisplayArea.Size, Element.Epsilon))
|
||||||
this.SetAreaDirty();
|
this.SetAreaDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckTextChange(string newText) {
|
private void CheckTextChange() {
|
||||||
if (this.lastText == newText)
|
var newText = this.GetTextCallback?.Invoke(this) ?? this.explicitlySetText;
|
||||||
|
if (this.displayedText == newText)
|
||||||
return;
|
return;
|
||||||
var emptyChanged = string.IsNullOrWhiteSpace(this.lastText) != string.IsNullOrWhiteSpace(newText);
|
var emptyChanged = string.IsNullOrWhiteSpace(this.displayedText) != string.IsNullOrWhiteSpace(newText);
|
||||||
this.lastText = newText;
|
this.displayedText = newText;
|
||||||
if (emptyChanged)
|
if (emptyChanged)
|
||||||
this.SetAreaDirty();
|
this.SetAreaDirty();
|
||||||
this.SetTextDirty();
|
this.SetTextDirty();
|
||||||
|
@ -213,6 +190,37 @@ namespace MLEM.Ui.Elements {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TokenizeIfNecessary() {
|
||||||
|
if (this.tokenizedText != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// tokenize the text
|
||||||
|
this.tokenizedText = this.System.TextFormatter.Tokenize(this.RegularFont, this.Text, this.Alignment);
|
||||||
|
this.lastAlignSplitWidth = null;
|
||||||
|
this.lastAlignSplitScale = null;
|
||||||
|
|
||||||
|
// add links to the paragraph
|
||||||
|
this.RemoveChildren(c => c is Link);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AlignAndSplitIfNecessary(Vector2 size) {
|
||||||
|
var width = size.X - this.ScaledPadding.Width;
|
||||||
|
var scale = this.TextScale * this.TextScaleMultiplier * this.Scale;
|
||||||
|
|
||||||
|
if (this.lastAlignSplitWidth == width && this.lastAlignSplitScale == scale)
|
||||||
|
return;
|
||||||
|
this.lastAlignSplitWidth = width;
|
||||||
|
this.lastAlignSplitScale = scale;
|
||||||
|
|
||||||
|
if (this.TruncateIfLong) {
|
||||||
|
this.tokenizedText.Truncate(this.RegularFont, width, scale, this.Ellipsis, this.Alignment);
|
||||||
|
} else {
|
||||||
|
this.tokenizedText.Split(this.RegularFont, width, scale, this.Alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate method used for <see cref="Paragraph.GetTextCallback"/>
|
/// A delegate method used for <see cref="Paragraph.GetTextCallback"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue