From 4104a6ff28d3a3be7069663c5677a5ee5076984a Mon Sep 17 00:00:00 2001 From: Thomas White Date: Fri, 1 Mar 2019 00:23:04 +0100 Subject: Narrative rendering machinery --- libstorycode/gtk/gtknarrativeview.c | 42 +----- libstorycode/gtk/gtknarrativeview.h | 1 + libstorycode/narrative.c | 8 +- libstorycode/narrative_priv.h | 70 +++++++++ libstorycode/narrative_render_cairo.c | 266 ++++++++++++++++++++++++++++++++++ libstorycode/narrative_render_cairo.h | 43 ++++++ libstorycode/presentation.c | 7 + libstorycode/presentation.h | 1 + libstorycode/stylesheet.c | 8 +- libstorycode/stylesheet.h | 2 +- meson.build | 1 + 11 files changed, 405 insertions(+), 44 deletions(-) create mode 100644 libstorycode/narrative_priv.h create mode 100644 libstorycode/narrative_render_cairo.c create mode 100644 libstorycode/narrative_render_cairo.h diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index 70d59f5..9040d55 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -34,6 +34,7 @@ #include #include +#include //#include "slide_window.h" #include "gtknarrativeview.h" @@ -121,24 +122,6 @@ static void set_vertical_params(GtkNarrativeView *e) } -static void update_size(GtkNarrativeView *e) -{ -// double total = total_height(e->top); -// -// e->w = e->top->w; -// e->h = total + e->top->pad_t + e->top->pad_b; -// -// e->top->h = e->h; -// -// if ( e->top->h < e->visible_height ) { -// e->top->h = e->visible_height; -// } -// -// set_vertical_params(e); -// set_horizontal_params(e); -} - - static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, GtkNarrativeView *e) { @@ -149,23 +132,13 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, e->visible_height = event->height; e->visible_width = event->width; - /* Wrap everything with the current width, to get the total height */ - //e->top = interp_and_shape(e->scblocks, e->stylesheet, e->cbl, - // e->is, e->slidenum, pc, - // w, h, e->lang); -// e->top->scblocks = e->scblocks; -// recursive_wrap(e->top, pc); -// } -// -// /* Wrap using current width */ -// e->top->w = event->width; -// e->top->h = 0.0; /* To be updated in a moment */ -// e->top->x = 0.0; -// e->top->y = 0.0; -// /* Only the top level needs to be wrapped */ -// wrap_frame(e->top, pc); + e->w = e->visible_width; + e->h = narrative_get_height(presentation_get_narrative(e->p)); - update_size(e); + /* Wrap everything with the current width, to get the total height */ + narrative_wrap(presentation_get_narrative(e->p), + presentation_get_stylesheet(e->p), + pango_language_get_default(), pc, e->w); g_object_unref(pc); @@ -1045,6 +1018,7 @@ GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang, nview->h = 100; nview->scroll_pos = 0; nview->lang = lang; + nview->p = p; nview->para_highlight = 0; diff --git a/libstorycode/gtk/gtknarrativeview.h b/libstorycode/gtk/gtknarrativeview.h index 1b0802f..717b0d0 100644 --- a/libstorycode/gtk/gtknarrativeview.h +++ b/libstorycode/gtk/gtknarrativeview.h @@ -91,6 +91,7 @@ struct _gtknarrativeview GtkDrawingArea parent_instance; /*< private >*/ + Presentation *p; GtkIMContext *im_context; PangoContext *pc; PangoLanguage *lang; diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c index 23b8e34..85f5410 100644 --- a/libstorycode/narrative.c +++ b/libstorycode/narrative.c @@ -29,13 +29,7 @@ #include #include "narrative.h" - -struct _narrative -{ - int n_items; - struct narrative_item *items; -}; - +#include "narrative_priv.h" Narrative *narrative_new() { diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h new file mode 100644 index 0000000..059b015 --- /dev/null +++ b/libstorycode/narrative_priv.h @@ -0,0 +1,70 @@ +/* + * narrative_priv.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 NARRATIVE_PRIV_H +#define NARRATIVE_PRIV_H + +#ifdef HAVE_PANGO +#include +#endif + +#include "storycode.h" + + +enum narrative_item_type +{ + NARRATIVE_ITEM_TEXT, + NARRATIVE_ITEM_SLIDE, + NARRATIVE_ITEM_BP, +}; + + +struct narrative_item +{ + enum narrative_item_type type; + + /* For TEXT, SLIDETITLE, PRESTITLE */ + char **paragraphs; + int n_paras; + enum alignment align; +#ifdef HAVE_PANGO + PangoLayout **layouts; +#endif + + /* For IMAGE */ + char *filename; + + /* For TEXT and IMAGE */ + struct frame_geom geom; +}; + + +struct _narrative +{ + int n_items; + struct narrative_item *items; + double w; + double total_h; +}; + + +#endif /* NARRATIVE_PRIV_H */ diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c new file mode 100644 index 0000000..746ce62 --- /dev/null +++ b/libstorycode/narrative_render_cairo.c @@ -0,0 +1,266 @@ +/* + * narrative_render_cairo.c + * + * Copyright © 2013-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 +#include +#include +#include + +#include "slide.h" +#include "narrative.h" +#include "stylesheet.h" + +#include "narrative_priv.h" + + +static double lcalc(struct length l, double pd) +{ + if ( l.unit == LENGTH_UNIT ) { + return l.len; + } else { + return l.len * pd; + } +} + + +static PangoAlignment to_pangoalignment(enum alignment align) +{ + switch ( align ) { + case ALIGN_LEFT : return PANGO_ALIGN_LEFT; + case ALIGN_RIGHT : return PANGO_ALIGN_RIGHT; + case ALIGN_CENTER : return PANGO_ALIGN_CENTER; + default: return PANGO_ALIGN_LEFT; + } +} + + +static double wrap_text(struct narrative_item *item, PangoContext *pc, + Stylesheet *ss, enum style_element el, double wrap_w, + PangoFontDescription *fontdesc, enum alignment align) +{ + int i; + PangoAlignment palignment; + double total_h = 0.0; + + if ( item->layouts == NULL ) { + item->layouts = malloc(item->n_paras*sizeof(PangoLayout *)); + if ( item->layouts == NULL ) return 0.0; + for ( i=0; in_paras; i++ ) { + item->layouts[i] = NULL; + } + } + + if ( item->align == ALIGN_INHERIT ) { + /* Use value from stylesheet */ + palignment = to_pangoalignment(align); + } else { + /* Use item-specific value */ + palignment = to_pangoalignment(item->align); + } + + for ( i=0; in_paras; i++ ) { + + PangoRectangle rect; + + if ( item->layouts[i] == NULL ) { + item->layouts[i] = pango_layout_new(pc); + } + pango_layout_set_width(item->layouts[i], pango_units_from_double(wrap_w)); + pango_layout_set_text(item->layouts[i], item->paragraphs[i], -1); + pango_layout_set_alignment(item->layouts[i], palignment); + pango_layout_set_font_description(item->layouts[i], fontdesc); + + /* FIXME: Handle *bold*, _underline_, /italic/ etc. */ + //pango_layout_set_attributes(item->layouts[i], attrs); + //pango_attr_list_unref(attrs); + + pango_layout_get_extents(item->layouts[i], NULL, &rect); + total_h += pango_units_to_double(rect.height); + + } + + return total_h; +} + + +static void draw_text(struct narrative_item *item, cairo_t *cr) +{ + int i; + double hpos = 0.0; + + cairo_save(cr); + + for ( i=0; in_paras; i++ ) { + + PangoRectangle rect; + double cur_h; + + pango_layout_get_extents(item->layouts[i], NULL, &rect); + cur_h = rect.height; + + cairo_save(cr); + cairo_translate(cr, 0.0, hpos); + + //if ( (hpos + cur_h > min_y) && (hpos < max_y) ) { + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + pango_cairo_update_layout(cr, item->layouts[i]); + pango_cairo_show_layout(cr, item->layouts[i]); + cairo_fill(cr); + //} /* else paragraph is not visible */ + + hpos += cur_h; + cairo_restore(cr); + + } + + cairo_restore(cr); +} + + +int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, + PangoContext *pc, double w) +{ + int i; + struct length pad[4]; + double pad_l, pad_r, pad_t, pad_b; + const char *font; + PangoFontDescription *fontdesc; + double wrap_w; + enum alignment align; + + if ( stylesheet_get_padding(stylesheet, STYEL_NARRATIVE, pad) ) return 1; + pad_l = lcalc(pad[0], w); + pad_r = lcalc(pad[1], w); + pad_t = lcalc(pad[2], 1024.0); /* dummy value, h not allowed in narrative */ + pad_b = lcalc(pad[3], 1024.0); /* dummy value, h not allowed in narrative */ + wrap_w = w - pad_l - pad_r; + + n->w = w; + n->total_h = pad_t + pad_b; + + font = stylesheet_get_font(stylesheet, STYEL_NARRATIVE, NULL, &align); + if ( font == NULL ) return 1; + fontdesc = pango_font_description_from_string(font); + + for ( i=0; in_items; i++ ) { + + switch ( n->items[i].type ) { + + case NARRATIVE_ITEM_TEXT : + n->total_h += wrap_text(&n->items[i], pc, stylesheet, + STYEL_NARRATIVE, wrap_w, fontdesc, + align); + break; + + case NARRATIVE_ITEM_BP : + n->total_h += wrap_text(&n->items[i], pc, stylesheet, + STYEL_NARRATIVE, wrap_w, fontdesc, + align); + break; + + case NARRATIVE_ITEM_SLIDE : + break; + + default : + break; + + } + } + + return 0; +} + + +double narrative_get_height(Narrative *n) +{ + return n->total_h; +} + + +int narrative_render_cairo(Narrative *n, cairo_t *cr, Stylesheet *stylesheet, + PangoLanguage *lang, PangoContext *pc, double w) +{ + int i, r; + enum gradient bg; + double bgcol[4]; + double bgcol2[4]; + cairo_pattern_t *patt = NULL; + + r = stylesheet_get_background(stylesheet, STYEL_SLIDE, &bg, bgcol, bgcol2); + if ( r ) return 1; + + /* Overall background */ + cairo_rectangle(cr, 0.0, 0.0, n->w, n->total_h); + switch ( bg ) { + + case GRAD_NONE: + cairo_set_source_rgb(cr, bgcol[0], bgcol[1], bgcol[2]); + break; + + case GRAD_VERT: + patt = cairo_pattern_create_linear(0.0, 0.0, 0.0, n->total_h); + cairo_pattern_add_color_stop_rgb(patt, 0.0, bgcol[0], bgcol[1], bgcol[2]); + cairo_pattern_add_color_stop_rgb(patt, 1.0, bgcol2[0], bgcol2[1], bgcol2[2]); + cairo_set_source(cr, patt); + break; + + case GRAD_HORIZ: + patt = cairo_pattern_create_linear(0.0, 0.0, n->w, 0.0); + cairo_pattern_add_color_stop_rgb(patt, 0.0, bgcol[0], bgcol[1], bgcol[2]); + cairo_pattern_add_color_stop_rgb(patt, 1.0, bgcol2[0], bgcol2[1], bgcol2[2]); + cairo_set_source(cr, patt); + break; + + } + cairo_fill(cr); + + for ( i=0; in_items; i++ ) { + + switch ( n->items[i].type ) { + + case NARRATIVE_ITEM_TEXT : + draw_text(&n->items[i], cr); + break; + + case NARRATIVE_ITEM_BP : + draw_text(&n->items[i], cr); + break; + + case NARRATIVE_ITEM_SLIDE : + break; + + default : + break; + + } + } + + return 0; +} diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h new file mode 100644 index 0000000..1f16aae --- /dev/null +++ b/libstorycode/narrative_render_cairo.h @@ -0,0 +1,43 @@ +/* + * narrative_render_cairo.h + * + * Copyright © 2013-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 NARRATIVE_RENDER_CAIRO_H +#define NARRATIVE_RENDER_CAIRO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "presentation.h" +#include "imagestore.h" + + +extern int narrative_wrap(Narrative *n, Stylesheet *stylesheet, + PangoLanguage *lang, PangoContext *pc, double w); + +extern double narrative_get_height(Narrative *n); + +extern int narrative_render_cairo(Narrative *n, cairo_t *cr, + Stylesheet *stylesheet, PangoLanguage *lang, + PangoContext *pc); + +#endif /* NARRATIVE_RENDER_CAIRO_H */ diff --git a/libstorycode/presentation.c b/libstorycode/presentation.c index 6eb7a50..f81dc84 100644 --- a/libstorycode/presentation.c +++ b/libstorycode/presentation.c @@ -148,3 +148,10 @@ Stylesheet *presentation_get_stylesheet(Presentation *p) if ( p == NULL ) return NULL; return p->stylesheet; } + + +Narrative *presentation_get_narrative(Presentation *p) +{ + if ( p == NULL ) return NULL; + return p->narrative; +} diff --git a/libstorycode/presentation.h b/libstorycode/presentation.h index 250d7a6..d5269b9 100644 --- a/libstorycode/presentation.h +++ b/libstorycode/presentation.h @@ -46,5 +46,6 @@ extern void presentation_add_slide(Presentation *p, Slide *s); extern int presentation_num_slides(Presentation *p); extern Slide *presentation_slide(Presentation *p, int i); extern Stylesheet *presentation_get_stylesheet(Presentation *p); +extern Narrative *presentation_get_narrative(Presentation *p); #endif /* PRESENTATION_H */ diff --git a/libstorycode/stylesheet.c b/libstorycode/stylesheet.c index 88b60cd..6dc1504 100644 --- a/libstorycode/stylesheet.c +++ b/libstorycode/stylesheet.c @@ -246,14 +246,18 @@ int stylesheet_set_alignment(Stylesheet *s, enum style_element el, enum alignmen const char *stylesheet_get_font(Stylesheet *s, enum style_element el, - double fgcol[4], enum alignment *alignment) + double *fgcol, enum alignment *alignment) { int i; struct style *sty = get_style(s, el); if ( sty == NULL ) return NULL; *alignment = sty->alignment; - for ( i=0; i<4; i++ ) fgcol[i] = sty->fgcol[i]; + if ( fgcol != NULL ) { + for ( i=0; i<4; i++ ) { + fgcol[i] = sty->fgcol[i]; + } + } return sty->font; } diff --git a/libstorycode/stylesheet.h b/libstorycode/stylesheet.h index 5bd1695..e905295 100644 --- a/libstorycode/stylesheet.h +++ b/libstorycode/stylesheet.h @@ -95,7 +95,7 @@ extern int stylesheet_set_background(Stylesheet *s, enum style_element el, enum double bgcol[4], double bgcol2[4]); extern const char *stylesheet_get_font(Stylesheet *s, enum style_element el, - double fgcol[4], enum alignment *alignment); + double *fgcol, enum alignment *alignment); extern int stylesheet_get_background(Stylesheet *s, enum style_element el, enum gradient *grad, double *bgcol, double *bgcol2); extern int stylesheet_get_padding(Stylesheet *s, enum style_element el, diff --git a/meson.build b/meson.build index 88d1051..c1daeea 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ libstorycode = library('storycode', 'libstorycode/stylesheet.c', 'libstorycode/storycode.c', 'libstorycode/slide_render_cairo.c', + 'libstorycode/narrative_render_cairo.c', 'libstorycode/imagestore.c', storycode_lex_ch, storycode_parse_ch, -- cgit v1.2.3