URI: 
       tStart work on actual text buffer - ltkx - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltkx.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit c990c56e3031b2973a251347dc2f8935b957cd79
   DIR parent 91ef917f5e9467ba6f4c187b70ed98517010489e
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Thu, 21 May 2020 17:43:02 +0200
       
       Start work on actual text buffer
       
       Diffstat:
         M test1.c                             |       2 +-
         M text_buffer.c                       |     124 ++++++++++++++++++++++++-------
         M text_buffer.h                       |       4 ++--
         M text_edit.c                         |      22 ++++------------------
       
       4 files changed, 106 insertions(+), 46 deletions(-)
       ---
   DIR diff --git a/test1.c b/test1.c
       t@@ -42,6 +42,6 @@ int main(int argc, char *argv[])
                LtkTextEdit *edit = ltk_create_text_edit(window1, "ہمارے بارے میں blabla bla");
                LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", &bob3, edit);
                ltk_grid_widget(button4, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT);
       -        ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM | LTK_STICKY_TOP | LTK_STICKY_RIGHT);
       +        ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_TOP | LTK_STICKY_RIGHT);
                ltk_mainloop();
        }
   DIR diff --git a/text_buffer.c b/text_buffer.c
       t@@ -21,6 +21,7 @@
         * SOFTWARE.
         */
        
       +#include <sys/time.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <stdint.h>
       t@@ -76,14 +77,12 @@ ltk_text_line_cleanup_soft_lines(struct ltk_array_line *soft_lines, int old_len)
                ltk_array_resize_line(soft_lines, soft_lines->len);
        }
        
       -/* FIXME: redo this to store a list of all runs and indeces to be drawn in
       -   each soft line -> that would take a bit more space but simplify later
       -   logic and (most importantly) allow ltk_soft_line_get_index_from_pos to
       -   loop over the actual runs and see what direction each one is (that's
       -   necessary for determining on which side of the glyph the new text has
       -   to be inserted) */
        void
        ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) {
       +        struct timeval t1, t2;
       +        gettimeofday(&t1, NULL);
       +        printf("wrap1: %d, %d\n", t1.tv_sec, t1.tv_usec);
       +
                tl->w_wrapped = max_width;
                int old_len = tl->soft_lines->len;
                tl->soft_lines->len = 0;
       t@@ -213,6 +212,9 @@ ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) {
                ltk_text_line_cleanup_soft_lines(tl->soft_lines, old_len);
                tl->w_wrapped = max_width;
                tl->h_wrapped = tl->soft_lines->len * tl->h;
       +
       +        gettimeofday(&t2, NULL);
       +        printf("wrap2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
        }
        
        XImage *
       t@@ -266,6 +268,9 @@ ltk_text_line_render(
                XColor fg,
                XColor bg)
        {
       +        struct timeval t1, t2;
       +        gettimeofday(&t1, NULL);
       +        printf("render1: %d, %d\n", t1.tv_sec, t1.tv_usec);
                LtkGlyph *glyph;
                int par_is_rtl = tl->dir == HB_DIRECTION_RTL;
        
       t@@ -341,7 +346,11 @@ ltk_text_line_render(
                                }
                                cur = par_is_rtl ? cur->last : cur->next;
                        }
       +                ltk_array_resize_int(sl->glyph_pos, sl->glyph_pos->len);
       +                ltk_array_resize_uint32(sl->glyph_clusters, sl->glyph_clusters->len);
                }
       +        gettimeofday(&t2, NULL);
       +        printf("render2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
        }
        
        uint32_t
       t@@ -588,6 +597,8 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
        static void
        ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
            struct ltk_text_line *tl, uint16_t font_size, uint16_t font_id, int *ret_y_max) {
       +        struct timeval t1, t2;
       +        gettimeofday(&t1, NULL);
                khash_t(glyphinfo) *glyph_cache;
                khint_t k;
        
       t@@ -607,15 +618,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
                tr->num_glyphs = 0;
        
                buf = hb_buffer_create();
       -        /* Harfbuzz requires the original, non-reversed text.
       -           Yes, I know this is a bit hacky
       -           Update: This is now done in the ltk_text_line_itemize already */
       -        /*
       -        size_t start_index = tl->vis2log->buf[tr->start_index];
       -        size_t end_index = tl->vis2log->buf[tr->start_index + tr->len - 1];
       -        if (start_index > end_index)
       -                start_index = end_index;
       -        */
                hb_buffer_add_utf32(buf, tl->log_buf->buf, tl->len, tr->start_index, tr->len);
                hb_buffer_set_direction(buf, tr->dir);
                hb_buffer_set_script(buf, tr->script);
       t@@ -625,6 +627,8 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
                hb_shape(tr->font->hb, buf, NULL, 0);
                ginf = hb_buffer_get_glyph_infos(buf, &tr->num_glyphs);
                gpos = hb_buffer_get_glyph_positions(buf, &tr->num_glyphs);
       +        gettimeofday(&t2, NULL);
       +        printf("hb_shape: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
                float scale = stbtt_ScaleForMappingEmToPixels(&tr->font->info, font_size);
        
                int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN;
       t@@ -676,6 +680,8 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
                *ret_y_max = y_max;
        
                tr->font->refs++;
       +        gettimeofday(&t2, NULL);
       +        printf("run_shape: %d\n", t2.tv_usec - t1.tv_usec);
        }
        
        static void
       t@@ -685,14 +691,17 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
                int y_max;
                int y_max_overall = INT_MIN;
                int y_min_overall = INT_MAX;
       +        struct timeval t1, t2;
                while (run) {
       -                /* Question: Why does this not work with Duplicate? */
       -                FcPattern *pat = FcPatternCreate();//FcPatternDuplicate(tm->fcpattern);
       +                /* Question: Why does this not work with FcPatternDuplicate? */
       +                gettimeofday(&t1, NULL);
       +                FcPattern *pat = FcPatternCreate();
                        FcPattern *match;
                        FcResult result;
                        FcPatternAddBool(pat, FC_SCALABLE, 1);
                        FcConfigSubstitute(NULL, pat, FcMatchPattern);
                        FcDefaultSubstitute(pat);
       +                /* FIXME: make this more efficient */
                        FcCharSet *cs = FcCharSetCreate();
                        for (size_t i = run->start_index; i < run->start_index + run->len; i++) {
                                FcCharSetAddChar(cs, tl->log_buf->buf[i]);
       t@@ -706,6 +715,8 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
                        run->font = kh_value(tm->font_cache, k);
                        FcPatternDestroy(match);
                        FcPatternDestroy(pat);
       +                gettimeofday(&t2, NULL);
       +                printf("fontconfig: %d\n", t2.tv_usec - t1.tv_usec);
                        ltk_text_run_shape(tm, run, tl, tl->font_size, font_id, &y_max);
                        if (y_max_overall < y_max)
                                y_max_overall = y_max;
       t@@ -776,18 +787,31 @@ ltk_text_line_destroy_runs(struct ltk_text_run *runs) {
        static void
        ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) {
                FriBidiCharType par_dir = FRIBIDI_TYPE_ON;
       +        struct timeval t1, t2;
       +        gettimeofday(&t1, NULL);
       +        printf("fribidi1: %d, %d\n", t1.tv_sec, t1.tv_usec);
                fribidi_log2vis(
                    tl->log_buf->buf, tl->log_buf->len,
                    &par_dir, tl->vis_buf->buf, tl->log2vis->buf, tl->vis2log->buf, tl->bidi_levels->buf
                );
       +        gettimeofday(&t2, NULL);
       +        printf("fribidi2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
                if (FRIBIDI_IS_RTL(par_dir))
                        tl->dir = HB_DIRECTION_RTL;
                else
                        tl->dir = HB_DIRECTION_LTR;
                struct ltk_text_run *old_runs = tl->first_run;
       +        gettimeofday(&t1, NULL);
       +        printf("itemize1: %d, %d\n", t1.tv_sec, t1.tv_usec);
                ltk_text_line_itemize(tl);
       +        gettimeofday(&t2, NULL);
       +        printf("itemize2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
                struct ltk_text_run *cur = tl->first_run;
       +        gettimeofday(&t1, NULL);
       +        printf("shape1: %d, %d\n", t1.tv_sec, t1.tv_usec);
                ltk_text_line_shape(tm, tl);
       +        gettimeofday(&t2, NULL);
       +        printf("shape2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
                /* this needs to be done after shaping so the fonts, etc. aren't
                   removed if their reference counts drop and then loaded again
                   right afterwards */
       t@@ -797,25 +821,24 @@ ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) {
        
        
        void
       -ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) {
       -        ltk_array_insert_uint32(tl->log_buf, tl->cursor_pos, text, len);
       -        ltk_array_prepare_gap_script(tl->scripts, tl->cursor_pos, len);
       +ltk_text_line_insert_utf32(struct ltk_text_line *tl, size_t index, uint32_t *text, size_t len) {
       +        ltk_array_insert_uint32(tl->log_buf, index, text, len);
       +        ltk_array_prepare_gap_script(tl->scripts, index, len);
                hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
                for (int i = 0; i < len; i++)
       -                tl->scripts->buf[tl->cursor_pos + i] = hb_unicode_script(ufuncs, text[i]);
       +                tl->scripts->buf[index + i] = hb_unicode_script(ufuncs, text[i]);
                ltk_array_resize_uint32(tl->vis_buf, tl->len + len);
                ltk_array_resize_int(tl->log2vis, tl->len + len);
                ltk_array_resize_int(tl->vis2log, tl->len + len);
                ltk_array_resize_level(tl->bidi_levels, tl->len + len);
                tl->len += len;
       -        /*tl->cursor_pos += len;*/ /* FIXME */
                /* FIXME: Why am I passing tm? It's global anyways */
                ltk_text_line_recalculate(ltk_global->tm, tl);
        }
        
        /* must be NULL-terminated */
        void
       -ltk_text_line_insert_utf8(struct ltk_text_line *tl, char *text) {
       +ltk_text_line_insert_utf8(struct ltk_text_line *tl, size_t index, char *text) {
                size_t len = u8_strlen(text);
                uint32_t *new = malloc(sizeof(uint32_t) * len);
                if (!new) {
       t@@ -825,7 +848,7 @@ ltk_text_line_insert_utf8(struct ltk_text_line *tl, char *text) {
                size_t inc = 0;
                for (int i = 0; i < len; i++)
                        new[i] = u8_nextmemchar(text, &inc);
       -        ltk_text_line_insert_text(tl, new, len);
       +        ltk_text_line_insert_utf32(tl, index, new, len);
                free(new);
        }
        
       t@@ -843,7 +866,6 @@ ltk_text_line_create(void) {
                line->first_run = NULL;
                line->next = NULL;
                line->len = 0;
       -        line->cursor_pos = 0;
                line->w_wrapped = line->h_wrapped = 0;
                line->img = NULL;
                /* FIXME */
       t@@ -855,6 +877,57 @@ error:
                exit(1);
        }
        
       +void
       +ltk_text_buffer_scroll(struct ltk_text_buffer *tb, int offset_y) {
       +}
       +
       +void
       +ltk_text_buffer_render(struct ltk_text_buffer *tb, int offset_y, int offset_x, int w, int h) {
       +        struct ltk_text_line *cur = tb->head;
       +        int cur_y = 0;
       +        while (cur) {
       +                if (cur_y > offset_y + h)
       +                        break;
       +                if (cur_y > offset_y || cur_y + cur->h_wrapped > offset_y) {
       +                }
       +                cur_y += cur->h_wrapped;
       +                cur = cur->next;
       +        }
       +}
       +
       +void
       +ltk_text_buffer_wrap(struct ltk_text_buffer *tb, int max_width) {
       +        struct ltk_text_line *cur = tb->head;
       +        while (cur) {
       +                ltk_text_line_wrap(cur, max_width);
       +                cur = cur->next;
       +        }
       +}
       +
       +void
       +ltk_text_buffer_insert_utf8_at_cursor(struct ltk_text_buffer *tb, char *text) {
       +        size_t len = u8_strlen(text);
       +        uint32_t *new = malloc(sizeof(uint32_t) * len);
       +        if (!new) {
       +                (void)fprintf(stderr, "Error allocating memory for string\n");
       +                exit(1);
       +        }
       +        size_t inc = 0;
       +        uint32_t c;
       +        size_t actual_len = 0;
       +        for (int i = 0; i < len; i++) {
       +                c = u8_nextmemchar(text, &inc);
       +                if (c == 0x000A) {
       +                        printf("newline\n");
       +                } else {
       +                        actual_len++;
       +                        new[i] = c;
       +                }
       +        }
       +        ltk_text_line_insert_utf32(tb->cur_line, tb->cursor_pos, new, actual_len);
       +        free(new);
       +}
       +
        struct ltk_text_buffer *
        ltk_text_buffer_create(void) {
                struct ltk_text_buffer *buf = malloc(sizeof(struct ltk_text_buffer));
       t@@ -864,6 +937,7 @@ ltk_text_buffer_create(void) {
                }
                buf->head = ltk_text_line_create();
                buf->cur_line = buf->head;
       +        buf->cursor_pos = 0;
                buf->line_gap = 0;
        }
        
   DIR diff --git a/text_buffer.h b/text_buffer.h
       t@@ -84,7 +84,6 @@ struct ltk_text_line {
                int h;
                int w_wrapped;
                int h_wrapped;
       -        size_t cursor_pos;
                unsigned int line_gap;
                XImage *img;
        };
       t@@ -100,7 +99,8 @@ void ltk_soft_line_destroy(struct ltk_soft_line *sl);
        void ltk_text_line_render(struct ltk_text_line *tl,
            Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg);
        uint32_t ltk_soft_line_get_index_from_pos(int x, struct ltk_text_line *tl, struct ltk_soft_line *sl, int *found_pos);
       -void ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len);
       +void ltk_text_line_insert_utf32(struct ltk_text_line *tl, size_t index, uint32_t *text, size_t len);
       +void ltk_text_line_insert_utf8(struct ltk_text_line *tl, size_t index, char *text);
        struct ltk_text_line *ltk_text_line_create(void);
        void ltk_text_line_destroy(struct ltk_text_line *tl);
        
   DIR diff --git a/text_edit.c b/text_edit.c
       t@@ -49,20 +49,7 @@ ltk_draw_text_edit(LtkTextEdit *te) {
                   to avoid recalculating everything when it really only has to drawn */
                ltk_text_line_wrap(te->tl, rect.w);
                ltk_text_line_render(te->tl, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
       -        XPutImage(ltk_global->display, window->xwindow, window->gc, te->tl->img, 0, 0, rect.x, rect.y, te->tl->img->width, te->tl->img->height);
       -        /*
       -        if (!te->soft_lines)
       -                te->soft_lines = ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
       -        XSetForeground(ltk_global->display, window->gc, bg.pixel);
       -        XFillRectangle(ltk_global->display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
       -        for (int i = 0; i < te->soft_lines->len; i++) {
       -                XImage *img = te->soft_lines->buf[i]->img;
       -                int x = rect.x;
       -                if (te->tl->dir == HB_DIRECTION_RTL)
       -                        x += rect.w - img->width;
       -                XPutImage(ltk_global->display, window->xwindow, window->gc, img, 0, 0, x, rect.y + te->tl->h * i, img->width, img->height);
       -        }
       -        */
       +        XPutImage(ltk_global->display, window->xwindow, window->gc, te->tl->img, 0, 0, rect.x, rect.y, rect.w, rect.h);
        }
        
        #if 0
       t@@ -89,15 +76,14 @@ ltk_create_text_edit(LtkWindow *window, const char *text) {
                ltk_fill_widget_defaults(&te->widget, window, &ltk_draw_text_edit, &ltk_destroy_text_edit, 1);
                /*te->widget.mouse_press = &ltk_text_edit_tmp;*/
                te->tl = ltk_text_line_create();
       -        ltk_text_line_insert_utf8(te->tl, text);
       -        te->cursor = 0;
       +        ltk_text_line_insert_utf8(te->tl, 0, text);
                return te;
        }
        
        void
        ltk_text_edit_insert_text(LtkTextEdit *te, const char *text) {
       -        te->tl->cursor_pos = te->cursor;
       -        ltk_text_line_insert_utf8(te->tl, text);
       +        /* FIXME */
       +        ltk_text_line_insert_utf8(te->tl, 0, text);
                /* FIXME: Need to "queue redraw" for whole window */
                ltk_draw_text_edit(te);
        }