aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2014-12-04 08:39:48 +0100
committerThomas White <taw@bitwiz.org.uk>2014-12-04 08:39:48 +0100
commit96938310335d61b55e076d4b9b562c488f421a59 (patch)
treea1035c1f3468e6747e4fb368126734aaf66de383
parent091dc6c4ac53e59f7700893de712a3b6a1caf9b1 (diff)
parent192220c6aeff3c0bfbeb643da41ce239e8c67609 (diff)
Merge branch 'narrative'
Conflicts: src/mainwindow.c
-rw-r--r--Makefile.am12
-rw-r--r--data/colloquium.ui61
-rw-r--r--src/colloquium.c350
-rw-r--r--src/colloquium.h (renamed from src/mainwindow.h)18
-rw-r--r--src/frame.c2
-rw-r--r--src/mainwindow.c2039
-rw-r--r--src/narrative_window.c230
-rw-r--r--src/narrative_window.h37
-rw-r--r--src/notes.c57
-rw-r--r--src/notes.h7
-rw-r--r--src/presentation.c125
-rw-r--r--src/presentation.h127
-rw-r--r--src/render.c102
-rw-r--r--src/render.h11
-rw-r--r--src/sc_editor.c1464
-rw-r--r--src/sc_editor.h157
-rw-r--r--src/sc_interp.c5
-rw-r--r--src/slide_sorter.c75
-rw-r--r--src/slide_window.c621
-rw-r--r--src/slide_window.h46
-rw-r--r--src/slideshow.c278
-rw-r--r--src/slideshow.h20
-rw-r--r--src/wrap.c146
-rw-r--r--src/wrap.h4
-rw-r--r--tests/render_test.c44
-rw-r--r--tests/render_test_sc1.c44
26 files changed, 3197 insertions, 2885 deletions
diff --git a/Makefile.am b/Makefile.am
index 7aa90c6..5d29aaf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,27 +11,25 @@ LDADD = $(top_builddir)/lib/libgnu.la @IGNORE_UNUSED_LIBRARIES_CFLAGS@ \
harfatum/src/libharfatum.la src/default_stylesheet.o
src_colloquium_SOURCES = src/colloquium.c src/render.c \
- src/mainwindow.c src/presentation.c \
+ src/presentation.c \
src/frame.c src/sc_parse.c \
src/slideshow.c src/wrap.c src/sc_interp.c \
src/imagestore.c src/notes.c src/pr_clock.c \
src/inhibit_screensaver.c src/slide_sorter.c \
- src/shape.c
+ src/shape.c src/sc_editor.c src/narrative_window.c \
+ src/slide_window.c
INCLUDES = -Iharfatum/src
EXTRA_DIST += src/presentation.h src/render.h src/wrap.h \
src/slideshow.h src/sc_parse.h src/sc_interp.h \
src/imagestore.h src/notes.h src/pr_clock.h \
- src/inhibit_screensaver.h src/slide_sorter.h src/shape.h
+ src/inhibit_screensaver.h src/slide_sorter.h src/shape.h \
+ src/sc_editor.h src/slide_window.h src/narrative_window.c
src/default_stylesheet.o: src/default_stylesheet.sty
ld -r -b binary -o src/default_stylesheet.o src/default_stylesheet.sty
-colloquiumdir = $(datadir)/colloquium
-colloquium_DATA = data/colloquium.ui
-EXTRA_DIST += $(colloquium_DATA)
-
iconsdir = $(datadir)/icons/hicolor/scalable/apps
icons_DATA = data/colloquium.svg
EXTRA_DIST += $(icons_DATA)
diff --git a/data/colloquium.ui b/data/colloquium.ui
deleted file mode 100644
index 76a9084..0000000
--- a/data/colloquium.ui
+++ /dev/null
@@ -1,61 +0,0 @@
-<ui>
- <menubar name="displaywindow">
-
- <menu name="file" action="FileAction">
- <menuitem name="new" action="NewAction" />
- <menuitem name="open" action="OpenAction" />
- <menuitem name="save" action="SaveAction" />
- <menuitem name="saveas" action="SaveAsAction" />
- <separator />
- <menuitem name="loadstyle" action="LoadStyleAction" />
- <menuitem name="savestyle" action="SaveStyleAction" />
- <menuitem name="exportpdf" action="ExportPDFAction" />
- <separator />
- <menuitem name="quit" action="QuitAction" />
- </menu>
-
- <menu name="edit" action="EditAction">
- <menuitem name="undo" action="UndoAction" />
- <menuitem name="redo" action="RedoAction" />
- <separator />
- <menuitem name="cut" action="CutAction" />
- <menuitem name="copy" action="CopyAction" />
- <menuitem name="paste" action="PasteAction" />
- <separator />
- <menuitem name="deleteframe" action="DeleteFrameAction" />
- <separator />
- <menuitem name="slidesorter" action="SorterAction" />
- <menuitem name="stylesheet" action="EditStyleAction" />
- </menu>
-
- <menu name="insert" action="InsertAction">
- <menuitem name="newslide" action="NewSlideAction" />
- </menu>
-
- <menu name="tools" action="ToolsAction">
- <menuitem name="slideshow" action="TSlideshowAction" />
- <menuitem name="notes" action="NotesAction" />
- <menuitem name="clock" action="ClockAction" />
- <menuitem name="preferences" action="PrefsAction" />
- </menu>
-
- <menu name="help" action="HelpAction">
- <menuitem name="about" action="AboutAction" />
- </menu>
-
- </menubar>
-
- <toolbar name="displaywindowtoolbar">
-
- <toolitem name="slideshow" action="SlideshowAction" />
- <separator />
- <toolitem name="add" action="AddSlideAction" />
- <separator />
- <toolitem name="first" action="ButtonFirstSlideAction" />
- <toolitem name="prev" action="ButtonPrevSlideAction" />
- <toolitem name="next" action="ButtonNextSlideAction" />
- <toolitem name="last" action="ButtonLastSlideAction" />
-
- </toolbar>
-
-</ui>
diff --git a/src/colloquium.c b/src/colloquium.c
index 1f372d8..588aea8 100644
--- a/src/colloquium.c
+++ b/src/colloquium.c
@@ -1,7 +1,7 @@
/*
* colloquium.c
*
- * Copyright © 2013 Thomas White <taw@bitwiz.org.uk>
+ * Copyright © 2013-2014 Thomas White <taw@bitwiz.org.uk>
*
* This file is part of Colloquium.
*
@@ -28,13 +28,305 @@
#include <gtk/gtk.h>
#include <getopt.h>
+#include "colloquium.h"
#include "presentation.h"
-#include "mainwindow.h"
+#include "narrative_window.h"
+
+
+struct _colloquium
+{
+ GtkApplication parent_instance;
+};
+
+
+typedef GtkApplicationClass ColloquiumClass;
+
+
+G_DEFINE_TYPE(Colloquium, colloquium, GTK_TYPE_APPLICATION)
+
+
+static void colloquium_activate(GApplication *app)
+{
+ printf("activate!\n");
+}
+
+
+static void new_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ GApplication *app = vp;
+ g_application_activate(app);
+}
+
+
+static void about_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw@bitwiz.org.uk>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+
+ gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(window),
+ "Colloquium");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window),
+ PACKAGE_VERSION);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window),
+ "© 2013 Thomas White <taw@bitwiz.org.uk>");
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window),
+ "A tiny presentation program");
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window),
+ "© 2013 Thomas White <taw@bitwiz.org.uk>\n");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window),
+ "http://www.bitwiz.org.uk/");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
+
+ g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show_all(window);
+}
+
+
+static void quit_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ GApplication *app = vp;
+ g_application_quit(app);
+}
+
+
+GActionEntry app_entries[] = {
+
+ { "new", new_sig, NULL, NULL, NULL },
+ { "about", about_sig, NULL, NULL, NULL },
+ { "quit", quit_sig, NULL, NULL, NULL },
+};
+
+
+static void colloquium_open(GApplication *app, GFile **files, gint n_files,
+ const gchar *hint)
+{
+ int i;
+
+ for ( i = 0; i<n_files; i++ ) {
+ struct presentation *p;
+ char *uri = g_file_get_path(files[i]);
+ p = new_presentation();
+ load_presentation(p, uri);
+ narrative_window_new(p, app);
+ g_free(uri);
+ }
+}
+
+
+static void colloquium_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(colloquium_parent_class)->finalize(object);
+}
+
+
+static void colloquium_startup(GApplication *app)
+{
+ GtkBuilder *builder;
+
+ G_APPLICATION_CLASS(colloquium_parent_class)->startup(app);
+
+ g_action_map_add_action_entries(G_ACTION_MAP(app), app_entries,
+ G_N_ELEMENTS(app_entries), app);
+
+ builder = gtk_builder_new();
+ gtk_builder_add_from_string(builder,
+ "<interface>"
+
+ " <menu id='app-menu'>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>_New</attribute>"
+ " <attribute name='action'>app.new</attribute>"
+ " <attribute name='accel'>&lt;Primary&gt;n</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>_Open</attribute>"
+ " <attribute name='action'>app.open</attribute>"
+ " <attribute name='accel'>&lt;Primary&gt;o</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Preferences...</attribute>"
+ " <attribute name='action'>app.prefs</attribute>"
+ " </item>"
+ " </section>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>_About</attribute>"
+ " <attribute name='action'>app.about</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>_Quit</attribute>"
+ " <attribute name='action'>app.quit</attribute>"
+ " <attribute name='accel'>&lt;Primary&gt;q</attribute>"
+ " </item>"
+ " </section>"
+ " </menu>"
+
+ " <menu id='menubar'>"
+ " <submenu>"
+ " <attribute name='label' translatable='yes'>File</attribute>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>_Save</attribute>"
+ " <attribute name='action'>win.save</attribute>"
+ " <attribute name='accel'>&lt;Primary&gt;s</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Save As...</attribute>"
+ " <attribute name='action'>win.saveas</attribute>"
+ " </item>"
+ " </section>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Load stylesheet</attribute>"
+ " <attribute name='action'>win.loadstyle</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Save stylesheet</attribute>"
+ " <attribute name='action'>win.savestyle</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Export PDF</attribute>"
+ " <attribute name='action'>win.exportpdf</attribute>"
+ " </item>"
+ " </section>"
+ " </submenu>"
+
+ " <submenu>"
+ " <attribute name='label' translatable='yes'>Edit</attribute>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Undo</attribute>"
+ " <attribute name='action'>win.undo</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Redo</attribute>"
+ " <attribute name='action'>win.redo</attribute>"
+ " </item>"
+ " </section>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Cut</attribute>"
+ " <attribute name='action'>win.cut</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Copy</attribute>"
+ " <attribute name='action'>win.copy</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Paste</attribute>"
+ " <attribute name='action'>win.paste</attribute>"
+ " </item>"
+ " </section>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Delete frame</attribute>"
+ " <attribute name='action'>win.deleteframe</attribute>"
+ " </item>"
+ " </section>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Slide sorter...</attribute>"
+ " <attribute name='action'>win.slidesorter</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Edit stylesheet...</attribute>"
+ " <attribute name='action'>win.stylesheet</attribute>"
+ " </item>"
+ " </section>"
+ " </submenu>"
+
+ " <submenu>"
+ " <attribute name='label' translatable='yes'>Insert</attribute>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Slide</attribute>"
+ " <attribute name='action'>win.slide</attribute>"
+ " </item>"
+ " </section>"
+ " </submenu>"
+
+ " <submenu>"
+ " <attribute name='label' translatable='yes'>Tools</attribute>"
+ " <section>"
+ " <item>"
+ " <attribute name='label'>Start slideshow</attribute>"
+ " <attribute name='action'>win.startslideshow</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Slide notes...</attribute>"
+ " <attribute name='action'>win.notes</attribute>"
+ " </item>"
+ " <item>"
+ " <attribute name='label'>Presentation clock...</attribute>"
+ " <attribute name='action'>win.clock</attribute>"
+ " </item>"
+ " </section>"
+ " </submenu>"
+ " </menu>"
+
+ "</interface>", -1, NULL);
+
+ gtk_application_set_app_menu(GTK_APPLICATION(app),
+ G_MENU_MODEL(gtk_builder_get_object(builder, "app-menu")));
+ gtk_application_set_menubar(GTK_APPLICATION(app),
+ G_MENU_MODEL(gtk_builder_get_object(builder, "menubar")));
+
+ g_object_unref(builder);
+}
+
+
+static void colloquium_shutdown(GApplication *app)
+{
+ G_APPLICATION_CLASS(colloquium_parent_class)->shutdown(app);
+}
+
+
+static void colloquium_class_init(ColloquiumClass *class)
+{
+ GApplicationClass *app_class = G_APPLICATION_CLASS(class);
+ GObjectClass *object_class = G_OBJECT_CLASS(class);
+
+ app_class->startup = colloquium_startup;
+ app_class->shutdown = colloquium_shutdown;
+ app_class->activate = colloquium_activate;
+ app_class->open = colloquium_open;
+
+ object_class->finalize = colloquium_finalize;
+}
+
+
+static void colloquium_init(Colloquium *app)
+{
+}
+
+
+static Colloquium *colloquium_new()
+{
+ Colloquium *app;
+
+ g_type_init();
+ g_set_application_name("Colloquium");
+ app = g_object_new(colloquium_get_type(),
+ "application-id", "uk.org.bitwiz.Colloquium",
+ "flags", G_APPLICATION_HANDLES_OPEN,
+ "register-session", TRUE,
+ NULL);
+ return app;
+}
static void show_help(const char *s)
{
- printf("Syntax: %s [options] [<file.clq>]\n\n", s);
+ printf("Syntax: %s [options] [<file.sc>]\n\n", s);
printf(
"A tiny presentation program.\n"
"\n"
@@ -46,6 +338,8 @@ static void show_help(const char *s)
int main(int argc, char *argv[])
{
int c;
+ int status;
+ Colloquium *app;
/* Long options */
const struct option longopts[] = {
@@ -53,56 +347,26 @@ int main(int argc, char *argv[])
{0, 0, NULL, 0}
};
- gtk_init(&argc, &argv);
-
/* Short options */
- while ((c = getopt_long(argc, argv, "h",
- longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "h", longopts, NULL)) != -1) {
- switch (c) {
- case 'h' :
+ switch (c)
+ {
+ case 'h' :
show_help(argv[0]);
return 0;
- case 0 :
+ case 0 :
break;
- default :
- return 1;
- }
-
- }
-
- if ( optind == argc ) {
-
- struct presentation *p;
-
- p = new_presentation();
- p->cur_edit_slide = add_slide(p, 0);
- p->completely_empty = 1;
- if ( open_mainwindow(p) ) {
- fprintf(stderr, "Couldn't open main window.\n");
+ default :
return 1;
}
- }
-
- while ( optind < argc ) {
-
- char *filename;
- struct presentation *p;
-
- filename = argv[optind++];
-
- p = new_presentation();
- if ( load_presentation(p, filename) ) {
- fprintf(stderr, "Failed to open presentation");
- } else {
- open_mainwindow(p);
- }
}
- gtk_main();
-
- return 0;
+ app = colloquium_new();
+ status = g_application_run(G_APPLICATION(app), argc, argv);
+ g_object_unref(app);
+ return status;
}
diff --git a/src/mainwindow.h b/src/colloquium.h
index b406492..b927728 100644
--- a/src/mainwindow.h
+++ b/src/colloquium.h
@@ -1,7 +1,7 @@
/*
- * presentation.h
+ * colloquium.h
*
- * Copyright © 2013 Thomas White <taw@bitwiz.org.uk>
+ * Copyright © 2014 Thomas White <taw@bitwiz.org.uk>
*
* This file is part of Colloquium.
*
@@ -20,21 +20,17 @@
*
*/
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
+#ifndef COLLOQUIUM_H
+#define COLLOQUIUM_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include <glib-object.h>
-extern void rerender_slide(struct presentation *p);
-extern int open_mainwindow(struct presentation *p);
-extern void change_edit_slide(struct presentation *p, struct slide *np);
-extern void redraw_editor(struct presentation *p);
-extern void update_titlebar(struct presentation *p);
-extern void update_toolbar(struct presentation *p);
+typedef struct _colloquium Colloquium;
-#endif /* MAINWINDOW_H */
+#endif /* COLLOQUIUM_H */
diff --git a/src/frame.c b/src/frame.c
index 9b3ab06..f7f0e83 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -85,7 +85,7 @@ void renew_frame(struct frame *fr)
if ( fr == NULL ) return;
for ( i=0; i<fr->n_lines; i++ ) {
- // wrap_line_free(&fr->lines[i]);
+ wrap_line_free(&fr->lines[i]);
}
free(fr->lines);
fr->lines = NULL;
diff --git a/src/mainwindow.c b/src/mainwindow.c
deleted file mode 100644
index 2794a31..0000000
--- a/src/mainwindow.c
+++ /dev/null
@@ -1,2039 +0,0 @@
-/*
- * mainwindow.c
- *
- * Copyright © 2013-2014 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 <stdlib.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include <assert.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <math.h>
-
-#include "presentation.h"
-#include "mainwindow.h"
-#include "render.h"
-#include "frame.h"
-#include "slideshow.h"
-#include "wrap.h"
-#include "notes.h"
-#include "pr_clock.h"
-#include "slide_sorter.h"
-#include "sc_parse.h"
-#include "sc_interp.h"
-
-
-/* Update a slide, once it's been edited in some way. */
-void rerender_slide(struct presentation *p)
-{
- struct slide *s = p->cur_edit_slide;
- int n = slide_number(p, s);
-
- free_render_buffers(s);
-
- s->rendered_thumb = render_slide(s, s->parent->thumb_slide_width,
- p->slide_width, p->slide_height, p->is,
- ISZ_THUMBNAIL, n);
-
- s->rendered_proj = render_slide(s, s->parent->proj_slide_width,
- p->slide_width, p->slide_height, p->is,
- ISZ_SLIDESHOW, n);
-
- s->rendered_edit = render_slide(s, s->parent->edit_slide_width,
- p->slide_width, p->slide_height, p->is,
- ISZ_EDITOR, n);
-}
-
-
-/* Ensure that "edit" and "proj" renderings are in order */
-static void render_edit_and_proj(struct presentation *p)
-{
- struct slide *s = p->cur_edit_slide;
- int n = slide_number(p, s);
-
- if ( s->rendered_proj == NULL ) {
- s->rendered_proj = render_slide(s, s->parent->proj_slide_width,
- p->slide_width, p->slide_height,
- p->is, ISZ_SLIDESHOW, n);
- }
-
- if ( s->rendered_edit == NULL ) {
- s->rendered_edit = render_slide(s, s->parent->edit_slide_width,
- p->slide_width, p->slide_height,
- p->is, ISZ_EDITOR, n);
- }
-}
-
-
-
-/* Force a redraw of the editor window */
-void redraw_editor(struct presentation *p)
-{
- gint w, h;
-
- w = gtk_widget_get_allocated_width(GTK_WIDGET(p->drawingarea));
- h = gtk_widget_get_allocated_height(GTK_WIDGET(p->drawingarea));
-
- gtk_widget_queue_draw_area(p->drawingarea, 0, 0, w, h);
-}
-
-
-static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget,
- GtkContainer *container)
-{
- gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
- if ( GTK_IS_TOOLBAR(widget) ) {
- gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE);
- }
-}
-
-
-static gint quit_sig(GtkWidget *widget, struct presentation *p)
-{
- return 0;
-}
-
-
-static void show_error(struct presentation *p, const char *message)
-{
- GtkWidget *window;
-
- window = gtk_message_dialog_new(GTK_WINDOW(p->window),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_CLOSE, message);
- gtk_window_set_title(GTK_WINDOW(window), "Error");
-
- g_signal_connect_swapped(window, "response",
- G_CALLBACK(gtk_widget_destroy), window);
- gtk_widget_show(window);
-}
-
-
-void update_toolbar(struct presentation *p)
-{
- GtkWidget *d;
- int cur_slide_number;
-
- d = gtk_ui_manager_get_widget(p->ui, "/ui/displaywindowtoolbar/first");
- gtk_widget_set_sensitive(GTK_WIDGET(d), TRUE);
- d = gtk_ui_manager_get_widget(p->ui, "/ui/displaywindowtoolbar/prev");
- gtk_widget_set_sensitive(GTK_WIDGET(d), TRUE);
- d = gtk_ui_manager_get_widget(p->ui, "/ui/displaywindowtoolbar/next");
- gtk_widget_set_sensitive(GTK_WIDGET(d), TRUE);
- d = gtk_ui_manager_get_widget(p->ui, "/ui/displaywindowtoolbar/last");
- gtk_widget_set_sensitive(GTK_WIDGET(d), TRUE);
-
- cur_slide_number = slide_number(p, p->cur_edit_slide);
- if ( cur_slide_number == 0 ) {
-
- d = gtk_ui_manager_get_widget(p->ui,
- "/ui/displaywindowtoolbar/first");
- gtk_widget_set_sensitive(GTK_WIDGET(d), FALSE);
- d = gtk_ui_manager_get_widget(p->ui,
- "/ui/displaywindowtoolbar/prev");
- gtk_widget_set_sensitive(GTK_WIDGET(d), FALSE);
-
- }
-
- if ( cur_slide_number == p->num_slides-1 ) {
-
- d = gtk_ui_manager_get_widget(p->ui,
- "/ui/displaywindowtoolbar/next");
- gtk_widget_set_sensitive(GTK_WIDGET(d), FALSE);
- d = gtk_ui_manager_get_widget(p->ui,
- "/ui/displaywindowtoolbar/last");
- gtk_widget_set_sensitive(GTK_WIDGET(d), FALSE);
-
- }
-
-
-}
-
-
-static void do_slide_update(struct presentation *p, PangoContext *pc)
-{
- rerender_slide(p);
- redraw_editor(p);
- if ( (p->slideshow != NULL)
- && (p->cur_edit_slide == p->cur_proj_slide) )
- {
- redraw_slideshow(p);
- }
-}
-
-
-/* Inelegance to make furniture selection menus work */
-struct menu_pl
-{
- struct presentation *p;
- char *style_name;
- GtkWidget *widget;
-};
-
-
-static gint add_furniture(GtkWidget *widget, struct menu_pl *pl)
-{
- sc_block_append_end(pl->p->cur_edit_slide->scblocks,
- strdup(pl->style_name), NULL, NULL);
-
- do_slide_update(pl->p, pl->p->pc);
-
- return 0;
-}
-
-
-static void update_style_menus(struct presentation *p)
-{
- GtkWidget *menu;
- SCInterpreter *scin;
- struct style_id *styles;
- int i, n_sty;
-
- /* Free old list */
- for ( i=0; i<p->n_style_menu; i++ ) {
- gtk_widget_destroy(p->style_menu[i].widget);
- free(p->style_menu[i].style_name);
- }
- free(p->style_menu);
-
- /* Get the list of styles from the style sheet */
- scin = sc_interp_new(NULL, NULL);
- if ( scin == NULL ) {
- fprintf(stderr, "Failed to set up interpreter.\n");
- return;
- }
- sc_interp_run_stylesheet(scin, p->stylesheet);
-
- styles = list_styles(scin, &n_sty);
- if ( styles == NULL ) return;
-
- sc_interp_destroy(scin);
-
- /* Set up list for next time */
- p->style_menu = calloc(n_sty, sizeof(struct menu_pl));
- if ( p->style_menu == NULL ) return;
-
- /* Add the styles to the "Insert" menu */
- menu = gtk_ui_manager_get_widget(p->ui, "/displaywindow/insert");
- menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
-
- for ( i=0; i<n_sty; i++ ) {
-
- GtkWidget *item;
-
- item = gtk_menu_item_new_with_label(styles[i].friendlyname);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-
- p->style_menu[i].p = p;
- p->style_menu[i].widget = item;
- p->style_menu[i].style_name = styles[i].name;
-
- g_signal_connect(G_OBJECT(item), "activate",
- G_CALLBACK(add_furniture),
- &p->style_menu[i]);
-
- free(styles[i].friendlyname);
- }
-
- gtk_widget_show_all(menu);
- free(styles);
-}
-
-
-static gint open_response_sig(GtkWidget *d, gint response,
- struct presentation *p)
-{
- if ( response == GTK_RESPONSE_ACCEPT ) {
-
- char *filename;
-
- filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
-
- if ( p->completely_empty ) {
-
- if ( load_presentation(p, filename) ) {
- show_error(p, "Failed to open presentation");
- }
- p->cur_edit_slide = p->slides[0];
- rerender_slide(p);
- update_toolbar(p);
- update_style_menus(p);
- if ( p->slideshow != NULL ) end_slideshow(p);
-
- } else {
-
- struct presentation *p;
-
- /* FIXME */
- p = new_presentation();
- if ( load_presentation(p, filename) ) {
- show_error(p, "Failed to open presentation");
- } else {
- open_mainwindow(p);
- }
-
- }
-
- g_free(filename);
-
- }
-
- gtk_widget_destroy(d);
-
- return 0;
-}
-
-
-static gint open_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *d;
-
- d = gtk_file_chooser_dialog_new("Open Presentation",
- GTK_WINDOW(p->window),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
-
- g_signal_connect(G_OBJECT(d), "response",
- G_CALLBACK(open_response_sig), p);
-
- gtk_widget_show_all(d);
-
- return 0;
-}
-
-
-static gint loadstyle_response_sig(GtkWidget *d, gint response,
- struct presentation *p)
-{
- if ( response == GTK_RESPONSE_ACCEPT ) {
-
- char *filename;
-
- filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
- /* FIXME: Implement this (now easy) */
- //replace_stylesheet(p, filename);
- g_free(filename);
- update_style_menus(p);
- rerender_slide(p);
-
- }
-
- gtk_widget_destroy(d);
-
- return 0;
-}
-
-
-static gint loadstyle_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *d;
-
- d = gtk_file_chooser_dialog_new("Load Stylesheet",
- GTK_WINDOW(p->window),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
-
- g_signal_connect(G_OBJECT(d), "response",
- G_CALLBACK(loadstyle_response_sig), p);
-
- gtk_widget_show_all(d);
-
- return 0;
-}
-
-
-static gint new_sig(GtkWidget *widget, struct presentation *pnn)
-{
- struct presentation *p;
-
- p = new_presentation();
- if ( p != NULL ) {
- struct slide *new;
- new = add_slide(p, 0);
- p->completely_empty = 1;
- /* FIXME: position */
- new->scblocks = sc_block_append_end(p->scblocks, "slide",
- NULL, NULL);
- attach_notes(new);
- open_mainwindow(p);
- }
-
- return 0;
-}
-
-
-static gint saveas_response_sig(GtkWidget *d, gint response,
- struct presentation *p)
-{
- if ( response == GTK_RESPONSE_ACCEPT ) {
-
- char *filename;
-
- filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
-
- if ( save_presentation(p, filename) ) {
- show_error(p, "Failed to save presentation");
- }
-
- g_free(filename);
-
- }
-
- gtk_widget_destroy(d);
-
- return 0;
-}
-
-
-static gint saveas_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *d;
-
- d = gtk_file_chooser_dialog_new("Save Presentation",
- GTK_WINDOW(p->window),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
- TRUE);
-
- g_signal_connect(G_OBJECT(d), "response",
- G_CALLBACK(saveas_response_sig), p);
-
- gtk_widget_show_all(d);
-
- return 0;
-}
-
-
-static gint save_sig(GtkWidget *widget, struct presentation *p)
-{
- if ( p->filename == NULL ) {
- return saveas_sig(widget, p);
- }
-
- save_presentation(p, p->filename);
-
- return 0;
-}
-
-
-static gint save_ss_response_sig(GtkWidget *d, gint response,
- struct presentation *p)
-{
- if ( response == GTK_RESPONSE_ACCEPT ) {
-
- char *filename;
-
- filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
-
- /* FIXME: Implement this */
-// if ( save_stylesheet(p->ss, filename) ) {
-// show_error(p, "Failed to save style sheet");
-// }
-
- g_free(filename);
-
- }
-
- gtk_widget_destroy(d);
-
- return 0;
-}
-
-
-static gint save_ss_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *d;
-
- d = gtk_file_chooser_dialog_new("Save Style sheet",
- GTK_WINDOW(p->window),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
- TRUE);
-
- g_signal_connect(G_OBJECT(d), "response",
- G_CALLBACK(save_ss_response_sig), p);
-
- gtk_widget_show_all(d);
-
- return 0;
-}
-
-
-static gint export_pdf_response_sig(GtkWidget *d, gint response,
- struct presentation *p)
-{
- if ( response == GTK_RESPONSE_ACCEPT ) {
-
- char *filename;
-
- filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
-
- if ( export_pdf(p, filename) ) {
- show_error(p, "Failed to export as PDF");
- }
-
- g_free(filename);
-
- }
-
- gtk_widget_destroy(d);
-
- return 0;
-}
-
-
-static gint export_pdf_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *d;
-
- d = gtk_file_chooser_dialog_new("Export PDF",
- GTK_WINDOW(p->window),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
- TRUE);
-
- g_signal_connect(G_OBJECT(d), "response",
- G_CALLBACK(export_pdf_response_sig), p);
-
- gtk_widget_show_all(d);
-
- return 0;
-}
-
-
-static gint about_sig(GtkWidget *widget, struct presentation *p)
-{
- GtkWidget *window;
-
- const gchar *authors[] = {
- "Thomas White <taw@bitwiz.org.uk>",
- NULL
- };
-
- window = gtk_about_dialog_new();
- gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(p->window));
-
- gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(window),
- "Colloquium");
- gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window),
- PACKAGE_VERSION);
- gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window),
- "© 2013 Thomas White <taw@bitwiz.org.uk>");
- gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window),
- "A tiny presentation program");
- gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window),
- "© 2013 Thomas White <taw@bitwiz.org.uk>\n");
- gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window),
- "http://www.bitwiz.org.uk/");
- gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
-
- g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy),
- NULL);
-
- gtk_widget_show_all(window);
-
- return 0;
-}
-
-
-static gint start_slideshow_sig(GtkWidget *widget, struct presentation *p)
-{
- try_start_slideshow(p);
- return FALSE;
-}
-
-
-/* Change the editor's slide to "np" */
-void change_edit_slide(struct presentation *p, struct slide *np)
-{
- /* If this slide is not being shown on the projector, we can free the
- * buffers */
- if ( p->cur_proj_slide != p->cur_edit_slide ) {
- free_render_buffers_except_thumb(p->cur_edit_slide);
- }
-
- p->cur_edit_slide = np;
- render_edit_and_proj(p);
-
- set_selection(p, NULL);
- update_toolbar(p);
- redraw_editor(p);
-
- if ( p->notes != NULL ) {
- notify_notes_slide_changed(p, np);
- }
-
- if ( (p->slideshow != NULL) && p->slideshow_linked ) {
- change_proj_slide(p, np);
- } /* else leave the slideshow alone */
-}
-
-
-static gint add_slide_sig(GtkWidget *widget, struct presentation *p)
-{
- struct slide *new;
- int cur_slide_number;
-
- cur_slide_number = slide_number(p, p->cur_edit_slide);
-
- new = add_slide(p, cur_slide_number+1);
- new->scblocks = sc_block_insert_after(p->cur_edit_slide->scblocks,
- "slide", NULL, NULL);
-
- change_edit_slide(p, new);
-
- return FALSE;
-}
-
-
-static gint first_slide_sig(GtkWidget *widget, struct presentation *p)
-{
- change_edit_slide(p, p->slides[0]);
- return FALSE;
-}
-
-
-static gint prev_slide_sig(GtkWidget *widget, struct presentation *p)
-{
- int cur_slide_number;
-
- cur_slide_number = slide_number(p, p->cur_edit_slide);
- if ( cur_slide_number == 0 ) return FALSE;
-
- change_edit_slide(p, p->slides[cur_slide_number-1]);
-
- return FALSE;
-}
-
-
-static gint next_slide_sig(GtkWidget *widget, struct presentation *p)
-{
- int cur_slide_number;
-
- cur_slide_number = slide_number(p, p->cur_edit_slide);
- if ( cur_slide_number == p->num_slides-1 ) return FALSE;
-
- change_edit_slide(p, p->slides[cur_slide_number+1]);
-
- return FALSE;
-}
-
-
-static gint last_slide_sig(GtkWidget *widget, struct presentation *p)
-{
- change_edit_slide(p, p->slides[p->num_slides-1]);
-
- return FALSE;
-}
-
-
-static gint open_stylesheet_sig(GtkWidget *widget, struct presentation *p)
-{
- /* FIXME */
- //if ( p->stylesheetwindow == NULL ) {
- // p->stylesheetwindow = open_stylesheet(p);
- //} /* else already open */
-
- return FALSE;
-}
-
-
-static gint open_notes_sig(GtkWidget *widget, struct presentation *p)
-{
- open_notes(p);
- return FALSE;
-}
-
-
-static gint open_clock_sig(GtkWidget *widget, struct presentation *p)
-{
- open_clock(p);
- return FALSE;
-}
-
-
-static gint open_slidesorter_sig(GtkWidget *widget, struct presentation *p)
-{
- open_slidesorter(p);
- return FALSE;
-}
-
-static gint delete_frame_sig(GtkWidget *widget, struct presentation *p)
-{
- int i;
-
- for ( i=0; i<p->n_selection; i++ ) {
- delete_subframe(p->cur_edit_slide, p->selection[i]);
- }
- p->n_selection = 0;
-
- rerender_slide(p);
- redraw_editor(p);
-
- return FALSE;
-}
-
-
-static void add_menu_bar(struct presentation *p, GtkWidget *vbox)
-{
- GError *error = NULL;
- GtkWidget *toolbar;
- GtkWidget *menu;
- GtkWidget *item;
-
- GtkActionEntry entries[] = {
-
- { "FileAction", NULL, "_File", NULL, NULL, NULL },
- { "NewAction", GTK_STOCK_NEW, "_New",
- NULL, NULL, G_CALLBACK(new_sig) },
- { "OpenAction", GTK_STOCK_OPEN, "_Open...",
- NULL, NULL, G_CALLBACK(open_sig) },
- { "LoadStyleAction", NULL, "_Load Stylesheet...",
- NULL, NULL, G_CALLBACK(loadstyle_sig) },
- { "SaveAction", GTK_STOCK_SAVE, "_Save",
- NULL, NULL, G_CALLBACK(save_sig) },
- { "SaveAsAction", GTK_STOCK_SAVE_AS, "Save _As...",
- NULL, NULL, G_CALLBACK(saveas_sig) },
- { "SaveStyleAction", NULL, "Save St_ylesheet",
- NULL, NULL, G_CALLBACK(save_ss_sig) },
- { "ExportPDFAction", NULL, "Export PDF",
- NULL, NULL, G_CALLBACK(export_pdf_sig) },
- { "QuitAction", GTK_STOCK_QUIT, "_Quit",
- NULL, NULL, G_CALLBACK(quit_sig) },
-
- { "EditAction", NULL, "_Edit", NULL, NULL, NULL },
- { "SorterAction", NULL, "_Open Slide Sorter...",
- NULL, NULL, G_CALLBACK(open_slidesorter_sig) },
- { "UndoAction", GTK_STOCK_UNDO, "_Undo",
- NULL, NULL, NULL },
- { "RedoAction", GTK_STOCK_REDO, "_Redo",
- NULL, NULL, NULL },
- { "CutAction", GTK_STOCK_CUT, "Cut",
- NULL, NULL, NULL },
- { "CopyAction", GTK_STOCK_COPY, "Copy",
- NULL, NULL, NULL },
- { "PasteAction", GTK_STOCK_PASTE, "Paste",
- NULL, NULL, NULL },
- { "DeleteFrameAction", GTK_STOCK_DELETE, "Delete Frame",
- NULL, NULL, G_CALLBACK(delete_frame_sig) },
- { "EditStyleAction", NULL, "Stylesheet...",
- NULL, NULL, G_CALLBACK(open_stylesheet_sig) },
-
- { "InsertAction", NULL, "_Insert", NULL, NULL, NULL },
- { "NewSlideAction", GTK_STOCK_ADD, "_New Slide",
- NULL, NULL, G_CALLBACK(add_slide_sig) },
-
- { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
- { "TSlideshowAction", GTK_STOCK_FULLSCREEN, "_Start Slideshow",
- "F5", NULL, G_CALLBACK(start_slideshow_sig) },
- { "NotesAction", NULL, "_Open slide notes",
- "F8", NULL, G_CALLBACK(open_notes_sig) },
- { "ClockAction", NULL, "_Open presentation clock",
- "F9", NULL, G_CALLBACK(open_clock_sig) },
- { "PrefsAction", GTK_STOCK_PREFERENCES, "_Preferences",
- NULL, NULL, NULL },
-
- { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
- { "AboutAction", GTK_STOCK_ABOUT, "_About...",
- NULL, NULL, G_CALLBACK(about_sig) },
-
- { "SlideshowAction", GTK_STOCK_FULLSCREEN, "Start Presentation",
- NULL, NULL, G_CALLBACK(start_slideshow_sig) },
- { "AddSlideAction", GTK_STOCK_ADD, "Add Slide",
- NULL, NULL, G_CALLBACK(add_slide_sig) },
- { "ButtonFirstSlideAction", GTK_STOCK_GOTO_FIRST, "First Slide",
- NULL, NULL, G_CALLBACK(first_slide_sig) },
- { "ButtonPrevSlideAction", GTK_STOCK_GO_BACK, "Previous Slide",
- NULL, NULL, G_CALLBACK(prev_slide_sig) },
- { "ButtonNextSlideAction", GTK_STOCK_GO_FORWARD, "Next Slide",
- NULL, NULL, G_CALLBACK(next_slide_sig) },
- { "ButtonLastSlideAction", GTK_STOCK_GOTO_LAST, "Last Slide",
- NULL, NULL, G_CALLBACK(last_slide_sig) },
-
- };
- guint n_entries = G_N_ELEMENTS(entries);
-
- p->action_group = gtk_action_group_new("mainwindow");
- gtk_action_group_add_actions(p->action_group, entries, n_entries, p);
-
- p->ui = gtk_ui_manager_new();
- gtk_ui_manager_insert_action_group(p->ui, p->action_group, 0);
- g_signal_connect(p->ui, "add_widget", G_CALLBACK(add_ui_sig), vbox);
- if ( gtk_ui_manager_add_ui_from_file(p->ui,
- DATADIR"/colloquium/colloquium.ui", &error) == 0 ) {
- fprintf(stderr, "Error loading main window menu bar: %s\n",
- error->message);
- return;
- }
-
- gtk_window_add_accel_group(GTK_WINDOW(p->window),
- gtk_ui_manager_get_accel_group(p->ui));
- gtk_ui_manager_ensure_update(p->ui);
-
- toolbar = gtk_ui_manager_get_widget(p->ui, "/displaywindowtoolbar");
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar),
- gtk_separator_tool_item_new(), -1);
-
- menu = gtk_ui_manager_get_widget(p->ui, "/displaywindow/insert");
- menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
- item = gtk_separator_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-
- update_style_menus(p);
- update_toolbar(p);
-}
-
-
-static gint close_sig(GtkWidget *window, struct presentation *p)
-{
- free_presentation(p);
- return 0;
-}
-
-
-static void draw_editing_box(cairo_t *cr, struct frame *fr)
-{
- const double dash[] = {2.0, 2.0};
- double xmin, ymin, width, height;
- double ptot_w, ptot_h;
-
- xmin = fr->x;
- ymin = fr->y;
- width = fr->w;
- height = fr->h;
-
- cairo_new_path(cr);
- cairo_rectangle(cr, xmin, ymin, width, height);
- cairo_set_source_rgb(cr, 0.0, 0.69, 1.0);
- cairo_set_line_width(cr, 0.5);
- cairo_stroke(cr);
-
- cairo_new_path(cr);
- ptot_w = fr->pad_l + fr->pad_r;
- ptot_h = fr->pad_t + fr->pad_b;
- cairo_rectangle(cr, xmin+fr->pad_l, ymin+fr->pad_t,
- width-ptot_w, height-ptot_h);
- cairo_set_dash(cr, dash, 2, 0.0);
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_set_line_width(cr, 0.1);
- cairo_stroke(cr);
-
- cairo_set_dash(cr, NULL, 0, 0.0);
-}
-
-
-static void draw_caret(cairo_t *cr, struct frame *fr,
- int cursor_line, int cursor_box, int cursor_pos)
-{
- double xposd, yposd, line_height;
- double cx, clow, chigh;
- const double t = 1.8;
- struct wrap_box *box;
- int i;
-
- if ( fr == NULL ) return;
- if ( fr->n_lines == 0 ) return;
-
- /* Locate the cursor in a "logical" and "geographical" sense */
- box = &fr->lines[cursor_line].boxes[cursor_box];
- get_cursor_pos(box, cursor_pos, &xposd, &yposd, &line_height);
- xposd += fr->pad_l;
- yposd += fr->pad_t;
-
- for ( i=0; i<cursor_line; i++ ) {
- yposd += pango_units_to_double(fr->lines[i].height);
- }
-
- for ( i=0; i<cursor_box; i++ ) {
- int w = fr->lines[cursor_line].boxes[i].width;
- w += fr->lines[cursor_line].boxes[i].sp;
- xposd += pango_units_to_double(w);
- }
-
- cx = fr->x + xposd;
- clow = fr->y + yposd;
- chigh = clow + line_height;
-
- cairo_move_to(cr, cx, clow);
- cairo_line_to(cr, cx, chigh);
-
- cairo_move_to(cr, cx-t, clow-t);
- cairo_line_to(cr, cx, clow);
- cairo_move_to(cr, cx+t, clow-t);
- cairo_line_to(cr, cx, clow);
-
- cairo_move_to(cr, cx-t, chigh+t);
- cairo_line_to(cr, cx, chigh);
- cairo_move_to(cr, cx+t, chigh+t);
- cairo_line_to(cr, cx, chigh);
-
- cairo_set_source_rgb(cr, 0.86, 0.0, 0.0);
- cairo_set_line_width(cr, 1.0);
- cairo_stroke(cr);
-}
-
-
-static void draw_resize_handle(cairo_t *cr, double x, double y)
-{
- cairo_new_path(cr);
- cairo_rectangle(cr, x, y, 20.0, 20.0);
- cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.5);
- cairo_fill(cr);
-}
-
-
-static void draw_overlay(cairo_t *cr, struct presentation *p)
-{
- int i;
-
- for ( i=0; i<p->n_selection; i++ ) {
-
- double x, y, w, h;
-
- draw_editing_box(cr, p->selection[i]);
-
- x = p->selection[i]->x;
- y = p->selection[i]->y;
- w = p->selection[i]->w;
- h = p->selection[i]->h;
-
- /* Draw resize handles */
- /* FIXME: Not if this frame can't be resized */
- draw_resize_handle(cr, x, y+h-20.0);
- draw_resize_handle(cr, x+w-20.0, y);
- draw_resize_handle(cr, x, y);
- draw_resize_handle(cr, x+w-20.0, y+h-20.0);
- }
-
- /* If only one frame is selected, draw the caret */
- if ( p->n_selection == 1 ) {
- draw_caret(cr, p->cursor_frame, p->cursor_line, p->cursor_box,
- p->cursor_pos);
- }
-
- if ( (p->drag_status == DRAG_STATUS_DRAGGING)
- && ((p->drag_reason == DRAG_REASON_CREATE)
- || (p->drag_reason == DRAG_REASON_IMPORT)) )
- {
- cairo_new_path(cr);
- cairo_rectangle(cr, p->start_corner_x, p->start_corner_y,
- p->drag_corner_x - p->start_corner_x,
- p->drag_corner_y - p->start_corner_y);
- cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
- cairo_set_line_width(cr, 0.5);
- cairo_stroke(cr);
- }
-
- if ( (p->drag_status == DRAG_STATUS_DRAGGING)
- && ((p->drag_reason == DRAG_REASON_RESIZE)
- || (p->drag_reason == DRAG_REASON_MOVE)) )
- {
- cairo_new_path(cr);
- cairo_rectangle(cr, p->box_x, p->box_y,
- p->box_width, p->box_height);
- cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
- cairo_set_line_width(cr, 0.5);
- cairo_stroke(cr);
- }
-}
-
-
-static gboolean draw_sig(GtkWidget *da, cairo_t *cr,
- struct presentation *p)
-{
- double xoff, yoff;
- int width, height;
- int edit_slide_height;
-
- width = gtk_widget_get_allocated_width(GTK_WIDGET(da));
- height = gtk_widget_get_allocated_height(GTK_WIDGET(da));
-
- /* Overall background */
- cairo_rectangle(cr, 0.0, 0.0, width, height);
- if ( (p->slideshow != NULL) && !p->slideshow_linked ) {
- cairo_set_source_rgb(cr, 1.0, 0.3, 0.2);
- } else {
- cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
- }
- cairo_fill(cr);
-
- /* Get the overall size */
- edit_slide_height = (p->slide_height/p->slide_width)*p->edit_slide_width;
- xoff = (width - p->edit_slide_width)/2.0;
- yoff = (height - edit_slide_height)/2.0;
- p->border_offs_x = xoff; p->border_offs_y = yoff;
-
- /* Draw the slide from the cache */
- if ( p->cur_edit_slide->rendered_edit != NULL ) {
- cairo_set_source_surface(cr, p->cur_edit_slide->rendered_edit,
- xoff, yoff);
- cairo_paint(cr);
- } else {
- fprintf(stderr, "Current slide not rendered yet!\n");
- }
-
- cairo_translate(cr, xoff, yoff);
- draw_overlay(cr, p);
-
- return FALSE;
-}
-
-
-void update_titlebar(struct presentation *p)
-{
- get_titlebar_string(p);
-
- if ( p->window != NULL ) {
-
- char *title;
-
- title = malloc(strlen(p->titlebar)+14);
- sprintf(title, "%s - Colloquium", p->titlebar);
- gtk_window_set_title(GTK_WINDOW(p->window), title);
- free(title);
-
- }
-}
-
-
-static void fixup_cursor(struct presentation *p)
-{
- struct frame *fr;
- struct wrap_line *sline;
- struct wrap_box *sbox;
-
- fr = p->cursor_frame;
-
- if ( p->cursor_line >= fr->n_lines ) {
- /* We find ourselves on a line which doesn't exist */
- p->cursor_line = fr->n_lines-1;
- p->cursor_box = fr->lines[fr->n_lines-1].n_boxes-1;
- }
-
- sline = &fr->lines[p->cursor_line];
-
- if ( p->cursor_box >= sline->n_boxes ) {
-
- /* We find ourselves in a box which doesn't exist */
-
- if ( p->cursor_line > fr->n_lines-1 ) {
- /* This isn't the last line, so go to the first box of
- * the next line */
- p->cursor_line++;
- p->cursor_box = 0;
- sline = &p->cursor_frame->lines[p->cursor_line];
- } else {
- /* There are no more lines, so just go to the end */
- p->cursor_line = fr->n_lines-1;
- sline = &p->cursor_frame->lines[p->cursor_line];
- p->cursor_box = sline->n_boxes-1;
- }
- }
-
- sbox = &sline->boxes[p->cursor_box];
-
- if ( p->cursor_pos > sbox->len_chars ) {
- advance_cursor(p);
- }
-}
-
-
-static void move_cursor(struct presentation *p, signed int x, signed int y)
-{
- if ( x > 0 ) {
- advance_cursor(p);
- } else {
- move_cursor_back(p);
- }
-}
-
-
-static void insert_text(char *t, struct presentation *p)
-{
- int sln, sbx, sps;
- struct wrap_box *sbox;
- struct frame *fr = p->cursor_frame;
-
- if ( fr == NULL ) return;
-
- /* If this is, say, the top level frame, do nothing */
- if ( fr->boxes == NULL ) return;
-
- sln = p->cursor_line;
- sbx = p->cursor_box;
- sps = p->cursor_pos;
- sbox = &p->cursor_frame->lines[sln].boxes[sbx];
-
- sc_insert_text(sbox->scblock, sps+sbox->offs_char, t);
-
- fr->empty = 0;
-
- rerender_slide(p);
-
- fixup_cursor(p);
- advance_cursor(p);
-
- redraw_editor(p);
-}
-
-
-static void do_backspace(struct frame *fr, struct presentation *p)
-{
- int sln, sbx, sps;
-
- if ( fr == NULL ) return;
-
- /* If this is, say, the top level frame, do nothing */
- if ( fr->n_lines == 0 ) return;
-
- sln = p->cursor_line;
- sbx = p->cursor_box;
- sps = p->cursor_pos;
- struct wrap_box *sbox = &p->cursor_frame->lines[sln].boxes[sbx];
-
- move_cursor_back(p);
-
- /* Delete may cross wrap boxes and maybe SCBlock boundaries */
- struct wrap_line *fline = &p->cursor_frame->lines[p->cursor_line];
- struct wrap_box *fbox = &fline->boxes[p->cursor_box];
-
-// SCBlock *scbl = sbox->scblock;
-// do {
-// show_sc_blocks(scbl);
-// scbl = sc_block_next(scbl);
-// } while ( (scbl != fbox->scblock) && (scbl != NULL) );
-
- if ( (fbox->scblock == NULL) || (sbox->scblock == NULL) ) return;
- sc_delete_text(fbox->scblock, p->cursor_pos+fbox->offs_char,
- sbox->scblock, sps+sbox->offs_char);
-
-// scbl = sbox->scblock;
-// do {
-// show_sc_blocks(scbl);
-// scbl = sc_block_next(scbl);
-// } while ( (scbl != fbox->scblock) && (scbl != NULL) );
-
- rerender_slide(p);
- fixup_cursor(p);
- redraw_editor(p);
-}
-
-
-static gboolean im_commit_sig(GtkIMContext *im, gchar *str,
- struct presentation *p)
-{
- if ( p->n_selection == 0 ) {
- if ( str[0] == 'b' ) {
- check_toggle_blank(p);
- } else {
- printf("IM keypress: %s\n", str);
- }
- return FALSE;
- }
-
- insert_text(str, p);
-
- return FALSE;
-}
-
-
-static int within_frame(struct frame *fr, double x, double y)
-{
- if ( x < fr->x ) return 0;
- if ( y < fr->y ) return 0;
- if ( x > fr->x + fr->w ) return 0;
- if ( y > fr->y + fr->h ) return 0;
- return 1;
-}
-
-
-static struct frame *find_frame_at_position(struct frame *fr,
- double x, double y)
-{
- int i;
-
- for ( i=0; i<fr->num_children; i++ ) {
-
- if ( within_frame(fr->children[i], x, y) ) {
- return find_frame_at_position(fr->children[i], x, y);
- }
-
- }
-
- if ( within_frame(fr, x, y) ) return fr;
- return NULL;
-}
-
-
-static enum corner which_corner(double xp, double yp, struct frame *fr)
-{
- double x, y; /* Relative to object position */
-
- x = xp - fr->x;
- y = yp - fr->y;
-
- if ( x < 0.0 ) return CORNER_NONE;
- if ( y < 0.0 ) return CORNER_NONE;
- if ( x > fr->w ) return CORNER_NONE;
- if ( y > fr->h ) return CORNER_NONE;
-
- /* Top left? */
- if ( (x<20.0) && (y<20.0) ) return CORNER_TL;
- if ( (x>fr->w-20.0) && (y<20.0) ) return CORNER_TR;
- if ( (x<20.0) && (y>fr->h-20.0) ) {
- return CORNER_BL;
- }
- if ( (x>fr->w-20.0) && (y>fr->h-20.0) ) {
- return CORNER_BR;
- }
-
- return CORNER_NONE;
-}
-
-
-static void calculate_box_size(struct frame *fr, struct presentation *p,
- double x, double y)
-{
- double ddx, ddy, dlen, mult;
- double vx, vy, dbx, dby;
-
- ddx = x - p->start_corner_x;
- ddy = y - p->start_corner_y;
-
- if ( !fr->is_image ) {
-
- switch ( p->drag_corner ) {
-
- case CORNER_BR :
- p->box_x = fr->x;
- p->box_y = fr->y;
- p->box_width = fr->w + ddx;
- p->box_height = fr->h + ddy;
- break;
-
- case CORNER_BL :
- p->box_x = fr->x + ddx;
- p->box_y = fr->y;
- p->box_width = fr->w - ddx;
- p->box_height = fr->h + ddy;
- break;
-
- case CORNER_TL :
- p->box_x = fr->x + ddx;
- p->box_y = fr->y + ddy;
- p->box_width = fr->w - ddx;
- p->box_height = fr->h - ddy;
- break;
-
- case CORNER_TR :
- p->box_x = fr->x;
- p->box_y = fr->y + ddy;
- p->box_width = fr->w + ddx;
- p->box_height = fr->h - ddy;
- break;
-
- case CORNER_NONE :
- break;
-
- }
- return;
-
-
- }
-
- switch ( p->drag_corner ) {
-
- case CORNER_BR :
- vx = fr->w;
- vy = fr->h;
- break;
-
- case CORNER_BL :
- vx = -fr->w;
- vy = fr->h;
- break;
-
- case CORNER_TL :
- vx = -fr->w;
- vy = -fr->h;
- break;
-
- case CORNER_TR :
- vx = fr->w;
- vy = -fr->h;
- break;
-
- case CORNER_NONE :
- default:
- vx = 0.0;
- vy = 0.0;
- break;
-
- }
-
- dlen = (ddx*vx + ddy*vy) / p->diagonal_length;
- mult = (dlen+p->diagonal_length) / p->diagonal_length;
-
- p->box_width = fr->w * mult;
- p->box_height = fr->h * mult;
- dbx = p->box_width - fr->w;
- dby = p->box_height - fr->h;
-
- if ( p->box_width < 40.0 ) {
- mult = 40.0 / fr->w;
- }
- if ( p->box_height < 40.0 ) {
- mult = 40.0 / fr->h;
- }
- p->box_width = fr->w * mult;
- p->box_height = fr->h * mult;
- dbx = p->box_width - fr->w;
- dby = p->box_height - fr->h;
-
- switch ( p->drag_corner ) {
-
- case CORNER_BR :
- p->box_x = fr->x;
- p->box_y = fr->y;
- break;
-
- case CORNER_BL :
- p->box_x = fr->x - dbx;
- p->box_y = fr->y;
- break;
-
- case CORNER_TL :
- p->box_x = fr->x - dbx;
- p->box_y = fr->y - dby;
- break;
-
- case CORNER_TR :
- p->box_x = fr->x;
- p->box_y = fr->y - dby;
- break;
-
- case CORNER_NONE :
- break;
-
- }
-
-}
-
-
-static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
- struct presentation *p)
-{
- enum corner c;
- gdouble x, y;
- struct frame *clicked;
-
- x = event->x - p->border_offs_x;
- y = event->y - p->border_offs_y;
-
- if ( (p->n_selection > 0) && within_frame(p->selection[0], x, y) ) {
- clicked = p->selection[0];
- } else {
- clicked = find_frame_at_position(p->cur_edit_slide->top, x, y);
- }
-
- /* If the user clicked the currently selected frame, position cursor
- * or possibly prepare for resize */
- if ( (p->n_selection > 0) && (clicked == p->selection[0]) ) {
-
- struct frame *fr;
-
- fr = p->selection[0];
-
- /* Within the resizing region? */
- c = which_corner(x, y, fr);
- if ( c != CORNER_NONE ) {
-
- p->drag_reason = DRAG_REASON_RESIZE;
- p->drag_corner = c;
-
- p->start_corner_x = x;
- p->start_corner_y = y;
- p->diagonal_length = pow(fr->w, 2.0);
- p->diagonal_length += pow(fr->h, 2.0);
- p->diagonal_length = sqrt(p->diagonal_length);
-
- calculate_box_size(fr, p, x, y);
-
- p->drag_status = DRAG_STATUS_COULD_DRAG;
- p->drag_reason = DRAG_REASON_RESIZE;
-
- } else {
-
- p->cursor_frame = clicked;
- find_cursor(clicked, x-fr->x, y-fr->y,
- &p->cursor_line, &p->cursor_box,
- &p->cursor_pos);
-
- p->start_corner_x = event->x - p->border_offs_x;
- p->start_corner_y = event->y - p->border_offs_y;
- p->drag_status = DRAG_STATUS_COULD_DRAG;
- p->drag_reason = DRAG_REASON_MOVE;
-
- }
-
- } else if ( (clicked == NULL) || (clicked == p->cur_edit_slide->top) ) {
-
- /* Clicked no object. Deselect old object and set up for
- * (maybe) creating a new one. */
- set_selection(p, NULL);
- p->start_corner_x = event->x - p->border_offs_x;
- p->start_corner_y = event->y - p->border_offs_y;
- p->drag_status = DRAG_STATUS_COULD_DRAG;
- p->drag_reason = DRAG_REASON_CREATE;
-
- } else {
-
- /* Select new frame, no immediate dragging */
- p->drag_status = DRAG_STATUS_NONE;
- p->drag_reason = DRAG_REASON_NONE;
- set_selection(p, clicked);
-
- }
-
- gtk_widget_grab_focus(GTK_WIDGET(da));
- redraw_editor(p);
- return FALSE;
-}
-
-
-static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
- struct presentation *p)
-{
- struct frame *fr = p->selection[0];
- gdouble x, y;
-
- x = event->x - p->border_offs_x;
- y = event->y - p->border_offs_y;
-
- if ( p->drag_status == DRAG_STATUS_COULD_DRAG ) {
-
- /* We just got a motion signal, and the status was "could drag",
- * therefore the drag has started. */
- p->drag_status = DRAG_STATUS_DRAGGING;
-
- }
-
- switch ( p->drag_reason ) {
-
- case DRAG_REASON_NONE :
- break;
-
- case DRAG_REASON_CREATE :
- p->drag_corner_x = x;
- p->drag_corner_y = y;
- redraw_editor(p);
- break;
-
- case DRAG_REASON_IMPORT :
- /* Do nothing, handled by dnd_motion() */
- break;
-
- case DRAG_REASON_RESIZE :
- calculate_box_size(fr, p, x, y);
- redraw_editor(p);
- break;
-
- case DRAG_REASON_MOVE :
- p->box_x = (fr->x - p->start_corner_x) + x;
- p->box_y = (fr->y - p->start_corner_y) + y;
- p->box_width = fr->w;
- p->box_height = fr->h;
- redraw_editor(p);
- break;
-
- }
-
- gdk_event_request_motions(event);
- return FALSE;
-}
-
-
-static struct frame *create_frame(struct presentation *p, double x, double y,
- double w, double h)
-{
- struct frame *parent;
- struct frame *fr;
-
- parent = p->cur_edit_slide->top;
-
- if ( w < 0.0 ) {
- x += w;
- w = -w;
- }
-
- if ( h < 0.0 ) {
- y += h;
- h = -h;
- }
-
- fr = add_subframe(parent);
-
- /* Add to SC */
- fr->scblocks = sc_block_append_end(p->cur_edit_slide->scblocks,
- "f", NULL, NULL);
- sc_block_set_frame(fr->scblocks, fr);
- sc_block_append_inside(fr->scblocks, NULL, NULL, strdup(""));
-
- fr->x = x;
- fr->y = y;
- fr->w = w;
- fr->h = h;
- fr->is_image = 0;
- fr->empty = 1;
-
- update_geom(fr);
-
- return fr;
-}
-
-
-static void do_resize(struct presentation *p, double x, double y,
- double w, double h)
-{
- struct frame *fr;
-
- assert(p->n_selection > 0);
-
- if ( w < 0.0 ) {
- w = -w;
- x -= w;
- }
-
- if ( h < 0.0 ) {
- h = -h;
- y -= h;
- }
-
- fr = p->selection[0];
- fr->x = x;
- fr->y = y;
- fr->w = w;
- fr->h = h;
- update_geom(fr);
-
- rerender_slide(p);
- redraw_editor(p);
-}
-
-
-static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event,
- struct presentation *p)
-{
- gdouble x, y;
- struct frame *fr;
-
- x = event->x - p->border_offs_x;
- y = event->y - p->border_offs_y;
-
- /* Not dragging? Then I don't care. */
- if ( p->drag_status != DRAG_STATUS_DRAGGING ) return FALSE;
-
- p->drag_corner_x = x;
- p->drag_corner_y = y;
- p->drag_status = DRAG_STATUS_NONE;
-
- switch ( p->drag_reason )
- {
-
- case DRAG_REASON_NONE :
- printf("Release on pointless drag.\n");
- break;
-
- case DRAG_REASON_CREATE :
- fr = create_frame(p, p->start_corner_x, p->start_corner_y,
- p->drag_corner_x - p->start_corner_x,
- p->drag_corner_y - p->start_corner_y);
- rerender_slide(p);
- set_selection(p, fr);
- break;
-
- case DRAG_REASON_IMPORT :
- /* Do nothing, handled in dnd_drop() or dnd_leave() */
- break;
-
- case DRAG_REASON_RESIZE :
- do_resize(p, p->box_x, p->box_y, p->box_width, p->box_height);
- break;
-
- case DRAG_REASON_MOVE :
- do_resize(p, p->box_x, p->box_y, p->box_width, p->box_height);
- break;
-
- }
-
- p->drag_reason = DRAG_REASON_NONE;
-
- gtk_widget_grab_focus(GTK_WIDGET(da));
- redraw_editor(p);
- return FALSE;
-}
-
-
-static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event,
- struct presentation *p)
-{
- gboolean r;
- int claim = 0;
-
- /* Throw the event to the IM context and let it sort things out */
- r = gtk_im_context_filter_keypress(GTK_IM_CONTEXT(p->im_context),
- event);
- if ( r ) return FALSE; /* IM ate it */
-
- switch ( event->keyval ) {
-
- case GDK_KEY_Page_Up :
- prev_slide_sig(NULL, p);
- claim = 1;
- break;
-
- case GDK_KEY_Page_Down :
- next_slide_sig(NULL, p);
- claim = 1;
- break;
-
- case GDK_KEY_Escape :
- if ( p->slideshow != NULL ) end_slideshow(p);
- set_selection(p, NULL);
- redraw_editor(p);
- claim = 1;
- break;
-
- case GDK_KEY_Left :
- if ( p->n_selection == 1 ) {
- move_cursor(p, -1, 0);
- redraw_editor(p);
- }
- claim = 1;
- break;
-
- case GDK_KEY_Right :
- if ( p->n_selection == 1 ) {
- move_cursor(p, +1, 0);
- redraw_editor(p);
- }
- claim = 1;
- break;
-
- case GDK_KEY_Up :
- if ( p->n_selection == 1 ) {
- move_cursor(p, 0, -1);
- redraw_editor(p);
- }
- claim = 1;
- break;
-
- case GDK_KEY_Down :
- if ( p->n_selection == 1 ) {
- move_cursor(p, 0, +1);
- redraw_editor(p);
- }
- claim = 1;
- break;
-
-
- case GDK_KEY_Return :
- im_commit_sig(NULL, "\n", p);
- claim = 1;
- break;
-
- case GDK_KEY_BackSpace :
- if ( p->n_selection == 1 ) {
- do_backspace(p->selection[0], p);
- claim = 1;
- }
- break;
-
- case GDK_KEY_B :
- case GDK_KEY_b :
- if ( p->slideshow != NULL ) {
- //if ( p->prefs->b_splits ) {
- toggle_slideshow_link(p);
- //} else {
- // p->ss_blank = 1-p->ss_blank;
- // redraw_slideshow(p);
- //}
- }
- claim = 1;
- break;
-
- }
-
- if ( claim ) return TRUE;
- return FALSE;
-}
-
-
-static gboolean dnd_motion(GtkWidget *widget, GdkDragContext *drag_context,
- gint x, gint y, guint time, struct presentation *p)
-{
- GdkAtom target;
-
- /* If we haven't already requested the data, do so now */
- if ( !p->drag_preview_pending && !p->have_drag_data ) {
-
- target = gtk_drag_dest_find_target(widget, drag_context, NULL);
-
- if ( target != GDK_NONE ) {
- gtk_drag_get_data(widget, drag_context, target, time);
- p->drag_preview_pending = 1;
- } else {
- p->import_acceptable = 0;
- gdk_drag_status(drag_context, 0, time);
- }
-
- }
-
- if ( p->have_drag_data && p->import_acceptable ) {
-
- gdk_drag_status(drag_context, GDK_ACTION_LINK, time);
- p->start_corner_x = x - p->import_width/2.0;
- p->start_corner_y = y - p->import_height/2.0;
- p->drag_corner_x = x + p->import_width/2.0;
- p->drag_corner_y = y + p->import_height/2.0;
-
- redraw_editor(p);
-
- }
-
- return TRUE;
-}
-
-
-static gboolean dnd_drop(GtkWidget *widget, GdkDragContext *drag_context,
- gint x, gint y, guint time, struct presentation *p)
-{
- GdkAtom target;
-
- target = gtk_drag_dest_find_target(widget, drag_context, NULL);
-
- if ( target == GDK_NONE ) {
- gtk_drag_finish(drag_context, FALSE, FALSE, time);
- } else {
- gtk_drag_get_data(widget, drag_context, target, time);
- }
-
- return TRUE;
-}
-
-
-static void chomp(char *s)
-{
- size_t i;
-
- if ( !s ) return;
-
- for ( i=0; i<strlen(s); i++ ) {
- if ( (s[i] == '\n') || (s[i] == '\r') ) {
- s[i] = '\0';
- return;
- }
- }
-}
-
-
-/* Scale the image down if it's a silly size */
-static void check_import_size(struct presentation *p)
-{
- if ( p->import_width > p->slide_width ) {
-
- int new_import_width;
-
- new_import_width = p->slide_width/2;
- p->import_height = (new_import_width *p->import_height)
- / p->import_width;
- p->import_width = new_import_width;
- }
-
- if ( p->import_height > p->slide_height ) {
-
- int new_import_height;
-
- new_import_height = p->slide_height/2;
- p->import_width = (new_import_height*p->import_width)
- / p->import_height;
- p->import_height = new_import_height;
- }
-}
-
-
-static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context,
- gint x, gint y, GtkSelectionData *seldata,
- guint info, guint time, struct presentation *p)
-{
- if ( p->drag_preview_pending ) {
-
- gchar *filename = NULL;
- GdkPixbufFormat *f;
- gchar **uris;
- int w, h;
-
- p->have_drag_data = 1;
- p->drag_preview_pending = 0;
- uris = gtk_selection_data_get_uris(seldata);
- if ( uris != NULL ) {
- filename = g_filename_from_uri(uris[0], NULL, NULL);
- }
- g_strfreev(uris);
-
- if ( filename == NULL ) {
-
- /* This doesn't even look like a sensible URI.
- * Bail out. */
- gdk_drag_status(drag_context, 0, time);
- if ( p->drag_highlight ) {
- gtk_drag_unhighlight(widget);
- p->drag_highlight = 0;
- }
- p->import_acceptable = 0;
- return;
-
- }
- chomp(filename);
-
- f = gdk_pixbuf_get_file_info(filename, &w, &h);
- g_free(filename);
-
- p->import_width = w;
- p->import_height = h;
-
- if ( f == NULL ) {
-
- gdk_drag_status(drag_context, 0, time);
- if ( p->drag_highlight ) {
- gtk_drag_unhighlight(widget);
- p->drag_highlight = 0;
- }
- p->drag_status = DRAG_STATUS_NONE;
- p->drag_reason = DRAG_REASON_NONE;
- p->import_acceptable = 0;
-
- } else {
-
- /* Looks like a sensible image */
- gdk_drag_status(drag_context, GDK_ACTION_PRIVATE, time);
- p->import_acceptable = 1;
-
- if ( !p->drag_highlight ) {
- gtk_drag_highlight(widget);
- p->drag_highlight = 1;
- }
-
- check_import_size(p);
- p->drag_reason = DRAG_REASON_IMPORT;
- p->drag_status = DRAG_STATUS_DRAGGING;
-
- }
-
- } else {
-
- gchar **uris;
- char *filename = NULL;
-
- uris = gtk_selection_data_get_uris(seldata);
- if ( uris != NULL ) {
- filename = g_filename_from_uri(uris[0], NULL, NULL);
- }
- g_strfreev(uris);
-
- if ( filename != NULL ) {
-
- struct frame *fr;
- char *opts;
- size_t len;
- int w, h;
-
- gtk_drag_finish(drag_context, TRUE, FALSE, time);
- chomp(filename);
-
- w = p->drag_corner_x - p->start_corner_x;
- h = p->drag_corner_y - p->start_corner_y;
-
- len = strlen(filename)+64;
- opts = malloc(len);
- if ( opts == NULL ) {
- free(filename);
- fprintf(stderr, "Failed to allocate SC\n");
- return;
- }
- snprintf(opts, len, "1fx1f+0+0,filename=\"%s\"",
- filename);
-
- fr = create_frame(p, p->start_corner_x,
- p->start_corner_y, w, h);
- fr->is_image = 1;
- fr->empty = 0;
- sc_block_append_inside(fr->scblocks, "image", opts, "");
- show_hierarchy(p->cur_edit_slide->top, "");
- rerender_slide(p);
- set_selection(p, fr);
- redraw_editor(p);
- free(filename);
-
- } else {
-
- gtk_drag_finish(drag_context, FALSE, FALSE, time);
-
- }
-
- }
-}
-
-
-static void dnd_leave(GtkWidget *widget, GdkDragContext *drag_context,
- guint time, struct presentation *p)
-{
- if ( p->drag_highlight ) {
- gtk_drag_unhighlight(widget);
- }
- p->have_drag_data = 0;
- p->drag_highlight = 0;
- p->drag_status = DRAG_STATUS_NONE;
- p->drag_reason = DRAG_REASON_NONE;
-}
-
-
-static gint realise_sig(GtkWidget *da, struct presentation *p)
-{
- GdkWindow *win;
-
- /* Keyboard and input method stuff */
- p->im_context = gtk_im_multicontext_new();
- win = gtk_widget_get_window(p->drawingarea);
- gtk_im_context_set_client_window(GTK_IM_CONTEXT(p->im_context), win);
- gdk_window_set_accept_focus(win, TRUE);
- g_signal_connect(G_OBJECT(p->im_context), "commit",
- G_CALLBACK(im_commit_sig), p);
- g_signal_connect(G_OBJECT(p->drawingarea), "key-press-event",
- G_CALLBACK(key_press_sig), p);
-
- /* FIXME: Can do this "properly" by setting up a separate font map */
- p->pc = gtk_widget_get_pango_context(da);
- rerender_slide(p);
-
- return FALSE;
-}
-
-
-int open_mainwindow(struct presentation *p)
-{
- GtkWidget *window;
- GtkWidget *vbox;
- GtkWidget *sw;
- GtkTargetEntry targets[1];
-
- if ( p->window != NULL ) {
- fprintf(stderr, "Presentation window is already open!\n");
- return 1;
- }
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- p->window = window;
-
- update_titlebar(p);
-
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(close_sig), p);
-
- vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_container_add(GTK_CONTAINER(window), vbox);
-
- p->drawingarea = gtk_drawing_area_new();
- sw = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw),
- p->drawingarea);
- gtk_widget_set_size_request(GTK_WIDGET(p->drawingarea),
- p->slide_width + 20,
- p->slide_height + 20);
-
- add_menu_bar(p, vbox);
- gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
- g_signal_connect(G_OBJECT(p->drawingarea), "realize",
- G_CALLBACK(realise_sig), p);
- g_signal_connect(G_OBJECT(p->drawingarea), "button-press-event",
- G_CALLBACK(button_press_sig), p);
- g_signal_connect(G_OBJECT(p->drawingarea), "button-release-event",
- G_CALLBACK(button_release_sig), p);
- g_signal_connect(G_OBJECT(p->drawingarea), "motion-notify-event",
- G_CALLBACK(motion_sig), p);
-
- /* Drag and drop */
- targets[0].target = "text/uri-list";
- targets[0].flags = 0;
- targets[0].info = 1;
- gtk_drag_dest_set(p->drawingarea, 0, targets, 1, GDK_ACTION_PRIVATE);
- g_signal_connect(p->drawingarea, "drag-data-received",
- G_CALLBACK(dnd_receive), p);
- g_signal_connect(p->drawingarea, "drag-motion",
- G_CALLBACK(dnd_motion), p);
- g_signal_connect(p->drawingarea, "drag-drop",
- G_CALLBACK(dnd_drop), p);
- g_signal_connect(p->drawingarea, "drag-leave",
- G_CALLBACK(dnd_leave), p);
-
- gtk_widget_set_can_focus(GTK_WIDGET(p->drawingarea), TRUE);
- gtk_widget_add_events(GTK_WIDGET(p->drawingarea),
- GDK_POINTER_MOTION_HINT_MASK
- | GDK_BUTTON1_MOTION_MASK
- | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
-
- g_signal_connect(G_OBJECT(p->drawingarea), "draw",
- G_CALLBACK(draw_sig), p);
-
- /* Default size */
- gtk_window_set_default_size(GTK_WINDOW(p->window), 1024+100, 768+150);
- gtk_window_set_resizable(GTK_WINDOW(p->window), TRUE);
-
- assert(p->num_slides > 0);
-
- gtk_widget_grab_focus(GTK_WIDGET(p->drawingarea));
-
- gtk_widget_show_all(window);
-
- return 0;
-}
diff --git a/src/narrative_window.c b/src/narrative_window.c
new file mode 100644
index 0000000..9c58c86
--- /dev/null
+++ b/src/narrative_window.c
@@ -0,0 +1,230 @@
+/*
+ * narrative_window.c
+ *
+ * Copyright © 2014 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 <gtk/gtk.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "presentation.h"
+#include "narrative_window.h"
+#include "sc_editor.h"
+
+
+struct _narrative_window
+{
+ GtkWidget *window;
+ SCEditor *sceditor;
+ GApplication *app;
+ struct presentation *p;
+};
+
+
+static gint saveas_response_sig(GtkWidget *d, gint response,
+ NarrativeWindow *nw)
+{
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ if ( save_presentation(nw->p, filename) ) {
+ //show_error(sw, "Failed to save presentation");
+ }
+
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(d);
+
+ return 0;
+}
+
+
+static void saveas_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ GtkWidget *d;
+ NarrativeWindow *nw = vp;
+
+ d = gtk_file_chooser_dialog_new("Save Presentation",
+ GTK_WINDOW(nw->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
+ TRUE);
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(saveas_response_sig), nw);
+
+ gtk_widget_show_all(d);
+}
+
+
+static void save_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ NarrativeWindow *nw = vp;
+
+ if ( nw->p->filename == NULL ) {
+ return saveas_sig(NULL, NULL, nw);
+ }
+
+ save_presentation(nw->p, nw->p->filename);
+}
+
+
+static void exportpdf_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+}
+
+
+static void open_slidesorter_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+static void delete_frame_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+static void add_slide_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+static void start_slideshow_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+static void open_notes_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+static void open_clock_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+}
+
+
+GActionEntry nw_entries[] = {
+
+ { "save", save_sig, NULL, NULL, NULL },
+ { "saveas", saveas_sig, NULL, NULL, NULL },
+ { "exportpdf", exportpdf_sig, NULL, NULL, NULL },
+ { "sorter", open_slidesorter_sig, NULL, NULL, NULL },
+ { "deleteframe", delete_frame_sig, NULL, NULL, NULL },
+ { "slide", add_slide_sig, NULL, NULL, NULL },
+ { "startslideshow", start_slideshow_sig, NULL, NULL, NULL },
+ { "notes", open_notes_sig, NULL, NULL, NULL },
+ { "clock", open_clock_sig, NULL, NULL, NULL },
+};
+
+
+static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
+ NarrativeWindow *nw)
+{
+ if ( event->type == GDK_2BUTTON_PRESS ) {
+ nw->p->slidewindow = slide_window_open(nw->p, nw->app);
+ }
+
+ return 0;
+}
+
+
+static void nw_update_titlebar(NarrativeWindow *nw)
+{
+ get_titlebar_string(nw->p);
+
+ if ( nw->p->slidewindow != NULL ) {
+
+ char *title;
+
+ title = malloc(strlen(nw->p->titlebar)+14);
+ sprintf(title, "%s - Colloquium", nw->p->titlebar);
+ gtk_window_set_title(GTK_WINDOW(nw->window), title);
+ free(title);
+
+ }
+
+}
+
+
+NarrativeWindow *narrative_window_new(struct presentation *p, GApplication *app)
+{
+ NarrativeWindow *nw;
+ GtkWidget *vbox;
+ GtkWidget *scroll;
+
+ if ( p->narrative_window != NULL ) {
+ fprintf(stderr, "Narrative window is already open!\n");
+ return NULL;
+ }
+
+ nw = calloc(1, sizeof(NarrativeWindow));
+ if ( nw == NULL ) return NULL;
+
+ nw->app = app;
+ nw->p = p;
+
+ nw->window = gtk_application_window_new(GTK_APPLICATION(app));
+ p->narrative_window = nw;
+
+ g_action_map_add_action_entries(G_ACTION_MAP(nw->window), nw_entries,
+ G_N_ELEMENTS(nw_entries), nw);
+
+ nw_update_titlebar(nw);
+
+ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add(GTK_CONTAINER(nw->window), vbox);
+
+ nw->sceditor = sc_editor_new(nw->p->scblocks, p->stylesheet);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_ALWAYS);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll),
+ GTK_WIDGET(nw->sceditor));
+
+ sc_editor_set_size(nw->sceditor, 640, 1024);
+ sc_editor_set_logical_size(nw->sceditor, 640.0, 1024.0);
+
+ g_signal_connect(G_OBJECT(nw->sceditor), "button-press-event",
+ G_CALLBACK(button_press_sig), nw);
+
+ gtk_window_set_default_size(GTK_WINDOW(nw->window), 768, 768);
+ gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
+
+ gtk_widget_show_all(nw->window);
+
+ return nw;
+}
diff --git a/src/narrative_window.h b/src/narrative_window.h
new file mode 100644
index 0000000..8c32c71
--- /dev/null
+++ b/src/narrative_window.h
@@ -0,0 +1,37 @@
+/*
+ * narrative_window.h
+ *
+ * Copyright © 2014 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 NARRATIVE_WINDOW_H
+#define NARRATIVE_WINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+typedef struct _narrative_window NarrativeWindow;
+
+extern NarrativeWindow *narrative_window_new(struct presentation *p,
+ GApplication *app);
+
+
+#endif /* NARRATIVE_WINDOW_H */
diff --git a/src/notes.c b/src/notes.c
index 2210f55..6ec0773 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -31,50 +31,44 @@
#include <gtk/gtk.h>
#include "presentation.h"
-
+#include "notes.h"
struct notes
{
GtkWidget *window;
GtkWidget *v;
- struct slide *slide;
+ struct slide *cur_slide;
+ SlideWindow *sw;
};
-static void set_notes_title(struct presentation *p)
-{
- gtk_window_set_title(GTK_WINDOW(p->notes->window), "Colloquium notes");
-}
-
-
-static void update_notes(struct presentation *p)
+static void update_notes(struct notes *notes)
{
GtkTextBuffer *tb;
const char *ntext;
SCBlock *ch;
- if ( p->notes == NULL ) return;
+ if ( notes == NULL ) return;
- ch = sc_block_child(p->cur_edit_slide->notes);
+ ch = sc_block_child(notes->cur_slide->notes);
if ( ch != NULL ) {
ntext = sc_block_contents(ch);
} else {
ntext = "NOTES ERROR";
}
- tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(p->notes->v));
+ tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(notes->v));
gtk_text_buffer_set_text(tb, ntext, -1);
}
-void grab_current_notes(struct presentation *p)
+void grab_current_notes(struct notes *n)
{
gchar *text;
GtkTextBuffer *tb;
GtkTextIter i1, i2;
SCBlock *ch;
- struct notes *n = p->notes;
if ( n == NULL ) return;
@@ -83,7 +77,7 @@ void grab_current_notes(struct presentation *p)
gtk_text_buffer_get_end_iter(tb, &i2);
text = gtk_text_buffer_get_text(tb, &i1, &i2, TRUE);
- ch = sc_block_child(n->slide->notes);
+ ch = sc_block_child(n->cur_slide->notes);
if ( ch != NULL ) {
sc_block_set_contents(ch, text);
} else {
@@ -92,35 +86,33 @@ void grab_current_notes(struct presentation *p)
}
-void notify_notes_slide_changed(struct presentation *p, struct slide *np)
+void notes_set_slide(struct notes *notes, struct slide *np)
{
- grab_current_notes(p);
- p->notes->slide = np;
- update_notes(p);
+ if ( notes == NULL ) return;
+ grab_current_notes(notes);
+ notes->cur_slide = np;
+ update_notes(notes);
}
-static gint close_notes_sig(GtkWidget *w, struct presentation *p)
+static gint close_notes_sig(GtkWidget *w, struct notes *notes)
{
- grab_current_notes(p);
- p->notes = NULL;
+ grab_current_notes(notes);
+ slidewindow_notes_closed(notes->sw);
return FALSE;
}
-void open_notes(struct presentation *p)
+struct notes *open_notes(SlideWindow *sw, struct slide *slide)
{
struct notes *n;
GtkWidget *sc;
PangoFontDescription *desc;
- if ( p->notes != NULL ) return; /* Already open */
-
n = malloc(sizeof(struct notes));
- if ( n == NULL ) return;
- p->notes = n;
-
- p->notes->slide = p->cur_edit_slide;
+ if ( n == NULL ) return NULL;
+ n->sw = sw;
+ n->cur_slide = slide;
n->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(n->window), 800, 256);
@@ -137,12 +129,13 @@ void open_notes(struct presentation *p)
gtk_container_add(GTK_CONTAINER(sc), n->v);
g_signal_connect(G_OBJECT(n->v), "destroy",
- G_CALLBACK(close_notes_sig), p);
+ G_CALLBACK(close_notes_sig), n);
- set_notes_title(p);
+ gtk_window_set_title(GTK_WINDOW(n->window), "Colloquium notes");
gtk_widget_show_all(n->window);
- update_notes(p);
+ update_notes(n);
+ return n;
}
diff --git a/src/notes.h b/src/notes.h
index 31c5e3a..426cb7e 100644
--- a/src/notes.h
+++ b/src/notes.h
@@ -29,12 +29,11 @@
struct notes;
-extern void open_notes(struct presentation *p);
+extern struct notes *open_notes(SlideWindow *sw, struct slide *slide);
-extern void notify_notes_slide_changed(struct presentation *p,
- struct slide *np);
+extern void notes_set_slide(struct notes *n, struct slide *np);
-extern void grab_current_notes(struct presentation *p);
+extern void grab_current_notes(struct notes *n);
extern void attach_notes(struct slide *s);
diff --git a/src/presentation.c b/src/presentation.c
index 56bbbd6..d99ec55 100644
--- a/src/presentation.c
+++ b/src/presentation.c
@@ -31,7 +31,7 @@
#include <gtk/gtk.h>
#include "presentation.h"
-#include "mainwindow.h"
+#include "slide_window.h"
#include "frame.h"
#include "imagestore.h"
#include "wrap.h"
@@ -41,9 +41,6 @@
#include "sc_interp.h"
-static int num_presentations = 0;
-
-
void free_presentation(struct presentation *p)
{
int i;
@@ -53,11 +50,6 @@ void free_presentation(struct presentation *p)
free_slide(p->slides[i]);
}
- (*p->num_presentations)--;
- if ( *p->num_presentations == 0 ) final = 1;
-
- if ( p->inhibit != NULL ) inhibit_cleanup(p->inhibit);
-
/* FIXME: Loads of stuff leaks here */
free(p->filename);
imagestore_destroy(p->is);
@@ -132,13 +124,6 @@ struct slide *new_slide()
new = calloc(1, sizeof(struct slide));
if ( new == NULL ) return NULL;
- new->rendered_edit = NULL;
- new->rendered_proj = NULL;
- new->rendered_thumb = NULL;
-
- new->top = frame_new();
- /* FIXME: Set zero margins etc on top level frame */
-
new->scblocks = NULL;
new->notes = NULL;
@@ -198,14 +183,12 @@ static char *safe_basename(const char *in)
}
-void get_titlebar_string(struct presentation *p)
+char *get_titlebar_string(struct presentation *p)
{
- free(p->titlebar);
-
if ( p->filename == NULL ) {
- p->titlebar = strdup("(untitled)");
+ return strdup("(untitled)");
} else {
- p->titlebar = safe_basename(p->filename);
+ return safe_basename(p->filename);
}
}
@@ -222,17 +205,6 @@ int slide_number(struct presentation *p, struct slide *s)
}
-static int alloc_selection(struct presentation *p)
-{
- struct frame **new_selection;
- new_selection = realloc(p->selection,
- p->max_selection*sizeof(struct frame *));
- if ( new_selection == NULL ) return 1;
- p->selection = new_selection;
- return 0;
-}
-
-
struct presentation *new_presentation()
{
struct presentation *new;
@@ -240,43 +212,18 @@ struct presentation *new_presentation()
new = calloc(1, sizeof(struct presentation));
if ( new == NULL ) return NULL;
- num_presentations++;
- new->num_presentations = &num_presentations;
-
new->filename = NULL;
- new->titlebar = NULL;
- get_titlebar_string(new);
-
- new->window = NULL;
- new->ui = NULL;
- new->action_group = NULL;
- new->slideshow = NULL;
+ new->titlebar = get_titlebar_string(new);
new->slide_width = 1024.0;
new->slide_height = 768.0;
- new->edit_slide_width = 1024;
- new->proj_slide_width = 2048;
- new->thumb_slide_width = 180;
-
- /* Add one blank slide and view it */
new->num_slides = 0;
new->slides = NULL;
- new->cur_edit_slide = NULL;
- new->cur_proj_slide = NULL;
+ add_slide(new, 0);
new->completely_empty = 1;
-
new->stylesheet = NULL;
-
- new->n_style_menu = 0;
- new->style_menu = NULL;
-
- new->selection = NULL;
- new->n_selection = 0;
- new->max_selection = 64;
- if ( alloc_selection(new) ) return NULL;
-
new->is = imagestore_new();
return new;
@@ -288,7 +235,7 @@ int save_presentation(struct presentation *p, const char *filename)
FILE *fh;
char *old_fn;
- grab_current_notes(p);
+ // FIXME grab_current_notes(p);
fh = fopen(filename, "w");
if ( fh == NULL ) return 1;
@@ -361,7 +308,6 @@ int load_presentation(struct presentation *p, const char *filename)
{
FILE *fh;
int r = 0;
- int i;
char *everything;
size_t el = 1;
SCBlock *block;
@@ -369,6 +315,7 @@ int load_presentation(struct presentation *p, const char *filename)
everything = strdup("");
assert(p->completely_empty);
+ delete_slide(p, p->slides[0]);
fh = fopen(filename, "r");
if ( fh == NULL ) return 1;
@@ -400,8 +347,6 @@ int load_presentation(struct presentation *p, const char *filename)
if ( p->scblocks == NULL ) r = 1;
if ( r ) {
- p->cur_edit_slide = new_slide();
- insert_slide(p, p->cur_edit_slide, 0);
p->completely_empty = 1;
return r; /* Error */
}
@@ -422,8 +367,6 @@ int load_presentation(struct presentation *p, const char *filename)
if ( s != NULL ) {
s->scblocks = sc_block_child(block);
- s->top = frame_new();
- s->top->scblocks = sc_block_child(block);
attach_notes(s);
}
@@ -440,16 +383,6 @@ next:
update_titlebar(p);
imagestore_set_presentation_file(p->is, filename);
- p->cur_edit_slide = p->slides[0];
-
- for ( i=0; i<p->num_slides; i++ ) {
- struct slide *s = p->slides[i];
- s->rendered_thumb = render_slide(s, p->thumb_slide_width,
- p->slide_width,
- p->slide_height,
- p->is, ISZ_THUMBNAIL, i);
- }
-
return 0;
}
@@ -474,12 +407,12 @@ static struct frame *find_parent(struct frame *fr, struct frame *search)
}
-void delete_subframe(struct slide *s, struct frame *fr)
+void delete_subframe(struct frame *top, struct frame *fr)
{
struct frame *parent;
int i, idx, found;
- parent = find_parent(s->top, fr);
+ parent = find_parent(top, fr);
if ( parent == NULL ) {
fprintf(stderr, "Couldn't find parent when deleting frame.\n");
return;
@@ -506,41 +439,3 @@ void delete_subframe(struct slide *s, struct frame *fr)
parent->num_children--;
}
-
-void set_edit(struct presentation *p, struct slide *s)
-{
- p->cur_edit_slide = s;
-}
-
-
-void set_selection(struct presentation *p, struct frame *fr)
-{
- if ( p->n_selection != 0 ) {
- int i;
- for ( i=0; i<p->n_selection; i++ ) {
- if ( p->selection[i]->empty ) {
- delete_subframe(p->cur_edit_slide,
- p->selection[i]);
- }
- }
- }
-
- p->selection[0] = fr;
- p->n_selection = 1;
-
- if ( fr == NULL ) p->n_selection = 0;
-}
-
-
-void add_selection(struct presentation *p, struct frame *fr)
-{
- if ( p->n_selection == p->max_selection ) {
- p->max_selection += 64;
- if ( alloc_selection(p) ) {
- fprintf(stderr, "Not enough memory for selection.\n");
- return;
- }
- }
-
- p->selection[p->n_selection++] = fr;
-}
diff --git a/src/presentation.h b/src/presentation.h
index a7bb0e9..fd78a11 100644
--- a/src/presentation.h
+++ b/src/presentation.h
@@ -30,165 +30,68 @@
#include <cairo.h>
#include <gtk/gtk.h>
+struct presentation;
+struct slide;
+
#include "imagestore.h"
#include "sc_parse.h"
-
+#include "slideshow.h"
+#include "narrative_window.h"
+#include "slide_window.h"
struct slide
{
struct presentation *parent;
struct slide_template *st;
- /* Any of these may be NULL */
- cairo_surface_t *rendered_proj;
- cairo_surface_t *rendered_edit;
-
- /* This should always be present (and up to date). */
- cairo_surface_t *rendered_thumb;
-
- struct frame *top;
-
SCBlock *scblocks;
SCBlock *notes;
};
-
-enum drag_reason
-{
- DRAG_REASON_NONE,
- DRAG_REASON_CREATE,
- DRAG_REASON_IMPORT,
- DRAG_REASON_RESIZE,
- DRAG_REASON_MOVE
-};
-
-
-enum corner
-{
- CORNER_NONE,
- CORNER_TL,
- CORNER_TR,
- CORNER_BL,
- CORNER_BR
-};
-
-
-enum drag_status
-{
- DRAG_STATUS_NONE,
- DRAG_STATUS_COULD_DRAG,
- DRAG_STATUS_DRAGGING,
-};
-
-
struct menu_pl;
-
struct presentation
{
- char *titlebar;
char *filename;
+ char *titlebar; /* basename(filename) or "(untitled)" */
int completely_empty;
- int *num_presentations;
-
- struct presentation_constants *constants;
-
- GtkWidget *window;
- GtkWidget *drawingarea;
- GtkUIManager *ui;
- GtkActionGroup *action_group;
- GtkIMContext *im_context;
- struct menu_pl *style_menu;
- int n_style_menu;
- PangoContext *pc;
+
ImageStore *is;
+ NarrativeWindow *narrative_window;
+ SlideWindow *slidewindow;
+
struct notes *notes;
struct pr_clock *clock;
struct slide_sorter *slide_sorter;
- /* Pointers to the current "editing" and "projection" slides */
- struct slide *cur_edit_slide;
- struct slide *cur_proj_slide;
- int slideshow_linked;
-
- /* Pointers to the frame currently being edited */
- struct frame **selection;
- int n_selection;
- int max_selection;
-
- /* Location of the cursor */
- struct frame *cursor_frame;
- int cursor_line;
- int cursor_box;
- int cursor_pos; /* characters into box */
-
/* This is the "native" size of the slide. It only exists to give
* font size some meaning in the context of a somewhat arbitrary DPI */
double slide_width;
double slide_height;
- /* Width of a slide in the editor, projector or thumbnail (pixels) */
- int edit_slide_width;
- int proj_slide_width;
- int thumb_slide_width;
-
- /* This is just to help with rendering the slides within the
- * editing window. */
- double border_offs_x;
- double border_offs_y;
-
- /* Rubber band boxes and related stuff */
- double start_corner_x;
- double start_corner_y;
- double drag_corner_x;
- double drag_corner_y;
- double diagonal_length;
- double box_x;
- double box_y;
- double box_width;
- double box_height;
- enum drag_reason drag_reason;
- enum drag_status drag_status;
- enum corner drag_corner;
-
- /* Stuff to do with drag and drop import of "content" */
- int drag_preview_pending;
- int have_drag_data;
- int drag_highlight;
- double import_width;
- double import_height;
- int import_acceptable;
-
- /* Slideshow stuff */
- GtkWidget *slideshow;
- GtkWidget *ss_drawingarea;
- GdkCursor *blank_cursor;
- int ss_blank;
- char ss_geom[256];
-
unsigned int num_slides;
struct slide **slides;
SCBlock *stylesheet;
SCBlock *scblocks;
- struct inhibit_sys *inhibit;
};
extern struct presentation *new_presentation(void);
extern void free_presentation(struct presentation *p);
+extern char *get_titlebar_string(struct presentation *p);
+
extern struct slide *new_slide(void);
extern struct slide *add_slide(struct presentation *p, int pos);
extern int insert_slide(struct presentation *p, struct slide *s, int pos);
extern void free_slide(struct slide *s);
extern void delete_slide(struct presentation *p, struct slide *s);
-extern void delete_subframe(struct slide *s, struct frame *fr);
+extern void delete_subframe(struct frame *top, struct frame *fr);
-extern void get_titlebar_string(struct presentation *p);
extern char *packed_sc(struct frame *fr);
@@ -198,8 +101,6 @@ extern int load_presentation(struct presentation *p, const char *filename);
extern int save_presentation(struct presentation *p, const char *filename);
extern void set_edit(struct presentation *p, struct slide *s);
-extern void set_selection(struct presentation *p, struct frame *fr);
-extern void add_selection(struct presentation *p, struct frame *fr);
#define UNUSED __attribute__((unused))
diff --git a/src/render.c b/src/render.c
index 598a40f..719677a 100644
--- a/src/render.c
+++ b/src/render.c
@@ -343,45 +343,19 @@ static int recursive_wrap_and_draw(struct frame *fr, cairo_t *cr,
}
-void free_render_buffers(struct slide *s)
-{
- if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit);
- if ( s->rendered_proj != NULL ) cairo_surface_destroy(s->rendered_proj);
- if ( s->rendered_thumb != NULL ) {
- cairo_surface_destroy(s->rendered_thumb);
- }
-
- s->rendered_edit = NULL;
- s->rendered_proj = NULL;
- s->rendered_thumb = NULL;
-}
-
-
-void free_render_buffers_except_thumb(struct slide *s)
-{
- if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit);
- if ( s->rendered_proj != NULL ) cairo_surface_destroy(s->rendered_proj);
-
- s->rendered_edit = NULL;
- s->rendered_proj = NULL;
-}
-
-
-
-static void render_slide_to_surface(struct slide *s, cairo_surface_t *surf,
- cairo_t *cr, enum is_size isz,
- double scale,
- ImageStore *is, int slide_number)
+static void render_sc_to_surface(SCBlock *scblocks, cairo_surface_t *surf,
+ cairo_t *cr, double log_w, double log_h,
+ SCBlock *stylesheet,
+ ImageStore *is, enum is_size isz,
+ int slide_number)
{
PangoFontMap *fontmap;
PangoContext *pc;
SCInterpreter *scin;
char snum[64];
+ struct frame *top;
- cairo_scale(cr, scale, scale);
-
- cairo_rectangle(cr, 0.0, 0.0,
- s->parent->slide_width, s->parent->slide_height);
+ cairo_rectangle(cr, 0.0, 0.0, log_w, log_h);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_fill(cr);
@@ -397,7 +371,17 @@ static void render_slide_to_surface(struct slide *s, cairo_surface_t *surf,
pc = pango_font_map_create_context(fontmap);
pango_cairo_update_context(cr, pc);
- scin = sc_interp_new(pc, s->top);
+ top = sc_block_frame(scblocks);
+ if ( top == NULL ) {
+ top = frame_new();
+ sc_block_set_frame(scblocks, top);
+ }
+ top->x = 0.0;
+ top->y = 0.0;
+ top->w = log_w;
+ top->h = log_h;
+
+ scin = sc_interp_new(pc, top);
if ( scin == NULL ) {
fprintf(stderr, "Failed to set up interpreter.\n");
return;
@@ -407,10 +391,10 @@ static void render_slide_to_surface(struct slide *s, cairo_surface_t *surf,
add_macro(scin, "slidenumber", snum);
/* "The rendering pipeline" */
- sc_interp_run_stylesheet(scin, s->parent->stylesheet);
- renew_frame(s->top);
- sc_interp_add_blocks(scin, s->scblocks);
- recursive_wrap_and_draw(s->top, cr, is, isz);
+ if ( stylesheet != NULL ) sc_interp_run_stylesheet(scin, stylesheet);
+ renew_frame(top);
+ sc_interp_add_blocks(scin, scblocks);
+ recursive_wrap_and_draw(top, cr, is, isz);
sc_interp_destroy(scin);
cairo_font_options_destroy(fopts);
@@ -421,33 +405,27 @@ static void render_slide_to_surface(struct slide *s, cairo_surface_t *surf,
/**
* render_slide:
* @s: A slide.
- * @w: Width of the bitmap to produce
- * @ww: Width of the slide in Cairo units
- * @hh: Height of the slide in Cairo units
+ * @w: Width of bitmap to output
+ * @h: Height of bitmap to produce
+ * @ww: Logical width of the rendering area
+ * @hh: Logical height of the rendering area
*
* Render the entire slide.
*/
-cairo_surface_t *render_slide(struct slide *s, int w, double ww, double hh,
- ImageStore *is, enum is_size isz,
- int slide_number)
+cairo_surface_t *render_sc(SCBlock *scblocks, int w, int h,
+ double log_w, double log_h,
+ SCBlock *stylesheet,
+ ImageStore *is, enum is_size isz,
+ int slide_number)
{
cairo_surface_t *surf;
cairo_t *cr;
- int h;
- double scale;
-
- h = (hh/ww)*w;
- scale = w/ww;
-
- s->top->x = 0.0;
- s->top->y = 0.0;
- s->top->w = ww;
- s->top->h = hh;
surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
cr = cairo_create(surf);
- render_slide_to_surface(s, surf, cr, isz, scale, is,
- slide_number);
+ cairo_scale(cr, w/log_w, h/log_h);
+ render_sc_to_surface(scblocks, surf, cr, log_w, log_h,
+ stylesheet, is, isz,slide_number);
cairo_destroy(cr);
return surf;
}
@@ -481,17 +459,15 @@ int export_pdf(struct presentation *p, const char *filename)
cairo_save(cr);
+ cairo_scale(cr, scale, scale);
+
cairo_rectangle(cr, 0.0, 0.0, p->slide_width, p->slide_height);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_fill(cr);
- s->top->x = 0.0;
- s->top->y = 0.0;
- s->top->w = w;
- s->top->h = w*r;
-
- render_slide_to_surface(s, surf, cr, ISZ_SLIDESHOW, scale,
- p->is, i);
+ render_sc_to_surface(s->scblocks, surf, cr, p->slide_width,
+ p->slide_height, p->stylesheet,
+ p->is, ISZ_SLIDESHOW, i);
cairo_restore(cr);
diff --git a/src/render.h b/src/render.h
index 3099d35..37e66b2 100644
--- a/src/render.h
+++ b/src/render.h
@@ -30,11 +30,12 @@
#include "presentation.h"
#include "imagestore.h"
-extern cairo_surface_t *render_slide(struct slide *s, int w,
- double ww, double hh, ImageStore *is,
- enum is_size isz, int slide_number);
-extern void free_render_buffers(struct slide *s);
-extern void free_render_buffers_except_thumb(struct slide *s);
+extern cairo_surface_t *render_sc(SCBlock *scblocks, int w, int h,
+ double log_w, double log_h,
+ SCBlock *stylesheet,
+ ImageStore *is, enum is_size isz,
+ int slide_number);
+
extern int export_pdf(struct presentation *p, const char *filename);
#endif /* RENDER_H */
diff --git a/src/sc_editor.c b/src/sc_editor.c
new file mode 100644
index 0000000..f357514
--- /dev/null
+++ b/src/sc_editor.c
@@ -0,0 +1,1464 @@
+/*
+ * sc_editor.c
+ *
+ * Copyright © 2013-2014 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 <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <assert.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <math.h>
+
+#include "colloquium.h"
+#include "presentation.h"
+#include "slide_window.h"
+#include "render.h"
+#include "frame.h"
+#include "wrap.h"
+#include "sc_parse.h"
+#include "sc_interp.h"
+#include "sc_editor.h"
+#include "slideshow.h"
+
+
+G_DEFINE_TYPE(SCEditor, sc_editor, GTK_TYPE_DRAWING_AREA);
+
+
+static void sc_editor_class_init(SCEditorClass *klass)
+{
+}
+
+
+static void sc_editor_init(SCEditor *self)
+{
+}
+
+
+void sc_editor_set_background(SCEditor *e, double r, double g, double b)
+{
+ e->bgcol[0] = r;
+ e->bgcol[1] = g;
+ e->bgcol[2] = b;
+}
+
+
+/* Update the view, once it's been edited in some way. */
+static void rerender(SCEditor *e)
+{
+ if ( e->surface != NULL ) {
+ cairo_surface_destroy(e->surface);
+ }
+
+ e->surface = render_sc(e->scblocks, e->w, e->h, e->log_w, e->log_h,
+ e->stylesheet, e->is, ISZ_EDITOR, e->slidenum);
+}
+
+
+/* Force a redraw of the editor window */
+static void redraw_editor(SCEditor *e)
+{
+ gint w, h;
+
+ w = gtk_widget_get_allocated_width(GTK_WIDGET(e));
+ h = gtk_widget_get_allocated_height(GTK_WIDGET(e));
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(e), 0, 0, w, h);
+}
+
+
+/* Force a redraw of the editor window */
+void sc_editor_redraw(SCEditor *e)
+{
+ redraw_editor(e);
+}
+
+
+static void move_cursor_back(SCEditor *e)
+{
+ int retreat = 0;
+ signed int cp, cb, cl;
+ struct wrap_line *line;
+ struct wrap_box *box;
+
+ cp = e->cursor_pos;
+ cb = e->cursor_box;
+ cl = e->cursor_line;
+
+ line = &e->cursor_frame->lines[e->cursor_line];
+ box = &line->boxes[e->cursor_box];
+ if ( box->type == WRAP_BOX_PANGO ) {
+
+ if ( cp == 0 ) {
+ retreat = 1;
+ } else {
+ cp--;
+ }
+
+ } else {
+ cp--;
+ if ( cp < 0 ) retreat = 1;
+ }
+
+ if ( retreat ) {
+
+ do {
+
+ cb--;
+
+ if ( cb < 0 ) {
+ cl--;
+ if ( cl < 0 ) return;
+ e->cursor_line = cl;
+ line = &e->cursor_frame->lines[cl];
+ cb = line->n_boxes - 1;
+ }
+
+ } while ( !line->boxes[cb].editable );
+
+ e->cursor_box = cb;
+ box = &line->boxes[cb];
+ if ( box->type == WRAP_BOX_PANGO ) {
+ cp = box->len_chars;
+ if ( box->space == WRAP_SPACE_NONE ) {
+ cp--;
+ }
+ } else {
+ cp = 1;
+ }
+
+ }
+ e->cursor_pos = cp;
+}
+
+
+void cur_box_diag(SCEditor *e)
+{
+ int sln, sbx, sps;
+ struct frame *fr;
+
+ fr = e->cursor_frame;
+ sln = e->cursor_line;
+ sbx = e->cursor_box;
+ sps = e->cursor_pos;
+
+ struct wrap_box *sbox = &e->cursor_frame->lines[sln].boxes[sbx];
+
+ printf("line/box/pos: [%i of %i]/[%i of %i]/[%i of %i]\n",
+ sln, fr->n_lines,
+ sbx, e->cursor_frame->lines[sln].n_boxes,
+ sps, sbox->len_chars);
+ printf("box type is %i, space type is %i\n", sbox->type, sbox->space);
+ if ( sbox->type == WRAP_BOX_NOTHING ) {
+ printf("Warning: in a nothing box!\n");
+ }
+}
+
+
+void advance_cursor(SCEditor *e)
+{
+ int advance = 0;
+ signed int cp, cb, cl;
+ struct wrap_line *line = &e->cursor_frame->lines[e->cursor_line];
+ struct wrap_box *box = &line->boxes[e->cursor_box];
+
+ cp = e->cursor_pos;
+ cb = e->cursor_box;
+ cl = e->cursor_line;
+
+ switch ( box->type ) {
+
+ case WRAP_BOX_PANGO:
+ if ( cp+1 > box->len_chars ) {
+ advance = 1;
+ } else {
+ cp++;
+ }
+ break;
+
+ case WRAP_BOX_NOTHING:
+ case WRAP_BOX_SENTINEL:
+ advance = 1;
+ break;
+
+ case WRAP_BOX_IMAGE:
+ cp++;
+ if ( cp > 1 ) advance = 1;
+ break;
+
+ }
+
+ if ( advance ) {
+
+ do {
+
+ cb++;
+ cp = 0;
+
+ if ( box->space == WRAP_SPACE_NONE ) {
+ cp = 1;
+ }
+
+ if ( cb >= line->n_boxes ) {
+ cl++;
+ if ( cl >= e->cursor_frame->n_lines ) {
+ /* Give up - could not move */
+ return;
+ }
+ line = &e->cursor_frame->lines[cl];
+ cb = 0;
+ cp = 0;
+ }
+
+ } while ( !line->boxes[cb].editable );
+
+ e->cursor_line = cl;
+ e->cursor_box = cb;
+
+ }
+ e->cursor_pos = cp;
+}
+
+
+static gint destroy_sig(GtkWidget *window, SCEditor *sceditor)
+{
+ /* FIXME: free stuff */
+ return 0;
+}
+
+
+static void draw_editing_box(cairo_t *cr, struct frame *fr)
+{
+ const double dash[] = {2.0, 2.0};
+ double xmin, ymin, width, height;
+ double ptot_w, ptot_h;
+
+ xmin = fr->x;
+ ymin = fr->y;
+ width = fr->w;
+ height = fr->h;
+
+ cairo_new_path(cr);
+ cairo_rectangle(cr, xmin, ymin, width, height);
+ cairo_set_source_rgb(cr, 0.0, 0.69, 1.0);
+ cairo_set_line_width(cr, 0.5);
+ cairo_stroke(cr);
+
+ cairo_new_path(cr);
+ ptot_w = fr->pad_l + fr->pad_r;
+ ptot_h = fr->pad_t + fr->pad_b;
+ cairo_rectangle(cr, xmin+fr->pad_l, ymin+fr->pad_t,
+ width-ptot_w, height-ptot_h);
+ cairo_set_dash(cr, dash, 2, 0.0);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_set_line_width(cr, 0.1);
+ cairo_stroke(cr);
+
+ cairo_set_dash(cr, NULL, 0, 0.0);
+}
+
+
+static void draw_caret(cairo_t *cr, struct frame *fr,
+ int cursor_line, int cursor_box, int cursor_pos)
+{
+ double xposd, yposd, line_height;
+ double cx, clow, chigh;
+ const double t = 1.8;
+ struct wrap_box *box;
+ int i;
+
+ if ( fr == NULL ) return;
+ if ( fr->n_lines == 0 ) return;
+
+ /* Locate the cursor in a "logical" and "geographical" sense */
+ box = &fr->lines[cursor_line].boxes[cursor_box];
+ get_cursor_pos(box, cursor_pos, &xposd, &yposd, &line_height);
+ xposd += fr->pad_l;
+ yposd += fr->pad_t;
+
+ for ( i=0; i<cursor_line; i++ ) {
+ yposd += pango_units_to_double(fr->lines[i].height);
+ }
+
+ for ( i=0; i<cursor_box; i++ ) {
+ int w = fr->lines[cursor_line].boxes[i].width;
+ w += fr->lines[cursor_line].boxes[i].sp;
+ xposd += pango_units_to_double(w);
+ }
+
+ cx = fr->x + xposd;
+ clow = fr->y + yposd;
+ chigh = clow + line_height;
+
+ cairo_move_to(cr, cx, clow);
+ cairo_line_to(cr, cx, chigh);
+
+ cairo_move_to(cr, cx-t, clow-t);
+ cairo_line_to(cr, cx, clow);
+ cairo_move_to(cr, cx+t, clow-t);
+ cairo_line_to(cr, cx, clow);
+
+ cairo_move_to(cr, cx-t, chigh+t);
+ cairo_line_to(cr, cx, chigh);
+ cairo_move_to(cr, cx+t, chigh+t);
+ cairo_line_to(cr, cx, chigh);
+
+ cairo_set_source_rgb(cr, 0.86, 0.0, 0.0);
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+}
+
+
+static void draw_resize_handle(cairo_t *cr, double x, double y)
+{
+ cairo_new_path(cr);
+ cairo_rectangle(cr, x, y, 20.0, 20.0);
+ cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.5);
+ cairo_fill(cr);
+}
+
+
+static void draw_overlay(cairo_t *cr, SCEditor *e)
+{
+ double x, y, w, h;
+
+
+ if ( e->selection != NULL ) {
+
+ draw_editing_box(cr, e->selection);
+
+ x = e->selection->x;
+ y = e->selection->y;
+ w = e->selection->w;
+ h = e->selection->h;
+
+ /* Draw resize handles */
+ /* FIXME: Not if this frame can't be resized */
+ draw_resize_handle(cr, x, y+h-20.0);
+ draw_resize_handle(cr, x+w-20.0, y);
+ draw_resize_handle(cr, x, y);
+ draw_resize_handle(cr, x+w-20.0, y+h-20.0);
+
+ draw_caret(cr, e->cursor_frame, e->cursor_line, e->cursor_box,
+ e->cursor_pos);
+
+ }
+
+ if ( (e->drag_status == DRAG_STATUS_DRAGGING)
+ && ((e->drag_reason == DRAG_REASON_CREATE)
+ || (e->drag_reason == DRAG_REASON_IMPORT)) )
+ {
+ cairo_new_path(cr);
+ cairo_rectangle(cr, e->start_corner_x, e->start_corner_y,
+ e->drag_corner_x - e->start_corner_x,
+ e->drag_corner_y - e->start_corner_y);
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_set_line_width(cr, 0.5);
+ cairo_stroke(cr);
+ }
+
+ if ( (e->drag_status == DRAG_STATUS_DRAGGING)
+ && ((e->drag_reason == DRAG_REASON_RESIZE)
+ || (e->drag_reason == DRAG_REASON_MOVE)) )
+ {
+ cairo_new_path(cr);
+ cairo_rectangle(cr, e->box_x, e->box_y,
+ e->box_width, e->box_height);
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_set_line_width(cr, 0.5);
+ cairo_stroke(cr);
+ }
+}
+
+
+static gboolean draw_sig(GtkWidget *da, cairo_t *cr,
+ SCEditor *e)
+{
+ double xoff, yoff;
+ int width, height;
+
+ width = gtk_widget_get_allocated_width(GTK_WIDGET(da));
+ height = gtk_widget_get_allocated_height(GTK_WIDGET(da));
+
+ /* Overall background */
+ cairo_rectangle(cr, 0.0, 0.0, width, height);
+ cairo_set_source_rgb(cr, e->bgcol[0], e->bgcol[1], e->bgcol[2]);
+ cairo_fill(cr);
+
+ /* Get the overall size */
+ xoff = (width - e->w)/2.0;
+ yoff = (height - e->h)/2.0;
+ e->border_offs_x = xoff;
+ e->border_offs_y = yoff;
+
+ /* Draw the slide from the cache */
+ if ( e->surface != NULL ) {
+ cairo_set_source_surface(cr, e->surface, xoff, yoff);
+ cairo_paint(cr);
+ } else {
+ fprintf(stderr, "Current slide not rendered yet!\n");
+ }
+
+ cairo_translate(cr, xoff, yoff);
+ draw_overlay(cr, e);
+
+ return FALSE;
+}
+
+
+static void fixup_cursor(SCEditor *e)
+{
+ struct frame *fr;
+ struct wrap_line *sline;
+ struct wrap_box *sbox;
+
+ fr = e->cursor_frame;
+
+ if ( e->cursor_line >= fr->n_lines ) {
+ /* We find ourselves on a line which doesn't exist */
+ e->cursor_line = fr->n_lines-1;
+ e->cursor_box = fr->lines[fr->n_lines-1].n_boxes-1;
+ }
+
+ sline = &fr->lines[e->cursor_line];
+
+ if ( e->cursor_box >= sline->n_boxes ) {
+
+ /* We find ourselves in a box which doesn't exist */
+
+ if ( e->cursor_line > fr->n_lines-1 ) {
+ /* This isn't the last line, so go to the first box of
+ * the next line */
+ e->cursor_line++;
+ e->cursor_box = 0;
+ sline = &e->cursor_frame->lines[e->cursor_line];
+ } else {
+ /* There are no more lines, so just go to the end */
+ e->cursor_line = fr->n_lines-1;
+ sline = &e->cursor_frame->lines[e->cursor_line];
+ e->cursor_box = sline->n_boxes-1;
+ }
+ }
+
+ sbox = &sline->boxes[e->cursor_box];
+
+ if ( e->cursor_pos > sbox->len_chars ) {
+ advance_cursor(e);
+ }
+}
+
+
+static void move_cursor(SCEditor *e, signed int x, signed int y)
+{
+ if ( x > 0 ) {
+ advance_cursor(e);
+ } else {
+ move_cursor_back(e);
+ }
+}
+
+
+static void insert_text(char *t, SCEditor *e)
+{
+ int sln, sbx, sps;
+ struct wrap_box *sbox;
+ struct frame *fr = e->cursor_frame;
+
+ if ( fr == NULL ) return;
+
+ /* If this is, say, the top level frame, do nothing */
+ if ( fr->boxes == NULL ) return;
+
+ sln = e->cursor_line;
+ sbx = e->cursor_box;
+ sps = e->cursor_pos;
+ sbox = &e->cursor_frame->lines[sln].boxes[sbx];
+
+ sc_insert_text(sbox->scblock, sps+sbox->offs_char, t);
+
+ fr->empty = 0;
+
+ rerender(e);
+
+ fixup_cursor(e);
+ advance_cursor(e);
+
+ redraw_editor(e);
+}
+
+
+static void do_backspace(struct frame *fr, SCEditor *e)
+{
+ int sln, sbx, sps;
+
+ if ( fr == NULL ) return;
+
+ /* If this is, say, the top level frame, do nothing */
+ if ( fr->n_lines == 0 ) return;
+
+ sln = e->cursor_line;
+ sbx = e->cursor_box;
+ sps = e->cursor_pos;
+ struct wrap_box *sbox = &e->cursor_frame->lines[sln].boxes[sbx];
+
+ move_cursor_back(e);
+
+ /* Delete may cross wrap boxes and maybe SCBlock boundaries */
+ struct wrap_line *fline = &e->cursor_frame->lines[e->cursor_line];
+ struct wrap_box *fbox = &fline->boxes[e->cursor_box];
+
+// SCBlock *scbl = sbox->scblock;
+// do {
+// show_sc_blocks(scbl);
+// scbl = sc_block_next(scbl);
+// } while ( (scbl != fbox->scblock) && (scbl != NULL) );
+
+ if ( (fbox->scblock == NULL) || (sbox->scblock == NULL) ) return;
+ sc_delete_text(fbox->scblock, e->cursor_pos+fbox->offs_char,
+ sbox->scblock, sps+sbox->offs_char);
+
+// scbl = sbox->scblock;
+// do {
+// show_sc_blocks(scbl);
+// scbl = sc_block_next(scbl);
+// } while ( (scbl != fbox->scblock) && (scbl != NULL) );
+
+ rerender(e);
+ fixup_cursor(e);
+ redraw_editor(e);
+}
+
+
+static gboolean im_commit_sig(GtkIMContext *im, gchar *str,
+ SCEditor *e)
+{
+ insert_text(str, e);
+ return FALSE;
+}
+
+
+static int within_frame(struct frame *fr, double x, double y)
+{
+ if ( fr == NULL ) return 0;
+ if ( x < fr->x ) return 0;
+ if ( y < fr->y ) return 0;
+ if ( x > fr->x + fr->w ) return 0;
+ if ( y > fr->y + fr->h ) return 0;
+ return 1;
+}
+
+
+static struct frame *find_frame_at_position(struct frame *fr,
+ double x, double y)
+{
+ int i;
+
+ for ( i=0; i<fr->num_children; i++ ) {
+
+ if ( within_frame(fr->children[i], x, y) ) {
+ return find_frame_at_position(fr->children[i], x, y);
+ }
+
+ }
+
+ if ( within_frame(fr, x, y) ) return fr;
+ return NULL;
+}
+
+
+static enum corner which_corner(double xp, double yp, struct frame *fr)
+{
+ double x, y; /* Relative to object position */
+
+ x = xp - fr->x;
+ y = yp - fr->y;
+
+ if ( x < 0.0 ) return CORNER_NONE;
+ if ( y < 0.0 ) return CORNER_NONE;
+ if ( x > fr->w ) return CORNER_NONE;
+ if ( y > fr->h ) return CORNER_NONE;
+
+ /* Top left? */
+ if ( (x<20.0) && (y<20.0) ) return CORNER_TL;
+ if ( (x>fr->w-20.0) && (y<20.0) ) return CORNER_TR;
+ if ( (x<20.0) && (y>fr->h-20.0) ) {
+ return CORNER_BL;
+ }
+ if ( (x>fr->w-20.0) && (y>fr->h-20.0) ) {
+ return CORNER_BR;
+ }
+
+ return CORNER_NONE;
+}
+
+
+static void calculate_box_size(struct frame *fr, SCEditor *e,
+ double x, double y)
+{
+ double ddx, ddy, dlen, mult;
+ double vx, vy, dbx, dby;
+
+ ddx = x - e->start_corner_x;
+ ddy = y - e->start_corner_y;
+
+ if ( !fr->is_image ) {
+
+ switch ( e->drag_corner ) {
+
+ case CORNER_BR :
+ e->box_x = fr->x;
+ e->box_y = fr->y;
+ e->box_width = fr->w + ddx;
+ e->box_height = fr->h + ddy;
+ break;
+
+ case CORNER_BL :
+ e->box_x = fr->x + ddx;
+ e->box_y = fr->y;
+ e->box_width = fr->w - ddx;
+ e->box_height = fr->h + ddy;
+ break;
+
+ case CORNER_TL :
+ e->box_x = fr->x + ddx;
+ e->box_y = fr->y + ddy;
+ e->box_width = fr->w - ddx;
+ e->box_height = fr->h - ddy;
+ break;
+
+ case CORNER_TR :
+ e->box_x = fr->x;
+ e->box_y = fr->y + ddy;
+ e->box_width = fr->w + ddx;
+ e->box_height = fr->h - ddy;
+ break;
+
+ case CORNER_NONE :
+ break;
+
+ }
+ return;
+
+
+ }
+
+ switch ( e->drag_corner ) {
+
+ case CORNER_BR :
+ vx = fr->w;
+ vy = fr->h;
+ break;
+
+ case CORNER_BL :
+ vx = -fr->w;
+ vy = fr->h;
+ break;
+
+ case CORNER_TL :
+ vx = -fr->w;
+ vy = -fr->h;
+ break;
+
+ case CORNER_TR :
+ vx = fr->w;
+ vy = -fr->h;
+ break;
+
+ case CORNER_NONE :
+ default:
+ vx = 0.0;
+ vy = 0.0;
+ break;
+
+ }
+
+ dlen = (ddx*vx + ddy*vy) / e->diagonal_length;
+ mult = (dlen+e->diagonal_length) / e->diagonal_length;
+
+ e->box_width = fr->w * mult;
+ e->box_height = fr->h * mult;
+ dbx = e->box_width - fr->w;
+ dby = e->box_height - fr->h;
+
+ if ( e->box_width < 40.0 ) {
+ mult = 40.0 / fr->w;
+ }
+ if ( e->box_height < 40.0 ) {
+ mult = 40.0 / fr->h;
+ }
+ e->box_width = fr->w * mult;
+ e->box_height = fr->h * mult;
+ dbx = e->box_width - fr->w;
+ dby = e->box_height - fr->h;
+
+ switch ( e->drag_corner ) {
+
+ case CORNER_BR :
+ e->box_x = fr->x;
+ e->box_y = fr->y;
+ break;
+
+ case CORNER_BL :
+ e->box_x = fr->x - dbx;
+ e->box_y = fr->y;
+ break;
+
+ case CORNER_TL :
+ e->box_x = fr->x - dbx;
+ e->box_y = fr->y - dby;
+ break;
+
+ case CORNER_TR :
+ e->box_x = fr->x;
+ e->box_y = fr->y - dby;
+ break;
+
+ case CORNER_NONE :
+ break;
+
+ }
+}
+
+
+static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
+ SCEditor *e)
+{
+ enum corner c;
+ gdouble x, y;
+ struct frame *clicked;
+
+ x = event->x - e->border_offs_x;
+ y = event->y - e->border_offs_y;
+
+ if ( within_frame(e->selection, x, y) ) {
+ clicked = e->selection;
+ } else {
+ clicked = find_frame_at_position(sc_block_frame(e->scblocks),
+ x, y);
+ }
+
+ /* If the user clicked the currently selected frame, position cursor
+ * or possibly prepare for resize */
+ if ( (e->selection != NULL) && (clicked == e->selection) ) {
+
+ struct frame *fr;
+
+ fr = e->selection;
+
+ /* Within the resizing region? */
+ c = which_corner(x, y, fr);
+ if ( c != CORNER_NONE ) {
+
+ e->drag_reason = DRAG_REASON_RESIZE;
+ e->drag_corner = c;
+
+ e->start_corner_x = x;
+ e->start_corner_y = y;
+ e->diagonal_length = pow(fr->w, 2.0);
+ e->diagonal_length += pow(fr->h, 2.0);
+ e->diagonal_length = sqrt(e->diagonal_length);
+
+ calculate_box_size(fr, e, x, y);
+
+ e->drag_status = DRAG_STATUS_COULD_DRAG;
+ e->drag_reason = DRAG_REASON_RESIZE;
+
+ } else {
+
+ e->cursor_frame = clicked;
+ find_cursor(clicked, x-fr->x, y-fr->y,
+ &e->cursor_line, &e->cursor_box,
+ &e->cursor_pos);
+
+ e->start_corner_x = event->x - e->border_offs_x;
+ e->start_corner_y = event->y - e->border_offs_y;
+ e->drag_status = DRAG_STATUS_COULD_DRAG;
+ e->drag_reason = DRAG_REASON_MOVE;
+
+ }
+
+ } else if ( (clicked == NULL)
+ || (clicked == sc_block_frame(e->scblocks)) )
+ {
+ /* Clicked no object. Deselect old object and set up for
+ * (maybe) creating a new one. */
+ e->selection = NULL;
+ e->start_corner_x = event->x - e->border_offs_x;
+ e->start_corner_y = event->y - e->border_offs_y;
+ e->drag_status = DRAG_STATUS_COULD_DRAG;
+ e->drag_reason = DRAG_REASON_CREATE;
+
+ } else {
+
+ /* Select new frame, no immediate dragging */
+ e->drag_status = DRAG_STATUS_NONE;
+ e->drag_reason = DRAG_REASON_NONE;
+ e->selection = clicked;
+
+ }
+
+ gtk_widget_grab_focus(GTK_WIDGET(da));
+ redraw_editor(e);
+ return FALSE;
+}
+
+
+static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
+ SCEditor *e)
+{
+ struct frame *fr = e->selection;
+ gdouble x, y;
+
+ x = event->x - e->border_offs_x;
+ y = event->y - e->border_offs_y;
+
+ if ( e->drag_status == DRAG_STATUS_COULD_DRAG ) {
+
+ /* We just got a motion signal, and the status was "could drag",
+ * therefore the drag has started. */
+ e->drag_status = DRAG_STATUS_DRAGGING;
+
+ }
+
+ switch ( e->drag_reason ) {
+
+ case DRAG_REASON_NONE :
+ break;
+
+ case DRAG_REASON_CREATE :
+ e->drag_corner_x = x;
+ e->drag_corner_y = y;
+ redraw_editor(e);
+ break;
+
+ case DRAG_REASON_IMPORT :
+ /* Do nothing, handled by dnd_motion() */
+ break;
+
+ case DRAG_REASON_RESIZE :
+ calculate_box_size(fr, e, x, y);
+ redraw_editor(e);
+ break;
+
+ case DRAG_REASON_MOVE :
+ e->box_x = (fr->x - e->start_corner_x) + x;
+ e->box_y = (fr->y - e->start_corner_y) + y;
+ e->box_width = fr->w;
+ e->box_height = fr->h;
+ redraw_editor(e);
+ break;
+
+ }
+
+ gdk_event_request_motions(event);
+ return FALSE;
+}
+
+
+static struct frame *create_frame(SCEditor *e, double x, double y,
+ double w, double h)
+{
+ struct frame *parent;
+ struct frame *fr;
+
+ parent = sc_block_frame(e->scblocks);
+
+ if ( w < 0.0 ) {
+ x += w;
+ w = -w;
+ }
+
+ if ( h < 0.0 ) {
+ y += h;
+ h = -h;
+ }
+
+ fr = add_subframe(parent);
+
+ /* Add to SC */
+ fr->scblocks = sc_block_append_end(e->scblocks,
+ "f", NULL, NULL);
+ sc_block_set_frame(fr->scblocks, fr);
+ sc_block_append_inside(fr->scblocks, NULL, NULL, strdup(""));
+
+ fr->x = x;
+ fr->y = y;
+ fr->w = w;
+ fr->h = h;
+ fr->is_image = 0;
+ fr->empty = 1;
+
+ update_geom(fr);
+
+ return fr;
+}
+
+
+static void do_resize(SCEditor *e, double x, double y, double w, double h)
+{
+ struct frame *fr;
+
+ assert(e->selection != NULL);
+
+ if ( w < 0.0 ) {
+ w = -w;
+ x -= w;
+ }
+
+ if ( h < 0.0 ) {
+ h = -h;
+ y -= h;
+ }
+
+ fr = e->selection;
+ fr->x = x;
+ fr->y = y;
+ fr->w = w;
+ fr->h = h;
+ update_geom(fr);
+
+ rerender(e);
+ redraw_editor(e);
+}
+
+
+static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event,
+ SCEditor *e)
+{
+ gdouble x, y;
+ struct frame *fr;
+
+ x = event->x - e->border_offs_x;
+ y = event->y - e->border_offs_y;
+
+ /* Not dragging? Then I don't care. */
+ if ( e->drag_status != DRAG_STATUS_DRAGGING ) return FALSE;
+
+ e->drag_corner_x = x;
+ e->drag_corner_y = y;
+ e->drag_status = DRAG_STATUS_NONE;
+
+ switch ( e->drag_reason )
+ {
+
+ case DRAG_REASON_NONE :
+ printf("Release on pointless drag.\n");
+ break;
+
+ case DRAG_REASON_CREATE :
+ fr = create_frame(e, e->start_corner_x, e->start_corner_y,
+ e->drag_corner_x - e->start_corner_x,
+ e->drag_corner_y - e->start_corner_y);
+ rerender(e);
+ e->selection = fr;
+ break;
+
+ case DRAG_REASON_IMPORT :
+ /* Do nothing, handled in dnd_drop() or dnd_leave() */
+ break;
+
+ case DRAG_REASON_RESIZE :
+ do_resize(e, e->box_x, e->box_y, e->box_width, e->box_height);
+ break;
+
+ case DRAG_REASON_MOVE :
+ do_resize(e, e->box_x, e->box_y, e->box_width, e->box_height);
+ break;
+
+ }
+
+ e->drag_reason = DRAG_REASON_NONE;
+
+ gtk_widget_grab_focus(GTK_WIDGET(da));
+ redraw_editor(e);
+ return FALSE;
+}
+
+
+static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event,
+ SCEditor *e)
+{
+ gboolean r;
+ int claim = 0;
+
+ /* Throw the event to the IM context and let it sort things out */
+ r = gtk_im_context_filter_keypress(GTK_IM_CONTEXT(e->im_context),
+ event);
+ if ( r ) return FALSE; /* IM ate it */
+
+ switch ( event->keyval ) {
+
+ case GDK_KEY_Escape :
+ e->selection = NULL;
+ redraw_editor(e);
+ claim = 1;
+ break;
+
+ case GDK_KEY_Left :
+ if ( e->selection != NULL ) {
+ move_cursor(e, -1, 0);
+ redraw_editor(e);
+ }
+ claim = 1;
+ break;
+
+ case GDK_KEY_Right :
+ if ( e->selection != NULL ) {
+ move_cursor(e, +1, 0);
+ redraw_editor(e);
+ }
+ claim = 1;
+ break;
+
+ case GDK_KEY_Up :
+ if ( e->selection != NULL ) {
+ move_cursor(e, 0, -1);
+ redraw_editor(e);
+ }
+ claim = 1;
+ break;
+
+ case GDK_KEY_Down :
+ if ( e->selection != NULL ) {
+ move_cursor(e, 0, +1);
+ redraw_editor(e);
+ }
+ claim = 1;
+ break;
+
+
+ case GDK_KEY_Return :
+ im_commit_sig(NULL, "\n", e);
+ claim = 1;
+ break;
+
+ case GDK_KEY_BackSpace :
+ if ( e->selection != NULL ) {
+ do_backspace(e->selection, e);
+ claim = 1;
+ }
+ break;
+
+ }
+
+ if ( claim ) return TRUE;
+ return FALSE;
+}
+
+
+static gboolean dnd_motion(GtkWidget *widget, GdkDragContext *drag_context,
+ gint x, gint y, guint time, SCEditor *e)
+{
+ GdkAtom target;
+
+ /* If we haven't already requested the data, do so now */
+ if ( !e->drag_preview_pending && !e->have_drag_data ) {
+
+ target = gtk_drag_dest_find_target(widget, drag_context, NULL);
+
+ if ( target != GDK_NONE ) {
+ gtk_drag_get_data(widget, drag_context, target, time);
+ e->drag_preview_pending = 1;
+ } else {
+ e->import_acceptable = 0;
+ gdk_drag_status(drag_context, 0, time);
+ }
+
+ }
+
+ if ( e->have_drag_data && e->import_acceptable ) {
+
+ gdk_drag_status(drag_context, GDK_ACTION_LINK, time);
+ e->start_corner_x = x - e->import_width/2.0;
+ e->start_corner_y = y - e->import_height/2.0;
+ e->drag_corner_x = x + e->import_width/2.0;
+ e->drag_corner_y = y + e->import_height/2.0;
+
+ redraw_editor(e);
+
+ }
+
+ return TRUE;
+}
+
+
+static gboolean dnd_drop(GtkWidget *widget, GdkDragContext *drag_context,
+ gint x, gint y, guint time, SCEditor *e)
+{
+ GdkAtom target;
+
+ target = gtk_drag_dest_find_target(widget, drag_context, NULL);
+
+ if ( target == GDK_NONE ) {
+ gtk_drag_finish(drag_context, FALSE, FALSE, time);
+ } else {
+ gtk_drag_get_data(widget, drag_context, target, time);
+ }
+
+ return TRUE;
+}
+
+
+static void chomp(char *s)
+{
+ size_t i;
+
+ if ( !s ) return;
+
+ for ( i=0; i<strlen(s); i++ ) {
+ if ( (s[i] == '\n') || (s[i] == '\r') ) {
+ s[i] = '\0';
+ return;
+ }
+ }
+}
+
+
+/* Scale the image down if it's a silly size */
+static void check_import_size(SCEditor *e)
+{
+ if ( e->import_width > e->w ) {
+
+ int new_import_width;
+
+ new_import_width = e->w/2;
+ e->import_height = (new_import_width *e->import_height)
+ / e->w;
+ e->import_width = new_import_width;
+ }
+
+ if ( e->import_height > e->h ) {
+
+ int new_import_height;
+
+ new_import_height = e->w/2;
+ e->import_width = (new_import_height*e->import_width)
+ / e->import_height;
+ e->import_height = new_import_height;
+ }
+}
+
+
+static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context,
+ gint x, gint y, GtkSelectionData *seldata,
+ guint info, guint time, SCEditor *e)
+{
+ if ( e->drag_preview_pending ) {
+
+ gchar *filename = NULL;
+ GdkPixbufFormat *f;
+ gchar **uris;
+ int w, h;
+
+ e->have_drag_data = 1;
+ e->drag_preview_pending = 0;
+ uris = gtk_selection_data_get_uris(seldata);
+ if ( uris != NULL ) {
+ filename = g_filename_from_uri(uris[0], NULL, NULL);
+ }
+ g_strfreev(uris);
+
+ if ( filename == NULL ) {
+
+ /* This doesn't even look like a sensible URI.
+ * Bail out. */
+ gdk_drag_status(drag_context, 0, time);
+ if ( e->drag_highlight ) {
+ gtk_drag_unhighlight(widget);
+ e->drag_highlight = 0;
+ }
+ e->import_acceptable = 0;
+ return;
+
+ }
+ chomp(filename);
+
+ f = gdk_pixbuf_get_file_info(filename, &w, &h);
+ g_free(filename);
+
+ e->import_width = w;
+ e->import_height = h;
+
+ if ( f == NULL ) {
+
+ gdk_drag_status(drag_context, 0, time);
+ if ( e->drag_highlight ) {
+ gtk_drag_unhighlight(widget);
+ e->drag_highlight = 0;
+ }
+ e->drag_status = DRAG_STATUS_NONE;
+ e->drag_reason = DRAG_REASON_NONE;
+ e->import_acceptable = 0;
+
+ } else {
+
+ /* Looks like a sensible image */
+ gdk_drag_status(drag_context, GDK_ACTION_PRIVATE, time);
+ e->import_acceptable = 1;
+
+ if ( !e->drag_highlight ) {
+ gtk_drag_highlight(widget);
+ e->drag_highlight = 1;
+ }
+
+ check_import_size(e);
+ e->drag_reason = DRAG_REASON_IMPORT;
+ e->drag_status = DRAG_STATUS_DRAGGING;
+
+ }
+
+ } else {
+
+ gchar **uris;
+ char *filename = NULL;
+
+ uris = gtk_selection_data_get_uris(seldata);
+ if ( uris != NULL ) {
+ filename = g_filename_from_uri(uris[0], NULL, NULL);
+ }
+ g_strfreev(uris);
+
+ if ( filename != NULL ) {
+
+ struct frame *fr;
+ char *opts;
+ size_t len;
+ int w, h;
+
+ gtk_drag_finish(drag_context, TRUE, FALSE, time);
+ chomp(filename);
+
+ w = e->drag_corner_x - e->start_corner_x;
+ h = e->drag_corner_y - e->start_corner_y;
+
+ len = strlen(filename)+64;
+ opts = malloc(len);
+ if ( opts == NULL ) {
+ free(filename);
+ fprintf(stderr, "Failed to allocate SC\n");
+ return;
+ }
+ snprintf(opts, len, "1fx1f+0+0,filename=\"%s\"",
+ filename);
+
+ fr = create_frame(e, e->start_corner_x,
+ e->start_corner_y, w, h);
+ fr->is_image = 1;
+ fr->empty = 0;
+ sc_block_append_inside(fr->scblocks, "image", opts, "");
+ rerender(e);
+ e->selection = fr;
+ redraw_editor(e);
+ free(filename);
+
+ } else {
+
+ gtk_drag_finish(drag_context, FALSE, FALSE, time);
+
+ }
+
+ }
+}
+
+
+static void dnd_leave(GtkWidget *widget, GdkDragContext *drag_context,
+ guint time, SCEditor *sceditor)
+{
+ if ( sceditor->drag_highlight ) {
+ gtk_drag_unhighlight(widget);
+ }
+ sceditor->have_drag_data = 0;
+ sceditor->drag_highlight = 0;
+ sceditor->drag_status = DRAG_STATUS_NONE;
+ sceditor->drag_reason = DRAG_REASON_NONE;
+}
+
+
+static gint realise_sig(GtkWidget *da, SCEditor *e)
+{
+ GdkWindow *win;
+
+ /* Keyboard and input method stuff */
+ e->im_context = gtk_im_multicontext_new();
+ win = gtk_widget_get_window(GTK_WIDGET(e));
+ gtk_im_context_set_client_window(GTK_IM_CONTEXT(e->im_context),
+ win);
+ gdk_window_set_accept_focus(win, TRUE);
+ g_signal_connect(G_OBJECT(e->im_context), "commit",
+ G_CALLBACK(im_commit_sig), e);
+ g_signal_connect(G_OBJECT(e), "key-press-event",
+ G_CALLBACK(key_press_sig), e);
+
+ /* FIXME: Can do this "properly" by setting up a separate font map */
+ e->pc = gtk_widget_get_pango_context(GTK_WIDGET(e));
+ rerender(e);
+
+ return FALSE;
+}
+
+
+static void unset_all_frames(SCBlock *bl)
+{
+ while ( bl != NULL ) {
+ sc_block_set_frame(bl, NULL);
+ if ( sc_block_child(bl) != NULL ) {
+ unset_all_frames(sc_block_child(bl));
+ }
+ if ( sc_block_macro_child(bl) != NULL ) {
+ unset_all_frames(sc_block_macro_child(bl));
+ }
+ bl = sc_block_next(bl);
+ }
+}
+
+
+static void free_frame_contents(struct frame *fr)
+{
+ int i;
+
+ if ( fr == NULL ) return;
+
+ for ( i=0; i<fr->n_lines; i++ ) {
+ wrap_line_free(&fr->lines[i]);
+ }
+ free(fr->lines);
+ fr->lines = NULL;
+ fr->n_lines = 0;
+ fr->max_lines = 0;
+
+ if ( fr->boxes != NULL ) {
+ free(fr->boxes->boxes);
+ free(fr->boxes);
+ }
+
+ fr->boxes = NULL;
+
+ for ( i=0; i<fr->num_children; i++ ) {
+ free_frame_contents(fr->children[i]);
+ }
+
+ fr->num_children = 0;
+}
+
+
+void sc_editor_set_scblock(SCEditor *e, SCBlock *scblocks)
+{
+ unset_all_frames(e->scblocks);
+ e->scblocks = scblocks;
+
+ /* Free all subframes */
+ free_frame_contents(sc_block_frame(e->scblocks));
+
+ rerender(e);
+ redraw_editor(e);
+}
+
+
+void sc_editor_set_size(SCEditor *e, int w, int h)
+{
+ e->w = w;
+ e->h = h;
+ gtk_widget_set_size_request(GTK_WIDGET(e), w, h);
+}
+
+
+void sc_editor_set_logical_size(SCEditor *e, double w, double h)
+{
+ e->log_w = w;
+ e->log_h = h;
+}
+
+
+void sc_editor_set_slidenum(SCEditor *e, int slidenum)
+{
+ e->slidenum = slidenum;
+}
+
+
+SCEditor *sc_editor_new(SCBlock *scblocks, SCBlock *stylesheet)
+{
+ SCEditor *sceditor;
+ GtkTargetEntry targets[1];
+
+ sceditor = g_object_new(SC_TYPE_EDITOR, NULL);
+
+ sceditor->scblocks = scblocks;
+ sceditor->surface = NULL;
+ sceditor->w = 100;
+ sceditor->h = 100;
+ sceditor->log_w = 100;
+ sceditor->log_h = 100;
+ sceditor->is = imagestore_new();
+ sceditor->stylesheet = stylesheet;
+ sceditor->slidenum = 0;
+
+ rerender(sceditor);
+
+ gtk_widget_set_size_request(GTK_WIDGET(sceditor),
+ sceditor->w, sceditor->h);
+
+ g_signal_connect(G_OBJECT(sceditor), "destroy",
+ G_CALLBACK(destroy_sig), sceditor);
+ g_signal_connect(G_OBJECT(sceditor), "realize",
+ G_CALLBACK(realise_sig), sceditor);
+ g_signal_connect(G_OBJECT(sceditor), "button-press-event",
+ G_CALLBACK(button_press_sig), sceditor);
+ g_signal_connect(G_OBJECT(sceditor), "button-release-event",
+ G_CALLBACK(button_release_sig), sceditor);
+ g_signal_connect(G_OBJECT(sceditor), "motion-notify-event",
+ G_CALLBACK(motion_sig), sceditor);
+
+ /* Drag and drop */
+ targets[0].target = "text/uri-list";
+ targets[0].flags = 0;
+ targets[0].info = 1;
+ gtk_drag_dest_set(GTK_WIDGET(sceditor), 0, targets, 1,
+ GDK_ACTION_PRIVATE);
+ g_signal_connect(sceditor, "drag-data-received",
+ G_CALLBACK(dnd_receive), sceditor);
+ g_signal_connect(sceditor, "drag-motion",
+ G_CALLBACK(dnd_motion), sceditor);
+ g_signal_connect(sceditor, "drag-drop",
+ G_CALLBACK(dnd_drop), sceditor);
+ g_signal_connect(sceditor, "drag-leave",
+ G_CALLBACK(dnd_leave), sceditor);
+
+ gtk_widget_set_can_focus(GTK_WIDGET(sceditor), TRUE);
+ gtk_widget_add_events(GTK_WIDGET(sceditor),
+ GDK_POINTER_MOTION_HINT_MASK
+ | GDK_BUTTON1_MOTION_MASK
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+
+ g_signal_connect(G_OBJECT(sceditor), "draw",
+ G_CALLBACK(draw_sig), sceditor);
+
+ gtk_widget_grab_focus(GTK_WIDGET(sceditor));
+
+ gtk_widget_show(GTK_WIDGET(sceditor));
+
+ return sceditor;
+}
diff --git a/src/sc_editor.h b/src/sc_editor.h
new file mode 100644
index 0000000..8bfcd59
--- /dev/null
+++ b/src/sc_editor.h
@@ -0,0 +1,157 @@
+/*
+ * sc_editor.h
+ *
+ * Copyright © 2014 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 SC_EDITOR_H
+#define SC_EDITOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include "frame.h"
+
+struct presentation;
+
+
+#define SC_TYPE_EDITOR (sc_editor_get_type())
+
+#define SC_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ SC_TYPE_EDITOR, SCEditor))
+
+#define SC_IS_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ SC_TYPE_EDITOR))
+
+#define SC_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), \
+ SC_TYPE_EDITOR, SCEditorClass))
+
+#define SC_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), \
+ SC_TYPE_EDITOR))
+
+#define SC_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ SC_TYPE_EDITOR, SCEditorClass))
+
+enum drag_reason
+{
+ DRAG_REASON_NONE,
+ DRAG_REASON_CREATE,
+ DRAG_REASON_IMPORT,
+ DRAG_REASON_RESIZE,
+ DRAG_REASON_MOVE
+};
+
+
+enum corner
+{
+ CORNER_NONE,
+ CORNER_TL,
+ CORNER_TR,
+ CORNER_BL,
+ CORNER_BR
+};
+
+
+enum drag_status
+{
+ DRAG_STATUS_NONE,
+ DRAG_STATUS_COULD_DRAG,
+ DRAG_STATUS_DRAGGING,
+};
+
+
+struct _sceditor
+{
+ GtkDrawingArea parent_instance;
+
+ /*< private >*/
+ GtkIMContext *im_context;
+ int w; /* Surface size in pixels */
+ int h;
+ double log_w; /* Size of surface in "SC units" */
+ double log_h;
+ SCBlock *scblocks;
+ cairo_surface_t *surface;
+ SCBlock *stylesheet;
+ ImageStore *is;
+
+ /* Pointers to the frame currently being edited */
+ struct frame *selection;
+
+ PangoContext *pc;
+
+ /* Location of the cursor */
+ struct frame *cursor_frame;
+ int cursor_line;
+ int cursor_box;
+ int cursor_pos; /* characters into box */
+
+ /* Border surrounding actual slide within drawingarea */
+ double border_offs_x;
+ double border_offs_y;
+ double bgcol[3];
+
+ /* Rubber band boxes and related stuff */
+ double start_corner_x;
+ double start_corner_y;
+ double drag_corner_x;
+ double drag_corner_y;
+ double diagonal_length;
+ double box_x;
+ double box_y;
+ double box_width;
+ double box_height;
+ enum drag_reason drag_reason;
+ enum drag_status drag_status;
+ enum corner drag_corner;
+
+ /* Stuff to do with drag and drop import of "content" */
+ int drag_preview_pending;
+ int have_drag_data;
+ int drag_highlight;
+ double import_width;
+ double import_height;
+ int import_acceptable;
+
+ /* Stuff that doesn't really belong here */
+ int slidenum;
+};
+
+struct _sceditorclass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+typedef struct _sceditor SCEditor;
+typedef struct _sceditorclass SCEditorClass;
+
+extern void sc_editor_set_scblock(SCEditor *e, SCBlock *scblocks);
+extern GtkWidget *sc_editor_get_widget(SCEditor *e);
+extern SCEditor *sc_editor_new(SCBlock *scblocks, SCBlock *stylesheet);
+extern void sc_editor_set_size(SCEditor *e, int w, int h);
+extern void sc_editor_set_logical_size(SCEditor *e, double w, double h);
+extern void sc_editor_redraw(SCEditor *e);
+extern void sc_editor_set_background(SCEditor *e, double r, double g, double b);
+extern void sc_editor_set_slidenum(SCEditor *e, int slidenum);
+
+#endif /* SC_EDITOR_H */
diff --git a/src/sc_interp.c b/src/sc_interp.c
index 646a132..703b73f 100644
--- a/src/sc_interp.c
+++ b/src/sc_interp.c
@@ -390,6 +390,7 @@ void sc_interp_destroy(SCInterpreter *scin)
pango_font_description_free(scin->state[0].fontdesc);
+ free(scin->state);
free(scin);
}
@@ -788,10 +789,6 @@ int sc_interp_add_blocks(SCInterpreter *scin, SCBlock *bl)
set_padding(sc_interp_get_frame(scin), options);
maybe_recurse_after(scin, child);
- } else if ( strcmp(name, "slide") == 0 ) {
- maybe_recurse_before(scin, child);
- maybe_recurse_after(scin, child);
-
} else if ( strcmp(name, "bgcol") == 0 ) {
maybe_recurse_before(scin, child);
set_frame_bgcolour(sc_interp_get_frame(scin), options);
diff --git a/src/slide_sorter.c b/src/slide_sorter.c
index c64e408..53bee9d 100644
--- a/src/slide_sorter.c
+++ b/src/slide_sorter.c
@@ -32,7 +32,7 @@
#include "presentation.h"
#include "render.h"
-#include "mainwindow.h"
+#include "slide_window.h"
#include "slideshow.h"
@@ -99,7 +99,7 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, struct slide_sorter *n)
int x = i % n->width;
int y = i / n->width;
- struct slide *s = n->p->slides[i];
+ //struct slide *s = n->p->slides[i];
cairo_save(cr);
@@ -120,17 +120,9 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, struct slide_sorter *n)
cairo_rectangle(cr, 0.0, 0.0, n->tw, n->th);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_fill_preserve(cr);
- if ( (s != NULL) && (s->rendered_thumb != NULL) ) {
- cairo_set_source_surface(cr, s->rendered_thumb,
- 0.0, 0.0);
- } else {
- printf("Slide %i: %p", i, s);
- if ( s != NULL ) {
- printf(" %p\n", s->rendered_thumb);
- } else {
- printf("\n");
- }
- }
+ /* FIXME */
+ //cairo_set_source_surface(cr, s->rendered_thumb,
+ // 0.0, 0.0);
cairo_fill(cr);
cairo_rectangle(cr, 0.5, 0.5, n->tw, n->th);
@@ -210,18 +202,19 @@ static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
/* If we are dragging the current editor or projector slide,
* we'd better remember to update when we're finished. */
+#if 0 /* FIXME! */
if ( n->p->cur_edit_slide == n->selected_slide ) {
n->dragging_cur_edit_slide = 1;
} else {
n->dragging_cur_edit_slide = 0;
}
- if ( n->p->cur_proj_slide == n->selected_slide ) {
+ if ( slideshow_slide(n->p->slideshow) == n->selected_slide ) {
n->dragging_cur_proj_slide = 1;
} else {
n->dragging_cur_proj_slide = 0;
}
-
+#endif
list = gtk_target_list_new(targets, 1);
gtk_drag_begin(da, list, GDK_ACTION_COPY | GDK_ACTION_MOVE,
1, (GdkEvent *)event);
@@ -329,15 +322,7 @@ static gboolean dnd_drop(GtkWidget *widget, GdkDragContext *drag_context,
* gets there first. When re-arranging slides, this might not happen */
static void fixup_proj(struct presentation *p, struct slide *s)
{
- int n;
-
- if ( s->rendered_proj != NULL ) return;
-
- n = slide_number(p, s);
-
- s->rendered_proj = render_slide(s, s->parent->proj_slide_width,
- p->slide_width, p->slide_height,
- p->is, ISZ_SLIDESHOW, n);
+// slideshow_rerender(p->slideshow); FIXME
}
@@ -356,10 +341,10 @@ static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context,
} else {
- const char *sc;
+ //const char *sc;
struct slide *s = NULL;
- sc = (const char *)gtk_selection_data_get_data(seldata);
+ //sc = (const char *)gtk_selection_data_get_data(seldata);
n->dragging = 0;
gtk_drag_finish(drag_context, TRUE, TRUE, time);
@@ -371,28 +356,21 @@ static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context,
if ( s != NULL ) {
/* FIXME: Do something */
- int sn = slide_number(n->p, s);
+ //int sn = slide_number(n->p, s);
- s->rendered_thumb = render_slide(s,
- n->p->thumb_slide_width,
- n->p->slide_width,
- n->p->slide_height,
- n->p->is,
- ISZ_THUMBNAIL, sn);
+ //s->rendered_thumb = render_slide(s, n->tw,
+ // n->p->slide_width,
+ // n->p->slide_height,
+ // n->p->is,
+ // ISZ_THUMBNAIL, sn);
/* FIXME: Transfer the notes as well */
- if ( n->dragging_cur_edit_slide ) {
- change_edit_slide(n->p, s);
- } else {
- /* Slide order has changed, so slide change
- * buttons might need to be greyed out */
- update_toolbar(n->p);
- }
+ change_edit_slide(n->p->slidewindow, s);
if ( n->dragging_cur_proj_slide ) {
fixup_proj(n->p, s);
- change_proj_slide(n->p, s);
+ // FIXME change_proj_slide(n->p->slideshow, s);
}
redraw_slidesorter(n);
@@ -422,6 +400,7 @@ static void dnd_get(GtkWidget *widget, GdkDragContext *drag_context,
char *sc;
/* FIXME: packed sc */
//sc = packed_sc(n->p->slides[n->selection]->top, n->p->ss);
+ sc = NULL;
gtk_selection_data_set(seldata, target, 8, (guchar *)sc,
strlen(sc));
@@ -460,6 +439,7 @@ static void dnd_delete(GtkWidget *widget, GdkDragContext *drag_context,
if ( sn < n->drop_here ) n->drop_here--;
+#if 0 /* FIXME ! */
if ( n->p->cur_edit_slide == n->selected_slide ) {
if ( same ) {
@@ -477,14 +457,13 @@ static void dnd_delete(GtkWidget *widget, GdkDragContext *drag_context,
ct = sn - 1;
}
- change_edit_slide(n->p, n->p->slides[ct]);
- update_toolbar(n->p);
+ change_edit_slide(n->p->slidewindow, n->p->slides[ct]);
}
}
- if ( n->p->cur_proj_slide == n->selected_slide ) {
+ if ( slideshow_slide(n->p->slideshow) == n->selected_slide ) {
if ( same ) {
@@ -501,12 +480,12 @@ static void dnd_delete(GtkWidget *widget, GdkDragContext *drag_context,
ct = sn - 1;
}
- change_proj_slide(n->p, n->p->slides[ct]);
+ change_proj_slide(n->p->slideshow, n->p->slides[ct]);
}
}
-
+#endif
delete_slide(n->p, n->selected_slide);
}
@@ -527,8 +506,8 @@ void open_slidesorter(struct presentation *p)
n->width = 6;
n->bw = 5;
n->selection = 0;
- n->tw = p->thumb_slide_width;
- n->th = (p->slide_height/p->slide_width) * p->thumb_slide_width;
+ n->tw = 320;
+ n->th = (p->slide_height/p->slide_width) * n->tw;
n->drag_preview_pending = 0;
n->have_drag_data = 0;
n->dragging = 0;
diff --git a/src/slide_window.c b/src/slide_window.c
new file mode 100644
index 0000000..f262875
--- /dev/null
+++ b/src/slide_window.c
@@ -0,0 +1,621 @@
+/*
+ * slide_window.c
+ *
+ * Copyright © 2013-2014 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 <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <assert.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <math.h>
+
+#include "presentation.h"
+#include "slide_window.h"
+#include "render.h"
+#include "frame.h"
+#include "slideshow.h"
+#include "wrap.h"
+#include "notes.h"
+#include "pr_clock.h"
+#include "slide_sorter.h"
+#include "sc_parse.h"
+#include "sc_interp.h"
+#include "sc_editor.h"
+
+
+struct _slidewindow
+{
+ struct presentation *p;
+ GtkWidget *window;
+ GtkToolItem *bfirst;
+ GtkToolItem *bprev;
+ GtkToolItem *bnext;
+ GtkToolItem *blast;
+
+ SCEditor *sceditor;
+
+ struct menu_pl *style_menu;
+ int n_style_menu;
+
+ struct slide *cur_slide; /* FIXME: SPOT inside SCEditor */
+
+ SlideShow *show;
+ struct notes *notes;
+};
+
+
+
+void update_toolbar(SlideWindow *sw)
+{
+ int cur_slide_number;
+
+ cur_slide_number = slide_number(sw->p, sw->cur_slide);
+ if ( cur_slide_number == 0 ) {
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bfirst), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bprev), FALSE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bfirst), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bprev), TRUE);
+ }
+
+ if ( cur_slide_number == sw->p->num_slides-1 ) {
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bnext), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->blast), FALSE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->bnext), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(sw->blast), TRUE);
+ }
+
+}
+
+
+/* Inelegance to make furniture selection menus work */
+struct menu_pl
+{
+ SlideWindow *sw;
+ char *style_name;
+ GtkWidget *widget;
+};
+
+
+static gint add_furniture(GtkWidget *widget, struct menu_pl *pl)
+{
+ sc_block_append_end(pl->sw->cur_slide->scblocks,
+ strdup(pl->style_name), NULL, NULL);
+
+ //do_slide_update(pl->p, pl->sw->pc); FIXME
+
+ return 0;
+}
+
+
+static void update_style_menus(SlideWindow *sw)
+{
+ GtkWidget *menu;
+ SCInterpreter *scin;
+ struct style_id *styles;
+ int i, n_sty;
+
+ /* Free old list */
+ for ( i=0; i<sw->n_style_menu; i++ ) {
+ gtk_widget_destroy(sw->style_menu[i].widget);
+ free(sw->style_menu[i].style_name);
+ }
+ free(sw->style_menu);
+
+ /* Get the list of styles from the style sheet */
+ scin = sc_interp_new(NULL, NULL);
+ if ( scin == NULL ) {
+ fprintf(stderr, "Failed to set up interpreter.\n");
+ return;
+ }
+ sc_interp_run_stylesheet(scin, sw->p->stylesheet);
+
+ styles = list_styles(scin, &n_sty);
+ if ( styles == NULL ) return;
+
+ sc_interp_destroy(scin);
+
+ /* Set up list for next time */
+ sw->style_menu = calloc(n_sty, sizeof(struct menu_pl));
+ if ( sw->style_menu == NULL ) return;
+
+#if 0 // FIXME
+ /* Add the styles to the "Insert" menu */
+ menu = gtk_ui_manager_get_widget(sw->ui, "/displaywindow/insert");
+ menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
+
+ for ( i=0; i<n_sty; i++ ) {
+
+ GtkWidget *item;
+
+ item = gtk_menu_item_new_with_label(styles[i].friendlyname);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ sw->style_menu[i].sw = sw;
+ sw->style_menu[i].widget = item;
+ sw->style_menu[i].style_name = styles[i].name;
+
+ g_signal_connect(G_OBJECT(item), "activate",
+ G_CALLBACK(add_furniture),
+ &sw->style_menu[i]);
+
+ free(styles[i].friendlyname);
+ }
+
+ gtk_widget_show_all(menu);
+ free(styles);
+#endif
+}
+
+
+static gint saveas_response_sig(GtkWidget *d, gint response,
+ SlideWindow *sw)
+{
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ if ( save_presentation(sw->p, filename) ) {
+ //show_error(sw, "Failed to save presentation");
+ }
+
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(d);
+
+ return 0;
+}
+
+
+static void saveas_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ GtkWidget *d;
+ SlideWindow *sw = vp;
+
+ d = gtk_file_chooser_dialog_new("Save Presentation",
+ GTK_WINDOW(sw->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
+ TRUE);
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(saveas_response_sig), sw);
+
+ gtk_widget_show_all(d);
+}
+
+
+static void save_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ SlideWindow *sw = vp;
+
+ if ( sw->p->filename == NULL ) {
+ return saveas_sig(NULL, NULL, sw);
+ }
+
+ save_presentation(sw->p, sw->p->filename);
+}
+
+
+static void open_slidesorter_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ SlideWindow *sw = vp;
+ open_slidesorter(sw->p);
+}
+
+
+static void delete_frame_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ SlideWindow *sw = vp;
+#if 0
+ int i;
+
+ delete_subframe(sw->cur_slide, sw->p->selection);
+ p->n_selection = 0;
+
+ rerender_slide(p);
+ redraw_editor(p);
+#endif
+/* FIXME: implement */
+}
+
+
+static void add_slide_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ SlideWindow *sw = vp;
+ struct slide *new;
+ int cur_slide_number;
+
+ cur_slide_number = slide_number(sw->p, sw->cur_slide);
+
+ new = add_slide(sw->p, cur_slide_number+1);
+ new->scblocks = sc_block_insert_after(sw->cur_slide->scblocks,
+ "slide", NULL, NULL);
+
+ change_edit_slide(sw, new);
+
+}
+
+
+static void start_slideshow_sig(GSimpleAction *action, GVariant *parameter, gpointer vp)
+{
+ SlideWindow *sw = vp;
+ sw->show = try_start_slideshow(sw, sw->p);
+}
+
+
+static gint export_pdf_response_sig(GtkWidget *d, gint response,
+ SlideWindow *sw)
+{
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ if ( export_pdf(sw->p, filename) ) {
+ //show_error(sw, "Failed to export as PDF");
+ }
+
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(d);
+
+ return 0;
+}
+
+
+static void exportpdf_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ GtkWidget *d;
+
+ d = gtk_file_chooser_dialog_new("Export PDF",
+ GTK_WINDOW(sw->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
+ TRUE);
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(export_pdf_response_sig), sw);
+
+ gtk_widget_show_all(d);
+}
+
+
+void slidewindow_slideshow_ended(SlideWindow *sw)
+{
+ sw->show = NULL;
+}
+
+
+void slidewindow_notes_closed(SlideWindow *sw)
+{
+ sw->notes = NULL;
+}
+
+
+/* Change the editor's slide to "np" */
+void change_edit_slide(SlideWindow *sw, struct slide *np)
+{
+ sw->cur_slide = np;
+
+ update_toolbar(sw);
+
+ sc_editor_set_slidenum(sw->sceditor, slide_number(sw->p, np));
+ sc_editor_set_scblock(sw->sceditor, np->scblocks);
+
+ if ( sw->notes != NULL ) notes_set_slide(sw->notes, np);
+
+ if ( slideshow_linked(sw->show) ) {
+ change_proj_slide(sw->show, np);
+ } /* else leave the slideshow alone */
+}
+
+
+void change_slide_first(SlideWindow *sw)
+{
+ change_edit_slide(sw, sw->p->slides[0]);
+}
+
+
+void change_slide_backwards(SlideWindow *sw)
+{
+ int cur_slide_number;
+
+ cur_slide_number = slide_number(sw->p, sw->cur_slide);
+ if ( cur_slide_number == 0 ) return;
+
+ change_edit_slide(sw, sw->p->slides[cur_slide_number-1]);
+}
+
+
+void change_slide_forwards(SlideWindow *sw)
+{
+ int cur_slide_number;
+
+ cur_slide_number = slide_number(sw->p, sw->cur_slide);
+ if ( cur_slide_number == sw->p->num_slides-1 ) return;
+
+ change_edit_slide(sw, sw->p->slides[cur_slide_number+1]);
+}
+
+
+void change_slide_last(SlideWindow *sw)
+{
+ change_edit_slide(sw, sw->p->slides[sw->p->num_slides-1]);
+}
+
+
+static void first_slide_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ change_slide_first(sw);
+}
+
+
+static void prev_slide_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ change_slide_backwards(sw);
+}
+
+
+static void next_slide_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ change_slide_forwards(sw);
+}
+
+
+static void last_slide_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ change_slide_last(sw);
+}
+
+
+static void open_notes_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ sw->notes = open_notes(sw, sw->cur_slide);
+}
+
+
+static void open_clock_sig(GSimpleAction *action, GVariant *parameter,
+ gpointer vp)
+{
+ SlideWindow *sw = vp;
+ open_clock(sw->p);
+}
+
+
+static void slidewindow_set_background(SlideWindow *sw)
+{
+ if ( (sw->show != NULL) && !slideshow_linked(sw->show) ) {
+ sc_editor_set_background(sw->sceditor, 1.0, 0.3, 0.2);
+ } else {
+ sc_editor_set_background(sw->sceditor, 0.9, 0.9, 0.9);
+ }
+}
+
+
+void slidewindow_redraw(SlideWindow *sw)
+{
+ slidewindow_set_background(sw);
+ sc_editor_redraw(sw->sceditor);
+}
+
+
+struct slide *slidewindow_get_slide(SlideWindow *sw)
+{
+ return sw->cur_slide;
+}
+
+
+void update_titlebar(struct presentation *p)
+{
+ get_titlebar_string(p);
+
+ if ( p->slidewindow != NULL ) {
+
+ char *title;
+
+ title = malloc(strlen(p->titlebar)+14);
+ sprintf(title, "%s - Colloquium", p->titlebar);
+ gtk_window_set_title(GTK_WINDOW(p->slidewindow->window), title);
+ free(title);
+
+ }
+
+}
+
+
+static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event,
+ SlideWindow *sw)
+{
+ switch ( event->keyval ) {
+
+ case GDK_KEY_Page_Up :
+ change_slide_backwards(sw);
+ break;
+
+ case GDK_KEY_Page_Down :
+ change_slide_forwards(sw);
+ break;
+
+ case GDK_KEY_B :
+ case GDK_KEY_b :
+ if ( sw->show != NULL ) {
+ toggle_slideshow_link(sw->show);
+ }
+ }
+
+ return FALSE;
+}
+
+
+GActionEntry sw_entries[] = {
+
+ { "save", save_sig, NULL, NULL, NULL },
+ { "saveas", saveas_sig, NULL, NULL, NULL },
+ { "exportpdf", exportpdf_sig, NULL, NULL, NULL },
+ { "sorter", open_slidesorter_sig, NULL, NULL, NULL },
+ { "deleteframe", delete_frame_sig, NULL, NULL, NULL },
+ { "slide", add_slide_sig, NULL, NULL, NULL },
+ { "startslideshow", start_slideshow_sig, NULL, NULL, NULL },
+ { "notes", open_notes_sig, NULL, NULL, NULL },
+ { "clock", open_clock_sig, NULL, NULL, NULL },
+ { "first", first_slide_sig, NULL, NULL, NULL },
+ { "prev", prev_slide_sig, NULL, NULL, NULL },
+ { "next", next_slide_sig, NULL, NULL, NULL },
+ { "last", last_slide_sig, NULL, NULL, NULL },
+};
+
+
+SlideWindow *slide_window_open(struct presentation *p, GApplication *app)
+{
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *scroll;
+ GtkWidget *toolbar;
+ GtkToolItem *button;
+ SlideWindow *sw;
+
+ if ( p->slidewindow != NULL ) {
+ fprintf(stderr, "Slide window is already open!\n");
+ return p->slidewindow;
+ }
+
+ sw = calloc(1, sizeof(SlideWindow));
+ if ( sw == NULL ) return NULL;
+
+ window = gtk_application_window_new(GTK_APPLICATION(app));
+ g_action_map_add_action_entries(G_ACTION_MAP(window), sw_entries,
+ G_N_ELEMENTS(sw_entries), sw);
+ sw->window = window;
+ sw->p = p;
+ sw->cur_slide = p->slides[0];
+ sw->show = NULL;
+
+ update_titlebar(p);
+
+// g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(close_sig), p);
+
+ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ toolbar = gtk_toolbar_new();
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), FALSE, FALSE, 0);
+
+ /* Fullscreen */
+ button = gtk_tool_button_new_from_stock(GTK_STOCK_FULLSCREEN);
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(button),
+ "win.startslideshow");
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
+
+ button = gtk_separator_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
+
+ /* Add slide */
+ button = gtk_tool_button_new_from_stock(GTK_STOCK_ADD);
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(button),
+ "win.slide");
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
+
+ button = gtk_separator_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
+
+ /* Change slide */
+ sw->bfirst = gtk_tool_button_new_from_stock(GTK_STOCK_GOTO_FIRST);
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(sw->bfirst));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(sw->bfirst),
+ "win.first");
+ sw->bprev = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(sw->bprev));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(sw->bprev),
+ "win.prev");
+ sw->bnext = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(sw->bnext));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(sw->bnext),
+ "win.next");
+ sw->blast = gtk_tool_button_new_from_stock(GTK_STOCK_GOTO_LAST);
+ gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(sw->blast));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(sw->blast),
+ "win.last");
+ update_toolbar(sw);
+
+ sw->sceditor = sc_editor_new(sw->cur_slide->scblocks, p->stylesheet);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll),
+ GTK_WIDGET(sw->sceditor));
+ gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(sw->sceditor));
+
+ /* Size of SCEditor surface in pixels */
+ g_signal_connect(G_OBJECT(sw->sceditor), "key-press-event",
+ G_CALLBACK(key_press_sig), sw);
+
+ /* FIXME: Somewhat arbitrary. Should come from slide itself */
+ sc_editor_set_size(sw->sceditor, 1024, 768);
+ sc_editor_set_logical_size(sw->sceditor, 1024.0, 768.0);
+
+ gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
+
+ /* Default size */
+ gtk_window_set_default_size(GTK_WINDOW(sw->window), 1024+100, 768+150);
+ gtk_window_set_resizable(GTK_WINDOW(sw->window), TRUE);
+
+ /* Initial background colour */
+ slidewindow_set_background(sw);
+
+ gtk_widget_show_all(window);
+
+ return sw;
+}
diff --git a/src/slide_window.h b/src/slide_window.h
new file mode 100644
index 0000000..72a2f24
--- /dev/null
+++ b/src/slide_window.h
@@ -0,0 +1,46 @@
+/*
+ * slide_window.h
+ *
+ * Copyright © 2013-2014 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 SLIDEWINDOW_H
+#define SLIDEWINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct _slidewindow SlideWindow;
+
+extern SlideWindow *slide_window_open(struct presentation *p, GApplication *app);
+extern void change_edit_slide(SlideWindow *sw, struct slide *np);
+extern void update_titlebar(struct presentation *p);
+
+extern void change_slide_first(SlideWindow *sw);
+extern void change_slide_backwards(SlideWindow *sw);
+extern void change_slide_forwards(SlideWindow *sw);
+extern void change_slide_last(SlideWindow *sw);
+
+extern struct slide *slidewindow_get_slide(SlideWindow *sw);
+extern void slidewindow_redraw(SlideWindow *sw);
+extern void slidewindow_slideshow_ended(SlideWindow *sw);
+extern void slidewindow_notes_closed(SlideWindow *sw);
+
+#endif /* SLIDEWINDOW_H */
diff --git a/src/slideshow.c b/src/slideshow.c
index 66e4994..4755ed6 100644
--- a/src/slideshow.c
+++ b/src/slideshow.c
@@ -1,7 +1,7 @@
/*
* slideshow.c
*
- * Copyright © 2013 Thomas White <taw@bitwiz.org.uk>
+ * Copyright © 2013-2014 Thomas White <taw@bitwiz.org.uk>
*
* This file is part of Colloquium.
*
@@ -32,33 +32,67 @@
#include <gdk/gdkkeysyms.h>
#include "presentation.h"
-#include "mainwindow.h"
+#include "slide_window.h"
#include "render.h"
#include "pr_clock.h"
#include "inhibit_screensaver.h"
+#include "frame.h"
+
+struct _slideshow
+{
+ struct presentation *p;
+ SlideWindow *slide_window; /* Slide window controlling us */
+ struct slide *cur_slide;
+ GtkWidget *window;
+ GtkWidget *drawingarea;
+ GdkCursor *blank_cursor;
+ int blank;
+ char geom[256];
+ int slide_width;
+ int slide_height;
+ struct inhibit_sys *inhibit;
+ int linked;
+ cairo_surface_t *surface;
+ struct frame top;
+};
/* Force a redraw of the slideshow */
-void redraw_slideshow(struct presentation *p)
+void redraw_slideshow(SlideShow *ss)
{
gint w, h;
- w = gtk_widget_get_allocated_width(GTK_WIDGET(p->ss_drawingarea));
- h = gtk_widget_get_allocated_height(GTK_WIDGET(p->ss_drawingarea));
+ 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(p->ss_drawingarea, 0, 0, w, h);
+ gtk_widget_queue_draw_area(ss->drawingarea, 0, 0, w, h);
}
-static gint ss_destroy_sig(GtkWidget *widget, struct presentation *p)
+void slideshow_rerender(SlideShow *ss)
{
- p->slideshow = NULL;
- g_object_unref(p->blank_cursor);
+ int n;
+
+ n = slide_number(ss->p, ss->cur_slide);
+ ss->surface = render_sc(ss->cur_slide->scblocks,
+ ss->slide_width, ss->slide_height,
+ ss->p->slide_width, ss->p->slide_height,
+ ss->p->stylesheet,
+ ss->p->is, ISZ_SLIDESHOW, n);
+}
+
+
+static gint ss_destroy_sig(GtkWidget *widget, SlideShow *ss)
+{
+ g_object_unref(ss->blank_cursor);
+ slidewindow_slideshow_ended(ss->slide_window);
+ slidewindow_redraw(ss->slide_window);
+ free(ss);
return FALSE;
}
-static gboolean ss_draw_sig(GtkWidget *da, cairo_t *cr, struct presentation *p)
+static gboolean ss_draw_sig(GtkWidget *da, cairo_t *cr, SlideShow *ss)
{
double xoff, yoff;
double width, height;
@@ -71,22 +105,21 @@ static gboolean ss_draw_sig(GtkWidget *da, cairo_t *cr, struct presentation *p)
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_fill(cr);
- if ( !p->ss_blank ) {
+ if ( !ss->blank ) {
int h;
/* FIXME: Assumes that monitor and slide sizes are such that
* letterboxing at sides. This needn't be the case. */
- h = p->proj_slide_width * p->slide_height / p->slide_width;
+ h = ss->slide_width * ss->p->slide_height / ss->p->slide_width;
/* Get the overall size */
- xoff = (width - p->proj_slide_width)/2.0;
+ xoff = (width - ss->slide_width)/2.0;
yoff = (height - h)/2.0;
/* Draw the slide from the cache */
- cairo_rectangle(cr, xoff, yoff, p->proj_slide_width, h);
- cairo_set_source_surface(cr, p->cur_proj_slide->rendered_proj,
- xoff, yoff);
+ cairo_rectangle(cr, xoff, yoff, ss->slide_width, h);
+ cairo_set_source_surface(cr, ss->surface, xoff, yoff);
cairo_fill(cr);
}
@@ -95,101 +128,85 @@ static gboolean ss_draw_sig(GtkWidget *da, cairo_t *cr, struct presentation *p)
}
-void change_proj_slide(struct presentation *p, struct slide *np)
+void change_proj_slide(SlideShow *ss, struct slide *np)
{
- /* If this slide is not being shown on the editor, we can free the
- * buffers */
- if ( p->cur_proj_slide != p->cur_edit_slide ) {
- free_render_buffers_except_thumb(p->cur_proj_slide);
- }
+ ss->cur_slide = np;
- p->cur_proj_slide = np;
+ notify_clock_slide_changed(ss->p, np);
- notify_clock_slide_changed(p, np);
-
- /* The slide is already rendered, because the editor always gets there
- * first, so we only need to do this: */
- redraw_slideshow(p);
+ slideshow_rerender(ss);
+ redraw_slideshow(ss);
}
-static gint prev_slide_sig(GtkWidget *widget, struct presentation *p)
+static gint prev_slide_sig(GtkWidget *widget, SlideShow *ss)
{
- int cur_slide_number;
- cur_slide_number = slide_number(p, p->cur_edit_slide);
- if ( cur_slide_number == 0 ) return FALSE;
- change_edit_slide(p, p->slides[cur_slide_number-1]);
+ change_slide_backwards(ss->slide_window);
return FALSE;
}
-static gint next_slide_sig(GtkWidget *widget, struct presentation *p)
+static gint next_slide_sig(GtkWidget *widget, SlideShow *ss)
{
- int cur_slide_number;
- cur_slide_number = slide_number(p, p->cur_edit_slide);
- if ( cur_slide_number == p->num_slides-1 ) return FALSE;
- change_edit_slide(p, p->slides[cur_slide_number+1]);
+ change_slide_forwards(ss->slide_window);
return FALSE;
}
-void end_slideshow(struct presentation *p)
+void end_slideshow(SlideShow *ss)
{
- if ( p->inhibit != NULL ) do_inhibit(p->inhibit, 0);
- gtk_widget_destroy(p->ss_drawingarea);
- gtk_widget_destroy(p->slideshow);
- p->slideshow = NULL;
- p->cur_proj_slide = NULL;
- redraw_editor(p);
+ if ( ss->inhibit != NULL ) do_inhibit(ss->inhibit, 0);
+ gtk_widget_destroy(ss->drawingarea);
+ gtk_widget_destroy(ss->window);
}
-void toggle_slideshow_link(struct presentation *p)
+void toggle_slideshow_link(SlideShow *ss)
{
- p->slideshow_linked = 1 - p->slideshow_linked;
- if ( p->slideshow_linked ) {
- change_proj_slide(p, p->cur_edit_slide);
+ ss->linked = 1 - ss->linked;
+ if ( ss->linked ) {
+ change_proj_slide(ss, slidewindow_get_slide(ss->slide_window));
}
- redraw_editor(p);
+ slidewindow_redraw(ss->slide_window);
}
-void check_toggle_blank(struct presentation *p)
+int slideshow_linked(SlideShow *ss)
{
- if ( p->slideshow != NULL ) {
- //if ( p->prefs->b_splits ) {
- toggle_slideshow_link(p);
- //} else {
- // p->ss_blank = 1-p->ss_blank;
- // gdk_window_invalidate_rect(p->ss_drawingarea->window,
- // NULL, FALSE);
- //} FIXME!
- }
+ if ( ss == NULL ) return 0;
+ return ss->linked;
+}
+
+
+void check_toggle_blank(SlideShow *ss)
+{
+ toggle_slideshow_link(ss);
}
static gboolean ss_key_press_sig(GtkWidget *da, GdkEventKey *event,
- struct presentation *p)
+ SlideShow *ss)
{
- switch ( event->keyval ) {
+ switch ( event->keyval )
+ {
- case GDK_KEY_B :
- case GDK_KEY_b :
- check_toggle_blank(p);
+ case GDK_KEY_B :
+ case GDK_KEY_b :
+ check_toggle_blank(ss);
break;
- case GDK_KEY_Page_Up :
- case GDK_KEY_Up :
- prev_slide_sig(NULL, p);
+ case GDK_KEY_Page_Up :
+ case GDK_KEY_Up :
+ prev_slide_sig(NULL, ss);
break;
- case GDK_KEY_Page_Down :
- case GDK_KEY_Down :
- next_slide_sig(NULL, p);
+ case GDK_KEY_Page_Down :
+ case GDK_KEY_Down :
+ next_slide_sig(NULL, ss);
break;
- case GDK_KEY_Escape :
- end_slideshow(p);
+ case GDK_KEY_Escape :
+ end_slideshow(ss);
break;
}
@@ -198,55 +215,89 @@ static gboolean ss_key_press_sig(GtkWidget *da, GdkEventKey *event,
}
-static gboolean ss_realize_sig(GtkWidget *w, struct presentation *p)
+static gboolean ss_realize_sig(GtkWidget *w, SlideShow *ss)
{
GdkWindow *win;
win = gtk_widget_get_window(w);
- p->blank_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
- gdk_window_set_cursor(GDK_WINDOW(win), p->blank_cursor);
+ ss->blank_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+ gdk_window_set_cursor(GDK_WINDOW(win), ss->blank_cursor);
- gtk_window_parse_geometry(GTK_WINDOW(w), p->ss_geom);
+ gtk_window_parse_geometry(GTK_WINDOW(w), ss->geom);
+ slideshow_rerender(ss);
return FALSE;
}
-void try_start_slideshow(struct presentation *p)
+struct slide *slideshow_slide(SlideShow *ss)
+{
+ if ( ss == NULL ) return NULL;
+ return ss->cur_slide;
+}
+
+
+SlideShow *try_start_slideshow(SlideWindow *sw, struct presentation *p)
{
- GtkWidget *n;
GdkScreen *screen;
int n_monitors;
int i;
-
- /* Presentation already running? */
- if ( p->slideshow != NULL ) return;
-
- p->ss_blank = 0;
-
- if ( p->inhibit == NULL ) {
- p->inhibit = inhibit_prepare();
+ SlideShow *ss;
+ double slide_width = 1024.0; /* Logical slide size */
+ double slide_height = 768.0; /* FIXME: Should come from slide */
+ ss = calloc(1, sizeof(SlideShow));
+ if ( ss == NULL ) return NULL;
+
+ ss->slide_window = sw;
+ ss->blank = 0;
+ ss->p = p;
+ ss->cur_slide = slidewindow_get_slide(sw);
+
+ if ( ss->inhibit == NULL ) {
+ ss->inhibit = inhibit_prepare();
}
- n = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- p->ss_drawingarea = gtk_drawing_area_new();
- gtk_container_add(GTK_CONTAINER(n), p->ss_drawingarea);
-
- gtk_widget_set_can_focus(GTK_WIDGET(p->ss_drawingarea), TRUE);
- gtk_widget_add_events(GTK_WIDGET(p->ss_drawingarea),
+ ss->top.children = NULL;
+ ss->top.num_children = 0;
+ ss->top.max_children = 0;
+ ss->top.lines = NULL;
+ ss->top.n_lines = 0;
+ ss->top.max_lines = 0;
+ ss->top.pad_l = 0;
+ ss->top.pad_r = 0;
+ ss->top.pad_t = 0;
+ ss->top.pad_b = 0;
+ ss->top.x = 0.0;
+ ss->top.y = 0.0;
+ ss->top.w = slide_width;
+ ss->top.h = slide_height;
+ ss->top.grad = GRAD_NONE;
+ ss->top.bgcol[0] = 1.0;
+ ss->top.bgcol[1] = 1.0;
+ ss->top.bgcol[2] = 1.0;
+ ss->top.bgcol[3] = 1.0;
+
+ ss->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ ss->drawingarea = gtk_drawing_area_new();
+ gtk_container_add(GTK_CONTAINER(ss->window), 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(p->ss_drawingarea), "key-press-event",
- G_CALLBACK(ss_key_press_sig), p);
- g_signal_connect(G_OBJECT(n), "destroy", G_CALLBACK(ss_destroy_sig), p);
- g_signal_connect(G_OBJECT(n), "realize", G_CALLBACK(ss_realize_sig), p);
+ g_signal_connect(G_OBJECT(ss->drawingarea), "key-press-event",
+ G_CALLBACK(ss_key_press_sig), ss);
+ g_signal_connect(G_OBJECT(ss->window), "destroy",
+ G_CALLBACK(ss_destroy_sig), ss);
+ g_signal_connect(G_OBJECT(ss->window), "realize",
+ G_CALLBACK(ss_realize_sig), ss);
- g_signal_connect(G_OBJECT(p->ss_drawingarea), "draw",
- G_CALLBACK(ss_draw_sig), p);
+ g_signal_connect(G_OBJECT(ss->drawingarea), "draw",
+ G_CALLBACK(ss_draw_sig), ss);
- gtk_widget_grab_focus(GTK_WIDGET(p->ss_drawingarea));
+ gtk_widget_grab_focus(GTK_WIDGET(ss->drawingarea));
screen = gdk_screen_get_default();
n_monitors = gdk_screen_get_n_monitors(screen);
@@ -256,27 +307,24 @@ void try_start_slideshow(struct presentation *p)
int w;
gdk_screen_get_monitor_geometry(screen, i, &rect);
- snprintf(p->ss_geom, 255, "%ix%i+%i+%i",
+ snprintf(ss->geom, 255, "%ix%i+%i+%i",
rect.width, rect.height, rect.x, rect.y);
- w = rect.height * p->slide_width/p->slide_height;
+ w = rect.height * slide_width/slide_height;
if ( w > rect.width ) w = rect.width;
- p->proj_slide_width = w;
+ ss->slide_width = w;
+ ss->slide_height = rect.height;
} /* FIXME: Sensible (configurable) choice of monitor */
- rerender_slide(p);
+ ss->linked = 1;
+ gtk_window_fullscreen(GTK_WINDOW(ss->window));
+ gtk_widget_show_all(GTK_WIDGET(ss->window));
- p->slideshow = n;
- p->slideshow_linked = 1;
- gtk_window_fullscreen(GTK_WINDOW(n));
- gtk_widget_show_all(GTK_WIDGET(n));
+ if ( ss->inhibit != NULL ) do_inhibit(ss->inhibit, 1);
- if ( p->inhibit != NULL ) do_inhibit(p->inhibit, 1);
+ //notify_clock_slide_changed(p, ss->cur_slide); FIXME
- //if ( p->prefs->open_notes ) open_notes(p); FIXME!
-
- p->cur_proj_slide = p->cur_edit_slide;
-
- notify_clock_slide_changed(p, p->cur_proj_slide);
+ return ss;
}
+
diff --git a/src/slideshow.h b/src/slideshow.h
index 66f3560..16bd6e0 100644
--- a/src/slideshow.h
+++ b/src/slideshow.h
@@ -1,7 +1,7 @@
/*
* slideshow.h
*
- * Copyright © 2013 Thomas White <taw@bitwiz.org.uk>
+ * Copyright © 2013-2014 Thomas White <taw@bitwiz.org.uk>
*
* This file is part of Colloquium.
*
@@ -27,16 +27,22 @@
#include <config.h>
#endif
+#include "slide_window.h"
-extern void try_start_slideshow(struct presentation *p);
+/* Opaque data structure representing a slideshow */
+typedef struct _slideshow SlideShow;
-extern void change_proj_slide(struct presentation *p, struct slide *np);
+extern SlideShow *try_start_slideshow(SlideWindow *sw, struct presentation *p);
+extern void end_slideshow(SlideShow *ss);
-extern void toggle_slideshow_link(struct presentation *p);
-extern void check_toggle_blank(struct presentation *p);
+extern void change_proj_slide(SlideShow *ss, struct slide *np);
+extern struct slide *slideshow_slide(SlideShow *ss);
-extern void redraw_slideshow(struct presentation *p);
+extern void toggle_slideshow_link(SlideShow *ss);
+extern int slideshow_linked(SlideShow *ss);
+extern void check_toggle_blank(SlideShow *ss);
-extern void end_slideshow(struct presentation *p);
+extern void redraw_slideshow(SlideShow *ss);
+extern void slideshow_rerender(SlideShow *ss);
#endif /* SLIDESHOW_H */
diff --git a/src/wrap.c b/src/wrap.c
index ee2a56a..c0f3b9d 100644
--- a/src/wrap.c
+++ b/src/wrap.c
@@ -167,152 +167,6 @@ void get_cursor_pos(struct wrap_box *box, int pos,
}
-void move_cursor_back(struct presentation *p)
-{
- int retreat = 0;
- signed int cp, cb, cl;
- struct wrap_line *line;
- struct wrap_box *box;
-
- cp = p->cursor_pos;
- cb = p->cursor_box;
- cl = p->cursor_line;
-
- line = &p->cursor_frame->lines[p->cursor_line];
- box = &line->boxes[p->cursor_box];
- if ( box->type == WRAP_BOX_PANGO ) {
-
- if ( cp == 0 ) {
- retreat = 1;
- } else {
- cp--;
- }
-
- } else {
- cp--;
- if ( cp < 0 ) retreat = 1;
- }
-
- if ( retreat ) {
-
- do {
-
- cb--;
-
- if ( cb < 0 ) {
- cl--;
- if ( cl < 0 ) return;
- p->cursor_line = cl;
- line = &p->cursor_frame->lines[cl];
- cb = line->n_boxes - 1;
- }
-
- } while ( !line->boxes[cb].editable );
-
- p->cursor_box = cb;
- box = &line->boxes[cb];
- if ( box->type == WRAP_BOX_PANGO ) {
- cp = box->len_chars;
- if ( box->space == WRAP_SPACE_NONE ) {
- cp--;
- }
- } else {
- cp = 1;
- }
-
- }
- p->cursor_pos = cp;
-}
-
-
-void cur_box_diag(struct presentation *p)
-{
- int sln, sbx, sps;
- struct frame *fr;
-
- fr = p->cursor_frame;
- sln = p->cursor_line;
- sbx = p->cursor_box;
- sps = p->cursor_pos;
-
- struct wrap_box *sbox = &p->cursor_frame->lines[sln].boxes[sbx];
-
- printf("line/box/pos: [%i of %i]/[%i of %i]/[%i of %i]\n",
- sln, fr->n_lines,
- sbx, p->cursor_frame->lines[sln].n_boxes,
- sps, sbox->len_chars);
- printf("box type is %i, space type is %i\n", sbox->type, sbox->space);
- if ( sbox->type == WRAP_BOX_NOTHING ) {
- printf("Warning: in a nothing box!\n");
- }
-}
-
-
-void advance_cursor(struct presentation *p)
-{
- int advance = 0;
- signed int cp, cb, cl;
- struct wrap_line *line = &p->cursor_frame->lines[p->cursor_line];
- struct wrap_box *box = &line->boxes[p->cursor_box];
-
- cp = p->cursor_pos;
- cb = p->cursor_box;
- cl = p->cursor_line;
-
- switch ( box->type ) {
-
- case WRAP_BOX_PANGO:
- if ( cp+1 > box->len_chars ) {
- advance = 1;
- } else {
- cp++;
- }
- break;
-
- case WRAP_BOX_NOTHING:
- case WRAP_BOX_SENTINEL:
- advance = 1;
- break;
-
- case WRAP_BOX_IMAGE:
- cp++;
- if ( cp > 1 ) advance = 1;
- break;
-
- }
-
- if ( advance ) {
-
- do {
-
- cb++;
- cp = 0;
-
- if ( box->space == WRAP_SPACE_NONE ) {
- cp = 1;
- }
-
- if ( cb >= line->n_boxes ) {
- cl++;
- if ( cl >= p->cursor_frame->n_lines ) {
- /* Give up - could not move */
- return;
- }
- line = &p->cursor_frame->lines[cl];
- cb = 0;
- cp = 0;
- }
-
- } while ( !line->boxes[cb].editable );
-
- p->cursor_line = cl;
- p->cursor_box = cb;
-
- }
- p->cursor_pos = cp;
-}
-
-
static int find_cursor_line(struct frame *fr, double yposd, int *end)
{
int i;
diff --git a/src/wrap.h b/src/wrap.h
index 441ec62..2d229ba 100644
--- a/src/wrap.h
+++ b/src/wrap.h
@@ -105,10 +105,6 @@ extern int wrap_contents(struct frame *fr);
extern void get_cursor_pos(struct wrap_box *box, int pos,
double *xposd, double *yposd, double *line_height);
-extern void move_cursor_back(struct presentation *p);
-extern void cur_box_diag(struct presentation *p);
-extern void advance_cursor(struct presentation *p);
-
extern void find_cursor(struct frame *fr, double xposd, double yposd,
int *line, int *box, int *pos);
diff --git a/tests/render_test.c b/tests/render_test.c
index 0e7c3c9..62bab25 100644
--- a/tests/render_test.c
+++ b/tests/render_test.c
@@ -49,21 +49,18 @@ static gint mw_destroy(GtkWidget *w, void *p)
static gboolean draw_sig(GtkWidget *da, cairo_t *cr, gpointer data)
{
gint w, h;
- struct slide *s = data;
+ cairo_surface_t *surface;
+ SCBlock *scblocks = data;
w = gtk_widget_get_allocated_width(da);
h = gtk_widget_get_allocated_height(da);
- /* Overall background */
+ surface = render_sc(scblocks, w, h, w, h, NULL, NULL,
+ ISZ_EDITOR, 1);
cairo_rectangle(cr, 0.0, 0.0, w, h);
- cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
- cairo_fill(cr);
-
- if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit);
- s->rendered_edit = render_slide(s, w, w, h, NULL, ISZ_EDITOR, 1);
- cairo_rectangle(cr, 0.0, 0.0, w, h);
- cairo_set_source_surface(cr, s->rendered_edit, 0.0, 0.0);
+ cairo_set_source_surface(cr, surface, 0.0, 0.0);
cairo_fill(cr);
+ cairo_surface_destroy(surface);
return FALSE;
}
@@ -73,35 +70,16 @@ int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *drawingarea;
- struct frame *fr;
- struct slide s;
- struct presentation p;
+ SCBlock *scblocks;
gtk_init(&argc, &argv);
- fr = frame_new();
- if ( fr == NULL ) return 1;
- fr->scblocks = sc_parse(sc);
- if ( fr->scblocks == NULL ) {
+ scblocks = sc_parse(sc);
+ if ( scblocks == NULL ) {
fprintf(stderr, "SC parse failed.\n");
return 1;
}
- fr->pad_l = 20.0;
- fr->pad_r = 20.0;
- fr->pad_t = 20.0;
- fr->pad_b = 20.0;
-
- s.top = fr;
- s.rendered_edit = NULL;
- s.rendered_proj = NULL;
- s.rendered_thumb = NULL;
- s.parent = &p;
- s.scblocks = fr->scblocks;
-
- p.stylesheet = NULL;
- p.scblocks = fr->scblocks;
-
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
drawingarea = gtk_drawing_area_new();
@@ -112,12 +90,10 @@ int main(int argc, char *argv[])
NULL);
g_signal_connect(G_OBJECT(drawingarea), "draw",
- G_CALLBACK(draw_sig), &s);
+ G_CALLBACK(draw_sig), scblocks);
gtk_widget_show_all(window);
gtk_main();
- free_render_buffers(&s);
-
return 0;
}
diff --git a/tests/render_test_sc1.c b/tests/render_test_sc1.c
index d8172cd..cf297e9 100644
--- a/tests/render_test_sc1.c
+++ b/tests/render_test_sc1.c
@@ -44,24 +44,22 @@ static gint mw_destroy(GtkWidget *w, void *p)
exit(0);
}
+
static gboolean draw_sig(GtkWidget *da, cairo_t *cr, gpointer data)
{
gint w, h;
- struct slide *s = data;
+ cairo_surface_t *surface;
+ SCBlock *scblocks = data;
w = gtk_widget_get_allocated_width(da);
h = gtk_widget_get_allocated_height(da);
- /* Overall background */
- cairo_rectangle(cr, 0.0, 0.0, w, h);
- cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
- cairo_fill(cr);
-
- if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit);
- s->rendered_edit = render_slide(s, w, w, h, NULL, ISZ_EDITOR, 1);
+ surface = render_sc(scblocks, w, h, w, h, NULL, NULL,
+ ISZ_EDITOR, 1);
cairo_rectangle(cr, 0.0, 0.0, w, h);
- cairo_set_source_surface(cr, s->rendered_edit, 0.0, 0.0);
+ cairo_set_source_surface(cr, surface, 0.0, 0.0);
cairo_fill(cr);
+ cairo_surface_destroy(surface);
return FALSE;
}
@@ -71,35 +69,15 @@ int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *drawingarea;
- struct frame *fr;
- struct slide s;
- struct presentation p;
+ SCBlock *scblocks;
gtk_init(&argc, &argv);
- fr = frame_new();
- if ( fr == NULL ) return 1;
- fr->scblocks = sc_parse(sc);
- if ( fr->scblocks == NULL ) {
+ scblocks = sc_parse(sc);
+ if ( scblocks == NULL ) {
fprintf(stderr, "SC parse failed.\n");
return 1;
}
-
- fr->pad_l = 20.0;
- fr->pad_r = 20.0;
- fr->pad_t = 20.0;
- fr->pad_b = 20.0;
-
- s.top = fr;
- s.rendered_edit = NULL;
- s.rendered_proj = NULL;
- s.rendered_thumb = NULL;
- s.parent = &p;
- s.scblocks = fr->scblocks;
-
- p.scblocks = fr->scblocks;
- p.stylesheet = NULL;
-
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
drawingarea = gtk_drawing_area_new();
@@ -110,7 +88,7 @@ int main(int argc, char *argv[])
NULL);
g_signal_connect(G_OBJECT(drawingarea), "draw",
- G_CALLBACK(draw_sig), &s);
+ G_CALLBACK(draw_sig), scblocks);
gtk_widget_show_all(window);
gtk_main();