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

Compare commits

...

4 commits

7 changed files with 65 additions and 55 deletions

View file

@ -12,10 +12,17 @@ Jump to version:
## 6.1.0
### MLEM
Additions
- Added TokenizedString.Realign
Improvements
- Improved EnumHelper.GetValues signature to return an array
- Allow using external gesture handling alongside InputHandler through ExternalGestureHandling
Fixes
- Fixed TokenizedString handling trailing spaces incorrectly in the last line of non-left aligned text
- Fixed some TokenizedString tokens starting with a line break not being split correctly
### MLEM.Ui
Additions
- Added some extension methods for querying Anchor types

View file

@ -2,7 +2,8 @@
"metadata": [{
"src": [{
"src": "../",
"files": ["**/MLEM**.csproj"]
"files": ["**/MLEM**.csproj"],
"exclude": ["**.FNA.**"]
}],
"dest": "api"
}],

2
FNA

@ -1 +1 @@
Subproject commit 46fdbd55f5da71688c5be7136456a00b7945b67c
Subproject commit ab59f5f2f6e79f3d0adc36e4f2d15fde2c77b8e0

@ -1 +1 @@
Subproject commit 7373710db2260a5a0214c8102015b1e11425fa25
Subproject commit 38849f3ac2887c14b8fa1c69c17468032e5233e1

View file

