From 43ef7c6fbc161f0174946f8c7500f71f24924b75 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Fri, 11 Oct 2019 22:33:27 +0200 Subject: Implement text deletion and paragraph splitting in slide text boxes --- libstorycode/gtk/gtkslideview.c | 12 +-- libstorycode/slide.c | 161 ++++++++++++++++++++++++++++------------ 2 files changed, 118 insertions(+), 55 deletions(-) diff --git a/libstorycode/gtk/gtkslideview.c b/libstorycode/gtk/gtkslideview.c index 11cf05a..986f666 100644 --- a/libstorycode/gtk/gtkslideview.c +++ b/libstorycode/gtk/gtkslideview.c @@ -1064,8 +1064,6 @@ static void sort_slide_positions(struct slide_pos *a, struct slide_pos *b) static void gtksv_do_backspace(GtkSlideView *e, signed int dir) { - /* FIXME! */ -#if 0 struct slide_pos p1, p2; size_t o1, o2; @@ -1089,18 +1087,14 @@ static void gtksv_do_backspace(GtkSlideView *e, signed int dir) } sort_slide_positions(&p1, &p2); - o1 = pos_trail_to_offset(e->cursor_frame, p1.para, p1.run, p1.pos, p1.trail); - o2 = pos_trail_to_offset(e->cursor_frame, p2.para, p1.run, p2.pos, p2.trail); + o1 = slide_pos_trail_to_offset(e->cursor_frame, p1.para, p1.pos, p1.trail); + o2 = slide_pos_trail_to_offset(e->cursor_frame, p2.para, p2.pos, p2.trail); slide_item_delete_text(e->cursor_frame, p1.para, o1, p2.para, o2); e->cpos = p1; - gtksv_unset_selection(e); - - pango_layout_set_text(e->cursor_frame->paras[e->cpos.para].layout, - e->cursor_frame->paras[e->cpos.para].text, -1); + gtksv_unset_selection(e); gtksv_emit_change_sig(e); gtksv_redraw(e); -#endif } diff --git a/libstorycode/slide.c b/libstorycode/slide.c index 07b01ff..f5728c7 100644 --- a/libstorycode/slide.c +++ b/libstorycode/slide.c @@ -324,88 +324,157 @@ void slide_item_get_padding(SlideItem *item, Stylesheet *ss, } -void slide_item_split_text_paragraph(SlideItem *item, int para, size_t off) +static struct slide_text_paragraph *insert_paragraph(SlideItem *item, int pos) { - /* FIXME */ -#if 0 - struct slide_text_paragraph *np; + struct slide_text_paragraph *paras_new; - np = realloc(item->paras, (item->n_paras+1)*sizeof(struct slide_text_paragraph)); - if ( np == NULL ) return; + paras_new = realloc(item->paras, (item->n_paras+1)*sizeof(struct slide_text_paragraph)); + if ( paras_new == NULL ) return NULL; - item->paras = np; + item->paras = paras_new; item->n_paras++; - memmove(&item->paras[para+1], &item->paras[para], - (item->n_paras - para - 1)*sizeof(struct slide_text_paragraph)); + memmove(&item->paras[pos+1], &item->paras[pos], + (item->n_paras-pos-1)*sizeof(struct slide_text_paragraph)); - item->paras[para+1].text = strdup(&item->paras[para].text[off]); - item->paras[para+1].layout = NULL; - item->paras[para].text[off] = '\0'; -#endif + item->paras[pos].runs = NULL; + item->paras[pos].layout = NULL; + item->paras[pos].n_runs = 0; + return &item->paras[pos]; } -static void delete_paragraph(SlideItem *item, int del) +void slide_item_split_text_paragraph(SlideItem *item, int para_num, size_t off) +{ + size_t run_offs; + int j; + struct slide_text_paragraph *para1; + struct slide_text_paragraph *para2; + int run = slide_which_run(&item->paras[para_num], off, &run_offs); + + para2 = insert_paragraph(item, para_num+1); + para1 = &item->paras[para_num]; /* NB n->items was realloced by insert_item */ + + para2->n_runs = para1->n_runs - run; + para2->runs = malloc(para2->n_runs*sizeof(struct text_run)); + for ( j=run; jn_runs; j++ ) { + para2->runs[j-run] = para1->runs[j]; + } + + /* Now break the run */ + para2->runs[0].text = strdup(para1->runs[run].text+run_offs); + para1->runs[run].text[run_offs] = '\0'; + para1->n_runs = run + 1; +} + + +static void delete_paragraph(SlideItem *item, int del, int delete_runs) { - /* FIXME */ -#if 0 int i; #ifdef HAVE_PANGO g_object_unref(item->paras[del].layout); #endif - free(item->paras[del].text); + + if ( delete_runs ) { + for ( i=0; iparas[del].n_runs; i++ ) { + free(item->paras[del].runs[i].text); + } + } for ( i=del; in_paras-1; i++ ) { item->paras[i] = item->paras[i+1]; } item->n_paras--; -#endif } -void slide_item_delete_text(SlideItem *item, int i1, size_t o1, int i2, size_t o2) +static void slide_paragraph_delete_text(struct slide_text_paragraph *para, + size_t o1, ssize_t o2) +{ + int r1, r2; + size_t roffs1, roffs2; + + r1 = slide_which_run(para, o1, &roffs1); + + /* This means 'delete to end' */ + if ( o2 == -1 ) { + int i; + o2 = 0; + for ( i=0; in_runs; i++ ) { + o2 += strlen(para->runs[i].text); + } + } + + r2 = slide_which_run(para, o2, &roffs2); + + if ( r1 == r2 ) { + + /* Easy case */ + memmove(¶->runs[r1].text[roffs1], + ¶->runs[r2].text[roffs2], + strlen(para->runs[r1].text)-roffs2+1); + + } else { + + int n_middle; + + /* Truncate the first run */ + para->runs[r1].text[roffs1] = '\0'; + + /* Delete any middle runs */ + n_middle = r2 - r1 - 1; + if ( n_middle > 0 ) { + memmove(¶->runs[r1+1], ¶->runs[r2], + (para->n_runs-r2)*sizeof(struct text_run)); + para->n_runs -= n_middle; + r2 -= n_middle; + } + + /* Last run */ + memmove(para->runs[r2].text, ¶->runs[r2].text[roffs2], + strlen(¶->runs[r2].text[roffs2])+1); + } +} + + +void slide_item_delete_text(SlideItem *item, int p1, size_t o1, int p2, size_t o2) { - /* FIXME */ -#if 0 int i; + struct text_run *new_runs; int n_del = 0; - /* Starting item */ - if ( i1 == i2 ) { - memmove(&item->paras[i1].text[o1], - &item->paras[i1].text[o2], - strlen(item->paras[i1].text)-o2+1); + /* Starting paragraph */ + if ( p1 == p2 ) { + slide_paragraph_delete_text(&item->paras[p1], o1, o2); return; /* easy case */ } else { - item->paras[i1].text[o1] = '\0'; + slide_paragraph_delete_text(&item->paras[p1], o1, -1); } /* Middle items */ - for ( i=i1+1; iparas[i2].text[0], - &item->paras[i2].text[o2], - strlen(&item->paras[i2].text[o2])+1); - - assert(i1 != i2); - char *new_text; - size_t len = strlen(item->paras[i1].text); - len += strlen(item->paras[i2].text); - new_text = malloc(len+1); - if ( new_text == NULL ) return; - strcpy(new_text, item->paras[i1].text); - strcat(new_text, item->paras[i2].text); - free(item->paras[i1].text); - item->paras[i1].text = new_text; - delete_paragraph(item, i2); -#endif + slide_paragraph_delete_text(&item->paras[p2], 0, o2); + + /* Move runs from p2 to p1, then delete p2 */ + assert(p1 != p2); + new_runs = realloc(item->paras[p1].runs, + (item->paras[p1].n_runs+item->paras[p2].n_runs)*sizeof(struct text_run)); + if ( new_runs == NULL ) return; + + memcpy(&new_runs[item->paras[p1].n_runs], item->paras[p2].runs, + item->paras[p2].n_runs*sizeof(struct text_run)); + item->paras[p1].n_runs += item->paras[p2].n_runs; + item->paras[p1].runs = new_runs; + + /* Delete the paragraph, but not the runs which we just copied */ + delete_paragraph(item, p2, 0); } -- cgit v1.2.3