diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c index 1153737a2d..be16535ca2 100644 --- a/app/actions/layers-actions.c +++ b/app/actions/layers-actions.c @@ -33,6 +33,8 @@ #include "text/gimptextlayer.h" +#include "vectors/gimpvectorlayer.h" + #include "widgets/gimphelp-ids.h" #include "widgets/gimpactiongroup.h" #include "widgets/gimpwidgets-utils.h" @@ -60,6 +62,12 @@ static const GimpActionEntry layers_actions[] = layers_edit_text_cmd_callback, GIMP_HELP_LAYER_EDIT }, +{ "layers-edit-vector", GIMP_ICON_TOOL_PATH, + N_("Path Tool"), NULL, { NULL }, + N_("Activate the path tool on this vector layer's path"), + layers_edit_vector_cmd_callback, + GIMP_HELP_TOOL_PATH }, + { "layers-edit-attributes", GIMP_ICON_EDIT, NC_("layers-action", "_Edit Layer Attributes..."), NULL, { NULL }, NC_("layers-action", "Edit the layer's name"), @@ -191,6 +199,18 @@ static const GimpActionEntry layers_actions[] = layers_text_along_vectors_cmd_callback, GIMP_HELP_LAYER_TEXT_ALONG_PATH }, + { "layers-vector-fill-stroke", NULL, + NC_("layers-action", "Fill / Stroke"), NULL, { NULL }, + NC_("layers-action", "Edit the fill and stroke of this vector layer"), + layers_vector_fill_stroke_cmd_callback, + NULL }, + + { "layers-vector-discard", NULL, + NC_("layers-action", "Discard Vector Information"), NULL, { NULL }, + NC_("layers-action", "Turn this vector layer into a normal layer"), + layers_vector_discard_cmd_callback, + NULL }, + { "layers-resize", GIMP_ICON_OBJECT_RESIZE, NC_("layers-action", "Layer B_oundary Size..."), NULL, { NULL }, NC_("layers-action", "Adjust the layer dimensions"), @@ -757,6 +777,7 @@ layers_actions_update (GimpActionGroup *group, gboolean lock_alpha = TRUE; gboolean can_lock_alpha = FALSE; gboolean text_layer = FALSE; + gboolean vector_layer = FALSE; gboolean bs_mutable = FALSE; /* At least 1 selected layers' blend space is mutable. */ gboolean cs_mutable = FALSE; /* At least 1 selected layers' composite space is mutable. */ gboolean cm_mutable = FALSE; /* At least 1 selected layers' composite mode is mutable. */ @@ -977,7 +998,8 @@ layers_actions_update (GimpActionGroup *group, gimp_action_group_set_action_active (group, action, TRUE); - text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer)); + text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer)); + vector_layer = gimp_item_is_vector_layer (GIMP_ITEM (layer)); } } @@ -993,6 +1015,7 @@ layers_actions_update (GimpActionGroup *group, SET_SENSITIVE ("layers-edit", !ac && ((layer && !fs) || text_layer)); SET_VISIBLE ("layers-edit-text", text_layer && !ac); SET_SENSITIVE ("layers-edit-text", text_layer && !ac); + SET_VISIBLE ("layers-edit-vector", vector_layer && !ac); SET_SENSITIVE ("layers-edit-attributes", layer && !fs && !ac); if (layer && gimp_layer_is_floating_sel (layer)) @@ -1042,6 +1065,9 @@ layers_actions_update (GimpActionGroup *group, SET_VISIBLE ("layers-text-to-vectors", n_text_layers > 0 && !ac); SET_VISIBLE ("layers-text-along-vectors", text_layer && !ac); + SET_VISIBLE ("layers-vector-fill-stroke", vector_layer && !ac); + SET_VISIBLE ("layers-vector-discard", vector_layer && !ac); + SET_SENSITIVE ("layers-resize", n_selected_layers == 1 && all_writable && all_movable && !ac); SET_SENSITIVE ("layers-resize-to-image", all_writable && all_movable && !ac); SET_SENSITIVE ("layers-scale", n_selected_layers == 1 && all_writable && all_movable && !ac); diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index bde74e484a..8bf4d6b429 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -62,6 +62,8 @@ #include "vectors/gimppath.h" #include "vectors/gimppath-warp.h" #include "vectors/gimpstroke.h" +#include "vectors/gimpvectorlayer.h" +#include "vectors/gimpvectorlayeroptions.h" #include "widgets/gimpaction.h" #include "widgets/gimpdock.h" @@ -73,6 +75,7 @@ #include "display/gimpimagewindow.h" #include "tools/gimptexttool.h" +#include "tools/gimpvectortool.h" #include "tools/tool_manager.h" #include "dialogs/dialogs.h" @@ -80,6 +83,7 @@ #include "dialogs/layer-options-dialog.h" #include "dialogs/resize-dialog.h" #include "dialogs/scale-dialog.h" +#include "dialogs/vector-layer-options-dialog.h" #include "actions.h" #include "items-commands.h" @@ -200,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); @@ -251,6 +259,52 @@ layers_edit_text_cmd_callback (GimpAction *action, } } +void +layers_edit_vector_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data) +{ + GimpImage *image; + GimpLayer *layer; + GList *layers; + GtkWidget *widget; + GimpTool *active_tool; + return_if_no_layers (image, layers, data); + return_if_no_widget (widget, data); + + if (g_list_length (layers) != 1) + return; + + layer = layers->data; + + if (! gimp_item_is_vector_layer (GIMP_ITEM (layer))) + { + layers_edit_attributes_cmd_callback (action, value, data); + return; + } + + active_tool = tool_manager_get_active (image->gimp); + + if (! GIMP_IS_VECTOR_TOOL (active_tool)) + { + GimpToolInfo *tool_info; + + tool_info = (GimpToolInfo *) + gimp_container_get_child_by_name (image->gimp->tool_info_list, + "gimp-vector-tool"); + + if (GIMP_IS_TOOL_INFO (tool_info)) + { + gimp_context_set_tool (action_data_get_context (data), tool_info); + active_tool = tool_manager_get_active (image->gimp); + } + } + + if (GIMP_IS_VECTOR_TOOL (active_tool)) + gimp_vector_tool_set_vectors (GIMP_VECTOR_TOOL (active_tool), + GIMP_VECTOR_LAYER (layer)->options->path); +} + void layers_edit_attributes_cmd_callback (GimpAction *action, GVariant *value, @@ -2591,6 +2645,56 @@ layers_scale_callback (GtkWidget *dialog, } } +void +layers_vector_fill_stroke_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data) +{ + GimpImage *image; + GimpLayer *layer; + GList *layers; + GtkWidget *widget; + return_if_no_layers (image, layers, data); + return_if_no_widget (widget, data); + + if (g_list_length (layers) != 1) + return; + + layer = layers->data; + + if (GIMP_IS_VECTOR_LAYER (layer)) + { + GtkWidget *dialog; + + dialog = vector_layer_options_dialog_new (GIMP_VECTOR_LAYER (layer), + action_data_get_context (data), + _("Fill / Stroke"), + "gimp-vector-layer-stroke", + NULL, + widget); + gtk_widget_show (dialog); + } +} + +void +layers_vector_discard_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data) +{ + GimpImage *image; + GimpLayer *layer; + GList *layers; + return_if_no_layers (image, layers, data); + + if (g_list_length (layers) != 1) + return; + + layer = layers->data; + + if (GIMP_IS_VECTOR_LAYER (layer)) + gimp_vector_layer_discard (GIMP_VECTOR_LAYER (layer)); +} + static void layers_resize_callback (GtkWidget *dialog, GimpViewable *viewable, diff --git a/app/actions/layers-commands.h b/app/actions/layers-commands.h index 6e28d641e5..f29fd7b3e3 100644 --- a/app/actions/layers-commands.h +++ b/app/actions/layers-commands.h @@ -25,6 +25,9 @@ void layers_edit_cmd_callback (GimpAction *action, void layers_edit_text_cmd_callback (GimpAction *action, GVariant *value, gpointer data); +void layers_edit_vector_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data); void layers_edit_attributes_cmd_callback (GimpAction *action, GVariant *value, gpointer data); @@ -84,6 +87,12 @@ void layers_text_to_vectors_cmd_callback (GimpAction *action, void layers_text_along_vectors_cmd_callback (GimpAction *action, GVariant *value, gpointer data); +void layers_vector_fill_stroke_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data); +void layers_vector_discard_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data); void layers_resize_cmd_callback (GimpAction *action, GVariant *value, diff --git a/app/actions/paths-actions.c b/app/actions/paths-actions.c index 3d3c1ff58c..8a1366995e 100644 --- a/app/actions/paths-actions.c +++ b/app/actions/paths-actions.c @@ -149,7 +149,12 @@ static const GimpActionEntry paths_actions[] = { "paths-import", GIMP_ICON_DOCUMENT_OPEN, NC_("paths-action", "I_mport Path..."), NULL, { NULL }, NULL, paths_import_cmd_callback, - GIMP_HELP_PATH_IMPORT } + GIMP_HELP_PATH_IMPORT }, + + { "paths-to-vector-layer", NULL, + NC_("paths-action", "Path to Vector Layer"), NULL, { NULL }, NULL, + path_to_vector_layer_cmd_callback, + NULL }, }; static const GimpToggleActionEntry paths_toggle_actions[] = @@ -429,6 +434,8 @@ paths_actions_update (GimpActionGroup *group, SET_SENSITIVE ("paths-export", n_selected_paths > 0); SET_SENSITIVE ("paths-import", image); + SET_SENSITIVE ("paths-to-vector-layer", n_selected_paths > 0); + SET_SENSITIVE ("paths-selection-to-path", image && !mask_empty); SET_SENSITIVE ("paths-selection-to-path-advanced", image && !mask_empty); SET_SENSITIVE ("paths-fill", n_selected_paths > 0 && diff --git a/app/actions/paths-commands.c b/app/actions/paths-commands.c index d273f42c55..a85f29b6e5 100644 --- a/app/actions/paths-commands.c +++ b/app/actions/paths-commands.c @@ -47,6 +47,7 @@ #include "vectors/gimppath.h" #include "vectors/gimppath-export.h" #include "vectors/gimppath-import.h" +#include "vectors/gimpvectorlayer.h" #include "widgets/gimpaction.h" #include "widgets/gimpclipboard.h" @@ -509,6 +510,28 @@ paths_merge_visible_cmd_callback (GimpAction *action, gimp_image_flush (image); } +void +path_to_vector_layer_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data) +{ + GimpImage *image; + GList *paths; + GimpVectorLayer *layer; + return_if_no_paths (image, paths, data); + + layer = gimp_vector_layer_new (image, paths->data, + gimp_get_user_context (image->gimp)); + gimp_image_add_layer (image, + GIMP_LAYER (layer), + GIMP_IMAGE_ACTIVE_PARENT, + -1, + TRUE); + gimp_vector_layer_refresh (layer); + + gimp_image_flush (image); +} + void paths_to_selection_cmd_callback (GimpAction *action, GVariant *value, diff --git a/app/actions/paths-commands.h b/app/actions/paths-commands.h index 8d071f93d4..5ea6fc2cb1 100644 --- a/app/actions/paths-commands.h +++ b/app/actions/paths-commands.h @@ -51,6 +51,9 @@ void paths_duplicate_cmd_callback (GimpAction *action, void paths_delete_cmd_callback (GimpAction *action, GVariant *value, gpointer data); +void path_to_vector_layer_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data); void paths_merge_visible_cmd_callback (GimpAction *action, GVariant *value, gpointer data); 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 5db3dfd541..f84626986b 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -621,6 +621,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 468146e13a..7d723fc95c 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -60,6 +60,8 @@ #include "vectors/gimppathmodundo.h" #include "vectors/gimppathpropundo.h" #include "vectors/gimppathundo.h" +#include "vectors/gimpvectorlayer.h" +#include "vectors/gimpvectorlayerundo.h" #include "gimp-intl.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 c13850ce98..8c7f7497d3 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -216,6 +216,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/dialogs/meson.build b/app/dialogs/meson.build index 2555e12752..f70c7926c6 100644 --- a/app/dialogs/meson.build +++ b/app/dialogs/meson.build @@ -56,6 +56,7 @@ libappdialogs_sources = [ 'tips-dialog.c', 'tips-parser.c', 'user-install-dialog.c', + 'vector-layer-options-dialog.c', 'welcome-dialog.c', gitversion_h, welcome_dialog_data_c, diff --git a/app/dialogs/vector-layer-options-dialog.c b/app/dialogs/vector-layer-options-dialog.c new file mode 100644 index 0000000000..d5bbd7dc3a --- /dev/null +++ b/app/dialogs/vector-layer-options-dialog.c @@ -0,0 +1,301 @@ +/* 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/gimpcontainercombobox.h" +#include "widgets/gimpcontainerview.h" +#include "widgets/gimppropwidgets.h" +#include "widgets/gimpviewabledialog.h" +#include "widgets/gimpstrokeeditor.h" + +#include "vectors/gimppath.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); +static void vector_layer_options_dialog_path_selected (GtkWidget *widget, + GList *items, + GList *paths, + 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, + _("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); + + + 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_select_item (GIMP_CONTAINER_VIEW (combo), + GIMP_VIEWABLE (saved_options->path)); + g_signal_connect_object (combo, "select-items", + 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; + + 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; + 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) + { + 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 (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 (GtkWidget *widget, + GList *items, + GList *paths, + GtkWidget *dialog) +{ + GimpPath *path = NULL; + GimpVectorLayer *layer; + + layer = g_object_get_data (G_OBJECT (dialog), "layer"); + + if (items) + path = items->data; + + 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 new file mode 100644 index 0000000000..c7294366f7 --- /dev/null +++ b/app/dialogs/vector-layer-options-dialog.h @@ -0,0 +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__ */ diff --git a/app/tools/gimpvectoroptions.c b/app/tools/gimpvectoroptions.c index 01dd3f7ff5..aed1ed071b 100644 --- a/app/tools/gimpvectoroptions.c +++ b/app/tools/gimpvectoroptions.c @@ -192,7 +192,7 @@ gimp_vector_options_gui (GimpToolOptions *tool_options) gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive (button, FALSE); gimp_help_set_help_data (button, str, GIMP_HELP_PATH_SELECTION_REPLACE); - gtk_widget_show (button); + gtk_widget_set_visible (button, TRUE); g_free (str); @@ -202,7 +202,7 @@ gimp_vector_options_gui (GimpToolOptions *tool_options) 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_show (button); + gtk_widget_set_visible (button, TRUE); options->fill_button = button; @@ -210,9 +210,17 @@ gimp_vector_options_gui (GimpToolOptions *tool_options) 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_show (button); + gtk_widget_set_visible (button, TRUE); options->stroke_button = button; + button = gtk_button_new_with_label (_("Create 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); + gtk_widget_set_visible (button, TRUE); + + options->vector_layer_button = button; + return vbox; } diff --git a/app/tools/gimpvectoroptions.h b/app/tools/gimpvectoroptions.h index e13e8f3207..a69d3a3d4c 100644 --- a/app/tools/gimpvectoroptions.h +++ b/app/tools/gimpvectoroptions.h @@ -44,6 +44,7 @@ struct _GimpVectorOptions GtkWidget *to_selection_button; GtkWidget *fill_button; GtkWidget *stroke_button; + GtkWidget *vector_layer_button; }; diff --git a/app/tools/gimpvectortool.c b/app/tools/gimpvectortool.c index 7bf9c60e47..0eb25cb800 100644 --- a/app/tools/gimpvectortool.c +++ b/app/tools/gimpvectortool.c @@ -41,6 +41,8 @@ #include "paint/gimppaintoptions.h" /* GIMP_PAINT_OPTIONS_CONTEXT_MASK */ #include "vectors/gimppath.h" +#include "vectors/gimpvectorlayer.h" +#include "vectors/gimpvectorlayeroptions.h" #include "widgets/gimpdialogfactory.h" #include "widgets/gimpdockcontainer.h" @@ -70,6 +72,7 @@ /* local function prototypes */ +static void gimp_vector_tool_constructed (GObject *object); static void gimp_vector_tool_dispose (GObject *object); static void gimp_vector_tool_control (GimpTool *tool, @@ -106,6 +109,12 @@ static void gimp_vector_tool_start (GimpVectorTool *vector_ GimpDisplay *display); static void gimp_vector_tool_halt (GimpVectorTool *vector_tool); +static void gimp_vector_tool_image_changed (GimpVectorTool *vector_tool, + GimpImage *image, + GimpContext *context); +static void gimp_vector_tool_image_selected_layers_changed + (GimpVectorTool *vector_tool); + static void gimp_vector_tool_path_changed (GimpToolWidget *path, GimpVectorTool *vector_tool); static void gimp_vector_tool_path_begin_change @@ -147,6 +156,10 @@ static void gimp_vector_tool_stroke_callback (GtkWidget *dialog, GimpStrokeOptions *options, gpointer data); +static void gimp_vector_tool_create_vector_layer + (GimpVectorTool *vector_tool, + GtkWidget *button); + G_DEFINE_TYPE (GimpVectorTool, gimp_vector_tool, GIMP_TYPE_DRAW_TOOL) @@ -178,6 +191,7 @@ gimp_vector_tool_class_init (GimpVectorToolClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass); + object_class->constructed = gimp_vector_tool_constructed; object_class->dispose = gimp_vector_tool_dispose; tool_class->control = gimp_vector_tool_control; @@ -202,6 +216,29 @@ gimp_vector_tool_init (GimpVectorTool *vector_tool) vector_tool->saved_mode = GIMP_VECTOR_MODE_DESIGN; } +static void +gimp_vector_tool_constructed (GObject *object) +{ + GimpVectorTool *vector_tool = GIMP_VECTOR_TOOL (object); + GimpContext *context; + GimpToolInfo *tool_info; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + tool_info = GIMP_TOOL (vector_tool)->tool_info; + + context = gimp_get_user_context (tool_info->gimp); + + g_signal_connect_object (context, "image-changed", + G_CALLBACK (gimp_vector_tool_image_changed), + vector_tool, G_CONNECT_SWAPPED); + + gimp_vector_tool_image_changed (vector_tool, + gimp_context_get_image (context), + context); +} + + static void gimp_vector_tool_dispose (GObject *object) { @@ -210,6 +247,8 @@ gimp_vector_tool_dispose (GObject *object) gimp_vector_tool_set_vectors (vector_tool, NULL); g_clear_object (&vector_tool->widget); + gimp_vector_tool_image_changed (vector_tool, NULL, NULL); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -444,6 +483,51 @@ gimp_vector_tool_halt (GimpVectorTool *vector_tool) tool->display = NULL; } +static void +gimp_vector_tool_image_changed (GimpVectorTool *vector_tool, + GimpImage *image, + GimpContext *context) +{ + if (vector_tool->current_image) + g_signal_handlers_disconnect_by_func (vector_tool->current_image, + gimp_vector_tool_image_selected_layers_changed, + NULL); + + g_set_weak_pointer (&vector_tool->current_image, image); + + if (vector_tool->current_image) + g_signal_connect_object (vector_tool->current_image, "selected-layers-changed", + G_CALLBACK (gimp_vector_tool_image_selected_layers_changed), + vector_tool, G_CONNECT_SWAPPED); + + gimp_vector_tool_image_selected_layers_changed (vector_tool); +} + +static void +gimp_vector_tool_image_selected_layers_changed (GimpVectorTool *vector_tool) +{ + GList *current_layers = NULL; + + if (vector_tool->current_image) + current_layers = + gimp_image_get_selected_layers (vector_tool->current_image); + + if (current_layers) + { + /* If we've selected a single vector layer, make its path editable */ + if (g_list_length (current_layers) == 1 && + GIMP_IS_VECTOR_LAYER (current_layers->data)) + { + GimpVectorLayer *vector_layer = current_layers->data; + + if (vector_layer->options && vector_layer->options->path) + gimp_vector_tool_set_vectors (vector_tool, + vector_layer->options->path); + } + } +} + + static void gimp_vector_tool_path_changed (GimpToolWidget *path, GimpVectorTool *vector_tool) @@ -609,6 +693,14 @@ gimp_vector_tool_set_vectors (GimpVectorTool *vector_tool, gimp_vector_tool_stroke_vectors, tool); } + + if (options->vector_layer_button) + { + gtk_widget_set_sensitive (options->vector_layer_button, FALSE); + g_signal_handlers_disconnect_by_func (options->vector_layer_button, + gimp_vector_tool_create_vector_layer, + tool); + } } if (! vectors || @@ -657,6 +749,15 @@ gimp_vector_tool_set_vectors (GimpVectorTool *vector_tool, gtk_widget_set_sensitive (options->stroke_button, TRUE); } + if (options->vector_layer_button) + { + g_signal_connect_swapped (options->vector_layer_button, "clicked", + G_CALLBACK (gimp_vector_tool_create_vector_layer), + tool); + + gtk_widget_set_sensitive (options->vector_layer_button, TRUE); + } + if (tool->display) { gimp_tool_path_set_vectors (GIMP_TOOL_PATH (vector_tool->widget), vectors); @@ -898,3 +999,30 @@ gimp_vector_tool_stroke_callback (GtkWidget *dialog, gimp_image_flush (image); gtk_widget_destroy (dialog); } + + +static void +gimp_vector_tool_create_vector_layer (GimpVectorTool *vector_tool, + GtkWidget *button) +{ + GimpImage *image; + GimpVectorLayer *layer; + + if (! vector_tool->vectors) + return; + + image = gimp_item_get_image (GIMP_ITEM (vector_tool->vectors)); + + layer = gimp_vector_layer_new (image, vector_tool->vectors, + gimp_get_user_context (image->gimp)); + + gimp_image_add_layer (image, + GIMP_LAYER (layer), + GIMP_IMAGE_ACTIVE_PARENT, + -1, + TRUE); + + gimp_vector_layer_refresh (layer); + + gimp_image_flush (image); +} diff --git a/app/tools/gimpvectortool.h b/app/tools/gimpvectortool.h index d08910e216..05316147ed 100644 --- a/app/tools/gimpvectortool.h +++ b/app/tools/gimpvectortool.h @@ -42,6 +42,8 @@ struct _GimpVectorTool { GimpDrawTool parent_instance; + GimpImage *current_image; + GimpPath *vectors; /* the current Path data */ GimpVectorMode saved_mode; /* used by modifier_key() */ diff --git a/app/vectors/gimpvectorlayer-xcf.c b/app/vectors/gimpvectorlayer-xcf.c new file mode 100644 index 0000000000..6b5637db63 --- /dev/null +++ b/app/vectors/gimpvectorlayer-xcf.c @@ -0,0 +1,171 @@ +/* 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 "vectors-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/vectors/gimpvectorlayer-xcf.h b/app/vectors/gimpvectorlayer-xcf.h new file mode 100644 index 0000000000..5757c7baa3 --- /dev/null +++ b/app/vectors/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/vectors/gimpvectorlayer.c b/app/vectors/gimpvectorlayer.c new file mode 100644 index 0000000000..a1ba0901c2 --- /dev/null +++ b/app/vectors/gimpvectorlayer.c @@ -0,0 +1,712 @@ +/* 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 "vectors-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, + GimpPath *path); +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"; + + 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->default_name = _("Vector Layer"); + 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)); + + 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); + gint x, y; + + if (vector_layer->options && vector_layer->options->path) + gimp_item_translate (GIMP_ITEM (vector_layer->options->path), + offset_x, offset_y, FALSE); + + /* Correct offset for vector layer after moving path */ + gimp_item_get_offset (GIMP_ITEM (layer), &x, &y); + + x += offset_x; + y += offset_y; + + gimp_item_set_offset (GIMP_ITEM (layer), x, 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); + } +} + +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); + } +} + +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); + } +} + +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); + } +} + +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 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); + + layer = + GIMP_VECTOR_LAYER (gimp_drawable_new (GIMP_TYPE_VECTOR_LAYER, + image, NULL, + 0, 0, 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; +} + +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); +} + +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); + GimpItem *item = GIMP_ITEM (layer); + GimpImage *image = gimp_item_get_image (item); + + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); + + g_object_freeze_notify (G_OBJECT (drawable)); + + /* 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, layer->options->path); + + g_object_thaw_notify (G_OBJECT (drawable)); + + return TRUE; +} + +static void +gimp_vector_layer_render_path (GimpVectorLayer *layer, + GimpPath *path) +{ + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + GimpChannel *selection = gimp_image_get_mask (image); + GList *drawables; + GimpCustomStyle style; + + /* 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 (layer->options->fill_options); + if (style == GIMP_CUSTOM_STYLE_SOLID_COLOR || + ! gimp_context_get_pattern (GIMP_CONTEXT (layer->options->fill_options))) + gimp_fill_options_set_style (layer->options->fill_options, + GIMP_FILL_STYLE_FG_COLOR); + else + gimp_fill_options_set_style (layer->options->fill_options, + GIMP_FILL_STYLE_PATTERN); + + style = + gimp_fill_options_get_custom_style (GIMP_FILL_OPTIONS (layer->options->stroke_options)); + if (style == GIMP_CUSTOM_STYLE_SOLID_COLOR || + ! gimp_context_get_pattern (GIMP_CONTEXT (layer->options->stroke_options))) + gimp_fill_options_set_style (GIMP_FILL_OPTIONS (layer->options->stroke_options), + GIMP_FILL_STYLE_FG_COLOR); + else + gimp_fill_options_set_style (GIMP_FILL_OPTIONS (layer->options->stroke_options), + GIMP_FILL_STYLE_PATTERN); + + /* Fill the path object onto the layer */ + gimp_drawable_fill_path (GIMP_DRAWABLE (layer), + layer->options->fill_options, + path, FALSE, NULL); + + drawables = g_list_prepend (NULL, GIMP_DRAWABLE (layer)); + /* stroke the path object onto the layer */ + gimp_item_stroke (GIMP_ITEM (path), + drawables, + gimp_get_user_context (gimp_item_get_image (GIMP_ITEM (layer))->gimp), + layer->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/vectors/gimpvectorlayer.h b/app/vectors/gimpvectorlayer.h new file mode 100644 index 0000000000..d4d86cf2a4 --- /dev/null +++ b/app/vectors/gimpvectorlayer.h @@ -0,0 +1,66 @@ +/* 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); +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/vectors/gimpvectorlayeroptions-parasite.c b/app/vectors/gimpvectorlayeroptions-parasite.c new file mode 100644 index 0000000000..6303bc3653 --- /dev/null +++ b/app/vectors/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 "vectors-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/vectors/gimpvectorlayeroptions-parasite.h b/app/vectors/gimpvectorlayeroptions-parasite.h new file mode 100644 index 0000000000..7765cb6c67 --- /dev/null +++ b/app/vectors/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/vectors/gimpvectorlayeroptions.c b/app/vectors/gimpvectorlayeroptions.c new file mode 100644 index 0000000000..da787c9487 --- /dev/null +++ b/app/vectors/gimpvectorlayeroptions.c @@ -0,0 +1,339 @@ +/* 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 "vectors-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_FILL_OPTIONS, + 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_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_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_FILL_OPTIONS: + g_value_set_object (value, options->fill_options); + 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_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_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->stroke_options, + "width", 3.0, + NULL); + + g_object_set (options, + "path", path, + NULL); + + return options; +} diff --git a/app/vectors/gimpvectorlayeroptions.h b/app/vectors/gimpvectorlayeroptions.h new file mode 100644 index 0000000000..73657853ae --- /dev/null +++ b/app/vectors/gimpvectorlayeroptions.h @@ -0,0 +1,64 @@ +/* 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; + + 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/vectors/gimpvectorlayerundo.c b/app/vectors/gimpvectorlayerundo.c new file mode 100644 index 0000000000..2475546249 --- /dev/null +++ b/app/vectors/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 "vectors-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/vectors/gimpvectorlayerundo.h b/app/vectors/gimpvectorlayerundo.h new file mode 100644 index 0000000000..37894a3b92 --- /dev/null +++ b/app/vectors/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/vectors/meson.build b/app/vectors/meson.build index 46cb025d43..b6a5a26980 100644 --- a/app/vectors/meson.build +++ b/app/vectors/meson.build @@ -12,6 +12,11 @@ libappvectors_sources = [ 'gimppathundo.c', 'gimpstroke-new.c', 'gimpstroke.c', + 'gimpvectorlayer.c', + 'gimpvectorlayer-xcf.c', + 'gimpvectorlayeroptions.c', + 'gimpvectorlayeroptions-parasite.c', + 'gimpvectorlayerundo.c', ] libappvectors = static_library('appvectors', diff --git a/app/vectors/vectors-types.h b/app/vectors/vectors-types.h index 37193a0055..e7963f5c25 100644 --- a/app/vectors/vectors-types.h +++ b/app/vectors/vectors-types.h @@ -33,5 +33,9 @@ typedef struct _GimpPath GimpPath; typedef struct _GimpStroke GimpStroke; typedef struct _GimpBezierStroke GimpBezierStroke; +typedef struct _GimpVectorLayer GimpVectorLayer; +typedef struct _GimpVectorLayerOptions GimpVectorLayerOptions; +typedef struct _GimpVectorLayerUndo GimpVectorLayerUndo; + #endif /* __VECTORS_TYPES_H__ */ diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index a530db281c..73ba3bb4a4 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -76,6 +76,8 @@ #include "vectors/gimpbezierstroke.h" #include "vectors/gimppath.h" #include "vectors/gimppath-compat.h" +#include "vectors/gimpvectorlayer.h" +#include "vectors/gimpvectorlayer-xcf.h" #include "xcf-private.h" #include "xcf-load.h" @@ -3149,7 +3151,7 @@ xcf_load_layer (XcfInfo *info, xcf_progress_update (info); - /* call the evil text layer hack that might change our layer pointer */ + /* call the evil text and vector layer hack that might change our layer pointer */ selected = g_list_find (info->selected_layers, layer); linked = g_list_find (info->linked_layers, layer); floating = (info->floating_sel == layer); @@ -3172,6 +3174,16 @@ xcf_load_layer (XcfInfo *info, if (floating) info->floating_sel = layer; } + else if (gimp_vector_layer_xcf_load_hack (&layer)) + { + if (selected) + { + info->selected_layers = g_list_delete_link (info->selected_layers, selected); + info->selected_layers = g_list_prepend (info->selected_layers, layer); + } + if (floating) + info->floating_sel = layer; + } /* if this is not the floating selection, we can fix the layer's * space already now, the function will do nothing if we already diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c index 39b162b7a6..ce587f9121 100644 --- a/app/xcf/xcf-save.c +++ b/app/xcf/xcf-save.c @@ -70,6 +70,8 @@ #include "vectors/gimppath.h" #include "vectors/gimpstroke.h" #include "vectors/gimppath-compat.h" +#include "vectors/gimpvectorlayer.h" +#include "vectors/gimpvectorlayer-xcf.h" #include "xcf-private.h" #include "xcf-read.h" @@ -720,6 +722,12 @@ xcf_save_layer_props (XcfInfo *info, image, PROP_TEXT_LAYER_FLAGS, error, flags), ;); } + else if (GIMP_IS_VECTOR_LAYER (layer) && GIMP_VECTOR_LAYER (layer)->options) + { + GimpVectorLayer *vector_layer = GIMP_VECTOR_LAYER (layer); + + gimp_vector_layer_xcf_save_prepare (vector_layer); + } if (gimp_viewable_get_children (GIMP_VIEWABLE (layer))) { diff --git a/menus/image-menu.ui.in.in b/menus/image-menu.ui.in.in index 633c4dfff4..2df5d65761 100644 --- a/menus/image-menu.ui.in.in +++ b/menus/image-menu.ui.in.in @@ -433,6 +433,10 @@ app.layers-text-to-vectors app.layers-text-along-vectors +
+ app.layers-vector-fill-stroke + app.layers-vector-discard +
Stac_k diff --git a/menus/layers-menu.ui b/menus/layers-menu.ui index e780d64387..69e4270a9b 100644 --- a/menus/layers-menu.ui +++ b/menus/layers-menu.ui @@ -7,6 +7,7 @@ gimp-layers app.layers-edit-text + app.layers-edit-vector app.layers-edit-attributes Blend Space @@ -63,6 +64,10 @@ app.layers-text-to-vectors app.layers-text-along-vectors
+
+ app.layers-vector-fill-stroke + app.layers-vector-discard +
app.layers-resize app.layers-resize-to-image diff --git a/menus/paths-menu.ui b/menus/paths-menu.ui index 11570eb1fd..b6fafd2e58 100644 --- a/menus/paths-menu.ui +++ b/menus/paths-menu.ui @@ -29,6 +29,7 @@ app.paths-merge-visible
+ app.paths-to-vector-layer app.paths-selection-replace app.paths-selection-add app.paths-selection-subtract