@ -68,8 +68,8 @@ namespace MLEM.Formatting {
/// </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="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>
/// <param name="alignment">The text alignment that should be used. This alignment can later be changed using <see cref="TokenizedString.Realign"/>.</param>
/// <returns>The tokenized string.</returns>
public TokenizedString Tokenize(GenericFont font, string s, TextAlignment alignment = TextAlignment.Left) {
// resolve macros
s = this.ResolveMacros(s);

View file

@ -52,7 +52,7 @@ namespace MLEM.Formatting {
foreach (var code in this.AllCodes)
code.Tokens = new ReadOnlyCollection<Token>(this.Tokens.Where(t => t.AppliedCodes.Contains(code)).ToList());
this.RecalculateTokenData(font, alignment);
this.Realign(font, alignment);
}
/// <summary>
@ -84,6 +84,42 @@ namespace MLEM.Formatting {
this.StoreModifiedSubstrings(font, alignment);
}
/// <summary>
/// Realigns this tokenized string using the given <see cref="TextAlignment"/>.
/// If the <paramref name="alignment"/> is <see cref="TextAlignment.Right"/>, trailing space characters (but not <see cref="GenericFont.Nbsp"/>) will be removed.
/// </summary>
/// <param name="font">The font to use for width calculations.</param>
/// <param name="alignment">The text alignment that should be used for width calculations.</param>
public void Realign(GenericFont font, TextAlignment alignment) {
// split display strings
foreach (var token in this.Tokens)
token.SplitDisplayString = token.DisplayString.Split('\n');
// token areas and inner offsets
this.initialInnerOffset = this.GetInnerOffsetX(font, 0, 0, alignment);
var innerOffset = new Vector2(this.initialInnerOffset, 0);
for (var t = 0; t < this.Tokens.Length; t++) {
var token = this.Tokens[t];
var tokenFont = token.GetFont(font);
token.InnerOffsets = new float[token.SplitDisplayString.Length - 1];
var area = new List<RectangleF>();
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
var size = tokenFont.MeasureString(token.SplitDisplayString[l]);
var rect = new RectangleF(innerOffset, size);
if (!rect.IsEmpty)
area.Add(rect);
if (l < token.SplitDisplayString.Length - 1) {
innerOffset.X = token.InnerOffsets[l] = this.GetInnerOffsetX(font, t, l + 1, alignment);
innerOffset.Y += font.LineHeight;
} else {
innerOffset.X += size.X;
}
}
token.Area = area.ToArray();
}
}
/// <inheritdoc cref="GenericFont.MeasureString(string,bool)"/>
public Vector2 Measure(GenericFont font) {
return font.MeasureString(new CharSource(this.DisplayString), false, i => this.GetFontForIndex(font, i));
@ -179,37 +215,7 @@ namespace MLEM.Formatting {
this.Tokens[currToken++].ModifiedSubstring = string.Empty;
}
this.RecalculateTokenData(font, alignment);
}
private void RecalculateTokenData(GenericFont font, TextAlignment alignment) {
// split display strings
foreach (var token in this.Tokens)
token.SplitDisplayString = token.DisplayString.Split('\n');
// token areas and inner offsets
this.initialInnerOffset = this.GetInnerOffsetX(font, 0, 0, alignment);
var innerOffset = new Vector2(this.initialInnerOffset, 0);
for (var t = 0; t < this.Tokens.Length; t++) {
var token = this.Tokens[t];
var tokenFont = token.GetFont(font);
token.InnerOffsets = new float[token.SplitDisplayString.Length - 1];
var area = new List<RectangleF>();
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
var size = tokenFont.MeasureString(token.SplitDisplayString[l]);
var rect = new RectangleF(innerOffset, size);
if (!rect.IsEmpty)
area.Add(rect);
if (l < token.SplitDisplayString.Length - 1) {
innerOffset.X = token.InnerOffsets[l] = this.GetInnerOffsetX(font, t, l + 1, alignment);
innerOffset.Y += font.LineHeight;
} else {
innerOffset.X += size.X;
}
}
token.Area = area.ToArray();
}
this.Realign(font, alignment);
}
private float GetInnerOffsetX(GenericFont defaultFont, int tokenIndex, int lineIndex, TextAlignment alignment) {
@ -217,22 +223,16 @@ namespace MLEM.Formatting {
var token = this.Tokens[tokenIndex];
var tokenFont = token.GetFont(defaultFont);
// if we're the last line in our line array, then we don't contain a line split, so the line ends in a later token
var endsLater = lineIndex >= token.SplitDisplayString.Length - 1;
var endsLater = lineIndex >= token.SplitDisplayString.Length - 1 && tokenIndex < this.Tokens.Length - 1;
// if the line ends in our token, we should ignore trailing white space
var restOfLine = tokenFont.MeasureString(token.SplitDisplayString[lineIndex], !endsLater).X;
if (endsLater) {
for (var i = tokenIndex + 1; i < this.Tokens.Length; i++) {
var other = this.Tokens[i];
var otherFont = other.GetFont(defaultFont);
if (other.SplitDisplayString.Length > 1) {
// the line ends in this token (so we also ignore trailing whitespaces)
restOfLine += otherFont.MeasureString(other.SplitDisplayString[0], true).X;
restOfLine += other.GetFont(defaultFont).MeasureString(other.SplitDisplayString[0], true).X;
// if the token's split display string has multiple lines, then the line ends in it, which means we can stop
if (other.SplitDisplayString.Length > 1)
break;
} else {
// the line doesn't end in this token (or it's the last token), so add it fully
var lastToken = i >= this.Tokens.Length - 1;
restOfLine += otherFont.MeasureString(other.DisplayString, lastToken).X;
}
}
}
if (alignment == TextAlignment.Center)

View file

@ -136,13 +136,13 @@ public class GameImpl : MlemGame {
this.SpriteBatch.End();
};*/
var sc = 4;
var sc = 2;
var formatter = new TextFormatter();
formatter.AddImage("Test", new TextureRegion(tex, 0, 8, 24, 24));
formatter.Macros.Add(new Regex("<testmacro>"), (_, _, _) => "<test1>");
formatter.Macros.Add(new Regex("<test1>"), (_, _, _) => "<test2> blue");
formatter.Macros.Add(new Regex("<test2>"), (_, _, _) => "<c Blue>");
var strg = "This text uses a bunch of non-breaking~spaces to see if macros work. Additionally, it uses a macro that resolves into a bunch of other macros and then, at the end, into <testmacro> text</c>.";
const string strg = "This \nstring \nis\n split \n weirdly \n . ";
//var strg = "Lorem Ipsum <i Test> is simply dummy text of the <i Test> printing and typesetting <i Test> industry. Lorem Ipsum has been the industry's standard dummy text <i Test> ever since the <i Test> 1500s, when <i Test><i Test><i Test><i Test><i Test><i Test><i Test> an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
//var strg = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
//var strg = "This is <u>a test of the underlined formatting code</u>!";
@ -159,7 +159,7 @@ public class GameImpl : MlemGame {
foreach (var r in atlas.Regions)
Console.WriteLine(r.Name + ": " + r.U + " " + r.V + " " + r.Width + " " + r.Height + " " + r.PivotPixels);
this.OnDraw += (_, _) => {
this.OnDraw += (_, time) => {
this.SpriteBatch.Begin(samplerState: SamplerState.PointClamp);
//this.SpriteBatch.Draw(square, new Rectangle(10, 10, 400, 400), Color.White);
//this.SpriteBatch.Draw(round, new Rectangle(10, 10, 400, 400), Color.White);
@ -169,14 +169,16 @@ public class GameImpl : MlemGame {
//this.SpriteBatch.FillRectangle(new RectangleF(400, 20, 400, 1000), Color.Green);
//font.DrawString(this.SpriteBatch, this.tokenized.DisplayString, new Vector2(400, 20), Color.White * 0.25F, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
//this.tokenized.Draw(time, this.SpriteBatch, new Vector2(400, 20), font, Color.White, sc, 0);
this.tokenized.Draw(time, this.SpriteBatch, new Vector2(200, 20), font, Color.White, sc, 0);
//this.SpriteBatch.DrawGrid(new Vector2(30, 30), new Vector2(40, 60), new Point(10, 5), Color.Yellow, 3);
this.SpriteBatch.End();
};
var alignment = TextAlignment.Left;
this.OnUpdate += (_, time) => {
if (this.InputHandler.IsPressed(Keys.W)) {
alignment = alignment == TextAlignment.Left ? TextAlignment.Right : TextAlignment.Left;
this.tokenized = formatter.Tokenize(font, strg);
this.tokenized.Split(font, this.InputHandler.IsModifierKeyDown(ModifierKey.Shift) ? 400 : 500, sc);
this.tokenized.Realign(font, alignment);
}
this.tokenized.Update(time);
};
@ -278,13 +280,13 @@ public class GameImpl : MlemGame {
}
}
this.SpriteBatch.Begin();
/*this.SpriteBatch.Begin();
if (MlemGame.Input.IsKeyDown(Keys.LeftShift)) {
this.SpriteBatch.DrawString(regularFont, testString, pos, Color.Red, rotation, origin, scale, effects, 0);
} else {
genericFont.DrawString(this.SpriteBatch, testString, pos, Color.Green, rotation, origin, scale, effects, 0);
}
this.SpriteBatch.End();
this.SpriteBatch.End();*/
};
/*var viewport = new BoxingViewportAdapter(this.Window, this.GraphicsDevice, 1280, 720);