diff --git a/Wobble/Graphics/Sprites/Text/SpriteTextPlus.cs b/Wobble/Graphics/Sprites/Text/SpriteTextPlus.cs index 9905597f..a1ec2dd4 100644 --- a/Wobble/Graphics/Sprites/Text/SpriteTextPlus.cs +++ b/Wobble/Graphics/Sprites/Text/SpriteTextPlus.cs @@ -5,6 +5,7 @@ using Microsoft.Xna.Framework; using SpriteFontPlus; using Wobble.Graphics.Animations; +using Wobble.Helpers; namespace Wobble.Graphics.Sprites.Text { @@ -193,7 +194,7 @@ private void RefreshText() // which aren't supported yet anyway), but C# doesn't have a built-in method // for binary search by an arbitrary predicate. So I guess we'll just go with a regular find-last, // which can be slower, but has a bonus of not making any of the aforementioned assumptions. - var splitOnIndex = spaces.FindLastIndex(spacePosition => + var splitOnIndex = spaces.LastTrue(spacePosition => { var lineBeforeSpace = line.Substring(0, spacePosition); var sprite = new SpriteTextPlusLine(Font, lineBeforeSpace, FontSize); @@ -219,23 +220,24 @@ private void RefreshText() if (spaces.Count > 0) lastIndex = spaces[0]; - for (var i = lastIndex; i != 0; i--) + nextLineStart = new ListHelper.Iota(0, lastIndex).LastTrue(i => { - var lineCut = line.Substring(0, i); - var sprite = new SpriteTextPlusLine(Font, lineCut, FontSize); + var testLineCut = line.Substring(0, i); + var testSprite = new SpriteTextPlusLine(Font, testLineCut, FontSize); // If we're left with 1 character, just go with it even if we're over MaxWidth. - if (sprite.Width > MaxWidth && i > 1) + if (testSprite.Width > MaxWidth && i > 1) { - sprite.Destroy(); - continue; + testSprite.Destroy(); + return false; } + return true; + }); - lineSprite.Destroy(); - lineSprite = sprite; - nextLineStart = i; - break; - } + var lineCut = line.Substring(0, nextLineStart.Value); + var sprite = new SpriteTextPlusLine(Font, lineCut, FontSize); + lineSprite.Destroy(); + lineSprite = sprite; } else { diff --git a/Wobble/Helpers/ListHelper.cs b/Wobble/Helpers/ListHelper.cs new file mode 100644 index 00000000..3256dc05 --- /dev/null +++ b/Wobble/Helpers/ListHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Wobble.Helpers +{ + public static class ListHelper + { + public static int LastTrue(this IReadOnlyList list, Func f, int lo = 0, int hi = -1) + { + if (hi == -1) + hi = list.Count - 1; + + // if none of the values in the range work, return lo - 1 + lo--; + while (lo < hi) + { + // find the middle of the current range (rounding up) + var mid = lo + (hi - lo + 1) / 2; + if (f(list[mid])) + { + // if mid works, then all numbers smaller than mid also work + lo = mid; + } + else + { + // if mid does not work, greater values would not work either + hi = mid - 1; + } + } + + return lo; + } + + public class Iota : IReadOnlyList + { + public Iota(int start, int end) + { + Start = start; + End = end; + } + + public int Start { get; } + public int End { get; } + + public IEnumerator GetEnumerator() + { + for (var i = Start; i <= End; i++) + { + yield return i; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int Count => End - Start + 1; + + public int this[int index] => Start + index; + } + } +} \ No newline at end of file