Simplify uilabel to caller-owned buffers

uilabel no longer owns fixed-size text/sprite arrays or copies text
internally - callers pass in their own buffers and write text
directly, then mark the label dirty. This drops SetText/GetText and
the textMax bound in favor of a single Rebuffer entry point, and lets
widgets like uibutton alias an existing (possibly immutable) label
string instead of duplicating it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 12:43:02 -05:00
parent c019271e12
commit af4cb53e5f
4 changed files with 47 additions and 42 deletions
+27 -14
View File
@@ -6,25 +6,25 @@
*/ */
#include "uilabel.h" #include "uilabel.h"
#include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/string.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"
void uiLabelInit(uilabel_t *label, const char_t *text) { void uiLabelInit(
uilabel_t *label,
const char_t *text,
spritebatchsprite_t *sprites,
const int32_t spritesMax
) {
assertNotNull(text, "Text buffer cannot be NULL");
assertNotNull(sprites, "Sprites buffer cannot be NULL");
memoryZero(label, sizeof(uilabel_t)); memoryZero(label, sizeof(uilabel_t));
uiLabelSetText(label, text); label->text = text;
} label->sprites = sprites;
label->spritesMax = spritesMax;
void uiLabelSetText(uilabel_t *label, const char_t *text) {
if(stringCompare(label->text, text) == 0) return;
stringCopy(label->text, text, UI_LABEL_TEXT_MAX);
label->dirty = true;
}
const char_t * uiLabelGetText(const uilabel_t *label) {
return label->text;
} }
void uiLabelSetX(uilabel_t *label, const float_t x) { void uiLabelSetX(uilabel_t *label, const float_t x) {
@@ -49,6 +49,19 @@ float_t uiLabelGetY(const uilabel_t *label) {
void uiLabelRebuffer(uilabel_t *label) { void uiLabelRebuffer(uilabel_t *label) {
if(!label->dirty) return; if(!label->dirty) return;
textMeasure(label->text, &FONT_DEFAULT, &label->width, &label->height);
int32_t charIndex = 0;
float_t posX = label->x;
float_t posY = label->y;
label->spriteCount = textBuffer(
label->x, label->y, label->text, &FONT_DEFAULT,
label->sprites, label->spritesMax,
&charIndex, &posX, &posY
);
label->dirty = false;
} }
errorret_t uiLabelRender(uilabel_t *label, const color_t color) { errorret_t uiLabelRender(uilabel_t *label, const color_t color) {
@@ -62,7 +75,7 @@ errorret_t uiLabelRender(uilabel_t *label, const color_t color) {
} }
}; };
errorChain(spriteBatchBuffer( errorChain(spriteBatchBuffer(
label->buffer, label->spriteCount, &SHADER_UNLIT, material label->sprites, label->spriteCount, &SHADER_UNLIT, material
)); ));
errorOk(); errorOk();
+20 -28
View File
@@ -10,12 +10,10 @@
#include "display/spritebatch/spritebatchsprite.h" #include "display/spritebatch/spritebatchsprite.h"
#include "display/color.h" #include "display/color.h"
#define UI_LABEL_TEXT_MAX 128
typedef struct { typedef struct {
char_t text[UI_LABEL_TEXT_MAX]; const char_t *text;
spritebatchsprite_t sprites[UI_LABEL_TEXT_MAX]; spritebatchsprite_t *sprites;
spritebatchsprite_t buffer[UI_LABEL_TEXT_MAX]; int32_t spritesMax;
uint32_t spriteCount; uint32_t spriteCount;
int32_t width; int32_t width;
int32_t height; int32_t height;
@@ -25,28 +23,23 @@ typedef struct {
} uilabel_t; } uilabel_t;
/** /**
* Initializes a label. * Initializes a label. The caller owns the text buffer and writes its
* contents directly (setting label->dirty afterwards); call
* uiLabelRebuffer or uiLabelRender to rebuild the cached sprites.
* *
* @param label The label to initialize. * @param label The label to initialize.
* @param text Display text; copied internally, safe to be transient. * @param text Caller-owned, null-terminated string the label reads from
* directly; never written to by the label. Cannot be NULL.
* @param sprites Caller-owned sprite buffer the label writes cached
* glyph sprites into. Cannot be NULL.
* @param spritesMax Number of sprites the sprites buffer can hold.
*/ */
void uiLabelInit(uilabel_t *label, const char_t *text); void uiLabelInit(
uilabel_t *label,
/** const char_t *text,
* Sets the display text of the label, rebuilding its cached sprites. spritebatchsprite_t *sprites,
* const int32_t spritesMax
* @param label The label to update. );
* @param text Display text; copied internally, safe to be transient.
*/
void uiLabelSetText(uilabel_t *label, const char_t *text);
/**
* Returns the display text of the label.
*
* @param label The label to query.
* @returns The label's text.
*/
const char_t * uiLabelGetText(const uilabel_t *label);
/** /**
* Sets the screen x position of the label. * Sets the screen x position of the label.
@@ -81,10 +74,9 @@ void uiLabelSetY(uilabel_t *label, const float_t y);
float_t uiLabelGetY(const uilabel_t *label); float_t uiLabelGetY(const uilabel_t *label);
/** /**
* Rebuffers the label: rebuilds its cached local-space sprites if the * Rebuffers the label's cached sprites from its current text at its
* text has changed, then re-translates them into its render buffer at * current x/y position. No-op unless the label is dirty. Called
* its current x/y position. Called internally by uiLabelRender when * internally by uiLabelRender.
* either dirty flag is set.
* *
* @param label The label to rebuffer. * @param label The label to rebuffer.
*/ */