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"
29 #include "wdgt-line.h"
30 #include "wdgt-fill.h"
31 #include "wdgt-size.h"
32 #include "wdgt-position.h"
34 #include "pixmaps/cursor_image.xbm"
35 #include "pixmaps/cursor_image_mask.xbm"
39 /*========================================================*/
40 /* Private macros and constants. */
41 /*========================================================*/
45 /*========================================================*/
47 /*========================================================*/
49 struct _glViewImagePrivate {
50 GnomeCanvasItem *item;
53 GtkWidget *pixmap_entry;
60 /*========================================================*/
61 /* Private globals. */
62 /*========================================================*/
64 static glViewObjectClass *parent_class = NULL;
66 /* Save state of image file entry */
67 static gchar *image_path = NULL;
70 /*========================================================*/
71 /* Private function prototypes. */
72 /*========================================================*/
74 static void gl_view_image_class_init (glViewImageClass *klass);
75 static void gl_view_image_instance_init (glViewImage *view_image);
76 static void gl_view_image_finalize (GObject *object);
78 static void update_view_image_cb (glLabelObject *object,
79 glViewImage *view_image);
81 static GtkWidget *construct_properties_dialog (glViewObject *view_object);
83 static void response_cb (GtkDialog *dialog,
85 glViewImage *view_image);
87 static void file_changed_cb (GtkEntry *pixmap_entry,
88 glViewImage *view_image);
90 static void position_changed_cb (glWdgtPosition *position,
91 glViewImage *view_image);
93 static void size_changed_cb (glWdgtSize *size,
94 glViewImage *view_image);
96 static void size_reset_cb (GtkButton *button,
97 glViewImage *view_image);
99 static void update_dialog_cb (glLabelObject *object,
100 glViewImage *view_image);
102 static void update_dialog_from_move_cb (glLabelObject *object,
105 glViewImage *view_image);
108 /*****************************************************************************/
109 /* Boilerplate object stuff. */
110 /*****************************************************************************/
112 gl_view_image_get_type (void)
114 static GType type = 0;
118 sizeof (glViewImageClass),
121 (GClassInitFunc) gl_view_image_class_init,
124 sizeof (glViewImage),
126 (GInstanceInitFunc) gl_view_image_instance_init,
129 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
130 "glViewImage", &info, 0);
137 gl_view_image_class_init (glViewImageClass *klass)
139 GObjectClass *object_class = (GObjectClass *) klass;
140 glViewObjectClass *view_object_class = (glViewObjectClass *) klass;
142 gl_debug (DEBUG_VIEW, "START");
144 parent_class = g_type_class_peek_parent (klass);
146 object_class->finalize = gl_view_image_finalize;
148 view_object_class->construct_dialog = construct_properties_dialog;
150 gl_debug (DEBUG_VIEW, "END");
154 gl_view_image_instance_init (glViewImage *view_image)
156 gl_debug (DEBUG_VIEW, "START");
158 view_image->private = g_new0 (glViewImagePrivate, 1);
160 gl_debug (DEBUG_VIEW, "END");
164 gl_view_image_finalize (GObject *object)
168 gl_debug (DEBUG_VIEW, "START");
170 g_return_if_fail (object && GL_IS_VIEW_IMAGE (object));
172 G_OBJECT_CLASS (parent_class)->finalize (object);
174 gl_debug (DEBUG_VIEW, "END");
177 /*****************************************************************************/
178 /* NEW image object view. */
179 /*****************************************************************************/
181 gl_view_image_new (glLabelImage *object,
184 glViewImage *view_image;
185 const GdkPixbuf *pixbuf;
189 gl_debug (DEBUG_VIEW, "START");
190 g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
191 g_return_if_fail (view && GL_IS_VIEW (view));
193 view_image = g_object_new (gl_view_image_get_type(), NULL);
195 gl_view_object_set_view (GL_VIEW_OBJECT(view_image), view);
196 gl_view_object_set_object (GL_VIEW_OBJECT(view_image),
197 GL_LABEL_OBJECT(object),
198 GL_VIEW_HIGHLIGHT_BOX_RESIZABLE);
200 /* Query properties of object. */
201 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
202 pixbuf = gl_label_image_get_pixbuf(object);
204 /* Create analogous canvas item. */
205 view_image->private->item =
206 gl_view_object_item_new (GL_VIEW_OBJECT(view_image),
207 gnome_canvas_pixbuf_get_type (),
217 g_signal_connect (G_OBJECT (object), "changed",
218 G_CALLBACK (update_view_image_cb), view_image);
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 gl_debug (DEBUG_VIEW, "END");
253 /*****************************************************************************/
254 /* Create a properties dialog for a image object. */
255 /*****************************************************************************/
257 construct_properties_dialog (glViewObject *view_object)
259 glViewImage *view_image = (glViewImage *)view_object;
260 GtkWidget *dialog, *wsection, *wbutton;
261 glLabelObject *object;
262 gdouble x, y, w, h, label_width, label_height;
264 GtkSizeGroup *label_size_group;
267 gl_debug (DEBUG_VIEW, "START");
269 /* retrieve object and query parameters */
270 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
271 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
272 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
273 filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
274 gl_label_get_size (GL_LABEL(object->parent),
275 &label_width, &label_height);
277 /*-----------------------------------------------------------------*/
279 /*-----------------------------------------------------------------*/
280 window = gtk_widget_get_toplevel (
281 GTK_WIDGET(gl_view_object_get_view(GL_VIEW_OBJECT(view_image))));
282 dialog = gl_hig_dialog_new_with_buttons ( _("Edit image object properties"),
284 GTK_DIALOG_DESTROY_WITH_PARENT,
288 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
289 g_signal_connect (G_OBJECT (dialog), "response",
290 G_CALLBACK (response_cb), view_image);
292 label_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
294 /*---------------------------*/
296 /*---------------------------*/
297 wsection = gl_hig_category_new (_("Image"));
298 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
299 view_image->private->pixmap_entry =
300 gnome_pixmap_entry_new ("image", "Load image", TRUE);
301 gnome_pixmap_entry_set_preview_size (GNOME_PIXMAP_ENTRY
302 (view_image->private->pixmap_entry),
305 /* Set default path for image entry */
306 if (filename != NULL) {
307 /* Set default path to the directory containing image. */
308 if (image_path != NULL)
310 image_path = g_path_get_dirname (filename);
311 if (image_path != NULL) {
312 image_path = g_strconcat (image_path, "/", NULL);
314 } else if (image_path == NULL) {
315 /* First time, set it to our CWD. */
316 image_path = g_get_current_dir ();
319 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
320 view_image->private->pixmap_entry);
321 g_signal_connect ( G_OBJECT(gnome_file_entry_gtk_entry
322 (GNOME_FILE_ENTRY (view_image->private->pixmap_entry))),
323 "changed", G_CALLBACK (file_changed_cb),
327 /*----------------------------*/
328 /* Position section */
329 /*----------------------------*/
330 wsection = gl_hig_category_new (_("Position"));
331 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
332 view_image->private->position = gl_wdgt_position_new ();
333 gl_wdgt_position_set_label_size_group (GL_WDGT_POSITION(view_image->private->position),
335 gl_wdgt_position_set_params (GL_WDGT_POSITION (view_image->private->position),
336 x, y, label_width, label_height);
337 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
338 view_image->private->position);
339 g_signal_connect (G_OBJECT (view_image->private->position),
341 G_CALLBACK(position_changed_cb), view_image);
344 /*----------------------------*/
346 /*----------------------------*/
347 wsection = gl_hig_category_new (_("Size"));
348 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
349 view_image->private->size = gl_wdgt_size_new ();
350 gl_wdgt_size_set_label_size_group (GL_WDGT_SIZE(view_image->private->size),
352 gl_wdgt_size_set_params (GL_WDGT_SIZE (view_image->private->size),
353 w, h, TRUE, label_width, label_height);
354 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
355 view_image->private->size);
356 g_signal_connect (G_OBJECT (view_image->private->size), "changed",
357 G_CALLBACK(size_changed_cb), view_image);
359 /* ------ Size Reset Button ------ */
360 wbutton = gtk_button_new_with_label (_("Reset image size"));
361 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection), wbutton);
362 g_signal_connect (G_OBJECT (wbutton), "clicked",
363 G_CALLBACK (size_reset_cb), view_image);
366 /*----------------------------*/
367 /* Track object changes. */
368 /*----------------------------*/
369 g_signal_connect (G_OBJECT (object), "changed",
370 G_CALLBACK (update_dialog_cb), view_image);
371 g_signal_connect (G_OBJECT (object), "moved",
372 G_CALLBACK (update_dialog_from_move_cb), view_image);
374 gl_debug (DEBUG_VIEW, "END");
379 /*---------------------------------------------------------------------------*/
380 /* PRIVATE. "Response" callback. */
381 /*---------------------------------------------------------------------------*/
383 response_cb (GtkDialog *dialog,
385 glViewImage *view_image)
387 gl_debug (DEBUG_VIEW, "START");
389 g_return_if_fail(dialog != NULL);
390 g_return_if_fail(GTK_IS_DIALOG(dialog));
393 case GTK_RESPONSE_CLOSE:
394 gtk_widget_hide (GTK_WIDGET(dialog));
396 case GTK_RESPONSE_DELETE_EVENT:
399 g_print ("response = %d", response);
400 g_assert_not_reached();
403 gl_debug (DEBUG_VIEW, "END");
406 /*---------------------------------------------------------------------------*/
407 /* PRIVATE. file "changed" callback. */
408 /*---------------------------------------------------------------------------*/
410 file_changed_cb (GtkEntry *pixmap_entry,
411 glViewImage *view_image)
413 glLabelObject *object;
416 gl_debug (DEBUG_VIEW, "START");
418 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
420 filename = gnome_pixmap_entry_get_filename (GNOME_PIXMAP_ENTRY(view_image->private->pixmap_entry));
421 gl_debug (DEBUG_VIEW, "filename = %s", filename);
423 g_signal_handlers_block_by_func (G_OBJECT(object),
424 update_dialog_cb, view_image);
425 gl_label_image_set_filename(GL_LABEL_IMAGE(object), filename);
426 g_signal_handlers_unblock_by_func (G_OBJECT(object),
427 update_dialog_cb, view_image);
431 gl_debug (DEBUG_VIEW, "END");
434 /*---------------------------------------------------------------------------*/
435 /* PRIVATE. position "changed" callback. */
436 /*---------------------------------------------------------------------------*/
438 position_changed_cb (glWdgtPosition *position,
439 glViewImage *view_image)
441 glLabelObject *object;
444 gl_debug (DEBUG_VIEW, "START");
446 gl_wdgt_position_get_position (GL_WDGT_POSITION (position), &x, &y);
448 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
450 g_signal_handlers_block_by_func (G_OBJECT(object),
451 update_dialog_cb, view_image);
452 gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
453 g_signal_handlers_unblock_by_func (G_OBJECT(object),
454 update_dialog_cb, view_image);
456 gl_debug (DEBUG_VIEW, "END");
459 /*---------------------------------------------------------------------------*/
460 /* PRIVATE. size "changed" callback. */
461 /*---------------------------------------------------------------------------*/
463 size_changed_cb (glWdgtSize *size,
464 glViewImage *view_image)
466 glLabelObject *object;
468 gboolean keep_aspect_ratio_flag;
470 gl_debug (DEBUG_VIEW, "START");
472 gl_wdgt_size_get_size (GL_WDGT_SIZE (size),
473 &w, &h, &keep_aspect_ratio_flag);
475 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
477 g_signal_handlers_block_by_func (G_OBJECT(object),
478 update_dialog_cb, view_image);
479 gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
480 g_signal_handlers_unblock_by_func (G_OBJECT(object),
481 update_dialog_cb, view_image);
483 gl_debug (DEBUG_VIEW, "END");
486 /*---------------------------------------------------------------------------*/
487 /* PRIVATE. size "changed" callback. */
488 /*---------------------------------------------------------------------------*/
490 size_reset_cb (GtkButton *button,
491 glViewImage *view_image)
493 glLabelObject *object;
494 gdouble image_w, image_h;
495 const GdkPixbuf *pixbuf;
497 gl_debug (DEBUG_VIEW, "START");
499 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_image));
500 pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE(object));
502 image_w = gdk_pixbuf_get_width (pixbuf);
503 image_h = gdk_pixbuf_get_height (pixbuf);
505 gl_label_object_set_size (GL_LABEL_OBJECT(object), image_w, image_h);
507 gl_debug (DEBUG_VIEW, "END");
510 /*---------------------------------------------------------------------------*/
511 /* PRIVATE. label object "changed" callback. */
512 /*---------------------------------------------------------------------------*/
514 update_dialog_cb (glLabelObject *object,
515 glViewImage *view_image)
520 gl_debug (DEBUG_VIEW, "START");
522 /* Query properties of object. */
523 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
524 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
525 filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
527 /* Block widget handlers to prevent recursion */
528 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->pixmap_entry),
529 file_changed_cb, view_image);
530 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->position),
531 position_changed_cb, view_image);
532 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->size),
533 size_changed_cb, view_image);
535 /* Update widgets in property dialog */
537 if ( filename != NULL ) {
538 gnome_file_entry_set_filename (GNOME_FILE_ENTRY (view_image->private->pixmap_entry),
541 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_image->private->position),
543 gl_wdgt_size_set_size (GL_WDGT_SIZE(view_image->private->size), w, h);
545 /* Unblock widget handlers */
546 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->pixmap_entry),
547 file_changed_cb, view_image);
548 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->position),
549 position_changed_cb, view_image);
550 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->size),
551 size_changed_cb, view_image);
555 gl_debug (DEBUG_VIEW, "END");
558 /*---------------------------------------------------------------------------*/
559 /* PRIVATE. label object "moved" callback. */
560 /*---------------------------------------------------------------------------*/
562 update_dialog_from_move_cb (glLabelObject *object,
565 glViewImage *view_image)
569 gl_debug (DEBUG_VIEW, "START");
571 /* Query properties of object. */
572 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
574 /* Block widget handlers to prevent recursion */
575 g_signal_handlers_block_by_func (G_OBJECT(view_image->private->position),
576 position_changed_cb, view_image);
578 /* Update widgets in property dialog */
579 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_image->private->position),
582 /* Unblock widget handlers */
583 g_signal_handlers_unblock_by_func (G_OBJECT(view_image->private->position),
584 position_changed_cb, view_image);
586 gl_debug (DEBUG_VIEW, "END");
589 /*****************************************************************************/
590 /* Return apropos cursor for create object mode. */
591 /*****************************************************************************/
593 gl_view_image_get_create_cursor (void)
595 static GdkCursor *cursor = NULL;
596 GdkPixmap *pixmap_data, *pixmap_mask;
597 GdkColor fg = { 0, 0, 0, 0 };
598 GdkColor bg = { 0, 65535, 65535, 65535 };
600 gl_debug (DEBUG_VIEW, "START");
603 pixmap_data = gdk_bitmap_create_from_data (NULL,
606 cursor_image_height);
607 pixmap_mask = gdk_bitmap_create_from_data (NULL,
608 cursor_image_mask_bits,
609 cursor_image_mask_width,
610 cursor_image_mask_height);
612 gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
613 &bg, cursor_image_x_hot,
617 gl_debug (DEBUG_VIEW, "END");
622 /*****************************************************************************/
623 /* Canvas event handler for creating image objects. */
624 /*****************************************************************************/
626 gl_view_image_create_event_handler (GnomeCanvas *canvas,
630 static gdouble x0, y0;
631 static gboolean dragging = FALSE;
632 static glViewObject *view_image;
633 static GObject *object;
635 guint line_color, fill_color;
638 gl_debug (DEBUG_VIEW, "");
640 switch (event->type) {
642 case GDK_BUTTON_PRESS:
643 switch (event->button.button) {
646 gnome_canvas_item_grab (canvas->root,
647 GDK_POINTER_MOTION_MASK |
648 GDK_BUTTON_RELEASE_MASK |
649 GDK_BUTTON_PRESS_MASK,
650 NULL, event->button.time);
651 gnome_canvas_window_to_world (canvas,
653 event->button.y, &x, &y);
654 object = gl_label_image_new (view->label);
655 gl_label_object_set_position (GL_LABEL_OBJECT(object),
657 gl_label_object_set_size (GL_LABEL_OBJECT(object),
659 view_image = gl_view_image_new (GL_LABEL_IMAGE(object),
669 case GDK_BUTTON_RELEASE:
670 switch (event->button.button) {
673 gnome_canvas_item_ungrab (canvas->root, event->button.time);
674 gnome_canvas_window_to_world (canvas,
676 event->button.y, &x, &y);
677 if ((x0 == x) && (y0 == y)) {
681 gl_label_object_set_position (GL_LABEL_OBJECT(object),
682 MIN (x, x0), MIN (y, y0));
683 w = MAX (x, x0) - MIN (x, x0);
684 h = MAX (y, y0) - MIN (y, y0);
685 gl_label_object_set_size (GL_LABEL_OBJECT(object),
687 gl_view_unselect_all (view);
688 gl_view_object_select (GL_VIEW_OBJECT(view_image));
689 gl_view_arrow_mode (view);
696 case GDK_MOTION_NOTIFY:
697 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
698 gnome_canvas_window_to_world (canvas,
700 event->motion.y, &x, &y);
701 gl_label_object_set_position (GL_LABEL_OBJECT(object),
702 MIN (x, x0), MIN (y, y0));
703 w = MAX (x, x0) - MIN (x, x0);
704 h = MAX (y, y0) - MIN (y, y0);
705 gl_label_object_set_size (GL_LABEL_OBJECT(object),