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:
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;
}