aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-10-11 22:33:27 +0200
committerThomas White <taw@bitwiz.me.uk>2019-10-11 22:33:27 +0200
commit43ef7c6fbc161f0174946f8c7500f71f24924b75 (patch)
tree074a587902f5fed916e1d15b8b1dd6d63e507806
parent61a374637ac02ee73090a595323408904320a5f7 (diff)
Implement text deletion and paragraph splitting in slide text boxes
-rw-r--r--libstorycode/gtk/gtkslideview.c12
-rw-r--r--libstorycode/slide.c161
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; j<para1->n_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; i<item->paras[del].n_runs; i++ ) {
+ free(item->paras[del].runs[i].text);
+ }
+ }
for ( i=del; i<item->n_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; i<para->n_runs; i++ ) {
+ o2 += strlen(para->runs[i].text);
+ }
+ }
+
+ r2 = slide_which_run(para, o2, &roffs2);
+
+ if ( r1 == r2 ) {
+
+ /* Easy case */
+ memmove(&para->runs[r1].text[roffs1],
+ &para->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(&para->runs[r1+1], &para->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, &para->runs[r2].text[roffs2],
+ strlen(&para->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; i<i2; i++ ) {
+ for ( i=p1+1; i<p2; i++ ) {
/* Deleting the item moves all the subsequent items up, so the
* index to be deleted doesn't change. */
- delete_paragraph(item, i1+1);
+ delete_paragraph(item, p1+1, 1);
n_del++;
}
- i2 -= n_del;
+ p2 -= n_del;
/* Last item */
- memmove(&item->paras[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);
}