URI: 
       tAdd basic line breaking to stb text renderer - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit f1e4126fb66f7b15d1a0ed50a4b5da72e8224fb4
   DIR parent 657c2bb9354fc1f5d1e224c5db412ce0c4da447f
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Mon,  1 Mar 2021 20:07:48 +0100
       
       Add basic line breaking to stb text renderer
       
       This is not very good line breaking.
       
       Diffstat:
         M src/button.h                        |       1 -
         M src/label.c                         |       2 +-
         M src/label.h                         |       1 -
         M src/text_stb.c                      |      97 ++++++++++++++++++++++++++-----
       
       4 files changed, 83 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/src/button.h b/src/button.h
       t@@ -22,7 +22,6 @@
        typedef struct {
                ltk_widget widget;
                ltk_text_line *tl;
       -        Pixmap pixmap;
        } ltk_button;
        
        void ltk_button_setup_theme_defaults(ltk_window *window);
   DIR diff --git a/src/label.c b/src/label.c
       t@@ -113,11 +113,11 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) {
                uint16_t font_size = window->theme.font_size;
                text_copy = ltk_strdup(text);
                label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
       +        ltk_text_line_render(label->tl, &window->theme.bg, &theme.text_color);
                int text_w, text_h;
                ltk_text_line_get_size(label->tl, &text_w, &text_h);
                label->widget.ideal_w = text_w + theme.pad * 2;
                label->widget.ideal_h = text_h + theme.pad * 2;
       -        ltk_text_line_render(label->tl, &window->theme.bg, &theme.text_color);
                ltk_fill_widget_defaults(&label->widget, id, window, &vtable, label->widget.ideal_w, label->widget.ideal_h);
        
                return label;
   DIR diff --git a/src/label.h b/src/label.h
       t@@ -22,7 +22,6 @@
        typedef struct {
                ltk_widget widget;
                ltk_text_line *tl;
       -        Pixmap text_pixmap;
        } ltk_label;
        
        void ltk_label_setup_theme_defaults(ltk_window *window);
   DIR diff --git a/src/text_stb.c b/src/text_stb.c
       t@@ -36,6 +36,8 @@
        #include "util.h"
        #include "text.h"
        
       +/* FIXME: Actually implement reference counting for the glyphs! */
       +
        typedef struct {
                stbtt_fontinfo info;
                char *path;
       t@@ -46,7 +48,7 @@ typedef struct {
        
        /* Contains general info on glyphs that doesn't change regardless of the context */
        typedef struct {
       -        int id;
       +        int id; /* FIXME: shouldn't this be uint32_t or larger? */
                unsigned char *alphamap;
                int w;
                int h;
       t@@ -60,21 +62,30 @@ typedef struct {
        /* Contains glyph info specific to one run of text */
        typedef struct {
                ltk_glyph_info *info;
       +        uint32_t codepoint;
                int x;
                int y;
        } ltk_glyph;
        
        struct ltk_text_line {
       -        Window window;
                XImage *img;
                char *text;
                ltk_glyph *glyphs;
                size_t glyph_len;
       -        uint16_t font_size;
       +
       +        int *line_indeces;
       +        int lines;
       +        int lines_alloc;
       +
       +        Window window;
       +
       +        int w_max;
                int w;
                int h;
       +        int line_h;
                int x_min;
                int y_min;
       +        uint16_t font_size;
        };
        
        /* Hash definitions */
       t@@ -115,7 +126,7 @@ static ltk_font *ltk_get_font(char *path, int index);
        static void ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text,
            uint16_t font_size, int *x_min, int *y_min, int *x_max, int *y_max);
        static void ltk_text_line_create_glyphs(ltk_text_line *tl);
       -static void ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff,
       +static void ltk_text_line_draw_glyph(ltk_glyph *glyph, int x, int y,
            XImage *img, XColor fg);
        static XImage *ltk_create_ximage(int w, int h, int depth, XColor bg);
        
       t@@ -422,6 +433,7 @@ ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_
        
                        glyphs[i].x = x1_abs;
                        glyphs[i].y = y;
       +                glyphs[i].codepoint = c1;
        
                        stbtt_GetGlyphHMetrics(&font->info, gid, &ax, 0);
                        x += (int) (ax * scale);
       t@@ -484,9 +496,7 @@ ltk_create_ximage(int w, int h, int depth, XColor bg) {
        
        /* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
        static void
       -ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, XImage *img, XColor fg) {
       -        int x = glyph->x + xoff;
       -        int y = glyph->y + yoff;
       +ltk_text_line_draw_glyph(ltk_glyph *glyph, int x, int y, XImage *img, XColor fg) {
                double a;
                int b;
                for (int i = 0; i < glyph->info->h; i++) {
       t@@ -503,6 +513,47 @@ ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, XImage *img, XCol
                }
        }
        
       +static void
       +ltk_text_line_break_lines(ltk_text_line *tl) {
       +        tl->lines = 1;
       +        if (tl->w_max == -1)
       +                return;
       +
       +        if (!tl->line_indeces) {
       +                tl->line_indeces = ltk_malloc(sizeof(int));
       +                tl->lines_alloc = 1;
       +        }
       +        tl->w = tl->w_max;
       +
       +        /* FIXME: make this actually work properly */
       +        size_t last_space = 0;
       +        size_t last_break = 0;
       +        int last_break_pos = tl->x_min;
       +        size_t i = 0;
       +        while (i < tl->glyph_len) {
       +                /* 0x20 == space character */
       +                if (tl->glyphs[i].codepoint == 0x20)
       +                        last_space = i + 1; /* actually break after the space */
       +                if (tl->glyphs[i].x + tl->glyphs[i].info->w - last_break_pos > tl->w) {
       +                        /* FIXME: safeguard for widths smaller than a single char */
       +                        if (last_space > last_break)
       +                                last_break = last_space;
       +                        else
       +                                last_break = i;
       +                        i = last_break - 1;
       +                        last_break_pos = tl->glyphs[last_break].x;
       +                        if (tl->lines >= tl->lines_alloc) {
       +                                tl->lines_alloc = tl->lines_alloc ? tl->lines_alloc * 2 : 2;
       +                                tl->line_indeces = ltk_realloc(tl->line_indeces, tl->lines_alloc * sizeof(int));
       +                        }
       +                        tl->line_indeces[tl->lines - 1] = last_break;
       +                        tl->lines++;
       +                }
       +                i++;
       +        }
       +        tl->h = tl->line_h * tl->lines;
       +}
       +
        void
        ltk_text_line_render(
                ltk_text_line *tl,
       t@@ -512,12 +563,24 @@ ltk_text_line_render(
                XWindowAttributes attrs;
                XGetWindowAttributes(tm.dpy, tl->window, &attrs);
                int depth = attrs.depth;
       -        /* FIXME: pass old image; if it has same dimensions, just clear it */
       +        /* FIXME: if old image has same or smaller dimensions, just clear it */
                if (tl->img)
                        XDestroyImage(tl->img);
                tl->img = ltk_create_ximage(tl->w, tl->h, depth, bg->xcolor);
       -        for (size_t i = 0; i < tl->glyph_len; i++) {
       -                ltk_text_line_draw_glyph(&tl->glyphs[i], -tl->x_min, -tl->y_min, tl->img, fg->xcolor);
       +
       +        int last_break = 0;
       +        for (int i = 0; i < tl->lines; i++) {
       +                int next_break;
       +                if (i <= tl->lines - 2)
       +                        next_break = tl->line_indeces[i];
       +                else
       +                        next_break = tl->glyph_len;
       +                for (int j = last_break; j < next_break; j++) {
       +                        int x = tl->glyphs[j].x - tl->glyphs[last_break].x;
       +                        int y = tl->glyphs[j].y - tl->y_min + tl->line_h * i;
       +                        ltk_text_line_draw_glyph(&tl->glyphs[j], x, y, tl->img, fg->xcolor);
       +                }
       +                last_break = next_break;
                }
        }
        
       t@@ -539,9 +602,10 @@ ltk_text_line_draw(ltk_text_line *tl, Drawable d, GC gc, int x, int y, ltk_rect 
        
        void
        ltk_text_line_set_width(ltk_text_line *tl, int width) {
       -        (void)tl;
       -        (void)width;
       -        /* FIXME: implement */
       +        /* FIXME: clarify what the difference between w_max and w is */
       +        tl->w_max = width;
       +        tl->w = width;
       +        ltk_text_line_break_lines(tl);
        }
        
        void
       t@@ -559,12 +623,11 @@ ltk_text_line_create_glyphs(ltk_text_line *tl) {
                tl->x_min = x_min;
                tl->y_min = y_min;
                tl->w = x_max - x_min;
       -        tl->h = y_max - y_min;
       +        tl->h = tl->line_h = y_max - y_min;
        }
        
        ltk_text_line *
        ltk_text_line_create(Window window, uint16_t font_size, char *text, int width) {
       -        (void)width;
                ltk_text_line *line = ltk_malloc(sizeof(ltk_text_line));
                line->window = window;
                line->img = NULL;
       t@@ -572,7 +635,11 @@ ltk_text_line_create(Window window, uint16_t font_size, char *text, int width) {
                line->glyph_len = u8_strlen(text);
                line->glyphs = ltk_malloc(line->glyph_len * sizeof(ltk_glyph));
                line->font_size = font_size;
       +        line->w_max = width;
                ltk_text_line_create_glyphs(line);
       +        line->lines_alloc = line->lines = 0;
       +        line->line_indeces = NULL;
       +        ltk_text_line_break_lines(line);
                return line;
        }