diff --git a/CHANGELOG.md b/CHANGELOG.md index 27d4456..6e0887e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ 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 diff --git a/FNA b/FNA index 46fdbd5..ab59f5f 160000 --- a/FNA +++ b/FNA @@ -1 +1 @@ -Subproject commit 46fdbd55f5da71688c5be7136456a00b7945b67c +Subproject commit ab59f5f2f6e79f3d0adc36e4f2d15fde2c77b8e0 diff --git a/FontStashSharp b/FontStashSharp index 7373710..38849f3 160000 --- a/FontStashSharp +++ b/FontStashSharp @@ -1 +1 @@ -Subproject commit 7373710db2260a5a0214c8102015b1e11425fa25 +Subproject commit 38849f3ac2887c14b8fa1c69c17468032e5233e1 diff --git a/MLEM/Formatting/TextFormatter.cs b/MLEM/Formatting/TextFormatter.cs index 67b4562..6899197 100644 --- a/MLEM/Formatting/TextFormatter.cs +++ b/MLEM/Formatting/TextFormatter.cs @@ -68,8 +68,8 @@ namespace MLEM.Formatting { /// /// 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. /// The string to tokenize - /// 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. - /// + /// The text alignment that should be used. This alignment can later be changed using . + /// The tokenized string. public TokenizedString Tokenize(GenericFont font, string s, TextAlignment alignment = TextAlignment.Left) { // resolve macros s = this.ResolveMacros(s); diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs index abb6ee6..dd437e0 100644 --- a/MLEM/Formatting/TokenizedString.cs +++ b/MLEM/Formatting/TokenizedString.cs @@ -52,7 +52,7 @@ namespace MLEM.Formatting { foreach (var code in this.AllCodes) code.Tokens = new ReadOnlyCollection(this.Tokens.Where(t => t.AppliedCodes.Contains(code)).ToList()); - this.RecalculateTokenData(font, alignment); + this.Realign(font, alignment); } /// @@ -84,6 +84,42 @@ namespace MLEM.Formatting { this.StoreModifiedSubstrings(font, alignment); } + /// + /// Realigns this tokenized string using the given . + /// If the is , trailing space characters (but not ) will be removed. + /// + /// The font to use for width calculations. + /// The text alignment that should be used for width calculations. + 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(); + 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(); + } + } + /// 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(); - 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) { diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 5d9e714..2d4c077 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -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(""), (_, _, _) => ""); formatter.Macros.Add(new Regex(""), (_, _, _) => " blue"); formatter.Macros.Add(new Regex(""), (_, _, _) => ""); - 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 text."; + const string strg = "This \nstring \nis\n split \n weirdly \n . "; //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 = "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 a test of the underlined formatting code!"; @@ -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);