2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * view_image.c: GLabels label image object widget
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
25 #include "view-image.h"
27 #include "view-highlight.h"
30 #include "wdgt-line.h"
31 #include "wdgt-fill.h"
32 #include "wdgt-size.h"
33 #include "wdgt-position.h"
35 #include "pixmaps/cursor_image.xbm"
36 #include "pixmaps/cursor_image_mask.xbm"
40 /*========================================================*/
41 /* Private macros and constants. */
42 /*========================================================*/
46 /*========================================================*/
48 /*========================================================*/
50 struct _glViewImagePrivate {
51 GnomeCanvasItem *item;
54 GtkWidget *pixmap_entry;
61 /*========================================================*/
62 /* Private globals. */
63 /*========================================================*/
65 static glViewObjectClass *parent_class = NULL;
67 /* Save state of image file entry */
68 static gchar *image_path = NULL;
71 /*========================================================*/
72 /* Private function prototypes. */
73 /*========================================================*/
75 static void gl_view_image_class_init (glViewImageClass *klass);
76 static void gl_view_image_instance_init (glViewImage *view_image);
77 static void gl_view_image_finalize (GObject *object);
79 static void update_view_image_cb (glLabelObject *object,
80 glViewImage *view_image);
82 static GtkWidget *construct_properties_dialog (glViewImage *view_image);
84 static void response_cb (GtkDialog *dialog,
86 glViewImage *view_image);
88 static void file_changed_cb (GtkEntry *pixmap_entry,
89 glViewImage *view_image);
91 static void position_changed_cb (glWdgtPosition *position,
92 glViewImage *view_image);
94 static void size_changed_cb (glWdgtSize *size,
95 glViewImage *view_image);
97 static void size_reset_cb (GtkButton *button,
98 glViewImage *view_image);
100 static void update_dialog_cb (glLabelObject *object,
101 glViewImage *view_image);
104 /*****************************************************************************/
105 /* Boilerplate object stuff. */
106 /*****************************************************************************/
108 gl_view_image_get_type (void)
110 static GType type = 0;
114 sizeof (glViewImageClass),
117 (GClassInitFunc) gl_view_image_class_init,
120 sizeof (glViewImage),
122 (GInstanceInitFunc) gl_view_image_instance_init,
125 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
126 "glViewImage", &info, 0);
133 gl_view_image_class_init (glViewImageClass *klass)
135 GObjectClass *object_class = (GObjectClass *) klass;
137 gl_debug (DEBUG_VIEW, "START");
139 parent_class = g_type_class_peek_parent (klass);
141 object_class->finalize = gl_view_image_finalize;
143 gl_debug (DEBUG_VIEW, "END");
147 gl_view_image_instance_init (glViewImage *view_image)
149 gl_debug (DEBUG_VIEW, "START");
151 view_image->private = g_new0 (glViewImagePrivate, 1);
153 gl_debug (DEBUG_VIEW, "END");
157 gl_view_image_finalize (GObject *object)
161 gl_debug (DEBUG_VIEW, "START");
163 g_return_if_fail (object && GL_IS_VIEW_IMAGE (object));
165 G_OBJECT_CLASS (parent_class)->finalize (object);
167 gl_debug (DEBUG_VIEW, "END");
170 /*****************************************************************************/
171 /* NEW image object view. */
172 /*****************************************************************************/
174 gl_view_image_new (glLabelImage *object,
177 glViewImage *view_image;
178 GnomeCanvasItem *group;
179 const GdkPixbuf *pixbuf;
184 gl_debug (DEBUG_VIEW, "START");
185 g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
186 g_return_if_fail (view && GL_IS_VIEW (view));
188 view_image = g_object_new (gl_view_image_get_type(), NULL);
190 gl_view_object_set_view (GL_VIEW_OBJECT(view_image), view);
191 gl_view_object_set_object (GL_VIEW_OBJECT(view_image),
192 GL_LABEL_OBJECT(object),
193 GL_VIEW_HIGHLIGHT_BOX_RESIZABLE);
195 /* Query properties of object. */
196 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
197 pixbuf = gl_label_image_get_pixbuf(object);
199 /* Create analogous canvas item. */
200 group = gl_view_object_get_group (GL_VIEW_OBJECT(view_image));
201 view_image->private->item =
202 gnome_canvas_item_new (GNOME_CANVAS_GROUP(group),
203 gnome_canvas_pixbuf_get_type (),
213 g_signal_connect (G_OBJECT (object), "changed",
214 G_CALLBACK (update_view_image_cb), view_image);
216 /* Create a dialog for controlling/viewing object properties. */
217 dialog = construct_properties_dialog (view_image);
218 gl_view_object_set_dialog (GL_VIEW_OBJECT(view_image), dialog);
220 gl_debug (DEBUG_VIEW, "END");
222 return GL_VIEW_OBJECT (view_image);
225 /*---------------------------------------------------------------------------*/
226 /* PRIVATE. label object "changed" callback. */
227 /*---------------------------------------------------------------------------*/
229 update_view_image_cb (glLabelObject *object,
230 glViewImage *view_image)
232 const GdkPixbuf *pixbuf;
235 gl_debug (DEBUG_VIEW, "START");
237 /* Query properties of object. */
238 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
239 pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE(object));
241 /* Adjust appearance of analogous canvas item. */
242 gnome_canvas_item_set (view_image->private->item,
250 /* Adjust highlight */
251 gl_view_object_update_highlight (GL_VIEW_OBJECT(view_image));
253 gl_debug (DEBUG_VIEW, "END");
256 /*****************************************************************************/
257 /* Create a properties dialog for a image object. */
258 /*****************************************************************************/
260 construct_properties_dialog (glViewImage *view_image)
262 GtkWidget *dialog, *notebook, *wvbox, *wbutton;
263 BonoboWindow *win = glabels_get_active_window ();
264 glLabelObject *object;
265 gdouble x, y, w, h, label_width, label_height;
268 gl_debug (DEBUG_VIEW, "START");
270 /* retrieve object and query parameters */
271 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
272 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
273 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
274 filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
275 gl_label_get_size (GL_LABEL(object->parent),
276 &label_width, &label_height);
278 /*-----------------------------------------------------------------*/
279 /* Build dialog with notebook. */
280 /*-----------------------------------------------------------------*/
281 dialog = gtk_dialog_new_with_buttons ( _("Edit image object properties"),
283 GTK_DIALOG_DESTROY_WITH_PARENT,
287 g_signal_connect (G_OBJECT (dialog), "response",
288 G_CALLBACK (response_cb), view_image);
290 notebook = gtk_notebook_new ();
291 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
292 notebook, TRUE, TRUE, 0);
294 /*---------------------------*/
295 /* Image Notebook Tab */
296 /*---------------------------*/
297 wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
298 gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
299 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
300 gtk_label_new (_("Image")));
303 view_image->private->pixmap_entry =
304 gnome_pixmap_entry_new ("image", "Load image", TRUE);
305 gnome_pixmap_entry_set_preview_size (GNOME_PIXMAP_ENTRY
306 (view_image->private->pixmap_entry),
309 /* Set default path for image entry */
310 if (filename != NULL) {
311 /* Set default path to the directory containing image. */
312 if (image_path != NULL)
314 image_path = g_path_get_dirname (filename);
315 if (image_path != NULL) {
316 image_path = g_strconcat (image_path, "/", NULL);
318 } else if (image_path == NULL) {
319 /* First time, set it to our CWD. */
320 image_path = g_get_current_dir ();
323 gtk_box_pack_start (GTK_BOX (wvbox), view_image->private->pixmap_entry,
325 g_signal_connect ( G_OBJECT(gnome_file_entry_gtk_entry
326 (GNOME_FILE_ENTRY (view_image->private->pixmap_entry))),
327 "changed", G_CALLBACK (file_changed_cb),
331 /*----------------------------*/
332 /* Position/Size Notebook Tab */
333 /*----------------------------*/
334 wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
335 gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
336 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
337 gtk_label_new (_("Position/Size")));
339 /* ------ Position Frame ------ */
340 view_image->private->position = gl_wdgt_position_new (_("Position"));
341 gl_wdgt_position_set_params (GL_WDGT_POSITION (view_image->private->position),
343 label_width, label_height);
344 gtk_box_pack_start (GTK_BOX (wvbox),
345 view_image->private->position,
347 g_signal_connect (G_OBJECT (view_image->private->position),
349 G_CALLBACK(position_changed_cb), view_image);
352 /* ------ Size Frame ------ */
353 view_image->private->size = gl_wdgt_size_new (_("Size"));
354 gl_wdgt_size_set_params (GL_WDGT_SIZE (view_image->private->size),
357 label_width, label_height);
358 gtk_box_pack_start (GTK_BOX (wvbox), view_image->private->size,
360 g_signal_connect (G_OBJECT (view_image->private->size), "changed",
361 G_CALLBACK(size_changed_cb), view_image);
363 /* ------ Size Reset Button ------ */
364 wbutton = gtk_button_new_with_label (_("Reset image size"));
365 gtk_box_pack_start (GTK_BOX (wvbox), wbutton, FALSE, FALSE, 0);
366 g_signal_connect (G_OBJECT (wbutton), "clicked",
367 G_CALLBACK (size_reset_cb), view_image);
370 /*----------------------------*/
371 /* Track object changes. */
372 /*----------------------------*/
373 g_signal_connect (G_OBJECT (object), "changed",
374 G_CALLBACK (update_dialog_cb), view_image);
376 gl_debug (DEBUG_VIEW, "END");
381 /*---------------------------------------------------------------------------*/
382 /* PRIVATE. "Response" callback. */
383 /*---------------------------------------------------------------------------*/
385 response_cb (GtkDialog *dialog,
387 glViewImage *view_image)
389 gl_debug (DEBUG_VIEW, "START");
391 g_return_if_fail(dialog != NULL);
392 g_return_if_fail(GTK_IS_DIALOG(dialog));
395 case GTK_RESPONSE_CLOSE:
396 gtk_widget_hide (GTK_WIDGET(dialog));
399 g_assert_not_reached();
402 gl_debug (DEBUG_VIEW, "END");
405 /*---------------------------------------------------------------------------*/
406 /* PRIVATE. file "changed" callback. */
407 /*---------------------------------------------------------------------------*/
409 file_changed_cb (GtkEntry *pixmap_entry,
410 glViewImage *view_image)
412 glLabelObject *object;
415 gl_debug (DEBUG_VIEW, "START");
417 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
419 filename = gnome_pixmap_entry_get_filename (GNOME_PIXMAP_ENTRY(view_image->private->pixmap_entry));
420 gl_debug (DEBUG_VIEW, "filename = %s", filename);
422 g_signal_handlers_block_by_func (G_OBJECT(object),
423 update_dialog_cb, view_image);
424 gl_label_image_set_filename(GL_LABEL_IMAGE(object), filename);
425 g_signal_handlers_unblock_by_func (G_OBJECT(object),
426 update_dialog_cb, view_image);
430 gl_debug (DEBUG_VIEW, "END");
433 /*---------------------------------------------------------------------------*/
434 /* PRIVATE. position "changed" callback. */
435 /*---------------------------------------------------------------------------*/
437 position_changed_cb (glWdgtPosition *position,
438 glViewImage *view_image)
440 glLabelObject *object;
443 gl_debug (DEBUG_VIEW, "START");
445 gl_wdgt_position_get_position (GL_WDGT_POSITION (position), &x, &y);
447 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
449 g_signal_handlers_block_by_func (G_OBJECT(object),
450 update_dialog_cb, view_image);
451 gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
452 g_signal_handlers_unblock_by_func (G_OBJECT(object),
453 update_dialog_cb, view_image);
455 gl_debug (DEBUG_VIEW, "END");
458 /*---------------------------------------------------------------------------*/
459 /* PRIVATE. size "changed" callback. */
460 /*---------------------------------------------------------------------------*/
462 size_changed_cb (glWdgtSize *size,
463 glViewImage *view_image)
465 glLabelObject *object;
467 gboolean keep_aspect_ratio_flag;
469 gl_debug (DEBUG_VIEW, "START");
471 gl_wdgt_size_get_size (GL_WDGT_SIZE (size),
472 &w, &h, &keep_aspect_ratio_flag);
474 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
476 g_signal_handlers_block_by_func (G_OBJECT(object),
477 update_dialog_cb, view_image);
478 gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
479 g_signal_handlers_unblock_by_func (G_OBJECT(object),
480 update_dialog_cb, view_image);
482 gl_debug (DEBUG_VIEW, "END");
485 /*---------------------------------------------------------------------------*/
486 /* PRIVATE. size "changed" callback. */
487 /*---------------------------------------------------------------------------*/
489 size_reset_cb (GtkButton *button,
490 glViewImage *view_image)
492 glLabelObject *object;
493 gdouble image_w, image_h;
494 const GdkPixbuf *pixbuf;
496 gl_debug (DEBUG_VIEW, "START");
498 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
499 pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE(object));
501 image_w = gdk_pixbuf_get_width (pixbuf);
502 image_h = gdk_pixbuf_get_height (pixbuf);
504 gl_label_object_set_size (GL_LABEL_OBJECT(object), image_w, image_h);
506 gl_debug (DEBUG_VIEW, "END");
509 /*---------------------------------------------------------------------------*/
510 /* PRIVATE. label object "changed" callback. */
511 /*---------------------------------------------------------------------------*/
513 update_dialog_cb (glLabelObject *object,
514 glViewImage *view_image)
519 gl_debug (DEBUG_VIEW, "START");
521 /* Query properties of object. */
522 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
523 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
524 filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
526 /* Block widget handlers to prevent recursion */
527 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->pixmap_entry),
528 file_changed_cb, view_image);
529 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->position),
530 position_changed_cb, view_image);
531 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->size),
532 size_changed_cb, view_image);
534 /* Update widgets in property dialog */
536 if ( filename != NULL ) {
537 gnome_file_entry_set_filename (GNOME_FILE_ENTRY (view_image->private->pixmap_entry),
540 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_image->private->position),
542 gl_wdgt_size_set_size (GL_WDGT_SIZE(view_image->private->size), w, h);
544 /* Unblock widget handlers */
545 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->pixmap_entry),
546 file_changed_cb, view_image);
547 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->position),
548 position_changed_cb, view_image);
549 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->size),
550 size_changed_cb, view_image);
554 gl_debug (DEBUG_VIEW, "END");
557 /*****************************************************************************/
558 /* Return apropos cursor for create object mode. */
559 /*****************************************************************************/
561 gl_view_image_get_create_cursor (void)
563 static GdkCursor *cursor = NULL;
564 GdkPixmap *pixmap_data, *pixmap_mask;
565 GdkColor fg = { 0, 0, 0, 0 };
566 GdkColor bg = { 0, 65535, 65535, 65535 };
568 gl_debug (DEBUG_VIEW, "START");
571 pixmap_data = gdk_bitmap_create_from_data (NULL,
574 cursor_image_height);
575 pixmap_mask = gdk_bitmap_create_from_data (NULL,
576 cursor_image_mask_bits,
577 cursor_image_mask_width,
578 cursor_image_mask_height);
580 gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
581 &bg, cursor_image_x_hot,
585 gl_debug (DEBUG_VIEW, "END");
590 /*****************************************************************************/
591 /* Canvas event handler for creating image objects. */
592 /*****************************************************************************/
594 gl_view_image_create_event_handler (GnomeCanvas *canvas,
598 static gdouble x0, y0;
599 static gboolean dragging = FALSE;
600 static glViewObject *view_image;
601 static GObject *object;
603 guint line_color, fill_color;
606 gl_debug (DEBUG_VIEW, "");
608 switch (event->type) {
610 case GDK_BUTTON_PRESS:
611 switch (event->button.button) {
614 gdk_pointer_grab (GTK_WIDGET (view->canvas)->window,
616 GDK_POINTER_MOTION_MASK |
617 GDK_BUTTON_RELEASE_MASK |
618 GDK_BUTTON_PRESS_MASK,
619 NULL, NULL, event->button.time);
620 gnome_canvas_window_to_world (canvas,
622 event->button.y, &x, &y);
623 object = gl_label_image_new (view->label);
624 gl_label_object_set_position (GL_LABEL_OBJECT(object),
626 gl_label_object_set_size (GL_LABEL_OBJECT(object),
628 view_image = gl_view_image_new (GL_LABEL_IMAGE(object),
638 case GDK_BUTTON_RELEASE:
639 switch (event->button.button) {
642 gdk_pointer_ungrab (event->button.time);
643 gnome_canvas_window_to_world (canvas,
645 event->button.y, &x, &y);
646 if ((x0 == x) && (y0 == y)) {
650 gl_label_object_set_position (GL_LABEL_OBJECT(object),
651 MIN (x, x0), MIN (y, y0));
652 w = MAX (x, x0) - MIN (x, x0);
653 h = MAX (y, y0) - MIN (y, y0);
654 gl_label_object_set_size (GL_LABEL_OBJECT(object),
656 gl_view_unselect_all (view);
657 gl_view_object_select (GL_VIEW_OBJECT(view_image));
658 gl_view_arrow_mode (view);
665 case GDK_MOTION_NOTIFY:
666 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
667 gnome_canvas_window_to_world (canvas,
669 event->button.y, &x, &y);
670 gl_label_object_set_position (GL_LABEL_OBJECT(object),
671 MIN (x, x0), MIN (y, y0));
672 w = MAX (x, x0) - MIN (x, x0);
673 h = MAX (y, y0) - MIN (y, y0);
674 gl_label_object_set_size (GL_LABEL_OBJECT(object),