aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-09-14 23:45:38 +0200
committerThomas White <taw@bitwiz.me.uk>2019-09-14 23:45:38 +0200
commitc6abe4626c40d4925d6233cf0ca1c30cd49a22cd (patch)
tree4c2b419987f909695993c9b2b51a335fa1b67111
parentbef894ac4fc76a7c163fba44a8127162a6c40d2b (diff)
Handle *bold* in parser, rather than as a separate stage
-rw-r--r--libstorycode/gtk/gtknarrativeview.c67
-rw-r--r--libstorycode/narrative.c134
-rw-r--r--libstorycode/narrative.h22
-rw-r--r--libstorycode/narrative_priv.h13
-rw-r--r--libstorycode/narrative_render_cairo.c285
-rw-r--r--libstorycode/narrative_render_cairo.h2
-rw-r--r--libstorycode/scparse_priv.h7
-rw-r--r--libstorycode/storycode.c22
-rw-r--r--libstorycode/storycode.l39
-rw-r--r--libstorycode/storycode.y113
-rw-r--r--src/colloquium.c2
11 files changed, 371 insertions, 335 deletions
diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c
index 0fe2c59..bb549d4 100644
--- a/libstorycode/gtk/gtknarrativeview.c
+++ b/libstorycode/gtk/gtknarrativeview.c
@@ -343,7 +343,7 @@ static void paste_text_received(GtkClipboard *cb, GtkSelectionData *seldata,
// }
//
// para = e->cursor_frame->paras[e->cpos.para];
-// offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail);
+// offs = narrative_pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail);
//
// get_sc_pos(e->cursor_frame, e->cpos.para, offs, &cur_bl, &cur_sc_pos);
// sc_insert_block(cur_bl, cur_sc_pos, bl);
@@ -496,22 +496,6 @@ static void draw_para_highlight(cairo_t *cr, Narrative *n, int cursor_para,
}
-static size_t pos_trail_to_offset(struct narrative_item *item, int offs, int trail)
-{
- glong char_offs;
- char *ptr;
-
- if ( item->type == NARRATIVE_ITEM_SLIDE ) {
- return offs;
- }
-
- char_offs = g_utf8_pointer_to_offset(item->layout_text, item->layout_text+offs);
- char_offs += trail;
- ptr = g_utf8_offset_to_pointer(item->layout_text, char_offs);
- return ptr - item->layout_text;
-}
-
-
static void get_cursor_pos(Narrative *n, struct edit_pos cpos,
double *x, double *y, double *h)
{
@@ -532,7 +516,7 @@ static void get_cursor_pos(Narrative *n, struct edit_pos cpos,
return;
}
- offs = pos_trail_to_offset(item, cpos.pos, cpos.trail);
+ offs = narrative_pos_trail_to_offset(n, cpos.para, cpos.pos, cpos.trail);
pango_layout_get_cursor_pos(item->layout, offs, &rect, NULL);
*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;
@@ -656,9 +640,14 @@ static void check_cursor_visible(GtkNarrativeView *e)
static size_t end_offset_of_para(Narrative *n, int pnum)
{
+ int i;
+ size_t len;
assert(pnum >= 0);
if ( !narrative_item_is_text(n, pnum) ) return 0;
- return strlen(n->items[pnum].text);
+ for ( i=0; i<n->items[pnum].n_runs; i++ ) {
+ len += strlen(n->items[pnum].runs[i].text);
+ }
+ return len;
}
@@ -773,8 +762,6 @@ static void do_backspace(GtkNarrativeView *e, signed int dir)
{
struct edit_pos p1, p2;
size_t o1, o2;
- struct narrative_item *item1;
- struct narrative_item *item2;
if ( !positions_equal(e->sel_start, e->sel_end) ) {
@@ -791,12 +778,8 @@ static void do_backspace(GtkNarrativeView *e, signed int dir)
}
sort_positions(&p1, &p2);
- item1 = &e->n->items[p1.para];
- item2 = &e->n->items[p2.para];
- o1 = pos_trail_to_offset(item1, p1.pos, p1.trail);
- o2 = pos_trail_to_offset(item2, p2.pos, p2.trail);
- o1 = layout_index_to_text(item1, o1);
- o2 = layout_index_to_text(item2, o2);
+ o1 = narrative_pos_trail_to_offset(e->n, p1.para, p1.pos, p1.trail);
+ o2 = narrative_pos_trail_to_offset(e->n, p2.para, p2.pos, p2.trail);
narrative_delete_block(e->n, p1.para, o1, p2.para, o2);
e->cpos = p1;
unset_selection(e);
@@ -815,14 +798,25 @@ static void do_backspace(GtkNarrativeView *e, signed int dir)
static void insert_text_in_paragraph(struct narrative_item *item, size_t offs,
char *t)
{
- char *n = malloc(strlen(t) + strlen(item->text) + 1);
+ char *n;
+ int run;
+ size_t pos;
+
+ pos = 0;
+ for ( run=0; run<item->n_runs; run++ ) {
+ pos += strlen(item->runs[run].text);
+ if ( pos > offs ) break;
+ }
+ offs -= pos;
+
+ n = malloc(strlen(t) + strlen(item->runs[run].text) + 1);
if ( n == NULL ) return;
- strncpy(n, item->text, offs);
+ strncpy(n, item->runs[run].text, offs);
n[offs] = '\0';
strcat(n, t);
- strcat(n, item->text+offs);
- free(item->text);
- item->text = n;
+ strcat(n, item->runs[run].text+offs);
+ free(item->runs[run].text);
+ item->runs[run].text = n;
}
@@ -838,8 +832,7 @@ static void insert_text(char *t, GtkNarrativeView *e)
if ( narrative_item_is_text(e->n, e->cpos.para) ) {
- size_t off = pos_trail_to_offset(item, e->cpos.pos, e->cpos.trail);
- off = layout_index_to_text(item, off);
+ size_t off = narrative_pos_trail_to_offset(e->n, e->cpos.para, e->cpos.pos, e->cpos.trail);
if ( strcmp(t, "\n") == 0 ) {
narrative_split_item(e->n, e->cpos.para, off);
@@ -1208,9 +1201,9 @@ void gtk_narrative_view_add_slide_at_cursor(GtkNarrativeView *e)
if ( s == NULL ) return;
if ( narrative_item_is_text(e->n, e->cpos.para) ) {
- size_t off = pos_trail_to_offset(&e->n->items[e->cpos.para],
- e->cpos.pos, e->cpos.trail);
- if ( (off > 0) && (off < strlen(e->n->items[e->cpos.para].text)) ) {
+ size_t off = narrative_pos_trail_to_offset(e->n, e->cpos.para,
+ e->cpos.pos, e->cpos.trail);
+ if ( (off > 0) && (off < end_offset_of_para(e->n, e->cpos.para)) ) {
narrative_split_item(e->n, e->cpos.para, off);
narrative_insert_slide(e->n, s, e->cpos.para+1);
} else if ( off == 0 ) {
diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c
index 7db31d9..6ed427d 100644
--- a/libstorycode/narrative.c
+++ b/libstorycode/narrative.c
@@ -70,13 +70,15 @@ Narrative *narrative_new()
static void narrative_item_destroy(struct narrative_item *item)
{
- free(item->text);
+ int i;
+ for ( i=0; i<item->n_runs; i++ ) {
+ free(item->runs[i].text);
+ }
+ free(item->runs);
#ifdef HAVE_PANGO
if ( item->layout != NULL ) {
g_object_unref(item->layout);
}
- free(item->chars_removed);
- free(item->layout_text);
#endif
#ifdef HAVE_CAIRO
if ( item->slide_thumbnail != NULL ) {
@@ -98,6 +100,24 @@ 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);
+ }
+}
+
+
Narrative *narrative_load(GFile *file)
{
GBytes *bytes;
@@ -115,7 +135,7 @@ Narrative *narrative_load(GFile *file)
if ( n->n_items == 0 ) {
/* Presentation is empty. Add a dummy to start things off */
- narrative_add_text(n, strdup(""));
+ narrative_add_empty_item(n);
}
imagestore_set_parent(n->imagestore, g_file_get_parent(file));
@@ -204,11 +224,9 @@ static void init_item(struct narrative_item *item)
{
#ifdef HAVE_PANGO
item->layout = NULL;
- item->layout_text = NULL;
- item->chars_removed = NULL;
- item->n_chars_removed = 0;
#endif
- item->text = NULL;
+ item->runs = NULL;
+ item->n_runs = 0;
item->slide = NULL;
item->slide_thumbnail = NULL;
}
@@ -238,45 +256,52 @@ static struct narrative_item *insert_item(Narrative *n, int pos)
}
-void narrative_add_prestitle(Narrative *n, char *text)
+extern void add_text_item(Narrative *n, char **texts, enum narrative_run_type *types,
+ int n_runs, enum narrative_item_type type)
{
struct narrative_item *item;
+ int i;
item = add_item(n);
if ( item == NULL ) return;
- item->type = NARRATIVE_ITEM_PRESTITLE;
- item->text = text;
+ item->type = type;
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;
+ }
-void narrative_add_bp(Narrative *n, char *text)
-{
- struct narrative_item *item;
+ for ( i=0; i<n_runs; i++ ) {
+ item->runs[i].type = types[i];
+ item->runs[i].text = texts[i];
+ }
+ item->n_runs = n_runs;
+}
- item = add_item(n);
- if ( item == NULL ) return;
- item->type = NARRATIVE_ITEM_BP;
- item->text = text;
- item->align = ALIGN_INHERIT;
- item->layout = NULL;
+void narrative_add_text(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs)
+{
+ add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_TEXT);
}
-void narrative_add_text(Narrative *n, char *text)
+void narrative_add_prestitle(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs)
{
- struct narrative_item *item;
+ add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_PRESTITLE);
+}
- item = add_item(n);
- if ( item == NULL ) return;
- item->type = NARRATIVE_ITEM_TEXT;
- item->text = text;
- item->align = ALIGN_INHERIT;
- item->layout = NULL;
+void narrative_add_bp(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs)
+{
+ add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_BP);
}
@@ -327,6 +352,7 @@ static void delete_item(Narrative *n, int del)
/* Delete from item i1 offset o1 to item i2 offset o2, inclusive */
void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2)
{
+#if 0
int i;
int n_del = 0;
int merge = 1;
@@ -388,11 +414,13 @@ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2)
n->items[i1].text = new_text;
delete_item(n, i2);
}
+#endif
}
void narrative_split_item(Narrative *n, int i1, size_t o1)
{
+#if 0
struct narrative_item *item1;
struct narrative_item *item2;
@@ -407,6 +435,7 @@ void narrative_split_item(Narrative *n, int i1, size_t o1)
}
item2->type = NARRATIVE_ITEM_TEXT;
+#endif
}
@@ -482,3 +511,50 @@ Slide *narrative_get_slide_by_number(Narrative *n, int pos)
}
return NULL;
}
+
+
+static void debug_runs(struct narrative_item *item)
+{
+ int j;
+ for ( j=0; j<item->n_runs; j++ ) {
+ printf("Run %i: '%s'\n", j, item->runs[j].text);
+ }
+}
+
+void narrative_debug(Narrative *n)
+{
+ int i;
+
+ for ( i=0; i<n->n_items; i++ ) {
+
+ struct narrative_item *item = &n->items[i];
+ printf("Item %i ", i);
+ switch ( item->type ) {
+
+ case NARRATIVE_ITEM_TEXT :
+ printf("(text):\n");
+ debug_runs(item);
+ break;
+
+ case NARRATIVE_ITEM_BP :
+ printf("(bp):\n");
+ debug_runs(item);
+ break;
+
+ case NARRATIVE_ITEM_PRESTITLE :
+ printf("(prestitle):\n");
+ debug_runs(item);
+ break;
+
+ case NARRATIVE_ITEM_EOP :
+ printf("(EOP marker)\n");
+ break;
+
+ case NARRATIVE_ITEM_SLIDE :
+ printf("(slide)\n");
+ break;
+
+ }
+
+ }
+}
diff --git a/libstorycode/narrative.h b/libstorycode/narrative.h
index 3e21ca1..a51136b 100644
--- a/libstorycode/narrative.h
+++ b/libstorycode/narrative.h
@@ -31,11 +31,20 @@
typedef struct _narrative Narrative;
+enum narrative_run_type
+{
+ NARRATIVE_RUN_NORMAL,
+ NARRATIVE_RUN_BOLD,
+ NARRATIVE_RUN_ITALIC,
+ NARRATIVE_RUN_UNDERLINE,
+};
+
#include "slide.h"
#include "imagestore.h"
extern Narrative *narrative_new(void);
extern void narrative_free(Narrative *n);
+extern void narrative_add_empty_item(Narrative *n);
extern void narrative_add_stylesheet(Narrative *n, Stylesheet *ss);
extern Stylesheet *narrative_get_stylesheet(Narrative *n);
@@ -51,9 +60,15 @@ extern int narrative_get_unsaved(Narrative *n);
extern int narrative_item_is_text(Narrative *n, int item);
-extern void narrative_add_prestitle(Narrative *n, char *text);
-extern void narrative_add_bp(Narrative *n, char *text);
-extern void narrative_add_text(Narrative *n, char *text);
+extern void narrative_add_text(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs);
+
+extern void narrative_add_bp(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs);
+
+extern void narrative_add_prestitle(Narrative *n, char **texts,
+ enum narrative_run_type *types, int n_runs);
+
extern void narrative_add_slide(Narrative *n, Slide *slide);
extern void narrative_add_eop(Narrative *n);
extern void narrative_insert_slide(Narrative *n, Slide *slide, int pos);
@@ -68,5 +83,6 @@ extern Slide *narrative_get_slide_by_number(Narrative *n, int pos);
extern int narrative_get_slide_number_for_para(Narrative *n, int para);
extern int narrative_get_slide_number_for_slide(Narrative *n, Slide *s);
+extern void narrative_debug(Narrative *n);
#endif /* NARRATIVE_H */
diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h
index 86aa612..c783df2 100644
--- a/libstorycode/narrative_priv.h
+++ b/libstorycode/narrative_priv.h
@@ -42,6 +42,13 @@ enum narrative_item_type
};
+struct narrative_text_run
+{
+ enum narrative_run_type type;
+ char *text;
+};
+
+
struct narrative_item
{
enum narrative_item_type type;
@@ -60,13 +67,11 @@ struct narrative_item
* obj_w + space_l + space_r might be less than width of rendering surface */
/* For TEXT, BP, PRESTITLE */
- char *text;
+ int n_runs;
+ struct narrative_text_run *runs;
enum alignment align;
#ifdef HAVE_PANGO
PangoLayout *layout;
- char *layout_text;
- int *chars_removed;
- int n_chars_removed;
#else
void *layout;
#endif
diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c
index aaa05ee..8b009b5 100644
--- a/libstorycode/narrative_render_cairo.c
+++ b/libstorycode/narrative_render_cairo.c
@@ -69,197 +69,6 @@ static PangoAlignment to_pangoalignment(enum alignment align)
}
-static int find_pair(const gchar *p, gunichar c, gchar **start, gchar **end)
-{
- gchar *s;
- gchar *e;
- gchar *next;
-
- /* FIXME: Check it's not escaped */
- s = g_utf8_strchr(p, -1, c);
- if ( s == NULL ) return 0;
-
- next = g_utf8_find_next_char(s, NULL);
- if ( next == NULL ) return 0;
-
- e = g_utf8_strchr(next, -1, c);
- if ( e == NULL ) return 0;
-
- *start = s;
- *end = e;
- return 1;
-}
-
-
-struct attr_to_add
-{
- int start;
- int end;
- char type; /* b=bold, i=italic, u=underline */
-};
-
-
-static int add_range(struct narrative_item *item, int *max_chars_removed,
- int start, int end, int *n_add, int *max_add,
- struct attr_to_add **add, char type)
-{
- if ( item->n_chars_removed == *max_chars_removed ) {
- (*max_chars_removed) += 256;
- item->chars_removed = realloc(item->chars_removed, *max_chars_removed*sizeof(int));
- if ( item->chars_removed == NULL ) return 1;
- }
-
- item->chars_removed[item->n_chars_removed++] = start;
- item->chars_removed[item->n_chars_removed++] = end;
-
- if ( *n_add == *max_add ) {
- *max_add += 64;
- *add = realloc(*add, *max_add*sizeof(struct attr_to_add));
- if ( *add == NULL ) return 1;
- }
-
- /* Indices NOT including the markers */
- (*add)[*n_add].start = start+1;
- (*add)[*n_add].end = end-1;
- (*add)[*n_add].type = type;
- (*n_add)++;
-
- return 0;
-}
-
-
-/* How many bytes were removed up to idx? */
-int layout_index_to_text(struct narrative_item *item, int idx)
-{
- int i;
-
- for ( i=0; i<item->n_chars_removed; i++ ) {
- if ( item->chars_removed[i] > idx ) break;
- }
-
- return idx + i;
-}
-
-
-/* How many bytes were removed up to idx? */
-int text_index_to_layout(struct narrative_item *item, int idx)
-{
- int i;
-
- for ( i=0; i<item->n_chars_removed; i++ ) {
- assert(item->chars_removed[i] != idx);
- if ( item->chars_removed[i] > idx ) break;
- }
-
- return idx - i;
-}
-
-
-static int cmpi(const void *a, const void *b)
-{
- return *(int *)a - *(int *)b;
-}
-
-
-static void process_tags(struct narrative_item *item, PangoAttrList *attrs)
-{
- gchar *efstart;
- gchar *efend;
- gchar *text;
- PangoAttribute *attr;
- struct attr_to_add *add;
- int n_add;
- int max_add;
- int max_chars_removed;
- int i, j, k;
- size_t len;
-
- item->n_chars_removed = 0;
- free(item->chars_removed);
- item->chars_removed = NULL;
- max_chars_removed = 0;
-
- add = NULL;
- n_add = 0;
- max_add = 0;
-
- /* Scan the text, identify characters to remove and character ranges
- * (in the original text) which need attributes applied */
- text = item->text;
- while ( find_pair(text, '*', &efstart, &efend) ) {
- if ( add_range(item, &max_chars_removed,
- efstart - item->text, efend - item->text,
- &n_add, &max_add, &add, 'b') ) return;
- text = g_utf8_find_next_char(efend, NULL);
- }
- text = item->text;
- while ( find_pair(text, '/', &efstart, &efend) ) {
- if ( add_range(item, &max_chars_removed,
- efstart - item->text, efend - item->text,
- &n_add, &max_add, &add, 'i') ) return;
- text = g_utf8_find_next_char(efend, NULL);
- }
- text = item->text;
- while ( find_pair(text, '_', &efstart, &efend) ) {
- if ( add_range(item, &max_chars_removed,
- efstart - item->text, efend - item->text,
- &n_add, &max_add, &add, 'u') ) return;
- text = g_utf8_find_next_char(efend, NULL);
- }
-
- /* Sort the list of removed characters */
- qsort(item->chars_removed, item->n_chars_removed, sizeof(int), cmpi);
-
- /* Go through the list of attributes, and correct the character ranges
- * so that they refer to the text with characters removed, and add them
- * to the PangoAttrList */
- for ( i=0; i<n_add; i++ ) {
-
- switch ( add[i].type ) {
-
- case 'b' :
- attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
- break;
-
- case 'i' :
- attr = pango_attr_style_new(PANGO_STYLE_ITALIC);
- break;
-
- case 'u' :
- attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
- break;
-
- }
-
- attr->start_index = text_index_to_layout(item, add[i].start);
-
- attr->end_index = text_index_to_layout(item, add[i].end)+1;
-
- pango_attr_list_insert(attrs, attr);
-
- }
-
- /* Create the version of the text with characters removed */
- if ( item->n_chars_removed == 0 ) {
- item->layout_text = strdup(item->text);
- } else {
- len = strlen(item->text);
- item->layout_text = malloc(len);
- if ( item->layout_text == NULL ) return;
- j = 0;
- for ( i=0; i<len+1; i++ ) { /* \0 terminator please */
- if ( item->chars_removed[k] == i ) {
- k++;
- } else {
- item->layout_text[j++] = item->text[i];
- }
- }
- }
-
- free(add);
-}
-
-
static void wrap_text(struct narrative_item *item, PangoContext *pc,
Stylesheet *ss, const char *stn, double w,
size_t sel_start, size_t sel_end)
@@ -314,13 +123,67 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
pango_layout_set_alignment(item->layout, palignment);
pango_layout_set_font_description(item->layout, fontdesc);
- /* Handle *bold*, _underline_, /italic/ etc. */
- process_tags(item, attrs);
+ size_t total_len = 0;
+ int i;
+ char *text;
+
+ /* Work out length of all text in item (paragraph) */
+ for ( i=0; i<item->n_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; i<item->n_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);
- pango_layout_set_text(item->layout, item->layout_text, -1);
-
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);
@@ -387,18 +250,30 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore *
}
-static size_t pos_trail_to_offset(Narrative *n, int i, int offs, int trail)
+size_t narrative_pos_trail_to_offset(Narrative *n, int i, int offs, int trail)
{
- glong char_offs;
- char *ptr;
+ int run;
struct narrative_item *item = &n->items[i];
+ size_t pos;
if ( !narrative_item_is_text(n, i) ) return offs;
- char_offs = g_utf8_pointer_to_offset(item->text, item->text+offs);
- char_offs += trail;
- ptr = g_utf8_offset_to_pointer(item->text, char_offs);
- return ptr - item->text;
+ pos = 0;
+ for ( run=0; run<item->n_runs; run++ ) {
+ pos += strlen(item->runs[run].text);
+ if ( pos > offs ) {
+ glong char_offs;
+ char *ptr;
+ char_offs = g_utf8_pointer_to_offset(item->runs[run].text,
+ item->runs[run].text+offs);
+ char_offs += trail;
+ ptr = g_utf8_offset_to_pointer(item->runs[run].text, char_offs);
+ return ptr - item->runs[run].text;
+ }
+ }
+
+ fprintf(stderr, "narrative_pos_trail_to_offset: Outside last run\n");
+ return 0;
}
@@ -465,8 +340,10 @@ 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) ) {
- 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);
+ sel_s = narrative_pos_trail_to_offset(n, sel_start.para,
+ sel_start.pos, sel_start.trail);
+ sel_e = narrative_pos_trail_to_offset(n, sel_end.para,
+ sel_end.pos, sel_end.trail);
} else {
sel_s = 0;
sel_e = 0;
diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h
index c62d2e9..bfd2a05 100644
--- a/libstorycode/narrative_render_cairo.h
+++ b/libstorycode/narrative_render_cairo.h
@@ -46,6 +46,8 @@ extern double narrative_get_height(Narrative *n);
extern double narrative_item_get_height(Narrative *n, int i);
+extern size_t narrative_pos_trail_to_offset(Narrative *n, int i, int offs, int trail);
+
extern int narrative_render_item_cairo(Narrative*n, cairo_t *cr, int i);
extern int narrative_render_cairo(Narrative *n, cairo_t *cr,
diff --git a/libstorycode/scparse_priv.h b/libstorycode/scparse_priv.h
index 3d97ead..98ddbda 100644
--- a/libstorycode/scparse_priv.h
+++ b/libstorycode/scparse_priv.h
@@ -42,9 +42,10 @@ struct scpctx
Narrative *n;
Slide *s;
- int n_str;
- int max_str;
- char **str;
+ 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
diff --git a/libstorycode/storycode.c b/libstorycode/storycode.c
index ca0d2d0..e17d5dd 100644
--- a/libstorycode/storycode.c
+++ b/libstorycode/storycode.c
@@ -40,14 +40,19 @@
#include "scparse_priv.h"
+extern int scdebug;
+
+
Narrative *storycode_parse_presentation(const char *sc)
{
YY_BUFFER_STATE b;
struct scpctx parse_ctx;
b = sc_scan_string(sc);
+ //scdebug = 1;
scparse(&parse_ctx);
sc_delete_buffer(b);
+ //narrative_debug(parse_ctx.n);
return parse_ctx.n;
}
@@ -189,26 +194,37 @@ static int write_slide(GOutputStream *fh, Slide *s)
static int write_item(GOutputStream *fh, struct narrative_item *item)
{
+ int i;
+
switch ( item->type ) {
case NARRATIVE_ITEM_TEXT:
/* FIXME: separate alignment */
if ( write_string(fh, ": ") ) return 1;
- if ( write_string(fh, item->text) ) return 1;
+ for ( i=0; i<item->n_runs; i++ ) {
+ /* FIXME: Run markers (e.g. '*') */
+ if ( write_string(fh, item->runs[i].text) ) return 1;
+ }
if ( write_string(fh, "\n") ) return 1;
break;
case NARRATIVE_ITEM_PRESTITLE:
/* FIXME: separate alignment */
if ( write_string(fh, "PRESTITLE: ") ) return 1;
- if ( write_string(fh, item->text) ) return 1;
+ for ( i=0; i<item->n_runs; i++ ) {
+ /* FIXME: Run markers (e.g. '*') */
+ if ( write_string(fh, item->runs[i].text) ) return 1;
+ }
if ( write_string(fh, "\n") ) return 1;
break;
case NARRATIVE_ITEM_BP:
/* FIXME: separate alignment */
if ( write_string(fh, "BP: ") ) return 1;
- if ( write_string(fh, item->text) ) return 1;
+ for ( i=0; i<item->n_runs; i++ ) {
+ /* FIXME: Run markers (e.g. '*') */
+ if ( write_string(fh, item->runs[i].text) ) return 1;
+ }
if ( write_string(fh, "\n") ) return 1;
break;
diff --git a/libstorycode/storycode.l b/libstorycode/storycode.l
index b1bd81a..b4dbb03 100644
--- a/libstorycode/storycode.l
+++ b/libstorycode/storycode.l
@@ -30,18 +30,23 @@
#include "storycode_parse.h"
int lineno = 0;
+ int sqb_caller = 0;
%}
%option prefix="sc"
%option noyywrap nounput noinput
-%s string
%s geom
%s font
+%s filename
%s paraspace
%s pad
%s align
%s col
%s sqb
+%x stringesc
+%x runtext
+%s image
+%s image_filename
%%
@@ -54,7 +59,6 @@ ENDOFPRESENTATION { return SC_EOP; }
BP { return SC_BP; }
GEOMETRY { BEGIN(geom); return SC_GEOMETRY; }
TEXT { return SC_TEXTFRAME; }
-IMAGE { return SC_IMAGEFRAME; }
FOOTER { return SC_FOOTER; }
FONT[ ] { BEGIN(font); return SC_FONT; }
PAD { BEGIN(pad); return SC_PAD; }
@@ -69,19 +73,36 @@ BGCOL { BEGIN(col); return SC_BGCOL; }
<align,sqb>(?i:left) { return SC_LEFT; }
<align,sqb>(?i:center) { return SC_CENTER; }
<align,sqb>(?i:right) { return SC_RIGHT; }
-<string,font>.*\n { sclval.str = strdup(yytext);
+
+<font>.*\n { sclval.str = strdup(yytext);
sclval.str[yyleng-1] = '\0';
BEGIN(0);
lineno++;
- return SC_STRING; }
-"[" { BEGIN(sqb); return SC_SQOPEN; }
-"]" { BEGIN(0); return SC_SQCLOSE; }
-<INITIAL>:[ ] { BEGIN(string); }
-:\n { sclval.str = strdup(""); lineno++; return SC_STRING; }
+ return SC_FONTNAME; }
+
+<INITIAL>IMAGE { BEGIN(image); return SC_IMAGEFRAME; }
+<image>:[ ] { BEGIN(image_filename); return SC_TEXT_START; }
+<image_filename>[^\n]* { sclval.str = strdup(yytext);
+ lineno++;
+ return SC_FILENAME; }
+
+<INITIAL>:[ ] { BEGIN(runtext); return SC_TEXT_START; }
+<runtext>[\\] { BEGIN(stringesc); }
+<stringesc>[.] { sclval.str = strdup(yytext); BEGIN(runtext); return SC_RUN_TEXT; }
+<runtext>[\*] { return '*'; }
+<runtext>[^\*\n]* { sclval.str = strdup(yytext);
+ sclval.str[yyleng] = '\0';
+ lineno++;
+ return SC_RUN_TEXT; }
+<runtext>\n { BEGIN(0); lineno++; }
+
+\n { BEGIN(0); lineno++; }
+
+"[" { sqb_caller = YY_START; BEGIN(sqb); return SC_SQOPEN; }
+"]" { BEGIN(sqb_caller); return SC_SQCLOSE; }
[{] { return '{'; }
[}] { return '}'; }
[. ] {}
-\n { BEGIN(0); lineno++; }
[0-9\.]+ { sclval.val = atof(yytext); return SC_VALUE; }
[uf] { sclval.character = yytext[0]; return SC_UNIT; }
[+] { return '+'; }
diff --git a/libstorycode/storycode.y b/libstorycode/storycode.y
index b5ac68e..daf2504 100644
--- a/libstorycode/storycode.y
+++ b/libstorycode/storycode.y
@@ -27,10 +27,12 @@
%code requires {
#include "narrative.h"
+ #include "narrative_priv.h"
#include "slide.h"
#include "stylesheet.h"
#include "scparse_priv.h"
+
}
%union {
@@ -38,6 +40,10 @@
Narrative *n;
Slide *s;
char *str;
+ struct {
+ char *text;
+ enum narrative_run_type type;
+ } str_w_type;
struct length len;
struct length lenquad[4];
struct frame_geom geom;
@@ -59,6 +65,8 @@
extern int lineno;
%}
+%define parse.trace
+
%token STYLES
%token SLIDE
%token EOP
@@ -68,24 +76,27 @@
%token FOOTER
%token TEXTFRAME
%token IMAGEFRAME
+%token FILENAME
%token BP
%token FONT GEOMETRY PAD ALIGN FGCOL BGCOL PARASPACE
%token VERT HORIZ
%token LEFT CENTER RIGHT
-%token STRING
+%token FONTNAME RUN_TEXT
%token SQOPEN SQCLOSE
%token UNIT VALUE HEXCOL
+%token TEXT_START
%type <n> narrative
%type <s> slide
%type <ss> stylesheet
-%type <str> narrative_prestitle
%type <str> slide_prestitle
-%type <str> STRING
+%type <str> FONTNAME
%type <str> imageframe
%type <str> slide_bulletpoint
-%type <str> narrative_bulletpoint
%type <str> frameopt
+%type <str> FILENAME
+%type <str> RUN_TEXT
+%type <str_w_type> text_run
%type <geom> geometry
%type <lenquad> lenquad
%type <col> colour
@@ -106,10 +117,11 @@
* Will be added to the narrative when complete */
ctx->s = slide_new();
- ctx->max_str = 32;
- ctx->str = malloc(ctx->max_str*sizeof(char *));
- if ( ctx->str == NULL ) ctx->max_str = 0;
- str_reset(ctx);
+ 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);
}
%{
@@ -144,24 +156,34 @@ static int hex_to_double(const char *v, double *r)
return 1;
}
-void str_reset(struct scpctx *ctx)
+
+void reset_runs(struct scpctx *ctx)
{
- ctx->n_str = 0;
+ ctx->n_runs = 0;
ctx->mask = 0;
ctx->alignment = ALIGN_INHERIT;
}
-void add_str(struct scpctx *ctx, char *str)
+
+void add_run(struct scpctx *ctx, char *str, enum narrative_run_type type)
{
- if ( ctx->n_str == ctx->max_str ) {
- char **nstr = realloc(ctx->str, (ctx->max_str+32)*sizeof(char *));
- if ( nstr == NULL ) return;
- ctx->max_str += 32;
+ 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;
}
- ctx->str[ctx->n_str++] = str;
+ ctx->runs[ctx->n_runs] = str;
+ ctx->run_types[ctx->n_runs] = type;
+ ctx->n_runs++;
}
+
void set_style(struct scpctx *ctx, const char *element)
{
if ( ctx->mask & STYMASK_GEOM ) stylesheet_set_geometry(narrative_get_stylesheet(ctx->n),
@@ -198,26 +220,29 @@ presentation:
/* ------ Narrative ------ */
narrative:
- narrative_el { }
+ narrative_el { }
| narrative narrative_el { }
;
narrative_el:
- narrative_prestitle { narrative_add_prestitle(ctx->n, $1); }
-| narrative_bulletpoint { narrative_add_bp(ctx->n, $1); }
-| slide { }
-| STRING { narrative_add_text(ctx->n, $1); }
-| EOP { narrative_add_eop(ctx->n); }
+ 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); }
;
-narrative_prestitle:
- PRESTITLE STRING { $$ = $2; }
-;
-
-narrative_bulletpoint:
- BP STRING { $$ = $2; }
+text_line:
+ %empty
+| text_line text_run { add_run(ctx, $2.text, $2.type); }
;
+text_run:
+ RUN_TEXT { $$.text = $1; $$.type = NARRATIVE_RUN_NORMAL; }
+| '*' RUN_TEXT '*' { $$.text = $2; $$.type = NARRATIVE_RUN_BOLD; }
/* -------- Slide -------- */
@@ -233,16 +258,16 @@ slide_parts:
;
slide_part:
- slide_prestitle { slide_add_prestitle(ctx->s, ctx->str, ctx->n_str);
- str_reset(ctx); }
+ slide_prestitle { slide_add_prestitle(ctx->s, ctx->runs, ctx->n_runs);
+ reset_runs(ctx); }
| imageframe { slide_add_image(ctx->s, $1, ctx->geom);
- str_reset(ctx); }
-| textframe { slide_add_text(ctx->s, ctx->str, ctx->n_str,
+ reset_runs(ctx); }
+| textframe { slide_add_text(ctx->s, ctx->runs, ctx->n_runs,
ctx->geom, ctx->alignment);
- str_reset(ctx); }
+ reset_runs(ctx); }
| FOOTER { slide_add_footer(ctx->s); }
-| slidetitle { slide_add_slidetitle(ctx->s, ctx->str, ctx->n_str);
- str_reset(ctx); }
+| slidetitle { slide_add_slidetitle(ctx->s, ctx->runs, ctx->n_runs);
+ reset_runs(ctx); }
;
slide_prestitle:
@@ -256,7 +281,7 @@ slidetitle:
;
imageframe:
- IMAGEFRAME frame_options STRING { $$ = $STRING; }
+ IMAGEFRAME frame_options TEXT_START FILENAME { $$ = $FILENAME; }
;
textframe:
@@ -264,15 +289,19 @@ textframe:
| TEXTFRAME frame_options '{' multi_line_string '}' { }
;
+text_line_with_start:
+ TEXT_START text_line { }
+;
+
multi_line_string:
- STRING { add_str(ctx, $1); }
-| multi_line_string STRING { add_str(ctx, $2); }
-| slide_bulletpoint { add_str(ctx, $1); }
-| multi_line_string slide_bulletpoint { add_str(ctx, $2); }
+ text_line_with_start { }
+| multi_line_string text_line_with_start { }
+| slide_bulletpoint { }
+| multi_line_string slide_bulletpoint { }
;
slide_bulletpoint:
- BP STRING { $$ = $2; }
+ BP TEXT_START text_line { }
;
/* There can be any number of options */
@@ -414,7 +443,7 @@ styledefs:
;
styledef:
- FONT STRING { ctx->font = $2;
+ FONT FONTNAME { ctx->font = $2;
ctx->mask |= STYMASK_FONT; }
| GEOMETRY geometry { ctx->geom = $2;
ctx->mask |= STYMASK_GEOM; }
diff --git a/src/colloquium.c b/src/colloquium.c
index 95b5231..745ccef 100644
--- a/src/colloquium.c
+++ b/src/colloquium.c
@@ -62,7 +62,7 @@ static void colloquium_activate(GApplication *papp)
Colloquium *app = COLLOQUIUM(papp);
if ( !app->first_run ) {
Narrative *n = narrative_new();
- narrative_add_text(n, strdup(""));
+ narrative_add_empty_item(n);
narrative_window_new(n, NULL, papp);
}
}