From a1cd2a2588a289f553b978c867fbad025a3e98b3 Mon Sep 17 00:00:00 2001 From: Alx Sa Date: Sat, 12 Jul 2025 21:56:50 -0400 Subject: [PATCH] path, tools, pdb: UX updates to vector layers This patch improves vector layer UX based on feedback. In summary: * Makes vector layer editable from the Path tool * Adds initial PDB for creating vector layers in scripts * Size vector layers to the path size, rather than image * Transform tools utilize the path for resizing * Path tool automatically selects vector layer path --- app/actions/layers-actions.c | 4 +- app/actions/layers-commands.c | 18 +- app/actions/paths-commands.c | 13 +- app/core/core-enums.c | 4 + app/core/core-enums.h | 2 + app/core/gimpimage-undo-push.c | 41 ++ app/core/gimpimage-undo-push.h | 11 + app/core/gimpimage.c | 12 + app/core/gimpparamspecs.c | 1 + app/dialogs/vector-layer-options-dialog.c | 574 ++++++++------- app/dialogs/vector-layer-options-dialog.h | 68 +- app/display/gimpcanvas-style.c | 11 + app/gimpcore.def | 3 +- app/path/gimppath.c | 85 +++ app/path/gimppath.h | 3 + app/path/gimpvectorlayer-xcf.c | 172 +++++ app/path/gimpvectorlayer-xcf.h | 33 + app/path/gimpvectorlayer.c | 801 +++++++++++++++++++++ app/path/gimpvectorlayer.h | 69 ++ app/path/gimpvectorlayeroptions-parasite.c | 95 +++ app/path/gimpvectorlayeroptions-parasite.h | 33 + app/path/gimpvectorlayeroptions.c | 364 ++++++++++ app/path/gimpvectorlayeroptions.h | 66 ++ app/path/gimpvectorlayerundo.c | 288 ++++++++ app/path/gimpvectorlayerundo.h | 58 ++ app/path/meson.build | 5 + app/path/path-types.h | 12 +- app/pdb/internal-procs.c | 3 +- app/pdb/internal-procs.h | 1 + app/pdb/item-cmds.c | 65 ++ app/pdb/meson.build | 1 + app/pdb/vector-layer-cmds.c | 232 ++++++ app/plug-in/gimpgpparams.c | 1 + app/tools/gimppainttool.c | 20 + app/tools/gimppathoptions.c | 476 +++++++++++- app/tools/gimppathoptions.h | 35 +- app/tools/gimppathtool.c | 418 ++++++----- app/tools/gimppathtool.h | 13 +- libgimp/gimp.c | 1 + libgimp/gimp.def | 11 + libgimp/gimp.h | 1 + libgimp/gimp_pdb_headers.h | 1 + libgimp/gimpgpparams-body.c | 9 + libgimp/gimpitem_pdb.c | 40 + libgimp/gimpitem_pdb.h | 1 + libgimp/gimpparamspecs-body.c | 80 ++ libgimp/gimpparamspecs.h | 19 + libgimp/gimpplugin.c | 6 + libgimp/gimpprocedure-params.c | 78 ++ libgimp/gimpprocedure-params.h | 31 + libgimp/gimptypes.h | 1 + libgimp/gimpvectorlayer.c | 75 ++ libgimp/gimpvectorlayer.h | 45 ++ libgimp/gimpvectorlayer_pdb.c | 159 ++++ libgimp/gimpvectorlayer_pdb.h | 43 ++ libgimp/meson.build | 4 + pdb/app.pl | 10 + pdb/groups.pl | 1 + pdb/groups/item.pdb | 40 +- pdb/groups/vector_layer.pdb | 144 ++++ pdb/meson.build | 1 + pdb/pdb.pl | 12 + 62 files changed, 4392 insertions(+), 532 deletions(-) create mode 100644 app/path/gimpvectorlayer-xcf.c create mode 100644 app/path/gimpvectorlayer-xcf.h create mode 100644 app/path/gimpvectorlayer.c create mode 100644 app/path/gimpvectorlayer.h create mode 100644 app/path/gimpvectorlayeroptions-parasite.c create mode 100644 app/path/gimpvectorlayeroptions-parasite.h create mode 100644 app/path/gimpvectorlayeroptions.c create mode 100644 app/path/gimpvectorlayeroptions.h create mode 100644 app/path/gimpvectorlayerundo.c create mode 100644 app/path/gimpvectorlayerundo.h create mode 100644 app/pdb/vector-layer-cmds.c create mode 100644 libgimp/gimpvectorlayer.c create mode 100644 libgimp/gimpvectorlayer.h create mode 100644 libgimp/gimpvectorlayer_pdb.c create mode 100644 libgimp/gimpvectorlayer_pdb.h create mode 100644 pdb/groups/vector_layer.pdb diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c index b52d0a5d38..2dd69ba7a2 100644 --- a/app/actions/layers-actions.c +++ b/app/actions/layers-actions.c @@ -33,7 +33,7 @@ #include "text/gimptextlayer.h" -#include "vectors/gimpvectorlayer.h" +#include "path/gimpvectorlayer.h" #include "widgets/gimphelp-ids.h" #include "widgets/gimpactiongroup.h" @@ -999,7 +999,7 @@ layers_actions_update (GimpActionGroup *group, gimp_action_group_set_action_active (group, action, TRUE); text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer)); - vector_layer = gimp_drawable_is_vector_layer (GIMP_DRAWABLE (layer)); + vector_layer = gimp_item_is_vector_layer (GIMP_ITEM (layer)); } } diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index 939a27d3ea..0ec271a799 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -74,8 +74,8 @@ #include "display/gimpdisplayshell.h" #include "display/gimpimagewindow.h" +#include "tools/gimppathtool.h" #include "tools/gimptexttool.h" -#include "tools/gimpvectortool.h" #include "tools/tool_manager.h" #include "dialogs/dialogs.h" @@ -204,6 +204,10 @@ layers_edit_cmd_callback (GimpAction *action, { layers_edit_text_cmd_callback (action, value, data); } + else if (gimp_item_is_vector_layer (GIMP_ITEM (layers->data))) + { + layers_vector_fill_stroke_cmd_callback (action, value, data); + } else { layers_edit_attributes_cmd_callback (action, value, data); @@ -273,7 +277,7 @@ layers_edit_vector_cmd_callback (GimpAction *action, layer = layers->data; - if (! gimp_drawable_is_vector_layer (GIMP_DRAWABLE (layer))) + if (! gimp_item_is_vector_layer (GIMP_ITEM (layer))) { layers_edit_attributes_cmd_callback (action, value, data); return; @@ -281,13 +285,13 @@ layers_edit_vector_cmd_callback (GimpAction *action, active_tool = tool_manager_get_active (image->gimp); - if (! GIMP_IS_VECTOR_TOOL (active_tool)) + if (! GIMP_IS_PATH_TOOL (active_tool)) { GimpToolInfo *tool_info; tool_info = (GimpToolInfo *) gimp_container_get_child_by_name (image->gimp->tool_info_list, - "gimp-vector-tool"); + "gimp-path-tool"); if (GIMP_IS_TOOL_INFO (tool_info)) { @@ -296,9 +300,9 @@ layers_edit_vector_cmd_callback (GimpAction *action, } } - if (GIMP_IS_VECTOR_TOOL (active_tool)) - gimp_vector_tool_set_vectors (GIMP_VECTOR_TOOL (active_tool), - GIMP_VECTOR_LAYER (layer)->options->path); + if (GIMP_IS_PATH_TOOL (active_tool)) + gimp_path_tool_set_path (GIMP_PATH_TOOL (active_tool), + GIMP_VECTOR_LAYER (layer)->options->path); } void diff --git a/app/actions/paths-commands.c b/app/actions/paths-commands.c index 717c467569..e36831ad6c 100644 --- a/app/actions/paths-commands.c +++ b/app/actions/paths-commands.c @@ -470,6 +470,7 @@ paths_delete_cmd_callback (GimpAction *action, { GimpImage *image; GList *paths; + gboolean attached_to_vector_layer = FALSE; return_if_no_paths (image, paths, data); paths = g_list_copy (paths); @@ -479,11 +480,21 @@ paths_delete_cmd_callback (GimpAction *action, _("Remove Paths")); for (GList *iter = paths; iter; iter = iter->next) - gimp_image_remove_path (image, iter->data, TRUE, NULL); + { + /* Verify path is not attached to vector layer */ + if (! gimp_path_attached_to_vector_layer (GIMP_PATH (iter->data), image)) + gimp_image_remove_path (image, iter->data, TRUE, NULL); + else + attached_to_vector_layer = TRUE; + } gimp_image_undo_group_end (image); gimp_image_flush (image); g_list_free (paths); + + if (attached_to_vector_layer) + gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_WARNING, + _("Paths attached to vector layers weren't deleted")); } void diff --git a/app/core/core-enums.c b/app/core/core-enums.c index 827f0b5f11..db511084d8 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -1267,6 +1267,8 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_TEXT_LAYER, "GIMP_UNDO_TEXT_LAYER", "text-layer" }, { GIMP_UNDO_TEXT_LAYER_MODIFIED, "GIMP_UNDO_TEXT_LAYER_MODIFIED", "text-layer-modified" }, { GIMP_UNDO_TEXT_LAYER_CONVERT, "GIMP_UNDO_TEXT_LAYER_CONVERT", "text-layer-convert" }, + { GIMP_UNDO_VECTOR_LAYER, "GIMP_UNDO_VECTOR_LAYER", "vector-layer" }, + { GIMP_UNDO_VECTOR_LAYER_MODIFIED, "GIMP_UNDO_VECTOR_LAYER_MODIFIED", "vector-layer-modified" }, { GIMP_UNDO_LAYER_MASK_ADD, "GIMP_UNDO_LAYER_MASK_ADD", "layer-mask-add" }, { GIMP_UNDO_LAYER_MASK_REMOVE, "GIMP_UNDO_LAYER_MASK_REMOVE", "layer-mask-remove" }, { GIMP_UNDO_LAYER_MASK_APPLY, "GIMP_UNDO_LAYER_MASK_APPLY", "layer-mask-apply" }, @@ -1380,6 +1382,8 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_TEXT_LAYER, NC_("undo-type", "Text layer"), NULL }, { GIMP_UNDO_TEXT_LAYER_MODIFIED, NC_("undo-type", "Text layer modification"), NULL }, { GIMP_UNDO_TEXT_LAYER_CONVERT, NC_("undo-type", "Convert text layer"), NULL }, + { GIMP_UNDO_VECTOR_LAYER, NC_("undo-type", "Vector layer"), NULL }, + { GIMP_UNDO_VECTOR_LAYER_MODIFIED, NC_("undo-type", "Vector layer modification"), NULL }, { GIMP_UNDO_LAYER_MASK_ADD, NC_("undo-type", "Add layer masks"), NULL }, { GIMP_UNDO_LAYER_MASK_REMOVE, NC_("undo-type", "Delete layer masks"), NULL }, { GIMP_UNDO_LAYER_MASK_APPLY, NC_("undo-type", "Apply layer masks"), NULL }, diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 972e0ce725..227251102b 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -619,6 +619,8 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_TEXT_LAYER, /*< desc="Text layer" >*/ GIMP_UNDO_TEXT_LAYER_MODIFIED, /*< desc="Text layer modification" >*/ GIMP_UNDO_TEXT_LAYER_CONVERT, /*< desc="Convert text layer" >*/ + GIMP_UNDO_VECTOR_LAYER, /*< desc="Vector layer" >*/ + GIMP_UNDO_VECTOR_LAYER_MODIFIED, /*< desc="Vector layer modification" >*/ GIMP_UNDO_LAYER_MASK_ADD, /*< desc="Add layer masks" >*/ GIMP_UNDO_LAYER_MASK_REMOVE, /*< desc="Delete layer masks" >*/ GIMP_UNDO_LAYER_MASK_APPLY, /*< desc="Apply layer masks" >*/ diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index b8d6a377bf..e6850df9a4 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -57,6 +57,8 @@ #include "path/gimppathmodundo.h" #include "path/gimppathpropundo.h" #include "path/gimppathundo.h" +#include "path/gimpvectorlayer.h" +#include "path/gimpvectorlayerundo.h" #include "text/gimptextlayer.h" #include "text/gimptextundo.h" @@ -877,6 +879,45 @@ gimp_image_undo_push_text_layer_convert (GimpImage *image, } +/************************/ +/* Vector Layer Undos */ +/************************/ + +GimpUndo * +gimp_image_undo_push_vector_layer (GimpImage *image, + const gchar *undo_desc, + GimpVectorLayer *layer, + const GParamSpec *pspec) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER (layer), NULL); + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)), NULL); + + return gimp_image_undo_push (image, GIMP_TYPE_VECTOR_LAYER_UNDO, + GIMP_UNDO_VECTOR_LAYER, undo_desc, + GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE, + "item", layer, + "param", pspec, + NULL); +} + +GimpUndo * +gimp_image_undo_push_vector_layer_modified (GimpImage *image, + const gchar *undo_desc, + GimpVectorLayer *layer) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER (layer), NULL); + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)), NULL); + + return gimp_image_undo_push (image, GIMP_TYPE_VECTOR_LAYER_UNDO, + GIMP_UNDO_VECTOR_LAYER_MODIFIED, undo_desc, + GIMP_DIRTY_ITEM_META, + "item", layer, + NULL); +} + + /**********************/ /* Layer Mask Undos */ /**********************/ diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h index d50d355f8c..6e0404c740 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -215,6 +215,17 @@ GimpUndo * gimp_image_undo_push_text_layer_convert (GimpImage *image, GimpTextLayer *layer); +/* vector layer undos */ + +GimpUndo * gimp_image_undo_push_vector_layer (GimpImage *image, + const gchar *undo_desc, + GimpVectorLayer *layer, + const GParamSpec *pspec); +GimpUndo * gimp_image_undo_push_vector_layer_modified + (GimpImage *image, + const gchar *undo_desc, + GimpVectorLayer *layer); + /* layer mask undos */ GimpUndo * gimp_image_undo_push_layer_mask_add (GimpImage *image, diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index ed7e7be4a3..946e8db3d2 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -87,6 +87,7 @@ #include "text/gimptextlayer.h" #include "path/gimppath.h" +#include "path/gimpvectorlayer.h" #include "gimp-log.h" #include "gimp-intl.h" @@ -5457,6 +5458,17 @@ gimp_image_add_layer (GimpImage *image, gimp_drawable_attach_floating_sel (gimp_layer_get_floating_sel_drawable (layer), layer); + /* If the layer is a vector layer, also add its path to the image */ + if (gimp_item_is_vector_layer (GIMP_ITEM (layer))) + { + GimpPath *path = gimp_vector_layer_get_path (GIMP_VECTOR_LAYER (layer)); + + if (path && + (! gimp_item_is_attached (GIMP_ITEM (path))) && + gimp_item_get_image (GIMP_ITEM (path)) == image) + gimp_image_add_path (image, path, NULL, -1, FALSE); + } + if (old_has_alpha != gimp_image_has_alpha (image)) private->flush_accum.alpha_changed = TRUE; diff --git a/app/core/gimpparamspecs.c b/app/core/gimpparamspecs.c index fece6f1b43..79dc7463e1 100644 --- a/app/core/gimpparamspecs.c +++ b/app/core/gimpparamspecs.c @@ -42,6 +42,7 @@ #include "gimpselection.h" #include "path/gimppath.h" +#include "path/gimpvectorlayer.h" #include "text/gimpfont.h" #include "text/gimptextlayer.h" diff --git a/app/dialogs/vector-layer-options-dialog.c b/app/dialogs/vector-layer-options-dialog.c index 91ae832923..23028e87ed 100644 --- a/app/dialogs/vector-layer-options-dialog.c +++ b/app/dialogs/vector-layer-options-dialog.c @@ -1,248 +1,326 @@ -/* GIMP - The GNU Image Manipulation Program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - * vector-layer-options-dialog.h - * - * Copyright 2006 Hendrik Boom - * - * 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 "libgimpconfig/gimpconfig.h" -#include "libgimpwidgets/gimpwidgets.h" - -#include "dialogs-types.h" - -#include "core/gimp.h" -#include "core/gimpdrawable.h" -#include "core/gimpimage.h" -#include "core/gimpimage-undo-push.h" -#include "core/gimpstrokeoptions.h" - -#include "widgets/gimpcolorpanel.h" -#include "widgets/gimppropwidgets.h" -#include "widgets/gimpviewabledialog.h" -#include "widgets/gimpstrokeeditor.h" - -#include "vectors/gimpvectorlayer.h" -#include "vectors/gimpvectorlayeroptions.h" - -#include "vector-layer-options-dialog.h" - -#include "gimp-intl.h" - - -#define RESPONSE_RESET 1 - - -/* local functions */ - -static void vector_layer_options_dialog_notify (GObject *options, - const GParamSpec *pspec, - GtkWidget *dialog); -static void vector_layer_options_dialog_response (GtkWidget *widget, - gint response_id, - GtkWidget *dialog); - - -/* public function */ - -GtkWidget * -vector_layer_options_dialog_new (GimpVectorLayer *layer, - GimpContext *context, - const gchar *title, - const gchar *icon_name, - const gchar *help_id, - GtkWidget *parent) -{ - GimpVectorLayerOptions *saved_options; - GimpFillOptions *fill_options; - GimpStrokeOptions *stroke_options; - GtkWidget *dialog; - GtkWidget *main_vbox; - - g_return_val_if_fail (GIMP_IS_VECTOR_LAYER (layer), NULL); - g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); - g_return_val_if_fail (icon_name != NULL, NULL); - g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL); - - saved_options = gimp_config_duplicate (GIMP_CONFIG (layer->options)); - fill_options = gimp_config_duplicate (GIMP_CONFIG (saved_options->fill_options)); - stroke_options = gimp_config_duplicate (GIMP_CONFIG (saved_options->stroke_options)); - - dialog = gimp_viewable_dialog_new (g_list_prepend (NULL, GIMP_VIEWABLE (layer)), - context, - title, "gimp-vectorlayer-options", - icon_name, - _("Choose vector layer options"), - parent, - gimp_standard_help_func, - help_id, - _("_Reset"), RESPONSE_RESET, - _("_Cancel"), GTK_RESPONSE_CANCEL, - _("_Apply"), GTK_RESPONSE_OK, - - NULL); - - gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog), - RESPONSE_RESET, - GTK_RESPONSE_OK, - GTK_RESPONSE_CANCEL, - -1); - - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - - g_signal_connect (dialog, "response", - G_CALLBACK (vector_layer_options_dialog_response), - dialog); - - g_object_set_data (G_OBJECT (dialog), "layer", layer); - - g_object_set_data_full (G_OBJECT (dialog), "saved-options", - saved_options, - (GDestroyNotify) g_object_unref); - g_object_set_data_full (G_OBJECT (dialog), "fill-options", - fill_options, - (GDestroyNotify) g_object_unref); - g_object_set_data_full (G_OBJECT (dialog), "stroke-options", - stroke_options, - (GDestroyNotify) g_object_unref); - - g_signal_connect_object (fill_options, "notify", - G_CALLBACK (vector_layer_options_dialog_notify), - dialog, 0); - g_signal_connect_object (stroke_options, "notify", - G_CALLBACK (vector_layer_options_dialog_notify), - dialog, 0); - - 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))), - main_vbox, TRUE, TRUE, 0); - gtk_widget_set_visible (main_vbox, TRUE); - - /* The fill editor */ - { - GtkWidget *frame; - GtkWidget *fill_editor; - - frame = gimp_frame_new (_("Fill Style")); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); - gtk_widget_set_visible (frame, TRUE); - - fill_editor = gimp_fill_editor_new (fill_options, TRUE, TRUE); - gtk_container_add (GTK_CONTAINER (frame), fill_editor); - gtk_widget_set_visible (fill_editor, TRUE); - } - - /* The stroke editor */ - { - GtkWidget *frame; - GtkWidget *stroke_editor; - gdouble xres; - gdouble yres; - - frame = gimp_frame_new (_("Stroke Style")); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); - gtk_widget_set_visible (frame, TRUE); - - gimp_image_get_resolution (gimp_item_get_image (GIMP_ITEM (layer)), - &xres, &yres); - - stroke_editor = gimp_stroke_editor_new (stroke_options, yres, TRUE, TRUE); - gtk_container_add (GTK_CONTAINER (frame), stroke_editor); - gtk_widget_set_visible (stroke_editor, TRUE); - } - - return dialog; -} - -static void -vector_layer_options_dialog_notify (GObject *options, - const GParamSpec *pspec, - GtkWidget *dialog) -{ - GimpVectorLayer *layer; - GimpFillOptions *fill_options; - GimpStrokeOptions *stroke_options; - - layer = g_object_get_data (G_OBJECT (dialog), "layer"); - - fill_options = g_object_get_data (G_OBJECT (dialog), "fill-options"); - stroke_options = g_object_get_data (G_OBJECT (dialog), "stroke-options"); - - gimp_config_sync (G_OBJECT (fill_options), - G_OBJECT (layer->options->fill_options), 0); - gimp_config_sync (G_OBJECT (stroke_options), - G_OBJECT (layer->options->stroke_options), 0); - - gimp_vector_layer_refresh (layer); - gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); -} - -static void -vector_layer_options_dialog_response (GtkWidget *widget, - gint response_id, - GtkWidget *dialog) -{ - GimpVectorLayer *layer; - GimpVectorLayerOptions *saved_options; - GimpFillOptions *fill_options; - GimpStrokeOptions *stroke_options; - - layer = g_object_get_data (G_OBJECT (dialog), "layer"); - - saved_options = g_object_get_data (G_OBJECT (dialog), "saved-options"); - fill_options = g_object_get_data (G_OBJECT (dialog), "fill-options"); - stroke_options = g_object_get_data (G_OBJECT (dialog), "stroke-options"); - - switch (response_id) - { - case GTK_RESPONSE_OK: - if (layer && layer->options ) - { - gimp_config_sync (G_OBJECT (saved_options->fill_options), - G_OBJECT (layer->options->fill_options), 0); - gimp_config_sync (G_OBJECT (saved_options->stroke_options), - G_OBJECT (layer->options->stroke_options), 0); - - gimp_image_undo_push_vector_layer (gimp_item_get_image (GIMP_ITEM (layer)), - _("Fill/Stroke Vector Layer"), - layer, NULL); - - gimp_config_sync (G_OBJECT (fill_options), - G_OBJECT (layer->options->fill_options), 0); - gimp_config_sync (G_OBJECT (stroke_options), - G_OBJECT (layer->options->stroke_options), 0); - } - - gtk_widget_destroy (dialog); - break; - - default: - gimp_config_sync (G_OBJECT (saved_options->fill_options), - G_OBJECT (fill_options), 0); - gimp_config_sync (G_OBJECT (saved_options->stroke_options), - G_OBJECT (stroke_options), 0); - - if (response_id != RESPONSE_RESET) - gtk_widget_destroy (dialog); - break; - } -} +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * vector-layer-options-dialog.h + * + * Copyright 2006 Hendrik Boom + * + * 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 "libgimpconfig/gimpconfig.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "dialogs-types.h" + +#include "core/gimp.h" +#include "core/gimpdrawable.h" +#include "core/gimpimage.h" +#include "core/gimpimage-undo-push.h" +#include "core/gimpstrokeoptions.h" + +#include "path/gimppath.h" +#include "path/gimpvectorlayer.h" +#include "path/gimpvectorlayeroptions.h" + +#include "widgets/gimpcolorpanel.h" +#include "widgets/gimpcontainercombobox.h" +#include "widgets/gimpcontainerview.h" +#include "widgets/gimppropwidgets.h" +#include "widgets/gimpviewabledialog.h" +#include "widgets/gimpstrokeeditor.h" + +#include "vector-layer-options-dialog.h" + +#include "gimp-intl.h" + + +#define RESPONSE_RESET 1 + + +/* local functions */ + +static void vector_layer_options_dialog_notify (GObject *options, + const GParamSpec *pspec, + GtkWidget *dialog); +static void vector_layer_options_dialog_response (GtkWidget *widget, + gint response_id, + GtkWidget *dialog); +static void vector_layer_options_dialog_path_selected (GimpContainerView *view, + GtkWidget *dialog); + + +/* public function */ + +GtkWidget * +vector_layer_options_dialog_new (GimpVectorLayer *layer, + GimpContext *context, + const gchar *title, + const gchar *icon_name, + const gchar *help_id, + GtkWidget *parent) +{ + GimpVectorLayerOptions *saved_options; + GimpFillOptions *fill_options; + GimpStrokeOptions *stroke_options; + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *combo; + + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER (layer), NULL); + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + g_return_val_if_fail (icon_name != NULL, NULL); + g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL); + + saved_options = gimp_config_duplicate (GIMP_CONFIG (layer->options)); + fill_options = gimp_config_duplicate (GIMP_CONFIG (saved_options->fill_options)); + stroke_options = gimp_config_duplicate (GIMP_CONFIG (saved_options->stroke_options)); + + dialog = gimp_viewable_dialog_new (g_list_prepend (NULL, GIMP_VIEWABLE (layer)), + context, + title, "gimp-vectorlayer-options", + icon_name, + _("Edit Vector Layer Attributes"), + parent, + gimp_standard_help_func, + help_id, + _("_Reset"), RESPONSE_RESET, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Apply"), GTK_RESPONSE_OK, + + NULL); + + gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog), + RESPONSE_RESET, + GTK_RESPONSE_OK, + GTK_RESPONSE_CANCEL, + -1); + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + g_signal_connect (dialog, "response", + G_CALLBACK (vector_layer_options_dialog_response), + dialog); + + g_object_set_data (G_OBJECT (dialog), "layer", layer); + + g_object_set_data_full (G_OBJECT (dialog), "saved-options", + saved_options, + (GDestroyNotify) g_object_unref); + g_object_set_data_full (G_OBJECT (dialog), "fill-options", + fill_options, + (GDestroyNotify) g_object_unref); + g_object_set_data_full (G_OBJECT (dialog), "stroke-options", + stroke_options, + (GDestroyNotify) g_object_unref); + + g_signal_connect_object (saved_options, "notify::enable-fill", + G_CALLBACK (vector_layer_options_dialog_notify), + dialog, 0); + g_signal_connect_object (saved_options, "notify::enable-stroke", + G_CALLBACK (vector_layer_options_dialog_notify), + dialog, 0); + + g_signal_connect_object (fill_options, "notify", + G_CALLBACK (vector_layer_options_dialog_notify), + dialog, 0); + g_signal_connect_object (stroke_options, "notify", + G_CALLBACK (vector_layer_options_dialog_notify), + dialog, 0); + + 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))), + main_vbox, TRUE, TRUE, 0); + gtk_widget_set_visible (main_vbox, TRUE); + + + combo = gimp_container_combo_box_new (gimp_image_get_paths (gimp_item_get_image (GIMP_ITEM (layer))), + context, + GIMP_VIEW_SIZE_SMALL, 1); + gimp_container_view_set_1_selected (GIMP_CONTAINER_VIEW (combo), + GIMP_VIEWABLE (saved_options->path)); + g_signal_connect_object (combo, "selection-changed", + G_CALLBACK (vector_layer_options_dialog_path_selected), + dialog, 0); + + gtk_box_pack_start (GTK_BOX (main_vbox), combo, FALSE, FALSE, 0); + gtk_widget_set_visible (combo, TRUE); + + /* The fill editor */ + { + GtkWidget *frame; + GtkWidget *fill_editor; + + fill_editor = gimp_fill_editor_new (fill_options, TRUE, TRUE); + gtk_widget_set_visible (fill_editor, TRUE); + + frame = gimp_prop_expanding_frame_new (G_OBJECT (saved_options), + "enable-fill", NULL, fill_editor, + NULL); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + } + + /* The stroke editor */ + { + GtkWidget *frame; + GtkWidget *stroke_editor; + gdouble xres; + gdouble yres; + + gimp_image_get_resolution (gimp_item_get_image (GIMP_ITEM (layer)), + &xres, &yres); + + stroke_editor = gimp_stroke_editor_new (stroke_options, yres, TRUE, TRUE); + gtk_widget_set_visible (stroke_editor, TRUE); + + frame = gimp_prop_expanding_frame_new (G_OBJECT (saved_options), + "enable-stroke", NULL, stroke_editor, + NULL); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + } + + return dialog; +} + +static void +vector_layer_options_dialog_notify (GObject *options, + const GParamSpec *pspec, + GtkWidget *dialog) +{ + GimpVectorLayer *layer; + GimpFillOptions *fill_options; + GimpStrokeOptions *stroke_options; + gboolean enable_fill; + gboolean enable_stroke; + + layer = g_object_get_data (G_OBJECT (dialog), "layer"); + + enable_fill = layer->options->enable_fill; + enable_stroke = layer->options->enable_stroke; + + fill_options = g_object_get_data (G_OBJECT (dialog), "fill-options"); + stroke_options = g_object_get_data (G_OBJECT (dialog), "stroke-options"); + + gimp_config_sync (G_OBJECT (fill_options), + G_OBJECT (layer->options->fill_options), 0); + gimp_config_sync (G_OBJECT (stroke_options), + G_OBJECT (layer->options->stroke_options), 0); + + if (! strcmp (pspec->name, "enable-fill") || + ! strcmp (pspec->name, "enable-stroke")) + { + GimpVectorLayerOptions *vector_options; + + vector_options = GIMP_VECTOR_LAYER_OPTIONS (options); + + layer->options->enable_fill = vector_options->enable_fill; + layer->options->enable_stroke = vector_options->enable_stroke; + } + + gimp_vector_layer_refresh (layer); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); + + layer->options->enable_fill = enable_fill; + layer->options->enable_stroke = enable_stroke; +} + +static void +vector_layer_options_dialog_response (GtkWidget *widget, + gint response_id, + GtkWidget *dialog) +{ + GimpVectorLayer *layer; + GimpPath *path; + GimpVectorLayerOptions *saved_options; + GimpFillOptions *fill_options; + GimpStrokeOptions *stroke_options; + + layer = g_object_get_data (G_OBJECT (dialog), "layer"); + + saved_options = g_object_get_data (G_OBJECT (dialog), "saved-options"); + fill_options = g_object_get_data (G_OBJECT (dialog), "fill-options"); + stroke_options = g_object_get_data (G_OBJECT (dialog), "stroke-options"); + + switch (response_id) + { + case GTK_RESPONSE_OK: + if (layer && layer->options) + { + layer->options->enable_fill = saved_options->enable_fill; + gimp_config_sync (G_OBJECT (saved_options->fill_options), + G_OBJECT (layer->options->fill_options), 0); + layer->options->enable_stroke = saved_options->enable_stroke; + gimp_config_sync (G_OBJECT (saved_options->stroke_options), + G_OBJECT (layer->options->stroke_options), 0); + + gimp_image_undo_push_vector_layer (gimp_item_get_image (GIMP_ITEM (layer)), + _("Fill/Stroke Vector Layer"), + layer, NULL); + + gimp_config_sync (G_OBJECT (fill_options), + G_OBJECT (layer->options->fill_options), 0); + gimp_config_sync (G_OBJECT (stroke_options), + G_OBJECT (layer->options->stroke_options), 0); + } + + gtk_widget_destroy (dialog); + break; + + default: + gimp_config_sync (G_OBJECT (saved_options->fill_options), + G_OBJECT (fill_options), 0); + gimp_config_sync (G_OBJECT (saved_options->stroke_options), + G_OBJECT (stroke_options), 0); + if (layer && layer->options) + { + g_object_get (saved_options, "path", &path, NULL); + g_object_set (layer->options, "path", path, NULL); + + gimp_vector_layer_refresh (layer); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); + } + + if (response_id != RESPONSE_RESET) + gtk_widget_destroy (dialog); + break; + } +} + +static void +vector_layer_options_dialog_path_selected (GimpContainerView *view, + GtkWidget *dialog) +{ + GimpViewable *item = gimp_container_view_get_1_selected (view); + GimpPath *path = NULL; + GimpVectorLayer *layer; + + layer = g_object_get_data (G_OBJECT (dialog), "layer"); + + if (item) + path = GIMP_PATH (item); + + if (path && GIMP_IS_PATH (path)) + { + g_object_set (layer->options, "path", path, NULL); + + gimp_vector_layer_refresh (layer); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); + } +} diff --git a/app/dialogs/vector-layer-options-dialog.h b/app/dialogs/vector-layer-options-dialog.h index c7294366f7..e2ed040a1b 100644 --- a/app/dialogs/vector-layer-options-dialog.h +++ b/app/dialogs/vector-layer-options-dialog.h @@ -1,34 +1,34 @@ -/* GIMP - The GNU Image Manipulation Program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - * vector-layer-options-dialog.h - * - * Copyright 2006 Hendrik Boom - * - * 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 . - */ - -#ifndef __VECTOR_LAYER_OPTIONS_DIALOG_H__ -#define __VECTOR_LAYER_OPTIONS_DIALOG_H__ - - -GtkWidget * vector_layer_options_dialog_new (GimpVectorLayer *layer, - GimpContext *context, - const gchar *title, - const gchar *icon_name, - const gchar *help_id, - GtkWidget *parent); - - -#endif /* __VECTOR_LAYER_OPTIONS_DIALOG_H__ */ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * vector-layer-options-dialog.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __VECTOR_LAYER_OPTIONS_DIALOG_H__ +#define __VECTOR_LAYER_OPTIONS_DIALOG_H__ + + +GtkWidget * vector_layer_options_dialog_new (GimpVectorLayer *layer, + GimpContext *context, + const gchar *title, + const gchar *icon_name, + const gchar *help_id, + GtkWidget *parent); + + +#endif /* __VECTOR_LAYER_OPTIONS_DIALOG_H__ */ diff --git a/app/display/gimpcanvas-style.c b/app/display/gimpcanvas-style.c index 6991637697..7dd1a0485d 100644 --- a/app/display/gimpcanvas-style.c +++ b/app/display/gimpcanvas-style.c @@ -34,6 +34,8 @@ #include "core/gimpgrid.h" #include "core/gimplayer.h" +#include "path/gimpvectorlayer.h" + #include "gimpcanvas.h" #include "gimpcanvas-style.h" @@ -431,6 +433,15 @@ gimp_canvas_set_layer_style (GtkWidget *canvas, pattern = gimp_cairo_pattern_create_stipple (layer_group_fg, layer_group_bg, 0, offset_x, offset_y, render_space); } + else if (gimp_item_is_vector_layer (GIMP_ITEM (layer))) + { + GeglColor *transparent = gegl_color_new ("transparent"); + + pattern = gimp_cairo_pattern_create_stipple (transparent, transparent, 0, + offset_x, offset_y, render_space); + + g_clear_object (&transparent); + } else { pattern = gimp_cairo_pattern_create_stipple (layer_fg, layer_bg, 0, diff --git a/app/gimpcore.def b/app/gimpcore.def index 9527b1473a..d243e4417c 100644 --- a/app/gimpcore.def +++ b/app/gimpcore.def @@ -398,6 +398,7 @@ EXPORTS gimp_item_get_visible gimp_item_height gimp_item_is_text_layer + gimp_item_is_vector_layer gimp_item_offsets gimp_item_rename gimp_item_resize @@ -450,7 +451,7 @@ EXPORTS gimp_marshal_VOID__OBJECT_OBJECT gimp_marshal_VOID__OBJECT_POINTER gimp_marshal_VOID__POINTER_BOXED - gimp_marshal_VOID__POINTER_ENUM + gimp_marshal_VOID__POINTER_ENUM gimp_marshal_VOID__STRING_BOOLEAN_UINT_FLAGS gimp_marshal_VOID__STRING_FLAGS gimp_message diff --git a/app/path/gimppath.c b/app/path/gimppath.c index 125bf53f2c..2f2a498cc8 100644 --- a/app/path/gimppath.c +++ b/app/path/gimppath.c @@ -40,6 +40,7 @@ #include "core/gimperror.h" #include "core/gimpimage.h" #include "core/gimpimage-undo-push.h" +#include "core/gimpitemstack.h" #include "core/gimppaintinfo.h" #include "core/gimpstrokeoptions.h" @@ -50,6 +51,8 @@ #include "gimppath.h" #include "gimppath-preview.h" #include "gimpstroke.h" +#include "gimpvectorlayer.h" +#include "gimpvectorlayeroptions.h" #include "gimp-intl.h" @@ -164,6 +167,10 @@ static gint gimp_path_real_interpolate (GimpPath *path, gint max_points, GimpCoords *ret_coords); +static gboolean gimp_path_attached_to_vector_layer_rec + (GimpPath *path, + GList *layers); + static GimpBezierDesc * gimp_path_make_bezier (GimpPath *path); static GimpBezierDesc * gimp_path_real_make_bezier (GimpPath *path); @@ -1200,6 +1207,84 @@ gimp_path_real_interpolate (GimpPath *path, return 0; } +gboolean +gimp_path_attached_to_vector_layer (GimpPath *path, + GimpImage *image) +{ + GList *layers; + GList *list; + + g_return_val_if_fail (GIMP_IS_PATH (path), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + layers = gimp_image_get_layer_iter (image); + + for (list = layers; list; list = g_list_next (list)) + { + if (GIMP_IS_VECTOR_LAYER (list->data)) + { + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (list->data); + + if (vector_layer->options && + vector_layer->options->path && + (path == vector_layer->options->path)) + return TRUE; + } + + if (gimp_viewable_get_children (GIMP_VIEWABLE (list->data))) + { + GimpContainer *container; + GList *iter2; + + container = gimp_viewable_get_children (GIMP_VIEWABLE (list->data)); + + iter2 = + gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (container)); + + if (gimp_path_attached_to_vector_layer_rec (path, iter2)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gimp_path_attached_to_vector_layer_rec (GimpPath *path, + GList *layers) +{ + GList *list; + + for (list = layers; list; list = g_list_next (list)) + { + if (GIMP_IS_VECTOR_LAYER (list->data)) + { + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (list->data); + + if (vector_layer->options && + vector_layer->options->path && + (path == vector_layer->options->path)) + return TRUE; + } + + if (gimp_viewable_get_children (GIMP_VIEWABLE (list->data))) + { + GimpContainer *container; + GList *iter2; + + container = gimp_viewable_get_children (GIMP_VIEWABLE (list->data)); + + iter2 = + gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (container)); + + if (gimp_path_attached_to_vector_layer_rec (path, iter2)) + return TRUE; + } + } + + return FALSE; +} + const GimpBezierDesc * gimp_path_get_bezier (GimpPath *path) { diff --git a/app/path/gimppath.h b/app/path/gimppath.h index 1f8979b6e5..e92a569ff9 100644 --- a/app/path/gimppath.h +++ b/app/path/gimppath.h @@ -175,6 +175,9 @@ gint gimp_path_interpolate (GimpPath *path, gint max_points, GimpCoords *ret_coords); +gboolean gimp_path_attached_to_vector_layer + (GimpPath *path, + GimpImage *image); /* usually overloaded */ /* returns a bezier representation */ diff --git a/app/path/gimpvectorlayer-xcf.c b/app/path/gimpvectorlayer-xcf.c new file mode 100644 index 0000000000..fadb64a37e --- /dev/null +++ b/app/path/gimpvectorlayer-xcf.c @@ -0,0 +1,172 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayer-xcf.c + * + * Copyright 2006 Hendrik Boom + * + * 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 + +#include "libgimpbase/gimpbase.h" + +#include "path-types.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimpparasitelist.h" + +#include "gimpvectorlayeroptions.h" +#include "gimpvectorlayeroptions-parasite.h" +#include "gimpvectorlayer.h" +#include "gimpvectorlayer-xcf.h" + +#include "gimp-intl.h" + + +static GimpLayer * gimp_vector_layer_from_layer (GimpLayer *layer, + GimpVectorLayerOptions *options); + + +gboolean +gimp_vector_layer_xcf_load_hack (GimpLayer **layer) +{ + const gchar *name; + GimpVectorLayerOptions *options = NULL; + const GimpParasite *parasite; + + g_return_val_if_fail (layer != NULL, FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (*layer), FALSE); + + name = gimp_vector_layer_options_parasite_name (); + parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name); + + if (parasite) + { + GError *error = NULL; + + options = gimp_vector_layer_options_from_parasite ( + parasite, &error, gimp_item_get_image (GIMP_ITEM (*layer))->gimp); + + g_object_set (G_OBJECT (options), + "path", gimp_image_get_path_by_tattoo ( + gimp_item_get_image (GIMP_ITEM (*layer)), + options->path_tattoo), + NULL); + + if (error) + { + g_message (_("Problems parsing the vector layer parasite for layer '%s':\n" + "%s\n\n" + "Some vector layer properties may be wrong. "), + gimp_object_get_name (GIMP_OBJECT (*layer)), + error->message); + + g_error_free (error); + } + } + + if (options) + { + *layer = gimp_vector_layer_from_layer (*layer, options); + + /* let the text layer know what parasite was used to create it */ + GIMP_VECTOR_LAYER (*layer)->parasite = name; + } + + return (options != NULL); +} + +void +gimp_vector_layer_xcf_save_prepare (GimpVectorLayer *layer) +{ + GimpVectorLayerOptions *options; + + g_return_if_fail (GIMP_IS_VECTOR_LAYER (layer)); + + /* If the layer has a text parasite already, it wasn't changed and we + * can simply save the original parasite back which is still attached. + */ + if (layer->parasite) + return; + + g_object_get (layer, "vector-layer-options", &options, NULL); + if (options) + { + GimpParasite *parasite = gimp_vector_layer_options_to_parasite (options); + + gimp_parasite_list_add (gimp_item_get_parasites (GIMP_ITEM (layer)), parasite); + } +} + +/** + * gimp_vector_layer_from_layer: + * @layer: a #GimpLayer object + * @options: a #GimpVectorLayerOptions object + * + * Converts a standard #GimpLayer and a #GimpVectorLayerOptions object + * into a #GimpVectorLayer. The new vector layer takes ownership of the + * @options and @layer objects. The @layer object is rendered unusable + * by this function. Don't even try to use it afterwards! + * + * This is a gross hack that is needed in order to load vector layers + * from XCF files in a backwards-compatible way. Please don't use it + * for anything else! + * + * Return value: a newly allocated #GimpVectorLayer object + **/ +static GimpLayer * +gimp_vector_layer_from_layer (GimpLayer *layer, + GimpVectorLayerOptions *options) +{ + GimpVectorLayer *vector_layer; + GimpDrawable *drawable; + + g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER_OPTIONS (options), NULL); + + vector_layer = g_object_new (GIMP_TYPE_VECTOR_LAYER, + "image", gimp_item_get_image (GIMP_ITEM (layer)), + "vector-layer-options", options, + NULL); + + gimp_item_replace_item (GIMP_ITEM (vector_layer), GIMP_ITEM (layer)); + + drawable = GIMP_DRAWABLE (vector_layer); + gimp_drawable_steal_buffer (drawable, GIMP_DRAWABLE (layer)); + + gimp_layer_set_opacity (GIMP_LAYER (vector_layer), + gimp_layer_get_opacity (layer), FALSE); + gimp_layer_set_mode (GIMP_LAYER (vector_layer), + gimp_layer_get_mode (layer), FALSE); + gimp_layer_set_blend_space (GIMP_LAYER (vector_layer), + gimp_layer_get_blend_space (layer), FALSE); + gimp_layer_set_composite_space (GIMP_LAYER (vector_layer), + gimp_layer_get_composite_space (layer), FALSE); + gimp_layer_set_composite_mode (GIMP_LAYER (vector_layer), + gimp_layer_get_composite_mode (layer), FALSE); + gimp_layer_set_lock_alpha (GIMP_LAYER (vector_layer), + gimp_layer_get_lock_alpha (layer), FALSE); + + g_object_unref (options); + g_object_unref (layer); + + return GIMP_LAYER (vector_layer); +} diff --git a/app/path/gimpvectorlayer-xcf.h b/app/path/gimpvectorlayer-xcf.h new file mode 100644 index 0000000000..5757c7baa3 --- /dev/null +++ b/app/path/gimpvectorlayer-xcf.h @@ -0,0 +1,33 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayer-xcf.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __GIMP_VECTOR_LAYER_XCF_H__ +#define __GIMP_VECTOR_LAYER_XCF_H__ + + +const gchar * gimp_vector_layer_vector_parasite_name (void) G_GNUC_CONST; +const gchar * gimp_vector_layer_fill_parasite_name (void) G_GNUC_CONST; +const gchar * gimp_vector_layer_stroke_parasite_name (void) G_GNUC_CONST; +gboolean gimp_vector_layer_xcf_load_hack (GimpLayer **layer); +void gimp_vector_layer_xcf_save_prepare (GimpVectorLayer *layer); + + +#endif /* __GIMP_VECTOR_LAYER_XCF_H__ */ diff --git a/app/path/gimpvectorlayer.c b/app/path/gimpvectorlayer.c new file mode 100644 index 0000000000..70ea8b07c5 --- /dev/null +++ b/app/path/gimpvectorlayer.c @@ -0,0 +1,801 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayer.c + * + * Copyright 2006 Hendrik Boom + * + * 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 +#include + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "path-types.h" + +#include "core/gimp.h" +#include "core/gimpdrawable-fill.h" +#include "core/gimpdrawable-stroke.h" +#include "core/gimpimage.h" +#include "core/gimpselection.h" +#include "core/gimpimage-undo.h" +#include "core/gimpimage-undo-push.h" +#include "core/gimpstrokeoptions.h" +#include "core/gimpparasitelist.h" + +#include "gimpvectorlayer.h" +#include "gimpvectorlayeroptions.h" +#include "gimppath.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_VECTOR_LAYER_OPTIONS, + PROP_MODIFIED +}; + + +/* local function declarations */ + +static void gimp_vector_layer_finalize (GObject *object); +static void gimp_vector_layer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_vector_layer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_vector_layer_set_vector_options + (GimpVectorLayer *layer, + GimpVectorLayerOptions *options); + +static void gimp_vector_layer_set_buffer (GimpDrawable *drawable, + gboolean push_undo, + const gchar *undo_desc, + GeglBuffer *buffer, + const GeglRectangle *bounds); +static void gimp_vector_layer_push_undo (GimpDrawable *drawable, + const gchar *undo_desc, + GeglBuffer *buffer, + gint x, + gint y, + gint width, + gint height); + +static gint64 gimp_vector_layer_get_memsize (GimpObject *object, + gint64 *gui_size); + +static GimpItem * gimp_vector_layer_duplicate (GimpItem *item, + GType new_type); + +static void gimp_vector_layer_translate (GimpLayer *layer, + gint offset_x, + gint offset_y); +static void gimp_vector_layer_scale (GimpItem *item, + gint new_width, + gint new_height, + gint new_offset_x, + gint new_offset_y, + GimpInterpolationType interp_type, + GimpProgress *progress); +static void gimp_vector_layer_flip (GimpItem *item, + GimpContext *context, + GimpOrientationType flip_type, + gdouble axis, + gboolean clip_result); +static void gimp_vector_layer_rotate (GimpItem *item, + GimpContext *context, + GimpRotationType rotate_type, + gdouble center_x, + gdouble center_y, + gboolean clip_result); +static void gimp_vector_layer_transform (GimpItem *item, + GimpContext *context, + const GimpMatrix3 *matrix, + GimpTransformDirection direction, + GimpInterpolationType interp_type, + GimpTransformResize clip_result, + GimpProgress *progress); + +static gboolean gimp_vector_layer_render (GimpVectorLayer *layer); +static void gimp_vector_layer_render_path (GimpVectorLayer *layer); +static void gimp_vector_layer_changed_options (GimpVectorLayer *layer); + +static void gimp_vector_layer_removed (GimpItem *item); + +static void gimp_vector_layer_removed_options_path + (GimpVectorLayer *layer); + + +G_DEFINE_TYPE (GimpVectorLayer, gimp_vector_layer, GIMP_TYPE_LAYER) + +#define parent_class gimp_vector_layer_parent_class + + +static void +gimp_vector_layer_class_init (GimpVectorLayerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + GimpItemClass *item_class = GIMP_ITEM_CLASS (klass); + GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass); + GimpLayerClass *layer_class = GIMP_LAYER_CLASS (klass); + + drawable_class->set_buffer = gimp_vector_layer_set_buffer; + drawable_class->push_undo = gimp_vector_layer_push_undo; + + object_class->finalize = gimp_vector_layer_finalize; + object_class->set_property = gimp_vector_layer_set_property; + object_class->get_property = gimp_vector_layer_get_property; + + gimp_object_class->get_memsize = gimp_vector_layer_get_memsize; + + viewable_class->default_icon_name = "gimp-vector-layer"; + viewable_class->default_name = _("Vector Layer"); + + layer_class->translate = gimp_vector_layer_translate; + + item_class->removed = gimp_vector_layer_removed; + item_class->duplicate = gimp_vector_layer_duplicate; + item_class->scale = gimp_vector_layer_scale; + item_class->flip = gimp_vector_layer_flip; + item_class->rotate = gimp_vector_layer_rotate; + item_class->transform = gimp_vector_layer_transform; + item_class->rename_desc = _("Rename Vector Layer"); + item_class->translate_desc = _("Move Vector Layer"); + item_class->scale_desc = _("Scale Vector Layer"); + item_class->resize_desc = _("Resize Vector Layer"); + item_class->flip_desc = _("Flip Vector Layer"); + item_class->rotate_desc = _("Rotate Vector Layer"); + item_class->transform_desc = _("Transform Vector Layer"); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_VECTOR_LAYER_OPTIONS, + "vector-layer-options", NULL, NULL, + GIMP_TYPE_VECTOR_LAYER_OPTIONS, + G_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_MODIFIED, + "modified", + NULL, NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_vector_layer_init (GimpVectorLayer *layer) +{ + layer->options = NULL; + layer->parasite = NULL; + layer->modified = FALSE; +} + +static void +gimp_vector_layer_finalize (GObject *object) +{ + GimpVectorLayer *layer = GIMP_VECTOR_LAYER (object); + + if (layer->options) + { + g_object_unref (layer->options); + layer->options = NULL; + } + + if (layer->parasite) + { + gimp_parasite_list_remove (gimp_item_get_parasites (GIMP_ITEM (layer)), + layer->parasite); + layer->parasite = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_vector_layer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (object); + + switch (property_id) + { + case PROP_VECTOR_LAYER_OPTIONS: + g_value_set_object (value, vector_layer->options); + break; + case PROP_MODIFIED: + g_value_set_boolean (value, vector_layer->modified); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_vector_layer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (object); + + switch (property_id) + { + case PROP_VECTOR_LAYER_OPTIONS: + if (vector_layer->options) + { + g_signal_handlers_disconnect_by_func (vector_layer->options, + G_CALLBACK (gimp_vector_layer_changed_options), + vector_layer); + if (vector_layer->options->path) + g_signal_handlers_disconnect_by_func (vector_layer->options->path, + G_CALLBACK (gimp_vector_layer_removed_options_path), + vector_layer); + + g_object_unref (vector_layer->options); + } + + vector_layer->options = g_value_dup_object (value); + + if (vector_layer->options) + { + if (vector_layer->options->path) + g_signal_connect_object (vector_layer->options->path, "removed", + G_CALLBACK (gimp_vector_layer_removed_options_path), + vector_layer, G_CONNECT_SWAPPED); + + g_signal_connect_object (vector_layer->options, "notify", + G_CALLBACK (gimp_vector_layer_changed_options), + vector_layer, G_CONNECT_SWAPPED); + + } + break; + case PROP_MODIFIED: + vector_layer->modified = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_vector_layer_set_vector_options (GimpVectorLayer *layer, + GimpVectorLayerOptions *options) +{ + if (layer->options) + { + g_signal_handlers_disconnect_by_func (layer->options, + G_CALLBACK (gimp_vector_layer_changed_options), + layer); + g_object_unref (layer->options); + } + + layer->options = options; + gimp_vector_layer_changed_options (layer); + + if (layer->options) + g_signal_connect_object (layer->options, "notify", + G_CALLBACK (gimp_vector_layer_changed_options), + layer, G_CONNECT_SWAPPED); +} + +static void +gimp_vector_layer_set_buffer (GimpDrawable *drawable, + gboolean push_undo, + const gchar *undo_desc, + GeglBuffer *buffer, + const GeglRectangle *bounds) +{ + GimpVectorLayer *layer = GIMP_VECTOR_LAYER (drawable); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + + if (push_undo && ! layer->modified) + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD, + undo_desc); + + GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable, + push_undo, undo_desc, + buffer, bounds); + + if (push_undo && ! layer->modified) + { + gimp_image_undo_push_vector_layer_modified (image, NULL, layer); + + g_object_set (drawable, "modified", TRUE, NULL); + + gimp_image_undo_group_end (image); + } +} + +static void +gimp_vector_layer_push_undo (GimpDrawable *drawable, + const gchar *undo_desc, + GeglBuffer *buffer, + gint x, + gint y, + gint width, + gint height) +{ + GimpVectorLayer *layer = GIMP_VECTOR_LAYER (drawable); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + + if (! layer->modified) + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE, undo_desc); + + GIMP_DRAWABLE_CLASS (parent_class)->push_undo (drawable, undo_desc, + buffer, + x, y, width, height); + + if (! layer->modified) + { + gimp_image_undo_push_vector_layer_modified (image, NULL, layer); + + g_object_set (drawable, "modified", TRUE, NULL); + + gimp_image_undo_group_end (image); + } +} + +static gint64 +gimp_vector_layer_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (object); + gint64 memsize = 0; + + memsize += gimp_object_get_memsize (GIMP_OBJECT (vector_layer->options), + gui_size); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static GimpItem * +gimp_vector_layer_duplicate (GimpItem *item, + GType new_type) +{ + GimpItem *new_item; + + g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL); + + new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type); + + if (GIMP_IS_VECTOR_LAYER (new_item)) + { + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + GimpVectorLayer *new_vector_layer = GIMP_VECTOR_LAYER (new_item); + + if (vector_layer->options) + { + GimpVectorLayerOptions *new_options = + gimp_config_duplicate (GIMP_CONFIG (vector_layer->options)); + + if (vector_layer->options->path) + { + GimpPath *path = gimp_vector_layer_get_path (vector_layer); + GimpPath *new_path; + + new_path = GIMP_PATH (gimp_item_duplicate (GIMP_ITEM (path), + G_TYPE_FROM_INSTANCE (GIMP_ITEM (path)))); + + g_object_set (new_options, "path", new_path, NULL); + } + + g_object_set (new_vector_layer, + "vector-layer-options", new_options, + NULL); + g_object_unref (new_options); + } + } + + return new_item; +} + +static void +gimp_vector_layer_translate (GimpLayer *layer, + gint offset_x, + gint offset_y) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (layer); + + if (vector_layer->options && vector_layer->options->path) + { + gimp_item_translate (GIMP_ITEM (vector_layer->options->path), + offset_x, offset_y, FALSE); + } + else + { + GIMP_LAYER_CLASS (parent_class)->translate (layer, offset_x, offset_y); + } +} + +static void +gimp_vector_layer_scale (GimpItem *item, + gint new_width, + gint new_height, + gint new_offset_x, + gint new_offset_y, + GimpInterpolationType interp_type, + GimpProgress *progress) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + + if (vector_layer->options && vector_layer->options->path) + { + gimp_item_scale (GIMP_ITEM (vector_layer->options->path), + new_width, new_height, new_offset_x, new_offset_y, + interp_type, progress); + } + else + { + GIMP_ITEM_CLASS (parent_class)->scale (item, new_width, new_height, + new_offset_x, new_offset_y, + interp_type, progress); + } +} + +static void +gimp_vector_layer_flip (GimpItem *item, + GimpContext *context, + GimpOrientationType flip_type, + gdouble axis, + gboolean clip_result) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + + if (vector_layer->options && vector_layer->options->path) + { + gimp_item_flip (GIMP_ITEM (vector_layer->options->path), + context, flip_type, axis, clip_result); + } + else + { + GIMP_ITEM_CLASS (parent_class)->flip (item, context, flip_type, + axis, clip_result); + } +} + +static void +gimp_vector_layer_rotate (GimpItem *item, + GimpContext *context, + GimpRotationType rotate_type, + gdouble center_x, + gdouble center_y, + gboolean clip_result) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + + if (vector_layer->options && vector_layer->options->path) + { + gimp_item_rotate (GIMP_ITEM (vector_layer->options->path), + context, rotate_type, center_x, center_y, clip_result); + } + else + { + GIMP_ITEM_CLASS (parent_class)->rotate (item, context, rotate_type, + center_x, center_y, clip_result); + } +} + +static void +gimp_vector_layer_transform (GimpItem *item, + GimpContext *context, + const GimpMatrix3 *matrix, + GimpTransformDirection direction, + GimpInterpolationType interp_type, + GimpTransformResize clip_result, + GimpProgress *progress) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + + if (vector_layer->options && vector_layer->options->path) + { + gimp_item_transform (GIMP_ITEM (vector_layer->options->path), + context, matrix, direction, interp_type, + clip_result, progress); + } + else + { + GIMP_ITEM_CLASS (parent_class)->transform (item, context, matrix, + direction, interp_type, + clip_result, progress); + } +} + +static void +gimp_vector_layer_removed_options_path (GimpVectorLayer *layer) +{ + if (layer->options) + { + gimp_image_undo_push_vector_layer (gimp_item_get_image (GIMP_ITEM (layer)), + _("Discard Vector Informations"), + layer, NULL); + + g_object_set (layer->options, "path", NULL, NULL); + } +} + +static void +gimp_vector_layer_removed (GimpItem *item) +{ + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (item); + + if (vector_layer->options && vector_layer->options->path) + g_signal_handlers_disconnect_by_func (vector_layer->options->path, + G_CALLBACK (gimp_vector_layer_removed_options_path), + vector_layer); + + GIMP_ITEM_CLASS (parent_class)->removed (item); +} + + +/* public functions */ + +/** + * gimp_vector_layer_new: + * @image: the #GimpImage the layer should belong to + * @path: the #GimpPath object the layer should render + * @context: the #GimpContext from which to pull context properties + * + * Creates a new vector layer. + * + * Return value: a new #GimpVectorLayer or %NULL in case of a problem + **/ +GimpVectorLayer * +gimp_vector_layer_new (GimpImage *image, + GimpPath *path, + GimpContext *context) +{ + GimpVectorLayer *layer; + GimpVectorLayerOptions *options; + 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_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_PATH (path), NULL); + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + + options = gimp_vector_layer_options_new (image, path, context); + + gimp_item_bounds (GIMP_ITEM (path), &x, &y, &width, &height); + + /* Set boundaries to image size if it's a blank path */ + if (width == 0 || height == 0) + { + width = gimp_image_get_width (image); + height = gimp_image_get_height (image); + } + + layer = + GIMP_VECTOR_LAYER (gimp_drawable_new (GIMP_TYPE_VECTOR_LAYER, + image, NULL, + x, y, width, height, + gimp_image_get_layer_format (image, + TRUE))); + + gimp_object_set_name (GIMP_OBJECT (layer), + gimp_object_get_name (GIMP_OBJECT (path))); + + gimp_layer_set_mode (GIMP_LAYER (layer), + gimp_image_get_default_new_layer_mode (image), + FALSE); + + gimp_vector_layer_set_vector_options (layer, options); + + return layer; +} + +/** + * gimp_vector_layer_get_path: + * @layer: a #GimpVectorLayer + * + * Gets the path from @layer if one is associated with it. + * + * Return value: a #GimpPath or %NULL if no path is set. + */ +GimpPath * +gimp_vector_layer_get_path (GimpVectorLayer *layer) +{ + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER (layer), NULL); + + if (gimp_item_is_vector_layer (GIMP_ITEM (layer))) + return layer->options->path; + + return NULL; +} + +void +gimp_vector_layer_refresh (GimpVectorLayer *layer) +{ + if (layer->options) + gimp_vector_layer_render (layer); +} + +/** + * gimp_vector_layer_discard: + * @layer: a #GimpVectorLayer + * + * Discards the vector information. This makes @layer behave like a + * normal layer. + */ +void +gimp_vector_layer_discard (GimpVectorLayer *layer) +{ + g_return_if_fail (GIMP_IS_VECTOR_LAYER (layer)); + g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); + + if (! layer->options) + return; + + if (layer->options->path) + gimp_image_undo_push_vector_layer (gimp_item_get_image (GIMP_ITEM (layer)), + _("Discard Vector Information"), + layer, NULL); + + g_object_set (layer, "vector-layer-options", NULL, NULL); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); +} + +gboolean +gimp_item_is_vector_layer (GimpItem *item) +{ + return (GIMP_IS_VECTOR_LAYER (item) && + GIMP_VECTOR_LAYER (item)->options); +} + + +/* private functions */ + +static gboolean +gimp_vector_layer_render (GimpVectorLayer *layer) +{ + GimpDrawable *drawable = GIMP_DRAWABLE (layer); + GeglBuffer *buffer = NULL; + GimpItem *item = GIMP_ITEM (layer); + GimpImage *image = gimp_item_get_image (item); + gint layer_x = 0; + gint layer_y = 0; + gint x = 0; + gint y = 0; + gint width = gimp_image_get_width (image); + gint height = gimp_image_get_height (image); + gdouble stroke = 0; + + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); + + g_object_freeze_notify (G_OBJECT (drawable)); + + if (layer->options->enable_stroke) + stroke = gimp_stroke_options_get_width (layer->options->stroke_options); + + /* Resize layer according to path size */ + gimp_item_get_offset (GIMP_ITEM (layer), &layer_x, &layer_y); + gimp_item_bounds (GIMP_ITEM (layer->options->path), &x, &y, &width, &height); + + buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, + width + stroke, height + stroke), + gimp_drawable_get_format (drawable)); + gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer); + g_object_unref (buffer); + + gimp_item_set_offset (GIMP_ITEM (layer), x - (stroke / 2), y - (stroke / 2)); + + /* make the layer background transparent */ + gimp_drawable_fill (GIMP_DRAWABLE (layer), + gimp_get_user_context (image->gimp), + GIMP_FILL_TRANSPARENT); + + /* render path to the layer */ + gimp_vector_layer_render_path (layer); + + g_object_thaw_notify (G_OBJECT (drawable)); + + return TRUE; +} + +static void +gimp_vector_layer_render_path (GimpVectorLayer *layer) +{ + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + GimpVectorLayerOptions *options = layer->options; + GimpPath *path = NULL; + GimpChannel *selection = gimp_image_get_mask (image); + GList *drawables; + GimpCustomStyle style; + + if (options) + path = options->path; + + /* Don't mask these fill/stroke operations */ + gimp_selection_suspend (GIMP_SELECTION (selection)); + + /* Convert from custom to standard styles */ + style = gimp_fill_options_get_custom_style (options->fill_options); + if (style == GIMP_CUSTOM_STYLE_SOLID_COLOR || + ! gimp_context_get_pattern (GIMP_CONTEXT (options->fill_options))) + gimp_fill_options_set_style (options->fill_options, + GIMP_FILL_STYLE_FG_COLOR); + else + gimp_fill_options_set_style (options->fill_options, + GIMP_FILL_STYLE_PATTERN); + + style = + gimp_fill_options_get_custom_style (GIMP_FILL_OPTIONS (options->stroke_options)); + if (style == GIMP_CUSTOM_STYLE_SOLID_COLOR || + ! gimp_context_get_pattern (GIMP_CONTEXT (options->stroke_options))) + gimp_fill_options_set_style (GIMP_FILL_OPTIONS (options->stroke_options), + GIMP_FILL_STYLE_FG_COLOR); + else + gimp_fill_options_set_style (GIMP_FILL_OPTIONS (options->stroke_options), + GIMP_FILL_STYLE_PATTERN); + + /* Fill the path object onto the layer */ + if (options->enable_fill) + gimp_drawable_fill_path (GIMP_DRAWABLE (layer), + options->fill_options, + path, FALSE, NULL); + + drawables = g_list_prepend (NULL, GIMP_DRAWABLE (layer)); + /* stroke the path object onto the layer */ + if (options->enable_stroke && gimp_item_is_attached (GIMP_ITEM (path))) + gimp_item_stroke (GIMP_ITEM (path), drawables, + gimp_get_user_context (image->gimp), + options->stroke_options, + FALSE, FALSE, + NULL, NULL); + + g_list_free (drawables); + + gimp_selection_resume (GIMP_SELECTION (selection)); +} + +static void +gimp_vector_layer_changed_options (GimpVectorLayer *layer) +{ + GimpItem *item = GIMP_ITEM (layer); + + if (layer->parasite) + { + /* parasite is out of date, discard it */ + gimp_parasite_list_remove (gimp_item_get_parasites (GIMP_ITEM (layer)), + layer->parasite); + layer->parasite = NULL; + } + + if (layer->options && !layer->options->path) + gimp_vector_layer_discard (layer); + else if (gimp_item_is_attached (item)) + gimp_vector_layer_refresh (layer); +} diff --git a/app/path/gimpvectorlayer.h b/app/path/gimpvectorlayer.h new file mode 100644 index 0000000000..ebca98d963 --- /dev/null +++ b/app/path/gimpvectorlayer.h @@ -0,0 +1,69 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayer.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __GIMP_VECTOR_LAYER_H__ +#define __GIMP_VECTOR_LAYER_H__ + + +#include "core/gimplayer.h" + + +#define GIMP_TYPE_VECTOR_LAYER (gimp_vector_layer_get_type ()) +#define GIMP_VECTOR_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTOR_LAYER, GimpVectorLayer)) +#define GIMP_VECTOR_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VECTOR_LAYER, GimpVectorLayerClass)) +#define GIMP_IS_VECTOR_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VECTOR_LAYER)) +#define GIMP_IS_VECTOR_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_VECTOR_LAYER)) +#define GIMP_VECTOR_LAYER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_VECTOR_LAYER, GimpVectorLayerClass)) + + +typedef struct _GimpVectorLayerClass GimpVectorLayerClass; + +struct _GimpVectorLayer +{ + GimpLayer parent_instance; + + GimpVectorLayerOptions *options; + const gchar *parasite; + + gboolean modified; +}; + +struct _GimpVectorLayerClass +{ + GimpLayerClass parent_class; +}; + + +GType gimp_vector_layer_get_type (void) G_GNUC_CONST; + +GimpVectorLayer * gimp_vector_layer_new (GimpImage *image, + GimpPath *path, + GimpContext *context); + +GimpPath * gimp_vector_layer_get_path (GimpVectorLayer *layer); + +void gimp_vector_layer_refresh (GimpVectorLayer *layer); +void gimp_vector_layer_discard (GimpVectorLayer *layer); + +gboolean gimp_item_is_vector_layer (GimpItem *item); + + +#endif /* __GIMP_VECTOR_LAYER_H__ */ diff --git a/app/path/gimpvectorlayeroptions-parasite.c b/app/path/gimpvectorlayeroptions-parasite.c new file mode 100644 index 0000000000..488174909b --- /dev/null +++ b/app/path/gimpvectorlayeroptions-parasite.c @@ -0,0 +1,95 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayeroptions-parasite.c + * + * Copyright 2006 Hendrik Boom + * + * 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 +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "path-types.h" + +#include "gimpvectorlayeroptions.h" +#include "gimpvectorlayeroptions-parasite.h" + +#include "gimp-intl.h" + + +const gchar * +gimp_vector_layer_options_parasite_name (void) +{ + return "gimp-vector-layer-options"; +} + +GimpParasite * +gimp_vector_layer_options_to_parasite (GimpVectorLayerOptions *options) +{ + GimpParasite *parasite; + gchar *str; + + g_return_val_if_fail (GIMP_IS_VECTOR_LAYER_OPTIONS (options), NULL); + + str = gimp_config_serialize_to_string (GIMP_CONFIG (options), NULL); + g_return_val_if_fail (str != NULL, NULL); + + parasite = gimp_parasite_new (gimp_vector_layer_options_parasite_name (), + GIMP_PARASITE_PERSISTENT, + strlen (str) + 1, str); + g_free (str); + + return parasite; +} + +GimpVectorLayerOptions * +gimp_vector_layer_options_from_parasite (const GimpParasite *parasite, + GError **error, + Gimp *gimp) +{ + GimpVectorLayerOptions *options; + const gchar *str; + guint32 parasite_length; + + g_return_val_if_fail (parasite != NULL, NULL); + g_return_val_if_fail (strcmp (gimp_parasite_get_name (parasite), + gimp_vector_layer_options_parasite_name ()) == 0, + NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + str = gimp_parasite_get_data (parasite, ¶site_length); + g_return_val_if_fail (str != NULL, NULL); + + options = g_object_new (GIMP_TYPE_VECTOR_LAYER_OPTIONS, + "gimp", gimp, + NULL); + + gimp_config_deserialize_string (GIMP_CONFIG (options), + str, + parasite_length, + NULL, + error); + + return options; +} diff --git a/app/path/gimpvectorlayeroptions-parasite.h b/app/path/gimpvectorlayeroptions-parasite.h new file mode 100644 index 0000000000..7765cb6c67 --- /dev/null +++ b/app/path/gimpvectorlayeroptions-parasite.h @@ -0,0 +1,33 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayeroptions-parasite.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __GIMP_VECTOR_LAYER_OPTIONS_PARASITE_H__ +#define __GIMP_VECTOR_LAYER_OPTIONS_PARASITE_H__ + + +const gchar * gimp_vector_layer_options_parasite_name (void) G_GNUC_CONST; +GimpParasite * gimp_vector_layer_options_to_parasite (GimpVectorLayerOptions *text); +GimpVectorLayerOptions * gimp_vector_layer_options_from_parasite (const GimpParasite *parasite, + GError **error, + Gimp *gimp); + + +#endif /* __GIMP_VECTOR_LAYER_OPTIONS_PARASITE_H__ */ diff --git a/app/path/gimpvectorlayeroptions.c b/app/path/gimpvectorlayeroptions.c new file mode 100644 index 0000000000..eda0f68ab5 --- /dev/null +++ b/app/path/gimpvectorlayeroptions.c @@ -0,0 +1,364 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayers.c + * + * Copyright 2006 Hendrik Boom + * + * 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 + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" +#include "libgimpcolor/gimpcolor.h" + +#include "path-types.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimpstrokeoptions.h" + +#include "gimppath.h" +#include "gimpvectorlayer.h" +#include "gimpvectorlayeroptions.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_GIMP, + PROP_PATH, + PROP_PATH_TATTOO, + PROP_ENABLE_FILL, + PROP_FILL_OPTIONS, + PROP_ENABLE_STROKE, + PROP_STROKE_OPTIONS +}; + + +/* local function declarations */ + +static GObject *gimp_vector_layer_options_constructor (GType type, + guint n_params, + GObjectConstructParam *params); +static void gimp_vector_layer_options_finalize (GObject *object); + +static void gimp_vector_layer_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_vector_layer_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_vector_layer_options_path_changed (GimpVectorLayerOptions *options); + + +G_DEFINE_TYPE_WITH_CODE (GimpVectorLayerOptions, + gimp_vector_layer_options, + GIMP_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, NULL)) + +#define parent_class gimp_vector_layer_options_parent_class + + +static void +gimp_vector_layer_options_class_init (GimpVectorLayerOptionsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = gimp_vector_layer_options_constructor; + object_class->finalize = gimp_vector_layer_options_finalize; + object_class->set_property = gimp_vector_layer_options_set_property; + object_class->get_property = gimp_vector_layer_options_get_property; + + g_object_class_install_property (object_class, PROP_GIMP, + g_param_spec_object ("gimp", + NULL, NULL, + GIMP_TYPE_GIMP, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_PATH, + "path", NULL, NULL, + GIMP_TYPE_PATH, + GIMP_PARAM_READWRITE | + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_UINT (object_class, PROP_PATH_TATTOO, + "path-tattoo", NULL, NULL, + 0, G_MAXUINT32, 0, + G_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ENABLE_FILL, + "enable-fill", + _("Fill Style"), NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FILL_OPTIONS, + "fill-options", NULL, NULL, + GIMP_TYPE_FILL_OPTIONS, + G_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_AGGREGATE); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ENABLE_STROKE, + "enable-stroke", + _("Stroke Style"), NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_STROKE_OPTIONS, + "stroke-options", NULL, NULL, + GIMP_TYPE_STROKE_OPTIONS, + G_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_AGGREGATE); +} + +static void +gimp_vector_layer_options_init (GimpVectorLayerOptions *options) +{ + options->path = NULL; + options->path_tattoo = 0; +} + +static GObject * +gimp_vector_layer_options_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GObject *object; + GimpVectorLayerOptions *options; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); + + options = GIMP_VECTOR_LAYER_OPTIONS (object); + g_assert (GIMP_IS_GIMP (options->gimp)); + + options->fill_options = gimp_fill_options_new (options->gimp, NULL, FALSE); + options->stroke_options = gimp_stroke_options_new (options->gimp, NULL, FALSE); + + return object; +} + +static void +gimp_vector_layer_options_finalize (GObject *object) +{ + GimpVectorLayerOptions *options = GIMP_VECTOR_LAYER_OPTIONS (object); + + if (options->path) + { + g_object_unref (options->path); + options->path = NULL; + } + + if (options->fill_options) + { + g_object_unref (options->fill_options); + options->fill_options = NULL; + } + + if (options->stroke_options) + { + g_object_unref (options->stroke_options); + options->stroke_options = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_vector_layer_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayerOptions *options = GIMP_VECTOR_LAYER_OPTIONS (object); + + switch (property_id) + { + case PROP_GIMP: + g_value_set_object (value, options->gimp); + break; + case PROP_PATH: + g_value_set_object (value, options->path); + break; + case PROP_PATH_TATTOO: + g_value_set_uint (value, options->path_tattoo); + break; + case PROP_ENABLE_FILL: + g_value_set_boolean (value, options->enable_fill); + break; + case PROP_FILL_OPTIONS: + g_value_set_object (value, options->fill_options); + break; + case PROP_ENABLE_STROKE: + g_value_set_boolean (value, options->enable_stroke); + break; + case PROP_STROKE_OPTIONS: + g_value_set_object (value, options->stroke_options); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_vector_layer_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayerOptions *options = GIMP_VECTOR_LAYER_OPTIONS (object); + + switch (property_id) + { + case PROP_GIMP: + options->gimp = g_value_get_object (value); + break; + + case PROP_PATH: + if (options->path) + { + g_signal_handlers_disconnect_by_func (options->path, + G_CALLBACK (gimp_vector_layer_options_path_changed), + options); + g_object_unref (options->path); + } + + options->path = g_value_dup_object (value); + + if (options->path) + { + g_signal_connect_object (options->path, "invalidate-preview", + G_CALLBACK (gimp_vector_layer_options_path_changed), + options, G_CONNECT_SWAPPED); + g_signal_connect_object (options->path, "name-changed", + G_CALLBACK (gimp_vector_layer_options_path_changed), + options, G_CONNECT_SWAPPED); + + /* update the tattoo */ + options->path_tattoo = gimp_item_get_tattoo (GIMP_ITEM (options->path)); + } + break; + + case PROP_PATH_TATTOO: + options->path_tattoo = g_value_get_uint (value); + + if (options->path && + gimp_item_get_tattoo (GIMP_ITEM (options->path)) != options->path_tattoo) + { + GimpImage *image = gimp_item_get_image (GIMP_ITEM (options->path)); + + g_object_set (options, + "path", gimp_image_get_path_by_tattoo + (image, options->path_tattoo), + NULL); + } + break; + + case PROP_ENABLE_FILL: + options->enable_fill = g_value_get_boolean (value); + break; + + case PROP_FILL_OPTIONS: + if (g_value_get_object (value)) + gimp_config_sync (g_value_get_object (value), + G_OBJECT (options->fill_options), 0); + break; + + case PROP_ENABLE_STROKE: + options->enable_stroke = g_value_get_boolean (value); + break; + + case PROP_STROKE_OPTIONS: + if (g_value_get_object (value)) + { + if (options->stroke_options) + g_object_unref (options->stroke_options); + options->stroke_options = gimp_config_duplicate (g_value_get_object (value)); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_vector_layer_options_path_changed (GimpVectorLayerOptions *options) +{ + g_object_notify (G_OBJECT (options), "path"); +} + + +/* public functions */ + +/** + * gimp_vector_layer_options_new: + * @image: the #GimpImage the layer belongs to + * @path: the #GimpPath object for the layer to render + * @context: the #GimpContext from which to pull context properties + * + * Creates a new vector layer options. + * + * Return value: a new #GimpVectorLayerOptions or %NULL in case of a problem + **/ +GimpVectorLayerOptions * +gimp_vector_layer_options_new (GimpImage *image, + GimpPath *path, + GimpContext *context) +{ + GimpVectorLayerOptions *options; + GimpPattern *pattern; + GeglColor *stroke_color; + GeglColor *fill_color; + + 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 (GIMP_IS_CONTEXT (context), NULL); + + options = g_object_new (GIMP_TYPE_VECTOR_LAYER_OPTIONS, + "gimp", image->gimp, + NULL); + + stroke_color = gimp_context_get_foreground (context); + fill_color = gimp_context_get_background (context); + pattern = gimp_context_get_pattern (context); + + gimp_context_set_foreground (GIMP_CONTEXT (options->fill_options), + fill_color); + gimp_context_set_pattern (GIMP_CONTEXT (options->fill_options), pattern); + + gimp_context_set_foreground (GIMP_CONTEXT (options->stroke_options), + stroke_color); + gimp_context_set_pattern (GIMP_CONTEXT (options->stroke_options), pattern); + + g_object_set (options, + "path", path, + NULL); + + return options; +} diff --git a/app/path/gimpvectorlayeroptions.h b/app/path/gimpvectorlayeroptions.h new file mode 100644 index 0000000000..97a90515a4 --- /dev/null +++ b/app/path/gimpvectorlayeroptions.h @@ -0,0 +1,66 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayeroptions.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __GIMP_VECTOR_LAYER_OPTIONS_H__ +#define __GIMP_VECTOR_LAYER_OPTIONS_H__ + + +#include "core/gimpobject.h" + + +#define GIMP_TYPE_VECTOR_LAYER_OPTIONS (gimp_vector_layer_options_get_type ()) +#define GIMP_VECTOR_LAYER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTOR_LAYER_OPTIONS, GimpVectorLayerOptions)) +#define GIMP_VECTOR_LAYER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VECTOR_LAYER_OPTIONS, GimpVectorLayerOptionsClass)) +#define GIMP_IS_VECTOR_LAYER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VECTOR_LAYER_OPTIONS)) +#define GIMP_IS_VECTOR_LAYER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_VECTOR_LAYER_OPTIONS)) +#define GIMP_VECTOR_LAYER_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_VECTOR_LAYER_OPTIONS, GimpVectorLayerOptionsClass)) + + +typedef struct _GimpVectorLayerOptionsClass GimpVectorLayerOptionsClass; + +struct _GimpVectorLayerOptions +{ + GimpObject parent_instance; + + Gimp *gimp; + + GimpTattoo path_tattoo; + GimpPath *path; + + gboolean enable_fill; + gboolean enable_stroke; + GimpFillOptions *fill_options; + GimpStrokeOptions *stroke_options; +}; + +struct _GimpVectorLayerOptionsClass +{ + GimpObjectClass parent_class; +}; + +GType gimp_vector_layer_options_get_type (void) G_GNUC_CONST; + +GimpVectorLayerOptions * gimp_vector_layer_options_new (GimpImage *image, + GimpPath *path, + GimpContext *context); + + +#endif /* __GIMP_VECTOR_LAYER_OPTIONS_H__ */ diff --git a/app/path/gimpvectorlayerundo.c b/app/path/gimpvectorlayerundo.c new file mode 100644 index 0000000000..c002d9aed0 --- /dev/null +++ b/app/path/gimpvectorlayerundo.c @@ -0,0 +1,288 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayerundo.h + * + * Copyright 2006 Hendrik Boom + * + * 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 + +#include "libgimpconfig/gimpconfig.h" + +#include "path-types.h" + +#include "core/gimp-memsize.h" +#include "core/gimpitem.h" +#include "core/gimpitemundo.h" +#include "core/gimp-utils.h" + +#include "gimpvectorlayer.h" +#include "gimpvectorlayeroptions.h" +#include "gimpvectorlayerundo.h" + +enum +{ + PROP_0, + PROP_PARAM +}; + + +static void gimp_vector_layer_undo_constructed (GObject *object); +static void gimp_vector_layer_undo_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_vector_layer_undo_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static gint64 gimp_vector_layer_undo_get_memsize (GimpObject *object, + gint64 *gui_size); +static void gimp_vector_layer_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_vector_layer_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + + + +G_DEFINE_TYPE (GimpVectorLayerUndo, gimp_vector_layer_undo, GIMP_TYPE_ITEM_UNDO) + +#define parent_class gimp_vector_layer_undo_parent_class + + +static void +gimp_vector_layer_undo_class_init (GimpVectorLayerUndoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); + + object_class->constructed = gimp_vector_layer_undo_constructed; + object_class->set_property = gimp_vector_layer_undo_set_property; + object_class->get_property = gimp_vector_layer_undo_get_property; + + gimp_object_class->get_memsize = gimp_vector_layer_undo_get_memsize; + + undo_class->pop = gimp_vector_layer_undo_pop; + undo_class->free = gimp_vector_layer_undo_free; + + g_object_class_install_property (object_class, PROP_PARAM, + g_param_spec_param ("param", NULL, NULL, + G_TYPE_PARAM, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gimp_vector_layer_undo_init (GimpVectorLayerUndo *undo) +{ +} + +static void +gimp_vector_layer_undo_constructed (GObject *object) +{ + GimpVectorLayerUndo *vector_undo = GIMP_VECTOR_LAYER_UNDO (object); + GimpVectorLayer *vector_layer; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + g_assert (GIMP_IS_VECTOR_LAYER (GIMP_ITEM_UNDO (vector_undo)->item)); + + vector_layer = GIMP_VECTOR_LAYER (GIMP_ITEM_UNDO (vector_undo)->item); + + switch (GIMP_UNDO (object)->undo_type) + { + case GIMP_UNDO_VECTOR_LAYER: + if (vector_undo->pspec) + { + g_assert (vector_undo->pspec->owner_type == GIMP_TYPE_VECTOR_LAYER_OPTIONS); + + vector_undo->value = g_slice_new0 (GValue); + + g_value_init (vector_undo->value, vector_undo->pspec->value_type); + g_object_get_property (G_OBJECT (vector_layer->options), + vector_undo->pspec->name, vector_undo->value); + } + else if (vector_layer->options) + { + vector_undo->vector_layer_options = gimp_config_duplicate (GIMP_CONFIG (vector_layer->options)); + } + break; + + case GIMP_UNDO_VECTOR_LAYER_MODIFIED: + vector_undo->modified = vector_layer->modified; + break; + + default: + g_assert_not_reached (); + } +} + +static void +gimp_vector_layer_undo_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayerUndo *vector_undo = GIMP_VECTOR_LAYER_UNDO (object); + + switch (property_id) + { + case PROP_PARAM: + vector_undo->pspec = g_value_get_param (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_vector_layer_undo_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpVectorLayerUndo *vector_undo = GIMP_VECTOR_LAYER_UNDO (object); + + switch (property_id) + { + case PROP_PARAM: + g_value_set_param (value, (GParamSpec *) vector_undo->pspec); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint64 +gimp_vector_layer_undo_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpVectorLayerUndo *undo = GIMP_VECTOR_LAYER_UNDO (object); + gint64 memsize = 0; + + memsize += gimp_g_value_get_memsize (undo->value); + memsize += gimp_object_get_memsize (GIMP_OBJECT (undo->vector_layer_options), NULL); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static void +gimp_vector_layer_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GimpVectorLayerUndo *vector_undo = GIMP_VECTOR_LAYER_UNDO (undo); + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (GIMP_ITEM_UNDO (undo)->item); + + GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); + + switch (undo->undo_type) + { + case GIMP_UNDO_VECTOR_LAYER: + if (vector_undo->pspec) + { + GValue *value; + + g_return_if_fail (vector_layer->options != NULL); + + value = g_slice_new0 (GValue); + g_value_init (value, vector_undo->pspec->value_type); + + g_object_get_property (G_OBJECT (vector_layer->options), + vector_undo->pspec->name, value); + + g_object_set_property (G_OBJECT (vector_layer->options), + vector_undo->pspec->name, vector_undo->value); + + g_value_unset (vector_undo->value); + g_slice_free (GValue, vector_undo->value); + + vector_undo->value = value; + } + else + { + GimpVectorLayerOptions *vector_layer_options; + + vector_layer_options = (vector_layer->options ? + gimp_config_duplicate (GIMP_CONFIG (vector_layer->options)) : NULL); + + if (vector_layer->options && vector_undo->vector_layer_options) + gimp_config_sync (G_OBJECT (vector_undo->vector_layer_options), + G_OBJECT (vector_layer->options), 0); + else + g_object_set (vector_layer, + "vector-layer-options", vector_undo->vector_layer_options, + NULL); + + if (vector_undo->vector_layer_options) + g_object_unref (vector_undo->vector_layer_options); + + vector_undo->vector_layer_options = vector_layer_options; + } + break; + + case GIMP_UNDO_VECTOR_LAYER_MODIFIED: + { + gboolean modified; + + modified = vector_layer->modified; + g_object_set (vector_layer, "modified", vector_undo->modified, NULL); + vector_undo->modified = modified; + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (vector_layer)); + } + break; + + default: + g_assert_not_reached (); + } +} + +static void +gimp_vector_layer_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GimpVectorLayerUndo *vector_undo = GIMP_VECTOR_LAYER_UNDO (undo); + + if (vector_undo->vector_layer_options) + { + g_object_unref (vector_undo->vector_layer_options); + vector_undo->vector_layer_options = NULL; + } + + if (vector_undo->pspec) + { + g_value_unset (vector_undo->value); + g_slice_free (GValue, vector_undo->value); + + vector_undo->value = NULL; + vector_undo->pspec = NULL; + } + + GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); +} diff --git a/app/path/gimpvectorlayerundo.h b/app/path/gimpvectorlayerundo.h new file mode 100644 index 0000000000..37894a3b92 --- /dev/null +++ b/app/path/gimpvectorlayerundo.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpvectorlayerundo.h + * + * Copyright 2006 Hendrik Boom + * + * 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 . + */ + +#ifndef __GIMP_VECTOR_LAYER_UNDO_H__ +#define __GIMP_VECTOR_LAYER_UNDO_H__ + + +#include "core/gimpitemundo.h" + + +#define GIMP_TYPE_VECTOR_LAYER_UNDO (gimp_vector_layer_undo_get_type ()) +#define GIMP_VECTOR_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTOR_LAYER_UNDO, GimpVectorLayerUndo)) +#define GIMP_VECTOR_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VECTOR_LAYER_UNDO, GimpVectorLayerUndoClass)) +#define GIMP_IS_VECTOR_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VECTOR_LAYER_UNDO)) +#define GIMP_IS_VECTOR_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_VECTOR_LAYER_UNDO)) +#define GIMP_VECTOR_LAYER_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_VECTOR_LAYER_UNDO, GimpVectorLayerUndoClass)) + + +typedef struct _GimpVectorLayerUndoClass GimpVectorLayerUndoClass; + +struct _GimpVectorLayerUndo +{ + GimpItemUndo parent_instance; + + GimpVectorLayerOptions *vector_layer_options; + const GParamSpec *pspec; + GValue *value; + gboolean modified; +}; + +struct _GimpVectorLayerUndoClass +{ + GimpItemClass parent_class; +}; + + +GType gimp_vector_layer_undo_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_VECTOR_LAYER_UNDO_H__ */ diff --git a/app/path/meson.build b/app/path/meson.build index aafc83890a..feb5b2081e 100644 --- a/app/path/meson.build +++ b/app/path/meson.build @@ -12,6 +12,11 @@ libapppath_sources = [ 'gimppathundo.c', 'gimpstroke-new.c', 'gimpstroke.c', + 'gimpvectorlayer.c', + 'gimpvectorlayer-xcf.c', + 'gimpvectorlayeroptions.c', + 'gimpvectorlayeroptions-parasite.c', + 'gimpvectorlayerundo.c', ] libapppath = static_library('apppath', diff --git a/app/path/path-types.h b/app/path/path-types.h index ab5a69f1ce..b2f9217748 100644 --- a/app/path/path-types.h +++ b/app/path/path-types.h @@ -25,8 +25,12 @@ #include "path-enums.h" -typedef struct _GimpAnchor GimpAnchor; +typedef struct _GimpAnchor GimpAnchor; -typedef struct _GimpPath GimpPath; -typedef struct _GimpStroke GimpStroke; -typedef struct _GimpBezierStroke GimpBezierStroke; +typedef struct _GimpPath GimpPath; +typedef struct _GimpStroke GimpStroke; +typedef struct _GimpBezierStroke GimpBezierStroke; + +typedef struct _GimpVectorLayer GimpVectorLayer; +typedef struct _GimpVectorLayerOptions GimpVectorLayerOptions; +typedef struct _GimpVectorLayerUndo GimpVectorLayerUndo; diff --git a/app/pdb/internal-procs.c b/app/pdb/internal-procs.c index 124df49769..6e60775639 100644 --- a/app/pdb/internal-procs.c +++ b/app/pdb/internal-procs.c @@ -30,7 +30,7 @@ #include "internal-procs.h" -/* 721 procedures registered total */ +/* 725 procedures registered total */ void internal_procs_init (GimpPDB *pdb) @@ -94,4 +94,5 @@ internal_procs_init (GimpPDB *pdb) register_text_layer_procs (pdb); register_text_tool_procs (pdb); register_unit_procs (pdb); + register_vector_layer_procs (pdb); } diff --git a/app/pdb/internal-procs.h b/app/pdb/internal-procs.h index ac6aadd206..2bddfd3bd7 100644 --- a/app/pdb/internal-procs.h +++ b/app/pdb/internal-procs.h @@ -81,3 +81,4 @@ void register_selection_procs (GimpPDB *pdb); void register_text_layer_procs (GimpPDB *pdb); void register_text_tool_procs (GimpPDB *pdb); void register_unit_procs (GimpPDB *pdb); +void register_vector_layer_procs (GimpPDB *pdb); diff --git a/app/pdb/item-cmds.c b/app/pdb/item-cmds.c index 4edccd6871..3c4ee01ac1 100644 --- a/app/pdb/item-cmds.c +++ b/app/pdb/item-cmds.c @@ -39,6 +39,7 @@ #include "core/gimpparamspecs.h" #include "core/gimpselection.h" #include "path/gimppath.h" +#include "path/gimpvectorlayer.h" #include "text/gimptextlayer.h" #include "gimppdb.h" @@ -179,6 +180,39 @@ item_id_is_text_layer_invoker (GimpProcedure *procedure, return return_vals; } +static GimpValueArray * +item_id_is_vector_layer_invoker (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const GimpValueArray *args, + GError **error) +{ + gboolean success = TRUE; + GimpValueArray *return_vals; + gint item_id; + gboolean vector_layer = FALSE; + + item_id = g_value_get_int (gimp_value_array_index (args, 0)); + + if (success) + { + GimpItem *item = gimp_item_get_by_id (gimp, item_id); + + vector_layer = (GIMP_IS_LAYER (item) && + ! gimp_item_is_removed (item) && + gimp_item_is_vector_layer (item)); + } + + return_vals = gimp_procedure_get_return_values (procedure, success, + error ? *error : NULL); + + if (success) + g_value_set_boolean (gimp_value_array_index (return_vals, 1), vector_layer); + + return return_vals; +} + static GimpValueArray * item_id_is_group_layer_invoker (GimpProcedure *procedure, Gimp *gimp, @@ -1191,6 +1225,37 @@ register_item_procs (GimpPDB *pdb) gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); + /* + * gimp-item-id-is-vector-layer + */ + procedure = gimp_procedure_new (item_id_is_vector_layer_invoker, FALSE); + gimp_object_set_static_name (GIMP_OBJECT (procedure), + "gimp-item-id-is-vector-layer"); + gimp_procedure_set_static_help (procedure, + "Returns whether the item ID is a vector layer.", + "This procedure returns %TRUE if the specified item ID is a vector layer.\n" + "\n" + "*Note*: in most use cases, you should not use this function. See [func@Gimp.Item.id_is_layer] for a discussion on alternatives.", + NULL); + gimp_procedure_set_static_attribution (procedure, + "Alex S.", + "Alex S.", + "2025"); + gimp_procedure_add_argument (procedure, + g_param_spec_int ("item-id", + "item id", + "The item ID", + G_MININT32, G_MAXINT32, 0, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_return_value (procedure, + g_param_spec_boolean ("vector-layer", + "vector layer", + "TRUE if the item is a vector layer, FALSE otherwise.", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_pdb_register_procedure (pdb, procedure); + g_object_unref (procedure); + /* * gimp-item-id-is-group-layer */ diff --git a/app/pdb/meson.build b/app/pdb/meson.build index a02af884e1..3b8fb0500b 100644 --- a/app/pdb/meson.build +++ b/app/pdb/meson.build @@ -66,6 +66,7 @@ libappinternalprocs_sources = [ 'text-layer-cmds.c', 'text-tool-cmds.c', 'unit-cmds.c', + 'vector-layer-cmds.c', ] libapppdb = static_library('apppdb', diff --git a/app/pdb/vector-layer-cmds.c b/app/pdb/vector-layer-cmds.c new file mode 100644 index 0000000000..64e55b1d53 --- /dev/null +++ b/app/pdb/vector-layer-cmds.c @@ -0,0 +1,232 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-2003 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 . + */ + +/* NOTE: This file is auto-generated by pdbgen.pl. */ + +#include "config.h" + +#include "stamp-pdbgen.h" + +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "libgimpbase/gimpbase.h" + +#include "pdb-types.h" + +#include "core/gimpcontext.h" +#include "core/gimpimage.h" +#include "core/gimpparamspecs.h" +#include "path/gimppath.h" +#include "path/gimpvectorlayer.h" + +#include "gimppdb.h" +#include "gimppdberror.h" +#include "gimppdb-utils.h" +#include "gimpprocedure.h" +#include "internal-procs.h" + +#include "gimp-intl.h" + + +static GimpValueArray * +vector_layer_new_invoker (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const GimpValueArray *args, + GError **error) +{ + gboolean success = TRUE; + GimpValueArray *return_vals; + GimpImage *image; + GimpPath *path; + GimpVectorLayer *layer = NULL; + + image = g_value_get_object (gimp_value_array_index (args, 0)); + path = g_value_get_object (gimp_value_array_index (args, 1)); + + if (success) + { + if (path == NULL) + { + g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT, + _("Failed to create vector layer")); + + success = FALSE; + } + + if (success) + { + layer = GIMP_VECTOR_LAYER (gimp_vector_layer_new (image, path, context)); + + if (! layer) + { + g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT, + _("Failed to create vector layer")); + + success = FALSE; + } + } + } + + return_vals = gimp_procedure_get_return_values (procedure, success, + error ? *error : NULL); + + if (success) + g_value_set_object (gimp_value_array_index (return_vals, 1), layer); + + return return_vals; +} + +static GimpValueArray * +vector_layer_refresh_invoker (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const GimpValueArray *args, + GError **error) +{ + gboolean success = TRUE; + GimpVectorLayer *layer; + + layer = g_value_get_object (gimp_value_array_index (args, 0)); + + if (success) + { + gimp_vector_layer_refresh (layer); + } + + return gimp_procedure_get_return_values (procedure, success, + error ? *error : NULL); +} + +static GimpValueArray * +vector_layer_discard_invoker (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const GimpValueArray *args, + GError **error) +{ + gboolean success = TRUE; + GimpVectorLayer *layer; + + layer = g_value_get_object (gimp_value_array_index (args, 0)); + + if (success) + { + gimp_vector_layer_discard (layer); + } + + return gimp_procedure_get_return_values (procedure, success, + error ? *error : NULL); +} + +void +register_vector_layer_procs (GimpPDB *pdb) +{ + GimpProcedure *procedure; + + /* + * gimp-vector-layer-new + */ + procedure = gimp_procedure_new (vector_layer_new_invoker, FALSE); + gimp_object_set_static_name (GIMP_OBJECT (procedure), + "gimp-vector-layer-new"); + gimp_procedure_set_static_help (procedure, + "Creates a new vector layer.", + "This procedure creates a new path layer displaying the specified @path. By default, the fill and stroke properties will be defined by the context.\n" + "\n" + "The new layer still needs to be added to the image as this is not automatic. Add the new layer with the [method@Image.insert_layer] method.\n" + "\n" + "The arguments are kept as simple as necessary for the basic case. All vector attributes, however, can be modified with the appropriate `gimp_vector_layer_set_*()` procedures.", + NULL); + gimp_procedure_set_static_attribution (procedure, + "Alex S.", + "Alex S.", + "2025"); + gimp_procedure_add_argument (procedure, + gimp_param_spec_image ("image", + "image", + "The image", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_argument (procedure, + gimp_param_spec_path ("path", + "path", + "The path to create the layer from", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_return_value (procedure, + gimp_param_spec_vector_layer ("layer", + "layer", + "The new vector layer. The object belongs to libgimp and you should not free it.", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_pdb_register_procedure (pdb, procedure); + g_object_unref (procedure); + + /* + * gimp-vector-layer-refresh + */ + procedure = gimp_procedure_new (vector_layer_refresh_invoker, FALSE); + gimp_object_set_static_name (GIMP_OBJECT (procedure), + "gimp-vector-layer-refresh"); + gimp_procedure_set_static_help (procedure, + "Rerender the vector layer", + "This procedure causes the vector layer to refresh itself after changes.", + NULL); + gimp_procedure_set_static_attribution (procedure, + "Alex S.", + "Alex S.", + "2025"); + gimp_procedure_add_argument (procedure, + gimp_param_spec_vector_layer ("layer", + "layer", + "The vector layer", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_pdb_register_procedure (pdb, procedure); + g_object_unref (procedure); + + /* + * gimp-vector-layer-discard + */ + procedure = gimp_procedure_new (vector_layer_discard_invoker, FALSE); + gimp_object_set_static_name (GIMP_OBJECT (procedure), + "gimp-vector-layer-discard"); + gimp_procedure_set_static_help (procedure, + "Discard the vector layer information.", + "Discards the vector information. This makes the layer behave like a normal layer.", + NULL); + gimp_procedure_set_static_attribution (procedure, + "Alex S.", + "Alex S.", + "2025"); + gimp_procedure_add_argument (procedure, + gimp_param_spec_vector_layer ("layer", + "layer", + "The vector layer", + FALSE, + GIMP_PARAM_READWRITE)); + gimp_pdb_register_procedure (pdb, procedure); + g_object_unref (procedure); +} diff --git a/app/plug-in/gimpgpparams.c b/app/plug-in/gimpgpparams.c index 4dad05f7f7..292580b566 100644 --- a/app/plug-in/gimpgpparams.c +++ b/app/plug-in/gimpgpparams.c @@ -46,6 +46,7 @@ #include "core/gimpunit.h" #include "path/gimppath.h" +#include "path/gimpvectorlayer.h" #include "text/gimpfont.h" #include "text/gimptextlayer.h" diff --git a/app/tools/gimppainttool.c b/app/tools/gimppainttool.c index ccd967b8c1..30271b9c0d 100644 --- a/app/tools/gimppainttool.c +++ b/app/tools/gimppainttool.c @@ -41,6 +41,8 @@ #include "paint/gimppaintcore.h" #include "paint/gimppaintoptions.h" +#include "path/gimpvectorlayer.h" + #include "widgets/gimpdevices.h" #include "widgets/gimpwidgets-utils.h" @@ -342,6 +344,24 @@ gimp_paint_tool_button_press (GimpTool *tool, } } + if (gimp_item_is_vector_layer (GIMP_ITEM (drawable))) + { + gboolean constrain_only; + + /* Allow vector layers to be set as sources */ + constrain_only = (state & gimp_get_constrain_behavior_mask () && + ! (state & gimp_get_extend_selection_mask ())); + if (! (GIMP_IS_SOURCE_TOOL (tool) && constrain_only)) + { + gimp_tool_message_literal (tool, display, + _("Vector layers must be rasterized " + "before they can be painted on.")); + g_list_free (drawables); + + return; + } + } + if (! gimp_paint_tool_check_alpha (paint_tool, drawable, display, &error)) { GtkWidget *options_gui; diff --git a/app/tools/gimppathoptions.c b/app/tools/gimppathoptions.c index 5a150b6265..57c458298a 100644 --- a/app/tools/gimppathoptions.c +++ b/app/tools/gimppathoptions.c @@ -24,12 +24,21 @@ #include #include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" #include "libgimpconfig/gimpconfig.h" #include "libgimpwidgets/gimpwidgets.h" #include "tools-types.h" +#include "core/gimp.h" +#include "core/gimpcontainer.h" +#include "core/gimpdatafactory.h" +#include "core/gimppattern.h" +#include "core/gimpstrokeoptions.h" + #include "widgets/gimphelp-ids.h" +#include "widgets/gimppropwidgets.h" +#include "widgets/gimpstrokeeditor.h" #include "widgets/gimpwidgets-utils.h" #include "gimppathoptions.h" @@ -42,28 +51,68 @@ enum { PROP_0, PROP_PATH_EDIT_MODE, - PROP_PATH_POLYGONAL + PROP_PATH_POLYGONAL, + PROP_ENABLE_FILL, + PROP_ENABLE_STROKE, + PROP_FILL_STYLE, + PROP_FILL_FOREGROUND, + PROP_FILL_PATTERN, + PROP_FILL_ANTIALIAS, + PROP_STROKE_STYLE, + PROP_STROKE_FOREGROUND, + PROP_STROKE_PATTERN, + PROP_STROKE_WIDTH, + PROP_STROKE_UNIT, + PROP_STROKE_ANTIALIAS, + PROP_STROKE_CAP_STYLE, + PROP_STROKE_JOIN_STYLE, + PROP_STROKE_MITER_LIMIT, + PROP_STROKE_DASH_OFFSET }; +static void gimp_path_options_config_iface_init (GimpConfigInterface *config_iface); +static gboolean gimp_path_options_serialize_property (GimpConfig *config, + guint property_id, + const GValue *value, + GParamSpec *pspec, + GimpConfigWriter *writer); +static gboolean gimp_path_options_deserialize_property (GimpConfig *config, + guint property_id, + GValue *value, + GParamSpec *pspec, + GScanner *scanner, + GTokenType *expected); -static void gimp_path_options_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_path_options_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); +static void gimp_path_options_finalize (GObject *object); +static void gimp_path_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_path_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); -G_DEFINE_TYPE (GimpPathOptions, gimp_path_options, GIMP_TYPE_TOOL_OPTIONS) +G_DEFINE_TYPE_WITH_CODE (GimpPathOptions, gimp_path_options, + GIMP_TYPE_TOOL_OPTIONS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_path_options_config_iface_init)) + + +#define parent_class gimp_path_options_parent_class + +static GimpConfigInterface *parent_config_iface = NULL; static void gimp_path_options_class_init (GimpPathOptionsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglColor *black = gegl_color_new ("black"); + GeglColor *white = gegl_color_new ("white"); + object_class->finalize = gimp_path_options_finalize; object_class->set_property = gimp_path_options_set_property; object_class->get_property = gimp_path_options_get_property; @@ -81,11 +130,140 @@ gimp_path_options_class_init (GimpPathOptionsClass *klass) _("Restrict editing to polygons"), FALSE, GIMP_PARAM_STATIC_STRINGS); + + /* Vector layer specific properties */ + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ENABLE_FILL, + "enable-fill", + _("Enable Fill"), NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ENABLE_STROKE, + "enable-stroke", + _("Enable Stroke"), NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_FILL_STYLE, + "fill-custom-style", + NULL, NULL, + GIMP_TYPE_CUSTOM_STYLE, + GIMP_CUSTOM_STYLE_SOLID_COLOR, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_COLOR (object_class, PROP_FILL_FOREGROUND, + "fill-foreground", + NULL, NULL, + TRUE, white, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FILL_PATTERN, + "fill-pattern", + NULL, NULL, + GIMP_TYPE_PATTERN, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_FILL_ANTIALIAS, + "fill-antialias", + NULL, NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_STROKE_STYLE, + "stroke-custom-style", + NULL, NULL, + GIMP_TYPE_CUSTOM_STYLE, + GIMP_CUSTOM_STYLE_SOLID_COLOR, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_COLOR (object_class, PROP_STROKE_FOREGROUND, + "stroke-foreground", + NULL, NULL, + TRUE, black, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_STROKE_PATTERN, + "stroke-pattern", + NULL, NULL, + GIMP_TYPE_PATTERN, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_STROKE_WIDTH, + "stroke-width", + NULL, NULL, + 0.0, 2000.0, 6.0, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_UNIT (object_class, PROP_STROKE_UNIT, + "stroke-unit", + NULL, NULL, + TRUE, FALSE, gimp_unit_pixel (), + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_STROKE_ANTIALIAS, + "stroke-antialias", + NULL, NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_STROKE_CAP_STYLE, + "stroke-cap-style", + NULL, NULL, + GIMP_TYPE_CAP_STYLE, GIMP_CAP_BUTT, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_STROKE_JOIN_STYLE, + "stroke-join-style", + NULL, NULL, + GIMP_TYPE_JOIN_STYLE, GIMP_JOIN_MITER, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_STROKE_MITER_LIMIT, + "stroke-miter-limit", + NULL, NULL, + 0.0, 100.0, 10.0, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_STROKE_DASH_OFFSET, + "stroke-dash-offset", + NULL, NULL, + 0.0, 2000.0, 0.0, + GIMP_PARAM_STATIC_STRINGS); + + g_clear_object (&white); + g_clear_object (&black); +} + +static void +gimp_path_options_config_iface_init (GimpConfigInterface *config_iface) +{ + parent_config_iface = g_type_interface_peek_parent (config_iface); + + config_iface->serialize_property = gimp_path_options_serialize_property; + config_iface->deserialize_property = gimp_path_options_deserialize_property; } static void gimp_path_options_init (GimpPathOptions *options) { + GeglColor *black = gegl_color_new ("black"); + GeglColor *white = gegl_color_new ("white"); + + options->fill_foreground = white; + options->stroke_foreground = black; +} + +static void +gimp_path_options_finalize (GObject *object) +{ + GimpPathOptions *options = GIMP_PATH_OPTIONS (object); + + g_clear_object (&options->fill_options); + g_clear_object (&options->stroke_options); + g_clear_object (&options->fill_foreground); + g_clear_object (&options->stroke_foreground); + + G_OBJECT_CLASS (parent_class)->finalize (object); } static void @@ -104,13 +282,84 @@ gimp_path_options_set_property (GObject *object, case PROP_PATH_POLYGONAL: options->polygonal = g_value_get_boolean (value); break; + + case PROP_ENABLE_FILL: + options->enable_fill = g_value_get_boolean (value); + break; + case PROP_ENABLE_STROKE: + options->enable_stroke = g_value_get_boolean (value); + break; + + case PROP_FILL_STYLE: + options->fill_style = g_value_get_enum (value); + break; + case PROP_FILL_FOREGROUND: + g_set_object (&options->fill_foreground, g_value_get_object (value)); + break; + case PROP_FILL_PATTERN: + { + GimpPattern *pattern = g_value_get_object (value); + + if (options->fill_pattern != pattern) + { + if (options->fill_pattern) + g_object_unref (options->fill_pattern); + + options->fill_pattern = pattern ? g_object_ref (pattern) : pattern; + } + break; + } + case PROP_FILL_ANTIALIAS: + options->fill_antialias = g_value_get_boolean (value); + break; + case PROP_STROKE_STYLE: + options->stroke_style = g_value_get_enum (value); + break; + case PROP_STROKE_FOREGROUND: + g_set_object (&options->stroke_foreground, g_value_get_object (value)); + break; + case PROP_STROKE_PATTERN: + { + GimpPattern *pattern = g_value_get_object (value); + + if (options->stroke_pattern != pattern) + { + if (options->stroke_pattern) + g_object_unref (options->stroke_pattern); + + options->stroke_pattern = pattern ? + g_object_ref (pattern) : pattern; + } + break; + } + case PROP_STROKE_WIDTH: + options->stroke_width = g_value_get_double (value); + break; + case PROP_STROKE_UNIT: + options->stroke_unit = g_value_get_object (value); + break; + case PROP_STROKE_ANTIALIAS: + options->stroke_antialias = g_value_get_boolean (value); + break; + case PROP_STROKE_CAP_STYLE: + options->stroke_cap_style = g_value_get_enum (value); + break; + case PROP_STROKE_JOIN_STYLE: + options->stroke_join_style = g_value_get_enum (value); + break; + case PROP_STROKE_MITER_LIMIT: + options->stroke_miter_limit = g_value_get_double (value); + break; + case PROP_STROKE_DASH_OFFSET: + options->stroke_dash_offset = g_value_get_double (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } - static void gimp_path_options_get_property (GObject *object, guint property_id, @@ -127,12 +376,138 @@ gimp_path_options_get_property (GObject *object, case PROP_PATH_POLYGONAL: g_value_set_boolean (value, options->polygonal); break; + + case PROP_ENABLE_FILL: + g_value_set_boolean (value, options->enable_fill); + break; + case PROP_ENABLE_STROKE: + g_value_set_boolean (value, options->enable_stroke); + break; + + case PROP_FILL_STYLE: + g_value_set_enum (value, options->fill_style); + break; + case PROP_FILL_FOREGROUND: + g_value_set_object (value, options->fill_foreground); + break; + case PROP_FILL_PATTERN: + g_value_set_object (value, options->fill_pattern); + break; + case PROP_FILL_ANTIALIAS: + g_value_set_boolean (value, options->fill_antialias); + break; + case PROP_STROKE_STYLE: + g_value_set_enum (value, options->stroke_style); + break; + case PROP_STROKE_FOREGROUND: + g_value_set_object (value, options->stroke_foreground); + break; + case PROP_STROKE_PATTERN: + g_value_set_object (value, options->stroke_pattern); + break; + case PROP_STROKE_WIDTH: + g_value_set_double (value, options->stroke_width); + break; + case PROP_STROKE_UNIT: + g_value_set_object (value, options->stroke_unit); + break; + case PROP_STROKE_ANTIALIAS: + g_value_set_boolean (value, options->stroke_antialias); + break; + case PROP_STROKE_CAP_STYLE: + g_value_set_enum (value, options->stroke_cap_style); + break; + case PROP_STROKE_JOIN_STYLE: + g_value_set_enum (value, options->stroke_join_style); + break; + case PROP_STROKE_MITER_LIMIT: + g_value_set_double (value, options->stroke_miter_limit); + break; + case PROP_STROKE_DASH_OFFSET: + g_value_set_double (value, options->stroke_dash_offset); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } +static gboolean +gimp_path_options_serialize_property (GimpConfig *config, + guint property_id, + const GValue *value, + GParamSpec *pspec, + GimpConfigWriter *writer) +{ + if (property_id == PROP_FILL_PATTERN || + property_id == PROP_STROKE_PATTERN) + { + GimpObject *serialize_obj = g_value_get_object (value); + + gimp_config_writer_open (writer, pspec->name); + + if (serialize_obj) + gimp_config_writer_string (writer, + gimp_object_get_name (serialize_obj)); + else + gimp_config_writer_print (writer, "NULL", 4); + + gimp_config_writer_close (writer); + + return TRUE; + } + + return FALSE; +} + +static gboolean +gimp_path_options_deserialize_property (GimpConfig *object, + guint property_id, + GValue *value, + GParamSpec *pspec, + GScanner *scanner, + GTokenType *expected) +{ + if (property_id == PROP_FILL_PATTERN || + property_id == PROP_STROKE_PATTERN) + { + gchar *object_name; + + if (gimp_scanner_parse_identifier (scanner, "NULL")) + { + g_value_set_object (value, NULL); + } + else if (gimp_scanner_parse_string (scanner, &object_name)) + { + GimpContext *context = GIMP_CONTEXT (object); + GimpContainer *container; + GimpObject *deserialize_obj; + + if (! object_name) + object_name = g_strdup (""); + + container = + gimp_data_factory_get_container (context->gimp->pattern_factory); + + deserialize_obj = gimp_container_get_child_by_name (container, + object_name); + + g_value_set_object (value, deserialize_obj); + + g_free (object_name); + } + else + { + *expected = G_TOKEN_STRING; + } + + return TRUE; + } + + return FALSE; +} + static void button_append_modifier (GtkWidget *button, GdkModifierType modifiers) @@ -149,7 +524,7 @@ GtkWidget * gimp_path_options_gui (GimpToolOptions *tool_options) { GObject *config = G_OBJECT (tool_options); - GimpPathOptions *options = GIMP_PATH_OPTIONS (tool_options); + GimpPathOptions *options = GIMP_PATH_OPTIONS (tool_options); GtkWidget *vbox = gimp_tool_options_gui (tool_options); GtkWidget *frame; GtkWidget *button; @@ -198,23 +573,7 @@ gimp_path_options_gui (GimpToolOptions *tool_options) options->to_selection_button = button; - button = gtk_button_new_with_label (_("Fill Path")); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive (button, FALSE); - gimp_help_set_help_data (button, NULL, GIMP_HELP_PATH_FILL); - gtk_widget_set_visible (button, TRUE); - - options->fill_button = button; - - button = gtk_button_new_with_label (_("Stroke Path")); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive (button, FALSE); - gimp_help_set_help_data (button, NULL, GIMP_HELP_PATH_STROKE); - gtk_widget_set_visible (button, TRUE); - - options->stroke_button = button; - - button = gtk_button_new_with_label (_("Create Vector Layer")); + button = gtk_button_new_with_label (_("Create New Vector Layer")); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive (button, FALSE); gimp_help_set_help_data (button, NULL, NULL); @@ -222,5 +581,64 @@ gimp_path_options_gui (GimpToolOptions *tool_options) options->vector_layer_button = button; + /* The fill editor */ + { + GtkWidget *frame; + GtkWidget *fill_editor; + + options->fill_options = + gimp_fill_options_new (GIMP_CONTEXT (options)->gimp, + NULL, FALSE); + +#define FILL_BIND(a) \ + g_object_bind_property (options, "fill-" #a, \ + options->fill_options, #a, \ + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE) + FILL_BIND (custom-style); + FILL_BIND (foreground); + FILL_BIND (pattern); + + fill_editor = gimp_fill_editor_new (options->fill_options, + TRUE, TRUE); + gtk_widget_set_visible (fill_editor, TRUE); + + frame = gimp_prop_expanding_frame_new (config, "enable-fill", NULL, + fill_editor, NULL); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + } + + /* The stroke editor */ + { + GtkWidget *frame; + GtkWidget *stroke_editor; + + options->stroke_options = + gimp_stroke_options_new (GIMP_CONTEXT (options)->gimp, + NULL, FALSE); + +#define STROKE_BIND(a) \ + g_object_bind_property (options, "stroke-" #a, \ + options->stroke_options, #a, \ + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE) + STROKE_BIND (custom-style); + STROKE_BIND (foreground); + STROKE_BIND (pattern); + STROKE_BIND (width); + STROKE_BIND (unit); + STROKE_BIND (cap-style); + STROKE_BIND (join-style); + STROKE_BIND (miter-limit); + STROKE_BIND (antialias); + STROKE_BIND (dash-offset); + + stroke_editor = gimp_stroke_editor_new (options->stroke_options, 72.0, + TRUE, TRUE); + gtk_widget_set_visible (stroke_editor, TRUE); + + frame = gimp_prop_expanding_frame_new (config, "enable-stroke", NULL, + stroke_editor, NULL); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + } + return vbox; } diff --git a/app/tools/gimppathoptions.h b/app/tools/gimppathoptions.h index 71655cc9bc..ec20b38d3a 100644 --- a/app/tools/gimppathoptions.h +++ b/app/tools/gimppathoptions.h @@ -28,20 +28,41 @@ #define GIMP_PATH_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PATH_OPTIONS, GimpPathOptionsClass)) -typedef struct _GimpPathOptions GimpPathOptions; +typedef struct _GimpPathOptions GimpPathOptions; typedef struct _GimpToolOptionsClass GimpPathOptionsClass; struct _GimpPathOptions { - GimpToolOptions parent_instance; + GimpToolOptions parent_instance; - GimpPathMode edit_mode; - gboolean polygonal; + GimpPathMode edit_mode; + gboolean polygonal; + + /* vector layer */ + gboolean enable_fill; + gboolean enable_stroke; + GimpFillOptions *fill_options; + GimpStrokeOptions *stroke_options; + + GimpCustomStyle fill_style; + GeglColor *fill_foreground; + GimpPattern *fill_pattern; + gboolean fill_antialias; + + GimpCustomStyle stroke_style; + GeglColor *stroke_foreground; + GimpPattern *stroke_pattern; + gboolean stroke_antialias; + gdouble stroke_width; + GimpUnit *stroke_unit; + GimpCapStyle stroke_cap_style; + GimpJoinStyle stroke_join_style; + gdouble stroke_miter_limit; + gdouble stroke_dash_offset; /* options gui */ - GtkWidget *to_selection_button; - GtkWidget *fill_button; - GtkWidget *stroke_button; + GtkWidget *to_selection_button; + GtkWidget *vector_layer_button; }; diff --git a/app/tools/gimppathtool.c b/app/tools/gimppathtool.c index 48b5573257..9565c3a0a3 100644 --- a/app/tools/gimppathtool.c +++ b/app/tools/gimppathtool.c @@ -35,12 +35,15 @@ #include "core/gimpimage-pick-item.h" #include "core/gimpimage-undo.h" #include "core/gimpimage-undo-push.h" +#include "core/gimpstrokeoptions.h" #include "core/gimptoolinfo.h" #include "core/gimpundostack.h" #include "paint/gimppaintoptions.h" /* GIMP_PAINT_OPTIONS_CONTEXT_MASK */ #include "path/gimppath.h" +#include "path/gimpvectorlayer.h" +#include "path/gimpvectorlayeroptions.h" #include "widgets/gimpdialogfactory.h" #include "widgets/gimpdockcontainer.h" @@ -70,6 +73,7 @@ /* local function prototypes */ +static void gimp_path_tool_constructed (GObject *object); static void gimp_path_tool_dispose (GObject *object); static void gimp_path_tool_control (GimpTool *tool, @@ -106,6 +110,12 @@ static void gimp_path_tool_start (GimpPathTool *path_t GimpDisplay *display); static void gimp_path_tool_halt (GimpPathTool *path_tool); +static void gimp_path_tool_image_changed (GimpPathTool *path_tool, + GimpImage *image, + GimpContext *context); +static void gimp_path_tool_image_selected_layers_changed + (GimpPathTool *path_tool); + static void gimp_path_tool_tool_path_changed (GimpToolWidget *tool_path, GimpPathTool *path_tool); static void gimp_path_tool_tool_path_begin_change @@ -130,23 +140,12 @@ static void gimp_path_tool_to_selection_extended (GimpPathTool *path_tool, GdkModifierType state); -static void gimp_path_tool_fill_path (GimpPathTool *path_tool, - GtkWidget *button); -static void gimp_path_tool_fill_callback (GtkWidget *dialog, - GList *items, - GList *drawables, - GimpContext *context, - GimpFillOptions *options, - gpointer data); - -static void gimp_path_tool_stroke_path (GimpPathTool *path_tool, - GtkWidget *button); -static void gimp_path_tool_stroke_callback (GtkWidget *dialog, - GList *items, - GList *drawables, - GimpContext *context, - GimpStrokeOptions *options, - gpointer data); +static void gimp_path_tool_create_vector_layer(GimpPathTool *path_tool, + GtkWidget *button); +static void gimp_path_tool_vector_change_notify + (GObject *options, + const GParamSpec *pspec, + GimpVectorLayer *layer); G_DEFINE_TYPE (GimpPathTool, gimp_path_tool, GIMP_TYPE_DRAW_TOOL) @@ -179,6 +178,7 @@ gimp_path_tool_class_init (GimpPathToolClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass); + object_class->constructed = gimp_path_tool_constructed; object_class->dispose = gimp_path_tool_dispose; tool_class->control = gimp_path_tool_control; @@ -203,6 +203,28 @@ gimp_path_tool_init (GimpPathTool *path_tool) path_tool->saved_mode = GIMP_PATH_MODE_DESIGN; } +static void +gimp_path_tool_constructed (GObject *object) +{ + GimpPathTool *path_tool = GIMP_PATH_TOOL (object); + GimpContext *context; + GimpToolInfo *tool_info; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + tool_info = GIMP_TOOL (path_tool)->tool_info; + + context = gimp_get_user_context (tool_info->gimp); + + g_signal_connect_object (context, "image-changed", + G_CALLBACK (gimp_path_tool_image_changed), + path_tool, G_CONNECT_SWAPPED); + + gimp_path_tool_image_changed (path_tool, + gimp_context_get_image (context), + context); +} + static void gimp_path_tool_dispose (GObject *object) { @@ -211,6 +233,8 @@ gimp_path_tool_dispose (GObject *object) gimp_path_tool_set_path (path_tool, NULL); g_clear_object (&path_tool->widget); + gimp_path_tool_image_changed (path_tool, NULL, NULL); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -445,6 +469,87 @@ gimp_path_tool_halt (GimpPathTool *path_tool) tool->display = NULL; } +static void +gimp_path_tool_image_changed (GimpPathTool *path_tool, + GimpImage *image, + GimpContext *context) +{ + if (path_tool->current_image) + g_signal_handlers_disconnect_by_func (path_tool->current_image, + gimp_path_tool_image_selected_layers_changed, + NULL); + + g_set_weak_pointer (&path_tool->current_image, image); + + if (path_tool->current_image) + g_signal_connect_object (path_tool->current_image, "selected-layers-changed", + G_CALLBACK (gimp_path_tool_image_selected_layers_changed), + path_tool, G_CONNECT_SWAPPED); + + gimp_path_tool_image_selected_layers_changed (path_tool); +} + +static void +gimp_path_tool_image_selected_layers_changed (GimpPathTool *path_tool) +{ + GimpPathOptions *options = GIMP_PATH_TOOL_GET_OPTIONS (path_tool); + GList *current_layers = NULL; + + if (path_tool->current_vector_layer) + { + g_signal_handlers_disconnect_by_func (options, + gimp_path_tool_vector_change_notify, + path_tool->current_vector_layer); + g_signal_handlers_disconnect_by_func (options->fill_options, + gimp_path_tool_vector_change_notify, + path_tool->current_vector_layer); + 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 = NULL; + gimp_path_tool_set_path (path_tool, 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_item_is_vector_layer (GIMP_ITEM (current_layers->data))) + { + GimpVectorLayer *vector_layer = current_layers->data; + + gimp_path_tool_set_path (path_tool, + gimp_vector_layer_get_path (vector_layer)); + + g_object_set (options, + "enable-fill", vector_layer->options->enable_fill, + "enable_stroke", vector_layer->options->enable_stroke, + NULL); + gimp_config_sync (G_OBJECT (vector_layer->options->stroke_options), + G_OBJECT (options->stroke_options), 0); + gimp_config_sync (G_OBJECT (vector_layer->options->fill_options), + G_OBJECT (options->fill_options), 0); + + g_signal_connect_object (options, "notify::enable-fill", + G_CALLBACK (gimp_path_tool_vector_change_notify), + vector_layer, 0); + g_signal_connect_object (options, "notify::enable-stroke", + G_CALLBACK (gimp_path_tool_vector_change_notify), + vector_layer, 0); + g_signal_connect_object (options->fill_options, "notify", + G_CALLBACK (gimp_path_tool_vector_change_notify), + vector_layer, 0); + g_signal_connect_object (options->stroke_options, "notify", + G_CALLBACK (gimp_path_tool_vector_change_notify), + vector_layer, 0); + + path_tool->current_vector_layer = vector_layer; + } +} + static void gimp_path_tool_tool_path_changed (GimpToolWidget *tool_path, GimpPathTool *path_tool) @@ -453,9 +558,7 @@ gimp_path_tool_tool_path_changed (GimpToolWidget *tool_path, GimpImage *image = gimp_display_get_image (shell->display); GimpPath *path; - g_object_get (tool_path, - "path", &path, - NULL); + g_object_get (tool_path, "path", &path, NULL); if (path != path_tool->path) { @@ -595,19 +698,11 @@ gimp_path_tool_set_path (GimpPathTool *path_tool, tool); } - if (options->fill_button) + if (options->vector_layer_button) { - gtk_widget_set_sensitive (options->fill_button, FALSE); - g_signal_handlers_disconnect_by_func (options->fill_button, - gimp_path_tool_fill_path, - tool); - } - - if (options->stroke_button) - { - gtk_widget_set_sensitive (options->stroke_button, FALSE); - g_signal_handlers_disconnect_by_func (options->stroke_button, - gimp_path_tool_stroke_path, + gtk_widget_set_sensitive (options->vector_layer_button, FALSE); + g_signal_handlers_disconnect_by_func (options->vector_layer_button, + gimp_path_tool_create_vector_layer, tool); } } @@ -642,20 +737,13 @@ gimp_path_tool_set_path (GimpPathTool *path_tool, gtk_widget_set_sensitive (options->to_selection_button, TRUE); } - if (options->fill_button) + if (options->vector_layer_button) { - g_signal_connect_swapped (options->fill_button, "clicked", - G_CALLBACK (gimp_path_tool_fill_path), - tool); - gtk_widget_set_sensitive (options->fill_button, TRUE); - } + g_signal_connect_swapped (options->vector_layer_button, "clicked", + G_CALLBACK (gimp_path_tool_create_vector_layer), + tool); - if (options->stroke_button) - { - g_signal_connect_swapped (options->stroke_button, "clicked", - G_CALLBACK (gimp_path_tool_stroke_path), - tool); - gtk_widget_set_sensitive (options->stroke_button, TRUE); + gtk_widget_set_sensitive (options->vector_layer_button, TRUE); } if (tool->display) @@ -722,180 +810,126 @@ gimp_path_tool_to_selection_extended (GimpPathTool *path_tool, gimp_image_flush (image); } - static void -gimp_path_tool_fill_path (GimpPathTool *path_tool, - GtkWidget *button) +gimp_path_tool_create_vector_layer (GimpPathTool *path_tool, + GtkWidget *button) { - GimpDialogConfig *config; - GimpImage *image; - GList *drawables; - GList *path_list = NULL; - GtkWidget *dialog; + GimpImage *image; + GimpVectorLayer *layer; + GimpPathOptions *options = GIMP_PATH_TOOL_GET_OPTIONS (path_tool); if (! path_tool->path) return; image = gimp_item_get_image (GIMP_ITEM (path_tool->path)); - config = GIMP_DIALOG_CONFIG (image->gimp->config); + g_signal_handlers_block_by_func (image, + gimp_path_tool_image_selected_layers_changed, + path_tool); - drawables = gimp_image_get_selected_drawables (image); - - if (! drawables) + /* If there's already an active vector layer, create a new blank path */ + if (path_tool->current_vector_layer) { - gimp_tool_message (GIMP_TOOL (path_tool), - GIMP_TOOL (path_tool)->display, - _("There are no selected layers or channels to fill.")); - return; + GimpPath *new_path = gimp_path_new (image, _("Vector Layer")); + + gimp_image_add_path (image, new_path, GIMP_IMAGE_ACTIVE_PARENT, -1, + TRUE); + + g_signal_handlers_disconnect_by_func (options, + gimp_path_tool_vector_change_notify, + path_tool->current_vector_layer); + g_signal_handlers_disconnect_by_func (options->fill_options, + gimp_path_tool_vector_change_notify, + path_tool->current_vector_layer); + g_signal_handlers_disconnect_by_func (options->stroke_options, + gimp_path_tool_vector_change_notify, + path_tool->current_vector_layer); } - if (g_list_length (drawables) == 1 && - gimp_item_is_content_locked (GIMP_ITEM (drawables->data), NULL)) - { - gimp_tool_message (GIMP_TOOL (path_tool), - GIMP_TOOL (path_tool)->display, - _("A selected layer's pixels are locked.")); - return; - } + layer = gimp_vector_layer_new (image, path_tool->path, + gimp_get_user_context (image->gimp)); + path_tool->current_vector_layer = layer; - path_list = g_list_prepend (NULL, path_tool->path); - dialog = fill_dialog_new (path_list, drawables, - GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (path_tool)), - _("Fill Path"), - GIMP_ICON_TOOL_BUCKET_FILL, - GIMP_HELP_PATH_FILL, - button, - config->fill_options, - gimp_path_tool_fill_callback, - path_tool); - gtk_widget_show (dialog); - g_list_free (path_list); - g_list_free (drawables); -} + gimp_image_add_layer (image, + GIMP_LAYER (layer), + GIMP_IMAGE_ACTIVE_PARENT, + -1, + TRUE); -static void -gimp_path_tool_fill_callback (GtkWidget *dialog, - GList *items, - GList *drawables, - GimpContext *context, - GimpFillOptions *options, - gpointer data) -{ - GimpDialogConfig *config = GIMP_DIALOG_CONFIG (context->gimp->config); - GimpImage *image = gimp_item_get_image (items->data); - GError *error = NULL; + g_object_set (layer->options, + "enable-fill", options->enable_fill, + "enable-stroke", options->enable_stroke, + NULL); - gimp_config_sync (G_OBJECT (options), - G_OBJECT (config->fill_options), 0); + gimp_config_sync (G_OBJECT (options->fill_options), + G_OBJECT (layer->options->fill_options), 0); + gimp_config_sync (G_OBJECT (options->stroke_options), + G_OBJECT (layer->options->stroke_options), 0); - gimp_image_undo_group_start (image, - GIMP_UNDO_GROUP_DRAWABLE_MOD, - "Fill"); + g_signal_connect_object (options, "notify::enable-fill", + G_CALLBACK (gimp_path_tool_vector_change_notify), + layer, 0); + g_signal_connect_object (options, "notify::enable-stroke", + G_CALLBACK (gimp_path_tool_vector_change_notify), + layer, 0); + g_signal_connect_object (options->fill_options, "notify", + G_CALLBACK (gimp_path_tool_vector_change_notify), + layer, 0); + g_signal_connect_object (options->stroke_options, "notify", + G_CALLBACK (gimp_path_tool_vector_change_notify), + layer, 0); - for (GList *iter = items; iter; iter = iter->next) - if (! gimp_item_fill (iter->data, drawables, options, - TRUE, NULL, &error)) - { - gimp_message_literal (context->gimp, - G_OBJECT (dialog), - GIMP_MESSAGE_WARNING, - error ? error->message : "NULL"); - - g_clear_error (&error); - break; - } - - gimp_image_undo_group_end (image); + gimp_vector_layer_refresh (layer); gimp_image_flush (image); - gtk_widget_destroy (dialog); -} - -static void -gimp_path_tool_stroke_path (GimpPathTool *path_tool, - GtkWidget *button) -{ - GimpDialogConfig *config; - GimpImage *image; - GList *drawables; - GList *path_list = NULL; - GtkWidget *dialog; - - if (! path_tool->path) - return; - - image = gimp_item_get_image (GIMP_ITEM (path_tool->path)); - - config = GIMP_DIALOG_CONFIG (image->gimp->config); - - drawables = gimp_image_get_selected_drawables (image); - - if (! drawables) - { - gimp_tool_message (GIMP_TOOL (path_tool), - GIMP_TOOL (path_tool)->display, - _("There are no selected layers or channels to stroke to.")); - return; - } - - if (g_list_length (drawables) == 1 && - gimp_item_is_content_locked (GIMP_ITEM (drawables->data), NULL)) - { - gimp_tool_message (GIMP_TOOL (path_tool), - GIMP_TOOL (path_tool)->display, - _("A selected layer's pixels are locked.")); - return; - } - - path_list = g_list_prepend (NULL, path_tool->path); - dialog = stroke_dialog_new (path_list, drawables, - GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (path_tool)), - _("Stroke Path"), - GIMP_ICON_PATH_STROKE, - GIMP_HELP_PATH_STROKE, - button, - config->stroke_options, - gimp_path_tool_stroke_callback, - path_tool); - gtk_widget_show (dialog); - g_list_free (path_list); - g_list_free (drawables); + g_signal_handlers_unblock_by_func (image, + gimp_path_tool_image_selected_layers_changed, + path_tool); } static void -gimp_path_tool_stroke_callback (GtkWidget *dialog, - GList *items, - GList *drawables, - GimpContext *context, - GimpStrokeOptions *options, - gpointer data) +gimp_path_tool_vector_change_notify (GObject *options, + const GParamSpec *pspec, + GimpVectorLayer *layer) { - GimpDialogConfig *config = GIMP_DIALOG_CONFIG (context->gimp->config); - GimpImage *image = gimp_item_get_image (items->data); - GError *error = NULL; + GimpImage *image; + gboolean needs_update = FALSE; - gimp_config_sync (G_OBJECT (options), - G_OBJECT (config->stroke_options), 0); + image = gimp_item_get_image (GIMP_ITEM (layer)); - gimp_image_undo_group_start (image, - GIMP_UNDO_GROUP_DRAWABLE_MOD, - "Stroke"); + if (GIMP_IS_STROKE_OPTIONS (options)) + { + GimpStrokeOptions *stroke_options = GIMP_STROKE_OPTIONS (options); - for (GList *iter = items; iter; iter = iter->next) - if (! gimp_item_stroke (iter->data, drawables, context, options, NULL, - TRUE, NULL, &error)) - { - gimp_message_literal (context->gimp, - G_OBJECT (dialog), - GIMP_MESSAGE_WARNING, - error ? error->message : "NULL"); + gimp_config_sync (G_OBJECT (stroke_options), + G_OBJECT (layer->options->stroke_options), 0); - g_clear_error (&error); - break; - } + needs_update = TRUE; + } + else if (GIMP_IS_FILL_OPTIONS (options)) + { + GimpFillOptions *fill_options = GIMP_FILL_OPTIONS (options); - gimp_image_undo_group_end (image); - gimp_image_flush (image); - gtk_widget_destroy (dialog); + gimp_config_sync (G_OBJECT (fill_options), + G_OBJECT (layer->options->fill_options), 0); + + 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); + + needs_update = TRUE; + } + + if (needs_update) + { + gimp_vector_layer_refresh (layer); + gimp_image_flush (image); + } } diff --git a/app/tools/gimppathtool.h b/app/tools/gimppathtool.h index 5c9f761bb7..da65773700 100644 --- a/app/tools/gimppathtool.h +++ b/app/tools/gimppathtool.h @@ -38,13 +38,16 @@ typedef struct _GimpPathToolClass GimpPathToolClass; struct _GimpPathTool { - GimpDrawTool parent_instance; + GimpDrawTool parent_instance; - GimpPath *path; /* the current Path data */ - GimpPathMode saved_mode; /* used by modifier_key() */ + GimpImage *current_image; + GimpVectorLayer *current_vector_layer; - GimpToolWidget *widget; - GimpToolWidget *grab_widget; + GimpPath *path; /* the current Path data */ + GimpPathMode saved_mode; /* used by modifier_key() */ + + GimpToolWidget *widget; + GimpToolWidget *grab_widget; }; struct _GimpPathToolClass diff --git a/libgimp/gimp.c b/libgimp/gimp.c index b768bc4295..cc7f1359d8 100644 --- a/libgimp/gimp.c +++ b/libgimp/gimp.c @@ -449,6 +449,7 @@ gimp_main (GType plug_in_type, GIMP_TYPE_DRAWABLE, GIMP_TYPE_PARAM_DRAWABLE, GIMP_TYPE_LAYER, GIMP_TYPE_PARAM_LAYER, GIMP_TYPE_TEXT_LAYER, GIMP_TYPE_PARAM_TEXT_LAYER, + GIMP_TYPE_VECTOR_LAYER, GIMP_TYPE_PARAM_VECTOR_LAYER, GIMP_TYPE_GROUP_LAYER, GIMP_TYPE_PARAM_GROUP_LAYER, GIMP_TYPE_CHANNEL, GIMP_TYPE_PARAM_CHANNEL, GIMP_TYPE_LAYER_MASK, GIMP_TYPE_PARAM_LAYER_MASK, diff --git a/libgimp/gimp.def b/libgimp/gimp.def index 789b84ae2b..991dfe79cf 100644 --- a/libgimp/gimp.def +++ b/libgimp/gimp.def @@ -601,6 +601,7 @@ EXPORTS gimp_item_id_is_selection gimp_item_id_is_text_layer gimp_item_id_is_valid + gimp_item_id_is_vector_layer gimp_item_is_channel gimp_item_is_drawable gimp_item_is_group @@ -749,7 +750,9 @@ EXPORTS gimp_param_spec_resource_none_allowed gimp_param_spec_selection gimp_param_spec_text_layer + gimp_param_spec_vector_layer gimp_param_text_layer_get_type + gimp_param_vector_layer_get_type gimp_path_bezier_stroke_conicto gimp_path_bezier_stroke_cubicto gimp_path_bezier_stroke_lineto @@ -912,6 +915,9 @@ EXPORTS gimp_procedure_add_unit_argument gimp_procedure_add_unit_aux_argument gimp_procedure_add_unit_return_value + gimp_procedure_add_vector_layer_argument + gimp_procedure_add_vector_layer_aux_argument + gimp_procedure_add_vector_layer_return_value gimp_procedure_config_get_choice_id gimp_procedure_config_get_color_array gimp_procedure_config_get_core_object_array @@ -1063,6 +1069,11 @@ EXPORTS gimp_unit_new gimp_update_metadata gimp_user_time + gimp_vector_layer_discard + gimp_vector_layer_get_by_id + gimp_vector_layer_get_type + gimp_vector_layer_new + gimp_vector_layer_refresh gimp_vector_load_procedure_extract_dimensions gimp_vector_load_procedure_get_type gimp_vector_load_procedure_new diff --git a/libgimp/gimp.h b/libgimp/gimp.h index 840d2efcb4..9b9abfcc00 100644 --- a/libgimp/gimp.h +++ b/libgimp/gimp.h @@ -71,6 +71,7 @@ #include #include #include +#include #include #include diff --git a/libgimp/gimp_pdb_headers.h b/libgimp/gimp_pdb_headers.h index 65ef2e9104..7e4bb5322b 100644 --- a/libgimp/gimp_pdb_headers.h +++ b/libgimp/gimp_pdb_headers.h @@ -82,5 +82,6 @@ #include #include #include +#include #endif /* __GIMP_PDB_HEADERS_H__ */ diff --git a/libgimp/gimpgpparams-body.c b/libgimp/gimpgpparams-body.c index afed740c41..f2b10ace67 100644 --- a/libgimp/gimpgpparams-body.c +++ b/libgimp/gimpgpparams-body.c @@ -284,6 +284,11 @@ _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def) param_def->meta.m_id.none_ok, flags); + if (! strcmp (param_def->type_name, "GimpParamVectorLayer")) + return gimp_param_spec_vector_layer (name, nick, blurb, + param_def->meta.m_id.none_ok, + flags); + if (! strcmp (param_def->type_name, "GimpParamGroupLayer")) return gimp_param_spec_group_layer (name, nick, blurb, param_def->meta.m_id.none_ok, @@ -716,6 +721,10 @@ _gimp_param_spec_to_gp_param_def (GParamSpec *pspec, { type_name = "GimpParamTextLayer"; } + else if (value_type == GIMP_TYPE_VECTOR_LAYER) + { + type_name = "GimpParamVectorLayer"; + } else if (value_type == GIMP_TYPE_GROUP_LAYER) { type_name = "GimpParamGroupLayer"; diff --git a/libgimp/gimpitem_pdb.c b/libgimp/gimpitem_pdb.c index b4c57d2c99..e7672d22f7 100644 --- a/libgimp/gimpitem_pdb.c +++ b/libgimp/gimpitem_pdb.c @@ -211,6 +211,46 @@ gimp_item_id_is_text_layer (gint item_id) return text_layer; } +/** + * gimp_item_id_is_vector_layer: + * @item_id: The item ID. + * + * Returns whether the item ID is a vector layer. + * + * This procedure returns %TRUE if the specified item ID is a vector + * layer. + * + * *Note*: in most use cases, you should not use this function. See + * [func@Gimp.Item.id_is_layer] for a discussion on alternatives. + * + * Returns: TRUE if the item is a vector layer, FALSE otherwise. + * + * Since: 3.2 + **/ +gboolean +gimp_item_id_is_vector_layer (gint item_id) +{ + GimpValueArray *args; + GimpValueArray *return_vals; + gboolean vector_layer = FALSE; + + args = gimp_value_array_new_from_types (NULL, + G_TYPE_INT, item_id, + G_TYPE_NONE); + + return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), + "gimp-item-id-is-vector-layer", + args); + gimp_value_array_unref (args); + + if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS) + vector_layer = GIMP_VALUES_GET_BOOLEAN (return_vals, 1); + + gimp_value_array_unref (return_vals); + + return vector_layer; +} + /** * gimp_item_id_is_group_layer: * @item_id: The item ID. diff --git a/libgimp/gimpitem_pdb.h b/libgimp/gimpitem_pdb.h index 58a858ef4e..0b1bb166c7 100644 --- a/libgimp/gimpitem_pdb.h +++ b/libgimp/gimpitem_pdb.h @@ -36,6 +36,7 @@ gboolean gimp_item_id_is_valid (gint item_id); gboolean gimp_item_id_is_drawable (gint item_id); gboolean gimp_item_id_is_layer (gint item_id); gboolean gimp_item_id_is_text_layer (gint item_id); +gboolean gimp_item_id_is_vector_layer (gint item_id); gboolean gimp_item_id_is_group_layer (gint item_id); gboolean gimp_item_id_is_channel (gint item_id); gboolean gimp_item_id_is_layer_mask (gint item_id); diff --git a/libgimp/gimpparamspecs-body.c b/libgimp/gimpparamspecs-body.c index 60946ff90d..1f388dbd49 100644 --- a/libgimp/gimpparamspecs-body.c +++ b/libgimp/gimpparamspecs-body.c @@ -532,6 +532,86 @@ gimp_param_spec_text_layer (const gchar *name, } +/* + * GIMP_TYPE_PARAM_VECTOR_LAYER + */ + +static void gimp_param_vector_layer_class_init (GParamSpecClass *klass); +static void gimp_param_vector_layer_init (GParamSpec *pspec); + +GType +gimp_param_vector_layer_get_type (void) +{ + static GType type = 0; + + if (! type) + { + const GTypeInfo info = + { + sizeof (GParamSpecClass), + NULL, NULL, + (GClassInitFunc) gimp_param_vector_layer_class_init, + NULL, NULL, + sizeof (GimpParamSpecItem), + 0, + (GInstanceInitFunc) gimp_param_vector_layer_init + }; + + type = g_type_register_static (GIMP_TYPE_PARAM_LAYER, + "GimpParamVectorLayer", &info, 0); + } + + return type; +} + +static void +gimp_param_vector_layer_class_init (GParamSpecClass *klass) +{ + klass->value_type = GIMP_TYPE_VECTOR_LAYER; +} + +static void +gimp_param_vector_layer_init (GParamSpec *pspec) +{ +} + +/** + * gimp_param_spec_vector_layer: + * @name: Canonical name of the property specified. + * @nick: Nick name of the property specified. + * @blurb: Description of the property specified. + * @none_ok: Whether no is a valid value. + * @flags: Flags for the property specified. + * + * Creates a new #GimpParamSpecVectorLayer specifying a + * [type@VectorLayer] property. + * + * See g_param_spec_internal() for details on property names. + * + * Returns: (transfer floating): The newly created #GimpParamSpecVectorLayer. + * + * Since: 3.2 + **/ +GParamSpec * +gimp_param_spec_vector_layer (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags) +{ + GimpParamSpecItem *ispec; + + ispec = g_param_spec_internal (GIMP_TYPE_PARAM_VECTOR_LAYER, + name, nick, blurb, flags); + + g_return_val_if_fail (ispec, NULL); + + ispec->none_ok = none_ok ? TRUE : FALSE; + + return G_PARAM_SPEC (ispec); +} + + /* * GIMP_TYPE_PARAM_GROUP_LAYER */ diff --git a/libgimp/gimpparamspecs.h b/libgimp/gimpparamspecs.h index d5e5ecfdca..1d9b2f2679 100644 --- a/libgimp/gimpparamspecs.h +++ b/libgimp/gimpparamspecs.h @@ -129,6 +129,25 @@ GParamSpec * gimp_param_spec_text_layer (const gchar *name, GParamFlags flags); +/* + * GIMP_TYPE_PARAM_VECTOR_LAYER + */ + +#define GIMP_VALUE_HOLDS_VECTOR_LAYER(value) (G_TYPE_CHECK_VALUE_TYPE ((value),\ + GIMP_TYPE_VECTOR_LAYER)) + +#define GIMP_TYPE_PARAM_VECTOR_LAYER (gimp_param_vector_layer_get_type ()) +#define GIMP_IS_PARAM_SPEC_VECTOR_LAYER(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_VECTOR_LAYER)) + +GType gimp_param_vector_layer_get_type (void) G_GNUC_CONST; + +GParamSpec * gimp_param_spec_vector_layer (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags); + + /* * GIMP_TYPE_PARAM_GROUP_LAYER */ diff --git a/libgimp/gimpplugin.c b/libgimp/gimpplugin.c index 309cfd34d2..21c3d7295e 100644 --- a/libgimp/gimpplugin.c +++ b/libgimp/gimpplugin.c @@ -1801,6 +1801,12 @@ _gimp_plug_in_get_item (GimpPlugIn *plug_in, "id", item_id, NULL); } + else if (gimp_item_id_is_vector_layer (item_id)) + { + item = g_object_new (GIMP_TYPE_VECTOR_LAYER, + "id", item_id, + NULL); + } else if (gimp_item_id_is_group_layer (item_id)) { item = g_object_new (GIMP_TYPE_GROUP_LAYER, diff --git a/libgimp/gimpprocedure-params.c b/libgimp/gimpprocedure-params.c index 48a1dbf8d2..b74aee30a7 100644 --- a/libgimp/gimpprocedure-params.c +++ b/libgimp/gimpprocedure-params.c @@ -1884,6 +1884,84 @@ gimp_procedure_add_text_layer_return_value (GimpProcedure *procedure, none_ok, flags)); } +/** + * gimp_procedure_add_vector_layer_argument: + * @procedure: the #GimpProcedure. + * @name: the name of the argument to be created. + * @nick: the label used in #GimpProcedureDialog. + * @blurb: (nullable): a more detailed help description. + * @none_ok: Whether no is a valid value. + * @flags: argument flags. + * + * Add a new #GimpVectorLayer argument to @procedure. + * + * Since: 3.0 + **/ +void +gimp_procedure_add_vector_layer_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags) +{ + _gimp_procedure_add_argument (procedure, + gimp_param_spec_vector_layer (name, nick, blurb, + none_ok, flags)); +} + +/** + * gimp_procedure_add_vector_layer_aux_argument: + * @procedure: the #GimpProcedure. + * @name: the name of the argument to be created. + * @nick: the label used in #GimpProcedureDialog. + * @blurb: (nullable): a more detailed help description. + * @none_ok: Whether no is a valid value. + * @flags: argument flags. + * + * Add a new #GimpVectorLayer auxiliary argument to @procedure. + * + * Since: 3.0 + **/ +void +gimp_procedure_add_vector_layer_aux_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags) +{ + _gimp_procedure_add_aux_argument (procedure, + gimp_param_spec_vector_layer (name, nick, blurb, + none_ok, flags)); +} + +/** + * gimp_procedure_add_vector_layer_return_value: + * @procedure: the #GimpProcedure. + * @name: the name of the argument to be created. + * @nick: the label used in #GimpProcedureDialog. + * @blurb: (nullable): a more detailed help description. + * @none_ok: Whether no is a valid value. + * @flags: argument flags. + * + * Add a new #GimpVectorLayer return value to @procedure. + * + * Since: 3.0 + **/ +void +gimp_procedure_add_vector_layer_return_value (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags) +{ + _gimp_procedure_add_return_value (procedure, + gimp_param_spec_vector_layer (name, nick, blurb, + none_ok, flags)); +} + /** * gimp_procedure_add_group_layer_argument: * @procedure: the #GimpProcedure. diff --git a/libgimp/gimpprocedure-params.h b/libgimp/gimpprocedure-params.h index e92b09a94f..899d8c5f2f 100644 --- a/libgimp/gimpprocedure-params.h +++ b/libgimp/gimpprocedure-params.h @@ -313,6 +313,18 @@ G_BEGIN_DECLS g_value_set_object (gimp_value_array_index (args, n), value) +/* vector layer */ + +#define GIMP_VALUES_GET_VECTOR_LAYER(args, n) \ + g_value_get_object (gimp_value_array_index (args, n)) + +#define GIMP_VALUES_GET_VECTOR_LAYER_ID(args, n) \ + gimp_item_get_id (g_value_get_object (gimp_value_array_index (args, n))) + +#define GIMP_VALUES_SET_VECTOR_LAYER(args, n, value) \ + g_value_set_object (gimp_value_array_index (args, n), value) + + /* group layer */ #define GIMP_VALUES_GET_GROUP_LAYER(args, n) \ @@ -899,6 +911,25 @@ void gimp_procedure_add_text_layer_return_value (GimpProcedure *procedure gboolean none_ok, GParamFlags flags); +void gimp_procedure_add_vector_layer_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags); +void gimp_procedure_add_vector_layer_aux_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags); +void gimp_procedure_add_vector_layer_return_value (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags); + void gimp_procedure_add_group_layer_argument (GimpProcedure *procedure, const gchar *name, const gchar *nick, diff --git a/libgimp/gimptypes.h b/libgimp/gimptypes.h index e1afbe1541..23da350321 100644 --- a/libgimp/gimptypes.h +++ b/libgimp/gimptypes.h @@ -52,6 +52,7 @@ typedef struct _GimpTextLayer GimpTextLayer; typedef struct _GimpPath GimpPath; typedef struct _GimpDrawableFilter GimpDrawableFilter; typedef struct _GimpDrawableFilterConfig GimpDrawableFilterConfig; +typedef struct _GimpVectorLayer GimpVectorLayer; typedef struct _GimpDisplay GimpDisplay; diff --git a/libgimp/gimpvectorlayer.c b/libgimp/gimpvectorlayer.c new file mode 100644 index 0000000000..dbf3832626 --- /dev/null +++ b/libgimp/gimpvectorlayer.c @@ -0,0 +1,75 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball + * + * gimpvectorlayer.c + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include "gimp.h" + + +struct _GimpVectorLayer +{ + GimpLayer parent_instance; +}; + + + +G_DEFINE_TYPE (GimpVectorLayer, gimp_vector_layer, GIMP_TYPE_LAYER) + +#define parent_class gimp_vector_layer_parent_class + + +static void +gimp_vector_layer_class_init (GimpVectorLayerClass *klass) +{ +} + +static void +gimp_vector_layer_init (GimpVectorLayer *layer) +{ +} + + +/* Public API. */ + +/** + * gimp_vector_layer_get_by_id: + * @layer_id: The layer id. + * + * Returns a #GimpVectorLayer representing @layer_id. This function calls + * gimp_item_get_by_id() and returns the item if it is layer or %NULL + * otherwise. + * + * Returns: (nullable) (transfer none): a #GimpVectorLayer for @layer_id or + * %NULL if @layer_id does not represent a valid layer. The + * object belongs to libgimp and you must not modify or unref + * it. + * + * Since: 3.0 + **/ +GimpVectorLayer * +gimp_vector_layer_get_by_id (gint32 layer_id) +{ + GimpItem *item = gimp_item_get_by_id (layer_id); + + if (GIMP_IS_VECTOR_LAYER (item)) + return (GimpVectorLayer *) item; + + return NULL; +} diff --git a/libgimp/gimpvectorlayer.h b/libgimp/gimpvectorlayer.h new file mode 100644 index 0000000000..b9a9447a7d --- /dev/null +++ b/libgimp/gimpvectorlayer.h @@ -0,0 +1,45 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball + * + * gimpvectorlayer.h + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GIMP_VECTOR_LAYER_H__ +#define __GIMP_VECTOR_LAYER_H__ + +G_BEGIN_DECLS + +/* For information look into the C source or the html documentation */ + + +#include + + +#define GIMP_TYPE_VECTOR_LAYER (gimp_vector_layer_get_type ()) +G_DECLARE_FINAL_TYPE (GimpVectorLayer, gimp_vector_layer, GIMP, VECTOR_LAYER, GimpLayer) + + +GimpVectorLayer * gimp_vector_layer_get_by_id (gint32 layer_id); + + +G_END_DECLS + +#endif /* __GIMP_VECTOR_LAYER_H__ */ diff --git a/libgimp/gimpvectorlayer_pdb.c b/libgimp/gimpvectorlayer_pdb.c new file mode 100644 index 0000000000..0b748ca53b --- /dev/null +++ b/libgimp/gimpvectorlayer_pdb.c @@ -0,0 +1,159 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball + * + * gimpvectorlayer_pdb.c + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +/* NOTE: This file is auto-generated by pdbgen.pl */ + +#include "config.h" + +#include "stamp-pdbgen.h" + +#include "gimp.h" + + +/** + * SECTION: gimpvectorlayer + * @title: gimpvectorlayer + * @short_description: Functions for querying and manipulating vector layers. + * + * Functions for querying and manipulating vector layers. + **/ + + +/** + * gimp_vector_layer_new: + * @image: The image. + * @path: The path to create the layer from. + * + * Creates a new vector layer. + * + * This procedure creates a new path layer displaying the specified + * @path. By default, the fill and stroke properties will be defined by + * the context. + * + * The new layer still needs to be added to the image as this is not + * automatic. Add the new layer with the [method@Image.insert_layer] + * method. + * + * The arguments are kept as simple as necessary for the basic case. + * All vector attributes, however, can be modified with the appropriate + * `gimp_vector_layer_set_*()` procedures. + * + * Returns: (transfer none): + * The new vector layer. The object belongs to libgimp and you should not free it. + * + * Since: 3.2 + **/ +GimpVectorLayer * +gimp_vector_layer_new (GimpImage *image, + GimpPath *path) +{ + GimpValueArray *args; + GimpValueArray *return_vals; + GimpVectorLayer *layer = NULL; + + args = gimp_value_array_new_from_types (NULL, + GIMP_TYPE_IMAGE, image, + GIMP_TYPE_PATH, path, + G_TYPE_NONE); + + return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), + "gimp-vector-layer-new", + args); + gimp_value_array_unref (args); + + if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS) + layer = GIMP_VALUES_GET_VECTOR_LAYER (return_vals, 1); + + gimp_value_array_unref (return_vals); + + return layer; +} + +/** + * gimp_vector_layer_refresh: + * @layer: The vector layer. + * + * Rerender the vector layer + * + * This procedure causes the vector layer to refresh itself after + * changes. + * + * Returns: TRUE on success. + * + * Since: 3.2 + **/ +gboolean +gimp_vector_layer_refresh (GimpVectorLayer *layer) +{ + GimpValueArray *args; + GimpValueArray *return_vals; + gboolean success = TRUE; + + args = gimp_value_array_new_from_types (NULL, + GIMP_TYPE_VECTOR_LAYER, layer, + G_TYPE_NONE); + + return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), + "gimp-vector-layer-refresh", + args); + gimp_value_array_unref (args); + + success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS; + + gimp_value_array_unref (return_vals); + + return success; +} + +/** + * gimp_vector_layer_discard: + * @layer: The vector layer. + * + * Discard the vector layer information. + * + * Discards the vector information. This makes the layer behave like a + * normal layer. + * + * Returns: TRUE on success. + * + * Since: 3.2 + **/ +gboolean +gimp_vector_layer_discard (GimpVectorLayer *layer) +{ + GimpValueArray *args; + GimpValueArray *return_vals; + gboolean success = TRUE; + + args = gimp_value_array_new_from_types (NULL, + GIMP_TYPE_VECTOR_LAYER, layer, + G_TYPE_NONE); + + return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), + "gimp-vector-layer-discard", + args); + gimp_value_array_unref (args); + + success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS; + + gimp_value_array_unref (return_vals); + + return success; +} diff --git a/libgimp/gimpvectorlayer_pdb.h b/libgimp/gimpvectorlayer_pdb.h new file mode 100644 index 0000000000..0424adc343 --- /dev/null +++ b/libgimp/gimpvectorlayer_pdb.h @@ -0,0 +1,43 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball + * + * gimpvectorlayer_pdb.h + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +/* NOTE: This file is auto-generated by pdbgen.pl */ + +#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GIMP_VECTOR_LAYER_PDB_H__ +#define __GIMP_VECTOR_LAYER_PDB_H__ + +G_BEGIN_DECLS + +/* For information look into the C source or the html documentation */ + + +GimpVectorLayer* gimp_vector_layer_new (GimpImage *image, + GimpPath *path); +gboolean gimp_vector_layer_refresh (GimpVectorLayer *layer); +gboolean gimp_vector_layer_discard (GimpVectorLayer *layer); + + +G_END_DECLS + +#endif /* __GIMP_VECTOR_LAYER_PDB_H__ */ diff --git a/libgimp/meson.build b/libgimp/meson.build index e1915765cd..6e1d974e10 100644 --- a/libgimp/meson.build +++ b/libgimp/meson.build @@ -114,6 +114,7 @@ pdb_wrappers_sources = [ 'gimptextlayer_pdb.c', 'gimptexttool_pdb.c', 'gimpunit_pdb.c', + 'gimpvectorlayer_pdb.c', ] pdb_wrappers_headers = [ @@ -173,6 +174,7 @@ pdb_wrappers_headers = [ 'gimptextlayer_pdb.h', 'gimptexttool_pdb.h', 'gimpunit_pdb.h', + 'gimpvectorlayer_pdb.h', ] libgimp_sources_introspectable = [ @@ -214,6 +216,7 @@ libgimp_sources_introspectable = [ 'gimpselection.c', 'gimptextlayer.c', 'gimpthumbnailprocedure.c', + 'gimpvectorlayer.c', 'gimpvectorloadprocedure.c', gimpenums, pdb_wrappers_sources, @@ -276,6 +279,7 @@ libgimp_headers_introspectable = [ 'gimpselection.h', 'gimptextlayer.h', 'gimpthumbnailprocedure.h', + 'gimpvectorlayer.h', 'gimpvectorloadprocedure.h', pdb_wrappers_headers, ] diff --git a/pdb/app.pl b/pdb/app.pl index c4de9552af..133bc70ab1 100644 --- a/pdb/app.pl +++ b/pdb/app.pl @@ -381,6 +381,16 @@ gimp_param_spec_text_layer ("$name", "$blurb", $none_ok, $flags) +CODE + } + elsif ($pdbtype eq 'vector_layer') { + $none_ok = exists $arg->{none_ok} ? 'TRUE' : 'FALSE'; + $pspec = < 'item_id', type => 'int32', + desc => 'The item ID' } + ); + + @outargs = ( + { name => 'vector_layer', type => 'boolean', + desc => 'TRUE if the item is a vector layer, FALSE otherwise.' } + ); + + %invoke = ( + code => <<'CODE' +{ + GimpItem *item = gimp_item_get_by_id (gimp, item_id); + + vector_layer = (GIMP_IS_LAYER (item) && + ! gimp_item_is_removed (item) && + gimp_item_is_vector_layer (item)); +} +CODE + ); +} + sub item_id_is_group_layer { $blurb = 'Returns whether the item ID is a group layer.'; @@ -1056,7 +1092,8 @@ CODE "core/gimplayermask.h" "core/gimplist.h" "core/gimpselection.h" - "path/gimppath.h" + "path/gimppath.h" + "path/gimpvectorlayer.h" "text/gimptextlayer.h" "gimppdb-utils.h" "gimppdbcontext.h" @@ -1066,6 +1103,7 @@ CODE item_id_is_drawable item_id_is_layer item_id_is_text_layer + item_id_is_vector_layer item_id_is_group_layer item_id_is_channel item_id_is_layer_mask diff --git a/pdb/groups/vector_layer.pdb b/pdb/groups/vector_layer.pdb new file mode 100644 index 0000000000..607be35eb8 --- /dev/null +++ b/pdb/groups/vector_layer.pdb @@ -0,0 +1,144 @@ +# GIMP - The GNU Image Manipulation Program +# Copyright (C) 1995 Spencer Kimball and Peter Mattis + +# New Vector Layer PDB API + +# 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 . + + +sub vector_layer_new { + $blurb = 'Creates a new vector layer.'; + + $help = <<'HELP'; +This procedure creates a new path layer displaying the specified @path. By +default, the fill and stroke properties will be defined by the context. + + +The new layer still needs to be added to the image as this is not +automatic. Add the new layer with the [method@Image.insert_layer] +method. + + +The arguments are kept as simple as necessary for the basic case. All +vector attributes, however, can be modified with the appropriate +`gimp_vector_layer_set_*()` procedures. +HELP + + &alxsa_pdb_misc('2025', '3.2'); + + @inargs = ( + { name => 'image', type => 'image', + desc => 'The image' }, + { name => 'path', type => 'path', + desc => 'The path to create the layer from' } + ); + + @outargs = ( + { name => 'layer', type => 'vector_layer', + desc => 'The new vector layer. The object belongs to libgimp and you should not free it.' } + ); + + %invoke = ( + code => <<'CODE' +{ + if (path == NULL) + { + g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT, + _("Failed to create vector layer")); + + success = FALSE; + } + + if (success) + { + layer = GIMP_VECTOR_LAYER (gimp_vector_layer_new (image, path, context)); + + if (! layer) + { + g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT, + _("Failed to create vector layer")); + + success = FALSE; + } + } +} +CODE + ); +} + +sub vector_layer_refresh { + $blurb = 'Rerender the vector layer'; + + $help = <<'HELP'; +This procedure causes the vector layer to refresh itself after changes. +HELP + + &alxsa_pdb_misc('2025', '3.2'); + + @inargs = ( + { name => 'layer', type => 'vector_layer', + desc => 'The vector layer' } + ); + + %invoke = ( + code => <<'CODE' +{ + gimp_vector_layer_refresh (layer); +} +CODE + ); +} + +sub vector_layer_discard { + $blurb = 'Discard the vector layer information.'; + + $help = <<'HELP'; +Discards the vector information. This makes the layer behave like a normal layer. +HELP + + &alxsa_pdb_misc('2025', '3.2'); + + @inargs = ( + { name => 'layer', type => 'vector_layer', + desc => 'The vector layer' } + ); + + %invoke = ( + code => <<'CODE' +{ + gimp_vector_layer_discard (layer); +} +CODE + ); +} + +@headers = qw("libgimpbase/gimpbase.h" + "core/gimpcontext.h" + "path/gimpvectorlayer.h" + "gimppdb-utils.h" + "gimppdberror.h" + "gimp-intl.h"); + +@procs = qw(vector_layer_new + vector_layer_refresh + vector_layer_discard); + +%exports = (app => [@procs], lib => [@procs]); + +$desc = 'Vector layer procedures'; +$doc_title = 'gimpvectorlayer'; +$doc_short_desc = 'Functions for querying and manipulating vector layers.'; +$doc_long_desc = 'Functions for querying and manipulating vector layers.'; + +1; diff --git a/pdb/meson.build b/pdb/meson.build index 0ec68d25b9..d0c0a5f20c 100644 --- a/pdb/meson.build +++ b/pdb/meson.build @@ -59,6 +59,7 @@ pdb_names = [ 'text_layer', 'text_tool', 'unit', + 'vector_layer', ] pdb_sources = [] diff --git a/pdb/pdb.pl b/pdb/pdb.pl index 68fd0fe1c8..aa8591d575 100644 --- a/pdb/pdb.pl +++ b/pdb/pdb.pl @@ -371,6 +371,18 @@ package Gimp::CodeGen::pdb; take_value_func => 'g_value_set_object ($value, $var)', headers => [ qw("text/gimptextlayer.h") ] }, + vector_layer => { name => 'VECTOR_LAYER', + gtype => 'GIMP_TYPE_VECTOR_LAYER', + type => 'GimpVectorLayer *', + const_type => 'GimpVectorLayer *', + init_value => 'NULL', + out_annotate => '(transfer none)', + get_value_func => '$var = g_value_get_object ($value)', + dup_value_func => '$var = GIMP_VALUES_GET_VECTOR_LAYER ($value)', + set_value_func => 'g_value_set_object ($value, $var)', + take_value_func => 'g_value_set_object ($value, $var)', + headers => [ qw("path/gimpvectorlayer.h") ] }, + group_layer => { name => 'GROUP_LAYER', gtype => 'GIMP_TYPE_GROUP_LAYER', type => 'GimpGroupLayer *',