/// /// Class that can automatically wrap a given string. /// public class StringWrap { /// /// List of characters to break a string around. A char key points to an /// int weight. Higher weights indicate a higher preference to break at /// that character. /// public readonly Hashtable Breakable = new Hashtable(); /// /// Class that can automatically wrap a given string. /// public StringWrap() { Breakable[' '] = 10; Breakable[','] = 20; Breakable[';'] = 30; Breakable['.'] = 40; } /// /// Cleanse the given text from duplicate (two or more in a row) characters, as /// specified by Breakable. Will also remove all existing newlines. /// /// Text to be cleansed. /// Cleansed text. protected string Cleanse(string text) { text = text.Replace('\n', ' '); string find, replace; foreach(char c in Breakable.Keys) { find = new string(c, 2); replace = new string(c, 1); while(text.IndexOf(find) != -1) text = text.Replace(find, replace); } return text; } /// /// Perform an automatic wrap given text, a target ratio, and a font ratio. /// /// Text to automatically wrap. /// Ratio (Height / Width) of the target area /// for this text. /// Average ratio (Height / Width) of a single /// character. /// Automatically wrapped text. public string PerformWrap(string text, float targetRatio, float fontRatio) { string wrap = ""; text = Cleanse(text); int rows = (int) Math.Sqrt(targetRatio * text.Length / fontRatio), cols = text.Length / rows, start = cols, index = 0, last; for(int i = 0; i < rows - 1; i++) { last = index; index = BestBreak(text, start, cols * 2); wrap += text.Substring(last, index - last).Trim() + "\n"; start = index + cols; } wrap += text.Substring(index); return wrap; } /// /// Find the best place to break text given a starting index and a search radius. /// /// Full text to search through. /// Index in string to start searching at. Will be used /// as the center of the radius. /// Radius (in characters) to search around the given /// starting index. /// Optimal index to break the text at. protected int BestBreak(string text, int start, int radius) { int bestIndex = start; float bestWeight = 0, examWeight; radius = Math.Min(Math.Min(start + radius, text.Length - 1) - start, start - Math.Max(start - radius, 0)); for(int i = start - radius; i <= start + radius; i++) { object o = Breakable[text[i]]; if(o == null) continue; examWeight = (int) o / (float) Math.Abs(start - i); if(examWeight > bestWeight) { bestIndex = i; bestWeight = examWeight; } } return Math.Min(bestIndex + 1, text.Length - 1); } }