aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-03-04 23:46:47 +0100
committerThomas White <taw@bitwiz.me.uk>2019-03-04 23:46:47 +0100
commit915fcacee4c49f017ab2599b4307198ca3f713d3 (patch)
treeed4c7a8f8aec7327934f86d9f3100f982ee1d624
parent373d5183849c2855345ea45c964479086d67a7d2 (diff)
Thumbnail slide rendering in narrative
-rw-r--r--libstorycode/gtk/gtknarrativeview.c12
-rw-r--r--libstorycode/gtk/gtknarrativeview.h6
-rw-r--r--libstorycode/narrative.c1
-rw-r--r--libstorycode/narrative_priv.h5
-rw-r--r--libstorycode/narrative_render_cairo.c65
-rw-r--r--libstorycode/narrative_render_cairo.h3
-rw-r--r--libstorycode/presentation.c32
-rw-r--r--libstorycode/presentation.h3
-rw-r--r--libstorycode/slide.c1
-rw-r--r--libstorycode/slide_render_cairo.c24
-rw-r--r--src/narrative_window.c4
11 files changed, 122 insertions, 34 deletions
diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c
index 5d89ae5..90915ab 100644
--- a/libstorycode/gtk/gtknarrativeview.c
+++ b/libstorycode/gtk/gtknarrativeview.c
@@ -126,6 +126,8 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event,
GtkNarrativeView *e)
{
PangoContext *pc;
+ PangoLanguage *lang;
+ const char *langname;
pc = gdk_pango_context_get();
@@ -133,10 +135,14 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event,
e->visible_width = event->width;
e->w = e->visible_width;
+ langname = presentation_get_language(e->p);
+ lang = pango_language_from_string(langname);
+
/* 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);
+ lang, gtk_widget_get_pango_context(widget), e->w,
+ presentation_get_imagestore(e->p));
e->w = e->visible_width;
e->h = narrative_get_height(presentation_get_narrative(e->p));
@@ -1012,8 +1018,7 @@ static void update_size_request(GtkNarrativeView *e)
}
-GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang,
- const char *storename)
+GtkNarrativeView *gtk_narrative_view_new(Presentation *p)
{
GtkNarrativeView *nview;
GtkTargetEntry targets[1];
@@ -1023,7 +1028,6 @@ GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang,
nview->w = 100;
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 717b0d0..bf596fc 100644
--- a/libstorycode/gtk/gtknarrativeview.h
+++ b/libstorycode/gtk/gtknarrativeview.h
@@ -33,6 +33,7 @@
#include <stylesheet.h>
#include <narrative.h>
#include <presentation.h>
+#include <imagestore.h>
#define GTK_TYPE_NARRATIVE_VIEW (gtk_narrative_view_get_type())
@@ -94,7 +95,6 @@ struct _gtknarrativeview
Presentation *p;
GtkIMContext *im_context;
PangoContext *pc;
- PangoLanguage *lang;
int w; /* Surface size in pixels */
int h;
@@ -129,9 +129,7 @@ struct _gtknarrativeviewclass
typedef struct _gtknarrativeview GtkNarrativeView;
typedef struct _gtknarrativeviewclass GtkNarrativeViewClass;
-extern GtkNarrativeView *gtk_narrative_view_new(Presentation *p,
- PangoLanguage *lang,
- const char *storename);
+extern GtkNarrativeView *gtk_narrative_view_new(Presentation *p);
extern void gtk_narrative_view_set_logical_size(GtkNarrativeView *e, double w, double h);
diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c
index 91c87c5..18e2203 100644
--- a/libstorycode/narrative.c
+++ b/libstorycode/narrative.c
@@ -109,4 +109,5 @@ void narrative_add_slide(Narrative *n, Slide *slide)
item->type = NARRATIVE_ITEM_SLIDE;
item->slide = slide;
+ item->slide_thumbnail = NULL;
}
diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h
index 5c0af27..1a461c4 100644
--- a/libstorycode/narrative_priv.h
+++ b/libstorycode/narrative_priv.h
@@ -62,6 +62,11 @@ struct narrative_item
Slide *slide;
double slide_w;
double slide_h;
+#ifdef HAVE_CAIRO
+ cairo_surface_t *slide_thumbnail;
+#else
+ void *slide_thumbnail;
+#endif
};
diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c
index cd2d872..6024ccc 100644
--- a/libstorycode/narrative_render_cairo.c
+++ b/libstorycode/narrative_render_cairo.c
@@ -36,6 +36,8 @@
#include "slide.h"
#include "narrative.h"
#include "stylesheet.h"
+#include "imagestore.h"
+#include "slide_render_cairo.h"
#include "narrative_priv.h"
@@ -107,13 +109,51 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
//pango_layout_set_attributes(item->layout, attrs);
//pango_attr_list_unref(attrs);
-
pango_layout_get_extents(item->layout, NULL, &rect);
item->h = pango_units_to_double(rect.height)+item->space_t+item->space_b;
}
-static void wrap_slide(struct narrative_item *item, Stylesheet *ss)
+/* Render a thumbnail of the slide */
+static cairo_surface_t *render_thumbnail(Slide *s, Stylesheet *ss, ImageStore *is,
+ int w, int h)
+{
+ cairo_surface_t *surf;
+ cairo_surface_t *full_surf;
+ cairo_t *cr;
+ double logical_w, logical_h;
+ PangoContext *pc;
+ const int rh = 1024; /* "reasonably big" height for slide */
+ int rw;
+
+ slide_get_logical_size(s, ss, &logical_w, &logical_h);
+ rw = rh*(logical_w/logical_h);
+
+ /* Render at a reasonably big size. Rendering to a small surface makes
+ * rounding of text positions (due to font hinting) cause significant
+ * differences between the thumbnail and "normal" rendering. */
+ full_surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, rw, rh);
+ cr = cairo_create(full_surf);
+ cairo_scale(cr, (double)rw/logical_w, (double)rh/logical_h);
+ pc = pango_cairo_create_context(cr);
+ slide_render_cairo(s, cr, is, ss, 0, pango_language_get_default(), pc);
+ g_object_unref(pc);
+ cairo_destroy(cr);
+
+ /* Scale down to the actual size of the thumbnail */
+ surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
+ cr = cairo_create(surf);
+ cairo_scale(cr, (double)w/rw, (double)h/rh);
+ cairo_set_source_surface(cr, full_surf, 0.0, 0.0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ cairo_surface_destroy(full_surf);
+ return surf;
+}
+
+
+static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore *is)
{
double w, h;
@@ -123,16 +163,21 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss)
item->space_b = 10.0;
slide_get_logical_size(item->slide, ss, &w, &h);
- item->slide_h = 320.0;
- item->slide_w = item->slide_h*w/h;
+ item->slide_h = 320.0; /* Actual height of thumbnail */
+ item->slide_w = rint(item->slide_h*w/h);
item->h = item->slide_h + item->space_t + item->space_b;
+ if ( item->slide_thumbnail != NULL ) {
+ cairo_surface_destroy(item->slide_thumbnail);
+ }
+ item->slide_thumbnail = render_thumbnail(item->slide, ss, is,
+ item->slide_w, item->slide_h);
}
int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang,
- PangoContext *pc, double w)
+ PangoContext *pc, double w, ImageStore *is)
{
int i;
struct length pad[4];
@@ -166,7 +211,7 @@ int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang,
break;
case NARRATIVE_ITEM_SLIDE :
- wrap_slide(&n->items[i], stylesheet);
+ wrap_slide(&n->items[i], stylesheet, is);
break;
default :
@@ -201,9 +246,13 @@ static void draw_slide(struct narrative_item *item, cairo_t *cr)
cairo_user_to_device(cr, &x, &y);
x = rint(x); y = rint(y);
cairo_device_to_user(cr, &x, &y);
- cairo_rectangle(cr, x+0.5, y+0.5, item->slide_w, item->slide_h);
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+ cairo_rectangle(cr, x, y, item->slide_w, item->slide_h);
+ cairo_set_source_surface(cr, item->slide_thumbnail, 0.0, 0.0);
+ cairo_fill(cr);
+
+ cairo_rectangle(cr, x+0.5, y+0.5, item->slide_w, item->slide_h);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_set_line_width(cr, 1.0);
cairo_stroke(cr);
diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h
index ebabb4d..835c5a9 100644
--- a/libstorycode/narrative_render_cairo.h
+++ b/libstorycode/narrative_render_cairo.h
@@ -32,7 +32,8 @@
extern int narrative_wrap(Narrative *n, Stylesheet *stylesheet,
- PangoLanguage *lang, PangoContext *pc, double w);
+ PangoLanguage *lang, PangoContext *pc, double w,
+ ImageStore *is);
extern double narrative_get_height(Narrative *n);
diff --git a/libstorycode/presentation.c b/libstorycode/presentation.c
index f81dc84..d49f965 100644
--- a/libstorycode/presentation.c
+++ b/libstorycode/presentation.c
@@ -31,6 +31,10 @@
#include <stdio.h>
#include <gio/gio.h>
+#ifdef HAVE_PANGO
+#include <pango/pango.h>
+#endif
+
#include "presentation.h"
#include "stylesheet.h"
#include "slide.h"
@@ -42,9 +46,11 @@ struct _presentation
{
Stylesheet *stylesheet;
Narrative *narrative;
+ ImageStore *imagestore;
int n_slides;
Slide **slides;
int max_slides;
+ const char *language;
};
@@ -58,6 +64,12 @@ Presentation *presentation_new()
p->slides = NULL;
p->n_slides = 0;
p->max_slides = 0;
+ p->imagestore = NULL;
+#ifdef HAVE_PANGO
+ p->language = pango_language_to_string(pango_language_get_default());
+#else
+ p->language = NULL;
+#endif
return p;
}
@@ -68,7 +80,6 @@ Presentation *presentation_load(GFile *file)
const char *text;
size_t len;
Presentation *p;
- ImageStore *is;
bytes = g_file_load_bytes(file, NULL, NULL, NULL);
if ( bytes == NULL ) return NULL;
@@ -78,8 +89,8 @@ Presentation *presentation_load(GFile *file)
g_bytes_unref(bytes);
if ( p == NULL ) return NULL;
- is = imagestore_new(".");
- imagestore_set_parent(is, g_file_get_parent(file));
+ p->imagestore = imagestore_new("."); /* FIXME: From app config */
+ imagestore_set_parent(p->imagestore, g_file_get_parent(file));
return p;
}
@@ -93,6 +104,7 @@ int presentation_save(Presentation *p, GFile *file)
void presentation_free(Presentation *p)
{
+ /* FIXME: Free narrative, slides, imagestore */
free(p);
}
@@ -155,3 +167,17 @@ Narrative *presentation_get_narrative(Presentation *p)
if ( p == NULL ) return NULL;
return p->narrative;
}
+
+
+const char *presentation_get_language(Presentation *p)
+{
+ if ( p == NULL ) return NULL;
+ return p->language;
+}
+
+
+ImageStore *presentation_get_imagestore(Presentation *p)
+{
+ if ( p == NULL ) return NULL;
+ return p->imagestore;
+}
diff --git a/libstorycode/presentation.h b/libstorycode/presentation.h
index d5269b9..3abe91e 100644
--- a/libstorycode/presentation.h
+++ b/libstorycode/presentation.h
@@ -33,6 +33,7 @@ typedef struct _presentation Presentation;
#include "stylesheet.h"
#include "narrative.h"
+#include "imagestore.h"
extern Presentation *presentation_new(void);
extern Presentation *presentation_load(GFile *file);
@@ -47,5 +48,7 @@ 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);
+extern const char *presentation_get_language(Presentation *p);
+extern ImageStore *presentation_get_imagestore(Presentation *p);
#endif /* PRESENTATION_H */
diff --git a/libstorycode/slide.c b/libstorycode/slide.c
index 9db5995..694f29a 100644
--- a/libstorycode/slide.c
+++ b/libstorycode/slide.c
@@ -87,6 +87,7 @@ int add_text_item(Slide *s, char **text, int n_text, struct frame_geom geom,
if ( item == NULL ) return 1;
item->type = slide_item;
+ item->layouts = NULL;
item->paragraphs = malloc(n_text*sizeof(char *));
if ( item->paragraphs == NULL ) {
s->n_items--;
diff --git a/libstorycode/slide_render_cairo.c b/libstorycode/slide_render_cairo.c
index ed9b948..e74a13f 100644
--- a/libstorycode/slide_render_cairo.c
+++ b/libstorycode/slide_render_cairo.c
@@ -68,8 +68,8 @@ static void render_text(struct slide_item *item, cairo_t *cr, PangoContext *pc,
double parent_w, double parent_h)
{
int i;
- double x, y, w, h;
- double pad_l, pad_r, pad_t, pad_b;
+ double x, y, w;
+ double pad_l, pad_r, pad_t;
struct length pad[4];
const char *font;
enum alignment align;
@@ -81,13 +81,11 @@ static void render_text(struct slide_item *item, cairo_t *cr, PangoContext *pc,
x = lcalc(item->geom.x, parent_w);
y = lcalc(item->geom.y, parent_h);
w = lcalc(item->geom.w, parent_w);
- h = lcalc(item->geom.h, parent_h);
if ( stylesheet_get_padding(ss, el, pad) ) return;
pad_l = lcalc(pad[0], parent_w);
pad_r = lcalc(pad[1], parent_w);
pad_t = lcalc(pad[2], parent_h);
- pad_b = lcalc(pad[3], parent_h);
font = stylesheet_get_font(ss, el, fgcol, &align);
if ( font == NULL ) return;
@@ -200,7 +198,7 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles
slide_get_logical_size(s, stylesheet, &w, &h);
/* Overall background */
- cairo_rectangle(cr, 0.0, 0.0, s->logical_w, s->logical_h);
+ cairo_rectangle(cr, 0.0, 0.0, w, h);
switch ( bg ) {
case GRAD_NONE:
@@ -208,19 +206,23 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles
break;
case GRAD_VERT:
- patt = cairo_pattern_create_linear(0.0, 0.0, 0.0, s->logical_h);
+ patt = cairo_pattern_create_linear(0.0, 0.0, 0.0, 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, s->logical_w, 0.0);
+ patt = cairo_pattern_create_linear(0.0, 0.0, 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;
+ default:
+ fprintf(stderr, "Unrecognised slide background type %i\n", bg);
+ break;
+
}
cairo_fill(cr);
@@ -230,22 +232,22 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles
case SLIDE_ITEM_TEXT :
render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_TEXT,
- s->logical_w, s->logical_h);
+ w, h);
break;
case SLIDE_ITEM_IMAGE :
render_image(&s->items[i], cr, stylesheet, is,
- s->logical_w, s->logical_h);
+ w, h);
break;
case SLIDE_ITEM_SLIDETITLE :
render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_SLIDETITLE,
- s->logical_w, s->logical_h);
+ w, h);
break;
case SLIDE_ITEM_PRESTITLE :
render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_PRESTITLE,
- s->logical_w, s->logical_h);
+ w, h);
break;
default :
diff --git a/src/narrative_window.c b/src/narrative_window.c
index 45f20c5..b6d8514 100644
--- a/src/narrative_window.c
+++ b/src/narrative_window.c
@@ -697,9 +697,7 @@ NarrativeWindow *narrative_window_new(Presentation *p, GApplication *papp)
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(nw->window), vbox);
- /* FIXME: Language should be a property of the presentation */
- nw->nv = gtk_narrative_view_new(p, pango_language_get_default(),
- colloquium_get_imagestore(app));
+ nw->nv = gtk_narrative_view_new(p);
toolbar = gtk_toolbar_new();
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);