2019-07-04 14:49:20 -07:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2019 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 <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
|
#include <gegl.h>
|
|
|
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
|
|
|
|
|
|
#include "core-types.h"
|
|
|
|
|
|
|
|
|
|
#include "gimpimage.h"
|
|
|
|
|
#include "gimplayer.h"
|
|
|
|
|
#include "gimplink.h"
|
|
|
|
|
#include "gimplinklayer.h"
|
|
|
|
|
#include "gimplinklayerundo.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_PREV_LINK
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gimp_link_layer_undo_constructed (GObject *object);
|
2025-08-09 14:26:13 -07:00
|
|
|
static void gimp_link_layer_undo_finalize (GObject *object);
|
2019-07-04 14:49:20 -07:00
|
|
|
static void gimp_link_layer_undo_set_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
static void gimp_link_layer_undo_get_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
|
|
static gint64 gimp_link_layer_undo_get_memsize (GimpObject *object,
|
|
|
|
|
gint64 *gui_size);
|
|
|
|
|
|
|
|
|
|
static void gimp_link_layer_undo_pop (GimpUndo *undo,
|
|
|
|
|
GimpUndoMode undo_mode,
|
|
|
|
|
GimpUndoAccumulator *accum);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GimpLinkLayerUndo, gimp_link_layer_undo, GIMP_TYPE_ITEM_UNDO)
|
|
|
|
|
|
|
|
|
|
#define parent_class gimp_link_layer_undo_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_class_init (GimpLinkLayerUndoClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
|
GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
|
|
|
|
|
|
|
|
|
|
object_class->constructed = gimp_link_layer_undo_constructed;
|
2025-08-09 14:26:13 -07:00
|
|
|
object_class->finalize = gimp_link_layer_undo_finalize;
|
2019-07-04 14:49:20 -07:00
|
|
|
object_class->set_property = gimp_link_layer_undo_set_property;
|
|
|
|
|
object_class->get_property = gimp_link_layer_undo_get_property;
|
|
|
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_link_layer_undo_get_memsize;
|
|
|
|
|
|
|
|
|
|
undo_class->pop = gimp_link_layer_undo_pop;
|
|
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_PREV_LINK,
|
|
|
|
|
g_param_spec_object ("prev-link",
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GIMP_TYPE_LINK,
|
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_init (GimpLinkLayerUndo *undo)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_constructed (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
|
|
|
|
|
GimpLinkLayer *layer;
|
2025-08-09 14:26:13 -07:00
|
|
|
GimpLink *link;
|
2019-07-04 14:49:20 -07:00
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
|
|
|
|
|
|
|
|
gimp_assert (GIMP_IS_LINK_LAYER (GIMP_ITEM_UNDO (object)->item));
|
|
|
|
|
|
|
|
|
|
layer = GIMP_LINK_LAYER (GIMP_ITEM_UNDO (undo)->item);
|
|
|
|
|
|
2025-08-09 14:26:13 -07:00
|
|
|
link = gimp_link_layer_get_link (layer);
|
|
|
|
|
undo->link = link ? gimp_link_duplicate (link) : NULL;
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 05:49:12 -07:00
|
|
|
gimp_link_layer_get_transform (layer,
|
|
|
|
|
&undo->matrix,
|
|
|
|
|
&undo->offset_x,
|
|
|
|
|
&undo->offset_y,
|
|
|
|
|
&undo->interpolation);
|
2025-08-09 14:26:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
|
|
|
|
|
|
|
|
|
|
g_clear_object (&undo->link);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
2019-07-04 14:49:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_set_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
|
|
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_PREV_LINK:
|
2025-08-09 14:26:13 -07:00
|
|
|
g_clear_object (&undo->link);
|
|
|
|
|
undo->link = g_value_get_object (value) ? gimp_link_duplicate (g_value_get_object (value)) : NULL;
|
2019-07-04 14:49:20 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_get_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
|
|
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_PREV_LINK:
|
|
|
|
|
g_value_set_object (value, undo->link);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint64
|
|
|
|
|
gimp_link_layer_undo_get_memsize (GimpObject *object,
|
|
|
|
|
gint64 *gui_size)
|
|
|
|
|
{
|
|
|
|
|
GimpItemUndo *item_undo = GIMP_ITEM_UNDO (object);
|
|
|
|
|
gint64 memsize = 0;
|
|
|
|
|
|
|
|
|
|
if (! gimp_item_is_attached (item_undo->item))
|
|
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (item_undo->item),
|
|
|
|
|
gui_size);
|
|
|
|
|
|
|
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
|
gui_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_link_layer_undo_pop (GimpUndo *undo,
|
|
|
|
|
GimpUndoMode undo_mode,
|
|
|
|
|
GimpUndoAccumulator *accum)
|
|
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 05:49:12 -07:00
|
|
|
GimpLinkLayerUndo *layer_undo = GIMP_LINK_LAYER_UNDO (undo);
|
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (GIMP_ITEM_UNDO (undo)->item);
|
|
|
|
|
GimpLink *link;
|
|
|
|
|
GimpMatrix3 matrix;
|
|
|
|
|
gint offset_x;
|
|
|
|
|
gint offset_y;
|
|
|
|
|
GimpInterpolationType interpolation;
|
2019-07-04 14:49:20 -07:00
|
|
|
|
|
|
|
|
GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
|
|
|
|
|
|
2025-08-09 14:26:13 -07:00
|
|
|
link = gimp_link_layer_get_link (layer);
|
|
|
|
|
link = link ? g_object_ref (link) : NULL;
|
2019-07-04 14:49:20 -07:00
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 05:49:12 -07:00
|
|
|
gimp_link_layer_get_transform (layer, &matrix, &offset_x, &offset_y, &interpolation);
|
|
|
|
|
gimp_link_layer_set_link_with_matrix (layer, layer_undo->link,
|
|
|
|
|
&layer_undo->matrix,
|
|
|
|
|
layer_undo->interpolation,
|
|
|
|
|
layer_undo->offset_x,
|
|
|
|
|
layer_undo->offset_y,
|
|
|
|
|
FALSE);
|
2019-07-04 14:49:20 -07:00
|
|
|
|
2025-08-06 02:47:33 -07:00
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 05:49:12 -07:00
|
|
|
layer_undo->matrix = matrix;
|
|
|
|
|
layer_undo->interpolation = interpolation;
|
|
|
|
|
layer_undo->offset_x = offset_x;
|
|
|
|
|
layer_undo->offset_y = offset_y;
|
|
|
|
|
|
|
|
|
|
g_clear_object (&layer_undo->link);
|
2025-08-09 14:26:13 -07:00
|
|
|
layer_undo->link = link;
|
2019-07-04 14:49:20 -07:00
|
|
|
}
|