ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit f1e4126fb66f7b15d1a0ed50a4b5da72e8224fb4
parent 657c2bb9354fc1f5d1e224c5db412ce0c4da447f
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:
Msrc/button.h | 1-
Msrc/label.c | 2+-
Msrc/label.h | 1-
Msrc/text_stb.c | 97++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
4 files changed, 83 insertions(+), 18 deletions(-)

diff --git a/src/button.h b/src/button.h @@ -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); diff --git a/src/label.c b/src/label.c @@ -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; diff --git a/src/label.h b/src/label.h @@ -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); diff --git a/src/text_stb.c b/src/text_stb.c @@ -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; @@ -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; @@ -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 */ @@ -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); @@ -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); @@ -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++) { @@ -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, @@ -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; } } @@ -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 @@ -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; @@ -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; }