]> git.sur5r.net Git - glabels/blob - glabels2/src/view-object.c
62b951dfdc1e435a100f8e76e80e015bb4740c03
[glabels] / glabels2 / src / view-object.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  view_object.c:  GLabels label object base class
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <glib.h>
24
25 #include "view-object.h"
26 #include "libart_lgpl/libart.h"
27
28 #include "debug.h"
29
30 /*========================================================*/
31 /* Private constants and macros.                          */
32 /*========================================================*/
33
34 /* Used for a workaround for a bug with images when flipped or rotated by 90 degrees. */
35 #define DELTA_DEG 0.001
36
37 /*========================================================*/
38 /* Private types.                                         */
39 /*========================================================*/
40
41 struct _glViewObjectPrivate {
42
43         glView                     *view;
44         glLabelObject              *object;
45
46         GnomeCanvasItem            *group;
47         glViewHighlight            *highlight;
48
49         GtkWidget                  *menu;
50         GtkWidget                  *property_dialog;
51
52         glViewObjectDlgConstructor  dialog_constructor;
53 };
54
55 /*========================================================*/
56 /* Private globals.                                       */
57 /*========================================================*/
58
59 static GObjectClass *parent_class = NULL;
60
61
62 /*========================================================*/
63 /* Private function prototypes.                           */
64 /*========================================================*/
65
66 static void     gl_view_object_class_init    (glViewObjectClass   *klass);
67 static void     gl_view_object_instance_init (glViewObject        *view_object);
68 static void     gl_view_object_finalize      (GObject             *object);
69
70 static GtkMenu *new_menu                     (glViewObject        *view_object);
71
72 static void     object_moved_cb              (glLabelObject       *object,
73                                               gdouble              x,
74                                               gdouble              y,
75                                               glViewObject        *view_object);
76
77 static void     raise_object_cb              (glLabelObject       *object,
78                                               glViewObject        *view_object);
79
80 static void     lower_object_cb              (glLabelObject       *object,
81                                               glViewObject        *view_object);
82
83 static void     flip_rotate_object_cb        (glLabelObject       *object,
84                                               glViewObject        *view_object);
85
86
87 \f
88 /*****************************************************************************/
89 /* Boilerplate object stuff.                                                 */
90 /*****************************************************************************/
91 GType
92 gl_view_object_get_type (void)
93 {
94         static GType type = 0;
95
96         if (!type) {
97                 GTypeInfo info = {
98                         sizeof (glViewObjectClass),
99                         NULL,
100                         NULL,
101                         (GClassInitFunc) gl_view_object_class_init,
102                         NULL,
103                         NULL,
104                         sizeof (glViewObject),
105                         0,
106                         (GInstanceInitFunc) gl_view_object_instance_init,
107                 };
108
109                 type = g_type_register_static (G_TYPE_OBJECT,
110                                                "glViewObject", &info, 0);
111         }
112
113         return type;
114 }
115
116 static void
117 gl_view_object_class_init (glViewObjectClass *klass)
118 {
119         GObjectClass *object_class = (GObjectClass *) klass;
120
121         gl_debug (DEBUG_VIEW, "START");
122
123         parent_class = g_type_class_peek_parent (klass);
124
125         object_class->finalize = gl_view_object_finalize;
126
127         gl_debug (DEBUG_VIEW, "END");
128 }
129
130 static void
131 gl_view_object_instance_init (glViewObject *view_object)
132 {
133         gl_debug (DEBUG_VIEW, "START");
134
135         view_object->private = g_new0 (glViewObjectPrivate, 1);
136
137         gl_debug (DEBUG_VIEW, "END");
138 }
139
140 static void
141 gl_view_object_finalize (GObject *object)
142 {
143         glLabel       *parent;
144         glView        *view;
145
146         gl_debug (DEBUG_VIEW, "START");
147
148         g_return_if_fail (object && GL_IS_VIEW_OBJECT (object));
149
150         view = GL_VIEW_OBJECT(object)->private->view;
151         view->object_list = g_list_remove (view->object_list, object);
152         view->selected_object_list =
153                 g_list_remove (view->selected_object_list, object);
154
155         g_object_unref (GL_VIEW_OBJECT(object)->private->object);
156         g_object_unref (G_OBJECT(GL_VIEW_OBJECT(object)->private->highlight));
157         gtk_object_destroy (GTK_OBJECT(GL_VIEW_OBJECT(object)->private->group));
158         gtk_object_destroy (GTK_OBJECT(GL_VIEW_OBJECT(object)->private->menu));
159         if (GL_VIEW_OBJECT(object)->private->property_dialog) {
160                 gtk_object_destroy (GTK_OBJECT(GL_VIEW_OBJECT(object)->private->property_dialog));
161         }
162
163         G_OBJECT_CLASS (parent_class)->finalize (object);
164
165         gl_debug (DEBUG_VIEW, "END");
166 }
167
168 /*****************************************************************************/
169 /* NEW object view.                                                          */
170 /*****************************************************************************/
171 GObject *
172 gl_view_object_new (void)
173 {
174         glViewObject *view_object;
175
176         gl_debug (DEBUG_VIEW, "START");
177
178         view_object = g_object_new (gl_view_object_get_type(), NULL);
179
180         gl_debug (DEBUG_VIEW, "END");
181
182         return G_OBJECT (view_object);
183 }
184
185 /*****************************************************************************/
186 /* Set parent view to which this object view belongs.                        */
187 /*****************************************************************************/
188 void
189 gl_view_object_set_view       (glViewObject *view_object,
190                                glView *view)
191 {
192         gl_debug (DEBUG_VIEW, "START");
193
194         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
195         g_return_if_fail (view && GL_IS_VIEW (view));
196         
197         view_object->private->view = view;
198
199         view->object_list = g_list_prepend (view->object_list, view_object);
200
201         gl_debug (DEBUG_VIEW, "END");
202 }
203
204 /*****************************************************************************/
205 /* Set Label object to follow.                                               */
206 /*****************************************************************************/
207 void
208 gl_view_object_set_object     (glViewObject         *view_object,
209                                glLabelObject        *object,
210                                glViewHighlightStyle style)
211 {
212         GnomeCanvas        *canvas;
213         GnomeCanvasGroup   *root;
214         gdouble            x, y, w, h;
215
216         gl_debug (DEBUG_VIEW, "START");
217
218         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
219         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
220         
221         view_object->private->object = object;
222
223         gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
224         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
225
226         /* create canvas group to contain items representing object */
227         view_object->private->group =
228                 gnome_canvas_item_new (view_object->private->view->label_group,
229                                        gnome_canvas_group_get_type (),
230                                        "x", x,
231                                        "y", y,
232                                        NULL);
233
234         /* Create appropriate selection highlight canvas item. */
235         view_object->private->highlight =
236                 GL_VIEW_HIGHLIGHT (gl_view_highlight_new (view_object, style));
237
238         view_object->private->menu = GTK_WIDGET(new_menu (view_object));
239
240         g_signal_connect (G_OBJECT (object), "moved",
241                           G_CALLBACK (object_moved_cb),
242                           view_object);
243
244         g_signal_connect (G_OBJECT (object), "top",
245                           G_CALLBACK (raise_object_cb),
246                           view_object);
247
248         g_signal_connect (G_OBJECT (object), "bottom",
249                           G_CALLBACK (lower_object_cb),
250                           view_object);
251
252         g_signal_connect (G_OBJECT (object), "flip_rotate",
253                           G_CALLBACK (flip_rotate_object_cb),
254                           view_object);
255
256         g_signal_connect (G_OBJECT (view_object->private->group), "event",
257                           G_CALLBACK (gl_view_item_event_handler),
258                           view_object);
259
260         gl_debug (DEBUG_VIEW, "END");
261 }
262
263 /*****************************************************************************/
264 /* Set dialog for controlling/viewing object properties.                     */
265 /*****************************************************************************/
266 void
267 gl_view_object_set_dlg_constructor (glViewObject               *view_object,
268                                     glViewObjectDlgConstructor  dlg_constructor)
269
270 {
271         gl_debug (DEBUG_VIEW, "START");
272
273         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
274         
275         view_object->private->dialog_constructor = dlg_constructor;
276
277         gl_debug (DEBUG_VIEW, "END");
278 }
279
280 /*****************************************************************************/
281 /* Return parent view associated with this view.                             */
282 /*****************************************************************************/
283 glView *
284 gl_view_object_get_view   (glViewObject *view_object)
285 {
286         gl_debug (DEBUG_VIEW, "START");
287
288         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
289
290         gl_debug (DEBUG_VIEW, "END");
291
292         return view_object->private->view;
293 }
294
295 /*****************************************************************************/
296 /* Return label object that we are following.                                */
297 /*****************************************************************************/
298 glLabelObject *
299 gl_view_object_get_object (glViewObject *view_object)
300 {
301         gl_debug (DEBUG_VIEW, "START");
302
303         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
304         
305         gl_debug (DEBUG_VIEW, "END");
306
307         return view_object->private->object;
308 }
309
310 /*****************************************************************************/
311 /* Return canvas item representing our object in this view.                  */
312 /*****************************************************************************/
313 GnomeCanvasItem *
314 gl_view_object_get_group   (glViewObject *view_object)
315 {
316         gl_debug (DEBUG_VIEW, "START");
317
318         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
319         
320         gl_debug (DEBUG_VIEW, "END");
321
322         return view_object->private->group;
323 }
324
325 /*****************************************************************************/
326 /* Create canvas item for this object.                                       */
327 /*****************************************************************************/
328 GnomeCanvasItem *
329 gl_view_object_item_new (glViewObject *view_object,
330                          GType         type,
331                          const gchar  *first_arg_name,
332                          ...)
333 {
334         GnomeCanvasItem *item;
335         va_list          args;
336         gdouble          affine[6], delta_affine[6];
337
338         gl_debug (DEBUG_VIEW, "START");
339
340         g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
341
342         item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(view_object->private->group),
343                                       type, NULL);
344         
345         va_start (args, first_arg_name);
346         gnome_canvas_item_set_valist (item, first_arg_name, args);
347         va_end (args);
348
349         gl_label_object_get_applied_affine (view_object->private->object, affine);
350
351         /* Apply a very small rotation, fixes problems with flipped or rotated images */
352         art_affine_rotate (delta_affine, DELTA_DEG);
353         art_affine_multiply (affine, affine, delta_affine);
354         
355         gnome_canvas_item_affine_absolute (item, affine);
356
357         gl_debug (DEBUG_VIEW, "END");
358
359         return item;
360 }
361
362 /*****************************************************************************/
363 /* Return dialog for controlling/viewing object properties.                  */
364 /*****************************************************************************/
365 GtkWidget *
366 gl_view_object_get_dialog (glViewObject *view_object)
367 {
368         gl_debug (DEBUG_VIEW, "START");
369
370         g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
371         
372         gl_debug (DEBUG_VIEW, "END");
373
374         return view_object->private->property_dialog;
375 }
376
377 /*****************************************************************************/
378 /* Popup menu for this object.                                               */
379 /*****************************************************************************/
380 GtkMenu *
381 gl_view_object_get_menu (glViewObject *view_object)
382 {
383         gl_debug (DEBUG_VIEW, "START");
384
385         g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
386
387         gl_debug (DEBUG_VIEW, "END");
388
389         return GTK_MENU(view_object->private->menu);
390 }
391
392 /*****************************************************************************/
393 /* Highlight view of object.                                                 */
394 /*****************************************************************************/
395 void
396 gl_view_object_show_highlight     (glViewObject *view_object)
397 {
398         gl_debug (DEBUG_VIEW, "START");
399
400         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
401         g_return_if_fail (view_object->private->highlight);
402         
403         gl_view_highlight_show (view_object->private->highlight);
404
405         gl_debug (DEBUG_VIEW, "END");
406 }
407
408 /*****************************************************************************/
409 /* Remove highlight from view of object.                                     */
410 /*****************************************************************************/
411 void
412 gl_view_object_hide_highlight   (glViewObject *view_object)
413 {
414         gl_debug (DEBUG_VIEW, "START");
415
416         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
417         g_return_if_fail (view_object->private->highlight);
418         
419         gl_view_highlight_hide (view_object->private->highlight);
420
421         gl_debug (DEBUG_VIEW, "END");
422 }
423
424
425 /*---------------------------------------------------------------------------*/
426 /* Create a popup menu for this object view.                                 */
427 /*---------------------------------------------------------------------------*/
428 static GtkMenu *
429 new_menu (glViewObject *view_object)
430 {
431         GtkWidget *menu, *menuitem;
432
433         gl_debug (DEBUG_VIEW, "START");
434
435         g_return_val_if_fail (view_object && GL_VIEW_OBJECT(view_object), NULL);
436
437         menu = gtk_menu_new ();
438
439         menuitem = gtk_menu_item_new_with_label (_("Edit properties..."));
440         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
441         gtk_widget_show (menuitem);
442         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
443                                   G_CALLBACK (gl_view_object_show_dialog),
444                                   view_object);
445
446         menuitem = gtk_menu_item_new ();
447         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
448         gtk_widget_show (menuitem);
449
450         menuitem = gtk_menu_item_new_with_label (_("Delete"));
451         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
452         gtk_widget_show (menuitem);
453         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
454                                   G_CALLBACK (g_object_unref), view_object);
455
456         menuitem = gtk_menu_item_new ();
457         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
458         gtk_widget_show (menuitem);
459
460         menuitem = gtk_menu_item_new_with_label (_("Bring to front"));
461         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
462         gtk_widget_show (menuitem);
463         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
464                                   G_CALLBACK (gl_label_object_raise_to_top),
465                                   view_object->private->object);
466
467         menuitem = gtk_menu_item_new_with_label (_("Send to back"));
468         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
469         gtk_widget_show (menuitem);
470         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
471                                   G_CALLBACK (gl_label_object_lower_to_bottom),
472                                   view_object->private->object);
473
474         gl_debug (DEBUG_VIEW, "END");
475
476         return GTK_MENU(menu);
477 }
478
479 /*****************************************************************************/
480 /* Show property dialog.                                                     */
481 /*****************************************************************************/
482 void
483 gl_view_object_show_dialog (glViewObject *view_object)
484 {
485         gl_debug (DEBUG_VIEW, "START");
486
487         g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
488
489         if (view_object->private->property_dialog != NULL) {
490                 gtk_window_present (GTK_WINDOW (view_object->private->property_dialog));
491                 return;
492         }
493
494         view_object->private->property_dialog =
495                 view_object->private->dialog_constructor (view_object);
496
497         g_signal_connect (G_OBJECT (view_object->private->property_dialog),
498                           "destroy",
499                           G_CALLBACK (gtk_widget_destroyed),
500                           &view_object->private->property_dialog);
501         
502         gtk_widget_show_all (view_object->private->property_dialog);
503
504
505         gl_debug (DEBUG_VIEW, "END");
506 }
507
508
509 /*---------------------------------------------------------------------------*/
510 /* PRIVATE.  Object moved callback.                                          */
511 /*---------------------------------------------------------------------------*/
512 static void
513 object_moved_cb (glLabelObject *object,
514                  gdouble        dx,
515                  gdouble        dy,
516                  glViewObject  *view_object)
517 {
518         gl_debug (DEBUG_VIEW, "START");
519
520         /* Adjust location of analogous canvas group. */
521         gnome_canvas_item_move (view_object->private->group, dx, dy);
522
523         gl_debug (DEBUG_VIEW, "END");
524 }
525
526 /*---------------------------------------------------------------------------*/
527 /* PRIVATE.  raise item to front callback.                                   */
528 /*---------------------------------------------------------------------------*/
529 static void
530 raise_object_cb (glLabelObject *object,
531                  glViewObject  *view_object)
532 {
533         gl_debug (DEBUG_VIEW, "START");
534
535         /* send to top */
536         gnome_canvas_item_raise_to_top (view_object->private->group);
537
538         gl_debug (DEBUG_VIEW, "END");
539 }
540
541 /*---------------------------------------------------------------------------*/
542 /* PRIVATE.  lower item to back callback.                                    */
543 /*---------------------------------------------------------------------------*/
544 static void
545 lower_object_cb (glLabelObject *object,
546                  glViewObject  *view_object)
547 {
548         gl_debug (DEBUG_VIEW, "START");
549
550         /* Send to bottom */
551         gnome_canvas_item_lower_to_bottom (view_object->private->group);
552
553         gl_debug (DEBUG_VIEW, "END");
554 }
555
556 /*---------------------------------------------------------------------------*/
557 /* PRIVATE.  Flip/rotate object callback.                                    */
558 /*---------------------------------------------------------------------------*/
559 static void
560 flip_rotate_object_cb (glLabelObject *object,
561                        glViewObject  *view_object)
562 {
563         gdouble          affine[6], delta_affine[6];
564         gdouble          w, h;
565         GList           *p, *item_list;
566         GnomeCanvasItem *item;
567
568         gl_debug (DEBUG_VIEW, "START");
569
570         gl_label_object_get_applied_affine (object, affine);
571
572         /* Apply a very small rotation, fixes problems with flipped or rotated images */
573         art_affine_rotate (delta_affine, DELTA_DEG);
574         art_affine_multiply (affine, affine, delta_affine);
575         
576         item_list = GNOME_CANVAS_GROUP(view_object->private->group)->item_list;
577         for ( p=item_list; p != NULL; p=p->next ) {
578                 item = GNOME_CANVAS_ITEM(p->data);
579                 gnome_canvas_item_affine_absolute (item, affine);
580         }
581
582         gl_debug (DEBUG_VIEW, "END");
583 }
584
585 /*****************************************************************************/
586 /* Select object.                                                            */
587 /*****************************************************************************/
588 void
589 gl_view_object_select (glViewObject *view_object)
590 {
591         gl_debug (DEBUG_VIEW, "START");
592
593         gl_view_select_object(view_object->private->view, view_object);
594
595         gl_debug (DEBUG_VIEW, "END");
596 }
597