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; } }