]> git.sur5r.net Git - glabels/blob - glabels1/src/item_image.c
2009-09-22 Jim Evins <evins@snaught.com>
[glabels] / glabels1 / src / item_image.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  item_image.c:  GLabels Image Object (canvas item) module
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 <config.h>
24
25 #include <string.h>
26
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 #include <gdk-pixbuf/gnome-canvas-pixbuf.h>
29
30 #include "display.h"
31 #include "item_image.h"
32
33 #include "highlight.h"
34
35 #include "mdi.h"
36 #include "propertybox.h"
37 #include "prop_position.h"
38 #include "prop_size.h"
39
40 #include "pixmaps/cursor_image.xbm"
41 #include "pixmaps/cursor_image_mask.xbm"
42
43 #include "pixmaps/checkerboard.xpm"
44
45 #include "debug.h"
46
47 #define RED(x)   ( ((x)>>24) & 0xff )
48 #define GREEN(x) ( ((x)>>16) & 0xff )
49 #define BLUE(x)  ( ((x)>>8)  & 0xff )
50 #define ALPHA(x) (  (x)      & 0xff )
51
52 /*===========================================*/
53 /* Private data types                        */
54 /*===========================================*/
55
56 typedef struct {
57         GnomeCanvasItem *item;
58         gboolean keep_aspect_ratio_flag;
59
60         /* Page 0 widgets */
61         GtkWidget *pixmap_entry;
62
63         /* Page 1 widgets */
64         GtkWidget *position;
65         GtkWidget *size;
66 } PropertyDialogPassback;
67
68 /*===========================================*/
69 /* Private globals                           */
70 /*===========================================*/
71
72 /* Save state of image file entry */
73 static gchar *image_path = NULL;
74
75 /*===========================================*/
76 /* Local function prototypes                 */
77 /*===========================================*/
78
79 static void item_image_update (GnomeCanvasItem * item);
80
81 static void changed_cb (glPropertyBox * propertybox);
82 static void size_reset_cb (glPropertyBox * propertybox);
83 static void apply_cb (glPropertyBox * propertybox,
84                       gint page, PropertyDialogPassback * data);
85 \f
86 /****************************************************************************/
87 /* Create a image object                                                    */
88 /****************************************************************************/
89 GnomeCanvasItem *
90 gl_item_image_new (glLabelObject * object,
91                    glDisplay * display)
92 {
93         GnomeCanvasGroup *group;
94         GnomeCanvasItem *item;
95
96         if (object->arg.image.image == NULL) {
97                 object->arg.image.image =
98                     gdk_pixbuf_new_from_xpm_data ((const char **)
99                                                   checkerboard_xpm);
100         }
101
102         group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
103         item = gnome_canvas_item_new (group, gnome_canvas_pixbuf_get_type (),
104                                       "x", object->x,
105                                       "y", object->y,
106                                       "width_set", TRUE,
107                                       "height_set", TRUE,
108                                       "width", object->arg.image.w,
109                                       "height", object->arg.image.h,
110                                       "pixbuf", object->arg.image.image, NULL);
111
112         /* Squirrel away pointers to object and display in the canvas item. */
113         gtk_object_set_data (GTK_OBJECT (item), "label_object", object);
114         gtk_object_set_data (GTK_OBJECT (item), "display", display);
115         gtk_object_set_data (GTK_OBJECT (item), "highlight", NULL);
116
117         gtk_signal_connect (GTK_OBJECT (item), "event",
118                             GTK_SIGNAL_FUNC (gl_display_item_event_handler),
119                             display);
120
121         gl_display_new_item_menu (item);
122
123         gl_display_set_modified (display);
124
125         return item;
126 }
127
128 /*--------------------------------------------------------------------------*/
129 /* PRIVATE. Update an image object                                          */
130 /*--------------------------------------------------------------------------*/
131 static void
132 item_image_update (GnomeCanvasItem * item)
133 {
134         glLabelObject *object;
135         glDisplay *display;
136         gdouble affine[6];
137
138         object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
139
140         if (object->arg.image.image == NULL) {
141                 object->arg.image.image =
142                     gdk_pixbuf_new_from_xpm_data ((const char **)
143                                                   checkerboard_xpm);
144         }
145
146         art_affine_identity (affine);
147         gnome_canvas_item_affine_absolute (item, affine);
148         gnome_canvas_item_set (item,
149                                "x", object->x,
150                                "y", object->y,
151                                "width_set", TRUE,
152                                "height_set", TRUE,
153                                "width", object->arg.image.w,
154                                "height", object->arg.image.h,
155                                "pixbuf", object->arg.image.image, NULL);
156
157         display = gtk_object_get_data (GTK_OBJECT (item), "display");
158         gl_display_set_modified (display);
159 }
160
161 /****************************************************************************/
162 /* Return a selection canvas item/group for given item                      */
163 /****************************************************************************/
164 void
165 gl_item_image_highlight (GnomeCanvasItem * item)
166 {
167         gl_highlight (item, GL_HIGHLIGHT_BOX_RESIZABLE);
168 }
169
170 /****************************************************************************/
171 /* Get position and size of object.                                         */
172 /****************************************************************************/
173 void
174 gl_item_image_get_position_size (GnomeCanvasItem * item,
175                                  gdouble * x,
176                                  gdouble * y,
177                                  gdouble * w,
178                                  gdouble * h)
179 {
180         glLabelObject *object;
181
182         object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
183
184         *x = object->x;
185         *y = object->y;
186
187         *w = object->arg.image.w;
188         *h = object->arg.image.h;
189 }
190
191 /****************************************************************************/
192 /* Get position and size of object.                                         */
193 /****************************************************************************/
194 void
195 gl_item_image_set_position_size (GnomeCanvasItem * item,
196                                  gdouble x,
197                                  gdouble y,
198                                  gdouble w,
199                                  gdouble h)
200 {
201         glLabelObject *object;
202
203         object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
204
205         object->x = x;
206         object->y = y;
207
208         object->arg.image.w = w;
209         object->arg.image.h = h;
210
211         item_image_update (item);
212 }
213
214 /****************************************************************************/
215 /* Get image item bounds.                                                   */
216 /****************************************************************************/
217 void
218 gl_item_image_get_bounds (GnomeCanvasItem * item,
219                           gdouble * x1,
220                           gdouble * y1,
221                           gdouble * x2,
222                           gdouble * y2)
223 {
224         gnome_canvas_item_get_bounds (item, x1, y1, x2, y2);
225 }
226
227 /****************************************************************************/
228 /* Create and run an edit dialog on a image object.                         */
229 /****************************************************************************/
230 void
231 gl_item_image_edit_dialog (GnomeCanvasItem * item)
232 {
233         GtkWidget *dialog;
234         static PropertyDialogPassback *data = NULL;
235         GtkWidget *wbutton;
236         glLabelObject *object;
237         glDisplay *display;
238         GtkWidget *wvbox;
239         gdouble image_w, image_h;
240
241         object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
242         display = gtk_object_get_data (GTK_OBJECT (item), "display");
243
244         /*-----------------------------------------------------------------*/
245         /* Build dialog with notebook.                                     */
246         /*-----------------------------------------------------------------*/
247         if (data == NULL) {
248                 data = g_new0 (PropertyDialogPassback, 1);
249         }
250         data->item = item;
251
252         dialog = gl_property_box_new ();
253         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
254         gtk_window_set_transient_for (GTK_WINDOW (dialog),
255                                       GTK_WINDOW (gl_mdi_get_active_window ()));
256         gtk_window_set_title (GTK_WINDOW (dialog),
257                               _("Edit image object properties"));
258         gtk_signal_connect (GTK_OBJECT (dialog), "apply",
259                             GTK_SIGNAL_FUNC (apply_cb), data);
260         gtk_object_set_data (GTK_OBJECT (dialog), "data", data);
261
262         /*---------------------------*/
263         /* Image Notebook Tab        */
264         /*---------------------------*/
265         wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
266         gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
267         gl_property_box_append_page (GL_PROPERTY_BOX (dialog), wvbox,
268                                      gtk_label_new (_("Image")));
269
270         /* image entry */
271         data->pixmap_entry =
272             gnome_pixmap_entry_new ("image", "Load image", TRUE);
273         gnome_pixmap_entry_set_preview_size (GNOME_PIXMAP_ENTRY
274                                              (data->pixmap_entry), 128, 128);
275
276         /* Set default path for image entry */
277         if (object->arg.image.filename != NULL) {
278                 /* Set default path to the directory containing image. */
279                 if (image_path != NULL)
280                         g_free (image_path);
281                 image_path = g_dirname (object->arg.image.filename);
282                 if (image_path != NULL) {
283                         image_path = g_strconcat (image_path, "/", NULL);
284                 }
285         } else if (image_path == NULL) {
286                 /* First time, set it to our CWD. */
287                 image_path = g_get_current_dir ();
288         }
289         /* Otherwise, leave it in the last directory that we got an image. */
290         gnome_file_entry_set_default_path (GNOME_FILE_ENTRY
291                                            (GNOME_PIXMAP_ENTRY
292                                             (data->pixmap_entry)->fentry),
293                                            image_path);
294
295         if (object->arg.image.filename != NULL) {
296                 gtk_entry_set_text (GTK_ENTRY
297                                     (gnome_pixmap_entry_gtk_entry
298                                      (GNOME_PIXMAP_ENTRY (data->pixmap_entry))),
299                                     object->arg.image.filename);
300         }
301         gtk_box_pack_start (GTK_BOX (wvbox), data->pixmap_entry, FALSE, FALSE,
302                             0);
303         gtk_signal_connect_object (GTK_OBJECT
304                                    (gnome_pixmap_entry_gtk_entry
305                                     (GNOME_PIXMAP_ENTRY (data->pixmap_entry))),
306                                    "changed", GTK_SIGNAL_FUNC (changed_cb),
307                                    GTK_OBJECT (dialog));
308
309         /*----------------------------*/
310         /* Position/Size Notebook Tab */
311         /*----------------------------*/
312         wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
313         gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
314         gl_property_box_append_page (GL_PROPERTY_BOX (dialog), wvbox,
315                                      gtk_label_new (_("Position/Size")));
316
317         /* ------ Position Frame ------ */
318         data->position = gl_prop_position_new (_("Position"));
319         gl_prop_position_set_params (GL_PROP_POSITION (data->position),
320                                      object->x, object->y,
321                                      display->label->width,
322                                      display->label->height);
323         gtk_box_pack_start (GTK_BOX (wvbox), data->position, FALSE, FALSE, 0);
324         gtk_signal_connect_object (GTK_OBJECT (data->position), "changed",
325                                    GTK_SIGNAL_FUNC (changed_cb),
326                                    GTK_OBJECT (dialog));
327
328         /* ------ Size Frame ------ */
329         data->size = gl_prop_size_new (_("Size"));
330         image_w = gdk_pixbuf_get_width (object->arg.image.image);
331         image_h = gdk_pixbuf_get_height (object->arg.image.image);
332         gl_prop_size_set_params (GL_PROP_SIZE (data->size),
333                                  object->arg.image.w, object->arg.image.h,
334                                  data->keep_aspect_ratio_flag,
335                                  display->label->width, display->label->height);
336         gtk_box_pack_start (GTK_BOX (wvbox), data->size, FALSE, FALSE, 0);
337         gtk_signal_connect_object (GTK_OBJECT (data->size), "changed",
338                                    GTK_SIGNAL_FUNC (changed_cb),
339                                    GTK_OBJECT (dialog));
340
341         /* ------ Size Reset Button ------ */
342         wbutton = gtk_button_new_with_label (_("Reset image size"));
343         gtk_box_pack_start (GTK_BOX (wvbox), wbutton, FALSE, FALSE, 0);
344         gtk_signal_connect_object (GTK_OBJECT (wbutton), "clicked",
345                                    GTK_SIGNAL_FUNC (size_reset_cb),
346                                    GTK_OBJECT (dialog));
347
348         /*-----------------------------------------------------------------*/
349         /* Run dialog, and update state of object if "Applied."            */
350         /*-----------------------------------------------------------------*/
351         gtk_widget_show_all (GTK_WIDGET (dialog));
352
353 }
354
355 /*---------------------------------------------------------------------------*/
356 /* PRIVATE.  Callback for when any control in the dialog has changed.        */
357 /*---------------------------------------------------------------------------*/
358 static void
359 changed_cb (glPropertyBox * propertybox)
360 {
361         gl_property_box_changed (propertybox);
362 }
363
364 /*---------------------------------------------------------------------------*/
365 /* PRIVATE.  Callback to reset size to original image size.                  */
366 /*---------------------------------------------------------------------------*/
367 static void
368 size_reset_cb (glPropertyBox * propertybox)
369 {
370         PropertyDialogPassback *data = NULL;
371         glDisplay *display;
372         gchar *filename, *ext;
373         GdkPixbuf *image;
374         gdouble image_w, image_h;
375
376         data = gtk_object_get_data (GTK_OBJECT (propertybox), "data");
377
378         display = gtk_object_get_data (GTK_OBJECT (data->item), "display");
379
380         filename =
381             gnome_pixmap_entry_get_filename (GNOME_PIXMAP_ENTRY
382                                              (data->pixmap_entry));
383         if (filename != NULL) {
384                 ext = strrchr (filename, '.');
385                 if (g_strcasecmp (ext, ".tga") != 0) {
386                         image = gdk_pixbuf_new_from_file (filename);
387                 } else {
388                         gnome_error_dialog (_
389                                             ("Image format not currently supported"));
390                         return;
391                 }
392         } else {
393                 return;
394         }
395         image_w = gdk_pixbuf_get_width (image);
396         image_h = gdk_pixbuf_get_height (image);
397         gdk_pixbuf_unref (image);
398
399         data->keep_aspect_ratio_flag = TRUE;
400
401         gl_prop_size_set_params (GL_PROP_SIZE (data->size),
402                                  image_w, image_h,
403                                  data->keep_aspect_ratio_flag,
404                                  display->label->width, display->label->height);
405
406         gl_property_box_changed (propertybox);
407 }
408
409 /*---------------------------------------------------------------------------*/
410 /* PRIVATE.  "Apply" callback.                                               */
411 /*---------------------------------------------------------------------------*/
412 static void
413 apply_cb (glPropertyBox * propertybox,
414           gint page,
415           PropertyDialogPassback * data)
416 {
417         glLabelObject *object;
418         glDisplay *display;
419         gchar *filename, *ext;
420         gdouble image_w, image_h;
421
422         object = gtk_object_get_data (GTK_OBJECT (data->item), "label_object");
423         display = gtk_object_get_data (GTK_OBJECT (data->item), "display");
424
425         switch (page) {
426
427         case 0:
428                 /* ------ Update image ------ */
429                 filename =
430                     gnome_pixmap_entry_get_filename (GNOME_PIXMAP_ENTRY
431                                                      (data->pixmap_entry));
432                 if (filename != NULL) {
433                         ext = strrchr (filename, '.');
434                         if (g_strcasecmp (ext, ".tga") != 0) {
435
436                                 g_free (object->arg.image.filename);
437                                 object->arg.image.filename = filename;
438                                 gdk_pixbuf_unref (object->arg.image.image);
439                                 object->arg.image.image =
440                                     gdk_pixbuf_new_from_file (object->arg.image.
441                                                               filename);
442
443                                 /* save state of image entry. */
444                                 if (image_path != NULL)
445                                         g_free (image_path);
446                                 image_path = g_dirname (filename);
447                                 if (image_path != NULL) {
448                                         image_path =
449                                             g_strconcat (image_path, "/", NULL);
450                                 }
451
452                         } else {
453                                 gnome_error_dialog (_
454                                                     ("Image format not currently supported"));
455                         }
456                 }
457                 break;
458
459         case 1:
460                 /* ------ get updated position ------ */
461                 gl_prop_position_get_position (GL_PROP_POSITION
462                                                (data->position), &object->x,
463                                                &object->y);
464
465                 /* ------ get updated size ------ */
466                 gl_prop_size_get_size (GL_PROP_SIZE (data->size),
467                                        &object->arg.image.w,
468                                        &object->arg.image.h,
469                                        &data->keep_aspect_ratio_flag);
470                 break;
471
472         default:
473                 return;
474         }
475
476         /* ------ Udate state of object ------ */
477         item_image_update (data->item);
478         gl_display_select_item (display, data->item);
479
480         /* update size controls */
481         image_w = gdk_pixbuf_get_width (object->arg.image.image);
482         image_h = gdk_pixbuf_get_height (object->arg.image.image);
483         gl_prop_size_set_params (GL_PROP_SIZE (data->size),
484                                  object->arg.image.w, object->arg.image.h,
485                                  data->keep_aspect_ratio_flag,
486                                  display->label->width, display->label->height);
487 }
488
489 /****************************************************************************/
490 /* Return apropos cursor for create object mode.                            */
491 /****************************************************************************/
492 GdkCursor *
493 gl_item_image_get_create_cursor (void)
494 {
495         static GdkCursor *cursor = NULL;
496         GdkPixmap *pixmap_data, *pixmap_mask;
497         GdkColor fg = { 0, 0, 0, 0 };
498         GdkColor bg = { 0, 65535, 65535, 65535 };
499
500         if (!cursor) {
501                 pixmap_data = gdk_bitmap_create_from_data (NULL,
502                                                            cursor_image_bits,
503                                                            cursor_image_width,
504                                                            cursor_image_height);
505                 pixmap_mask = gdk_bitmap_create_from_data (NULL,
506                                                            cursor_image_mask_bits,
507                                                            cursor_image_mask_width,
508                                                            cursor_image_mask_height);
509                 cursor =
510                     gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
511                                                 &bg, cursor_image_x_hot,
512                                                 cursor_image_y_hot);
513         }
514
515         return cursor;
516 }
517
518 /****************************************************************************/
519 /* Canvas event handler (image mode)                                        */
520 /****************************************************************************/
521 gint
522 gl_item_image_create_event_handler (GnomeCanvas * canvas,
523                                     GdkEvent * event,
524                                     gpointer data)
525 {
526         static gdouble x0, y0;
527         static gboolean dragging = FALSE;
528         static GnomeCanvasItem *item;
529         static glLabelObject *object;
530         glDisplay *display = GL_DISPLAY (data);
531         gdouble x, y;
532
533         switch (event->type) {
534
535         case GDK_BUTTON_PRESS:
536                 switch (event->button.button) {
537                 case 1:
538                         dragging = TRUE;
539                         gdk_pointer_grab (GTK_WIDGET (display->canvas)->window,
540                                           FALSE,
541                                           GDK_POINTER_MOTION_MASK |
542                                           GDK_BUTTON_RELEASE_MASK |
543                                           GDK_BUTTON_PRESS_MASK,
544                                           NULL, NULL, event->button.time);
545                         gnome_canvas_window_to_world (canvas,
546                                                       event->button.x,
547                                                       event->button.y, &x, &y);
548                         object =
549                             gl_label_object_new (display->label,
550                                                  GL_LABEL_OBJECT_IMAGE);
551                         object->x = x;
552                         object->y = y;
553                         object->arg.image.w = 1.0;
554                         object->arg.image.h = 1.0;
555                         object->arg.image.image = NULL;
556                         object->arg.image.filename = NULL;
557                         item = gl_item_image_new (object, display);
558                         x0 = x;
559                         y0 = y;
560                         return TRUE;
561
562                 default:
563                         return FALSE;
564                 }
565
566         case GDK_BUTTON_RELEASE:
567                 switch (event->button.button) {
568                 case 1:
569                         dragging = FALSE;
570                         gdk_pointer_ungrab (event->button.time);
571                         gnome_canvas_window_to_world (canvas,
572                                                       event->button.x,
573                                                       event->button.y, &x, &y);
574                         if ((x0 == x) || (y0 == y)) {
575                                 x = x0 + 24.0;
576                                 y = y0 + 24.0;
577                         }
578                         object->x = MIN (x, x0);
579                         object->y = MIN (y, y0);
580                         object->arg.image.w = MAX (x, x0) - MIN (x, x0);
581                         object->arg.image.h = MAX (y, y0) - MIN (y, y0);
582                         item_image_update (item);
583                         gl_display_add_item (display, item);
584                         gl_display_unselect_all (display);
585                         gl_display_select_item (display, item);
586                         gl_display_arrow_mode (display);
587                         return TRUE;
588
589                 default:
590                         return FALSE;
591                 }
592
593         case GDK_MOTION_NOTIFY:
594                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
595                         gnome_canvas_window_to_world (canvas,
596                                                       event->motion.x,
597                                                       event->motion.y, &x, &y);
598                         object->x = MIN (x, x0);
599                         object->y = MIN (y, y0);
600                         object->arg.image.w = MAX (x, x0) - MIN (x, x0);
601                         object->arg.image.h = MAX (y, y0) - MIN (y, y0);
602                         item_image_update (item);
603                         return TRUE;
604                 } else {
605                         return FALSE;
606                 }
607
608         default:
609                 return FALSE;
610         }
611
612 }