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