SimpleJavaEngine/src/main/java/speiger/src/coreengine/rendering/gui/components/TextPanelComponent.java

688 lines
16 KiB
Java

package speiger.src.coreengine.rendering.gui.components;
import java.util.function.Predicate;
import org.lwjgl.glfw.GLFW;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.gui.GuiComponent;
import speiger.src.coreengine.rendering.gui.base.IButtonComponent;
import speiger.src.coreengine.rendering.gui.base.IKeyComponent;
import speiger.src.coreengine.rendering.gui.helper.Align;
import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox;
import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.gui.renderer.UIRenderer;
import speiger.src.coreengine.rendering.gui.renderer.lexer.Line;
import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata;
import speiger.src.coreengine.rendering.gui.renderer.lexer.Word;
import speiger.src.coreengine.rendering.gui.renderer.lexer.WordType;
import speiger.src.coreengine.rendering.input.Keyboard;
import speiger.src.coreengine.rendering.utils.Cursor;
import speiger.src.coreengine.utils.functions.Functions;
public class TextPanelComponent extends GuiComponent implements IButtonComponent, IKeyComponent
{
public static final int FLAG_FOCUS = 1024;
public static final int FLAG_CAN_LOSE_FOCUS = 2048;
TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.LEFT_TOP).singleLine(true).special(false).cast();
int color;
int curserPosition = 0;
Vec2i curserPos = Vec2i.mutable();
int selectionPosition = 0;
Vec2i selectionPos = Vec2i.mutable();
long lastClickTime = 0;
int maxTextLength = 64;
int clickCount = 0;
Predicate<String> validator = Functions.getAlwaysTrue();
public TextPanelComponent(int color)
{
super(0F, 0F, 0F, 0F);
this.color = color;
}
public TextPanelComponent(float x, float y, float width, float height, int color)
{
super(x, y, width, height);
this.color = color;
}
@Override
public void init()
{
addChild(text, Constrains.parent(1F));
}
public TextPanelComponent setValidator(Predicate<String> validator)
{
this.validator = validator;
return this;
}
public TextPanelComponent setMaxTextLength(int charLimit)
{
maxTextLength = charLimit;
return this;
}
public TextPanelComponent setColor(int color)
{
this.color = color;
return this;
}
public TextComponent getRawText()
{
return text;
}
public String getText()
{
return text.getText();
}
public String getSelectedText()
{
return text.getText(Math.min(getCurserPosition(), getSelectionPosition()), Math.max(getCurserPosition(), getSelectionPosition()));
}
public TextPanelComponent setText(String s)
{
if(s == null)
{
return this;
}
if(validator.test(s))
{
if(s.length() > maxTextLength)
{
s = s.substring(0, maxTextLength);
}
float height = text.getBox().getHeight();
float scale = text.getTextScale();
while(s.length() > 0 && text.getFont().height(s) * scale > height)
{
s = s.substring(0, s.length() - 1);
}
text.setText(s);
}
return this;
}
@Override
protected boolean updateSelf(int mouseX, int mouseY, float particalTicks)
{
if(text.isMouseOver(mouseX, mouseY) && !text.isOverChild(mouseX, mouseY))
{
bindCursor(Cursor.CURSOR_IBEAM);
}
return true;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
float brightness = getActiveBrightness();
UIRenderer render = getRenderer();
render.setBrightness(brightness * 0.7F).drawQuad(getBox(), color).setBrightness(brightness);
IGuiBox box = text.getBox();
render.drawQuad(box, 0.001F, color);
if(isFlagSet(FLAG_FOCUS) && (getGlobalClock() / 15) % 2L == 0)
{
TextMetadata data = text.getMetadata();
float height = text.getFont().height() * text.getTextScale();
if(hasSelectedText())
{
if(selectionPos.getY() == curserPos.getY())
{
render.drawQuad(box.getMinX() + data.getWidth(Math.min(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * curserPos.getY()), box.getMinX() + data.getWidth(Math.max(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor());
}
else
{
Vec2i min = selectionPos.getY() < curserPos.getY() ? selectionPos : curserPos;
Vec2i max = selectionPos.getY() > curserPos.getY() ? selectionPos : curserPos;
for(int i = min.getY(),m=max.getY();i<=m;i++)
{
if(i == min.getY())
{
render.drawQuad(box.getMinX() + data.getWidth(min.getX()), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor());
}
else if(i == max.getY())
{
render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getWidth(max.getX()), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor());
}
else
{
render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor());
}
}
}
return true;
}
float width = data.getWidth(curserPos.getX(), curserPos.getY());
render.drawQuad(box.getMinX()+width, box.getMinY() + (height * curserPos.getY()), box.getMinX()+width+text.getTextScale(), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor());
}
return true;
}
@Override
public boolean onClick(int button, int mouseX, int mouseY)
{
setFlag(FLAG_FOCUS);
if(hasSelectedText() && clickCount <= 0)
{
setSelectionPosition(-1);
setCurserPosition(getMousePosition(mouseX, mouseY));
return true;
}
int pos = getMousePosition(mouseX, mouseY);
if(pos == getCurserPosition())
{
if(System.currentTimeMillis() - lastClickTime < 500L)
{
if(clickCount == 1)
{
Line line = text.getMetadata().getLine(curserPos.getY());
setSelectionPosition(line.getStart());
setCurserPosition(line.getEnd());
clickCount = 2;
}
else if(clickCount == 2)
{
clickCount = 3;
setSelectionPosition(0);
setCurserToEnd();
}
else
{
clickCount = 1;
handleDoubleClick(pos);
}
}
else
{
clickCount = 0;
}
lastClickTime = System.currentTimeMillis();
return true;
}
lastClickTime = System.currentTimeMillis();
setCurserPosition(pos);
setSelectionPosition(-1);
clickCount = 0;
return false;
}
@Override
public boolean onDrag(int mouseX, int mouseY)
{
if(!hasSelectedText())
{
setSelectionPosition(getCurserPosition());
}
setCurserPosition(getMousePosition(mouseX, mouseY));
return true;
}
@Override
public void onFocusLost()
{
clearFlag(FLAG_FOCUS);
}
@Override
public boolean isAcceptingInput()
{
return isFlagSet(FLAG_FOCUS);
}
@Override
public boolean isBlockingMovement()
{
return true;
}
@Override
public boolean onKeyPressed(int key)
{
if(isFlagNotSet(FLAG_FOCUS))
{
return false;
}
if(key == GLFW.GLFW_KEY_BACKSPACE)
{
if(Keyboard.isCtrlDown())
{
Word word = text.getMetadata().getWord(getCurserPosition());
if(word == null)
{
return true;
}
if(getCurserPosition() == word.getStartIndex())
{
if(word.getPrev() != null)
{
deleteAtCurser(word.getPrev().getStartIndex() - word.getStartIndex());
}
}
else
{
setCurserPosition(word.getStartIndex());
deleteAtCurser(word.getEndIndex() - word.getStartIndex());
}
return true;
}
else if(deleteAtCurser(-1))
{
return true;
}
}
else if(key == GLFW.GLFW_KEY_DELETE)
{
if(Keyboard.isCtrlDown())
{
Word word = text.getMetadata().getWord(getCurserPosition());
if(word == null)
{
return true;
}
if(getCurserPosition() == word.getEndIndex())
{
if(word.getNext() != null)
{
deleteAtCurser(word.getNext().getEndIndex() - word.getEndIndex());
}
}
else
{
setCurserPosition(word.getStartIndex());
deleteAtCurser(word.getEndIndex() - word.getStartIndex());
}
return true;
}
else if(deleteAtCurser(1))
{
return true;
}
}
else if(key == GLFW.GLFW_KEY_LEFT)
{
if(getCurserPosition() >= 0)
{
if(Keyboard.isShiftDown() && getSelectionPosition() == -1)
{
setSelectionPosition(getCurserPosition());
}
else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1)
{
setSelectionPosition(-1);
}
if(Keyboard.isCtrlDown())
{
Word word = text.getMetadata().getWord(getCurserPosition());
if(word == null)
{
return true;
}
if(word.getStartIndex() == getCurserPosition())
{
if(word.getPrev() != null)
{
setCurserPosition(word.getPrev().getStartIndex());
}
}
else
{
setCurserPosition(word.getStartIndex());
}
}
else
{
setCurserPosition(getCurserPosition()-1);
}
return true;
}
}
else if(key == GLFW.GLFW_KEY_RIGHT)
{
if(getCurserPosition() < text.length())
{
if(Keyboard.isShiftDown() && getSelectionPosition() == -1)
{
setSelectionPosition(getCurserPosition());
}
else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1)
{
setSelectionPosition(-1);
}
if(Keyboard.isCtrlDown())
{
Word word = text.getMetadata().getWord(getCurserPosition());
if(word == null)
{
return true;
}
if(word.getEndIndex() == getCurserPosition())
{
if(word.getNext() != null)
{
setCurserPosition(word.getNext().getEndIndex());
}
}
else
{
setCurserPosition(word.getEndIndex());
}
}
else
{
setCurserPosition(getCurserPosition()+1);
}
return true;
}
else
{
if(!Keyboard.isShiftDown() && hasSelectedText())
{
setSelectionPosition(-1);
}
return true;
}
}
else if(key == GLFW.GLFW_KEY_UP)
{
if(Keyboard.isShiftDown() && !hasSelectedText())
{
setSelectionPosition(getCurserPosition());
}
else if(!Keyboard.isShiftDown() && hasSelectedText())
{
setSelectionPosition(-1);
}
setCurserPosition(text.getMetadata().moveDown(curserPos));
}
else if(key == GLFW.GLFW_KEY_DOWN)
{
if(Keyboard.isShiftDown() && !hasSelectedText())
{
setSelectionPosition(getCurserPosition());
}
else if(!Keyboard.isShiftDown() && hasSelectedText())
{
setSelectionPosition(-1);
}
setCurserPosition(text.getMetadata().moveUp(curserPos));
}
else if(key == GLFW.GLFW_KEY_END)
{
if(Keyboard.isShiftDown())
{
if(!hasSelectedText())
{
setSelectionPosition(getCurserPosition());
}
}
else
{
setSelectionPosition(-1);
}
setCurserToEnd();
return true;
}
else if(key == GLFW.GLFW_KEY_HOME)
{
if(Keyboard.isShiftDown())
{
if(getSelectionPosition() == -1)
{
setSelectionPosition(getCurserPosition());
}
}
else
{
setSelectionPosition(-1);
}
setCurserPosition(0);
return true;
}
else if(key == GLFW.GLFW_KEY_TAB)
{
writeText(Character.toString('\t'));
return true;
}
else if(key == GLFW.GLFW_KEY_ENTER)
{
writeText(Character.toString('\n'));
return true;
}
else if(isSelect(key))
{
setSelectionPosition(0);
setCurserToEnd();
return true;
}
else if(isCopy(key))
{
if(hasSelectedText())
{
getWindow().setClipboardString(getSelectedText());
}
return true;
}
else if(isPaste(key))
{
String text = getWindow().getClipboardString();
if(text != null)
{
writeText(text);
}
return true;
}
else if(isCut(key))
{
if(hasSelectedText())
{
getWindow().setClipboardString(getSelectedText());
writeText("");
}
return true;
}
else if(Keyboard.isPrintableKey(key))
{
return true;
}
return false;
}
@Override
public boolean onKeyTyped(char letter, int codepoint)
{
return isFlagSet(FLAG_FOCUS) && text.getFont().isCharValid(codepoint) && writeText(new String(Character.toChars(codepoint)));
}
public boolean deleteAtCurser(int amount)
{
if(text.length() > 0)
{
if(hasSelectedText())
{
int startPos = Math.min(getCurserPosition(), getSelectionPosition());
writeText("");
setCurserPosition(startPos);
}
else
{
int startPos = Math.min(getCurserPosition(), getCurserPosition() + amount);
int endPos = Math.max(getCurserPosition(), getCurserPosition() + amount);
StringBuilder builder = new StringBuilder();
if(startPos >= 0)
{
builder.append(text.getText(0, startPos));
}
if(endPos < text.length())
{
builder.append(text.getText(endPos));
}
String s = builder.toString();
if (validator.test(s))
{
setText(s);
setCurserPosition(Math.min(startPos, text.length()));
notifyListeners(LISTENER_USER_ACTION);
}
}
return true;
}
return false;
}
public boolean writeText(String toWrite)
{
toWrite = text.getFont().clearInvalidLetters(toWrite);
StringBuilder builder = new StringBuilder();
int startPos = hasSelectedText() ? Math.min(getSelectionPosition(), getCurserPosition()) : getCurserPosition();
int endPos = hasSelectedText() ? Math.max(getSelectionPosition(), getCurserPosition()) : getCurserPosition();
int room = maxTextLength - text.length() - (startPos - endPos);
if(text.length() > 0)
{
builder.append(text.getText(0, startPos));
}
int moved = 0;
if(room < toWrite.length())
{
builder.append(toWrite.substring(0, room));
moved = room;
}
else
{
builder.append(toWrite);
moved = toWrite.length();
}
if(text.length() > 0 && endPos < text.length())
{
builder.append(text.getText(endPos));
}
String s = builder.toString();
if(validator.test(s))
{
setText(s);
setCurserPosition(Math.min(endPos + moved, text.length()));
setSelectionPosition(-1);
notifyListeners(LISTENER_USER_ACTION);
return true;
}
return false;
}
protected void handleDoubleClick(int position)
{
Word word = text.getMetadata().getWord(position);
if(word == null)
{
return;
}
if(!word.isSpecial())
{
setSelectionPosition(word.getStartIndex());
setCurserPosition(word.getEndIndex());
return;
}
WordType type = word.getType();
if(type.isStartWord())
{
Word other = type.findEndWord(word);
if(other != null)
{
setSelectionPosition(word.getStartIndex());
setCurserPosition(other.getEndIndex());
}
}
else if(type.isEndWord())
{
Word other = type.findStartWord(word);
if(other != null)
{
setSelectionPosition(other.getStartIndex());
setCurserPosition(word.getEndIndex());
}
}
else if(type.isDualWord())
{
if(word.getStartIndex() == position && word.getPrev() != null)
{
Word other = type.findStartWord(word);
if(other != null)
{
setSelectionPosition(other.getStartIndex());
setCurserPosition(word.getEndIndex());
}
}
else
{
Word other = type.findEndWord(word);
if(other != null)
{
setSelectionPosition(word.getStartIndex());
setCurserPosition(other.getEndIndex());
}
}
}
else
{
setSelectionPosition(word.getStartIndex());
setCurserPosition(word.getEndIndex());
}
}
public int getMousePosition(int mouseX, int mouseY)
{
return text.getMetadata().getIndex(mouseX - text.getBox().getMinX(), mouseY - text.getBox().getMinY());
}
public void setCurserToEnd()
{
setCurserPosition(curserPosition);
}
public void setCurserPosition(int curserPosition)
{
if(this.curserPosition == curserPosition)
{
return;
}
this.curserPosition = curserPosition;
text.getMetadata().convert(curserPosition, curserPos);
}
public int getCurserPosition()
{
return curserPosition;
}
public void setSelectionPosition(int selectionPosition)
{
if(this.selectionPosition == selectionPosition)
{
return;
}
this.selectionPosition = selectionPosition;
if(selectionPosition == -1)
{
selectionPos.set(Vec2i.MINUS_ONE);
return;
}
text.getMetadata().convert(selectionPosition, selectionPos);
}
public int getSelectionPosition()
{
return selectionPosition;
}
public boolean hasSelectedText()
{
return selectionPosition != -1;
}
}