gimp/app/channels_dialog.c
Lauri Alanko faeaa7cc23 Removed most of the image id system. They're still used with pdb.
At quick glance, nothing seems to be broken, but if things weird
	out, blame me.

	Now just the same for layers, channels and displays...
1998-06-29 00:24:44 +00:00

2034 lines
58 KiB
C

/* 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 <stdio.h>
#include <stdlib.h>
#include "gdk/gdkkeysyms.h"
#include "appenv.h"
#include "actionarea.h"
#include "buildmenu.h"
#include "channels_dialog.h"
#include "colormaps.h"
#include "color_panel.h"
#include "drawable.h"
#include "errors.h"
#include "gdisplay.h"
#include "gimage.h"
#include "gimage_mask.h"
#include "gimprc.h"
#include "general.h"
#include "interface.h"
#include "layers_dialogP.h"
#include "ops_buttons.h"
#include "paint_funcs.h"
#include "palette.h"
#include "resize.h"
#include "tools/eye.xbm"
#include "tools/channel.xbm"
#include "tools/new.xpm"
#include "tools/new_is.xpm"
#include "tools/raise.xpm"
#include "tools/raise_is.xpm"
#include "tools/lower.xpm"
#include "tools/lower_is.xpm"
#include "tools/duplicate.xpm"
#include "tools/duplicate_is.xpm"
#include "tools/delete.xpm"
#include "tools/delete_is.xpm"
#include "channel_pvt.h"
#define PREVIEW_EVENT_MASK GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK
#define BUTTON_EVENT_MASK GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | \
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
#define CHANNEL_LIST_WIDTH 200
#define CHANNEL_LIST_HEIGHT 150
#define NORMAL 0
#define SELECTED 1
#define INSENSITIVE 2
#define COMPONENT_BASE_ID 0x10000000
typedef struct _ChannelWidget ChannelWidget;
struct _ChannelWidget {
GtkWidget *eye_widget;
GtkWidget *clip_widget;
GtkWidget *channel_preview;
GtkWidget *list_item;
GtkWidget *label;
GImage *gimage;
Channel *channel;
GdkPixmap *channel_pixmap;
ChannelType type;
int ID;
int width, height;
int visited;
};
typedef struct _ChannelsDialog ChannelsDialog;
struct _ChannelsDialog {
GtkWidget *vbox;
GtkWidget *channel_list;
GtkWidget *preview;
GtkWidget *ops_menu;
GtkAccelGroup *accel_group;
int num_components;
int base_type;
ChannelType components[3];
double ratio;
int image_width, image_height;
int gimage_width, gimage_height;
/* state information */
GimpImage* gimage;
Channel * active_channel;
Layer *floating_sel;
GSList *channel_widgets;
};
/* channels dialog widget routines */
static void channels_dialog_preview_extents (void);
static void channels_dialog_set_menu_sensitivity (void);
static void channels_dialog_set_channel (ChannelWidget *);
static void channels_dialog_unset_channel (ChannelWidget *);
static void channels_dialog_position_channel (ChannelWidget *, int);
static void channels_dialog_add_channel (Channel *);
static void channels_dialog_remove_channel (ChannelWidget *);
static gint channel_list_events (GtkWidget *, GdkEvent *);
/* channels dialog menu callbacks */
static void channels_dialog_map_callback (GtkWidget *, gpointer);
static void channels_dialog_unmap_callback (GtkWidget *, gpointer);
static void channels_dialog_new_channel_callback (GtkWidget *, gpointer);
static void channels_dialog_raise_channel_callback (GtkWidget *, gpointer);
static void channels_dialog_lower_channel_callback (GtkWidget *, gpointer);
static void channels_dialog_duplicate_channel_callback (GtkWidget *, gpointer);
static void channels_dialog_delete_channel_callback (GtkWidget *, gpointer);
static void channels_dialog_channel_to_sel_callback (GtkWidget *, gpointer);
/* channel widget function prototypes */
static ChannelWidget *channel_widget_get_ID (Channel *);
static ChannelWidget *create_channel_widget (GImage *, Channel *, ChannelType);
static void channel_widget_delete (ChannelWidget *);
static void channel_widget_select_update (GtkWidget *, gpointer);
static gint channel_widget_button_events (GtkWidget *, GdkEvent *);
static gint channel_widget_preview_events (GtkWidget *, GdkEvent *);
static void channel_widget_preview_redraw (ChannelWidget *);
static void channel_widget_no_preview_redraw (ChannelWidget *);
static void channel_widget_eye_redraw (ChannelWidget *);
static void channel_widget_exclusive_visible (ChannelWidget *);
static void channel_widget_channel_flush (GtkWidget *, gpointer);
/* assorted query dialogs */
static void channels_dialog_new_channel_query (GimpImage*);
static void channels_dialog_edit_channel_query (ChannelWidget *);
/* Only one channels dialog */
static ChannelsDialog *channelsD = NULL;
static GdkPixmap *eye_pixmap[3] = { NULL, NULL, NULL };
static GdkPixmap *channel_pixmap[3] = { NULL, NULL, NULL };
static int suspend_gimage_notify = 0;
static guint32 button_click_time = 0;
static int button_last_id = 0;
static MenuItem channels_ops[] =
{
{ "New Channel", 'N', GDK_CONTROL_MASK,
channels_dialog_new_channel_callback, NULL, NULL, NULL },
{ "Raise Channel", 'F', GDK_CONTROL_MASK,
channels_dialog_raise_channel_callback, NULL, NULL, NULL },
{ "Lower Channel", 'B', GDK_CONTROL_MASK,
channels_dialog_lower_channel_callback, NULL, NULL, NULL },
{ "Duplicate Channel", 'C', GDK_CONTROL_MASK,
channels_dialog_duplicate_channel_callback, NULL, NULL, NULL },
{ "Delete Channel", 'X', GDK_CONTROL_MASK,
channels_dialog_delete_channel_callback, NULL, NULL, NULL },
{ "Channel To Selection", 'S', GDK_CONTROL_MASK,
channels_dialog_channel_to_sel_callback, NULL, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL },
};
/* the ops buttons */
static OpsButton channels_ops_buttons[] =
{
{ new_xpm, new_is_xpm, channels_dialog_new_channel_callback, "New Channel", NULL, NULL, NULL, NULL, NULL, NULL },
{ raise_xpm, raise_is_xpm, channels_dialog_raise_channel_callback, "Raise Channel", NULL, NULL, NULL, NULL, NULL, NULL },
{ lower_xpm, lower_is_xpm, channels_dialog_lower_channel_callback, "Lower Channel", NULL, NULL, NULL, NULL, NULL, NULL },
{ duplicate_xpm, duplicate_is_xpm, channels_dialog_duplicate_channel_callback, "Duplicate Channel", NULL, NULL, NULL, NULL, NULL, NULL },
{ delete_xpm, delete_is_xpm, channels_dialog_delete_channel_callback, "Delete Channel", NULL, NULL, NULL, NULL, NULL, NULL },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
/**************************************/
/* Public channels dialog functions */
/**************************************/
GtkWidget *
channels_dialog_create ()
{
GtkWidget *vbox;
GtkWidget *listbox;
GtkWidget *button_box;
if (!channelsD)
{
channelsD = g_malloc (sizeof (ChannelsDialog));
channelsD->preview = NULL;
channelsD->gimage = NULL;
channelsD->active_channel = NULL;
channelsD->floating_sel = NULL;
channelsD->channel_widgets = NULL;
channelsD->accel_group = gtk_accel_group_new ();
if (preview_size)
{
channelsD->preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
gtk_preview_size (GTK_PREVIEW (channelsD->preview), preview_size, preview_size);
}
/* The main vbox */
channelsD->vbox = vbox = gtk_vbox_new (FALSE, 1);
gtk_container_border_width (GTK_CONTAINER (vbox), 2);
/* The layers commands pulldown menu */
channelsD->ops_menu = build_menu (channels_ops, channelsD->accel_group);
/* The channels listbox */
listbox = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_usize (listbox, CHANNEL_LIST_WIDTH, CHANNEL_LIST_HEIGHT);
gtk_box_pack_start (GTK_BOX (vbox), listbox, TRUE, TRUE, 2);
channelsD->channel_list = gtk_list_new ();
gtk_container_add (GTK_CONTAINER (listbox), channelsD->channel_list);
gtk_list_set_selection_mode (GTK_LIST (channelsD->channel_list), GTK_SELECTION_MULTIPLE);
gtk_signal_connect (GTK_OBJECT (channelsD->channel_list), "event",
(GtkSignalFunc) channel_list_events,
channelsD);
gtk_container_set_focus_vadjustment (GTK_CONTAINER (channelsD->channel_list),
gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (listbox)));
GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (listbox)->vscrollbar, GTK_CAN_FOCUS);
gtk_widget_show (channelsD->channel_list);
gtk_widget_show (listbox);
/* The ops buttons */
button_box = ops_button_box_new (lc_shell, tool_tips, channels_ops_buttons);
gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2);
gtk_widget_show (button_box);
/* Set up signals for map/unmap for the accelerators */
gtk_signal_connect (GTK_OBJECT (channelsD->vbox), "map",
(GtkSignalFunc) channels_dialog_map_callback,
NULL);
gtk_signal_connect (GTK_OBJECT (channelsD->vbox), "unmap",
(GtkSignalFunc) channels_dialog_unmap_callback,
NULL);
gtk_widget_show (vbox);
}
return channelsD->vbox;
}
void
channels_dialog_flush ()
{
GImage *gimage;
Channel *channel;
ChannelWidget *cw;
GSList *list;
int gimage_pos;
int pos;
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
/* Check if the gimage extents have changed */
if ((gimage->width != channelsD->gimage_width) ||
(gimage->height != channelsD->gimage_height) ||
(gimage_base_type (gimage) != channelsD->base_type))
{
channelsD->gimage = NULL;
channels_dialog_update (gimage);
}
/* Set all current channel widgets to visited = FALSE */
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
cw->visited = FALSE;
list = g_slist_next (list);
}
/* Add any missing channels */
list = gimage->channels;
while (list)
{
channel = (Channel *) list->data;
cw = channel_widget_get_ID (channel);
/* If the channel isn't in the channel widget list, add it */
if (cw == NULL)
channels_dialog_add_channel (channel);
else
cw->visited = TRUE;
list = g_slist_next (list);
}
/* Remove any extraneous auxillary channels */
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
list = g_slist_next (list);
if (cw->visited == FALSE && cw->type == Auxillary)
/* will only be true for auxillary channels */
channels_dialog_remove_channel (cw);
}
/* Switch positions of items if necessary */
list = channelsD->channel_widgets;
pos = -channelsD->num_components + 1;
while (list)
{
cw = (ChannelWidget *) list->data;
list = g_slist_next (list);
if (cw->type == Auxillary)
if ((gimage_pos = gimage_get_channel_index (gimage, cw->channel)) != pos)
channels_dialog_position_channel (cw, gimage_pos);
pos++;
}
/* Set the active channel */
if (channelsD->active_channel != gimage->active_channel)
channelsD->active_channel = gimage->active_channel;
/* set the menus if floating sel status has changed */
if (channelsD->floating_sel != gimage->floating_sel)
channelsD->floating_sel = gimage->floating_sel;
channels_dialog_set_menu_sensitivity ();
gtk_container_foreach (GTK_CONTAINER (channelsD->channel_list),
channel_widget_channel_flush, NULL);
}
/*************************************/
/* channels dialog widget routines */
/*************************************/
void
channels_dialog_update (GimpImage* gimage)
{
ChannelWidget *cw;
Channel *channel;
GSList *list;
GList *item_list;
if (!channelsD)
return;
if (channelsD->gimage == gimage)
return;
channelsD->gimage=gimage;
suspend_gimage_notify++;
/* Free all elements in the channels listbox */
gtk_list_clear_items (GTK_LIST (channelsD->channel_list), 0, -1);
suspend_gimage_notify--;
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
list = g_slist_next (list);
channel_widget_delete (cw);
}
channelsD->channel_widgets = NULL;
/* Find the preview extents */
channels_dialog_preview_extents ();
channelsD->active_channel = NULL;
channelsD->floating_sel = NULL;
/* The image components */
item_list = NULL;
switch ((channelsD->base_type = gimage_base_type (gimage)))
{
case RGB:
cw = create_channel_widget (gimage, NULL, Red);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
channelsD->components[0] = Red;
cw = create_channel_widget (gimage, NULL, Green);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
channelsD->components[1] = Green;
cw = create_channel_widget (gimage, NULL, Blue);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
channelsD->components[2] = Blue;
channelsD->num_components = 3;
break;
case GRAY:
cw = create_channel_widget (gimage, NULL, Gray);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
channelsD->components[0] = Gray;
channelsD->num_components = 1;
break;
case INDEXED:
cw = create_channel_widget (gimage, NULL, Indexed);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
channelsD->components[0] = Indexed;
channelsD->num_components = 1;
break;
}
/* The auxillary image channels */
list = gimage->channels;
while (list)
{
/* create a channel list item */
channel = (Channel *) list->data;
cw = create_channel_widget (gimage, channel, Auxillary);
channelsD->channel_widgets = g_slist_append (channelsD->channel_widgets, cw);
item_list = g_list_append (item_list, cw->list_item);
list = g_slist_next (list);
}
/* get the index of the active channel */
if (item_list)
gtk_list_insert_items (GTK_LIST (channelsD->channel_list), item_list, 0);
}
void
channels_dialog_clear ()
{
ops_button_box_set_insensitive (channels_ops_buttons);
suspend_gimage_notify++;
gtk_list_clear_items (GTK_LIST (channelsD->channel_list), 0, -1);
suspend_gimage_notify--;
}
void
channels_dialog_free ()
{
GSList *list;
ChannelWidget *cw;
if (channelsD == NULL)
return;
suspend_gimage_notify++;
/* Free all elements in the channels listbox */
gtk_list_clear_items (GTK_LIST (channelsD->channel_list), 0, -1);
suspend_gimage_notify--;
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
list = g_slist_next (list);
channel_widget_delete (cw);
}
channelsD->channel_widgets = NULL;
channelsD->active_channel = NULL;
channelsD->floating_sel = NULL;
if (channelsD->preview)
gtk_object_sink (GTK_OBJECT (channelsD->preview));
if (channelsD->ops_menu)
gtk_object_sink (GTK_OBJECT (channelsD->ops_menu));
g_free (channelsD);
channelsD = NULL;
}
static void
channels_dialog_preview_extents ()
{
GImage *gimage;
g_return_if_fail(channelsD);
g_return_if_fail(gimage = channelsD->gimage);
channelsD->gimage_width = gimage->width;
channelsD->gimage_height = gimage->height;
/* Get the image width and height variables, based on the gimage */
if (gimage->width > gimage->height)
channelsD->ratio = (double) preview_size / (double) gimage->width;
else
channelsD->ratio = (double) preview_size / (double) gimage->height;
if (preview_size)
{
channelsD->image_width = (int) (channelsD->ratio * gimage->width);
channelsD->image_height = (int) (channelsD->ratio * gimage->height);
if (channelsD->image_width < 1) channelsD->image_width = 1;
if (channelsD->image_height < 1) channelsD->image_height = 1;
}
else
{
channelsD->image_width = channel_width;
channelsD->image_height = channel_height;
}
}
static void
channels_dialog_set_menu_sensitivity ()
{
ChannelWidget *cw;
gint fs_sensitive;
gint aux_sensitive;
cw = channel_widget_get_ID (channelsD->active_channel);
fs_sensitive = (channelsD->floating_sel != NULL);
if (cw)
aux_sensitive = (cw->type == Auxillary);
else
aux_sensitive = FALSE;
/* new channel */
gtk_widget_set_sensitive (channels_ops[0].widget, !fs_sensitive);
ops_button_set_sensitive (channels_ops_buttons[0], !fs_sensitive);
/* raise channel */
gtk_widget_set_sensitive (channels_ops[1].widget, !fs_sensitive && aux_sensitive);
ops_button_set_sensitive (channels_ops_buttons[1], !fs_sensitive && aux_sensitive);
/* lower channel */
gtk_widget_set_sensitive (channels_ops[2].widget, !fs_sensitive && aux_sensitive);
ops_button_set_sensitive (channels_ops_buttons[2], !fs_sensitive && aux_sensitive);
/* duplicate channel */
gtk_widget_set_sensitive (channels_ops[3].widget, !fs_sensitive && aux_sensitive);
ops_button_set_sensitive (channels_ops_buttons[3], !fs_sensitive && aux_sensitive);
/* delete channel */
gtk_widget_set_sensitive (channels_ops[4].widget, !fs_sensitive && aux_sensitive);
ops_button_set_sensitive (channels_ops_buttons[4], !fs_sensitive && aux_sensitive);
/* channel to selection */
gtk_widget_set_sensitive (channels_ops[5].widget, aux_sensitive);
}
static void
channels_dialog_set_channel (ChannelWidget *channel_widget)
{
GtkStateType state;
int index;
if (!channelsD || !channel_widget)
return;
/* Make sure the gimage is not notified of this change */
suspend_gimage_notify++;
/* get the list item data */
state = channel_widget->list_item->state;
if (channel_widget->type == Auxillary)
{
/* turn on the specified auxillary channel */
index = gimage_get_channel_index (channel_widget->gimage, channel_widget->channel);
if ((index >= 0) && (state != GTK_STATE_SELECTED))
{
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), NULL);
gtk_list_select_item (GTK_LIST (channelsD->channel_list), index + channelsD->num_components);
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), channel_widget);
}
}
else
{
if (state != GTK_STATE_SELECTED)
{
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), NULL);
switch (channel_widget->type)
{
case Red: case Gray: case Indexed:
gtk_list_select_item (GTK_LIST (channelsD->channel_list), 0);
break;
case Green:
gtk_list_select_item (GTK_LIST (channelsD->channel_list), 1);
break;
case Blue:
gtk_list_select_item (GTK_LIST (channelsD->channel_list), 2);
break;
case Auxillary:
g_error ("error in %s at %d: this shouldn't happen.",
__FILE__, __LINE__);
break;
}
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), channel_widget);
}
}
suspend_gimage_notify--;
}
static void
channels_dialog_unset_channel (ChannelWidget * channel_widget)
{
GtkStateType state;
int index;
if (!channelsD || !channel_widget)
return;
/* Make sure the gimage is not notified of this change */
suspend_gimage_notify++;
/* get the list item data */
state = channel_widget->list_item->state;
if (channel_widget->type == Auxillary)
{
/* turn off the specified auxillary channel */
index = gimage_get_channel_index (channel_widget->gimage, channel_widget->channel);
if ((index >= 0) && (state == GTK_STATE_SELECTED))
{
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), NULL);
gtk_list_unselect_item (GTK_LIST (channelsD->channel_list), index + channelsD->num_components);
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), channel_widget);
}
}
else
{
if (state == GTK_STATE_SELECTED)
{
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), NULL);
switch (channel_widget->type)
{
case Red: case Gray: case Indexed:
gtk_list_unselect_item (GTK_LIST (channelsD->channel_list), 0);
break;
case Green:
gtk_list_unselect_item (GTK_LIST (channelsD->channel_list), 1);
break;
case Blue:
gtk_list_unselect_item (GTK_LIST (channelsD->channel_list), 2);
break;
case Auxillary:
g_error ("error in %s at %d: this shouldn't happen.",
__FILE__, __LINE__);
break;
}
gtk_object_set_user_data (GTK_OBJECT (channel_widget->list_item), channel_widget);
}
}
suspend_gimage_notify--;
}
static void
channels_dialog_position_channel (ChannelWidget *channel_widget,
int new_index)
{
GList *list = NULL;
if (!channelsD || !channel_widget)
return;
/* Make sure the gimage is not notified of this change */
suspend_gimage_notify++;
/* Remove the channel from the dialog */
list = g_list_append (list, channel_widget->list_item);
gtk_list_remove_items (GTK_LIST (channelsD->channel_list), list);
channelsD->channel_widgets = g_slist_remove (channelsD->channel_widgets, channel_widget);
suspend_gimage_notify--;
/* Add it back at the proper index */
gtk_list_insert_items (GTK_LIST (channelsD->channel_list), list, new_index + channelsD->num_components);
channelsD->channel_widgets = g_slist_insert (channelsD->channel_widgets, channel_widget, new_index + channelsD->num_components);
}
static void
channels_dialog_add_channel (Channel *channel)
{
GImage *gimage;
GList *item_list;
ChannelWidget *channel_widget;
int position;
if (!channelsD || !channel)
return;
if (! (gimage = channelsD->gimage))
return;
item_list = NULL;
channel_widget = create_channel_widget (gimage, channel, Auxillary);
item_list = g_list_append (item_list, channel_widget->list_item);
position = gimage_get_channel_index (gimage, channel);
channelsD->channel_widgets = g_slist_insert (channelsD->channel_widgets, channel_widget,
position + channelsD->num_components);
gtk_list_insert_items (GTK_LIST (channelsD->channel_list), item_list,
position + channelsD->num_components);
}
static void
channels_dialog_remove_channel (ChannelWidget *channel_widget)
{
GList *list = NULL;
if (!channelsD || !channel_widget)
return;
/* Make sure the gimage is not notified of this change */
suspend_gimage_notify++;
/* Remove the requested channel from the dialog */
list = g_list_append (list, channel_widget->list_item);
gtk_list_remove_items (GTK_LIST (channelsD->channel_list), list);
/* Delete the channel_widget */
channel_widget_delete (channel_widget);
suspend_gimage_notify--;
}
static gint
channel_list_events (GtkWidget *widget,
GdkEvent *event)
{
GdkEventKey *kevent;
GdkEventButton *bevent;
GtkWidget *event_widget;
ChannelWidget *channel_widget;
event_widget = gtk_get_event_widget (event);
if (GTK_IS_LIST_ITEM (event_widget))
{
channel_widget = (ChannelWidget *) gtk_object_get_user_data (GTK_OBJECT (event_widget));
switch (event->type)
{
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
if (bevent->button == 3 || bevent->button == 2)
{
gtk_menu_popup (GTK_MENU (channelsD->ops_menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
return TRUE;
}
/* Grumble - we have to handle double clicks ourselves because channels_dialog_flush is broken */
if (channel_widget->type == Auxillary)
if ((event->button.time < (button_click_time + 250)) && (channel_widget->ID == button_last_id)) {
channels_dialog_edit_channel_query (channel_widget);
return TRUE;
} else {
button_click_time = event->button.time;
button_last_id = channel_widget->ID;
}
break;
case GDK_2BUTTON_PRESS:
if (channel_widget->type == Auxillary)
channels_dialog_edit_channel_query (channel_widget);
return TRUE;
break;
case GDK_KEY_PRESS:
kevent = (GdkEventKey *) event;
switch (kevent->keyval)
{
case GDK_Up:
/* printf ("up arrow\n"); */
break;
case GDK_Down:
/* printf ("down arrow\n"); */
break;
default:
return FALSE;
break;
}
return TRUE;
break;
default:
break;
}
}
return FALSE;
}
/*******************************/
/* channels dialog callbacks */
/*******************************/
static void
channels_dialog_map_callback (GtkWidget *w,
gpointer client_data)
{
if (!channelsD)
return;
gtk_window_add_accel_group (GTK_WINDOW (lc_shell),
channelsD->accel_group);
}
static void
channels_dialog_unmap_callback (GtkWidget *w,
gpointer client_data)
{
if (!channelsD)
return;
gtk_window_remove_accel_group (GTK_WINDOW (lc_shell),
channelsD->accel_group);
}
static void
channels_dialog_new_channel_callback (GtkWidget *w,
gpointer client_data)
{
/* if there is a currently selected gimage, request a new channel
*/
if (!channelsD)
return;
if (channelsD->gimage == NULL)
return;
channels_dialog_new_channel_query (channelsD->gimage);
}
static void
channels_dialog_raise_channel_callback (GtkWidget *w,
gpointer client_data)
{
GImage *gimage;
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
if (gimage->active_channel != NULL)
{
gimage_raise_channel (gimage, gimage->active_channel);
gdisplays_flush ();
}
}
static void
channels_dialog_lower_channel_callback (GtkWidget *w,
gpointer client_data)
{
GImage *gimage;
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
if (gimage->active_channel != NULL)
{
gimage_lower_channel (gimage, gimage->active_channel);
gdisplays_flush ();
}
}
static void
channels_dialog_duplicate_channel_callback (GtkWidget *w,
gpointer client_data)
{
GImage *gimage;
Channel *active_channel;
Channel *new_channel;
/* if there is a currently selected gimage, request a new channel
*/
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
if ((active_channel = gimage_get_active_channel (gimage)))
{
new_channel = channel_copy (active_channel);
gimage_add_channel (gimage, new_channel, -1);
gdisplays_flush ();
}
}
static void
channels_dialog_delete_channel_callback (GtkWidget *w,
gpointer client_data)
{
GImage *gimage;
/* if there is a currently selected gimage
*/
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
if (gimage->active_channel != NULL)
{
gimage_remove_channel (gimage, gimage->active_channel);
gdisplays_flush ();
}
}
static void
channels_dialog_channel_to_sel_callback (GtkWidget *w,
gpointer client_data)
{
GImage *gimage;
/* if there is a currently selected gimage
*/
if (!channelsD)
return;
if (! (gimage = channelsD->gimage))
return;
if (gimage->active_channel != NULL)
{
gimage_mask_load (gimage, gimage->active_channel);
gdisplays_flush ();
}
}
/****************************/
/* channel widget functions */
/****************************/
static ChannelWidget *
channel_widget_get_ID (Channel *channel)
{
ChannelWidget *lw;
GSList *list;
if (!channelsD)
return NULL;
list = channelsD->channel_widgets;
while (list)
{
lw = (ChannelWidget *) list->data;
if (lw->channel == channel)
return lw;
list = g_slist_next (list);
}
return NULL;
}
static ChannelWidget *
create_channel_widget (GImage *gimage,
Channel *channel,
ChannelType type)
{
ChannelWidget *channel_widget;
GtkWidget *list_item;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *alignment;
list_item = gtk_list_item_new ();
/* create the channel widget and add it to the list */
channel_widget = (ChannelWidget *) g_malloc (sizeof (ChannelWidget));
channel_widget->gimage = gimage;
channel_widget->channel = channel;
channel_widget->channel_preview = NULL;
channel_widget->channel_pixmap = NULL;
channel_widget->type = type;
channel_widget->ID = (type == Auxillary) ? GIMP_DRAWABLE(channel)->ID : (COMPONENT_BASE_ID + type);
channel_widget->list_item = list_item;
channel_widget->width = -1;
channel_widget->height = -1;
channel_widget->visited = TRUE;
/* Need to let the list item know about the channel_widget */
gtk_object_set_user_data (GTK_OBJECT (list_item), channel_widget);
/* set up the list item observer */
gtk_signal_connect (GTK_OBJECT (list_item), "select",
(GtkSignalFunc) channel_widget_select_update,
channel_widget);
gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
(GtkSignalFunc) channel_widget_select_update,
channel_widget);
vbox = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (list_item), vbox);
hbox = gtk_hbox_new (FALSE, 1);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
/* Create the visibility toggle button */
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, TRUE, 2);
channel_widget->eye_widget = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (channel_widget->eye_widget), eye_width, eye_height);
gtk_widget_set_events (channel_widget->eye_widget, BUTTON_EVENT_MASK);
gtk_signal_connect (GTK_OBJECT (channel_widget->eye_widget), "event",
(GtkSignalFunc) channel_widget_button_events,
channel_widget);
gtk_object_set_user_data (GTK_OBJECT (channel_widget->eye_widget), channel_widget);
gtk_container_add (GTK_CONTAINER (alignment), channel_widget->eye_widget);
gtk_widget_show (channel_widget->eye_widget);
gtk_widget_show (alignment);
/* The preview */
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, FALSE, 2);
gtk_widget_show (alignment);
channel_widget->channel_preview = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (channel_widget->channel_preview),
channelsD->image_width, channelsD->image_height);
gtk_widget_set_events (channel_widget->channel_preview, PREVIEW_EVENT_MASK);
gtk_signal_connect (GTK_OBJECT (channel_widget->channel_preview), "event",
(GtkSignalFunc) channel_widget_preview_events,
channel_widget);
gtk_object_set_user_data (GTK_OBJECT (channel_widget->channel_preview), channel_widget);
gtk_container_add (GTK_CONTAINER (alignment), channel_widget->channel_preview);
gtk_widget_show (channel_widget->channel_preview);
/* the channel name label */
switch (channel_widget->type)
{
case Red: channel_widget->label = gtk_label_new ("Red"); break;
case Green: channel_widget->label = gtk_label_new ("Green"); break;
case Blue: channel_widget->label = gtk_label_new ("Blue"); break;
case Gray: channel_widget->label = gtk_label_new ("Gray"); break;
case Indexed: channel_widget->label = gtk_label_new ("Indexed"); break;
case Auxillary: channel_widget->label = gtk_label_new (GIMP_DRAWABLE(channel)->name); break;
}
gtk_box_pack_start (GTK_BOX (hbox), channel_widget->label, FALSE, FALSE, 2);
gtk_widget_show (channel_widget->label);
gtk_widget_show (hbox);
gtk_widget_show (vbox);
gtk_widget_show (list_item);
gtk_widget_ref (channel_widget->list_item);
return channel_widget;
}
static void
channel_widget_delete (ChannelWidget *channel_widget)
{
if (channel_widget->channel_pixmap)
gdk_pixmap_unref (channel_widget->channel_pixmap);
/* Remove the channel widget from the list */
channelsD->channel_widgets = g_slist_remove (channelsD->channel_widgets, channel_widget);
/* Release the widget */
gtk_widget_unref (channel_widget->list_item);
g_free (channel_widget);
}
static void
channel_widget_select_update (GtkWidget *w,
gpointer data)
{
ChannelWidget *channel_widget;
if ((channel_widget = (ChannelWidget *) data) == NULL)
return;
if (suspend_gimage_notify == 0)
{
if (channel_widget->type == Auxillary)
{
if (w->state == GTK_STATE_SELECTED)
/* set the gimage's active channel to be this channel */
gimage_set_active_channel (channel_widget->gimage, channel_widget->channel);
else
/* unset the gimage's active channel */
gimage_unset_active_channel (channel_widget->gimage);
gdisplays_flush ();
}
else if (channel_widget->type != Auxillary)
{
if (w->state == GTK_STATE_SELECTED)
gimage_set_component_active (channel_widget->gimage, channel_widget->type, TRUE);
else
gimage_set_component_active (channel_widget->gimage, channel_widget->type, FALSE);
}
}
}
static gint
channel_widget_button_events (GtkWidget *widget,
GdkEvent *event)
{
static int button_down = 0;
static GtkWidget *click_widget = NULL;
static int old_state;
static int exclusive;
ChannelWidget *channel_widget;
GtkWidget *event_widget;
GdkEventButton *bevent;
gint return_val;
int visible;
int width, height;
channel_widget = (ChannelWidget *) gtk_object_get_user_data (GTK_OBJECT (widget));
switch (channel_widget->type)
{
case Auxillary:
visible = GIMP_DRAWABLE(channel_widget->channel)->visible;
width = GIMP_DRAWABLE(channel_widget->channel)->width;
height = GIMP_DRAWABLE(channel_widget->channel)->height;
break;
default:
visible = gimage_get_component_visible (channel_widget->gimage, channel_widget->type);
width = channel_widget->gimage->width;
height = channel_widget->gimage->height;
break;
}
return_val = FALSE;
switch (event->type)
{
case GDK_EXPOSE:
if (widget == channel_widget->eye_widget)
channel_widget_eye_redraw (channel_widget);
break;
case GDK_BUTTON_PRESS:
return_val = TRUE;
bevent = (GdkEventButton *) event;
if (bevent->button == 3) {
gtk_menu_popup (GTK_MENU (channelsD->ops_menu), NULL, NULL, NULL, NULL, 3, bevent->time);
return TRUE;
}
button_down = 1;
click_widget = widget;
gtk_grab_add (click_widget);
if (widget == channel_widget->eye_widget)
{
old_state = visible;
/* If this was a shift-click, make all/none visible */
if (event->button.state & GDK_SHIFT_MASK)
{
exclusive = TRUE;
channel_widget_exclusive_visible (channel_widget);
}
else
{
exclusive = FALSE;
if (channel_widget->type == Auxillary)
GIMP_DRAWABLE(channel_widget->channel)->visible = !visible;
else
gimage_set_component_visible (channel_widget->gimage, channel_widget->type, !visible);
channel_widget_eye_redraw (channel_widget);
}
}
break;
case GDK_BUTTON_RELEASE:
return_val = TRUE;
button_down = 0;
gtk_grab_remove (click_widget);
if (widget == channel_widget->eye_widget)
{
if (exclusive)
{
gdisplays_update_area (channel_widget->gimage, 0, 0, width, height);
gdisplays_flush ();
}
else if (old_state != visible)
{
gdisplays_update_area (channel_widget->gimage, 0, 0, width, height);
gdisplays_flush ();
}
}
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
event_widget = gtk_get_event_widget (event);
if (button_down && (event_widget == click_widget))
{
if (widget == channel_widget->eye_widget)
{
if (exclusive)
{
channel_widget_exclusive_visible (channel_widget);
}
else
{
if (channel_widget->type == Auxillary)
GIMP_DRAWABLE(channel_widget->channel)->visible = !visible;
else
gimage_set_component_visible (channel_widget->gimage, channel_widget->type, !visible);
channel_widget_eye_redraw (channel_widget);
}
}
}
break;
default:
break;
}
return return_val;
}
static gint
channel_widget_preview_events (GtkWidget *widget,
GdkEvent *event)
{
GdkEventExpose *eevent;
GdkEventButton *bevent;
ChannelWidget *channel_widget;
int valid;
channel_widget = (ChannelWidget *) gtk_object_get_user_data (GTK_OBJECT (widget));
switch (event->type)
{
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
if (bevent->button == 3) {
gtk_menu_popup (GTK_MENU (channelsD->ops_menu), NULL, NULL, NULL, NULL, 3, bevent->time);
return TRUE;
}
break;
case GDK_EXPOSE:
if (!preview_size)
channel_widget_no_preview_redraw (channel_widget);
else
{
switch (channel_widget->type)
{
case Auxillary:
valid = GIMP_DRAWABLE(channel_widget->channel)->preview_valid;
break;
default:
valid = gimage_preview_valid (channel_widget->gimage, channel_widget->type);
break;
}
if (!valid || !channel_widget->channel_pixmap)
{
channel_widget_preview_redraw (channel_widget);
gdk_draw_pixmap (widget->window,
widget->style->black_gc,
channel_widget->channel_pixmap,
0, 0, 0, 0,
channelsD->image_width,
channelsD->image_height);
}
else
{
eevent = (GdkEventExpose *) event;
gdk_draw_pixmap (widget->window,
widget->style->black_gc,
channel_widget->channel_pixmap,
eevent->area.x, eevent->area.y,
eevent->area.x, eevent->area.y,
eevent->area.width, eevent->area.height);
}
}
break;
default:
break;
}
return FALSE;
}
static void
channel_widget_preview_redraw (ChannelWidget *channel_widget)
{
TempBuf * preview_buf;
int width, height;
int channel;
/* allocate the channel widget pixmap */
if (! channel_widget->channel_pixmap)
channel_widget->channel_pixmap = gdk_pixmap_new (channel_widget->channel_preview->window,
channelsD->image_width,
channelsD->image_height,
-1);
/* determine width and height */
switch (channel_widget->type)
{
case Auxillary:
width = GIMP_DRAWABLE(channel_widget->channel)->width;
height = GIMP_DRAWABLE(channel_widget->channel)->height;
channel_widget->width = (int) (channelsD->ratio * width);
channel_widget->height = (int) (channelsD->ratio * height);
preview_buf = channel_preview (channel_widget->channel,
channel_widget->width,
channel_widget->height);
break;
default:
width = channel_widget->gimage->width;
height = channel_widget->gimage->height;
channel_widget->width = (int) (channelsD->ratio * width);
channel_widget->height = (int) (channelsD->ratio * height);
preview_buf = gimage_composite_preview (channel_widget->gimage,
channel_widget->type,
channel_widget->width,
channel_widget->height);
break;
}
switch (channel_widget->type)
{
case Red: channel = RED_PIX; break;
case Green: channel = GREEN_PIX; break;
case Blue: channel = BLUE_PIX; break;
case Gray: channel = GRAY_PIX; break;
case Indexed: channel = INDEXED_PIX; break;
case Auxillary: channel = -1; break;
default: channel = -1; break;
}
render_preview (preview_buf,
channelsD->preview,
channelsD->image_width,
channelsD->image_height,
channel);
gtk_preview_put (GTK_PREVIEW (channelsD->preview),
channel_widget->channel_pixmap,
channel_widget->channel_preview->style->black_gc,
0, 0, 0, 0, channelsD->image_width, channelsD->image_height);
/* make sure the image has been transfered completely to the pixmap before
* we use it again...
*/
gdk_flush ();
}
static void
channel_widget_no_preview_redraw (ChannelWidget *channel_widget)
{
GdkPixmap *pixmap;
GdkPixmap **pixmap_normal;
GdkPixmap **pixmap_selected;
GdkPixmap **pixmap_insensitive;
GdkColor *color;
GtkWidget *widget;
GtkStateType state;
gchar *bits;
int width, height;
state = channel_widget->list_item->state;
widget = channel_widget->channel_preview;
pixmap_normal = &channel_pixmap[NORMAL];
pixmap_selected = &channel_pixmap[SELECTED];
pixmap_insensitive = &channel_pixmap[INSENSITIVE];
bits = (gchar *) channel_bits;
width = channel_width;
height = channel_height;
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
{
if (state == GTK_STATE_SELECTED)
color = &widget->style->bg[GTK_STATE_SELECTED];
else
color = &widget->style->white;
}
else
color = &widget->style->bg[GTK_STATE_INSENSITIVE];
gdk_window_set_background (widget->window, color);
if (!*pixmap_normal)
{
*pixmap_normal =
gdk_pixmap_create_from_data (widget->window,
bits, width, height, -1,
&widget->style->fg[GTK_STATE_SELECTED],
&widget->style->bg[GTK_STATE_SELECTED]);
*pixmap_selected =
gdk_pixmap_create_from_data (widget->window,
bits, width, height, -1,
&widget->style->fg[GTK_STATE_NORMAL],
&widget->style->white);
*pixmap_insensitive =
gdk_pixmap_create_from_data (widget->window,
bits, width, height, -1,
&widget->style->fg[GTK_STATE_INSENSITIVE],
&widget->style->bg[GTK_STATE_INSENSITIVE]);
}
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
{
if (state == GTK_STATE_SELECTED)
pixmap = *pixmap_selected;
else
pixmap = *pixmap_normal;
}
else
pixmap = *pixmap_insensitive;
gdk_draw_pixmap (widget->window,
widget->style->black_gc,
pixmap, 0, 0, 0, 0, width, height);
}
static void
channel_widget_eye_redraw (ChannelWidget *channel_widget)
{
GdkPixmap *pixmap;
GdkColor *color;
GtkStateType state;
int visible;
state = channel_widget->list_item->state;
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
{
if (state == GTK_STATE_SELECTED)
color = &channel_widget->eye_widget->style->bg[GTK_STATE_SELECTED];
else
color = &channel_widget->eye_widget->style->white;
}
else
color = &channel_widget->eye_widget->style->bg[GTK_STATE_INSENSITIVE];
gdk_window_set_background (channel_widget->eye_widget->window, color);
switch (channel_widget->type)
{
case Auxillary:
visible = GIMP_DRAWABLE(channel_widget->channel)->visible;
break;
default:
visible = gimage_get_component_visible (channel_widget->gimage, channel_widget->type);
break;
}
if (visible)
{
if (!eye_pixmap[NORMAL])
{
eye_pixmap[NORMAL] =
gdk_pixmap_create_from_data (channel_widget->eye_widget->window,
(gchar*) eye_bits, eye_width, eye_height, -1,
&channel_widget->eye_widget->style->fg[GTK_STATE_NORMAL],
&channel_widget->eye_widget->style->white);
eye_pixmap[SELECTED] =
gdk_pixmap_create_from_data (channel_widget->eye_widget->window,
(gchar*) eye_bits, eye_width, eye_height, -1,
&channel_widget->eye_widget->style->fg[GTK_STATE_SELECTED],
&channel_widget->eye_widget->style->bg[GTK_STATE_SELECTED]);
eye_pixmap[INSENSITIVE] =
gdk_pixmap_create_from_data (channel_widget->eye_widget->window,
(gchar*) eye_bits, eye_width, eye_height, -1,
&channel_widget->eye_widget->style->fg[GTK_STATE_INSENSITIVE],
&channel_widget->eye_widget->style->bg[GTK_STATE_INSENSITIVE]);
}
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
{
if (state == GTK_STATE_SELECTED)
pixmap = eye_pixmap[SELECTED];
else
pixmap = eye_pixmap[NORMAL];
}
else
pixmap = eye_pixmap[INSENSITIVE];
gdk_draw_pixmap (channel_widget->eye_widget->window,
channel_widget->eye_widget->style->black_gc,
pixmap, 0, 0, 0, 0, eye_width, eye_height);
}
else
{
gdk_window_clear (channel_widget->eye_widget->window);
}
}
static void
channel_widget_exclusive_visible (ChannelWidget *channel_widget)
{
GSList *list;
ChannelWidget *cw;
int visible = FALSE;
if (!channelsD)
return;
/* First determine if _any_ other channel widgets are set to visible */
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
if (cw != channel_widget)
{
switch (cw->type)
{
case Auxillary:
visible |= GIMP_DRAWABLE(cw->channel)->visible;
break;
default:
visible |= gimage_get_component_visible (cw->gimage, cw->type);
break;
}
}
list = g_slist_next (list);
}
/* Now, toggle the visibility for all channels except the specified one */
list = channelsD->channel_widgets;
while (list)
{
cw = (ChannelWidget *) list->data;
if (cw != channel_widget)
switch (cw->type)
{
case Auxillary:
GIMP_DRAWABLE(cw->channel)->visible = !visible;
break;
default:
gimage_set_component_visible (cw->gimage, cw->type, !visible);
break;
}
else
switch (cw->type)
{
case Auxillary:
GIMP_DRAWABLE(cw->channel)->visible = TRUE;
break;
default:
gimage_set_component_visible (cw->gimage, cw->type, TRUE);
break;
}
channel_widget_eye_redraw (cw);
list = g_slist_next (list);
}
}
static void
channel_widget_channel_flush (GtkWidget *widget,
gpointer client_data)
{
ChannelWidget *channel_widget;
int update_preview;
channel_widget = (ChannelWidget *) gtk_object_get_user_data (GTK_OBJECT (widget));
/*** Sensitivity ***/
/* If there is a floating selection... */
if (channelsD->floating_sel != NULL)
{
/* to insensitive if this is an auxillary channel */
if (channel_widget->type == Auxillary)
{
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
gtk_widget_set_sensitive (channel_widget->list_item, FALSE);
}
/* to sensitive otherwise */
else
{
if (! GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
gtk_widget_set_sensitive (channel_widget->list_item, TRUE);
}
}
else
{
/* to insensitive if there is an active channel, and this is a component channel */
if (channel_widget->type != Auxillary && channelsD->active_channel != NULL)
{
if (GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
gtk_widget_set_sensitive (channel_widget->list_item, FALSE);
}
/* to sensitive otherwise */
else
{
if (! GTK_WIDGET_IS_SENSITIVE (channel_widget->list_item))
gtk_widget_set_sensitive (channel_widget->list_item, TRUE);
}
}
/*** Selection ***/
/* If this is an auxillary channel */
if (channel_widget->type == Auxillary)
{
/* select if this is the active channel */
if (channelsD->active_channel == (channel_widget->channel))
channels_dialog_set_channel (channel_widget);
/* unselect if this is not the active channel */
else
channels_dialog_unset_channel (channel_widget);
}
else
{
/* If the component is active, select. otherwise, deselect */
if (gimage_get_component_active (channel_widget->gimage, channel_widget->type))
channels_dialog_set_channel (channel_widget);
else
channels_dialog_unset_channel (channel_widget);
}
switch (channel_widget->type)
{
case Auxillary:
update_preview = !GIMP_DRAWABLE(channel_widget->channel)->preview_valid;
break;
default:
update_preview = !gimage_preview_valid (channel_widget->gimage, channel_widget->type);
break;
}
if (update_preview)
gtk_widget_draw (channel_widget->channel_preview, NULL);
}
/*
* The new channel query dialog
*/
typedef struct _NewChannelOptions NewChannelOptions;
struct _NewChannelOptions {
GtkWidget *query_box;
GtkWidget *name_entry;
ColorPanel *color_panel;
GimpImage* gimage;
double opacity;
};
static char *channel_name = NULL;
static unsigned char channel_color[3] = {0, 0, 0};
static void
new_channel_query_ok_callback (GtkWidget *w,
gpointer client_data)
{
NewChannelOptions *options;
Channel *new_channel;
GImage *gimage;
int i;
options = (NewChannelOptions *) client_data;
if (channel_name)
g_free (channel_name);
channel_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (options->name_entry)));
if ((gimage = options->gimage))
{
new_channel = channel_new (gimage, gimage->width, gimage->height,
channel_name, (int) (255 * options->opacity) / 100,
options->color_panel->color);
drawable_fill (GIMP_DRAWABLE(new_channel), TRANSPARENT_FILL);
for (i = 0; i < 3; i++)
channel_color[i] = options->color_panel->color[i];
gimage_add_channel (gimage, new_channel, -1);
gdisplays_flush ();
}
color_panel_free (options->color_panel);
gtk_widget_destroy (options->query_box);
g_free (options);
}
static void
new_channel_query_cancel_callback (GtkWidget *w,
gpointer client_data)
{
NewChannelOptions *options;
options = (NewChannelOptions *) client_data;
color_panel_free (options->color_panel);
gtk_widget_destroy (options->query_box);
g_free (options);
}
static gint
new_channel_query_delete_callback (GtkWidget *w,
GdkEvent *e,
gpointer client_data)
{
new_channel_query_cancel_callback (w, client_data);
return TRUE;
}
static void
new_channel_query_scale_update (GtkAdjustment *adjustment,
double *scale_val)
{
*scale_val = adjustment->value;
}
static void
channels_dialog_new_channel_query (GimpImage* gimage)
{
static ActionAreaItem action_items[2] =
{
{ "OK", new_channel_query_ok_callback, NULL, NULL },
{ "Cancel", new_channel_query_cancel_callback, NULL, NULL }
};
NewChannelOptions *options;
GtkWidget *vbox;
GtkWidget *table;
GtkWidget *label;
GtkWidget *opacity_scale;
GtkObject *opacity_scale_data;
/* the new options structure */
options = (NewChannelOptions *) g_malloc (sizeof (NewChannelOptions));
options->gimage = gimage;
options->opacity = 50.0;
options->color_panel = color_panel_new (channel_color, 48, 64);
/* the dialog */
options->query_box = gtk_dialog_new ();
gtk_window_set_wmclass (GTK_WINDOW (options->query_box), "new_channel_options", "Gimp");
gtk_window_set_title (GTK_WINDOW (options->query_box), "New Channel Options");
gtk_window_position (GTK_WINDOW (options->query_box), GTK_WIN_POS_MOUSE);
/* handle the wm close signal */
gtk_signal_connect (GTK_OBJECT (options->query_box), "delete_event",
GTK_SIGNAL_FUNC (new_channel_query_delete_callback),
options);
/* the main vbox */
vbox = gtk_vbox_new (FALSE, 1);
gtk_container_border_width (GTK_CONTAINER (vbox), 1);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (options->query_box)->vbox), vbox, TRUE, TRUE, 0);
/* The table */
table = gtk_table_new (2, 3, FALSE);
gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
/* the name entry hbox, label and entry */
label = gtk_label_new ("Channel name: ");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 1);
gtk_widget_show (label);
options->name_entry = gtk_entry_new ();
gtk_widget_set_usize (options->name_entry, 75, 0);
gtk_table_attach (GTK_TABLE (table), options->name_entry, 1, 2, 0, 1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 1, 1);
gtk_entry_set_text (GTK_ENTRY (options->name_entry), (channel_name ? channel_name : "New Channel"));
gtk_widget_show (options->name_entry);
/* the opacity scale */
label = gtk_label_new ("Fill Opacity: ");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 1);
gtk_widget_show (label);
opacity_scale_data = gtk_adjustment_new (options->opacity, 0.0, 100.0, 1.0, 1.0, 0.0);
opacity_scale = gtk_hscale_new (GTK_ADJUSTMENT (opacity_scale_data));
gtk_table_attach (GTK_TABLE (table), opacity_scale, 1, 2, 1, 2,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 1, 1);
gtk_scale_set_value_pos (GTK_SCALE (opacity_scale), GTK_POS_TOP);
gtk_range_set_update_policy (GTK_RANGE (opacity_scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (opacity_scale_data), "value_changed",
(GtkSignalFunc) new_channel_query_scale_update,
&options->opacity);
gtk_widget_show (opacity_scale);
/* the color panel */
gtk_table_attach (GTK_TABLE (table), options->color_panel->color_panel_widget,
2, 3, 0, 2, GTK_EXPAND, GTK_EXPAND, 4, 2);
gtk_widget_show (options->color_panel->color_panel_widget);
action_items[0].user_data = options;
action_items[1].user_data = options;
build_action_area (GTK_DIALOG (options->query_box), action_items, 2, 0);
gtk_widget_show (table);
gtk_widget_show (vbox);
gtk_widget_show (options->query_box);
}
/*
* The edit channel attributes dialog
*/
typedef struct _EditChannelOptions EditChannelOptions;
struct _EditChannelOptions {
GtkWidget *query_box;
GtkWidget *name_entry;
ChannelWidget *channel_widget;
GimpImage* gimage;
ColorPanel *color_panel;
double opacity;
};
static void
edit_channel_query_ok_callback (GtkWidget *w,
gpointer client_data)
{
EditChannelOptions *options;
Channel *channel;
int opacity;
int update = FALSE;
int i;
options = (EditChannelOptions *) client_data;
channel = options->channel_widget->channel;
opacity = (int) (255 * options->opacity) / 100;
if (options->gimage) {
/* Set the new channel name */
if (GIMP_DRAWABLE(channel)->name)
g_free (GIMP_DRAWABLE(channel)->name);
GIMP_DRAWABLE(channel)->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (options->name_entry)));
gtk_label_set (GTK_LABEL (options->channel_widget->label), GIMP_DRAWABLE(channel)->name);
if (channel->opacity != opacity)
{
channel->opacity = opacity;
update = TRUE;
}
for (i = 0; i < 3; i++)
if (options->color_panel->color[i] != channel->col[i])
{
channel->col[i] = options->color_panel->color[i];
update = TRUE;
}
if (update)
{
drawable_update (GIMP_DRAWABLE(channel), 0, 0, GIMP_DRAWABLE(channel)->width, GIMP_DRAWABLE(channel)->height);
gdisplays_flush ();
}
}
color_panel_free (options->color_panel);
gtk_widget_destroy (options->query_box);
g_free (options);
}
static void
edit_channel_query_cancel_callback (GtkWidget *w,
gpointer client_data)
{
EditChannelOptions *options;
options = (EditChannelOptions *) client_data;
color_panel_free (options->color_panel);
gtk_widget_destroy (options->query_box);
g_free (options);
}
static gint
edit_channel_query_delete_callback (GtkWidget *w,
GdkEvent *e,
gpointer client_data)
{
edit_channel_query_cancel_callback (w, client_data);
return TRUE;
}
static void
channels_dialog_edit_channel_query (ChannelWidget *channel_widget)
{
static ActionAreaItem action_items[2] =
{
{ "OK", edit_channel_query_ok_callback, NULL, NULL },
{ "Cancel", edit_channel_query_cancel_callback, NULL, NULL }
};
EditChannelOptions *options;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *table;
GtkWidget *label;
GtkWidget *opacity_scale;
GtkObject *opacity_scale_data;
int i;
/* the new options structure */
options = (EditChannelOptions *) g_malloc (sizeof (EditChannelOptions));
options->channel_widget = channel_widget;
options->gimage = channel_widget->gimage;
options->opacity = (double) channel_widget->channel->opacity / 2.55;
for (i = 0; i < 3; i++)
channel_color[i] = channel_widget->channel->col[i];
options->color_panel = color_panel_new (channel_color, 48, 64);
/* the dialog */
options->query_box = gtk_dialog_new ();
gtk_window_set_wmclass (GTK_WINDOW (options->query_box), "edit_channel_atributes", "Gimp");
gtk_window_set_title (GTK_WINDOW (options->query_box), "Edit Channel Attributes");
gtk_window_position (GTK_WINDOW (options->query_box), GTK_WIN_POS_MOUSE);
/* deal with the wm close signal */
gtk_signal_connect (GTK_OBJECT (options->query_box), "delete_event",
GTK_SIGNAL_FUNC (edit_channel_query_delete_callback),
options);
/* the main vbox */
vbox = gtk_vbox_new (FALSE, 1);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (options->query_box)->vbox), vbox, TRUE, TRUE, 0);
/* The table */
table = gtk_table_new (2, 2, FALSE);
gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
/* the name entry hbox, label and entry */
hbox = gtk_hbox_new (FALSE, 1);
gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, 0, 2, 2);
label = gtk_label_new ("Channel name:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
options->name_entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), options->name_entry, TRUE, TRUE, 0);
gtk_entry_set_text (GTK_ENTRY (options->name_entry), GIMP_DRAWABLE(channel_widget->channel)->name);
gtk_widget_show (options->name_entry);
gtk_widget_show (hbox);
/* the opacity scale */
hbox = gtk_hbox_new (FALSE, 1);
gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, 0, 2, 2);
label = gtk_label_new ("Fill Opacity");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
opacity_scale_data = gtk_adjustment_new (options->opacity, 0.0, 100.0, 1.0, 1.0, 0.0);
opacity_scale = gtk_hscale_new (GTK_ADJUSTMENT (opacity_scale_data));
gtk_box_pack_start (GTK_BOX (hbox), opacity_scale, TRUE, TRUE, 0);
gtk_scale_set_value_pos (GTK_SCALE (opacity_scale), GTK_POS_TOP);
gtk_signal_connect (GTK_OBJECT (opacity_scale_data), "value_changed",
(GtkSignalFunc) new_channel_query_scale_update,
&options->opacity);
gtk_widget_show (opacity_scale);
gtk_widget_show (hbox);
/* the color panel */
gtk_table_attach (GTK_TABLE (table), options->color_panel->color_panel_widget,
1, 2, 0, 2, GTK_EXPAND, GTK_EXPAND, 4, 2);
gtk_widget_show (options->color_panel->color_panel_widget);
action_items[0].user_data = options;
action_items[1].user_data = options;
build_action_area (GTK_DIALOG (options->query_box), action_items, 2, 0);
gtk_widget_show (table);
gtk_widget_show (vbox);
gtk_widget_show (options->query_box);
}