/// <summary>Draw a block of text to the screen with the specified wrap width.</summary> /// <param name="batch">The sprite batch.</param> /// <param name="font">The sprite font.</param> /// <param name="text">The block of text to write.</param> /// <param name="position">The position at which to draw the text.</param> /// <param name="wrapWidth">The width at which to wrap the text.</param> /// <param name="scale">The font scale.</param> /// <returns>Returns the text dimensions.</returns> public static Vector2 DrawTextBlock(this SpriteBatch batch, SpriteFont font, IEnumerable <IFormattedText> text, Vector2 position, float wrapWidth, float scale = 1) { if (text == null) { return(new Vector2(0, 0)); } // track draw values float xOffset = 0; float yOffset = 0; float lineHeight = font.MeasureString("ABC").Y *scale; float spaceWidth = DrawHelper.GetSpaceWidth(font) * scale; float blockWidth = 0; float blockHeight = lineHeight; // draw text snippets foreach (IFormattedText snippet in text) { if (snippet?.Text == null) { continue; } // track surrounding spaces for combined translations bool startSpace = snippet.Text.StartsWith(" "); bool endSpace = snippet.Text.EndsWith(" "); // get word list IList <string> words = new List <string>(); string[] rawWords = snippet.Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0, last = rawWords.Length - 1; i <= last; i++) { // get word string word = rawWords[i]; if (startSpace && i == 0) { word = $" {word}"; } if (endSpace && i == last) { word += " "; } // split on newlines string wordPart = word; int newlineIndex; while ((newlineIndex = wordPart.IndexOf(Environment.NewLine, StringComparison.Ordinal)) >= 0) { if (newlineIndex == 0) { words.Add(Environment.NewLine); wordPart = wordPart.Substring(Environment.NewLine.Length); } else if (newlineIndex > 0) { words.Add(wordPart.Substring(0, newlineIndex)); words.Add(Environment.NewLine); wordPart = wordPart.Substring(newlineIndex + Environment.NewLine.Length); } } // add remaining word (after newline split) if (wordPart.Length > 0) { words.Add(wordPart); } } // draw words to screen bool isFirstOfLine = true; foreach (string word in words) { // check wrap width float wordWidth = font.MeasureString(word).X *scale; float prependSpace = isFirstOfLine ? 0 : spaceWidth; if (word == Environment.NewLine || ((wordWidth + xOffset + prependSpace) > wrapWidth && (int)xOffset != 0)) { xOffset = 0; yOffset += lineHeight; blockHeight += lineHeight; isFirstOfLine = true; } if (word == Environment.NewLine) { continue; } // draw text Vector2 wordPosition = new Vector2(position.X + xOffset + prependSpace, position.Y + yOffset); if (snippet.Bold) { Utility.drawBoldText(batch, word, font, wordPosition, snippet.Color ?? Color.Black, scale); } else { batch.DrawString(font, word, wordPosition, snippet.Color ?? Color.Black, 0, Vector2.Zero, scale, SpriteEffects.None, 1); } // update draw values if (xOffset + wordWidth + prependSpace > blockWidth) { blockWidth = xOffset + wordWidth + prependSpace; } xOffset += wordWidth + prependSpace; isFirstOfLine = false; } } // return text position & dimensions return(new Vector2(blockWidth, blockHeight)); }
/// <summary>Draw a block of text to the screen with the specified wrap width.</summary> /// <param name="batch">The sprite batch.</param> /// <param name="font">The sprite font.</param> /// <param name="text">The block of text to write.</param> /// <param name="position">The position at which to draw the text.</param> /// <param name="wrapWidth">The width at which to wrap the text.</param> /// <param name="scale">The font scale.</param> /// <returns>Returns the text dimensions.</returns> public static Vector2 DrawTextBlock(this SpriteBatch batch, SpriteFont font, IEnumerable <IFormattedText> text, Vector2 position, float wrapWidth, float scale = 1) { if (text == null) { return(new Vector2(0, 0)); } // track draw values float xOffset = 0; float yOffset = 0; float lineHeight = font.MeasureString("ABC").Y *scale; float spaceWidth = DrawHelper.GetSpaceWidth(font) * scale; float blockWidth = 0; float blockHeight = lineHeight; // draw text snippets foreach (IFormattedText snippet in text) { if (snippet?.Text == null) { continue; } // get word list List <string> words = new List <string>(); foreach (string word in snippet.Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) { // split on newlines string wordPart = word; int newlineIndex; while ((newlineIndex = wordPart.IndexOf(Environment.NewLine, StringComparison.InvariantCulture)) >= 0) { if (newlineIndex == 0) { words.Add(Environment.NewLine); wordPart = wordPart.Substring(Environment.NewLine.Length); } else if (newlineIndex > 0) { words.Add(wordPart.Substring(0, newlineIndex)); words.Add(Environment.NewLine); wordPart = wordPart.Substring(newlineIndex + Environment.NewLine.Length); } } // add remaining word (after newline split) if (wordPart.Length > 0) { words.Add(wordPart); } } // draw words to screen foreach (string word in words) { // check wrap width float wordWidth = font.MeasureString(word).X *scale; if (word == Environment.NewLine || ((wordWidth + xOffset) > wrapWidth && (int)xOffset != 0)) { xOffset = 0; yOffset += lineHeight; blockHeight += lineHeight; } if (word == Environment.NewLine) { continue; } // draw text Vector2 wordPosition = new Vector2(position.X + xOffset, position.Y + yOffset); if (snippet.Bold) { Utility.drawBoldText(batch, word, font, wordPosition, snippet.Color ?? Color.Black, scale); } else { batch.DrawString(font, word, wordPosition, snippet.Color ?? Color.Black, 0, Vector2.Zero, scale, SpriteEffects.None, 1); } // update draw values if (xOffset + wordWidth > blockWidth) { blockWidth = xOffset + wordWidth; } xOffset += wordWidth + spaceWidth; } } // return text position & dimensions return(new Vector2(blockWidth, blockHeight)); }