Files
gimp/app/actions/layers-commands.c
Michael Natterer c49df22eef Action code review and pre-release consistency cleanup:
2004-10-18  Michael Natterer  <mitch@gimp.org>

	Action code review and pre-release consistency cleanup:

	* app/actions/*-actions.c: added some missing and resolved
	conflicting mnemonics, added missing help IDs. Cleaned up the
	*_actions_update() functions.

	* app/actions/channels-actions.c
	* app/actions/layers-actions.c
	* app/actions/vectors-actions.c (*_actions_update): simplified
	the code that figures the prev and next channel,layer,vectors.

	* app/actions/qmask-actions.c: use the same accelerator for
	"qmask-active" and "qmask-toggle". Fixed action sensitivity.

	* app/actions/channels-commands.c
	* app/actions/dockable-commands.c
	* app/actions/documents-commands.c
	* app/actions/gradients-commands.c
	* app/actions/layers-commands.c
	* app/actions/palettes-commands.c
	* app/actions/image-commands.c
	* app/actions/select-commands.c
	* app/actions/vectors-commands.c: folded tons of private utility
	functions into their only callers (they used to be public and
	called from outside before the switch to action based menus).
	Renamed functions and variables saying "query" or "qbox" to
	"dialog". Moved static functions to the end of the files. Misc
	minor cleanups.

	* app/actions/drawable-actions.c
	* app/actions/drawable-commands.c: made the "drawable-visible" and
	"drawable-linked" actions affect the layer if the active drawable
	is a layer mask.

	* app/actions/select-commands.c: added action to stroke with the
	last values used in an attempt to address bug #135746 but #if 0'ed
	it because the approach is too ugly.

	* app/tools/gimpiscissorstool.c: changed mnemonic from I to S.

	* menus/image-menu-xml.in: added more stuff to the (commented out)
	"context" menu.
2004-10-18 11:29:58 +00:00

1328 lines
38 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 "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "actions-types.h"
#include "config/gimpcoreconfig.h"
#include "core/gimp.h"
#include "core/gimpchannel-select.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimpimage-merge.h"
#include "core/gimpimage-undo.h"
#include "core/gimpitemundo.h"
#include "core/gimplayer.h"
#include "core/gimplayer-floating-sel.h"
#include "core/gimplayermask.h"
#include "core/gimplist.h"
#include "core/gimptoolinfo.h"
#include "core/gimpundostack.h"
#include "core/gimpprogress.h"
#include "text/gimptext.h"
#include "text/gimptextlayer.h"
#include "widgets/gimpaction.h"
#include "widgets/gimpdock.h"
#include "widgets/gimpenumwidgets.h"
#include "widgets/gimphelp-ids.h"
#include "widgets/gimpitemtreeview.h"
#include "widgets/gimpprogressdialog.h"
#include "widgets/gimppropwidgets.h"
#include "widgets/gimpviewabledialog.h"
#include "display/gimpdisplay.h"
#include "display/gimpdisplayshell.h"
#include "tools/gimptexttool.h"
#include "tools/tool_manager.h"
#include "dialogs/resize-dialog.h"
#include "dialogs/scale-dialog.h"
#include "actions.h"
#include "layers-commands.h"
#include "gimp-intl.h"
static const GimpLayerModeEffects layer_modes[] =
{
GIMP_NORMAL_MODE,
GIMP_DISSOLVE_MODE,
GIMP_MULTIPLY_MODE,
GIMP_DIVIDE_MODE,
GIMP_SCREEN_MODE,
GIMP_OVERLAY_MODE,
GIMP_DODGE_MODE,
GIMP_BURN_MODE,
GIMP_HARDLIGHT_MODE,
GIMP_SOFTLIGHT_MODE,
GIMP_GRAIN_EXTRACT_MODE,
GIMP_GRAIN_MERGE_MODE,
GIMP_DIFFERENCE_MODE,
GIMP_ADDITION_MODE,
GIMP_SUBTRACT_MODE,
GIMP_DARKEN_ONLY_MODE,
GIMP_LIGHTEN_ONLY_MODE,
GIMP_HUE_MODE,
GIMP_SATURATION_MODE,
GIMP_COLOR_MODE,
GIMP_VALUE_MODE
};
typedef struct _NewLayerOptions NewLayerOptions;
struct _NewLayerOptions
{
GtkWidget *dialog;
GtkWidget *name_entry;
GtkWidget *size_se;
GimpFillType fill_type;
gint xsize;
gint ysize;
GimpContext *context;
GimpImage *gimage;
};
typedef struct _EditLayerOptions EditLayerOptions;
struct _EditLayerOptions
{
GtkWidget *dialog;
GtkWidget *name_entry;
GtkWidget *toggle;
GimpLayer *layer;
GimpImage *gimage;
};
typedef struct _AddMaskOptions AddMaskOptions;
struct _AddMaskOptions
{
GtkWidget *dialog;
GimpLayer *layer;
GimpAddMaskType add_mask_type;
gboolean invert;
};
typedef struct _ResizeLayerOptions ResizeLayerOptions;
struct _ResizeLayerOptions
{
GimpLayer *layer;
GimpContext *context;
ResizeDialog *dialog;
};
/* local function prototypes */
static void layers_new_layer_dialog (GimpImage *gimage,
GimpContext *context,
GtkWidget *parent);
static void layers_new_layer_response (GtkWidget *widget,
gint response_id,
NewLayerOptions *options);
static void layers_edit_layer_dialog (GimpLayer *layer,
GimpContext *context,
GtkWidget *parent);
static void layers_edit_layer_response (GtkWidget *widget,
gint response_id,
EditLayerOptions *options);
static void layers_add_mask_response (GtkWidget *widget,
gint response_id,
AddMaskOptions *options);
static void layers_scale_layer_callback (GtkWidget *dialog,
GimpViewable *viewable,
gint width,
gint height,
GimpUnit unit,
GimpInterpolationType interpolation,
gpointer data);
static void layers_resize_layer_callback (GtkWidget *widget,
gpointer data);
static gint layers_mode_index (GimpLayerModeEffects layer_mode);
/* private variables */
static GimpFillType fill_type = GIMP_TRANSPARENT_FILL;
static gchar *layer_name = NULL;
/* public functions */
void
layers_text_tool_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GtkWidget *widget;
GimpTool *active_tool;
return_if_no_layer (gimage, layer, data);
return_if_no_widget (widget, data);
if (! gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer)))
{
layers_edit_layer_dialog (layer, action_data_get_context (data), widget);
return;
}
active_tool = tool_manager_get_active (gimage->gimp);
if (! GIMP_IS_TEXT_TOOL (active_tool))
{
GimpToolInfo *tool_info;
tool_info = (GimpToolInfo *)
gimp_container_get_child_by_name (gimage->gimp->tool_info_list,
"gimp-text-tool");
if (GIMP_IS_TOOL_INFO (tool_info))
{
gimp_context_set_tool (action_data_get_context (data), tool_info);
active_tool = tool_manager_get_active (gimage->gimp);
}
}
if (GIMP_IS_TEXT_TOOL (active_tool))
gimp_text_tool_set_layer (GIMP_TEXT_TOOL (active_tool), layer);
}
void
layers_edit_attributes_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GtkWidget *widget;
return_if_no_layer (gimage, layer, data);
return_if_no_widget (widget, data);
layers_edit_layer_dialog (layer, action_data_get_context (data), widget);
}
void
layers_new_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GtkWidget *widget;
GimpLayer *floating_sel;
return_if_no_image (gimage, data);
return_if_no_widget (widget, data);
/* If there is a floating selection, the new command transforms
* the current fs into a new layer
*/
if ((floating_sel = gimp_image_floating_sel (gimage)))
{
floating_sel_to_layer (floating_sel);
gimp_image_flush (gimage);
return;
}
layers_new_layer_dialog (gimage, action_data_get_context (data), widget);
}
void
layers_new_default_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *floating_sel;
GimpLayer *new_layer;
gint width, height;
gint off_x, off_y;
gdouble opacity;
GimpLayerModeEffects mode;
return_if_no_image (gimage, data);
/* If there is a floating selection, the new command transforms
* the current fs into a new layer
*/
if ((floating_sel = gimp_image_floating_sel (gimage)))
{
floating_sel_to_layer (floating_sel);
gimp_image_flush (gimage);
return;
}
if (GIMP_IS_LAYER (GIMP_ACTION (action)->viewable))
{
GimpLayer *template = GIMP_LAYER (GIMP_ACTION (action)->viewable);
gimp_item_offsets (GIMP_ITEM (template), &off_x, &off_y);
width = gimp_item_width (GIMP_ITEM (template));
height = gimp_item_height (GIMP_ITEM (template));
opacity = template->opacity;
mode = template->mode;
}
else
{
width = gimp_image_get_width (gimage);
height = gimp_image_get_height (gimage);
off_x = 0;
off_y = 0;
opacity = 1.0;
mode = GIMP_NORMAL_MODE;
}
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_EDIT_PASTE,
_("New Layer"));
new_layer = gimp_layer_new (gimage, width, height,
gimp_image_base_type_with_alpha (gimage),
_("Empty Layer"), opacity, mode);
gimp_drawable_fill_by_type (GIMP_DRAWABLE (new_layer),
action_data_get_context (data),
GIMP_TRANSPARENT_FILL);
gimp_item_translate (GIMP_ITEM (new_layer), off_x, off_y, FALSE);
gimp_image_add_layer (gimage, new_layer, -1);
gimp_image_undo_group_end (gimage);
gimp_image_flush (gimage);
}
void
layers_select_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayer *new_layer;
return_if_no_image (gimage, data);
layer = gimp_image_get_active_layer (gimage);
new_layer = (GimpLayer *) action_select_object ((GimpActionSelectType) value,
gimage->layers,
(GimpObject *) layer);
if (new_layer && new_layer != layer)
{
gimp_image_set_active_layer (gimage, new_layer);
gimp_image_flush (gimage);
}
}
void
layers_raise_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_image_raise_layer (gimage, layer);
gimp_image_flush (gimage);
}
void
layers_raise_to_top_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_image_raise_layer_to_top (gimage, layer);
gimp_image_flush (gimage);
}
void
layers_lower_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_image_lower_layer (gimage, layer);
gimp_image_flush (gimage);
}
void
layers_lower_to_bottom_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_image_lower_layer_to_bottom (gimage, layer);
gimp_image_flush (gimage);
}
void
layers_duplicate_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayer *new_layer;
return_if_no_layer (gimage, layer, data);
new_layer =
GIMP_LAYER (gimp_item_duplicate (GIMP_ITEM (layer),
G_TYPE_FROM_INSTANCE (layer),
TRUE));
gimp_image_add_layer (gimage, new_layer, -1);
gimp_image_flush (gimage);
}
void
layers_anchor_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
if (gimp_layer_is_floating_sel (layer))
{
floating_sel_anchor (layer);
gimp_image_flush (gimage);
}
}
void
layers_merge_down_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_image_merge_down (gimage, layer, action_data_get_context (data),
GIMP_EXPAND_AS_NECESSARY);
gimp_image_flush (gimage);
}
void
layers_delete_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
if (gimp_layer_is_floating_sel (layer))
floating_sel_remove (layer);
else
gimp_image_remove_layer (gimage, layer);
gimp_image_flush (gimage);
}
void
layers_text_discard_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
if (GIMP_IS_TEXT_LAYER (layer))
gimp_text_layer_discard (GIMP_TEXT_LAYER (layer));
}
void
layers_resize_cmd_callback (GtkAction *action,
gpointer data)
{
ResizeLayerOptions *options;
GimpImage *gimage;
GimpLayer *layer;
GtkWidget *widget;
GimpDisplay *gdisp;
return_if_no_layer (gimage, layer, data);
return_if_no_widget (widget, data);
gdisp = GIMP_IS_DISPLAY (data) ? data : NULL;
options = g_new0 (ResizeLayerOptions, 1);
options->context = action_data_get_context (data);
options->layer = layer;
options->dialog =
resize_dialog_new (GIMP_VIEWABLE (layer), widget,
RESIZE_DIALOG,
gimp_item_width (GIMP_ITEM (layer)),
gimp_item_height (GIMP_ITEM (layer)),
gimage->xresolution,
gimage->yresolution,
(gdisp ?
GIMP_DISPLAY_SHELL (gdisp->shell)->unit :
GIMP_UNIT_PIXEL),
G_CALLBACK (layers_resize_layer_callback),
options);
g_object_weak_ref (G_OBJECT (options->dialog->shell),
(GWeakNotify) g_free,
options);
gtk_widget_show (options->dialog->shell);
}
void
layers_resize_to_image_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
gimp_layer_resize_to_image (layer, action_data_get_context (data));
gimp_image_flush (gimage);
}
void
layers_scale_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GtkWidget *widget;
GimpDisplay *gdisp;
GtkWidget *dialog;
GimpUnit unit;
return_if_no_layer (gimage, layer, data);
return_if_no_widget (widget, data);
gdisp = action_data_get_display (data);
unit = gdisp ? GIMP_DISPLAY_SHELL (gdisp->shell)->unit : GIMP_UNIT_PIXEL;
dialog = scale_dialog_new (GIMP_VIEWABLE (layer),
_("Scale Layer"), "gimp-layer-scale",
widget,
gimp_standard_help_func, GIMP_HELP_LAYER_SCALE,
unit, gimage->gimp->config->interpolation_type,
layers_scale_layer_callback,
gdisp);
gtk_widget_show (dialog);
}
void
layers_crop_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
gint x1, y1, x2, y2;
gint off_x, off_y;
return_if_no_layer (gimage, layer, data);
if (! gimp_channel_bounds (gimp_image_get_mask (gimage),
&x1, &y1, &x2, &y2))
{
g_message (_("Cannot crop because the current selection is empty."));
return;
}
gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);
off_x -= x1;
off_y -= y1;
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_ITEM_RESIZE,
_("Crop Layer"));
gimp_item_resize (GIMP_ITEM (layer), action_data_get_context (data),
x2 - x1, y2 - y1, off_x, off_y);
gimp_image_undo_group_end (gimage);
gimp_image_flush (gimage);
}
void
layers_mask_add_cmd_callback (GtkAction *action,
gpointer data)
{
AddMaskOptions *options;
GimpImage *gimage;
GimpLayer *layer;
GtkWidget *widget;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *button;
return_if_no_layer (gimage, layer, data);
return_if_no_widget (widget, data);
options = g_new0 (AddMaskOptions, 1);
options->layer = layer;
options->add_mask_type = GIMP_ADD_WHITE_MASK;
options->invert = FALSE;
options->dialog =
gimp_viewable_dialog_new (GIMP_VIEWABLE (layer),
_("Add Layer Mask"), "gimp-layer-add-mask",
GIMP_STOCK_LAYER_MASK,
_("Add a Mask to the Layer"),
widget,
gimp_standard_help_func,
GIMP_HELP_LAYER_MASK_ADD,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect (options->dialog, "response",
G_CALLBACK (layers_add_mask_response),
options);
g_object_weak_ref (G_OBJECT (options->dialog),
(GWeakNotify) g_free, options);
vbox = gtk_vbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (options->dialog)->vbox),
vbox);
gtk_widget_show (vbox);
frame =
gimp_enum_radio_frame_new (GIMP_TYPE_ADD_MASK_TYPE,
gtk_label_new (_("Initialize Layer Mask to:")),
G_CALLBACK (gimp_radio_button_update),
&options->add_mask_type,
&button);
gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (button),
options->add_mask_type);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
button = gtk_check_button_new_with_mnemonic (_("In_vert Mask"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), options->invert);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&options->invert);
gtk_widget_show (options->dialog);
}
void
layers_mask_apply_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpMaskApplyMode mode;
return_if_no_layer (gimage, layer, data);
mode = (GimpMaskApplyMode) value;
if (gimp_layer_get_mask (layer))
{
gimp_layer_apply_mask (layer, mode, TRUE);
gimp_image_flush (gimage);
}
}
void
layers_mask_edit_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayerMask *mask;
return_if_no_layer (gimage, layer, data);
mask = gimp_layer_get_mask (layer);
if (mask)
{
gboolean active;
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gimp_layer_mask_set_edit (mask, active);
gimp_image_flush (gimage);
}
}
void
layers_mask_show_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayerMask *mask;
return_if_no_layer (gimage, layer, data);
mask = gimp_layer_get_mask (layer);
if (mask)
{
gboolean active;
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gimp_layer_mask_set_show (mask, active);
gimp_image_flush (gimage);
}
}
void
layers_mask_disable_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayerMask *mask;
return_if_no_layer (gimage, layer, data);
mask = gimp_layer_get_mask (layer);
if (mask)
{
gboolean active;
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gimp_layer_mask_set_apply (mask, ! active);
gimp_image_flush (gimage);
}
}
void
layers_mask_to_selection_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpChannelOps op;
GimpImage *gimage;
GimpLayer *layer;
GimpLayerMask *mask;
return_if_no_layer (gimage, layer, data);
op = (GimpChannelOps) value;
mask = gimp_layer_get_mask (layer);
if (mask)
{
gint off_x, off_y;
gimp_item_offsets (GIMP_ITEM (mask), &off_x, &off_y);
gimp_channel_select_channel (gimp_image_get_mask (gimage),
_("Layer Mask to Selection"),
GIMP_CHANNEL (mask),
off_x, off_y,
op, FALSE, 0.0, 0.0);
gimp_image_flush (gimage);
}
}
void
layers_alpha_add_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
{
gimp_layer_add_alpha (layer);
gimp_image_flush (gimage);
}
}
void
layers_alpha_to_selection_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpChannelOps op;
GimpImage *gimage;
GimpLayer *layer;
return_if_no_layer (gimage, layer, data);
op = (GimpChannelOps) value;
gimp_channel_select_alpha (gimp_image_get_mask (gimage),
GIMP_DRAWABLE (layer),
op, FALSE, 0.0, 0.0);
gimp_image_flush (gimage);
}
void
layers_opacity_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
gdouble opacity;
GimpUndo *undo;
gboolean push_undo = TRUE;
return_if_no_layer (gimage, layer, data);
undo = gimp_image_undo_can_compress (gimage, GIMP_TYPE_ITEM_UNDO,
GIMP_UNDO_LAYER_OPACITY);
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
push_undo = FALSE;
opacity = action_select_value ((GimpActionSelectType) value,
gimp_layer_get_opacity (layer),
0.0, 1.0,
0.01, 0.1, FALSE);
gimp_layer_set_opacity (layer, opacity, push_undo);
gimp_image_flush (gimage);
}
void
layers_mode_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
GimpLayerModeEffects layer_mode;
gint index;
GimpUndo *undo;
gboolean push_undo = TRUE;
return_if_no_layer (gimage, layer, data);
undo = gimp_image_undo_can_compress (gimage, GIMP_TYPE_ITEM_UNDO,
GIMP_UNDO_LAYER_MODE);
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
push_undo = FALSE;
layer_mode = gimp_layer_get_mode (layer);
index = action_select_value ((GimpActionSelectType) value,
layers_mode_index (layer_mode),
0, G_N_ELEMENTS (layer_modes) - 1,
1.0, 1.0, FALSE);
gimp_layer_set_mode (layer, layer_modes[index], push_undo);
gimp_image_flush (gimage);
}
void
layers_preserve_trans_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
GimpLayer *layer;
gboolean preserve;
return_if_no_layer (gimage, layer, data);
preserve = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
if (preserve != gimp_layer_get_preserve_trans (layer))
{
GimpUndo *undo;
gboolean push_undo = TRUE;
undo = gimp_image_undo_can_compress (gimage, GIMP_TYPE_ITEM_UNDO,
GIMP_UNDO_LAYER_PRESERVE_TRANS);
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
push_undo = FALSE;
gimp_layer_set_preserve_trans (layer, preserve, push_undo);
gimp_image_flush (gimage);
}
}
/* private functions */
static void
layers_new_layer_dialog (GimpImage *gimage,
GimpContext *context,
GtkWidget *parent)
{
NewLayerOptions *options;
GtkWidget *vbox;
GtkWidget *table;
GtkWidget *label;
GtkObject *adjustment;
GtkWidget *spinbutton;
GtkWidget *frame;
GtkWidget *button;
options = g_new0 (NewLayerOptions, 1);
options->fill_type = fill_type;
options->gimage = gimage;
options->context = context;
options->dialog =
gimp_viewable_dialog_new (GIMP_VIEWABLE (gimage),
_("New Layer"), "gimp-layer-new",
GIMP_STOCK_LAYER,
_("Create a New Layer"),
parent,
gimp_standard_help_func,
GIMP_HELP_LAYER_NEW,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect (options->dialog, "response",
G_CALLBACK (layers_new_layer_response),
options);
g_object_weak_ref (G_OBJECT (options->dialog),
(GWeakNotify) g_free,
options);
vbox = gtk_vbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (options->dialog)->vbox),
vbox);
gtk_widget_show (vbox);
table = gtk_table_new (3, 2, FALSE);
gtk_table_set_col_spacing (GTK_TABLE (table), 0, 6);
gtk_table_set_row_spacing (GTK_TABLE (table), 0, 6);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
/* The name label and entry */
options->name_entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (options->name_entry),
(layer_name ? layer_name : _("New Layer")));
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("Layer _Name:"), 0.0, 0.5,
options->name_entry, 1, FALSE);
/* The size labels */
label = gtk_label_new (_("Width:"));
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, 0);
gtk_widget_show (label);
label = gtk_label_new (_("Height:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_widget_show (label);
/* The size sizeentry */
spinbutton = gimp_spin_button_new (&adjustment,
1, 1, 1, 1, 10, 1,
1, 2);
gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
options->size_se = gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a",
TRUE, TRUE, FALSE, 10,
GIMP_SIZE_ENTRY_UPDATE_SIZE);
gtk_table_set_col_spacing (GTK_TABLE (options->size_se), 1, 4);
gtk_table_set_row_spacing (GTK_TABLE (options->size_se), 0, 2);
gimp_size_entry_add_field (GIMP_SIZE_ENTRY (options->size_se),
GTK_SPIN_BUTTON (spinbutton), NULL);
gtk_table_attach_defaults (GTK_TABLE (options->size_se), spinbutton,
1, 2, 0, 1);
gtk_widget_show (spinbutton);
gtk_table_attach (GTK_TABLE (table), options->size_se, 1, 2, 1, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (options->size_se);
gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (options->size_se),
GIMP_UNIT_PIXEL);
gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (options->size_se), 0,
gimage->xresolution, FALSE);
gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (options->size_se), 1,
gimage->yresolution, FALSE);
gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (options->size_se), 0,
GIMP_MIN_IMAGE_SIZE,
GIMP_MAX_IMAGE_SIZE);
gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (options->size_se), 1,
GIMP_MIN_IMAGE_SIZE,
GIMP_MAX_IMAGE_SIZE);
gimp_size_entry_set_size (GIMP_SIZE_ENTRY (options->size_se), 0,
0, gimage->width);
gimp_size_entry_set_size (GIMP_SIZE_ENTRY (options->size_se), 1,
0, gimage->height);
gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (options->size_se), 0,
gimage->width);
gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (options->size_se), 1,
gimage->height);
/* The radio frame */
frame = gimp_enum_radio_frame_new_with_range (GIMP_TYPE_FILL_TYPE,
GIMP_FOREGROUND_FILL,
GIMP_TRANSPARENT_FILL,
gtk_label_new (_("Layer Fill Type")),
G_CALLBACK (gimp_radio_button_update),
&options->fill_type,
&button);
gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (button),
options->fill_type);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
gtk_widget_show (options->dialog);
}
static void
layers_new_layer_response (GtkWidget *widget,
gint response_id,
NewLayerOptions *options)
{
if (response_id == GTK_RESPONSE_OK)
{
GimpLayer *layer;
if (layer_name)
g_free (layer_name);
layer_name =
g_strdup (gtk_entry_get_text (GTK_ENTRY (options->name_entry)));
options->xsize =
RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (options->size_se),
0));
options->ysize =
RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (options->size_se),
1));
fill_type = options->fill_type;
layer = gimp_layer_new (options->gimage,
options->xsize,
options->ysize,
gimp_image_base_type_with_alpha (options->gimage),
layer_name,
GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
if (layer)
{
gimp_drawable_fill_by_type (GIMP_DRAWABLE (layer),
options->context,
fill_type);
gimp_image_add_layer (options->gimage, layer, -1);
gimp_image_flush (options->gimage);
}
else
{
g_message ("new_layer_query_response: "
"could not allocate new layer");
}
}
gtk_widget_destroy (options->dialog);
}
static void
layers_edit_layer_toggle_rename (GtkWidget *widget,
EditLayerOptions *options)
{
if (GTK_TOGGLE_BUTTON (widget)->active &&
gimp_drawable_is_text_layer (GIMP_DRAWABLE (options->layer)))
{
GimpTextLayer *text_layer = GIMP_TEXT_LAYER (options->layer);
GimpText *text = gimp_text_layer_get_text (text_layer);
if (text && text->text)
{
gchar *name = gimp_utf8_strtrim (text->text, 30);
gtk_entry_set_text (GTK_ENTRY (options->name_entry), name);
g_free (name);
}
}
}
static void
layers_edit_layer_dialog (GimpLayer *layer,
GimpContext *context,
GtkWidget *parent)
{
EditLayerOptions *options;
GtkWidget *vbox;
GtkWidget *table;
g_return_if_fail (GIMP_IS_LAYER (layer));
g_return_if_fail (GIMP_IS_CONTEXT (context));
options = g_new0 (EditLayerOptions, 1);
options->layer = layer;
options->gimage = gimp_item_get_image (GIMP_ITEM (layer));
options->dialog =
gimp_viewable_dialog_new (GIMP_VIEWABLE (layer),
_("Layer Attributes"), "gimp-layer-edit",
GIMP_STOCK_EDIT,
_("Edit Layer Attributes"),
parent,
gimp_standard_help_func,
GIMP_HELP_LAYER_EDIT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect (options->dialog, "response",
G_CALLBACK (layers_edit_layer_response),
options);
g_object_weak_ref (G_OBJECT (options->dialog),
(GWeakNotify) g_free,
options);
vbox = gtk_vbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (options->dialog)->vbox),
vbox);
gtk_widget_show (vbox);
table = gtk_table_new (1, 2, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
options->name_entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (options->name_entry), TRUE);
gtk_entry_set_text (GTK_ENTRY (options->name_entry),
gimp_object_get_name (GIMP_OBJECT (layer)));
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("Layer _Name"), 1.0, 0.5,
options->name_entry, 1, FALSE);
/* For text layers add a toggle to control "auto-rename" */
if (gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer)))
{
options->toggle =
gtk_check_button_new_with_mnemonic (_("Set Name from _Text"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->toggle),
GIMP_TEXT_LAYER (layer)->auto_rename);
gtk_table_attach (GTK_TABLE (table), options->toggle, 1, 2, 1, 2,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (options->toggle);
g_signal_connect (options->toggle, "toggled",
G_CALLBACK (layers_edit_layer_toggle_rename),
options);
}
gtk_widget_show (options->dialog);
}
static void
layers_edit_layer_response (GtkWidget *widget,
gint response_id,
EditLayerOptions *options)
{
if (response_id == GTK_RESPONSE_OK)
{
GimpLayer *layer = options->layer;
const gchar *new_name;
new_name = gtk_entry_get_text (GTK_ENTRY (options->name_entry));
if (strcmp (new_name, gimp_object_get_name (GIMP_OBJECT (layer))))
{
gimp_item_rename (GIMP_ITEM (layer), new_name);
gimp_image_flush (options->gimage);
}
if (options->toggle &&
gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer)))
{
g_object_set (layer,
"auto-rename",
GTK_TOGGLE_BUTTON (options->toggle)->active,
NULL);
}
}
gtk_widget_destroy (options->dialog);
}
static void
layers_add_mask_response (GtkWidget *widget,
gint response_id,
AddMaskOptions *options)
{
if (response_id == GTK_RESPONSE_OK)
{
GimpImage *gimage;
GimpLayerMask *mask;
GimpLayer *layer;
if ((layer = (options->layer)) && (gimage = GIMP_ITEM (layer)->gimage))
{
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_LAYER_ADD_MASK,
_("Add Layer Mask"));
mask = gimp_layer_create_mask (layer, options->add_mask_type);
if (options->invert)
gimp_channel_invert (GIMP_CHANNEL (mask), FALSE);
gimp_layer_add_mask (layer, mask, TRUE);
gimp_image_undo_group_end (gimage);
gimp_image_flush (gimage);
}
}
gtk_widget_destroy (options->dialog);
}
static void
layers_scale_layer_callback (GtkWidget *dialog,
GimpViewable *viewable,
gint width,
gint height,
GimpUnit unit,
GimpInterpolationType interpolation,
gpointer data)
{
GimpDisplay *gdisp = data ? GIMP_DISPLAY (data) : NULL;
if (width > 0 && height > 0)
{
GimpItem *item = GIMP_ITEM (viewable);
GimpProgress *progress;
GtkWidget *progress_dialog = NULL;
gtk_widget_destroy (dialog);
if (width == gimp_item_width (item) && height == gimp_item_height (item))
return;
if (gdisp)
{
progress = GIMP_PROGRESS (gdisp);
}
else
{
progress_dialog = gimp_progress_dialog_new ();
progress = GIMP_PROGRESS (progress_dialog);
}
progress = gimp_progress_start (progress, _("Scaling..."), FALSE);
gimp_item_scale_by_origin (item,
width, height, interpolation,
progress, TRUE);
if (progress)
gimp_progress_end (progress);
if (progress_dialog)
gtk_widget_destroy (progress_dialog);
gimp_image_flush (gimp_item_get_image (item));
}
else
{
g_message (_("Invalid width or height. Both must be positive."));
}
}
static void
layers_resize_layer_callback (GtkWidget *widget,
gpointer data)
{
ResizeLayerOptions *options = data;
if (options->dialog->width > 0 && options->dialog->height > 0)
{
GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (options->layer));
gtk_widget_set_sensitive (options->dialog->shell, FALSE);
gimp_item_resize (GIMP_ITEM (options->layer),
options->context,
options->dialog->width,
options->dialog->height,
options->dialog->offset_x,
options->dialog->offset_y);
gimp_image_flush (gimage);
gtk_widget_destroy (options->dialog->shell);
}
else
{
g_message (_("Invalid width or height. Both must be positive."));
}
}
static gint
layers_mode_index (GimpLayerModeEffects layer_mode)
{
gint i = 0;
while (i < (G_N_ELEMENTS (layer_modes) - 1) && layer_modes[i] != layer_mode)
i++;
return i;
}