package electrosphere.renderer.ui.elements; import org.joml.Vector3f; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.framebuffer.Framebuffer; import electrosphere.renderer.model.Material; 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.HoverableElement; import electrosphere.renderer.ui.events.ClickEvent; import electrosphere.renderer.ui.events.Event; import electrosphere.renderer.ui.events.FocusEvent; import electrosphere.renderer.ui.events.HoverEvent; import electrosphere.renderer.ui.events.MouseEvent; import electrosphere.renderer.ui.frame.UIFrameUtils; /** * A button element */ public class Button extends StandardContainerElement implements DrawableElement, FocusableElement, ClickableElement, HoverableElement { static Vector3f COLOR_DEFAULT = new Vector3f(1.0f); static float COLOR_FRAME_FOCUSED_DEFAULT = 0.1f; static float COLOR_FRAME_UNFOCUSED_DEFAULT = 0.01f; /** * Default padding applied to buttons */ static final int DEFAULT_PADDING = 10; /** * The color of the backing element */ Vector3f color = new Vector3f(COLOR_DEFAULT); /** * The color of the frame */ Vector3f frameColor = new Vector3f(COLOR_FRAME_FOCUSED_DEFAULT); /** * The color of the background of the frame */ Vector3f frameBackgroundColor = new Vector3f(COLOR_FRAME_UNFOCUSED_DEFAULT); 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(); boolean visible = false; boolean focused = false; /** * Controls whether the button draws its decorative frame or not */ boolean drawFrame = true; FocusEventCallback onFocusCallback; FocusEventCallback onLoseFocusCallback; ClickEventCallback clickCallback; HoverEventCallback hoverEventCallback; static final Vector3f windowDrawDebugColor = new Vector3f(1.0f,1.0f,1.0f); /** * Audio path played on clicking the button */ String audioPathOnClick = AssetDataStrings.UI_TONE_CONFIRM_PRIMARY; public Button(){ super(); } /** * Creates a button with * @param text * @return */ public static Button createButton(String text, ClickableElement.ClickEventCallback callback){ Button rVal = new Button(); Label rValLabel = Label.createLabel(text); rValLabel.setText(text); rVal.addChild(rValLabel); rVal.setOnClick(callback); rVal.setAlignSelf(YogaAlignment.Start); return rVal; } /** * Creates a button that fires a callback when clicked * @param text The text for the button label * @param callback The callback * @return The button */ public static Button createButton(String text, Runnable callback){ Button rVal = new Button(); rVal.setPaddingTop(DEFAULT_PADDING); rVal.setPaddingRight(DEFAULT_PADDING); rVal.setPaddingLeft(DEFAULT_PADDING); rVal.setPaddingBottom(DEFAULT_PADDING); Label rValLabel = Label.createLabel(text); rValLabel.setText(text); rVal.addChild(rValLabel); rVal.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ callback.run(); if(Globals.virtualAudioSourceManager != null && rVal.audioPathOnClick != null){ Globals.virtualAudioSourceManager.createUI(rVal.audioPathOnClick); } return false; }}); rVal.setAlignSelf(YogaAlignment.Start); return rVal; } /** * Creates a button that fires a callback when clicked * @param text The text for the button label * @param callback The callback * @return The button */ public static Button createButtonCentered(String text, Runnable callback){ Button rVal = new Button(); rVal.setPaddingTop(DEFAULT_PADDING); rVal.setPaddingRight(DEFAULT_PADDING); rVal.setPaddingLeft(DEFAULT_PADDING); rVal.setPaddingBottom(DEFAULT_PADDING); Label rValLabel = Label.createLabel(text); rValLabel.setText(text); rVal.addChild(rValLabel); rVal.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ callback.run(); if(Globals.virtualAudioSourceManager != null && rVal.audioPathOnClick != null){ Globals.virtualAudioSourceManager.createUI(rVal.audioPathOnClick); } return false; }}); rVal.setAlignSelf(YogaAlignment.Center); return rVal; } /** * Creates a button that fires a callback when clicked * @param text The text for the button label * @param fontSize The size of the font for the label * @param callback The callback * @return The button */ public static Button createButtonCentered(String text, float fontSize, Runnable callback){ Button rVal = new Button(); rVal.setPaddingTop(DEFAULT_PADDING); rVal.setPaddingRight(DEFAULT_PADDING); rVal.setPaddingLeft(DEFAULT_PADDING); rVal.setPaddingBottom(DEFAULT_PADDING); Label rValLabel = Label.createLabel(text, fontSize); rValLabel.setText(text); rVal.addChild(rValLabel); rVal.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ callback.run(); if(Globals.virtualAudioSourceManager != null && rVal.audioPathOnClick != null){ Globals.virtualAudioSourceManager.createUI(rVal.audioPathOnClick); } return false; }}); rVal.setAlignSelf(YogaAlignment.Center); return rVal; } public boolean getVisible() { return visible; } public void setVisible(boolean draw) { this.visible = draw; } @Override public boolean isFocused() { return focused; } void onFocus(FocusEvent event) { if(onFocusCallback != null){ onFocusCallback.execute(event); } else { for(Element child : childList){ if(child instanceof Label){ Label childLabel = (Label) child; childLabel.setColor(new Vector3f(1,0,0)); } } } } void onLoseFocus(FocusEvent event) { if(onLoseFocusCallback != null){ onLoseFocusCallback.execute(event); } else { for(Element child : childList){ if(child instanceof Label){ Label childLabel = (Label) child; childLabel.setColor(new Vector3f(1,1,1)); } } } } /** * Default hover event handling * @param event the hover event */ void onHoverEvent(HoverEvent event){ if(event.isHovered()){ for(Element child : childList){ if(child instanceof Label){ Label childLabel = (Label) child; childLabel.setColor(new Vector3f(1,0,0)); } } } else { for(Element child : childList){ if(child instanceof Label){ Label childLabel = (Label) child; childLabel.setColor(new Vector3f(1,1,1)); } } } } @Override public void draw( RenderPipelineState renderPipelineState, OpenGLState openGLState, Framebuffer framebuffer, int framebufferPosX, int framebufferPosY ) { // //Draw decorations float ndcWidth = (float)getWidth()/framebuffer.getWidth(); float ndcHeight = (float)getHeight()/framebuffer.getHeight(); float ndcX = (float)this.absoluteToFramebuffer(getAbsoluteX(),framebufferPosX)/framebuffer.getWidth(); float ndcY = (float)this.absoluteToFramebuffer(getAbsoluteY(),framebufferPosY)/framebuffer.getHeight(); boxPosition = new Vector3f(ndcX,ndcY,0); boxDimensions = new Vector3f(ndcWidth,ndcHeight,0); //this call binds the screen as the "texture" we're rendering to //have to call before actually rendering framebuffer.bind(openGLState); openGLState.glViewport(framebuffer.getWidth(), framebuffer.getHeight()); //render background of window if(this.drawFrame){ if(this.isFocused()){ UIFrameUtils.drawFrame( AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_3, frameColor, 48, 12, this.getAbsoluteX(), this.getAbsoluteY(), this.getWidth(), this.getHeight(), framebuffer, framebufferPosX, framebufferPosY ); } else { UIFrameUtils.drawFrame( AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_3, frameBackgroundColor, 48, 12, this.getAbsoluteX(), this.getAbsoluteY(), this.getWidth(), this.getHeight(), framebuffer, framebufferPosX, framebufferPosY ); } } // //Draw children elements for(Element child : childList){ if(child instanceof DrawableElement){ DrawableElement drawableChild = (DrawableElement) child; drawableChild.draw( renderPipelineState, openGLState, framebuffer, framebufferPosX, framebufferPosY ); } } } @Override public void setOnFocus(FocusEventCallback callback) { onFocusCallback = callback; } @Override public void setOnLoseFocus(FocusEventCallback callback) { onLoseFocusCallback = callback; } @Override public void setOnClick(ClickEventCallback callback) { clickCallback = callback; } public boolean handleEvent(Event event){ if(event instanceof MouseEvent){ return false; } if(event instanceof FocusEvent){ FocusEvent focusEvent = (FocusEvent) event; if(focusEvent.isFocused()){ this.focused = true; onFocus(focusEvent); } else { this.focused = false; onLoseFocus(focusEvent); } return false; } if(event instanceof ClickEvent){ if(clickCallback != null){ clickCallback.execute((ClickEvent)event); } } if(event instanceof HoverEvent){ if(hoverEventCallback != null){ hoverEventCallback.execute((HoverEvent)event); } else { //default hover handling onHoverEvent((HoverEvent)event); } } return true; } @Override public void setOnHoverCallback(HoverEventCallback callback) { this.hoverEventCallback = callback; } @Override public void setFocused(boolean focused) { this.focused = focused; } /** * Sets the audio path to play on click * @param audioPath The audio path */ public Button setOnClickAudio(String audioPath){ this.audioPathOnClick = audioPath; return this; } /** * Sets the background color of this element * @param color The color */ public void setColor(Vector3f color){ this.color.set(color); } /** * Sets whether the button should draw its frame or not * @param drawFrame true if it should draw its frame, false otherwise */ public void setDrawFrame(boolean drawFrame){ this.drawFrame = drawFrame; } /** * Gets whether the button should draw its frame or not * @return true if it should draw its frame, false otherwise */ public boolean getDrawFrame(){ return this.drawFrame; } }