Tanoda
TextWrapper.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using System;
10using System.Collections.Generic;
11
13
14 public static class TextWrapper {
15
19 public struct Token {
20 public int start;
21 public int end;
22
23 public int length {
24 get {
25 return end - start;
26 }
27 set {
28 end = start + value;
29 }
30 }
31
32 public bool IsNewline(string source) {
33 return source[start] == '\n';
34 }
35
36 public bool IsWhitespace(string source) {
37 return char.IsWhiteSpace(source[start]);
38 }
39
40 public float GetWidth(string source, Func<char, float> charWidth) {
41 float width = 0;
42 for (int i = 0; i < length; i++) {
43 width += charWidth(source[i + start]);
44 }
45 return width;
46 }
47 }
48
52 public struct Line {
53 public int start;
54 public int end;
55 public float width;
56
57 public int length {
58 get {
59 return end - start;
60 }
61 set {
62 end = start + value;
63 }
64 }
65
66 public void TrimEnd(string source, Func<char, float> charWidth) {
67 while (length > 0) {
68 char end = source[start + length - 1];
69 if (char.IsWhiteSpace(end)) {
70 width -= charWidth(end);
71 length--;
72 } else {
73 return;
74 }
75 }
76 }
77 }
78
86 public static void Tokenize(string text, List<Token> tokens) {
87 int index = 0;
88 int textLength = text.Length;
89
90 while (true) {
91 while (true) {
92 if (index >= textLength) {
93 return;
94 }
95
96 if (!char.IsWhiteSpace(text[index])) {
97 break;
98 }
99
100 tokens.Add(new Token() {
101 start = index,
102 length = 1
103 });
104
105 index++;
106 }
107
108 Token token = new Token() {
109 start = index
110 };
111
112 index++;
113 while (index < textLength && !char.IsWhiteSpace(text[index])) {
114 index++;
115 }
116
117 token.length = index - token.start;
118 tokens.Add(token);
119 }
120 }
121
134 public static void Wrap(string source, List<Token> tokens, List<Line> lines, Func<char, float> widthFunc, float maxLineWidth) {
135 if (tokens.Count == 0) {
136 return;
137 }
138
139 int tokenIndex = 0;
140 Token token = tokens[0];
141
142 while (true) {
143 if (token.IsNewline(source)) {
144 lines.Add(new Line() {
145 start = token.start,
146 length = 0,
147 width = 0
148 });
149
150 goto LOOP_END;
151 }
152
153 NEW_LINE_CONTINUE_TOKEN:
154
155 float firstTokenWidth = widthFunc(source[token.start]);
156
157 //Line starts out equal to the first character of the first token
158 Line line = new Line() {
159 start = token.start,
160 end = token.end,
161 width = firstTokenWidth
162 };
163
164 //Add as many of the rest of the characters of the token as we can
165 for (int i = token.start + 1; i < token.end; i++) {
166 float charWidth = widthFunc(source[i]);
167
168 //If the line gets too big, we are forced to truncate!
169 if (firstTokenWidth + charWidth > maxLineWidth) {
170 line.end = i;
171 line.width = firstTokenWidth;
172 lines.Add(line);
173
174 token.start = i;
175
176 //Start a new line with the remainder of the current token
177 goto NEW_LINE_CONTINUE_TOKEN;
178 }
179
180 firstTokenWidth += charWidth;
181 }
182
183 //Set line equal to the first token
184 line.width = firstTokenWidth;
185 line.length = token.length;
186
187 //Move to the next token to begin adding them to the line
188 tokenIndex++;
189 if (tokenIndex >= tokens.Count) {
190 //Line only contains first token, which cannot be whitespace, so we don't trim
191 lines.Add(line);
192 return;
193 }
194 token = tokens[tokenIndex];
195
196 //Fit the rest of the tokens on this line
197 while (true) {
198 //If the token is a newline, simply add the line and finish the main loop
199 if (token.IsNewline(source)) {
200 line.TrimEnd(source, widthFunc);
201 lines.Add(line);
202 break;
203 }
204
205 //If a non-whitespace token is too big, finish the line
206 float tokenWidth = token.GetWidth(source, widthFunc);
207 if (line.width + tokenWidth > maxLineWidth && !token.IsWhitespace(source)) {
208 line.TrimEnd(source, widthFunc);
209 lines.Add(line);
210
211 //Go start a new line with the current token
212 goto NEW_LINE_CONTINUE_TOKEN;
213 }
214
215 //Otherwise append to the line and keep trying tokens
216 line.length += token.length;
217 line.width += tokenWidth;
218
219 tokenIndex++;
220 if (tokenIndex >= tokens.Count) {
221 lines.Add(line);
222 return;
223 }
224 token = tokens[tokenIndex];
225 }
226
227 LOOP_END:
228
229 tokenIndex++;
230 if (tokenIndex >= tokens.Count) {
231 return;
232 }
233 token = tokens[tokenIndex];
234 }
235 }
236 }
237}
References a contiguous sequence of characters in a string
Definition: TextWrapper.cs:52
void TrimEnd(string source, Func< char, float > charWidth)
Definition: TextWrapper.cs:66
References a contiguous sequence of characters in a string.
Definition: TextWrapper.cs:19
float GetWidth(string source, Func< char, float > charWidth)
Definition: TextWrapper.cs:40