Plug in stylesheets and load/save
authorThomas White <taw@bitwiz.org.uk>
Sat, 8 Sep 2012 09:07:54 +0000 (11:07 +0200)
committerThomas White <taw@bitwiz.org.uk>
Sat, 8 Sep 2012 09:07:54 +0000 (11:07 +0200)
Makefile.am
src/loadsave.c [new file with mode: 0644]
src/loadsave.h [new file with mode: 0644]
src/mainwindow.c
src/presentation.c
src/presentation.h
src/stylesheet.c [new file with mode: 0644]
src/stylesheet.h

index f565eb7..2111532 100644 (file)
@@ -10,12 +10,13 @@ AM_CPPFLAGS = -DDATADIR=\""$(datadir)"\" -I$(top_builddir)/lib \
 LDADD = $(top_builddir)/lib/libgnu.a @IGNORE_UNUSED_LIBRARIES_CFLAGS@
 
 src_colloquium_SOURCES = src/colloquium.c src/storycode.c src/render.c \
-                         src/layout.c src/mainwindow.c src/presentation.c
+                         src/layout.c src/mainwindow.c src/presentation.c \
+                         src/stylesheet.c src/loadsave.c
 
 INCLUDES = "-I$(top_srcdir)/data"
 
 EXTRA_DIST += src/layout.h src/presentation.h src/render.h src/storycode.h \
-              src/stylesheet.h
+              src/stylesheet.h src/loadsave.h
 
 colloquiumdir = $(datadir)/colloquium
 colloquium_DATA = data/colloquium.ui
