[gimp/wip/Jehan/layers-dockable-refresh: 105/105] app, devel-docs: saving the item sets in XCF (bumping to XCF 16).
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/Jehan/layers-dockable-refresh: 105/105] app, devel-docs: saving the item sets in XCF (bumping to XCF 16).
- Date: Thu, 23 Dec 2021 00:44:41 +0000 (UTC)
commit 9d941c0b760f9586c0822003e2dd02bc161c5a30
Author: Jehan <jehan girinstud io>
Date: Wed Dec 22 22:53:15 2021 +0100
app, devel-docs: saving the item sets in XCF (bumping to XCF 16).
We now save and load layer and channel item sets. Only missing set types
are path ones, but the whole path item is just its own exception in the
XCF format, and adding support for it, while keeping compatibility with
older XCF seem like a small headache. I could do it, but I actually
wonder if it is worth it. Would people really need to store sets of
paths?
Also this commit finally gets rid of any remnant of the old item "link"
concept (I think), so we are getting close to merging the branch.
app/core/gimpimage.c | 29 +++++++-
app/core/gimpitem.c | 27 --------
app/core/gimpitem.h | 3 -
app/core/gimpitemlist.c | 39 +++++++++--
app/core/gimpitemlist.h | 5 +-
app/gimpcore.def | 1 -
app/pdb/gimp-pdb-compat.c | 6 --
app/widgets/gimplayertreeview.c | 2 +-
app/xcf/xcf-load.c | 149 +++++++++++++++++++++++++++++++++++++++-
app/xcf/xcf-private.h | 5 ++
app/xcf/xcf-save.c | 111 ++++++++++++++++++++++++++++--
devel-docs/app/app-sections.txt | 1 -
devel-docs/xcf.txt | 48 ++++++++++++-
13 files changed, 369 insertions(+), 57 deletions(-)
---
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 850a6f34f1..76f87202b7 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -2914,6 +2914,21 @@ gimp_image_get_xcf_version (GimpImage *image,
}
}
+ if (gimp_image_get_stored_item_sets (image, GIMP_TYPE_LAYER) ||
+ gimp_image_get_stored_item_sets (image, GIMP_TYPE_CHANNEL))
+ {
+ ADD_REASON (g_strdup_printf (_("Item set and pattern search in item's name were "
+ "added in %s"), "GIMP 3.0.0"));
+ version = MAX (16, version);
+ }
+ if (g_list_length (gimp_image_get_selected_channels (image)) > 1)
+ {
+ ADD_REASON (g_strdup_printf (_("Multiple channel selection was "
+ "added in %s"), "GIMP 3.0.0"));
+ version = MAX (16, version);
+ }
+
+
#undef ADD_REASON
switch (version)
@@ -2945,6 +2960,7 @@ gimp_image_get_xcf_version (GimpImage *image,
break;
case 14:
case 15:
+ case 16:
if (gimp_version) *gimp_version = 300;
if (version_string) *version_string = "GIMP 3.0";
break;
@@ -5439,8 +5455,16 @@ gimp_image_store_item_set (GimpImage *image,
for (iter = *stored_sets; iter; iter = iter->next)
{
+ gboolean is_pattern;
+ gboolean is_pattern2;
+ GimpSelectMethod pattern_syntax;
+ GimpSelectMethod pattern_syntax2;
+
+ is_pattern = gimp_item_list_is_pattern (iter->data, &pattern_syntax);
+ is_pattern2 = gimp_item_list_is_pattern (set, &pattern_syntax2);
+
/* Remove a previous item set of same type and name. */
- if (gimp_item_list_is_pattern (iter->data) == gimp_item_list_is_pattern (set) &&
+ if (is_pattern == is_pattern2 && (! is_pattern || pattern_syntax == pattern_syntax2) &&
g_strcmp0 (gimp_object_get_name (iter->data), gimp_object_get_name (set)) == 0)
break;
}
@@ -5513,9 +5537,10 @@ gimp_image_unlink_item_set (GimpImage *image,
/*
* @gimp_image_get_stored_item_sets:
* @image:
+ * @item_type:
*
* Returns: (transfer none): the list of all the layer sets (which you
- * should not modify). Order of items is not relevant.
+ * should not modify). Order of items is relevant.
*/
GList *
gimp_image_get_stored_item_sets (GimpImage *image,
diff --git a/app/core/gimpitem.c b/app/core/gimpitem.c
index f4817bba6b..d4e2f81bfc 100644
--- a/app/core/gimpitem.c
+++ b/app/core/gimpitem.c
@@ -53,7 +53,6 @@ enum
{
REMOVED,
VISIBILITY_CHANGED,
- LINKED_CHANGED,
COLOR_TAG_CHANGED,
LOCK_CONTENT_CHANGED,
LOCK_POSITION_CHANGED,
@@ -71,7 +70,6 @@ enum
PROP_OFFSET_X,
PROP_OFFSET_Y,
PROP_VISIBLE,
- PROP_LINKED,
PROP_COLOR_TAG,
PROP_LOCK_CONTENT,
PROP_LOCK_POSITION,
@@ -97,7 +95,6 @@ struct _GimpItemPrivate
guint visible : 1; /* item visibility */
guint bind_visible_to_active : 1; /* visibility bound to active */
- guint linked : 1; /* control linkage */
guint lock_content : 1; /* content editability */
guint lock_position : 1; /* content movability */
guint lock_visibility : 1; /* automatic visibility change */
@@ -204,14 +201,6 @@ gimp_item_class_init (GimpItemClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 0);
- gimp_item_signals[LINKED_CHANGED] =
- g_signal_new ("linked-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GimpItemClass, linked_changed),
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-
gimp_item_signals[COLOR_TAG_CHANGED] =
g_signal_new ("color-tag-changed",
G_TYPE_FROM_CLASS (klass),
@@ -257,7 +246,6 @@ gimp_item_class_init (GimpItemClass *klass)
klass->removed = NULL;
klass->visibility_changed = NULL;
- klass->linked_changed = NULL;
klass->color_tag_changed = NULL;
klass->lock_content_changed = NULL;
klass->lock_position_changed = NULL;
@@ -329,10 +317,6 @@ gimp_item_class_init (GimpItemClass *klass)
TRUE,
GIMP_PARAM_READABLE);
- gimp_item_props[PROP_LINKED] = g_param_spec_boolean ("linked", NULL, NULL,
- FALSE,
- GIMP_PARAM_READABLE);
-
gimp_item_props[PROP_COLOR_TAG] = g_param_spec_enum ("color-tag", NULL, NULL,
GIMP_TYPE_COLOR_TAG,
GIMP_COLOR_TAG_NONE,
@@ -453,9 +437,6 @@ gimp_item_get_property (GObject *object,
case PROP_VISIBLE:
g_value_set_boolean (value, private->visible);
break;
- case PROP_LINKED:
- g_value_set_boolean (value, private->linked);
- break;
case PROP_COLOR_TAG:
g_value_set_enum (value, private->color_tag);
break;
@@ -2380,14 +2361,6 @@ gimp_item_bind_visible_to_active (GimpItem *item,
gimp_filter_set_active (GIMP_FILTER (item), gimp_item_get_visible (item));
}
-gboolean
-gimp_item_get_linked (GimpItem *item)
-{
- g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
-
- return GET_PRIVATE (item)->linked;
-}
-
void
gimp_item_set_color_tag (GimpItem *item,
GimpColorTag color_tag,
diff --git a/app/core/gimpitem.h b/app/core/gimpitem.h
index 53ae990430..38685fb2c4 100644
--- a/app/core/gimpitem.h
+++ b/app/core/gimpitem.h
@@ -44,7 +44,6 @@ struct _GimpItemClass
/* signals */
void (* removed) (GimpItem *item);
void (* visibility_changed) (GimpItem *item);
- void (* linked_changed) (GimpItem *item);
void (* color_tag_changed) (GimpItem *item);
void (* lock_content_changed) (GimpItem *item);
void (* lock_position_changed) (GimpItem *item);
@@ -364,8 +363,6 @@ gboolean gimp_item_is_visible (GimpItem *item);
void gimp_item_bind_visible_to_active (GimpItem *item,
gboolean bind);
-gboolean gimp_item_get_linked (GimpItem *item);
-
void gimp_item_set_color_tag (GimpItem *item,
GimpColorTag color_tag,
gboolean push_undo);
diff --git a/app/core/gimpitemlist.c b/app/core/gimpitemlist.c
index 7dd5c08e89..bf8f548c9d 100644
--- a/app/core/gimpitemlist.c
+++ b/app/core/gimpitemlist.c
@@ -65,7 +65,6 @@ struct _GimpItemListPrivate
{
GimpImage *image;
- gchar *label; /* Item set name or pattern. */
gboolean is_pattern; /* Whether a named fixed set or a pattern-search. */
GimpSelectMethod select_method; /* Pattern format if is_pattern is TRUE */
@@ -174,7 +173,6 @@ gimp_item_list_init (GimpItemList *set)
{
set->p = gimp_item_list_get_instance_private (set);
- set->p->label = NULL;
set->p->items = NULL;
set->p->select_method = GIMP_SELECT_PLAIN_TEXT;
set->p->is_pattern = FALSE;
@@ -188,7 +186,6 @@ gimp_item_list_constructed (GObject *object)
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_IMAGE (set->p->image));
- gimp_assert (set->p->items != NULL || set->p->is_pattern);
gimp_assert (set->p->item_type == GIMP_TYPE_LAYER ||
set->p->item_type == GIMP_TYPE_VECTORS ||
set->p->item_type == GIMP_TYPE_CHANNEL);
@@ -244,7 +241,6 @@ gimp_item_list_finalize (GObject *object)
g_list_free (set->p->items);
g_list_free_full (set->p->deleted_items,
(GDestroyNotify) gimp_item_list_free_deleted_item);
- g_free (set->p->label);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -460,14 +456,47 @@ gimp_item_list_get_items (GimpItemList *set,
return items;
}
+/**
+ * gimp_item_list_is_pattern:
+ * @set: The #GimpItemList.
+ * @pattern_syntax: The type of patterns @set handles.
+ *
+ * Indicate if @set is a pattern list. If the returned value is %TRUE,
+ * then @pattern_syntax will be set to the syntax we are dealing with.
+ *
+ * Returns: %TRUE if @set is a pattern list, %FALSE if it is a named
+ * list.
+ */
gboolean
-gimp_item_list_is_pattern (GimpItemList *set)
+gimp_item_list_is_pattern (GimpItemList *set,
+ GimpSelectMethod *pattern_syntax)
{
g_return_val_if_fail (GIMP_IS_ITEM_LIST (set), FALSE);
+ if (set->p->is_pattern && pattern_syntax)
+ *pattern_syntax = set->p->select_method;
+
return (set->p->is_pattern);
}
+/**
+ * gimp_item_list_is_pattern:
+ * @set: The #GimpItemList.
+ * @item: #GimpItem to add to @set.
+ *
+ * Add @item to the named list @set whose item type must also agree.
+ */
+void
+gimp_item_list_add (GimpItemList *set,
+ GimpItem *item)
+{
+ g_return_if_fail (GIMP_IS_ITEM_LIST (set));
+ g_return_if_fail (! gimp_item_list_is_pattern (set, NULL));
+ g_return_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (item), set->p->item_type));
+
+ set->p->items = g_list_prepend (set->p->items, item);
+}
+
/* Private functions */
diff --git a/app/core/gimpitemlist.h b/app/core/gimpitemlist.h
index 180beae5c0..5575d7ad73 100644
--- a/app/core/gimpitemlist.h
+++ b/app/core/gimpitemlist.h
@@ -61,7 +61,10 @@ GimpItemList * gimp_item_list_pattern_new (GimpImage *image,
GType gimp_item_list_get_item_type (GimpItemList *set);
GList * gimp_item_list_get_items (GimpItemList *set,
GError **error);
-gboolean gimp_item_list_is_pattern (GimpItemList *set);
+gboolean gimp_item_list_is_pattern (GimpItemList *set,
+ GimpSelectMethod *pattern_syntax);
+void gimp_item_list_add (GimpItemList *set,
+ GimpItem *item);
#endif /* __GIMP_ITEM_LIST_H__ */
diff --git a/app/gimpcore.def b/app/gimpcore.def
index b93cbb91ba..30c66ee0bd 100644
--- a/app/gimpcore.def
+++ b/app/gimpcore.def
@@ -394,7 +394,6 @@ EXPORTS
gimp_item_get_by_ID
gimp_item_get_ID
gimp_item_get_image
- gimp_item_get_linked
gimp_item_get_type
gimp_item_get_visible
gimp_item_height
diff --git a/app/pdb/gimp-pdb-compat.c b/app/pdb/gimp-pdb-compat.c
index 77e0aaf364..98e84abe7e 100644
--- a/app/pdb/gimp-pdb-compat.c
+++ b/app/pdb/gimp-pdb-compat.c
@@ -60,12 +60,10 @@ gimp_pdb_compat_procs_register (GimpPDB *pdb,
{ "gimp-image-active-drawable", "gimp-image-get-active-drawable" },
{ "gimp-image-floating-selection", "gimp-image-get-floating-sel" },
{ "gimp-layer-delete", "gimp-item-delete" },
- { "gimp-layer-get-linked", "gimp-item-get-linked" },
{ "gimp-layer-get-name", "gimp-item-get-name" },
{ "gimp-layer-get-tattoo", "gimp-item-get-tattoo" },
{ "gimp-layer-get-visible", "gimp-item-get-visible" },
{ "gimp-layer-mask", "gimp-layer-get-mask" },
- { "gimp-layer-set-linked", "gimp-item-set-linked" },
{ "gimp-layer-set-name", "gimp-item-set-name" },
{ "gimp-layer-set-tattoo", "gimp-item-set-tattoo" },
{ "gimp-layer-set-visible", "gimp-item-set-visible" },
@@ -115,8 +113,6 @@ gimp_pdb_compat_procs_register (GimpPDB *pdb,
{ "gimp-drawable-set-name", "gimp-item-set-name" },
{ "gimp-drawable-get-visible", "gimp-item-get-visible" },
{ "gimp-drawable-set-visible", "gimp-item-set-visible" },
- { "gimp-drawable-get-linked", "gimp-item-get-linked" },
- { "gimp-drawable-set-linked", "gimp-item-set-linked" },
{ "gimp-drawable-get-tattoo", "gimp-item-get-tattoo" },
{ "gimp-drawable-set-tattoo", "gimp-item-set-tattoo" },
{ "gimp-drawable-parasite-find", "gimp-item-get-parasite" },
@@ -142,8 +138,6 @@ gimp_pdb_compat_procs_register (GimpPDB *pdb,
{ "gimp-vectors-set-name", "gimp-item-set-name" },
{ "gimp-vectors-get-visible", "gimp-item-get-visible" },
{ "gimp-vectors-set-visible", "gimp-item-set-visible" },
- { "gimp-vectors-get-linked", "gimp-item-get-linked" },
- { "gimp-vectors-set-linked", "gimp-item-set-linked" },
{ "gimp-vectors-get-tattoo", "gimp-item-get-tattoo" },
{ "gimp-vectors-set-tattoo", "gimp-item-set-tattoo" },
{ "gimp-vectors-parasite-find", "gimp-item-get-parasite" },
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index 3ee84bcaf7..c35c243553 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -1125,7 +1125,7 @@ gimp_layer_tree_view_layer_links_changed (GimpImage *image,
label = gtk_label_new (gimp_object_get_name (iter->data));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- if (gimp_item_list_is_pattern (iter->data))
+ if (gimp_item_list_is_pattern (iter->data, NULL))
{
PangoAttrList *attrs = pango_attr_list_new ();
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 6920956a81..53d625d594 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -256,6 +256,10 @@ xcf_load_image (Gimp *gimp,
GIMP_LOG (XCF, "image props loaded");
+ /* Order matters for item sets. */
+ info->layer_sets = g_list_reverse (info->layer_sets);
+ info->channel_sets = g_list_reverse (info->channel_sets);
+
/* check for a GimpGrid parasite */
parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
gimp_grid_parasite_name ());
@@ -705,18 +709,48 @@ xcf_load_image (Gimp *gimp,
_("Linked Channels"),
info->linked_channels);
gimp_image_store_item_set (image, set);
- g_clear_pointer (&info->linked_layers, g_list_free);
+ g_clear_pointer (&info->linked_channels, g_list_free);
}
if (info->linked_paths)
{
+ /* It is kind of ugly but vectors are really implemented as
+ * exception in our XCF spec and building over it seems like a
+ * mistake. Since I'm seriously not sure this would be much of an
+ * issue, I'll let it as it for now.
+ * Note that it's still possible to multi-select paths. It's only
+ * not possible to store these selections.
+ *
+ * Only warn for more than 1 linked path. Less is kind of
+ * pointless and doesn't deserve worrying people for no reason.
+ */
+ if (g_list_length (info->linked_paths) > 1)
+ g_printerr ("xcf: some paths were linked. "
+ "GIMP does not support linked paths since version 3.0.\n");
+
+#if 0
GimpItemList *set;
set = gimp_item_list_named_new (image, GIMP_TYPE_VECTORS,
_("Linked Paths"),
info->linked_paths);
gimp_image_store_item_set (image, set);
- g_clear_pointer (&info->linked_layers, g_list_free);
+#endif
+ g_clear_pointer (&info->linked_paths, g_list_free);
+ }
+
+ for (iter = g_list_last (info->layer_sets); iter; iter = iter->prev)
+ {
+ if (iter->data)
+ gimp_image_store_item_set (image, iter->data);
+ }
+ g_list_free (info->layer_sets);
+
+ for (iter = g_list_last (info->channel_sets); iter; iter = iter->prev)
+ {
+ if (iter->data)
+ gimp_image_store_item_set (image, iter->data);
}
+ g_list_free (info->channel_sets);
if (info->file)
gimp_image_set_file (image, info->file);
@@ -1203,6 +1237,74 @@ xcf_load_image_props (XcfInfo *info,
}
break;
+ case PROP_ITEM_SET:
+ {
+ GimpItemList *set = NULL;
+ gchar *label;
+ GType item_type = 0;
+ guint32 itype;
+ guint32 method;
+
+ xcf_read_int32 (info, &itype, 1);
+ xcf_read_int32 (info, &method, 1);
+ xcf_read_string (info, &label, 1);
+
+ if (itype == 0)
+ item_type = GIMP_TYPE_LAYER;
+ else
+ item_type = GIMP_TYPE_CHANNEL;
+
+ if (itype > 1)
+ {
+ g_printerr ("xcf: unsupported item set '%s' type: %d (skipping)\n",
+ label ? label : "unnamed", itype);
+ /* Only case where we break because we wouldn't even
+ * know where to categorize the item set anyway. */
+ break;
+ }
+ else if (label == NULL)
+ {
+ g_printerr ("xcf: item set without a name or pattern (skipping)\n");
+ }
+ else if (method != G_MAXUINT32 && method > GIMP_SELECT_GLOB_PATTERN)
+ {
+ g_printerr ("xcf: unsupported item set '%s' selection method attribute: 0x%x (skipping)\n",
+ label, method);
+ }
+ else
+ {
+ if (method == G_MAXUINT32)
+ {
+ /* Don't use gimp_item_list_named_new() because it
+ * doesn't allow NULL items (it would try to get the
+ * selected items instead).
+ */
+ set = g_object_new (GIMP_TYPE_ITEM_LIST,
+ "image", image,
+ "name", label,
+ "is-pattern", FALSE,
+ "item-type", item_type,
+ "items", NULL,
+ NULL);
+ }
+ else
+ {
+ set = gimp_item_list_pattern_new (image, item_type,
+ method, label);
+ }
+ }
+
+ /* Note: we are still adding invalid item sets as NULL on
+ * purpose, in order not to break order-base association
+ * between PROP_ITEM_SET and PROP_ITEM_SET_ITEM.
+ */
+ if (item_type == GIMP_TYPE_LAYER)
+ info->layer_sets = g_list_prepend (info->layer_sets, set);
+ else
+ info->channel_sets = g_list_prepend (info->channel_sets, set);
+ }
+ break;
+
default:
#ifdef GIMP_UNSTABLE
g_printerr ("unexpected/unknown image property: %d (skipping)\n",
@@ -1579,6 +1681,29 @@ xcf_load_layer_props (XcfInfo *info,
xcf_read_int32 (info, group_layer_flags, 1);
break;
+ case PROP_ITEM_SET_ITEM:
+ {
+ GimpItemList *set;
+ guint32 n;
+
+ xcf_read_int32 (info, &n, 1);
+ set = g_list_nth_data (info->layer_sets, n);
+ if (set == NULL)
+ g_printerr ("xcf: layer '%s' cannot be added to unknown layer set at index %d (skipping)\n",
+ gimp_object_get_name (*layer), n);
+ else if (! g_type_is_a (G_TYPE_FROM_INSTANCE (*layer),
+ gimp_item_list_get_item_type (set)))
+ g_printerr ("xcf: layer '%s' cannot be added to item set '%s' with item type %s
(skipping)\n",
+ gimp_object_get_name (*layer), gimp_object_get_name (set),
+ g_type_name (gimp_item_list_get_item_type (set)));
+ else if (gimp_item_list_is_pattern (set, NULL))
+ g_printerr ("xcf: layer '%s' cannot be added to pattern item set '%s' (skipping)\n",
+ gimp_object_get_name (*layer), gimp_object_get_name (set));
+ else
+ gimp_item_list_add (set, GIMP_ITEM (*layer));
+ }
+ break;
+
default:
#ifdef GIMP_UNSTABLE
g_printerr ("unexpected/unknown layer property: %d (skipping)\n",
@@ -1672,6 +1797,7 @@ xcf_check_layer_props (XcfInfo *info,
case PROP_COMPOSITE_MODE:
case PROP_TATTOO:
case PROP_PARASITES:
+ case PROP_ITEM_SET_ITEM:
if (! xcf_skip_unknown_prop (info, prop_size))
return FALSE;
/* Just ignore for now. */
@@ -1896,6 +2022,25 @@ xcf_load_channel_props (XcfInfo *info,
}
break;
+ case PROP_ITEM_SET_ITEM:
+ {
+ GimpItemList *set;
+ guint32 n;
+
+ xcf_read_int32 (info, &n, 1);
+ set = g_list_nth_data (info->channel_sets, n);
+ if (set == NULL)
+ g_printerr ("xcf: unknown channel set: %d (skipping)\n", n);
+ else if (! g_type_is_a (G_TYPE_FROM_INSTANCE (*channel),
+ gimp_item_list_get_item_type (set)))
+ g_printerr ("xcf: channel '%s' cannot be added to item set '%s' with item type %s
(skipping)\n",
+ gimp_object_get_name (*channel), gimp_object_get_name (set),
+ g_type_name (gimp_item_list_get_item_type (set)));
+ else
+ gimp_item_list_add (set, GIMP_ITEM (*channel));
+ }
+ break;
+
default:
#ifdef GIMP_UNSTABLE
g_printerr ("unexpected/unknown channel property: %d (skipping)\n",
diff --git a/app/xcf/xcf-private.h b/app/xcf/xcf-private.h
index b9fecf8f9a..f371dac15d 100644
--- a/app/xcf/xcf-private.h
+++ b/app/xcf/xcf-private.h
@@ -65,6 +65,8 @@ typedef enum
PROP_BLEND_SPACE = 37,
PROP_FLOAT_COLOR = 38,
PROP_SAMPLE_POINTS = 39,
+ PROP_ITEM_SET = 40,
+ PROP_ITEM_SET_ITEM = 41,
} PropType;
typedef enum
@@ -116,6 +118,9 @@ struct _XcfInfo
GList *linked_channels;
GList *linked_paths;
+ GList *layer_sets;
+ GList *channel_sets;
+
GimpDrawable *floating_sel_drawable;
GimpLayer *floating_sel;
goffset floating_sel_offset;
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index b325243687..56b773788b 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -46,6 +46,7 @@
#include "core/gimpimage-private.h"
#include "core/gimpimage-sample-points.h"
#include "core/gimpimage-symmetry.h"
+#include "core/gimpitemlist.h"
#include "core/gimplayer.h"
#include "core/gimplayermask.h"
#include "core/gimpparasitelist.h"
@@ -487,6 +488,14 @@ xcf_save_image_props (XcfInfo *info,
g_list_free_full (symmetry_parasites,
(GDestroyNotify) gimp_parasite_free);
+ info->layer_sets = gimp_image_get_stored_item_sets (image, GIMP_TYPE_LAYER);
+ info->channel_sets = gimp_image_get_stored_item_sets (image, GIMP_TYPE_CHANNEL);
+
+ for (iter = info->layer_sets; iter; iter = iter->next)
+ xcf_check_error (xcf_save_prop (info, image, PROP_ITEM_SET, error, iter->data));
+ for (iter = info->channel_sets; iter; iter = iter->next)
+ xcf_check_error (xcf_save_prop (info, image, PROP_ITEM_SET, error, iter->data));
+
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
return TRUE;
@@ -499,6 +508,7 @@ xcf_save_layer_props (XcfInfo *info,
GError **error)
{
GimpParasiteList *parasites;
+ GList *iter;
gint offset_x;
gint offset_y;
@@ -531,8 +541,6 @@ xcf_save_layer_props (XcfInfo *info,
gimp_layer_get_opacity (layer)));
xcf_check_error (xcf_save_prop (info, image, PROP_VISIBLE, error,
gimp_item_get_visible (GIMP_ITEM (layer))));
- xcf_check_error (xcf_save_prop (info, image, PROP_LINKED, error,
- gimp_item_get_linked (GIMP_ITEM (layer))));
xcf_check_error (xcf_save_prop (info, image, PROP_COLOR_TAG, error,
gimp_item_get_color_tag (GIMP_ITEM (layer))));
xcf_check_error (xcf_save_prop (info, image, PROP_LOCK_CONTENT, error,
@@ -612,6 +620,22 @@ xcf_save_layer_props (XcfInfo *info,
parasites));
}
+ for (iter = info->layer_sets; iter; iter = iter->next)
+ {
+ GimpItemList *set = iter->data;
+
+ if (! gimp_item_list_is_pattern (set, NULL))
+ {
+ GList *items = gimp_item_list_get_items (set, NULL);
+
+ if (g_list_find (items, GIMP_ITEM (layer)))
+ xcf_check_error (xcf_save_prop (info, image, PROP_ITEM_SET_ITEM, error,
+ g_list_position (info->layer_sets, iter)));
+
+ g_list_free (items);
+ }
+ }
+
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
return TRUE;
@@ -624,6 +648,7 @@ xcf_save_channel_props (XcfInfo *info,
GError **error)
{
GimpParasiteList *parasites;
+ GList *iter;
if (g_list_find (gimp_image_get_selected_channels (image), channel))
xcf_check_error (xcf_save_prop (info, image, PROP_ACTIVE_CHANNEL, error));
@@ -637,8 +662,6 @@ xcf_save_channel_props (XcfInfo *info,
gimp_channel_get_opacity (channel)));
xcf_check_error (xcf_save_prop (info, image, PROP_VISIBLE, error,
gimp_item_get_visible (GIMP_ITEM (channel))));
- xcf_check_error (xcf_save_prop (info, image, PROP_LINKED, error,
- gimp_item_get_linked (GIMP_ITEM (channel))));
xcf_check_error (xcf_save_prop (info, image, PROP_COLOR_TAG, error,
gimp_item_get_color_tag (GIMP_ITEM (channel))));
xcf_check_error (xcf_save_prop (info, image, PROP_LOCK_CONTENT, error,
@@ -662,6 +685,22 @@ xcf_save_channel_props (XcfInfo *info,
parasites));
}
+ for (iter = info->channel_sets; iter; iter = iter->next)
+ {
+ GimpItemList *set = iter->data;
+
+ if (! gimp_item_list_is_pattern (set, NULL))
+ {
+ GList *items = gimp_item_list_get_items (set, NULL);
+
+ if (g_list_find (items, GIMP_ITEM (channel)))
+ xcf_check_error (xcf_save_prop (info, image, PROP_ITEM_SET_ITEM, error,
+ g_list_position (info->channel_sets, iter)));
+
+ g_list_free (items);
+ }
+ }
+
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
return TRUE;
@@ -850,6 +889,9 @@ xcf_save_prop (XcfInfo *info,
break;
case PROP_LINKED:
+ /* This code should not be called any longer. */
+ g_return_val_if_reached (FALSE);
+#if 0
{
guint32 linked = va_arg (args, guint32);
@@ -860,6 +902,7 @@ xcf_save_prop (XcfInfo *info,
xcf_write_int32_check_error (info, &linked, 1);
}
+#endif
break;
case PROP_COLOR_TAG:
@@ -1344,6 +1387,60 @@ xcf_save_prop (XcfInfo *info,
xcf_write_int32_check_error (info, &flags, 1);
}
break;
+
+ case PROP_ITEM_SET:
+ {
+ GimpItemList *set = va_arg (args, GimpItemList *);
+ const gchar *string;
+ guint32 method;
+ guint32 item_type;
+ goffset base;
+ goffset pos;
+
+ size = 0;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &size, 1);
+ base = info->cp;
+
+ if (gimp_item_list_get_item_type (set) == GIMP_TYPE_LAYER)
+ item_type = 0;
+ else if (gimp_item_list_get_item_type (set) == GIMP_TYPE_CHANNEL)
+ item_type = 1;
+ else if (gimp_item_list_get_item_type (set) == GIMP_TYPE_VECTORS)
+ item_type = 2;
+ else
+ g_return_val_if_reached (FALSE);
+ xcf_write_int32_check_error (info, &item_type, 1);
+
+ if (! gimp_item_list_is_pattern (set, &method))
+ method = G_MAXUINT32;
+ xcf_write_int32_check_error (info, &method, 1);
+
+ string = gimp_object_get_name (set);
+ xcf_write_string_check_error (info, (gchar **) &string, 1);
+
+ /* go back to the saved position and write the length */
+ size = info->cp - base;
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32_check_error (info, &size, 1);
+
+ xcf_check_error (xcf_seek_pos (info, base + size, error));
+ }
+ break;
+
+ case PROP_ITEM_SET_ITEM:
+ {
+ guint32 set_n = va_arg (args, guint32);
+
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &set_n, 1);
+ }
+ break;
}
va_end (args);
@@ -2074,7 +2171,8 @@ xcf_save_old_paths (XcfInfo *info,
* around to fix that cruft */
name = (gchar *) gimp_object_get_name (vectors);
- locked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ /* The 'linked' concept does not exist anymore in GIMP 3.0 and over. */
+ locked = 0;
state = closed ? 4 : 2; /* EDIT : ADD (editing state, 1.2 compat) */
version = 3;
pathtype = 1; /* BEZIER (1.2 compat) */
@@ -2175,7 +2273,8 @@ xcf_save_vectors (XcfInfo *info,
name = gimp_object_get_name (vectors);
visible = gimp_item_get_visible (GIMP_ITEM (vectors));
- linked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ /* The 'linked' concept does not exist anymore in GIMP 3.0 and over. */
+ linked = 0;
tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
parasites = gimp_item_get_parasites (GIMP_ITEM (vectors));
num_parasites = gimp_parasite_list_persistent_length (parasites);
diff --git a/devel-docs/app/app-sections.txt b/devel-docs/app/app-sections.txt
index 19b2ddf2b3..faab30eb7e 100644
--- a/devel-docs/app/app-sections.txt
+++ b/devel-docs/app/app-sections.txt
@@ -2513,7 +2513,6 @@ gimp_item_parasite_list
gimp_item_get_visible
gimp_item_set_visible
gimp_item_is_visible
-gimp_item_get_linked
gimp_item_get_lock_content
gimp_item_set_lock_content
gimp_item_can_lock_content
diff --git a/devel-docs/xcf.txt b/devel-docs/xcf.txt
index 0692b9c17e..faf5125a02 100644
--- a/devel-docs/xcf.txt
+++ b/devel-docs/xcf.txt
@@ -185,6 +185,15 @@ Since GIMP 3.0.0, released on TODO.
PROP_GUIDES now allows off-canvas guide positions, i.e. negative
positions and over canvas-dimensions positions.
+Version 16:
+Since GIMP 3.0.0, released on TODO.
+- Allows multiple channels to have the property PROP_ACTIVE_CHANNEL,
+ hence multiple channels selected at once.
+- PROP_LINKED is deprecated. Old XCF files loaded by newer GIMP will
+ transform linked items into stored item sets PROP_ITEM_SET.
+- New PROP_ITEM_SET and PROP_ITEM_SET_ITEM to store sets of layers,
+ channels or paths.
+
1. BASIC CONCEPTS
=================
@@ -641,6 +650,10 @@ PROP_LINKED (editing state)
all other linked elements will be transformed the same way.
It appears in the property list for layers, channels and paths.
+ PROP_LINKED property is deprecated and must not be used since XCF
+ version 16. XCF readers and writers are expected to convert linked
+ items into item sets instead (see PROP_ITEM_SET).
+
PROP_LOCK_CONTENT (since version 3, editing state)
uint32 28 Type identification
uint32 4 Four bytes of payload
@@ -713,6 +726,19 @@ PROP_VISIBLE (essential)
When reading old XCF files that lack this property, assume that
layers are visible and channels are not.
+PROP_ITEM_SET_ITEM (since GIMP 3.0)
+ uint32 41 Type identification
+ uint32 4 Four bytes of payload
+ uint32 set The PROP_ITEM_SET this item is listed in.
+
+ PROP_ITEM_SET_ITEM can be assigned to layers, channels and paths. They are
+ only organisational properties and have no consequence on render.
+
+ The 'set' attribute corresponds to the numbered PROP_ITEM_SET this
+ item belongs to, considering that the appearance order of
+ PROP_ITEM_SET properties matter. It can only belong to a named item
+ set and all items in a set must be of the proper type.
+
3. THE IMAGE STRUCTURE
======================
@@ -921,7 +947,7 @@ PROP_PATHS
Note: the attribute 'linked' was formerly erroneously called 'locked'
(but meant 'linked' anyway).
-
+
A closed path is a path which has the last and the first point connected,
for instance a triangle.
@@ -956,7 +982,7 @@ PROP_RESOLUTION (not editing state, but not _really_ essential either)
resolution.
PROP_SAMPLE_POINTS
- uint32 17 Type identification
+ uint32 39 Type identification
uint32 plength Total length of the following payload in bytes
,---------------- Repeat for each sample point:
| uint32 x X coordinate
@@ -1040,6 +1066,24 @@ PROP_VECTORS
without parsing the individual parasites. (Note that this is _not_
the case for PROP_PATHS).
+PROP_ITEM_SET (since GIMP 3.0)
+ uint32 40 Type identification
+ uint32 plength Total length of the following payload in bytes
+ uint32 item_type The type of item in this set:
+ 0: layers
+ 1: channels
+ 2: paths
+ uint32 method Selection method:
+ 0: basic text search
+ 1: regular expression search
+ 2: glob pattern search
+ 0xffffffff (max uint32): named item set
+ string label Pattern to use for selection or name of the item
+ set if method is 0xffffffff.
+
+ They are only organisational properties and have no consequence on
+ render. The order matters for display and also for PROP_ITEM_SET_ITEM.
+
4. THE CHANNEL STRUCTURE
========================
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]