2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * wdgt_mini_preview.c: mini preview widget module
6 * Copyright (C) 2001 Jim Evins <evins@snaught.com>.
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.
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.
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
27 #include "wdgt-mini-preview.h"
33 #define WDGT_MINI_PREVIEW_MAX_PIXELS 175
34 #define SHADOW_X_OFFSET 5
35 #define SHADOW_Y_OFFSET 5
37 #define RES 5 /* Resolution in degrees for Business Card CD outlines */
39 /*===========================================*/
41 /*===========================================*/
50 /*===========================================*/
52 /*===========================================*/
54 static GtkContainerClass *parent_class;
56 static gint wdgt_mini_preview_signals[LAST_SIGNAL] = { 0 };
58 /*===========================================*/
59 /* Local function prototypes */
60 /*===========================================*/
62 static void gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass * class);
63 static void gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview);
64 static void gl_wdgt_mini_preview_finalize (GObject * object);
66 static void gl_wdgt_mini_preview_construct (glWdgtMiniPreview * preview,
67 gint height, gint width);
69 static GList *mini_outline_list_new (GnomeCanvas *canvas,
70 const glTemplate *template);
71 static void mini_outline_list_free (GList ** list);
73 static gint canvas_event_cb (GnomeCanvas * canvas,
77 static GnomeCanvasItem *cdbc_item (GnomeCanvasGroup *group,
80 const glTemplate *template);
82 static void style_set_cb (GtkWidget *widget,
83 GtkStyle *previous_style,
89 /****************************************************************************/
90 /* Boilerplate Object stuff. */
91 /****************************************************************************/
93 gl_wdgt_mini_preview_get_type (void)
95 static guint wdgt_mini_preview_type = 0;
97 if (!wdgt_mini_preview_type) {
98 GTypeInfo wdgt_mini_preview_info = {
99 sizeof (glWdgtMiniPreviewClass),
102 (GClassInitFunc) gl_wdgt_mini_preview_class_init,
105 sizeof (glWdgtMiniPreview),
107 (GInstanceInitFunc) gl_wdgt_mini_preview_instance_init,
110 wdgt_mini_preview_type =
111 g_type_register_static (gtk_hbox_get_type (),
113 &wdgt_mini_preview_info, 0);
116 return wdgt_mini_preview_type;
120 gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass * class)
122 GObjectClass *object_class;
124 gl_debug (DEBUG_MINI_PREVIEW, "START");
126 object_class = (GObjectClass *) class;
128 parent_class = gtk_type_class (gtk_hbox_get_type ());
130 object_class->finalize = gl_wdgt_mini_preview_finalize;
132 wdgt_mini_preview_signals[CLICKED] =
133 g_signal_new ("clicked",
134 G_OBJECT_CLASS_TYPE(object_class),
136 G_STRUCT_OFFSET (glWdgtMiniPreviewClass, clicked),
138 gl_marshal_VOID__INT,
139 G_TYPE_NONE, 1, G_TYPE_INT);
141 wdgt_mini_preview_signals[PRESSED] =
142 g_signal_new ("pressed",
143 G_OBJECT_CLASS_TYPE(object_class),
145 G_STRUCT_OFFSET (glWdgtMiniPreviewClass, pressed),
147 gl_marshal_VOID__INT_INT,
148 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
150 gl_debug (DEBUG_MINI_PREVIEW, "END");
154 gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview)
156 gl_debug (DEBUG_MINI_PREVIEW, "START");
158 preview->canvas = NULL;
159 preview->label_items = NULL;
161 gl_debug (DEBUG_MINI_PREVIEW, "END");
165 gl_wdgt_mini_preview_finalize (GObject * object)
167 glWdgtMiniPreview *preview;
168 glWdgtMiniPreviewClass *class;
170 gl_debug (DEBUG_MINI_PREVIEW, "START");
172 g_return_if_fail (object != NULL);
173 g_return_if_fail (GL_IS_WDGT_MINI_PREVIEW (object));
175 preview = GL_WDGT_MINI_PREVIEW (object);
177 G_OBJECT_CLASS (parent_class)->finalize (object);
179 gl_debug (DEBUG_MINI_PREVIEW, "END");
183 gl_wdgt_mini_preview_new (gint height,
186 glWdgtMiniPreview *preview;
188 gl_debug (DEBUG_MINI_PREVIEW, "START");
190 preview = g_object_new (gl_wdgt_mini_preview_get_type (), NULL);
192 gl_wdgt_mini_preview_construct (preview, height, width);
194 gl_debug (DEBUG_MINI_PREVIEW, "END");
196 return GTK_WIDGET (preview);
199 /*--------------------------------------------------------------------------*/
200 /* Construct composite widget. */
201 /*--------------------------------------------------------------------------*/
203 gl_wdgt_mini_preview_construct (glWdgtMiniPreview * preview,
208 GnomeCanvasGroup *group;
212 gl_debug (DEBUG_MINI_PREVIEW, "START");
214 whbox = GTK_WIDGET (preview);
216 preview->height = height;
217 preview->width = width;
220 gtk_widget_push_colormap (gdk_rgb_get_colormap ());
221 preview->canvas = gnome_canvas_new_aa ();
222 gtk_widget_pop_colormap ();
223 gtk_box_pack_start (GTK_BOX (whbox), preview->canvas, TRUE, TRUE, 0);
224 gtk_widget_set_size_request (preview->canvas, width, height);
225 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
226 0.0, 0.0, width, height);
228 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas), 1.0);
229 group = gnome_canvas_root (GNOME_CANVAS (preview->canvas));
232 style = gtk_widget_get_style (GTK_WIDGET(preview));
233 shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
234 preview->shadow_item =
235 gnome_canvas_item_new (group,
236 gnome_canvas_rect_get_type (),
237 "x1", (gdouble)SHADOW_X_OFFSET,
238 "y1", (gdouble)SHADOW_Y_OFFSET,
239 "x2", (gdouble)(SHADOW_X_OFFSET + width),
240 "y2", (gdouble)(SHADOW_Y_OFFSET + height),
241 "fill_color_rgba", shadow_color,
244 /* draw an initial paper outline */
245 preview->paper_item =
246 gnome_canvas_item_new (group,
247 gnome_canvas_rect_get_type (),
250 "x2", (gdouble)width,
251 "y2", (gdouble)height,
253 "outline_color", "black",
254 "fill_color", "white",
257 /* create empty list of label canvas items */
258 preview->label_items = NULL;
259 preview->labels_per_sheet = 0;
262 g_signal_connect (G_OBJECT (preview->canvas), "event",
263 G_CALLBACK (canvas_event_cb), preview);
266 /* Style changed handler */
267 g_signal_connect (G_OBJECT (preview), "style_set",
268 G_CALLBACK (style_set_cb), NULL);
270 gl_debug (DEBUG_MINI_PREVIEW, "END");
273 /****************************************************************************/
274 /* Set label for mini-preview to determine geometry. */
275 /****************************************************************************/
276 void gl_wdgt_mini_preview_set_label_by_name (glWdgtMiniPreview *preview,
279 glTemplate *template;
281 gl_debug (DEBUG_MINI_PREVIEW, "START");
284 template = gl_template_from_name (name);
286 gl_wdgt_mini_preview_set_template (preview, template);
288 gl_template_free (template);
290 gl_debug (DEBUG_MINI_PREVIEW, "END");
293 /****************************************************************************/
294 /* Set label for mini-preview to determine geometry. */
295 /****************************************************************************/
296 void gl_wdgt_mini_preview_set_template (glWdgtMiniPreview *preview,
297 const glTemplate *template)
300 gdouble canvas_scale;
302 gdouble offset_x, offset_y;
303 gdouble shadow_x, shadow_y;
305 gl_debug (DEBUG_MINI_PREVIEW, "START");
307 gl_debug (DEBUG_MINI_PREVIEW, "page_size = %s, page_width = %g, page_height = %g",
308 template->page_size, template->page_width, template->page_height);
310 /* get paper size and set scale */
311 w = preview->width - 4 - 2*SHADOW_X_OFFSET;
312 h = preview->height - 4 - 2*SHADOW_Y_OFFSET;
313 if ( (w/template->page_width) > (h/template->page_height) ) {
314 canvas_scale = h / template->page_height;
316 canvas_scale = w / template->page_width;
318 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas),
320 offset_x = (preview->width/canvas_scale - template->page_width) / 2.0;
321 offset_y = (preview->height/canvas_scale - template->page_height) / 2.0;
323 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
324 -offset_x, -offset_y,
325 preview->width/canvas_scale - offset_x,
326 preview->height/canvas_scale - offset_y);
329 shadow_x = SHADOW_X_OFFSET/canvas_scale;
330 shadow_y = SHADOW_Y_OFFSET/canvas_scale;
331 gnome_canvas_item_set (preview->shadow_item,
334 "x2", shadow_x + template->page_width,
335 "y2", shadow_y + template->page_height,
338 /* update paper outline */
339 gnome_canvas_item_set (preview->paper_item,
340 "x2", template->page_width,
341 "y2", template->page_height,
344 /* update label items */
345 mini_outline_list_free (&preview->label_items);
346 preview->label_items =
347 mini_outline_list_new (GNOME_CANVAS(preview->canvas),
350 gl_debug (DEBUG_MINI_PREVIEW, "END");
353 /*--------------------------------------------------------------------------*/
354 /* PRIVATE. Draw label outlines and return canvas item list. */
355 /*--------------------------------------------------------------------------*/
357 mini_outline_list_new (GnomeCanvas *canvas,
358 const glTemplate *template)
360 GnomeCanvasGroup *group = NULL;
361 const glTemplateLabelType *label_type;
362 GnomeCanvasItem *item = NULL;
365 glTemplateOrigin *origins;
366 gdouble x1, y1, x2, y2, w, h;
368 gl_debug (DEBUG_MINI_PREVIEW, "START");
370 group = gnome_canvas_root (canvas);
372 label_type = gl_template_get_first_label_type (template);
374 /* draw mini label outlines */
375 n_labels = gl_template_get_n_labels (label_type);
376 origins = gl_template_get_origins (label_type);
377 gl_template_get_label_size (label_type, &w, &h);
378 for ( i=0; i < n_labels; i++ ) {
385 switch (label_type->shape) {
386 case GL_TEMPLATE_SHAPE_RECT:
387 item = gnome_canvas_item_new (group,
388 gnome_canvas_rect_get_type(),
394 "outline_color", "black",
395 "fill_color", "white",
398 case GL_TEMPLATE_SHAPE_ROUND:
399 item = gnome_canvas_item_new (group,
400 gnome_canvas_ellipse_get_type(),
406 "outline_color", "black",
407 "fill_color", "white",
410 case GL_TEMPLATE_SHAPE_CD:
412 item = gnome_canvas_item_new (group,
413 gnome_canvas_ellipse_get_type(),
419 "outline_color", "black",
420 "fill_color", "white",
423 item = cdbc_item (group, x1, y1, template);
427 g_warning ("Unknown label style");
431 g_object_set_data (G_OBJECT (item), "i",
432 GINT_TO_POINTER (i+1));
434 list = g_list_append (list, item);
437 gl_debug (DEBUG_MINI_PREVIEW, "END");
441 /*--------------------------------------------------------------------------*/
442 /* PRIVATE. Draw label outlines and return canvas item list. */
443 /*--------------------------------------------------------------------------*/
445 mini_outline_list_free (GList ** list)
447 GnomeCanvasItem *item;
450 gl_debug (DEBUG_MINI_PREVIEW, "START");
452 if ( *list != NULL ) {
454 for (p = *list; p != NULL; p = p->next) {
455 item = GNOME_CANVAS_ITEM (p->data);
456 gtk_object_destroy (GTK_OBJECT (item));
464 gl_debug (DEBUG_MINI_PREVIEW, "END");
467 /*--------------------------------------------------------------------------*/
468 /* PRIVATE. Canvas event handler, select first and last items. */
469 /*--------------------------------------------------------------------------*/
471 canvas_event_cb (GnomeCanvas * canvas,
475 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
476 GnomeCanvasItem *item;
477 static gboolean dragging = FALSE;
478 static gint prev_i = 0, first, last;
482 gl_debug (DEBUG_MINI_PREVIEW, "START");
484 switch (event->type) {
486 case GDK_BUTTON_PRESS:
487 gnome_canvas_window_to_world (canvas,
488 event->button.x, event->button.y,
490 switch (event->button.button) {
492 /* Get item at cursor and make sure
493 it's a label object ("i" is valid) */
494 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
498 i = GPOINTER_TO_INT (g_object_get_data
499 (G_OBJECT (item), "i"));
502 /* Go into dragging mode while remains pressed. */
504 gnome_canvas_item_grab (canvas->root,
505 GDK_POINTER_MOTION_MASK |
506 GDK_BUTTON_RELEASE_MASK |
507 GDK_BUTTON_PRESS_MASK,
508 NULL, event->button.time);
509 g_signal_emit (G_OBJECT(preview),
510 wdgt_mini_preview_signals[CLICKED],
514 g_signal_emit (G_OBJECT(preview),
515 wdgt_mini_preview_signals[PRESSED],
525 case GDK_BUTTON_RELEASE:
526 gnome_canvas_window_to_world (canvas,
527 event->button.x, event->button.y,
529 switch (event->button.button) {
531 /* Exit dragging mode */
533 gnome_canvas_item_ungrab (canvas->root, event->button.time);
541 case GDK_MOTION_NOTIFY:
542 gnome_canvas_window_to_world (canvas,
543 event->motion.x, event->motion.y,
545 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
546 /* Get item at cursor and
547 make sure it's a label object ("i" is valid) */
548 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
552 i = GPOINTER_TO_INT (g_object_get_data
553 (G_OBJECT (item), "i"));
557 /* Entered into a new item */
559 g_signal_emit (G_OBJECT(preview),
560 wdgt_mini_preview_signals[PRESSED],
573 gl_debug (DEBUG_MINI_PREVIEW, "END");
578 /****************************************************************************/
579 /* Highlight given label outlines. */
580 /****************************************************************************/
582 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview *preview,
588 GnomeCanvasItem *item = NULL;
592 gl_debug (DEBUG_MINI_PREVIEW, "START");
594 style = gtk_widget_get_style (GTK_WIDGET(preview));
595 select_color = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
596 gl_debug (DEBUG_MINI_PREVIEW, "select color = 0x%08x", select_color);
598 for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
600 item = GNOME_CANVAS_ITEM (p->data);
602 if ((i >= first_label) && (i <= last_label)) {
603 gnome_canvas_item_set (item,
604 "fill_color_rgba", select_color,
607 gnome_canvas_item_set (item,
608 "fill_color", "white", NULL);
613 preview->highlight_first = first_label;
614 preview->highlight_last = last_label;
616 gl_debug (DEBUG_MINI_PREVIEW, "END");
619 /*--------------------------------------------------------------------------*/
620 /* PRIVATE. Refresh colors, if style changed. */
621 /*--------------------------------------------------------------------------*/
623 style_set_cb (GtkWidget *widget,
624 GtkStyle *previous_style,
627 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
631 style = gtk_widget_get_style (GTK_WIDGET(preview));
633 shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
634 gnome_canvas_item_set (preview->shadow_item,
635 "fill_color_rgba", shadow_color,
638 gl_wdgt_mini_preview_highlight_range (preview,
639 preview->highlight_first,
640 preview->highlight_last);
643 /*--------------------------------------------------------------------------*/
644 /* PRIVATE. Draw CD business card item (cut-off in w and/or h). */
645 /*--------------------------------------------------------------------------*/
646 static GnomeCanvasItem *
647 cdbc_item (GnomeCanvasGroup *group,
650 const glTemplate *template)
652 const glTemplateLabelType *label_type;
653 GnomeCanvasPoints *points;
654 gint i_coords, i_theta;
655 gdouble theta1, theta2;
656 gdouble x0, y0, w, h, r;
657 GnomeCanvasItem *item;
659 label_type = gl_template_get_first_label_type (template);
661 gl_template_get_label_size (label_type, &w, &h);
662 r = label_type->size.cd.r1;
666 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
667 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
669 points = gnome_canvas_points_new (360/RES + 1);
672 points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
673 points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
675 for ( i_theta = theta1 + RES; i_theta < theta2; i_theta +=RES ) {
676 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
677 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
680 points->coords[i_coords++] = x0 + r * cos (theta2 * G_PI / 180.0);
681 points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
684 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
685 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
686 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
689 for ( i_theta = 180-theta2+RES; i_theta < (180-theta1); i_theta +=RES ) {
690 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
691 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
694 points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
695 points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
697 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
698 points->coords[i_coords++] = x0 + r * cos ((180+theta1) * G_PI / 180.0);
699 points->coords[i_coords++] = y0 + r * sin ((180+theta1) * G_PI / 180.0);
702 for ( i_theta = 180+theta1+RES; i_theta < (180+theta2); i_theta +=RES ) {
703 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
704 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
707 points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
708 points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
710 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
711 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
712 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
715 for ( i_theta = 360-theta2+RES; i_theta < (360-theta1); i_theta +=RES ) {
716 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
717 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
720 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
721 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
722 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
725 points->num_points = i_coords / 2;
728 item = gnome_canvas_item_new (group,
729 gnome_canvas_polygon_get_type (),
732 "outline_color", "black",
733 "fill_color", "white",
736 gnome_canvas_points_free (points);
741 /****************************************************************************/
742 /* Change/set background color of preview. */
743 /****************************************************************************/
745 gl_wdgt_mini_preview_set_bg_color (glWdgtMiniPreview *preview,
750 gdk_color = gl_color_to_gdk_color (color);
751 gtk_widget_modify_bg (GTK_WIDGET(preview->canvas), GTK_STATE_NORMAL, gdk_color);