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 shadow_x, shadow_y;
304 gl_debug (DEBUG_MINI_PREVIEW, "START");
306 gl_debug (DEBUG_MINI_PREVIEW, "page_size = %s, page_width = %g, page_height = %g",
307 template->page_size, template->page_width, template->page_height);
309 /* get paper size and set scale */
310 w = preview->width - 4 - 2*SHADOW_X_OFFSET;
311 h = preview->height - 4 - 2*SHADOW_Y_OFFSET;
312 if ( (w/template->page_width) > (h/template->page_height) ) {
313 canvas_scale = h / template->page_height;
315 canvas_scale = w / template->page_width;
317 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (preview->canvas),
320 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
322 template->page_width, template->page_height);
324 gnome_canvas_set_scroll_region (GNOME_CANVAS (preview->canvas),
326 preview->width/canvas_scale,
327 preview->height/canvas_scale);
331 shadow_x = SHADOW_X_OFFSET/canvas_scale;
332 shadow_y = SHADOW_Y_OFFSET/canvas_scale;
333 gnome_canvas_item_set (preview->shadow_item,
336 "x2", shadow_x + template->page_width,
337 "y2", shadow_y + template->page_height,
340 /* update paper outline */
341 gnome_canvas_item_set (preview->paper_item,
342 "x2", template->page_width,
343 "y2", template->page_height,
346 /* update label items */
347 mini_outline_list_free (&preview->label_items);
348 preview->label_items =
349 mini_outline_list_new (GNOME_CANVAS(preview->canvas),
352 gl_debug (DEBUG_MINI_PREVIEW, "END");
355 /*--------------------------------------------------------------------------*/
356 /* PRIVATE. Draw label outlines and return canvas item list. */
357 /*--------------------------------------------------------------------------*/
359 mini_outline_list_new (GnomeCanvas *canvas,
360 const glTemplate *template)
362 GnomeCanvasGroup *group = NULL;
363 GnomeCanvasItem *item = NULL;
366 glTemplateOrigin *origins;
367 gdouble x1, y1, x2, y2, w, h;
369 gl_debug (DEBUG_MINI_PREVIEW, "START");
371 group = gnome_canvas_root (canvas);
373 /* draw mini label outlines */
374 n_labels = gl_template_get_n_labels (template);
375 origins = gl_template_get_origins (template);
376 gl_template_get_label_size (template, &w, &h);
377 for ( i=0; i < n_labels; i++ ) {
384 switch (template->label.style) {
385 case GL_TEMPLATE_STYLE_RECT:
386 item = gnome_canvas_item_new (group,
387 gnome_canvas_rect_get_type(),
393 "outline_color", "black",
394 "fill_color", "white",
397 case GL_TEMPLATE_STYLE_ROUND:
398 item = gnome_canvas_item_new (group,
399 gnome_canvas_ellipse_get_type(),
405 "outline_color", "black",
406 "fill_color", "white",
409 case GL_TEMPLATE_STYLE_CD:
411 item = gnome_canvas_item_new (group,
412 gnome_canvas_ellipse_get_type(),
418 "outline_color", "black",
419 "fill_color", "white",
422 item = cdbc_item (group, x1, y1, template);
426 g_warning ("Unknown label style");
430 g_object_set_data (G_OBJECT (item), "i",
431 GINT_TO_POINTER (i+1));
433 list = g_list_append (list, item);
436 gl_debug (DEBUG_MINI_PREVIEW, "END");
440 /*--------------------------------------------------------------------------*/
441 /* PRIVATE. Draw label outlines and return canvas item list. */
442 /*--------------------------------------------------------------------------*/
444 mini_outline_list_free (GList ** list)
446 GnomeCanvasItem *item;
449 gl_debug (DEBUG_MINI_PREVIEW, "START");
451 if ( *list != NULL ) {
453 for (p = *list; p != NULL; p = p->next) {
454 item = GNOME_CANVAS_ITEM (p->data);
455 gtk_object_destroy (GTK_OBJECT (item));
463 gl_debug (DEBUG_MINI_PREVIEW, "END");
466 /*--------------------------------------------------------------------------*/
467 /* PRIVATE. Canvas event handler, select first and last items. */
468 /*--------------------------------------------------------------------------*/
470 canvas_event_cb (GnomeCanvas * canvas,
474 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (data);
475 GnomeCanvasItem *item;
476 static gboolean dragging = FALSE;
477 static gint prev_i = 0, first, last;
481 gl_debug (DEBUG_MINI_PREVIEW, "START");
483 switch (event->type) {
485 case GDK_BUTTON_PRESS:
486 gnome_canvas_window_to_world (canvas,
487 event->button.x, event->button.y,
489 switch (event->button.button) {
491 /* Get item at cursor and make sure
492 it's a label object ("i" is valid) */
493 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
497 i = GPOINTER_TO_INT (g_object_get_data
498 (G_OBJECT (item), "i"));
501 /* Go into dragging mode while remains pressed. */
503 gnome_canvas_item_grab (canvas->root,
504 GDK_POINTER_MOTION_MASK |
505 GDK_BUTTON_RELEASE_MASK |
506 GDK_BUTTON_PRESS_MASK,
507 NULL, event->button.time);
508 g_signal_emit (G_OBJECT(preview),
509 wdgt_mini_preview_signals[CLICKED],
513 g_signal_emit (G_OBJECT(preview),
514 wdgt_mini_preview_signals[PRESSED],
524 case GDK_BUTTON_RELEASE:
525 gnome_canvas_window_to_world (canvas,
526 event->button.x, event->button.y,
528 switch (event->button.button) {
530 /* Exit dragging mode */
532 gnome_canvas_item_ungrab (canvas->root, event->button.time);
540 case GDK_MOTION_NOTIFY:
541 gnome_canvas_window_to_world (canvas,
542 event->motion.x, event->motion.y,
544 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
545 /* Get item at cursor and
546 make sure it's a label object ("i" is valid) */
547 item = gnome_canvas_get_item_at (GNOME_CANVAS (canvas),
551 i = GPOINTER_TO_INT (g_object_get_data
552 (G_OBJECT (item), "i"));
556 /* Entered into a new item */
558 g_signal_emit (G_OBJECT(preview),
559 wdgt_mini_preview_signals[PRESSED],
572 gl_debug (DEBUG_MINI_PREVIEW, "END");
577 /****************************************************************************/
578 /* Highlight given label outlines. */
579 /****************************************************************************/
581 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview *preview,
587 GnomeCanvasItem *item = NULL;
591 gl_debug (DEBUG_MINI_PREVIEW, "START");
593 style = gtk_widget_get_style (GTK_WIDGET(preview));
594 select_color = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
595 gl_debug (DEBUG_MINI_PREVIEW, "select color = 0x%08x", select_color);
597 for (p = preview->label_items, i = 1; p != NULL; i++, p = p->next) {
599 item = GNOME_CANVAS_ITEM (p->data);
601 if ((i >= first_label) && (i <= last_label)) {
602 gnome_canvas_item_set (item,
603 "fill_color_rgba", select_color,
606 gnome_canvas_item_set (item,
607 "fill_color", "white", NULL);
612 preview->highlight_first = first_label;
613 preview->highlight_last = last_label;
615 gl_debug (DEBUG_MINI_PREVIEW, "END");
618 /*--------------------------------------------------------------------------*/
619 /* PRIVATE. Refresh colors, if style changed. */
620 /*--------------------------------------------------------------------------*/
622 style_set_cb (GtkWidget *widget,
623 GtkStyle *previous_style,
626 glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
630 style = gtk_widget_get_style (GTK_WIDGET(preview));
632 shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
633 gnome_canvas_item_set (preview->shadow_item,
634 "fill_color_rgba", shadow_color,
637 gl_wdgt_mini_preview_highlight_range (preview,
638 preview->highlight_first,
639 preview->highlight_last);
642 /*--------------------------------------------------------------------------*/
643 /* PRIVATE. Draw CD business card item (cut-off in w and/or h). */
644 /*--------------------------------------------------------------------------*/
645 static GnomeCanvasItem *
646 cdbc_item (GnomeCanvasGroup *group,
649 const glTemplate *template)
651 GnomeCanvasPoints *points;
652 gint i_coords, i_theta;
653 gdouble theta1, theta2;
654 gdouble x0, y0, w, h, r;
655 GnomeCanvasItem *item;
657 gl_template_get_label_size (template, &w, &h);
658 r = template->label.cd.r1;
662 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
663 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
665 points = gnome_canvas_points_new (360/RES + 1);
668 points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
669 points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
671 for ( i_theta = theta1 + RES; i_theta < theta2; 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 (theta2 * G_PI / 180.0);
677 points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
680 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
681 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
682 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
685 for ( i_theta = 180-theta2+RES; i_theta < (180-theta1); i_theta +=RES ) {
686 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
687 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
690 points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
691 points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
693 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
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);
698 for ( i_theta = 180+theta1+RES; i_theta < (180+theta2); i_theta +=RES ) {
699 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
700 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
703 points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
704 points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
706 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
707 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
708 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
711 for ( i_theta = 360-theta2+RES; i_theta < (360-theta1); i_theta +=RES ) {
712 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
713 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
716 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
717 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
718 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
721 points->num_points = i_coords / 2;
724 item = gnome_canvas_item_new (group,
725 gnome_canvas_polygon_get_type (),
728 "outline_color", "black",
729 "fill_color", "white",
732 gnome_canvas_points_free (points);