The GEGL projection does floating selections now:

2009-01-26  Michael Natterer  <mitch@gimp.org>

	The GEGL projection does floating selections now:

	* app/core/gimpdrawable.[ch] (struct GimpDrawable): add a couple
	of GeglNodes which are used to create a sub-graph for this
	drawable's floating selection.

	(gimp_drawable_detach_floating_sel)
	(gimp_drawable_attach_floating_sel): new functions to call
	whenever a floating selection gets attached or detached.

	Change the role of the drawable's "source_node": it's no longer a
	direct tile source but an arbitrary graph. Add new internal
	function gimp_drawable_sync_source_node() which creates a
	sub-graph for the floating selection within the source node, and
	uses the new "tile_source_node" directly otherwise. Connect to
	"notify" of the floating selection and reconfigure its sub-graph
	when its properties change. This is also one more refactoring in
	the direction of layer trees.

	* app/core/gimpfloatingselundo.c
	* app/core/gimpimage.c
	* app/core/gimplayer-floating-sel.c: call the new attach/detach
	API whenever a floating selection is attached or detached from a
	drawable. This will need more refactoring i guess...


svn path=/trunk/; revision=27961
This commit is contained in:
Michael Natterer 2009-01-26 22:05:07 +00:00 committed by Michael Natterer
parent abe3230755
commit 785eef1af9
6 changed files with 242 additions and 25 deletions

View File

@ -1,3 +1,30 @@
2009-01-26 Michael Natterer <mitch@gimp.org>
The GEGL projection does floating selections now:
* app/core/gimpdrawable.[ch] (struct GimpDrawable): add a couple
of GeglNodes which are used to create a sub-graph for this
drawable's floating selection.
(gimp_drawable_detach_floating_sel)
(gimp_drawable_attach_floating_sel): new functions to call
whenever a floating selection gets attached or detached.
Change the role of the drawable's "source_node": it's no longer a
direct tile source but an arbitrary graph. Add new internal
function gimp_drawable_sync_source_node() which creates a
sub-graph for the floating selection within the source node, and
uses the new "tile_source_node" directly otherwise. Connect to
"notify" of the floating selection and reconfigure its sub-graph
when its properties change. This is also one more refactoring in
the direction of layer trees.
* app/core/gimpfloatingselundo.c
* app/core/gimpimage.c
* app/core/gimplayer-floating-sel.c: call the new attach/detach
API whenever a floating selection is attached or detached from a
drawable. This will need more refactoring i guess...
2009-01-26 Michael Natterer <mitch@gimp.org>
* app/core/gimpdrawable.c (gimp_drawable_visibility_changed):

View File

