2006-12-09 21:33:38 +00:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2001-04-20 16:27:44 +00:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-04-20 16:27:44 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 22:28:01 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-04-20 16:27:44 +00:00
|
|
|
* (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
|
2018-07-11 23:27:07 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2001-04-20 16:27:44 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2003-08-31 18:10:15 +00:00
|
|
|
#include <string.h>
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2008-10-09 20:24:04 +00:00
|
|
|
#include <gegl.h>
|
2001-04-20 16:27:44 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
#include "libgimpmath/gimpmath.h"
|
2001-05-21 20:30:16 +00:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2016-05-04 00:00:28 +02:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2001-04-20 16:27:44 +00:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2004-04-20 13:25:55 +00:00
|
|
|
#include "actions-types.h"
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2016-08-23 19:18:20 +02:00
|
|
|
#include "config/gimpdialogconfig.h"
|
2004-10-12 14:59:14 +00:00
|
|
|
|
2017-02-20 23:51:32 +01:00
|
|
|
#include "operations/layer-modes/gimp-layer-modes.h"
|
|
|
|
|
2001-07-07 12:17:23 +00:00
|
|
|
#include "core/gimp.h"
|
2012-03-17 18:30:13 +01:00
|
|
|
#include "core/gimpchannel.h"
|
2020-05-20 18:16:30 +02:00
|
|
|
#include "core/gimpchannel-combine.h"
|
2016-08-23 19:18:20 +02:00
|
|
|
#include "core/gimpcontainer.h"
|
2001-12-03 17:59:48 +00:00
|
|
|
#include "core/gimpcontext.h"
|
2016-03-08 01:38:05 +01:00
|
|
|
#include "core/gimpdrawable-fill.h"
|
2009-08-06 18:37:54 +02:00
|
|
|
#include "core/gimpgrouplayer.h"
|
2001-05-09 02:32:03 +00:00
|
|
|
#include "core/gimpimage.h"
|
include the new "paint-funcs/paint-funcs-types.h".
2001-11-28 Michael Natterer <mitch@gimp.org>
* app/base/base-types.h: include the new
"paint-funcs/paint-funcs-types.h".
* app/paint-funcs/Makefile.am
* app/paint-funcs/paint-funcs-types.h: new file. Includes
"base/base-types.h".
* app/paint-funcs/paint-funcs.[ch]: removed the enums here,
include "paint-funcs-types.h".
* app/widgets/widgets-types.h: include "display/display-types.h"
* app/display/display-types.h: include "widgets/widgets-types.h".
* app/tools/tools-types.h: include "display/display-types.h"
* app/gui/gui-types.h: include "tools/tools-types.h".
The order of namespaces/dependencies should be (but is not):
(base, paint-funcs) -> (core, file, xcf, pdb) ->
(widgets, display) -> tools -> gui
* app/path.c: include "tools/tools-types.h".
* app/core/Makefile.am
* app/core/gimpimage-guides.[ch]
* app/core/gimpimage-merge.[ch]
* app/core/gimpimage-resize.[ch]
* app/core/gimpimage-scale.[ch]: new files.
* app/core/gimpimage.[ch]: removed the stuff which is in the new
files. Reordered all functions in both the .h and .c files,
commented the groups of functions.
* app/core/gimpcontainer.c: create the handler_id using a counter,
not the address of a pointer, because the address *may* be the
same twice, added debugging output.
* app/core/gimpviewable.[ch]: added primitive support for getting
a preview GdkPixbuf.
* app/nav_window.c
* app/undo.c
* app/undo_history.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage-mask.[ch]
* app/display/gimpdisplay.c
* app/display/gimpdisplayshell-callbacks.c
* app/display/gimpdisplayshell-dnd.c
* app/display/gimpdisplayshell-render.c
* app/display/gimpdisplayshell-scale.c
* app/display/gimpdisplayshell-scroll.c
* app/gui/image-commands.c
* app/gui/info-window.c
* app/gui/layers-commands.c
* app/gui/palette-import-dialog.c
* app/tools/gimpbycolorselecttool.c
* app/tools/gimpeditselectiontool.c
* app/tools/gimpmeasuretool.c
* app/tools/gimpmovetool.c
* app/widgets/gimpcontainerview-utils.c
* app/xcf/xcf-load.c: changed accordingly, some cleanup.
* tools/pdbgen/pdb/guides.pdb
* tools/pdbgen/pdb/image.pdb: changed accordingly, reordered functions.
* app/plug_in.c: set the labels of the "Repeat" and "Re-Show" menu
items to the name of the last plug-in (Fixes #50986).
* app/display/gimpdisplayshell.[ch]: set the labels of "Undo" and
"Redo" to the resp. undo names. Much simplified the WM icon stuff
by removing most code and using gimp_viewable_get_new_preview_pixbuf().
* app/widgets/gimpbrushfactoryview.c: forgot to assign the GQuark
returned by gimp_container_add_handler().
* app/pdb/guides_cmds.c
* app/pdb/image_cmds.c
* libgimp/gimpimage_pdb.[ch]: regenerated.
2001-11-28 17:51:06 +00:00
|
|
|
#include "core/gimpimage-merge.h"
|
2003-02-13 11:23:50 +00:00
|
|
|
#include "core/gimpimage-undo.h"
|
2005-03-24 17:10:03 +00:00
|
|
|
#include "core/gimpimage-undo-push.h"
|
2004-06-23 00:23:25 +00:00
|
|
|
#include "core/gimpitemundo.h"
|
2017-02-02 00:38:25 +01:00
|
|
|
#include "core/gimplayerpropundo.h"
|
2016-05-20 16:46:26 +02:00
|
|
|
#include "core/gimplayer-floating-selection.h"
|
2015-06-17 13:21:01 +02:00
|
|
|
#include "core/gimplayer-new.h"
|
2008-11-04 12:07:17 +00:00
|
|
|
#include "core/gimppickable.h"
|
2012-09-22 20:35:36 +02:00
|
|
|
#include "core/gimppickable-auto-shrink.h"
|
2004-01-13 19:08:16 +00:00
|
|
|
#include "core/gimptoolinfo.h"
|
2004-06-23 00:23:25 +00:00
|
|
|
#include "core/gimpundostack.h"
|
2004-08-10 18:47:21 +00:00
|
|
|
#include "core/gimpprogress.h"
|
2001-05-09 02:32:03 +00:00
|
|
|
|
2004-03-18 18:00:38 +00:00
|
|
|
#include "text/gimptext.h"
|
2006-05-13 19:48:18 +00:00
|
|
|
#include "text/gimptext-vectors.h"
|
2004-01-05 00:28:12 +00:00
|
|
|
#include "text/gimptextlayer.h"
|
|
|
|
|
2018-11-13 11:30:49 +09:00
|
|
|
#include "vectors/gimpstroke.h"
|
|
|
|
#include "vectors/gimpvectors.h"
|
2006-05-13 19:48:18 +00:00
|
|
|
#include "vectors/gimpvectors-warp.h"
|
|
|
|
|
2004-10-16 15:48:23 +00:00
|
|
|
#include "widgets/gimpaction.h"
|
2004-01-31 20:23:53 +00:00
|
|
|
#include "widgets/gimpdock.h"
|
2003-08-21 15:54:47 +00:00
|
|
|
#include "widgets/gimphelp-ids.h"
|
2004-10-12 14:59:14 +00:00
|
|
|
#include "widgets/gimpprogressdialog.h"
|
2001-05-25 16:04:54 +00:00
|
|
|
|
2002-12-10 16:38:16 +00:00
|
|
|
#include "display/gimpdisplay.h"
|
2004-06-01 22:04:20 +00:00
|
|
|
#include "display/gimpdisplayshell.h"
|
2010-06-06 16:44:36 +02:00
|
|
|
#include "display/gimpimagewindow.h"
|
2002-12-10 16:38:16 +00:00
|
|
|
|
2004-01-13 19:08:16 +00:00
|
|
|
#include "tools/gimptexttool.h"
|
|
|
|
#include "tools/tool_manager.h"
|
|
|
|
|
2016-09-12 00:03:22 +02:00
|
|
|
#include "dialogs/dialogs.h"
|
2004-10-23 14:02:53 +00:00
|
|
|
#include "dialogs/layer-add-mask-dialog.h"
|
2004-10-22 22:28:45 +00:00
|
|
|
#include "dialogs/layer-options-dialog.h"
|
2004-09-13 15:15:23 +00:00
|
|
|
#include "dialogs/resize-dialog.h"
|
2004-10-12 14:59:14 +00:00
|
|
|
#include "dialogs/scale-dialog.h"
|
2004-04-20 13:25:55 +00:00
|
|
|
|
2004-05-03 14:03:51 +00:00
|
|
|
#include "actions.h"
|
2016-10-29 16:50:13 +02:00
|
|
|
#include "items-commands.h"
|
2001-04-20 16:27:44 +00:00
|
|
|
#include "layers-commands.h"
|
|
|
|
|
2003-03-25 16:38:19 +00:00
|
|
|
#include "gimp-intl.h"
|
2001-04-20 16:27:44 +00:00
|
|
|
|
|
|
|
|
2001-11-30 14:41:56 +00:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
static void layers_new_callback (GtkWidget *dialog,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const gchar *layer_name,
|
2017-01-08 23:00:19 +01:00
|
|
|
GimpLayerMode layer_mode,
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace layer_blend_space,
|
|
|
|
GimpLayerColorSpace layer_composite_space,
|
|
|
|
GimpLayerCompositeMode layer_composite_mode,
|
2016-10-21 22:54:10 +02:00
|
|
|
gdouble layer_opacity,
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpFillType layer_fill_type,
|
|
|
|
gint layer_width,
|
|
|
|
gint layer_height,
|
2016-10-21 22:54:10 +02:00
|
|
|
gint layer_offset_x,
|
|
|
|
gint layer_offset_y,
|
2016-10-23 22:45:08 +02:00
|
|
|
gboolean layer_visible,
|
2016-10-29 16:50:13 +02:00
|
|
|
GimpColorTag layer_color_tag,
|
2016-10-23 22:45:08 +02:00
|
|
|
gboolean layer_lock_pixels,
|
|
|
|
gboolean layer_lock_position,
|
|
|
|
gboolean layer_lock_alpha,
|
2016-09-24 21:10:07 +02:00
|
|
|
gboolean rename_text_layer,
|
|
|
|
gpointer user_data);
|
|
|
|
static void layers_edit_attributes_callback (GtkWidget *dialog,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const gchar *layer_name,
|
2017-01-08 23:00:19 +01:00
|
|
|
GimpLayerMode layer_mode,
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace layer_blend_space,
|
|
|
|
GimpLayerColorSpace layer_composite_space,
|
|
|
|
GimpLayerCompositeMode layer_composite_mode,
|
2016-10-21 22:54:10 +02:00
|
|
|
gdouble layer_opacity,
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpFillType layer_fill_type,
|
|
|
|
gint layer_width,
|
|
|
|
gint layer_height,
|
2016-10-21 22:54:10 +02:00
|
|
|
gint layer_offset_x,
|
|
|
|
gint layer_offset_y,
|
2016-10-23 22:45:08 +02:00
|
|
|
gboolean layer_visible,
|
2016-10-29 16:50:13 +02:00
|
|
|
GimpColorTag layer_color_tag,
|
2016-10-23 22:45:08 +02:00
|
|
|
gboolean layer_lock_pixels,
|
|
|
|
gboolean layer_lock_position,
|
|
|
|
gboolean layer_lock_alpha,
|
2016-09-24 21:10:07 +02:00
|
|
|
gboolean rename_text_layer,
|
|
|
|
gpointer user_data);
|
|
|
|
static void layers_add_mask_callback (GtkWidget *dialog,
|
2020-05-02 01:42:04 +02:00
|
|
|
GList *layers,
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpAddMaskType add_mask_type,
|
|
|
|
GimpChannel *channel,
|
|
|
|
gboolean invert,
|
|
|
|
gpointer user_data);
|
2016-09-25 22:18:37 +02:00
|
|
|
static void layers_scale_callback (GtkWidget *dialog,
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpUnit unit,
|
|
|
|
GimpInterpolationType interpolation,
|
|
|
|
gdouble xresolution,
|
|
|
|
gdouble yresolution,
|
|
|
|
GimpUnit resolution_unit,
|
|
|
|
gpointer user_data);
|
2016-09-25 22:18:37 +02:00
|
|
|
static void layers_resize_callback (GtkWidget *dialog,
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpViewable *viewable,
|
|
|
|
GimpContext *context,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpUnit unit,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
2021-02-07 22:06:41 +06:00
|
|
|
gdouble unused0,
|
|
|
|
gdouble unused1,
|
|
|
|
GimpUnit unused2,
|
2016-10-20 00:30:10 +02:00
|
|
|
GimpFillType fill_type,
|
2021-02-07 22:06:41 +06:00
|
|
|
GimpItemSet unused3,
|
|
|
|
gboolean unused4,
|
2016-09-24 21:10:07 +02:00
|
|
|
gpointer data);
|
|
|
|
|
2017-02-20 23:51:32 +01:00
|
|
|
static gint layers_mode_index (GimpLayerMode layer_mode,
|
|
|
|
const GimpLayerMode *modes,
|
|
|
|
gint n_modes);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
|
|
|
|
2004-09-19 22:26:41 +00:00
|
|
|
/* private variables */
|
|
|
|
|
2006-10-14 16:51:30 +00:00
|
|
|
static GimpUnit layer_resize_unit = GIMP_UNIT_PIXEL;
|
|
|
|
static GimpUnit layer_scale_unit = GIMP_UNIT_PIXEL;
|
|
|
|
static GimpInterpolationType layer_scale_interp = -1;
|
2004-09-19 22:26:41 +00:00
|
|
|
|
|
|
|
|
2001-11-30 14:41:56 +00:00
|
|
|
/* public functions */
|
|
|
|
|
2004-05-25 14:37:02 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_edit_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2017-05-13 00:15:05 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GtkWidget *widget;
|
|
|
|
return_if_no_layer (image, layer, data);
|
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
|
|
|
if (gimp_item_is_text_layer (GIMP_ITEM (layer)))
|
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
layers_edit_text_cmd_callback (action, value, data);
|
2017-05-13 00:15:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
layers_edit_attributes_cmd_callback (action, value, data);
|
2017-05-13 00:15:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_edit_text_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-05-25 14:37:02 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2004-05-25 14:37:02 +00:00
|
|
|
GimpLayer *layer;
|
|
|
|
GtkWidget *widget;
|
2004-10-16 15:48:23 +00:00
|
|
|
GimpTool *active_tool;
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_layer (image, layer, data);
|
2004-05-25 14:37:02 +00:00
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
2017-05-13 00:01:56 +02:00
|
|
|
g_return_if_fail (gimp_item_is_text_layer (GIMP_ITEM (layer)));
|
2004-10-16 15:48:23 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
active_tool = tool_manager_get_active (image->gimp);
|
2004-10-16 15:48:23 +00:00
|
|
|
|
|
|
|
if (! GIMP_IS_TEXT_TOOL (active_tool))
|
|
|
|
{
|
2006-09-08 13:42:00 +00:00
|
|
|
GimpToolInfo *tool_info = gimp_get_tool_info (image->gimp,
|
|
|
|
"gimp-text-tool");
|
2004-10-16 15:48:23 +00:00
|
|
|
|
|
|
|
if (GIMP_IS_TOOL_INFO (tool_info))
|
|
|
|
{
|
|
|
|
gimp_context_set_tool (action_data_get_context (data), tool_info);
|
2006-03-28 17:08:36 +00:00
|
|
|
active_tool = tool_manager_get_active (image->gimp);
|
2004-10-16 15:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GIMP_IS_TEXT_TOOL (active_tool))
|
2017-05-13 00:55:43 +02:00
|
|
|
{
|
2018-05-29 10:19:50 -04:00
|
|
|
if (gimp_text_tool_set_layer (GIMP_TEXT_TOOL (active_tool), layer))
|
|
|
|
{
|
|
|
|
GimpDisplayShell *shell;
|
2017-05-13 00:55:43 +02:00
|
|
|
|
2018-05-29 10:19:50 -04:00
|
|
|
shell = gimp_display_get_shell (active_tool->display);
|
|
|
|
gtk_widget_grab_focus (shell->canvas);
|
|
|
|
}
|
2017-05-13 00:55:43 +02:00
|
|
|
}
|
2004-05-25 14:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_edit_attributes_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-05-25 14:37:02 +00:00
|
|
|
{
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GtkWidget *widget;
|
|
|
|
GtkWidget *dialog;
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_layer (image, layer, data);
|
2004-05-25 14:37:02 +00:00
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
#define EDIT_DIALOG_KEY "gimp-layer-edit-attributes-dialog"
|
|
|
|
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (layer), EDIT_DIALOG_KEY);
|
|
|
|
|
|
|
|
if (! dialog)
|
|
|
|
{
|
2016-10-26 16:51:56 +02:00
|
|
|
GimpItem *item = GIMP_ITEM (layer);
|
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
dialog = layer_options_dialog_new (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
|
|
layer,
|
|
|
|
action_data_get_context (data),
|
|
|
|
widget,
|
|
|
|
_("Layer Attributes"),
|
|
|
|
"gimp-layer-edit",
|
2017-03-05 16:01:59 +01:00
|
|
|
GIMP_ICON_EDIT,
|
2016-09-24 21:10:07 +02:00
|
|
|
_("Edit Layer Attributes"),
|
|
|
|
GIMP_HELP_LAYER_EDIT,
|
|
|
|
gimp_object_get_name (layer),
|
2016-10-21 22:54:10 +02:00
|
|
|
gimp_layer_get_mode (layer),
|
2017-02-12 23:49:26 +01:00
|
|
|
gimp_layer_get_blend_space (layer),
|
|
|
|
gimp_layer_get_composite_space (layer),
|
|
|
|
gimp_layer_get_composite_mode (layer),
|
2016-10-21 22:54:10 +02:00
|
|
|
gimp_layer_get_opacity (layer),
|
2016-09-24 21:10:07 +02:00
|
|
|
0 /* unused */,
|
2016-10-26 16:51:56 +02:00
|
|
|
gimp_item_get_visible (item),
|
2016-10-29 16:50:13 +02:00
|
|
|
gimp_item_get_color_tag (item),
|
2016-10-26 16:51:56 +02:00
|
|
|
gimp_item_get_lock_content (item),
|
|
|
|
gimp_item_get_lock_position (item),
|
|
|
|
gimp_layer_get_lock_alpha (layer),
|
2016-09-24 21:10:07 +02:00
|
|
|
layers_edit_attributes_callback,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
dialogs_attach_dialog (G_OBJECT (layer), EDIT_DIALOG_KEY, dialog);
|
|
|
|
}
|
2016-08-24 12:33:56 +02:00
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
2004-05-25 14:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_new_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-05-25 14:37:02 +00:00
|
|
|
{
|
2016-09-24 21:10:07 +02:00
|
|
|
GimpImage *image;
|
|
|
|
GtkWidget *widget;
|
|
|
|
GimpLayer *floating_sel;
|
|
|
|
GtkWidget *dialog;
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_image (image, data);
|
2004-05-25 14:37:02 +00:00
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
2004-10-16 15:48:23 +00:00
|
|
|
/* If there is a floating selection, the new command transforms
|
|
|
|
* the current fs into a new layer
|
|
|
|
*/
|
2008-11-14 15:01:44 +00:00
|
|
|
if ((floating_sel = gimp_image_get_floating_selection (image)))
|
2004-10-16 15:48:23 +00:00
|
|
|
{
|
2007-12-06 18:00:10 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! floating_sel_to_layer (floating_sel, &error))
|
|
|
|
{
|
2008-11-04 12:33:09 +00:00
|
|
|
gimp_message_literal (image->gimp,
|
2013-09-15 04:59:20 +12:00
|
|
|
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
|
|
|
error->message);
|
2007-12-06 18:00:10 +00:00
|
|
|
g_clear_error (&error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2004-10-16 15:48:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
#define NEW_DIALOG_KEY "gimp-layer-new-dialog"
|
|
|
|
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), NEW_DIALOG_KEY);
|
|
|
|
|
|
|
|
if (! dialog)
|
|
|
|
{
|
2018-04-24 13:58:30 +02:00
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
2020-05-03 00:28:13 +02:00
|
|
|
const gchar *title;
|
|
|
|
gchar *desc;
|
|
|
|
gint n_layers;
|
2018-04-24 13:58:30 +02:00
|
|
|
GimpLayerMode layer_mode = config->layer_new_mode;
|
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
n_layers = g_list_length (gimp_image_get_selected_layers (image));
|
|
|
|
title = ngettext ("New Layer", "New Layers", n_layers > 0 ? n_layers : 1);
|
|
|
|
desc = ngettext ("Create a New Layer", "Create %d New Layers", n_layers > 0 ? n_layers : 1);
|
|
|
|
desc = g_strdup_printf (desc, n_layers > 0 ? n_layers : 1);
|
|
|
|
|
2018-04-24 13:58:30 +02:00
|
|
|
if (layer_mode == GIMP_LAYER_MODE_NORMAL ||
|
|
|
|
layer_mode == GIMP_LAYER_MODE_NORMAL_LEGACY)
|
|
|
|
{
|
|
|
|
layer_mode = gimp_image_get_default_new_layer_mode (image);
|
|
|
|
}
|
2016-09-24 21:10:07 +02:00
|
|
|
|
|
|
|
dialog = layer_options_dialog_new (image, NULL,
|
|
|
|
action_data_get_context (data),
|
|
|
|
widget,
|
2020-05-03 00:28:13 +02:00
|
|
|
title,
|
2016-09-24 21:10:07 +02:00
|
|
|
"gimp-layer-new",
|
2017-03-05 16:01:59 +01:00
|
|
|
GIMP_ICON_LAYER,
|
2020-05-03 00:28:13 +02:00
|
|
|
desc,
|
2016-09-24 21:10:07 +02:00
|
|
|
GIMP_HELP_LAYER_NEW,
|
|
|
|
config->layer_new_name,
|
2018-04-24 13:58:30 +02:00
|
|
|
layer_mode,
|
2017-02-12 23:49:26 +01:00
|
|
|
config->layer_new_blend_space,
|
|
|
|
config->layer_new_composite_space,
|
2017-02-02 00:38:25 +01:00
|
|
|
config->layer_new_composite_mode,
|
2016-10-21 22:54:10 +02:00
|
|
|
config->layer_new_opacity,
|
2016-09-24 21:10:07 +02:00
|
|
|
config->layer_new_fill_type,
|
2016-10-26 16:51:56 +02:00
|
|
|
TRUE,
|
2016-10-29 16:50:13 +02:00
|
|
|
GIMP_COLOR_TAG_NONE,
|
2016-10-26 16:51:56 +02:00
|
|
|
FALSE,
|
|
|
|
FALSE,
|
|
|
|
FALSE,
|
2016-09-24 21:10:07 +02:00
|
|
|
layers_new_callback,
|
|
|
|
NULL);
|
2020-05-03 00:28:13 +02:00
|
|
|
g_free (desc);
|
2016-09-24 21:10:07 +02:00
|
|
|
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), NEW_DIALOG_KEY, dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
2004-10-16 15:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_new_last_vals_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-10-16 15:48:23 +00:00
|
|
|
{
|
2017-01-08 23:00:19 +01:00
|
|
|
GimpImage *image;
|
|
|
|
GtkWidget *widget;
|
2018-03-25 14:08:50 +02:00
|
|
|
GimpLayer *layer;
|
2017-01-08 23:00:19 +01:00
|
|
|
GimpDialogConfig *config;
|
2020-04-20 01:56:23 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *new_layers = NULL;
|
|
|
|
GList *iter;
|
2018-04-24 13:58:30 +02:00
|
|
|
GimpLayerMode layer_mode;
|
2020-05-03 00:28:13 +02:00
|
|
|
gint n_layers;
|
|
|
|
gboolean run_once;
|
2018-03-23 18:43:22 +01:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_image (image, data);
|
2007-12-06 18:00:10 +00:00
|
|
|
return_if_no_widget (widget, data);
|
2004-10-16 15:48:23 +00:00
|
|
|
|
2016-08-24 12:33:56 +02:00
|
|
|
config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
|
2004-10-16 15:48:23 +00:00
|
|
|
/* If there is a floating selection, the new command transforms
|
|
|
|
* the current fs into a new layer
|
|
|
|
*/
|
2018-03-25 14:08:50 +02:00
|
|
|
if (gimp_image_get_floating_selection (image))
|
2004-10-16 15:48:23 +00:00
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
layers_new_cmd_callback (action, value, data);
|
2004-10-16 15:48:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-24 13:58:30 +02:00
|
|
|
layer_mode = config->layer_new_mode;
|
|
|
|
|
|
|
|
if (layer_mode == GIMP_LAYER_MODE_NORMAL ||
|
|
|
|
layer_mode == GIMP_LAYER_MODE_NORMAL_LEGACY)
|
|
|
|
{
|
|
|
|
layer_mode = gimp_image_get_default_new_layer_mode (image);
|
|
|
|
}
|
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
layers = gimp_image_get_selected_layers (image);
|
|
|
|
layers = g_list_copy (layers);
|
|
|
|
n_layers = g_list_length (layers);
|
|
|
|
run_once = (n_layers == 0);
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
ngettext ("New layer",
|
|
|
|
"New layers",
|
|
|
|
n_layers > 0 ? n_layers : 1));
|
|
|
|
for (iter = layers; iter || run_once ; iter = iter ? iter->next : NULL)
|
2020-04-20 01:56:23 +02:00
|
|
|
{
|
|
|
|
GimpLayer *parent;
|
|
|
|
gint position;
|
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
run_once = FALSE;
|
|
|
|
if (iter)
|
2020-04-20 01:56:23 +02:00
|
|
|
{
|
2020-05-03 00:28:13 +02:00
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)))
|
|
|
|
{
|
|
|
|
parent = iter->data;
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parent = GIMP_LAYER (gimp_item_get_parent (iter->data));
|
|
|
|
position = gimp_item_get_index (iter->data);
|
|
|
|
}
|
2020-04-20 01:56:23 +02:00
|
|
|
}
|
2020-05-03 00:28:13 +02:00
|
|
|
else /* run_once */
|
2020-04-20 01:56:23 +02:00
|
|
|
{
|
2020-05-03 00:28:13 +02:00
|
|
|
parent = NULL;
|
|
|
|
position = -1;
|
2020-04-20 01:56:23 +02:00
|
|
|
}
|
|
|
|
layer = gimp_layer_new (image,
|
|
|
|
gimp_image_get_width (image),
|
|
|
|
gimp_image_get_height (image),
|
|
|
|
gimp_image_get_layer_format (image, TRUE),
|
|
|
|
config->layer_new_name,
|
|
|
|
config->layer_new_opacity,
|
|
|
|
layer_mode);
|
|
|
|
|
|
|
|
gimp_drawable_fill (GIMP_DRAWABLE (layer),
|
|
|
|
action_data_get_context (data),
|
|
|
|
config->layer_new_fill_type);
|
|
|
|
gimp_layer_set_blend_space (layer,
|
|
|
|
config->layer_new_blend_space, FALSE);
|
|
|
|
gimp_layer_set_composite_space (layer,
|
|
|
|
config->layer_new_composite_space, FALSE);
|
|
|
|
gimp_layer_set_composite_mode (layer,
|
|
|
|
config->layer_new_composite_mode, FALSE);
|
|
|
|
|
|
|
|
gimp_image_add_layer (image, layer, parent, position, TRUE);
|
|
|
|
new_layers = g_list_prepend (new_layers, layer);
|
|
|
|
}
|
2020-05-03 00:28:13 +02:00
|
|
|
gimp_image_set_selected_layers (image, new_layers);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
2020-04-20 01:56:23 +02:00
|
|
|
g_list_free (layers);
|
|
|
|
g_list_free (new_layers);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2004-05-25 14:37:02 +00:00
|
|
|
}
|
|
|
|
|
2008-08-07 15:53:15 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_new_from_visible_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2008-08-07 15:53:15 +00:00
|
|
|
{
|
2016-05-04 00:00:28 +02:00
|
|
|
GimpImage *image;
|
2019-09-19 20:00:00 +03:00
|
|
|
GimpDisplayShell *shell;
|
2016-05-04 00:00:28 +02:00
|
|
|
GimpLayer *layer;
|
|
|
|
GimpPickable *pickable;
|
|
|
|
GimpColorProfile *profile;
|
2008-08-07 15:53:15 +00:00
|
|
|
return_if_no_image (image, data);
|
2019-09-19 20:00:00 +03:00
|
|
|
return_if_no_shell (shell, data);
|
2008-08-07 15:53:15 +00:00
|
|
|
|
2019-09-19 20:00:00 +03:00
|
|
|
pickable = gimp_display_shell_get_canvas_pickable (shell);
|
2008-08-07 15:53:15 +00:00
|
|
|
|
2009-12-14 14:00:01 +01:00
|
|
|
gimp_pickable_flush (pickable);
|
|
|
|
|
2016-05-04 00:00:28 +02:00
|
|
|
profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
|
|
|
2015-06-20 00:02:11 +02:00
|
|
|
layer = gimp_layer_new_from_gegl_buffer (gimp_pickable_get_buffer (pickable),
|
|
|
|
image,
|
|
|
|
gimp_image_get_layer_format (image,
|
|
|
|
TRUE),
|
|
|
|
_("Visible"),
|
|
|
|
GIMP_OPACITY_OPAQUE,
|
2017-08-21 20:04:25 +02:00
|
|
|
gimp_image_get_default_new_layer_mode (image),
|
2016-05-04 00:00:28 +02:00
|
|
|
profile);
|
2009-08-03 22:30:36 +02:00
|
|
|
|
2016-09-25 22:18:37 +02:00
|
|
|
gimp_image_add_layer (image, layer, GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2008-08-07 15:53:15 +00:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
|
2009-08-06 18:37:54 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_new_group_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2009-08-06 18:37:54 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-03 00:28:13 +02:00
|
|
|
GList *new_layers = NULL;
|
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
gint n_layers;
|
|
|
|
gboolean run_once;
|
|
|
|
|
2009-08-06 18:37:54 +02:00
|
|
|
return_if_no_image (image, data);
|
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
layers = gimp_image_get_selected_layers (image);
|
|
|
|
layers = g_list_copy (layers);
|
|
|
|
n_layers = g_list_length (layers);
|
|
|
|
run_once = (n_layers == 0);
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
ngettext ("New layer group",
|
|
|
|
"New layer groups",
|
|
|
|
n_layers > 0 ? n_layers : 1));
|
2009-08-06 18:37:54 +02:00
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
for (iter = layers; iter || run_once ; iter = iter ? iter->next : NULL)
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayer *parent;
|
|
|
|
gint position;
|
|
|
|
|
|
|
|
run_once = FALSE;
|
|
|
|
if (iter)
|
|
|
|
{
|
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)))
|
|
|
|
{
|
|
|
|
parent = iter->data;
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parent = GIMP_LAYER (gimp_item_get_parent (iter->data));
|
|
|
|
position = gimp_item_get_index (iter->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* run_once */
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
position = -1;
|
|
|
|
}
|
|
|
|
layer = gimp_group_layer_new (image);
|
|
|
|
|
|
|
|
gimp_image_add_layer (image, layer, parent, position, TRUE);
|
|
|
|
new_layers = g_list_prepend (new_layers, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_set_selected_layers (image, new_layers);
|
|
|
|
gimp_image_undo_group_end (image);
|
2009-08-06 18:37:54 +02:00
|
|
|
gimp_image_flush (image);
|
2020-05-03 00:28:13 +02:00
|
|
|
|
|
|
|
g_list_free (layers);
|
|
|
|
g_list_free (new_layers);
|
2009-08-06 18:37:54 +02:00
|
|
|
}
|
|
|
|
|
2001-04-20 16:27:44 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_select_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpImage *image;
|
2020-05-05 11:53:07 +02:00
|
|
|
GList *new_layers = NULL;
|
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpActionSelectType select_type;
|
2020-05-05 11:53:07 +02:00
|
|
|
gboolean run_once;
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_image (image, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
select_type = (GimpActionSelectType) g_variant_get_int32 (value);
|
|
|
|
|
2020-05-05 11:53:07 +02:00
|
|
|
layers = gimp_image_get_selected_layers (image);
|
|
|
|
run_once = (g_list_length (layers) == 0);
|
2003-06-06 10:30:14 +00:00
|
|
|
|
2020-05-05 11:53:07 +02:00
|
|
|
for (iter = layers; iter || run_once; iter = iter ? iter->next : NULL)
|
|
|
|
{
|
2021-06-20 15:38:10 +02:00
|
|
|
GimpLayer *new_layer;
|
|
|
|
GimpContainer *container;
|
|
|
|
|
2020-05-05 11:53:07 +02:00
|
|
|
if (iter)
|
2021-06-20 15:38:10 +02:00
|
|
|
{
|
|
|
|
container = gimp_item_get_container (GIMP_ITEM (iter->data));
|
|
|
|
}
|
2020-05-05 11:53:07 +02:00
|
|
|
else /* run_once */
|
2021-06-20 15:38:10 +02:00
|
|
|
{
|
|
|
|
container = gimp_image_get_layers (image);
|
|
|
|
run_once = FALSE;
|
|
|
|
}
|
2020-05-05 11:53:07 +02:00
|
|
|
new_layer = (GimpLayer *) action_select_object (select_type,
|
|
|
|
container,
|
2021-06-20 15:38:10 +02:00
|
|
|
iter ? iter->data : NULL);
|
2020-05-05 11:53:07 +02:00
|
|
|
if (new_layer)
|
|
|
|
new_layers = g_list_prepend (new_layers, new_layer);
|
|
|
|
}
|
2003-06-06 10:30:14 +00:00
|
|
|
|
2020-05-05 11:53:07 +02:00
|
|
|
if (new_layers)
|
2003-06-06 10:30:14 +00:00
|
|
|
{
|
2020-05-05 11:53:07 +02:00
|
|
|
gimp_image_set_selected_layers (image, new_layers);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2003-06-06 10:30:14 +00:00
|
|
|
}
|
2020-05-05 11:53:07 +02:00
|
|
|
|
|
|
|
g_list_free (new_layers);
|
2003-06-06 10:30:14 +00:00
|
|
|
}
|
|
|
|
|
2001-04-20 16:27:44 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_raise_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-05-04 17:11:14 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *raised_layers = NULL;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
index = gimp_item_get_index (iter->data);
|
|
|
|
if (index > 0)
|
|
|
|
raised_layers = g_list_prepend (raised_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_DISPLACE,
|
|
|
|
ngettext ("Raise Layer",
|
|
|
|
"Raise Layers",
|
|
|
|
g_list_length (raised_layers)));
|
|
|
|
for (iter = raised_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_raise_item (image, iter->data, NULL);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-04 17:11:14 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (raised_layers);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_raise_to_top_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-05-04 17:11:14 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *raised_layers = NULL;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
index = gimp_item_get_index (iter->data);
|
|
|
|
if (index > 0)
|
|
|
|
raised_layers = g_list_prepend (raised_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_DISPLACE,
|
|
|
|
ngettext ("Raise Layer to Top",
|
|
|
|
"Raise Layers to Top",
|
|
|
|
g_list_length (raised_layers)));
|
|
|
|
|
|
|
|
for (iter = raised_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_raise_item_to_top (image, iter->data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-04 17:11:14 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (raised_layers);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_lower_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-05-04 17:11:14 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *lowered_layers = NULL;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GList *layer_list;
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
layer_list = gimp_item_get_container_iter (GIMP_ITEM (iter->data));
|
|
|
|
index = gimp_item_get_index (iter->data);
|
|
|
|
if (index < g_list_length (layer_list) - 1)
|
|
|
|
lowered_layers = g_list_prepend (lowered_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_DISPLACE,
|
|
|
|
ngettext ("Lower Layer",
|
|
|
|
"Lower Layers",
|
|
|
|
g_list_length (lowered_layers)));
|
|
|
|
|
|
|
|
for (iter = lowered_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_lower_item (image, iter->data, NULL);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-04 17:11:14 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (lowered_layers);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_lower_to_bottom_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-05-04 17:11:14 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *lowered_layers = NULL;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GList *layer_list;
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
layer_list = gimp_item_get_container_iter (GIMP_ITEM (iter->data));
|
|
|
|
index = gimp_item_get_index (iter->data);
|
|
|
|
if (index < g_list_length (layer_list) - 1)
|
|
|
|
lowered_layers = g_list_prepend (lowered_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_DISPLACE,
|
|
|
|
ngettext ("Lower Layer to Bottom",
|
|
|
|
"Lower Layers to Bottom",
|
|
|
|
g_list_length (lowered_layers)));
|
|
|
|
|
|
|
|
for (iter = lowered_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_lower_item_to_bottom (image, iter->data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-04 17:11:14 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (lowered_layers);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_duplicate_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-04-20 19:42:58 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *new_layers = NULL;
|
|
|
|
GList *iter;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
layers = g_list_copy (layers);
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
_("Duplicate layers"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GimpLayer *new_layer;
|
|
|
|
|
|
|
|
new_layer = GIMP_LAYER (gimp_item_duplicate (GIMP_ITEM (iter->data),
|
|
|
|
G_TYPE_FROM_INSTANCE (iter->data)));
|
|
|
|
|
|
|
|
/* use the actual parent here, not GIMP_IMAGE_ACTIVE_PARENT because
|
|
|
|
* the latter would add a duplicated group inside itself instead of
|
|
|
|
* above it
|
|
|
|
*/
|
|
|
|
gimp_image_add_layer (image, new_layer,
|
|
|
|
gimp_layer_get_parent (iter->data),
|
|
|
|
gimp_item_get_index (iter->data),
|
|
|
|
TRUE);
|
|
|
|
new_layers = g_list_prepend (new_layers, new_layer);
|
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-04-20 19:42:58 +02:00
|
|
|
gimp_image_set_selected_layers (image, new_layers);
|
|
|
|
g_list_free (layers);
|
|
|
|
g_list_free (new_layers);
|
2009-08-03 22:30:36 +02:00
|
|
|
|
2020-04-20 19:42:58 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_anchor_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-05-21 15:06:48 +02:00
|
|
|
GList *layers;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-05-21 15:06:48 +02:00
|
|
|
if (g_list_length (layers) == 1 &&
|
|
|
|
gimp_layer_is_floating_sel (layers->data))
|
2003-02-17 13:33:29 +00:00
|
|
|
{
|
2020-05-21 15:06:48 +02:00
|
|
|
floating_sel_anchor (layers->data);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2003-02-17 13:33:29 +00:00
|
|
|
}
|
2001-12-03 17:59:48 +00:00
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2002-02-13 14:41:35 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_merge_down_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2002-02-13 14:41:35 +00:00
|
|
|
{
|
app: merge layers in chunks, and show progress
In gimp_image_merge_layers() -- the internal function used by the
various layer-merging/flattenning functions -- process the merged-
layer graph in chunks, using gimp_gegl_apply_operation(), instead
of in one go, using gegl_node_blit_buffer(). Processing in chunks
better utilizes the cache, since it reduces the size of
intermediate buffers, reducing the chances of hitting the swap when
merging large images (see, for example, issue #3012.)
Additionally, this allows us to show progress indication. Have the
relevant gimpimage-merge functions take a GimpProgress, and pass it
down to gimp_image_merge_layers(). Adapt all callers.
2019-02-25 04:49:04 -05:00
|
|
|
GimpImage *image;
|
2020-06-30 23:29:05 +02:00
|
|
|
GList *layers;
|
app: merge layers in chunks, and show progress
In gimp_image_merge_layers() -- the internal function used by the
various layer-merging/flattenning functions -- process the merged-
layer graph in chunks, using gimp_gegl_apply_operation(), instead
of in one go, using gegl_node_blit_buffer(). Processing in chunks
better utilizes the cache, since it reduces the size of
intermediate buffers, reducing the chances of hitting the swap when
merging large images (see, for example, issue #3012.)
Additionally, this allows us to show progress indication. Have the
relevant gimpimage-merge functions take a GimpProgress, and pass it
down to gimp_image_merge_layers(). Adapt all callers.
2019-02-25 04:49:04 -05:00
|
|
|
GimpDisplay *display;
|
2020-06-30 23:29:05 +02:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
return_if_no_layers (image, layers, data);
|
app: merge layers in chunks, and show progress
In gimp_image_merge_layers() -- the internal function used by the
various layer-merging/flattenning functions -- process the merged-
layer graph in chunks, using gimp_gegl_apply_operation(), instead
of in one go, using gegl_node_blit_buffer(). Processing in chunks
better utilizes the cache, since it reduces the size of
intermediate buffers, reducing the chances of hitting the swap when
merging large images (see, for example, issue #3012.)
Additionally, this allows us to show progress indication. Have the
relevant gimpimage-merge functions take a GimpProgress, and pass it
down to gimp_image_merge_layers(). Adapt all callers.
2019-02-25 04:49:04 -05:00
|
|
|
return_if_no_display (display, data);
|
2002-02-13 14:41:35 +00:00
|
|
|
|
2020-06-30 23:29:05 +02:00
|
|
|
layers = gimp_image_merge_down (image, layers, action_data_get_context (data),
|
|
|
|
GIMP_EXPAND_AS_NECESSARY,
|
|
|
|
GIMP_PROGRESS (display), &error);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
gimp_message_literal (image->gimp,
|
|
|
|
G_OBJECT (display), GIMP_MESSAGE_WARNING,
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gimp_image_set_selected_layers (image, layers);
|
|
|
|
g_list_free (layers);
|
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2002-02-13 14:41:35 +00:00
|
|
|
}
|
|
|
|
|
2009-09-21 19:17:02 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_merge_group_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2009-09-21 19:17:02 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-21 15:06:48 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *merge_layers = NULL;
|
|
|
|
GList *iter;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)))
|
|
|
|
{
|
|
|
|
GList *iter2;
|
|
|
|
|
|
|
|
for (iter2 = layers; iter2; iter2 = iter2->next)
|
|
|
|
{
|
|
|
|
/* Do not merge a layer when we already merge one of its
|
|
|
|
* ancestors.
|
|
|
|
*/
|
2020-10-22 12:43:51 +02:00
|
|
|
if (gimp_viewable_is_ancestor (iter2->data, iter->data))
|
2020-05-21 15:06:48 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iter2 == NULL)
|
|
|
|
merge_layers = g_list_prepend (merge_layers, iter->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (merge_layers) > 1)
|
|
|
|
{
|
|
|
|
gchar *undo_name;
|
|
|
|
|
|
|
|
undo_name = g_strdup_printf (C_("undo-type", "Merge %d Layer Groups"),
|
|
|
|
g_list_length (merge_layers));
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
|
|
|
|
undo_name);
|
|
|
|
g_free (undo_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iter = merge_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_merge_group_layer (image, GIMP_GROUP_LAYER (iter->data));
|
|
|
|
|
|
|
|
if (g_list_length (merge_layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2009-09-21 19:17:02 +02:00
|
|
|
|
2020-05-21 15:06:48 +02:00
|
|
|
g_list_free (merge_layers);
|
2009-09-21 19:17:02 +02:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
|
2001-12-03 17:59:48 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_delete_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-12-03 17:59:48 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-03-21 14:22:58 +01:00
|
|
|
GList *layers;
|
|
|
|
GList *removed_layers;
|
2020-03-31 18:00:23 +02:00
|
|
|
GList *iter;
|
|
|
|
GList *iter2;
|
2020-03-21 14:22:58 +01:00
|
|
|
|
|
|
|
return_if_no_image (image, data);
|
|
|
|
|
|
|
|
layers = gimp_image_get_selected_layers (image);
|
|
|
|
|
|
|
|
/*TODO: we should have a failsafe to determine when we are going to
|
|
|
|
* delete all layers (i.e. all layers of first level at least) and
|
|
|
|
* forbid it. */
|
|
|
|
|
|
|
|
/* Copy of the original selection. */
|
|
|
|
removed_layers = g_list_copy (layers);
|
|
|
|
|
2020-03-31 18:00:23 +02:00
|
|
|
/* Removing children layers (they will be removed anyway by removing
|
|
|
|
* the parent.
|
|
|
|
*/
|
|
|
|
for (iter = removed_layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
for (iter2 = removed_layers; iter2; iter2 = iter2->next)
|
|
|
|
{
|
|
|
|
if (iter->data != iter2->data &&
|
2020-10-22 12:43:51 +02:00
|
|
|
gimp_viewable_is_ancestor (iter2->data, iter->data))
|
2020-03-31 18:00:23 +02:00
|
|
|
{
|
|
|
|
removed_layers = g_list_delete_link (removed_layers, iter);
|
|
|
|
iter = removed_layers;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 14:22:58 +01:00
|
|
|
if (g_list_length (removed_layers) > 1)
|
|
|
|
{
|
|
|
|
gchar *undo_name;
|
|
|
|
|
|
|
|
undo_name = g_strdup_printf (C_("undo-type", "Remove %d Layers"),
|
|
|
|
g_list_length (removed_layers));
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
|
|
|
|
undo_name);
|
|
|
|
}
|
|
|
|
|
2020-03-31 18:00:23 +02:00
|
|
|
for (iter = removed_layers; iter; iter = iter->next)
|
|
|
|
gimp_image_remove_layer (image, iter->data, TRUE, NULL);
|
2020-03-21 14:22:58 +01:00
|
|
|
|
|
|
|
if (g_list_length (removed_layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-03-21 14:22:58 +01:00
|
|
|
g_list_free (removed_layers);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2001-12-03 17:59:48 +00:00
|
|
|
}
|
|
|
|
|
2004-01-05 00:28:12 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_text_discard_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-01-05 00:28:12 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2004-05-12 18:36:33 +00:00
|
|
|
GimpLayer *layer;
|
2006-03-28 17:08:36 +00:00
|
|
|
return_if_no_layer (image, layer, data);
|
2004-01-05 00:28:12 +00:00
|
|
|
|
2004-05-12 18:36:33 +00:00
|
|
|
if (GIMP_IS_TEXT_LAYER (layer))
|
|
|
|
gimp_text_layer_discard (GIMP_TEXT_LAYER (layer));
|
2004-01-05 00:28:12 +00:00
|
|
|
}
|
|
|
|
|
2006-05-13 19:48:18 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_text_to_vectors_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2006-05-13 19:48:18 +00:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
return_if_no_layer (image, layer, data);
|
|
|
|
|
|
|
|
if (GIMP_IS_TEXT_LAYER (layer))
|
|
|
|
{
|
|
|
|
GimpVectors *vectors;
|
|
|
|
gint x, y;
|
|
|
|
|
|
|
|
vectors = gimp_text_vectors_new (image, GIMP_TEXT_LAYER (layer)->text);
|
|
|
|
|
2008-11-02 23:03:29 +00:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (layer), &x, &y);
|
2006-05-13 19:48:18 +00:00
|
|
|
gimp_item_translate (GIMP_ITEM (vectors), x, y, FALSE);
|
|
|
|
|
2009-08-03 22:30:36 +02:00
|
|
|
gimp_image_add_vectors (image, vectors,
|
|
|
|
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2006-05-13 19:48:18 +00:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_text_along_vectors_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2006-05-13 19:48:18 +00:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpVectors *vectors;
|
|
|
|
return_if_no_layer (image, layer, data);
|
|
|
|
return_if_no_vectors (image, vectors, data);
|
|
|
|
|
|
|
|
if (GIMP_IS_TEXT_LAYER (layer))
|
|
|
|
{
|
2018-11-13 11:30:49 +09:00
|
|
|
gdouble box_width;
|
|
|
|
gdouble box_height;
|
2006-05-13 19:48:18 +00:00
|
|
|
GimpVectors *new_vectors;
|
2018-11-13 11:30:49 +09:00
|
|
|
gdouble offset;
|
|
|
|
|
|
|
|
box_width = gimp_item_get_width (GIMP_ITEM (layer));
|
|
|
|
box_height = gimp_item_get_height (GIMP_ITEM (layer));
|
2006-05-13 19:48:18 +00:00
|
|
|
|
|
|
|
new_vectors = gimp_text_vectors_new (image, GIMP_TEXT_LAYER (layer)->text);
|
|
|
|
|
2018-11-13 11:30:49 +09:00
|
|
|
offset = 0;
|
|
|
|
switch (GIMP_TEXT_LAYER (layer)->text->base_dir)
|
|
|
|
{
|
|
|
|
case GIMP_TEXT_DIRECTION_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_RTL:
|
|
|
|
offset = 0.5 * box_height;
|
|
|
|
break;
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
|
|
|
{
|
|
|
|
GimpStroke *stroke = NULL;
|
|
|
|
|
|
|
|
while ((stroke = gimp_vectors_stroke_get_next (new_vectors, stroke)))
|
|
|
|
{
|
|
|
|
gimp_stroke_rotate (stroke, 0, 0, 270);
|
|
|
|
gimp_stroke_translate (stroke, 0, box_width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
offset = 0.5 * box_width;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gimp_vectors_warp_vectors (vectors, new_vectors, offset);
|
2006-05-13 19:48:18 +00:00
|
|
|
|
|
|
|
gimp_item_set_visible (GIMP_ITEM (new_vectors), TRUE, FALSE);
|
|
|
|
|
2009-08-03 22:30:36 +02:00
|
|
|
gimp_image_add_vectors (image, new_vectors,
|
|
|
|
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2006-05-13 19:48:18 +00:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-03 17:59:48 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_resize_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-12-03 17:59:48 +00:00
|
|
|
{
|
2016-09-12 00:03:22 +02:00
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
2020-07-30 21:26:13 +02:00
|
|
|
GList *layers;
|
2016-09-12 00:03:22 +02:00
|
|
|
GtkWidget *widget;
|
|
|
|
GtkWidget *dialog;
|
2020-07-30 21:26:13 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2004-04-29 12:52:29 +00:00
|
|
|
return_if_no_widget (widget, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2016-09-12 00:03:22 +02:00
|
|
|
#define RESIZE_DIALOG_KEY "gimp-resize-dialog"
|
2010-06-06 16:44:36 +02:00
|
|
|
|
2020-07-30 21:26:13 +02:00
|
|
|
g_return_if_fail (g_list_length (layers) == 1);
|
|
|
|
|
|
|
|
layer = layers->data;
|
|
|
|
|
2016-09-12 00:03:22 +02:00
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (layer), RESIZE_DIALOG_KEY);
|
2005-08-24 17:22:07 +00:00
|
|
|
|
2016-09-12 00:03:22 +02:00
|
|
|
if (! dialog)
|
|
|
|
{
|
2016-10-20 00:30:10 +02:00
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
GimpDisplay *display = NULL;
|
2016-09-12 00:03:22 +02:00
|
|
|
|
|
|
|
if (GIMP_IS_IMAGE_WINDOW (data))
|
|
|
|
display = action_data_get_display (data);
|
|
|
|
|
|
|
|
if (layer_resize_unit != GIMP_UNIT_PERCENT && display)
|
|
|
|
layer_resize_unit = gimp_display_get_shell (display)->unit;
|
|
|
|
|
|
|
|
dialog = resize_dialog_new (GIMP_VIEWABLE (layer),
|
|
|
|
action_data_get_context (data),
|
|
|
|
_("Set Layer Boundary Size"),
|
|
|
|
"gimp-layer-resize",
|
|
|
|
widget,
|
|
|
|
gimp_standard_help_func,
|
|
|
|
GIMP_HELP_LAYER_RESIZE,
|
|
|
|
layer_resize_unit,
|
2016-10-20 00:30:10 +02:00
|
|
|
config->layer_resize_fill_type,
|
|
|
|
GIMP_ITEM_SET_NONE,
|
|
|
|
FALSE,
|
2016-09-25 22:18:37 +02:00
|
|
|
layers_resize_callback,
|
2016-09-24 15:07:04 +02:00
|
|
|
NULL);
|
2016-09-12 00:03:22 +02:00
|
|
|
|
|
|
|
dialogs_attach_dialog (G_OBJECT (layer), RESIZE_DIALOG_KEY, dialog);
|
|
|
|
}
|
2004-10-27 10:33:08 +00:00
|
|
|
|
2016-09-12 00:03:22 +02:00
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_resize_to_image_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-07-01 01:00:48 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
|
|
|
|
_("Layers to Image Size"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
gimp_layer_resize_to_image (iter->data,
|
|
|
|
action_data_get_context (data),
|
|
|
|
GIMP_FILL_TRANSPARENT);
|
|
|
|
|
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2003-08-31 18:10:15 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2002-04-12 12:29:51 +00:00
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2002-04-12 12:29:51 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_scale_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2002-04-12 12:29:51 +00:00
|
|
|
{
|
2016-09-24 14:14:43 +02:00
|
|
|
GimpImage *image;
|
2020-07-30 21:26:13 +02:00
|
|
|
GList *layers;
|
2016-09-24 14:14:43 +02:00
|
|
|
GimpLayer *layer;
|
|
|
|
GtkWidget *widget;
|
|
|
|
GtkWidget *dialog;
|
2020-07-30 21:26:13 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2004-04-29 12:52:29 +00:00
|
|
|
return_if_no_widget (widget, data);
|
2002-04-12 12:29:51 +00:00
|
|
|
|
2016-09-24 14:14:43 +02:00
|
|
|
#define SCALE_DIALOG_KEY "gimp-scale-dialog"
|
2010-06-06 16:44:36 +02:00
|
|
|
|
2020-07-30 21:26:13 +02:00
|
|
|
g_return_if_fail (g_list_length (layers) == 1);
|
|
|
|
|
|
|
|
layer = layers->data;
|
|
|
|
|
2016-09-24 14:14:43 +02:00
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (layer), SCALE_DIALOG_KEY);
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2016-09-24 14:14:43 +02:00
|
|
|
if (! dialog)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = NULL;
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2016-09-24 14:14:43 +02:00
|
|
|
if (GIMP_IS_IMAGE_WINDOW (data))
|
|
|
|
display = action_data_get_display (data);
|
|
|
|
|
|
|
|
if (layer_scale_unit != GIMP_UNIT_PERCENT && display)
|
|
|
|
layer_scale_unit = gimp_display_get_shell (display)->unit;
|
|
|
|
|
|
|
|
if (layer_scale_interp == -1)
|
|
|
|
layer_scale_interp = image->gimp->config->interpolation_type;
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2016-09-24 14:14:43 +02:00
|
|
|
dialog = scale_dialog_new (GIMP_VIEWABLE (layer),
|
|
|
|
action_data_get_context (data),
|
|
|
|
_("Scale Layer"), "gimp-layer-scale",
|
|
|
|
widget,
|
|
|
|
gimp_standard_help_func, GIMP_HELP_LAYER_SCALE,
|
|
|
|
layer_scale_unit,
|
|
|
|
layer_scale_interp,
|
2016-09-25 22:18:37 +02:00
|
|
|
layers_scale_callback,
|
2016-09-24 14:14:43 +02:00
|
|
|
display);
|
|
|
|
|
|
|
|
dialogs_attach_dialog (G_OBJECT (layer), SCALE_DIALOG_KEY, dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_crop_to_selection_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-07-30 18:35:34 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2006-10-09 18:49:15 +00:00
|
|
|
GtkWidget *widget;
|
2020-07-30 18:35:34 +02:00
|
|
|
gchar *desc;
|
2015-07-01 15:19:03 +02:00
|
|
|
gint x, y;
|
|
|
|
gint width, height;
|
2020-07-30 18:35:34 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2006-10-09 18:49:15 +00:00
|
|
|
return_if_no_widget (widget, data);
|
2002-04-12 12:29:51 +00:00
|
|
|
|
2015-07-01 15:19:03 +02:00
|
|
|
if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
|
|
|
|
&x, &y, &width, &height))
|
2002-04-12 12:29:51 +00:00
|
|
|
{
|
2008-11-04 12:33:09 +00:00
|
|
|
gimp_message_literal (image->gimp,
|
2013-09-15 04:59:20 +12:00
|
|
|
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
2016-09-25 22:40:28 +02:00
|
|
|
_("Cannot crop because the current selection "
|
|
|
|
"is empty."));
|
2002-04-12 12:29:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
desc = g_strdup_printf (ngettext ("Crop Layer to Selection",
|
|
|
|
"Crop %d Layers to Selection",
|
|
|
|
g_list_length (layers)),
|
|
|
|
g_list_length (layers));
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, desc);
|
|
|
|
g_free (desc);
|
2002-04-12 12:29:51 +00:00
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
gint off_x, off_y;
|
|
|
|
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (iter->data), &off_x, &off_y);
|
|
|
|
off_x -= x;
|
|
|
|
off_y -= y;
|
2002-04-12 12:29:51 +00:00
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
gimp_item_resize (GIMP_ITEM (iter->data),
|
|
|
|
action_data_get_context (data), GIMP_FILL_TRANSPARENT,
|
|
|
|
width, height, off_x, off_y);
|
|
|
|
}
|
2002-04-12 12:29:51 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-09-22 20:35:36 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_crop_to_content_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2012-09-22 20:35:36 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-07-30 18:35:34 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2012-09-22 20:35:36 +02:00
|
|
|
GtkWidget *widget;
|
2020-07-30 18:35:34 +02:00
|
|
|
gchar *desc;
|
2016-09-25 22:40:28 +02:00
|
|
|
gint x, y;
|
|
|
|
gint width, height;
|
2020-07-30 18:35:34 +02:00
|
|
|
gint n_croppable = 0;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2012-09-22 20:35:36 +02:00
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
2012-09-22 20:35:36 +02:00
|
|
|
{
|
2020-07-30 18:35:34 +02:00
|
|
|
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (iter->data),
|
|
|
|
0, 0,
|
|
|
|
gimp_item_get_width (iter->data),
|
|
|
|
gimp_item_get_height (iter->data),
|
|
|
|
&x, &y, &width, &height))
|
|
|
|
{
|
|
|
|
case GIMP_AUTO_SHRINK_SHRINK:
|
|
|
|
n_croppable++;
|
|
|
|
break;
|
2012-09-22 20:35:36 +02:00
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
case GIMP_AUTO_SHRINK_EMPTY:
|
|
|
|
/* Cannot crop because the layer has no content. */
|
|
|
|
case GIMP_AUTO_SHRINK_UNSHRINKABLE:
|
|
|
|
/* Cannot crop because the active layer is already cropped to
|
|
|
|
* its content. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-22 20:35:36 +02:00
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
if (n_croppable == 0)
|
|
|
|
{
|
2014-08-31 17:38:49 +02:00
|
|
|
gimp_message_literal (image->gimp,
|
|
|
|
G_OBJECT (widget), GIMP_MESSAGE_INFO,
|
2020-07-30 18:35:34 +02:00
|
|
|
_("Cannot crop because none of the selected"
|
|
|
|
" layers have content or they are already"
|
|
|
|
" cropped to their content."));
|
|
|
|
return;
|
|
|
|
}
|
2012-09-22 20:35:36 +02:00
|
|
|
|
2020-07-30 18:35:34 +02:00
|
|
|
desc = g_strdup_printf (ngettext ("Crop Layer to Content",
|
|
|
|
"Crop %d Layers to Content",
|
|
|
|
n_croppable),
|
|
|
|
n_croppable);
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, desc);
|
|
|
|
g_free (desc);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (iter->data),
|
|
|
|
0, 0,
|
|
|
|
gimp_item_get_width (iter->data),
|
|
|
|
gimp_item_get_height (iter->data),
|
|
|
|
&x, &y, &width, &height))
|
|
|
|
{
|
|
|
|
case GIMP_AUTO_SHRINK_SHRINK:
|
|
|
|
gimp_item_resize (iter->data,
|
|
|
|
action_data_get_context (data), GIMP_FILL_TRANSPARENT,
|
|
|
|
width, height, -x, -y);
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2014-08-31 17:38:49 +02:00
|
|
|
}
|
2020-07-30 18:35:34 +02:00
|
|
|
gimp_image_flush (image);
|
|
|
|
gimp_image_undo_group_end (image);
|
2012-09-22 20:35:36 +02:00
|
|
|
}
|
|
|
|
|
2001-04-20 16:27:44 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_add_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2016-09-23 14:35:14 +02:00
|
|
|
GimpImage *image;
|
2020-05-02 01:42:04 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2016-09-23 14:35:14 +02:00
|
|
|
GtkWidget *widget;
|
|
|
|
GtkWidget *dialog;
|
2020-05-02 01:42:04 +02:00
|
|
|
GList *update_layers = NULL;
|
|
|
|
gint n_channels = 0;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-04-29 12:52:29 +00:00
|
|
|
return_if_no_widget (widget, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (iter->data));
|
|
|
|
|
|
|
|
if (! gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
update_layers = g_list_prepend (update_layers, iter->data);
|
|
|
|
n_channels++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (n_channels == 0)
|
|
|
|
/* No layers or they all have masks already. */
|
2016-08-23 19:18:20 +02:00
|
|
|
return;
|
|
|
|
|
2016-09-23 14:35:14 +02:00
|
|
|
#define ADD_MASK_DIALOG_KEY "gimp-add-mask-dialog"
|
2016-08-23 19:18:20 +02:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
for (iter = update_layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (iter->data), ADD_MASK_DIALOG_KEY);
|
|
|
|
if (dialog)
|
|
|
|
break;
|
|
|
|
}
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2016-09-23 14:35:14 +02:00
|
|
|
if (! dialog)
|
|
|
|
{
|
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
dialog = layer_add_mask_dialog_new (update_layers, action_data_get_context (data),
|
2016-09-23 14:35:14 +02:00
|
|
|
widget,
|
|
|
|
config->layer_add_mask_type,
|
|
|
|
config->layer_add_mask_invert,
|
|
|
|
layers_add_mask_callback,
|
|
|
|
NULL);
|
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
for (iter = update_layers; iter; iter = iter->next)
|
|
|
|
dialogs_attach_dialog (G_OBJECT (iter->data), ADD_MASK_DIALOG_KEY, dialog);
|
2016-09-23 14:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2016-08-23 19:18:20 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_add_last_vals_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2016-08-23 19:18:20 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-04-22 00:05:31 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2016-08-23 19:18:20 +02:00
|
|
|
GtkWidget *widget;
|
|
|
|
GimpDialogConfig *config;
|
|
|
|
GimpChannel *channel = NULL;
|
|
|
|
GimpLayerMask *mask;
|
2020-04-22 00:05:31 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2016-08-23 19:18:20 +02:00
|
|
|
return_if_no_widget (widget, data);
|
|
|
|
|
|
|
|
config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
|
|
|
|
if (config->layer_add_mask_type == GIMP_ADD_MASK_CHANNEL)
|
|
|
|
{
|
2021-06-20 00:16:38 +02:00
|
|
|
GList *selected_channels;
|
2016-08-23 19:18:20 +02:00
|
|
|
|
2021-06-20 00:16:38 +02:00
|
|
|
selected_channels = gimp_image_get_selected_channels (image);
|
|
|
|
|
|
|
|
if (selected_channels)
|
|
|
|
{
|
|
|
|
channel = selected_channels->data;
|
|
|
|
}
|
|
|
|
else
|
2016-08-23 19:18:20 +02:00
|
|
|
{
|
|
|
|
GimpContainer *channels = gimp_image_get_channels (image);
|
|
|
|
|
|
|
|
channel = GIMP_CHANNEL (gimp_container_get_first_child (channels));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! channel)
|
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
layers_mask_add_cmd_callback (action, value, data);
|
2016-08-23 19:18:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 00:05:31 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (! gimp_layer_get_mask (iter->data))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (iter == NULL)
|
|
|
|
/* No layers or they all have masks already. */
|
|
|
|
return;
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
_("Add Layer Masks"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
continue;
|
2016-08-23 19:18:20 +02:00
|
|
|
|
2020-04-22 00:05:31 +02:00
|
|
|
mask = gimp_layer_create_mask (iter->data,
|
|
|
|
config->layer_add_mask_type,
|
|
|
|
channel);
|
|
|
|
|
|
|
|
if (config->layer_add_mask_invert)
|
|
|
|
gimp_channel_invert (GIMP_CHANNEL (mask), FALSE);
|
|
|
|
|
|
|
|
gimp_layer_add_mask (iter->data, mask, TRUE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_group_end (image);
|
2016-08-23 19:18:20 +02:00
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
|
2001-04-20 16:27:44 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_apply_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2020-04-24 18:23:40 +02:00
|
|
|
GimpMaskApplyMode mode;
|
|
|
|
GimpImage *image;
|
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
gchar *undo_text = NULL;
|
|
|
|
GimpUndoType undo_type = GIMP_UNDO_GROUP_NONE;
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-04-24 18:23:40 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
mode = (GimpMaskApplyMode) g_variant_get_int32 (value);
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2020-04-24 18:23:40 +02:00
|
|
|
if (gimp_layer_get_mask (iter->data) &&
|
|
|
|
(mode != GIMP_MASK_APPLY ||
|
|
|
|
(! gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)) &&
|
2022-02-15 15:42:44 +01:00
|
|
|
! gimp_item_is_content_locked (GIMP_ITEM (iter->data), NULL))))
|
2020-04-24 18:23:40 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (iter == NULL)
|
2020-08-08 05:58:47 +00:00
|
|
|
/* No layers or none have applicable masks. */
|
2020-04-24 18:23:40 +02:00
|
|
|
return;
|
2016-08-23 19:18:20 +02:00
|
|
|
|
2020-04-24 18:23:40 +02:00
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case GIMP_MASK_APPLY:
|
|
|
|
undo_type = GIMP_UNDO_GROUP_MASK;
|
|
|
|
undo_text = _("Apply Layer Masks");
|
|
|
|
break;
|
|
|
|
case GIMP_MASK_DISCARD:
|
|
|
|
undo_type = GIMP_UNDO_GROUP_MASK;
|
|
|
|
undo_text = _("Delete Layer Masks");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_warning ("%s: unhandled GimpMaskApplyMode %d\n",
|
|
|
|
G_STRFUNC, mode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (undo_type != GIMP_UNDO_GROUP_NONE)
|
|
|
|
gimp_image_undo_group_start (image, undo_type, undo_text);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
if (mode == GIMP_MASK_APPLY &&
|
|
|
|
(gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)) ||
|
2022-02-15 15:42:44 +01:00
|
|
|
gimp_item_is_content_locked (GIMP_ITEM (iter->data), NULL)))
|
2020-04-24 18:23:40 +02:00
|
|
|
/* Layer groups cannot apply masks. Neither can
|
|
|
|
* content-locked layers.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
|
|
|
|
gimp_layer_apply_mask (iter->data, mode, TRUE);
|
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
2020-04-24 18:23:40 +02:00
|
|
|
|
|
|
|
if (undo_type != GIMP_UNDO_GROUP_NONE)
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2004-08-20 22:32:14 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_edit_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-08-20 22:32:14 +00:00
|
|
|
{
|
2016-08-23 19:18:20 +02:00
|
|
|
GimpImage *image;
|
2020-07-30 22:30:17 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
gboolean active = g_variant_get_boolean (value);
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-07-30 22:30:17 +02:00
|
|
|
/* Multiple-layer selection cannot edit masks. */
|
|
|
|
active = active && (g_list_length (layers) == 1);
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-07-30 22:30:17 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
gimp_layer_set_edit_mask (iter->data, active);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
2004-08-20 22:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_show_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-08-20 22:32:14 +00:00
|
|
|
{
|
2016-08-23 19:18:20 +02:00
|
|
|
GimpImage *image;
|
2020-04-28 17:04:47 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
gboolean active = g_variant_get_boolean (value);
|
|
|
|
gboolean have_masks = FALSE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-04-28 17:04:47 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
2004-08-20 22:32:14 +00:00
|
|
|
{
|
2020-04-28 17:04:47 +02:00
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
have_masks = TRUE;
|
|
|
|
/* A bit of tricky to handle multiple and diverse layers with
|
|
|
|
* a toggle action (with only binary state).
|
|
|
|
* In non-active state, we will consider sets of both shown
|
|
|
|
* and hidden masks as ok and exits. This allows us to switch
|
|
|
|
* the action "active" state without actually changing
|
|
|
|
* individual masks state without explicit user request.
|
|
|
|
*/
|
|
|
|
if (! active && ! gimp_layer_get_show_mask (iter->data))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! have_masks)
|
|
|
|
return;
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-04-28 17:04:47 +02:00
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
_("Show Layer Masks"));
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
gimp_layer_set_show_mask (iter->data, active, TRUE);
|
|
|
|
}
|
2004-08-20 22:32:14 +00:00
|
|
|
}
|
2020-04-28 17:04:47 +02:00
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gimp_image_undo_group_end (image);
|
2004-08-20 22:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_disable_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-08-20 22:32:14 +00:00
|
|
|
{
|
2016-08-23 19:18:20 +02:00
|
|
|
GimpImage *image;
|
2020-04-28 17:04:47 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
gboolean active = g_variant_get_boolean (value);
|
|
|
|
gboolean have_masks = FALSE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-04-28 17:04:47 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
2004-08-20 22:32:14 +00:00
|
|
|
{
|
2020-04-28 17:04:47 +02:00
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
have_masks = TRUE;
|
|
|
|
/* A bit of tricky to handle multiple and diverse layers with
|
|
|
|
* a toggle action (with only binary state).
|
|
|
|
* In non-active state, we will consider sets of both enabled
|
|
|
|
* and disabled masks as ok and exits. This allows us to
|
|
|
|
* switch the action "active" state without actually changing
|
|
|
|
* individual masks state without explicit user request.
|
|
|
|
*/
|
|
|
|
if (! active && gimp_layer_get_apply_mask (iter->data))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! have_masks)
|
|
|
|
return;
|
2004-08-20 22:32:14 +00:00
|
|
|
|
2020-04-28 17:04:47 +02:00
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
_("Disable Layer Masks"));
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
{
|
|
|
|
gimp_layer_set_apply_mask (iter->data, ! active, TRUE);
|
|
|
|
}
|
2004-08-20 22:32:14 +00:00
|
|
|
}
|
2020-04-28 17:04:47 +02:00
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gimp_image_undo_group_end (image);
|
2004-08-20 22:32:14 +00:00
|
|
|
}
|
|
|
|
|
2003-08-27 00:52:00 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mask_to_selection_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2003-08-27 00:52:00 +00:00
|
|
|
{
|
2010-07-20 23:09:19 +02:00
|
|
|
GimpImage *image;
|
2020-05-20 22:59:34 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *masks = NULL;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-05-20 22:59:34 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_get_mask (iter->data))
|
|
|
|
masks = g_list_prepend (masks, gimp_layer_get_mask (iter->data));
|
|
|
|
}
|
2003-08-21 15:54:47 +00:00
|
|
|
|
2020-05-20 22:59:34 +02:00
|
|
|
if (masks)
|
2002-02-26 16:30:14 +00:00
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpChannelOps operation = (GimpChannelOps) g_variant_get_int32 (value);
|
|
|
|
|
2020-05-20 22:59:34 +02:00
|
|
|
switch (operation)
|
|
|
|
{
|
|
|
|
case GIMP_CHANNEL_OP_REPLACE:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Masks to Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_ADD:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Add Masks to Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_SUBTRACT:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Subtract Masks from Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_INTERSECT:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Intersect Masks with Selection"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gimp_channel_combine_items (gimp_image_get_mask (image),
|
|
|
|
masks, operation);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-20 22:59:34 +02:00
|
|
|
g_list_free (masks);
|
2002-02-26 16:30:14 +00:00
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2003-08-21 15:54:47 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_alpha_add_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-07-30 21:01:10 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2020-07-30 21:01:10 +02:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_ADD_ALPHA,
|
|
|
|
_("Add Alpha Channel"));
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
if (! gimp_drawable_has_alpha (iter->data))
|
|
|
|
gimp_layer_add_alpha (iter->data);
|
|
|
|
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2005-08-07 16:38:35 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_alpha_remove_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2005-08-07 16:38:35 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-07-30 21:01:10 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2005-08-07 16:38:35 +00:00
|
|
|
|
2020-07-30 21:01:10 +02:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_ADD_ALPHA,
|
|
|
|
_("Remove Alpha Channel"));
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
if (gimp_drawable_has_alpha (iter->data))
|
|
|
|
gimp_layer_remove_alpha (iter->data, action_data_get_context (data));
|
|
|
|
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
2005-08-07 16:38:35 +00:00
|
|
|
}
|
|
|
|
|
2003-08-27 00:52:00 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_alpha_to_selection_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2003-08-21 15:54:47 +00:00
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpImage *image;
|
2020-05-25 17:40:57 +02:00
|
|
|
GimpDisplay *display;
|
2020-05-18 12:22:08 +02:00
|
|
|
GList *layers;
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpChannelOps operation;
|
2020-05-18 12:22:08 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2020-05-25 17:40:57 +02:00
|
|
|
return_if_no_display (display, data);
|
2003-08-21 15:54:47 +00:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
operation = (GimpChannelOps) g_variant_get_int32 (value);
|
|
|
|
|
2020-05-20 21:18:20 +02:00
|
|
|
switch (operation)
|
|
|
|
{
|
|
|
|
case GIMP_CHANNEL_OP_REPLACE:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Alpha to Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_ADD:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Add Alpha to Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_SUBTRACT:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Subtract Alpha from Selection"));
|
|
|
|
break;
|
|
|
|
case GIMP_CHANNEL_OP_INTERSECT:
|
|
|
|
gimp_channel_push_undo (gimp_image_get_mask (image),
|
|
|
|
C_("undo-type", "Intersect Alpha with Selection"));
|
|
|
|
break;
|
|
|
|
}
|
2020-05-20 18:16:30 +02:00
|
|
|
gimp_channel_combine_items (gimp_image_get_mask (image),
|
|
|
|
layers, operation);
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2020-05-25 17:40:57 +02:00
|
|
|
|
|
|
|
if (gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
|
|
{
|
|
|
|
gimp_message_literal (image->gimp, G_OBJECT (display),
|
|
|
|
GIMP_MESSAGE_WARNING,
|
|
|
|
_("Empty Selection"));
|
|
|
|
}
|
2003-08-21 15:54:47 +00:00
|
|
|
}
|
|
|
|
|
2004-06-23 00:23:25 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_opacity_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-06-23 00:23:25 +00:00
|
|
|
{
|
2020-04-29 13:30:35 +02:00
|
|
|
GimpImage *image;
|
2020-04-29 02:12:00 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2020-04-29 13:30:35 +02:00
|
|
|
gdouble opacity;
|
|
|
|
GimpUndo *undo;
|
|
|
|
GimpActionSelectType select_type;
|
2020-04-29 02:12:00 +02:00
|
|
|
gboolean push_undo = TRUE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-06-23 00:23:25 +00:00
|
|
|
|
2020-04-29 13:30:35 +02:00
|
|
|
select_type = (GimpActionSelectType) g_variant_get_int32 (value);
|
2020-04-29 02:12:00 +02:00
|
|
|
if (g_list_length (layers) == 1)
|
|
|
|
{
|
|
|
|
undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
|
|
|
|
GIMP_UNDO_LAYER_OPACITY);
|
2020-04-29 13:30:35 +02:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layers->data))
|
|
|
|
push_undo = FALSE;
|
|
|
|
}
|
2004-08-03 14:09:49 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_OPACITY,
|
|
|
|
_("Set layers opacity"));
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
opacity = action_select_value (select_type,
|
|
|
|
gimp_layer_get_opacity (iter->data),
|
|
|
|
0.0, 1.0, 1.0,
|
app: allow to change the brush size on alt-right click.
I started from mitch's patch (though code changed so it was not working,
yet I ended up with quite a different direction).
Modified from original proposition in #498:
* Do not mix opacity and brush size in a same action, one on horizontal
movement, the other on vertical. The problem is that it's hard to stay
perfectly horizontal or vertical, so you nearly necessarily change one
while changing the other and this would be frustrating.
* Do not just use modifiers, but modifiers + right click. The logics is
that left (or whatever is the first button) click is for the tool
actions. The middle click for navigation (panning, rotation, and even
layer navigation now). Right click for now is only for menu. With this
change, let's use right click for various settings-related changes
too. Also we already have people complaining with things like canvas
rotation happening unexpectedly even though it requires button clicks.
Imagine an action just made of modifiers! Many people would hit these
by mistake all the time!
* Focus on brush size only for now. Instead of just calling the action
repetitively with the "SElECT_NEXT" action as proposed in the original
patch by mitch, let's compute the actual size between the press and
release. This would allow to have a real visual hint and also would
make it a lot more useful and meaningful to be an on-canvas change.
Say you want to reproduce a stroke size on canvas. You can click the
center and expand to retrieve approximately the size without computing
it in pixels.
Limitations and future work:
* This is a first draft and I still want to test if it works well with
the "lock brush to view" and with scale factor > 1.
* I want to associate this with work done for #7034 so that visual hint
still appear even when we have no visual hint set.
* I am not so fond of with the way we use enum actions which doesn't
really make satisfying logics (I hacked a bit over it, but it's
getting ugly). I'm considering creating int/double actions to really
set some values with exact numbers through actions.
* Right now we need to stop the right click first. I want to be able to
stop the brush sizing with releasing Alt too.
* It would be nice to make this all more customizable, which is why I
called internal variable "mod1_setting". The goal will be to have
other types of actions possibly. Also it could be deactivatable for
people really not liking these or hitting these by mistake (while not
needing these). Same for the navigation shorcuts.
* Similarly the right-click menu could be deactivatable or switched to
other actions conditionally (through Preferences). It is doubtful how
useful it is (compared to using the same menus on top of the GUI)
though I don't want to just delete the option because some people
would clearly be used to it.
* I think we should start breaking down the whole tool events code a bit
more, in particular the function gimp_display_shell_canvas_tool_events().
* For more settings, a small on-canvas GUI could be of interest where
you could customize various values through sliders and buttons, and
also where you could put your favorite brushes or dynamics or whatnot.
It's not replacing the more complete dockable but could be a nice
quick version for fast editing.
2022-02-15 00:10:34 +01:00
|
|
|
1.0 / 255.0, 0.01, 0.1, 0.0, FALSE, FALSE);
|
2020-04-29 02:12:00 +02:00
|
|
|
gimp_layer_set_opacity (iter->data, opacity, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2004-06-23 00:23:25 +00:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2004-06-23 00:23:25 +00:00
|
|
|
}
|
|
|
|
|
2004-09-15 13:24:45 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_mode_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-09-15 13:24:45 +00:00
|
|
|
{
|
2020-04-29 13:30:35 +02:00
|
|
|
GimpImage *image;
|
2020-04-29 02:12:00 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2020-04-29 13:30:35 +02:00
|
|
|
GimpActionSelectType select_type;
|
|
|
|
gboolean push_undo = TRUE;
|
2020-04-29 02:12:00 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 13:30:35 +02:00
|
|
|
select_type = (GimpActionSelectType) g_variant_get_int32 (value);
|
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
if (g_list_length (layers) == 1)
|
|
|
|
{
|
|
|
|
GimpUndo *undo;
|
|
|
|
|
|
|
|
undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
|
|
|
|
GIMP_UNDO_LAYER_MODE);
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layers->data))
|
|
|
|
push_undo = FALSE;
|
|
|
|
}
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_OPACITY,
|
|
|
|
_("Set layers opacity"));
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GimpLayerMode *modes;
|
|
|
|
gint n_modes;
|
|
|
|
GimpLayerMode layer_mode;
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
layer_mode = gimp_layer_get_mode (iter->data);
|
|
|
|
|
|
|
|
modes = gimp_layer_mode_get_context_array (layer_mode,
|
|
|
|
GIMP_LAYER_MODE_CONTEXT_LAYER,
|
|
|
|
&n_modes);
|
|
|
|
index = layers_mode_index (layer_mode, modes, n_modes);
|
|
|
|
index = action_select_value (select_type,
|
|
|
|
index, 0, n_modes - 1, 0,
|
app: allow to change the brush size on alt-right click.
I started from mitch's patch (though code changed so it was not working,
yet I ended up with quite a different direction).
Modified from original proposition in #498:
* Do not mix opacity and brush size in a same action, one on horizontal
movement, the other on vertical. The problem is that it's hard to stay
perfectly horizontal or vertical, so you nearly necessarily change one
while changing the other and this would be frustrating.
* Do not just use modifiers, but modifiers + right click. The logics is
that left (or whatever is the first button) click is for the tool
actions. The middle click for navigation (panning, rotation, and even
layer navigation now). Right click for now is only for menu. With this
change, let's use right click for various settings-related changes
too. Also we already have people complaining with things like canvas
rotation happening unexpectedly even though it requires button clicks.
Imagine an action just made of modifiers! Many people would hit these
by mistake all the time!
* Focus on brush size only for now. Instead of just calling the action
repetitively with the "SElECT_NEXT" action as proposed in the original
patch by mitch, let's compute the actual size between the press and
release. This would allow to have a real visual hint and also would
make it a lot more useful and meaningful to be an on-canvas change.
Say you want to reproduce a stroke size on canvas. You can click the
center and expand to retrieve approximately the size without computing
it in pixels.
Limitations and future work:
* This is a first draft and I still want to test if it works well with
the "lock brush to view" and with scale factor > 1.
* I want to associate this with work done for #7034 so that visual hint
still appear even when we have no visual hint set.
* I am not so fond of with the way we use enum actions which doesn't
really make satisfying logics (I hacked a bit over it, but it's
getting ugly). I'm considering creating int/double actions to really
set some values with exact numbers through actions.
* Right now we need to stop the right click first. I want to be able to
stop the brush sizing with releasing Alt too.
* It would be nice to make this all more customizable, which is why I
called internal variable "mod1_setting". The goal will be to have
other types of actions possibly. Also it could be deactivatable for
people really not liking these or hitting these by mistake (while not
needing these). Same for the navigation shorcuts.
* Similarly the right-click menu could be deactivatable or switched to
other actions conditionally (through Preferences). It is doubtful how
useful it is (compared to using the same menus on top of the GUI)
though I don't want to just delete the option because some people
would clearly be used to it.
* I think we should start breaking down the whole tool events code a bit
more, in particular the function gimp_display_shell_canvas_tool_events().
* For more settings, a small on-canvas GUI could be of interest where
you could customize various values through sliders and buttons, and
also where you could put your favorite brushes or dynamics or whatnot.
It's not replacing the more complete dockable but could be a nice
quick version for fast editing.
2022-02-15 00:10:34 +01:00
|
|
|
0.0, 1.0, 1.0, 0.0, FALSE, FALSE);
|
2020-04-29 02:12:00 +02:00
|
|
|
layer_mode = modes[index];
|
|
|
|
g_free (modes);
|
|
|
|
|
|
|
|
gimp_layer_set_mode (iter->data, layer_mode, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2017-02-20 23:51:32 +01:00
|
|
|
|
2006-03-28 17:08:36 +00:00
|
|
|
gimp_image_flush (image);
|
2004-09-15 13:24:45 +00:00
|
|
|
}
|
|
|
|
|
2017-02-02 00:38:25 +01:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_blend_space_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2017-02-12 23:49:26 +01:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-20 23:37:42 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *update_layers = NULL;
|
|
|
|
GList *iter;
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace blend_space;
|
2020-05-20 23:37:42 +02:00
|
|
|
gboolean push_undo = TRUE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
blend_space = (GimpLayerColorSpace) g_variant_get_int32 (value);
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GimpLayerMode mode;
|
|
|
|
|
|
|
|
mode = gimp_layer_get_mode (iter->data);
|
|
|
|
if (gimp_layer_mode_is_blend_space_mutable (mode) &&
|
|
|
|
blend_space != gimp_layer_get_blend_space (iter->data))
|
|
|
|
update_layers = g_list_prepend (update_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (update_layers) == 1)
|
2017-02-12 23:49:26 +01:00
|
|
|
{
|
|
|
|
GimpUndo *undo;
|
|
|
|
|
|
|
|
undo = gimp_image_undo_can_compress (image, GIMP_TYPE_LAYER_PROP_UNDO,
|
|
|
|
GIMP_UNDO_LAYER_MODE);
|
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (update_layers->data))
|
2017-02-12 23:49:26 +01:00
|
|
|
push_undo = FALSE;
|
2020-05-20 23:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (update_layers)
|
|
|
|
{
|
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_MODE,
|
|
|
|
_("Set layers' blend space"));
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
for (iter = update_layers; iter; iter = iter->next)
|
|
|
|
gimp_layer_set_blend_space (iter->data, blend_space, push_undo);
|
|
|
|
|
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (update_layers);
|
2017-02-12 23:49:26 +01:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_composite_space_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2017-02-12 23:49:26 +01:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-20 23:37:42 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *update_layers = NULL;
|
|
|
|
GList *iter;
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace composite_space;
|
2020-05-20 23:37:42 +02:00
|
|
|
gboolean push_undo = TRUE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
composite_space = (GimpLayerColorSpace) g_variant_get_int32 (value);
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GimpLayerMode mode;
|
|
|
|
|
|
|
|
mode = gimp_layer_get_mode (iter->data);
|
|
|
|
if (gimp_layer_mode_is_composite_space_mutable (mode) &&
|
|
|
|
composite_space != gimp_layer_get_composite_space (iter->data))
|
|
|
|
update_layers = g_list_prepend (update_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (update_layers) == 1)
|
2017-02-12 23:49:26 +01:00
|
|
|
{
|
|
|
|
GimpUndo *undo;
|
|
|
|
|
|
|
|
undo = gimp_image_undo_can_compress (image, GIMP_TYPE_LAYER_PROP_UNDO,
|
|
|
|
GIMP_UNDO_LAYER_MODE);
|
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (update_layers->data))
|
2017-02-12 23:49:26 +01:00
|
|
|
push_undo = FALSE;
|
2020-05-20 23:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (update_layers)
|
|
|
|
{
|
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_MODE,
|
|
|
|
_("Set layers' composite space"));
|
|
|
|
|
|
|
|
for (iter = update_layers; iter; iter = iter->next)
|
|
|
|
gimp_layer_set_composite_space (iter->data, composite_space, push_undo);
|
2017-02-12 23:49:26 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
g_list_free (update_layers);
|
2017-02-12 23:49:26 +01:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_composite_mode_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2017-02-02 00:38:25 +01:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-20 23:37:42 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *update_layers = NULL;
|
|
|
|
GList *iter;
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerCompositeMode composite_mode;
|
2020-05-20 23:37:42 +02:00
|
|
|
gboolean push_undo = TRUE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2017-02-02 00:38:25 +01:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
composite_mode = (GimpLayerCompositeMode) g_variant_get_int32 (value);
|
2017-02-02 00:38:25 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
GimpLayerMode mode;
|
|
|
|
|
|
|
|
mode = gimp_layer_get_mode (iter->data);
|
|
|
|
if (gimp_layer_mode_is_composite_mode_mutable (mode) &&
|
|
|
|
composite_mode != gimp_layer_get_composite_mode (iter->data))
|
|
|
|
update_layers = g_list_prepend (update_layers, iter->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_list_length (update_layers) == 1)
|
2017-02-02 00:38:25 +01:00
|
|
|
{
|
|
|
|
GimpUndo *undo;
|
|
|
|
|
|
|
|
undo = gimp_image_undo_can_compress (image, GIMP_TYPE_LAYER_PROP_UNDO,
|
|
|
|
GIMP_UNDO_LAYER_MODE);
|
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (update_layers->data))
|
2017-02-02 00:38:25 +01:00
|
|
|
push_undo = FALSE;
|
2020-05-20 23:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (update_layers)
|
|
|
|
{
|
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_MODE,
|
|
|
|
_("Set layers' composite mode"));
|
|
|
|
|
|
|
|
for (iter = update_layers; iter; iter = iter->next)
|
|
|
|
gimp_layer_set_composite_mode (iter->data, composite_mode, push_undo);
|
|
|
|
|
|
|
|
if (g_list_length (update_layers) > 1)
|
|
|
|
gimp_image_undo_group_end (image);
|
2017-02-02 00:38:25 +01:00
|
|
|
|
2020-05-20 23:37:42 +02:00
|
|
|
g_list_free (update_layers);
|
2017-02-02 00:38:25 +01:00
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-29 16:50:13 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_visible_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2016-10-29 16:50:13 +02:00
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
return_if_no_layer (image, layer, data);
|
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
items_visible_cmd_callback (action, value, image, GIMP_ITEM (layer));
|
2016-10-29 16:50:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_lock_content_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2016-10-29 16:50:13 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-04 17:31:46 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *locked_layers = NULL;
|
|
|
|
gboolean locked = g_variant_get_boolean (value);
|
|
|
|
gchar *undo_label;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
if (gimp_item_can_lock_content (iter->data))
|
|
|
|
{
|
|
|
|
if (! locked && ! gimp_item_get_lock_content (iter->data))
|
|
|
|
{
|
|
|
|
/* When unlocking, we expect all selected layers to be locked. */
|
|
|
|
g_list_free (locked_layers);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (locked != gimp_item_get_lock_content (iter->data))
|
|
|
|
{
|
|
|
|
locked_layers = g_list_prepend (locked_layers, iter->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! locked_layers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (locked)
|
|
|
|
undo_label = _("Lock content");
|
|
|
|
else
|
|
|
|
undo_label = _("Unlock content");
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_LOCK_CONTENTS,
|
|
|
|
undo_label);
|
|
|
|
|
|
|
|
for (iter = locked_layers; iter; iter = iter->next)
|
|
|
|
gimp_item_set_lock_content (iter->data, locked, TRUE);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gimp_image_undo_group_end (image);
|
2016-10-29 16:50:13 +02:00
|
|
|
|
2020-05-04 17:31:46 +02:00
|
|
|
g_list_free (locked_layers);
|
2016-10-29 16:50:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_lock_position_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2016-10-29 16:50:13 +02:00
|
|
|
{
|
|
|
|
GimpImage *image;
|
2020-05-04 17:31:46 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
|
|
|
GList *locked_layers = NULL;
|
|
|
|
gboolean locked = g_variant_get_boolean (value);
|
|
|
|
gchar *undo_label;
|
|
|
|
return_if_no_layers (image, layers, data);
|
|
|
|
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
if (gimp_item_can_lock_position (iter->data))
|
|
|
|
{
|
|
|
|
if (! locked && ! gimp_item_get_lock_position (iter->data))
|
|
|
|
{
|
|
|
|
/* When unlocking, we expect all selected layers to be locked. */
|
|
|
|
g_list_free (locked_layers);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (locked != gimp_item_get_lock_position (iter->data))
|
|
|
|
{
|
|
|
|
locked_layers = g_list_prepend (locked_layers, iter->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! locked_layers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (locked)
|
|
|
|
undo_label = _("Lock position");
|
|
|
|
else
|
|
|
|
undo_label = _("Unlock position");
|
|
|
|
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_LOCK_POSITION,
|
|
|
|
undo_label);
|
|
|
|
|
|
|
|
for (iter = locked_layers; iter; iter = iter->next)
|
|
|
|
gimp_item_set_lock_position (iter->data, locked, TRUE);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gimp_image_undo_group_end (image);
|
2016-10-29 16:50:13 +02:00
|
|
|
|
2020-05-04 17:31:46 +02:00
|
|
|
g_list_free (locked_layers);
|
2016-10-29 16:50:13 +02:00
|
|
|
}
|
|
|
|
|
2004-09-15 13:24:45 +00:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_lock_alpha_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2004-09-15 13:24:45 +00:00
|
|
|
{
|
2006-03-28 17:08:36 +00:00
|
|
|
GimpImage *image;
|
2020-04-29 02:12:00 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2005-07-10 21:17:22 +00:00
|
|
|
gboolean lock_alpha;
|
2020-04-29 02:12:00 +02:00
|
|
|
gboolean lock_change = FALSE;
|
|
|
|
return_if_no_layers (image, layers, data);
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
lock_alpha = g_variant_get_boolean (value);
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
2004-09-15 13:24:45 +00:00
|
|
|
{
|
2020-04-29 02:12:00 +02:00
|
|
|
if (gimp_layer_can_lock_alpha (iter->data))
|
|
|
|
{
|
|
|
|
/* Similar trick as in layers_mask_show_cmd_callback().
|
|
|
|
* When unlocking, we expect all selected layers to be locked,
|
2020-08-08 05:58:47 +00:00
|
|
|
* otherwise SET_ACTIVE() calls in layers-actions.c will
|
2020-04-29 02:12:00 +02:00
|
|
|
* trigger lock updates.
|
|
|
|
*/
|
|
|
|
if (! lock_alpha && ! gimp_layer_get_lock_alpha (iter->data))
|
|
|
|
return;
|
|
|
|
if (lock_alpha != gimp_layer_get_lock_alpha (iter->data))
|
|
|
|
lock_change = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! lock_change)
|
|
|
|
/* No layer locks would be changed. */
|
|
|
|
return;
|
2004-09-15 13:24:45 +00:00
|
|
|
|
2020-04-29 02:12:00 +02:00
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_LOCK_ALPHA,
|
|
|
|
lock_alpha ? _("Lock alpha channels") : _("Unlock alpha channels"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
if (gimp_layer_can_lock_alpha (iter->data))
|
|
|
|
{
|
|
|
|
if (lock_alpha != gimp_layer_get_lock_alpha (iter->data))
|
|
|
|
gimp_layer_set_lock_alpha (iter->data, lock_alpha, TRUE);
|
|
|
|
}
|
2004-09-15 13:24:45 +00:00
|
|
|
}
|
2020-04-29 02:12:00 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
2004-09-15 13:24:45 +00:00
|
|
|
}
|
|
|
|
|
2016-10-29 16:50:13 +02:00
|
|
|
void
|
2019-07-02 16:12:18 +02:00
|
|
|
layers_color_tag_cmd_callback (GimpAction *action,
|
2019-07-04 01:11:48 +02:00
|
|
|
GVariant *value,
|
2019-07-02 16:12:18 +02:00
|
|
|
gpointer data)
|
2016-10-29 16:50:13 +02:00
|
|
|
{
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpImage *image;
|
2020-04-28 18:17:59 +02:00
|
|
|
GList *layers;
|
|
|
|
GList *iter;
|
2019-07-04 01:11:48 +02:00
|
|
|
GimpColorTag color_tag;
|
2020-04-28 18:17:59 +02:00
|
|
|
return_if_no_layers (image, layers, data);
|
2016-10-29 16:50:13 +02:00
|
|
|
|
2019-07-04 01:11:48 +02:00
|
|
|
color_tag = (GimpColorTag) g_variant_get_int32 (value);
|
|
|
|
|
2020-04-28 18:17:59 +02:00
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
items_color_tag_cmd_callback (action, image, GIMP_ITEM (iter->data),
|
|
|
|
color_tag);
|
2016-10-29 16:50:13 +02:00
|
|
|
}
|
|
|
|
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2004-10-18 11:29:58 +00:00
|
|
|
/* private functions */
|
2001-04-20 16:27:44 +00:00
|
|
|
|
|
|
|
static void
|
2017-02-02 00:38:25 +01:00
|
|
|
layers_new_callback (GtkWidget *dialog,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const gchar *layer_name,
|
|
|
|
GimpLayerMode layer_mode,
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace layer_blend_space,
|
|
|
|
GimpLayerColorSpace layer_composite_space,
|
|
|
|
GimpLayerCompositeMode layer_composite_mode,
|
2017-02-02 00:38:25 +01:00
|
|
|
gdouble layer_opacity,
|
|
|
|
GimpFillType layer_fill_type,
|
|
|
|
gint layer_width,
|
|
|
|
gint layer_height,
|
|
|
|
gint layer_offset_x,
|
|
|
|
gint layer_offset_y,
|
|
|
|
gboolean layer_visible,
|
|
|
|
GimpColorTag layer_color_tag,
|
|
|
|
gboolean layer_lock_pixels,
|
|
|
|
gboolean layer_lock_position,
|
|
|
|
gboolean layer_lock_alpha,
|
|
|
|
gboolean rename_text_layer, /* unused */
|
|
|
|
gpointer user_data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2020-05-03 00:28:13 +02:00
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
GList *layers = gimp_image_get_selected_layers (image);
|
|
|
|
GList *new_layers = NULL;
|
|
|
|
GList *iter;
|
|
|
|
gint n_layers = g_list_length (layers);
|
|
|
|
gboolean run_once = (n_layers == 0);
|
2002-02-26 00:04:55 +00:00
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
g_object_set (config,
|
2017-02-12 23:49:26 +01:00
|
|
|
"layer-new-name", layer_name,
|
|
|
|
"layer-new-mode", layer_mode,
|
|
|
|
"layer-new-blend-space", layer_blend_space,
|
|
|
|
"layer-new-composite-space", layer_composite_space,
|
|
|
|
"layer-new-composite-mode", layer_composite_mode,
|
|
|
|
"layer-new-opacity", layer_opacity,
|
|
|
|
"layer-new-fill-type", layer_fill_type,
|
2016-09-24 21:10:07 +02:00
|
|
|
NULL);
|
2004-10-18 11:29:58 +00:00
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
layers = g_list_copy (layers);
|
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
ngettext ("New layer",
|
|
|
|
"New layers",
|
|
|
|
n_layers > 0 ? n_layers : 1));
|
|
|
|
for (iter = layers; iter || run_once; iter = iter ? iter->next : NULL)
|
2016-09-24 21:10:07 +02:00
|
|
|
{
|
2020-05-03 00:28:13 +02:00
|
|
|
GimpLayer *parent;
|
|
|
|
gint position;
|
|
|
|
|
|
|
|
run_once = FALSE;
|
|
|
|
if (iter)
|
|
|
|
{
|
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)))
|
|
|
|
{
|
|
|
|
parent = iter->data;
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parent = GIMP_LAYER (gimp_item_get_parent (iter->data));
|
|
|
|
position = gimp_item_get_index (iter->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* run_once */
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
layer = gimp_layer_new (image, layer_width, layer_height,
|
|
|
|
gimp_image_get_layer_format (image, TRUE),
|
|
|
|
config->layer_new_name,
|
|
|
|
config->layer_new_opacity,
|
|
|
|
config->layer_new_mode);
|
|
|
|
|
|
|
|
if (layer)
|
|
|
|
{
|
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer), layer_offset_x, layer_offset_y);
|
|
|
|
gimp_drawable_fill (GIMP_DRAWABLE (layer), context,
|
|
|
|
config->layer_new_fill_type);
|
|
|
|
gimp_item_set_visible (GIMP_ITEM (layer), layer_visible, FALSE);
|
|
|
|
gimp_item_set_color_tag (GIMP_ITEM (layer), layer_color_tag, FALSE);
|
|
|
|
gimp_item_set_lock_content (GIMP_ITEM (layer), layer_lock_pixels,
|
|
|
|
FALSE);
|
|
|
|
gimp_item_set_lock_position (GIMP_ITEM (layer), layer_lock_position,
|
|
|
|
FALSE);
|
|
|
|
gimp_layer_set_lock_alpha (layer, layer_lock_alpha, FALSE);
|
|
|
|
gimp_layer_set_blend_space (layer, layer_blend_space, FALSE);
|
|
|
|
gimp_layer_set_composite_space (layer, layer_composite_space, FALSE);
|
|
|
|
gimp_layer_set_composite_mode (layer, layer_composite_mode, FALSE);
|
|
|
|
|
|
|
|
gimp_image_add_layer (image, layer, parent, position, TRUE);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
|
|
|
|
new_layers = g_list_prepend (new_layers, layer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("%s: could not allocate new layer", G_STRFUNC);
|
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 00:28:13 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_set_selected_layers (image, new_layers);
|
|
|
|
|
|
|
|
g_list_free (layers);
|
|
|
|
g_list_free (new_layers);
|
2016-09-24 21:10:07 +02:00
|
|
|
gtk_widget_destroy (dialog);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2004-03-18 18:00:38 +00:00
|
|
|
static void
|
2017-02-02 00:38:25 +01:00
|
|
|
layers_edit_attributes_callback (GtkWidget *dialog,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const gchar *layer_name,
|
|
|
|
GimpLayerMode layer_mode,
|
2017-02-12 23:49:26 +01:00
|
|
|
GimpLayerColorSpace layer_blend_space,
|
|
|
|
GimpLayerColorSpace layer_composite_space,
|
|
|
|
GimpLayerCompositeMode layer_composite_mode,
|
2017-02-02 00:38:25 +01:00
|
|
|
gdouble layer_opacity,
|
|
|
|
GimpFillType unused1,
|
|
|
|
gint unused2,
|
|
|
|
gint unused3,
|
|
|
|
gint layer_offset_x,
|
|
|
|
gint layer_offset_y,
|
|
|
|
gboolean layer_visible,
|
|
|
|
GimpColorTag layer_color_tag,
|
|
|
|
gboolean layer_lock_pixels,
|
|
|
|
gboolean layer_lock_position,
|
|
|
|
gboolean layer_lock_alpha,
|
|
|
|
gboolean rename_text_layer,
|
|
|
|
gpointer user_data)
|
2004-10-18 11:29:58 +00:00
|
|
|
{
|
2016-10-21 22:54:10 +02:00
|
|
|
GimpItem *item = GIMP_ITEM (layer);
|
|
|
|
|
2017-02-12 23:49:26 +01:00
|
|
|
if (strcmp (layer_name, gimp_object_get_name (layer)) ||
|
|
|
|
layer_mode != gimp_layer_get_mode (layer) ||
|
|
|
|
layer_blend_space != gimp_layer_get_blend_space (layer) ||
|
|
|
|
layer_composite_space != gimp_layer_get_composite_space (layer) ||
|
|
|
|
layer_composite_mode != gimp_layer_get_composite_mode (layer) ||
|
|
|
|
layer_opacity != gimp_layer_get_opacity (layer) ||
|
|
|
|
layer_offset_x != gimp_item_get_offset_x (item) ||
|
|
|
|
layer_offset_y != gimp_item_get_offset_y (item) ||
|
|
|
|
layer_visible != gimp_item_get_visible (item) ||
|
|
|
|
layer_color_tag != gimp_item_get_color_tag (item) ||
|
|
|
|
layer_lock_pixels != gimp_item_get_lock_content (item) ||
|
|
|
|
layer_lock_position != gimp_item_get_lock_position (item) ||
|
|
|
|
layer_lock_alpha != gimp_layer_get_lock_alpha (layer))
|
2004-10-18 11:29:58 +00:00
|
|
|
{
|
2016-10-21 22:54:10 +02:00
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
|
|
|
|
_("Layer Attributes"));
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2016-10-21 22:54:10 +02:00
|
|
|
if (strcmp (layer_name, gimp_object_get_name (layer)))
|
2004-10-18 11:29:58 +00:00
|
|
|
{
|
2016-10-21 22:54:10 +02:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! gimp_item_rename (GIMP_ITEM (layer), layer_name, &error))
|
|
|
|
{
|
|
|
|
gimp_message_literal (image->gimp,
|
|
|
|
G_OBJECT (dialog), GIMP_MESSAGE_WARNING,
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
2004-10-18 11:29:58 +00:00
|
|
|
}
|
2016-09-24 21:10:07 +02:00
|
|
|
|
2016-10-21 22:54:10 +02:00
|
|
|
if (layer_mode != gimp_layer_get_mode (layer))
|
|
|
|
gimp_layer_set_mode (layer, layer_mode, TRUE);
|
|
|
|
|
2017-02-12 23:49:26 +01:00
|
|
|
if (layer_blend_space != gimp_layer_get_blend_space (layer))
|
|
|
|
gimp_layer_set_blend_space (layer, layer_blend_space, TRUE);
|
|
|
|
|
|
|
|
if (layer_composite_space != gimp_layer_get_composite_space (layer))
|
|
|
|
gimp_layer_set_composite_space (layer, layer_composite_space, TRUE);
|
|
|
|
|
|
|
|
if (layer_composite_mode != gimp_layer_get_composite_mode (layer))
|
|
|
|
gimp_layer_set_composite_mode (layer, layer_composite_mode, TRUE);
|
2017-02-02 00:38:25 +01:00
|
|
|
|
2016-10-21 22:54:10 +02:00
|
|
|
if (layer_opacity != gimp_layer_get_opacity (layer))
|
|
|
|
gimp_layer_set_opacity (layer, layer_opacity, TRUE);
|
|
|
|
|
|
|
|
if (layer_offset_x != gimp_item_get_offset_x (item) ||
|
|
|
|
layer_offset_y != gimp_item_get_offset_y (item))
|
|
|
|
{
|
|
|
|
gimp_item_translate (item,
|
|
|
|
layer_offset_x - gimp_item_get_offset_x (item),
|
|
|
|
layer_offset_y - gimp_item_get_offset_y (item),
|
|
|
|
TRUE);
|
2004-10-18 11:29:58 +00:00
|
|
|
}
|
2016-10-21 22:54:10 +02:00
|
|
|
|
2016-10-23 22:45:08 +02:00
|
|
|
if (layer_visible != gimp_item_get_visible (item))
|
|
|
|
gimp_item_set_visible (item, layer_visible, TRUE);
|
|
|
|
|
2016-10-29 16:50:13 +02:00
|
|
|
if (layer_color_tag != gimp_item_get_color_tag (item))
|
|
|
|
gimp_item_set_color_tag (item, layer_color_tag, TRUE);
|
|
|
|
|
2016-10-23 22:45:08 +02:00
|
|
|
if (layer_lock_pixels != gimp_item_get_lock_content (item))
|
|
|
|
gimp_item_set_lock_content (item, layer_lock_pixels, TRUE);
|
|
|
|
|
|
|
|
if (layer_lock_position != gimp_item_get_lock_position (item))
|
|
|
|
gimp_item_set_lock_position (item, layer_lock_position, TRUE);
|
|
|
|
|
|
|
|
if (layer_lock_alpha != gimp_layer_get_lock_alpha (layer))
|
|
|
|
gimp_layer_set_lock_alpha (layer, layer_lock_alpha, TRUE);
|
|
|
|
|
2016-10-21 22:54:10 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
2004-10-18 11:29:58 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 21:10:07 +02:00
|
|
|
if (gimp_item_is_text_layer (GIMP_ITEM (layer)))
|
|
|
|
{
|
|
|
|
g_object_set (layer,
|
|
|
|
"auto-rename", rename_text_layer,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_destroy (dialog);
|
2004-10-18 11:29:58 +00:00
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
|
|
|
|
static void
|
2016-09-23 14:35:14 +02:00
|
|
|
layers_add_mask_callback (GtkWidget *dialog,
|
2020-05-02 01:42:04 +02:00
|
|
|
GList *layers,
|
2016-09-23 14:35:14 +02:00
|
|
|
GimpAddMaskType add_mask_type,
|
|
|
|
GimpChannel *channel,
|
|
|
|
gboolean invert,
|
|
|
|
gpointer user_data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2020-05-02 01:42:04 +02:00
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layers->data));
|
2016-09-23 14:35:14 +02:00
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
GimpLayerMask *mask;
|
2020-05-02 01:42:04 +02:00
|
|
|
GList *iter;
|
2016-09-23 14:35:14 +02:00
|
|
|
GError *error = NULL;
|
2003-11-26 15:48:50 +00:00
|
|
|
|
2016-09-23 14:35:14 +02:00
|
|
|
g_object_set (config,
|
|
|
|
"layer-add-mask-type", add_mask_type,
|
|
|
|
"layer-add-mask-invert", invert,
|
|
|
|
NULL);
|
2003-03-06 13:22:11 +00:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
gimp_image_undo_group_start (image,
|
|
|
|
GIMP_UNDO_GROUP_LAYER_ADD,
|
|
|
|
_("Add Layer Masks"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
mask = gimp_layer_create_mask (iter->data,
|
|
|
|
config->layer_add_mask_type,
|
|
|
|
channel);
|
2002-09-01 07:25:41 +00:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
if (config->layer_add_mask_invert)
|
|
|
|
gimp_channel_invert (GIMP_CHANNEL (mask), FALSE);
|
2003-11-26 15:48:50 +00:00
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
if (! gimp_layer_add_mask (iter->data, mask, TRUE, &error))
|
|
|
|
{
|
|
|
|
gimp_message_literal (image->gimp,
|
|
|
|
G_OBJECT (dialog), GIMP_MESSAGE_WARNING,
|
|
|
|
error->message);
|
|
|
|
g_object_unref (mask);
|
|
|
|
g_clear_error (&error);
|
|
|
|
return;
|
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 01:42:04 +02:00
|
|
|
gimp_image_undo_group_end (image);
|
2016-09-23 14:35:14 +02:00
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-09-25 22:18:37 +02:00
|
|
|
layers_scale_callback (GtkWidget *dialog,
|
|
|
|
GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpUnit unit,
|
|
|
|
GimpInterpolationType interpolation,
|
|
|
|
gdouble xresolution, /* unused */
|
|
|
|
gdouble yresolution, /* unused */
|
|
|
|
GimpUnit resolution_unit,/* unused */
|
|
|
|
gpointer user_data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2016-09-24 15:07:04 +02:00
|
|
|
GimpDisplay *display = GIMP_DISPLAY (user_data);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2006-10-14 16:51:30 +00:00
|
|
|
layer_scale_unit = unit;
|
|
|
|
layer_scale_interp = interpolation;
|
|
|
|
|
2004-10-12 14:59:14 +00:00
|
|
|
if (width > 0 && height > 0)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2004-10-12 14:59:14 +00:00
|
|
|
GimpItem *item = GIMP_ITEM (viewable);
|
2004-04-13 13:54:54 +00:00
|
|
|
GimpProgress *progress;
|
2004-10-12 14:59:14 +00:00
|
|
|
GtkWidget *progress_dialog = NULL;
|
|
|
|
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
|
2008-11-03 00:09:01 +00:00
|
|
|
if (width == gimp_item_get_width (item) &&
|
|
|
|
height == gimp_item_get_height (item))
|
2004-10-12 14:59:14 +00:00
|
|
|
return;
|
2002-02-25 17:58:50 +00:00
|
|
|
|
2006-03-28 17:55:52 +00:00
|
|
|
if (display)
|
2004-10-12 14:59:14 +00:00
|
|
|
{
|
2006-03-28 17:55:52 +00:00
|
|
|
progress = GIMP_PROGRESS (display);
|
2004-10-12 14:59:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
progress_dialog = gimp_progress_dialog_new ();
|
|
|
|
progress = GIMP_PROGRESS (progress_dialog);
|
|
|
|
}
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2014-07-12 23:45:20 +02:00
|
|
|
progress = gimp_progress_start (progress, FALSE, _("Scaling"));
|
2002-02-25 17:58:50 +00:00
|
|
|
|
2004-10-12 14:59:14 +00:00
|
|
|
gimp_item_scale_by_origin (item,
|
|
|
|
width, height, interpolation,
|
|
|
|
progress, TRUE);
|
2004-02-09 00:09:20 +00:00
|
|
|
|
2004-08-10 18:47:21 +00:00
|
|
|
if (progress)
|
|
|
|
gimp_progress_end (progress);
|
2003-05-07 11:09:00 +00:00
|
|
|
|
2004-10-12 14:59:14 +00:00
|
|
|
if (progress_dialog)
|
|
|
|
gtk_widget_destroy (progress_dialog);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2004-10-12 14:59:14 +00:00
|
|
|
gimp_image_flush (gimp_item_get_image (item));
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-10-14 16:51:30 +00:00
|
|
|
g_warning ("Scale Error: "
|
|
|
|
"Both width and height must be greater than zero.");
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-09-25 22:18:37 +02:00
|
|
|
layers_resize_callback (GtkWidget *dialog,
|
|
|
|
GimpViewable *viewable,
|
|
|
|
GimpContext *context,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpUnit unit,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
2021-02-07 22:06:41 +06:00
|
|
|
gdouble unused0,
|
|
|
|
gdouble unused1,
|
|
|
|
GimpUnit unused2,
|
2016-10-20 00:30:10 +02:00
|
|
|
GimpFillType fill_type,
|
2021-02-07 22:06:41 +06:00
|
|
|
GimpItemSet unused3,
|
|
|
|
gboolean unused4,
|
2016-09-25 22:18:37 +02:00
|
|
|
gpointer user_data)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2006-10-14 16:51:30 +00:00
|
|
|
layer_resize_unit = unit;
|
|
|
|
|
2004-10-27 10:33:08 +00:00
|
|
|
if (width > 0 && height > 0)
|
2001-04-20 16:27:44 +00:00
|
|
|
{
|
2016-10-20 00:30:10 +02:00
|
|
|
GimpItem *item = GIMP_ITEM (viewable);
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
|
|
|
|
g_object_set (config,
|
|
|
|
"layer-resize-fill-type", fill_type,
|
|
|
|
NULL);
|
2002-02-25 17:58:50 +00:00
|
|
|
|
2004-10-27 10:33:08 +00:00
|
|
|
gtk_widget_destroy (dialog);
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2008-11-03 00:09:01 +00:00
|
|
|
if (width == gimp_item_get_width (item) &&
|
|
|
|
height == gimp_item_get_height (item))
|
2004-10-27 10:33:08 +00:00
|
|
|
return;
|
2001-04-20 16:27:44 +00:00
|
|
|
|
2016-10-10 00:02:16 +02:00
|
|
|
gimp_item_resize (item, context, fill_type,
|
2004-10-27 10:33:08 +00:00
|
|
|
width, height, offset_x, offset_y);
|
|
|
|
gimp_image_flush (gimp_item_get_image (item));
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-10-14 16:51:30 +00:00
|
|
|
g_warning ("Resize Error: "
|
|
|
|
"Both width and height must be greater than zero.");
|
2001-04-20 16:27:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-15 13:24:45 +00:00
|
|
|
static gint
|
2017-02-20 23:51:32 +01:00
|
|
|
layers_mode_index (GimpLayerMode layer_mode,
|
|
|
|
const GimpLayerMode *modes,
|
|
|
|
gint n_modes)
|
2004-09-15 13:24:45 +00:00
|
|
|
{
|
|
|
|
gint i = 0;
|
|
|
|
|
2017-02-20 23:51:32 +01:00
|
|
|
while (i < (n_modes - 1) && modes[i] != layer_mode)
|
2004-09-15 13:24:45 +00:00
|
|
|
i++;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|