Save stuff
[colloquium.git] / src / stylesheet.c
1 /*
2  * stylesheet.c
3  *
4  * Copyright © 2013 Thomas White <taw@bitwiz.org.uk>
5  *
6  * This file is part of Colloquium.
7  *
8  * Colloquium is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <gtk/gtk.h>
31 #include <assert.h>
32
33 #include "presentation.h"
34 #include "stylesheet.h"
35 #include "loadsave.h"
36
37
38 struct _stylesheet
39 {
40         struct style          **styles;
41         int                     n_styles;
42
43         struct slide_template **templates;
44         int                     n_templates;
45 };
46
47
48 struct style *new_style(StyleSheet *ss, const char *name)
49 {
50         struct style *sty;
51         int n;
52         struct style **styles_new;
53
54         sty = calloc(1, sizeof(*sty));
55         if ( sty == NULL ) return NULL;
56
57         sty->name = strdup(name);
58
59         /* DS9K compatibility */
60         sty->lop.x = 0.0;
61         sty->lop.y = 0.0;
62         sty->lop.w = 100.0;
63         sty->lop.h = 100.0;
64
65         n = ss->n_styles;
66         styles_new = realloc(ss->styles, (n+1)*sizeof(sty));
67         if ( styles_new == NULL ) {
68                 free(sty->name);
69                 free(sty);
70                 return NULL;
71         }
72         ss->styles = styles_new;
73         ss->styles[n] = sty;
74         ss->n_styles = n+1;
75
76         return sty;
77 }
78
79
80 void free_stylesheet(StyleSheet *ss)
81 {
82         int i;
83
84         for ( i=0; i<ss->n_styles; i++ ) {
85                 free(ss->styles[i]->name);
86                 free(ss->styles[i]->sc_prologue);
87                 free(ss->styles[i]);
88         }
89
90         free(ss->styles);
91         free(ss);
92 }
93
94
95 void default_stylesheet(StyleSheet *ss)
96 {
97         struct style *sty;
98         struct slide_template *titlepage;
99         struct slide_template *slide;
100         struct slide_template *acknowledgements;
101
102         titlepage = new_template(ss, "Title page");
103         slide = new_template(ss, "Slide");
104         acknowledgements = new_template(ss, "Acknowledgements");
105
106         sty = new_style(ss, "Presentation title");
107         sty->lop.margin_l = 0.0;
108         sty->lop.margin_r = 0.0;
109         sty->lop.margin_t = 0.0;
110         sty->lop.margin_b = 0.0;
111         sty->lop.pad_l = 0.0;
112         sty->lop.pad_r = 0.0;
113         sty->lop.pad_t = 0.0;
114         sty->lop.pad_b = 0.0;
115         sty->lop.w = 1.0;
116         sty->lop.w_units = UNITS_FRAC;
117         sty->lop.h = 100.0;
118         sty->lop.h_units = UNITS_SLIDE;
119         sty->lop.x = 0.0;
120         sty->lop.y = 300.0;
121         sty->sc_prologue = strdup("\\font[Sorts Mill Goudy 64]");
122         add_to_template(titlepage, sty);
123
124         sty = new_style(ss, "Slide title");
125         sty->lop.margin_l = 0.0;
126         sty->lop.margin_r = 0.0;
127         sty->lop.margin_t = 0.0;
128         sty->lop.margin_b = 0.0;
129         sty->lop.pad_l = 20.0;
130         sty->lop.pad_r = 20.0;
131         sty->lop.pad_t = 20.0;
132         sty->lop.pad_b = 20.0;
133         sty->lop.w = 1.0;
134         sty->lop.w_units = UNITS_FRAC;
135         sty->lop.h = 100.0;
136         sty->lop.h_units = UNITS_SLIDE;
137         sty->lop.x = 0.0;
138         sty->lop.y = 0.0;
139         sty->sc_prologue = strdup("\\bgcol{#00a6eb}\\fgcol{#ffffff}"
140                                   "\\font[Sans 40]");
141         add_to_template(slide, sty);
142
143         sty = new_style(ss, "Slide title");
144         sty->lop.margin_r = 0.0;
145         sty->lop.margin_t = 0.0;
146         sty->lop.margin_b = 0.0;
147         sty->lop.pad_l = 20.0;
148         sty->lop.pad_r = 20.0;
149         sty->lop.pad_t = 20.0;
150         sty->lop.pad_b = 20.0;
151         sty->lop.w = 1.0;
152         sty->lop.w_units = UNITS_FRAC;
153         sty->lop.h = 100.0;
154         sty->lop.h_units = UNITS_SLIDE;
155         sty->lop.x = 0.0;
156         sty->lop.y = 0.0;
157         sty->sc_prologue = strdup("\\bgcol{#00a6eb}\\fgcol{#ffffff}"
158                                   "\\font[Sans 40]Acknowledgements");
159         add_to_template(acknowledgements, sty);
160
161         sty = new_style(ss, "Content");
162         sty->lop.margin_l = 10.0;
163         sty->lop.margin_r = 10.0;
164         sty->lop.margin_t = 120.0;
165         sty->lop.margin_b = 10.0;
166         sty->lop.pad_l = 20.0;
167         sty->lop.pad_r = 20.0;
168         sty->lop.pad_t = 20.0;
169         sty->lop.pad_b = 20.0;
170         sty->lop.w = 1.0;
171         sty->lop.w_units = UNITS_FRAC;
172         sty->lop.h = 1.0;
173         sty->lop.h_units = UNITS_FRAC;
174         sty->lop.x = 0.0;
175         sty->lop.y = 0.0;
176         sty->sc_prologue = strdup("\\bgcol{#dddddd}\\fgcol{#ffffff}"
177                                   "\\font[Sans 24]");
178         add_to_template(acknowledgements, sty);
179 }
180
181
182 static int read_style(struct style *sty, struct ds_node *root)
183 {
184         get_field_f(root, "margin_l", &sty->lop.margin_l);
185         get_field_f(root, "margin_r", &sty->lop.margin_r);
186         get_field_f(root, "margin_t", &sty->lop.margin_t);
187         get_field_f(root, "margin_b", &sty->lop.margin_b);
188
189         return 0;
190 }
191
192
193 StyleSheet *tree_to_stylesheet(struct ds_node *root)
194 {
195         StyleSheet *ss;
196         struct ds_node *node;
197         int i;
198
199         ss = new_stylesheet();
200         if ( ss == NULL ) return NULL;
201
202         node = find_node(root, "styles", 0);
203         if ( node == NULL ) {
204                 fprintf(stderr, "Couldn't find styles\n");
205                 free_stylesheet(ss);
206                 return NULL;
207         }
208
209         for ( i=0; i<node->n_children; i++ ) {
210
211                 struct style *ns;
212                 char *v;
213
214                 get_field_s(node->children[i], "name", &v);
215                 if ( v == NULL ) {
216                         fprintf(stderr, "No name for style '%s'\n",
217                                 node->children[i]->key);
218                         continue;
219                 }
220
221                 ns = new_style(ss, v);
222                 if ( ns == NULL ) {
223                         fprintf(stderr, "Couldn't create style for '%s'\n",
224                                 node->children[i]->key);
225                         continue;
226                 }
227
228                 if ( read_style(ns, node->children[i]) ) {
229                         fprintf(stderr, "Couldn't read style '%s'\n", v);
230                         continue;
231                 }
232
233         }
234
235         node = find_node(root, "bgblocks", 0);
236         if ( node == NULL ) {
237                 fprintf(stderr, "Couldn't find bgblocks\n");
238                 free_stylesheet(ss);
239                 return NULL;
240         }
241
242         return ss;
243 }
244
245
246 StyleSheet *new_stylesheet()
247 {
248         StyleSheet *ss;
249
250         ss = calloc(1, sizeof(struct _stylesheet));
251         if ( ss == NULL ) return NULL;
252
253         ss->n_styles = 0;
254         ss->styles = NULL;
255
256         return ss;
257 }
258
259
260 int save_stylesheet(StyleSheet *ss, const char *filename)
261 {
262         FILE *fh;
263         struct serializer ser;
264
265         fh = fopen(filename, "w");
266         if ( fh == NULL ) return 1;
267
268         /* Set up the serializer */
269         ser.fh = fh;
270         ser.stack_depth = 0;
271         ser.prefix = NULL;
272
273         fprintf(fh, "# Colloquium style sheet file\n");
274         serialize_f(&ser, "version", 0.1);
275
276         serialize_start(&ser, "stylesheet");
277         write_stylesheet(ss, &ser);
278         serialize_end(&ser);
279
280         return 0;
281 }
282
283
284 StyleSheet *load_stylesheet(const char *filename)
285 {
286         StyleSheet *ss;
287
288         ss = new_stylesheet();
289         if ( ss == NULL ) return NULL;
290
291         /* FIXME: Implement this */
292
293         return ss;
294 }
295
296
297 static const char *units(LengthUnits un)
298 {
299         switch ( un ) {
300                 case UNITS_SLIDE : return "u";
301                 case UNITS_FRAC : return "fr";
302         }
303         return "annoyingly unspecified units";
304 }
305
306
307 static void serialize_f_units(struct serializer *s, const char *key, double val,
308                               LengthUnits un)
309 {
310         char tmp[64];
311
312         snprintf(tmp, 63, "%.2f %s", val, units(un));
313         serialize_s(s, key, tmp);
314 }
315
316
317 static int style_number(StyleSheet *ss, struct style *s)
318 {
319         int i;
320
321         for ( i=0; i<ss->n_styles; i++ ) {
322                 if ( ss->styles[i] == s ) return i;
323         }
324
325         return -1;
326 }
327
328
329 void write_stylesheet(StyleSheet *ss, struct serializer *ser)
330 {
331         int i;
332
333         serialize_start(ser, "styles");
334         for ( i=0; i<ss->n_styles; i++ ) {
335
336                 struct style *s = ss->styles[i];
337                 char id[32];
338
339                 snprintf(id, 31, "%i", i);
340
341                 serialize_start(ser, id);
342                 serialize_s(ser, "name", s->name);
343                 serialize_f(ser, "margin_l", s->lop.margin_l);
344                 serialize_f(ser, "margin_r", s->lop.margin_r);
345                 serialize_f(ser, "margin_t", s->lop.margin_t);
346                 serialize_f(ser, "margin_b", s->lop.margin_b);
347                 serialize_f(ser, "pad_l", s->lop.pad_l);
348                 serialize_f(ser, "pad_r", s->lop.pad_r);
349                 serialize_f(ser, "pad_t", s->lop.pad_t);
350                 serialize_f(ser, "pad_b", s->lop.pad_b);
351                 serialize_f_units(ser, "w", s->lop.w, s->lop.w_units);
352                 serialize_f_units(ser, "h", s->lop.h, s->lop.h_units);
353                 serialize_s(ser, "prologue", s->sc_prologue);
354                 serialize_end(ser);
355
356         }
357         serialize_end(ser);
358
359         serialize_start(ser, "templates");
360         for ( i=0; i<ss->n_templates; i++ ) {
361
362                 struct slide_template *t = ss->templates[i];
363                 char id[32];
364                 int j;
365
366                 snprintf(id, 31, "%i", i);
367
368                 serialize_start(ser, id);
369                 serialize_s(ser, "name", t->name);
370                 for ( j=0; j<t->n_styles; j++ ) {
371
372                         struct style *s = t->styles[j];
373                         char id[32];
374
375                         snprintf(id, 31, "sty%i", i);
376
377                         serialize_i(ser, id, style_number(ss, s));
378
379                 }
380                 serialize_end(ser);
381
382         }
383         serialize_end(ser);
384
385 }
386
387
388 struct style *find_style(StyleSheet *ss, const char *name)
389 {
390         int i;
391         for ( i=0; i<ss->n_styles; i++ ) {
392                 if ( strcmp(ss->styles[i]->name, name) == 0 ) {
393                         return ss->styles[i];
394                 }
395         }
396
397         return NULL;
398 }
399
400
401 struct slide_template *new_template(StyleSheet *ss, const char *name)
402 {
403         struct slide_template *t;
404         int n;
405         struct slide_template **templates_new;
406
407         t = calloc(1, sizeof(*t));
408         if ( t == NULL ) return NULL;
409
410         t->name = strdup(name);
411
412         n = ss->n_templates;
413         templates_new = realloc(ss->templates, (n+1)*sizeof(t));
414         if ( templates_new == NULL ) {
415                 free(t->name);
416                 free(t);
417                 return NULL;
418         }
419         ss->templates = templates_new;
420         ss->templates[n] = t;
421         ss->n_templates = n+1;
422
423         return t;
424 }
425
426
427 void add_to_template(struct slide_template *t, struct style *sty)
428 {
429         int n;
430         struct style **styles_new;
431
432         n = t->n_styles;
433         styles_new = realloc(t->styles, (n+1)*sizeof(sty));
434         if ( styles_new == NULL ) {
435                 fprintf(stderr, "Failed to add style '%s' to template '%s'.\n",
436                         sty->name, t->name);
437                 return;
438         }
439         t->styles = styles_new;
440         t->styles[n] = sty;
441         t->n_styles = n+1;
442 }
443
444
445 struct _styleiterator
446 {
447         int n;
448 };
449
450 struct style *style_first(StyleSheet *ss, StyleIterator **piter)
451 {
452         StyleIterator *iter;
453
454         if ( ss->n_styles == 0 ) return NULL;
455
456         iter = calloc(1, sizeof(StyleIterator));
457         if ( iter == NULL ) return NULL;
458
459         iter->n = 0;
460         *piter = iter;
461
462         return ss->styles[0];
463 }
464
465
466 struct style *style_next(StyleSheet *ss, StyleIterator *iter)
467 {
468         iter->n++;
469         if ( iter->n == ss->n_styles ) {
470                 free(iter);
471                 return NULL;
472         }
473
474         return ss->styles[iter->n];
475 }
476
477
478 struct _templateiterator
479 {
480         int n;
481 };
482
483 struct slide_template *template_first(StyleSheet *ss, TemplateIterator **piter)
484 {
485         TemplateIterator *iter;
486
487         if ( ss->n_templates == 0 ) return NULL;
488
489         iter = calloc(1, sizeof(TemplateIterator));
490         if ( iter == NULL ) return NULL;
491
492         iter->n = 0;
493         *piter = iter;
494
495         return ss->templates[0];
496 }
497
498
499 struct slide_template *template_next(StyleSheet *ss, TemplateIterator *iter)
500 {
501         iter->n++;
502         if ( iter->n == ss->n_templates ) {
503                 free(iter);
504                 return NULL;
505         }
506
507         return ss->templates[iter->n];
508 }