2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * item_image.c: GLabels Image Object (canvas item) module
6 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 #include <gdk-pixbuf/gnome-canvas-pixbuf.h>
31 #include "item_image.h"
33 #include "highlight.h"
36 #include "propertybox.h"
37 #include "prop_position.h"
38 #include "prop_size.h"
40 #include "pixmaps/cursor_image.xbm"
41 #include "pixmaps/cursor_image_mask.xbm"
43 #include "pixmaps/checkerboard.xpm"
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 )
52 /*===========================================*/
53 /* Private data types */
54 /*===========================================*/
57 GnomeCanvasItem *item;
58 gboolean keep_aspect_ratio_flag;
61 GtkWidget *pixmap_entry;
66 } PropertyDialogPassback;
68 /*===========================================*/
70 /*===========================================*/
72 /* Save state of image file entry */
73 static gchar *image_path = NULL;
75 /*===========================================*/
76 /* Local function prototypes */
77 /*===========================================*/
79 static void item_image_update (GnomeCanvasItem * item);
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);
86 /****************************************************************************/
87 /* Create a image object */
88 /****************************************************************************/
90 gl_item_image_new (glLabelObject * object,
93 GnomeCanvasGroup *group;
94 GnomeCanvasItem *item;
96 if (object->arg.image.image == NULL) {
97 object->arg.image.image =
98 gdk_pixbuf_new_from_xpm_data ((const char **)
102 group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
103 item = gnome_canvas_item_new (group, gnome_canvas_pixbuf_get_type (),
108 "width", object->arg.image.w,
109 "height", object->arg.image.h,
110 "pixbuf", object->arg.image.image, NULL);
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);
117 gtk_signal_connect (GTK_OBJECT (item), "event",
118 GTK_SIGNAL_FUNC (gl_display_item_event_handler),
121 gl_display_new_item_menu (item);
123 gl_display_set_modified (display);
128 /*--------------------------------------------------------------------------*/
129 /* PRIVATE. Update an image object */
130 /*--------------------------------------------------------------------------*/
132 item_image_update (GnomeCanvasItem * item)
134 glLabelObject *object;
138 object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
140 if (object->arg.image.image == NULL) {
141 object->arg.image.image =
142 gdk_pixbuf_new_from_xpm_data ((const char **)
146 art_affine_identity (affine);
147 gnome_canvas_item_affine_absolute (item, affine);
148 gnome_canvas_item_set (item,
153 "width", object->arg.image.w,
154 "height", object->arg.image.h,
155 "pixbuf", object->arg.image.image, NULL);
157 display = gtk_object_get_data (GTK_OBJECT (item), "display");
158 gl_display_set_modified (display);
161 /****************************************************************************/
162 /* Return a selection canvas item/group for given item */
163 /****************************************************************************/
165 gl_item_image_highlight (GnomeCanvasItem * item)
167 gl_highlight (item, GL_HIGHLIGHT_BOX_RESIZABLE);
170 /****************************************************************************/
171 /* Get position and size of object. */
172 /****************************************************************************/
174 gl_item_image_get_position_size (GnomeCanvasItem * item,
180 glLabelObject *object;
182 object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
187 *w = object->arg.image.w;
188 *h = object->arg.image.h;
191 /****************************************************************************/
192 /* Get position and size of object. */
193 /****************************************************************************/
195 gl_item_image_set_position_size (GnomeCanvasItem * item,
201 glLabelObject *object;
203 object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
208 object->arg.image.w = w;
209 object->arg.image.h = h;
211 item_image_update (item);
214 /****************************************************************************/
215 /* Get image item bounds. */
216 /****************************************************************************/
218 gl_item_image_get_bounds (GnomeCanvasItem * item,
224 gnome_canvas_item_get_bounds (item, x1, y1, x2, y2);
227 /****************************************************************************/
228 /* Create and run an edit dialog on a image object. */
229 /****************************************************************************/
231 gl_item_image_edit_dialog (GnomeCanvasItem * item)
234 static PropertyDialogPassback *data = NULL;
236 glLabelObject *object;
239 gdouble image_w, image_h;
241 object = gtk_object_get_data (GTK_OBJECT (item), "label_object");
242 display = gtk_object_get_data (GTK_OBJECT (item), "display");
244 /*-----------------------------------------------------------------*/
245 /* Build dialog with notebook. */
246 /*-----------------------------------------------------------------*/
248 data = g_new0 (PropertyDialogPassback, 1);
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);
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")));
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);
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)
281 image_path = g_dirname (object->arg.image.filename);
282 if (image_path != NULL) {
283 image_path = g_strconcat (image_path, "/", NULL);
285 } else if (image_path == NULL) {
286 /* First time, set it to our CWD. */
287 image_path = g_get_current_dir ();
289 /* Otherwise, leave it in the last directory that we got an image. */
290 gnome_file_entry_set_default_path (GNOME_FILE_ENTRY
292 (data->pixmap_entry)->fentry),
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);
301 gtk_box_pack_start (GTK_BOX (wvbox), data->pixmap_entry, FALSE, FALSE,
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));
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")));
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));
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));
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));
348 /*-----------------------------------------------------------------*/
349 /* Run dialog, and update state of object if "Applied." */
350 /*-----------------------------------------------------------------*/
351 gtk_widget_show_all (GTK_WIDGET (dialog));
355 /*---------------------------------------------------------------------------*/
356 /* PRIVATE. Callback for when any control in the dialog has changed. */
357 /*---------------------------------------------------------------------------*/
359 changed_cb (glPropertyBox * propertybox)
361 gl_property_box_changed (propertybox);
364 /*---------------------------------------------------------------------------*/
365 /* PRIVATE. Callback to reset size to original image size. */
366 /*---------------------------------------------------------------------------*/
368 size_reset_cb (glPropertyBox * propertybox)
370 PropertyDialogPassback *data = NULL;
372 gchar *filename, *ext;
374 gdouble image_w, image_h;
376 data = gtk_object_get_data (GTK_OBJECT (propertybox), "data");
378 display = gtk_object_get_data (GTK_OBJECT (data->item), "display");
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);
388 gnome_error_dialog (_
389 ("Image format not currently supported"));
395 image_w = gdk_pixbuf_get_width (image);
396 image_h = gdk_pixbuf_get_height (image);
397 gdk_pixbuf_unref (image);
399 data->keep_aspect_ratio_flag = TRUE;
401 gl_prop_size_set_params (GL_PROP_SIZE (data->size),
403 data->keep_aspect_ratio_flag,
404 display->label->width, display->label->height);
406 gl_property_box_changed (propertybox);
409 /*---------------------------------------------------------------------------*/
410 /* PRIVATE. "Apply" callback. */
411 /*---------------------------------------------------------------------------*/
413 apply_cb (glPropertyBox * propertybox,
415 PropertyDialogPassback * data)
417 glLabelObject *object;
419 gchar *filename, *ext;
420 gdouble image_w, image_h;
422 object = gtk_object_get_data (GTK_OBJECT (data->item), "label_object");
423 display = gtk_object_get_data (GTK_OBJECT (data->item), "display");
428 /* ------ Update image ------ */
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) {
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.
443 /* save state of image entry. */
444 if (image_path != NULL)
446 image_path = g_dirname (filename);
447 if (image_path != NULL) {
449 g_strconcat (image_path, "/", NULL);
453 gnome_error_dialog (_
454 ("Image format not currently supported"));
460 /* ------ get updated position ------ */
461 gl_prop_position_get_position (GL_PROP_POSITION
462 (data->position), &object->x,
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);
476 /* ------ Udate state of object ------ */
477 item_image_update (data->item);
478 gl_display_select_item (display, data->item);
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);
489 /****************************************************************************/
490 /* Return apropos cursor for create object mode. */
491 /****************************************************************************/
493 gl_item_image_get_create_cursor (void)
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 };
501 pixmap_data = gdk_bitmap_create_from_data (NULL,
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);
510 gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
511 &bg, cursor_image_x_hot,
518 /****************************************************************************/
519 /* Canvas event handler (image mode) */
520 /****************************************************************************/
522 gl_item_image_create_event_handler (GnomeCanvas * canvas,
526 static gdouble x0, y0;
527 static gboolean dragging = FALSE;
528 static GnomeCanvasItem *item;
529 static glLabelObject *object;
530 glDisplay *display = GL_DISPLAY (data);
533 switch (event->type) {
535 case GDK_BUTTON_PRESS:
536 switch (event->button.button) {
539 gdk_pointer_grab (GTK_WIDGET (display->canvas)->window,
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,
547 event->button.y, &x, &y);
549 gl_label_object_new (display->label,
550 GL_LABEL_OBJECT_IMAGE);
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);
566 case GDK_BUTTON_RELEASE:
567 switch (event->button.button) {
570 gdk_pointer_ungrab (event->button.time);
571 gnome_canvas_window_to_world (canvas,
573 event->button.y, &x, &y);
574 if ((x0 == x) || (y0 == y)) {
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);
593 case GDK_MOTION_NOTIFY:
594 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
595 gnome_canvas_window_to_world (canvas,
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);