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.
This commit is contained in:
Jehan 2021-12-22 22:53:15 +01:00
parent 7c5e88323c
commit 362fae9147
13 changed files with 369 additions and 57 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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 */

View File

@ -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__ */

View File

@ -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

View File

@ -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" },

View File

@ -1122,7 +1122,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 ();

View File

@ -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,19 +709,49 @@ 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",

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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
========================