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 GnomeCanvasItem *item = NULL;
364 glTemplateOrigin *origins;
365 gdouble x1, y1, x2, y2, w, h;
367 gl_debug (DEBUG_MINI_PREVIEW, "START");
369 group = gnome_canvas_root (canvas);
371 /* draw mini label outlines */
372 n_labels = gl_template_get_n_labels (template);
373 origins = gl_template_get_origins (template);
374 gl_template_get_label_size (template, &w, &h);
375 for ( i=0; i < n_labels; i++ ) {
382 switch (template->label.style) {
383 case GL_TEMPLATE_STYLE_RECT:
384 item = gnome_canvas_item_new (group,
385 gnome_canvas_rect_get_type(),
391 "outline_color", "black",
392 "fill_color", "white",
395 case GL_TEMPLATE_STYLE_ROUND:
396 item = gnome_canvas_item_new (group,
397 gnome_canvas_ellipse_get_type(),
403 "outline_color", "black",
404 "fill_color", "white",
407 case GL_TEMPLATE_STYLE_CD:
409 item = gnome_canvas_item_new (group,
410 gnome_canvas_ellipse_get_type(),
416 "outline_color", "black",
417 "fill_color", "white",
420 item = cdbc_item (group, x1, y1, template);
424 g_warning ("Unknown label style");
428 g_object_set_data (G_OBJECT (item), "i",
429 GINT_TO_POINTER (i+1));
431 list = g_list_append (list, item);
434 gl_debug (DEBUG_MINI_PREVIEW, "END");
438 /*--------------------------------------------------------------------------*/
439 /* PRIVATE. Draw label outlines and return canvas item list. */
440 /*--------------------------------------------------------------------------*/
442 mini_outline_list_free (GList ** list)
444 GnomeCanvasItem *item;
447 gl_debug (DEBUG_MINI_PREVIEW, "START");
449 if ( *list != NULL ) {
451 for (p = *list; p != NULL; p = p->next) {
452 item = GNOME_CANVAS_ITEM (p->data);
453 gtk_object_destroy (GTK_OBJECT (item));
461 gl_debug (DEBUG_MINI_PREVIEW, "END");
464 /*--------------------------------------------------------------------------*/
465 /* PRIVATE. Canvas event handler, select first and last items. */
466 /*--------------------------------------------------------------------------*/
468 canvas_event_cb (GnomeCanvas * canvas,
472 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
473 GnomeCanvasItem *item;
474 static gboolean dragging = FALSE;
475 static gint prev_i = 0, first, last;
479 gl_debug (DEBUG_MINI_PREVIEW, "START");
481 switch (event->type) {
483 case GDK_BUTTON_PRESS:
484 gnome_canvas_window_to_world (canvas,
485 event->button.x, event->button.y,
487 switch (event->button.button) {
489 /* Get item at cursor and make sure
490 it's a label object ("i" is valid) */
491 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
495 i = GPOINTER_TO_INT (g_object_get_data
496 (G_OBJECT (item), "i"));
499 /* Go into dragging mode while remains pressed. */
501 gnome_canvas_item_grab (canvas->root,
502 GDK_POINTER_MOTION_MASK |
503 GDK_BUTTON_RELEASE_MASK |
504 GDK_BUTTON_PRESS_MASK,
505 NULL, event->button.time);
506 g_signal_emit (G_OBJECT(preview),
507 wdgt_mini_preview_signals[CLICKED],
511 g_signal_emit (G_OBJECT(preview),
512 wdgt_mini_preview_signals[PRESSED],
522 case GDK_BUTTON_RELEASE:
523 gnome_canvas_window_to_world (canvas,
524 event->button.x, event->button.y,
526 switch (event->button.button) {
528 /* Exit dragging mode */
530 gnome_canvas_item_ungrab (canvas->root, event->button.time);
538 case GDK_MOTION_NOTIFY:
539 gnome_canvas_window_to_world (canvas,
540 event->motion.x, event->motion.y,
542 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
543 /* Get item at cursor and
544 make sure it's a label object ("i" is valid) */
545 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
549 i = GPOINTER_TO_INT (g_object_get_data
550 (G_OBJECT (item), "i"));
554 /* Entered into a new item */
556 g_signal_emit (G_OBJECT(preview),
557 wdgt_mini_preview_signals[PRESSED],
570 gl_debug (DEBUG_MINI_PREVIEW, "END");
575 /****************************************************************************/
576 /* Highlight given label outlines. */
577 /****************************************************************************/
579 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview *preview,
585 GnomeCanvasItem *item = NULL;
589 gl_debug (DEBUG_MINI_PREVIEW, "START");
591 style = gtk_widget_get_style (GTK_WIDGET(preview));
592 select_color = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
593 gl_debug (DEBUG_MINI_PREVIEW, "select color = 0x%08x", select_color);
595 for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
597 item = GNOME_CANVAS_ITEM (p->data);
599 if ((i >= first_label) && (i <= last_label)) {
600 gnome_canvas_item_set (item,
601 "fill_color_rgba", select_color,
604 gnome_canvas_item_set (item,
605 "fill_color", "white", NULL);
610 preview->highlight_first = first_label;
611 preview->highlight_last = last_label;
613 gl_debug (DEBUG_MINI_PREVIEW, "END");
616 /*--------------------------------------------------------------------------*/
617 /* PRIVATE. Refresh colors, if style changed. */
618 /*--------------------------------------------------------------------------*/
620 style_set_cb (GtkWidget *widget,
621 GtkStyle *previous_style,
624 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
628 style = gtk_widget_get_style (GTK_WIDGET(preview));
630 shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
631 gnome_canvas_item_set (preview->shadow_item,
632 "fill_color_rgba", shadow_color,
635 gl_wdgt_mini_preview_highlight_range (preview,
636 preview->highlight_first,
637 preview->highlight_last);
640 /*--------------------------------------------------------------------------*/
641 /* PRIVATE. Draw CD business card item (cut-off in w and/or h). */
642 /*--------------------------------------------------------------------------*/
643 static GnomeCanvasItem *
644 cdbc_item (GnomeCanvasGroup *group,
647 const glTemplate *template)
649 GnomeCanvasPoints *points;
650 gint i_coords, i_theta;
651 gdouble theta1, theta2;
652 gdouble x0, y0, w, h, r;
653 GnomeCanvasItem *item;
655 gl_template_get_label_size (template, &w, &h);
656 r = template->label.cd.r1;
660 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
661 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
663 points = gnome_canvas_points_new (360/RES + 1);
666 points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
667 points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
669 for ( i_theta = theta1 + RES; i_theta < theta2; i_theta +=RES ) {
670 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
671 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
674 points->coords[i_coords++] = x0 + r * cos (theta2 * G_PI / 180.0);
675 points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
678 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
679 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
680 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
683 for ( i_theta = 180-theta2+RES; i_theta < (180-theta1); i_theta +=RES ) {
684 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
685 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
688 points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
689 points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
691 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
692 points->coords[i_coords++] = x0 + r * cos ((180+theta1) * G_PI / 180.0);
693 points->coords[i_coords++] = y0 + r * sin ((180+theta1) * G_PI / 180.0);
696 for ( i_theta = 180+theta1+RES; i_theta < (180+theta2); i_theta +=RES ) {
697 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
698 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
701 points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
702 points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
704 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
705 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
706 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
709 for ( i_theta = 360-theta2+RES; i_theta < (360-theta1); i_theta +=RES ) {
710 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
711 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
714 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
715 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
716 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
719 points->num_points = i_coords / 2;
722 item = gnome_canvas_item_new (group,
723 gnome_canvas_polygon_get_type (),
726 "outline_color", "black",
727 "fill_color", "white",
730 gnome_canvas_points_free (points);
735 /****************************************************************************/
736 /* Change/set background color of preview. */
737 /****************************************************************************/
739 gl_wdgt_mini_preview_set_bg_color (glWdgtMiniPreview *preview,
744 gdk_color = gl_color_to_gdk_color (color);
745 gtk_widget_modify_bg (GTK_WIDGET(preview->canvas), GTK_STATE_NORMAL, gdk_color);