Renderer/src/main/java/electrosphere/renderer/ui/elements/Button.java
austin 183a8ce901
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
panel work
2025-04-01 21:02:40 -04:00

386 lines
12 KiB
Java

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