SimpleJavaEngine/src/main/java/speiger/src/coreengine/rendering/gui/renderer/lexer/TextLexer.java

139 lines
3.5 KiB
Java

package speiger.src.coreengine.rendering.gui.renderer.lexer;
import java.util.List;
import java.util.Locale;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.rendering.gui.renderer.FontRenderer;
import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.utils.helpers.TextUtil;
public class TextLexer
{
FontRenderer render;
List<Word> helper = new ObjectArrayList<Word>();
public TextLexer(FontRenderer render)
{
this.render = render;
}
public void getWords(String text, TextContext context, List<Word> words)
{
text = render.clearInvalidLetters(text);
Word current = new Word(context.getScale());
for(int i = 0,j=0,m=text.length();i<m;i++,j++)
{
char letter = text.charAt(i);
if(letter == '§' && context.allowsSpecial() && i + 1 < m && text.charAt(i + 1) == '<')
{
String search = TextUtil.searchUntil(text, i + 2, '>', FontRenderer.INVALID_SEARCH);
if(search.length() > 0)
{
context.apply(search.toLowerCase(Locale.ROOT).split(","), j--);
i += search.length()+2;
continue;
}
}
WordType type = WordType.getByLetter(letter);
if(current.getType() != type || type != null && type.isNewLine())
{
if(!current.isEmpty())
{
words.add(current);
current = new Word(current);
}
current.setSpecail(type);
}
if(Character.isHighSurrogate(letter) && i + 1 < m)
{
char extra = text.charAt(i + 1);
if(Character.isLowSurrogate(extra))
{
i++;
current.addLetter(render.getInstance(Character.toCodePoint(letter, extra), context.isBold()));
continue;
}
}
current.addLetter(render.getInstance(letter, context.isBold()));
}
if(!current.isEmpty())
{
words.add(current);
}
}
public List<Line> evaluateLines(String text, TextContext context, float maxWidth)
{
if(text == null || text.isEmpty() || maxWidth < 10F * context.getScale())
{
return ObjectLists.empty();
}
List<Line> lines = new ObjectArrayList<>();
getWords(text, context, helper);
Line line = new Line(maxWidth);
for(int i = 0;i<helper.size();i++)
{
Word word = helper.get(i);
if(word.isNewLine())
{
line.addWord(word);
line.finishLine();
lines.add(line);
line = new Line(maxWidth);
continue;
}
if(!line.attemptAddingWord(word))
{
if(line.isEmpty() || (context.isSingle() && (word.size() != 1 || word.getWidth() < maxWidth - line.getWidth())))
{
Word removedWord = helper.remove(i--);
splitWords(i+1, removedWord, maxWidth - line.getWidth() - 1F, context.getScale());
}
else
{
line.finishLine();
lines.add(line);
line = new Line(maxWidth);
i--;
}
}
}
if(!line.isEmpty())
{
line.finishLine();
lines.add(line);
}
helper.clear();
return lines;
}
private void splitWords(int index, Word word, float maxLength, float scale)
{
Word newWord = word.getPrev() != null ? new Word(word.getPrev()) : new Word(scale);
for(CharInstance letter : word.instanceIterator())
{
float width = letter.getXAdvance() * scale;
if(width + newWord.getWidth() > maxLength)
{
helper.add(index++, newWord);
newWord = new Word(newWord);
}
newWord.addLetter(letter);
}
if(newWord.size() > 0)
{
helper.add(index++, newWord);
if(word.getNext() != null)
{
word.getNext().setPrev(newWord);
}
}
else if(word.getNext() != null)
{
word.getNext().setPrev(newWord.getPrev());
}
}
}