diff --git a/src/loadsave.c b/src/loadsave.c
new file mode 100644 (file)
index 0000000..8200200
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * loadsave.c
+ *
+ * Colloquium - A tiny presentation program
+ *
+ * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "presentation.h"
+#include "stylesheet.h"
+#include "mainwindow.h"
+
+
+static int alloc_children(struct ds_node *node)
+{
+       struct ds_node **new;
+
+       new = realloc(node->children,
+                     node->max_children*sizeof(*node->children));
+       if ( new == NULL ) return 1;
+
+       node->children = new;
+       return 0;
+}
+
+
+static struct ds_node *new_ds_node(const char *key)
+{
+       struct ds_node *new;
+
+       new = malloc(sizeof(*new));
+       if ( new == NULL ) return NULL;
+
+       new->key = strdup(key);
+       if ( new->key == NULL ) {
+               free(new);
+               return NULL;
+       }
+
+       new->value = NULL;
+       new->n_children = 0;
+       new->max_children = 32;
+       new->children = NULL;
+
+       if ( alloc_children(new) ) {
+               free(new);
+               return NULL;
+       }
+
+       return new;
+}
+
+
+static struct ds_node *add_child(struct ds_node *node, const char *key)
+{
+       struct ds_node *new;
+
+       new = new_ds_node(key);
+       if ( new == NULL ) return NULL;
+
+       if ( node->n_children >= new->max_children ) {
+               new->max_children += 32;
+               if ( alloc_children(node) ) {
+                       free(new);
+                       return NULL;
+               }
+       }
+
+       node->children[node->n_children++] = new;
+
+       return new;
+}
+
+
+void show_tree(struct ds_node *root, const char *path)
+{
+       char newpath[1024];
+       int i;
+
+       snprintf(newpath, 1023, "%s%s/", path, root->key);
+
+       printf("%s\n", newpath);
+       for ( i=0; i<root->n_children; i++ ) {
+               printf("     %s => %s\n", root->children[i]->key,
+                                         root->children[i]->value);
+       }
+
+       for ( i=0; i<root->n_children; i++ ) {
+               if ( root->children[i]->n_children > 0 ) {
+                       printf("\n");
+                       show_tree(root->children[i], newpath);
+               }
+       }
+}
+
+
+struct ds_node *find_node(struct ds_node *root, const char *path, int cr)
+{
+       size_t start, len;
+       char element[1024];
+       struct ds_node *cur = root;
+
+       len = strlen(path);
+
+       start = 0;
+       while ( start < len ) {
+
+               size_t pos, i;
+               int child;
+               int found = 0;
+
+               pos = 0;
+               for ( i=start; i<len; i++ ) {
+
+                       if ( path[i] == '/' ) break;
+                       element[pos++] = path[i];
+
+               }
+               element[pos++] = '\0';
+               if ( element[0] == '\0' ) {
+                       goto out;
+               }
+               start = i+1;
+
+               for ( child=0; child<cur->n_children; child++ ) {
+
+                       const char *this_key = cur->children[child]->key;
+
+                       if ( strcmp(this_key, element) == 0 ) {
+                               cur = cur->children[child];
+                               found = 1;
+                               break;
+                       }
+
+               }
+
+               if ( !found ) {
+
+                       if ( cr ) {
+                               cur = add_child(cur, element);
+                               if ( cur == NULL ) {
+                                       return NULL;  /* Error */
+                               }
+                       } else {
+                               return NULL;
+                       }
+
+               }
+
+       }
+
+out:
+       return cur;
+}
+
+
+static void parse_line(struct ds_node *root, struct ds_node **cn,
+                       const char *line)
+{
+       size_t i;
+       size_t len, s_start;
+       size_t s_equals = 0;
+       size_t s_val = 0;
+       size_t s_openbracket = 0;
+       size_t s_closebracket = 0;
+       int h_start = 0;
+       int h_equals = 0;
+       int h_val = 0;
+       int h_openbracket = 0;
+       int h_closebracket = 0;
+       struct ds_node *cur_node = *cn;
+
+       len = strlen(line);
+
+       s_start = len;
+
+       for ( i=0; i<len; i++ ) {
+               if ( !h_start && !isspace(line[i]) ) {
+                       s_start = i;
+                       h_start = 1;
+               }
+               if ( !h_val && h_equals && !isspace(line[i]) ) {
+                       s_val = i;
+                       h_val = 1;
+               }
+               if ( !h_equals && (line[i] == '=') ) {
+                       s_equals = i;
+                       h_equals = 1;
+               }
+               if ( !h_openbracket && (line[i] == '[') ) {
+                       s_openbracket = i;
+                       h_openbracket = 1;
+               }
+               if ( h_openbracket && !h_closebracket
+                    && (line[i] == ']') )
+               {
+                       s_closebracket = i;
+                       h_closebracket = 1;
+               }
+       }
+
+       if ( (h_openbracket && !h_closebracket)
+         || (!h_openbracket && h_closebracket) )
+       {
+               fprintf(stderr, "Mismatched square brackets: %s", line);
+               return;
+       }
+
+       if ( !h_openbracket && !h_equals ) return;
+
+       if ( !h_openbracket && (!h_start || !h_val || !h_equals) ) {
+               fprintf(stderr, "Incomplete assignment: %s", line);
+               return;
+       }
+
+       if ( h_equals && (h_openbracket || h_closebracket) ) {
+               fprintf(stderr, "Brackets and equals: %s", line);
+               return;
+       }
+
+       if ( !h_openbracket ) {
+
+               size_t pos = 0;
+               char *key;
+               char *value;
+               struct ds_node *node;
+
+               key = malloc(len);
+               value = malloc(len);
+
+               for ( i=s_start; i<s_equals; i++ ) {
+                       if ( !isspace(line[i]) ) key[pos++] = line[i];
+               }
+               key[pos] = '\0';
+
+               pos = 0;
+               for ( i=s_val; i<len; i++ ) {
+                       if ( line[i] != '\n' ) value[pos++] = line[i];
+               }
+               value[pos] = '\0';
+
+               node = find_node(cur_node, key, 1);
+               node->value = strdup(value);
+
+               free(key);
+               free(value);
+
+       } else {
+
+               size_t pos = 0;
+               char *path;
+
+               path = malloc(len);
+
+               for ( i=s_openbracket+1; i<s_closebracket; i++ ) {
+                       if ( !isspace(line[i]) ) path[pos++] = line[i];
+               }
+               path[pos] = '\0';
+               cur_node = find_node(root, path, 1);
+
+               free(path);
+
+       }
+
+       *cn = cur_node;
+}
+
+
+static char *fgets_long(FILE *fh)
+{
+       char *line;
+       size_t la, l;
+
+       la = 1024;
+       line = malloc(la);
+       if ( line == NULL ) return NULL;
+
+       l = 0;
+       do {
+
+               int r;
+
+               r = fgetc(fh);
+               if ( r == EOF ) {
+                       free(line);
+                       return NULL;
+               }
+
+               if ( r == '\n' ) {
+                       line[l++] = '\0';
+                       return line;
+               }
+
+               line[l++] = r;
+
+               if ( l == la ) {
+
+                       char *ln;
+
+                       la += 1024;
+                       ln = realloc(line, la);
+                       if ( ln == NULL ) {
+                               free(line);
+                               return NULL;
+                       }
+
+                       line = ln;
+
+               }
+
+       } while ( 1 );
+}
+
+
+static int deserialize_file(FILE *fh, struct ds_node *root)
+{
+       char *line;
+       struct ds_node *cur_node = root;
+
+       line = NULL;
+       do {
+
+               line = fgets_long(fh);
+               if ( line == NULL ) {
+                       if ( ferror(fh) ) printf("Read error!\n");
+                       continue;
+               }
+
+               parse_line(root, &cur_node, line);
+
+       } while ( line != NULL );
+
+       return 0;
+}
+
+
+static void free_ds_tree(struct ds_node *root)
+{
+       int i;
+
+       for ( i=0; i<root->n_children; i++ ) {
+               if ( root->children[i]->n_children > 0 ) {
+                       free_ds_tree(root->children[i]);
+               }
+       }
+
+       free(root->key);
+       free(root->value);  /* Might free(NULL), but that's fine */
+       free(root);
+}
+
+
+char *escape_text(const char *a)
+{
+       char *b;
+       size_t l1, l, i;
+
+       l1 = strlen(a);
+
+       b = malloc(2*l1 + 1);
+       l = 0;
+
+       for ( i=0; i<l1; i++ ) {
+
+               char c = a[i];
+
+               /* Yes, this is horribly confusing */
+               if ( c == '\n' ) {
+                       b[l++] = '\\';  b[l++] = 'n';
+               } else if ( c == '\r' ) {
+                       b[l++] = '\\';  b[l++] = 'r';
+               } else if ( c == '\"' ) {
+                       b[l++] = '\\';  b[l++] = '\"';
+               } else if ( c == '\t' ) {
+                       b[l++] = '\\';  b[l++] = 't';
+               } else {
+                       b[l++] = c;
+               }
+
+       }
+       b[l++] = '\0';
+
+       return realloc(b, l);
+}
+
+
+char *unescape_text(const char *a)
+{
+       char *b;
+       size_t l1, l, i;
+       int escape;
+
+       l1 = strlen(a);
+
+       b = malloc(l1 + 1);
+       l = 0;
+       escape = 0;
+
+       for ( i=0; i<l1; i++ ) {
+
+               char c = a[i];
+
+               if ( escape ) {
+                       if ( c == 'r' ) b[l++] = '\r';
+                       if ( c == 'n' ) b[l++] = '\n';
+                       if ( c == '\"' ) b[l++] = '\"';
+                       if ( c == 't' ) b[l++] = '\t';
+                       escape = 0;
+                       continue;
+               }
+
+               if ( c == '\\' ) {
+                       escape = 1;
+                       continue;
+               }
+
+               b[l++] = c;
+
+       }
+       b[l++] = '\0';
+
+       return realloc(b, l);
+}
+
+
+
+int get_field_f(struct ds_node *root, const char *key, double *val)
+{
+       struct ds_node *node;
+       double v;
+       char *check;
+
+       node = find_node(root, key, 0);
+       if ( node == NULL ) {
+               fprintf(stderr, "Couldn't find field '%s'\n", key);
+               return 1;
+       }
+
+       v = strtod(node->value, &check);
+       if ( check == node->value ) {
+               fprintf(stderr, "Invalid value for '%s'\n", key);
+               return 1;
+       }
+
+       *val = v;
+
+       return 0;
+}
+
+
+int get_field_i(struct ds_node *root, const char *key, int *val)
+{
+       struct ds_node *node;
+       int v;
+       char *check;
+
+       node = find_node(root, key, 0);
+       if ( node == NULL ) {
+               fprintf(stderr, "Couldn't find field '%s'\n", key);
+               return 1;
+       }
+
+       v = strtol(node->value, &check, 0);
+       if ( check == node->value ) {
+               fprintf(stderr, "Invalid value for '%s'\n", key);
+               return 1;
+       }
+
+       *val = v;
+
+       return 0;
+}
+
+
+int get_field_s(struct ds_node *root, const char *key, char **val)
+{
+       struct ds_node *node;
+       char *v;
+       size_t i, len, s1, s2;
+       int hq;
+
+       node = find_node(root, key, 0);
+       if ( node == NULL ) {
+               *val = NULL;
+               return 1;
+       }
+
+       len = strlen(node->value);
+       hq = 0;
+       for ( i=0; i<len; i++ ) {
+               if ( node->value[i] == '"' ) {
+                       s1 = i;
+                       hq = 1;
+                       break;
+               }
+       }
+       if ( !hq ) {
+               fprintf(stderr, "No quotes in '%s'\n", node->value);
+               return 1;
+       }
+
+       for ( i=len-1; i>=0; i-- ) {
+               if ( node->value[i] == '"' ) {
+                       s2 = i;
+                       break;
+               }
+       }
+
+       if ( s1 == s2 ) {
+               fprintf(stderr, "Mismatched quotes in '%s'\n", node->value);
+               return 1;
+       }
+
+       v = malloc(s2-s1+1);
+       if ( v == NULL ) {
+               fprintf(stderr, "Failed to allocate space for '%s'\n", key);
+               return 1;
+       }
+
+       strncpy(v, node->value+s1+1, s2-s1-1);
+       v[s2-s1-1] = '\0';
+
+       *val = unescape_text(v);
+       free(v);
+
+       return 0;
+}
+
+
+static struct slide *tree_to_slide(struct presentation *p, struct ds_node *root)
+{
+       struct slide *s;
+
+       s = new_slide();
+       s->parent = p;
+
+       /* FIXME: Load stuff */
+
+       return s;
+}
+
+
+static int tree_to_slides(struct ds_node *root, struct presentation *p)
+{
+       int i;
+
+       for ( i=0; i<root->n_children; i++ ) {
+
+               struct slide *s;
+
+               s = tree_to_slide(p, root->children[i]);
+               if ( s != NULL ) {
+                       insert_slide(p, s, p->num_slides-1);
+               }
+
+       }
+
+       return 0;
+}
+
+
+int tree_to_presentation(struct ds_node *root, struct presentation *p)
+{
+       struct ds_node *node;
+       char *check;
+       int i;
+
+       p->cur_edit_slide = NULL;
+       p->cur_proj_slide = NULL;
+
+       node = find_node(root, "slide-properties/width", 0);
+       if ( node == NULL ) return 1;
+       p->slide_width = strtod(node->value, &check);
+       if ( check == node->value ) {
+               fprintf(stderr, "Invalid slide width\n");
+               return 1;
+       }
+
+       node = find_node(root, "slide-properties/height", 0);
+       if ( node == NULL ) return 1;
+       p->slide_height = strtod(node->value, &check);
+       if ( check == node->value ) {
+               fprintf(stderr, "Invalid slide height\n");
+               return 1;
+       }
+
+       node = find_node(root, "stylesheet", 0);
+       if ( node != NULL ) {
+               free_stylesheet(p->ss);
+               p->ss = tree_to_stylesheet(node);
+               if ( p->ss == NULL ) {
+                       fprintf(stderr, "Invalid style sheet\n");
+                       return 1;
+               }
+       }
+
+       for ( i=0; i<p->num_slides; i++ ) {
+               free_slide(p->slides[i]);
+               p->num_slides = 0;
+       }
+
+       node = find_node(root, "slides", 0);
+       if ( node != NULL ) {
+               tree_to_slides(node, p);
+               if ( p->num_slides == 0 ) {
+                       fprintf(stderr, "Failed to load any slides\n");
+                       p->cur_edit_slide = add_slide(p, 0);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+int load_presentation(struct presentation *p, const char *filename)
+{
+       FILE *fh;
+       struct ds_node *root;
+       int r;
+
+       assert(p->completely_empty);
+
+       fh = fopen(filename, "r");
+       if ( fh == NULL ) return 1;
+
+       root = new_ds_node("root");
+       if ( root == NULL ) return 1;
+
+       if ( deserialize_file(fh, root) ) {
+               fclose(fh);
+               return 1;
+       }
+
+       r = tree_to_presentation(root, p);
+       free_ds_tree(root);
+
+       fclose(fh);
+
+       if ( r ) {
+               p->cur_edit_slide = new_slide();
+               insert_slide(p, p->cur_edit_slide, 0);
+               p->completely_empty = 1;
+               return r;  /* Error */
+       }
+
+       assert(p->filename == NULL);
+       p->filename = strdup(filename);
+       update_titlebar(p);
+
+       p->cur_edit_slide = p->slides[0];
+
+       return 0;
+}
+
+
+static void rebuild_prefix(struct serializer *ser)
+{
+       int i;
+       size_t sz = 1;  /* Space for terminator */
+
+       for ( i=0; i<ser->stack_depth; i++ ) {
+               sz += strlen(ser->stack[i]) + 1;
+       }
+
+       free(ser->prefix);
+       ser->prefix = malloc(sz);
+       if ( ser->prefix == NULL ) return;  /* Probably bad! */
+
+       ser->prefix[0] = '\0';
+       for ( i=0; i<ser->stack_depth; i++ ) {
+               if ( i != 0 ) strcat(ser->prefix, "/");
+               strcat(ser->prefix, ser->stack[i]);
+       }
+}
+
+
+void serialize_start(struct serializer *ser, const char *id)
+{
+       ser->stack[ser->stack_depth++] = strdup(id);
+       rebuild_prefix(ser);
+       ser->empty_set = 1;
+}
+
+
+static void check_prefix_output(struct serializer *ser)
+{
+       if ( ser->empty_set ) {
+               ser->empty_set = 0;
+               if ( ser->prefix != NULL ) {
+                       fprintf(ser->fh, "\n");
+                       fprintf(ser->fh, "[%s]\n", ser->prefix);
+               }
+       }
+}
+
+
+void serialize_s(struct serializer *ser, const char *key, const char *val)
+{
+       char *n;
+
+       n = escape_text(val);
+       if ( n == NULL ) {
+               fprintf(stderr, "Failed to escape '%s'\n", val);
+               return;
+       }
+
+       check_prefix_output(ser);
+       fprintf(ser->fh, "%s = \"%s\"\n", key, n);
+
+       free(n);
+}
+
+
+void serialize_f(struct serializer *ser, const char *key, double val)
+{
+       check_prefix_output(ser);
+       fprintf(ser->fh, "%s = %.2f\n", key, val);
+}
+
+
+void serialize_b(struct serializer *ser, const char *key, int val)
+{
+       check_prefix_output(ser);
+       fprintf(ser->fh, "%s = %i\n", key, val);
+}
+
+
+void serialize_end(struct serializer *ser)
+{
+       free(ser->stack[--ser->stack_depth]);
+       rebuild_prefix(ser);
+       ser->empty_set = 1;
+}
+
+
+int save_presentation(struct presentation *p, const char *filename)
+{
+       FILE *fh;
+       int i;
+       struct serializer ser;
+       char *old_fn;
+
+       //grab_current_notes(p);
+
+       fh = fopen(filename, "w");
+       if ( fh == NULL ) return 1;
+
+       /* Set up the serializer */
+       ser.fh = fh;
+       ser.stack_depth = 0;
+       ser.prefix = NULL;
+
+       fprintf(fh, "# Colloquium presentation file\n");
+       serialize_f(&ser, "version", 0.1);
+
+       serialize_start(&ser, "slide-properties");
+       serialize_f(&ser, "width", p->slide_width);
+       serialize_f(&ser, "height", p->slide_height);
+       serialize_end(&ser);
+
+       serialize_start(&ser, "stylesheet");
+       write_stylesheet(p->ss, &ser);
+       serialize_end(&ser);
+
+       serialize_start(&ser, "slides");
+       for ( i=0; i<p->num_slides; i++ ) {
+
+               struct slide *s;
+               char s_id[32];
+
+               s = p->slides[i];
+
+               snprintf(s_id, 31, "%i", i);
+               serialize_start(&ser, s_id);
+
+               /* FIXME: Save stuff */
+
+               serialize_end(&ser);
+
+       }
+       serialize_end(&ser);
+
+       /* Slightly fiddly because someone might
+        * do save_presentation(p, p->filename) */
+       old_fn = p->filename;
+       p->filename = strdup(filename);
+       if ( old_fn != NULL ) free(old_fn);
+       update_titlebar(p);
+
+       fclose(fh);
+       return 0;
+}
diff --git a/src/loadsave.h b/src/loadsave.h
new file mode 100644 (file)
index 0000000..14fb6ff
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * loadsave.h
+ *
+ * Colloquium - A tiny presentation program
+ *
+ * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program 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 LOADSAVE_H
+#define LOADSAVE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Forward declaration */
+struct presentation;
+
+struct ds_node
+{
+       char *key;
+       char *value;
+       struct ds_node **children;
+       int n_children;
+       int max_children;
+};
+
+/* Would be opaque if I could be bothered to write the constructor */
+struct serializer
+{
+       FILE *fh;
+
+       char *stack[32];
+       int stack_depth;
+       char *prefix;
+       int empty_set;
+       int blank_written;
+};
+
+extern void show_tree(struct ds_node *root, const char *path);
+
+extern char *escape_text(const char *a);
+extern char *unescape_text(const char *a);
+
+extern void serialize_start(struct serializer *s, const char *id);
+extern void serialize_s(struct serializer *s, const char *key, const char *val);
+extern void serialize_f(struct serializer *s, const char *key, double val);
+extern void serialize_b(struct serializer *s, const char *key, int val);
+extern void serialize_end(struct serializer *s);
+
+extern int get_field_f(struct ds_node *root, const char *key, double *val);
+extern int get_field_i(struct ds_node *root, const char *key, int *val);
+extern int get_field_s(struct ds_node *root, const char *key, char **val);
+
+extern struct ds_node *find_node(struct ds_node *root, const char *path,
+                                 int cr);
+
+extern int load_presentation(struct presentation *p, const char *filename);
+extern int save_presentation(struct presentation *p, const char *filename);
+
+#endif /* LOADSAVE_H */
index a5601a5..65a94df 100644 (file)
@@ -94,8 +94,7 @@ static gint quit_sig(GtkWidget *widget, struct presentation *p)
 }
 
 
-/* FIXME (unused) */
-static UNUSED void show_error(struct presentation *p, const char *message)
+static void show_error(struct presentation *p, const char *message)
 {
        GtkWidget *window;
 
@@ -163,11 +162,11 @@ static gint open_response_sig(GtkWidget *d, gint response,
 
                if ( p->completely_empty ) {
 
-                       /* FIXME */
-                       //if ( load_presentation(p, filename) ) {
-                       //      show_error(p, "Failed to open presentation");
-                       //}
-                       //redraw_slide(p->cur_edit_slide);
+                       if ( load_presentation(p, filename) ) {
+                               show_error(p, "Failed to open presentation");
+                       }
+                       p->cur_edit_slide = p->slides[0];
+                       redraw_slide(p->cur_edit_slide);
                        update_toolbar(p);
 
                } else {
@@ -176,11 +175,11 @@ static gint open_response_sig(GtkWidget *d, gint response,
 
                        /* FIXME */
                        p = new_presentation();
-                       //if ( load_presentation(p, filename) ) {
-                       //      show_error(p, "Failed to open presentation");
-                       //} else {
+                       if ( load_presentation(p, filename) ) {
+                               show_error(p, "Failed to open presentation");
+                       } else {
                                open_mainwindow(p);
-                       //}
+                       }
 
                }
 
@@ -238,10 +237,9 @@ static gint saveas_response_sig(GtkWidget *d, gint response,
 
                filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
 
-               /* FIXME */
-               //if ( save_presentation(p, filename) ) {
-               //      show_error(p, "Failed to save presentation");
-               //}
+               if ( save_presentation(p, filename) ) {
+                       show_error(p, "Failed to save presentation");
+               }
 
                g_free(filename);
 
@@ -281,8 +279,7 @@ static gint save_sig(GtkWidget *widget, struct presentation *p)
                return saveas_sig(widget, p);
        }
 
-       /* FIXME */
-       //save_presentation(p, p->filename);
+       save_presentation(p, p->filename);
 
        return 0;
 }
@@ -432,9 +429,9 @@ void notify_slide_changed(struct presentation *p, struct slide *np)
        update_toolbar(p);
        redraw_slide(p->cur_edit_slide);
 
-       if ( p->notes != NULL ) {
-               //notify_notes_slide_changed(p, np);
-       }
+       //if ( p->notes != NULL ) {
+       //      notify_notes_slide_changed(p, np);
+       //}
 
        if ( (p->slideshow != NULL) && p->slideshow_linked ) {
                //notify_slideshow_slide_changed(p, np);
@@ -610,9 +607,6 @@ static void add_menu_bar(struct presentation *p, GtkWidget *vbox)
        gtk_toolbar_insert(GTK_TOOLBAR(toolbar),
                           gtk_separator_tool_item_new(), -1);
 
-       p->tbox = GTK_WIDGET(gtk_tool_item_new());
-       gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(p->tbox), -1);
-
        /* 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));
index 01a8fbf..405cf49 100644 (file)
@@ -62,7 +62,7 @@ void free_presentation(struct presentation *p)
 int insert_slide(struct presentation *p, struct slide *new, int pos)
 {
        struct slide **try;
-       
+
        try = realloc(p->slides, (1+p->num_slides)*sizeof(struct slide *));
        if ( try == NULL ) {
                free(new);
@@ -207,7 +207,6 @@ struct presentation *new_presentation()
        new->ui = NULL;
        new->action_group = NULL;
        new->slideshow = NULL;
-       new->notes = NULL;
 
        new->slide_width = 1024.0;
        new->slide_height = 768.0;
@@ -220,8 +219,8 @@ struct presentation *new_presentation()
 
        new->completely_empty = 1;
 
-       //new->ss = new_stylesheet();
-       //default_stylesheet(new->ss);
+       new->ss = new_stylesheet();
+       default_stylesheet(new->ss);
 
        return new;
 }
index d8fe5c4..62237c0 100644 (file)
@@ -33,6 +33,7 @@
 
 struct frame;
 #include "layout.h"
+#include "stylesheet.h"
 
 struct slide
 {
@@ -83,20 +84,11 @@ struct presentation
        int               completely_empty;
        int              *num_presentations;
 
-       struct prefs     *prefs;
-
-       struct toolinfo  *select_tool;
-       struct toolinfo  *text_tool;
-       struct toolinfo  *image_tool;
-
        GtkWidget        *window;
        GtkWidget        *drawingarea;
        GtkUIManager     *ui;
        GtkActionGroup   *action_group;
        GtkIMContext     *im_context;
-       GtkWidget        *tbox;
-       GtkWidget        *cur_tbox;
-       struct notes     *notes;
 
        /* Pointers to the current "editing" and "projection" slides */
        struct slide     *cur_edit_slide;
@@ -126,17 +118,7 @@ struct presentation
        int               ss_blank;
        char              ss_geom[256];
 
-       /* Tool status */
-       struct toolinfo  *cur_tool;
-
-       /* 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;
-
+       StyleSheet       *ss;
        unsigned int      num_slides;
        struct slide    **slides;
 };
diff --git a/src/stylesheet.c b/src/stylesheet.c
new file mode 100644 (file)
index 0000000..8cf519f
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * stylesheet.c
+ *
+ * Colloquium - A tiny presentation program
+ *
+ * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program 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 "presentation.h"
+#include "stylesheet.h"
+#include "loadsave.h"
+
+
+struct style *new_style(StyleSheet *ss, const char *name)
+{
+       struct style *sty;
+       int n;
+       struct style **styles_new;
+
+       sty = calloc(1, sizeof(*sty));
+       if ( sty == NULL ) return NULL;
+
+       sty->name = strdup(name);
+
+       n = ss->n_styles;
+       styles_new = realloc(ss->styles, (n+1)*sizeof(sty));
+       if ( styles_new == NULL ) {
+               free(sty->name);
+               free(sty);
+               return NULL;
+       }
+       ss->styles = styles_new;
+       ss->styles[n] = sty;
+       ss->n_styles = n+1;
+
+       return sty;
+}
+
+
+void free_stylesheet(StyleSheet *ss)
+{
+       int i;
+
+       for ( i=0; i<ss->n_styles; i++ ) {
+               free(ss->styles[i]->name);
+               free(ss->styles[i]);
+       }
+
+       free(ss->styles);
+       free(ss);
+}
+
+
+void default_stylesheet(StyleSheet *ss)
+{
+       struct style *sty;
+
+       /* Default style must be first */
+       sty = new_style(ss, "Default");
+       sty->lop.margin_l = 20.0;
+       sty->lop.margin_r = 20.0;
+       sty->lop.margin_t = 20.0;
+       sty->lop.margin_b = 20.0;
+
+       sty = new_style(ss, "Slide title");
+       sty->lop.margin_l = 20.0;
+       sty->lop.margin_r = 20.0;
+       sty->lop.margin_t = 20.0;
+       sty->lop.margin_b = 20.0;
+}
+
+
+static int read_style(struct style *sty, struct ds_node *root)
+{
+       get_field_f(root, "margin_l", &sty->lop.margin_l);
+       get_field_f(root, "margin_r", &sty->lop.margin_r);
+       get_field_f(root, "margin_t", &sty->lop.margin_t);
+       get_field_f(root, "margin_b", &sty->lop.margin_b);
+
+       return 0;
+}
+
+
+StyleSheet *tree_to_stylesheet(struct ds_node *root)
+{
+       StyleSheet *ss;
+       struct ds_node *node;
+       int i;
+
+       ss = new_stylesheet();
+       if ( ss == NULL ) return NULL;
+
+       node = find_node(root, "styles", 0);
+       if ( node == NULL ) {
+               fprintf(stderr, "Couldn't find styles\n");
+               free_stylesheet(ss);
+               return NULL;
+       }
+
+       for ( i=0; i<node->n_children; i++ ) {
+
+               struct style *ns;
+               char *v;
+
+               get_field_s(node->children[i], "name", &v);
+               if ( v == NULL ) {
+                       fprintf(stderr, "No name for style '%s'\n",
+                               node->children[i]->key);
+                       continue;
+               }
+
+               ns = new_style(ss, v);
+               if ( ns == NULL ) {
+                       fprintf(stderr, "Couldn't create style for '%s'\n",
+                               node->children[i]->key);
+                       continue;
+               }
+
+               if ( read_style(ns, node->children[i]) ) {
+                       fprintf(stderr, "Couldn't read style '%s'\n", v);
+                       continue;
+               }
+
+       }
+
+       node = find_node(root, "bgblocks", 0);
+       if ( node == NULL ) {
+               fprintf(stderr, "Couldn't find bgblocks\n");
+               free_stylesheet(ss);
+               return NULL;
+       }
+
+       return ss;
+}
+
+
+StyleSheet *new_stylesheet()
+{
+       StyleSheet *ss;
+
+       ss = calloc(1, sizeof(struct _stylesheet));
+       if ( ss == NULL ) return NULL;
+
+       ss->n_styles = 0;
+       ss->styles = NULL;
+
+       return ss;
+}
+
+
+int save_stylesheet(StyleSheet *ss, const char *filename)
+{
+       FILE *fh;
+       struct serializer ser;
+
+       fh = fopen(filename, "w");
+       if ( fh == NULL ) return 1;
+
+       /* Set up the serializer */
+       ser.fh = fh;
+       ser.stack_depth = 0;
+       ser.prefix = NULL;
+
+       fprintf(fh, "# Colloquium style sheet file\n");
+       serialize_f(&ser, "version", 0.1);
+
+       serialize_start(&ser, "stylesheet");
+       write_stylesheet(ss, &ser);
+       serialize_end(&ser);
+
+       return 0;
+}
+
+
+StyleSheet *load_stylesheet(const char *filename)
+{
+       StyleSheet *ss;
+
+       ss = new_stylesheet();
+       if ( ss == NULL ) return NULL;
+
+       /* FIXME: Implement this */
+
+       return ss;
+}
+
+
+void write_stylesheet(StyleSheet *ss, struct serializer *ser)
+{
+       int i;
+
+       serialize_start(ser, "styles");
+       for ( i=0; i<ss->n_styles; i++ ) {
+
+               struct style *s = ss->styles[i];
+               char id[32];
+
+               snprintf(id, 31, "%i", i);
+
+               serialize_start(ser, id);
+               serialize_s(ser, "name", s->name);
+               serialize_f(ser, "margin_l", s->lop.margin_l);
+               serialize_f(ser, "margin_r", s->lop.margin_r);
+               serialize_f(ser, "margin_t", s->lop.margin_t);
+               serialize_f(ser, "margin_b", s->lop.margin_b);
+               serialize_end(ser);
+
+       }
+       serialize_end(ser);
+}
+
+
+struct style *find_style(StyleSheet *ss, const char *name)
+{
+       int i;
+       for ( i=0; i<ss->n_styles; i++ ) {
+               if ( strcmp(ss->styles[i]->name, name) == 0 ) {
+                       return ss->styles[i];
+               }
+       }
+
+       return NULL;
+}
index f2f72b2..58f4c13 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Colloquium - A tiny presentation program
  *
- * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk>
+ * Copyright (c) 2012 Thomas White <taw@bitwiz.org.uk>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@
 
 struct frame;
 #include "layout.h"
+#include "loadsave.h"
 
 
 struct style
@@ -50,13 +51,35 @@ struct slide_template
 
        struct frame_class  **frame_classes;
        int                   n_frame_classes;
+};
+
 
-       struct bgblock      **bgblocks;
-       int                   n_bgblocks;
+struct _stylesheet
+{
+       struct style  **styles;
+       int             n_styles;
 };
 
 
 typedef struct _stylesheet StyleSheet;
 struct presentation;
 
+extern StyleSheet *new_stylesheet();
+extern StyleSheet *load_stylesheet(const char *filename);
+extern void free_stylesheet(StyleSheet *ss);
+extern void default_stylesheet(StyleSheet *ss);
+
+extern struct style *new_style(StyleSheet *ss, const char *name);
+
+extern int save_stylesheet(StyleSheet *ss, const char *filename);
+
+extern struct style *find_style(StyleSheet *ss, const char *name);
+
+extern enum justify str_to_halign(char *halign);
+extern enum vert_pos str_to_valign(char *valign);
+
+extern StyleSheet *tree_to_stylesheet(struct ds_node *root);
+extern void write_stylesheet(StyleSheet *ss, struct serializer *ser);
+
+
 #endif /* STYLESHEET_H */