diff --git a/assets/Scenes/defaultLevel_2/scene.ts b/assets/Scenes/defaultLevel_2/scene.ts index 0987cc14..92fc1e26 100644 --- a/assets/Scenes/defaultLevel_2/scene.ts +++ b/assets/Scenes/defaultLevel_2/scene.ts @@ -27,8 +27,8 @@ class TestScene1 extends Scene { { signal: "equipItem", callback: (entityId: number) => { - console.log("Item equipped to entity " + entityId) - engine.classes.simulation.static.setFramestep(0) + // console.log("Item equipped to entity " + entityId) + // engine.classes.simulation.static.setFramestep(0) } }, @@ -38,7 +38,7 @@ class TestScene1 extends Scene { { signal: "entityGroundMove", callback: (entityId: number, newPos: Vector) => { - console.log("Entity moved " + entityId + " to " + Vector.toString(newPos)) + // console.log("Entity moved " + entityId + " to " + Vector.toString(newPos)) } }, @@ -48,7 +48,7 @@ class TestScene1 extends Scene { { signal: "itemPickup", callback: (entityId: number, inWorldItemEntityId: number, inInventoryItemEntityId: number) => { - console.log(entityId + ' picked up an item, destroying ' + inWorldItemEntityId + ' and creating ' + inInventoryItemEntityId) + // console.log(entityId + ' picked up an item, destroying ' + inWorldItemEntityId + ' and creating ' + inInventoryItemEntityId) engine.classes.simulation.static.setFramestep(0) engine.classes.tutorialUtils.static.showTutorialHint( "BasicNavigation", diff --git a/buildNumber.properties b/buildNumber.properties index 29e3a345..480af7c6 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Sat Jul 13 22:48:57 EDT 2024 -buildNumber=185 +#Sat Jul 20 11:59:30 EDT 2024 +buildNumber=186 diff --git a/docs/src/progress/currenttarget.md b/docs/src/progress/currenttarget.md index b600109c..6bece1da 100644 --- a/docs/src/progress/currenttarget.md +++ b/docs/src/progress/currenttarget.md @@ -1,6 +1,8 @@ + spawn into the world + there is a sword lying on the ground + when you grab the sword, a tutorial popup appears to tell you how to use in + Make tutorial popup prettier + Prevent tutorial popup opening firing twice + on clearing the tutorial, continue the game+ when the sword is equipped, create another popup to teach sword controls. it pauses the game + when popup is accepted, spawn an enemy with an effect enemy ai diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 31c53f1c..cb03dba3 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -437,6 +437,11 @@ Hook manager debugging (07/20/2024) Properly drill static classes to script context Expose framestep control to script side +Show tutorial hints from script side +TextBox element (not editable yet) +Word element +Text Wrap handling +Overflow handling # TODO diff --git a/src/main/java/electrosphere/logger/Logger.java b/src/main/java/electrosphere/logger/Logger.java index a48c15a8..3905c965 100644 --- a/src/main/java/electrosphere/logger/Logger.java +++ b/src/main/java/electrosphere/logger/Logger.java @@ -28,6 +28,15 @@ public class Logger { public Logger(LogLevel level){ this.level = level; } + + /** + * Sets the logging level of this logger + * @param level The logging level + */ + public void setLevel(LogLevel level){ + this.level = level; + new Exception("Changing log level to " + level + "!").printStackTrace(); + } /** * Logs a loop debug message. diff --git a/src/main/java/electrosphere/menu/tutorial/TutorialMenus.java b/src/main/java/electrosphere/menu/tutorial/TutorialMenus.java index 8d93f31a..958459ed 100644 --- a/src/main/java/electrosphere/menu/tutorial/TutorialMenus.java +++ b/src/main/java/electrosphere/menu/tutorial/TutorialMenus.java @@ -9,6 +9,7 @@ import electrosphere.menu.WindowStrings; import electrosphere.menu.WindowUtils; import electrosphere.renderer.ui.elements.Button; import electrosphere.renderer.ui.elements.Label; +import electrosphere.renderer.ui.elements.TextBox; import electrosphere.renderer.ui.elements.Window; import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment; import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection; @@ -19,6 +20,15 @@ import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification */ public class TutorialMenus { + /** + * The width of a tutorial popup + */ + static final int TUTORIAL_POPUP_WIDTH = 500; + /** + * The height of a tutorial popup + */ + static final int TUTORIAL_POPUP_HEIGHT = 500; + @Export /** * Shows a tutorial hint @@ -35,11 +45,15 @@ public class TutorialMenus { windowEl = (Window)Globals.elementManager.getWindow(WindowStrings.TUTORIAL_POPUP); } else { //create the window - windowEl = new Window(Globals.renderingEngine.getOpenGLState(),50,50,500,500,true); + windowEl = new Window(Globals.renderingEngine.getOpenGLState(),0,0,TUTORIAL_POPUP_WIDTH,TUTORIAL_POPUP_HEIGHT,true); + //parent container windowEl.setParentAlignContent(YogaAlignment.Center); windowEl.setParentAlignItem(YogaAlignment.Center); windowEl.setParentJustifyContent(YogaJustification.Center); + //child elements arrangement windowEl.setFlexDirection(YogaFlexDirection.Column); + windowEl.setAlignItems(YogaAlignment.Center); + windowEl.setJustifyContent(YogaJustification.Between); Globals.elementManager.registerWindow(WindowStrings.TUTORIAL_POPUP, windowEl); } @@ -53,7 +67,7 @@ public class TutorialMenus { //create tutorial elements windowEl.addChild(Label.createLabel(hintDefinition.getTitleString())); - windowEl.addChild(Label.createLabel(hintDefinition.getDescriptionString())); + windowEl.addChild(TextBox.createTextBox(hintDefinition.getDescriptionString(), false)); windowEl.addChild(Button.createButton("Close", () -> { WindowUtils.recursiveSetVisible(windowEl, false); if(onClose != null){ diff --git a/src/main/java/electrosphere/renderer/ui/elements/BitmapCharacter.java b/src/main/java/electrosphere/renderer/ui/elements/BitmapCharacter.java index 78985528..31ff2b15 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/BitmapCharacter.java +++ b/src/main/java/electrosphere/renderer/ui/elements/BitmapCharacter.java @@ -40,6 +40,20 @@ public class BitmapCharacter extends StandardElement implements DrawableElement this.text = "" + toDraw; this.font = font; } + + /** + * Creates a bitmap character that will be positioned by Yoga + * @param font The font of the character + * @param toDraw The glyph to draw + */ + public BitmapCharacter(Font font, char toDraw){ + super(); + this.text = "" + toDraw; + this.font = font; + Vector3f discreteDims = this.font.getDimensionOfCharacterDiscrete(toDraw); + setMinWidth((int)discreteDims.x); + setMinHeight((int)discreteDims.y); + } public String getText() { @@ -68,10 +82,10 @@ public class BitmapCharacter extends StandardElement implements DrawableElement ){ Globals.renderingEngine.bindFramebuffer(parentFramebufferPointer); openGLState.glViewport(parentWidth, parentHeight); - float ndcX = (float)(internalPositionX + parentPosX)/parentWidth; - float ndcY = (float)(parentHeight - (internalPositionY + parentPosY))/parentHeight; - float ndcWidth = (float)internalWidth/parentWidth; - float ndcHeight = (float)internalHeight/parentHeight; + float ndcX = (float)(getInternalX() + parentPosX)/parentWidth; + float ndcY = (float)(parentHeight - (getInternalY() + parentPosY))/parentHeight; + float ndcWidth = (float)getInternalWidth()/parentWidth; + float ndcHeight = (float)getInternalHeight()/parentHeight; // float charWidth = ndcWidth/cols; // float charHeight = ndcHeight/rows; char toDraw = text.charAt(0); @@ -119,6 +133,8 @@ public class BitmapCharacter extends StandardElement implements DrawableElement //apply the values to this component this.internalPositionX = (int)leftRaw; this.internalPositionY = (int)topRaw; + this.internalWidth = (int)Yoga.YGNodeLayoutGetWidth(yogaNode); + this.internalHeight = (int)Yoga.YGNodeLayoutGetHeight(yogaNode); //calculate absolute values if(!useAbsolutePosition){ this.absoluteX = parentX + internalPositionX; diff --git a/src/main/java/electrosphere/renderer/ui/elements/StandardContainerElement.java b/src/main/java/electrosphere/renderer/ui/elements/StandardContainerElement.java index 872323fb..989319a7 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/StandardContainerElement.java +++ b/src/main/java/electrosphere/renderer/ui/elements/StandardContainerElement.java @@ -249,7 +249,7 @@ public class StandardContainerElement extends StandardElement implements Contain float widthRaw = Yoga.YGNodeLayoutGetWidth(yogaNode); float heightRaw = Yoga.YGNodeLayoutGetHeight(yogaNode); LoggerInterface.loggerUI.INFO("" + this); - LoggerInterface.loggerUI.INFO(topRaw + " " + leftRaw + " " + heightRaw + " " + widthRaw); + LoggerInterface.loggerUI.INFO("pos(" + leftRaw + "," + topRaw + ") dim(" + widthRaw + "," + heightRaw + ")"); //apply the values to this component if(!useAbsolutePosition){ this.internalPositionX = (int)leftRaw; @@ -355,6 +355,36 @@ public class StandardContainerElement extends StandardElement implements Contain } Yoga.YGNodeStyleSetAlignContent(this.yogaNode, alignmentInteger); } + + @Override + public void setWrap(YogaWrap wrap) { + switch(wrap){ + case WRAP: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapWrap); + break; + case NO_WRAP: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapNoWrap); + break; + case REVERSE: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapReverse); + break; + } + } + + @Override + public void setOverflow(YogaOverflow overflow){ + switch(overflow){ + case Visible: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowVisible); + break; + case Hidden: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowHidden); + break; + case Scroll: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowScroll); + break; + } + } diff --git a/src/main/java/electrosphere/renderer/ui/elements/StandardDrawableContainerElement.java b/src/main/java/electrosphere/renderer/ui/elements/StandardDrawableContainerElement.java new file mode 100644 index 00000000..63777715 --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/elements/StandardDrawableContainerElement.java @@ -0,0 +1,58 @@ +package electrosphere.renderer.ui.elements; + +import electrosphere.renderer.OpenGLState; +import electrosphere.renderer.RenderPipelineState; +import electrosphere.renderer.ui.elementtypes.DrawableElement; +import electrosphere.renderer.ui.elementtypes.FocusableElement; + +/** + * A container element that is also drawable + */ +public class StandardDrawableContainerElement extends StandardContainerElement implements DrawableElement, FocusableElement { + + /** + * Visibility status + */ + boolean visible = true; + + /** + * Focus status + */ + boolean isFocused = false; + + @Override + public boolean getVisible() { + return visible; + } + + @Override + public void setVisible(boolean draw) { + this.visible = draw; + } + + @Override + public void draw(RenderPipelineState renderPipelineState, OpenGLState openGLState, int parentFramebufferPointer, int parentPosX, int parentPosY, int parentWidth, int parentHeight) { + throw new UnsupportedOperationException("Unimplemented method 'draw'"); + } + + @Override + public boolean isFocused() { + return this.isFocused; + } + + @Override + public void setFocused(boolean focused) { + this.isFocused = focused; + } + + @Override + public void setOnFocus(FocusEventCallback callback) { + throw new UnsupportedOperationException("Unimplemented method 'setOnFocus'"); + } + + @Override + public void setOnLoseFocus(FocusEventCallback callback) { + throw new UnsupportedOperationException("Unimplemented method 'setOnLoseFocus'"); + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/elements/StandardElement.java b/src/main/java/electrosphere/renderer/ui/elements/StandardElement.java index cf01def3..79cce48a 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/StandardElement.java +++ b/src/main/java/electrosphere/renderer/ui/elements/StandardElement.java @@ -199,21 +199,41 @@ public class StandardElement implements Element { Yoga.YGNodeStyleSetMaxWidth(yogaNode, width); } + @Override + public void setMaxWidthPercent(float percent) { + Yoga.YGNodeStyleSetMaxWidthPercent(yogaNode, percent); + } + @Override public void setMaxHeight(int height) { Yoga.YGNodeStyleSetMaxHeight(yogaNode, height); } + @Override + public void setMaxHeightPercent(float percent) { + Yoga.YGNodeStyleSetMaxHeight(yogaNode, percent); + } + @Override public void setMinWidth(int width) { Yoga.YGNodeStyleSetMinWidth(yogaNode, width); } + @Override + public void setMinWidthPercent(float percent) { + Yoga.YGNodeStyleSetMinWidthPercent(yogaNode, percent); + } + @Override public void setMinHeight(int height) { Yoga.YGNodeStyleSetMinHeight(yogaNode, height); } + @Override + public void setMinHeightPercent(float percent) { + Yoga.YGNodeStyleSetMinHeightPercent(yogaNode, percent); + } + /** * The value of the grow property * @param grow The grow value diff --git a/src/main/java/electrosphere/renderer/ui/elements/TextBox.java b/src/main/java/electrosphere/renderer/ui/elements/TextBox.java index 01afb263..37c00c70 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/TextBox.java +++ b/src/main/java/electrosphere/renderer/ui/elements/TextBox.java @@ -1,46 +1,128 @@ package electrosphere.renderer.ui.elements; +import org.lwjgl.util.yoga.Yoga; + +import electrosphere.engine.Globals; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.ui.elementtypes.DrawableElement; +import electrosphere.renderer.ui.elementtypes.Element; import electrosphere.renderer.ui.events.Event; -import org.joml.Vector3f; +import electrosphere.renderer.ui.font.Font; -public class TextBox extends StandardContainerElement implements DrawableElement { - +/** + * A wrapping text box + */ +public class TextBox extends StandardDrawableContainerElement { + + /** + * The default percentage width of the textbox element + */ + public static final float DEFAULT_MIN_WIDTH_PERCENT = 100.0f; + + /** + * The default percentage max height of the textbox element + */ + public static final float DEFAULT_MAX_HEIGHT_PERCENT = 100.0f; + /** + * The text contained in this box + */ String text; + + /** + * The editable status of this text box + */ boolean editable; - - Vector3f scalar; - public TextBox(int positionX, int positionY, int width, int height, String text, boolean render, boolean editable) { - super(); - this.text = text; - scalar = new Vector3f(1,1,1); + /** + * The font for the textbox + */ + Font font; + + /** + * Creates a textbox element + * @param content The content to prepopulate it with + * @param editable The editable status + * @return The textbox element + */ + public static TextBox createTextBox(String content, boolean editable){ + return new TextBox(content, editable); } - public TextBox(int positionX, int positionY, int width, int height, String text, boolean render, boolean editable, Vector3f scalar) { + /** + * Constructor + * @param text The content to prepopulate it with + * @param editable The editable status + */ + private TextBox(String text, boolean editable) { super(); this.text = text; - this.scalar = scalar; + this.font = Globals.fontManager.getFont("default"); + setFlexDirection(YogaFlexDirection.Row); + setAlignItems(YogaAlignment.Start); + setJustifyContent(YogaJustification.Start); + setMinHeight((int)(font.getFontHeight() * Label.DEFAULT_FONT_SIZE)); + setMaxHeightPercent(DEFAULT_MAX_HEIGHT_PERCENT); + setMaxWidthPercent(DEFAULT_MIN_WIDTH_PERCENT); + setWrap(YogaWrap.WRAP); + setOverflow(YogaOverflow.Hidden); + generateLetters(); } + /** + * Gets the text contained in the textbox + * @return The text + */ public String getText() { return text; } + /** + * Sets the text contained in the textbox + * @param text The text + */ public void setText(String text) { this.text = text; + generateLetters(); + applyYoga(0, 0); } + /** + * Gets the editable status of the textbox + * @return True if editable, false otherwise + */ public boolean isEditable() { return editable; } + /** + * Sets the editable status of the textbox + * @param editable true to make it editable, false otherwise + */ public void setEditable(boolean editable) { this.editable = editable; } + + /** + * Generates the individual character elements + */ + void generateLetters(){ + //free children + for(Element child : childList){ + Yoga.YGNodeFree(child.getYogaNode()); + } + childList.clear(); + String[] words = text.split(" "); + for(int i = 0; i < words.length - 1; i++){ + Word word = Word.createWord(words[i]); + this.addChild(word); + BitmapCharacter space = new BitmapCharacter(this.font, ' '); + this.addChild(space); + } + Word word = Word.createWord(words[words.length - 1]); + this.addChild(word); + } @Override @@ -53,45 +135,25 @@ public class TextBox extends StandardContainerElement implements DrawableElement int parentWidth, int parentHeight ){ - throw new UnsupportedOperationException("Transparent Text box draw function not implemented yet oop"); -// float ndcX = (float)positionX/Globals.WINDOW_WIDTH; -// float ndcY = (float)positionY/Globals.WINDOW_HEIGHT; -// float ndcWidth = (float)width/Globals.WINDOW_WIDTH; -// float ndcHeight = (float)height/Globals.WINDOW_HEIGHT; -// //monowidth for the moment -// float charWidth = ndcWidth/cols; -// float charHeight = ndcHeight/rows; -// for(int y = 0; y < rows; y++){ -// for(int x = 0; x < cols; x++){ -// char toDraw = ' '; -// if(x + y * cols < text.length()){ -// toDraw = text.charAt(x + y * cols); -// } -// Vector3f characterPosition = new Vector3f(ndcX + x * charWidth,ndcY + y * charHeight,0); -// Vector3f characterDimensions = new Vector3f(charWidth,charHeight,0); -// Vector3f bitMapPosition = FontUtils.getPositionOfCharacter(toDraw); -// Vector3f bitMapDimension = FontUtils.getDimensionOfCharacter(toDraw); -// Model charModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_BITMAP_FONT); -// if(charModel != null && toDraw != ' '){ -// charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mPosition", characterPosition); -// charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mDimension", characterDimensions); -// charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "tPosition", bitMapPosition); -// charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "tDimension", bitMapDimension); -// charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "color", color); -// charModel.drawUI(); -// } -// } -// } - } - public boolean getVisible() { - return visible; - } - - public void setVisible(boolean draw) { - this.visible = draw; + //draw characters + for(Element child : childList){ + ((DrawableElement)child).draw( + renderPipelineState, + openGLState, + parentFramebufferPointer, + parentPosX + this.internalPositionX, + parentPosY + this.internalPositionY, + parentWidth, + parentHeight + ); + } } + /** + * Event handling + * @param event The event to handle + */ public boolean handleEvent(Event event){ return true; } diff --git a/src/main/java/electrosphere/renderer/ui/elements/Window.java b/src/main/java/electrosphere/renderer/ui/elements/Window.java index 53110468..504ba6d8 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/Window.java +++ b/src/main/java/electrosphere/renderer/ui/elements/Window.java @@ -216,32 +216,40 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme Yoga.YGNodeStyleSetMaxWidth(yogaNode, width); } + @Override + public void setMaxWidthPercent(float percent) { + Yoga.YGNodeStyleSetMaxWidthPercent(yogaNode, percent); + } + @Override public void setMaxHeight(int height) { Yoga.YGNodeStyleSetMaxHeight(yogaNode, height); } + @Override + public void setMaxHeightPercent(float percent) { + Yoga.YGNodeStyleSetMaxHeight(yogaNode, percent); + } + @Override public void setMinWidth(int width) { Yoga.YGNodeStyleSetMinWidth(yogaNode, width); } + @Override + public void setMinWidthPercent(float percent) { + Yoga.YGNodeStyleSetMinWidthPercent(yogaNode, percent); + } + @Override public void setMinHeight(int height) { Yoga.YGNodeStyleSetMinHeight(yogaNode, height); } - - // public void setTextureCoord(int x, int y){ - // float ndcX = (float)x/Globals.WINDOW_WIDTH; - // float ndcY = (float)y/Globals.WINDOW_HEIGHT; - // texPosition = new Vector3f(ndcX,ndcY,0); - // } - - // public void setTextureScale(int x, int y){ - // float ndcWidth = (float)x/Globals.WINDOW_WIDTH; - // float ndcHeight = (float)y/Globals.WINDOW_HEIGHT; - // texScale = new Vector3f(ndcWidth,ndcHeight,0); - // } + + @Override + public void setMinHeightPercent(float percent) { + Yoga.YGNodeStyleSetMinHeightPercent(yogaNode, percent); + } public int width = 1; public int height = 1; @@ -350,7 +358,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme Yoga.YGNodeStyleSetWidth(parentWindowYogaNode, Globals.WINDOW_WIDTH); Yoga.YGNodeStyleSetHeight(parentWindowYogaNode, Globals.WINDOW_HEIGHT); //calculate yoga layout - Yoga.YGNodeCalculateLayout(parentWindowYogaNode, width, height, Yoga.YGFlexDirectionColumn); + Yoga.YGNodeCalculateLayout(parentWindowYogaNode, width, height, Yoga.YGDirectionInherit); //get the values from yoga float leftRaw = Yoga.YGNodeLayoutGetLeft(yogaNode); float topRaw = Yoga.YGNodeLayoutGetTop(yogaNode); @@ -672,6 +680,36 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme Yoga.YGNodeStyleSetJustifyContent(this.parentWindowYogaNode, justificationInteger); } + @Override + public void setWrap(YogaWrap wrap) { + switch(wrap){ + case WRAP: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapWrap); + break; + case NO_WRAP: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapNoWrap); + break; + case REVERSE: + Yoga.YGNodeStyleSetFlexWrap(yogaNode, Yoga.YGWrapReverse); + break; + } + } + + @Override + public void setOverflow(YogaOverflow overflow){ + switch(overflow){ + case Visible: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowVisible); + break; + case Hidden: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowHidden); + break; + case Scroll: + Yoga.YGNodeStyleSetOverflow(yogaNode, Yoga.YGOverflowScroll); + break; + } + } + @Override public int getRelativeX() { return this.positionX; diff --git a/src/main/java/electrosphere/renderer/ui/elements/Word.java b/src/main/java/electrosphere/renderer/ui/elements/Word.java new file mode 100644 index 00000000..b108e66b --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/elements/Word.java @@ -0,0 +1,141 @@ +package electrosphere.renderer.ui.elements; + +import org.lwjgl.util.yoga.Yoga; + +import electrosphere.engine.Globals; +import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.OpenGLState; +import electrosphere.renderer.RenderPipelineState; +import electrosphere.renderer.ui.elementtypes.DrawableElement; +import electrosphere.renderer.ui.elementtypes.Element; +import electrosphere.renderer.ui.events.Event; +import electrosphere.renderer.ui.font.Font; + +/** + * A collection of characters into a single element for wrapping purposes + */ +public class Word extends StandardDrawableContainerElement { + + /** + * The default percentage width of the word element + */ + public static final float DEFAULT_MIN_WIDTH_PERCENT = 100.0f; + + /** + * The default percentage max height of the word element + */ + public static final float DEFAULT_MAX_HEIGHT_PERCENT = 100.0f; + + /** + * The text contained in this box + */ + String text; + + /** + * The font for the word + */ + Font font; + + /** + * Creates a word element + * @param content The characters in the word + * @return The word element + */ + public static Word createWord(String content){ + return new Word(content); + } + + /** + * Constructor + * @param text The characters in the word + */ + private Word(String text) { + super(); + this.text = text; + this.font = Globals.fontManager.getFont("default"); + setFlexDirection(YogaFlexDirection.Row); + setAlignItems(YogaAlignment.Start); + setJustifyContent(YogaJustification.Start); + setMinHeight((int)(font.getFontHeight() * Label.DEFAULT_FONT_SIZE)); + setMaxHeightPercent(DEFAULT_MAX_HEIGHT_PERCENT); + setMaxWidthPercent(DEFAULT_MIN_WIDTH_PERCENT); + setWrap(YogaWrap.NO_WRAP); + setOverflow(YogaOverflow.Hidden); + generateLetters(); + } + + /** + * Gets the text contained in the word + * @return The text + */ + public String getText() { + return text; + } + + /** + * Sets the text contained in the word + * @param text The text + */ + public void setText(String text) { + this.text = text; + generateLetters(); + applyYoga(0, 0); + } + + /** + * Generates the individual character elements + */ + void generateLetters(){ + //free children + for(Element child : childList){ + Yoga.YGNodeFree(child.getYogaNode()); + } + childList.clear(); + for(int i = 0; i < text.length(); i++){ + char toDraw = text.charAt(i); + + //error checking input data + if(toDraw == ' ' || toDraw == '\n'){ + LoggerInterface.loggerRenderer.ERROR(new IllegalStateException("Tried to create a word with a '" + toDraw + "'! This is unintended!")); + } + + BitmapCharacter newLetter = new BitmapCharacter(this.font, toDraw); + this.addChild(newLetter); + } + } + + + @Override + public void draw( + RenderPipelineState renderPipelineState, + OpenGLState openGLState, + int parentFramebufferPointer, + int parentPosX, + int parentPosY, + int parentWidth, + int parentHeight + ){ + + //draw characters + for(Element child : childList){ + ((DrawableElement)child).draw( + renderPipelineState, + openGLState, + parentFramebufferPointer, + parentPosX + this.internalPositionX, + parentPosY + this.internalPositionY, + parentWidth, + parentHeight + ); + } + } + + /** + * Event handling + * @param event The event to handle + */ + public boolean handleEvent(Event event){ + return true; + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/elementtypes/ContainerElement.java b/src/main/java/electrosphere/renderer/ui/elementtypes/ContainerElement.java index 522252dd..f3614a49 100644 --- a/src/main/java/electrosphere/renderer/ui/elementtypes/ContainerElement.java +++ b/src/main/java/electrosphere/renderer/ui/elementtypes/ContainerElement.java @@ -43,6 +43,24 @@ public interface ContainerElement extends Element { Evenly, } + /** + * Different wrap strategies + */ + public static enum YogaWrap { + WRAP, + NO_WRAP, + REVERSE, + } + + /** + * Overflow strategies + */ + public static enum YogaOverflow { + Visible, + Hidden, + Scroll, + } + /** * Add a child element to this element * @param child The child element @@ -104,5 +122,17 @@ public interface ContainerElement extends Element { * @param alignment the alignment style */ public void setAlignContent(YogaAlignment alignment); + + /** + * Sets the wrap strategy + * @param wrap The wrap strategy + */ + public void setWrap(YogaWrap wrap); + + /** + * Sets the overflow strategy + * @param overflow The overflow strategy + */ + public void setOverflow(YogaOverflow overflow); } diff --git a/src/main/java/electrosphere/renderer/ui/elementtypes/Element.java b/src/main/java/electrosphere/renderer/ui/elementtypes/Element.java index 54292902..fca9f11a 100644 --- a/src/main/java/electrosphere/renderer/ui/elementtypes/Element.java +++ b/src/main/java/electrosphere/renderer/ui/elementtypes/Element.java @@ -10,9 +10,13 @@ public interface Element { public void setWidth(int width); public void setHeight(int height); public void setMaxWidth(int width); + public void setMaxWidthPercent(float percent); public void setMaxHeight(int height); + public void setMaxHeightPercent(float percent); public void setMinWidth(int width); + public void setMinWidthPercent(float percent); public void setMinHeight(int height); + public void setMinHeightPercent(float percent); //position public int getRelativeX();