1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-25 22:18:34 +01:00

Allow specifying start and end indices when drawing a TokenizedString or Paragraph

This commit is contained in:
Ell 2023-05-18 21:41:36 +02:00
parent a45a6adabd
commit a1064984ec
4 changed files with 44 additions and 11 deletions

View file

@ -22,6 +22,7 @@ Improvements
- Increased TextFormatter macro recursion limit to 64 - Increased TextFormatter macro recursion limit to 64
- Allow changing the default values used by default TextFormatter codes - Allow changing the default values used by default TextFormatter codes
- Allow setting ExternalGestureHandling through the InputHandler constructor - Allow setting ExternalGestureHandling through the InputHandler constructor
- Allow specifying start and end indices when drawing a TokenizedString
Fixes Fixes
- Fixed control characters being included in TextInput - Fixed control characters being included in TextInput
@ -40,6 +41,7 @@ Additions
Improvements Improvements
- Increased Element area calculation recursion limit to 64 - Increased Element area calculation recursion limit to 64
- Improved the SquishingGroup algorithm by prioritizing each element's final size - Improved the SquishingGroup algorithm by prioritizing each element's final size
- Allow specifying start and end indices when drawing a Paragraph
Fixes Fixes
- Fixed images not updating their hidden state properly when the displayed texture changes - Fixed images not updating their hidden state properly when the displayed texture changes

View file

@ -34,6 +34,8 @@ namespace Demos {
return TextFormattingDemo.DefaultScale * Math.Min(viewport.Width / 1280F, viewport.Height / 720F); return TextFormattingDemo.DefaultScale * Math.Min(viewport.Width / 1280F, viewport.Height / 720F);
} }
} }
private int startIndex;
private int endIndex;
public TextFormattingDemo(MlemGame game) : base(game) {} public TextFormattingDemo(MlemGame game) : base(game) {}
@ -60,6 +62,7 @@ namespace Demos {
// we specify our text alignment here too, so that all data is cached correctly for display // we specify our text alignment here too, so that all data is cached correctly for display
this.tokenizedText = this.formatter.Tokenize(this.font, TextFormattingDemo.Text, TextAlignment.Center); this.tokenizedText = this.formatter.Tokenize(this.font, TextFormattingDemo.Text, TextAlignment.Center);
this.tokenizedText.Split(this.font, this.GraphicsDevice.Viewport.Width * TextFormattingDemo.WidthMultiplier, this.Scale, TextAlignment.Center); this.tokenizedText.Split(this.font, this.GraphicsDevice.Viewport.Width * TextFormattingDemo.WidthMultiplier, this.Scale, TextAlignment.Center);
this.endIndex = this.tokenizedText.String.Length;
} }
public override void DoDraw(GameTime time) { public override void DoDraw(GameTime time) {
@ -81,8 +84,8 @@ namespace Demos {
} }
} }
// draw the text itself // draw the text itself (start and end indices are optional)
this.tokenizedText.Draw(time, this.SpriteBatch, pos, this.font, Color.White, this.Scale, 0); this.tokenizedText.Draw(time, this.SpriteBatch, pos, this.font, Color.White, this.Scale, 0, this.startIndex, this.endIndex);
this.SpriteBatch.End(); this.SpriteBatch.End();
} }
@ -90,8 +93,18 @@ namespace Demos {
public override void Update(GameTime time) { public override void Update(GameTime time) {
// update our tokenized string to animate the animation codes // update our tokenized string to animate the animation codes
this.tokenizedText.Update(time); this.tokenizedText.Update(time);
// change some demo showcase info based on keybinds
if (this.InputHandler.IsPressed(Keys.B)) if (this.InputHandler.IsPressed(Keys.B))
this.drawBounds = !this.drawBounds; this.drawBounds = !this.drawBounds;
if (this.startIndex > 0 && this.InputHandler.IsDown(Keys.Left))
this.startIndex--;
if (this.startIndex < this.tokenizedText.String.Length && this.InputHandler.IsDown(Keys.Right))
this.startIndex++;
if (this.endIndex > 0 && this.InputHandler.IsDown(Keys.Down))
this.endIndex--;
if (this.endIndex < this.tokenizedText.String.Length && this.InputHandler.IsDown(Keys.Up))
this.endIndex++;
} }
public override void Clear() { public override void Clear() {

View file

@ -139,6 +139,16 @@ namespace MLEM.Ui.Elements {
this.SetTextDirty(); this.SetTextDirty();
} }
} }
/// <summary>
/// The inclusive index in this paragraph's <see cref="Text"/> to start drawing at.
/// This value is passed to <see cref="TokenizedString.Draw"/>.
/// </summary>
public int? DrawStartIndex;
/// <summary>
/// The exclusive index in this paragraph's <see cref="Text"/> to stop drawing at.
/// This value is passed to <see cref="TokenizedString.Draw"/>.
/// </summary>
public int? DrawEndIndex;
/// <inheritdoc /> /// <inheritdoc />
public override bool IsHidden => base.IsHidden || string.IsNullOrWhiteSpace(this.Text); public override bool IsHidden => base.IsHidden || string.IsNullOrWhiteSpace(this.Text);
@ -206,7 +216,7 @@ namespace MLEM.Ui.Elements {
var pos = this.DisplayArea.Location + new Vector2(this.GetAlignmentOffset(), 0); var pos = this.DisplayArea.Location + new Vector2(this.GetAlignmentOffset(), 0);
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.TokenizedText.Draw(time, batch, pos, this.RegularFont, color, sc, 0, this.DrawStartIndex, this.DrawEndIndex);
base.Draw(time, batch, alpha, context); base.Draw(time, batch, alpha, context);
} }

