# HG changeset patch # User Mike Becker # Date 1712952195 -7200 # Node ID 26ebb2f1e6e6c06b12bf7003ddcad9d2c980a441 # Parent 7daec2f067a91b7b4c00be5ec860c6275e9da269 improve ui/text.h interface a lot diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/ascension/scene.h --- a/src/ascension/scene.h Wed Apr 10 19:43:34 2024 +0200 +++ b/src/ascension/scene.h Fri Apr 12 22:03:15 2024 +0200 @@ -65,8 +65,15 @@ bool hidden; bool need_graphics_update; bool need_transform_update; + /** + * Custom flags for this node. + * The #ASC_SCENE_NODE_FLAGS_MASK bits are reserved for general flags. + */ + uint32_t flags; }; +#define ASC_SCENE_NODE_FLAGS_MASK 0xFF000000 + /** * Place this as first member of a structure that shall be used as a scene node. */ diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/ascension/ui/text.h --- a/src/ascension/ui/text.h Wed Apr 10 19:43:34 2024 +0200 +++ b/src/ascension/ui/text.h Fri Apr 12 22:03:15 2024 +0200 @@ -31,17 +31,27 @@ #include "font.h" #include "../scene.h" #include "../texture.h" +#include "../utils.h" + +#include typedef struct AscText { extend_asc_scene_node; - char *text; + cxmutstr text; AscFont const *font; asc_col4i color; - unsigned max_width; - bool centered; + unsigned short max_width; + unsigned short offx; AscTexture tex; } AscText; +enum asc_text_alignment { + ASC_TEXT_ALIGN_LEFT = 0x00, + ASC_TEXT_ALIGN_CENTERED = 0x01, + ASC_TEXT_ALIGN_RIGHT = 0x02 +}; +#define ASC_TEXT_ALIGNMENT_MASK 0x03 +#define ASC_TEXT_CENTERED_FLAG 0x04 /** * Creates a text node. @@ -59,11 +69,65 @@ AscSceneNode *asc_text(int x, int y, char const* text); /** - * Provides access to the text data fields. + * Sets the text alignment. * - * @param node scene node created by asc_text() + * @param node the text node */ -#define asc_text_data(node) ((AscText*)node) +__attribute__((__nonnull__)) +static inline void asc_text_alignment( + AscSceneNode *node, + enum asc_text_alignment alignment +) { + asc_set_flag_masked(node->flags, ASC_TEXT_ALIGNMENT_MASK, alignment); + asc_node_update(node); +} + +/** + * Decides whether the text shall be centered. + * + * @param node the text node + * @param centered true when the text shall be centered + */ +__attribute__((__nonnull__)) +static inline void asc_text_centered( + AscSceneNode *node, + bool centered +) { + if (centered) { + asc_clear_flag(node->flags, ASC_TEXT_ALIGN_CENTERED); + } else { + asc_set_flag(node->flags, ASC_TEXT_ALIGN_CENTERED); + } + asc_node_update(node); +} + +/** + * Sets a new maximum width for the text. + * + * @param node the text node + * @param max_width the new maximum width + */ +__attribute__((__nonnull__)) +static inline void asc_text_max_width( + AscSceneNode *node, + unsigned max_width +) { + ((AscText*)node)->max_width = max_width; + asc_node_update(node); +} + +/** + * + * @param node + * @param format + * @param ... + */ +__attribute__((__nonnull__)) +void asc_text_printf( + AscSceneNode *node, + char const* format, + ... +); /** * Releases all the memory of this node. diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/ascension/utils.h --- a/src/ascension/utils.h Wed Apr 10 19:43:34 2024 +0200 +++ b/src/ascension/utils.h Fri Apr 12 22:03:15 2024 +0200 @@ -30,17 +30,11 @@ #include -static inline bool asc_test_flag(unsigned int reg, int flag) { - return (reg & flag) == flag; -} - -static inline void asc_set_flag(unsigned int *reg, int flag) { - *reg |= flag; -} - -static inline void asc_clear_flag(unsigned int *reg, int flag) { - *reg &= ~flag; -} +#define asc_test_flag(reg, flag) ((reg & flag) == flag) +#define asc_test_flag_masked(reg, mask, flag) ((reg & mask) == flag) +#define asc_clear_flag(reg, flag) (reg &= ~flag) +#define asc_set_flag(reg, flag) (reg |= flag) +#define asc_set_flag_masked(reg, mask, flag) (reg = (reg & ~mask) | flag) #endif /* ASCENSION_UTILS_H */ diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/context.c --- a/src/context.c Wed Apr 10 19:43:34 2024 +0200 +++ b/src/context.c Fri Apr 12 22:03:15 2024 +0200 @@ -66,7 +66,7 @@ } SDL_ClearError(); asc_context.total_nanos = asc_nanos(); - asc_set_flag(&asc_context.flags, ASC_FLAG_INITILIZED); + asc_set_flag(asc_context.flags, ASC_FLAG_INITILIZED); asc_dprintf("Ascension context initialized."); } @@ -104,7 +104,7 @@ while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: - asc_set_flag(&asc_context.flags, ASC_FLAG_QUIT); + asc_set_flag(asc_context.flags, ASC_FLAG_QUIT); break; case SDL_WINDOWEVENT: { if (event.window.event == SDL_WINDOWEVENT_RESIZED) diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/error.c --- a/src/error.c Wed Apr 10 19:43:34 2024 +0200 +++ b/src/error.c Fri Apr 12 22:03:15 2024 +0200 @@ -51,7 +51,7 @@ cxBufferWrite(text.ptr, 1, text.length, buf); cxBufferPut(buf, '\n'); - asc_set_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR); + asc_set_flag(asc_context.flags, ASC_FLAG_HAS_ERROR); } bool asc_has_error(void) { @@ -68,7 +68,7 @@ void asc_clear_error(void) { cxBufferClear(&asc_context.error_buffer); - asc_clear_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR); + asc_clear_flag(asc_context.flags, ASC_FLAG_HAS_ERROR); } void asc_error_gl(unsigned code, cxstring message) { diff -r 7daec2f067a9 -r 26ebb2f1e6e6 src/text.c --- a/src/text.c Wed Apr 10 19:43:34 2024 +0200 +++ b/src/text.c Fri Apr 12 22:03:15 2024 +0200 @@ -30,6 +30,8 @@ #include "ascension/error.h" #include "ascension/shader.h" +#include + #include static void asc_text_draw(AscText const *node) { @@ -58,19 +60,27 @@ // Render text onto a surface TTF_Font *font = asc_font_cache_validate(node->font)->ptr; + static int alignments[] = { + TTF_WRAPPED_ALIGN_LEFT, + TTF_WRAPPED_ALIGN_CENTER, + TTF_WRAPPED_ALIGN_RIGHT + }; TTF_SetFontWrappedAlign( - font, node->centered ? - TTF_WRAPPED_ALIGN_CENTER : TTF_WRAPPED_ALIGN_LEFT - ); + font, alignments[node->base.flags & ASC_TEXT_ALIGNMENT_MASK]); SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped( - font, node->text, asc_col_sdl(node->color), node->max_width + font, node->text.ptr, asc_col_sdl(node->color), node->max_width ); if (surface == NULL) { asc_error(SDL_GetError()); return; } asc_set_scale2d(&node->base, surface->w, surface->h); - asc_update_transform((AscSceneNode *) node); + if (asc_test_flag(node->base.flags, ASC_TEXT_CENTERED_FLAG)) { + unsigned short newoffx = surface->w / 2; + asc_vec2i pos = asc_get_position2d(&node->base); + asc_set_position2d(&node->base, pos.x + node->offx - newoffx, pos.y); + node->offx = newoffx; + } // Transfer Image Data asc_texture_from_surface(&node->tex, surface); @@ -80,6 +90,7 @@ } AscSceneNode *asc_text(int x, int y, char const *text) { + // TODO: implement fancy struct "named param" initialization AscText *node = calloc(1, sizeof(AscText)); node->base.render_group = ASC_RENDER_GROUP_SPRITE_BLEND; @@ -91,8 +102,10 @@ node->base.position.y = (float) y; node->font = asc_context.active_font; node->color = asc_context.ink; - if (text != NULL) { - node->text = strdup(text); + if (text == NULL) { + node->text = cx_mutstr(strdup(" ")); + } else { + node->text = cx_mutstr(strdup(text)); } // initialize @@ -103,6 +116,19 @@ void asc_text_free(AscText *node) { asc_texture_destroy(&node->tex); - free(node->text); + cx_strfree(&node->text); free(node); -} \ No newline at end of file +} + +void asc_text_printf( + AscSceneNode *node, + char const* format, + ... +) { + cxmutstr text = ((AscText*)node)->text; + va_list ap; + va_start(ap, format); + cx_vsprintf(&text.ptr, &text.length, format, ap); + va_end(ap); + asc_node_update(node); +} diff -r 7daec2f067a9 -r 26ebb2f1e6e6 test/snake.c --- a/test/snake.c Wed Apr 10 19:43:34 2024 +0200 +++ b/test/snake.c Fri Apr 12 22:03:15 2024 +0200 @@ -41,8 +41,7 @@ fps /= asc_context.frame_nanos; if (fps != last_fps) { last_fps = fps; - snprintf(asc_text_data(node)->text, 11, "%"PRIu64" FPS", fps); - asc_node_update(node); + asc_text_printf(node, "%"PRIu64" FPS", fps); } } } @@ -50,9 +49,9 @@ static void create_fps_counter(void) { asc_set_font(asc_font(ASC_FONT_REGULAR, 24)); asc_ink_rgb(255, 0, 0); - AscSceneNode* node = asc_text(10, 10, "XXXXXXX FPS"); + AscSceneNode* node = asc_text(10, 10, NULL); asc_scene_add_behavior(node, update_fps_counter); - asc_scene_node_link(asc_window_active->ui, node); + asc_add_ui_node(node); } static void update_score_counter(AscSceneNode *node) { @@ -73,7 +72,7 @@ asc_ink_rgb(0, 255, 0); AscSceneNode* node = asc_text(0, 0, "Score: 0"); asc_scene_add_behavior(node, update_score_counter); - asc_scene_node_link(asc_window_active->ui, node); + asc_add_ui_node(node); } int main(int argc, char** argv) { @@ -94,7 +93,6 @@ create_fps_counter(); create_score_counter(); - // Main Loop do { // quit application on any error