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 3
35 #define SHADOW_Y_OFFSET 3
36 #define SHADOW_COLOR GL_COLOR_A (33, 33, 33, 192)
38 #define RES 5 /* Resolution in degrees for Business Card CD outlines */
40 /*===========================================*/
42 /*===========================================*/
51 /*===========================================*/
53 /*===========================================*/
55 static GtkContainerClass *parent_class;
57 static gint wdgt_mini_preview_signals[LAST_SIGNAL] = { 0 };
59 /*===========================================*/
60 /* Local function prototypes */
61 /*===========================================*/
63 static void gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass * class);
64 static void gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview);
65 static void gl_wdgt_mini_preview_finalize (GObject * object);
67 static void gl_wdgt_mini_preview_construct (glWdgtMiniPreview * preview,
68 gint height, gint width);
70 static GList *mini_outline_list_new (GnomeCanvas *canvas,
71 glTemplate *template);
72 static void mini_outline_list_free (GList ** list);
74 static gint canvas_event_cb (GnomeCanvas * canvas,
78 static GnomeCanvasItem *cdbc_item (GnomeCanvasGroup *group,
81 glTemplate *template);
85 /****************************************************************************/
86 /* Boilerplate Object stuff. */
87 /****************************************************************************/
89 gl_wdgt_mini_preview_get_type (void)
91 static guint wdgt_mini_preview_type = 0;
93 if (!wdgt_mini_preview_type) {
94 GTypeInfo wdgt_mini_preview_info = {
95 sizeof (glWdgtMiniPreviewClass),
98 (GClassInitFunc) gl_wdgt_mini_preview_class_init,
101 sizeof (glWdgtMiniPreview),
103 (GInstanceInitFunc) gl_wdgt_mini_preview_instance_init,
106 wdgt_mini_preview_type =
107 g_type_register_static (gtk_hbox_get_type (),
109 &wdgt_mini_preview_info, 0);
112 return wdgt_mini_preview_type;
116 gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass * class)
118 GObjectClass *object_class;
120 gl_debug (DEBUG_MINI_PREVIEW, "START");
122 object_class = (GObjectClass *) class;
124 parent_class = gtk_type_class (gtk_hbox_get_type ());
126 object_class->finalize = gl_wdgt_mini_preview_finalize;
128 wdgt_mini_preview_signals[CLICKED] =
129 g_signal_new ("clicked",
130 G_OBJECT_CLASS_TYPE(object_class),
132 G_STRUCT_OFFSET (glWdgtMiniPreviewClass, clicked),
134 gl_marshal_VOID__INT,
135 G_TYPE_NONE, 1, G_TYPE_INT);
137 wdgt_mini_preview_signals[PRESSED] =
138 g_signal_new ("pressed",
139 G_OBJECT_CLASS_TYPE(object_class),
141 G_STRUCT_OFFSET (glWdgtMiniPreviewClass, pressed),
143 gl_marshal_VOID__INT_INT,
144 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
146 gl_debug (DEBUG_MINI_PREVIEW, "END");
150 gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview * preview)
152 gl_debug (DEBUG_MINI_PREVIEW, "START");
154 preview->canvas = NULL;
155 preview->label_items = NULL;
157 gl_debug (DEBUG_MINI_PREVIEW, "END");
161 gl_wdgt_mini_preview_finalize (GObject * object)
163 glWdgtMiniPreview *preview;
164 glWdgtMiniPreviewClass *class;
166 gl_debug (DEBUG_MINI_PREVIEW, "START");
168 g_return_if_fail (object != NULL);
169 g_return_if_fail (GL_IS_WDGT_MINI_PREVIEW (object));
171 preview = GL_WDGT_MINI_PREVIEW (object);
173 G_OBJECT_CLASS (parent_class)->finalize (object);
175 gl_debug (DEBUG_MINI_PREVIEW, "END");
179 gl_wdgt_mini_preview_new (gint height,
182 glWdgtMiniPreview *preview;
184 gl_debug (DEBUG_MINI_PREVIEW, "START");
186 preview = g_object_new (gl_wdgt_mini_preview_get_type (), NULL);
188 gl_wdgt_mini_preview_construct (preview, height, width);
190 gl_debug (DEBUG_MINI_PREVIEW, "END");
192 return GTK_WIDGET (preview);
195 /*--------------------------------------------------------------------------*/
196 /* Construct composite widget. */
197 /*--------------------------------------------------------------------------*/
199 gl_wdgt_mini_preview_construct (glWdgtMiniPreview * preview,
204 GnomeCanvasGroup *group;
206 gl_debug (DEBUG_MINI_PREVIEW, "START");
208 whbox = GTK_WIDGET (preview);
210 preview->height = height;
211 preview->width = width;
214 gtk_widget_push_colormap (gdk_rgb_get_colormap ());
215 preview->canvas = gnome_canvas_new_aa ();
216 gtk_widget_pop_colormap ();
217 gtk_box_pack_start (GTK_BOX (whbox), preview->canvas, TRUE, TRUE, 0);
218 gtk_widget_set_size_request (preview->canvas, width, height);
219 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
220 0.0, 0.0, width, height);
222 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas), 1.0);
223 group = gnome_canvas_root (GNOME_CANVAS (preview->canvas));
226 preview->shadow_item =
227 gnome_canvas_item_new (group,
228 gnome_canvas_rect_get_type (),
229 "x1", (gdouble)SHADOW_X_OFFSET,
230 "y1", (gdouble)SHADOW_Y_OFFSET,
231 "x2", (gdouble)(SHADOW_X_OFFSET + width),
232 "y2", (gdouble)(SHADOW_Y_OFFSET + height),
233 "fill_color_rgba", SHADOW_COLOR,
236 /* draw an initial paper outline */
237 preview->paper_item =
238 gnome_canvas_item_new (group,
239 gnome_canvas_rect_get_type (),
242 "x2", (gdouble)width,
243 "y2", (gdouble)height,
245 "outline_color", "black",
246 "fill_color", "white",
249 /* create empty list of label canvas items */
250 preview->label_items = NULL;
251 preview->labels_per_sheet = 0;
254 g_signal_connect (G_OBJECT (preview->canvas), "event",
255 G_CALLBACK (canvas_event_cb), preview);
257 gl_debug (DEBUG_MINI_PREVIEW, "END");
260 /****************************************************************************/
261 /* Set label for mini-preview to determine geometry. */
262 /****************************************************************************/
263 void gl_wdgt_mini_preview_set_label (glWdgtMiniPreview *preview,
266 glTemplate *template;
268 gdouble canvas_scale;
270 gdouble shadow_x, shadow_y;
272 gl_debug (DEBUG_MINI_PREVIEW, "START");
275 template = gl_template_from_name (name);
277 gl_debug (DEBUG_MINI_PREVIEW, "page_size = %s, page_width = %g, page_height = %g",
278 template->page_size, template->page_width, template->page_height);
280 /* get paper size and set scale */
281 w = preview->width - 4 - 2*SHADOW_X_OFFSET;
282 h = preview->height - 4 - 2*SHADOW_Y_OFFSET;
283 if ( (w/template->page_width) > (h/template->page_height) ) {
284 canvas_scale = h / template->page_height;
286 canvas_scale = w / template->page_width;
288 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas),
291 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
293 template->page_width, template->page_height);
295 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
297 preview->width/canvas_scale,
298 preview->height/canvas_scale);
302 shadow_x = SHADOW_X_OFFSET/canvas_scale;
303 shadow_y = SHADOW_Y_OFFSET/canvas_scale;
304 gnome_canvas_item_set (preview->shadow_item,
307 "x2", shadow_x + template->page_width,
308 "y2", shadow_y + template->page_height,
311 /* update paper outline */
312 gnome_canvas_item_set (preview->paper_item,
313 "x2", template->page_width,
314 "y2", template->page_height,
317 /* update label items */
318 mini_outline_list_free (&preview->label_items);
319 preview->label_items =
320 mini_outline_list_new (GNOME_CANVAS(preview->canvas),
323 gl_template_free( &template );
325 gl_debug (DEBUG_MINI_PREVIEW, "END");
328 /*--------------------------------------------------------------------------*/
329 /* PRIVATE. Draw label outlines and return canvas item list. */
330 /*--------------------------------------------------------------------------*/
332 mini_outline_list_new (GnomeCanvas *canvas,
333 glTemplate *template)
335 GnomeCanvasGroup *group = NULL;
336 GnomeCanvasItem *item = NULL;
339 glTemplateOrigin *origins;
340 gdouble x1, y1, x2, y2, w, h;
342 gl_debug (DEBUG_MINI_PREVIEW, "START");
344 group = gnome_canvas_root (canvas);
346 /* draw mini label outlines */
347 n_labels = gl_template_get_n_labels (template);
348 origins = gl_template_get_origins (template);
349 gl_template_get_label_size (template, &w, &h);
350 for ( i=0; i < n_labels; i++ ) {
357 switch (template->label.style) {
358 case GL_TEMPLATE_STYLE_RECT:
359 item = gnome_canvas_item_new (group,
360 gnome_canvas_rect_get_type(),
366 "outline_color", "black",
367 "fill_color", "white",
370 case GL_TEMPLATE_STYLE_ROUND:
371 item = gnome_canvas_item_new (group,
372 gnome_canvas_ellipse_get_type(),
378 "outline_color", "black",
379 "fill_color", "white",
382 case GL_TEMPLATE_STYLE_CD:
384 item = gnome_canvas_item_new (group,
385 gnome_canvas_ellipse_get_type(),
391 "outline_color", "black",
392 "fill_color", "white",
395 item = cdbc_item (group, x1, y1, template);
399 g_warning ("Unknown label style");
403 g_object_set_data (G_OBJECT (item), "i",
404 GINT_TO_POINTER (i+1));
406 list = g_list_append (list, item);
409 gl_debug (DEBUG_MINI_PREVIEW, "END");
413 /*--------------------------------------------------------------------------*/
414 /* PRIVATE. Draw label outlines and return canvas item list. */
415 /*--------------------------------------------------------------------------*/
417 mini_outline_list_free (GList ** list)
419 GnomeCanvasItem *item;
422 gl_debug (DEBUG_MINI_PREVIEW, "START");
424 if ( *list != NULL ) {
426 for (p = *list; p != NULL; p = p->next) {
427 item = GNOME_CANVAS_ITEM (p->data);
428 gtk_object_destroy (GTK_OBJECT (item));
436 gl_debug (DEBUG_MINI_PREVIEW, "END");
439 /*--------------------------------------------------------------------------*/
440 /* PRIVATE. Canvas event handler, select first and last items. */
441 /*--------------------------------------------------------------------------*/
443 canvas_event_cb (GnomeCanvas * canvas,
447 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
448 GnomeCanvasItem *item;
449 static gboolean dragging = FALSE;
450 static gint prev_i = 0, first, last;
454 gl_debug (DEBUG_MINI_PREVIEW, "START");
456 switch (event->type) {
458 case GDK_BUTTON_PRESS:
459 gnome_canvas_window_to_world (canvas,
460 event->button.x, event->button.y,
462 switch (event->button.button) {
464 /* Get item at cursor and make sure
465 it's a label object ("i" is valid) */
466 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
470 i = GPOINTER_TO_INT (g_object_get_data
471 (G_OBJECT (item), "i"));
474 /* Go into dragging mode while remains pressed. */
476 gnome_canvas_item_grab (canvas->root,
477 GDK_POINTER_MOTION_MASK |
478 GDK_BUTTON_RELEASE_MASK |
479 GDK_BUTTON_PRESS_MASK,
480 NULL, event->button.time);
481 g_signal_emit (G_OBJECT(preview),
482 wdgt_mini_preview_signals[CLICKED],
486 g_signal_emit (G_OBJECT(preview),
487 wdgt_mini_preview_signals[PRESSED],
497 case GDK_BUTTON_RELEASE:
498 gnome_canvas_window_to_world (canvas,
499 event->button.x, event->button.y,
501 switch (event->button.button) {
503 /* Exit dragging mode */
505 gnome_canvas_item_ungrab (canvas->root, event->button.time);
513 case GDK_MOTION_NOTIFY:
514 gnome_canvas_window_to_world (canvas,
515 event->motion.x, event->motion.y,
517 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
518 /* Get item at cursor and
519 make sure it's a label object ("i" is valid) */
520 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
524 i = GPOINTER_TO_INT (g_object_get_data
525 (G_OBJECT (item), "i"));
529 /* Entered into a new item */
531 g_signal_emit (G_OBJECT(preview),
532 wdgt_mini_preview_signals[PRESSED],
545 gl_debug (DEBUG_MINI_PREVIEW, "END");
550 /****************************************************************************/
551 /* Highlight given label outlines. */
552 /****************************************************************************/
554 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview * preview,
558 GnomeCanvasItem *item = NULL;
562 gl_debug (DEBUG_MINI_PREVIEW, "START");
564 for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
566 item = GNOME_CANVAS_ITEM (p->data);
568 if ((i >= first_label) && (i <= last_label)) {
569 gnome_canvas_item_set (item,
570 "fill_color", "light blue",
573 gnome_canvas_item_set (item,
574 "fill_color", "white", NULL);
579 gl_debug (DEBUG_MINI_PREVIEW, "END");
582 /*--------------------------------------------------------------------------*/
583 /* PRIVATE. Draw CD business card item (cut-off in w and/or h). */
584 /*--------------------------------------------------------------------------*/
585 static GnomeCanvasItem *
586 cdbc_item (GnomeCanvasGroup *group,
589 glTemplate *template)
591 GnomeCanvasPoints *points;
592 gint i_coords, i_theta;
593 gdouble theta1, theta2;
594 gdouble x0, y0, w, h, r;
595 GnomeCanvasItem *item;
597 gl_template_get_label_size (template, &w, &h);
598 r = template->label.cd.r1;
602 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
603 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
605 points = gnome_canvas_points_new (360/RES + 1);
608 points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
609 points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
611 for ( i_theta = theta1 + RES; i_theta < theta2; i_theta +=RES ) {
612 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
613 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
616 points->coords[i_coords++] = x0 + r * cos (theta2 * G_PI / 180.0);
617 points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
620 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
621 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
622 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
625 for ( i_theta = 180-theta2+RES; i_theta < (180-theta1); i_theta +=RES ) {
626 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
627 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
630 points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
631 points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
633 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
634 points->coords[i_coords++] = x0 + r * cos ((180+theta1) * G_PI / 180.0);
635 points->coords[i_coords++] = y0 + r * sin ((180+theta1) * G_PI / 180.0);
638 for ( i_theta = 180+theta1+RES; i_theta < (180+theta2); i_theta +=RES ) {
639 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
640 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
643 points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
644 points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
646 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
647 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
648 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
651 for ( i_theta = 360-theta2+RES; i_theta < (360-theta1); i_theta +=RES ) {
652 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
653 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
656 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
657 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
658 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
661 points->num_points = i_coords / 2;
664 item = gnome_canvas_item_new (group,
665 gnome_canvas_polygon_get_type (),
668 "outline_color", "black",
669 "fill_color", "white",
672 gnome_canvas_points_free (points);