aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-09-20 17:12:29 +0200
committerThomas White <taw@physics.org>2019-10-05 17:03:25 +0200
commit387858893a1a858e8205aae28a3609006c0c717d (patch)
tree1a52586a133e864097c6b3aa4c4e66aea2c14bdd
parent03ca4360631d5b0438912470c483989d294d7a1e (diff)
Parse emphasis blocks in Bison
-rw-r--r--data/demo.sc2
-rw-r--r--libstorycode/gtk/gtkslideview.c39
-rw-r--r--libstorycode/narrative.c57
-rw-r--r--libstorycode/narrative.h18
-rw-r--r--libstorycode/narrative_priv.h9
-rw-r--r--libstorycode/narrative_render_cairo.c65
-rw-r--r--libstorycode/render_cairo_common.c97
-rw-r--r--libstorycode/render_cairo_common.h36
-rw-r--r--libstorycode/scparse_priv.h5
-rw-r--r--libstorycode/slide.c42
-rw-r--r--libstorycode/slide.h7
-rw-r--r--libstorycode/slide_priv.h3
-rw-r--r--libstorycode/slide_render_cairo.c26
-rw-r--r--libstorycode/slide_render_cairo.h3
-rw-r--r--libstorycode/storycode.c23
-rw-r--r--libstorycode/storycode.h15
-rw-r--r--libstorycode/storycode.y199
-rw-r--r--meson.build1
-rw-r--r--src/slide_window.c12
19 files changed, 418 insertions, 241 deletions
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; i<n_runs; i++ ) {
- item->runs[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; 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);
+
+ 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 <taw@bitwiz.org.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <pango/pango.h>
+
+#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; i<n_runs; i++ ) {
+ total_len += strlen(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 1;
+ }
+
+ /* Put all of the text together */
+ text[0] = '\0';
+ size_t pos = 0;
+ for ( i=0; i<n_runs; i++ ) {
+
+ PangoAttribute *attr = NULL;
+ size_t run_len = strlen(runs[i].text);
+
+ switch ( runs[i].type ) {
+
+ case TEXT_RUN_NORMAL :
+ break;
+
+ case TEXT_RUN_BOLD:
+ attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
+ break;
+
+ case TEXT_RUN_ITALIC:
+ attr = pango_attr_style_new(PANGO_STYLE_ITALIC);
+ break;
+
+ case TEXT_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, 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 <taw@bitwiz.org.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef RENDER_CAIRO_COMMON_H
+#define RENDER_CAIRO_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pango/pango.h>
+
+#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; i<n_text; i++ ) {
- item->n_paras = n_text;
- item->paras[i].text = text[i];
+ for ( i=0; i<n_paras; i++ ) {
+ item->paras[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; i<n_runs; i++ ) {
+ write_run_border(fh, runs[i].type);
+ write_string(fh, runs[i].text);
+ write_run_border(fh, runs[i].type);
+ }
+}
+
+
static void write_text(GOutputStream *fh, SlideItem *item, int geom,
const char *t)
{
@@ -129,13 +148,13 @@ static void write_text(GOutputStream *fh, SlideItem *item, int geom,
indent = strlen(tmp);
write_string(fh, tmp);
write_string(fh, ": ");
- write_string(fh, item->paras[0].text);
+ write_para(fh, &item->paras[0], item->paras[0].n_runs);
write_string(fh, "\n");
for ( i=0; i<indent; i++ ) tmp[i] = ' ';
for ( i=1; i<item->n_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 <config.h>
#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 <n> narrative
%type <s> slide
%type <ss> stylesheet
-%type <str> slide_prestitle
+%type <many_paragraphs> textframe
+%type <many_paragraphs> slide_prestitle
+%type <many_paragraphs> slidetitle
+%type <many_paragraphs> multi_line_string
+%type <para> text_line
+%type <para> slide_bulletpoint
+%type <para> text_line_with_start
+%type <run> text_run
+%type <str> RUN_TEXT
+
%type <str> FONTNAME
%type <str> imageframe
-%type <str> slide_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
%type <str> HEXCOL
%type <len> length
%type <align> alignment
-%type <str> slidetitle
%type <character> UNIT
%type <val> VALUE
%type <grad> 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; i<mp.n_paras; i++ ) {
+ printf("para %i (%i runs)\n", i, mp.paras[i].n_runs);
+ for ( int j=0; j<mp.paras[i].n_runs; j++ ) {
+ printf("run %i: '%s'\n", j, mp.paras[i].runs[j].text);
+ }
+ combined_paras[i] = mp.paras[i].runs;
+ n_runs[i] = mp.paras[i].n_runs;
}
- ctx->runs[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: { $<para>$.n_runs = 0;
+ $<para>$.max_runs = 0;
+ $<para>$.runs = NULL;
+ }
%empty
-| text_line text_run { add_run(ctx, $2.text, $2.type); }
-;
+| text_line text_run {
+ if ( $<para>$.n_runs == $<para>$.max_runs ) {
+ struct text_run *nruns;
+ nruns = realloc($<para>$.runs,
+ ($<para>$.max_runs+8)*sizeof(struct text_run));
+ if ( nruns != NULL ) {
+ $<para>$.max_runs += 8;
+ $<para>$.runs = nruns;
+ }
+ }
+ if ( $<para>$.n_runs < $<para>$.max_runs ) {
+ $<para>$.runs[$<para>$.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: { $<many_paragraphs>$.n_paras = 0;
+ $<many_paragraphs>$.paras = NULL;
+ $<many_paragraphs>$.max_paras = 0; }
+ text_line_with_start { push_paragraph(&$<many_paragraphs>$, $2); }
+| multi_line_string text_line_with_start { push_paragraph(&$<many_paragraphs>$, $2); }
+| slide_bulletpoint { push_paragraph(&$<many_paragraphs>$, $1); }
+| multi_line_string slide_bulletpoint { push_paragraph(&$<many_paragraphs>$, $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);
}