home *** CD-ROM | disk | FTP | other *** search
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- #include "config.h"
-
- #include <gtk/gtk.h>
-
- #include "apptypes.h"
-
- #include "appenv.h"
- #include "dialog_handler.h"
- #include "gimage.h"
- #include "gimpcontext.h"
- #include "gimppreviewcache.h"
- #include "gimprc.h"
- #include "gimpset.h"
- #include "gimpui.h"
- #include "image_render.h"
- #include "lc_dialog.h"
- #include "lc_dialogP.h"
- #include "layers_dialogP.h"
- #include "session.h"
-
- #include "libgimp/gimpintl.h"
- #include "libgimp/gimplimits.h"
- #include "libgimp/gimpmath.h"
-
-
- #define MENU_THUMBNAIL_SIZE 24
-
-
- /* local function prototypes */
- static void lc_dialog_update (GimpImage *gimage);
- static void lc_dialog_image_menu_callback (GtkWidget *widget,
- gpointer data);
- static void lc_dialog_auto_callback (GtkWidget *widget,
- gpointer data);
- static gint lc_dialog_close_callback (GtkWidget *widget,
- gpointer data);
- static void lc_dialog_add_callback (GimpSet *set,
- GimpImage *gimage,
- gpointer data);
- static void lc_dialog_remove_callback (GimpSet *set,
- GimpImage *gimage,
- gpointer data);
- static void lc_dialog_change_image (GimpContext *context,
- GimpImage *gimage,
- gpointer data);
- static void lc_dialog_help_func (const gchar *help_data);
-
- static void lc_dialog_image_menu_preview_update_callback (GtkWidget *widget,
- gpointer data);
- static void lc_dialog_fill_preview_with_thumb (GtkWidget *widget,
- GimpImage *gimage,
- gint width,
- gint height);
-
-
- /* FIXME: move these to a better place */
- static GtkWidget * lc_dialog_create_image_menu (GimpImage **def,
- gint *default_index,
- GtkSignalFunc callback);
- static void lc_dialog_create_image_menu_callback (gpointer image,
- gpointer data);
-
-
- /* the main dialog structure */
- LCDialog * lc_dialog = NULL;
-
-
- /*********************************/
- /* Public L&C dialog functions */
- /*********************************/
-
- void
- lc_dialog_create (GimpImage *gimage)
- {
- GtkWidget *util_box;
- GtkWidget *auto_button;
- GtkWidget *button;
- GtkWidget *label;
- GtkWidget *separator;
- gint default_index;
-
- if (lc_dialog)
- {
- if (! GTK_WIDGET_VISIBLE (lc_dialog->shell))
- {
- gtk_widget_show (lc_dialog->shell);
- }
- else
- {
- gdk_window_raise (lc_dialog->shell->window);
- }
-
- if (gimage)
- lc_dialog_update (gimage);
-
- lc_dialog_update_image_list ();
-
- return;
- }
-
- lc_dialog = g_new (LCDialog, 1);
- lc_dialog->shell =
- gimp_dialog_new (_("Layers, Channels & Paths"), "layers_channels_paths",
- lc_dialog_help_func,
- "dialogs/layers_and_channels.html",
- GTK_WIN_POS_NONE,
- FALSE, TRUE, FALSE,
- NULL);
- lc_dialog->gimage = NULL;
- lc_dialog->auto_follow_active = TRUE;
-
- /* Register the dialog */
- dialog_register (lc_dialog->shell);
- session_set_window_geometry (lc_dialog->shell, &lc_dialog_session_info, TRUE);
-
- /* Handle the WM delete event */
- gtk_signal_connect (GTK_OBJECT (lc_dialog->shell), "delete_event",
- GTK_SIGNAL_FUNC (lc_dialog_close_callback), NULL);
-
- /* The toplevel vbox */
- lc_dialog->subshell = gtk_vbox_new (FALSE, 1);
- gtk_container_add (GTK_CONTAINER (GTK_DIALOG (lc_dialog->shell)->vbox),
- lc_dialog->subshell);
-
- /* The hbox to hold the image option menu box */
- util_box = gtk_hbox_new (FALSE, 2);
- gtk_container_set_border_width (GTK_CONTAINER (util_box), 2);
- gtk_box_pack_start (GTK_BOX (lc_dialog->subshell), util_box, FALSE, FALSE, 0);
-
- /* The GIMP image option menu */
- label = gtk_label_new (_("Image:"));
- gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2);
- gtk_widget_show (label);
-
- lc_dialog->image_option_menu = gtk_option_menu_new ();
- lc_dialog->image_menu =
- lc_dialog_create_image_menu (&gimage, &default_index,
- lc_dialog_image_menu_callback);
- gtk_box_pack_start (GTK_BOX (util_box), lc_dialog->image_option_menu,
- TRUE, TRUE, 0);
- gimp_help_set_help_data (lc_dialog->image_option_menu, NULL, "#image_menu");
- gtk_widget_show (lc_dialog->image_option_menu);
-
- gtk_option_menu_set_menu (GTK_OPTION_MENU (lc_dialog->image_option_menu),
- lc_dialog->image_menu);
- if (default_index != -1)
- gtk_option_menu_set_history
- (GTK_OPTION_MENU (lc_dialog->image_option_menu), default_index);
-
- /* The Auto-button */
- auto_button = gtk_toggle_button_new_with_label (_("Auto"));
- gtk_box_pack_start (GTK_BOX (util_box), auto_button, FALSE, FALSE, 0);
- gtk_signal_connect (GTK_OBJECT (auto_button), "clicked",
- (GtkSignalFunc) lc_dialog_auto_callback,
- auto_button);
- gimp_help_set_help_data (auto_button, NULL, "#auto_button");
- gtk_widget_show (auto_button);
- /* State will be set when the sub-dialogs exists (see below) */
-
- gtk_widget_show (util_box);
-
- separator = gtk_hseparator_new ();
- gtk_box_pack_start (GTK_BOX (lc_dialog->subshell), separator,
- FALSE, FALSE, 0);
- gtk_widget_show (separator);
-
- /* The notebook widget */
- lc_dialog->notebook = gtk_notebook_new ();
- gtk_container_set_border_width (GTK_CONTAINER (lc_dialog->notebook), 2);
- gtk_box_pack_start (GTK_BOX (lc_dialog->subshell), lc_dialog->notebook,
- TRUE, TRUE, 0);
-
- label = gtk_label_new (_("Layers"));
- gtk_notebook_append_page (GTK_NOTEBOOK (lc_dialog->notebook),
- layers_dialog_create (), label);
- gtk_widget_show (label);
-
- label = gtk_label_new (_("Channels"));
- gtk_notebook_append_page (GTK_NOTEBOOK (lc_dialog->notebook),
- channels_dialog_create (), label);
- gtk_widget_show (label);
-
- label = gtk_label_new (_("Paths"));
- gtk_notebook_append_page (GTK_NOTEBOOK (lc_dialog->notebook),
- paths_dialog_create (), label);
- gtk_widget_show (label);
-
- /* Now all notebook pages exist, we can set the Auto-togglebutton */
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (auto_button),
- lc_dialog->auto_follow_active);
-
- gtk_widget_show (lc_dialog->notebook);
-
- /* The action area */
- gtk_container_set_border_width
- (GTK_CONTAINER (GTK_DIALOG (lc_dialog->shell)->action_area), 1);
-
- /* The close button */
- button = gtk_button_new_with_label (_("Close"));
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (lc_dialog->shell)->action_area),
- button, TRUE, TRUE, 0);
- gtk_signal_connect (GTK_OBJECT (button), "clicked",
- (GtkSignalFunc) lc_dialog_close_callback,
- lc_dialog->shell);
- gtk_widget_show (button);
-
- /* Make sure the channels page is realized */
- gtk_notebook_set_page (GTK_NOTEBOOK (lc_dialog->notebook), 1);
- gtk_notebook_set_page (GTK_NOTEBOOK (lc_dialog->notebook), 0);
-
- gtk_signal_connect (GTK_OBJECT (image_context), "add",
- GTK_SIGNAL_FUNC (lc_dialog_add_callback), NULL);
- gtk_signal_connect (GTK_OBJECT (image_context), "remove",
- GTK_SIGNAL_FUNC (lc_dialog_remove_callback), NULL);
- gtk_signal_connect (GTK_OBJECT (gimp_context_get_user ()), "image_changed",
- GTK_SIGNAL_FUNC (lc_dialog_change_image), NULL);
-
- lc_dialog_update (gimage);
- lc_dialog_update_image_list ();
-
- gtk_widget_show (lc_dialog->subshell);
- gtk_widget_show (lc_dialog->shell);
-
- gdisplays_flush ();
- }
-
- void
- lc_dialog_free (void)
- {
- if (lc_dialog == NULL)
- return;
-
- session_get_window_info (lc_dialog->shell, &lc_dialog_session_info);
-
- layers_dialog_free ();
- channels_dialog_free ();
-
- gtk_widget_destroy (lc_dialog->shell);
-
- g_free (lc_dialog);
- lc_dialog = NULL;
- }
-
- void
- lc_dialog_rebuild (gint new_preview_size)
- {
- GimpImage *gimage;
- gboolean flag;
-
- gimage = NULL;
- flag = FALSE;
-
- if (lc_dialog)
- {
- flag = TRUE;
- gimage = lc_dialog->gimage;
- /* Unregister the dialog */
- dialog_unregister (lc_dialog->shell);
- lc_dialog_free ();
- }
-
- preview_size = new_preview_size;
- render_setup (transparency_type, transparency_size);
-
- if (flag)
- lc_dialog_create (gimage);
- }
-
- void
- lc_dialog_flush (void)
- {
- if (! lc_dialog || lc_dialog->gimage == NULL)
- return;
-
- layers_dialog_flush ();
- channels_dialog_flush ();
- paths_dialog_flush ();
- }
-
- static gint
- image_menu_preview_update_do (GimpImage *gimage)
- {
- if (lc_dialog)
- {
- gtk_container_foreach (GTK_CONTAINER (lc_dialog->image_menu),
- lc_dialog_image_menu_preview_update_callback,
- (gpointer) gimage);
- }
- return FALSE;
- }
-
- void
- lc_dialog_menu_preview_dirty (GtkObject *obj,
- gpointer data)
- {
- if (!preview_size)
- return;
-
- /* Update preview at a less busy time */
- gtk_idle_add ((GtkFunction) image_menu_preview_update_do, obj);
- }
-
- void
- lc_dialog_preview_update (GimpImage *gimage)
- {
- if (!preview_size)
- return;
-
- layers_dialog_invalidate_previews (gimage);
- gtk_idle_add ((GtkFunction) image_menu_preview_update_do, gimage);
- }
-
- static void
- lc_dialog_image_menu_preview_update_callback (GtkWidget *widget,
- gpointer data)
- {
- GtkWidget *menu_preview;
- GimpImage *gimage;
- GimpImage *gimage_to_update;
-
- gimage_to_update = (GimpImage *) data;
-
- /* This is called via an idle function, so it is possible
- * that the client_data no longer points to a GimpImage.. So don't
- * pass it to the GIMP_IMAGE() cast function. We never deference
- * it here anyways.
- */
-
- menu_preview = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (widget),
- "menu_preview");
- gimage = (GimpImage *) gtk_object_get_data (GTK_OBJECT (widget),
- "menu_preview_gimage");
-
- if (menu_preview && gimage && gimage_to_update == gimage)
- {
- /* Must update the preview? */
- lc_dialog_fill_preview_with_thumb (menu_preview,
- gimage,
- MENU_THUMBNAIL_SIZE,
- MENU_THUMBNAIL_SIZE);
- gtk_widget_queue_draw (GTK_WIDGET (menu_preview));
- }
- }
-
- void
- lc_dialog_update_image_list (void)
- {
- GimpImage *default_gimage;
- gint default_index;
-
- if (lc_dialog == NULL)
- return;
-
- default_gimage = lc_dialog->gimage;
- lc_dialog->image_menu =
- lc_dialog_create_image_menu (&default_gimage, &default_index,
- lc_dialog_image_menu_callback);
- gtk_option_menu_set_menu (GTK_OPTION_MENU (lc_dialog->image_option_menu),
- lc_dialog->image_menu);
-
- if (default_index != -1)
- {
- gtk_option_menu_set_history
- (GTK_OPTION_MENU (lc_dialog->image_option_menu), default_index);
-
- lc_dialog_update (default_gimage);
- gdisplays_flush ();
-
- if (! GTK_WIDGET_IS_SENSITIVE (lc_dialog->subshell))
- gtk_widget_set_sensitive (lc_dialog->subshell, TRUE);
- }
- else
- {
- layers_dialog_clear ();
- channels_dialog_clear ();
-
- lc_dialog->gimage = NULL;
-
- if (GTK_WIDGET_IS_SENSITIVE (lc_dialog->subshell))
- gtk_widget_set_sensitive (lc_dialog->subshell, FALSE);
- }
- }
-
- /**********************************/
- /* Private L&C dialog functions */
- /**********************************/
-
- static void
- lc_dialog_update (GimpImage *gimage)
- {
- if (! lc_dialog || lc_dialog->gimage == gimage)
- return;
-
- lc_dialog->gimage = gimage;
-
- layers_dialog_update (gimage);
- channels_dialog_update (gimage);
- paths_dialog_update (gimage);
- }
-
- typedef struct
- {
- GImage **def;
- gint *default_index;
- GtkSignalFunc callback;
- GtkWidget *menu;
- gint num_items;
- GImage *id;
- } IMCBData;
-
- static void
- lc_dialog_fill_preview_with_thumb (GtkWidget *widget,
- GimpImage *gimage,
- gint width,
- gint height)
- {
- guchar *drawable_data;
- TempBuf *buf;
- gint bpp;
- gint x, y;
- guchar *src;
- gdouble r, g, b, a;
- gdouble c0, c1;
- guchar *p0, *p1, *even, *odd;
- gdouble ratio;
-
- bpp = 0; /* Only returned */
-
- /* Get right aspect ratio */
- if (gimage->width > gimage->height)
- {
- ratio = (gdouble) width / (gdouble) gimage->width;
- }
- else
- {
- ratio = (gdouble) height / (gdouble) gimage->height;
- }
-
- width = RINT (ratio * (gdouble) gimage->width);
- height = RINT (ratio * (gdouble) gimage->height);
-
- if (width < 1) width = 1;
- if (height < 1) height = 1;
-
- if (ratio > 1.0) /* Preview is scaling up! */
- {
- TempBuf *tmp;
-
- tmp = gimp_image_construct_composite_preview (gimage,
- gimage->width,
- gimage->height);
- buf = gimp_preview_scale (tmp, width, height);
- temp_buf_free (tmp);
- }
- else
- {
- buf = gimp_image_construct_composite_preview (gimage,
- width,
- height);
- }
-
- gtk_preview_size (GTK_PREVIEW (widget), width, height);
- drawable_data = temp_buf_data (buf);
- bpp = buf->bytes;
-
- /* Draw the thumbnail with checks */
- src = drawable_data;
-
- even = g_malloc (width * 3);
- odd = g_malloc (width * 3);
-
- for (y = 0; y < height; y++)
- {
- p0 = even;
- p1 = odd;
-
- for (x = 0; x < width; x++)
- {
- if (bpp == 4)
- {
- r = ((gdouble) src[x * 4 + 0]) / 255.0;
- g = ((gdouble) src[x * 4 + 1]) / 255.0;
- b = ((gdouble) src[x * 4 + 2]) / 255.0;
- a = ((gdouble) src[x * 4 + 3]) / 255.0;
- }
- else
- {
- r = ((gdouble) src[x * bpp + 0]) / 255.0;
- g = b = r;
- a = ((gdouble) src[x * bpp + 1]) / 255.0;
- }
-
- if ((x / GIMP_CHECK_SIZE_SM) & 1)
- {
- c0 = GIMP_CHECK_LIGHT;
- c1 = GIMP_CHECK_DARK;
- }
- else
- {
- c0 = GIMP_CHECK_DARK;
- c1 = GIMP_CHECK_LIGHT;
- }
-
- *p0++ = (c0 + (r - c0) * a) * 255.0;
- *p0++ = (c0 + (g - c0) * a) * 255.0;
- *p0++ = (c0 + (b - c0) * a) * 255.0;
-
- *p1++ = (c1 + (r - c1) * a) * 255.0;
- *p1++ = (c1 + (g - c1) * a) * 255.0;
- *p1++ = (c1 + (b - c1) * a) * 255.0;
- }
-
- if ((y / GIMP_CHECK_SIZE_SM) & 1)
- {
- gtk_preview_draw_row (GTK_PREVIEW (widget),
- (guchar *) odd, 0, y, width);
- }
- else
- {
- gtk_preview_draw_row (GTK_PREVIEW (widget),
- (guchar *) even, 0, y, width);
- }
-
- src += width * bpp;
- }
-
- g_free (even);
- g_free (odd);
- temp_buf_free (buf);
- }
-
- static void
- lc_dialog_create_image_menu_callback (gpointer im,
- gpointer d)
- {
- GimpImage *gimage = GIMP_IMAGE (im);
- IMCBData *data = (IMCBData *) d;
- gchar *image_name;
- gchar *menu_item_label;
- GtkWidget *menu_item;
- GtkWidget *hbox;
- GtkWidget *vbox;
- GtkWidget *wcolor_box;
- GtkWidget *wlabel;
-
- /* make sure the default index gets set to _something_, if possible */
- if (*data->default_index == -1)
- {
- data->id = gimage;
- *data->default_index = data->num_items;
- }
-
- if (gimage == *data->def)
- {
- data->id = *data->def;
- *data->default_index = data->num_items;
- }
-
- image_name = g_basename (gimage_filename (gimage));
- menu_item_label =
- g_strdup_printf ("%s-%d", image_name, pdb_image_to_id (gimage));
- menu_item = gtk_menu_item_new();
- gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
- data->callback,
- gimage);
- hbox = gtk_hbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (menu_item), hbox);
- gtk_widget_show (hbox);
-
- if (preview_size)
- {
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
- gtk_widget_show (vbox);
-
- wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
- gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
- gtk_widget_set_usize (GTK_WIDGET (wcolor_box),
- MENU_THUMBNAIL_SIZE, MENU_THUMBNAIL_SIZE);
-
- lc_dialog_fill_preview_with_thumb (wcolor_box,
- gimage,
- MENU_THUMBNAIL_SIZE,
- MENU_THUMBNAIL_SIZE);
-
- gtk_container_add (GTK_CONTAINER (vbox), wcolor_box);
- gtk_widget_show (wcolor_box);
-
- if (gtk_object_get_data (GTK_OBJECT (gimage),
- "menu_preview_dirty") == NULL)
- {
- /* Only add this signal once */
- gtk_object_set_data (GTK_OBJECT (gimage), "menu_preview_dirty",
- (gpointer) 1);
- gtk_signal_connect_after (GTK_OBJECT (gimage), "dirty",
- GTK_SIGNAL_FUNC (lc_dialog_menu_preview_dirty),
- NULL);
- }
- gtk_object_set_data (GTK_OBJECT (menu_item), "menu_preview",
- wcolor_box);
- gtk_object_set_data (GTK_OBJECT (menu_item), "menu_preview_gimage",
- gimage);
- }
-
- gtk_container_add (GTK_CONTAINER (data->menu), menu_item);
-
- wlabel = gtk_label_new (menu_item_label);
- gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), wlabel, TRUE, TRUE, 4);
- gtk_widget_show (wlabel);
-
- gtk_widget_show (menu_item);
-
- g_free (menu_item_label);
- data->num_items++;
- }
-
- static GtkWidget *
- lc_dialog_create_image_menu (GimpImage **def,
- gint *default_index,
- GtkSignalFunc callback)
- {
- IMCBData data;
-
- data.def = def;
- data.default_index = default_index;
- data.callback = callback;
- data.menu = gtk_menu_new ();
- data.num_items = 0;
- data.id = NULL;
-
- *default_index = -1;
-
- gimage_foreach (lc_dialog_create_image_menu_callback, &data);
-
- if (! data.num_items)
- {
- GtkWidget *menu_item;
-
- menu_item = gtk_menu_item_new_with_label (_("none"));
- gtk_container_add (GTK_CONTAINER (data.menu), menu_item);
- gtk_widget_show (menu_item);
- }
-
- *def = data.id;
-
- return data.menu;
- }
-
- static void
- lc_dialog_image_menu_callback (GtkWidget *widget,
- gpointer data)
- {
- if (! lc_dialog)
- return;
-
- lc_dialog_update (GIMP_IMAGE (data));
- gdisplays_flush ();
- }
-
- static void
- lc_dialog_auto_callback (GtkWidget *widget,
- gpointer data)
- {
- GimpContext *context;
-
- if (! lc_dialog)
- return;
-
- lc_dialog->auto_follow_active =
- gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- context = gimp_context_get_user ();
-
- if (lc_dialog->auto_follow_active)
- lc_dialog_change_image (context,
- gimp_context_get_image (context),
- NULL);
- }
-
- static gint
- lc_dialog_close_callback (GtkWidget *widget,
- gpointer data)
- {
- if (! lc_dialog)
- return TRUE;
-
- lc_dialog->gimage = NULL;
- gtk_widget_hide (lc_dialog->shell);
-
- return TRUE;
- }
-
- static void
- lc_dialog_add_callback (GimpSet *set,
- GimpImage *gimage,
- gpointer data)
- {
- if (! lc_dialog)
- return;
-
- lc_dialog_update_image_list ();
- }
-
- static void
- lc_dialog_remove_callback (GimpSet *set,
- GimpImage *gimage,
- gpointer data)
- {
- if (! lc_dialog)
- return;
-
- lc_dialog_update_image_list ();
- }
-
- static void
- lc_dialog_change_image (GimpContext *context,
- GimpImage *gimage,
- gpointer data)
- {
- if (! lc_dialog || ! lc_dialog->auto_follow_active)
- return;
-
- if (gimage && gimp_set_have (image_context, gimage))
- {
- lc_dialog_update (gimage);
- lc_dialog_update_image_list ();
- }
- }
-
- static void
- lc_dialog_help_func (const gchar *help_data)
- {
- gchar *help_page;
- gint page_num;
-
- static gchar* dialog_names[] = { "layers", "channels", "paths" };
-
- page_num =
- gtk_notebook_get_current_page (GTK_NOTEBOOK (lc_dialog->notebook));
-
- if (page_num > 2)
- return;
-
- help_page = g_strconcat (dialog_names[page_num], "/",
- "dialogs/",
- dialog_names[page_num], ".html",
- NULL);
- gimp_standard_help_func (help_page);
- g_free (help_page);
- }
-