/// <summary>Creates node list object associated with the text.</summary> /// <returns></returns> public ProcessedText ProcessText(string text, float maxWidth, bool justify) { var nodeList = new TextNodeList(text); nodeList.MeasureNodes(fontData, Options); //we "crumble" words that are two long so that that can be split up var nodesToCrumble = new List<TextNode>(); foreach (TextNode node in nodeList) if (node.Length >= maxWidth && node.Type == TextNodeType.Word) nodesToCrumble.Add(node); foreach (var node in nodesToCrumble) nodeList.Crumble(node, 1); //need to measure crumbled words nodeList.MeasureNodes(fontData, Options); var processedText = new ProcessedText(); processedText.textNodeList = nodeList; processedText.maxWidth = maxWidth; processedText.justify = justify; return processedText; }
/// <summary>Measures the actual width and height of the block of text</summary> /// <param name="processedText"></param> /// <returns></returns> internal SizeF Measure(ProcessedText processedText) { float maxMeasuredWidth = 0f; float maxWidth = processedText.maxWidth; float yOffset = 0; var nodeList = processedText.textNodeList; for (TextNode node = nodeList.Head; node != null; node = node.Next) node.LengthTweak = 0f; //reset tweaks bool atLeastOneNodeCosumedOnLine = false; float length = 0f; for (TextNode node = nodeList.Head; node != null; node = node.Next) { bool newLine = false; if (node.Type == TextNodeType.LineBreak) newLine = true; else { if (SkipTrailingSpace(node, length, maxWidth) && atLeastOneNodeCosumedOnLine) { newLine = true; } else if (length + node.ModifiedLength <= maxWidth || !atLeastOneNodeCosumedOnLine) { atLeastOneNodeCosumedOnLine = true; length += node.ModifiedLength; maxMeasuredWidth = Math.Max(length, maxMeasuredWidth); } else { newLine = true; if (node.Previous != null) node = node.Previous; } } if (newLine) { yOffset += LineSpacing; length = 0f; atLeastOneNodeCosumedOnLine = false; } } return new SizeF(maxMeasuredWidth, yOffset + LineSpacing); }
//This overload allows justification, but it is quite slow.. maybe) Recomended for use only in case, when justification is necessary public void PrintText(BitmapFont font, ProcessedText processedText, float x, float y, Color4 color, float rotation = 0.0f, float scale = 1.0f, float xOrigin = 0.5f, float yOrigin = 0.5f, bool flipHorizontally = false, bool flipVertically = false) { if (font == null) throw new ArgumentException("font"); float maxMeasuredWidth = 0f; float maxWidth = processedText.maxWidth; float xOffset = 0f; float yOffset = 0f; SizeF size = font.Measure(processedText); var nodeList = processedText.textNodeList; for (TextNode node = nodeList.Head; node != null; node = node.Next) node.LengthTweak = 0f; //reset tweaks yOffset -= yOrigin * size.Height; if (processedText.justify) { font.JustifyLine(nodeList.Head, maxWidth); xOffset -= (int)(xOrigin * maxWidth); } else xOffset -= (float)Math.Ceiling(xOrigin * font.TextNodeLineLength(nodeList.Head, maxWidth)); bool atLeastOneNodeCosumedOnLine = false; float length = 0f; for (TextNode node = nodeList.Head; node != null; node = node.Next) { bool newLine = false; if (node.Type == TextNodeType.LineBreak) { newLine = true; } else { if (font.SkipTrailingSpace(node, length, maxWidth) && atLeastOneNodeCosumedOnLine) { newLine = true; } else if (length + node.ModifiedLength <= maxWidth || !atLeastOneNodeCosumedOnLine) { atLeastOneNodeCosumedOnLine = true; RenderWord(font, node, x, y, xOffset + length, yOffset, color, rotation, scale, flipHorizontally, flipVertically); length += node.ModifiedLength; maxMeasuredWidth = Math.Max(length, maxMeasuredWidth); } else { newLine = true; if (node.Previous != null) node = node.Previous; } } if (newLine) { yOffset += font.LineSpacing; xOffset = 0f; length = 0f; atLeastOneNodeCosumedOnLine = false; if (node.Next != null) { if (processedText.justify) { font.JustifyLine(node.Next, maxWidth); xOffset -= (int)(xOrigin * maxWidth); } else xOffset -= (float)Math.Ceiling(xOrigin * font.TextNodeLineLength(node.Next, maxWidth)); } } } }