Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2018. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
using System;
using System.Collections.Generic;
namespace Leap.Unity.GraphicalRenderer {
public static class TextWrapper {
/// <summary>
/// References a contiguous sequence of characters in a string.
/// </summary>
public struct Token {
public int start;
public int end;
public int length {
get {
return end - start;
}
set {
end = start + value;
}
}
public bool IsNewline(string source) {
return source[start] == '\n';
}
public bool IsWhitespace(string source) {
return char.IsWhiteSpace(source[start]);
}
public float GetWidth(string source, Func<char, float> charWidth) {
float width = 0;
for (int i = 0; i < length; i++) {
width += charWidth(source[i + start]);
}
return width;
}
}
/// <summary>
/// References a contiguous sequence of characters in a string
/// </summary>
public struct Line {
public int start;
public int end;
public float width;
public int length {
get {
return end - start;
}
set {
end = start + value;
}
}
public void TrimEnd(string source, Func<char, float> charWidth) {
while (length > 0) {
char end = source[start + length - 1];
if (char.IsWhiteSpace(end)) {
width -= charWidth(end);
length--;
} else {
return;
}
}
}
}
/// <summary>
/// Given a string, turn it into a list of tokens. A token is either:
/// - A single whitespace character
/// - A collection of non-whitespace characters
/// This algorithm will never create more than one token from a contiguous
/// section of non-whitespace tokens.
/// </summary>
public static void Tokenize(string text, List<Token> tokens) {
int index = 0;
int textLength = text.Length;
while (true) {
while (true) {
if (index >= textLength) {
return;
}
if (!char.IsWhiteSpace(text[index])) {
break;
}
tokens.Add(new Token() {
start = index,
length = 1
});
index++;
}
Token token = new Token() {
start = index
};
index++;
while (index < textLength && !char.IsWhiteSpace(text[index])) {
index++;
}
token.length = index - token.start;
tokens.Add(token);
}
}
/// <summary>
/// Given a list of tokens, turn it into a list of lines.
/// The lines will satisfy the following properties:
/// - No line will be longer than the maxLineWidth
/// - No token will be split unless it is both
/// - the first token on a line
/// - too long to fit on the line
/// - No line will contain any newline characters
///
/// Note that width is not measured in character count, but in
/// character width provided by the given delegate
/// </summary>
public static void Wrap(string source, List<Token> tokens, List<Line> lines, Func<char, float> widthFunc, float maxLineWidth) {
if (tokens.Count == 0) {
return;
}
int tokenIndex = 0;
Token token = tokens[0];
while (true) {
if (token.IsNewline(source)) {
lines.Add(new Line() {
start = token.start,
length = 0,
width = 0
});
goto LOOP_END;
}
NEW_LINE_CONTINUE_TOKEN:
float firstTokenWidth = widthFunc(source[token.start]);
//Line starts out equal to the first character of the first token
Line line = new Line() {
start = token.start,
end = token.end,
width = firstTokenWidth
};
//Add as many of the rest of the characters of the token as we can
for (int i = token.start + 1; i < token.end; i++) {
float charWidth = widthFunc(source[i]);
//If the line gets too big, we are forced to truncate!
if (firstTokenWidth + charWidth > maxLineWidth) {
line.end = i;
line.width = firstTokenWidth;
lines.Add(line);
token.start = i;
//Start a new line with the remainder of the current token
goto NEW_LINE_CONTINUE_TOKEN;
}
firstTokenWidth += charWidth;
}
//Set line equal to the first token
line.width = firstTokenWidth;
line.length = token.length;
//Move to the next token to begin adding them to the line
tokenIndex++;
if (tokenIndex >= tokens.Count) {
//Line only contains first token, which cannot be whitespace, so we don't trim
lines.Add(line);
return;
}
token = tokens[tokenIndex];
//Fit the rest of the tokens on this line
while (true) {
//If the token is a newline, simply add the line and finish the main loop
if (token.IsNewline(source)) {
line.TrimEnd(source, widthFunc);
lines.Add(line);
break;
}
//If a non-whitespace token is too big, finish the line
float tokenWidth = token.GetWidth(source, widthFunc);
if (line.width + tokenWidth > maxLineWidth && !token.IsWhitespace(source)) {
line.TrimEnd(source, widthFunc);
lines.Add(line);
//Go start a new line with the current token
goto NEW_LINE_CONTINUE_TOKEN;
}
//Otherwise append to the line and keep trying tokens
line.length += token.length;
line.width += tokenWidth;
tokenIndex++;
if (tokenIndex >= tokens.Count) {
lines.Add(line);
return;
}
token = tokens[tokenIndex];
}
LOOP_END:
tokenIndex++;
if (tokenIndex >= tokens.Count) {
return;
}
token = tokens[tokenIndex];
}
}
}
}
743f6b6f9This file is pinned to the selected release. Download the original to open it in your design tool.