From 528d0c29049546e130ab61dcc3f67d0ebc9a38cc Mon Sep 17 00:00:00 2001 From: Thomas White Date: Sun, 10 Mar 2019 10:58:20 +0100 Subject: Implement paragraph merge and forwards delete --- libstorycode/gtk/gtknarrativeview.c | 45 +++++++++++++++++-------------------- libstorycode/narrative.c | 22 ++++++++++++++++++ 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index 47ee43c..bf0d22c 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -722,47 +722,39 @@ static void cursor_moveh(Narrative *n, struct edit_pos *cp, signed int dir) } -static void do_backspace(GtkNarrativeView *e) +static void do_backspace(GtkNarrativeView *e, signed int dir) { Narrative *n; + struct edit_pos p1, p2; size_t o1, o2; n = presentation_get_narrative(e->p); if ( e->sel_active ) { - /* Delete the selected block */ - sort_positions(&e->sel_start, &e->sel_end); - o1 = pos_trail_to_offset(&n->items[e->sel_start.para], - e->sel_start.pos, e->sel_start.trail); - o2 = pos_trail_to_offset(&n->items[e->sel_end.para], - e->sel_end.pos, e->sel_end.trail); - narrative_delete_block(n, e->sel_start.para, o1, - e->sel_end.para, o2); - - /* Cursor goes at start of deletion */ - e->cpos = e->sel_start; - e->sel_active = 0; + /* Block delete */ + p1 = e->sel_start; + p2 = e->sel_end; } else { - struct edit_pos p1, p2; - /* Delete one character, as represented visually */ p2 = e->cpos; p1 = p2; - cursor_moveh(n, &p1, -1); - o1 = pos_trail_to_offset(&n->items[p1.para], p1.pos, p1.trail); - o2 = pos_trail_to_offset(&n->items[p2.para], p2.pos, p2.trail); - narrative_delete_block(n, p1.para, o1, p2.para, o2); - e->cpos = p1; - + cursor_moveh(n, &p1, dir); } + sort_positions(&p1, &p2); + o1 = pos_trail_to_offset(&n->items[p1.para], p1.pos, p1.trail); + o2 = pos_trail_to_offset(&n->items[p2.para], p2.pos, p2.trail); + narrative_delete_block(n, p1.para, o1, p2.para, o2); + e->cpos = p1; + e->sel_active = 0; + /* The only paragraphs which still exist and might have been * affected by the deletion are sel_start.para and the one * immediately afterwards. */ - rewrap_range(e, e->sel_start.para, e->sel_start.para+1); + rewrap_range(e, p1.para, p1.para+1); update_size(e); emit_change_sig(e); redraw(e); @@ -789,7 +781,7 @@ static void insert_text(char *t, GtkNarrativeView *e) struct narrative_item *item; if ( e->sel_active ) { - do_backspace(e); + do_backspace(e, 0); } item = get_current_item(e, &n); @@ -967,7 +959,12 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, break; case GDK_KEY_BackSpace : - do_backspace(e); + do_backspace(e, -1); + claim = 1; + break; + + case GDK_KEY_Delete : + do_backspace(e, +1); claim = 1; break; diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c index 8cb54c3..f32e8f0 100644 --- a/libstorycode/narrative.c +++ b/libstorycode/narrative.c @@ -27,6 +27,7 @@ #include #include +#include #include "narrative.h" #include "narrative_priv.h" @@ -155,12 +156,14 @@ static void delete_item(Narrative *n, int del) void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2) { int i; + int merge = 1; /* Starting item */ if ( n->items[i1].type == NARRATIVE_ITEM_SLIDE ) { delete_item(n, i1); i1--; i2--; + merge = 0; } else { if ( i1 == i2 ) { memmove(&n->items[i1].text[o1], @@ -181,8 +184,27 @@ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2) /* Last item */ if ( n->items[i2].type == NARRATIVE_ITEM_SLIDE ) { delete_item(n, i2); + merge = 0; } else { memmove(&n->items[i2].text[0], &n->items[i2].text[o2], o2); } + + /* If the start and end points are in different paragraphs, and both + * of them are text (any kind), merge them. Note that at this point, + * we know that i1 and i2 are different because otherwise we would've + * returned earlier ("easy case"). */ + assert(i1 != i2); + if ( merge ) { + char *new_text; + size_t len = strlen(n->items[i1].text); + len += strlen(n->items[i2].text); + new_text = malloc(len+1); + if ( new_text == NULL ) return; + strcpy(new_text, n->items[i1].text); + strcat(new_text, n->items[i2].text); + free(n->items[i1].text); + n->items[i1].text = new_text; + delete_item(n, i2); + } } -- cgit v1.2.3