Background gradient stuff
[colloquium.git] / src / slide_render.c
1 /*
2  * slide_render.c
3  *
4  * Colloquium - A tiny presentation program
5  *
6  * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk>
7  *
8  * This program 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 <cairo.h>
29 #include <pango/pangocairo.h>
30 #include <assert.h>
31
32 #include "slide_render.h"
33 #include "presentation.h"
34 #include "objects.h"
35 #include "stylesheet.h"
36
37
38 static void render_bgblock(cairo_t *cr, struct bgblock *b)
39 {
40         GdkColor col1;
41         GdkColor col2;
42         cairo_pattern_t *patt = NULL;
43         double cx, cy, r, r1, r2;
44
45         cairo_rectangle(cr, b->min_x, b->min_y,
46                             b->max_x - b->min_x,
47                             b->max_y - b->min_y);
48
49         switch ( b->type ) {
50
51                 case BGBLOCK_SOLID :
52                 gdk_color_parse(b->colour1, &col1);
53                 gdk_cairo_set_source_color(cr, &col1);
54                 /* FIXME: Honour alpha as well */
55                 cairo_fill(cr);
56                 break;
57
58                 case BGBLOCK_GRADIENT_CIRCULAR :
59                 cx = b->min_x + (b->max_x-b->min_x)/2.0;
60                 cy = b->min_y + (b->max_y-b->min_y)/2.0;
61                 r1 = (b->max_x-b->min_x)/2.0;
62                 r2 = (b->max_y-b->min_y)/2.0;
63                 r = r1 > r2 ? r1 : r2;
64                 patt = cairo_pattern_create_radial(cx, cy, r, cx, cy, 0.0);
65                 /* Fall-through */
66
67                 case BGBLOCK_GRADIENT_X :
68                 if ( patt == NULL ) {
69                         patt = cairo_pattern_create_linear(b->min_x, 0.0,
70                                                            b->max_y, 0.0);
71                 }
72                 /* Fall-through */
73
74                 case BGBLOCK_GRADIENT_Y :
75                 if ( patt == NULL ) {
76                         patt = cairo_pattern_create_linear(0.0, b->min_y,
77                                                            0.0, b->max_y);
78                 }
79
80                 gdk_color_parse(b->colour1, &col1);
81                 gdk_color_parse(b->colour2, &col2);
82                 cairo_pattern_add_color_stop_rgba(patt, 0.0, col1.red/65535.0,
83                                                              col1.green/65535.0,
84                                                              col1.blue/65535.0,
85                                                              b->alpha1);
86                 cairo_pattern_add_color_stop_rgba(patt, 1.0, col2.red/65535.0,
87                                                              col2.green/65535.0,
88                                                              col2.blue/65535.0,
89                                                              b->alpha2);
90                 cairo_set_source(cr, patt);
91                 cairo_fill(cr);
92                 cairo_pattern_destroy(patt);
93                 break;
94
95                 case BGBLOCK_IMAGE :
96                 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
97                 cairo_fill(cr);
98
99         }
100 }
101
102
103 static cairo_surface_t *render_slide(struct slide *s, int w, int h)
104 {
105         cairo_surface_t *surf;
106         cairo_t *cr;
107         int i;
108
109         surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
110
111         cr = cairo_create(surf);
112         cairo_scale(cr, w/s->parent->slide_width, h/s->parent->slide_height);
113
114         for ( i=0; i<s->parent->ss->n_bgblocks; i++ ) {
115                 render_bgblock(cr, &s->parent->ss->bgblocks[i]);
116         }
117
118         for ( i=0; i<s->num_objects; i++ ) {
119
120                 struct object *o = s->objects[i];
121
122                 o->render_object(cr, o);
123
124         }
125
126         cairo_destroy(cr);
127
128         return surf;
129 }
130
131
132 void redraw_slide(struct slide *s)
133 {
134         int w, h;
135
136         if ( s->rendered_thumb != NULL ) {
137                 cairo_surface_destroy(s->rendered_thumb);
138         }
139
140         w = s->parent->thumb_slide_width;
141         h = (s->parent->slide_height/s->parent->slide_width) * w;
142         s->rendered_thumb = render_slide(s, w, h);
143         /* FIXME: Request redraw for slide sorter if open */
144
145         /* Is this slide currently open in the editor? */
146         if ( s == s->parent->cur_edit_slide ) {
147
148                 GtkWidget *da;
149
150                 if ( s->rendered_edit != NULL ) {
151                         cairo_surface_destroy(s->rendered_edit);
152                 }
153
154                 w = s->parent->edit_slide_width;
155                 h = (s->parent->slide_height/s->parent->slide_width) * w;
156                 s->rendered_edit = render_slide(s, w, h);
157
158                 da = s->parent->drawingarea;
159                 if ( da != NULL ) {
160                         gdk_window_invalidate_rect(da->window, NULL, FALSE);
161                 }
162
163         }
164
165         /* Is this slide currently being displayed on the projector? */
166         if ( s == s->parent->cur_proj_slide ) {
167
168                 GtkWidget *da;
169
170                 if ( s->rendered_proj != NULL ) {
171                         cairo_surface_destroy(s->rendered_proj);
172                 }
173
174                 w = s->parent->proj_slide_width;
175                 h = (s->parent->slide_height/s->parent->slide_width) * w;
176                 s->rendered_proj = render_slide(s, w, h);
177
178                 da = s->parent->ss_drawingarea;
179                 if ( da != NULL ) {
180                         gdk_window_invalidate_rect(da->window, NULL, FALSE);
181                 }
182
183         }
184 }
185
186
187 void draw_rubberband_box(cairo_t *cr, double x, double y,
188                          double width, double height)
189 {
190         cairo_new_path(cr);
191         cairo_rectangle(cr, x, y, width, height);
192         cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
193         cairo_set_line_width(cr, 0.5);
194         cairo_stroke(cr);
195 }
196
197
198 void draw_resize_handle(cairo_t *cr, double x, double y)
199 {
200         cairo_new_path(cr);
201         cairo_rectangle(cr, x, y, 20.0, 20.0);
202         cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.5);
203         cairo_fill(cr);
204 }
205
206
207 void draw_editing_box(cairo_t *cr, double xmin, double ymin,
208                       double width, double height)
209 {
210         const double dash[] = {2.0, 2.0};
211
212         cairo_new_path(cr);
213         cairo_rectangle(cr, xmin-5.0, ymin-5.0, width+10.0, height+10.0);
214         cairo_set_source_rgb(cr, 0.0, 0.69, 1.0);
215         cairo_set_line_width(cr, 0.5);
216         cairo_stroke(cr);
217
218         cairo_new_path(cr);
219         cairo_rectangle(cr, xmin, ymin, width, height);
220         cairo_set_dash(cr, dash, 2, 0.0);
221         cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
222         cairo_set_line_width(cr, 0.1);
223         cairo_stroke(cr);
224
225         cairo_set_dash(cr, NULL, 0, 0.0);
226 }