diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index df92505dd0..97d62d70b2 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -53,6 +53,7 @@ #include "core/gimplist.h" #include "core/gimppickable.h" #include "core/gimppickable-auto-shrink.h" +#include "core/gimprasterizable.h" #include "core/gimptoolinfo.h" #include "core/gimpundostack.h" #include "core/gimpprogress.h" @@ -1121,12 +1122,8 @@ layers_rasterize_cmd_callback (GimpAction *action, for (iter = layers; iter; iter = iter->next) { - if (gimp_item_is_link_layer (iter->data)) - gimp_link_layer_discard (GIMP_LINK_LAYER (iter->data)); - else if (gimp_item_is_text_layer (iter->data)) - gimp_text_layer_discard (GIMP_TEXT_LAYER (iter->data)); - else if (gimp_item_is_vector_layer (iter->data)) - gimp_vector_layer_discard (GIMP_VECTOR_LAYER (iter->data)); + if (GIMP_IS_RASTERIZABLE (iter->data) && ! gimp_rasterizable_is_rasterized (iter->data)) + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (iter->data)); } gimp_image_undo_group_end (image); @@ -1148,12 +1145,8 @@ layers_retrieve_cmd_callback (GimpAction *action, for (iter = layers; iter; iter = iter->next) { - if (GIMP_IS_LINK_LAYER (iter->data) && ! gimp_item_is_link_layer (iter->data)) - gimp_link_layer_monitor (GIMP_LINK_LAYER (iter->data)); - else if (GIMP_IS_TEXT_LAYER (iter->data) && ! gimp_item_is_text_layer (iter->data)) - gimp_text_layer_retrieve (GIMP_TEXT_LAYER (iter->data)); - else if (GIMP_IS_VECTOR_LAYER (iter->data) && ! gimp_item_is_vector_layer (iter->data)) - gimp_vector_layer_retrieve (GIMP_VECTOR_LAYER (iter->data)); + if (GIMP_IS_RASTERIZABLE (iter->data) && gimp_rasterizable_is_rasterized (iter->data)) + gimp_rasterizable_restore (GIMP_RASTERIZABLE (iter->data)); } gimp_image_undo_group_end (image); diff --git a/app/core/core-enums.c b/app/core/core-enums.c index d414e46771..7f21288839 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -1266,10 +1266,8 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_GROUP_LAYER_END_TRANSFORM, "GIMP_UNDO_GROUP_LAYER_END_TRANSFORM", "group-layer-end-transform" }, { GIMP_UNDO_GROUP_LAYER_CONVERT, "GIMP_UNDO_GROUP_LAYER_CONVERT", "group-layer-convert" }, { 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" }, @@ -1291,6 +1289,7 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_FILTER_REMOVE, "GIMP_UNDO_FILTER_REMOVE", "filter-remove" }, { GIMP_UNDO_FILTER_REORDER, "GIMP_UNDO_FILTER_REORDER", "filter-reorder" }, { GIMP_UNDO_FILTER_MODIFIED, "GIMP_UNDO_FILTER_MODIFIED", "filter-modified" }, + { GIMP_UNDO_RASTERIZABLE, "GIMP_UNDO_RASTERIZABLE", "rasterizable" }, { GIMP_UNDO_CANT, "GIMP_UNDO_CANT", "cant" }, { 0, NULL, NULL } }; @@ -1382,10 +1381,8 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_GROUP_LAYER_END_TRANSFORM, NC_("undo-type", "End transforming group layer"), NULL }, { GIMP_UNDO_GROUP_LAYER_CONVERT, NC_("undo-type", "Convert group layer"), NULL }, { 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 }, @@ -1407,6 +1404,7 @@ gimp_undo_type_get_type (void) { GIMP_UNDO_FILTER_REMOVE, NC_("undo-type", "Remove effect"), NULL }, { GIMP_UNDO_FILTER_REORDER, NC_("undo-type", "Reorder effect"), NULL }, { GIMP_UNDO_FILTER_MODIFIED, NC_("undo-type", "Effect modification"), NULL }, + { GIMP_UNDO_RASTERIZABLE, NC_("undo-type", "Text, link or vector layer"), NULL }, { GIMP_UNDO_CANT, NC_("undo-type", "Not undoable"), NULL }, { 0, NULL, NULL } }; diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 32fdb59122..d2ba601d00 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -618,10 +618,8 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_GROUP_LAYER_END_TRANSFORM, /*< desc="End transforming group layer" >*/ GIMP_UNDO_GROUP_LAYER_CONVERT, /*< desc="Convert group layer" >*/ 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" >*/ @@ -643,6 +641,7 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_FILTER_REMOVE, /*< desc="Remove effect" >*/ GIMP_UNDO_FILTER_REORDER, /*< desc="Reorder effect" >*/ GIMP_UNDO_FILTER_MODIFIED, /*< desc="Effect modification" >*/ + GIMP_UNDO_RASTERIZABLE, /*< desc="Text, link or vector layer" >*/ GIMP_UNDO_CANT /*< desc="Not undoable" >*/ } GimpUndoType; diff --git a/app/core/core-types.h b/app/core/core-types.h index 0c892399ea..990be94727 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -163,6 +163,7 @@ typedef struct _GimpTagCache GimpTagCache; typedef struct _GimpDrawable GimpDrawable; typedef struct _GimpDrawableFilterMask GimpDrawableFilterMask; +typedef struct _GimpRasterizable GimpRasterizable; typedef struct _GimpChannel GimpChannel; typedef struct _GimpLayerMask GimpLayerMask; typedef struct _GimpSelection GimpSelection; diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index a033295600..25f621a98a 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -234,3 +234,5 @@ void gimp_drawable_start_paint (GimpDrawable *drawable) gboolean gimp_drawable_end_paint (GimpDrawable *drawable); gboolean gimp_drawable_flush_paint (GimpDrawable *drawable); gboolean gimp_drawable_is_painting (GimpDrawable *drawable); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GimpDrawable, g_object_unref); diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index df0345a962..fa0f4bdc8f 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -51,6 +51,8 @@ #include "gimplinklayer.h" #include "gimplinklayerundo.h" #include "gimpmaskundo.h" +#include "gimprasterizable.h" +#include "gimprasterizableundo.h" #include "gimpsamplepoint.h" #include "gimpsamplepointundo.h" #include "gimpselection.h" @@ -826,6 +828,27 @@ gimp_image_undo_push_group_layer_convert (GimpImage *image, } +/************************/ +/* Rasterizable Undos */ +/************************/ + +GimpUndo * +gimp_image_undo_push_rasterizable (GimpImage *image, + const gchar *undo_desc, + GimpRasterizable *rasterizable) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_RASTERIZABLE (rasterizable), NULL); + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (rasterizable)), NULL); + + return gimp_image_undo_push (image, GIMP_TYPE_RASTERIZABLE_UNDO, + GIMP_UNDO_RASTERIZABLE, undo_desc, + GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE, + "item", rasterizable, + NULL); +} + + /**********************/ /* Text Layer Undos */ /**********************/ @@ -848,22 +871,6 @@ gimp_image_undo_push_text_layer (GimpImage *image, NULL); } -GimpUndo * -gimp_image_undo_push_text_layer_modified (GimpImage *image, - const gchar *undo_desc, - GimpTextLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); - g_return_val_if_fail (GIMP_IS_TEXT_LAYER (layer), NULL); - g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)), NULL); - - return gimp_image_undo_push (image, GIMP_TYPE_TEXT_UNDO, - GIMP_UNDO_TEXT_LAYER_MODIFIED, undo_desc, - GIMP_DIRTY_ITEM_META, - "item", layer, - NULL); -} - GimpUndo * gimp_image_undo_push_text_layer_convert (GimpImage *image, const gchar *undo_desc, @@ -880,6 +887,7 @@ gimp_image_undo_push_text_layer_convert (GimpImage *image, NULL); } + /**********************/ /* Link Layer Undos */ /**********************/ @@ -922,22 +930,6 @@ gimp_image_undo_push_vector_layer (GimpImage *image, 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 a40237f435..c7f904cef2 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -200,6 +200,11 @@ GimpUndo * gimp_image_undo_push_group_layer_convert (GimpImage *image, const gchar *undo_desc, GimpGroupLayer *group); +/* rasterizable undos */ + +GimpUndo * gimp_image_undo_push_rasterizable (GimpImage *image, + const gchar *undo_desc, + GimpRasterizable *rasterizable); /* text layer undos */ @@ -207,9 +212,6 @@ GimpUndo * gimp_image_undo_push_text_layer (GimpImage *image, const gchar *undo_desc, GimpTextLayer *layer, const GParamSpec *pspec); -GimpUndo * gimp_image_undo_push_text_layer_modified (GimpImage *image, - const gchar *undo_desc, - GimpTextLayer *layer); GimpUndo * gimp_image_undo_push_text_layer_convert (GimpImage *image, const gchar *undo_desc, GimpTextLayer *layer); @@ -226,10 +228,6 @@ 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 */ diff --git a/app/core/gimpitemundo.h b/app/core/gimpitemundo.h index 20ae229b38..7f734884d3 100644 --- a/app/core/gimpitemundo.h +++ b/app/core/gimpitemundo.h @@ -45,3 +45,5 @@ struct _GimpItemUndoClass GType gimp_item_undo_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GimpItemUndo, g_object_unref); diff --git a/app/core/gimplinklayer.c b/app/core/gimplinklayer.c index 69c23429b5..69a1d234cf 100644 --- a/app/core/gimplinklayer.c +++ b/app/core/gimplinklayer.c @@ -43,11 +43,11 @@ #include "gimpimage-undo.h" #include "gimpimage-undo-push.h" #include "gimpitemtree.h" -#include "gimpobjectqueue.h" -#include "gimpprogress.h" - #include "gimplink.h" #include "gimplinklayer.h" +#include "gimpobjectqueue.h" +#include "gimpprogress.h" +#include "gimprasterizable.h" #include "gimp-intl.h" @@ -87,6 +87,9 @@ struct _GimpLinkLayerPrivate gboolean keep_monitoring; }; +static void gimp_link_layer_rasterizable_iface_init + (GimpRasterizableInterface *iface); + static void gimp_link_layer_finalize (GObject *object); static void gimp_link_layer_get_property (GObject *object, guint property_id, @@ -140,6 +143,9 @@ static void gimp_link_layer_push_undo (GimpDrawable *drawable, gint width, gint height); +static void gimp_link_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized); + static void gimp_link_layer_convert_type (GimpLayer *layer, GimpImage *dest_image, const Babl *new_format, @@ -162,7 +168,10 @@ static gboolean gint *new_offset_y); -G_DEFINE_TYPE_WITH_PRIVATE (GimpLinkLayer, gimp_link_layer, GIMP_TYPE_LAYER) +G_DEFINE_TYPE_WITH_CODE (GimpLinkLayer, gimp_link_layer, GIMP_TYPE_LAYER, + G_ADD_PRIVATE (GimpLinkLayer) + G_IMPLEMENT_INTERFACE (GIMP_TYPE_RASTERIZABLE, + gimp_link_layer_rasterizable_iface_init)) #define parent_class gimp_link_layer_parent_class @@ -245,6 +254,12 @@ gimp_link_layer_init (GimpLinkLayer *layer) layer->p->keep_monitoring = FALSE; } +static void +gimp_link_layer_rasterizable_iface_init (GimpRasterizableInterface *iface) +{ + iface->set_rasterized = gimp_link_layer_set_rasterized; +} + static void gimp_link_layer_finalize (GObject *object) { @@ -677,6 +692,24 @@ gimp_link_layer_push_undo (GimpDrawable *drawable, } } +static void +gimp_link_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized) +{ + GimpLinkLayer *layer = GIMP_LINK_LAYER (rasterizable); + + if (rasterized) + { + gimp_link_freeze (layer->p->link); + } + else + { + gimp_link_thaw (layer->p->link); + gimp_matrix3_identity (&layer->p->matrix); + gimp_link_layer_render_link (layer); + } +} + static void gimp_link_layer_convert_type (GimpLayer *layer, GimpImage *dest_image, @@ -822,44 +855,6 @@ gimp_link_layer_set_link_with_matrix (GimpLinkLayer *layer, return rendered; } -/** - * gimp_link_layer_discard: - * @layer: a #GimpLinkLayer - * - * Discards the link. This makes @layer behave like a - * normal layer. - */ -void -gimp_link_layer_discard (GimpLinkLayer *layer) -{ - g_return_if_fail (GIMP_IS_LINK_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)), - _("Discard Link"), layer); - - gimp_link_freeze (layer->p->link); - - /* Triggers thumbnail update. */ - gimp_drawable_update_all (GIMP_DRAWABLE (layer)); - /* Triggers contextual menu update. */ - gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); -} - -void -gimp_link_layer_monitor (GimpLinkLayer *layer) -{ - g_return_if_fail (GIMP_IS_LINK_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)), - _("Monitor Link"), layer); - - gimp_link_thaw (layer->p->link); - gimp_matrix3_identity (&layer->p->matrix); - gimp_link_layer_render_link (layer); -} - gboolean gimp_link_layer_is_monitored (GimpLinkLayer *layer) { diff --git a/app/core/gimplinklayer.h b/app/core/gimplinklayer.h index 814803821a..997545c375 100644 --- a/app/core/gimplinklayer.h +++ b/app/core/gimplinklayer.h @@ -64,8 +64,6 @@ gboolean gimp_link_layer_set_link_with_matrix (GimpLinkLayer *layer, gint offset_y, gboolean push_undo); -void gimp_link_layer_discard (GimpLinkLayer *layer); -void gimp_link_layer_monitor (GimpLinkLayer *layer); gboolean gimp_link_layer_is_monitored (GimpLinkLayer *layer); gboolean gimp_link_layer_get_transform (GimpLinkLayer *layer, diff --git a/app/core/gimprasterizable.c b/app/core/gimprasterizable.c new file mode 100644 index 0000000000..8a96e75111 --- /dev/null +++ b/app/core/gimprasterizable.c @@ -0,0 +1,212 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimprasterizable.c + * Copyright (C) 2025 Jehan + * + * 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 "core-types.h" + +#include "gimpimage.h" +#include "gimpimage-undo.h" +#include "gimpimage-undo-push.h" +#include "gimprasterizable.h" + +#include "gimp-intl.h" + + +enum +{ + SET_RASTERIZED, + LAST_SIGNAL +}; + + +typedef struct _GimpRasterizablePrivate GimpRasterizablePrivate; + +struct _GimpRasterizablePrivate +{ + gboolean rasterized; +}; + +#define GIMP_RASTERIZABLE_GET_PRIVATE(obj) (gimp_rasterizable_get_private ((GimpRasterizable *) (obj))) + + +static GimpRasterizablePrivate * gimp_rasterizable_get_private (GimpRasterizable *rasterizable); +static void gimp_rasterizable_private_finalize (GimpRasterizablePrivate *private); + + + +G_DEFINE_INTERFACE (GimpRasterizable, gimp_rasterizable, GIMP_TYPE_DRAWABLE) + + +static guint gimp_rasterizable_signals[LAST_SIGNAL] = { 0, }; + + +static void +gimp_rasterizable_default_init (GimpRasterizableInterface *iface) +{ + gimp_rasterizable_signals[SET_RASTERIZED] = + g_signal_new ("set-rasterized", + GIMP_TYPE_RASTERIZABLE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpRasterizableInterface, set_rasterized), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN); +} + + +/* Public functions */ + + +/** + * gimp_rasterizable_rasterize: + * @rasterizable: an object that implements the %GimpRasterizable interface + * + * Rasterize @rasterizable. + **/ +void +gimp_rasterizable_rasterize (GimpRasterizable *rasterizable) +{ + GimpRasterizablePrivate *private; + GimpImage *image; + gchar *undo_text; + + g_return_if_fail (GIMP_IS_RASTERIZABLE (rasterizable)); + g_return_if_fail (! gimp_rasterizable_is_rasterized (rasterizable)); + + private = GIMP_RASTERIZABLE_GET_PRIVATE (rasterizable); + image = gimp_item_get_image (GIMP_ITEM (rasterizable)); + + /* TRANSLATORS: the %s will be a type of item, i.e. "Text Layer". */ + undo_text = g_strdup_printf (_("Rasterize %s"), + GIMP_VIEWABLE_GET_CLASS (rasterizable)->default_name); + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_PROPERTIES, undo_text); + + gimp_image_undo_push_rasterizable (image, NULL, rasterizable); + + private->rasterized = TRUE; + g_signal_emit (rasterizable, gimp_rasterizable_signals[SET_RASTERIZED], 0, TRUE); + + gimp_image_undo_group_end (image); + + /* Triggers thumbnail update. */ + gimp_drawable_update_all (GIMP_DRAWABLE (rasterizable)); + /* Triggers contextual menu update. */ + gimp_image_flush (image); +} + +/** + * gimp_rasterizable_restore: + * @rasterizable: an object that implements the %GimpRasterizable interface + * + * Revert the rasterization of @rasterizable. + **/ +void +gimp_rasterizable_restore (GimpRasterizable *rasterizable) +{ + GimpRasterizablePrivate *private; + GimpImage *image; + gchar *undo_text; + + g_return_if_fail (GIMP_IS_RASTERIZABLE (rasterizable)); + g_return_if_fail (gimp_rasterizable_is_rasterized (rasterizable)); + + private = GIMP_RASTERIZABLE_GET_PRIVATE (rasterizable); + image = gimp_item_get_image (GIMP_ITEM (rasterizable)); + + /* TRANSLATORS: the %s will be a type of item, i.e. "Text Layer". */ + undo_text = g_strdup_printf (_("Revert Rasterize %s"), + GIMP_VIEWABLE_GET_CLASS (rasterizable)->default_name); + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_PROPERTIES, undo_text); + gimp_image_undo_push_rasterizable (image, NULL, rasterizable); + gimp_image_undo_push_drawable_mod (image, NULL, GIMP_DRAWABLE (rasterizable), TRUE); + + private->rasterized = FALSE; + g_signal_emit (rasterizable, gimp_rasterizable_signals[SET_RASTERIZED], 0, FALSE); + + gimp_image_undo_group_end (image); + gimp_image_flush (image); +} + +/** + * gimp_rasterizable_is_rasterized: + * @rasterizable: an object that implements the %GimpRasterizable interface + * + * Returns: whether @rasterizable is rasterized or not. + **/ +gboolean +gimp_rasterizable_is_rasterized (GimpRasterizable *rasterizable) +{ + GimpRasterizablePrivate *private; + + g_return_val_if_fail (GIMP_IS_RASTERIZABLE (rasterizable), FALSE); + + private = GIMP_RASTERIZABLE_GET_PRIVATE (rasterizable); + + return private->rasterized; +} + +void +gimp_rasterizable_set_undo_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized) +{ + GimpRasterizablePrivate *private; + + g_return_if_fail (GIMP_IS_RASTERIZABLE (rasterizable)); + + private = GIMP_RASTERIZABLE_GET_PRIVATE (rasterizable); + + private->rasterized = rasterized; +} + +/* Private functions */ + +static GimpRasterizablePrivate * +gimp_rasterizable_get_private (GimpRasterizable *rasterizable) +{ + GimpRasterizablePrivate *private; + + static GQuark private_key = 0; + + g_return_val_if_fail (GIMP_IS_RASTERIZABLE (rasterizable), NULL); + + if (! private_key) + private_key = g_quark_from_static_string ("gimp-rasterizable-private"); + + private = g_object_get_qdata ((GObject *) rasterizable, private_key); + + if (! private) + { + private = g_slice_new0 (GimpRasterizablePrivate); + + g_object_set_qdata_full ((GObject *) rasterizable, private_key, private, + (GDestroyNotify) gimp_rasterizable_private_finalize); + } + + return private; +} + +static void +gimp_rasterizable_private_finalize (GimpRasterizablePrivate *private) +{ + g_slice_free (GimpRasterizablePrivate, private); +} diff --git a/app/core/gimprasterizable.h b/app/core/gimprasterizable.h new file mode 100644 index 0000000000..d9920e18ec --- /dev/null +++ b/app/core/gimprasterizable.h @@ -0,0 +1,47 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * gimprasterizable.h + * Copyright (C) 2025 Jehan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "gimpdrawable.h" + +#define GIMP_TYPE_RASTERIZABLE (gimp_rasterizable_get_type ()) +G_DECLARE_INTERFACE (GimpRasterizable, gimp_rasterizable, GIMP, RASTERIZABLE, GimpDrawable) + + +struct _GimpRasterizableInterface +{ + GTypeInterface base_iface; + + /* signals */ + void (* set_rasterized) (GimpRasterizable *rasterizable, + gboolean rasterized); +}; + + +void gimp_rasterizable_rasterize (GimpRasterizable *rasterizable); +void gimp_rasterizable_restore (GimpRasterizable *rasterizable); + +gboolean gimp_rasterizable_is_rasterized (GimpRasterizable *rasterizable); + +/* To be used for undo steps only */ + +void gimp_rasterizable_set_undo_rasterized (GimpRasterizable *rasterizable, + gboolean rasterize); diff --git a/app/core/gimprasterizableundo.c b/app/core/gimprasterizableundo.c new file mode 100644 index 0000000000..d9996fcdb2 --- /dev/null +++ b/app/core/gimprasterizableundo.c @@ -0,0 +1,117 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimprasterizableundo.c + * Copyright (C) 2025 Jehan + * + * 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 "core-types.h" + +#include "gimprasterizable.h" +#include "gimprasterizableundo.h" + + +struct _GimpRasterizableUndo +{ + GimpItemUndo parent_instance; + + gboolean rasterized; +}; + + +static void gimp_rasterizable_undo_constructed (GObject *object); + +static void gimp_rasterizable_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); + + +G_DEFINE_TYPE (GimpRasterizableUndo, gimp_rasterizable_undo, GIMP_TYPE_ITEM_UNDO) + +#define parent_class gimp_rasterizable_undo_parent_class + + +static void +gimp_rasterizable_undo_class_init (GimpRasterizableUndoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); + + object_class->constructed = gimp_rasterizable_undo_constructed; + undo_class->pop = gimp_rasterizable_undo_pop; +} + +static void +gimp_rasterizable_undo_init (GimpRasterizableUndo *undo) +{ +} + +static void +gimp_rasterizable_undo_constructed (GObject *object) +{ + GimpRasterizableUndo *undo = GIMP_RASTERIZABLE_UNDO (object); + GimpRasterizable *rasterizable; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + gimp_assert (GIMP_IS_RASTERIZABLE (GIMP_ITEM_UNDO (undo)->item)); + + rasterizable = GIMP_RASTERIZABLE (GIMP_ITEM_UNDO (undo)->item); + + switch (GIMP_UNDO (object)->undo_type) + { + case GIMP_UNDO_RASTERIZABLE: + undo->rasterized = gimp_rasterizable_is_rasterized (rasterizable); + break; + + default: + gimp_assert_not_reached (); + } +} + +static void +gimp_rasterizable_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GimpRasterizableUndo *rundo = GIMP_RASTERIZABLE_UNDO (undo); + GimpRasterizable *rasterizable = GIMP_RASTERIZABLE (GIMP_ITEM_UNDO (undo)->item); + + GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); + + switch (undo->undo_type) + { + case GIMP_UNDO_RASTERIZABLE: + { + gboolean rasterized = gimp_rasterizable_is_rasterized (rasterizable); + + gimp_rasterizable_set_undo_rasterized (rasterizable, rundo->rasterized); + rundo->rasterized = rasterized; + + GIMP_RASTERIZABLE_GET_IFACE (rasterizable)->set_rasterized (rasterizable, ! rasterized); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (rasterizable)); + } + break; + + default: + gimp_assert_not_reached (); + } +} diff --git a/app/core/gimprasterizableundo.h b/app/core/gimprasterizableundo.h new file mode 100644 index 0000000000..2fc03cf54b --- /dev/null +++ b/app/core/gimprasterizableundo.h @@ -0,0 +1,26 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimprasterizableundo.h + * Copyright (C) 2025 Jehan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "gimpitemundo.h" + +#define GIMP_TYPE_RASTERIZABLE_UNDO (gimp_rasterizable_undo_get_type ()) +G_DECLARE_FINAL_TYPE (GimpRasterizableUndo, gimp_rasterizable_undo, GIMP, RASTERIZABLE_UNDO, GimpItemUndo) diff --git a/app/core/meson.build b/app/core/meson.build index 18f69f2ba7..656d36a9c2 100644 --- a/app/core/meson.build +++ b/app/core/meson.build @@ -224,6 +224,8 @@ libappcore_sources = [ 'gimpprogress.c', 'gimpprojectable.c', 'gimpprojection.c', + 'gimprasterizable.c', + 'gimprasterizableundo.c', 'gimpresource.c', 'gimpsamplepoint.c', 'gimpsamplepointundo.c', diff --git a/app/path/gimpvectorlayer.c b/app/path/gimpvectorlayer.c index 40930104f9..d8cfda860d 100644 --- a/app/path/gimpvectorlayer.c +++ b/app/path/gimpvectorlayer.c @@ -42,6 +42,7 @@ #include "core/gimpimage-undo-push.h" #include "core/gimpstrokeoptions.h" #include "core/gimpparasitelist.h" +#include "core/gimprasterizable.h" #include "gimpvectorlayer.h" #include "gimpvectorlayeroptions.h" @@ -54,12 +55,15 @@ enum { PROP_0, PROP_VECTOR_LAYER_OPTIONS, - PROP_MODIFIED }; /* local function declarations */ +static void gimp_vector_layer_rasterizable_iface_init + (GimpRasterizableInterface *iface); + + static void gimp_vector_layer_finalize (GObject *object); static void gimp_vector_layer_get_property (GObject *object, guint property_id, @@ -69,6 +73,10 @@ static void gimp_vector_layer_set_property (GObject *obj guint property_id, const GValue *value, GParamSpec *pspec); + +static void gimp_vector_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized); + static void gimp_vector_layer_set_vector_options (GimpVectorLayer *layer, GimpVectorLayerOptions *options); @@ -132,7 +140,9 @@ static void gimp_vector_layer_removed_options_path (GimpVectorLayer *layer); -G_DEFINE_TYPE (GimpVectorLayer, gimp_vector_layer, GIMP_TYPE_LAYER) +G_DEFINE_TYPE_WITH_CODE (GimpVectorLayer, gimp_vector_layer, GIMP_TYPE_LAYER, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_RASTERIZABLE, + gimp_vector_layer_rasterizable_iface_init)) #define parent_class gimp_vector_layer_parent_class @@ -180,19 +190,18 @@ gimp_vector_layer_class_init (GimpVectorLayerClass *klass) "vector-layer-options", NULL, NULL, GIMP_TYPE_VECTOR_LAYER_OPTIONS, G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - - 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->modified = FALSE; +} + +static void +gimp_vector_layer_rasterizable_iface_init (GimpRasterizableInterface *iface) +{ + iface->set_rasterized = gimp_vector_layer_set_rasterized; } static void @@ -222,9 +231,6 @@ gimp_vector_layer_get_property (GObject *object, 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); @@ -245,9 +251,6 @@ gimp_vector_layer_set_property (GObject *object, case PROP_VECTOR_LAYER_OPTIONS: gimp_vector_layer_set_vector_options (vector_layer, g_value_get_object (value)); break; - case PROP_MODIFIED: - vector_layer->modified = g_value_get_boolean (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -255,6 +258,14 @@ gimp_vector_layer_set_property (GObject *object, } } +static void +gimp_vector_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized) +{ + if (! rasterized) + gimp_vector_layer_render (GIMP_VECTOR_LAYER (rasterizable)); +} + static void gimp_vector_layer_set_vector_options (GimpVectorLayer *layer, GimpVectorLayerOptions *options) @@ -303,8 +314,11 @@ gimp_vector_layer_set_buffer (GimpDrawable *drawable, { GimpVectorLayer *layer = GIMP_VECTOR_LAYER (drawable); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + gboolean is_rasterized; - if (push_undo && ! layer->modified) + is_rasterized = gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer)); + + if (push_undo && ! is_rasterized) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD, undo_desc); @@ -312,12 +326,9 @@ gimp_vector_layer_set_buffer (GimpDrawable *drawable, push_undo, undo_desc, buffer, bounds); - if (push_undo && ! layer->modified) + if (push_undo && ! is_rasterized) { - gimp_image_undo_push_vector_layer_modified (image, NULL, layer); - - g_object_set (drawable, "modified", TRUE, NULL); - + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); gimp_image_undo_group_end (image); } } @@ -333,20 +344,20 @@ gimp_vector_layer_push_undo (GimpDrawable *drawable, { GimpVectorLayer *layer = GIMP_VECTOR_LAYER (drawable); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + gboolean is_rasterized; - if (! layer->modified) + is_rasterized = gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer)); + + if (! is_rasterized) 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) + if (! is_rasterized) { - gimp_image_undo_push_vector_layer_modified (image, NULL, layer); - - g_object_set (drawable, "modified", TRUE, NULL); - + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); gimp_image_undo_group_end (image); } } @@ -646,62 +657,11 @@ gimp_vector_layer_refresh (GimpVectorLayer *layer) 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) -{ - GimpImage *image; - - g_return_if_fail (GIMP_IS_VECTOR_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - if (layer->modified) - return; - - image = gimp_item_get_image (GIMP_ITEM (layer)); - - gimp_image_undo_push_vector_layer_modified (image, NULL, layer); - g_object_set (layer, "modified", TRUE, NULL); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); - gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer))); -} - -void -gimp_vector_layer_retrieve (GimpVectorLayer *layer) -{ - GimpImage *image; - - g_return_if_fail (GIMP_IS_VECTOR_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - if (! layer->modified) - return; - - image = gimp_item_get_image (GIMP_ITEM (layer)); - - gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_PROPERTIES, - _("Revert Rasterize Vector Layer")); - - gimp_image_undo_push_vector_layer_modified (image, NULL, layer); - gimp_image_undo_push_drawable_mod (image, NULL, GIMP_DRAWABLE (layer), TRUE); - g_object_set (layer, "modified", FALSE, NULL); - - gimp_image_undo_group_end (image); - gimp_vector_layer_render (layer); - gimp_image_flush (image); -} - gboolean gimp_item_is_vector_layer (GimpItem *item) { - return (GIMP_IS_VECTOR_LAYER (item) && ! GIMP_VECTOR_LAYER (item)->modified); + return (GIMP_IS_VECTOR_LAYER (item) && + ! gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (item))); } @@ -817,7 +777,7 @@ gimp_vector_layer_changed_options (GimpVectorLayer *layer) GimpItem *item = GIMP_ITEM (layer); if (layer->options && ! layer->options->path) - gimp_vector_layer_discard (layer); + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); else if (gimp_item_is_attached (item)) gimp_vector_layer_refresh (layer); } diff --git a/app/path/gimpvectorlayer.h b/app/path/gimpvectorlayer.h index 79edbd7062..072832a96f 100644 --- a/app/path/gimpvectorlayer.h +++ b/app/path/gimpvectorlayer.h @@ -41,7 +41,6 @@ struct _GimpVectorLayer GimpLayer parent_instance; GimpVectorLayerOptions *options; - gboolean modified; }; struct _GimpVectorLayerClass @@ -61,8 +60,6 @@ GimpPath * gimp_vector_layer_get_path (GimpVectorLayer *layer) GimpVectorLayerOptions * gimp_vector_layer_get_options (GimpVectorLayer *layer); void gimp_vector_layer_refresh (GimpVectorLayer *layer); -void gimp_vector_layer_discard (GimpVectorLayer *layer); -void gimp_vector_layer_retrieve (GimpVectorLayer *layer); gboolean gimp_item_is_vector_layer (GimpItem *item); diff --git a/app/path/gimpvectorlayerundo.c b/app/path/gimpvectorlayerundo.c index c002d9aed0..53124e445c 100644 --- a/app/path/gimpvectorlayerundo.c +++ b/app/path/gimpvectorlayerundo.c @@ -30,9 +30,9 @@ #include "path-types.h" #include "core/gimp-memsize.h" +#include "core/gimp-utils.h" #include "core/gimpitem.h" #include "core/gimpitemundo.h" -#include "core/gimp-utils.h" #include "gimpvectorlayer.h" #include "gimpvectorlayeroptions.h" @@ -128,10 +128,6 @@ gimp_vector_layer_undo_constructed (GObject *object) } break; - case GIMP_UNDO_VECTOR_LAYER_MODIFIED: - vector_undo->modified = vector_layer->modified; - break; - default: g_assert_not_reached (); } @@ -246,18 +242,6 @@ gimp_vector_layer_undo_pop (GimpUndo *undo, } 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 (); } diff --git a/app/path/gimpvectorlayerundo.h b/app/path/gimpvectorlayerundo.h index 37894a3b92..dbeae0e1ea 100644 --- a/app/path/gimpvectorlayerundo.h +++ b/app/path/gimpvectorlayerundo.h @@ -43,7 +43,6 @@ struct _GimpVectorLayerUndo GimpVectorLayerOptions *vector_layer_options; const GParamSpec *pspec; GValue *value; - gboolean modified; }; struct _GimpVectorLayerUndoClass diff --git a/app/pdb/link-layer-cmds.c b/app/pdb/link-layer-cmds.c index b9f102270d..96ed52a546 100644 --- a/app/pdb/link-layer-cmds.c +++ b/app/pdb/link-layer-cmds.c @@ -33,6 +33,7 @@ #include "core/gimplink.h" #include "core/gimplinklayer.h" #include "core/gimpparamspecs.h" +#include "core/gimprasterizable.h" #include "gimppdb.h" #include "gimppdberror.h" @@ -120,7 +121,7 @@ link_layer_discard_invoker (GimpProcedure *procedure, if (success) { - gimp_link_layer_discard (layer); + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); } return gimp_procedure_get_return_values (procedure, success, @@ -142,7 +143,7 @@ link_layer_monitor_invoker (GimpProcedure *procedure, if (success) { - gimp_link_layer_monitor (layer); + gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); } return gimp_procedure_get_return_values (procedure, success, diff --git a/app/pdb/vector-layer-cmds.c b/app/pdb/vector-layer-cmds.c index ac9adfdfdb..73cf90eea8 100644 --- a/app/pdb/vector-layer-cmds.c +++ b/app/pdb/vector-layer-cmds.c @@ -38,6 +38,7 @@ #include "core/gimpdashpattern.h" #include "core/gimpimage.h" #include "core/gimpparamspecs.h" +#include "core/gimprasterizable.h" #include "core/gimpstrokeoptions.h" #include "path/gimppath.h" #include "path/gimpvectorlayer.h" @@ -139,7 +140,7 @@ vector_layer_discard_invoker (GimpProcedure *procedure, if (success) { - gimp_vector_layer_discard (layer); + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); } return gimp_procedure_get_return_values (procedure, success, diff --git a/app/text/gimptextlayer-transform.c b/app/text/gimptextlayer-transform.c index 20e672019f..1b6abffe02 100644 --- a/app/text/gimptextlayer-transform.c +++ b/app/text/gimptextlayer-transform.c @@ -29,6 +29,7 @@ #include "core/gimp-transform-utils.h" #include "core/gimpimage-undo.h" +#include "core/gimprasterizable.h" #include "gimptext.h" #include "gimptextlayer.h" @@ -169,7 +170,7 @@ static gboolean gimp_text_layer_get_transformation (GimpTextLayer *layer, GimpMatrix3 *matrix) { - if (! layer->text || layer->modified) + if (! layer->text || gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer))) return FALSE; gimp_text_get_transformation (layer->text, matrix); diff --git a/app/text/gimptextlayer-xcf.c b/app/text/gimptextlayer-xcf.c index 8bb315fe9d..313e17d8ae 100644 --- a/app/text/gimptextlayer-xcf.c +++ b/app/text/gimptextlayer-xcf.c @@ -32,6 +32,7 @@ #include "core/gimpimage.h" #include "core/gimplayer-xcf.h" #include "core/gimpparasitelist.h" +#include "core/gimprasterizable.h" #include "gimptext.h" #include "gimptext-parasite.h" @@ -153,7 +154,7 @@ gimp_text_layer_get_xcf_flags (GimpTextLayer *text_layer) if (! text_layer->auto_rename) flags |= TEXT_LAYER_XCF_DONT_AUTO_RENAME; - if (text_layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (text_layer))) flags |= TEXT_LAYER_XCF_MODIFIED; return flags; @@ -167,6 +168,8 @@ gimp_text_layer_set_xcf_flags (GimpTextLayer *text_layer, g_object_set (text_layer, "auto-rename", (flags & TEXT_LAYER_XCF_DONT_AUTO_RENAME) == 0, - "modified", (flags & TEXT_LAYER_XCF_MODIFIED) != 0, NULL); + + if ((flags & TEXT_LAYER_XCF_MODIFIED) != 0) + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (text_layer)); } diff --git a/app/text/gimptextlayer.c b/app/text/gimptextlayer.c index ad33c9b00b..4fd9db5ff0 100644 --- a/app/text/gimptextlayer.c +++ b/app/text/gimptextlayer.c @@ -49,6 +49,7 @@ #include "core/gimpitemtree.h" #include "core/gimpparasitelist.h" #include "core/gimppattern.h" +#include "core/gimprasterizable.h" #include "core/gimptempbuf.h" #include "gimptext.h" @@ -64,7 +65,6 @@ enum PROP_0, PROP_TEXT, PROP_AUTO_RENAME, - PROP_MODIFIED }; struct _GimpTextLayerPrivate @@ -72,6 +72,9 @@ struct _GimpTextLayerPrivate GimpTextDirection base_dir; }; +static void gimp_text_layer_rasterizable_iface_init + (GimpRasterizableInterface *iface); + static void gimp_text_layer_finalize (GObject *object); static void gimp_text_layer_get_property (GObject *object, guint property_id, @@ -82,6 +85,9 @@ static void gimp_text_layer_set_property (GObject *object, const GValue *value, GParamSpec *pspec); +static void gimp_text_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized); + static gint64 gimp_text_layer_get_memsize (GimpObject *object, gint64 *gui_size); @@ -123,7 +129,10 @@ static void gimp_text_layer_render_layout (GimpTextLayer *layer, GimpTextLayout *layout); -G_DEFINE_TYPE_WITH_PRIVATE (GimpTextLayer, gimp_text_layer, GIMP_TYPE_LAYER) +G_DEFINE_TYPE_WITH_CODE (GimpTextLayer, gimp_text_layer, GIMP_TYPE_LAYER, + G_ADD_PRIVATE (GimpTextLayer) + G_IMPLEMENT_INTERFACE (GIMP_TYPE_RASTERIZABLE, + gimp_text_layer_rasterizable_iface_init)) #define parent_class gimp_text_layer_parent_class @@ -182,12 +191,6 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass) NULL, NULL, TRUE, GIMP_PARAM_STATIC_STRINGS); - - GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_MODIFIED, - "modified", - NULL, NULL, - FALSE, - GIMP_PARAM_STATIC_STRINGS); } static void @@ -199,6 +202,12 @@ gimp_text_layer_init (GimpTextLayer *layer) layer->private = gimp_text_layer_get_instance_private (layer); } +static void +gimp_text_layer_rasterizable_iface_init (GimpRasterizableInterface *iface) +{ + iface->set_rasterized = gimp_text_layer_set_rasterized; +} + static void gimp_text_layer_finalize (GObject *object) { @@ -225,9 +234,6 @@ gimp_text_layer_get_property (GObject *object, case PROP_AUTO_RENAME: g_value_set_boolean (value, text_layer->auto_rename); break; - case PROP_MODIFIED: - g_value_set_boolean (value, text_layer->modified); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -251,9 +257,6 @@ gimp_text_layer_set_property (GObject *object, case PROP_AUTO_RENAME: text_layer->auto_rename = g_value_get_boolean (value); break; - case PROP_MODIFIED: - text_layer->modified = g_value_get_boolean (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -261,6 +264,14 @@ gimp_text_layer_set_property (GObject *object, } } +static void +gimp_text_layer_set_rasterized (GimpRasterizable *rasterizable, + gboolean rasterized) +{ + if (! rasterized) + gimp_text_layer_render (GIMP_TEXT_LAYER (rasterizable)); +} + static gint64 gimp_text_layer_get_memsize (GimpObject *object, gint64 *gui_size) @@ -284,7 +295,7 @@ gimp_text_layer_size_changed (GimpViewable *viewable) * gimp_drawable_size_changed () if the layer has been rasterized by * a transform. This prevents filters like Drop Shadow from being * cropped just by typing */ - if (text_layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (text_layer))) GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable); } @@ -352,8 +363,11 @@ gimp_text_layer_set_buffer (GimpDrawable *drawable, { GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + gboolean is_rasterized; - if (push_undo && ! layer->modified) + is_rasterized = gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer)); + + if (push_undo && ! is_rasterized) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD, undo_desc); @@ -361,12 +375,9 @@ gimp_text_layer_set_buffer (GimpDrawable *drawable, push_undo, undo_desc, buffer, bounds); - if (push_undo && ! layer->modified) + if (push_undo && ! is_rasterized) { - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - - g_object_set (drawable, "modified", TRUE, NULL); - + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); gimp_image_undo_group_end (image); } } @@ -382,20 +393,20 @@ gimp_text_layer_push_undo (GimpDrawable *drawable, { GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + gboolean is_rasterized; - if (! layer->modified) + is_rasterized = gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer)); + + if (! is_rasterized) 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) + if (! is_rasterized) { - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - - g_object_set (drawable, "modified", TRUE, NULL); - + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); gimp_image_undo_group_end (image); } } @@ -414,8 +425,8 @@ gimp_text_layer_convert_type (GimpLayer *layer, GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer); GimpImage *image = gimp_item_get_image (GIMP_ITEM (text_layer)); - if (! text_layer->text || - text_layer->modified || + if (! text_layer->text || + gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer)) || layer_dither_type != GEGL_DITHER_NONE) { GIMP_LAYER_CLASS (parent_class)->convert_type (layer, dest_image, @@ -550,10 +561,8 @@ gimp_text_layer_set (GimpTextLayer *layer, g_object_freeze_notify (G_OBJECT (layer)); - if (layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer))) { - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - /* pass copy_tiles = TRUE so we not only ref the tiles; after * being a text layer again, undo doesn't care about the * layer's pixels any longer because they are generated, so @@ -568,74 +577,21 @@ gimp_text_layer_set (GimpTextLayer *layer, gimp_image_undo_push_text_layer (image, undo_desc, layer, NULL); va_start (var_args, first_property_name); - g_object_set_valist (G_OBJECT (text), first_property_name, var_args); - va_end (var_args); - g_object_set (layer, "modified", FALSE, NULL); + gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); g_object_thaw_notify (G_OBJECT (layer)); gimp_image_undo_group_end (image); } -/** - * gimp_text_layer_discard: - * @layer: a #GimpTextLayer - * - * Discards the text information. This makes @layer behave like a - * normal layer. - */ -void -gimp_text_layer_discard (GimpTextLayer *layer) -{ - GimpImage *image; - - g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - if (layer->modified) - return; - - image = gimp_item_get_image (GIMP_ITEM (layer)); - - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - g_object_set (layer, "modified", TRUE, NULL); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); - /* Though technically selected layers are not changed, it will trigger - * actions update, so that visibility of any action depending on text - * layers being rasterized or not will be updated. - */ - g_signal_emit_by_name (image, "selected-layers-changed"); -} - -void -gimp_text_layer_retrieve (GimpTextLayer *layer) -{ - GimpImage *image; - - g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); - g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); - - if (! layer->modified) - return; - - image = gimp_item_get_image (GIMP_ITEM (layer)); - - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - gimp_image_undo_push_drawable_mod (image, NULL, GIMP_DRAWABLE (layer), TRUE); - g_object_set (layer, "modified", FALSE, NULL); - - gimp_text_layer_render (layer); - gimp_image_flush (image); -} - gboolean gimp_item_is_text_layer (GimpItem *item) { - return (GIMP_IS_TEXT_LAYER (item) && ! GIMP_TEXT_LAYER (item)->modified); + return (GIMP_IS_TEXT_LAYER (item) && + ! gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (item))); } diff --git a/app/text/gimptextlayer.h b/app/text/gimptextlayer.h index 73529de511..88e4301418 100644 --- a/app/text/gimptextlayer.h +++ b/app/text/gimptextlayer.h @@ -45,7 +45,6 @@ struct _GimpTextLayer */ gboolean text_parasite_is_old; /* Format before XCF 19. */ gboolean auto_rename; - gboolean modified; const Babl *convert_format; @@ -65,8 +64,6 @@ GimpLayer * gimp_text_layer_new (GimpImage *image, GimpText * gimp_text_layer_get_text (GimpTextLayer *layer); void gimp_text_layer_set_text (GimpTextLayer *layer, GimpText *text); -void gimp_text_layer_discard (GimpTextLayer *layer); -void gimp_text_layer_retrieve (GimpTextLayer *layer); void gimp_text_layer_set (GimpTextLayer *layer, const gchar *undo_desc, const gchar *first_property_name, diff --git a/app/text/gimptextundo.c b/app/text/gimptextundo.c index 3d720b8a2e..8b616bd6d4 100644 --- a/app/text/gimptextundo.c +++ b/app/text/gimptextundo.c @@ -127,10 +127,6 @@ gimp_text_undo_constructed (GObject *object) } break; - case GIMP_UNDO_TEXT_LAYER_MODIFIED: - text_undo->modified = layer->modified; - break; - case GIMP_UNDO_TEXT_LAYER_CONVERT: text_undo->format = gimp_drawable_get_format (GIMP_DRAWABLE (layer)); break; @@ -247,24 +243,6 @@ gimp_text_undo_pop (GimpUndo *undo, } break; - case GIMP_UNDO_TEXT_LAYER_MODIFIED: - { - gboolean modified; - -#if 0 - g_print ("setting layer->modified from %s to %s\n", - layer->modified ? "TRUE" : "FALSE", - text_undo->modified ? "TRUE" : "FALSE"); -#endif - - modified = layer->modified; - g_object_set (layer, "modified", text_undo->modified, NULL); - text_undo->modified = modified; - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); - } - break; - case GIMP_UNDO_TEXT_LAYER_CONVERT: { const Babl *format; diff --git a/app/text/gimptextundo.h b/app/text/gimptextundo.h index 1444c37a9b..9372f3b319 100644 --- a/app/text/gimptextundo.h +++ b/app/text/gimptextundo.h @@ -37,7 +37,6 @@ struct _GimpTextUndo GimpText *text; const GParamSpec *pspec; GValue *value; - gboolean modified; const Babl *format; }; diff --git a/app/tools/gimppathtool.c b/app/tools/gimppathtool.c index a74f01d9ab..98e952f9d6 100644 --- a/app/tools/gimppathtool.c +++ b/app/tools/gimppathtool.c @@ -35,6 +35,7 @@ #include "core/gimpimage-pick-item.h" #include "core/gimpimage-undo.h" #include "core/gimpimage-undo-push.h" +#include "core/gimprasterizable.h" #include "core/gimpstrokeoptions.h" #include "core/gimptoolinfo.h" #include "core/gimpundostack.h" @@ -149,9 +150,8 @@ static void gimp_path_tool_vector_change_notify const GParamSpec *pspec, GimpVectorLayer *layer); -static void gimp_path_tool_vector_layer_modified - (GimpVectorLayer *layer, - const GParamSpec *pspec, +static void gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, + gboolean is_rasterized, GimpPathTool *tool); static void gimp_path_tool_set_layer (GimpPathTool *path_tool, @@ -903,11 +903,11 @@ gimp_path_tool_vector_change_notify (GObject *options, } static void -gimp_path_tool_vector_layer_modified (GimpVectorLayer *layer, - const GParamSpec *pspec, - GimpPathTool *tool) +gimp_path_tool_layer_rasterized (GimpVectorLayer *layer, + gboolean is_rasterized, + GimpPathTool *tool) { - if (! layer->modified && ! GIMP_TOOL (tool)->display) + if (! is_rasterized && ! GIMP_TOOL (tool)->display) { GList *current_layers = NULL; @@ -919,7 +919,7 @@ gimp_path_tool_vector_layer_modified (GimpVectorLayer *layer, current_layers->data == layer) gimp_path_tool_set_layer (tool, layer); } - else if (layer->modified && GIMP_TOOL (tool)->display) + else if (is_rasterized && GIMP_TOOL (tool)->display) { gimp_path_tool_set_layer (tool, NULL); } @@ -948,7 +948,7 @@ gimp_path_tool_set_layer (GimpPathTool *path_tool, path_tool->current_vector_layer); g_signal_handlers_disconnect_by_func (path_tool->current_vector_layer, - G_CALLBACK (gimp_path_tool_vector_layer_modified), + G_CALLBACK (gimp_path_tool_layer_rasterized), path_tool); } @@ -980,8 +980,8 @@ gimp_path_tool_set_layer (GimpPathTool *path_tool, G_CALLBACK (gimp_path_tool_vector_change_notify), vector_layer, 0); - g_signal_connect_object (vector_layer, "notify::modified", - G_CALLBACK (gimp_path_tool_vector_layer_modified), + g_signal_connect_object (vector_layer, "set-rasterized", + G_CALLBACK (gimp_path_tool_layer_rasterized), path_tool, 0); } } @@ -1078,7 +1078,7 @@ gimp_path_tool_confirm_response (GimpViewableDialog *dialog, break; case GTK_RESPONSE_ACCEPT: - gimp_vector_layer_retrieve (layer); + gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); gimp_path_tool_set_layer (path_tool, layer); break; diff --git a/app/tools/gimptexttool.c b/app/tools/gimptexttool.c index a15fa71f04..4ffd81db58 100644 --- a/app/tools/gimptexttool.c +++ b/app/tools/gimptexttool.c @@ -45,6 +45,7 @@ #include "core/gimpimage-undo-push.h" #include "core/gimplayer-floating-selection.h" #include "core/gimplist.h" +#include "core/gimprasterizable.h" #include "core/gimptoolinfo.h" #include "core/gimpundostack.h" @@ -1350,7 +1351,7 @@ gimp_text_tool_layer_notify (GimpTextLayer *layer, if (! strcmp (pspec->name, "modified")) { - if (layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer))) gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display); } else if (! strcmp (pspec->name, "text")) @@ -1909,7 +1910,7 @@ gimp_text_tool_set_drawable (GimpTextTool *text_tool, if (layer == text_tool->layer && layer->text == text_tool->text) return TRUE; - if (layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer))) { if (confirm) { @@ -2109,13 +2110,11 @@ gimp_text_tool_apply (GimpTextTool *text_tool, if (push_undo) { - if (layer->modified) + if (gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (layer))) { undo_group = TRUE; gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL); - gimp_image_undo_push_text_layer_modified (image, NULL, layer); - /* see comment in gimp_text_layer_set() */ gimp_image_undo_push_drawable_mod (image, NULL, GIMP_DRAWABLE (layer), TRUE); @@ -2129,12 +2128,10 @@ gimp_text_tool_apply (GimpTextTool *text_tool, g_list_free (text_tool->pending); text_tool->pending = NULL; - if (push_undo) + if (undo_group) { - g_object_set (layer, "modified", FALSE, NULL); - - if (undo_group) - gimp_image_undo_group_end (image); + gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); + gimp_image_undo_group_end (image); } gimp_text_tool_frame_item (text_tool); diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index a86899d613..fedaa80e61 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -68,6 +68,7 @@ #include "core/gimpparasitelist.h" #include "core/gimppattern.h" #include "core/gimpprogress.h" +#include "core/gimprasterizable.h" #include "core/gimpselection.h" #include "core/gimpstrokeoptions.h" #include "core/gimpsymmetry.h" @@ -1021,7 +1022,9 @@ xcf_load_image (Gimp *gimp, "vector-layer-options", options, NULL); g_object_unref (options); - GIMP_VECTOR_LAYER (vlayer)->modified = vdata->modified; + + if (vdata->modified) + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (vlayer)); if (selected) { diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c index 10fdca3b83..ded3e954c4 100644 --- a/app/xcf/xcf-save.c +++ b/app/xcf/xcf-save.c @@ -62,6 +62,7 @@ #include "core/gimplist.h" #include "core/gimpparasitelist.h" #include "core/gimpprogress.h" +#include "core/gimprasterizable.h" #include "core/gimpsamplepoint.h" #include "core/gimpstrokeoptions.h" #include "core/gimpsymmetry.h" @@ -1708,7 +1709,7 @@ xcf_save_prop (XcfInfo *info, xcf_write_int32_check_error (info, &size, 1, va_end (args)); base = info->cp; - uint_val = (guint32) vector_layer->modified; + uint_val = (guint32) gimp_rasterizable_is_rasterized (GIMP_RASTERIZABLE (vector_layer)); xcf_write_int32_check_error (info, (guint32 *) &uint_val, 1, va_end (args)); uint_val = gimp_item_get_tattoo (GIMP_ITEM (options->path)); diff --git a/pdb/groups/link_layer.pdb b/pdb/groups/link_layer.pdb index 19d16c6fbd..87786a60b4 100644 --- a/pdb/groups/link_layer.pdb +++ b/pdb/groups/link_layer.pdb @@ -107,7 +107,7 @@ HELP %invoke = ( code => <<'CODE' { - gimp_link_layer_discard (layer); + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); } CODE ); @@ -133,7 +133,7 @@ HELP %invoke = ( code => <<'CODE' { - gimp_link_layer_monitor (layer); + gimp_rasterizable_restore (GIMP_RASTERIZABLE (layer)); } CODE ); @@ -242,6 +242,7 @@ CODE } @headers = qw("core/gimplink.h" "core/gimplinklayer.h" + "core/gimprasterizable.h" "gimppdberror.h" "gimp-intl.h"); diff --git a/pdb/groups/vector_layer.pdb b/pdb/groups/vector_layer.pdb index acce19395f..3616541b4a 100644 --- a/pdb/groups/vector_layer.pdb +++ b/pdb/groups/vector_layer.pdb @@ -117,7 +117,7 @@ HELP %invoke = ( code => <<'CODE' { - gimp_vector_layer_discard (layer); + gimp_rasterizable_rasterize (GIMP_RASTERIZABLE (layer)); } CODE ); @@ -941,6 +941,7 @@ CODE @headers = qw("libgimpbase/gimpbase.h" "core/gimpcontext.h" "core/gimpdashpattern.h" + "core/gimprasterizable.h" "core/gimpstrokeoptions.h" "path/gimpvectorlayer.h" "path/gimpvectorlayeroptions.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 7820c5b0dd..244a6db557 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -197,6 +197,7 @@ app/core/gimppattern-save.c app/core/gimppatternclipboard.c app/core/gimppdbprogress.c app/core/gimpprogress.c +app/core/gimprasterizable.c app/core/gimpselection.c app/core/gimpsettings.c app/core/gimpstrokeoptions.c