Renderer/src/main/java/electrosphere/renderer/ui/elements/TextInput.java
2024-07-03 14:55:24 -04:00

279 lines
9.3 KiB
Java

package electrosphere.renderer.ui.elements;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.texture.Texture;
import electrosphere.renderer.ui.elementtypes.ClickableElement;
import electrosphere.renderer.ui.elementtypes.DrawableElement;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.elementtypes.FocusableElement;
import electrosphere.renderer.ui.elementtypes.KeyEventElement;
import electrosphere.renderer.ui.events.ClickEvent;
import electrosphere.renderer.ui.events.Event;
import electrosphere.renderer.ui.events.FocusEvent;
import electrosphere.renderer.ui.events.KeyboardEvent;
import electrosphere.renderer.ui.font.Font;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL30;
import org.lwjgl.util.yoga.Yoga;
import java.util.regex.Pattern;
/**
* A Text input
*/
public class TextInput extends StandardContainerElement implements DrawableElement, FocusableElement, KeyEventElement, ClickableElement {
Vector3f boxPosition = new Vector3f();
Vector3f boxDimensions = new Vector3f();
Vector3f texPosition = new Vector3f(0,0,0);
Vector3f texScale = new Vector3f(1,1,0);
Material customMat = new Material();
public boolean visible = false;
boolean focused = false;
FocusEventCallback onFocusCallback;
FocusEventCallback onLoseFocusCallback;
KeyboardEventCallback onKeyPressCallback;
ClickEventCallback onClickCallback;
Vector3f color;
String text = "";
int textPixelWidth = 0;
float fontSize = 1.0f;
Font font;
/**
* Creates a text input element
* @param fontSize the size of the font in the text element
* @return The text input
*/
public static TextInput createTextInput(float fontSize){
return new TextInput(fontSize);
}
/**
* Private constructor
* @param fontSize
*/
private TextInput(float fontSize){
super();
this.font = Globals.fontManager.getFont("default");
this.fontSize = fontSize;
this.color = new Vector3f(1,1,1);
setHeight((int)(font.getFontHeight() * fontSize));
Yoga.YGNodeStyleSetFlexDirection(this.yogaNode, Yoga.YGFlexDirectionRow);
Yoga.YGNodeStyleSetMinHeight(this.yogaNode, font.imageHeight * fontSize);
Yoga.YGNodeStyleSetMinWidth(this.yogaNode, 1);
}
/**
* Constructor
* @param x
* @param y
* @param fontSize
*/
public TextInput(int x, int y, float fontSize){
super();
this.font = Globals.fontManager.getFont("default");
this.fontSize = fontSize;
this.color = new Vector3f(1,1,1);
setHeight((int)(font.getFontHeight() * fontSize));
Yoga.YGNodeStyleSetFlexDirection(this.yogaNode, Yoga.YGFlexDirectionRow);
Yoga.YGNodeStyleSetMinHeight(this.yogaNode, font.imageHeight * fontSize);
Yoga.YGNodeStyleSetMinWidth(this.yogaNode, 1);
}
void generateLetters(){
for(Element el : getChildren()){
Yoga.YGNodeRemoveChild(this.yogaNode,el.getYogaNode());
el.destroy();
}
childList.clear();
for(int i = 0; i < text.length(); i++){
char toDraw = text.charAt(i);
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(toDraw);
BitmapCharacter newLetter = new BitmapCharacter(this.font,(int)(bitMapDimension.x * fontSize), this.height, toDraw);
newLetter.setColor(color);
this.addChild(newLetter);
}
}
public void setText(String text){
this.text = text;
textPixelWidth = 0;
for(int i = 0; i < text.length(); i++){
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(text.charAt(i));
textPixelWidth = textPixelWidth + (int)bitMapDimension.x;
}
generateLetters();
}
public void setColor(Vector3f color){
this.color.set(color);
for(Element character : childList){
((BitmapCharacter)character).setColor(color);
}
}
public String getText(){
return text;
}
@Override
public void draw(
RenderPipelineState renderPipelineState,
OpenGLState openGLState,
int parentFramebufferPointer,
int parentPosX,
int parentPosY,
int parentWidth,
int parentHeight
) {
//
//Draw decorations
float ndcWidth = (float)getInternalWidth()/parentWidth;
float ndcHeight = (float)getInternalHeight()/parentHeight;
float ndcX = (float)(getInternalX() + parentPosX)/parentWidth;
float ndcY = (float)(getInternalY() + parentPosY)/parentHeight;
boxPosition = new Vector3f(ndcX,ndcY,0);
boxDimensions = new Vector3f(ndcWidth,ndcHeight,0);
Model planeModel = Globals.assetManager.fetchModel(Globals.imagePlaneModelID);
Texture windowFrame = null;
if(this.isFocused()){
windowFrame = Globals.assetManager.fetchTexture("Textures/ui/uiFrame2.png");
} else {
windowFrame = Globals.assetManager.fetchTexture("Textures/ui/uiFrame1.png");
}
//this call binds the screen as the "texture" we're rendering to
//have to call before actually rendering
openGLState.glBindFramebuffer(GL30.GL_FRAMEBUFFER, parentFramebufferPointer);
openGLState.glViewport(parentWidth, parentHeight);
//error if assets are null
if(planeModel == null || windowFrame == null){
LoggerInterface.loggerRenderer.ERROR("Window unable to find plane model or window frame!!", new Exception());
}
//render background of window
if(planeModel != null && windowFrame != null){
planeModel.pushUniformToMesh("plane", "mPosition", boxPosition);
planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions);
planeModel.pushUniformToMesh("plane", "tPosition", texPosition);
planeModel.pushUniformToMesh("plane", "tDimension", texScale);
customMat.setTexturePointer(windowFrame.getTexturePointer());
planeModel.getMeshes().get(0).setMaterial(customMat);
planeModel.drawUI();
}
//
//Draw children elements
for(Element child : childList){
((DrawableElement)child).draw(renderPipelineState, openGLState, parentFramebufferPointer, parentPosX + this.internalPositionX, parentPosY + this.internalPositionY, parentWidth, parentHeight);
}
}
public boolean getVisible() {
return visible;
}
public void setVisible(boolean draw) {
this.visible = draw;
}
public boolean handleEvent(Event event){
boolean propagate = true;
if(event instanceof FocusEvent){
FocusEvent focusEvent = (FocusEvent)event;
if(focusEvent.isFocused()){
if(this.onFocusCallback != null){
this.onFocusCallback.execute(focusEvent);
} else {
this.focused = true;
this.setColor(new Vector3f(1,0,0));
propagate = false;
}
} else {
if(this.onLoseFocusCallback != null){
this.onLoseFocusCallback.execute(focusEvent);
} else {
this.focused = false;
this.setColor(new Vector3f(1,1,1));
propagate = false;
}
}
} else if(event instanceof KeyboardEvent){
KeyboardEvent keyEvent = (KeyboardEvent)event;
if(onKeyPressCallback != null){
onKeyPressCallback.execute(keyEvent);
} else {
propagate = defaultKeyHandling(keyEvent);
}
} else if(event instanceof ClickEvent){
ClickEvent clickEvent = (ClickEvent)event;
if(onClickCallback != null){
onClickCallback.execute(clickEvent);
} else {
Globals.elementManager.focusElement(this);
propagate = false;
}
}
return propagate;
}
/**
* The default handling for a keyboard event
* @param keyEvent the event
* @return whether to propagate or not
*/
public boolean defaultKeyHandling(KeyboardEvent keyEvent){
if(keyEvent.getKey().matches(Pattern.quote("bs"))){
if(this.text.length() > 0){
this.setText(this.text.substring(0, this.text.length() - 1));
}
} else {
this.setText(this.text + keyEvent.getKey());
}
return false;
}
@Override
public boolean isFocused() {
return focused;
}
@Override
public void setOnFocus(FocusEventCallback callback) {
onFocusCallback = callback;
}
@Override
public void setOnLoseFocus(FocusEventCallback callback) {
onLoseFocusCallback = callback;
}
@Override
public void setOnPress(KeyboardEventCallback callback) {
onKeyPressCallback = callback;
}
@Override
public void setOnClick(ClickEventCallback callback) {
onClickCallback = callback;
}
}