diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index e8c72c595e25aafaa295967a074978b21b5cc82b..9b190a9036c4c3f8de7688f963befd0b2687f9a7 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -48,6 +48,8 @@ #include "core/gimplayerpropundo.h" #include "core/gimplayer-floating-selection.h" #include "core/gimplayer-new.h" +#include "core/gimplayermask.h" +#include "core/gimplayervectormask.h" #include "core/gimplink.h" #include "core/gimplinklayer.h" #include "core/gimplist.h" @@ -152,6 +154,7 @@ static void layers_add_mask_callback (GtkWidget *dialog, GList *layers, GimpAddMaskType add_mask_type, GimpChannel *channel, + GimpPath *path, gboolean invert, gboolean edit_mask, gpointer user_data); @@ -304,7 +307,8 @@ layers_edit_vector_cmd_callback (GimpAction *action, } if (GIMP_IS_PATH_TOOL (active_tool)) - gimp_path_tool_set_path (GIMP_PATH_TOOL (active_tool), GIMP_VECTOR_LAYER (layer), NULL); + gimp_path_tool_set_path (GIMP_PATH_TOOL (active_tool), + GIMP_RASTERIZABLE (layer), NULL); } void @@ -2604,6 +2608,7 @@ layers_add_mask_callback (GtkWidget *dialog, GList *layers, GimpAddMaskType add_mask_type, GimpChannel *channel, + GimpPath *path, gboolean invert, gboolean edit_mask, gpointer user_data) @@ -2626,21 +2631,51 @@ layers_add_mask_callback (GtkWidget *dialog, for (iter = layers; iter; iter = iter->next) { - mask = gimp_layer_create_mask (iter->data, - config->layer_add_mask_type, - channel); + if (! path) + { + 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); + if (config->layer_add_mask_invert) + gimp_channel_invert (GIMP_CHANNEL (mask), FALSE); - if (! gimp_layer_add_mask (iter->data, mask, edit_mask, TRUE, &error)) + if (! gimp_layer_add_mask (iter->data, mask, edit_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; + } + } + else { - gimp_message_literal (image->gimp, - G_OBJECT (dialog), GIMP_MESSAGE_WARNING, - error->message); - g_object_unref (mask); - g_clear_error (&error); - return; + GimpImage *image; + GimpItem *item = GIMP_ITEM (iter->data); + GimpLayerVectorMask *vector_mask; + + image = gimp_item_get_image (item); + + vector_mask = gimp_layer_vector_mask_new (image, path, + gimp_item_get_width (item), + gimp_item_get_height (item), + "Vector Mask"); + + if (! gimp_layer_add_mask (iter->data, GIMP_LAYER_MASK (vector_mask), + edit_mask, TRUE, &error)) + { + gimp_message_literal (image->gimp, + G_OBJECT (dialog), GIMP_MESSAGE_WARNING, + error->message); + g_object_unref (vector_mask); + g_clear_error (&error); + return; + } + + gimp_layer_vector_mask_render (vector_mask); } } diff --git a/app/core/core-types.h b/app/core/core-types.h index 990be94727e1428039e7b931f0c845af12dccae1..5e623bd2fbec3aa77d954147cc9324ea3d3ce037 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -166,6 +166,7 @@ typedef struct _GimpDrawableFilterMask GimpDrawableFilterMask; typedef struct _GimpRasterizable GimpRasterizable; typedef struct _GimpChannel GimpChannel; typedef struct _GimpLayerMask GimpLayerMask; +typedef struct _GimpLayerVectorMask GimpLayerVectorMask; typedef struct _GimpSelection GimpSelection; typedef struct _GimpLayer GimpLayer; typedef struct _GimpGroupLayer GimpGroupLayer; diff --git a/app/core/gimplayervectormask.c b/app/core/gimplayervectormask.c new file mode 100644 index 0000000000000000000000000000000000000000..4836aeb3b7f13f651081454e90243610f47076c1 --- /dev/null +++ b/app/core/gimplayervectormask.c @@ -0,0 +1,230 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include + +#include "libgimpmath/gimpmath.h" + +#include "core-types.h" + +#include "gegl/gimp-babl.h" + +#include "core/gimp.h" +#include "core/gimpdrawable-fill.h" +#include "core/gimpfilloptions.h" +#include "core/gimpimage.h" +#include "core/gimpselection.h" +#include "core/gimprasterizable.h" + +#include "path/gimppath.h" + +#include "gimperror.h" +#include "gimpimage.h" +#include "gimplayer.h" +#include "gimplayervectormask.h" + +#include "gimp-intl.h" + +static void gimp_layer_vector_mask_rasterizable_iface_init + (GimpRasterizableInterface *iface); + +static void gimp_layer_vector_mask_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized); + + +static void gimp_layer_vector_mask_render_path (GimpLayerVectorMask *layer_mask); + +G_DEFINE_TYPE_WITH_CODE (GimpLayerVectorMask, gimp_layer_vector_mask, GIMP_TYPE_LAYER_MASK, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_RASTERIZABLE, + gimp_layer_vector_mask_rasterizable_iface_init)) + +#define parent_class gimp_layer_vector_mask_parent_class + + +static void +gimp_layer_vector_mask_class_init (GimpLayerVectorMaskClass *klass) +{ + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + GimpItemClass *item_class = GIMP_ITEM_CLASS (klass); + + viewable_class->default_icon_name = "gimp-tool-path"; + viewable_class->default_name = _("Vector Mask"); + + item_class->translate_desc = C_("undo-type", "Move Layer Vector Mask"); + item_class->to_selection_desc = C_("undo-type", "Layer Vector Mask to Selection"); +} + +static void +gimp_layer_vector_mask_init (GimpLayerVectorMask *layer_mask) +{ + layer_mask->layer = NULL; + layer_mask->path = NULL; +} + +static void +gimp_layer_vector_mask_rasterizable_iface_init (GimpRasterizableInterface *iface) +{ + iface->set_rasterized = gimp_layer_vector_mask_set_rasterized; +} + +static void +gimp_layer_vector_mask_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized) +{ + if (! rasterized) + gimp_layer_vector_mask_render (GIMP_LAYER_VECTOR_MASK (rasterizable)); +} + + +gboolean +gimp_layer_vector_mask_render (GimpLayerVectorMask *layer_mask) +{ + GimpDrawable *drawable = GIMP_DRAWABLE (layer_mask); + GimpLayer *layer = NULL; + GeglBuffer *buffer = NULL; + GeglColor *color = NULL; + GimpItem *item = GIMP_ITEM (layer_mask); + GimpImage *image = gimp_item_get_image (item); + gint x = 0; + gint y = 0; + gint width = gimp_image_get_width (image); + gint height = gimp_image_get_height (image); + + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); + + layer = gimp_layer_mask_get_layer (GIMP_LAYER_MASK (layer_mask)); + + g_object_freeze_notify (G_OBJECT (drawable)); + + /* Resize layer according to path size */ + gimp_item_bounds (GIMP_ITEM (layer), &x, &y, &width, &height); + + buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), + gimp_drawable_get_format (drawable)); + gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer); + g_object_unref (buffer); + + gimp_item_set_offset (GIMP_ITEM (layer_mask), x, y); + + /* make the layer background transparent */ + color = gegl_color_new ("black"); + gimp_channel_set_color (GIMP_CHANNEL (layer_mask), color, FALSE); + g_clear_object (&color); + + /* render path to the layer */ + gimp_layer_vector_mask_render_path (layer_mask); + + g_object_thaw_notify (G_OBJECT (drawable)); + + return TRUE; +} + +static void +gimp_layer_vector_mask_render_path (GimpLayerVectorMask *layer_mask) +{ + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer_mask)); + GimpChannel *selection = gimp_image_get_mask (image); + GimpFillOptions *fill_options; + GeglColor *fill_color; + GList *drawables; + + /* Don't mask these fill/stroke operations */ + gimp_selection_suspend (GIMP_SELECTION (selection)); + + fill_color = gegl_color_new ("white"); + + fill_options = gimp_fill_options_new (image->gimp, NULL, FALSE); + gimp_fill_options_set_style (GIMP_FILL_OPTIONS (fill_options), + GIMP_FILL_STYLE_FG_COLOR); + gimp_context_set_foreground (GIMP_CONTEXT (fill_options), + fill_color); + + /* Fill the path object onto the layer */ + gimp_drawable_fill_path (GIMP_DRAWABLE (layer_mask), + fill_options, + layer_mask->path, FALSE, NULL); + + drawables = g_list_prepend (NULL, GIMP_DRAWABLE (layer_mask)); + + g_list_free (drawables); + + /*gimp_rasterizable_auto_rename (GIMP_RASTERIZABLE (layer_mask), + GIMP_OBJECT (layer_mask->path), + NULL);*/ + + gimp_selection_resume (GIMP_SELECTION (selection)); + + g_clear_object (&fill_color); + g_object_unref (fill_options); +} + +/* Public Functions */ + +GimpLayerVectorMask * +gimp_layer_vector_mask_new (GimpImage *image, + GimpPath *path, + gint width, + gint height, + const gchar *name) +{ + GimpLayerVectorMask *layer_mask; + + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_PATH (path), NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + layer_mask = + GIMP_LAYER_VECTOR_MASK (gimp_drawable_new (GIMP_TYPE_LAYER_VECTOR_MASK, + image, name, + 0, 0, width, height, + gimp_image_get_mask_format (image))); + + layer_mask->path = path; + + /* set the layer_mask opacity */ + gimp_channel_set_show_masked (GIMP_CHANNEL (layer_mask), TRUE); + + /* selection mask variables */ + GIMP_CHANNEL (layer_mask)->x2 = width; + GIMP_CHANNEL (layer_mask)->y2 = height; + + return layer_mask; +} + +void +gimp_layer_vector_mask_set_path (GimpLayerVectorMask *layer_mask, + GimpPath *path) +{ + g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask)); + g_return_if_fail (GIMP_IS_PATH (path)); + + layer_mask->path = path; + + gimp_layer_vector_mask_render (layer_mask); +} + +GimpPath * +gimp_layer_vector_mask_get_path (GimpLayerVectorMask *layer_mask) +{ + g_return_val_if_fail (GIMP_IS_LAYER_VECTOR_MASK (layer_mask), NULL); + + return layer_mask->path; +} diff --git a/app/core/gimplayervectormask.h b/app/core/gimplayervectormask.h new file mode 100644 index 0000000000000000000000000000000000000000..0c31d12f0b52bbcb86e50e7de5db6310d4d6f2c1 --- /dev/null +++ b/app/core/gimplayervectormask.h @@ -0,0 +1,59 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "gimplayermask.h" + + +#define GIMP_TYPE_LAYER_VECTOR_MASK (gimp_layer_vector_mask_get_type ()) +#define GIMP_LAYER_VECTOR_MASK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LAYER_VECTOR_MASK, GimpLayerVectorMask)) +#define GIMP_LAYER_VECTOR_MASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LAYER_VECTOR_MASK, GimpLayerVectorMaskClass)) +#define GIMP_IS_LAYER_VECTOR_MASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LAYER_VECTOR_MASK)) +#define GIMP_IS_LAYER_VECTOR_MASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LAYER_VECTOR_MASK)) +#define GIMP_LAYER_VECTOR_MASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LAYER_VECTOR_MASK, GimpLayerVectorMaskClass)) + + +typedef struct _GimpLayerVectorMaskClass GimpLayerVectorMaskClass; + +struct _GimpLayerVectorMask +{ + GimpLayerMask parent_instance; + + GimpLayer *layer; + GimpPath *path; +}; + +struct _GimpLayerVectorMaskClass +{ + GimpLayerMaskClass parent_class; +}; + + +GType gimp_layer_vector_mask_get_type (void) G_GNUC_CONST; + +GimpLayerVectorMask * gimp_layer_vector_mask_new (GimpImage *image, + GimpPath *path, + gint width, + gint height, + const gchar *name); + +gboolean gimp_layer_vector_mask_render (GimpLayerVectorMask *layer_mask); + +void gimp_layer_vector_mask_set_path (GimpLayerVectorMask *layer_mask, + GimpPath *layer); +GimpPath * gimp_layer_vector_mask_get_path (GimpLayerVectorMask *layer_mask); diff --git a/app/core/meson.build b/app/core/meson.build index 656d36a9c2a03d094d18c08e2d81fc3faa4e397f..0dad5e50af119d16b6354c107566f6fa6a6139ed 100644 --- a/app/core/meson.build +++ b/app/core/meson.build @@ -191,6 +191,7 @@ libappcore_sources = [ 'gimplayermaskpropundo.c', 'gimplayermaskundo.c', 'gimplayerpropundo.c', + 'gimplayervectormask.c', 'gimplayerstack.c', 'gimplayerundo.c', 'gimplineart.c', diff --git a/app/dialogs/layer-add-mask-dialog.c b/app/dialogs/layer-add-mask-dialog.c index 1556fc8d4d4e140412bbf4716cc4585909eea89a..a48cc8b5c1cf4dc6e8f5eb5c08ca420f25d6409b 100644 --- a/app/dialogs/layer-add-mask-dialog.c +++ b/app/dialogs/layer-add-mask-dialog.c @@ -31,6 +31,8 @@ #include "core/gimpimage.h" #include "core/gimplayer.h" +#include "path/gimppath.h" + #include "widgets/gimpcontainercombobox.h" #include "widgets/gimpcontainerview.h" #include "widgets/gimphelp-ids.h" @@ -49,10 +51,13 @@ struct _LayerAddMaskDialog GList *layers; GimpAddMaskType add_mask_type; GimpChannel *channel; + GimpPath *path; gboolean invert; gboolean edit_mask; GimpAddMaskCallback callback; gpointer user_data; + + GtkWidget *stack; }; @@ -64,6 +69,8 @@ static void layer_add_mask_dialog_response (GtkWidget *dialog LayerAddMaskDialog *private); static void layer_add_mask_dialog_channel_selected (GimpContainerView *view, LayerAddMaskDialog *private); +static void layer_add_mask_dialog_path_selected (GimpContainerView *view, + LayerAddMaskDialog *private); /* public functions */ @@ -80,14 +87,18 @@ layer_add_mask_dialog_new (GList *layers, { LayerAddMaskDialog *private; GtkWidget *dialog; + GtkWidget *main_vbox; GtkWidget *vbox; GtkWidget *hbox; + GtkWidget *switcher; GtkWidget *frame; GtkWidget *combo; GtkWidget *button; GimpImage *image; GimpChannel *channel; GList *channels; + GimpPath *path; + GList *paths; gchar *title; gchar *desc; gint n_layers = g_list_length (layers); @@ -128,9 +139,9 @@ layer_add_mask_dialog_new (GList *layers, g_free (desc); gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog), - GTK_RESPONSE_OK, - GTK_RESPONSE_CANCEL, - -1); + GTK_RESPONSE_OK, + GTK_RESPONSE_CANCEL, + -1); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); @@ -141,12 +152,24 @@ layer_add_mask_dialog_new (GList *layers, G_CALLBACK (layer_add_mask_dialog_response), private); - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); + main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), - vbox, TRUE, TRUE, 0); - gtk_widget_show (vbox); + main_vbox, TRUE, TRUE, 0); + gtk_widget_set_visible (main_vbox, TRUE); + /* Switcher */ + switcher = gtk_stack_switcher_new (); + gtk_box_pack_start (GTK_BOX (main_vbox), switcher, TRUE, TRUE, 0); + gtk_widget_set_visible (switcher, TRUE); + + private->stack = gtk_stack_new (); + gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), + GTK_STACK (private->stack)); + gtk_box_pack_start (GTK_BOX (main_vbox), private->stack, TRUE, TRUE, 0); + gtk_widget_set_visible (private->stack, TRUE); + + /* Raster masks */ frame = gimp_enum_radio_frame_new (GIMP_TYPE_ADD_MASK_TYPE, gtk_label_new (_("Initialize Layer Mask to:")), @@ -155,8 +178,9 @@ layer_add_mask_dialog_new (GList *layers, &button); gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (button), private->add_mask_type); - - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_stack_add_titled (GTK_STACK (private->stack), + frame, "raster-mask", + _("Raster")); gtk_widget_show (frame); image = gimp_item_get_image (GIMP_ITEM (layers->data)); @@ -184,6 +208,38 @@ layer_add_mask_dialog_new (GList *layers, gimp_container_view_set_1_selected (GIMP_CONTAINER_VIEW (combo), GIMP_VIEWABLE (channel)); + /* Vector masks */ + frame = gimp_frame_new (_("Initialize Layer Mask to:")); + gtk_stack_add_titled (GTK_STACK (private->stack), + frame, + "vector-mask", + _("Vector")); + gtk_widget_set_visible (frame, TRUE); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_set_visible (vbox, TRUE); + + combo = gimp_container_combo_box_new (gimp_image_get_paths (image), + context, + GIMP_VIEW_SIZE_SMALL, 1); + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + gtk_widget_set_visible (combo, TRUE); + + g_signal_connect (combo, "selection-changed", + G_CALLBACK (layer_add_mask_dialog_path_selected), + private); + + paths = gimp_image_get_selected_paths (image); + if (paths) + path = paths->data; + else + path = GIMP_PATH (gimp_container_get_first_child (gimp_image_get_paths (image))); + + gimp_container_view_set_1_selected (GIMP_CONTAINER_VIEW (combo), + GIMP_VIEWABLE (path)); + + /* General options */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); @@ -226,20 +282,40 @@ layer_add_mask_dialog_response (GtkWidget *dialog, if (response_id == GTK_RESPONSE_OK) { GimpImage *image = gimp_item_get_image (GIMP_ITEM (private->layers->data)); + GimpPath *path = NULL; - if (private->add_mask_type == GIMP_ADD_MASK_CHANNEL && - ! private->channel) + if (g_strcmp0 (gtk_stack_get_visible_child_name (GTK_STACK (private->stack)), + "raster-mask") == 0) { - gimp_message_literal (image->gimp, - G_OBJECT (dialog), GIMP_MESSAGE_WARNING, - _("Please select a channel first")); - return; + if (private->add_mask_type == GIMP_ADD_MASK_CHANNEL && + ! private->channel) + { + gimp_message_literal (image->gimp, + G_OBJECT (dialog), GIMP_MESSAGE_WARNING, + _("Please select a channel first")); + return; + } + } + else + { + if (! private->path) + { + gimp_message_literal (image->gimp, + G_OBJECT (dialog), GIMP_MESSAGE_WARNING, + _("Please select a path first")); + return; + } + else + { + path = private->path; + } } private->callback (dialog, private->layers, private->add_mask_type, private->channel, + path, private->invert, private->edit_mask, private->user_data); @@ -256,3 +332,10 @@ layer_add_mask_dialog_channel_selected (GimpContainerView *view, { private->channel = GIMP_CHANNEL (gimp_container_view_get_1_selected (view)); } + +static void +layer_add_mask_dialog_path_selected (GimpContainerView *view, + LayerAddMaskDialog *private) +{ + private->path = GIMP_PATH (gimp_container_view_get_1_selected (view)); +} diff --git a/app/dialogs/layer-add-mask-dialog.h b/app/dialogs/layer-add-mask-dialog.h index a34be60f34549790f0a257c44d510647ac8461ef..7aacb91289f3bc011d0068d484ce2f6ec82eae41 100644 --- a/app/dialogs/layer-add-mask-dialog.h +++ b/app/dialogs/layer-add-mask-dialog.h @@ -22,6 +22,7 @@ typedef void (* GimpAddMaskCallback) (GtkWidget *dialog, GList *layers, GimpAddMaskType add_mask_type, GimpChannel *channel, + GimpPath *path, gboolean invert, gboolean edit_mask, gpointer user_data); diff --git a/app/tools/gimppathtool.c b/app/tools/gimppathtool.c index 3564a79d99608c319a67598277a83d571e424e1d..47307b909654db8a29ae85cc0205aa87b28c6bec 100644 --- a/app/tools/gimppathtool.c +++ b/app/tools/gimppathtool.c @@ -35,6 +35,9 @@ #include "core/gimpimage-pick-item.h" #include "core/gimpimage-undo.h" #include "core/gimpimage-undo-push.h" +#include "core/gimplayer.h" +#include "core/gimplayermask.h" +#include "core/gimplayervectormask.h" #include "core/gimprasterizable.h" #include "core/gimpstrokeoptions.h" #include "core/gimptoolinfo.h" @@ -153,14 +156,14 @@ static void gimp_path_tool_vector_layer_path_changed static void gimp_path_tool_vector_change_notify (GObject *options, const GParamSpec *pspec, - GimpVectorLayer *layer); + GimpRasterizable *layer); -static void gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, +static void gimp_path_tool_layer_rasterized (GimpRasterizable *layer, gboolean is_rasterized, GimpPathTool *tool); static void gimp_path_tool_set_layer (GimpPathTool *path_tool, - GimpVectorLayer *vector_layer); + GimpRasterizable *layer); static void gimp_path_tool_confirm_dialog (GimpPathTool *path_tool, GimpVectorLayer *layer); @@ -532,22 +535,31 @@ gimp_path_tool_image_changed (GimpPathTool *path_tool, static void gimp_path_tool_image_selected_layers_changed (GimpPathTool *path_tool) { - GList *current_layers = NULL; + GList *current_layers = NULL; + GimpLayerMask *mask = NULL; if (path_tool->current_image) current_layers = gimp_image_get_selected_layers (path_tool->current_image); /* If we've selected a single vector layer, make its path editable */ if (current_layers && - g_list_length (current_layers) == 1 && - GIMP_IS_VECTOR_LAYER (GIMP_ITEM (current_layers->data))) + g_list_length (current_layers) == 1) { - GimpVectorLayer *vector_layer = current_layers->data; + mask = gimp_layer_get_mask (GIMP_LAYER (current_layers->data)); - if (gimp_item_is_vector_layer (GIMP_ITEM (current_layers->data))) - gimp_path_tool_set_layer (path_tool, vector_layer); - else - gimp_path_tool_confirm_dialog (path_tool, vector_layer); + if (GIMP_IS_VECTOR_LAYER (GIMP_ITEM (current_layers->data))) + { + GimpVectorLayer *vector_layer = current_layers->data; + + if (gimp_item_is_vector_layer (GIMP_ITEM (current_layers->data))) + gimp_path_tool_set_layer (path_tool, GIMP_RASTERIZABLE (vector_layer)); + else + gimp_path_tool_confirm_dialog (path_tool, vector_layer); + } + else if (mask && GIMP_IS_LAYER_VECTOR_MASK (mask)) + { + gimp_path_tool_set_layer (path_tool, GIMP_RASTERIZABLE (mask)); + } } else { @@ -626,6 +638,10 @@ gimp_path_tool_tool_path_end_change (GimpToolWidget *tool_path, g_object_unref (undo); } + if (path_tool->current_vector && + GIMP_IS_LAYER_VECTOR_MASK (path_tool->current_vector)) + gimp_layer_vector_mask_render (GIMP_LAYER_VECTOR_MASK (path_tool->current_vector)); + gimp_image_flush (image); } @@ -658,9 +674,9 @@ gimp_path_tool_path_removed (GimpPath *path, } void -gimp_path_tool_set_path (GimpPathTool *path_tool, - GimpVectorLayer *layer, - GimpPath *path) +gimp_path_tool_set_path (GimpPathTool *path_tool, + GimpRasterizable *layer, + GimpPath *path) { GimpTool *tool; GimpItem *item = NULL; @@ -674,7 +690,12 @@ gimp_path_tool_set_path (GimpPathTool *path_tool, options = GIMP_PATH_TOOL_GET_OPTIONS (path_tool); if (layer != NULL) - path = gimp_vector_layer_get_path (layer); + { + if (gimp_item_is_vector_layer (GIMP_ITEM (layer))) + path = gimp_vector_layer_get_path (GIMP_VECTOR_LAYER (layer)); + else if (GIMP_IS_LAYER_VECTOR_MASK (layer)) + path = gimp_layer_vector_mask_get_path (GIMP_LAYER_VECTOR_MASK (layer)); + } if (path) item = GIMP_ITEM (path); @@ -682,7 +703,7 @@ gimp_path_tool_set_path (GimpPathTool *path_tool, if (path == path_tool->path) return; - if (path_tool->current_vector_layer && path && ! layer) + if (path_tool->current_vector && path && ! layer) { GimpImage *image = path_tool->current_image; GList *all_layers = gimp_image_get_layer_list (image); @@ -846,7 +867,7 @@ gimp_path_tool_create_vector_layer (GimpPathTool *path_tool) /* If there's already an active vector layer, or no paths are * selected, create a new blank path. */ - if (path_tool->current_vector_layer || ! path_tool->path) + if (path_tool->current_vector || ! path_tool->path) { GimpPath *new_path = gimp_path_new (image, _("Vector Layer")); @@ -855,13 +876,13 @@ gimp_path_tool_create_vector_layer (GimpPathTool *path_tool) g_signal_handlers_disconnect_by_func (options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); g_signal_handlers_disconnect_by_func (options->fill_options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); g_signal_handlers_disconnect_by_func (options->stroke_options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); } layer = gimp_vector_layer_new (image, path_tool->path, @@ -881,7 +902,7 @@ gimp_path_tool_create_vector_layer (GimpPathTool *path_tool) -1, TRUE); - gimp_path_tool_set_layer (path_tool, layer); + gimp_path_tool_set_layer (path_tool, GIMP_RASTERIZABLE (layer)); gimp_vector_layer_refresh (layer); gimp_image_flush (image); @@ -896,60 +917,73 @@ gimp_path_tool_vector_layer_path_changed (GimpVectorLayerOptions *options, const GParamSpec *pspec, GimpPathTool *tool) { - gimp_path_tool_set_path (tool, tool->current_vector_layer, NULL); + gimp_path_tool_set_path (tool, tool->current_vector, NULL); } static void gimp_path_tool_vector_change_notify (GObject *options, const GParamSpec *pspec, - GimpVectorLayer *layer) + GimpRasterizable *layer) { - GimpImage *image; - gboolean needs_update = FALSE; + GimpImage *image; + GimpVectorLayer *vector_layer = NULL; + gboolean needs_update = FALSE; image = gimp_item_get_image (GIMP_ITEM (layer)); - if (GIMP_IS_STROKE_OPTIONS (options)) + if (gimp_item_is_vector_layer (GIMP_ITEM (layer))) + vector_layer = GIMP_VECTOR_LAYER (layer); + + if (vector_layer) { - GimpStrokeOptions *stroke_options = GIMP_STROKE_OPTIONS (options); + if (GIMP_IS_STROKE_OPTIONS (options)) + { + GimpStrokeOptions *stroke_options = GIMP_STROKE_OPTIONS (options); - gimp_config_sync (G_OBJECT (stroke_options), - G_OBJECT (layer->options->stroke_options), 0); + gimp_config_sync (G_OBJECT (stroke_options), + G_OBJECT (vector_layer->options->stroke_options), + 0); - needs_update = TRUE; - } - else if (GIMP_IS_FILL_OPTIONS (options)) - { - GimpFillOptions *fill_options = GIMP_FILL_OPTIONS (options); + needs_update = TRUE; + } + else if (GIMP_IS_FILL_OPTIONS (options)) + { + GimpFillOptions *fill_options = GIMP_FILL_OPTIONS (options); - gimp_config_sync (G_OBJECT (fill_options), - G_OBJECT (layer->options->fill_options), 0); + gimp_config_sync (G_OBJECT (fill_options), + G_OBJECT (vector_layer->options->fill_options), + 0); - needs_update = TRUE; - } - else if (GIMP_IS_PATH_OPTIONS (options)) - { - GimpPathOptions *path_options = GIMP_PATH_OPTIONS (options); + needs_update = TRUE; + } + else if (GIMP_IS_PATH_OPTIONS (options)) + { + GimpPathOptions *path_options = GIMP_PATH_OPTIONS (options); - g_object_set (layer->options, - "enable-fill", path_options->enable_fill, - "enable-stroke", path_options->enable_stroke, - NULL); + g_object_set (vector_layer->options, + "enable-fill", path_options->enable_fill, + "enable-stroke", path_options->enable_stroke, + NULL); - needs_update = TRUE; + needs_update = TRUE; + } } if (needs_update) { - gimp_vector_layer_refresh (layer); + if (vector_layer) + gimp_vector_layer_refresh (vector_layer); + else if (GIMP_IS_LAYER_VECTOR_MASK (layer)) + gimp_layer_vector_mask_render (GIMP_LAYER_VECTOR_MASK (layer)); + gimp_image_flush (image); } } static void -gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, - gboolean is_rasterized, - GimpPathTool *tool) +gimp_path_tool_layer_rasterized (GimpRasterizable *layer, + gboolean is_rasterized, + GimpPathTool *tool) { if (! is_rasterized && ! GIMP_TOOL (tool)->display) { @@ -961,7 +995,7 @@ gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, if (current_layers && g_list_length (current_layers) == 1 && current_layers->data == layer) - gimp_path_tool_set_layer (tool, layer); + gimp_path_tool_set_layer (tool, GIMP_RASTERIZABLE (layer)); } else if (is_rasterized && GIMP_TOOL (tool)->display) { @@ -970,40 +1004,50 @@ gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, } static void -gimp_path_tool_set_layer (GimpPathTool *path_tool, - GimpVectorLayer *vector_layer) +gimp_path_tool_set_layer (GimpPathTool *path_tool, + GimpRasterizable *layer) { GimpPathOptions *options; + GimpVectorLayer *vector_layer = NULL; GimpVectorLayerOptions *layer_options; g_return_if_fail (GIMP_IS_PATH_TOOL (path_tool)); options = GIMP_PATH_TOOL_GET_OPTIONS (path_tool); - if (path_tool->current_vector_layer) + if (path_tool->current_vector && + gimp_item_is_vector_layer (GIMP_ITEM (path_tool->current_vector))) + vector_layer = GIMP_VECTOR_LAYER (path_tool->current_vector); + + if (vector_layer) { - layer_options = gimp_vector_layer_get_options (path_tool->current_vector_layer); + layer_options = gimp_vector_layer_get_options (vector_layer); g_signal_handlers_disconnect_by_func (layer_options, gimp_path_tool_vector_layer_path_changed, path_tool); g_signal_handlers_disconnect_by_func (options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); g_signal_handlers_disconnect_by_func (options->fill_options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); g_signal_handlers_disconnect_by_func (options->stroke_options, gimp_path_tool_vector_change_notify, - path_tool->current_vector_layer); + path_tool->current_vector); - g_signal_handlers_disconnect_by_func (path_tool->current_vector_layer, + g_signal_handlers_disconnect_by_func (path_tool->current_vector, G_CALLBACK (gimp_path_tool_layer_rasterized), path_tool); } - path_tool->current_vector_layer = vector_layer; - gimp_path_tool_set_path (path_tool, vector_layer, NULL); + path_tool->current_vector = layer; + gimp_path_tool_set_path (path_tool, layer, NULL); + + vector_layer = NULL; + if (path_tool->current_vector && + gimp_item_is_vector_layer (GIMP_ITEM (path_tool->current_vector))) + vector_layer = GIMP_VECTOR_LAYER (path_tool->current_vector); if (vector_layer) { @@ -1137,7 +1181,7 @@ gimp_path_tool_confirm_response (GimpViewableDialog *dialog, case GTK_RESPONSE_ACCEPT: gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); - gimp_path_tool_set_layer (path_tool, layer); + gimp_path_tool_set_layer (path_tool, GIMP_RASTERIZABLE (layer)); break; default: diff --git a/app/tools/gimppathtool.h b/app/tools/gimppathtool.h index 1b239836c8b83785a77ac4349a3a8e7b83a9ca12..7c7531ee11c8c9335f48fe79f7211d707cf37dc0 100644 --- a/app/tools/gimppathtool.h +++ b/app/tools/gimppathtool.h @@ -40,16 +40,16 @@ struct _GimpPathTool { GimpDrawTool parent_instance; - GimpImage *current_image; - GimpVectorLayer *current_vector_layer; + GimpImage *current_image; + GimpRasterizable *current_vector; - GimpPath *path; /* the current Path data */ - GimpPathMode saved_mode; /* used by modifier_key() */ + GimpPath *path; /* the current Path data */ + GimpPathMode saved_mode; /* used by modifier_key() */ - GimpToolWidget *widget; - GimpToolWidget *grab_widget; + GimpToolWidget *widget; + GimpToolWidget *grab_widget; - GtkWidget *confirm_dialog; + GtkWidget *confirm_dialog; }; struct _GimpPathToolClass @@ -64,5 +64,5 @@ void gimp_path_tool_register (GimpToolRegisterCallback callback, GType gimp_path_tool_get_type (void) G_GNUC_CONST; void gimp_path_tool_set_path (GimpPathTool *path_tool, - GimpVectorLayer *layer, + GimpRasterizable *layer, GimpPath *path); diff --git a/app/tools/gimptool.c b/app/tools/gimptool.c index 727c8513915819bc7ee901c691ec30e6f393102e..66f60976bd64ee9f2e3b336888d803a60265cca7 100644 --- a/app/tools/gimptool.c +++ b/app/tools/gimptool.c @@ -28,6 +28,7 @@ #include "core/gimp.h" #include "core/gimpcontainer.h" #include "core/gimpimage.h" +#include "core/gimplayervectormask.h" #include "core/gimplinklayer.h" #include "core/gimpprogress.h" #include "core/gimptoolinfo.h" @@ -739,12 +740,13 @@ gimp_tool_button_press (GimpTool *tool, drawables = gimp_image_get_selected_drawables (image); for (GList *iter = drawables; iter; iter = iter->next) { - GimpDrawable *drawable = iter->data; - GimpItem *locked_item = NULL; + GimpDrawable *drawable = iter->data; + GimpItem *locked_item = NULL; if (gimp_item_is_vector_layer (GIMP_ITEM (drawable)) || gimp_item_is_link_layer (GIMP_ITEM (drawable)) || gimp_item_is_text_layer (GIMP_ITEM (drawable)) || + GIMP_IS_LAYER_VECTOR_MASK (drawable) || gimp_item_is_content_locked (GIMP_ITEM (drawable), &locked_item)) { gboolean constrain_only; @@ -778,6 +780,14 @@ gimp_tool_button_press (GimpTool *tool, gimp_tool_message (tool, display, _("Vector layers must be rasterized (%s)."), menu_path); gimp_tools_blink_item (display->gimp, GIMP_ITEM (drawable)); } + else if (GIMP_IS_LAYER_VECTOR_MASK (drawable)) + { + GimpLayer *layer = + gimp_layer_mask_get_layer (GIMP_LAYER_MASK (drawable)); + /* TRANSLATORS: the string between parentheses will be a menu path. */ + gimp_tool_message (tool, display, _("Vector masks must be rasterized (%s)."), menu_path); + gimp_tools_blink_item (display->gimp, GIMP_ITEM (layer)); + } else { gimp_tool_message_literal (tool, display, diff --git a/po/POTFILES.in b/po/POTFILES.in index f18e02e3fded13f060f40d72e0bc58b486ff25c9..7e3f29a1e0d10a24fee278a3c0d02df96ed1ca4d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -182,6 +182,7 @@ app/core/gimpitem-exclusive.c app/core/gimplayer-floating-selection.c app/core/gimplayer.c app/core/gimplayermask.c +app/core/gimplayervectormask.c app/core/gimplineart.c app/core/gimplink.c app/core/gimplinklayer.c