View file

@ -189,29 +189,37 @@ 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) { public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth, int? startIndex = null, int? endIndex = null) {
var innerOffset = new Vector2(this.initialInnerOffset * scale, 0); var innerOffset = new Vector2(this.initialInnerOffset * scale, 0);
for (var t = 0; t < this.Tokens.Length; t++) { for (var t = 0; t < this.Tokens.Length; t++) {
var token = this.Tokens[t]; var token = this.Tokens[t];
if (endIndex != null && token.Index >= endIndex)
return;
var drawFont = token.GetFont(font); var drawFont = token.GetFont(font);
var drawColor = token.GetColor(color); var drawColor = token.GetColor(color);
if (startIndex == null || token.Index >= startIndex)
token.DrawSelf(time, batch, pos + innerOffset, drawFont, drawColor, scale, depth); token.DrawSelf(time, batch, pos + innerOffset, drawFont, drawColor, scale, depth);
innerOffset.X += token.GetSelfWidth(drawFont) * scale; innerOffset.X += token.GetSelfWidth(drawFont) * scale;
var indexInToken = 0; var indexInToken = 0;
for (var l = 0; l < token.SplitDisplayString.Length; l++) { for (var l = 0; l < token.SplitDisplayString.Length; l++) {
var charIndex = 0; var cpsIndex = 0;
var line = new CodePointSource(token.SplitDisplayString[l]); var line = new CodePointSource(token.SplitDisplayString[l]);
while (charIndex < line.Length) { while (cpsIndex < line.Length) {
var (codePoint, length) = line.GetCodePoint(charIndex); if (endIndex != null && token.Index + indexInToken >= endIndex)
return;
var (codePoint, length) = line.GetCodePoint(cpsIndex);
var character = CodePointSource.ToString(codePoint); var character = CodePointSource.ToString(codePoint);
if (startIndex == null || token.Index + indexInToken >= startIndex)
token.DrawCharacter(time, batch, codePoint, character, indexInToken, pos + innerOffset, drawFont, drawColor, scale, depth); token.DrawCharacter(time, batch, codePoint, character, indexInToken, pos + innerOffset, drawFont, drawColor, scale, depth);
innerOffset.X += drawFont.MeasureString(character).X * scale; innerOffset.X += drawFont.MeasureString(character).X * scale;
charIndex += length; indexInToken += length;
indexInToken++; cpsIndex += length;
} }
// only split at a new line, not between tokens! // only split at a new line, not between tokens!