From 387858893a1a858e8205aae28a3609006c0c717d Mon Sep 17 00:00:00 2001 From: Thomas White Date: Fri, 20 Sep 2019 17:12:29 +0200 Subject: Parse emphasis blocks in Bison --- data/demo.sc | 2 + libstorycode/gtk/gtkslideview.c | 39 ++++--- libstorycode/narrative.c | 57 ++++------ libstorycode/narrative.h | 18 +-- libstorycode/narrative_priv.h | 9 +- libstorycode/narrative_render_cairo.c | 65 +---------- libstorycode/render_cairo_common.c | 97 +++++++++++++++++ libstorycode/render_cairo_common.h | 36 ++++++ libstorycode/scparse_priv.h | 5 - libstorycode/slide.c | 42 ++++--- libstorycode/slide.h | 7 +- libstorycode/slide_priv.h | 3 +- libstorycode/slide_render_cairo.c | 26 +++-- libstorycode/slide_render_cairo.h | 3 +- libstorycode/storycode.c | 23 +++- libstorycode/storycode.h | 15 +++ libstorycode/storycode.y | 199 ++++++++++++++++++++++------------ meson.build | 1 + src/slide_window.c | 12 +- 19 files changed, 418 insertions(+), 241 deletions(-) create mode 100644 libstorycode/render_cairo_common.c create mode 100644 libstorycode/render_cairo_common.h diff --git a/data/demo.sc b/data/demo.sc index 8d1548e..1c71ed2 100644 --- a/data/demo.sc +++ b/data/demo.sc @@ -69,6 +69,8 @@ SLIDE { : Change their shape and size by shift-dragging the handles at the corners. } : You can add a new slide from the "Insert" menu or using the toolbar at the top of the narrative window. Try it now: click to place the cursor at the end of this paragraph, then add a new slide. +: Here is a web link: https:\/\/www.bitwiz.me.uk\/some\/where\/index.html +: Here is a setence with overlapping runs: _hello _*world*_ !!!!11one_ : What is the narrative window for? Well, it's up to you! Here are some suggestions: BP: Use it just to help plan a smooth flow for your talk, reading it through to spot awkward transitions. BP: Write your talk word for word. Deliver your talk precisely as you planned it, no matter how nervous you get. diff --git a/libstorycode/gtk/gtkslideview.c b/libstorycode/gtk/gtkslideview.c index 0ec1c5f..b3d56fc 100644 --- a/libstorycode/gtk/gtkslideview.c +++ b/libstorycode/gtk/gtkslideview.c @@ -161,17 +161,17 @@ static void draw_resize_handle(cairo_t *cr, double x, double y) } -static size_t pos_trail_to_offset(SlideItem *item, int para, +static size_t pos_trail_to_offset(SlideItem *item, int para, int run, size_t offs, int trail) { glong char_offs; char *ptr; - char_offs = g_utf8_pointer_to_offset(item->paras[para].text, - item->paras[para].text+offs); + char_offs = g_utf8_pointer_to_offset(item->paras[para].runs[run].text, + item->paras[para].runs[run].text+offs); char_offs += trail; - ptr = g_utf8_offset_to_pointer(item->paras[para].text, char_offs); - return ptr - item->paras[para].text; + ptr = g_utf8_offset_to_pointer(item->paras[para].runs[run].text, char_offs); + return ptr - item->paras[para].runs[run].text; } @@ -206,7 +206,7 @@ static int get_cursor_pos(SlideItem *item, Stylesheet *stylesheet, slide_item_get_padding(item, stylesheet, &padl, &padr, &padt, &padb, slide_w, slide_h); - offs = pos_trail_to_offset(item, cpos.para, cpos.pos, cpos.trail); + offs = pos_trail_to_offset(item, cpos.para, cpos.run, cpos.pos, cpos.trail); pango_layout_get_cursor_pos(item->paras[cpos.para].layout, offs, &rect, NULL); *x = pango_units_to_double(rect.x) + padl; *y = pango_units_to_double(rect.y) + para_top(item, cpos.para) + padt; @@ -841,10 +841,15 @@ static SlideItem *create_frame(GtkSlideView *e, double cx, double cy, double w, double h) { struct frame_geom geom; - char *text; + struct text_run *runs; + int nruns = 1; - text = strdup(""); - if ( text == NULL ) return NULL; + /* Ownership of this struct will be taken over by the Slide. */ + runs = malloc(sizeof(struct text_run)); + if ( runs == NULL ) return NULL; + runs[0].type = TEXT_RUN_NORMAL; + runs[0].text = strdup("Slide title"); + if ( runs[0].text == NULL ) return NULL; if ( w < 0.0 ) { cx += w; @@ -860,7 +865,7 @@ static SlideItem *create_frame(GtkSlideView *e, double cx, double cy, geom.y.len = cy; geom.y.unit = LENGTH_UNIT; geom.w.len = w; geom.w.unit = LENGTH_UNIT; geom.h.len = h; geom.h.unit = LENGTH_UNIT; - return slide_add_text(e->slide, &text, 1, geom, ALIGN_INHERIT); + return slide_add_text(e->slide, &runs, &nruns, 1, geom, ALIGN_INHERIT); } @@ -932,9 +937,11 @@ static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event, static size_t end_offset_of_para(SlideItem *item, int pnum) { + struct slide_text_paragraph *para; assert(pnum >= 0); if ( !is_text(item->type) ) return 0; - return strlen(item->paras[pnum].text); + para = &item->paras[pnum]; + return strlen(para->runs[para->n_runs-1].text); } @@ -1018,6 +1025,7 @@ static void sort_slide_positions(struct slide_pos *a, struct slide_pos *b) static void do_backspace(GtkSlideView *e, signed int dir) { +#if 0 struct slide_pos p1, p2; size_t o1, o2; @@ -1041,8 +1049,8 @@ static void do_backspace(GtkSlideView *e, signed int dir) } sort_slide_positions(&p1, &p2); - o1 = pos_trail_to_offset(e->cursor_frame, p1.para, p1.pos, p1.trail); - o2 = pos_trail_to_offset(e->cursor_frame, p2.para, p2.pos, p2.trail); + 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); slide_item_delete_text(e->cursor_frame, p1.para, o1, p2.para, o2); e->cpos = p1; unset_selection(e); @@ -1052,12 +1060,14 @@ static void do_backspace(GtkSlideView *e, signed int dir) emit_change_sig(e); redraw(e); +#endif } static void insert_text_in_paragraph(SlideItem *item, int para, size_t offs, char *t) { +#if 0 char *n = malloc(strlen(t) + strlen(item->paras[para].text) + 1); if ( n == NULL ) return; strncpy(n, item->paras[para].text, offs); @@ -1066,11 +1076,13 @@ static void insert_text_in_paragraph(SlideItem *item, int para, strcat(n, item->paras[para].text+offs); free(item->paras[para].text); item->paras[para].text = n; +#endif } static void insert_text(char *t, GtkSlideView *e) { +#if 0 size_t off; if ( e->cursor_frame == NULL ) return; @@ -1101,6 +1113,7 @@ static void insert_text(char *t, GtkSlideView *e) cursor_moveh(e, &e->cpos, +1); emit_change_sig(e); redraw(e); +#endif } diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c index 6ed427d..b1e156a 100644 --- a/libstorycode/narrative.c +++ b/libstorycode/narrative.c @@ -102,19 +102,19 @@ void narrative_free(Narrative *n) void narrative_add_empty_item(Narrative *n) { - char **texts; - enum narrative_run_type *types; - char *text; - - texts = malloc(sizeof(char *)); - types = malloc(sizeof(enum narrative_run_type)); - text = strdup(""); - - if ( (texts != NULL) && (types != NULL) && (text != NULL) ) { - texts[0] = text; - types[0] = NARRATIVE_RUN_NORMAL; - narrative_add_text(n, texts, types, 1); + struct text_run *runs; + + runs = malloc(sizeof(struct text_run)); + if ( runs == NULL ) return; + + runs[0].text = strdup(""); + runs[0].type = TEXT_RUN_NORMAL; + if ( runs[0].text == NULL ) { + free(runs); + return; } + + narrative_add_text(n, runs, 1); } @@ -256,11 +256,11 @@ static struct narrative_item *insert_item(Narrative *n, int pos) } -extern void add_text_item(Narrative *n, char **texts, enum narrative_run_type *types, - int n_runs, enum narrative_item_type type) +/* The new text item takes ownership of the array of runs */ +extern void add_text_item(Narrative *n, struct text_run *runs, int n_runs, + enum narrative_item_type type) { struct narrative_item *item; - int i; item = add_item(n); if ( item == NULL ) return; @@ -269,39 +269,26 @@ extern void add_text_item(Narrative *n, char **texts, enum narrative_run_type *t item->align = ALIGN_INHERIT; item->layout = NULL; - /* Add all the runs */ - item->runs = malloc(n_runs * sizeof(struct narrative_text_run)); - if ( item->runs == NULL ) { - item->n_runs = 0; - return; - } - - for ( i=0; iruns[i].type = types[i]; - item->runs[i].text = texts[i]; - } + item->runs = runs; item->n_runs = n_runs; } -void narrative_add_text(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs) +void narrative_add_text(Narrative *n, struct text_run *runs, int n_runs) { - add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_TEXT); + add_text_item(n, runs, n_runs, NARRATIVE_ITEM_TEXT); } -void narrative_add_prestitle(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs) +void narrative_add_prestitle(Narrative *n, struct text_run *runs, int n_runs) { - add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_PRESTITLE); + add_text_item(n, runs, n_runs, NARRATIVE_ITEM_PRESTITLE); } -void narrative_add_bp(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs) +void narrative_add_bp(Narrative *n, struct text_run *runs, int n_runs) { - add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_BP); + add_text_item(n, runs, n_runs, NARRATIVE_ITEM_BP); } diff --git a/libstorycode/narrative.h b/libstorycode/narrative.h index a51136b..c5cb6f3 100644 --- a/libstorycode/narrative.h +++ b/libstorycode/narrative.h @@ -31,15 +31,8 @@ typedef struct _narrative Narrative; -enum narrative_run_type -{ - NARRATIVE_RUN_NORMAL, - NARRATIVE_RUN_BOLD, - NARRATIVE_RUN_ITALIC, - NARRATIVE_RUN_UNDERLINE, -}; - #include "slide.h" +#include "storycode.h" #include "imagestore.h" extern Narrative *narrative_new(void); @@ -60,14 +53,11 @@ extern int narrative_get_unsaved(Narrative *n); extern int narrative_item_is_text(Narrative *n, int item); -extern void narrative_add_text(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs); +extern void narrative_add_text(Narrative *n, struct text_run *runs, int n_runs); -extern void narrative_add_bp(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs); +extern void narrative_add_bp(Narrative *n, struct text_run *runs, int n_runs); -extern void narrative_add_prestitle(Narrative *n, char **texts, - enum narrative_run_type *types, int n_runs); +extern void narrative_add_prestitle(Narrative *n, struct text_run *runs, int n_runs); extern void narrative_add_slide(Narrative *n, Slide *slide); extern void narrative_add_eop(Narrative *n); diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h index c783df2..4862455 100644 --- a/libstorycode/narrative_priv.h +++ b/libstorycode/narrative_priv.h @@ -42,13 +42,6 @@ enum narrative_item_type }; -struct narrative_text_run -{ - enum narrative_run_type type; - char *text; -}; - - struct narrative_item { enum narrative_item_type type; @@ -68,7 +61,7 @@ struct narrative_item /* For TEXT, BP, PRESTITLE */ int n_runs; - struct narrative_text_run *runs; + struct text_run *runs; enum alignment align; #ifdef HAVE_PANGO PangoLayout *layout; diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c index 8b009b5..c4d566f 100644 --- a/libstorycode/narrative_render_cairo.c +++ b/libstorycode/narrative_render_cairo.c @@ -42,6 +42,7 @@ #include "imagestore.h" #include "slide_render_cairo.h" #include "narrative_render_cairo.h" +#include "render_cairo_common.h" #include "narrative_priv.h" @@ -122,71 +123,15 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc, pango_layout_set_width(item->layout, pango_units_from_double(wrap_w)); pango_layout_set_alignment(item->layout, palignment); pango_layout_set_font_description(item->layout, fontdesc); - - size_t total_len = 0; - int i; - char *text; - - /* Work out length of all text in item (paragraph) */ - for ( i=0; in_runs; i++ ) { - total_len += strlen(item->runs[i].text); - } - - /* Allocate the complete text */ - text = malloc(total_len+1); - if ( text == NULL ) { - fprintf(stderr, "Couldn't allocate combined text (%lli)\n", - (long long int)total_len); - return; - } - - /* Put all of the text together */ - text[0] = '\0'; - size_t pos = 0; - for ( i=0; in_runs; i++ ) { - - PangoAttribute *attr = NULL; - size_t run_len = strlen(item->runs[i].text); - - switch ( item->runs[i].type ) { - - case NARRATIVE_RUN_NORMAL : - break; - - case NARRATIVE_RUN_BOLD: - attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - break; - - case NARRATIVE_RUN_ITALIC: - attr = pango_attr_style_new(PANGO_STYLE_ITALIC); - break; - - case NARRATIVE_RUN_UNDERLINE: - attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); - break; - - - - } - - if ( attr != NULL ) { - attr->start_index = pos; - attr->end_index = pos + run_len; - pango_attr_list_insert(attrs, attr); - } - - /* FIXME: Should check that each bit of text finishes on a character boundary */ - pos += run_len; - strcat(text, item->runs[i].text); - - } pango_layout_set_attributes(item->layout, attrs); - pango_layout_set_text(item->layout, text, -1); - pango_attr_list_unref(attrs); + + if ( runs_to_pangolayout(item->layout, item->runs, item->n_runs) ) return; pango_layout_get_extents(item->layout, NULL, &rect); item->obj_w = pango_units_to_double(rect.width); item->obj_h = pango_units_to_double(rect.height); + + pango_attr_list_unref(attrs); } diff --git a/libstorycode/render_cairo_common.c b/libstorycode/render_cairo_common.c new file mode 100644 index 0000000..b3883c9 --- /dev/null +++ b/libstorycode/render_cairo_common.c @@ -0,0 +1,97 @@ +/* + * render_cairo_common.c + * + * Copyright © 2019 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "storycode.h" + +int runs_to_pangolayout(PangoLayout *layout, struct text_run *runs, int n_runs) +{ + size_t total_len = 0; + int i; + char *text; + PangoAttrList *attrs; + + attrs = pango_layout_get_attributes(layout); + + /* Work out length of all text in item (paragraph) */ + for ( i=0; istart_index = pos; + attr->end_index = pos + run_len; + pango_attr_list_insert(attrs, attr); + } + + /* FIXME: Should check that each bit of text finishes on a character boundary */ + pos += run_len; + strcat(text, runs[i].text); + + } + pango_layout_set_text(layout, text, -1); + + return 0; +} diff --git a/libstorycode/render_cairo_common.h b/libstorycode/render_cairo_common.h new file mode 100644 index 0000000..69272ef --- /dev/null +++ b/libstorycode/render_cairo_common.h @@ -0,0 +1,36 @@ +/* + * render_cairo_common.h + * + * Copyright © 2019 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef RENDER_CAIRO_COMMON_H +#define RENDER_CAIRO_COMMON_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "storycode.h" + +extern int runs_to_pangolayout(PangoLayout *layout, struct text_run *runs, int n_runs); + +#endif /* RENDER_CAIRO_COMMON_H */ diff --git a/libstorycode/scparse_priv.h b/libstorycode/scparse_priv.h index 98ddbda..2b1dd16 100644 --- a/libstorycode/scparse_priv.h +++ b/libstorycode/scparse_priv.h @@ -42,11 +42,6 @@ struct scpctx Narrative *n; Slide *s; - int n_runs; - int max_runs; - char **runs; - enum narrative_run_type *run_types; - /* Current style or frame options. * These will be copied to a stylesheet entry or frame when the * top-level rule is matched. */ diff --git a/libstorycode/slide.c b/libstorycode/slide.c index fc7b24c..1e79aaf 100644 --- a/libstorycode/slide.c +++ b/libstorycode/slide.c @@ -103,8 +103,16 @@ SlideItem *slide_add_image(Slide *s, char *filename, struct frame_geom geom) } -static SlideItem *add_text_item(Slide *s, char **text, int n_text, struct frame_geom geom, - enum alignment alignment, enum slide_item_type slide_item) +/* paras: array of arrays of text runs + * n_runs: array of numbers of runs in each paragraph + * n_paras: the number of paragraphs + * + * Will take ownership of the arrays of text runs, but not the array of arrays + * Will NOT take ownership of the array of numbers of runs + */ +static SlideItem *add_text_item(Slide *s, struct text_run **paras, int *n_runs, int n_paras, + struct frame_geom geom, enum alignment alignment, + enum slide_item_type slide_item) { int i; SlideItem *item; @@ -113,18 +121,18 @@ static SlideItem *add_text_item(Slide *s, char **text, int n_text, struct frame_ if ( item == NULL ) return NULL; item->type = slide_item; - item->paras = malloc(n_text*sizeof(struct slide_text_paragraph)); + item->paras = malloc(n_paras*sizeof(struct slide_text_paragraph)); if ( item->paras == NULL ) { s->n_items--; return NULL; } + item->n_paras = n_paras; - for ( i=0; in_paras = n_text; - item->paras[i].text = text[i]; + for ( i=0; iparas[i].runs = paras[i]; + item->paras[i].n_runs = n_runs[i]; item->paras[i].layout = NULL; } - item->n_paras = n_text; item->geom = geom; item->align = alignment; @@ -146,15 +154,15 @@ int slide_add_footer(Slide *s) } -SlideItem *slide_add_text(Slide *s, char **text, int n_text, struct frame_geom geom, - enum alignment alignment) +SlideItem *slide_add_text(Slide *s, struct text_run **paras, int *n_runs, int n_paras, + struct frame_geom geom, enum alignment alignment) { - return add_text_item(s, text, n_text, geom, alignment, + return add_text_item(s, paras, n_runs, n_paras, geom, alignment, SLIDE_ITEM_TEXT); } -SlideItem *slide_add_slidetitle(Slide *s, char **text, int n_text) +SlideItem *slide_add_slidetitle(Slide *s, struct text_run **paras, int *n_runs, int n_paras) { struct frame_geom geom; @@ -168,12 +176,12 @@ SlideItem *slide_add_slidetitle(Slide *s, char **text, int n_text) geom.h.len = 1.0; geom.h.unit = LENGTH_FRAC; - return add_text_item(s, text, n_text, geom, ALIGN_INHERIT, + return add_text_item(s, paras, n_runs, n_paras, geom, ALIGN_INHERIT, SLIDE_ITEM_SLIDETITLE); } -SlideItem *slide_add_prestitle(Slide *s, char **text, int n_text) +SlideItem *slide_add_prestitle(Slide *s, struct text_run **paras, int *n_runs, int n_paras) { struct frame_geom geom; @@ -187,7 +195,7 @@ SlideItem *slide_add_prestitle(Slide *s, char **text, int n_text) geom.h.len = 1.0; geom.h.unit = LENGTH_FRAC; - return add_text_item(s, text, n_text, geom, ALIGN_INHERIT, + return add_text_item(s, paras, n_runs, n_paras, geom, ALIGN_INHERIT, SLIDE_ITEM_PRESTITLE); } @@ -324,6 +332,7 @@ void slide_item_get_padding(SlideItem *item, Stylesheet *ss, void slide_item_split_text_paragraph(SlideItem *item, int para, size_t off) { +#if 0 struct slide_text_paragraph *np; np = realloc(item->paras, (item->n_paras+1)*sizeof(struct slide_text_paragraph)); @@ -338,11 +347,13 @@ void slide_item_split_text_paragraph(SlideItem *item, int para, size_t off) item->paras[para+1].text = strdup(&item->paras[para].text[off]); item->paras[para+1].layout = NULL; item->paras[para].text[off] = '\0'; +#endif } static void delete_paragraph(SlideItem *item, int del) { +#if 0 int i; #ifdef HAVE_PANGO @@ -354,11 +365,13 @@ static void delete_paragraph(SlideItem *item, int del) 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) { +#if 0 int i; int n_del = 0; @@ -397,4 +410,5 @@ void slide_item_delete_text(SlideItem *item, int i1, size_t o1, int i2, size_t o free(item->paras[i1].text); item->paras[i1].text = new_text; delete_paragraph(item, i2); +#endif } diff --git a/libstorycode/slide.h b/libstorycode/slide.h index 3dbd20e..87635b8 100644 --- a/libstorycode/slide.h +++ b/libstorycode/slide.h @@ -33,6 +33,7 @@ typedef struct _slide Slide; typedef struct _slideitem SlideItem; #include "stylesheet.h" +#include "storycode.h" extern Slide *slide_new(void); extern void slide_free(Slide *s); @@ -40,11 +41,11 @@ extern void slide_free(Slide *s); extern void slide_delete_item(Slide *s, SlideItem *item); extern SlideItem *slide_add_image(Slide *s, char *filename, struct frame_geom geom); -extern SlideItem *slide_add_text(Slide *s, char **text, int n_text, +extern SlideItem *slide_add_text(Slide *s, struct text_run **paras, int *n_runs, int n_paras, struct frame_geom geom, enum alignment alignment); extern int slide_add_footer(Slide *s); -extern SlideItem *slide_add_slidetitle(Slide *s, char **text, int n_text); -extern SlideItem *slide_add_prestitle(Slide *s, char **text, int n_text); +extern SlideItem *slide_add_slidetitle(Slide *s, struct text_run **paras, int *n_runs, int n_paras); +extern SlideItem *slide_add_prestitle(Slide *s, struct text_run **paras, int *n_runs, int n_paras); extern int slide_set_logical_size(Slide *s, double w, double h); extern int slide_get_logical_size(Slide *s, Stylesheet *ss, double *w, double *h); diff --git a/libstorycode/slide_priv.h b/libstorycode/slide_priv.h index 8479463..64e6d75 100644 --- a/libstorycode/slide_priv.h +++ b/libstorycode/slide_priv.h @@ -41,7 +41,8 @@ enum slide_item_type struct slide_text_paragraph { - char *text; + struct text_run *runs; + int n_runs; #ifdef HAVE_PANGO PangoLayout *layout; #else diff --git a/libstorycode/slide_render_cairo.c b/libstorycode/slide_render_cairo.c index cfce28c..6a27787 100644 --- a/libstorycode/slide_render_cairo.c +++ b/libstorycode/slide_render_cairo.c @@ -41,6 +41,7 @@ #include "stylesheet.h" #include "imagestore.h" #include "slide_render_cairo.h" +#include "render_cairo_common.h" #include "slide_priv.h" @@ -75,17 +76,17 @@ static int slide_positions_equal(struct slide_pos a, struct slide_pos b) } -static size_t pos_trail_to_offset(SlideItem *item, int para, +static size_t pos_trail_to_offset(SlideItem *item, int para, int run, size_t offs, int trail) { glong char_offs; char *ptr; - char_offs = g_utf8_pointer_to_offset(item->paras[para].text, - item->paras[para].text+offs); + char_offs = g_utf8_pointer_to_offset(item->paras[para].runs[run].text, + item->paras[para].runs[run].text+offs); char_offs += trail; - ptr = g_utf8_offset_to_pointer(item->paras[para].text, char_offs); - return ptr - item->paras[para].text; + ptr = g_utf8_offset_to_pointer(item->paras[para].runs[run].text, char_offs); + return ptr - item->paras[para].runs[run].text; } @@ -191,8 +192,10 @@ static void render_text(SlideItem *item, cairo_t *cr, PangoContext *pc, } if ( !slide_positions_equal(sel_start, sel_end) ) { - sel_s = pos_trail_to_offset(item, sel_start.para, sel_start.pos, sel_start.trail); - sel_e = pos_trail_to_offset(item, sel_end.para, sel_end.pos, sel_end.trail); + sel_s = pos_trail_to_offset(item, sel_start.para, sel_start.run, + sel_start.pos, sel_start.trail); + sel_e = pos_trail_to_offset(item, sel_end.para, sel_end.run, + sel_end.pos, sel_end.trail); } else { sel_s = 0; sel_e = 0; @@ -245,10 +248,7 @@ static void render_text(SlideItem *item, cairo_t *cr, PangoContext *pc, } pango_layout_set_width(item->paras[i].layout, pango_units_from_double(w-pad_l-pad_r)); - pango_layout_set_text(item->paras[i].layout, item->paras[i].text, -1); - pango_layout_set_alignment(item->paras[i].layout, palignment); - pango_layout_set_font_description(item->paras[i].layout, fontdesc); attrs = pango_attr_list_new(); @@ -261,9 +261,11 @@ static void render_text(SlideItem *item, cairo_t *cr, PangoContext *pc, pango_attr_list_insert(attrs, attr); } - /* FIXME: Handle *bold*, _underline_, /italic/ etc. */ - pango_layout_set_attributes(item->paras[i].layout, attrs); + + runs_to_pangolayout(item->paras[i].layout, item->paras[i].runs, + item->paras[i].n_runs); + pango_attr_list_unref(attrs); /* FIXME: Clip to w,h */ diff --git a/libstorycode/slide_render_cairo.h b/libstorycode/slide_render_cairo.h index 6589945..9587007 100644 --- a/libstorycode/slide_render_cairo.h +++ b/libstorycode/slide_render_cairo.h @@ -33,7 +33,8 @@ struct slide_pos { int para; /* Paragraph number (corresponding to narrative items) */ - int pos; /* Byte position within paragraph (yes, really) */ + int run; /* Run number */ + int pos; /* Byte position within run (yes, really) */ int trail; /* 1 = end of character, 0 = before */ }; diff --git a/libstorycode/storycode.c b/libstorycode/storycode.c index e17d5dd..c35afcb 100644 --- a/libstorycode/storycode.c +++ b/libstorycode/storycode.c @@ -107,6 +107,25 @@ static const char *maybe_alignment(enum alignment ali) } +static void write_run_border(GOutputStream *fh, enum text_run_type t) +{ + if ( t == TEXT_RUN_BOLD ) write_string(fh, "*"); + if ( t == TEXT_RUN_ITALIC ) write_string(fh, "/"); + if ( t == TEXT_RUN_UNDERLINE ) write_string(fh, "_"); +} + + +static void write_para(GOutputStream *fh, struct text_run *runs, int n_runs) +{ + int i; + for ( i=0; iparas[0].text); + write_para(fh, &item->paras[0], item->paras[0].n_runs); write_string(fh, "\n"); for ( i=0; in_paras; i++ ) { write_string(fh, tmp); write_string(fh, ": "); - write_string(fh, item->paras[i].text); + write_para(fh, &item->paras[i], item->paras[i].n_runs); write_string(fh, "\n"); } } diff --git a/libstorycode/storycode.h b/libstorycode/storycode.h index df9f79c..cd98667 100644 --- a/libstorycode/storycode.h +++ b/libstorycode/storycode.h @@ -27,6 +27,21 @@ #include #endif +enum text_run_type +{ + TEXT_RUN_NORMAL, + TEXT_RUN_BOLD, + TEXT_RUN_ITALIC, + TEXT_RUN_UNDERLINE, +}; + +struct text_run +{ + enum text_run_type type; + char *text; +}; + + #include "narrative.h" extern const char *alignc(enum alignment ali); diff --git a/libstorycode/storycode.y b/libstorycode/storycode.y index 19d9b1f..d654bd7 100644 --- a/libstorycode/storycode.y +++ b/libstorycode/storycode.y @@ -33,17 +33,31 @@ #include "scparse_priv.h" + struct paragraph { + struct text_run *runs; + int n_runs; + int max_runs; + }; + + struct many_paragraphs { + struct paragraph *paras; + int n_paras; + int max_paras; + }; + } %union { + Stylesheet *ss; Narrative *n; Slide *s; + char *str; - struct { - char *text; - enum narrative_run_type type; - } str_w_type; + struct text_run run; + struct paragraph para; + struct many_paragraphs many_paragraphs; + struct length len; struct length lenquad[4]; struct frame_geom geom; @@ -52,6 +66,7 @@ struct colour col; enum alignment align; enum gradient grad; + } %{ @@ -89,21 +104,27 @@ %type narrative %type slide %type stylesheet -%type slide_prestitle +%type textframe +%type slide_prestitle +%type slidetitle +%type multi_line_string +%type text_line +%type slide_bulletpoint +%type text_line_with_start +%type text_run +%type RUN_TEXT + %type FONTNAME %type imageframe -%type slide_bulletpoint %type frameopt %type FILENAME -%type RUN_TEXT -%type text_run + %type geometry %type lenquad %type colour %type HEXCOL %type length %type alignment -%type slidetitle %type UNIT %type VALUE %type gradtype @@ -116,12 +137,6 @@ /* The slide currently being created. * Will be added to the narrative when complete */ ctx->s = slide_new(); - - ctx->max_runs = 32; - ctx->runs = malloc(ctx->max_runs*sizeof(char *)); - ctx->run_types = malloc(ctx->max_runs*sizeof(enum narrative_run_type)); - if ( (ctx->runs == NULL) || (ctx->run_types == NULL) ) ctx->max_runs = 0; - reset_runs(ctx); } %{ @@ -157,30 +172,43 @@ static int hex_to_double(const char *v, double *r) } -void reset_runs(struct scpctx *ctx) +void push_paragraph(struct many_paragraphs *mp, struct paragraph p) { - ctx->n_runs = 0; - ctx->mask = 0; - ctx->alignment = ALIGN_INHERIT; + if ( mp->n_paras == mp->max_paras ) { + struct paragraph *nparas; + nparas = realloc(mp->paras, (mp->max_paras+8)*sizeof(struct paragraph)); + if ( nparas == NULL ) return; + mp->max_paras += 8; + mp->paras = nparas; + } + +printf("pushing para with %i runs\n", p.n_runs); + + mp->paras[mp->n_paras++] = p; + printf("now %i paras\n", mp->n_paras); } -void add_run(struct scpctx *ctx, char *str, enum narrative_run_type type) +struct text_run **combine_paras(struct many_paragraphs mp, int **pn_runs) { - if ( ctx->n_runs == ctx->max_runs ) { - char **nruns; - enum narrative_run_type *ntype; - nruns = realloc(ctx->runs, (ctx->max_runs+32)*sizeof(char *)); - ntype = realloc(ctx->run_types, (ctx->max_runs+32)*sizeof(enum narrative_run_type)); - if ( (nruns == NULL) || (ntype == NULL) ) return; - ctx->max_runs += 32; - ctx->runs = nruns; - ctx->run_types = ntype; + struct text_run **combined_paras; + int *n_runs; + int i; + + printf("combining %i paras\n", mp.n_paras); + combined_paras = malloc(mp.n_paras * sizeof(struct text_run *)); + n_runs = malloc(mp.n_paras * sizeof(int)); + for ( i=0; iruns[ctx->n_runs] = str; - ctx->run_types[ctx->n_runs] = type; - ctx->n_runs++; + *pn_runs = n_runs; + return combined_paras; } @@ -225,26 +253,50 @@ narrative: ; narrative_el: - PRESTITLE TEXT_START text_line { narrative_add_prestitle(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); - reset_runs(ctx); } -| BP TEXT_START text_line { narrative_add_bp(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); - reset_runs(ctx); } -| TEXT_START text_line { narrative_add_text(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); - reset_runs(ctx); } -| slide { } -| EOP { narrative_add_eop(ctx->n); } + PRESTITLE TEXT_START text_line { narrative_add_prestitle(ctx->n, $3.runs, $3.n_runs); } +| BP TEXT_START text_line { narrative_add_bp(ctx->n, $3.runs, $3.n_runs); } +| TEXT_START text_line { narrative_add_text(ctx->n, $2.runs, $2.n_runs); } +| slide { } +| EOP { narrative_add_eop(ctx->n); } ; -text_line: +text_line: { $$.n_runs = 0; + $$.max_runs = 0; + $$.runs = NULL; + } %empty -| text_line text_run { add_run(ctx, $2.text, $2.type); } -; +| text_line text_run { + if ( $$.n_runs == $$.max_runs ) { + struct text_run *nruns; + nruns = realloc($$.runs, + ($$.max_runs+8)*sizeof(struct text_run)); + if ( nruns != NULL ) { + $$.max_runs += 8; + $$.runs = nruns; + } + } + if ( $$.n_runs < $$.max_runs ) { + $$.runs[$$.n_runs++] = $2; + } + } + +; + +/* FIXME: Modifiers might be nested or overlap, e.g. + * _hello *there*, world_ + * _hello *there_, world* + */ +/* FIXME: Adjacent RUN_TEXTs should be concatenated, otherwise escaped characters + * within modifiers won't work: + * *hello \\ backslash* + * = '*' RUN_TEXT RUN_TEXT RUN_TEXT '*' + */ text_run: - RUN_TEXT { $$.text = $1; $$.type = NARRATIVE_RUN_NORMAL; } -| '*' RUN_TEXT '*' { $$.text = $2; $$.type = NARRATIVE_RUN_BOLD; } -| '/' RUN_TEXT '/' { $$.text = $2; $$.type = NARRATIVE_RUN_ITALIC; } -| '_' RUN_TEXT '_' { $$.text = $2; $$.type = NARRATIVE_RUN_UNDERLINE; } + RUN_TEXT { $$.text = $1; $$.type = TEXT_RUN_NORMAL; } +| '*' RUN_TEXT '*' { $$.text = $2; $$.type = TEXT_RUN_BOLD; } +| '/' RUN_TEXT '/' { $$.text = $2; $$.type = TEXT_RUN_ITALIC; } +| '_' RUN_TEXT '_' { $$.text = $2; $$.type = TEXT_RUN_UNDERLINE; } /* -------- Slide -------- */ @@ -260,26 +312,31 @@ slide_parts: ; slide_part: - slide_prestitle { slide_add_prestitle(ctx->s, ctx->runs, ctx->n_runs); - reset_runs(ctx); } -| imageframe { slide_add_image(ctx->s, $1, ctx->geom); - reset_runs(ctx); } -| textframe { slide_add_text(ctx->s, ctx->runs, ctx->n_runs, - ctx->geom, ctx->alignment); - reset_runs(ctx); } + slide_prestitle { struct text_run **cp; + int *n_runs; + cp = combine_paras($1, &n_runs); + slide_add_prestitle(ctx->s, cp, n_runs, $1.n_paras); } +| textframe { struct text_run **cp; + int *n_runs; + cp = combine_paras($1, &n_runs); + slide_add_text(ctx->s, cp, n_runs, $1.n_paras, + ctx->geom, ctx->alignment); } +| slidetitle { struct text_run **cp; + int *n_runs; + cp = combine_paras($1, &n_runs); + slide_add_slidetitle(ctx->s, cp, n_runs, $1.n_paras); } +| imageframe { slide_add_image(ctx->s, $1, ctx->geom); } | FOOTER { slide_add_footer(ctx->s); } -| slidetitle { slide_add_slidetitle(ctx->s, ctx->runs, ctx->n_runs); - reset_runs(ctx); } ; slide_prestitle: - PRESTITLE frame_options multi_line_string { } -| PRESTITLE frame_options '{' multi_line_string '}' { } + PRESTITLE frame_options multi_line_string { $$ = $3; } +| PRESTITLE frame_options '{' multi_line_string '}' { $$ = $4; } ; slidetitle: - SLIDETITLE frame_options multi_line_string { } -| SLIDETITLE frame_options '{' multi_line_string '}' { } + SLIDETITLE frame_options multi_line_string { $$ = $3; } +| SLIDETITLE frame_options '{' multi_line_string '}' { $$ = $4; } ; imageframe: @@ -287,23 +344,25 @@ imageframe: ; textframe: - TEXTFRAME frame_options multi_line_string { } -| TEXTFRAME frame_options '{' multi_line_string '}' { } + TEXTFRAME frame_options multi_line_string { $$ = $3; } +| TEXTFRAME frame_options '{' multi_line_string '}' { $$ = $4; } ; text_line_with_start: - TEXT_START text_line { } + TEXT_START text_line { $$ = $2; } ; -multi_line_string: - text_line_with_start { } -| multi_line_string text_line_with_start { } -| slide_bulletpoint { } -| multi_line_string slide_bulletpoint { } +slide_bulletpoint: + BP TEXT_START text_line { $$ = $3; } ; -slide_bulletpoint: - BP TEXT_START text_line { } +multi_line_string: { $$.n_paras = 0; + $$.paras = NULL; + $$.max_paras = 0; } + text_line_with_start { push_paragraph(&$$, $2); } +| multi_line_string text_line_with_start { push_paragraph(&$$, $2); } +| slide_bulletpoint { push_paragraph(&$$, $1); } +| multi_line_string slide_bulletpoint { push_paragraph(&$$, $2); } ; /* There can be any number of options */ diff --git a/meson.build b/meson.build index 17537b6..139c818 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ libstorycode = library('storycode', 'libstorycode/storycode.c', 'libstorycode/slide_render_cairo.c', 'libstorycode/narrative_render_cairo.c', + 'libstorycode/render_cairo_common.c', 'libstorycode/imagestore.c', storycode_lex_ch, storycode_parse_ch, diff --git a/src/slide_window.c b/src/slide_window.c index d81aab3..fa172ea 100644 --- a/src/slide_window.c +++ b/src/slide_window.c @@ -59,9 +59,15 @@ static void insert_slidetitle_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { SlideWindow *sw = vp; - char **text = malloc(sizeof(char *)); - *text = strdup("Slide title"); - slide_add_slidetitle(sw->slide, text, 1); + struct text_run *runs; + int nruns = 1; + + /* Ownership of this struct will be taken over by the Slide. */ + runs = malloc(sizeof(struct text_run)); + runs[0].type = TEXT_RUN_NORMAL; + runs[0].text = strdup("Slide title"); + + slide_add_slidetitle(sw->slide, &runs, &nruns, 1); gtk_slide_view_set_slide(sw->sv, sw->slide); } -- cgit v1.2.3