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 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 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 (glWdgtMiniPreview *preview,
279 glTemplate *template;
281 gdouble canvas_scale;
283 gdouble shadow_x, shadow_y;
285 gl_debug (DEBUG_MINI_PREVIEW, "START");
288 template = gl_template_from_name (name);
290 gl_debug (DEBUG_MINI_PREVIEW, "page_size = %s, page_width = %g, page_height = %g",
291 template->page_size, template->page_width, template->page_height);
293 /* get paper size and set scale */
294 w = preview->width - 4 - 2*SHADOW_X_OFFSET;
295 h = preview->height - 4 - 2*SHADOW_Y_OFFSET;
296 if ( (w/template->page_width) > (h/template->page_height) ) {
297 canvas_scale = h / template->page_height;
299 canvas_scale = w / template->page_width;
301 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas),
304 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
306 template->page_width, template->page_height);
308 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
310 preview->width/canvas_scale,
311 preview->height/canvas_scale);
315 shadow_x = SHADOW_X_OFFSET/canvas_scale;
316 shadow_y = SHADOW_Y_OFFSET/canvas_scale;
317 gnome_canvas_item_set (preview->shadow_item,
320 "x2", shadow_x + template->page_width,
321 "y2", shadow_y + template->page_height,
324 /* update paper outline */
325 gnome_canvas_item_set (preview->paper_item,
326 "x2", template->page_width,
327 "y2", template->page_height,
330 /* update label items */
331 mini_outline_list_free (&preview->label_items);
332 preview->label_items =
333 mini_outline_list_new (GNOME_CANVAS(preview->canvas),
336 gl_template_free( &template );
338 gl_debug (DEBUG_MINI_PREVIEW, "END");
341 /*--------------------------------------------------------------------------*/
342 /* PRIVATE. Draw label outlines and return canvas item list. */
343 /*--------------------------------------------------------------------------*/
345 mini_outline_list_new (GnomeCanvas *canvas,
346 glTemplate *template)
348 GnomeCanvasGroup *group = NULL;
349 GnomeCanvasItem *item = NULL;
352 glTemplateOrigin *origins;
353 gdouble x1, y1, x2, y2, w, h;
355 gl_debug (DEBUG_MINI_PREVIEW, "START");
357 group = gnome_canvas_root (canvas);
359 /* draw mini label outlines */
360 n_labels = gl_template_get_n_labels (template);
361 origins = gl_template_get_origins (template);
362 gl_template_get_label_size (template, &w, &h);
363 for ( i=0; i < n_labels; i++ ) {
370 switch (template->label.style) {
371 case GL_TEMPLATE_STYLE_RECT:
372 item = gnome_canvas_item_new (group,
373 gnome_canvas_rect_get_type(),
379 "outline_color", "black",
380 "fill_color", "white",
383 case GL_TEMPLATE_STYLE_ROUND:
384 item = gnome_canvas_item_new (group,
385 gnome_canvas_ellipse_get_type(),
391 "outline_color", "black",
392 "fill_color", "white",
395 case GL_TEMPLATE_STYLE_CD:
397 item = gnome_canvas_item_new (group,
398 gnome_canvas_ellipse_get_type(),
404 "outline_color", "black",
405 "fill_color", "white",
408 item = cdbc_item (group, x1, y1, template);
412 g_warning ("Unknown label style");
416 g_object_set_data (G_OBJECT (item), "i",
417 GINT_TO_POINTER (i+1));
419 list = g_list_append (list, item);
422 gl_debug (DEBUG_MINI_PREVIEW, "END");
426 /*--------------------------------------------------------------------------*/
427 /* PRIVATE. Draw label outlines and return canvas item list. */
428 /*--------------------------------------------------------------------------*/
430 mini_outline_list_free (GList ** list)
432 GnomeCanvasItem *item;
435 gl_debug (DEBUG_MINI_PREVIEW, "START");
437 if ( *list != NULL ) {
439 for (p = *list; p != NULL; p = p->next) {
440 item = GNOME_CANVAS_ITEM (p->data);
441 gtk_object_destroy (GTK_OBJECT (item));
449 gl_debug (DEBUG_MINI_PREVIEW, "END");
452 /*--------------------------------------------------------------------------*/
453 /* PRIVATE. Canvas event handler, select first and last items. */
454 /*--------------------------------------------------------------------------*/
456 canvas_event_cb (GnomeCanvas * canvas,
460 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
461 GnomeCanvasItem *item;
462 static gboolean dragging = FALSE;
463 static gint prev_i = 0, first, last;
467 gl_debug (DEBUG_MINI_PREVIEW, "START");
469 switch (event->type) {
471 case GDK_BUTTON_PRESS:
472 gnome_canvas_window_to_world (canvas,
473 event->button.x, event->button.y,
475 switch (event->button.button) {
477 /* Get item at cursor and make sure
478 it's a label object ("i" is valid) */
479 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
483 i = GPOINTER_TO_INT (g_object_get_data
484 (G_OBJECT (item), "i"));
487 /* Go into dragging mode while remains pressed. */
489 gnome_canvas_item_grab (canvas->root,
490 GDK_POINTER_MOTION_MASK |
491 GDK_BUTTON_RELEASE_MASK |
492 GDK_BUTTON_PRESS_MASK,
493 NULL, event->button.time);
494 g_signal_emit (G_OBJECT(preview),
495 wdgt_mini_preview_signals[CLICKED],
499 g_signal_emit (G_OBJECT(preview),
500 wdgt_mini_preview_signals[PRESSED],
510 case GDK_BUTTON_RELEASE:
511 gnome_canvas_window_to_world (canvas,
512 event->button.x, event->button.y,
514 switch (event->button.button) {
516 /* Exit dragging mode */
518 gnome_canvas_item_ungrab (canvas->root, event->button.time);
526 case GDK_MOTION_NOTIFY:
527 gnome_canvas_window_to_world (canvas,
528 event->motion.x, event->motion.y,
530 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
531 /* Get item at cursor and
532 make sure it's a label object ("i" is valid) */
533 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
537 i = GPOINTER_TO_INT (g_object_get_data
538 (G_OBJECT (item), "i"));
542 /* Entered into a new item */
544 g_signal_emit (G_OBJECT(preview),
545 wdgt_mini_preview_signals[PRESSED],
558 gl_debug (DEBUG_MINI_PREVIEW, "END");
563 /****************************************************************************/
564 /* Highlight given label outlines. */
565 /****************************************************************************/
567 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview *preview,
573 GnomeCanvasItem *item = NULL;
577 gl_debug (DEBUG_MINI_PREVIEW, "START");
579 style = gtk_widget_get_style (GTK_WIDGET(preview));
580 select_color = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
581 gl_debug (DEBUG_MINI_PREVIEW, "select color = 0x%08x", select_color);
583 for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
585 item = GNOME_CANVAS_ITEM (p->data);
587 if ((i >= first_label) && (i <= last_label)) {
588 gnome_canvas_item_set (item,
589 "fill_color_rgba", select_color,
592 gnome_canvas_item_set (item,
593 "fill_color", "white", NULL);
598 preview->highlight_first = first_label;
599 preview->highlight_last = last_label;
601 gl_debug (DEBUG_MINI_PREVIEW, "END");
604 /*--------------------------------------------------------------------------*/
605 /* PRIVATE. Refresh colors, if style changed. */
606 /*--------------------------------------------------------------------------*/
608 style_set_cb (GtkWidget *widget,
609 GtkStyle *previous_style,
612 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
616 style = gtk_widget_get_style (GTK_WIDGET(preview));
618 shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
619 gnome_canvas_item_set (preview->shadow_item,
620 "fill_color_rgba", shadow_color,
623 gl_wdgt_mini_preview_highlight_range (preview,
624 preview->highlight_first,
625 preview->highlight_last);
628 /*--------------------------------------------------------------------------*/
629 /* PRIVATE. Draw CD business card item (cut-off in w and/or h). */
630 /*--------------------------------------------------------------------------*/
631 static GnomeCanvasItem *
632 cdbc_item (GnomeCanvasGroup *group,
635 glTemplate *template)
637 GnomeCanvasPoints *points;
638 gint i_coords, i_theta;
639 gdouble theta1, theta2;
640 gdouble x0, y0, w, h, r;
641 GnomeCanvasItem *item;
643 gl_template_get_label_size (template, &w, &h);
644 r = template->label.cd.r1;
648 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
649 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
651 points = gnome_canvas_points_new (360/RES + 1);
654 points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
655 points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
657 for ( i_theta = theta1 + RES; i_theta < theta2; i_theta +=RES ) {
658 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
659 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
662 points->coords[i_coords++] = x0 + r * cos (theta2 * G_PI / 180.0);
663 points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
666 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
667 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
668 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
671 for ( i_theta = 180-theta2+RES; i_theta < (180-theta1); i_theta +=RES ) {
672 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
673 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
676 points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
677 points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
679 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
680 points->coords[i_coords++] = x0 + r * cos ((180+theta1) * G_PI / 180.0);
681 points->coords[i_coords++] = y0 + r * sin ((180+theta1) * G_PI / 180.0);
684 for ( i_theta = 180+theta1+RES; i_theta < (180+theta2); i_theta +=RES ) {
685 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
686 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
689 points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
690 points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
692 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
693 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
694 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
697 for ( i_theta = 360-theta2+RES; i_theta < (360-theta1); i_theta +=RES ) {
698 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
699 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
702 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
703 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
704 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
707 points->num_points = i_coords / 2;
710 item = gnome_canvas_item_new (group,
711 gnome_canvas_polygon_get_type (),
714 "outline_color", "black",
715 "fill_color", "white",
718 gnome_canvas_points_free (points);