@ -150,6 +150,12 @@ static void gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
gint width,
gint height);
static void gimp_drawable_sync_source_node (GimpDrawable *drawable,
gboolean detach_fs);
static void gimp_drawable_fs_notify (GimpLayer *fs,
const GParamSpec *pspec,
GimpDrawable *drawable);
G_DEFINE_TYPE_WITH_CODE (GimpDrawable, gimp_drawable, GIMP_TYPE_ITEM,
G_IMPLEMENT_INTERFACE (GIMP_TYPE_PICKABLE,
@ -250,6 +256,9 @@ gimp_drawable_finalize (GObject *object)
{
GimpDrawable *drawable = GIMP_DRAWABLE (object);
if (drawable->fs_opacity_node)
gimp_drawable_sync_source_node (drawable, TRUE);
if (drawable->tiles)
{
tile_manager_unref (drawable->tiles);
@ -672,12 +681,12 @@ gimp_drawable_real_update (GimpDrawable *drawable,
gint width,
gint height)
{
if (drawable->source_node)
if (drawable->tile_source_node)
{
GObject *operation;
GeglRectangle rect;
g_object_get (drawable->source_node,
g_object_get (drawable->tile_source_node,
"gegl-operation", &operation,
NULL);
@ -757,8 +766,8 @@ gimp_drawable_real_set_tiles (GimpDrawable *drawable,
if (old_has_alpha != gimp_drawable_has_alpha (drawable))
gimp_drawable_alpha_changed (drawable);
if (drawable->source_node)
gegl_node_set (drawable->source_node,
if (drawable->tile_source_node)
gegl_node_set (drawable->tile_source_node,
"tile-manager", drawable->tiles,
NULL);
}
@ -888,6 +897,133 @@ gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
gimp_drawable_update (drawable, x, y, width, height);
}
static void
gimp_drawable_sync_source_node (GimpDrawable *drawable,
gboolean detach_fs)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
GimpLayer *fs = gimp_image_get_floating_selection (image);
GeglNode *output;
if (! drawable->source_node)
return;
output = gegl_node_get_output_proxy (drawable->source_node, "output");
if (gimp_drawable_has_floating_sel (drawable) && ! detach_fs)
{
gint off_x, off_y;
gint fs_off_x, fs_off_y;
if (! drawable->fs_opacity_node)
{
GeglNode *fs_source;
fs_source = gimp_drawable_get_source_node (GIMP_DRAWABLE (fs));
gegl_node_add_child (drawable->source_node, fs_source);
drawable->fs_opacity_node =
gegl_node_new_child (drawable->source_node,
"operation", "gegl:opacity",
NULL);
gegl_node_connect_to (fs_source, "output",
drawable->fs_opacity_node, "input");
drawable->fs_offset_node =
gegl_node_new_child (drawable->source_node,
"operation", "gegl:translate",
NULL);
gegl_node_connect_to (drawable->fs_opacity_node, "output",
drawable->fs_offset_node, "input");
drawable->fs_mode_node =
gegl_node_new_child (drawable->source_node,
"operation", "gimp:point-layer-mode",
NULL);
gegl_node_connect_to (drawable->tile_source_node, "output",
drawable->fs_mode_node, "input");
gegl_node_connect_to (drawable->fs_offset_node, "output",
drawable->fs_mode_node, "aux");
gegl_node_connect_to (drawable->fs_mode_node, "output",
output, "input");
g_signal_connect (fs, "notify",
G_CALLBACK (gimp_drawable_fs_notify),
drawable);
}
gegl_node_set (drawable->fs_opacity_node,
"value", gimp_layer_get_opacity (fs),
NULL);
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
gimp_item_get_offset (GIMP_ITEM (fs), &fs_off_x, &fs_off_y);
gegl_node_set (drawable->fs_offset_node,
"x", (gdouble) (fs_off_x - off_x),
"y", (gdouble) (fs_off_y - off_y),
NULL);
gegl_node_set (drawable->fs_mode_node,
"blend-mode", gimp_layer_get_mode (fs),
NULL);
}
else
{
if (drawable->fs_opacity_node)
{
GeglNode *fs_source;
gegl_node_disconnect (drawable->fs_opacity_node, "input");
gegl_node_disconnect (drawable->fs_offset_node, "input");
gegl_node_disconnect (drawable->fs_mode_node, "input");
gegl_node_disconnect (drawable->fs_mode_node, "aux");
fs_source = gimp_drawable_get_source_node (GIMP_DRAWABLE (fs));
gegl_node_remove_child (drawable->source_node,
fs_source);
gegl_node_remove_child (drawable->source_node,
drawable->fs_opacity_node);
drawable->fs_opacity_node = NULL;
gegl_node_remove_child (drawable->source_node,
drawable->fs_offset_node);
drawable->fs_offset_node = NULL;
gegl_node_remove_child (drawable->source_node,
drawable->fs_mode_node);
drawable->fs_mode_node = NULL;
g_signal_handlers_disconnect_by_func (fs,
gimp_drawable_fs_notify,
drawable);
}
gegl_node_connect_to (drawable->tile_source_node, "output",
output, "input");
}
}
static void
gimp_drawable_fs_notify (GimpLayer *fs,
const GParamSpec *pspec,
GimpDrawable *drawable)
{
if (! strcmp (pspec->name, "offset-x") ||
! strcmp (pspec->name, "offset-y") ||
! strcmp (pspec->name, "visible") ||
! strcmp (pspec->name, "mode") ||
! strcmp (pspec->name, "opacity"))
{
gimp_drawable_sync_source_node (drawable, FALSE);
}
}
/* public functions */
@ -932,8 +1068,8 @@ gimp_drawable_configure (GimpDrawable *drawable,
drawable->preview_cache = NULL;
drawable->preview_valid = FALSE;
if (drawable->source_node)
gegl_node_set (drawable->source_node,
if (drawable->tile_source_node)
gegl_node_set (drawable->tile_source_node,
"tile-manager", drawable->tiles,
NULL);
}
@ -1239,13 +1375,16 @@ gimp_drawable_get_source_node (GimpDrawable *drawable)
if (drawable->source_node)
return drawable->source_node;
drawable->source_node = g_object_new (GEGL_TYPE_NODE,
"operation", "gimp:tilemanager-source",
NULL);
gegl_node_set (drawable->source_node,
"tile-manager", drawable->tiles,
"linear", TRUE,
NULL);
drawable->source_node = gegl_node_new ();
drawable->tile_source_node =
gegl_node_new_child (drawable->source_node,
"operation", "gimp:tilemanager-source",
"tile-manager", drawable->tiles,
"linear", TRUE,
NULL);
gimp_drawable_sync_source_node (drawable, FALSE);
return drawable->source_node;
}
@ -1654,3 +1793,44 @@ gimp_drawable_get_colormap (const GimpDrawable *drawable)
return image ? gimp_image_get_colormap (image) : NULL;
}
void
gimp_drawable_attach_floating_sel (GimpDrawable *drawable,
GimpLayer *floating_sel)
{
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (GIMP_IS_LAYER (floating_sel));
g_printerr ("%s\n", G_STRFUNC);
gimp_drawable_sync_source_node (drawable, FALSE);
#ifdef __GNUC__
#warning FIXME: remove this hack when the floating sel is no layer any longer
#endif
g_signal_emit_by_name (floating_sel, "visibility-changed");
}
void
gimp_drawable_detach_floating_sel (GimpDrawable *drawable,
GimpLayer *floating_sel)
{
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (GIMP_IS_LAYER (floating_sel));
g_printerr ("%s\n", G_STRFUNC);
gimp_drawable_sync_source_node (drawable, TRUE);
#ifdef __GNUC__
#warning FIXME: remove this hack when the floating sel is no layer any longer
#endif
g_signal_emit_by_name (floating_sel, "visibility-changed");
/* Invalidate the preview of the obscured drawable. We do this here
* because it will not be done until the floating selection is removed,
* at which point the obscured drawable's preview will not be declared
* invalid.
*/
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (floating_sel));
}

View File

@ -40,6 +40,10 @@ struct _GimpDrawable
TileManager *shadow; /* shadow buffer tiles */
GeglNode *source_node;
GeglNode *tile_source_node;
GeglNode *fs_opacity_node;
GeglNode *fs_offset_node;
GeglNode *fs_mode_node;
GeglNode *mode_node;
@ -248,5 +252,10 @@ gboolean gimp_drawable_has_floating_sel (const GimpDrawable *drawable);
const guchar * gimp_drawable_get_colormap (const GimpDrawable *drawable);
void gimp_drawable_attach_floating_sel (GimpDrawable *drawable,
GimpLayer *floating_sel);
void gimp_drawable_detach_floating_sel (GimpDrawable *drawable,
GimpLayer *floating_sel);
#endif /* __GIMP_DRAWABLE_H__ */

View File

@ -114,11 +114,14 @@ gimp_floating_sel_undo_pop (GimpUndo *undo,
/* clear the selection */
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (floating_layer));
gimp_drawable_attach_floating_sel (floating_layer->fs.drawable,
floating_layer);
}
else
{
/* Update the preview for the underlying drawable */
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (floating_layer));
gimp_drawable_detach_floating_sel (floating_layer->fs.drawable,
floating_layer);
/* clear the selection */
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (floating_layer));

View File

@ -2969,7 +2969,11 @@ gimp_image_add_layer (GimpImage *image,
/* If the layer is a floating selection, set the fs pointer */
if (gimp_layer_is_floating_sel (layer))
gimp_image_set_floating_selection (image, layer);
{
gimp_image_set_floating_selection (image, layer);
gimp_drawable_attach_floating_sel (layer->fs.drawable, layer);
}
if (old_has_alpha != gimp_image_has_alpha (image))
image->flush_accum.alpha_changed = TRUE;
@ -3019,16 +3023,11 @@ gimp_image_remove_layer (GimpImage *image,
old_has_alpha = gimp_image_has_alpha (image);
if (gimp_image_get_floating_selection (image) == layer)
if (gimp_layer_is_floating_sel (layer))
{
undo_desc = _("Remove Floating Selection");
/* Invalidate the preview of the obscured drawable. We do this here
* because it will not be done until the floating selection is removed,
* at which point the obscured drawable's preview will not be declared
* invalid.
*/
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer));
gimp_drawable_detach_floating_sel (layer->fs.drawable, layer);
}
else
{

View File

@ -139,8 +139,7 @@ floating_sel_to_layer (GimpLayer *layer,
gimp_image_undo_push_fs_to_layer (image, NULL, layer);
/* clear the selection */
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer));
gimp_drawable_detach_floating_sel (layer->fs.drawable, layer);
/* Set pointers */
gimp_layer_set_floating_sel_drawable (layer, NULL);