Clean up narrative item size arithmetic
authorThomas White <taw@bitwiz.me.uk>
Thu, 9 May 2019 22:08:38 +0000 (00:08 +0200)
committerThomas White <taw@bitwiz.me.uk>
Thu, 9 May 2019 22:20:30 +0000 (00:20 +0200)
libstorycode/gtk/gtknarrativeview.c
libstorycode/narrative.c
libstorycode/narrative_priv.h
libstorycode/narrative_render_cairo.c

index a174c9d..0876111 100644 (file)
@@ -473,37 +473,23 @@ static double para_top(Narrative *n, int pnum)
 {
        int i;
        double py = 0.0;
-       for ( i=0; i<pnum; i++ ) py += n->items[i].h;
-       return py + n->items[pnum].space_t;
+       for ( i=0; i<pnum; i++ ) py += narrative_item_get_height(n, i);
+       return py;
 }
 
 
 static void draw_para_highlight(cairo_t *cr, Narrative *n, int cursor_para,
                                 double w)
 {
-       double cx, cy, cw, ch;
+       double cx, cy;
        struct narrative_item *item;
 
        item = &n->items[cursor_para];
-       cx = n->space_l;
-       cy = n->space_t + para_top(n, cursor_para);
-       cw = w - n->space_l - n->space_r;
-
-       if ( item->type == NARRATIVE_ITEM_SLIDE ) {
-               ch = item->slide_h;
-       } else {
-               if ( item->layout != NULL ) {
-                       PangoRectangle rect;
-                       pango_layout_get_extents(item->layout, NULL, &rect);
-                       ch = pango_units_to_double(rect.height);
-               } else {
-                       ch = 0.0;
-                       fprintf(stderr, "No layout when drawing highlight box\n");
-               }
-       }
+       cx = item->space_l;
+       cy = para_top(n, cursor_para) + item->space_t;
 
        cairo_new_path(cr);
-       cairo_rectangle(cr, cx, cy, cw, ch);
+       cairo_rectangle(cr, cx-5.0, cy-5.0, item->obj_w+10.0, item->obj_h+10.0);
        cairo_set_source_rgba(cr, 0.7, 0.7, 1.0, 0.5);
        cairo_set_line_width(cr, 5.0);
        cairo_stroke(cr);
@@ -534,10 +520,10 @@ static void get_cursor_pos(Narrative *n, struct edit_pos cpos,
        struct narrative_item *item;
 
        item = &n->items[cpos.para];
-       if ( item->type == NARRATIVE_ITEM_SLIDE ) {
-               *x = n->space_l + item->space_l;
-               *y = n->space_t + para_top(n, cpos.para);
-               *h = item->slide_h;
+       if ( !narrative_item_is_text(n, cpos.para) ) {
+               *x = item->space_l;
+               *y = para_top(n, cpos.para) + item->space_t;
+               *h = item->obj_h + item->space_t + item->space_b;
                return;
        }
 
@@ -548,8 +534,8 @@ static void get_cursor_pos(Narrative *n, struct edit_pos cpos,
 
        offs = pos_trail_to_offset(item, cpos.pos, cpos.trail);
        pango_layout_get_cursor_pos(item->layout, offs, &rect, NULL);
-       *x = pango_units_to_double(rect.x) + n->space_l + item->space_l;
-       *y = pango_units_to_double(rect.y) + n->space_t + para_top(n, cpos.para);
+       *x = pango_units_to_double(rect.x) + item->space_l;
+       *y = pango_units_to_double(rect.y) + para_top(n, cpos.para) + item->space_t;
        *h = pango_units_to_double(rect.height);
 }
 
@@ -591,11 +577,14 @@ static void draw_caret(cairo_t *cr, Narrative *n, struct edit_pos cpos, double w
                /* Block highlight cursor */
 
                double cx, cy, cw, ch;
+               struct narrative_item *item;
+
+               item = &n->items[cpos.para];
 
-               cx = n->space_l - 5.5;
-               cy = n->space_t + para_top(n, cpos.para) - 5.5;
-               cw = n->items[cpos.para].slide_w + 11.0;
-               ch = n->items[cpos.para].slide_h + 11.0;
+               cx = item->space_l - 5.5;
+               cy = para_top(n, cpos.para) + item->space_t - 5.5;
+               cw = item->obj_w + 11.0;
+               ch = item->obj_h + 11.0;
 
                cairo_new_path(cr);
                cairo_rectangle(cr, cx, cy, cw, ch);
@@ -639,6 +628,7 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, GtkNarrativeView *e)
        narrative_render_cairo(e->n, cr, narrative_get_stylesheet(e->n));
 
        /* Editing overlay */
+       cairo_translate(cr, e->n->space_l, e->n->space_t);
        draw_overlay(cr, e);
 
        return FALSE;
@@ -667,7 +657,7 @@ static void check_cursor_visible(GtkNarrativeView *e)
 static size_t end_offset_of_para(Narrative *n, int pnum)
 {
        assert(pnum >= 0);
-       if ( n->items[pnum].type == NARRATIVE_ITEM_SLIDE ) return 0;
+       if ( !narrative_item_is_text(n, pnum) ) return 0;
        return strlen(n->items[pnum].text);
 }
 
@@ -698,7 +688,7 @@ static void cursor_moveh(Narrative *n, struct edit_pos *cp, signed int dir)
        int np = cp->pos;
        int otrail = cp->trail;
 
-       if ( item->type == NARRATIVE_ITEM_SLIDE ) {
+       if ( !narrative_item_is_text(n, cp->para) ) {
                if ( dir > 0 ) {
                        np = G_MAXINT;
                        cp->trail = 0;
@@ -834,7 +824,7 @@ static void split_paragraph_at_cursor(Narrative *n, struct edit_pos *pos)
 {
        size_t off;
 
-       if ( n->items[pos->para].type != NARRATIVE_ITEM_SLIDE ) {
+       if ( narrative_item_is_text(n, pos->para) ) {
                off = pos_trail_to_offset(&n->items[pos->para],
                                          pos->pos, pos->trail);
        } else {
@@ -872,7 +862,7 @@ static void insert_text(char *t, GtkNarrativeView *e)
                return;
        }
 
-       if ( item->type != NARRATIVE_ITEM_SLIDE ) {
+       if ( narrative_item_is_text(e->n, e->cpos.para) ) {
 
                size_t off;
 
@@ -907,12 +897,12 @@ static int find_cursor(Narrative *n, double x, double y, struct edit_pos *pos)
        cur_y = n->space_t;
 
        do {
-               cur_y += n->items[i++].h;
+               cur_y += narrative_item_get_height(n, i++);
        } while ( (cur_y < y) && (i<n->n_items) );
 
        pos->para = i-1;
        item = &n->items[pos->para];
-       if ( item->type == NARRATIVE_ITEM_SLIDE ) {
+       if ( !narrative_item_is_text(n, pos->para) ) {
                pos->pos = 0;
                return 0;
        }
index cefbd0d..6ed719a 100644 (file)
@@ -313,7 +313,7 @@ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2)
        int middle;    /* This is where the "middle deletion" will begin */
 
        /* Starting item */
-       if ( n->items[i1].type == NARRATIVE_ITEM_SLIDE ) {
+       if ( !narrative_item_is_text(n, i1) ) {
                delete_item(n, i1);
                if ( i1 == i2 ) return;  /* only one slide to delete */
                middle = i1; /* ... which is now the item just after the slide */
@@ -341,7 +341,7 @@ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2)
        i2 -= n_del;
 
        /* Last item */
-       if ( n->items[i2].type == NARRATIVE_ITEM_SLIDE ) {
+       if ( !narrative_item_is_text(n, i2) ) {
                delete_item(n, i2);
                return;
        }
@@ -379,7 +379,7 @@ void narrative_split_item(Narrative *n, int i1, size_t o1)
        item1 = &n->items[i1];
        item2 = insert_item(n, i1);
 
-       if ( item1->type != NARRATIVE_ITEM_SLIDE ) {
+       if ( !narrative_item_is_text(n, i1) ) {
                item2->text = strdup(&item1->text[o1]);
                item1->text[o1] = '\0';
        } else {
index 7ba7028..cea2a53 100644 (file)
@@ -44,11 +44,19 @@ enum narrative_item_type
 struct narrative_item
 {
        enum narrative_item_type type;
-       double h;
+
+       /* Space around the thing (PangoLayout, slide, marker etc) */
        double space_l;
        double space_r;
-       double space_t;  /* Already included in "h" */
-       double space_b;  /* Already included in "h" */
+       double space_t;
+       double space_b;
+
+       /* Size of the thing (PangoLayout, slide, marker etc) */
+       double obj_w;
+       double obj_h;
+
+       /* Total height is obj_h + space_t + space_b.
+        * obj_w + space_l + space_r might be less than width of rendering surface */
 
        /* For TEXT, BP, PRESTITLE */
        char *text;
@@ -61,8 +69,6 @@ struct narrative_item
 
        /* For SLIDE */
        Slide *slide;
-       double slide_w;
-       double slide_h;
 #ifdef HAVE_CAIRO
        cairo_surface_t *slide_thumbnail;
 #else
index db1590f..160fc46 100644 (file)
@@ -75,7 +75,6 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
        const char *font;
        PangoFontDescription *fontdesc;
        enum alignment align;
-       struct length paraspace[4];
        double wrap_w;
        PangoAttrList *attrs;
        PangoAttribute *attr;
@@ -94,12 +93,6 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
                palignment = to_pangoalignment(item->align);
        }
 
-       if ( stylesheet_get_paraspace(ss, stn, paraspace) ) return;
-       item->space_l = lcalc(paraspace[0], w);
-       item->space_r = lcalc(paraspace[1], w);
-       item->space_t = lcalc(paraspace[2], dummy_h_val);
-       item->space_b = lcalc(paraspace[3], dummy_h_val);
-
        /* Calculate width of actual text */
        wrap_w = w - item->space_l - item->space_r;
 
@@ -134,7 +127,8 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
        //pango_attr_list_unref(attrs);
 
        pango_layout_get_extents(item->layout, NULL, &rect);
-       item->h = pango_units_to_double(rect.height)+item->space_t+item->space_b;
+       item->obj_w = pango_units_to_double(rect.width);
+       item->obj_h = pango_units_to_double(rect.height);
 }
 
 
@@ -185,34 +179,26 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore *
 {
        double w, h;
 
-       item->space_l = 0.0;
-       item->space_r = 0.0;
-       item->space_t = 10.0;
-       item->space_b = 10.0;
-
        slide_get_logical_size(item->slide, ss, &w, &h);
-       item->slide_h = 320.0;  /* Actual height of thumbnail */
-       item->slide_w = rint(item->slide_h*w/h);
-
-       item->h = item->slide_h + item->space_t + item->space_b;
+       item->obj_h = 320.0;  /* Actual height of thumbnail */
+       item->obj_w = rint(item->obj_h*w/h);
 
        if ( item->slide_thumbnail != NULL ) {
                cairo_surface_destroy(item->slide_thumbnail);
        }
        item->slide_thumbnail = render_thumbnail(item->slide, ss, is,
-                                                item->slide_w, item->slide_h);
+                                                item->obj_w, item->obj_h);
        item->selected = sel_block;
 }
 
 
-static size_t pos_trail_to_offset(struct narrative_item *item, int offs, int trail)
+static size_t pos_trail_to_offset(Narrative *n, int i, int offs, int trail)
 {
        glong char_offs;
        char *ptr;
+       struct narrative_item *item = &n->items[i];
 
-       if ( item->type == NARRATIVE_ITEM_SLIDE ) {
-               return offs;
-       }
+       if ( !narrative_item_is_text(n, i) ) return offs;
 
        char_offs = g_utf8_pointer_to_offset(item->text, item->text+offs);
        char_offs += trail;
@@ -258,6 +244,8 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
        int i;
        struct length pad[4];
        int sel_s, sel_e;
+       const char *stn;
+       struct length paraspace[4];
 
        if ( stylesheet_get_padding(stylesheet, "NARRATIVE", pad) ) return 1;
        n->space_l = lcalc(pad[0], w);
@@ -273,11 +261,8 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
        if ( max >= n->n_items ) max = n->n_items-1;
 
        if ( !positions_equal(sel_start, sel_end) ) {
-               struct narrative_item *item;
-               item = &n->items[sel_start.para];
-               sel_s = pos_trail_to_offset(item, sel_start.pos, sel_start.trail);
-               item = &n->items[sel_end.para];
-               sel_e = pos_trail_to_offset(item, sel_end.pos, sel_end.trail);
+               sel_s = pos_trail_to_offset(n, sel_start.para, sel_start.pos, sel_start.trail);
+               sel_e = pos_trail_to_offset(n, sel_end.para, sel_end.pos, sel_end.trail);
        } else {
                sel_s = 0;
                sel_e = 0;
@@ -311,27 +296,43 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
                switch ( n->items[i].type ) {
 
                        case NARRATIVE_ITEM_TEXT :
-                       wrap_text(&n->items[i], pc, stylesheet,
-                                 "NARRATIVE", w, srt, end);
+                       stn = "NARRATIVE.TEXT";
                        break;
 
                        case NARRATIVE_ITEM_BP :
-                       wrap_text(&n->items[i], pc, stylesheet,
-                                 "NARRATIVE.BP", w, srt, end);
+                       stn = "NARRATIVE.BP";
+                       break;
+
+                       case NARRATIVE_ITEM_PRESTITLE :
+                       stn = "NARRATIVE.PRESTITLE";
                        break;
 
+                       case NARRATIVE_ITEM_SLIDE :
+                       stn = "NARRATIVE.SLIDE";
+                       break;
+               }
+
+               if ( stylesheet_get_paraspace(stylesheet, stn, paraspace) == 0 ) {
+                       n->items[i].space_l = lcalc(paraspace[0], w);
+                       n->items[i].space_r = lcalc(paraspace[1], w);
+                       n->items[i].space_t = lcalc(paraspace[2], dummy_h_val);
+                       n->items[i].space_b = lcalc(paraspace[3], dummy_h_val);
+               }
+
+               switch ( n->items[i].type ) {
+
+                       case NARRATIVE_ITEM_TEXT :
+                       case NARRATIVE_ITEM_BP :
                        case NARRATIVE_ITEM_PRESTITLE :
                        wrap_text(&n->items[i], pc, stylesheet,
-                                 "NARRATIVE.PRESTITLE", w, srt, end);
+                                 stn, w, srt, end);
                        break;
 
                        case NARRATIVE_ITEM_SLIDE :
                        wrap_slide(&n->items[i], stylesheet, is, sel_block);
                        break;
 
-                       default :
                        break;
-
                }
        }
 
@@ -341,7 +342,7 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
 
 double narrative_item_get_height(Narrative *n, int i)
 {
-       return n->items[i].h;
+       return n->items[i].obj_h + n->items[i].space_t + n->items[i].space_b;
 }
 
 
@@ -350,7 +351,7 @@ double narrative_get_height(Narrative *n)
        int i;
        double total = 0.0;
        for ( i=0; i<n->n_items; i++ ) {
-               total += n->items[i].h;
+               total += narrative_item_get_height(n, i);
        }
        return total + n->space_t + n->space_b;
 }
@@ -369,16 +370,16 @@ static void draw_slide(struct narrative_item *item, cairo_t *cr)
        cairo_device_to_user(cr, &x, &y);
 
        if ( item->selected ) {
-               cairo_rectangle(cr, x-5.0, y-5.0, item->slide_w+10.0, item->slide_h+10.0);
+               cairo_rectangle(cr, x-5.0, y-5.0, item->obj_w+10.0, item->obj_h+10.0);
                cairo_set_source_rgb(cr, 0.655, 0.899, 1.0);
                cairo_fill(cr);
        }
 
-       cairo_rectangle(cr, x, y, item->slide_w, item->slide_h);
+       cairo_rectangle(cr, x, y, item->obj_w, item->obj_h);
        cairo_set_source_surface(cr, item->slide_thumbnail, 0.0, 0.0);
        cairo_fill(cr);
 
-       cairo_rectangle(cr, x+0.5, y+0.5, item->slide_w, item->slide_h);
+       cairo_rectangle(cr, x+0.5, y+0.5, item->obj_w, item->obj_h);
        cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
        cairo_set_line_width(cr, 1.0);
        cairo_stroke(cr);
@@ -477,7 +478,7 @@ int narrative_render_cairo(Narrative *n, cairo_t *cr, Stylesheet *stylesheet)
 
        for ( i=0; i<n->n_items; i++ ) {
                narrative_render_item_cairo(n, cr, i);
-               cairo_translate(cr, 0.0, n->items[i].h);
+               cairo_translate(cr, 0.0, narrative_item_get_height(n, i));
        }
 
        cairo_restore(cr);