From 6b60cafe0c2689531459f1cffd704da16ed2aec3 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Thu, 28 Mar 2019 15:05:10 +0100 Subject: Restore slideshow and clock --- src/narrative_window.c | 245 ++++++++++++++------------- src/pr_clock.c | 439 +++++++++++++++++++++++++++++++++++++++++++++++++ src/pr_clock.h | 37 +++++ src/slideshow.c | 222 +++++++++++++++++++++++++ src/slideshow.h | 79 +++++++++ 5 files changed, 905 insertions(+), 117 deletions(-) create mode 100644 src/pr_clock.c create mode 100644 src/pr_clock.h create mode 100644 src/slideshow.c create mode 100644 src/slideshow.h (limited to 'src') diff --git a/src/narrative_window.c b/src/narrative_window.c index c51d3a3..a6e71af 100644 --- a/src/narrative_window.c +++ b/src/narrative_window.c @@ -40,11 +40,10 @@ #include "narrative_window.h" #include "slide_window.h" #include "testcard.h" -//#include "pr_clock.h" +#include "pr_clock.h" +#include "slideshow.h" //#include "print.h" //#include "stylesheet_editor.h" -typedef struct _ss SCSlideshow; /* FIXME placeholder */ -typedef struct _pc PRClock; /* FIXME placeholder */ struct _narrative_window { @@ -109,25 +108,25 @@ static void update_titlebar(NarrativeWindow *nw) static void update_toolbar(NarrativeWindow *nw) { -// int cur_para; + int cur_para, n_para; - /* FIXME */ -// cur_para = sc_editor_get_cursor_para(nw->nv); -// if ( cur_para == 0 ) { -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bfirst), FALSE); -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bprev), FALSE); -// } else { -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bfirst), TRUE); -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bprev), TRUE); -// } -// -// if ( cur_para == sc_editor_get_num_paras(nw->nv)-1 ) { -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bnext), FALSE); -// gtk_widget_set_sensitive(GTK_WIDGET(nw->blast), FALSE); -// } else { -// gtk_widget_set_sensitive(GTK_WIDGET(nw->bnext), TRUE); -// gtk_widget_set_sensitive(GTK_WIDGET(nw->blast), TRUE); -// } + cur_para = gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv)); + if ( cur_para == 0 ) { + gtk_widget_set_sensitive(GTK_WIDGET(nw->bfirst), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(nw->bprev), FALSE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(nw->bfirst), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(nw->bprev), TRUE); + } + + n_para = narrative_get_num_items(presentation_get_narrative(nw->p)); + if ( cur_para == n_para - 1 ) { + gtk_widget_set_sensitive(GTK_WIDGET(nw->bnext), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(nw->blast), FALSE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(nw->bnext), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(nw->blast), TRUE); + } } @@ -318,87 +317,98 @@ static void add_slide_sig(GSimpleAction *action, GVariant *parameter, static void first_para_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { -// NarrativeWindow *nw = vp; -// sc_editor_set_cursor_para(nw->nv, 0); -// pr_clock_set_pos(nw->pr_clock, sc_editor_get_cursor_para(nw->nv), -// sc_editor_get_num_paras(nw->nv)); -// update_toolbar(nw); + NarrativeWindow *nw = vp; + int n_paras = narrative_get_num_items(presentation_get_narrative(nw->p)); + gtk_narrative_view_set_cursor_para(GTK_NARRATIVE_VIEW(nw->nv), 0); + pr_clock_set_pos(nw->pr_clock, + gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv)), + n_paras); + update_toolbar(nw); } static void ss_prev_para(SCSlideshow *ss, void *vp) { -// NarrativeWindow *nw = vp; -// if ( sc_editor_get_cursor_para(nw->nv) == 0 ) return; -// sc_editor_set_cursor_para(nw->nv, -// sc_editor_get_cursor_para(nw->nv)-1); -// pr_clock_set_pos(nw->pr_clock, sc_editor_get_cursor_para(nw->nv), -// sc_editor_get_num_paras(nw->nv)); -// update_toolbar(nw); + NarrativeWindow *nw = vp; + int n_paras = narrative_get_num_items(presentation_get_narrative(nw->p)); + if ( gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv)) == 0 ) return; + gtk_narrative_view_set_cursor_para(GTK_NARRATIVE_VIEW(nw->nv), + gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv))-1); + pr_clock_set_pos(nw->pr_clock, + gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv)), + n_paras); + update_toolbar(nw); } static void prev_para_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { -// NarrativeWindow *nw = vp; -// ss_prev_para(nw->show, nw); + NarrativeWindow *nw = vp; + ss_prev_para(nw->show, nw); } static void ss_next_para(SCSlideshow *ss, void *vp) { -// NarrativeWindow *nw = vp; -// SCBlock *ns; -// -// sc_editor_set_cursor_para(nw->nv, -// sc_editor_get_cursor_para(nw->nv)+1); -// -// /* If we only have one monitor, don't try to do paragraph counting */ -// if ( ss->single_monitor && !nw->show_no_slides ) { -// int i, max; -// max = sc_editor_get_num_paras(nw->nv); -// for ( i=sc_editor_get_cursor_para(nw->nv); inv, i); -// ns = sc_editor_get_cursor_bvp(nw->nv); -// if ( ns != NULL ) break; -// } -// } -// -// pr_clock_set_pos(nw->pr_clock, sc_editor_get_cursor_para(nw->nv), -// sc_editor_get_num_paras(nw->nv)); -// ns = sc_editor_get_cursor_bvp(nw->nv); -// if ( ns != NULL ) { -// sc_slideshow_set_slide(nw->show, ns); -// } -// update_toolbar(nw); + NarrativeWindow *nw = vp; + Slide *ns; + Narrative *narr; + GtkNarrativeView *nv; + int n_paras; + + narr = presentation_get_narrative(nw->p); + n_paras = narrative_get_num_items(narr); + nv = GTK_NARRATIVE_VIEW(nw->nv); + + gtk_narrative_view_set_cursor_para(nv, gtk_narrative_view_get_cursor_para(nv)+1); + + /* If we only have one monitor, skip to next slide */ + if ( ss->single_monitor && !nw->show_no_slides ) { + int i; + for ( i=gtk_narrative_view_get_cursor_para(nv); ipr_clock, gtk_narrative_view_get_cursor_para(nv), n_paras); + ns = narrative_get_slide(narr, gtk_narrative_view_get_cursor_para(nv)); + if ( ns != NULL ) { + sc_slideshow_set_slide(nw->show, ns); + } + update_toolbar(nw); } static void next_para_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { -// NarrativeWindow *nw = vp; -// ss_next_para(nw->show, nw); + NarrativeWindow *nw = vp; + ss_next_para(nw->show, nw); } static void last_para_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { -// NarrativeWindow *nw = vp; -// sc_editor_set_cursor_para(nw->nv, -1); -// pr_clock_set_pos(nw->pr_clock, sc_editor_get_cursor_para(nw->nv), -// sc_editor_get_num_paras(nw->nv)); -// update_toolbar(nw); + NarrativeWindow *nw = vp; + int n_paras = narrative_get_num_items(presentation_get_narrative(nw->p)); + gtk_narrative_view_set_cursor_para(GTK_NARRATIVE_VIEW(nw->nv), -1); + pr_clock_set_pos(nw->pr_clock, + gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv)), + n_paras); + update_toolbar(nw); } static void open_clock_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { - //NarrativeWindow *nw = vp; -// nw->pr_clock = pr_clock_new(); + NarrativeWindow *nw = vp; + nw->pr_clock = pr_clock_new(); } @@ -547,7 +557,7 @@ static gboolean nw_key_press_sig(GtkWidget *da, GdkEventKey *event, static gboolean ss_destroy_sig(GtkWidget *da, NarrativeWindow *nw) { nw->show = NULL; - //sc_editor_set_para_highlight(nw->nv, 0); FIXME + gtk_narrative_view_set_para_highlight(GTK_NARRATIVE_VIEW(nw->nv), 0); gtk_widget_set_sensitive(GTK_WIDGET(nw->bfirst), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(nw->bprev), FALSE); @@ -561,74 +571,75 @@ static gboolean ss_destroy_sig(GtkWidget *da, NarrativeWindow *nw) static void start_slideshow_here_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { - //NarrativeWindow *nw = vp; - //void *bvp; + NarrativeWindow *nw = vp; + Slide *slide; - //if ( num_slides(nw->p) == 0 ) return; + if ( presentation_get_num_slides(nw->p) == 0 ) return; - //bvp = sc_editor_get_cursor_bvp(nw->nv); - //if ( bvp == NULL ) return; + slide = narrative_get_slide(presentation_get_narrative(nw->p), + gtk_narrative_view_get_cursor_para(GTK_NARRATIVE_VIEW(nw->nv))); + if ( slide == NULL ) return; - //nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); - //if ( nw->show == NULL ) return; + nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); + if ( nw->show == NULL ) return; - //nw->show_no_slides = 0; + nw->show_no_slides = 0; - //g_signal_connect(G_OBJECT(nw->show), "key-press-event", - // G_CALLBACK(nw_key_press_sig), nw); - //g_signal_connect(G_OBJECT(nw->show), "destroy", - // G_CALLBACK(ss_destroy_sig), nw); - //sc_slideshow_set_slide(nw->show, bvp); - //sc_editor_set_para_highlight(nw->nv, 1); - //gtk_widget_show_all(GTK_WIDGET(nw->show)); - //update_toolbar(nw); + g_signal_connect(G_OBJECT(nw->show), "key-press-event", + G_CALLBACK(nw_key_press_sig), nw); + g_signal_connect(G_OBJECT(nw->show), "destroy", + G_CALLBACK(ss_destroy_sig), nw); + sc_slideshow_set_slide(nw->show, slide); + gtk_narrative_view_set_para_highlight(GTK_NARRATIVE_VIEW(nw->nv), 1); + gtk_widget_show_all(GTK_WIDGET(nw->show)); + update_toolbar(nw); } static void start_slideshow_noslides_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { - //NarrativeWindow *nw = vp; + NarrativeWindow *nw = vp; - //if ( num_slides(nw->p) == 0 ) return; + if ( presentation_get_num_slides(nw->p) == 0 ) return; - //nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); - //if ( nw->show == NULL ) return; + nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); + if ( nw->show == NULL ) return; - //nw->show_no_slides = 1; + nw->show_no_slides = 1; - //g_signal_connect(G_OBJECT(nw->show), "key-press-event", - // G_CALLBACK(nw_key_press_sig), nw); - //g_signal_connect(G_OBJECT(nw->show), "destroy", - // G_CALLBACK(ss_destroy_sig), nw); - //sc_slideshow_set_slide(nw->show, first_slide(nw->p)); - //sc_editor_set_para_highlight(nw->nv, 1); - //sc_editor_set_cursor_para(nw->nv, 0); - //update_toolbar(nw); + g_signal_connect(G_OBJECT(nw->show), "key-press-event", + G_CALLBACK(nw_key_press_sig), nw); + g_signal_connect(G_OBJECT(nw->show), "destroy", + G_CALLBACK(ss_destroy_sig), nw); + sc_slideshow_set_slide(nw->show, presentation_get_slide_by_number(nw->p, 0)); + gtk_narrative_view_set_para_highlight(GTK_NARRATIVE_VIEW(nw->nv), 1); + gtk_narrative_view_set_cursor_para(GTK_NARRATIVE_VIEW(nw->nv), 0); + update_toolbar(nw); } static void start_slideshow_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { -// NarrativeWindow *nw = vp; -// -// if ( num_slides(nw->p) == 0 ) return; -// -// nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); -// if ( nw->show == NULL ) return; -// -// nw->show_no_slides = 0; -// -// g_signal_connect(G_OBJECT(nw->show), "key-press-event", -// G_CALLBACK(nw_key_press_sig), nw); -// g_signal_connect(G_OBJECT(nw->show), "destroy", -// G_CALLBACK(ss_destroy_sig), nw); -// sc_slideshow_set_slide(nw->show, first_slide(nw->p)); -// sc_editor_set_para_highlight(nw->nv, 1); -// sc_editor_set_cursor_para(nw->nv, 0); -// gtk_widget_show_all(GTK_WIDGET(nw->show)); -// update_toolbar(nw); + NarrativeWindow *nw = vp; + + if ( presentation_get_num_slides(nw->p) == 0 ) return; + + nw->show = sc_slideshow_new(nw->p, GTK_APPLICATION(nw->app)); + if ( nw->show == NULL ) return; + + nw->show_no_slides = 0; + + g_signal_connect(G_OBJECT(nw->show), "key-press-event", + G_CALLBACK(nw_key_press_sig), nw); + g_signal_connect(G_OBJECT(nw->show), "destroy", + G_CALLBACK(ss_destroy_sig), nw); + sc_slideshow_set_slide(nw->show, presentation_get_slide_by_number(nw->p, 0)); + gtk_narrative_view_set_para_highlight(GTK_NARRATIVE_VIEW(nw->nv), 1); + gtk_narrative_view_set_cursor_para(GTK_NARRATIVE_VIEW(nw->nv), 0); + gtk_widget_show_all(GTK_WIDGET(nw->show)); + update_toolbar(nw); } diff --git a/src/pr_clock.c b/src/pr_clock.c new file mode 100644 index 0000000..aa1348e --- /dev/null +++ b/src/pr_clock.c @@ -0,0 +1,439 @@ +/* + * pr_clock.c + * + * Copyright © 2013-2018 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 +#define _(x) gettext(x) + +#include "presentation.h" +#include "pr_clock.h" + + +struct pr_clock +{ + int open; + + GtkWidget *window; + GtkWidget *entry; + GtkWidget *startbutton; + GtkWidget *da; + GtkWidget *wallclock; + GtkWidget *elapsed; + GtkWidget *remaining; + GtkWidget *status; + GTimeZone *tz; + + GDateTime *start; + double time_elapsed_at_start; + guint timer_id; + + int running; + double time_allowed; + double time_elapsed; + int pos; + int end; + int pos_reached; + + double t; + double tf; +}; + + +static char *format_span(int n) +{ + char tmp[32]; + int hours, mins, sec; + char *s; + + if ( n < 0 ) { + s = "-"; + n = -n; + } else { + s = ""; + } + + sec = n % 60; + mins = ((n-sec) % (60*60))/60; + hours = (n-sec-mins) / (60*60); + + snprintf(tmp, 31, "%s%i:%02i:%02i", s, hours, mins, sec); + + return strdup(tmp); +} + + +static char *format_span_nice(int n) +{ + char tmp[64]; + int hours, mins, sec; + char *s; + + if ( n < 0 ) { + s = "behind"; + n = -n; + } else { + s = "ahead"; + } + + sec = n % 60; + mins = ((n-sec) % (60*60))/60; + hours = (n-sec-mins) / (60*60); + + if ( n <= 60 ) { + snprintf(tmp, 63, "%i seconds %s", n, s); + return strdup(tmp); + } + + if ( n < 60*60 ) { + snprintf(tmp, 63, "%i min %i seconds %s", mins, sec, s); + return strdup(tmp); + } + + snprintf(tmp, 63, "%i hours, %i min, %i seconds %s", + hours, mins, sec, s); + return strdup(tmp); +} + + +static gboolean update_clock(gpointer data) +{ + struct pr_clock *n = data; + gchar *d; + GDateTime *dt; + GTimeSpan sp; + double time_remaining; + double delta; + gint w, h; + char *tmp; + + if ( !n->open ) { + g_date_time_unref(n->start); + g_time_zone_unref(n->tz); + free(n); + return FALSE; + } + + dt = g_date_time_new_now(n->tz); + + if ( n->running ) { + + sp = g_date_time_difference(dt, n->start); + n->time_elapsed = n->time_elapsed_at_start + + sp / G_TIME_SPAN_SECOND; + + time_remaining = n->time_allowed - n->time_elapsed; + + tmp = format_span(n->time_elapsed); + gtk_label_set_text(GTK_LABEL(n->elapsed), tmp); + free(tmp); + + tmp = format_span(time_remaining); + gtk_label_set_text(GTK_LABEL(n->remaining), tmp); + free(tmp); + + } else { + + n->time_elapsed = n->time_elapsed_at_start; + + time_remaining = n->time_allowed - n->time_elapsed; + + tmp = format_span(n->time_elapsed); + gtk_label_set_text(GTK_LABEL(n->elapsed), tmp); + free(tmp); + + tmp = format_span(time_remaining); + gtk_label_set_text(GTK_LABEL(n->remaining), tmp); + free(tmp); + + } + + d = g_date_time_format(dt, "%H:%M:%S"); + g_date_time_unref(dt); + + gtk_label_set_text(GTK_LABEL(n->wallclock), d); + free(d); + + n->t = n->time_elapsed / n->time_allowed; + + if ( n->time_allowed == 0.0 ) n->t = 0.0; + if ( n->time_elapsed > n->time_allowed ) n->t = 1.0; + + if ( n->end > 0 ) { + n->tf = (double)n->pos_reached / (n->end-1); + } else { + n->tf = 0.0; + } + + delta = (n->tf - n->t)*n->time_allowed; + tmp = format_span_nice(delta); + gtk_label_set_text(GTK_LABEL(n->status), tmp); + free(tmp); + + w = gtk_widget_get_allocated_width(GTK_WIDGET(n->da)); + h = gtk_widget_get_allocated_height(GTK_WIDGET(n->da)); + gtk_widget_queue_draw_area(n->da, 0, 0, w, h); + + return TRUE; +} + + +void pr_clock_set_pos(PRClock *n, int pos, int end) +{ + if ( n == NULL ) return; + n->pos = pos; + if ( n->pos > n->pos_reached ) { + n->pos_reached = pos; + } + n->end = end; + update_clock(n); +} + + +static gint close_clock_sig(GtkWidget *w, PRClock *n) +{ + g_source_remove(n->timer_id); + free(n); + return FALSE; +} + + +static gboolean clock_draw_sig(GtkWidget *da, cairo_t *cr, struct pr_clock *n) +{ + int width, height; + double s; + double ff; + + width = gtk_widget_get_allocated_width(GTK_WIDGET(da)); + height = gtk_widget_get_allocated_height(GTK_WIDGET(da)); + s = width-20.0; + + /* Overall background */ + cairo_rectangle(cr, 10.0, 0.0, s, height); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_fill(cr); + + cairo_rectangle(cr, 10.0, 0.0, s*n->t, height); + cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); + cairo_fill(cr); + + if ( n->tf > n->t ) { + cairo_rectangle(cr, 10.0+s*n->t, 0.0, (n->tf - n->t)*s, height); + cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); + cairo_fill(cr); + } else { + cairo_rectangle(cr, 10.0+s*n->t, 0.0, (n->tf - n->t)*s, height); + cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); + cairo_fill(cr); + } + + ff = (double)n->pos / (n->end-1); + if ( n->end == 1 ) ff = 0.0; + cairo_move_to(cr, 10.0+ff*s, 0.0); + cairo_line_to(cr, 10.0+ff*s, height); + cairo_set_line_width(cr, 2.0); + cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); + cairo_stroke(cr); + + if ( !n->running ) { + cairo_move_to(cr, 10.0, height*0.8); + cairo_set_font_size(cr, height*0.8); + cairo_select_font_face(cr, "sans-serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_show_text(cr, _("Timer is NOT running!")); + } + + return FALSE; +} + + +static void set_sig(GtkEditable *w, struct pr_clock *n) +{ + const gchar *t; + char *check; + + t = gtk_entry_get_text(GTK_ENTRY(n->entry)); + n->time_allowed = 60.0 * strtod(t, &check); + if ( check == t ) { + fprintf(stderr, "Invalid time '%s'\n", t); + n->time_allowed = 0.0; + } + + update_clock(n); +} + + +static gboolean reset_sig(GtkWidget *w, gpointer data) +{ + struct pr_clock *n = data; + + n->time_elapsed = 0; + n->time_elapsed_at_start = 0; + + if ( n->start != NULL ) { + g_date_time_unref(n->start); + } + + n->start = g_date_time_new_now(n->tz); + + update_clock(n); + + return FALSE; +} + + +static gboolean setpos_sig(GtkWidget *w, gpointer data) +{ + struct pr_clock *n = data; + n->pos_reached = n->pos; + update_clock(n); + return FALSE; +} + + +static gboolean start_sig(GtkWidget *w, gpointer data) +{ + struct pr_clock *n = data; + + if ( n->running ) { + n->running = 0; + n->time_elapsed_at_start = n->time_elapsed; + gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(w))), + _("Start")); + } else { + n->time_elapsed_at_start = n->time_elapsed; + if ( n->start != NULL ) { + g_date_time_unref(n->start); + } + n->start = g_date_time_new_now(n->tz); + n->running = 1; + gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(w))), + _("Stop")); + } + + update_clock(n); + + return FALSE; +} + + +PRClock *pr_clock_new() +{ + struct pr_clock *n; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *resetbutton; + GtkWidget *setposbutton; + GtkWidget *grid; + GtkWidget *label; + + n = malloc(sizeof(struct pr_clock)); + if ( n == NULL ) return NULL; + n->open = 1; + + n->tz = g_time_zone_new_local(); + + n->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(n->window), 600, 150); + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add(GTK_CONTAINER(n->window), vbox); + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10); + + label = gtk_label_new(_("Length (mins):")); + gtk_label_set_markup(GTK_LABEL(label), _("Length (mins):")); + g_object_set(G_OBJECT(label), "halign", GTK_ALIGN_END, NULL); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 10); + + n->entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), n->entry, TRUE, TRUE, 0); + + n->startbutton = gtk_button_new_with_label(_("Start")); + gtk_box_pack_start(GTK_BOX(hbox), n->startbutton, TRUE, TRUE, 10); + + resetbutton = gtk_button_new_with_label(_("Reset")); + gtk_box_pack_start(GTK_BOX(hbox), resetbutton, TRUE, TRUE, 10); + + setposbutton = gtk_button_new_with_label(_("Set position")); + gtk_box_pack_start(GTK_BOX(hbox), setposbutton, TRUE, TRUE, 10); + + n->da = gtk_drawing_area_new(); + gtk_box_pack_start(GTK_BOX(vbox), n->da, TRUE, TRUE, 0); + g_signal_connect(G_OBJECT(n->da), "draw", G_CALLBACK(clock_draw_sig), n); + g_signal_connect(G_OBJECT(n->window), "destroy", + G_CALLBACK(close_clock_sig), n); /* FIXME: Uniqueness */ + + grid = gtk_grid_new(); + gtk_grid_set_row_spacing(GTK_GRID(grid), 10); + gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); + gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 10); + label = gtk_label_new(_("Time elapsed")); + gtk_label_set_markup(GTK_LABEL(label), _("Time elapsed")); + gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1); + label = gtk_label_new(_("Time remaining")); + gtk_label_set_markup(GTK_LABEL(label), _("Time remaining")); + gtk_grid_attach(GTK_GRID(grid), label, 1, 0, 1, 1); + n->status = gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid), n->status, 2, 0, 1, 1); + n->elapsed = gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid), n->elapsed, 0, 1, 1, 1); + n->remaining = gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid), n->remaining, 1, 1, 1, 1); + n->wallclock = gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid), n->wallclock, 2, 1, 1, 1); + + g_signal_connect(G_OBJECT(n->startbutton), "clicked", + G_CALLBACK(start_sig), n); + g_signal_connect(G_OBJECT(resetbutton), "clicked", + G_CALLBACK(reset_sig), n); + g_signal_connect(G_OBJECT(setposbutton), "clicked", + G_CALLBACK(setpos_sig), n); + g_signal_connect(G_OBJECT(n->entry), "changed", + G_CALLBACK(set_sig), n); + + n->running = 0; + n->time_allowed = 0; + n->time_elapsed = 0; + n->time_elapsed_at_start = 0; + n->pos = 0; + n->pos_reached = 0; + n->end = 0; + n->start = NULL; + update_clock(n); + n->timer_id = g_timeout_add_seconds(1, update_clock, n); + + gtk_window_set_title(GTK_WINDOW(n->window), _("Presentation clock")); + + gtk_widget_show_all(n->window); + return n; +} diff --git a/src/pr_clock.h b/src/pr_clock.h new file mode 100644 index 0000000..97d2d0d --- /dev/null +++ b/src/pr_clock.h @@ -0,0 +1,37 @@ +/* + * pr_clock.h + * + * Copyright © 2013-2018 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 CLOCK_H +#define CLOCK_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +typedef struct pr_clock PRClock; + +extern PRClock *pr_clock_new(void); + +extern void pr_clock_set_pos(PRClock *n, int pos, int end); + + +#endif /* CLOCK_H */ diff --git a/src/slideshow.c b/src/slideshow.c new file mode 100644 index 0000000..1bd1930 --- /dev/null +++ b/src/slideshow.c @@ -0,0 +1,222 @@ +/* + * slideshow.c + * + * Copyright © 2013-2018 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 +#define _(x) gettext(x) + +#include + +#include "slide_render_cairo.h" +#include "slideshow.h" +#include "colloquium.h" +#include "pr_clock.h" + +G_DEFINE_TYPE_WITH_CODE(SCSlideshow, sc_slideshow, GTK_TYPE_WINDOW, NULL) + + +static void sc_slideshow_init(SCSlideshow *ss) +{ +} + + +void sc_slideshow_class_init(SCSlideshowClass *klass) +{ +} + + +static void redraw(SCSlideshow *ss) +{ + gint w, h; + w = gtk_widget_get_allocated_width(GTK_WIDGET(ss->drawingarea)); + h = gtk_widget_get_allocated_height(GTK_WIDGET(ss->drawingarea)); + gtk_widget_queue_draw_area(ss->drawingarea, 0, 0, w, h); +} + + +static gint ssh_destroy_sig(GtkWidget *widget, SCSlideshow *ss) +{ + if ( ss->blank_cursor != NULL ) { + g_object_unref(ss->blank_cursor); + } + if ( ss->inhibit_cookie ) { + gtk_application_uninhibit(ss->app, ss->inhibit_cookie); + } + return FALSE; +} + + +static gboolean ss_draw_sig(GtkWidget *da, cairo_t *cr, SCSlideshow *ss) +{ + double dw, dh; /* Size of drawing area */ + double lw, lh; /* Logical size of slide */ + double sw, sh; /* Size of slide on screen */ + double xoff, yoff; + + dw = gtk_widget_get_allocated_width(GTK_WIDGET(da)); + dh = gtk_widget_get_allocated_height(GTK_WIDGET(da)); + + /* Overall background */ + cairo_rectangle(cr, 0.0, 0.0, dw, dh); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_fill(cr); + + slide_get_logical_size(ss->cur_slide, + presentation_get_stylesheet(ss->p), &lw, &lh); + + if ( lw/lh > (double)dw/dh ) { + /* Slide is too wide. Letterboxing top/bottom */ + sw = dw; + sh = dw * lh/lw; + } else { + /* Letterboxing at sides */ + sw = dh * lw/lh; + sh = dh; + } + + xoff = (dw - sw)/2.0; + yoff = (dh - sh)/2.0; + + if ( !ss->blank ) { + + PangoContext *pc; + int n; + struct slide_pos sel; + + cairo_save(cr); + cairo_translate(cr, xoff, yoff); + cairo_scale(cr, sw/lw, sh/lh); + + sel.para = 0; sel.pos = 0; sel.trail = 0; + n = presentation_get_slide_number(ss->p, ss->cur_slide); + pc = pango_cairo_create_context(cr); + + slide_render_cairo(ss->cur_slide, cr, + presentation_get_imagestore(ss->p), + presentation_get_stylesheet(ss->p), + n, pango_language_get_default(), pc, + NULL, sel, sel); + + g_object_unref(pc); + cairo_restore(cr); + + } + + return FALSE; +} + + +static gboolean ss_realize_sig(GtkWidget *w, SCSlideshow *ss) +{ + if ( (ss->app == NULL) || colloquium_get_hidepointer(COLLOQUIUM(ss->app)) ) { + + /* Hide the pointer */ + GdkWindow *win; + win = gtk_widget_get_window(w); + ss->blank_cursor = gdk_cursor_new_for_display(gdk_display_get_default(), + GDK_BLANK_CURSOR); + gdk_window_set_cursor(GDK_WINDOW(win), ss->blank_cursor); + + } else { + ss->blank_cursor = NULL; + } + + return FALSE; +} + + +void sc_slideshow_set_slide(SCSlideshow *ss, Slide *ns) +{ + ss->cur_slide = ns; + redraw(ss); +} + + +SCSlideshow *sc_slideshow_new(Presentation *p, GtkApplication *app) +{ + GdkDisplay *display; + int n_monitors; + SCSlideshow *ss; + + ss = g_object_new(SC_TYPE_SLIDESHOW, NULL); + if ( ss == NULL ) return NULL; + + ss->blank = 0; + ss->p = p; + ss->cur_slide = NULL; + ss->blank_cursor = NULL; + ss->app = app; + + ss->drawingarea = gtk_drawing_area_new(); + gtk_container_add(GTK_CONTAINER(ss), ss->drawingarea); + + gtk_widget_set_can_focus(GTK_WIDGET(ss->drawingarea), TRUE); + gtk_widget_add_events(GTK_WIDGET(ss->drawingarea), + GDK_KEY_PRESS_MASK); + + g_signal_connect(G_OBJECT(ss), "destroy", + G_CALLBACK(ssh_destroy_sig), ss); + g_signal_connect(G_OBJECT(ss), "realize", + G_CALLBACK(ss_realize_sig), ss); + g_signal_connect(G_OBJECT(ss->drawingarea), "draw", + G_CALLBACK(ss_draw_sig), ss); + + gtk_widget_grab_focus(GTK_WIDGET(ss->drawingarea)); + + display = gdk_display_get_default(); + n_monitors = gdk_display_get_n_monitors(display); + + GdkMonitor *mon_ss; + if ( n_monitors == 1 ) { + mon_ss = gdk_display_get_primary_monitor(display); + printf(_("Single monitor mode\n")); + ss->single_monitor = 1; + } else { + mon_ss = gdk_display_get_monitor(display, 1); + printf(_("Dual monitor mode\n")); + ss->single_monitor = 0; + } + + /* Workaround because gtk_window_fullscreen_on_monitor doesn't work */ + GdkRectangle rect; + gdk_monitor_get_geometry(mon_ss, &rect); + gtk_window_move(GTK_WINDOW(ss), rect.x, rect.y); + gtk_window_fullscreen(GTK_WINDOW(ss)); + + if ( app != NULL ) { + ss->inhibit_cookie = gtk_application_inhibit(app, GTK_WINDOW(ss), + GTK_APPLICATION_INHIBIT_IDLE, + _("Presentation slide show is running")); + } + + return ss; +} + diff --git a/src/slideshow.h b/src/slideshow.h new file mode 100644 index 0000000..777b9f2 --- /dev/null +++ b/src/slideshow.h @@ -0,0 +1,79 @@ +/* + * slideshow.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 SLIDESHOW_H +#define SLIDESHOW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#define SC_TYPE_SLIDESHOW (sc_slideshow_get_type()) + +#define SC_SLIDESHOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + SC_TYPE_SLIDESHOW, SCEditor)) + +#define SC_IS_SLIDESHOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ + SC_TYPE_SLIDESHOW)) + +#define SC_SLIDESHOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), \ + SC_TYPE_SLIDESHOW, SCEditorClass)) + +#define SC_IS_SLIDESHOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), \ + SC_TYPE_SLIDESHOW)) + +#define SC_SLIDESHOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + SC_TYPE_SLIDESHOW, SCSlideShowClass)) + +struct _scslideshow +{ + GtkWindow parent_instance; + + /* */ + Presentation *p; + Slide *cur_slide; + GtkWidget *drawingarea; + GdkCursor *blank_cursor; + int blank; + int xoff; + int yoff; + int single_monitor; + GtkApplication *app; + gint inhibit_cookie; +}; + + +struct _scslideshowclass +{ + GtkWindowClass parent_class; +}; + +typedef struct _scslideshow SCSlideshow; +typedef struct _scslideshowclass SCSlideshowClass; + +extern SCSlideshow *sc_slideshow_new(Presentation *p, GtkApplication *app); +extern void sc_slideshow_set_slide(SCSlideshow *ss, Slide *ns); +extern Slide *sc_slideshow_get_slide(SCSlideshow *ss); + +#endif /* SLIDESHOW_H */ -- cgit v1.2.3