ltkx

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltkx.git
Log | Files | Refs | README | LICENSE

commit c990c56e3031b2973a251347dc2f8935b957cd79
parent 91ef917f5e9467ba6f4c187b70ed98517010489e
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 21 May 2020 17:43:02 +0200

Start work on actual text buffer

Diffstat:
Mtest1.c | 2+-
Mtext_buffer.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mtext_buffer.h | 4++--
Mtext_edit.c | 22++++------------------
4 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/test1.c b/test1.c @@ -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(); } diff --git a/text_buffer.c b/text_buffer.c @@ -21,6 +21,7 @@ * SOFTWARE. */ +#include <sys/time.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -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; @@ -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 * @@ -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; @@ -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 @@ -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; @@ -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); @@ -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; @@ -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 @@ -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]); @@ -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; @@ -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 */ @@ -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) { @@ -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); } @@ -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 */ @@ -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)); @@ -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; } diff --git a/text_buffer.h b/text_buffer.h @@ -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; }; @@ -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); diff --git a/text_edit.c b/text_edit.c @@ -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 @@ -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); }