]> git.sur5r.net Git - glabels/blob - glabels2/src/wdgt-rotate-label.c
993eab20f780317f2add8001ea77a0eaa43a3e5c
[glabels] / glabels2 / src / wdgt-rotate-label.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  wdgt_rotate_label.c:  label rotate selection widget module
7  *
8  *  Copyright (C) 2001-2006  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24
25 #include <config.h>
26
27 #include "wdgt-rotate-label.h"
28
29 #include <glib/gi18n.h>
30 #include <gtk/gtkradiobutton.h>
31 #include <gtk/gtkdrawingarea.h>
32 #include <math.h>
33
34 #include "marshal.h"
35 #include "color.h"
36 #include "hig.h"
37 #include <libglabels/db.h>
38 #include "cairo-label-path.h"
39
40 #include "debug.h"
41
42 /*========================================================*/
43 /* Private macros and constants.                          */
44 /*========================================================*/
45 #define MINI_PREVIEW_MAX_PIXELS 48
46 #define MINI_PREVIEW_CANVAS_PIXELS (MINI_PREVIEW_MAX_PIXELS + 8)
47
48 #define LINE_COLOR             GL_COLOR(0,0,0)
49 #define FILL_COLOR             GL_COLOR(255,255,255)
50 #define SHADOW_COLOR           GL_COLOR_A(192,192,192,128)
51
52 #define LINE_WIDTH_PIXELS    1.0
53
54 #define SHADOW_X_OFFSET 3
55 #define SHADOW_Y_OFFSET 3
56
57
58 /*===========================================*/
59 /* Private types                             */
60 /*===========================================*/
61
62 struct _glWdgtRotateLabelPrivate {
63
64         GtkWidget    *no_rotate_radio;
65         GtkWidget    *rotate_radio;
66         GtkWidget    *no_rotate_image;
67         GtkWidget    *rotate_image;
68
69         lglTemplate  *template;
70 };
71
72 enum {
73         CHANGED,
74         LAST_SIGNAL
75 };
76
77 /*===========================================*/
78 /* Private globals                           */
79 /*===========================================*/
80
81 static gint wdgt_rotate_label_signals[LAST_SIGNAL] = { 0 };
82
83 /*===========================================*/
84 /* Local function prototypes                 */
85 /*===========================================*/
86
87 static void gl_wdgt_rotate_label_finalize      (GObject                *object);
88
89 static void toggled_cb                         (GtkToggleButton        *toggle,
90                                                 gpointer                user_data);
91
92 static GdkPixbuf *create_pixbuf                (lglTemplate            *template,
93                                                 gboolean                rotate_flag);
94
95
96 /****************************************************************************/
97 /* Boilerplate Object stuff.                                                */
98 /****************************************************************************/
99 G_DEFINE_TYPE (glWdgtRotateLabel, gl_wdgt_rotate_label, GTK_TYPE_HBOX);
100
101
102 static void
103 gl_wdgt_rotate_label_class_init (glWdgtRotateLabelClass *class)
104 {
105         GObjectClass *object_class = G_OBJECT_CLASS (class);
106
107         gl_wdgt_rotate_label_parent_class = g_type_class_peek_parent (class);
108
109         object_class->finalize = gl_wdgt_rotate_label_finalize;
110
111         wdgt_rotate_label_signals[CHANGED] =
112             g_signal_new ("changed",
113                           G_OBJECT_CLASS_TYPE(object_class),
114                           G_SIGNAL_RUN_LAST,
115                           G_STRUCT_OFFSET (glWdgtRotateLabelClass, changed),
116                           NULL, NULL,
117                           gl_marshal_VOID__VOID,
118                           G_TYPE_NONE, 0);
119
120 }
121
122 static void
123 gl_wdgt_rotate_label_init (glWdgtRotateLabel *rotate_label)
124 {
125         rotate_label->priv = g_new0 (glWdgtRotateLabelPrivate, 1);
126
127         gtk_container_set_border_width (GTK_CONTAINER (rotate_label), GL_HIG_PAD2);
128
129         rotate_label->priv->no_rotate_radio = gtk_radio_button_new_with_label (NULL, _("Normal"));
130         rotate_label->priv->rotate_radio    = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (rotate_label->priv->no_rotate_radio), _("Rotated"));
131
132         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rotate_label->priv->no_rotate_radio),
133                                     FALSE);
134         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rotate_label->priv->rotate_radio),
135                                     FALSE);
136
137         gtk_button_set_image_position (GTK_BUTTON (rotate_label->priv->no_rotate_radio),
138                                        GTK_POS_TOP);
139         gtk_button_set_image_position (GTK_BUTTON (rotate_label->priv->rotate_radio),
140                                        GTK_POS_TOP);
141
142         rotate_label->priv->no_rotate_image = gtk_image_new ();
143         rotate_label->priv->rotate_image    = gtk_image_new ();
144
145         gtk_button_set_image (GTK_BUTTON (rotate_label->priv->no_rotate_radio),
146                               rotate_label->priv->no_rotate_image);
147         gtk_button_set_image (GTK_BUTTON (rotate_label->priv->rotate_radio),
148                               rotate_label->priv->rotate_image);
149
150         gtk_box_pack_start (GTK_BOX (rotate_label),
151                             rotate_label->priv->no_rotate_radio,
152                             FALSE, FALSE, GL_HIG_PAD1);
153         gtk_box_pack_start (GTK_BOX (rotate_label),
154                             rotate_label->priv->rotate_radio,
155                             FALSE, FALSE, GL_HIG_PAD1);
156         
157         /* Connect signals to controls */
158         g_signal_connect (G_OBJECT (rotate_label->priv->no_rotate_radio),
159                           "toggled",
160                           G_CALLBACK (toggled_cb), rotate_label);
161         g_signal_connect (G_OBJECT (rotate_label->priv->rotate_radio),
162                           "toggled",
163                           G_CALLBACK (toggled_cb), rotate_label);
164 }
165
166 static void
167 gl_wdgt_rotate_label_finalize (GObject *object)
168 {
169         glWdgtRotateLabel      *rotate_label = GL_WDGT_ROTATE_LABEL (object);
170
171         g_return_if_fail (object != NULL);
172         g_return_if_fail (GL_IS_WDGT_ROTATE_LABEL (object));
173
174         if (rotate_label->priv->template) {
175                 lgl_template_free (rotate_label->priv->template);
176                 rotate_label->priv->template = NULL;
177         }
178         g_free (rotate_label->priv);
179
180         G_OBJECT_CLASS (gl_wdgt_rotate_label_parent_class)->finalize (object);
181 }
182
183 GtkWidget *
184 gl_wdgt_rotate_label_new (void)
185 {
186         glWdgtRotateLabel *rotate_label;
187
188         rotate_label = g_object_new (gl_wdgt_rotate_label_get_type (), NULL);
189
190         return GTK_WIDGET (rotate_label);
191 }
192
193 /*--------------------------------------------------------------------------*/
194 /* PRIVATE.  modify widget due to change of check button                    */
195 /*--------------------------------------------------------------------------*/
196 static void
197 toggled_cb (GtkToggleButton *toggle,
198             gpointer         user_data)
199 {
200
201         /* Emit our "changed" signal */
202         g_signal_emit (G_OBJECT (user_data),
203                        wdgt_rotate_label_signals[CHANGED], 0);
204
205 }
206
207 /*--------------------------------------------------------------------------*/
208 /* PRIVATE.  Update mini-preview from template           .                  */
209 /*--------------------------------------------------------------------------*/
210 static GdkPixbuf *
211 create_pixbuf (lglTemplate    *template,
212                gboolean        rotate_flag)
213 {
214         GdkPixbuf                 *pixbuf;
215         cairo_surface_t           *surface;
216         const lglTemplateFrame    *frame;
217         gdouble                    m, m_canvas, w, h, scale;
218         GtkStyle                  *style;
219         cairo_t                   *cr;
220
221         /* Create pixbuf and cairo context. */
222         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, MINI_PREVIEW_CANVAS_PIXELS, MINI_PREVIEW_CANVAS_PIXELS);
223         surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (pixbuf),
224                                                        CAIRO_FORMAT_RGB24,
225                                                        gdk_pixbuf_get_width (pixbuf),
226                                                        gdk_pixbuf_get_height (pixbuf),
227                                                        gdk_pixbuf_get_rowstride (pixbuf));
228
229
230         if (template == NULL)
231         {
232                 return pixbuf;
233         }
234
235         frame = (lglTemplateFrame *)template->frames->data;
236
237         if (rotate_flag)
238         {
239                 lgl_template_frame_get_size (frame, &h, &w);
240         }
241         else
242         {
243                 lgl_template_frame_get_size (frame, &w, &h);
244         }
245         m = MAX (w, h);
246         scale = MINI_PREVIEW_MAX_PIXELS / m;
247         m_canvas = MINI_PREVIEW_CANVAS_PIXELS / scale;
248
249         cr = cairo_create (surface);
250         cairo_surface_destroy (surface);
251
252         /* Clear pixbuf */
253         cairo_save (cr);
254         cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
255         cairo_paint (cr);
256         cairo_restore (cr);
257
258         cairo_set_antialias (cr, CAIRO_ANTIALIAS_GRAY);
259   
260         cairo_identity_matrix (cr);
261         cairo_translate (cr, MINI_PREVIEW_CANVAS_PIXELS/2, MINI_PREVIEW_CANVAS_PIXELS/2);
262         cairo_scale (cr, scale, scale);
263         cairo_translate (cr, -w/2.0, -h/2.0);
264
265         /*
266          * Shadow
267          */
268         cairo_save (cr);
269         cairo_translate (cr, SHADOW_X_OFFSET/scale, SHADOW_Y_OFFSET/scale);
270         gl_cairo_label_path (cr, template, rotate_flag, FALSE);
271
272         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (SHADOW_COLOR));
273         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
274         cairo_fill (cr);
275         cairo_restore (cr);
276
277         /*
278          * Label + outline
279          */
280         gl_cairo_label_path (cr, template, rotate_flag, FALSE);
281
282         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (FILL_COLOR));
283         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
284         cairo_fill_preserve (cr);
285
286         cairo_set_line_width (cr, LINE_WIDTH_PIXELS/scale);
287         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (LINE_COLOR));
288         cairo_stroke (cr);
289
290
291         cairo_destroy (cr);
292
293         return pixbuf;
294 }
295
296 /****************************************************************************/
297 /* query state of widget.                                                   */
298 /****************************************************************************/
299 gboolean
300 gl_wdgt_rotate_label_get_state (glWdgtRotateLabel *rotate_label)
301 {
302         return
303             gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
304                                           (rotate_label->priv->rotate_radio));
305 }
306
307 /****************************************************************************/
308 /* set state of widget.                                                     */
309 /****************************************************************************/
310 void
311 gl_wdgt_rotate_label_set_state (glWdgtRotateLabel *rotate_label,
312                                 gboolean state)
313 {
314         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
315                                       (rotate_label->priv->rotate_radio), state);
316 }
317
318 /****************************************************************************/
319 /* set template for widget.                                                 */
320 /****************************************************************************/
321 void
322 gl_wdgt_rotate_label_set_template_name (glWdgtRotateLabel *rotate_label,
323                                         gchar             *name)
324 {
325         lglTemplate               *template;
326         const lglTemplateFrame    *frame;
327         gdouble                    raw_w, raw_h;
328
329         if (name == NULL)
330         {
331                 rotate_label->priv->template = NULL;
332
333                 gtk_widget_set_sensitive (rotate_label->priv->no_rotate_radio, FALSE);
334                 gtk_widget_set_sensitive (rotate_label->priv->rotate_radio, FALSE);
335         }
336         else
337         {
338                 template = lgl_db_lookup_template_from_name (name);
339                 frame = (lglTemplateFrame *)template->frames->data;
340
341                 rotate_label->priv->template = template;
342                 lgl_template_frame_get_size (frame, &raw_w, &raw_h);
343
344                 gtk_image_set_from_pixbuf (GTK_IMAGE (rotate_label->priv->no_rotate_image),
345                                            create_pixbuf (rotate_label->priv->template, FALSE));
346                 gtk_image_set_from_pixbuf (GTK_IMAGE (rotate_label->priv->rotate_image),
347                                            create_pixbuf (rotate_label->priv->template, TRUE));
348
349                 gtk_widget_set_sensitive (rotate_label->priv->no_rotate_radio,
350                                           (raw_w != raw_h));
351                 gtk_widget_set_sensitive (rotate_label->priv->rotate_radio,
352                                           (raw_w != raw_h));
353
354                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
355                                               (rotate_label->priv->no_rotate_radio), TRUE);
356                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
357                                               (rotate_label->priv->rotate_radio), FALSE);
358
359         }
360
361 }
362