This commit is contained in:
2026-06-25 15:33:17 -05:00
parent 8faf881399
commit a9e33660cb
22 changed files with 563 additions and 398 deletions
+4 -6
View File
@@ -4,16 +4,14 @@
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
add_subdirectory(debug) add_subdirectory(debug)
add_subdirectory(uifocus) add_subdirectory(frame)
add_subdirectory(focus)
add_subdirectory(overlay)
# Sources # Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME} target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
ui.c ui.c
uicrop.c
uielement.c uielement.c
uiframe.c # uitextbox.c
uifullbox.c
uiloading.c
uitextbox.c
) )
+10
View File
@@ -0,0 +1,10 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
uiframe.c
uisettings.c
)
@@ -1,43 +1,76 @@
// Copyright (c) 2026 Dominic Masters /**
// * Copyright (c) 2026 Dominic Masters
// This software is released under the MIT License. *
// https://opensource.org/licenses/MIT * This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "uiframe.h" #include "uiframe.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include "display/texture/texture.h"
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
#include "display/shader/shaderunlit.h" #include "display/shader/shaderunlit.h"
#include "display/color.h" #include "display/color.h"
errorret_t uiFrameInit(uiframe_t *frame) { uiframe_t UI_FRAME;
assertNotNull(frame, "frame must not be NULL");
memoryZero(frame, sizeof(uiframe_t)); errorret_t uiFrameInit(void) {
memoryZero(&UI_FRAME, sizeof(uiframe_t));
// Init texture.
color_t border = color4b(0, 100, 220, 200);
color_t center = color4b(0, 100, 220, 50);
for(uint8_t y = 0; y < UIFRAME_DUMMY_HEIGHT; y++) {
for(uint8_t x = 0; x < UIFRAME_DUMMY_WIDTH; x++) {
color_t c;
if(x >= 12 || y >= 12) {
c = COLOR_TRANSPARENT;
} else if(y < 4 || y >= 8 || x < 4 || x >= 8) {
c = border;
} else {
c = center;
}
UI_FRAME.pixels[y * UIFRAME_DUMMY_WIDTH + x] = c;
}
}
errorChain(textureInit(
&UI_FRAME.texture, UIFRAME_DUMMY_WIDTH, UIFRAME_DUMMY_HEIGHT,
TEXTURE_FORMAT_RGBA,
(texturedata_t){ .rgbaColors = UI_FRAME.pixels }
));
UI_FRAME.tileset.tileWidth = 4;
UI_FRAME.tileset.tileHeight = 4;
UI_FRAME.tileset.columns = 3;
UI_FRAME.tileset.rows = 3;
UI_FRAME.tileset.tileCount = 9;
UI_FRAME.tileset.uv[0] = 4.0f / UIFRAME_DUMMY_WIDTH;
UI_FRAME.tileset.uv[1] = 4.0f / UIFRAME_DUMMY_HEIGHT;
errorOk(); errorOk();
} }
errorret_t uiFrameDraw( errorret_t uiFrameDraw(
const uiframe_t *frame,
const float_t x, const float_t x,
const float_t y, const float_t y,
const float_t width, const float_t width,
const float_t height const float_t height
) { ) {
assertNotNull(frame, "frame must not be NULL");
assertNotNull(frame->texture, "frame texture must not be NULL");
shadermaterial_t material = { shadermaterial_t material = {
.unlit = { .unlit = {
.color = COLOR_WHITE, .color = COLOR_WHITE,
.texture = frame->texture .texture = &UI_FRAME.texture
} }
}; };
spritebatchsprite_t sprites[9]; spritebatchsprite_t sprites[9];
float_t tileW = (float_t)frame->tileset.tileWidth; float_t tileW = (float_t)UI_FRAME.tileset.tileWidth;
float_t tileH = (float_t)frame->tileset.tileHeight; float_t tileH = (float_t)UI_FRAME.tileset.tileHeight;
vec4 uv; vec4 uv;
tilesetPositionGetUV(&frame->tileset, 0, 0, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 0, 0, uv);
sprites[0].min[0] = x; sprites[0].min[0] = x;
sprites[0].min[1] = y; sprites[0].min[1] = y;
sprites[0].min[2] = 0.0f; sprites[0].min[2] = 0.0f;
@@ -49,7 +82,7 @@ errorret_t uiFrameDraw(
sprites[0].uvMax[0] = uv[2]; sprites[0].uvMax[0] = uv[2];
sprites[0].uvMax[1] = uv[3]; sprites[0].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 1, 0, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 1, 0, uv);
sprites[1].min[0] = x + tileW; sprites[1].min[0] = x + tileW;
sprites[1].min[1] = y; sprites[1].min[1] = y;
sprites[1].min[2] = 0.0f; sprites[1].min[2] = 0.0f;
@@ -61,7 +94,7 @@ errorret_t uiFrameDraw(
sprites[1].uvMax[0] = uv[2]; sprites[1].uvMax[0] = uv[2];
sprites[1].uvMax[1] = uv[3]; sprites[1].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 2, 0, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 2, 0, uv);
sprites[2].min[0] = x + width - tileW; sprites[2].min[0] = x + width - tileW;
sprites[2].min[1] = y; sprites[2].min[1] = y;
sprites[2].min[2] = 0.0f; sprites[2].min[2] = 0.0f;
@@ -73,7 +106,7 @@ errorret_t uiFrameDraw(
sprites[2].uvMax[0] = uv[2]; sprites[2].uvMax[0] = uv[2];
sprites[2].uvMax[1] = uv[3]; sprites[2].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 0, 1, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 0, 1, uv);
sprites[3].min[0] = x; sprites[3].min[0] = x;
sprites[3].min[1] = y + tileH; sprites[3].min[1] = y + tileH;
sprites[3].min[2] = 0.0f; sprites[3].min[2] = 0.0f;
@@ -85,7 +118,7 @@ errorret_t uiFrameDraw(
sprites[3].uvMax[0] = uv[2]; sprites[3].uvMax[0] = uv[2];
sprites[3].uvMax[1] = uv[3]; sprites[3].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 1, 1, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 1, 1, uv);
sprites[4].min[0] = x + tileW; sprites[4].min[0] = x + tileW;
sprites[4].min[1] = y + tileH; sprites[4].min[1] = y + tileH;
sprites[4].min[2] = 0.0f; sprites[4].min[2] = 0.0f;
@@ -97,7 +130,7 @@ errorret_t uiFrameDraw(
sprites[4].uvMax[0] = uv[2]; sprites[4].uvMax[0] = uv[2];
sprites[4].uvMax[1] = uv[3]; sprites[4].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 2, 1, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 2, 1, uv);
sprites[5].min[0] = x + width - tileW; sprites[5].min[0] = x + width - tileW;
sprites[5].min[1] = y + tileH; sprites[5].min[1] = y + tileH;
sprites[5].min[2] = 0.0f; sprites[5].min[2] = 0.0f;
@@ -109,7 +142,7 @@ errorret_t uiFrameDraw(
sprites[5].uvMax[0] = uv[2]; sprites[5].uvMax[0] = uv[2];
sprites[5].uvMax[1] = uv[3]; sprites[5].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 0, 2, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 0, 2, uv);
sprites[6].min[0] = x; sprites[6].min[0] = x;
sprites[6].min[1] = y + height - tileH; sprites[6].min[1] = y + height - tileH;
sprites[6].min[2] = 0.0f; sprites[6].min[2] = 0.0f;
@@ -121,7 +154,7 @@ errorret_t uiFrameDraw(
sprites[6].uvMax[0] = uv[2]; sprites[6].uvMax[0] = uv[2];
sprites[6].uvMax[1] = uv[3]; sprites[6].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 1, 2, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 1, 2, uv);
sprites[7].min[0] = x + tileW; sprites[7].min[0] = x + tileW;
sprites[7].min[1] = y + height - tileH; sprites[7].min[1] = y + height - tileH;
sprites[7].min[2] = 0.0f; sprites[7].min[2] = 0.0f;
@@ -133,7 +166,7 @@ errorret_t uiFrameDraw(
sprites[7].uvMax[0] = uv[2]; sprites[7].uvMax[0] = uv[2];
sprites[7].uvMax[1] = uv[3]; sprites[7].uvMax[1] = uv[3];
tilesetPositionGetUV(&frame->tileset, 2, 2, uv); tilesetPositionGetUV(&UI_FRAME.tileset, 2, 2, uv);
sprites[8].min[0] = x + width - tileW; sprites[8].min[0] = x + width - tileW;
sprites[8].min[1] = y + height - tileH; sprites[8].min[1] = y + height - tileH;
sprites[8].min[2] = 0.0f; sprites[8].min[2] = 0.0f;
@@ -148,7 +181,6 @@ errorret_t uiFrameDraw(
return spriteBatchBuffer(sprites, 9, &SHADER_UNLIT, material); return spriteBatchBuffer(sprites, 9, &SHADER_UNLIT, material);
} }
void uiFrameDispose(uiframe_t *frame) { errorret_t uiFrameDispose(void) {
assertNotNull(frame, "frame must not be NULL"); return textureDispose(&UI_FRAME.texture);
frame->texture = NULL;
} }
@@ -10,24 +10,29 @@
#include "display/texture/texture.h" #include "display/texture/texture.h"
#include "display/texture/tileset.h" #include "display/texture/tileset.h"
#define UIFRAME_DUMMY_WIDTH 16
#define UIFRAME_DUMMY_HEIGHT 16
typedef struct { typedef struct {
tileset_t tileset; tileset_t tileset;
texture_t *texture; texture_t texture;
color_t pixels[UIFRAME_DUMMY_WIDTH * UIFRAME_DUMMY_HEIGHT];
} uiframe_t; } uiframe_t;
/** extern uiframe_t UI_FRAME;
* Initializes a UI frame element.
*
* @param frame The frame to initialize.
* @return Any error that occurs.
*/
errorret_t uiFrameInit(uiframe_t *frame);
/** /**
* Draws a UI frame using 9-slice rendering from a 3x3 tileset. * Initializes the global UI_FRAME: builds the dummy texture and
* configures the tileset. Call once after displayInit().
*
* @return Any error that occurs.
*/
errorret_t uiFrameInit(void);
/**
* Draws UI_FRAME using 9-slice rendering from its 3x3 tileset.
* Pushes quads to the sprite batch without flushing. * Pushes quads to the sprite batch without flushing.
* *
* @param frame The frame to draw.
* @param x Screen x position. * @param x Screen x position.
* @param y Screen y position. * @param y Screen y position.
* @param width Total width of the frame. * @param width Total width of the frame.
@@ -35,7 +40,6 @@ errorret_t uiFrameInit(uiframe_t *frame);
* @return Any error that occurs. * @return Any error that occurs.
*/ */
errorret_t uiFrameDraw( errorret_t uiFrameDraw(
const uiframe_t *frame,
const float_t x, const float_t x,
const float_t y, const float_t y,
const float_t width, const float_t width,
@@ -43,8 +47,8 @@ errorret_t uiFrameDraw(
); );
/** /**
* Disposes of a UI frame element. Does not dispose the texture. * Disposes of the global UI_FRAME, releasing its GPU texture.
* *
* @param frame The frame to dispose. * @return Any error that occurs.
*/ */
void uiFrameDispose(uiframe_t *frame); errorret_t uiFrameDispose(void);
+34
View File
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "uisettings.h"
#include "ui/frame/uiframe.h"
#include "util/memory.h"
uisettings_t UI_SETTINGS;
errorret_t uiSettingsInit(void) {
memoryZero(&UI_SETTINGS, sizeof(uisettings_t));
errorOk();
}
errorret_t uiSettingsUpdate(void) {
// if(!UI_SETTINGS.visible) errorOk();
errorOk();
}
errorret_t uiSettingsDraw(void) {
// if(!UI_SETTINGS.visible) errorOk();
errorChain(uiFrameDraw(
100.0f, 100.0f, 1.0f, 1.0f
));
errorOk();
}
errorret_t uiSettingsDispose(void) {
errorOk();
}
+43
View File
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
typedef struct {
bool_t visible;
} uisettings_t;
extern uisettings_t UI_SETTINGS;
/**
* Initializes the settings panel.
*
* @return Any error that occurs.
*/
errorret_t uiSettingsInit(void);
/**
* Updates the settings panel. Handles input when visible.
*
* @return Any error that occurs.
*/
errorret_t uiSettingsUpdate(void);
/**
* Draws the settings panel. No-op when not visible.
*
* @return Any error that occurs.
*/
errorret_t uiSettingsDraw(void);
/**
* Disposes of the settings panel.
*
* @return Any error that occurs.
*/
errorret_t uiSettingsDispose(void);
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
uicrop.c
uifullbox.c
uiloading.c
)
@@ -12,7 +12,7 @@
#include "display/text/text.h" #include "display/text/text.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
#include "ui/uifullbox.h" #include "uifullbox.h"
#define UI_LOADING_TEXT "loading" #define UI_LOADING_TEXT "loading"
+5 -5
View File
@@ -11,7 +11,7 @@
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "ui/uielement.h" #include "ui/uielement.h"
#include "ui/uifocus/uifocus.h" #include "ui/focus/uifocus.h"
#include "log/log.h" #include "log/log.h"
ui_t UI; ui_t UI;
@@ -21,7 +21,7 @@ errorret_t uiInit(void) {
uiFocusInit(); uiFocusInit();
uielement_t *element = &UI_ELEMENTS[0]; uielement_t *element = &UI_ELEMENTS[0];
while(element->draw != NULL) { while(!uiElementIsNull(element)) {
errorChain(uiElementInit(element)); errorChain(uiElementInit(element));
element++; element++;
} }
@@ -33,7 +33,7 @@ errorret_t uiUpdate(void) {
uiFocusUpdate(); uiFocusUpdate();
uielement_t *element = &UI_ELEMENTS[0]; uielement_t *element = &UI_ELEMENTS[0];
while(element->draw != NULL) { while(!uiElementIsNull(element)) {
errorChain(uiElementUpdate(element)); errorChain(uiElementUpdate(element));
element++; element++;
} }
@@ -43,7 +43,7 @@ errorret_t uiUpdate(void) {
errorret_t uiRender(void) { errorret_t uiRender(void) {
const uielement_t *element = &UI_ELEMENTS[0]; const uielement_t *element = &UI_ELEMENTS[0];
while(element->draw != NULL) { while(!uiElementIsNull(element)) {
errorChain(uiElementDraw(element)); errorChain(uiElementDraw(element));
if(SPRITEBATCH.spriteCount > 0) { if(SPRITEBATCH.spriteCount > 0) {
@@ -58,7 +58,7 @@ errorret_t uiRender(void) {
errorret_t uiDispose(void) { errorret_t uiDispose(void) {
uielement_t *element = &UI_ELEMENTS[0]; uielement_t *element = &UI_ELEMENTS[0];
while(element->draw != NULL) { while(!uiElementIsNull(element)) {
errorChain(uiElementDispose(element)); errorChain(uiElementDispose(element));
element++; element++;
} }
+35 -11
View File
@@ -7,16 +7,24 @@
#include "uielement.h" #include "uielement.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "ui/frame/uiframe.h"
#include "ui/debug/uifps.h" #include "ui/debug/uifps.h"
#include "engine/engine.h" #include "engine/engine.h"
#include "ui/uitextbox.h" #include "ui/uitextbox.h"
#include "ui/uifullbox.h" #include "ui/overlay/uifullbox.h"
#include "ui/uiloading.h" #include "ui/overlay/uiloading.h"
#include "ui/debug/uiplayerpos.h" #include "ui/debug/uiplayerpos.h"
#include "ui/uicrop.h" #include "ui/overlay/uicrop.h"
#include "ui/debug/uiconsole.h" #include "ui/debug/uiconsole.h"
#include "ui/frame/uiframe.h"
#include "ui/frame/uisettings.h"
uielement_t UI_ELEMENTS[] = { uielement_t UI_ELEMENTS[] = {
{
.init = uiFrameInit,
.dispose = uiFrameDispose
},
// Fullbox under: above scene, below system UI. // Fullbox under: above scene, below system UI.
{ {
@@ -25,14 +33,21 @@ uielement_t UI_ELEMENTS[] = {
.draw = uiFullboxUnderDraw .draw = uiFullboxUnderDraw
}, },
{
.init = uiSettingsInit,
.update = uiSettingsUpdate,
.draw = uiSettingsDraw,
.dispose = uiSettingsDispose
},
// { .type = UI_ELEMENT_TYPE_SCRIPT, .script = { .script = "ui/test.js" } }, // { .type = UI_ELEMENT_TYPE_SCRIPT, .script = { .script = "ui/test.js" } },
{ // {
.init = uiTextboxInit, // .init = uiTextboxInit,
.update = uiTextboxUpdate, // .update = uiTextboxUpdate,
.draw = uiTextboxDraw, // .draw = uiTextboxDraw,
.dispose = uiTextboxDispose // .dispose = uiTextboxDispose
}, // },
// Fullbox over: above absolutely everything. // Fullbox over: above absolutely everything.
{ {
@@ -60,8 +75,16 @@ uielement_t UI_ELEMENTS[] = {
{ 0 } // Null terminator { 0 } // Null terminator
}; };
bool_t uiElementIsNull(const uielement_t *element) {
return element->init == NULL &&
element->update == NULL &&
element->draw == NULL &&
element->dispose == NULL;
}
errorret_t uiElementInit(uielement_t *element) { errorret_t uiElementInit(uielement_t *element) {
assertNotNull(element, "element must not be NULL"); assertNotNull(element, "element must not be NULL");
errorChain(uiFrameInit());
if(element->init != NULL) errorChain(element->init()); if(element->init != NULL) errorChain(element->init());
errorOk(); errorOk();
} }
@@ -74,12 +97,13 @@ errorret_t uiElementUpdate(uielement_t *element) {
errorret_t uiElementDraw(const uielement_t *element) { errorret_t uiElementDraw(const uielement_t *element) {
assertNotNull(element, "element must not be NULL"); assertNotNull(element, "element must not be NULL");
assertNotNull(element->draw, "element draw callback must not be NULL"); if(element->draw != NULL) errorChain(element->draw());
return element->draw(); errorOk();
} }
errorret_t uiElementDispose(uielement_t *element) { errorret_t uiElementDispose(uielement_t *element) {
assertNotNull(element, "element must not be NULL"); assertNotNull(element, "element must not be NULL");
if(element->dispose != NULL) errorChain(element->dispose()); if(element->dispose != NULL) errorChain(element->dispose());
errorChain(uiFrameDispose());
errorOk(); errorOk();
} }
+11 -2
View File
@@ -18,7 +18,16 @@ typedef struct {
extern uielement_t UI_ELEMENTS[]; extern uielement_t UI_ELEMENTS[];
/** /**
* Initializes a UI element, calling its init callback if set. * Returns true when all four callbacks on the element are NULL,
* which marks the end of the UI_ELEMENTS array.
*
* @param element The element to test.
* @returns True if the element is the null terminator.
*/
bool_t uiElementIsNull(const uielement_t *element);
/**
* Initializes a UI element, invoking its init callback if set.
* *
* @param element The element to initialize. * @param element The element to initialize.
* @return Any error that occurs. * @return Any error that occurs.
@@ -42,7 +51,7 @@ errorret_t uiElementUpdate(uielement_t *element);
errorret_t uiElementDraw(const uielement_t *element); errorret_t uiElementDraw(const uielement_t *element);
/** /**
* Disposes of a UI element, calling its dispose callback if set. * Disposes of a UI element, invoking its dispose callback if set.
* *
* @param element The element to dispose. * @param element The element to dispose.
* @return Any error that occurs. * @return Any error that occurs.
+230 -230
View File
@@ -1,278 +1,278 @@
// Copyright (c) 2026 Dominic Masters // // Copyright (c) 2026 Dominic Masters
// // //
// This software is released under the MIT License. // // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // // https://opensource.org/licenses/MIT
#include "uitextbox.h" // #include "uitextbox.h"
#include "assert/assert.h" // #include "assert/assert.h"
#include "util/memory.h" // #include "util/memory.h"
#include "util/string.h" // #include "util/string.h"
#include "time/time.h" // #include "time/time.h"
#include "input/input.h" // #include "input/input.h"
#include "event/event.h" // #include "event/event.h"
#include "display/screen/screen.h" // #include "display/screen/screen.h"
#include "display/texture/texture.h" // #include "display/texture/texture.h"
#include "display/text/text.h" // #include "display/text/text.h"
#include "display/spritebatch/spritebatch.h" // #include "display/spritebatch/spritebatch.h"
#include "display/shader/shaderunlit.h" // #include "display/shader/shaderunlit.h"
uitextbox_t UI_TEXTBOX; // uitextbox_t UI_TEXTBOX;
errorret_t uiTextboxInit(void) { // errorret_t uiTextboxInit(void) {
memoryZero(&UI_TEXTBOX, sizeof(uitextbox_t)); // memoryZero(&UI_TEXTBOX, sizeof(uitextbox_t));
UI_TEXTBOX.textColor = COLOR_WHITE; // UI_TEXTBOX.textColor = COLOR_WHITE;
UI_TEXTBOX.advanceAction = INPUT_ACTION_ACCEPT; // UI_TEXTBOX.advanceAction = INPUT_ACTION_ACCEPT;
UI_TEXTBOX.font = &FONT_DEFAULT; // UI_TEXTBOX.font = &FONT_DEFAULT;
float_t fontW = (float_t)FONT_DEFAULT.tileset->tileWidth; // float_t fontW = (float_t)FONT_DEFAULT.tileset->tileWidth;
float_t fontH = (float_t)FONT_DEFAULT.tileset->tileHeight; // float_t fontH = (float_t)FONT_DEFAULT.tileset->tileHeight;
float_t tbHeight = ( // float_t tbHeight = (
(float_t)UI_TEXTBOX_LINES_PER_PAGE_MAX * fontH + // (float_t)UI_TEXTBOX_LINES_PER_PAGE_MAX * fontH +
(float_t)(UI_TEXTBOX_LINES_PER_PAGE_MAX - 1) * UI_TEXTBOX_LINE_SPACING + // (float_t)(UI_TEXTBOX_LINES_PER_PAGE_MAX - 1) * UI_TEXTBOX_LINE_SPACING +
2.0f * fontH // 2.0f * fontH
); // );
UI_TEXTBOX.x = (float_t)SCREEN.scanX + 10.0f; // UI_TEXTBOX.x = (float_t)SCREEN.scanX + 10.0f;
UI_TEXTBOX.y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - // UI_TEXTBOX.y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) -
tbHeight - 10.0f; // tbHeight - 10.0f;
UI_TEXTBOX.width = (float_t)SCREEN.scanWidth - 20.0f; // UI_TEXTBOX.width = (float_t)SCREEN.scanWidth - 20.0f;
UI_TEXTBOX.height = tbHeight; // UI_TEXTBOX.height = tbHeight;
UI_TEXTBOX.frame.tileset.columns = 3; // UI_TEXTBOX.frame.tileset.columns = 3;
UI_TEXTBOX.frame.tileset.rows = 3; // UI_TEXTBOX.frame.tileset.rows = 3;
UI_TEXTBOX.frame.tileset.tileCount = 9; // UI_TEXTBOX.frame.tileset.tileCount = 9;
UI_TEXTBOX.frame.tileset.tileWidth = FONT_DEFAULT.tileset->tileWidth; // UI_TEXTBOX.frame.tileset.tileWidth = FONT_DEFAULT.tileset->tileWidth;
UI_TEXTBOX.frame.tileset.tileHeight = FONT_DEFAULT.tileset->tileHeight; // UI_TEXTBOX.frame.tileset.tileHeight = FONT_DEFAULT.tileset->tileHeight;
UI_TEXTBOX.frame.tileset.uv[0] = 1.0f / 3.0f; // UI_TEXTBOX.frame.tileset.uv[0] = 1.0f / 3.0f;
UI_TEXTBOX.frame.tileset.uv[1] = 1.0f / 3.0f; // UI_TEXTBOX.frame.tileset.uv[1] = 1.0f / 3.0f;
UI_TEXTBOX.frame.texture = &TEXTURE_WHITE; // UI_TEXTBOX.frame.texture = &TEXTURE_WHITE;
eventInit( // eventInit(
&UI_TEXTBOX.onPageComplete, // &UI_TEXTBOX.onPageComplete,
UI_TEXTBOX.onPageCompleteCallbacks, // UI_TEXTBOX.onPageCompleteCallbacks,
UI_TEXTBOX.onPageCompleteUsers, // UI_TEXTBOX.onPageCompleteUsers,
4 // 4
); // );
eventInit( // eventInit(
&UI_TEXTBOX.onLastPage, // &UI_TEXTBOX.onLastPage,
UI_TEXTBOX.onLastPageCallbacks, // UI_TEXTBOX.onLastPageCallbacks,
UI_TEXTBOX.onLastPageUsers, // UI_TEXTBOX.onLastPageUsers,
4 // 4
); // );
errorOk(); // errorOk();
} // }
void uiTextboxBuildLayout(void) { // void uiTextboxBuildLayout(void) {
UI_TEXTBOX.lineCount = 0; // UI_TEXTBOX.lineCount = 0;
UI_TEXTBOX.pageCount = 1; // UI_TEXTBOX.pageCount = 1;
float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth; // float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth;
float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight; // float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight;
float_t fontW = (float_t)UI_TEXTBOX.font->tileset->tileWidth; // float_t fontW = (float_t)UI_TEXTBOX.font->tileset->tileWidth;
float_t fontH = (float_t)UI_TEXTBOX.font->tileset->tileHeight; // float_t fontH = (float_t)UI_TEXTBOX.font->tileset->tileHeight;
if(fontW <= 0.0f || fontH <= 0.0f) return; // if(fontW <= 0.0f || fontH <= 0.0f) return;
float_t contentW = UI_TEXTBOX.width - 2.0f * frameTileW; // float_t contentW = UI_TEXTBOX.width - 2.0f * frameTileW;
float_t contentH = UI_TEXTBOX.height - 2.0f * frameTileH; // float_t contentH = UI_TEXTBOX.height - 2.0f * frameTileH;
UI_TEXTBOX.charsPerLine = (int32_t)(contentW / fontW); // UI_TEXTBOX.charsPerLine = (int32_t)(contentW / fontW);
UI_TEXTBOX.linesPerPage = UI_TEXTBOX_LINES_PER_PAGE_MAX; // UI_TEXTBOX.linesPerPage = UI_TEXTBOX_LINES_PER_PAGE_MAX;
if(UI_TEXTBOX.charsPerLine <= 0 || UI_TEXTBOX.linesPerPage <= 0) return; // if(UI_TEXTBOX.charsPerLine <= 0 || UI_TEXTBOX.linesPerPage <= 0) return;
if(UI_TEXTBOX.text[0] == '\0') return; // if(UI_TEXTBOX.text[0] == '\0') return;
char_t *src = UI_TEXTBOX.text; // char_t *src = UI_TEXTBOX.text;
int32_t i = 0; // int32_t i = 0;
while(src[i] != '\0' && UI_TEXTBOX.lineCount < UI_TEXTBOX_LINES_MAX) { // while(src[i] != '\0' && UI_TEXTBOX.lineCount < UI_TEXTBOX_LINES_MAX) {
if(src[i] == '\t') { // if(src[i] == '\t') {
i++; // i++;
int32_t rem = UI_TEXTBOX.lineCount % UI_TEXTBOX.linesPerPage; // int32_t rem = UI_TEXTBOX.lineCount % UI_TEXTBOX.linesPerPage;
int32_t pad = rem > 0 ? UI_TEXTBOX.linesPerPage - rem : 0; // int32_t pad = rem > 0 ? UI_TEXTBOX.linesPerPage - rem : 0;
while(pad > 0 && UI_TEXTBOX.lineCount < UI_TEXTBOX_LINES_MAX) { // while(pad > 0 && UI_TEXTBOX.lineCount < UI_TEXTBOX_LINES_MAX) {
UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].start = i; // UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].start = i;
UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].count = 0; // UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].count = 0;
UI_TEXTBOX.lineCount++; // UI_TEXTBOX.lineCount++;
pad--; // pad--;
} // }
continue; // continue;
} // }
int32_t lineStart = i; // int32_t lineStart = i;
int32_t lineWidth = 0; // int32_t lineWidth = 0;
while(src[i] != '\0') { // while(src[i] != '\0') {
char_t c = src[i]; // char_t c = src[i];
if(c == '\n') { // if(c == '\n') {
i++; // i++;
break; // break;
} // }
if(c == '\t') break; // if(c == '\t') break;
if(c == ' ') { // if(c == ' ') {
int32_t wordLen = 0; // int32_t wordLen = 0;
int32_t j = i + 1; // int32_t j = i + 1;
while( // while(
src[j] != ' ' && src[j] != '\n' && // src[j] != ' ' && src[j] != '\n' &&
src[j] != '\t' && src[j] != '\0' // src[j] != '\t' && src[j] != '\0'
) { // ) {
wordLen++; // wordLen++;
j++; // j++;
} // }
if( // if(
lineWidth > 0 && // lineWidth > 0 &&
lineWidth + 1 + wordLen > UI_TEXTBOX.charsPerLine // lineWidth + 1 + wordLen > UI_TEXTBOX.charsPerLine
) { // ) {
i++; // i++;
break; // break;
} // }
lineWidth++; // lineWidth++;
i++; // i++;
} else { // } else {
if(lineWidth >= UI_TEXTBOX.charsPerLine) break; // if(lineWidth >= UI_TEXTBOX.charsPerLine) break;
lineWidth++; // lineWidth++;
i++; // i++;
} // }
} // }
UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].start = lineStart; // UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].start = lineStart;
UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].count = lineWidth; // UI_TEXTBOX.lines[UI_TEXTBOX.lineCount].count = lineWidth;
UI_TEXTBOX.lineCount++; // UI_TEXTBOX.lineCount++;
} // }
if(UI_TEXTBOX.lineCount == 0) { // if(UI_TEXTBOX.lineCount == 0) {
UI_TEXTBOX.pageCount = 1; // UI_TEXTBOX.pageCount = 1;
} else { // } else {
int32_t div = UI_TEXTBOX.lineCount + UI_TEXTBOX.linesPerPage - 1; // int32_t div = UI_TEXTBOX.lineCount + UI_TEXTBOX.linesPerPage - 1;
UI_TEXTBOX.pageCount = div / UI_TEXTBOX.linesPerPage; // UI_TEXTBOX.pageCount = div / UI_TEXTBOX.linesPerPage;
} // }
} // }
void uiTextboxSetText(const char_t *text) { // void uiTextboxSetText(const char_t *text) {
assertNotNull(text, "text must not be NULL"); // assertNotNull(text, "text must not be NULL");
stringCopy(UI_TEXTBOX.text, text, UI_TEXTBOX_TEXT_MAX); // stringCopy(UI_TEXTBOX.text, text, UI_TEXTBOX_TEXT_MAX);
UI_TEXTBOX.currentPage = 0; // UI_TEXTBOX.currentPage = 0;
UI_TEXTBOX.scroll = 0; // UI_TEXTBOX.scroll = 0;
uiTextboxBuildLayout(); // uiTextboxBuildLayout();
} // }
errorret_t uiTextboxUpdate(void) { // errorret_t uiTextboxUpdate(void) {
#ifdef DUSK_TIME_DYNAMIC // #ifdef DUSK_TIME_DYNAMIC
if(TIME.dynamicUpdate) errorOk(); // if(TIME.dynamicUpdate) errorOk();
#endif // #endif
bool_t wasComplete = uiTextboxPageIsComplete(); // bool_t wasComplete = uiTextboxPageIsComplete();
if(!wasComplete) { // if(!wasComplete) {
UI_TEXTBOX.scroll += UI_TEXTBOX_SCROLL_CHARS_PER_TICK; // UI_TEXTBOX.scroll += UI_TEXTBOX_SCROLL_CHARS_PER_TICK;
} // }
if(inputPressed(UI_TEXTBOX.advanceAction)) { // if(inputPressed(UI_TEXTBOX.advanceAction)) {
if(!uiTextboxPageIsComplete()) { // if(!uiTextboxPageIsComplete()) {
UI_TEXTBOX.scroll = uiTextboxGetPageCharCount(); // UI_TEXTBOX.scroll = uiTextboxGetPageCharCount();
} else if(uiTextboxHasNextPage()) { // } else if(uiTextboxHasNextPage()) {
uiTextboxNextPage(); // uiTextboxNextPage();
} // }
} // }
if(!wasComplete && uiTextboxPageIsComplete()) { // if(!wasComplete && uiTextboxPageIsComplete()) {
eventInvoke(&UI_TEXTBOX.onPageComplete, &UI_TEXTBOX); // eventInvoke(&UI_TEXTBOX.onPageComplete, &UI_TEXTBOX);
if(!uiTextboxHasNextPage()) { // if(!uiTextboxHasNextPage()) {
eventInvoke(&UI_TEXTBOX.onLastPage, &UI_TEXTBOX); // eventInvoke(&UI_TEXTBOX.onLastPage, &UI_TEXTBOX);
} // }
} // }
errorOk(); // errorOk();
} // }
int32_t uiTextboxGetPageCharCount(void) { // int32_t uiTextboxGetPageCharCount(void) {
int32_t first = UI_TEXTBOX.currentPage * UI_TEXTBOX.linesPerPage; // int32_t first = UI_TEXTBOX.currentPage * UI_TEXTBOX.linesPerPage;
int32_t last = first + UI_TEXTBOX.linesPerPage; // int32_t last = first + UI_TEXTBOX.linesPerPage;
if(last > UI_TEXTBOX.lineCount) last = UI_TEXTBOX.lineCount; // if(last > UI_TEXTBOX.lineCount) last = UI_TEXTBOX.lineCount;
int32_t total = 0; // int32_t total = 0;
for(int32_t i = first; i < last; i++) { // for(int32_t i = first; i < last; i++) {
total += UI_TEXTBOX.lines[i].count; // total += UI_TEXTBOX.lines[i].count;
} // }
return total; // return total;
} // }
bool_t uiTextboxPageIsComplete(void) { // bool_t uiTextboxPageIsComplete(void) {
return UI_TEXTBOX.scroll >= uiTextboxGetPageCharCount(); // return UI_TEXTBOX.scroll >= uiTextboxGetPageCharCount();
} // }
bool_t uiTextboxHasNextPage(void) { // bool_t uiTextboxHasNextPage(void) {
return UI_TEXTBOX.currentPage + 1 < UI_TEXTBOX.pageCount; // return UI_TEXTBOX.currentPage + 1 < UI_TEXTBOX.pageCount;
} // }
void uiTextboxNextPage(void) { // void uiTextboxNextPage(void) {
if(!uiTextboxHasNextPage()) return; // if(!uiTextboxHasNextPage()) return;
UI_TEXTBOX.currentPage++; // UI_TEXTBOX.currentPage++;
UI_TEXTBOX.scroll = 0; // UI_TEXTBOX.scroll = 0;
} // }
errorret_t uiTextboxDraw(void) { // errorret_t uiTextboxDraw(void) {
if(UI_TEXTBOX.lineCount == 0 || UI_TEXTBOX.text[0] == '\0') errorOk(); // if(UI_TEXTBOX.lineCount == 0 || UI_TEXTBOX.text[0] == '\0') errorOk();
errorChain(uiFrameDraw( // errorChain(uiFrameDraw(
&UI_TEXTBOX.frame, // &UI_TEXTBOX.frame,
UI_TEXTBOX.x, UI_TEXTBOX.y, // UI_TEXTBOX.x, UI_TEXTBOX.y,
UI_TEXTBOX.width, UI_TEXTBOX.height // UI_TEXTBOX.width, UI_TEXTBOX.height
)); // ));
errorChain(spriteBatchFlush()); // errorChain(spriteBatchFlush());
shadermaterial_t textMaterial = { // shadermaterial_t textMaterial = {
.unlit = { // .unlit = {
.color = UI_TEXTBOX.textColor, // .color = UI_TEXTBOX.textColor,
.texture = UI_TEXTBOX.font->texture // .texture = UI_TEXTBOX.font->texture
} // }
}; // };
float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth; // float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth;
float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight; // float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight;
float_t fontW = (float_t)UI_TEXTBOX.font->tileset->tileWidth; // float_t fontW = (float_t)UI_TEXTBOX.font->tileset->tileWidth;
float_t fontH = (float_t)UI_TEXTBOX.font->tileset->tileHeight; // float_t fontH = (float_t)UI_TEXTBOX.font->tileset->tileHeight;
float_t contentX = UI_TEXTBOX.x + frameTileW; // float_t contentX = UI_TEXTBOX.x + frameTileW;
float_t contentY = UI_TEXTBOX.y + frameTileH; // float_t contentY = UI_TEXTBOX.y + frameTileH;
int32_t pageFirst = UI_TEXTBOX.currentPage * UI_TEXTBOX.linesPerPage; // int32_t pageFirst = UI_TEXTBOX.currentPage * UI_TEXTBOX.linesPerPage;
int32_t pageLast = pageFirst + UI_TEXTBOX.linesPerPage; // int32_t pageLast = pageFirst + UI_TEXTBOX.linesPerPage;
if(pageLast > UI_TEXTBOX.lineCount) pageLast = UI_TEXTBOX.lineCount; // if(pageLast > UI_TEXTBOX.lineCount) pageLast = UI_TEXTBOX.lineCount;
int32_t charsLeft = UI_TEXTBOX.scroll; // int32_t charsLeft = UI_TEXTBOX.scroll;
for(int32_t li = pageFirst; li < pageLast && charsLeft > 0; li++) { // for(int32_t li = pageFirst; li < pageLast && charsLeft > 0; li++) {
uitextboxline_t *line = &UI_TEXTBOX.lines[li]; // uitextboxline_t *line = &UI_TEXTBOX.lines[li];
int32_t visible = line->count < charsLeft ? line->count : charsLeft; // int32_t visible = line->count < charsLeft ? line->count : charsLeft;
float_t lineY = contentY + // float_t lineY = contentY +
(float_t)(li - pageFirst) * (fontH + UI_TEXTBOX_LINE_SPACING); // (float_t)(li - pageFirst) * (fontH + UI_TEXTBOX_LINE_SPACING);
for(int32_t ci = 0; ci < visible; ci++) { // for(int32_t ci = 0; ci < visible; ci++) {
char_t c = UI_TEXTBOX.text[line->start + ci]; // char_t c = UI_TEXTBOX.text[line->start + ci];
if(c == ' ') continue; // if(c == ' ') continue;
spritebatchsprite_t sprite = textGetSprite( // spritebatchsprite_t sprite = textGetSprite(
(vec2){ contentX + (float_t)ci * fontW, lineY }, // (vec2){ contentX + (float_t)ci * fontW, lineY },
c, // c,
UI_TEXTBOX.font // UI_TEXTBOX.font
); // );
errorChain(spriteBatchBuffer(&sprite, 1, &SHADER_UNLIT, textMaterial)); // errorChain(spriteBatchBuffer(&sprite, 1, &SHADER_UNLIT, textMaterial));
} // }
charsLeft -= visible; // charsLeft -= visible;
} // }
errorChain(spriteBatchFlush()); // errorChain(spriteBatchFlush());
errorOk(); // errorOk();
} // }
errorret_t uiTextboxDispose(void) { // errorret_t uiTextboxDispose(void) {
uiFrameDispose(&UI_TEXTBOX.frame); // uiFrameDispose(&UI_TEXTBOX.frame);
UI_TEXTBOX.font = NULL; // UI_TEXTBOX.font = NULL;
errorOk(); // errorOk();
} // }
+100 -100
View File
@@ -1,121 +1,121 @@
/** // /**
* Copyright (c) 2026 Dominic Masters // * Copyright (c) 2026 Dominic Masters
* // *
* This software is released under the MIT License. // * This software is released under the MIT License.
* https://opensource.org/licenses/MIT // * https://opensource.org/licenses/MIT
*/ // */
#pragma once // #pragma once
#include "uiframe.h" // #include "ui/frame/uiframe.h"
#include "display/text/text.h" // #include "display/text/text.h"
#include "input/inputaction.h" // #include "input/inputaction.h"
#include "event/event.h" // #include "event/event.h"
#define UI_TEXTBOX_TEXT_MAX 1024 // #define UI_TEXTBOX_TEXT_MAX 1024
#define UI_TEXTBOX_LINES_MAX 64 // #define UI_TEXTBOX_LINES_MAX 64
#define UI_TEXTBOX_SCROLL_CHARS_PER_TICK 1 // #define UI_TEXTBOX_SCROLL_CHARS_PER_TICK 1
#define UI_TEXTBOX_LINES_PER_PAGE_MAX 3 // #define UI_TEXTBOX_LINES_PER_PAGE_MAX 3
#define UI_TEXTBOX_LINE_SPACING 0.0f // #define UI_TEXTBOX_LINE_SPACING 0.0f
typedef struct { // typedef struct {
int32_t start; // int32_t start;
int32_t count; // int32_t count;
} uitextboxline_t; // } uitextboxline_t;
typedef struct { // typedef struct {
uiframe_t frame; // uiframe_t frame;
font_t *font; // font_t *font;
color_t textColor; // color_t textColor;
float_t x, y, width, height; // float_t x, y, width, height;
char_t text[UI_TEXTBOX_TEXT_MAX]; // char_t text[UI_TEXTBOX_TEXT_MAX];
uitextboxline_t lines[UI_TEXTBOX_LINES_MAX]; // uitextboxline_t lines[UI_TEXTBOX_LINES_MAX];
int32_t lineCount; // int32_t lineCount;
int32_t charsPerLine; // int32_t charsPerLine;
int32_t linesPerPage; // int32_t linesPerPage;
int32_t pageCount; // int32_t pageCount;
int32_t currentPage; // int32_t currentPage;
int32_t scroll; // int32_t scroll;
inputaction_t advanceAction; // inputaction_t advanceAction;
eventcallback_t onPageCompleteCallbacks[4]; // eventcallback_t onPageCompleteCallbacks[4];
void *onPageCompleteUsers[4]; // void *onPageCompleteUsers[4];
event_t onPageComplete; // event_t onPageComplete;
eventcallback_t onLastPageCallbacks[4]; // eventcallback_t onLastPageCallbacks[4];
void *onLastPageUsers[4]; // void *onLastPageUsers[4];
event_t onLastPage; // event_t onLastPage;
} uitextbox_t; // } uitextbox_t;
extern uitextbox_t UI_TEXTBOX; // extern uitextbox_t UI_TEXTBOX;
/** // /**
* Initializes UI_TEXTBOX. Sets position and size from current screen // * Initializes UI_TEXTBOX. Sets position and size from current screen
* dimensions and wires up the default font and frame textures. // * dimensions and wires up the default font and frame textures.
* Call after displayInit(). // * Call after displayInit().
* // *
* @return Any error that occurs. // * @return Any error that occurs.
*/ // */
errorret_t uiTextboxInit(void); // errorret_t uiTextboxInit(void);
/** // /**
* Rebuilds the word-wrap and page layout from the current text and dimensions. // * Rebuilds the word-wrap and page layout from the current text and dimensions.
* Called automatically by uiTextboxSetText. // * Called automatically by uiTextboxSetText.
*/ // */
void uiTextboxBuildLayout(void); // void uiTextboxBuildLayout(void);
/** // /**
* Copies text into UI_TEXTBOX and rebuilds the word-wrap / page layout. // * Copies text into UI_TEXTBOX and rebuilds the word-wrap / page layout.
* Resets currentPage and scroll to 0. // * Resets currentPage and scroll to 0.
* // *
* @param text Null-terminated source string. // * @param text Null-terminated source string.
*/ // */
void uiTextboxSetText(const char_t *text); // void uiTextboxSetText(const char_t *text);
/** // /**
* Advances the typewriter scroll by UI_TEXTBOX_SCROLL_CHARS_PER_TICK. // * Advances the typewriter scroll by UI_TEXTBOX_SCROLL_CHARS_PER_TICK.
* Skipped on dynamic ticks when DUSK_TIME_DYNAMIC is defined. // * Skipped on dynamic ticks when DUSK_TIME_DYNAMIC is defined.
* // *
* @return Any error that occurs. // * @return Any error that occurs.
*/ // */
errorret_t uiTextboxUpdate(void); // errorret_t uiTextboxUpdate(void);
/** // /**
* Draws the frame and the currently visible text, including a final flush. // * Draws the frame and the currently visible text, including a final flush.
* // *
* @return Any error that occurs. // * @return Any error that occurs.
*/ // */
errorret_t uiTextboxDraw(void); // errorret_t uiTextboxDraw(void);
/** // /**
* Returns the total char count for the current page. // * Returns the total char count for the current page.
* // *
* @return Total chars on current page. // * @return Total chars on current page.
*/ // */
int32_t uiTextboxGetPageCharCount(void); // int32_t uiTextboxGetPageCharCount(void);
/** // /**
* Returns true when scroll has fully revealed the current page. // * Returns true when scroll has fully revealed the current page.
*/ // */
bool_t uiTextboxPageIsComplete(void); // bool_t uiTextboxPageIsComplete(void);
/** // /**
* Returns true when there is at least one more page after the current one. // * Returns true when there is at least one more page after the current one.
*/ // */
bool_t uiTextboxHasNextPage(void); // bool_t uiTextboxHasNextPage(void);
/** // /**
* Advances to the next page and resets scroll to 0. // * Advances to the next page and resets scroll to 0.
* Has no effect if already on the last page. // * Has no effect if already on the last page.
*/ // */
void uiTextboxNextPage(void); // void uiTextboxNextPage(void);
/** // /**
* Disposes of UI_TEXTBOX, nulling out texture pointers. // * Disposes of UI_TEXTBOX, nulling out texture pointers.
* // *
* @return Any error that occurs. // * @return Any error that occurs.
*/ // */
errorret_t uiTextboxDispose(void); // errorret_t uiTextboxDispose(void);