]> git.sur5r.net Git - glabels/blob - glabels2/src/wdgt-mini-preview.c
Restructured template module to ultimately support multiple layouts and markups.
[glabels] / glabels2 / src / wdgt-mini-preview.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  wdgt_mini_preview.c:  mini preview widget module
5  *
6  *  Copyright (C) 2001  Jim Evins <evins@snaught.com>.
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 2 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, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <config.h>
24
25 #include "libgnomeprint/gnome-print-paper.h"
26
27 #include "wdgt-mini-preview.h"
28 #include "marshal.h"
29 #include "color.h"
30
31 #include "debug.h"
32
33 #define WDGT_MINI_PREVIEW_MAX_PIXELS 175
34 #define SHADOW_X_OFFSET 3
35 #define SHADOW_Y_OFFSET 3
36 #define SHADOW_COLOR GL_COLOR_A (33, 33, 33, 192)
37
38 /*===========================================*/
39 /* Private types                             */
40 /*===========================================*/
41
42 enum {
43         CLICKED,
44         PRESSED,
45         LAST_SIGNAL
46 };
47
48
49 /*===========================================*/
50 /* Private globals                           */
51 /*===========================================*/
52
53 static GtkContainerClass *parent_class;
54
55 static gint wdgt_mini_preview_signals[LAST_SIGNAL] = { 0 };
56
57 /*===========================================*/
58 /* Local function prototypes                 */
59 /*===========================================*/
60
61 static void gl_wdgt_mini_preview_class_init    (glWdgtMiniPreviewClass * class);
62 static void gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview);
63 static void gl_wdgt_mini_preview_finalize      (GObject * object);
64
65 static void gl_wdgt_mini_preview_construct     (glWdgtMiniPreview * preview,
66                                                 gint height, gint width);
67
68 static GList *mini_outline_list_new            (GnomeCanvas *canvas,
69                                                 glTemplate *template);
70 static void mini_outline_list_free             (GList ** list);
71
72 static gint canvas_event_cb                    (GnomeCanvas * canvas,
73                                                 GdkEvent * event,
74                                                 gpointer data);
75 \f
76 /****************************************************************************/
77 /* Boilerplate Object stuff.                                                */
78 /****************************************************************************/
79 guint
80 gl_wdgt_mini_preview_get_type (void)
81 {
82         static guint wdgt_mini_preview_type = 0;
83
84         if (!wdgt_mini_preview_type) {
85                 GTypeInfo wdgt_mini_preview_info = {
86                         sizeof (glWdgtMiniPreviewClass),
87                         NULL,
88                         NULL,
89                         (GClassInitFunc) gl_wdgt_mini_preview_class_init,
90                         NULL,
91                         NULL,
92                         sizeof (glWdgtMiniPreview),
93                         0,
94                         (GInstanceInitFunc) gl_wdgt_mini_preview_instance_init,
95                 };
96
97                 wdgt_mini_preview_type =
98                         g_type_register_static (gtk_hbox_get_type (),
99                                                 "glWdgtMiniPreview",
100                                                 &wdgt_mini_preview_info, 0);
101         }
102
103         return wdgt_mini_preview_type;
104 }
105
106 static void
107 gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass * class)
108 {
109         GObjectClass *object_class;
110
111         gl_debug (DEBUG_MINI_PREVIEW, "START");
112
113         object_class = (GObjectClass *) class;
114
115         parent_class = gtk_type_class (gtk_hbox_get_type ());
116
117         object_class->finalize = gl_wdgt_mini_preview_finalize;
118
119         wdgt_mini_preview_signals[CLICKED] =
120             g_signal_new ("clicked",
121                           G_OBJECT_CLASS_TYPE(object_class),
122                           G_SIGNAL_RUN_LAST,
123                           G_STRUCT_OFFSET (glWdgtMiniPreviewClass, clicked),
124                           NULL, NULL,
125                           gl_marshal_VOID__INT,
126                           G_TYPE_NONE, 1, G_TYPE_INT);
127
128         wdgt_mini_preview_signals[PRESSED] =
129             g_signal_new ("pressed",
130                           G_OBJECT_CLASS_TYPE(object_class),
131                           G_SIGNAL_RUN_LAST,
132                           G_STRUCT_OFFSET (glWdgtMiniPreviewClass, pressed),
133                           NULL, NULL,
134                           gl_marshal_VOID__INT_INT,
135                           G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
136
137         gl_debug (DEBUG_MINI_PREVIEW, "END");
138 }
139
140 static void
141 gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview)
142 {
143         gl_debug (DEBUG_MINI_PREVIEW, "START");
144
145         preview->canvas = NULL;
146         preview->label_items = NULL;
147
148         gl_debug (DEBUG_MINI_PREVIEW, "END");
149 }
150
151 static void
152 gl_wdgt_mini_preview_finalize (GObject * object)
153 {
154         glWdgtMiniPreview *preview;
155         glWdgtMiniPreviewClass *class;
156
157         gl_debug (DEBUG_MINI_PREVIEW, "START");
158
159         g_return_if_fail (object != NULL);
160         g_return_if_fail (GL_IS_WDGT_MINI_PREVIEW (object));
161
162         preview = GL_WDGT_MINI_PREVIEW (object);
163
164         G_OBJECT_CLASS (parent_class)->finalize (object);
165
166         gl_debug (DEBUG_MINI_PREVIEW, "END");
167 }
168
169 GtkWidget *
170 gl_wdgt_mini_preview_new (gint height,
171                           gint width)
172 {
173         glWdgtMiniPreview *preview;
174
175         gl_debug (DEBUG_MINI_PREVIEW, "START");
176
177         preview = g_object_new (gl_wdgt_mini_preview_get_type (), NULL);
178
179         gl_wdgt_mini_preview_construct (preview, height, width);
180
181         gl_debug (DEBUG_MINI_PREVIEW, "END");
182
183         return GTK_WIDGET (preview);
184 }
185
186 /*--------------------------------------------------------------------------*/
187 /* Construct composite widget.                                              */
188 /*--------------------------------------------------------------------------*/
189 static void
190 gl_wdgt_mini_preview_construct (glWdgtMiniPreview * preview,
191                                 gint height,
192                                 gint width)
193 {
194         GtkWidget *whbox;
195         GnomeCanvasGroup *group;
196
197         gl_debug (DEBUG_MINI_PREVIEW, "START");
198
199         whbox = GTK_WIDGET (preview);
200
201         preview->height = height;
202         preview->width  = width;
203
204         /* create canvas */
205         gtk_widget_push_colormap (gdk_rgb_get_colormap ());
206         preview->canvas = gnome_canvas_new_aa ();
207         gtk_widget_pop_colormap ();
208         gtk_box_pack_start (GTK_BOX (whbox), preview->canvas, TRUE, TRUE, 0);
209         gtk_widget_set_size_request (preview->canvas, width, height);
210         gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
211                                         0.0, 0.0, width, height);
212
213         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas), 1.0);
214         group = gnome_canvas_root (GNOME_CANVAS (preview->canvas));
215
216         /* draw shadow */
217         preview->shadow_item =
218                 gnome_canvas_item_new (group,
219                                        gnome_canvas_rect_get_type (),
220                                        "x1", (gdouble)SHADOW_X_OFFSET,
221                                        "y1", (gdouble)SHADOW_Y_OFFSET,
222                                        "x2", (gdouble)(SHADOW_X_OFFSET + width),
223                                        "y2", (gdouble)(SHADOW_Y_OFFSET + height),
224                                        "fill_color_rgba", SHADOW_COLOR,
225                                        NULL);
226
227         /* draw an initial paper outline */
228         preview->paper_item =
229                 gnome_canvas_item_new (group,
230                                        gnome_canvas_rect_get_type (),
231                                        "x1", 0.0,
232                                        "y1", 0.0,
233                                        "x2", (gdouble)width,
234                                        "y2", (gdouble)height,
235                                        "width_pixels", 1,
236                                        "outline_color", "black",
237                                        "fill_color", "white",
238                                        NULL);
239
240         /* create empty list of label canvas items */
241         preview->label_items = NULL;
242         preview->labels_per_sheet = 0;
243
244         /* Event handler */
245         g_signal_connect (G_OBJECT (preview->canvas), "event",
246                           G_CALLBACK (canvas_event_cb), preview);
247
248         gl_debug (DEBUG_MINI_PREVIEW, "END");
249 }
250
251 /****************************************************************************/
252 /* Set label for mini-preview to determine geometry.                        */
253 /****************************************************************************/
254 void gl_wdgt_mini_preview_set_label (glWdgtMiniPreview * preview,
255                                      gchar *name)
256 {
257         glTemplate *template;
258         gchar *page_size;
259         const GnomePrintPaper *paper = NULL;
260         gdouble paper_width, paper_height;
261         gdouble canvas_scale;
262         gdouble w, h;
263         gdouble shadow_x, shadow_y;
264
265         gl_debug (DEBUG_MINI_PREVIEW, "START");
266
267         /* Fetch template */
268         template = gl_template_from_name (name);
269
270         /* get paper size and set scale */
271         paper = gnome_print_paper_get_by_name (template->page_size);
272         paper_width = paper->width;
273         paper_height = paper->height;
274         w = preview->width - 4 - 2*SHADOW_X_OFFSET;
275         h = preview->height - 4 - 2*SHADOW_Y_OFFSET;
276         if ( (w/paper_width) > (h/paper_height) ) {
277                 canvas_scale = h / paper_height;
278         } else {
279                 canvas_scale = w / paper_width;
280         }
281         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas),
282                                           canvas_scale);
283         gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
284                                         0.0, 0.0, paper_width, paper_height);
285
286         /* update shadow */
287         shadow_x = SHADOW_X_OFFSET/canvas_scale;
288         shadow_y = SHADOW_Y_OFFSET/canvas_scale;
289         gnome_canvas_item_set (preview->shadow_item,
290                                "x1", shadow_x,
291                                "y1", shadow_y,
292                                "x2", shadow_x + paper_width,
293                                "y2", shadow_y + paper_height,
294                                NULL);
295
296         /* update paper outline */
297         gnome_canvas_item_set (preview->paper_item,
298                                "x2", paper_width,
299                                "y2", paper_height,
300                                NULL);
301
302         /* update label items */
303         mini_outline_list_free (&preview->label_items);
304         preview->label_items =
305                 mini_outline_list_new (GNOME_CANVAS(preview->canvas),
306                                        template);
307
308         gl_template_free( &template );
309         
310         gl_debug (DEBUG_MINI_PREVIEW, "END");
311 }
312
313 /*--------------------------------------------------------------------------*/
314 /* PRIVATE.  Draw label outlines and return canvas item list.               */
315 /*--------------------------------------------------------------------------*/
316 static GList *
317 mini_outline_list_new (GnomeCanvas *canvas,
318                        glTemplate  *template)
319 {
320         GnomeCanvasGroup      *group = NULL;
321         GnomeCanvasItem       *item = NULL;
322         GList                 *list = NULL;
323         gint                   i, n_labels;
324         glTemplateOrigin      *origins;
325         gdouble                x1, y1, x2, y2, y_temp, w, h;
326         const GnomePrintPaper *paper = NULL;
327         gdouble                paper_height;
328
329         gl_debug (DEBUG_MINI_PREVIEW, "START");
330
331         /* get paper height */
332         paper = gnome_print_paper_get_by_name  (template->page_size);
333         paper_height = paper->height;
334
335         group = gnome_canvas_root (canvas);
336
337         /* draw mini label outlines */
338         n_labels = gl_template_get_n_labels (template);
339         origins  = gl_template_get_origins (template);
340         gl_template_get_label_size (template, &w, &h);
341         for ( i=0; i < n_labels; i++ ) {
342
343                 x1 = origins[i].x;
344                 y1 = origins[i].y;
345                 x2 = x1 + w;
346                 y2 = y1 + h;
347
348                 /* transform origin from lower left to upper left */
349                 /* and swap y's so that (y1 < y2) */
350                 y_temp = y2;
351                 y2 = paper_height - y1;
352                 y1 = paper_height - y_temp;
353
354                 switch (template->label.style) {
355                 case GL_TEMPLATE_STYLE_RECT:
356                         item = gnome_canvas_item_new (group,
357                                                       gnome_canvas_rect_get_type(),
358                                                       "x1", x1,
359                                                       "y1", y1,
360                                                       "x2", x2,
361                                                       "y2", y2,
362                                                       "width_pixels", 1,
363                                                       "outline_color", "black",
364                                                       "fill_color", "white",
365                                                       NULL);
366                         break;
367                 case GL_TEMPLATE_STYLE_ROUND:
368                 case GL_TEMPLATE_STYLE_CD:
369                         item = gnome_canvas_item_new (group,
370                                                       gnome_canvas_ellipse_get_type(),
371                                                       "x1", x1,
372                                                       "y1", y1,
373                                                       "x2", x2,
374                                                       "y2", y2,
375                                                       "width_pixels", 1,
376                                                       "outline_color", "black",
377                                                       "fill_color", "white",
378                                                       NULL);
379                         break;
380                 default:
381                         g_warning ("Unknown label style");
382                         return list;
383                         break;
384                 }
385                 g_object_set_data (G_OBJECT (item), "i",
386                                    GINT_TO_POINTER (i));
387                 
388                 list = g_list_append (list, item);
389         }
390
391         gl_debug (DEBUG_MINI_PREVIEW, "END");
392         return list;
393 }
394
395 /*--------------------------------------------------------------------------*/
396 /* PRIVATE.  Draw label outlines and return canvas item list.               */
397 /*--------------------------------------------------------------------------*/
398 static void
399 mini_outline_list_free (GList ** list)
400 {
401         GnomeCanvasItem *item;
402         GList *p;
403
404         gl_debug (DEBUG_MINI_PREVIEW, "START");
405
406         if ( *list != NULL ) {
407
408                 for (p = *list; p != NULL; p = p->next) {
409                         item = GNOME_CANVAS_ITEM (p->data);
410                         gtk_object_destroy (GTK_OBJECT (item));
411                 }
412
413                 g_list_free (*list);
414                 *list = NULL;
415
416         }
417
418         gl_debug (DEBUG_MINI_PREVIEW, "END");
419 }
420
421 /*--------------------------------------------------------------------------*/
422 /* PRIVATE.  Canvas event handler, select first and last items.             */
423 /*--------------------------------------------------------------------------*/
424 static gint
425 canvas_event_cb (GnomeCanvas * canvas,
426                  GdkEvent * event,
427                  gpointer data)
428 {
429         glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
430         GnomeCanvasItem *item;
431         static gboolean dragging = FALSE;
432         static gint prev_i = 0, first, last;
433         gint i;
434         gdouble x, y;
435
436         gl_debug (DEBUG_MINI_PREVIEW, "START");
437
438         switch (event->type) {
439
440         case GDK_BUTTON_PRESS:
441                 gnome_canvas_window_to_world (canvas,
442                                               event->button.x, event->button.y,
443                                               &x, &y);
444                 switch (event->button.button) {
445                 case 1:
446                         /* Get item at cursor and make sure
447                            it's a label object ("i" is valid) */
448                         item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
449                                                          x, y);
450                         if (item == NULL)
451                                 break;
452                         i = GPOINTER_TO_INT (g_object_get_data
453                                              (G_OBJECT (item), "i"));
454                         if (i == 0)
455                                 break;
456                         /* Go into dragging mode while remains pressed. */
457                         dragging = TRUE;
458                         gdk_pointer_grab (GTK_WIDGET (canvas)->window,
459                                           FALSE,
460                                           GDK_POINTER_MOTION_MASK |
461                                           GDK_BUTTON_RELEASE_MASK |
462                                           GDK_BUTTON_PRESS_MASK, NULL, NULL,
463                                           event->button.time);
464                         g_signal_emit (G_OBJECT(preview),
465                                        wdgt_mini_preview_signals[CLICKED],
466                                        0, i);
467                         first = i;
468                         last = i;
469                         g_signal_emit (G_OBJECT(preview),
470                                        wdgt_mini_preview_signals[PRESSED],
471                                        0, first, last);
472                         prev_i = i;
473                         break;
474
475                 default:
476                         break;
477                 }
478                 break;
479
480         case GDK_BUTTON_RELEASE:
481                 gnome_canvas_window_to_world (canvas,
482                                               event->button.x, event->button.y,
483                                               &x, &y);
484                 switch (event->button.button) {
485                 case 1:
486                         /* Exit dragging mode */
487                         dragging = FALSE;
488                         gdk_pointer_ungrab (event->button.time);
489                         break;
490
491                 default:
492                         break;
493                 }
494                 break;
495
496         case GDK_MOTION_NOTIFY:
497                 gnome_canvas_window_to_world (canvas,
498                                               event->motion.x, event->motion.y,
499                                               &x, &y);
500                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
501                         /* Get item at cursor and
502                            make sure it's a label object ("i" is valid) */
503                         item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
504                                                          x, y);
505                         if (item == NULL)
506                                 break;
507                         i = GPOINTER_TO_INT (g_object_get_data
508                                              (G_OBJECT (item), "i"));
509                         if (i == 0)
510                                 break;
511                         if (prev_i != i) {
512                                 /* Entered into a new item */
513                                 last = i;
514                                 g_signal_emit (G_OBJECT(preview),
515                                                wdgt_mini_preview_signals[PRESSED],
516                                                0,
517                                                MIN (first, last),
518                                                MAX (first, last));
519                                 prev_i = i;
520                         }
521                 }
522                 break;
523
524         default:
525                 break;
526         }
527
528         gl_debug (DEBUG_MINI_PREVIEW, "END");
529
530         return FALSE;
531 }
532
533 /****************************************************************************/
534 /* Highlight given label outlines.                                          */
535 /****************************************************************************/
536 void
537 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview * preview,
538                                       gint first_label,
539                                       gint last_label)
540 {
541         GnomeCanvasItem *item = NULL;
542         GList *p = NULL;
543         gint i;
544
545         gl_debug (DEBUG_MINI_PREVIEW, "START");
546
547         for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
548
549                 item = GNOME_CANVAS_ITEM (p->data);
550
551                 if ((i >= first_label) && (i <= last_label)) {
552                         gnome_canvas_item_set (item,
553                                                "fill_color", "light blue",
554                                                NULL);
555                 } else {
556                         gnome_canvas_item_set (item,
557                                                "fill_color", "white", NULL);
558                 }
559
560         }
561
562         gl_debug (DEBUG_MINI_PREVIEW, "END");
563 }
564