]> git.sur5r.net Git - glabels/blob - glabels2/src/view.c
2005-05-14 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  view.c:  GLabels View module
7  *
8  *  Copyright (C) 2001-2005  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24
25 #include <config.h>
26
27 #include "view.h"
28
29 #include <glib/gi18n.h>
30 #include <gtk/gtkscrolledwindow.h>
31 #include <gtk/gtkselection.h>
32 #include <gtk/gtkinvisible.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <string.h>
35 #include <math.h>
36
37 #include "view-object.h"
38 #include "view-box.h"
39 #include "view-ellipse.h"
40 #include "view-line.h"
41 #include "view-image.h"
42 #include "view-text.h"
43 #include "view-barcode.h"
44 #include "xml-label.h"
45 #include "color.h"
46 #include "prefs.h"
47 #include "marshal.h"
48
49 #include "debug.h"
50
51 /*==========================================================================*/
52 /* Private macros and constants.                                            */
53 /*==========================================================================*/
54
55 #define BG_COLOR        GL_COLOR (192, 192, 192)
56 #define OUTLINE_COLOR   GL_COLOR (173, 216, 230)
57 #define PAPER_COLOR     GL_COLOR (255, 255, 255)
58 #define GRID_COLOR      BG_COLOR
59 #define MARKUP_COLOR    GL_COLOR (240, 100, 100)
60
61 #define SEL_LINE_COLOR  GL_COLOR_A (0, 0, 255, 128)
62 #define SEL_FILL_COLOR  GL_COLOR_A (192, 192, 255, 128)
63
64 #define ARC_FINE         2 /* Resolution in degrees of large arcs */
65 #define ARC_COURSE       5 /* Resolution in degrees of small arcs */
66
67 #define ZOOMTOFIT_PAD   16
68
69 #define POINTS_PER_MM    2.83464566929
70
71 #define DELTA 0.01
72
73 /*==========================================================================*/
74 /* Private types.                                                           */
75 /*==========================================================================*/
76
77 enum {
78         SELECTION_CHANGED,
79         CONTEXT_MENU_ACTIVATE,
80         ZOOM_CHANGED,
81         POINTER_MOVED,
82         POINTER_EXIT,
83         MODE_CHANGED,
84         LAST_SIGNAL
85 };
86
87
88 /*==========================================================================*/
89 /* Private globals                                                          */
90 /*==========================================================================*/
91
92 static GtkContainerClass *parent_class;
93
94 static guint signals[LAST_SIGNAL] = {0};
95
96 /* "CLIPBOARD" selection */
97 static GdkAtom clipboard_atom = GDK_NONE;
98
99 static gdouble zooms[] = {
100         8.00,
101         6.00,
102         4.00,
103         3.00,
104         2.00,
105         1.50,
106         1.00,
107         0.75,
108         0.67,
109         0.50,
110         0.33,
111         0.25,
112         0.20,
113         0.15,
114         0.10,
115 };
116 #define N_ZOOMS G_N_ELEMENTS(zooms)
117
118
119 /*==========================================================================*/
120 /* Local function prototypes                                                */
121 /*==========================================================================*/
122
123 static void       gl_view_class_init              (glViewClass *class);
124 static void       gl_view_init                    (glView *view);
125 static void       gl_view_finalize                (GObject *object);
126
127 static void       gl_view_construct               (glView *view);
128 static GtkWidget *gl_view_construct_canvas        (glView *view);
129 static void       gl_view_construct_selection     (glView *view);
130
131 static gdouble    get_home_scale                  (glView *view);
132
133 static void       draw_layers                     (glView *view);
134
135 static void       label_resized_cb                (glLabel *label,
136                                                    glView *view);
137
138 static void       draw_label_layer                (glView *view);
139
140 static void       draw_highlight_layer            (glView *view);
141
142 static void       draw_bg_fg_layers               (glView *view);
143 static void       draw_bg_fg_rect                 (glView *view);
144 static void       draw_bg_fg_rounded_rect         (glView *view);
145 static void       draw_bg_fg_round                (glView *view);
146 static void       draw_bg_fg_cd                   (glView *view);
147 static void       draw_bg_fg_cd_bc                (glView *view);
148
149 static void       draw_grid_layer                 (glView *view);
150
151 static void       draw_markup_layer               (glView *view);
152
153 static void       draw_markup_margin              (glView *view,
154                                                    glTemplateMarkup *margin);
155 static void       draw_markup_margin_rect         (glView *view,
156                                                    glTemplateMarkup *margin);
157 static void       draw_markup_margin_rounded_rect (glView *view,
158                                                    glTemplateMarkup *margin);
159 static void       draw_markup_margin_round        (glView *view,
160                                                    glTemplateMarkup *margin);
161 static void       draw_markup_margin_cd           (glView *view,
162                                                    glTemplateMarkup *margin);
163 static void       draw_markup_margin_cd_bc        (glView *view,
164                                                    glTemplateMarkup *margin);
165
166 static void       draw_markup_line                (glView *view,
167                                                    glTemplateMarkup *line);
168
169 static void       draw_markup_circle              (glView *view,
170                                                    glTemplateMarkup *circle);
171
172
173 static void       select_object_real              (glView *view,
174                                                    glViewObject *view_object);
175 static void       unselect_object_real            (glView *view,
176                                                    glViewObject *view_object);
177
178 static gboolean   object_at                       (glView *view,
179                                                    gdouble x, gdouble y);
180
181 static gboolean   is_item_member_of_group         (glView          *view,
182                                                    GnomeCanvasItem *item,
183                                                    GnomeCanvasItem *group);
184
185 static void       set_zoom_real                   (glView          *view,
186                                                    gdouble          zoom,
187                                                    gboolean         scale_to_fit_flag);
188
189 static void       size_allocate_cb                (glView          *view);
190
191 static void       screen_changed_cb               (glView          *view);
192
193 static int        canvas_event                    (GnomeCanvas *canvas,
194                                                    GdkEvent    *event,
195                                                    glView      *view);
196 static int        canvas_event_arrow_mode         (GnomeCanvas *canvas,
197                                                    GdkEvent    *event,
198                                                    glView      *view);
199
200 static void       selection_clear_cb             (GtkWidget         *widget,
201                                                   GdkEventSelection *event,
202                                                   gpointer          data);
203
204 static void       selection_get_cb               (GtkWidget         *widget,
205                                                   GtkSelectionData  *selection_data,
206                                                   guint             info,
207                                                   guint             time,
208                                                   gpointer          data);
209
210 static void       selection_received_cb          (GtkWidget         *widget,
211                                                   GtkSelectionData  *selection_data,
212                                                   guint             time,
213                                                   gpointer          data);
214 \f
215 /****************************************************************************/
216 /* Boilerplate Object stuff.                                                */
217 /****************************************************************************/
218 GType
219 gl_view_get_type (void)
220 {
221         static GType type = 0;
222
223         if (!type) {
224                 static const GTypeInfo info = {
225                         sizeof (glViewClass),
226                         NULL,
227                         NULL,
228                         (GClassInitFunc) gl_view_class_init,
229                         NULL,
230                         NULL,
231                         sizeof (glView),
232                         0,
233                         (GInstanceInitFunc) gl_view_init,
234                         NULL
235                 };
236
237                 type = g_type_register_static (GTK_TYPE_VBOX,
238                                                "glView", &info, 0);
239         }
240
241         return type;
242 }
243
244 static void
245 gl_view_class_init (glViewClass *class)
246 {
247         GObjectClass *object_class = (GObjectClass *) class;
248
249         gl_debug (DEBUG_VIEW, "START");
250
251         parent_class = g_type_class_peek_parent (class);
252
253         object_class->finalize = gl_view_finalize;
254
255         signals[SELECTION_CHANGED] =
256                 g_signal_new ("selection_changed",
257                               G_OBJECT_CLASS_TYPE (object_class),
258                               G_SIGNAL_RUN_LAST,
259                               G_STRUCT_OFFSET (glViewClass, selection_changed),
260                               NULL, NULL,
261                               gl_marshal_VOID__VOID,
262                               G_TYPE_NONE,
263                               0);
264
265         signals[CONTEXT_MENU_ACTIVATE] =
266                 g_signal_new ("context_menu_activate",
267                               G_OBJECT_CLASS_TYPE (object_class),
268                               G_SIGNAL_RUN_LAST,
269                               G_STRUCT_OFFSET (glViewClass, context_menu_activate),
270                               NULL, NULL,
271                               gl_marshal_VOID__INT_UINT,
272                               G_TYPE_NONE,
273                               2, G_TYPE_INT, G_TYPE_UINT);
274
275         signals[ZOOM_CHANGED] =
276                 g_signal_new ("zoom_changed",
277                               G_OBJECT_CLASS_TYPE (object_class),
278                               G_SIGNAL_RUN_LAST,
279                               G_STRUCT_OFFSET (glViewClass, zoom_changed),
280                               NULL, NULL,
281                               gl_marshal_VOID__DOUBLE,
282                               G_TYPE_NONE,
283                               1, G_TYPE_DOUBLE);
284
285         signals[POINTER_MOVED] =
286                 g_signal_new ("pointer_moved",
287                               G_OBJECT_CLASS_TYPE (object_class),
288                               G_SIGNAL_RUN_LAST,
289                               G_STRUCT_OFFSET (glViewClass, pointer_moved),
290                               NULL, NULL,
291                               gl_marshal_VOID__DOUBLE_DOUBLE,
292                               G_TYPE_NONE,
293                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
294
295         signals[POINTER_EXIT] =
296                 g_signal_new ("pointer_exit",
297                               G_OBJECT_CLASS_TYPE (object_class),
298                               G_SIGNAL_RUN_LAST,
299                               G_STRUCT_OFFSET (glViewClass, pointer_exit),
300                               NULL, NULL,
301                               gl_marshal_VOID__VOID,
302                               G_TYPE_NONE,
303                               0);
304
305         signals[MODE_CHANGED] =
306                 g_signal_new ("mode_changed",
307                               G_OBJECT_CLASS_TYPE (object_class),
308                               G_SIGNAL_RUN_LAST,
309                               G_STRUCT_OFFSET (glViewClass, mode_changed),
310                               NULL, NULL,
311                               gl_marshal_VOID__VOID,
312                               G_TYPE_NONE,
313                               0);
314
315         gl_debug (DEBUG_VIEW, "END");
316 }
317
318 static void
319 gl_view_init (glView *view)
320 {
321         gl_debug (DEBUG_VIEW, "START");
322
323         view->label = NULL;
324
325         view->grid_spacing = 9;
326
327         view->default_font_family = NULL;
328
329         gl_debug (DEBUG_VIEW, "END");
330 }
331
332 static void
333 gl_view_finalize (GObject *object)
334 {
335         glView *view;
336
337         gl_debug (DEBUG_VIEW, "START");
338
339         g_return_if_fail (object != NULL);
340         g_return_if_fail (GL_IS_VIEW (object));
341
342         view = GL_VIEW (object);
343
344         G_OBJECT_CLASS (parent_class)->finalize (object);
345
346         gl_debug (DEBUG_VIEW, "END");
347 }
348
349 /****************************************************************************/
350 /* NEW view object.                                                         */
351 /****************************************************************************/
352 GtkWidget *
353 gl_view_new (glLabel *label)
354 {
355         glView *view;
356
357         gl_debug (DEBUG_VIEW, "START");
358
359         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
360
361         view = g_object_new (gl_view_get_type (), NULL);
362         view->label = label;
363
364         gl_view_construct (view);
365
366         gl_debug (DEBUG_VIEW, "END");
367
368         return GTK_WIDGET (view);
369 }
370
371 /*---------------------------------------------------------------------------*/
372 /* PRIVATE.  Construct composite widget.                                     */
373 /*---------------------------------------------------------------------------*/
374 static void
375 gl_view_construct (glView *view)
376 {
377         GtkWidget *wvbox, *wscroll;
378
379         gl_debug (DEBUG_VIEW, "START");
380
381         g_return_if_fail (GL_IS_VIEW (view));
382
383         wvbox = GTK_WIDGET (view);
384
385         view->state = GL_VIEW_STATE_ARROW;
386         view->object_list = NULL;
387
388         gl_view_construct_canvas (view);
389         wscroll = gtk_scrolled_window_new (NULL, NULL);
390         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
391                                         GTK_POLICY_AUTOMATIC,
392                                         GTK_POLICY_AUTOMATIC);
393         gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
394         gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
395
396         gl_view_construct_selection (view);
397
398         gl_view_set_default_font_family      (view, gl_prefs->default_font_family);
399         gl_view_set_default_font_size        (view, gl_prefs->default_font_size);
400         gl_view_set_default_font_weight      (view, gl_prefs->default_font_weight);
401         gl_view_set_default_font_italic_flag (view, gl_prefs->default_font_italic_flag);
402         gl_view_set_default_text_color       (view, gl_prefs->default_text_color);
403         gl_view_set_default_text_alignment   (view, gl_prefs->default_text_alignment);
404         gl_view_set_default_text_line_spacing (view, gl_prefs->default_text_line_spacing);
405         gl_view_set_default_line_width       (view, gl_prefs->default_line_width);
406         gl_view_set_default_line_color       (view, gl_prefs->default_line_color);
407         gl_view_set_default_fill_color       (view, gl_prefs->default_fill_color);
408
409         gl_debug (DEBUG_VIEW, "END");
410 }
411
412 /*---------------------------------------------------------------------------*/
413 /* PRIVATE.  Create canvas w/ a background in the shape of the label/card.   */
414 /*---------------------------------------------------------------------------*/
415 static GtkWidget *
416 gl_view_construct_canvas (glView *view)
417 {
418         glLabel   *label;
419         gdouble    label_width, label_height;
420         GdkColor  *bg_color;
421
422         gl_debug (DEBUG_VIEW, "START");
423
424         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
425         g_return_val_if_fail (view->label && GL_IS_LABEL (view->label), NULL);
426
427         label = view->label;
428
429         gtk_widget_push_colormap (gdk_rgb_get_colormap ());
430         view->canvas = gnome_canvas_new_aa ();
431         gtk_widget_pop_colormap ();
432
433         bg_color = gl_color_to_gdk_color (BG_COLOR);
434         gtk_widget_modify_bg (GTK_WIDGET(view->canvas), GTK_STATE_NORMAL, bg_color);
435         g_free (bg_color);
436
437         gl_label_get_size (label, &label_width, &label_height);
438         gl_debug (DEBUG_VIEW, "Label size: w=%lf, h=%lf",
439                   label_width, label_height);
440
441         view->zoom = 1.0;
442         view->home_scale = get_home_scale (view);
443         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas), view->home_scale);
444
445         gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
446                                         0.0, 0.0, label_width, label_height);
447
448         draw_layers (view);
449
450         g_signal_connect (G_OBJECT (view->canvas), "event",
451                           G_CALLBACK (canvas_event), view);
452
453         g_signal_connect_swapped (G_OBJECT (view->canvas), "size-allocate",
454                                   G_CALLBACK (size_allocate_cb), view);
455
456         g_signal_connect_swapped (G_OBJECT (view->canvas), "screen-changed",
457                                   G_CALLBACK (screen_changed_cb), view);
458
459         gl_debug (DEBUG_VIEW, "END");
460
461         return view->canvas;
462 }
463
464 /*---------------------------------------------------------------------------*/
465 /* PRIAVTE.  Calculate 1:1 scale for screen.                                 */
466 /*---------------------------------------------------------------------------*/
467 static gdouble
468 get_home_scale (glView *view)
469 {
470         GdkScreen *screen;
471         gdouble    screen_width_pixels, screen_width_mm;
472         gdouble    screen_height_pixels, screen_height_mm;
473         gdouble    x_pixels_per_mm, y_pixels_per_mm;
474         gdouble    scale;
475
476         if (!gtk_widget_has_screen (GTK_WIDGET (view->canvas))) return 1.0;
477
478         screen = gtk_widget_get_screen (GTK_WIDGET (view->canvas));
479
480         gl_debug (DEBUG_VIEW, "Screen = %p", screen);
481
482         screen_width_pixels  = gdk_screen_get_width (screen);
483         screen_width_mm      = gdk_screen_get_width_mm (screen);
484         screen_height_pixels = gdk_screen_get_height (screen);
485         screen_height_mm     = gdk_screen_get_height_mm (screen);
486
487         x_pixels_per_mm      = screen_width_pixels / screen_width_mm;
488         y_pixels_per_mm      = screen_height_pixels / screen_height_mm;
489
490         gl_debug (DEBUG_VIEW, "Horizontal dot pitch: %g pixels/mm (%g dpi)",
491                   x_pixels_per_mm, x_pixels_per_mm * 25.4);
492         gl_debug (DEBUG_VIEW, "Vertical dot pitch: %g pixels/mm (%g dpi)",
493                   y_pixels_per_mm, y_pixels_per_mm * 25.4);
494
495         scale = (x_pixels_per_mm + y_pixels_per_mm) / 2.0;
496
497         gl_debug (DEBUG_VIEW, "Average dot pitch: %g pixels/mm (%g dpi)",
498                   scale, scale * 25.4);
499
500         scale /= POINTS_PER_MM;
501
502         gl_debug (DEBUG_VIEW, "Scale = %g pixels/point", scale);
503
504         /* Make sure scale is somewhat sane. */
505         if ( (scale < 0.25) || (scale > 4.0) ) return 1.0;
506
507         return scale;
508 }
509
510 /*---------------------------------------------------------------------------*/
511 /* PRIVATE.  Create clipboard selection targets.                             */
512 /*---------------------------------------------------------------------------*/
513 static void
514 gl_view_construct_selection (glView *view)
515 {
516         gl_debug (DEBUG_VIEW, "START");
517
518         g_return_if_fail (GL_IS_VIEW (view));
519
520         view->have_selection = FALSE;
521         view->selection_data = NULL;
522         view->invisible = gtk_invisible_new ();
523
524         view->selected_object_list = NULL;
525
526         if (!clipboard_atom) {
527                 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
528         }
529
530         gtk_selection_add_target (view->invisible,
531                                   clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
532
533         g_signal_connect (G_OBJECT (view->invisible),
534                           "selection_clear_event",
535                           G_CALLBACK (selection_clear_cb), view);
536
537         g_signal_connect (G_OBJECT (view->invisible), "selection_get",
538                           G_CALLBACK (selection_get_cb), view);
539
540         g_signal_connect (G_OBJECT (view->invisible),
541                           "selection_received",
542                           G_CALLBACK (selection_received_cb), view);
543
544         gl_debug (DEBUG_VIEW, "END");
545 }
546
547 /*---------------------------------------------------------------------------*/
548 /* PRIVATE.  Create, draw and order layers.                                  */
549 /*---------------------------------------------------------------------------*/
550 static void
551 draw_layers (glView *view)
552 {
553         g_return_if_fail (view && GL_IS_VIEW (view));
554         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
555
556         draw_bg_fg_layers (view);
557         draw_grid_layer (view);
558         draw_markup_layer (view);
559         draw_highlight_layer (view); /* Must be done before label layer */
560         draw_label_layer (view);
561
562         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->fg_group));
563         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->highlight_group));
564
565         g_signal_connect (G_OBJECT (view->label), "size_changed",
566                           G_CALLBACK (label_resized_cb), view);
567 }
568
569 /*---------------------------------------------------------------------------*/
570 /* PRIVATE.  Handle label resize event.   .                                  */
571 /*---------------------------------------------------------------------------*/
572 static void
573 label_resized_cb (glLabel *label,
574                   glView *view)
575 {
576         gdouble label_width, label_height;
577
578         g_return_if_fail (label && GL_IS_LABEL (label));
579         g_return_if_fail (view && GL_IS_VIEW (view));
580
581         gl_label_get_size (label, &label_width, &label_height);
582         gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
583                                         0.0, 0.0, label_width, label_height);
584
585         gtk_object_destroy (GTK_OBJECT (view->bg_group));
586         gtk_object_destroy (GTK_OBJECT (view->grid_group));
587         gtk_object_destroy (GTK_OBJECT (view->markup_group));
588         gtk_object_destroy (GTK_OBJECT (view->fg_group));
589
590         draw_bg_fg_layers (view);
591         draw_grid_layer (view);
592         draw_markup_layer (view);
593
594         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->label_group));
595         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->fg_group));
596         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->highlight_group));
597 }
598
599 /*---------------------------------------------------------------------------*/
600 /* PRIVATE.  Draw label layer.                                               */
601 /*---------------------------------------------------------------------------*/
602 static void
603 draw_label_layer (glView *view)
604 {
605         GnomeCanvasGroup *group;
606         glLabel          *label;
607         GList            *p_obj;
608         glLabelObject    *object;
609         glViewObject     *view_object;
610
611         g_return_if_fail (view && GL_IS_VIEW (view));
612         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
613
614         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
615         view->label_group = GNOME_CANVAS_GROUP(
616                 gnome_canvas_item_new (group,
617                                        gnome_canvas_group_get_type (),
618                                        "x", 0.0,
619                                        "y", 0.0,
620                                        NULL));
621
622         label = view->label;
623
624         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
625                 object = (glLabelObject *) p_obj->data;
626
627                 if (GL_IS_LABEL_BOX (object)) {
628                         view_object = gl_view_box_new (GL_LABEL_BOX(object),
629                                                        view);
630                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
631                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
632                                                            view);
633                 } else if (GL_IS_LABEL_LINE (object)) {
634                         view_object = gl_view_line_new (GL_LABEL_LINE(object),
635                                                         view);
636                 } else if (GL_IS_LABEL_IMAGE (object)) {
637                         view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
638                                                          view);
639                 } else if (GL_IS_LABEL_TEXT (object)) {
640                         view_object = gl_view_text_new (GL_LABEL_TEXT(object),
641                                                         view);
642                 } else if (GL_IS_LABEL_BARCODE (object)) {
643                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
644                                                            view);
645                 } else {
646                         /* Should not happen! */
647                         view_object = NULL;
648                         g_warning ("Invalid label object type.");
649                 }
650         }
651 }
652
653 /*---------------------------------------------------------------------------*/
654 /* PRIVATE.  Create highlight layer.                                         */
655 /*---------------------------------------------------------------------------*/
656 static void
657 draw_highlight_layer (glView *view)
658 {
659         GnomeCanvasGroup *group;
660
661         g_return_if_fail (view && GL_IS_VIEW (view));
662
663         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
664         view->highlight_group = GNOME_CANVAS_GROUP(
665                 gnome_canvas_item_new (group,
666                                        gnome_canvas_group_get_type (),
667                                        "x", 0.0,
668                                        "y", 0.0,
669                                        NULL));
670 }
671
672 /*---------------------------------------------------------------------------*/
673 /* PRIVATE.  Draw background and foreground outlines.                        */
674 /*---------------------------------------------------------------------------*/
675 static void
676 draw_bg_fg_layers (glView *view)
677 {
678         glLabel                   *label;
679         glTemplate                *template;
680         const glTemplateLabelType *label_type;
681         GnomeCanvasGroup          *group;
682
683         g_return_if_fail (view && GL_IS_VIEW (view));
684         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
685
686         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
687         view->bg_group = GNOME_CANVAS_GROUP(
688                 gnome_canvas_item_new (group,
689                                        gnome_canvas_group_get_type (),
690                                        "x", 0.0,
691                                        "y", 0.0,
692                                        NULL));
693         view->fg_group = GNOME_CANVAS_GROUP(
694                 gnome_canvas_item_new (group,
695                                        gnome_canvas_group_get_type (),
696                                        "x", 0.0,
697                                        "y", 0.0,
698                                        NULL));
699
700         label      = view->label;
701         template   = gl_label_get_template (label);
702         label_type = gl_template_get_first_label_type (template);
703
704         switch (label_type->shape) {
705
706         case GL_TEMPLATE_SHAPE_RECT:
707                 if (label_type->size.rect.r == 0.0) {
708                         /* Square corners. */
709                         draw_bg_fg_rect (view);
710                 } else {
711                         /* Rounded corners. */
712                         draw_bg_fg_rounded_rect (view);
713                 }
714                 break;
715
716         case GL_TEMPLATE_SHAPE_ROUND:
717                 draw_bg_fg_round (view);
718                 break;
719
720         case GL_TEMPLATE_SHAPE_CD:
721                 if ((label_type->size.cd.w == 0.0) && (label_type->size.cd.h == 0.0) ) {
722                         draw_bg_fg_cd (view);
723                 } else {
724                         draw_bg_fg_cd_bc (view);
725                 }
726                 break;
727
728         default:
729                 g_warning ("Unknown template label style");
730                 break;
731         }
732 }
733
734 /*---------------------------------------------------------------------------*/
735 /* PRIVATE.  Draw simple recangular background.                              */
736 /*---------------------------------------------------------------------------*/
737 static void
738 draw_bg_fg_rect (glView *view)
739 {
740         glLabel          *label;
741         gdouble           w, h;
742         GnomeCanvasItem  *item;
743
744         gl_debug (DEBUG_VIEW, "START");
745
746         g_return_if_fail (view && GL_IS_VIEW (view));
747         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
748
749         label = view->label;
750
751         gl_label_get_size (label, &w, &h);
752
753         /* Background */
754         item = gnome_canvas_item_new (view->bg_group,
755                                       gnome_canvas_rect_get_type (),
756                                       "x1", 0.0,
757                                       "y1", 0.0,
758                                       "x2", w,
759                                       "y2", h,
760                                       "fill_color_rgba", PAPER_COLOR,
761                                       NULL);
762
763         /* Foreground */
764         item = gnome_canvas_item_new (view->fg_group,
765                                       gnome_canvas_rect_get_type (),
766                                       "x1", 0.0,
767                                       "y1", 0.0,
768                                       "x2", w,
769                                       "y2", h,
770                                       "width_pixels", 2,
771                                       "outline_color_rgba", OUTLINE_COLOR,
772                                       NULL);
773
774         gl_debug (DEBUG_VIEW, "END");
775 }
776
777 /*---------------------------------------------------------------------------*/
778 /* PRIVATE.  Draw rounded recangular background.                             */
779 /*---------------------------------------------------------------------------*/
780 static void
781 draw_bg_fg_rounded_rect (glView *view)
782 {
783         glLabel                   *label;
784         GnomeCanvasPoints         *points;
785         gint                       i_coords, i_theta;
786         glTemplate                *template;
787         const glTemplateLabelType *label_type;
788         gdouble                    r, w, h;
789         GnomeCanvasItem           *item;
790
791         gl_debug (DEBUG_VIEW, "START");
792
793         g_return_if_fail (view && GL_IS_VIEW (view));
794         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
795
796         label      = view->label;
797         template   = gl_label_get_template (label);
798         label_type = gl_template_get_first_label_type (template);
799
800         gl_label_get_size (label, &w, &h);
801         r = label_type->size.rect.r;
802
803         points = gnome_canvas_points_new (4 * (1 + 90 / ARC_COURSE));
804         i_coords = 0;
805         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
806                 points->coords[i_coords++] =
807                     r - r * sin (i_theta * G_PI / 180.0);
808                 points->coords[i_coords++] =
809                     r - r * cos (i_theta * G_PI / 180.0);
810         }
811         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
812                 points->coords[i_coords++] =
813                     r - r * cos (i_theta * G_PI / 180.0);
814                 points->coords[i_coords++] =
815                     (h - r) + r * sin (i_theta * G_PI / 180.0);
816         }
817         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
818                 points->coords[i_coords++] =
819                     (w - r) + r * sin (i_theta * G_PI / 180.0);
820                 points->coords[i_coords++] =
821                     (h - r) + r * cos (i_theta * G_PI / 180.0);
822         }
823         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
824                 points->coords[i_coords++] =
825                     (w - r) + r * cos (i_theta * G_PI / 180.0);
826                 points->coords[i_coords++] =
827                     r - r * sin (i_theta * G_PI / 180.0);
828         }
829
830         /* Background */
831         item = gnome_canvas_item_new (view->bg_group,
832                                       gnome_canvas_polygon_get_type (),
833                                       "points", points,
834                                       "fill_color_rgba", PAPER_COLOR,
835                                       NULL);
836
837         /* Foreground */
838         item = gnome_canvas_item_new (view->fg_group,
839                                       gnome_canvas_polygon_get_type (),
840                                       "points", points,
841                                       "width_pixels", 2,
842                                       "outline_color_rgba", OUTLINE_COLOR,
843                                       NULL);
844
845         gnome_canvas_points_free (points);
846
847         gl_debug (DEBUG_VIEW, "END");
848 }
849
850 /*---------------------------------------------------------------------------*/
851 /* PRIVATE.  Draw round background.                                          */
852 /*---------------------------------------------------------------------------*/
853 static void
854 draw_bg_fg_round (glView *view)
855 {
856         glLabel                   *label;
857         glTemplate                *template;
858         const glTemplateLabelType *label_type;
859         gdouble                    r;
860         GnomeCanvasItem           *item;
861
862         gl_debug (DEBUG_VIEW, "START");
863
864         g_return_if_fail (view && GL_IS_VIEW (view));
865         g_return_if_fail (view->label && GL_IS_LABEL(view->label));
866
867         label      = view->label;
868         template   = gl_label_get_template (label);
869         label_type = gl_template_get_first_label_type (template);
870
871         r = label_type->size.round.r;
872
873         /* Background */
874         item = gnome_canvas_item_new (view->bg_group,
875                                       gnome_canvas_ellipse_get_type (),
876                                       "x1", 0.0,
877                                       "y1", 0.0,
878                                       "x2", 2.0*r,
879                                       "y2", 2.0*r,
880                                       "fill_color_rgba", PAPER_COLOR,
881                                       NULL);
882
883         /* Foreground */
884         item = gnome_canvas_item_new (view->fg_group,
885                                       gnome_canvas_ellipse_get_type (),
886                                       "x1", 0.0,
887                                       "y1", 0.0,
888                                       "x2", 2.0*r,
889                                       "y2", 2.0*r,
890                                       "width_pixels", 2,
891                                       "outline_color_rgba", OUTLINE_COLOR,
892                                       NULL);
893
894         gl_debug (DEBUG_VIEW, "END");
895 }
896
897 /*---------------------------------------------------------------------------*/
898 /* PRIVATE.  Draw CD style background, circular w/ concentric hole.          */
899 /*---------------------------------------------------------------------------*/
900 static void
901 draw_bg_fg_cd (glView *view)
902 {
903         glLabel                   *label;
904         glTemplate                *template;
905         const glTemplateLabelType *label_type;
906         gdouble                    r1, r2;
907         GnomeCanvasItem           *item;
908
909         gl_debug (DEBUG_VIEW, "START");
910
911         g_return_if_fail (view && GL_IS_VIEW (view));
912         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
913
914         label      = view->label;
915         template   = gl_label_get_template (label);
916         label_type = gl_template_get_first_label_type (template);
917
918         r1 = label_type->size.cd.r1;
919         r2 = label_type->size.cd.r2;
920
921         /* Background */
922         /* outer circle */
923         item = gnome_canvas_item_new (view->bg_group,
924                                       gnome_canvas_ellipse_get_type (),
925                                       "x1", 0.0,
926                                       "y1", 0.0,
927                                       "x2", 2.0*r1,
928                                       "y2", 2.0*r1,
929                                       "fill_color_rgba", PAPER_COLOR,
930                                       NULL);
931         /* hole */
932         item = gnome_canvas_item_new (view->bg_group,
933                                       gnome_canvas_ellipse_get_type (),
934                                       "x1", r1 - r2,
935                                       "y1", r1 - r2,
936                                       "x2", r1 + r2,
937                                       "y2", r1 + r2,
938                                       "fill_color_rgba", GRID_COLOR,
939                                       NULL);
940
941         /* Foreground */
942         /* outer circle */
943         item = gnome_canvas_item_new (view->fg_group,
944                                       gnome_canvas_ellipse_get_type (),
945                                       "x1", 0.0,
946                                       "y1", 0.0,
947                                       "x2", 2.0*r1,
948                                       "y2", 2.0*r1,
949                                       "width_pixels", 2,
950                                       "outline_color_rgba", OUTLINE_COLOR,
951                                       NULL);
952         /* hole */
953         item = gnome_canvas_item_new (view->fg_group,
954                                       gnome_canvas_ellipse_get_type (),
955                                       "x1", r1 - r2,
956                                       "y1", r1 - r2,
957                                       "x2", r1 + r2,
958                                       "y2", r1 + r2,
959                                       "width_pixels", 2,
960                                       "outline_color_rgba", OUTLINE_COLOR,
961                                       NULL);
962
963         gl_debug (DEBUG_VIEW, "END");
964 }
965
966 /*---------------------------------------------------------------------------*/
967 /* PRIVATE.  Draw Business Card CD style background, CD w/ chopped ends.     */
968 /*---------------------------------------------------------------------------*/
969 static void
970 draw_bg_fg_cd_bc (glView *view)
971 {
972         glLabel                   *label;
973         glTemplate                *template;
974         const glTemplateLabelType *label_type;
975         GnomeCanvasPoints         *points;
976         gint                       i_coords, i_theta;
977         gdouble                    theta1, theta2;
978         gdouble                    x0, y0, w, h, r1, r2;
979         GnomeCanvasItem           *item;
980
981         gl_debug (DEBUG_VIEW, "START");
982
983         g_return_if_fail (view && GL_IS_VIEW (view));
984         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
985
986         label      = view->label;
987         template   = gl_label_get_template (label);
988         label_type = gl_template_get_first_label_type (template);
989
990         gl_label_get_size (label, &w, &h);
991         x0 = w/2.0;
992         y0 = h/2.0;
993
994         r1 = label_type->size.cd.r1;
995         r2 = label_type->size.cd.r2;
996
997         theta1 = (180.0/G_PI) * acos (w / (2.0*r1));
998         theta2 = (180.0/G_PI) * asin (h / (2.0*r1));
999
1000         points = gnome_canvas_points_new (360/ARC_FINE + 1);
1001         i_coords = 0;
1002
1003         points->coords[i_coords++] = x0 + r1 * cos (theta1 * G_PI / 180.0);
1004         points->coords[i_coords++] = y0 + r1 * sin (theta1 * G_PI / 180.0);
1005
1006         for ( i_theta = theta1 + ARC_FINE; i_theta < theta2; i_theta +=ARC_FINE ) {
1007                 points->coords[i_coords++] = x0 + r1 * cos (i_theta * G_PI / 180.0);
1008                 points->coords[i_coords++] = y0 + r1 * sin (i_theta * G_PI / 180.0);
1009         }
1010
1011         points->coords[i_coords++] = x0 + r1 * cos (theta2 * G_PI / 180.0);
1012         points->coords[i_coords++] = y0 + r1 * sin (theta2 * G_PI / 180.0);
1013
1014
1015         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1016                 points->coords[i_coords++] = x0 + r1 * cos ((180-theta2) * G_PI / 180.0);
1017                 points->coords[i_coords++] = y0 + r1 * sin ((180-theta2) * G_PI / 180.0);
1018         }
1019
1020         for ( i_theta = 180-theta2+ARC_FINE; i_theta < (180-theta1); i_theta +=ARC_FINE ) {
1021                 points->coords[i_coords++] = x0 + r1 * cos (i_theta * G_PI / 180.0);
1022                 points->coords[i_coords++] = y0 + r1 * sin (i_theta * G_PI / 180.0);
1023         }
1024
1025         points->coords[i_coords++] = x0 + r1 * cos ((180-theta1) * G_PI / 180.0);
1026         points->coords[i_coords++] = y0 + r1 * sin ((180-theta1) * G_PI / 180.0);
1027
1028         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1029                 points->coords[i_coords++] = x0 + r1 * cos ((180+theta1) * G_PI / 180.0);
1030                 points->coords[i_coords++] = y0 + r1 * sin ((180+theta1) * G_PI / 180.0);
1031         }
1032
1033         for ( i_theta = 180+theta1+ARC_FINE; i_theta < (180+theta2); i_theta +=ARC_FINE ) {
1034                 points->coords[i_coords++] = x0 + r1 * cos (i_theta * G_PI / 180.0);
1035                 points->coords[i_coords++] = y0 + r1 * sin (i_theta * G_PI / 180.0);
1036         }
1037
1038         points->coords[i_coords++] = x0 + r1 * cos ((180+theta2) * G_PI / 180.0);
1039         points->coords[i_coords++] = y0 + r1 * sin ((180+theta2) * G_PI / 180.0);
1040
1041         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1042                 points->coords[i_coords++] = x0 + r1 * cos ((360-theta2) * G_PI / 180.0);
1043                 points->coords[i_coords++] = y0 + r1 * sin ((360-theta2) * G_PI / 180.0);
1044         }
1045
1046         for ( i_theta = 360-theta2+ARC_FINE; i_theta < (360-theta1); i_theta +=ARC_FINE ) {
1047                 points->coords[i_coords++] = x0 + r1 * cos (i_theta * G_PI / 180.0);
1048                 points->coords[i_coords++] = y0 + r1 * sin (i_theta * G_PI / 180.0);
1049         }
1050
1051         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1052                 points->coords[i_coords++] = x0 + r1 * cos ((360-theta1) * G_PI / 180.0);
1053                 points->coords[i_coords++] = y0 + r1 * sin ((360-theta1) * G_PI / 180.0);
1054         }
1055
1056         points->num_points = i_coords / 2;
1057
1058         /* Background */
1059         /* outer circle */
1060         item = gnome_canvas_item_new (view->bg_group,
1061                                       gnome_canvas_polygon_get_type (),
1062                                       "points", points,
1063                                       "fill_color_rgba", PAPER_COLOR,
1064                                       NULL);
1065         /* hole */
1066         item = gnome_canvas_item_new (view->bg_group,
1067                                       gnome_canvas_ellipse_get_type (),
1068                                       "x1", x0 - r2,
1069                                       "y1", y0 - r2,
1070                                       "x2", x0 + r2,
1071                                       "y2", y0 + r2,
1072                                       "fill_color_rgba", GRID_COLOR,
1073                                       NULL);
1074
1075         /* Foreground */
1076         /* outer circle */
1077         item = gnome_canvas_item_new (view->fg_group,
1078                                       gnome_canvas_polygon_get_type (),
1079                                       "points", points,
1080                                       "width_pixels", 2,
1081                                       "outline_color_rgba", OUTLINE_COLOR,
1082                                       NULL);
1083         /* hole */
1084         item = gnome_canvas_item_new (view->fg_group,
1085                                       gnome_canvas_ellipse_get_type (),
1086                                       "x1", x0 - r2,
1087                                       "y1", y0 - r2,
1088                                       "x2", x0 + r2,
1089                                       "y2", y0 + r2,
1090                                       "width_pixels", 2,
1091                                       "outline_color_rgba", OUTLINE_COLOR,
1092                                       NULL);
1093
1094         gnome_canvas_points_free (points);
1095
1096         gl_debug (DEBUG_VIEW, "END");
1097 }
1098
1099 /*---------------------------------------------------------------------------*/
1100 /* PRIVATE.  Draw grid lines.                                                */
1101 /*---------------------------------------------------------------------------*/
1102 static void
1103 draw_grid_layer (glView *view)
1104 {
1105         gdouble                    w, h, x, y, x0, y0;
1106         GnomeCanvasPoints         *points;
1107         GnomeCanvasItem           *item;
1108         GnomeCanvasGroup          *group;
1109         glTemplate                *template;
1110         const glTemplateLabelType *template_type;
1111
1112         gl_debug (DEBUG_VIEW, "START");
1113
1114         g_return_if_fail (view && GL_IS_VIEW (view));
1115         g_return_if_fail (view->label && GL_IS_LABEL(view->label));
1116
1117         gl_label_get_size (view->label, &w, &h);
1118         template = gl_label_get_template (view->label);
1119         template_type = gl_template_get_first_label_type (template);
1120         
1121         if (template_type->shape == GL_TEMPLATE_SHAPE_RECT) {
1122                 x0 = 0.0;
1123                 y0 = 0.0;
1124         } else {
1125                 /* for round labels, adjust grid to line up with center of label. */
1126                 x0 = fmod (w/2.0, view->grid_spacing);
1127                 y0 = fmod (h/2.0, view->grid_spacing);
1128         }
1129
1130         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
1131         view->grid_group = GNOME_CANVAS_GROUP(
1132                 gnome_canvas_item_new (group,
1133                                        gnome_canvas_group_get_type (),
1134                                        "x", 0.0,
1135                                        "y", 0.0,
1136                                        NULL));
1137         points = gnome_canvas_points_new (2);
1138
1139         points->coords[1] = 0.0;
1140         points->coords[3] = h;
1141         for ( x=x0+view->grid_spacing; x < w; x += view->grid_spacing ) {
1142                 points->coords[0] = points->coords[2] = x;
1143                 item = gnome_canvas_item_new (view->grid_group,
1144                                               gnome_canvas_line_get_type (),
1145                                               "points", points,
1146                                               "width_pixels", 1,
1147                                               "fill_color_rgba", GRID_COLOR,
1148                                               NULL);
1149         }
1150
1151         points->coords[0] = 0.0;
1152         points->coords[2] = w;
1153         for ( y=y0+view->grid_spacing; y < h; y += view->grid_spacing ) {
1154                 points->coords[1] = points->coords[3] = y;
1155                 item = gnome_canvas_item_new (view->grid_group,
1156                                               gnome_canvas_line_get_type (),
1157                                               "points", points,
1158                                               "width_pixels", 1,
1159                                               "fill_color_rgba", GRID_COLOR,
1160                                               NULL);
1161         }
1162
1163         gnome_canvas_points_free (points);
1164         gl_template_free (template);
1165
1166         gl_debug (DEBUG_VIEW, "END");
1167 }
1168
1169 /*---------------------------------------------------------------------------*/
1170 /* PRIVATE.  Draw markup lines.                                              */
1171 /*---------------------------------------------------------------------------*/
1172 static void
1173 draw_markup_layer (glView *view)
1174 {
1175         GnomeCanvasGroup          *group;
1176         glLabel                   *label;
1177         glTemplate                *template;
1178         const glTemplateLabelType *label_type;
1179         GList                     *p;
1180         glTemplateMarkup          *markup;
1181
1182         g_return_if_fail (view && GL_IS_VIEW (view));
1183         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1184
1185         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
1186         view->markup_group = GNOME_CANVAS_GROUP(
1187                 gnome_canvas_item_new (group,
1188                                        gnome_canvas_group_get_type (),
1189                                        "x", 0.0,
1190                                        "y", 0.0,
1191                                        NULL));
1192
1193         label      = view->label;
1194         template   = gl_label_get_template (label);
1195         label_type = gl_template_get_first_label_type (template);
1196
1197         for ( p=label_type->markups; p != NULL; p=p->next ) {
1198                 markup = (glTemplateMarkup *)p->data;
1199
1200                 switch (markup->type) {
1201                 case GL_TEMPLATE_MARKUP_MARGIN:
1202                         draw_markup_margin (view, markup);
1203                         break;
1204                 case GL_TEMPLATE_MARKUP_LINE:
1205                         draw_markup_line (view, markup);
1206                         break;
1207                 case GL_TEMPLATE_MARKUP_CIRCLE:
1208                         draw_markup_circle (view, markup);
1209                         break;
1210                 default:
1211                         g_warning ("Unknown template markup type");
1212                         break;
1213                 }
1214         }
1215 }
1216
1217 /*---------------------------------------------------------------------------*/
1218 /* PRIVATE.  Draw margin markup.                                             */
1219 /*---------------------------------------------------------------------------*/
1220 static void
1221 draw_markup_margin (glView           *view,
1222                     glTemplateMarkup *markup)
1223 {
1224         glLabel                   *label;
1225         glTemplate                *template;
1226         const glTemplateLabelType *label_type;
1227
1228         g_return_if_fail (view && GL_IS_VIEW (view));
1229         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1230
1231         label      = view->label;
1232         template   = gl_label_get_template (label);
1233         label_type = gl_template_get_first_label_type (template);
1234
1235         switch (label_type->shape) {
1236
1237         case GL_TEMPLATE_SHAPE_RECT:
1238                 if (label_type->size.rect.r == 0.0) {
1239                         /* Square corners. */
1240                         draw_markup_margin_rect (view, markup);
1241                 } else {
1242                         if ( markup->data.margin.size < label_type->size.rect.r) {
1243                                 /* Rounded corners. */
1244                                 draw_markup_margin_rounded_rect (view, markup);
1245                         } else {
1246                                 /* Square corners. */
1247                                 draw_markup_margin_rect (view, markup);
1248                         }
1249                 }
1250                 break;
1251
1252         case GL_TEMPLATE_SHAPE_ROUND:
1253                 draw_markup_margin_round (view, markup);
1254                 break;
1255
1256         case GL_TEMPLATE_SHAPE_CD:
1257                 if ((label_type->size.cd.w == 0.0) && (label_type->size.cd.h == 0.0) ) {
1258                         draw_markup_margin_cd (view, markup);
1259                 } else {
1260                         draw_markup_margin_cd_bc (view, markup);
1261                 }
1262                 break;
1263
1264         default:
1265                 g_warning ("Unknown template label style");
1266                 break;
1267         }
1268 }
1269
1270 /*---------------------------------------------------------------------------*/
1271 /* PRIVATE.  Draw simple recangular margin.                                  */
1272 /*---------------------------------------------------------------------------*/
1273 static void
1274 draw_markup_margin_rect (glView           *view,
1275                          glTemplateMarkup *markup)
1276 {
1277         glLabel                   *label;
1278         glTemplate                *template;
1279         const glTemplateLabelType *label_type;
1280         gdouble                    w, h, m;
1281         GnomeCanvasItem           *item;
1282
1283         gl_debug (DEBUG_VIEW, "START");
1284
1285         g_return_if_fail (view && GL_IS_VIEW (view));
1286         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1287
1288         label      = view->label;
1289         template   = gl_label_get_template (label);
1290         label_type = gl_template_get_first_label_type (template);
1291
1292         gl_label_get_size (label, &w, &h);
1293         m = markup->data.margin.size;
1294
1295         /* Bounding box @ margin */
1296         gnome_canvas_item_new (view->markup_group,
1297                                gnome_canvas_rect_get_type (),
1298                                "x1", m,
1299                                "y1", m,
1300                                "x2", w - m,
1301                                "y2", h - m,
1302                                "width_pixels", 1,
1303                                "outline_color_rgba", MARKUP_COLOR,
1304                                NULL);
1305
1306         gl_debug (DEBUG_VIEW, "END");
1307 }
1308
1309 /*---------------------------------------------------------------------------*/
1310 /* PRIVATE.  Draw rounded recangular markup.                                 */
1311 /*---------------------------------------------------------------------------*/
1312 static void
1313 draw_markup_margin_rounded_rect (glView           *view,
1314                                  glTemplateMarkup *markup)
1315 {
1316         glLabel                   *label;
1317         glTemplate                *template;
1318         const glTemplateLabelType *label_type;
1319         GnomeCanvasPoints         *points;
1320         gint                       i_coords, i_theta;
1321         gdouble                    r, w, h, m;
1322         GnomeCanvasItem           *item;
1323
1324         gl_debug (DEBUG_VIEW, "START");
1325
1326         g_return_if_fail (view && GL_IS_VIEW (view));
1327         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1328
1329         label      = view->label;
1330         template   = gl_label_get_template (label);
1331         label_type = gl_template_get_first_label_type (template);
1332
1333         gl_label_get_size (label, &w, &h);
1334         r = label_type->size.rect.r;
1335         m = markup->data.margin.size;
1336
1337         r = r - m;
1338         w = w - 2 * m;
1339         h = h - 2 * m;
1340
1341         /* rectangle with rounded corners */
1342         points = gnome_canvas_points_new (4 * (1 + 90 / ARC_COURSE));
1343         i_coords = 0;
1344         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1345                 points->coords[i_coords++] =
1346                         m + r - r * sin (i_theta * G_PI / 180.0);
1347                 points->coords[i_coords++] =
1348                         m + r - r * cos (i_theta * G_PI / 180.0);
1349         }
1350         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1351                 points->coords[i_coords++] =
1352                         m + r - r * cos (i_theta * G_PI / 180.0);
1353                 points->coords[i_coords++] =
1354                         m + (h - r) + r * sin (i_theta * G_PI / 180.0);
1355         }
1356         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1357                 points->coords[i_coords++] =
1358                         m + (w - r) + r * sin (i_theta * G_PI / 180.0);
1359                 points->coords[i_coords++] =
1360                         m + (h - r) + r * cos (i_theta * G_PI / 180.0);
1361         }
1362         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1363                 points->coords[i_coords++] =
1364                         m + (w - r) + r * cos (i_theta * G_PI / 180.0);
1365                 points->coords[i_coords++] =
1366                         m + r - r * sin (i_theta * G_PI / 180.0);
1367         }
1368         item = gnome_canvas_item_new (view->markup_group,
1369                                       gnome_canvas_polygon_get_type (),
1370                                       "points", points,
1371                                       "width_pixels", 1,
1372                                       "outline_color_rgba", MARKUP_COLOR,
1373                                       NULL);
1374         gnome_canvas_points_free (points);
1375
1376         gl_debug (DEBUG_VIEW, "END");
1377 }
1378
1379 /*---------------------------------------------------------------------------*/
1380 /* PRIVATE.  Draw round margin.                                              */
1381 /*---------------------------------------------------------------------------*/
1382 static void
1383 draw_markup_margin_round (glView           *view,
1384                           glTemplateMarkup *markup)
1385 {
1386         glLabel                   *label;
1387         glTemplate                *template;
1388         const glTemplateLabelType *label_type;
1389         gdouble                    r, m;
1390         GnomeCanvasItem           *item;
1391
1392         gl_debug (DEBUG_VIEW, "START");
1393
1394         g_return_if_fail (view && GL_IS_VIEW (view));
1395         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1396
1397         label      = view->label;
1398         template   = gl_label_get_template (label);
1399         label_type = gl_template_get_first_label_type (template);
1400
1401         r = label_type->size.round.r;
1402         m = markup->data.margin.size;
1403
1404         /* Margin outline */
1405         item = gnome_canvas_item_new (view->markup_group,
1406                                       gnome_canvas_ellipse_get_type (),
1407                                       "x1", m,
1408                                       "y1", m,
1409                                       "x2", 2.0*r - m,
1410                                       "y2", 2.0*r - m,
1411                                       "width_pixels", 1,
1412                                       "outline_color_rgba", MARKUP_COLOR,
1413                                       NULL);
1414
1415         gl_debug (DEBUG_VIEW, "END");
1416 }
1417
1418 /*---------------------------------------------------------------------------*/
1419 /* PRIVATE.  Draw CD margins.                                                */
1420 /*---------------------------------------------------------------------------*/
1421 static void
1422 draw_markup_margin_cd (glView           *view,
1423                        glTemplateMarkup *markup)
1424 {
1425         glLabel                   *label;
1426         glTemplate                *template;
1427         const glTemplateLabelType *label_type;
1428         gdouble                    m, r1, r2;
1429         GnomeCanvasItem           *item;
1430
1431         gl_debug (DEBUG_VIEW, "START");
1432
1433         g_return_if_fail (view && GL_IS_VIEW (view));
1434         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1435
1436         label      = view->label;
1437         template   = gl_label_get_template (label);
1438         label_type = gl_template_get_first_label_type (template);
1439
1440         r1 = label_type->size.cd.r1;
1441         r2 = label_type->size.cd.r2;
1442         m  = markup->data.margin.size;
1443
1444         /* outer margin */
1445         item = gnome_canvas_item_new (view->markup_group,
1446                                       gnome_canvas_ellipse_get_type (),
1447                                       "x1", m,
1448                                       "y1", m,
1449                                       "x2", 2.0*r1 - m,
1450                                       "y2", 2.0*r1 - m,
1451                                       "width_pixels", 1,
1452                                       "outline_color_rgba", MARKUP_COLOR,
1453                                       NULL);
1454         /* inner margin */
1455         item = gnome_canvas_item_new (view->markup_group,
1456                                       gnome_canvas_ellipse_get_type (),
1457                                       "x1", r1 - r2 - m,
1458                                       "y1", r1 - r2 - m,
1459                                       "x2", r1 + r2 + m,
1460                                       "y2", r1 + r2 + m,
1461                                       "width_pixels", 1,
1462                                       "outline_color_rgba", MARKUP_COLOR,
1463                                       NULL);
1464
1465         gl_debug (DEBUG_VIEW, "END");
1466 }
1467
1468 /*---------------------------------------------------------------------------*/
1469 /* PRIVATE.  Draw Business Card CD margins.                                  */
1470 /*---------------------------------------------------------------------------*/
1471 static void
1472 draw_markup_margin_cd_bc (glView           *view,
1473                           glTemplateMarkup *markup)
1474 {
1475         glLabel                   *label;
1476         glTemplate                *template;
1477         const glTemplateLabelType *label_type;
1478         gdouble                    m, r1, r2;
1479         GnomeCanvasPoints         *points;
1480         gint                       i_coords, i_theta;
1481         gdouble                    theta1, theta2;
1482         gdouble                    x0, y0, w, h, r;
1483         GnomeCanvasItem           *item;
1484
1485         gl_debug (DEBUG_VIEW, "START");
1486
1487         g_return_if_fail (view && GL_IS_VIEW (view));
1488         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
1489
1490         label      = view->label;
1491         template   = gl_label_get_template (label);
1492         label_type = gl_template_get_first_label_type (template);
1493
1494         gl_label_get_size (label, &w, &h);
1495         x0 = w/2.0;
1496         y0 = h/2.0;
1497
1498         r1 = label_type->size.cd.r1;
1499         r2 = label_type->size.cd.r2;
1500         m  = markup->data.margin.size;
1501
1502         /* outer margin */
1503         r = r1 - m;
1504         theta1 = (180.0/G_PI) * acos (w / (2.0*r1));
1505         theta2 = (180.0/G_PI) * asin (h / (2.0*r1));
1506
1507         points = gnome_canvas_points_new (360/ARC_FINE + 1);
1508         i_coords = 0;
1509
1510         points->coords[i_coords++] = x0 + r * cos (theta1 * G_PI / 180.0);
1511         points->coords[i_coords++] = y0 + r * sin (theta1 * G_PI / 180.0);
1512
1513         for ( i_theta = theta1 + ARC_FINE; i_theta < theta2; i_theta +=ARC_FINE ) {
1514                 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
1515                 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
1516         }
1517
1518         points->coords[i_coords++] = x0 + r * cos (theta2 * G_PI / 180.0);
1519         points->coords[i_coords++] = y0 + r * sin (theta2 * G_PI / 180.0);
1520
1521
1522         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1523                 points->coords[i_coords++] = x0 + r * cos ((180-theta2) * G_PI / 180.0);
1524                 points->coords[i_coords++] = y0 + r * sin ((180-theta2) * G_PI / 180.0);
1525         }
1526
1527         for ( i_theta = 180-theta2+ARC_FINE; i_theta < (180-theta1); i_theta +=ARC_FINE ) {
1528                 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
1529                 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
1530         }
1531
1532         points->coords[i_coords++] = x0 + r * cos ((180-theta1) * G_PI / 180.0);
1533         points->coords[i_coords++] = y0 + r * sin ((180-theta1) * G_PI / 180.0);
1534
1535         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1536                 points->coords[i_coords++] = x0 + r * cos ((180+theta1) * G_PI / 180.0);
1537                 points->coords[i_coords++] = y0 + r * sin ((180+theta1) * G_PI / 180.0);
1538         }
1539
1540         for ( i_theta = 180+theta1+ARC_FINE; i_theta < (180+theta2); i_theta +=ARC_FINE ) {
1541                 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
1542                 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
1543         }
1544
1545         points->coords[i_coords++] = x0 + r * cos ((180+theta2) * G_PI / 180.0);
1546         points->coords[i_coords++] = y0 + r * sin ((180+theta2) * G_PI / 180.0);
1547
1548         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1549                 points->coords[i_coords++] = x0 + r * cos ((360-theta2) * G_PI / 180.0);
1550                 points->coords[i_coords++] = y0 + r * sin ((360-theta2) * G_PI / 180.0);
1551         }
1552
1553         for ( i_theta = 360-theta2+ARC_FINE; i_theta < (360-theta1); i_theta +=ARC_FINE ) {
1554                 points->coords[i_coords++] = x0 + r * cos (i_theta * G_PI / 180.0);
1555                 points->coords[i_coords++] = y0 + r * sin (i_theta * G_PI / 180.0);
1556         }
1557
1558         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1559                 points->coords[i_coords++] = x0 + r * cos ((360-theta1) * G_PI / 180.0);
1560                 points->coords[i_coords++] = y0 + r * sin ((360-theta1) * G_PI / 180.0);
1561         }
1562
1563         points->num_points = i_coords / 2;
1564
1565         item = gnome_canvas_item_new (view->markup_group,
1566                                       gnome_canvas_polygon_get_type (),
1567                                       "points", points,
1568                                       "width_pixels", 1,
1569                                       "outline_color_rgba", MARKUP_COLOR,
1570                                       NULL);
1571
1572         gnome_canvas_points_free (points);
1573
1574         /* inner margin */
1575         item = gnome_canvas_item_new (view->markup_group,
1576                                       gnome_canvas_ellipse_get_type (),
1577                                       "x1", x0 - r2 - m,
1578                                       "y1", y0 - r2 - m,
1579                                       "x2", x0 + r2 + m,
1580                                       "y2", y0 + r2 + m,
1581                                       "width_pixels", 1,
1582                                       "outline_color_rgba", MARKUP_COLOR,
1583                                       NULL);
1584
1585         gl_debug (DEBUG_VIEW, "END");
1586 }
1587
1588 /*---------------------------------------------------------------------------*/
1589 /* PRIVATE.  Draw line markup.                                               */
1590 /*---------------------------------------------------------------------------*/
1591 static void
1592 draw_markup_line (glView           *view,
1593                   glTemplateMarkup *markup)
1594 {
1595         GnomeCanvasPoints *points;
1596
1597         gl_debug (DEBUG_VIEW, "START");
1598
1599         g_return_if_fail (view && GL_IS_VIEW (view));
1600
1601         points = gnome_canvas_points_new (2);
1602         points->coords[0] = markup->data.line.x1;
1603         points->coords[1] = markup->data.line.y1;
1604         points->coords[2] = markup->data.line.x2;
1605         points->coords[3] = markup->data.line.y2;
1606
1607         gnome_canvas_item_new (view->markup_group,
1608                                gnome_canvas_line_get_type (),
1609                                "points", points,
1610                                "width_pixels", 1,
1611                                "fill_color_rgba", MARKUP_COLOR,
1612                                NULL);
1613
1614         gnome_canvas_points_free (points);
1615
1616         gl_debug (DEBUG_VIEW, "END");
1617 }
1618
1619 /*---------------------------------------------------------------------------*/
1620 /* PRIVATE.  Draw circle markup.                                             */
1621 /*---------------------------------------------------------------------------*/
1622 static void
1623 draw_markup_circle (glView           *view,
1624                     glTemplateMarkup *markup)
1625 {
1626         gl_debug (DEBUG_VIEW, "START");
1627
1628         g_return_if_fail (view && GL_IS_VIEW (view));
1629
1630         /* Circle outline */
1631         gnome_canvas_item_new (view->markup_group,
1632                                gnome_canvas_ellipse_get_type (),
1633                                "x1", markup->data.circle.x0 - markup->data.circle.r,
1634                                "y1", markup->data.circle.y0 - markup->data.circle.r,
1635                                "x2", markup->data.circle.x0 + markup->data.circle.r,
1636                                "y2", markup->data.circle.y0 + markup->data.circle.r,
1637                                "width_pixels", 1,
1638                                "outline_color_rgba", MARKUP_COLOR,
1639                                NULL);
1640
1641         gl_debug (DEBUG_VIEW, "END");
1642 }
1643
1644 /*****************************************************************************/
1645 /* Show grid.                                                                */
1646 /*****************************************************************************/
1647 void       gl_view_show_grid               (glView            *view)
1648 {
1649         g_return_if_fail (view && GL_IS_VIEW (view));
1650
1651         gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->grid_group));
1652 }
1653
1654 /*****************************************************************************/
1655 /* Hide grid.                                                                */
1656 /*****************************************************************************/
1657 void       gl_view_hide_grid               (glView            *view)
1658 {
1659         g_return_if_fail (view && GL_IS_VIEW (view));
1660
1661         gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->grid_group));
1662 }
1663
1664 /*****************************************************************************/
1665 /* Set grid spacing.                                                         */
1666 /*****************************************************************************/
1667 void       gl_view_set_grid_spacing        (glView            *view,
1668                                             gdouble            spacing)
1669 {
1670         g_return_if_fail (view && GL_IS_VIEW (view));
1671
1672         view->grid_spacing = spacing;
1673
1674         gtk_object_destroy (GTK_OBJECT(view->grid_group));
1675         draw_grid_layer (view);
1676 }
1677
1678 /*****************************************************************************/
1679 /* Show markup.                                                              */
1680 /*****************************************************************************/
1681 void       gl_view_show_markup             (glView            *view)
1682 {
1683         g_return_if_fail (view && GL_IS_VIEW (view));
1684
1685         gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->markup_group));
1686 }
1687
1688 /*****************************************************************************/
1689 /* Hide markup.                                                              */
1690 /*****************************************************************************/
1691 void       gl_view_hide_markup             (glView            *view)
1692 {
1693         g_return_if_fail (view && GL_IS_VIEW (view));
1694
1695         gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->markup_group));
1696 }
1697
1698 /*****************************************************************************/
1699 /* Set arrow mode.                                                           */
1700 /*****************************************************************************/
1701 void
1702 gl_view_arrow_mode (glView *view)
1703 {
1704         static GdkCursor *cursor = NULL;
1705
1706         gl_debug (DEBUG_VIEW, "START");
1707
1708         g_return_if_fail (view && GL_IS_VIEW (view));
1709
1710         if (!cursor) {
1711                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1712         }
1713
1714         gdk_window_set_cursor (view->canvas->window, cursor);
1715
1716         view->state = GL_VIEW_STATE_ARROW;
1717
1718         gl_debug (DEBUG_VIEW, "END");
1719 }
1720
1721 /*****************************************************************************/
1722 /* Set create text object mode.                                              */
1723 /*****************************************************************************/
1724 void
1725 gl_view_object_create_mode (glView            *view,
1726                             glLabelObjectType type)
1727 {
1728         GdkCursor *cursor;
1729
1730         gl_debug (DEBUG_VIEW, "START");
1731
1732         g_return_if_fail (view && GL_IS_VIEW (view));
1733
1734         switch (type) {
1735         case GL_LABEL_OBJECT_BOX:
1736                 cursor = gl_view_box_get_create_cursor ();
1737                 break;
1738         case GL_LABEL_OBJECT_ELLIPSE:
1739                 cursor = gl_view_ellipse_get_create_cursor ();
1740                 break;
1741         case GL_LABEL_OBJECT_LINE:
1742                 cursor = gl_view_line_get_create_cursor ();
1743                 break;
1744         case GL_LABEL_OBJECT_IMAGE:
1745                 cursor = gl_view_image_get_create_cursor ();
1746                 break;
1747         case GL_LABEL_OBJECT_TEXT:
1748                 cursor = gl_view_text_get_create_cursor ();
1749                 break;
1750         case GL_LABEL_OBJECT_BARCODE:
1751                 cursor = gl_view_barcode_get_create_cursor ();
1752                 break;
1753         default:
1754                 g_warning ("Invalid label object type.");/*Should not happen!*/
1755                 break;
1756         }
1757
1758         gdk_window_set_cursor (view->canvas->window, cursor);
1759
1760         view->state = GL_VIEW_STATE_OBJECT_CREATE;
1761         view->create_type = type;
1762
1763         gl_debug (DEBUG_VIEW, "END");
1764 }
1765
1766 /*****************************************************************************/
1767 /* Select given object (adding to current selection).                        */
1768 /*****************************************************************************/
1769 void
1770 gl_view_select_object (glView       *view,
1771                        glViewObject *view_object)
1772 {
1773         gl_debug (DEBUG_VIEW, "START");
1774
1775         g_return_if_fail (view && GL_IS_VIEW (view));
1776
1777         select_object_real (view, view_object);
1778
1779         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1780
1781         gl_debug (DEBUG_VIEW, "END");
1782 }
1783
1784 /*****************************************************************************/
1785 /* Unselect given object (removing from current selection).                  */
1786 /*****************************************************************************/
1787 void
1788 gl_view_unselect_object (glView       *view,
1789                          glViewObject *view_object)
1790 {
1791         gl_debug (DEBUG_VIEW, "START");
1792
1793         g_return_if_fail (view && GL_IS_VIEW (view));
1794
1795         unselect_object_real (view, view_object);
1796
1797         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1798
1799         gl_debug (DEBUG_VIEW, "END");
1800 }
1801
1802 /*****************************************************************************/
1803 /* Select all items.                                                         */
1804 /*****************************************************************************/
1805 void
1806 gl_view_select_all (glView *view)
1807 {
1808         GList *p, *p_next;
1809
1810         gl_debug (DEBUG_VIEW, "START");
1811
1812         g_return_if_fail (view && GL_IS_VIEW (view));
1813
1814         /* 1st unselect anything already selected. */
1815         for (p = view->selected_object_list; p != NULL; p = p_next) {
1816                 p_next = p->next;
1817                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1818         }
1819
1820         /* Finally select all objects. */
1821         for (p = view->object_list; p != NULL; p = p->next) {
1822                 select_object_real (view, GL_VIEW_OBJECT (p->data));
1823         }
1824
1825         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1826
1827         gl_debug (DEBUG_VIEW, "END");
1828 }
1829
1830 /*****************************************************************************/
1831 /* Remove all selections                                                     */
1832 /*****************************************************************************/
1833 void
1834 gl_view_unselect_all (glView *view)
1835 {
1836         GList *p, *p_next;
1837
1838         gl_debug (DEBUG_VIEW, "START");
1839
1840         g_return_if_fail (view && GL_IS_VIEW (view));
1841
1842         for (p = view->selected_object_list; p != NULL; p = p_next) {
1843                 p_next = p->next;
1844                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1845         }
1846
1847         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1848
1849         gl_debug (DEBUG_VIEW, "END");
1850 }
1851
1852 /*****************************************************************************/
1853 /* Select all objects within given rectangular region (adding to selection). */
1854 /*****************************************************************************/
1855 void
1856 gl_view_select_region (glView  *view,
1857                        gdouble  x1,
1858                        gdouble  y1,
1859                        gdouble  x2,
1860                        gdouble  y2)
1861 {
1862         GList *p;
1863         glViewObject *view_object;
1864         glLabelObject *object;
1865         gdouble i_x1, i_y1, i_x2, i_y2;
1866
1867         gl_debug (DEBUG_VIEW, "START");
1868
1869         g_return_if_fail (view && GL_IS_VIEW (view));
1870         g_return_if_fail ((x1 <= x2) && (y1 <= y2));
1871
1872         for (p = view->object_list; p != NULL; p = p->next) {
1873                 view_object = GL_VIEW_OBJECT(p->data);
1874                 if (!gl_view_is_object_selected (view, view_object)) {
1875
1876                         object = gl_view_object_get_object (view_object);
1877
1878                         gl_label_object_get_extent (object, &i_x1, &i_y1, &i_x2, &i_y2);
1879                         if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
1880                             && (i_y2 <= y2)) {
1881                                 select_object_real (view, view_object);
1882                         }
1883
1884                 }
1885         }
1886
1887         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1888
1889         gl_debug (DEBUG_VIEW, "END");
1890 }
1891
1892 /*---------------------------------------------------------------------------*/
1893 /* PRIVATE. Select an object.                                                */
1894 /*---------------------------------------------------------------------------*/
1895 static void
1896 select_object_real (glView       *view,
1897                     glViewObject *view_object)
1898 {
1899         gl_debug (DEBUG_VIEW, "START");
1900
1901         g_return_if_fail (view && GL_IS_VIEW (view));
1902         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1903
1904         if (!gl_view_is_object_selected (view, view_object)) {
1905                 view->selected_object_list =
1906                     g_list_prepend (view->selected_object_list, view_object);
1907         }
1908         gl_view_object_show_highlight (view_object);
1909         gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
1910
1911         gl_debug (DEBUG_VIEW, "END");
1912 }
1913
1914 /*---------------------------------------------------------------------------*/
1915 /* PRIVATE.  Un-select object.                                               */
1916 /*---------------------------------------------------------------------------*/
1917 static void
1918 unselect_object_real (glView       *view,
1919                       glViewObject *view_object)
1920 {
1921         gl_debug (DEBUG_VIEW, "START");
1922
1923         g_return_if_fail (view && GL_IS_VIEW (view));
1924         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1925
1926         gl_view_object_hide_highlight (view_object);
1927
1928         view->selected_object_list =
1929             g_list_remove (view->selected_object_list, view_object);
1930
1931         gl_debug (DEBUG_VIEW, "END");
1932 }
1933
1934 /*---------------------------------------------------------------------------*/
1935 /* PRIVATE. Return object at (x,y).                                          */
1936 /*---------------------------------------------------------------------------*/
1937 static gboolean
1938 object_at (glView  *view,
1939            gdouble  x,
1940            gdouble  y)
1941 {
1942         GnomeCanvasItem *item, *p_item;
1943         GList *p;
1944
1945         gl_debug (DEBUG_VIEW, "");
1946
1947         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1948
1949         item = gnome_canvas_get_item_at (GNOME_CANVAS (view->canvas), x, y);
1950
1951         /* No item is at x, y */
1952         if (item == NULL)
1953                 return FALSE;
1954
1955         /* ignore items not in label or highlight layers, e.g. background items */
1956         if (!is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->label_group)) &&
1957             !is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->highlight_group)))
1958                 return FALSE;
1959
1960         return TRUE;
1961 }
1962
1963 /*---------------------------------------------------------------------------*/
1964 /* PRIVATE.  Is the item a child (or grandchild, etc.) of group.             */
1965 /*---------------------------------------------------------------------------*/
1966 static gboolean
1967 is_item_member_of_group (glView          *view,
1968                          GnomeCanvasItem *item,
1969                          GnomeCanvasItem *group)
1970 {
1971         GnomeCanvasItem *parent;
1972         GnomeCanvasItem *root_group;
1973
1974         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1975
1976         root_group = GNOME_CANVAS_ITEM(gnome_canvas_root (GNOME_CANVAS (view->canvas)));
1977
1978         for ( parent=item->parent; parent && (parent!=root_group); parent=parent->parent) {
1979                 if (parent == group) return TRUE;
1980         }
1981         return FALSE;
1982 }
1983
1984 /*****************************************************************************/
1985 /* Is the object in our current selection?                                   */
1986 /*****************************************************************************/
1987 gboolean
1988 gl_view_is_object_selected (glView       *view,
1989                     glViewObject *view_object)
1990 {
1991         gl_debug (DEBUG_VIEW, "");
1992
1993         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1994         g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
1995
1996         if (g_list_find (view->selected_object_list, view_object) == NULL) {
1997                 return FALSE;
1998         }
1999         return TRUE;
2000 }
2001
2002 /*****************************************************************************/
2003 /* Is our current selection empty?                                           */
2004 /*****************************************************************************/
2005 gboolean
2006 gl_view_is_selection_empty (glView *view)
2007 {
2008         gl_debug (DEBUG_VIEW, "");
2009
2010         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2011
2012         if (view->selected_object_list == NULL) {
2013                 return TRUE;
2014         } else {
2015                 return FALSE;
2016         }
2017 }
2018
2019 /*****************************************************************************/
2020 /* Is our current selection atomic?  I.e. only one item selected.            */
2021 /*****************************************************************************/
2022 gboolean
2023 gl_view_is_selection_atomic (glView *view)
2024 {
2025         gl_debug (DEBUG_VIEW, "");
2026
2027         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2028
2029         if (view->selected_object_list == NULL)
2030                 return FALSE;
2031         if (view->selected_object_list->next == NULL)
2032                 return TRUE;
2033         return FALSE;
2034 }
2035
2036 /*****************************************************************************/
2037 /* Delete selected objects. (Bypass clipboard)                               */
2038 /*****************************************************************************/
2039 void
2040 gl_view_delete_selection (glView *view)
2041 {
2042         GList *object_list, *p, *p_next;
2043
2044         gl_debug (DEBUG_VIEW, "START");
2045
2046         g_return_if_fail (view && GL_IS_VIEW (view));
2047
2048         object_list = view->selected_object_list;
2049         view->selected_object_list = NULL;
2050         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
2051
2052         for (p = object_list; p != NULL; p = p_next) {
2053                 p_next = p->next;
2054                 g_object_unref (G_OBJECT (p->data));
2055                 object_list = g_list_delete_link (object_list, p);
2056         }
2057
2058         gl_debug (DEBUG_VIEW, "END");
2059 }
2060
2061 /*****************************************************************************/
2062 /* Get object property editor of first selected object.                      */
2063 /*****************************************************************************/
2064 GtkWidget *
2065 gl_view_get_editor (glView *view)
2066 {
2067         glViewObject *view_object;
2068         GtkWidget    *editor = NULL;
2069
2070         gl_debug (DEBUG_VIEW, "START");
2071
2072         g_return_if_fail (view && GL_IS_VIEW (view));
2073
2074         if (!gl_view_is_selection_empty (view)) {
2075
2076                 view_object = GL_VIEW_OBJECT(view->selected_object_list->data);
2077                 editor = gl_view_object_get_editor (view_object);
2078
2079         }
2080
2081         gl_debug (DEBUG_VIEW, "END");
2082
2083         return editor;
2084 }
2085
2086 /*****************************************************************************/
2087 /* Raise selected items to top.                                              */
2088 /*****************************************************************************/
2089 void
2090 gl_view_raise_selection (glView *view)
2091 {
2092         GList         *p;
2093         glViewObject  *view_object;
2094         glLabelObject *object;
2095
2096         gl_debug (DEBUG_VIEW, "START");
2097
2098         g_return_if_fail (view && GL_IS_VIEW (view));
2099
2100         for (p = view->selected_object_list; p != NULL; p = p->next) {
2101                 view_object = GL_VIEW_OBJECT (p->data);
2102                 object = gl_view_object_get_object (view_object);
2103                 gl_label_object_raise_to_top (object);
2104         }
2105
2106         gl_debug (DEBUG_VIEW, "END");
2107 }
2108
2109 /*****************************************************************************/
2110 /* Lower selected items to bottom.                                           */
2111 /*****************************************************************************/
2112 void
2113 gl_view_lower_selection (glView *view)
2114 {
2115         GList         *p;
2116         glViewObject  *view_object;
2117         glLabelObject *object;
2118
2119         gl_debug (DEBUG_VIEW, "START");
2120
2121         g_return_if_fail (view && GL_IS_VIEW (view));
2122
2123         for (p = view->selected_object_list; p != NULL; p = p->next) {
2124                 view_object = GL_VIEW_OBJECT (p->data);
2125                 object = gl_view_object_get_object (view_object);
2126                 gl_label_object_lower_to_bottom (object);
2127         }
2128
2129         gl_debug (DEBUG_VIEW, "END");
2130 }
2131
2132 /*****************************************************************************/
2133 /* Rotate selected objects by given angle.                                   */
2134 /*****************************************************************************/
2135 void
2136 gl_view_rotate_selection (glView *view,
2137                           gdouble theta_degs)
2138 {
2139         GList         *p;
2140         glViewObject  *view_object;
2141         glLabelObject *object;
2142
2143         gl_debug (DEBUG_VIEW, "START");
2144
2145         g_return_if_fail (view && GL_IS_VIEW (view));
2146
2147         for (p = view->selected_object_list; p != NULL; p = p->next) {
2148                 view_object = GL_VIEW_OBJECT (p->data);
2149                 object = gl_view_object_get_object (view_object);
2150                 gl_label_object_rotate (object, theta_degs);
2151         }
2152
2153         gl_debug (DEBUG_VIEW, "END");
2154 }
2155
2156 /*****************************************************************************/
2157 /* Rotate selected objects 90 degrees left.                                  */
2158 /*****************************************************************************/
2159 void
2160 gl_view_rotate_selection_left (glView *view)
2161 {
2162         GList         *p;
2163         glViewObject  *view_object;
2164         glLabelObject *object;
2165
2166         gl_debug (DEBUG_VIEW, "START");
2167
2168         g_return_if_fail (view && GL_IS_VIEW (view));
2169
2170         for (p = view->selected_object_list; p != NULL; p = p->next) {
2171                 view_object = GL_VIEW_OBJECT (p->data);
2172                 object = gl_view_object_get_object (view_object);
2173                 gl_label_object_rotate (object, -90.0);
2174         }
2175
2176         gl_debug (DEBUG_VIEW, "END");
2177 }
2178
2179 /*****************************************************************************/
2180 /* Rotate selected objects 90 degrees right.                                 */
2181 /*****************************************************************************/
2182 void
2183 gl_view_rotate_selection_right (glView *view)
2184 {
2185         GList         *p;
2186         glViewObject  *view_object;
2187         glLabelObject *object;
2188
2189         gl_debug (DEBUG_VIEW, "START");
2190
2191         g_return_if_fail (view && GL_IS_VIEW (view));
2192
2193         for (p = view->selected_object_list; p != NULL; p = p->next) {
2194                 view_object = GL_VIEW_OBJECT (p->data);
2195                 object = gl_view_object_get_object (view_object);
2196                 gl_label_object_rotate (object, 90.0);
2197         }
2198
2199         gl_debug (DEBUG_VIEW, "END");
2200 }
2201
2202 /*****************************************************************************/
2203 /* Flip selected objects horizontally.                                       */
2204 /*****************************************************************************/
2205 void
2206 gl_view_flip_selection_horiz (glView *view)
2207 {
2208         GList         *p;
2209         glViewObject  *view_object;
2210         glLabelObject *object;
2211
2212         gl_debug (DEBUG_VIEW, "START");
2213
2214         g_return_if_fail (view && GL_IS_VIEW (view));
2215
2216         for (p = view->selected_object_list; p != NULL; p = p->next) {
2217                 view_object = GL_VIEW_OBJECT (p->data);
2218                 object = gl_view_object_get_object (view_object);
2219                 gl_label_object_flip_horiz (object);
2220         }
2221
2222         gl_debug (DEBUG_VIEW, "END");
2223 }
2224
2225 /*****************************************************************************/
2226 /* Flip selected objects vertically.                                         */
2227 /*****************************************************************************/
2228 void
2229 gl_view_flip_selection_vert (glView *view)
2230 {
2231         GList         *p;
2232         glViewObject  *view_object;
2233         glLabelObject *object;
2234
2235         gl_debug (DEBUG_VIEW, "START");
2236
2237         g_return_if_fail (view && GL_IS_VIEW (view));
2238
2239         for (p = view->selected_object_list; p != NULL; p = p->next) {
2240                 view_object = GL_VIEW_OBJECT (p->data);
2241                 object = gl_view_object_get_object (view_object);
2242                 gl_label_object_flip_vert (object);
2243         }
2244
2245         gl_debug (DEBUG_VIEW, "END");
2246 }
2247
2248 /*****************************************************************************/
2249 /* Align selected objects to left most edge.                                 */
2250 /*****************************************************************************/
2251 void
2252 gl_view_align_selection_left (glView *view)
2253 {
2254         GList         *p;
2255         glViewObject  *view_object;
2256         glLabelObject *object;
2257         gdouble        dx, x1min, x1, y1, x2, y2;
2258
2259         gl_debug (DEBUG_VIEW, "START");
2260
2261         g_return_if_fail (view && GL_IS_VIEW (view));
2262
2263         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2264                           !gl_view_is_selection_atomic (view));
2265
2266         /* find left most edge */
2267         p = view->selected_object_list;
2268         view_object = GL_VIEW_OBJECT (p->data);
2269         object = gl_view_object_get_object (view_object);
2270         gl_label_object_get_extent (object, &x1min, &y1, &x2, &y2);
2271         for (p = p->next; p != NULL; p = p->next) {
2272                 view_object = GL_VIEW_OBJECT (p->data);
2273                 object = gl_view_object_get_object (view_object);
2274                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2275                 if ( x1 < x1min ) x1min = x1;
2276         }
2277
2278         /* now adjust the object positions to line up the left edges */
2279         for (p = view->selected_object_list; p != NULL; p = p->next) {
2280                 view_object = GL_VIEW_OBJECT (p->data);
2281                 object = gl_view_object_get_object (view_object);
2282                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2283                 dx = x1min - x1;
2284                 gl_label_object_set_position_relative (object, dx, 0.0);
2285         }
2286
2287         gl_debug (DEBUG_VIEW, "END");
2288 }
2289
2290
2291 /*****************************************************************************/
2292 /* Align selected objects to right most edge.                                */
2293 /*****************************************************************************/
2294 void
2295 gl_view_align_selection_right (glView *view)
2296 {
2297         GList         *p;
2298         glViewObject  *view_object;
2299         glLabelObject *object;
2300         gdouble        dx, x2max, x1, y1, x2, y2;
2301
2302         gl_debug (DEBUG_VIEW, "START");
2303
2304         g_return_if_fail (view && GL_IS_VIEW (view));
2305
2306         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2307                           !gl_view_is_selection_atomic (view));
2308
2309         /* find right most edge */
2310         p = view->selected_object_list;
2311         view_object = GL_VIEW_OBJECT (p->data);
2312         object = gl_view_object_get_object (view_object);
2313         gl_label_object_get_extent (object, &x1, &y1, &x2max, &y2);
2314         for (p = p->next; p != NULL; p = p->next) {
2315                 view_object = GL_VIEW_OBJECT (p->data);
2316                 object = gl_view_object_get_object (view_object);
2317                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2318                 if ( x2 > x2max ) x2max = x2;
2319         }
2320
2321         /* now adjust the object positions to line up the right edges */
2322         for (p = view->selected_object_list; p != NULL; p = p->next) {
2323                 view_object = GL_VIEW_OBJECT (p->data);
2324                 object = gl_view_object_get_object (view_object);
2325                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2326                 dx = x2max - x2;
2327                 gl_label_object_set_position_relative (object, dx, 0.0);
2328         }
2329
2330         gl_debug (DEBUG_VIEW, "END");
2331 }
2332
2333 /*****************************************************************************/
2334 /* Align selected objects to horizontal center of objects.                   */
2335 /*****************************************************************************/
2336 void
2337 gl_view_align_selection_hcenter (glView *view)
2338 {
2339         GList         *p;
2340         glViewObject  *view_object;
2341         glLabelObject *object;
2342         gdouble        dx, dxmin, xsum, xavg, xcenter, x1, y1, x2, y2;
2343         gint           n;
2344
2345         gl_debug (DEBUG_VIEW, "START");
2346
2347         g_return_if_fail (view && GL_IS_VIEW (view));
2348
2349         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2350                           !gl_view_is_selection_atomic (view));
2351
2352         /* find average center of objects */
2353         xsum = 0.0;
2354         n = 0;
2355         for (p = view->selected_object_list; p != NULL; p = p->next) {
2356                 view_object = GL_VIEW_OBJECT (p->data);
2357                 object = gl_view_object_get_object (view_object);
2358                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2359                 xsum += (x1 + x2) / 2.0;
2360                 n++;
2361         }
2362         xavg = xsum / n;
2363
2364         /* find center of object closest to average center */
2365         p = view->selected_object_list;
2366         view_object = GL_VIEW_OBJECT (p->data);
2367         object = gl_view_object_get_object (view_object);
2368         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2369         dxmin = fabs (xavg - (x1 + x2)/2.0);
2370         xcenter = (x1 + x2)/2.0;
2371         for (p = p->next; p != NULL; p = p->next) {
2372                 view_object = GL_VIEW_OBJECT (p->data);
2373                 object = gl_view_object_get_object (view_object);
2374                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2375                 dx = fabs (xavg - (x1 + x2)/2.0);
2376                 if ( dx < dxmin ) {
2377                         dxmin = dx;
2378                         xcenter = (x1 + x2)/2.0;
2379                 }
2380         }
2381
2382         /* now adjust the object positions to line up this center */
2383         for (p = view->selected_object_list; p != NULL; p = p->next) {
2384                 view_object = GL_VIEW_OBJECT (p->data);
2385                 object = gl_view_object_get_object (view_object);
2386                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2387                 dx = xcenter - (x1 + x2)/2.0;
2388                 gl_label_object_set_position_relative (object, dx, 0.0);
2389         }
2390
2391         gl_debug (DEBUG_VIEW, "END");
2392 }
2393
2394 /*****************************************************************************/
2395 /* Align selected objects to top most edge.                                  */
2396 /*****************************************************************************/
2397 void
2398 gl_view_align_selection_top (glView *view)
2399 {
2400         GList         *p;
2401         glViewObject  *view_object;
2402         glLabelObject *object;
2403         gdouble        dy, y1min, x1, y1, x2, y2;
2404
2405         gl_debug (DEBUG_VIEW, "START");
2406
2407         g_return_if_fail (view && GL_IS_VIEW (view));
2408
2409         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2410                           !gl_view_is_selection_atomic (view));
2411
2412         /* find top most edge */
2413         p = view->selected_object_list;
2414         view_object = GL_VIEW_OBJECT (p->data);
2415         object = gl_view_object_get_object (view_object);
2416         gl_label_object_get_extent (object, &x1, &y1min, &x2, &y2);
2417         for (p = p->next; p != NULL; p = p->next) {
2418                 view_object = GL_VIEW_OBJECT (p->data);
2419                 object = gl_view_object_get_object (view_object);
2420                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2421                 if ( y1 < y1min ) y1min = y1;
2422         }
2423
2424         /* now adjust the object positions to line up the top edges */
2425         for (p = view->selected_object_list; p != NULL; p = p->next) {
2426                 view_object = GL_VIEW_OBJECT (p->data);
2427                 object = gl_view_object_get_object (view_object);
2428                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2429                 dy = y1min - y1;
2430                 gl_label_object_set_position_relative (object, 0.0, dy);
2431         }
2432
2433         gl_debug (DEBUG_VIEW, "END");
2434 }
2435
2436 /*****************************************************************************/
2437 /* Align selected objects to bottom most edge.                               */
2438 /*****************************************************************************/
2439 void
2440 gl_view_align_selection_bottom (glView *view)
2441 {
2442         GList         *p;
2443         glViewObject  *view_object;
2444         glLabelObject *object;
2445         gdouble        dy, y2max, x1, y1, x2, y2;
2446
2447         gl_debug (DEBUG_VIEW, "START");
2448
2449         g_return_if_fail (view && GL_IS_VIEW (view));
2450
2451         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2452                           !gl_view_is_selection_atomic (view));
2453
2454         /* find bottom most edge */
2455         p = view->selected_object_list;
2456         view_object = GL_VIEW_OBJECT (p->data);
2457         object = gl_view_object_get_object (view_object);
2458         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2max);
2459         for (p = p->next; p != NULL; p = p->next) {
2460                 view_object = GL_VIEW_OBJECT (p->data);
2461                 object = gl_view_object_get_object (view_object);
2462                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2463                 if ( y2 > y2max ) y2max = y2;
2464         }
2465
2466         /* now adjust the object positions to line up the bottom edges */
2467         for (p = view->selected_object_list; p != NULL; p = p->next) {
2468                 view_object = GL_VIEW_OBJECT (p->data);
2469                 object = gl_view_object_get_object (view_object);
2470                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2471                 dy = y2max - y2;
2472                 gl_label_object_set_position_relative (object, 0.0, dy);
2473         }
2474
2475         gl_debug (DEBUG_VIEW, "END");
2476 }
2477
2478 /*****************************************************************************/
2479 /* Align selected objects to viertical center of objects.                    */
2480 /*****************************************************************************/
2481 void
2482 gl_view_align_selection_vcenter (glView *view)
2483 {
2484         GList         *p;
2485         glViewObject  *view_object;
2486         glLabelObject *object;
2487         gdouble        dy, dymin, ysum, yavg, ycenter, x1, y1, x2, y2;
2488         gint           n;
2489
2490         gl_debug (DEBUG_VIEW, "START");
2491
2492         g_return_if_fail (view && GL_IS_VIEW (view));
2493
2494         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2495                           !gl_view_is_selection_atomic (view));
2496
2497         /* find average center of objects */
2498         ysum = 0.0;
2499         n = 0;
2500         for (p = view->selected_object_list; p != NULL; p = p->next) {
2501                 view_object = GL_VIEW_OBJECT (p->data);
2502                 object = gl_view_object_get_object (view_object);
2503                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2504                 ysum += (y1 + y2) / 2.0;
2505                 n++;
2506         }
2507         yavg = ysum / n;
2508
2509         /* find center of object closest to average center */
2510         p = view->selected_object_list;
2511         view_object = GL_VIEW_OBJECT (p->data);
2512         object = gl_view_object_get_object (view_object);
2513         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2514         dymin = fabs (yavg - (y1 + y2)/2.0);
2515         ycenter = (y1 + y2)/2.0;
2516         for (p = p->next; p != NULL; p = p->next) {
2517                 view_object = GL_VIEW_OBJECT (p->data);
2518                 object = gl_view_object_get_object (view_object);
2519                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2520                 dy = fabs (yavg - (y1 + y2)/2.0);
2521                 if ( dy < dymin ) {
2522                         dymin = dy;
2523                         ycenter = (y1 + y2)/2.0;
2524                 }
2525         }
2526
2527         /* now adjust the object positions to line up this center */
2528         for (p = view->selected_object_list; p != NULL; p = p->next) {
2529                 view_object = GL_VIEW_OBJECT (p->data);
2530                 object = gl_view_object_get_object (view_object);
2531                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2532                 dy = ycenter - (y1 + y2)/2.0;
2533                 gl_label_object_set_position_relative (object, 0.0, dy);
2534         }
2535
2536         gl_debug (DEBUG_VIEW, "END");
2537 }
2538
2539 /*****************************************************************************/
2540 /* Center selected objects to in center of label.                            */
2541 /*****************************************************************************/
2542 void
2543 gl_view_center_selection_horiz (glView *view)
2544 {
2545         GList         *p;
2546         glViewObject  *view_object;
2547         glLabelObject *object;
2548         gdouble        dx, x_label_center, x_obj_center, x1, y1, x2, y2, w, h;
2549
2550         gl_debug (DEBUG_VIEW, "START");
2551
2552         g_return_if_fail (view && GL_IS_VIEW (view));
2553
2554         g_return_if_fail (!gl_view_is_selection_empty (view));
2555
2556         gl_label_get_size (view->label, &w, &h);
2557         x_label_center = w / 2.0;
2558
2559         /* adjust the object positions */
2560         for (p = view->selected_object_list; p != NULL; p = p->next) {
2561                 view_object = GL_VIEW_OBJECT (p->data);
2562                 object = gl_view_object_get_object (view_object);
2563                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2564                 x_obj_center = (x1 + x2) / 2.0;
2565                 dx = x_label_center - x_obj_center;
2566                 gl_label_object_set_position_relative (object, dx, 0.0);
2567         }
2568
2569         gl_debug (DEBUG_VIEW, "END");
2570 }
2571
2572
2573 /*****************************************************************************/
2574 /* Center selected objects to in center of label.                            */
2575 /*****************************************************************************/
2576 void
2577 gl_view_center_selection_vert (glView *view)
2578 {
2579         GList         *p;
2580         glViewObject  *view_object;
2581         glLabelObject *object;
2582         gdouble        dy, y_label_center, y_obj_center, x1, y1, x2, y2, w, h;
2583
2584         gl_debug (DEBUG_VIEW, "START");
2585
2586         g_return_if_fail (view && GL_IS_VIEW (view));
2587
2588         g_return_if_fail (!gl_view_is_selection_empty (view));
2589
2590         gl_label_get_size (view->label, &w, &h);
2591         y_label_center = h / 2.0;
2592
2593         /* adjust the object positions */
2594         for (p = view->selected_object_list; p != NULL; p = p->next) {
2595                 view_object = GL_VIEW_OBJECT (p->data);
2596                 object = gl_view_object_get_object (view_object);
2597                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2598                 y_obj_center = (y1 + y2) / 2.0;
2599                 dy = y_label_center - y_obj_center;
2600                 gl_label_object_set_position_relative (object, 0.0, dy);
2601         }
2602
2603         gl_debug (DEBUG_VIEW, "END");
2604 }
2605
2606
2607 /*****************************************************************************/
2608 /* Move selected objects                                                     */
2609 /*****************************************************************************/
2610 void
2611 gl_view_move_selection (glView  *view,
2612                 gdouble  dx,
2613                 gdouble  dy)
2614 {
2615         GList *p;
2616         glLabelObject *object;
2617
2618         gl_debug (DEBUG_VIEW, "START");
2619
2620         g_return_if_fail (view && GL_IS_VIEW (view));
2621
2622         for (p = view->selected_object_list; p != NULL; p = p->next) {
2623
2624                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2625                 gl_label_object_set_position_relative (object, dx, dy);
2626
2627         }
2628
2629         gl_debug (DEBUG_VIEW, "END");
2630 }
2631
2632 /*****************************************************************************/
2633 /* Can text properties be set for selection?                                 */
2634 /*****************************************************************************/
2635 gboolean
2636 gl_view_can_selection_text (glView            *view)
2637 {
2638         GList *p;
2639         glLabelObject *object;
2640
2641         gl_debug (DEBUG_VIEW, "");
2642
2643         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2644
2645         for (p = view->selected_object_list; p != NULL; p = p->next) {
2646
2647                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2648                 if (gl_label_object_can_text (object)) {
2649                         return TRUE;
2650                 }
2651
2652         }
2653
2654         return FALSE;
2655 }
2656
2657 /*****************************************************************************/
2658 /* Set font family for all text contained in selected objects.               */
2659 /*****************************************************************************/
2660 void
2661 gl_view_set_selection_font_family (glView            *view,
2662                                    const gchar       *font_family)
2663 {
2664         GList *p;
2665         glLabelObject *object;
2666
2667         gl_debug (DEBUG_VIEW, "START");
2668
2669         g_return_if_fail (view && GL_IS_VIEW (view));
2670
2671         for (p = view->selected_object_list; p != NULL; p = p->next) {
2672
2673                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2674                 gl_label_object_set_font_family (object, font_family);
2675
2676         }
2677
2678         gl_debug (DEBUG_VIEW, "END");
2679 }
2680
2681 /*****************************************************************************/
2682 /* Set font size for all text contained in selected objects.                 */
2683 /*****************************************************************************/
2684 void
2685 gl_view_set_selection_font_size (glView            *view,
2686                                  gdouble            font_size)
2687 {
2688         GList *p;
2689         glLabelObject *object;
2690
2691         gl_debug (DEBUG_VIEW, "START");
2692
2693         g_return_if_fail (view && GL_IS_VIEW (view));
2694
2695         for (p = view->selected_object_list; p != NULL; p = p->next) {
2696
2697                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2698                 gl_label_object_set_font_size (object, font_size);
2699
2700         }
2701
2702         gl_debug (DEBUG_VIEW, "END");
2703 }
2704
2705 /*****************************************************************************/
2706 /* Set font weight for all text contained in selected objects.               */
2707 /*****************************************************************************/
2708 void
2709 gl_view_set_selection_font_weight (glView            *view,
2710                                    GnomeFontWeight    font_weight)
2711 {
2712         GList *p;
2713         glLabelObject *object;
2714
2715         gl_debug (DEBUG_VIEW, "START");
2716
2717         g_return_if_fail (view && GL_IS_VIEW (view));
2718
2719         for (p = view->selected_object_list; p != NULL; p = p->next) {
2720
2721                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2722                 gl_label_object_set_font_weight (object, font_weight);
2723
2724         }
2725
2726         gl_debug (DEBUG_VIEW, "END");
2727 }
2728
2729 /*****************************************************************************/
2730 /* Set font italic flag for all text contained in selected objects.          */
2731 /*****************************************************************************/
2732 void
2733 gl_view_set_selection_font_italic_flag (glView            *view,
2734                                         gboolean           font_italic_flag)
2735 {
2736         GList *p;
2737         glLabelObject *object;
2738
2739         gl_debug (DEBUG_VIEW, "START");
2740
2741         g_return_if_fail (view && GL_IS_VIEW (view));
2742
2743         for (p = view->selected_object_list; p != NULL; p = p->next) {
2744
2745                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2746                 gl_label_object_set_font_italic_flag (object, font_italic_flag);
2747
2748         }
2749
2750         gl_debug (DEBUG_VIEW, "END");
2751 }
2752
2753 /*****************************************************************************/
2754 /* Set text alignment for all text contained in selected objects.            */
2755 /*****************************************************************************/
2756 void
2757 gl_view_set_selection_text_alignment (glView            *view,
2758                                       GtkJustification   text_alignment)
2759 {
2760         GList *p;
2761         glLabelObject *object;
2762
2763         gl_debug (DEBUG_VIEW, "START");
2764
2765         g_return_if_fail (view && GL_IS_VIEW (view));
2766
2767         for (p = view->selected_object_list; p != NULL; p = p->next) {
2768
2769                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2770                 gl_label_object_set_text_alignment (object, text_alignment);
2771
2772         }
2773
2774         gl_debug (DEBUG_VIEW, "END");
2775 }
2776
2777 /*****************************************************************************/
2778 /* Set text line spacing for all text contained in selected objects.         */
2779 /*****************************************************************************/
2780 void
2781 gl_view_set_selection_text_line_spacing (glView            *view,
2782                                          gdouble            text_line_spacing)
2783 {
2784         GList *p;
2785         glLabelObject *object;
2786
2787         gl_debug (DEBUG_VIEW, "START");
2788
2789         g_return_if_fail (view && GL_IS_VIEW (view));
2790
2791         for (p = view->selected_object_list; p != NULL; p = p->next) {
2792
2793                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2794                 gl_label_object_set_text_line_spacing (object, text_line_spacing);
2795
2796         }
2797
2798         gl_debug (DEBUG_VIEW, "END");
2799 }
2800 /*****************************************************************************/
2801 /* Set text color for all text contained in selected objects.                */
2802 /*****************************************************************************/
2803 void
2804 gl_view_set_selection_text_color (glView            *view,
2805                                   glColorNode       *text_color_node)
2806 {
2807         GList *p;
2808         glLabelObject *object;
2809
2810         gl_debug (DEBUG_VIEW, "START");
2811
2812         g_return_if_fail (view && GL_IS_VIEW (view));
2813
2814         for (p = view->selected_object_list; p != NULL; p = p->next) {
2815
2816                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2817                 gl_label_object_set_text_color (object, text_color_node);
2818
2819         }
2820
2821         gl_debug (DEBUG_VIEW, "END");
2822 }
2823
2824 /*****************************************************************************/
2825 /* Can fill properties be set for selection?                                 */
2826 /*****************************************************************************/
2827 gboolean
2828 gl_view_can_selection_fill (glView            *view)
2829 {
2830         GList *p;
2831         glLabelObject *object;
2832
2833         gl_debug (DEBUG_VIEW, "");
2834
2835         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2836
2837         for (p = view->selected_object_list; p != NULL; p = p->next) {
2838
2839                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2840                 if (gl_label_object_can_fill (object)) {
2841                         return TRUE;
2842                 }
2843
2844         }
2845
2846         return FALSE;
2847 }
2848
2849 /*****************************************************************************/
2850 /* Set fill color for all selected objects.                                  */
2851 /*****************************************************************************/
2852 void
2853 gl_view_set_selection_fill_color (glView            *view,
2854                                   glColorNode       *fill_color_node)
2855 {
2856         GList *p;
2857         glLabelObject *object;
2858
2859         gl_debug (DEBUG_VIEW, "START");
2860
2861         g_return_if_fail (view && GL_IS_VIEW (view));
2862
2863         for (p = view->selected_object_list; p != NULL; p = p->next) {
2864
2865                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2866                 gl_label_object_set_fill_color (object, fill_color_node);
2867
2868         }
2869
2870         gl_debug (DEBUG_VIEW, "END");
2871 }
2872
2873 /*****************************************************************************/
2874 /* Can line color properties be set for selection?                           */
2875 /*****************************************************************************/
2876 gboolean
2877 gl_view_can_selection_line_color (glView            *view)
2878 {
2879         GList *p;
2880         glLabelObject *object;
2881
2882         gl_debug (DEBUG_VIEW, "");
2883
2884         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2885
2886         for (p = view->selected_object_list; p != NULL; p = p->next) {
2887
2888                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2889                 if (gl_label_object_can_line_color (object)) {
2890                         return TRUE;
2891                 }
2892
2893         }
2894
2895         return FALSE;
2896 }
2897
2898 /*****************************************************************************/
2899 /* Set line color for all selected objects.                                  */
2900 /*****************************************************************************/
2901 void
2902 gl_view_set_selection_line_color (glView            *view,
2903                                   glColorNode       *line_color_node)
2904 {
2905         GList *p;
2906         glLabelObject *object;
2907
2908         gl_debug (DEBUG_VIEW, "START");
2909
2910         g_return_if_fail (view && GL_IS_VIEW (view));
2911
2912         for (p = view->selected_object_list; p != NULL; p = p->next) {
2913
2914                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2915                 gl_label_object_set_line_color (object, line_color_node);
2916
2917         }
2918
2919         gl_debug (DEBUG_VIEW, "END");
2920 }
2921
2922 /*****************************************************************************/
2923 /* Can line width properties be set for selection?                           */
2924 /*****************************************************************************/
2925 gboolean
2926 gl_view_can_selection_line_width (glView            *view)
2927 {
2928         GList *p;
2929         glLabelObject *object;
2930
2931         gl_debug (DEBUG_VIEW, "");
2932
2933         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2934
2935         for (p = view->selected_object_list; p != NULL; p = p->next) {
2936
2937                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2938                 if (gl_label_object_can_line_width (object)) {
2939                         return TRUE;
2940                 }
2941
2942         }
2943
2944         return FALSE;
2945 }
2946
2947 /*****************************************************************************/
2948 /* Set line width for all selected objects.                                  */
2949 /*****************************************************************************/
2950 void
2951 gl_view_set_selection_line_width (glView            *view,
2952                                   gdouble            line_width)
2953 {
2954         GList *p;
2955         glLabelObject *object;
2956
2957         gl_debug (DEBUG_VIEW, "START");
2958
2959         g_return_if_fail (view && GL_IS_VIEW (view));
2960
2961         for (p = view->selected_object_list; p != NULL; p = p->next) {
2962
2963                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2964                 gl_label_object_set_line_width (object, line_width);
2965
2966         }
2967
2968         gl_debug (DEBUG_VIEW, "END");
2969 }
2970
2971 /*****************************************************************************/
2972 /* "Cut" selected items and place in clipboard selections.                   */
2973 /*****************************************************************************/
2974 void
2975 gl_view_cut (glView *view)
2976 {
2977         gl_debug (DEBUG_VIEW, "START");
2978
2979         g_return_if_fail (view && GL_IS_VIEW (view));
2980
2981         gl_view_copy (view);
2982         gl_view_delete_selection (view);
2983
2984         gl_debug (DEBUG_VIEW, "END");
2985 }
2986
2987 /*****************************************************************************/
2988 /* "Copy" selected items to clipboard selections.                            */
2989 /*****************************************************************************/
2990 void
2991 gl_view_copy (glView *view)
2992 {
2993         GList *p;
2994         glViewObject *view_object;
2995         glLabelObject *object;
2996         glTemplate *template;
2997         gboolean rotate_flag;
2998
2999         gl_debug (DEBUG_VIEW, "START");
3000
3001         g_return_if_fail (view && GL_IS_VIEW (view));
3002
3003         if (view->selected_object_list) {
3004
3005                 if ( view->selection_data ) {
3006                         g_object_unref (view->selection_data);
3007                 }
3008                 template = gl_label_get_template (view->label);
3009                 rotate_flag = gl_label_get_rotate_flag (view->label);
3010                 view->selection_data = GL_LABEL(gl_label_new ());
3011                 gl_label_set_template (view->selection_data, template);
3012                 gl_label_set_rotate_flag (view->selection_data, rotate_flag);
3013                 gl_template_free (template);
3014
3015                 for (p = view->selected_object_list; p != NULL; p = p->next) {
3016
3017                         view_object = GL_VIEW_OBJECT (p->data);
3018                         object = gl_view_object_get_object (view_object);
3019
3020                         gl_label_object_dup (object, view->selection_data);
3021
3022                 }
3023
3024                 gtk_selection_owner_set (view->invisible,
3025                                          clipboard_atom, GDK_CURRENT_TIME);
3026                 view->have_selection = TRUE;
3027
3028         }
3029
3030         gl_debug (DEBUG_VIEW, "END");
3031 }
3032
3033 /*****************************************************************************/
3034 /* "Paste" from private clipboard selection.                                 */
3035 /*****************************************************************************/
3036 void
3037 gl_view_paste (glView *view)
3038 {
3039         gl_debug (DEBUG_VIEW, "START");
3040
3041         g_return_if_fail (view && GL_IS_VIEW (view));
3042
3043         gtk_selection_convert (GTK_WIDGET (view->invisible),
3044                                clipboard_atom, GDK_SELECTION_TYPE_STRING,
3045                                GDK_CURRENT_TIME);
3046
3047         gl_debug (DEBUG_VIEW, "END");
3048 }
3049
3050 /*****************************************************************************/
3051 /* Zoom in one "notch"                                                       */
3052 /*****************************************************************************/
3053 void
3054 gl_view_zoom_in (glView *view)
3055 {
3056         gint i, i_min;
3057         gdouble dist, dist_min;
3058
3059         gl_debug (DEBUG_VIEW, "START");
3060
3061         g_return_if_fail (view && GL_IS_VIEW (view));
3062
3063         /* Find index of current scale (or best match) */
3064         i_min = 1;              /* start with 2nd largest scale */
3065         dist_min = fabs (zooms[1] - view->zoom);
3066         for (i = 2; i < N_ZOOMS; i++) {
3067                 dist = fabs (zooms[i] - view->zoom);
3068                 if (dist < dist_min) {
3069                         i_min = i;
3070                         dist_min = dist;
3071                 }
3072         }
3073
3074         /* zoom in one "notch" */
3075         i = MAX (0, i_min - 1);
3076         gl_debug (DEBUG_VIEW, "zoom[%d] = %g", i, zooms[i]);
3077         set_zoom_real (view, zooms[i], FALSE);
3078
3079         gl_debug (DEBUG_VIEW, "END");
3080 }
3081
3082 /*****************************************************************************/
3083 /* Zoom out one "notch"                                                      */
3084 /*****************************************************************************/
3085 void
3086 gl_view_zoom_out (glView *view)
3087 {
3088         gint i, i_min;
3089         gdouble dist, dist_min;
3090
3091         gl_debug (DEBUG_VIEW, "START");
3092
3093         g_return_if_fail (view && GL_IS_VIEW (view));
3094
3095         /* Find index of current scale (or best match) */
3096         i_min = 0;              /* start with largest scale */
3097         dist_min = fabs (zooms[0] - view->zoom);
3098         for (i = 1; i < N_ZOOMS; i++) {
3099                 dist = fabs (zooms[i] - view->zoom);
3100                 if (dist < dist_min) {
3101                         i_min = i;
3102                         dist_min = dist;
3103                 }
3104         }
3105
3106         /* zoom out one "notch" */
3107         if (i_min >= N_ZOOMS)
3108                 return;
3109         i = i_min + 1;
3110         if (i >= N_ZOOMS)
3111                 return;
3112         set_zoom_real (view, zooms[i], FALSE);
3113
3114         gl_debug (DEBUG_VIEW, "END");
3115 }
3116
3117 /*****************************************************************************/
3118 /* Set zoom to best fit.                                                     */
3119 /*****************************************************************************/
3120 void
3121 gl_view_zoom_to_fit (glView *view)
3122 {
3123         gint w_view, h_view;
3124         gdouble w_label, h_label;
3125         gdouble x_scale, y_scale, scale;
3126
3127         gl_debug (DEBUG_VIEW, "");
3128
3129         if ( ! GTK_WIDGET_VISIBLE(view)) {
3130                 set_zoom_real (view, 1.0, TRUE);
3131                 return;
3132         }
3133
3134         w_view = GTK_WIDGET(view)->allocation.width;
3135         h_view = GTK_WIDGET(view)->allocation.height;
3136
3137         gl_label_get_size (GL_LABEL(view->label), &w_label, &h_label);
3138
3139         gl_debug (DEBUG_VIEW, "View size: %d, %d", w_view, h_view);
3140         gl_debug (DEBUG_VIEW, "Label size: %g, %g", w_label, h_label);
3141
3142         /* Calculate best scale */
3143         x_scale = (double)(w_view - ZOOMTOFIT_PAD) / w_label;
3144         y_scale = (double)(h_view - ZOOMTOFIT_PAD) / h_label;
3145         scale = MIN (x_scale, y_scale);
3146         gl_debug (DEBUG_VIEW, "Candidate zooms: %g, %g => %g", x_scale, y_scale, scale);
3147
3148         /* Limit */
3149         gl_debug (DEBUG_VIEW, "Scale: %g", scale);
3150         scale = MIN (scale, zooms[0]*view->home_scale);
3151         scale = MAX (scale, zooms[N_ZOOMS-1]*view->home_scale);
3152         gl_debug (DEBUG_VIEW, "Limitted scale: %g", scale);
3153
3154         set_zoom_real (view, scale/view->home_scale, TRUE);
3155 }
3156
3157 /*****************************************************************************/
3158 /* Set current zoom factor to explicit value.                                */
3159 /*****************************************************************************/
3160 void
3161 gl_view_set_zoom (glView  *view,
3162                   gdouble zoom)
3163 {
3164         gl_debug (DEBUG_VIEW, "START");
3165
3166         set_zoom_real (view, zoom, FALSE);
3167
3168         gl_debug (DEBUG_VIEW, "END");
3169 }
3170
3171 /*---------------------------------------------------------------------------*/
3172 /* PRIVATE.  Set canvas scale.                                               *
3173 /*---------------------------------------------------------------------------*/
3174 static void
3175 set_zoom_real (glView          *view,
3176                gdouble          zoom,
3177                gboolean         zoom_to_fit_flag)
3178 {
3179         gl_debug (DEBUG_VIEW, "START");
3180
3181         g_return_if_fail (view && GL_IS_VIEW (view));
3182         g_return_if_fail (zoom > 0.0);
3183
3184         /* Limit, if needed */
3185         gl_debug (DEBUG_VIEW, "Zoom requested: %g", zoom);
3186         zoom = MIN (zoom, zooms[0]);
3187         zoom = MAX (zoom, zooms[N_ZOOMS-1]);
3188         gl_debug (DEBUG_VIEW, "Limitted zoom: %g", zoom);
3189
3190         if ( zoom != view->zoom ) {
3191
3192                 view->zoom = zoom;
3193                 view->zoom_to_fit_flag = zoom_to_fit_flag;
3194                 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
3195                                                   zoom*view->home_scale);
3196
3197                 g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, zoom);
3198
3199         }
3200
3201         gl_debug (DEBUG_VIEW, "END");
3202
3203 }
3204
3205
3206 /*---------------------------------------------------------------------------*/
3207 /* PRIVATE. Size allocation changed callback.                                */
3208 /*---------------------------------------------------------------------------*/
3209 static void
3210 size_allocate_cb (glView          *view)
3211 {
3212         gl_debug (DEBUG_VIEW, "START");
3213
3214         if (view->zoom_to_fit_flag) {
3215                 /* Maintain best fit zoom */
3216                 gl_view_zoom_to_fit (view);
3217         }
3218
3219         gl_debug (DEBUG_VIEW, "END");
3220 }
3221
3222
3223
3224 /*---------------------------------------------------------------------------*/
3225 /* PRIVATE. Screen changed callback.                                         */
3226 /*---------------------------------------------------------------------------*/
3227 static void
3228 screen_changed_cb (glView          *view)
3229 {
3230         gl_debug (DEBUG_VIEW, "START");
3231
3232         if (gtk_widget_has_screen (GTK_WIDGET (view->canvas))) {
3233
3234                 view->home_scale = get_home_scale (view);
3235
3236                 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
3237                                                   view->zoom * view->home_scale);
3238
3239                 if (view->zoom_to_fit_flag) {
3240                         /* Maintain best fit zoom */
3241                         gl_view_zoom_to_fit (view);
3242                 }
3243
3244         }
3245
3246         gl_debug (DEBUG_VIEW, "END");
3247 }
3248
3249
3250
3251 /*****************************************************************************/
3252 /* Get current zoom factor.                                                  */
3253 /*****************************************************************************/
3254 gdouble
3255 gl_view_get_zoom (glView *view)
3256 {
3257         gl_debug (DEBUG_VIEW, "");
3258
3259         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
3260
3261         return view->zoom;
3262 }
3263
3264 /*****************************************************************************/
3265 /* Is this the maximum zoom level.                                           */
3266 /*****************************************************************************/
3267 gboolean
3268 gl_view_is_zoom_max (glView *view)
3269 {
3270         gl_debug (DEBUG_VIEW, "");
3271
3272         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
3273
3274         return view->zoom >= zooms[0];
3275 }
3276
3277 /*****************************************************************************/
3278 /* Is this the minimum zoom level.                                           */
3279 /*****************************************************************************/
3280 gboolean
3281 gl_view_is_zoom_min (glView *view)
3282 {
3283         gl_debug (DEBUG_VIEW, "");
3284
3285         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
3286
3287         return view->zoom <= zooms[N_ZOOMS-1];
3288 }
3289
3290 /*---------------------------------------------------------------------------*/
3291 /* PRIVATE.  Canvas event handler.                                           */
3292 /*---------------------------------------------------------------------------*/
3293 static int
3294 canvas_event (GnomeCanvas *canvas,
3295               GdkEvent    *event,
3296               glView      *view)
3297 {
3298         gdouble x, y;
3299
3300         gl_debug (DEBUG_VIEW, "");
3301
3302         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
3303
3304         /* emit pointer signals regardless of state */
3305         switch (event->type) {
3306         case GDK_MOTION_NOTIFY:
3307                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
3308                 gnome_canvas_window_to_world (canvas,
3309                                               event->motion.x,
3310                                               event->motion.y, &x, &y);
3311                 g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
3312                 break; /* fall through */
3313
3314         case GDK_LEAVE_NOTIFY:
3315                 gl_debug (DEBUG_VIEW, "LEAVEW_NOTIFY");
3316                 g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
3317                 break; /* fall through */
3318
3319         default:
3320                 break; /* fall through */
3321         }
3322
3323
3324         switch (view->state) {
3325
3326         case GL_VIEW_STATE_ARROW:
3327                 return canvas_event_arrow_mode (canvas, event, view);
3328
3329         case GL_VIEW_STATE_OBJECT_CREATE:
3330                 switch (view->create_type) {
3331                 case GL_LABEL_OBJECT_BOX:
3332                         return gl_view_box_create_event_handler (canvas,
3333                                                                  event,
3334                                                                  view);
3335                         break;
3336                 case GL_LABEL_OBJECT_ELLIPSE:
3337                         return gl_view_ellipse_create_event_handler (canvas,
3338                                                                      event,
3339                                                                      view);
3340                         break;
3341                 case GL_LABEL_OBJECT_LINE:
3342                         return gl_view_line_create_event_handler (canvas,
3343                                                                   event,
3344                                                                   view);
3345                         break;
3346                 case GL_LABEL_OBJECT_IMAGE:
3347                         return gl_view_image_create_event_handler (canvas,
3348                                                                    event,
3349                                                                    view);
3350                         break;
3351                 case GL_LABEL_OBJECT_TEXT:
3352                         return gl_view_text_create_event_handler (canvas,
3353                                                                   event,
3354                                                                   view);
3355                         break;
3356                 case GL_LABEL_OBJECT_BARCODE:
3357                         return gl_view_barcode_create_event_handler (canvas,
3358                                                                      event,
3359                                                                      view);
3360                         break;
3361                 default:
3362                         /*Should not happen!*/
3363                         g_warning ("Invalid label object type.");
3364                         return FALSE;
3365         }
3366
3367         default:
3368                 g_warning ("Invalid view state.");      /*Should not happen!*/
3369                 return FALSE;
3370
3371         }
3372 }
3373
3374 /*---------------------------------------------------------------------------*/
3375 /* PRIVATE.  Canvas event handler (arrow mode)                               */
3376 /*---------------------------------------------------------------------------*/
3377 static int
3378 canvas_event_arrow_mode (GnomeCanvas *canvas,
3379                          GdkEvent    *event,
3380                          glView      *view)
3381 {
3382         static gdouble x0, y0;
3383         static gboolean dragging = FALSE;
3384         static GnomeCanvasItem *item;
3385         gdouble x, y, x1, y1, x2, y2;
3386         GnomeCanvasGroup *group;
3387         GdkCursor *cursor;
3388
3389         gl_debug (DEBUG_VIEW, "");
3390
3391         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
3392
3393         switch (event->type) {
3394
3395         case GDK_BUTTON_PRESS:
3396                 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
3397                 gtk_widget_grab_focus (GTK_WIDGET(canvas));
3398                 switch (event->button.button) {
3399                 case 1:
3400                         gnome_canvas_window_to_world (canvas,
3401                                                       event->button.x,
3402                                                       event->button.y, &x, &y);
3403
3404                         if (!object_at (view, x, y)) {
3405                                 if (!(event->button.state & GDK_CONTROL_MASK)) {
3406                                         gl_view_unselect_all (view);
3407                                 }
3408
3409                                 dragging = TRUE;
3410                                 gnome_canvas_item_grab (canvas->root,
3411                                                         GDK_POINTER_MOTION_MASK |
3412                                                         GDK_BUTTON_RELEASE_MASK |
3413                                                         GDK_BUTTON_PRESS_MASK,
3414                                                         NULL, event->button.time);
3415                                 group =
3416                                     gnome_canvas_root (GNOME_CANVAS
3417                                                        (view->canvas));
3418                                 item =
3419                                     gnome_canvas_item_new (group,
3420                                                            gnome_canvas_rect_get_type (),
3421                                                            "x1", x-DELTA,
3422                                                            "y1", y-DELTA,
3423                                                            "x2", x+DELTA,
3424                                                            "y2", y+DELTA,
3425                                                            "width_pixels", 2,
3426                                                            "outline_color_rgba",
3427                                                            SEL_LINE_COLOR,
3428                                                            "fill_color_rgba",
3429                                                            SEL_FILL_COLOR,
3430                                                            NULL);
3431                                 x0 = x;
3432                                 y0 = y;
3433
3434                         }
3435                         return FALSE;
3436                 case 3:
3437                         /* activate context menu. */
3438                         g_signal_emit (G_OBJECT (view),
3439                                        signals[CONTEXT_MENU_ACTIVATE], 0,
3440                                        event->button.button, event->button.time);
3441                         return FALSE;
3442                 default:
3443                         return FALSE;
3444                 }
3445
3446         case GDK_BUTTON_RELEASE:
3447                 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
3448                 switch (event->button.button) {
3449                 case 1:
3450                         if (dragging) {
3451                                 dragging = FALSE;
3452                                 gnome_canvas_item_ungrab (canvas->root,
3453                                                           event->button.time);
3454                                 gnome_canvas_window_to_world (canvas,
3455                                                               event->button.x,
3456                                                               event->button.y,
3457                                                               &x, &y);
3458                                 x1 = MIN (x, x0);
3459                                 y1 = MIN (y, y0);
3460                                 x2 = MAX (x, x0);
3461                                 y2 = MAX (y, y0);
3462                                 gl_view_select_region (view, x1, y1, x2, y2);
3463                                 gtk_object_destroy (GTK_OBJECT (item));
3464                                 return TRUE;
3465                         }
3466                         return FALSE;
3467
3468                 default:
3469                         return FALSE;
3470                 }
3471
3472         case GDK_MOTION_NOTIFY:
3473                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
3474                 gnome_canvas_window_to_world (canvas,
3475                                               event->motion.x,
3476                                               event->motion.y, &x, &y);
3477                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
3478                         gl_debug (DEBUG_VIEW,
3479                                   "Dragging: (x0=%g, y0=%g), (x=%g, y=%g)", x0, y0, x, y);
3480                         gnome_canvas_item_set (item,
3481                                                "x1", MIN (x, x0) - DELTA,
3482                                                "y1", MIN (y, y0) - DELTA,
3483                                                "x2", MAX (x, x0) + DELTA,
3484                                                "y2", MAX (y, y0) + DELTA,
3485                                                NULL);
3486                         return TRUE;
3487                 } else {
3488                         return FALSE;
3489                 }
3490
3491         case GDK_KEY_PRESS:
3492                 gl_debug (DEBUG_VIEW, "KEY_PRESS");
3493                 if (!dragging) {
3494                         switch (event->key.keyval) {
3495                         case GDK_Left:
3496                         case GDK_KP_Left:
3497                                 gl_view_move_selection (view,
3498                                                         -1.0 / (view->zoom), 0.0);
3499                                 break;
3500                         case GDK_Up:
3501                         case GDK_KP_Up:
3502                                 gl_view_move_selection (view,
3503                                                         0.0, -1.0 / (view->zoom));
3504                                 break;
3505                         case GDK_Right:
3506                         case GDK_KP_Right:
3507                                 gl_view_move_selection (view,
3508                                                         1.0 / (view->zoom), 0.0);
3509                                 break;
3510                         case GDK_Down:
3511                         case GDK_KP_Down:
3512                                 gl_view_move_selection (view,
3513                                                         0.0, 1.0 / (view->zoom));
3514                                 break;
3515                         case GDK_Delete:
3516                         case GDK_KP_Delete:
3517                                 gl_view_delete_selection (view);
3518                                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
3519                                 gdk_window_set_cursor (view->canvas->window,
3520                                                        cursor);
3521                                 gdk_cursor_unref (cursor);
3522                                 break;
3523                         default:
3524                                 return FALSE;
3525                         }
3526                 }
3527                 return TRUE;    /* We handled this or we were dragging. */
3528
3529         default:
3530                 gl_debug (DEBUG_VIEW, "default");
3531                 return FALSE;
3532         }
3533
3534 }
3535
3536 /*---------------------------------------------------------------------------*/
3537 /* PRIVATE.  Handle "selection-clear" signal.                                */
3538 /*---------------------------------------------------------------------------*/
3539 static void
3540 selection_clear_cb (GtkWidget         *widget,
3541                     GdkEventSelection *event,
3542                     gpointer          data)
3543 {
3544         glView *view = GL_VIEW (data);
3545
3546         gl_debug (DEBUG_VIEW, "START");
3547
3548         g_return_if_fail (view && GL_IS_VIEW (view));
3549
3550         view->have_selection = FALSE;
3551         g_object_unref (view->selection_data);
3552         view->selection_data = NULL;
3553
3554         gl_debug (DEBUG_VIEW, "END");
3555 }
3556
3557 /*---------------------------------------------------------------------------*/
3558 /* PRIVATE.  Handle "selection-get" signal.                                  */
3559 /*---------------------------------------------------------------------------*/
3560 static void
3561 selection_get_cb (GtkWidget        *widget,
3562                   GtkSelectionData *selection_data,
3563                   guint            info,
3564                   guint            time,
3565                   gpointer         data)
3566 {
3567         glView *view = GL_VIEW (data);
3568         gchar *buffer;
3569         glXMLLabelStatus status;
3570
3571         gl_debug (DEBUG_VIEW, "START");
3572
3573         g_return_if_fail (view && GL_IS_VIEW (view));
3574
3575         if (view->have_selection) {
3576
3577                 buffer = gl_xml_label_save_buffer (view->selection_data,
3578                                                    &status);
3579                 gtk_selection_data_set (selection_data,
3580                                         GDK_SELECTION_TYPE_STRING, 8, buffer,
3581                                         strlen (buffer));
3582                 g_free (buffer);
3583         }
3584
3585         gl_debug (DEBUG_VIEW, "END");
3586 }
3587
3588 /*---------------------------------------------------------------------------*/
3589 /* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
3590 /*---------------------------------------------------------------------------*/
3591 static void
3592 selection_received_cb (GtkWidget        *widget,
3593                        GtkSelectionData *selection_data,
3594                        guint            time,
3595                        gpointer         data)
3596 {
3597         glView *view = GL_VIEW (data);
3598         glLabel *label = NULL;
3599         glXMLLabelStatus status;
3600         GList *p, *p_next;
3601         glLabelObject *object, *newobject;
3602         glViewObject *view_object;
3603
3604         gl_debug (DEBUG_VIEW, "START");
3605
3606         g_return_if_fail (view && GL_IS_VIEW (view));
3607
3608         if (selection_data->length < 0) {
3609                 return;
3610         }
3611         if (selection_data->type != GDK_SELECTION_TYPE_STRING) {
3612                 return;
3613         }
3614
3615         gl_view_unselect_all (view);
3616
3617         label = gl_xml_label_open_buffer (selection_data->data, &status);
3618         for (p = label->objects; p != NULL; p = p_next) {
3619                 p_next = p->next;
3620
3621                 object = (glLabelObject *) p->data;
3622                 newobject = gl_label_object_dup (object, view->label);
3623
3624                 gl_debug (DEBUG_VIEW, "object pasted");
3625
3626                 if (GL_IS_LABEL_BOX (newobject)) {
3627                         view_object = gl_view_box_new (GL_LABEL_BOX(newobject),
3628                                                        view);
3629                 } else if (GL_IS_LABEL_ELLIPSE (newobject)) {
3630                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(newobject),
3631                                                            view);
3632                 } else if (GL_IS_LABEL_LINE (newobject)) {
3633                         view_object = gl_view_line_new (GL_LABEL_LINE(newobject),
3634                                                         view);
3635                 } else if (GL_IS_LABEL_IMAGE (newobject)) {
3636                         view_object = gl_view_image_new (GL_LABEL_IMAGE(newobject),
3637                                                          view);
3638                 } else if (GL_IS_LABEL_TEXT (newobject)) {
3639                         view_object = gl_view_text_new (GL_LABEL_TEXT(newobject),
3640                                                         view);
3641                 } else if (GL_IS_LABEL_BARCODE (newobject)) {
3642                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(newobject),
3643                                                            view);
3644                 } else {
3645                         /* Should not happen! */
3646                         view_object = NULL;
3647                         g_warning ("Invalid label object type.");
3648                 }
3649                 gl_view_select_object (view, view_object);
3650         }
3651         g_object_unref (label);
3652
3653         gl_debug (DEBUG_VIEW, "END");
3654 }
3655
3656 /****************************************************************************/
3657 /* Set default font family.                                                 */
3658 /****************************************************************************/
3659 void
3660 gl_view_set_default_font_family (glView            *view,
3661                                  const gchar       *font_family)
3662 {
3663         gl_debug (DEBUG_VIEW, "START");
3664
3665         g_return_if_fail (view && GL_IS_VIEW (view));
3666
3667         if (view->default_font_family) {
3668                 g_free (view->default_font_family);
3669         }
3670         view->default_font_family = g_strdup (font_family);
3671
3672         gl_debug (DEBUG_VIEW, "END");
3673 }
3674
3675
3676 /****************************************************************************/
3677 /* Set default font size.                                                   */
3678 /****************************************************************************/
3679 void
3680 gl_view_set_default_font_size (glView            *view,
3681                                gdouble            font_size)
3682 {
3683         gl_debug (DEBUG_VIEW, "START");
3684
3685         g_return_if_fail (view && GL_IS_VIEW (view));
3686
3687         view->default_font_size = font_size;
3688
3689         gl_debug (DEBUG_VIEW, "END");
3690 }
3691
3692
3693 /****************************************************************************/
3694 /* Set default font weight.                                                 */
3695 /****************************************************************************/
3696 void
3697 gl_view_set_default_font_weight (glView            *view,
3698                                  GnomeFontWeight    font_weight)
3699 {
3700         gl_debug (DEBUG_VIEW, "START");
3701
3702         g_return_if_fail (view && GL_IS_VIEW (view));
3703
3704         view->default_font_weight = font_weight;
3705
3706         gl_debug (DEBUG_VIEW, "END");
3707 }
3708
3709
3710 /****************************************************************************/
3711 /* Set default font italic flag.                                            */
3712 /****************************************************************************/
3713 void
3714 gl_view_set_default_font_italic_flag (glView            *view,
3715                                       gboolean           font_italic_flag)
3716 {
3717         gl_debug (DEBUG_VIEW, "START");
3718
3719         g_return_if_fail (view && GL_IS_VIEW (view));
3720
3721         view->default_font_italic_flag = font_italic_flag;
3722
3723         gl_debug (DEBUG_VIEW, "END");
3724 }
3725
3726
3727 /****************************************************************************/
3728 /* Set default text color.                                                  */
3729 /****************************************************************************/
3730 void
3731 gl_view_set_default_text_color (glView            *view,
3732                                 guint              text_color)
3733 {
3734         gl_debug (DEBUG_VIEW, "START");
3735
3736         g_return_if_fail (view && GL_IS_VIEW (view));
3737
3738         view->default_text_color = text_color;
3739
3740         gl_debug (DEBUG_VIEW, "END");
3741 }
3742
3743
3744 /****************************************************************************/
3745 /* Set default text alignment.                                              */
3746 /****************************************************************************/
3747 void
3748 gl_view_set_default_text_alignment (glView            *view,
3749                                     GtkJustification   text_alignment)
3750 {
3751         gl_debug (DEBUG_VIEW, "START");
3752
3753         g_return_if_fail (view && GL_IS_VIEW (view));
3754
3755         view->default_text_alignment = text_alignment;
3756         gl_debug (DEBUG_VIEW, "END");
3757 }
3758
3759 /****************************************************************************/
3760 /* Set default text line spacing.                                           */
3761 /****************************************************************************/
3762 void
3763 gl_view_set_default_text_line_spacing (glView            *view,
3764                                        gdouble            text_line_spacing)
3765 {
3766         gl_debug (DEBUG_VIEW, "START");
3767
3768         g_return_if_fail (view && GL_IS_VIEW (view));
3769
3770         view->default_text_line_spacing = text_line_spacing;
3771
3772         gl_debug (DEBUG_VIEW, "END");
3773 }
3774
3775
3776 /****************************************************************************/
3777 /* Set default line width.                                                  */
3778 /****************************************************************************/
3779 void
3780 gl_view_set_default_line_width (glView            *view,
3781                                 gdouble            line_width)
3782 {
3783         gl_debug (DEBUG_VIEW, "START");
3784
3785         g_return_if_fail (view && GL_IS_VIEW (view));
3786
3787         view->default_line_width = line_width;
3788
3789         gl_debug (DEBUG_VIEW, "END");
3790 }
3791
3792
3793 /****************************************************************************/
3794 /* Set default line color.                                                  */
3795 /****************************************************************************/
3796 void
3797 gl_view_set_default_line_color (glView            *view,
3798                                 guint              line_color)
3799 {
3800         gl_debug (DEBUG_VIEW, "START");
3801
3802         g_return_if_fail (view && GL_IS_VIEW (view));
3803
3804         view->default_line_color = line_color;
3805
3806         gl_debug (DEBUG_VIEW, "END");
3807 }
3808
3809
3810 /****************************************************************************/
3811 /* Set default fill color.                                                  */
3812 /****************************************************************************/
3813 void
3814 gl_view_set_default_fill_color (glView            *view,
3815                                 guint              fill_color)
3816 {
3817         gl_debug (DEBUG_VIEW, "START");
3818
3819         g_return_if_fail (view && GL_IS_VIEW (view));
3820
3821         view->default_fill_color = fill_color;
3822
3823         gl_debug (DEBUG_VIEW, "END");
3824 }
3825
3826
3827
3828 /****************************************************************************/
3829 /* Get default font family.                                                 */
3830 /****************************************************************************/
3831 gchar *
3832 gl_view_get_default_font_family (glView            *view)
3833 {
3834         gl_debug (DEBUG_VIEW, "START");
3835
3836         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
3837
3838         gl_debug (DEBUG_VIEW, "END");
3839
3840         return g_strdup (view->default_font_family);
3841 }
3842
3843
3844 /****************************************************************************/
3845 /* Get default font size.                                                   */
3846 /****************************************************************************/
3847 gdouble
3848 gl_view_get_default_font_size (glView            *view)
3849 {
3850         gl_debug (DEBUG_VIEW, "START");
3851
3852         g_return_val_if_fail (view && GL_IS_VIEW (view), 12.0);
3853
3854         gl_debug (DEBUG_VIEW, "END");
3855
3856         return view->default_font_size;
3857 }
3858
3859
3860 /****************************************************************************/
3861 /* Get default font weight.                                                 */
3862 /****************************************************************************/
3863 GnomeFontWeight
3864 gl_view_get_default_font_weight (glView            *view)
3865 {
3866         gl_debug (DEBUG_VIEW, "START");
3867
3868         g_return_val_if_fail (view && GL_IS_VIEW (view), GNOME_FONT_BOOK);
3869
3870         gl_debug (DEBUG_VIEW, "END");
3871
3872         return view->default_font_weight;
3873 }
3874
3875
3876 /****************************************************************************/
3877 /* Get default font italic flag.                                            */
3878 /****************************************************************************/
3879 gboolean
3880 gl_view_get_default_font_italic_flag (glView            *view)
3881 {
3882         gl_debug (DEBUG_VIEW, "START");
3883
3884         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
3885
3886         gl_debug (DEBUG_VIEW, "END");
3887
3888         return view->default_font_italic_flag;
3889 }
3890
3891
3892 /****************************************************************************/
3893 /* Get default text color.                                                  */
3894 /****************************************************************************/
3895 guint
3896 gl_view_get_default_text_color (glView            *view)
3897 {
3898         gl_debug (DEBUG_VIEW, "START");
3899
3900         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3901
3902         gl_debug (DEBUG_VIEW, "END");
3903
3904         return view->default_text_color;
3905 }
3906
3907
3908 /****************************************************************************/
3909 /* Get default text alignment.                                              */
3910 /****************************************************************************/
3911 GtkJustification
3912 gl_view_get_default_text_alignment (glView            *view)
3913 {
3914         gl_debug (DEBUG_VIEW, "START");
3915
3916         g_return_val_if_fail (view && GL_IS_VIEW (view), GTK_JUSTIFY_LEFT);
3917
3918         gl_debug (DEBUG_VIEW, "END");
3919
3920         return view->default_text_alignment;
3921 }
3922
3923 /****************************************************************************/
3924 /* Get default text line spacing.                                           */
3925 /****************************************************************************/
3926 gdouble
3927 gl_view_get_default_text_line_spacing (glView            *view)
3928 {
3929         gl_debug (DEBUG_VIEW, "START");
3930
3931         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
3932
3933         gl_debug (DEBUG_VIEW, "END");
3934
3935         return view->default_text_line_spacing;
3936 }
3937
3938
3939
3940 /****************************************************************************/
3941 /* Get default line width.                                                  */
3942 /****************************************************************************/
3943 gdouble
3944 gl_view_get_default_line_width (glView            *view)
3945 {
3946         gl_debug (DEBUG_VIEW, "START");
3947
3948         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
3949
3950         gl_debug (DEBUG_VIEW, "END");
3951
3952         return view->default_line_width;
3953 }
3954
3955
3956 /****************************************************************************/
3957 /* Get default line color.                                                  */
3958 /****************************************************************************/
3959 guint gl_view_get_default_line_color (glView            *view)
3960 {
3961         gl_debug (DEBUG_VIEW, "START");
3962
3963         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3964
3965         gl_debug (DEBUG_VIEW, "END");
3966
3967         return view->default_line_color;
3968 }
3969
3970
3971 /****************************************************************************/
3972 /* Get default fill color.                                                  */
3973 /****************************************************************************/
3974 guint gl_view_get_default_fill_color (glView            *view)
3975 {
3976         gl_debug (DEBUG_VIEW, "START");
3977
3978         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3979
3980         gl_debug (DEBUG_VIEW, "END");
3981
3982         return view->default_fill_color;
3983 }