From ceaa1b1f22ef86c5a592876c31e83cd04869b9ed Mon Sep 17 00:00:00 2001 From: Thomas White Date: Thu, 5 Jun 2014 09:22:13 +0200 Subject: Cursor stuff --- src/mainwindow.c | 114 ++++++++++++++----------------------------------------- src/sc_interp.c | 5 ++- src/sc_parse.c | 6 +++ src/sc_parse.h | 2 + src/shape.c | 30 ++++++++++----- src/shape.h | 6 ++- src/wrap.c | 83 ++++++++++++++++++++++++++++++++++++---- src/wrap.h | 9 ++++- 8 files changed, 147 insertions(+), 108 deletions(-) diff --git a/src/mainwindow.c b/src/mainwindow.c index 4706e15..ef89e8c 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -1125,40 +1125,30 @@ static void insert_text(struct frame *fr, char *t, struct presentation *p) static void do_backspace(struct frame *fr, struct presentation *p) { - int nln, nbx; - size_t pos; - struct wrap_box *box; - glong ptr; + int sln, sbx, sps; if ( fr == NULL ) return; /* If this is, say, the top level frame, do nothing */ if ( fr->boxes == NULL ) return; - nln = p->cursor_line; - nbx = p->cursor_box; - pos = p->cursor_pos; - - if ( pos == 0 ) { - if ( nbx == 0 ) { - if ( nln == 0 ) return; - nln--; - nbx = fr->lines[nln].n_boxes-1; /* The last box */ - } else { - nbx--; - } - pos = strlen(fr->lines[nln].boxes[nbx].text)-1; - } + printf("Old: frame %p, line %i, box %i, pos %li\n", + p->cursor_frame, p->cursor_line, p->cursor_box, p->cursor_pos); + sln = p->cursor_line; + sbx = p->cursor_box; + sps = p->cursor_pos; - box = &fr->lines[nln].boxes[nbx]; + move_cursor_back(p); - p->cursor_line = nln; - p->cursor_box = nbx; - p->cursor_pos = pos; + printf("New: frame %p, line %i, box %i, pos %li\n", + p->cursor_frame, p->cursor_line, p->cursor_box, p->cursor_pos); - ptr = g_utf8_pointer_to_offset(box->text, box->text+pos); + /* Delete may cross wrap boxes and maybe SCBlock boundaries */ + struct wrap_box *sbox = &p->cursor_frame->lines[sln].boxes[sbx]; + struct wrap_line *fline = &p->cursor_frame->lines[p->cursor_line]; + struct wrap_box *fbox = &fline->boxes[p->cursor_box]; + sc_delete_text(fbox->scblock, p->cursor_pos, sbox->scblock, sps); -// reshape_box(box); rerender_slide(p); redraw_editor(p); } @@ -1610,29 +1600,30 @@ static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event, } - static void move_cursor(struct presentation *p, signed int x, signed int y) { - struct wrap_line *line = &p->cursor_frame->lines[p->cursor_line]; - struct wrap_box *box = &line->boxes[p->cursor_box]; - signed int cp, cb, cl; - - cp = p->cursor_pos; - cb = p->cursor_box; - cl = p->cursor_line; - if ( x > 0 ) { int advance = 0; + signed int cp, cb, cl; + struct wrap_line *line = &p->cursor_frame->lines[p->cursor_line]; + struct wrap_box *box = &line->boxes[p->cursor_box]; + + cp = p->cursor_pos; + cb = p->cursor_box; + cl = p->cursor_line; if ( box->type == WRAP_BOX_PANGO ) { char *np; - np = g_utf8_find_next_char(box->text+cp, NULL); - if ( np == box->text+cp ) { + const char *box_text; + box_text = sc_block_contents(box->scblock) + box->offs; + np = g_utf8_offset_to_pointer(box_text, cp); + np = g_utf8_find_next_char(np, NULL); + if ( np > box_text+box->len_bytes ) { advance = 1; } else { - cp = np - box->text; + cp = np - box_text; } } else { @@ -1669,57 +1660,8 @@ static void move_cursor(struct presentation *p, signed int x, signed int y) p->cursor_pos = cp; } else { - - int retreat = 0; - - if ( box->type == WRAP_BOX_PANGO ) { - - char *np; - np = g_utf8_find_prev_char(box->text, box->text+cp); - if ( np == NULL ) { - retreat = 1; - } else { - cp = np - box->text; - } - - } else { - cp--; - if ( cp < 0 ) retreat = 1; - } - - if ( retreat ) { - - do { - - cb--; - - if ( cb < 0 ) { - cl--; - if ( cl < 0 ) return; - p->cursor_line = cl; - line = &p->cursor_frame->lines[cl]; - cb = line->n_boxes - 1; - } - - } while ( (line->boxes[cb].type == WRAP_BOX_SENTINEL) - || (line->boxes[cb].type == WRAP_BOX_NOTHING) - || !line->boxes[cb].editable ); - - p->cursor_box = cb; - box = &line->boxes[cb]; - if ( box->type == WRAP_BOX_PANGO ) { - cp = strlen(box->text); - } else { - cp = 1; - } - - } - p->cursor_pos = cp; - + move_cursor_back(p); } - - printf("Cursor at frame %p, line %i, box %i, pos %li\n", - p->cursor_frame, p->cursor_line, p->cursor_box, p->cursor_pos); } diff --git a/src/sc_interp.c b/src/sc_interp.c index a868a73..7dbe5f4 100644 --- a/src/sc_interp.c +++ b/src/sc_interp.c @@ -512,7 +512,7 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) if ( name == NULL ) { split_words(sc_interp_get_frame(scin)->boxes, - scin->pc, contents, scin->lang, 1, + scin->pc, bl, contents, scin->lang, 1, scin); } else if ( strcmp(name, "bgcol") == 0 ) { @@ -541,7 +541,8 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) snprintf(tmp, 63, "%i", scin->s_constants->slide_number); split_words(sc_interp_get_frame(scin)->boxes, - scin->pc, tmp, scin->lang, 0, scin); + scin->pc, bl, tmp, scin->lang, 0, + scin); } } else { printf("No slide constants.\n"); diff --git a/src/sc_parse.c b/src/sc_parse.c index aeb9ea9..71dd449 100644 --- a/src/sc_parse.c +++ b/src/sc_parse.c @@ -376,3 +376,9 @@ SCBlock *sc_parse(const char *sc) return blf; } + + +void sc_delete_text(SCBlock *b1, int p1, SCBlock *b2, int p2) +{ + printf("Deleting from %p/%i to %p/%i\n", b1, p1, b2, p2); +} diff --git a/src/sc_parse.h b/src/sc_parse.h index b5d2c5c..020c345 100644 --- a/src/sc_parse.h +++ b/src/sc_parse.h @@ -42,6 +42,8 @@ extern const char *sc_block_contents(const SCBlock *bl); extern struct frame *sc_block_frame(const SCBlock *bl); extern void sc_block_set_frame(SCBlock *bl, struct frame *fr); +extern void sc_delete_text(SCBlock *b1, int p1, SCBlock *b2, int p2); + extern void show_sc_blocks(const SCBlock *bl); extern void show_sc_block(const SCBlock *bl, const char *prefix); diff --git a/src/shape.c b/src/shape.c index 4c20812..6078b55 100644 --- a/src/shape.c +++ b/src/shape.c @@ -42,6 +42,8 @@ struct box_adding_stuff int editable; char *text; enum wrap_box_space space; + SCBlock *bl; + size_t offs; }; @@ -61,13 +63,15 @@ static void add_wrap_box(gpointer vi, gpointer vb) box = &bas->line->boxes[bas->line->n_boxes]; box->type = WRAP_BOX_PANGO; - box->text = bas->text; box->space = bas->space; box->font = sc_interp_get_font(bas->scin); box->width = 0; box->editable = bas->editable; box->ascent = sc_interp_get_ascent(bas->scin); box->height = sc_interp_get_height(bas->scin); + box->scblock = bas->bl; + box->offs = bas->offs + item->offset; + box->len_bytes = item->length; col = sc_interp_get_fgcol(bas->scin); box->col[0] = col[0]; /* Red */ box->col[1] = col[1]; /* Green */ @@ -96,7 +100,8 @@ static void add_wrap_box(gpointer vi, gpointer vb) /* Add "text", followed by a space of type "space", to "line" */ static int add_wrap_boxes(struct wrap_line *line, char *text, enum wrap_box_space space, PangoContext *pc, - SCInterpreter *scin, int editable) + SCInterpreter *scin, SCBlock *bl, size_t offs, + int editable) { GList *pango_items; PangoAttrList *attrs; @@ -113,6 +118,8 @@ static int add_wrap_boxes(struct wrap_line *line, char *text, bas.editable = editable; bas.text = text; bas.space = space; + bas.bl = bl; + bas.offs = offs; g_list_foreach(pango_items, add_wrap_box, &bas); g_list_free(pango_items); @@ -129,7 +136,8 @@ void add_image_box(struct wrap_line *line, const char *filename, box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_IMAGE; - box->text = NULL; + box->scblock = NULL; + box->offs = 0; box->space = WRAP_SPACE_NONE; box->width = pango_units_from_double(w); box->ascent = pango_units_from_double(h); @@ -140,8 +148,9 @@ void add_image_box(struct wrap_line *line, const char *filename, } -int split_words(struct wrap_line *boxes, PangoContext *pc, const char *text, - PangoLanguage *lang, int editable, SCInterpreter *scin) +int split_words(struct wrap_line *boxes, PangoContext *pc, SCBlock *bl, + const char *text, PangoLanguage *lang, int editable, + SCInterpreter *scin) { PangoLogAttr *log_attrs; glong len_chars, i; @@ -198,7 +207,7 @@ int split_words(struct wrap_line *boxes, PangoContext *pc, const char *text, } if ( add_wrap_boxes(boxes, word, type, - pc, scin, editable) ) { + pc, scin, bl, start, editable) ) { fprintf(stderr, "Failed to add wrap box.\n"); } start = offs; @@ -226,14 +235,17 @@ int split_words(struct wrap_line *boxes, PangoContext *pc, const char *text, word2 = strndup(word, l-1); add_wrap_boxes(boxes, word2, - WRAP_SPACE_EOP, pc, scin, editable); + WRAP_SPACE_EOP, pc, scin, bl, start, + editable); add_wrap_boxes(boxes, strdup(""), - WRAP_SPACE_NONE, pc, scin, editable); + WRAP_SPACE_NONE, pc, scin, bl, start, + editable); } else { add_wrap_boxes(boxes, word, - WRAP_SPACE_NONE, pc, scin, editable); + WRAP_SPACE_NONE, pc, scin, bl, start, + editable); } diff --git a/src/shape.h b/src/shape.h index bdc5775..43356e0 100644 --- a/src/shape.h +++ b/src/shape.h @@ -32,10 +32,12 @@ #include "wrap.h" extern int split_words(struct wrap_line *boxes, PangoContext *pc, - const char *text, PangoLanguage *lang, int editable, - SCInterpreter *scin); + SCBlock *bl, const char *text, PangoLanguage *lang, + int editable, SCInterpreter *scin); extern void add_image_box(struct wrap_line *line, const char *filename, int w, int h, int editable); +extern void reshape_box(struct wrap_box *box); + #endif /* SHAPE_H */ diff --git a/src/wrap.c b/src/wrap.c index 2b680ed..f356a75 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -123,6 +123,7 @@ void get_cursor_pos(struct wrap_box *box, size_t pos, double *xposd, double *yposd, double *line_height) { int p; + const char *box_text; *xposd = 0.0; *yposd = 0.0; @@ -140,8 +141,10 @@ void get_cursor_pos(struct wrap_box *box, size_t pos, switch ( box->type ) { case WRAP_BOX_PANGO : - pango_glyph_string_index_to_x(box->glyphs, box->text, - strlen(box->text), + box_text = sc_block_contents(box->scblock) + box->offs; + pango_glyph_string_index_to_x(box->glyphs, + box_text, + box->len_bytes, &box->item->analysis, pos, FALSE, &p); *xposd += pango_units_to_double(p); @@ -157,6 +160,70 @@ void get_cursor_pos(struct wrap_box *box, size_t pos, } +void move_cursor_back(struct presentation *p) +{ + int retreat = 0; + signed int cp, cb, cl; + struct wrap_line *line = &p->cursor_frame->lines[p->cursor_line]; + struct wrap_box *box = &line->boxes[p->cursor_box]; + + cp = p->cursor_pos; + cb = p->cursor_box; + cl = p->cursor_line; + + if ( box->type == WRAP_BOX_PANGO ) { + + char *np; + const char *box_text; + box_text = sc_block_contents(box->scblock) + box->offs; + np = g_utf8_offset_to_pointer(box_text, cp); + np = g_utf8_find_prev_char(box_text, np); + if ( np == NULL ) { + retreat = 1; + } else { + cp = np - box_text; + } + + } else { + cp--; + if ( cp < 0 ) retreat = 1; + } + + if ( retreat ) { + + const char *box_text; + + do { + + cb--; + + if ( cb < 0 ) { + cl--; + if ( cl < 0 ) return; + p->cursor_line = cl; + line = &p->cursor_frame->lines[cl]; + cb = line->n_boxes - 1; + } + + } while ( (line->boxes[cb].type == WRAP_BOX_SENTINEL) + || (line->boxes[cb].type == WRAP_BOX_NOTHING) + || !line->boxes[cb].editable ); + + p->cursor_box = cb; + box = &line->boxes[cb]; + box_text = sc_block_contents(box->scblock) + box->offs; + if ( box->type == WRAP_BOX_PANGO ) { + cp = g_utf8_pointer_to_offset(box_text, + box_text+box->len_bytes); + } else { + cp = 1; + } + + } + p->cursor_pos = cp; +} + + static int find_cursor_line(struct frame *fr, double yposd, int *end) { int i; @@ -212,6 +279,7 @@ void find_cursor(struct frame *fr, double xposd, double yposd, int x_pos_i; size_t offs; int ln, bn; + const char *box_text; if ( fr->n_lines == 0 ) { *line = 0; @@ -245,12 +313,14 @@ void find_cursor(struct frame *fr, double xposd, double yposd, case WRAP_BOX_PANGO : x_pos_i = pango_units_from_double(x_pos); - pango_glyph_string_x_to_index(b->glyphs, b->text, - strlen(b->text), + box_text = sc_block_contents(b->scblock) + b->offs; + pango_glyph_string_x_to_index(b->glyphs, box_text, + b->len_bytes, &b->item->analysis, x_pos_i, &idx, &trail); /* FIXME: Assumes 1 byte char */ offs = idx + trail; + break; case WRAP_BOX_SENTINEL : offs = 0; @@ -522,13 +592,14 @@ static void knuth_suboptimal_fit(struct wrap_line *boxes, double line_length, } box = &boxes->boxes[boxes->n_boxes]; box->type = WRAP_BOX_SENTINEL; - box->text = NULL; box->space = WRAP_SPACE_NONE; box->font = NULL; box->width = 0; box->ascent = 0; box->height = 0; box->editable = 1; + box->scblock = NULL; + box->offs = 0; boxes->n_boxes++; line_length *= PANGO_SCALE; @@ -689,7 +760,6 @@ void wrap_line_free(struct wrap_line *l) case WRAP_BOX_PANGO : pango_glyph_string_free(l->boxes[i].glyphs); pango_item_free(l->boxes[i].item); - free(l->boxes[i].text); break; case WRAP_BOX_IMAGE : @@ -752,7 +822,6 @@ void show_boxes(struct wrap_line *boxes) for ( i=0; in_boxes; i++ ) { printf("%3i", i); - printf(" '%s'", boxes->boxes[i].text); printf(" t=%i s=%i %i %5.2f\n", boxes->boxes[i].type, boxes->boxes[i].space, boxes->boxes[i].width, boxes->boxes[i].sp); diff --git a/src/wrap.h b/src/wrap.h index a4064e6..24438b2 100644 --- a/src/wrap.h +++ b/src/wrap.h @@ -3,7 +3,7 @@ * * Text wrapping, hyphenation, justification and shaping * - * Copyright © 2013 Thomas White + * Copyright © 2014 Thomas White * * This file is part of Colloquium. * @@ -61,6 +61,9 @@ struct wrap_box enum wrap_box_type type; int editable; + SCBlock *scblock; + size_t offs; /* offset into contents of scblock */ + /* Pango units */ int width; int height; @@ -73,8 +76,8 @@ struct wrap_box PangoGlyphString *glyphs; PangoItem *item; PangoFont *font; - char *text; double col[4]; /* rgba colour */ + size_t len_bytes; /* number of bytes (not characters) of text */ /* For type == WRAP_BOX_IMAGE */ char *filename; @@ -102,6 +105,8 @@ extern int wrap_contents(struct frame *fr); extern void get_cursor_pos(struct wrap_box *box, size_t pos, double *xposd, double *yposd, double *line_height); +extern void move_cursor_back(struct presentation *p); + extern void find_cursor(struct frame *fr, double xposd, double yposd, int *line, int *box, size_t *pos); -- cgit v1.2.3