]> git.sur5r.net Git - glabels/blob - glabels2/src/view-line.c
Initial revision
[glabels] / glabels2 / src / view-line.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  view_line.c:  GLabels label line object widget
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-line.h"
26
27 #include "view-highlight.h"
28
29 #include "glabels.h"
30 #include "wdgt-line.h"
31 #include "wdgt-vector.h"
32 #include "wdgt-position.h"
33
34 #include "pixmaps/cursor_line.xbm"
35 #include "pixmaps/cursor_line_mask.xbm"
36
37 #include "debug.h"
38
39 /*========================================================*/
40 /* Private macros and constants.                          */
41 /*========================================================*/
42 #define CREATE_LINE_COLOR   GNOME_CANVAS_COLOR_A (0, 0, 0, 192)
43
44 #define DEFAULT_LINE_COLOR  GNOME_CANVAS_COLOR_A (0, 0, 0, 255)
45
46 /*========================================================*/
47 /* Private types.                                         */
48 /*========================================================*/
49
50 struct _glViewLinePrivate {
51         GnomeCanvasItem       *item;
52
53         /* Property dialog Page 0 widgets */
54         GtkWidget             *line;
55
56         /* Property dialog Page 1 widgets */
57         GtkWidget             *position;
58         GtkWidget             *vector;
59 };
60
61 /*========================================================*/
62 /* Private globals.                                       */
63 /*========================================================*/
64
65 static glViewObjectClass *parent_class = NULL;
66
67
68 /*========================================================*/
69 /* Private function prototypes.                           */
70 /*========================================================*/
71
72 static void      gl_view_line_class_init    (glViewLineClass *klass);
73 static void      gl_view_line_instance_init (glViewLine *view_line);
74 static void      gl_view_line_finalize      (GObject *object);
75
76 static void      update_view_line_cb        (glLabelObject *object,
77                                              glViewLine *view_line);
78
79 static GtkWidget *construct_properties_dialog (glViewLine *view_line);
80
81 static void      response_cb                (GtkDialog *dialog,
82                                              gint response,
83                                              glViewLine *view_line);
84
85 static void      line_changed_cb            (glWdgtLine *line,
86                                              glViewLine *view_line);
87
88 static void      position_changed_cb        (glWdgtPosition *position,
89                                              glViewLine *view_line);
90
91 static void      vector_changed_cb          (glWdgtVector *vector,
92                                              glViewLine *view_line);
93
94 static void      update_dialog_cb           (glLabelObject *object,
95                                              glViewLine *view_line);
96
97 \f
98 /*****************************************************************************/
99 /* Boilerplate object stuff.                                                 */
100 /*****************************************************************************/
101 GType
102 gl_view_line_get_type (void)
103 {
104         static GType type = 0;
105
106         if (!type) {
107                 GTypeInfo info = {
108                         sizeof (glViewLineClass),
109                         NULL,
110                         NULL,
111                         (GClassInitFunc) gl_view_line_class_init,
112                         NULL,
113                         NULL,
114                         sizeof (glViewLine),
115                         0,
116                         (GInstanceInitFunc) gl_view_line_instance_init,
117                 };
118
119                 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
120                                                "glViewLine", &info, 0);
121         }
122
123         return type;
124 }
125
126 static void
127 gl_view_line_class_init (glViewLineClass *klass)
128 {
129         GObjectClass *object_class = (GObjectClass *) klass;
130
131         gl_debug (DEBUG_VIEW, "START");
132
133         parent_class = g_type_class_peek_parent (klass);
134
135         object_class->finalize = gl_view_line_finalize;
136
137         gl_debug (DEBUG_VIEW, "END");
138 }
139
140 static void
141 gl_view_line_instance_init (glViewLine *view_line)
142 {
143         gl_debug (DEBUG_VIEW, "START");
144
145         view_line->private = g_new0 (glViewLinePrivate, 1);
146
147         gl_debug (DEBUG_VIEW, "END");
148 }
149
150 static void
151 gl_view_line_finalize (GObject *object)
152 {
153         glLabel       *parent;
154
155         gl_debug (DEBUG_VIEW, "START");
156
157         g_return_if_fail (object && GL_IS_VIEW_LINE (object));
158
159         G_OBJECT_CLASS (parent_class)->finalize (object);
160
161         gl_debug (DEBUG_VIEW, "END");
162 }
163
164 /*****************************************************************************/
165 /* NEW line object view.                                                  */
166 /*****************************************************************************/
167 glViewObject *
168 gl_view_line_new (glLabelLine *object,
169                   glView     *view)
170 {
171         glViewLine         *view_line;
172         GnomeCanvasItem    *group;
173         gdouble            line_width;
174         guint              line_color;
175         gdouble            w, h;
176         GtkMenu            *menu;
177         GtkWidget          *dialog;
178         GnomeCanvasPoints  *points;
179
180         gl_debug (DEBUG_VIEW, "START");
181         g_return_if_fail (object && GL_IS_LABEL_LINE (object));
182         g_return_if_fail (view && GL_IS_VIEW (view));
183         
184         view_line = g_object_new (gl_view_line_get_type(), NULL);
185
186         gl_view_object_set_view (GL_VIEW_OBJECT(view_line), view);
187         gl_view_object_set_object (GL_VIEW_OBJECT(view_line),
188                                    GL_LABEL_OBJECT(object),
189                                    GL_VIEW_HIGHLIGHT_LINE_RESIZABLE);
190
191         /* Query properties of object. */
192         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
193         line_width = gl_label_line_get_line_width(object);
194         line_color = gl_label_line_get_line_color(object);
195
196         /* Create analogous canvas item. */
197         group = gl_view_object_get_group (GL_VIEW_OBJECT(view_line));
198
199         points = gnome_canvas_points_new (2);
200         points->coords[0] = 0.0;
201         points->coords[1] = 0.0;
202         points->coords[2] = w;
203         points->coords[3] = h;
204         view_line->private->item =
205                 gnome_canvas_item_new (GNOME_CANVAS_GROUP(group),
206                                        gnome_canvas_line_get_type (),
207                                        "points", points,
208                                        "width_units", line_width,
209                                        "fill_color_rgba", line_color,
210                                        NULL);
211         gnome_canvas_points_free (points);
212
213         g_signal_connect (G_OBJECT (object), "changed",
214                           G_CALLBACK (update_view_line_cb), view_line);
215
216         /* Create a dialog for controlling/viewing object properties. */
217         dialog = construct_properties_dialog (view_line);
218         gl_view_object_set_dialog     (GL_VIEW_OBJECT(view_line), dialog);
219
220         gl_debug (DEBUG_VIEW, "END");
221
222         return GL_VIEW_OBJECT (view_line);
223 }
224
225 /*---------------------------------------------------------------------------*/
226 /* PRIVATE. label object "changed" callback.                                 */
227 /*---------------------------------------------------------------------------*/
228 static void
229 update_view_line_cb (glLabelObject *object,
230                      glViewLine     *view_line)
231 {
232         gdouble            line_width;
233         guint              line_color;
234         gdouble            w, h;
235         GnomeCanvasPoints  *points;
236
237         gl_debug (DEBUG_VIEW, "START");
238
239         /* Query properties of object. */
240         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
241         line_width = gl_label_line_get_line_width(GL_LABEL_LINE(object));
242         line_color = gl_label_line_get_line_color(GL_LABEL_LINE(object));
243
244         /* Adjust appearance of analogous canvas item. */
245         points = gnome_canvas_points_new (2);
246         points->coords[0] = 0.0;
247         points->coords[1] = 0.0;
248         points->coords[2] = w;
249         points->coords[3] = h;
250         gnome_canvas_item_set (view_line->private->item,
251                                "points", points,
252                                "width_units", line_width,
253                                "fill_color_rgba", line_color,
254                                NULL);
255         gnome_canvas_points_free (points);
256
257         /* Adjust highlight */
258         gl_view_object_update_highlight (GL_VIEW_OBJECT(view_line));
259
260         gl_debug (DEBUG_VIEW, "END");
261 }
262
263 /*****************************************************************************/
264 /* Create a properties dialog for a line object.                          */
265 /*****************************************************************************/
266 static GtkWidget *
267 construct_properties_dialog (glViewLine *view_line)
268 {
269         GtkWidget          *dialog, *notebook, *wvbox;
270         BonoboWindow       *win = glabels_get_active_window ();
271         glLabelObject      *object;
272         gdouble            line_width;
273         guint              line_color;
274         gdouble            x, y, w, h, label_width, label_height;
275
276         gl_debug (DEBUG_VIEW, "START");
277
278         /* retrieve object and query parameters */
279         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_line));
280         gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
281         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
282         line_width = gl_label_line_get_line_width(GL_LABEL_LINE(object));
283         line_color = gl_label_line_get_line_color(GL_LABEL_LINE(object));
284         gl_label_get_size (GL_LABEL(object->parent),
285                            &label_width, &label_height);
286
287         /*-----------------------------------------------------------------*/
288         /* Build dialog with notebook.                                     */
289         /*-----------------------------------------------------------------*/
290         dialog = gtk_dialog_new_with_buttons ( _("Edit line object properties"),
291                                                GTK_WINDOW (win),
292                                                GTK_DIALOG_DESTROY_WITH_PARENT,
293                                                GTK_STOCK_CLOSE,
294                                                            GTK_RESPONSE_CLOSE,
295                                                NULL );
296         g_signal_connect (G_OBJECT (dialog), "response",
297                           G_CALLBACK (response_cb), view_line);
298
299         notebook = gtk_notebook_new ();
300         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
301                             notebook, TRUE, TRUE, 0);
302
303         /*---------------------------*/
304         /* Appearance Notebook Tab   */
305         /*---------------------------*/
306         wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
307         gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
308         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
309                                   gtk_label_new (_("Appearance")));
310
311         /* ------ Line line ------ */
312         view_line->private->line = gl_wdgt_line_new (_("Outline"));
313         gl_wdgt_line_set_params (GL_WDGT_LINE (view_line->private->line),
314                                  line_width,
315                                  line_color);
316         gtk_box_pack_start (GTK_BOX (wvbox), view_line->private->line,
317                             FALSE, FALSE, 0);
318         g_signal_connect (G_OBJECT (view_line->private->line), "changed",
319                           G_CALLBACK(line_changed_cb), view_line);
320
321
322         /*----------------------------*/
323         /* Position/Size Notebook Tab */
324         /*----------------------------*/
325         wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
326         gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
327         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
328                                   gtk_label_new (_("Position/Size")));
329
330         /* ------ Position Frame ------ */
331         view_line->private->position = gl_wdgt_position_new (_("Position"));
332         gl_wdgt_position_set_params (GL_WDGT_POSITION (view_line->private->position),
333                                      x, y,
334                                      label_width, label_height);
335         gtk_box_pack_start (GTK_BOX (wvbox),
336                             view_line->private->position,
337                             FALSE, FALSE, 0);
338         g_signal_connect (G_OBJECT (view_line->private->position),
339                           "changed",
340                           G_CALLBACK(position_changed_cb), view_line);
341
342
343         /* ------ Size Frame ------ */
344         view_line->private->vector = gl_wdgt_vector_new (_("Size"));
345         gl_wdgt_vector_set_params (GL_WDGT_VECTOR (view_line->private->vector),
346                                    w, h,
347                                    label_width, label_height);
348         gtk_box_pack_start (GTK_BOX (wvbox), view_line->private->vector,
349                                 FALSE, FALSE, 0);
350         g_signal_connect (G_OBJECT (view_line->private->vector), "changed",
351                           G_CALLBACK(vector_changed_cb), view_line);
352
353
354         /*----------------------------*/
355         /* Track object changes.      */
356         /*----------------------------*/
357         g_signal_connect (G_OBJECT (object), "changed",
358                           G_CALLBACK (update_dialog_cb), view_line);
359
360         gl_debug (DEBUG_VIEW, "END");
361
362         return dialog;
363 }
364
365 /*---------------------------------------------------------------------------*/
366 /* PRIVATE.  "Response" callback.                                            */
367 /*---------------------------------------------------------------------------*/
368 static void
369 response_cb (GtkDialog     *dialog,
370              gint          response,
371              glViewLine    *view_line)
372 {
373         gl_debug (DEBUG_VIEW, "START");
374
375         g_return_if_fail(dialog != NULL);
376         g_return_if_fail(GTK_IS_DIALOG(dialog));
377
378         switch(response) {
379         case GTK_RESPONSE_CLOSE:
380                 gtk_widget_hide (GTK_WIDGET(dialog));
381                 break;
382         default:
383                 g_assert_not_reached();
384         }
385
386         gl_debug (DEBUG_VIEW, "END");
387 }
388
389 /*---------------------------------------------------------------------------*/
390 /* PRIVATE.  line properties "changed" callback.                             */
391 /*---------------------------------------------------------------------------*/
392 static void
393 line_changed_cb (glWdgtLine     *line,
394                  glViewLine     *view_line)
395 {
396         glLabelObject      *object;
397         gdouble            line_width;
398         guint              line_color;
399
400         gl_debug (DEBUG_VIEW, "START");
401
402         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_line));
403
404         gl_wdgt_line_get_params (GL_WDGT_LINE (line),
405                                  &line_width,
406                                  &line_color);
407
408         g_signal_handlers_block_by_func (G_OBJECT(object),
409                                          update_dialog_cb, view_line);
410         gl_label_line_set_line_width(GL_LABEL_LINE(object), line_width);
411         gl_label_line_set_line_color(GL_LABEL_LINE(object), line_color);
412         g_signal_handlers_unblock_by_func (G_OBJECT(object),
413                                            update_dialog_cb, view_line);
414
415         gl_debug (DEBUG_VIEW, "END");
416 }
417
418 /*---------------------------------------------------------------------------*/
419 /* PRIVATE.  position "changed" callback.                                    */
420 /*---------------------------------------------------------------------------*/
421 static void
422 position_changed_cb (glWdgtPosition     *position,
423                      glViewLine         *view_line)
424 {
425         glLabelObject      *object;
426         gdouble            x, y;
427
428         gl_debug (DEBUG_VIEW, "START");
429
430         gl_wdgt_position_get_position (GL_WDGT_POSITION (position), &x, &y);
431
432         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_line));
433
434         g_signal_handlers_block_by_func (G_OBJECT(object),
435                                          update_dialog_cb, view_line);
436         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
437         g_signal_handlers_unblock_by_func (G_OBJECT(object),
438                                            update_dialog_cb, view_line);
439
440         gl_debug (DEBUG_VIEW, "END");
441 }
442
443 /*---------------------------------------------------------------------------*/
444 /* PRIVATE.  vector "changed" callback.                                      */
445 /*---------------------------------------------------------------------------*/
446 static void
447 vector_changed_cb (glWdgtVector     *vector,
448                    glViewLine     *view_line)
449 {
450         glLabelObject *object;
451         gdouble       w, h;
452         gboolean      keep_aspect_ratio_flag;
453
454         gl_debug (DEBUG_VIEW, "START");
455
456         gl_wdgt_vector_get_params (GL_WDGT_VECTOR (vector), &w, &h);
457
458         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_line));
459
460         g_signal_handlers_block_by_func (G_OBJECT(object),
461                                          update_dialog_cb, view_line);
462         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
463         g_signal_handlers_unblock_by_func (G_OBJECT(object),
464                                            update_dialog_cb, view_line);
465
466         gl_debug (DEBUG_VIEW, "END");
467 }
468
469 /*---------------------------------------------------------------------------*/
470 /* PRIVATE. label object "changed" callback.                                 */
471 /*---------------------------------------------------------------------------*/
472 static void
473 update_dialog_cb (glLabelObject     *object,
474                   glViewLine        *view_line)
475 {
476         gdouble            line_width;
477         guint              line_color;
478         gdouble            x, y, w, h, label_width, label_height;
479
480         gl_debug (DEBUG_VIEW, "START");
481
482         /* Query properties of object. */
483         gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
484         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
485         line_width = gl_label_line_get_line_width(GL_LABEL_LINE(object));
486         line_color = gl_label_line_get_line_color(GL_LABEL_LINE(object));
487         gl_label_get_size (GL_LABEL(object->parent),
488                            &label_width, &label_height);
489
490         /* Block widget handlers to prevent recursion */
491         g_signal_handlers_block_by_func (G_OBJECT(view_line->private->line),
492                                          line_changed_cb, view_line);
493         g_signal_handlers_block_by_func (G_OBJECT(view_line->private->position),
494                                          position_changed_cb, view_line);
495         g_signal_handlers_block_by_func (G_OBJECT(view_line->private->vector),
496                                          vector_changed_cb, view_line);
497
498         /* Update widgets in property dialog */
499         gl_wdgt_line_set_params (GL_WDGT_LINE (view_line->private->line),
500                                  line_width,
501                                  line_color);
502         gl_wdgt_position_set_position (GL_WDGT_POSITION(view_line->private->position),
503                                        x, y);
504         gl_wdgt_vector_set_params (GL_WDGT_VECTOR(view_line->private->vector),
505                                    w, h, label_width, label_height);
506
507         /* Unblock widget handlers */
508         g_signal_handlers_unblock_by_func (G_OBJECT(view_line->private->line),
509                                            line_changed_cb, view_line);
510         g_signal_handlers_unblock_by_func (G_OBJECT(view_line->private->position),
511                                            position_changed_cb, view_line);
512         g_signal_handlers_unblock_by_func (G_OBJECT(view_line->private->vector),
513                                            vector_changed_cb, view_line);
514
515
516         gl_debug (DEBUG_VIEW, "END");
517 }
518
519 /*****************************************************************************/
520 /* Return apropos cursor for create object mode.                             */
521 /*****************************************************************************/
522 GdkCursor *
523 gl_view_line_get_create_cursor (void)
524 {
525         static GdkCursor *cursor = NULL;
526         GdkPixmap        *pixmap_data, *pixmap_mask;
527         GdkColor         fg = { 0, 0, 0, 0 };
528         GdkColor         bg = { 0, 65535, 65535, 65535 };
529
530         gl_debug (DEBUG_VIEW, "START");
531
532         if (!cursor) {
533                 pixmap_data = gdk_bitmap_create_from_data (NULL,
534                                                            cursor_line_bits,
535                                                            cursor_line_width,
536                                                            cursor_line_height);
537                 pixmap_mask = gdk_bitmap_create_from_data (NULL,
538                                                            cursor_line_mask_bits,
539                                                            cursor_line_mask_width,
540                                                            cursor_line_mask_height);
541                 cursor =
542                     gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
543                                                 &bg, cursor_line_x_hot,
544                                                 cursor_line_y_hot);
545         }
546
547         gl_debug (DEBUG_VIEW, "END");
548
549         return cursor;
550 }
551
552 /*****************************************************************************/
553 /* Canvas event handler for creating line objects.                            */
554 /*****************************************************************************/
555 int
556 gl_view_line_create_event_handler (GnomeCanvas *canvas,
557                                    GdkEvent    *event,
558                                    glView      *view)
559 {
560         static gdouble      x0, y0;
561         static gboolean     dragging = FALSE;
562         static glViewObject *view_line;
563         static GObject      *object;
564         gdouble             line_width;
565         guint               line_color;
566         gdouble             x, y, w, h;
567
568         gl_debug (DEBUG_VIEW, "");
569
570         switch (event->type) {
571
572         case GDK_BUTTON_PRESS:
573                 switch (event->button.button) {
574                 case 1:
575                         dragging = TRUE;
576                         gdk_pointer_grab (GTK_WIDGET (view->canvas)->window,
577                                           FALSE,
578                                           GDK_POINTER_MOTION_MASK |
579                                           GDK_BUTTON_RELEASE_MASK |
580                                           GDK_BUTTON_PRESS_MASK,
581                                           NULL, NULL, event->button.time);
582                         gnome_canvas_window_to_world (canvas,
583                                                       event->button.x,
584                                                       event->button.y, &x, &y);
585                         object = gl_label_line_new (view->label);
586                         gl_label_object_set_position (GL_LABEL_OBJECT(object),
587                                                       x, y);
588                         gl_label_object_set_size (GL_LABEL_OBJECT(object),
589                                                   0.0, 0.0);
590                         line_width = 1.0;
591                         line_color = CREATE_LINE_COLOR;
592                         gl_label_line_set_line_width (GL_LABEL_LINE(object),
593                                                      line_width);
594                         gl_label_line_set_line_color (GL_LABEL_LINE(object),
595                                                      line_color);
596                         view_line = gl_view_line_new (GL_LABEL_LINE(object),
597                                                       view);
598                         x0 = x;
599                         y0 = y;
600                         return TRUE;
601
602                 default:
603                         return FALSE;
604                 }
605
606         case GDK_BUTTON_RELEASE:
607                 switch (event->button.button) {
608                 case 1:
609                         dragging = FALSE;
610                         gdk_pointer_ungrab (event->button.time);
611                         gnome_canvas_window_to_world (canvas,
612                                                       event->button.x,
613                                                       event->button.y, &x, &y);
614                         if ((x0 == x) && (y0 == y)) {
615                                 x = x0 + 36.0;
616                                 y = y0 + 36.0;
617                         }
618                         w = x - x0;
619                         h = y - y0;
620                         gl_label_object_set_size (GL_LABEL_OBJECT(object),
621                                                   w, h);
622                         line_color = DEFAULT_LINE_COLOR;
623                         gl_label_line_set_line_color (GL_LABEL_LINE(object),
624                                                      line_color);
625                         gl_view_unselect_all (view);
626                         gl_view_object_select (GL_VIEW_OBJECT(view_line));
627                         gl_view_arrow_mode (view);
628                         return TRUE;
629
630                 default:
631                         return FALSE;
632                 }
633
634         case GDK_MOTION_NOTIFY:
635                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
636                         gnome_canvas_window_to_world (canvas,
637                                                       event->button.x,
638                                                       event->button.y, &x, &y);
639                         w = x - x0;
640                         h = y - y0;
641                         gl_label_object_set_size (GL_LABEL_OBJECT(object),
642                                                   w, h);
643                         return TRUE;
644                 } else {
645                         return FALSE;
646                 }
647
648         default:
649                 return FALSE;
650         }
651
652 }