commit aed6b7ca52af0f276ca91bcf4d156469baf999d7
parent 4898ef0c1cc92eee1a6c61535a33e26e94b143a7
Author: lumidify <nobody@lumidify.org>
Date: Mon, 18 May 2020 20:56:54 +0200
Start adding basic position to index mapping
Diffstat:
4 files changed, 86 insertions(+), 13 deletions(-)
diff --git a/text_buffer.c b/text_buffer.c
@@ -48,10 +48,17 @@ LTK_ARRAY_INIT_IMPL(line, struct ltk_soft_line *)
void
ltk_soft_line_destroy(struct ltk_soft_line *sl) {
+ /* FIXME: destroy arrays */
if (sl->img) XDestroyImage(sl->img);
free(sl);
}
+/* 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_lien_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) */
struct ltk_array_line *
ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) {
struct ltk_array_line *soft_lines = ltk_array_create_line(1);
@@ -199,23 +206,26 @@ ltk_create_ximage(Display *dpy, int w, int h, int depth, XColor bg) {
/* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
void
-ltk_draw_glyph(LtkGlyph *glyph, XImage *img, int x, int y, XColor fg) {
- printf("%d,%d\n", x, y);
+ltk_soft_line_draw_glyph(LtkGlyph *glyph, struct ltk_soft_line *sl, int x, int y, XColor fg) {
+ ltk_array_append_int(sl->glyph_pos, x);
+ ltk_array_append_int(sl->glyph_clusters, glyph->cluster);
double a;
int b;
for (int i = 0; i < glyph->info->h; i++) {
for (int j = 0; j < glyph->info->w; j++) {
- if (y + i >= img->height || x + j >= img->width)
+ if (y + i >= sl->img->height || x + j >= sl->img->width)
continue;
- b = (y + i) * img->bytes_per_line + (x + j) * 4;
+ b = (y + i) * sl->img->bytes_per_line + (x + j) * 4;
a = glyph->info->alphamap[i * glyph->info->w + j] / 255.0;
- img->data[b] = (fg.blue * a + (1 - a) * (uint16_t)img->data[b] * 257) / 257;
- img->data[b + 1] = (fg.green * a + (1 - a) * (uint16_t)img->data[b + 1] * 257) / 257;
- img->data[b + 2] = (fg.red * a + (1 - a) * (uint16_t)img->data[b + 2] * 257) / 257;
+ sl->img->data[b] = (fg.blue * a + (1 - a) * (uint16_t)sl->img->data[b] * 257) / 257;
+ sl->img->data[b + 1] = (fg.green * a + (1 - a) * (uint16_t)sl->img->data[b + 1] * 257) / 257;
+ sl->img->data[b + 2] = (fg.red * a + (1 - a) * (uint16_t)sl->img->data[b + 2] * 257) / 257;
}
}
}
+/* FIXME: pass old soft lines and check if anything changed - only rerender then;
+ also reuse the old struct ltk_soft_line's to avoid reallocating */
/* FIXME: rename this once everything is cleaned up (currently conflicts with the
old render function */
struct ltk_array_line *
@@ -239,6 +249,9 @@ ltk_render_text_line_new(
for (int i = 0; i < soft_lines->len; i++) {
struct ltk_soft_line *sl = soft_lines->buf[i];
+ /* FIXME: allow to disable this if selection isn't needed */
+ sl->glyph_pos = ltk_array_create_int(tl->len);
+ sl->glyph_clusters = ltk_array_create_int(tl->len);
sl->img = ltk_create_ximage(dpy, sl->w, tl->h, depth, bg);
struct ltk_text_run *cur = sl->run;
size_t cur_len = 0;
@@ -257,14 +270,14 @@ ltk_render_text_line_new(
for (int i = start_index; i >= 0 && cur_len < sl->len; i--) {
cur_len++;
int x = cur_border - (local_border - cur->glyphs[i].x_abs);
- ltk_draw_glyph(&cur->glyphs[i], sl->img, x, cur->glyphs[i].y_abs, fg);
+ ltk_soft_line_draw_glyph(&cur->glyphs[i], sl, x, cur->glyphs[i].y_abs, fg);
}
cur_border -= local_border - cur->glyphs[end_index].x_abs;
} else {
for (int i = end_index; i <= start_index && cur_len < sl->len; i++) {
cur_len++;
int x = cur_border + (cur->glyphs[i].x_abs - cur->glyphs[end_index].x_abs);
- ltk_draw_glyph(&cur->glyphs[i], sl->img, x, cur->glyphs[i].y_abs, fg);
+ ltk_soft_line_draw_glyph(&cur->glyphs[i], sl, x, cur->glyphs[i].y_abs, fg);
}
cur_border += local_border - cur->glyphs[end_index].x_abs;
}
@@ -280,14 +293,14 @@ ltk_render_text_line_new(
for (int i = end_index; i >= start_index && cur_len < sl->len; i--) {
cur_len++;
int x = cur_border - (cur->glyphs[end_index].x_abs + cur->glyphs[end_index].x_advance - cur->glyphs[i].x_abs);
- ltk_draw_glyph(&cur->glyphs[i], sl->img, x, cur->glyphs[i].y_abs, fg);
+ ltk_soft_line_draw_glyph(&cur->glyphs[i], sl, x, cur->glyphs[i].y_abs, fg);
}
cur_border -= cur->glyphs[cur->num_glyphs - 1].x_abs + cur->glyphs[cur->num_glyphs - 1].x_advance - local_border;
} else {
for (int i = start_index; i < cur->num_glyphs && cur_len < sl->len; i++) {
cur_len++;
int x = cur_border + (cur->glyphs[i].x_abs - local_border);
- ltk_draw_glyph(&cur->glyphs[i], sl->img, x, cur->glyphs[i].y_abs, fg);
+ ltk_soft_line_draw_glyph(&cur->glyphs[i], sl, x, cur->glyphs[i].y_abs, fg);
}
cur_border += cur->glyphs[cur->num_glyphs - 1].x_abs + cur->glyphs[cur->num_glyphs - 1].x_advance - local_border;
}
@@ -299,8 +312,46 @@ ltk_render_text_line_new(
return soft_lines;
}
-size_t
-ltk_soft_line_get_index_from_pos(int x, struct ltk_soft_line *sl) {
+uint32_t
+ltk_soft_line_get_index_from_pos(int x, struct ltk_soft_line *sl, hb_direction_t dir, int *found_pos) {
+ /* FIXME: need par dir! for better guess! */
+ /* also need it to determine if insert should be before or after char */
+ /* FIXME: should I be messing around with casting between uint32_t and size_t? */
+ /* FIXME: handle negative x */
+ uint32_t guess = (int)(((double)x / sl->w) * (sl->len - 1));
+ guess = guess >= sl->len ? sl->len - 1 : guess;
+ int delta = 0;
+ int i = 0;
+ int last_dist;
+ /* FIXME: add more safety - sl->len and sl->glyph_pos->len *should* be the
+ same, but who knows? */
+ if (sl->glyph_pos->len - 1 > guess &&
+ abs(sl->glyph_pos->buf[guess + 1] - x) < abs(sl->glyph_pos->buf[guess] - x)) {
+ delta = 1;
+ i = guess + 1;
+ last_dist = abs(sl->glyph_pos->buf[guess + 1] - x);
+ } else if (guess > 0 &&
+ abs(sl->glyph_pos->buf[guess - 1] - x) < abs(sl->glyph_pos->buf[guess] - x)) {
+ delta = -1;
+ i = guess - 1;
+ last_dist = abs(sl->glyph_pos->buf[guess - 1] - x);
+ }
+ if (delta == 0) {
+ if (found_pos)
+ found_pos = sl->glyph_pos->buf[guess];
+ return guess;
+ }
+ int new_dist;
+ for (; i >= 0 && i < sl->len; i += delta) {
+ new_dist = abs(sl->glyph_pos->buf[i] - x);
+ if (last_dist < new_dist)
+ break;
+ last_dist = new_dist;
+ }
+ i -= delta;
+ if (found_pos)
+ *found_pos = sl->glyph_pos->buf[i];
+ return sl->glyph_clusters->buf[i];
}
/* Begin stuff stolen from raqm */
diff --git a/text_buffer.h b/text_buffer.h
@@ -61,6 +61,8 @@ struct ltk_soft_line {
int w;
struct ltk_text_run *run;
XImage *img;
+ struct ltk_array_int *glyph_pos;
+ struct ltk_array_int *glyph_clusters;
};
LTK_ARRAY_INIT_DECL(line, struct ltk_soft_line *)
@@ -98,6 +100,7 @@ struct ltk_text_buffer {
void ltk_soft_line_destroy(struct ltk_soft_line *sl);
struct ltk_array_line *ltk_render_text_line_new(struct ltk_text_line *tl, int max_width,
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_soft_line *sl, hb_direction_t dir, int *found_pos);
void ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len);
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
@@ -22,6 +22,7 @@
*/
#include <stdint.h>
+#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "khash.h"
@@ -57,20 +58,37 @@ ltk_draw_text_edit(LtkTextEdit *te) {
}
}
+void
+ltk_text_edit_tmp(LtkTextEdit *te, XEvent event) {
+ /* this should never be negative, but just to be sure... */
+ int local_y = abs(event.xbutton.y - te->widget.rect.y);
+ int i = ((double)local_y / te->tl->h) * te->soft_lines->len;
+ i = i >= te->soft_lines->len ? te->soft_lines->len - 1 : i;
+ int x = event.xbutton.x - te->widget.rect.x;
+ if (te->tl->dir == HB_DIRECTION_RTL)
+ x -= (te->widget.rect.w - te->soft_lines->buf[i]->img->width);
+ int found_pos = 0;
+ te->cursor = ltk_soft_line_get_index_from_pos(
+ x, te->soft_lines->buf[i], te->tl->dir, &found_pos);
+}
+
LtkTextEdit *
ltk_create_text_edit(LtkWindow *window, const char *text) {
LtkTextEdit *te = malloc(sizeof(LtkTextEdit));
if (!te)
ltk_fatal("ERROR: Unable to allocate memory for LtkTextEdit.\n");
ltk_fill_widget_defaults(&te->widget, window, <k_draw_text_edit, <k_destroy_text_edit, 1);
+ te->widget.mouse_press = <k_text_edit_tmp;
te->tl = ltk_text_line_create();
ltk_text_line_insert_utf8(te->tl, text);
te->soft_lines = NULL;
+ te->cursor = 0;
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);
if (te->soft_lines)
ltk_array_destroy_deep_line(te->soft_lines, <k_soft_line_destroy);
diff --git a/text_edit.h b/text_edit.h
@@ -26,6 +26,7 @@
typedef struct {
LtkWidget widget;
+ uint32_t cursor;
struct ltk_text_line *tl;
struct ltk_array_line *soft_lines;
} LtkTextEdit;