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
     1.1 --- a/src/ascension/scene.h	Wed Apr 10 19:43:34 2024 +0200
     1.2 +++ b/src/ascension/scene.h	Fri Apr 12 22:03:15 2024 +0200
     1.3 @@ -65,8 +65,15 @@
     1.4      bool hidden;
     1.5      bool need_graphics_update;
     1.6      bool need_transform_update;
     1.7 +    /**
     1.8 +     * Custom flags for this node.
     1.9 +     * The #ASC_SCENE_NODE_FLAGS_MASK bits are reserved for general flags.
    1.10 +     */
    1.11 +    uint32_t flags;
    1.12  };
    1.13  
    1.14 +#define ASC_SCENE_NODE_FLAGS_MASK 0xFF000000
    1.15 +
    1.16  /**
    1.17   * Place this as first member of a structure that shall be used as a scene node.
    1.18   */
     2.1 --- a/src/ascension/ui/text.h	Wed Apr 10 19:43:34 2024 +0200
     2.2 +++ b/src/ascension/ui/text.h	Fri Apr 12 22:03:15 2024 +0200
     2.3 @@ -31,17 +31,27 @@
     2.4  #include "font.h"
     2.5  #include "../scene.h"
     2.6  #include "../texture.h"
     2.7 +#include "../utils.h"
     2.8 +
     2.9 +#include <cx/string.h>
    2.10  
    2.11  typedef struct AscText {
    2.12      extend_asc_scene_node;
    2.13 -    char *text;
    2.14 +    cxmutstr text;
    2.15      AscFont const *font;
    2.16      asc_col4i color;
    2.17 -    unsigned max_width;
    2.18 -    bool centered;
    2.19 +    unsigned short max_width;
    2.20 +    unsigned short offx;
    2.21      AscTexture tex;
    2.22  } AscText;
    2.23  
    2.24 +enum asc_text_alignment {
    2.25 +    ASC_TEXT_ALIGN_LEFT = 0x00,
    2.26 +    ASC_TEXT_ALIGN_CENTERED = 0x01,
    2.27 +    ASC_TEXT_ALIGN_RIGHT = 0x02
    2.28 +};
    2.29 +#define ASC_TEXT_ALIGNMENT_MASK 0x03
    2.30 +#define ASC_TEXT_CENTERED_FLAG  0x04
    2.31  
    2.32  /**
    2.33   * Creates a text node.
    2.34 @@ -59,11 +69,65 @@
    2.35  AscSceneNode *asc_text(int x, int y, char const* text);
    2.36  
    2.37  /**
    2.38 - * Provides access to the text data fields.
    2.39 + * Sets the text alignment.
    2.40   *
    2.41 - * @param node scene node created by asc_text()
    2.42 + * @param node the text node
    2.43   */
    2.44 -#define asc_text_data(node) ((AscText*)node)
    2.45 +__attribute__((__nonnull__))
    2.46 +static inline void asc_text_alignment(
    2.47 +        AscSceneNode *node,
    2.48 +        enum asc_text_alignment alignment
    2.49 +) {
    2.50 +    asc_set_flag_masked(node->flags, ASC_TEXT_ALIGNMENT_MASK, alignment);
    2.51 +    asc_node_update(node);
    2.52 +}
    2.53 +
    2.54 +/**
    2.55 + * Decides whether the text shall be centered.
    2.56 + *
    2.57 + * @param node the text node
    2.58 + * @param centered true when the text shall be centered
    2.59 + */
    2.60 +__attribute__((__nonnull__))
    2.61 +static inline void asc_text_centered(
    2.62 +        AscSceneNode *node,
    2.63 +        bool centered
    2.64 +) {
    2.65 +    if (centered) {
    2.66 +        asc_clear_flag(node->flags, ASC_TEXT_ALIGN_CENTERED);
    2.67 +    } else {
    2.68 +        asc_set_flag(node->flags, ASC_TEXT_ALIGN_CENTERED);
    2.69 +    }
    2.70 +    asc_node_update(node);
    2.71 +}
    2.72 +
    2.73 +/**
    2.74 + * Sets a new maximum width for the text.
    2.75 + *
    2.76 + * @param node the text node
    2.77 + * @param max_width the new maximum width
    2.78 + */
    2.79 +__attribute__((__nonnull__))
    2.80 +static inline void asc_text_max_width(
    2.81 +        AscSceneNode *node,
    2.82 +        unsigned max_width
    2.83 +) {
    2.84 +    ((AscText*)node)->max_width = max_width;
    2.85 +    asc_node_update(node);
    2.86 +}
    2.87 +
    2.88 +/**
    2.89 + *
    2.90 + * @param node
    2.91 + * @param format
    2.92 + * @param ...
    2.93 + */
    2.94 +__attribute__((__nonnull__))
    2.95 +void asc_text_printf(
    2.96 +        AscSceneNode *node,
    2.97 +        char const* format,
    2.98 +        ...
    2.99 +);
   2.100  
   2.101  /**
   2.102   * Releases all the memory of this node.
     3.1 --- a/src/ascension/utils.h	Wed Apr 10 19:43:34 2024 +0200
     3.2 +++ b/src/ascension/utils.h	Fri Apr 12 22:03:15 2024 +0200
     3.3 @@ -30,17 +30,11 @@
     3.4  
     3.5  #include <stdbool.h>
     3.6  
     3.7 -static inline bool asc_test_flag(unsigned int reg, int flag) {
     3.8 -    return (reg & flag) == flag;
     3.9 -}
    3.10 -
    3.11 -static inline void asc_set_flag(unsigned int *reg, int flag) {
    3.12 -    *reg |= flag;
    3.13 -}
    3.14 -
    3.15 -static inline void asc_clear_flag(unsigned int *reg, int flag) {
    3.16 -    *reg &= ~flag;
    3.17 -}
    3.18 +#define asc_test_flag(reg, flag) ((reg & flag) == flag)
    3.19 +#define asc_test_flag_masked(reg, mask, flag) ((reg & mask) == flag)
    3.20 +#define asc_clear_flag(reg, flag) (reg &= ~flag)
    3.21 +#define asc_set_flag(reg, flag) (reg |= flag)
    3.22 +#define asc_set_flag_masked(reg, mask, flag) (reg = (reg & ~mask) | flag)
    3.23  
    3.24  #endif /* ASCENSION_UTILS_H */
    3.25  
     4.1 --- a/src/context.c	Wed Apr 10 19:43:34 2024 +0200
     4.2 +++ b/src/context.c	Fri Apr 12 22:03:15 2024 +0200
     4.3 @@ -66,7 +66,7 @@
     4.4      }
     4.5      SDL_ClearError();
     4.6      asc_context.total_nanos = asc_nanos();
     4.7 -    asc_set_flag(&asc_context.flags, ASC_FLAG_INITILIZED);
     4.8 +    asc_set_flag(asc_context.flags, ASC_FLAG_INITILIZED);
     4.9      asc_dprintf("Ascension context initialized.");
    4.10  }
    4.11  
    4.12 @@ -104,7 +104,7 @@
    4.13      while (SDL_PollEvent(&event)) {
    4.14          switch (event.type) {
    4.15              case SDL_QUIT:
    4.16 -                asc_set_flag(&asc_context.flags, ASC_FLAG_QUIT);
    4.17 +                asc_set_flag(asc_context.flags, ASC_FLAG_QUIT);
    4.18                  break;
    4.19              case SDL_WINDOWEVENT: {
    4.20                  if (event.window.event == SDL_WINDOWEVENT_RESIZED)
     5.1 --- a/src/error.c	Wed Apr 10 19:43:34 2024 +0200
     5.2 +++ b/src/error.c	Fri Apr 12 22:03:15 2024 +0200
     5.3 @@ -51,7 +51,7 @@
     5.4      cxBufferWrite(text.ptr, 1, text.length, buf);
     5.5      cxBufferPut(buf, '\n');
     5.6  
     5.7 -    asc_set_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR);
     5.8 +    asc_set_flag(asc_context.flags, ASC_FLAG_HAS_ERROR);
     5.9  }
    5.10  
    5.11  bool asc_has_error(void) {
    5.12 @@ -68,7 +68,7 @@
    5.13  
    5.14  void asc_clear_error(void) {
    5.15      cxBufferClear(&asc_context.error_buffer);
    5.16 -    asc_clear_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR);
    5.17 +    asc_clear_flag(asc_context.flags, ASC_FLAG_HAS_ERROR);
    5.18  }
    5.19  
    5.20  void asc_error_gl(unsigned code, cxstring message) {
     6.1 --- a/src/text.c	Wed Apr 10 19:43:34 2024 +0200
     6.2 +++ b/src/text.c	Fri Apr 12 22:03:15 2024 +0200
     6.3 @@ -30,6 +30,8 @@
     6.4  #include "ascension/error.h"
     6.5  #include "ascension/shader.h"
     6.6  
     6.7 +#include <cx/printf.h>
     6.8 +
     6.9  #include <GL/glew.h>
    6.10  
    6.11  static void asc_text_draw(AscText const *node) {
    6.12 @@ -58,19 +60,27 @@
    6.13  
    6.14      // Render text onto a surface
    6.15      TTF_Font *font = asc_font_cache_validate(node->font)->ptr;
    6.16 +    static int alignments[] = {
    6.17 +            TTF_WRAPPED_ALIGN_LEFT,
    6.18 +            TTF_WRAPPED_ALIGN_CENTER,
    6.19 +            TTF_WRAPPED_ALIGN_RIGHT
    6.20 +    };
    6.21      TTF_SetFontWrappedAlign(
    6.22 -            font, node->centered ?
    6.23 -                  TTF_WRAPPED_ALIGN_CENTER : TTF_WRAPPED_ALIGN_LEFT
    6.24 -    );
    6.25 +            font, alignments[node->base.flags & ASC_TEXT_ALIGNMENT_MASK]);
    6.26      SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(
    6.27 -            font, node->text, asc_col_sdl(node->color), node->max_width
    6.28 +            font, node->text.ptr, asc_col_sdl(node->color), node->max_width
    6.29      );
    6.30      if (surface == NULL) {
    6.31          asc_error(SDL_GetError());
    6.32          return;
    6.33      }
    6.34      asc_set_scale2d(&node->base, surface->w, surface->h);
    6.35 -    asc_update_transform((AscSceneNode *) node);
    6.36 +    if (asc_test_flag(node->base.flags, ASC_TEXT_CENTERED_FLAG)) {
    6.37 +        unsigned short newoffx = surface->w / 2;
    6.38 +        asc_vec2i pos = asc_get_position2d(&node->base);
    6.39 +        asc_set_position2d(&node->base, pos.x + node->offx - newoffx, pos.y);
    6.40 +        node->offx = newoffx;
    6.41 +    }
    6.42  
    6.43      // Transfer Image Data
    6.44      asc_texture_from_surface(&node->tex, surface);
    6.45 @@ -80,6 +90,7 @@
    6.46  }
    6.47  
    6.48  AscSceneNode *asc_text(int x, int y, char const *text) {
    6.49 +    // TODO: implement fancy struct "named param" initialization
    6.50      AscText *node = calloc(1, sizeof(AscText));
    6.51  
    6.52      node->base.render_group = ASC_RENDER_GROUP_SPRITE_BLEND;
    6.53 @@ -91,8 +102,10 @@
    6.54      node->base.position.y = (float) y;
    6.55      node->font = asc_context.active_font;
    6.56      node->color = asc_context.ink;
    6.57 -    if (text != NULL) {
    6.58 -        node->text = strdup(text);
    6.59 +    if (text == NULL) {
    6.60 +        node->text = cx_mutstr(strdup(" "));
    6.61 +    } else {
    6.62 +        node->text = cx_mutstr(strdup(text));
    6.63      }
    6.64  
    6.65      // initialize
    6.66 @@ -103,6 +116,19 @@
    6.67  
    6.68  void asc_text_free(AscText *node) {
    6.69      asc_texture_destroy(&node->tex);
    6.70 -    free(node->text);
    6.71 +    cx_strfree(&node->text);
    6.72      free(node);
    6.73 -}
    6.74 \ No newline at end of file
    6.75 +}
    6.76 +
    6.77 +void asc_text_printf(
    6.78 +        AscSceneNode *node,
    6.79 +        char const* format,
    6.80 +        ...
    6.81 +) {
    6.82 +    cxmutstr text = ((AscText*)node)->text;
    6.83 +    va_list ap;
    6.84 +    va_start(ap, format);
    6.85 +    cx_vsprintf(&text.ptr, &text.length, format, ap);
    6.86 +    va_end(ap);
    6.87 +    asc_node_update(node);
    6.88 +}
     7.1 --- a/test/snake.c	Wed Apr 10 19:43:34 2024 +0200
     7.2 +++ b/test/snake.c	Fri Apr 12 22:03:15 2024 +0200
     7.3 @@ -41,8 +41,7 @@
     7.4          fps /= asc_context.frame_nanos;
     7.5          if (fps != last_fps) {
     7.6              last_fps = fps;
     7.7 -            snprintf(asc_text_data(node)->text, 11, "%"PRIu64" FPS", fps);
     7.8 -            asc_node_update(node);
     7.9 +            asc_text_printf(node, "%"PRIu64" FPS", fps);
    7.10          }
    7.11      }
    7.12  }
    7.13 @@ -50,9 +49,9 @@
    7.14  static void create_fps_counter(void) {
    7.15      asc_set_font(asc_font(ASC_FONT_REGULAR, 24));
    7.16      asc_ink_rgb(255, 0, 0);
    7.17 -    AscSceneNode* node = asc_text(10, 10, "XXXXXXX FPS");
    7.18 +    AscSceneNode* node = asc_text(10, 10, NULL);
    7.19      asc_scene_add_behavior(node, update_fps_counter);
    7.20 -    asc_scene_node_link(asc_window_active->ui, node);
    7.21 +    asc_add_ui_node(node);
    7.22  }
    7.23  
    7.24  static void update_score_counter(AscSceneNode *node) {
    7.25 @@ -73,7 +72,7 @@
    7.26      asc_ink_rgb(0, 255, 0);
    7.27      AscSceneNode* node = asc_text(0, 0, "Score: 0");
    7.28      asc_scene_add_behavior(node, update_score_counter);
    7.29 -    asc_scene_node_link(asc_window_active->ui, node);
    7.30 +    asc_add_ui_node(node);
    7.31  }
    7.32  
    7.33  int main(int argc, char** argv) {
    7.34 @@ -94,7 +93,6 @@
    7.35      create_fps_counter();
    7.36      create_score_counter();
    7.37  
    7.38 -
    7.39      // Main Loop
    7.40      do {
    7.41          // quit application on any error

mercurial