improve ui/text.h interface a lot

Fri, 12 Apr 2024 22:03:15 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 12 Apr 2024 22:03:15 +0200
changeset 58
26ebb2f1e6e6
parent 57
7daec2f067a9
child 59
764fbb013252

improve ui/text.h interface a lot

src/ascension/scene.h file | annotate | diff | comparison | revisions
src/ascension/ui/text.h file | annotate | diff | comparison | revisions
src/ascension/utils.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
src/error.c file | annotate | diff | comparison | revisions
src/text.c file | annotate | diff | comparison | revisions
test/snake.c file | annotate | diff | comparison | revisions
--- 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.
  */
--- 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 <cx/string.h>
 
 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 the text 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 scene node created by asc_text()
+ * @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
  */
-#define asc_text_data(node) ((AscText*)node)
+__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.
--- 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 <stdbool.h>
 
-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 */
 
--- 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)
--- 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) {
--- 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 <cx/printf.h>
+
 #include <GL/glew.h>
 
 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);
+}
--- 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

mercurial