core: Initial non-destructive editing implementation
This patch implements an initial form of non-destructive editing. Filters now stay active instead of being immediately merged down. A new column is added to the layer tree view, which can be clicked to show a pop-over menu. Filters can currently be hidden/shown, edited, reordered, deleted, and merged down from this pop-over menu. Currently, this works on layers and layer selections only. Plenty of room for improvement!
This commit is contained in:
parent
ec90cd1d9a
commit
e678a20951
50 changed files with 3071 additions and 335 deletions
|
|
@ -51,12 +51,6 @@ static gchar * filters_parse_operation (Gimp *gimp,
|
|||
const gchar *icon_name,
|
||||
GimpObject **settings);
|
||||
|
||||
static void filters_run_procedure (Gimp *gimp,
|
||||
GimpDisplay *display,
|
||||
GimpProcedure *procedure,
|
||||
GimpRunMode run_mode);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
|
|
@ -86,6 +80,7 @@ filters_apply_cmd_callback (GimpAction *action,
|
|||
&settings);
|
||||
|
||||
procedure = gimp_gegl_procedure_new (image->gimp,
|
||||
NULL,
|
||||
GIMP_RUN_NONINTERACTIVE, settings,
|
||||
operation,
|
||||
gimp_action_get_name (action),
|
||||
|
|
@ -130,6 +125,7 @@ filters_apply_interactive_cmd_callback (GimpAction *action,
|
|||
}
|
||||
|
||||
procedure = gimp_gegl_procedure_new (image->gimp,
|
||||
NULL,
|
||||
GIMP_RUN_INTERACTIVE, NULL,
|
||||
g_variant_get_string (value, NULL),
|
||||
gimp_action_get_name (action),
|
||||
|
|
@ -240,7 +236,7 @@ filters_parse_operation (Gimp *gimp,
|
|||
return g_strdup (operation_str);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
filters_run_procedure (Gimp *gimp,
|
||||
GimpDisplay *display,
|
||||
GimpProcedure *procedure,
|
||||
|
|
|
|||
|
|
@ -33,5 +33,10 @@ void filters_history_cmd_callback (GimpAction *action,
|
|||
GVariant *value,
|
||||
gpointer data);
|
||||
|
||||
void filters_run_procedure (Gimp *gimp,
|
||||
GimpDisplay *display,
|
||||
GimpProcedure *procedure,
|
||||
GimpRunMode run_mode);
|
||||
|
||||
|
||||
#endif /* __FILTERS_COMMANDS_H__ */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpdisplay.h"
|
||||
#include "core/gimpdrawable-operation.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimplayermask.h"
|
||||
#include "core/gimpparamspecs.h"
|
||||
|
|
@ -366,6 +367,7 @@ gimp_gegl_procedure_execute_async (GimpProcedure *procedure,
|
|||
if (! strcmp (tool_name, "gimp-operation-tool"))
|
||||
{
|
||||
gimp_operation_tool_set_operation (GIMP_OPERATION_TOOL (active_tool),
|
||||
gegl_procedure->filter,
|
||||
gegl_procedure->operation,
|
||||
gimp_procedure_get_label (procedure),
|
||||
gimp_procedure_get_label (procedure),
|
||||
|
|
@ -376,6 +378,25 @@ gimp_gegl_procedure_execute_async (GimpProcedure *procedure,
|
|||
|
||||
tool_manager_initialize_active (gimp, display);
|
||||
|
||||
/* For GIMP-specific GEGL operations, we need to copy over the
|
||||
* config object stored in the GeglNode */
|
||||
if (gegl_procedure->filter &&
|
||||
(! strcmp (gegl_procedure->operation, "gimp:brightness-contrast") ||
|
||||
! strcmp (gegl_procedure->operation, "gimp:curves") ||
|
||||
! strcmp (gegl_procedure->operation, "gimp:levels") ||
|
||||
! strcmp (gegl_procedure->operation, "gimp:threshold")))
|
||||
{
|
||||
GeglNode *node;
|
||||
|
||||
GIMP_FILTER_TOOL (active_tool)->existing_filter = gegl_procedure->filter;
|
||||
gimp_filter_set_active (GIMP_FILTER (gegl_procedure->filter), FALSE);
|
||||
|
||||
node = gimp_drawable_filter_get_operation (gegl_procedure->filter);
|
||||
gegl_node_get (node,
|
||||
"config", &settings,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (settings)
|
||||
gimp_filter_tool_set_config (GIMP_FILTER_TOOL (active_tool),
|
||||
GIMP_CONFIG (settings));
|
||||
|
|
@ -386,15 +407,16 @@ gimp_gegl_procedure_execute_async (GimpProcedure *procedure,
|
|||
/* public functions */
|
||||
|
||||
GimpProcedure *
|
||||
gimp_gegl_procedure_new (Gimp *gimp,
|
||||
GimpRunMode default_run_mode,
|
||||
GimpObject *default_settings,
|
||||
const gchar *operation,
|
||||
const gchar *name,
|
||||
const gchar *menu_label,
|
||||
const gchar *tooltip,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id)
|
||||
gimp_gegl_procedure_new (Gimp *gimp,
|
||||
GimpDrawableFilter *filter,
|
||||
GimpRunMode default_run_mode,
|
||||
GimpObject *default_settings,
|
||||
const gchar *operation,
|
||||
const gchar *name,
|
||||
const gchar *menu_label,
|
||||
const gchar *tooltip,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id)
|
||||
{
|
||||
GimpProcedure *procedure;
|
||||
GimpGeglProcedure *gegl_procedure;
|
||||
|
|
@ -412,6 +434,7 @@ gimp_gegl_procedure_new (Gimp *gimp,
|
|||
|
||||
gegl_procedure = GIMP_GEGL_PROCEDURE (procedure);
|
||||
|
||||
gegl_procedure->filter = filter;
|
||||
gegl_procedure->operation = g_strdup (operation);
|
||||
gegl_procedure->default_run_mode = default_run_mode;
|
||||
gegl_procedure->menu_label = g_strdup (menu_label);
|
||||
|
|
|
|||
|
|
@ -40,12 +40,13 @@ struct _GimpGeglProcedure
|
|||
{
|
||||
GimpProcedure parent_instance;
|
||||
|
||||
gchar *operation;
|
||||
GimpDrawableFilter *filter;
|
||||
gchar *operation;
|
||||
|
||||
GimpRunMode default_run_mode;
|
||||
GimpObject *default_settings;
|
||||
GimpRunMode default_run_mode;
|
||||
GimpObject *default_settings;
|
||||
|
||||
gchar *menu_label;
|
||||
gchar *menu_label;
|
||||
};
|
||||
|
||||
struct _GimpGeglProcedureClass
|
||||
|
|
@ -56,15 +57,15 @@ struct _GimpGeglProcedureClass
|
|||
|
||||
GType gimp_gegl_procedure_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GimpProcedure * gimp_gegl_procedure_new (Gimp *gimp,
|
||||
GimpRunMode default_run_mode,
|
||||
GimpObject *default_settings,
|
||||
const gchar *operation,
|
||||
const gchar *name,
|
||||
const gchar *menu_label,
|
||||
const gchar *tooltip,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id);
|
||||
|
||||
GimpProcedure * gimp_gegl_procedure_new (Gimp *gimp,
|
||||
GimpDrawableFilter *filter,
|
||||
GimpRunMode default_run_mode,
|
||||
GimpObject *default_settings,
|
||||
const gchar *operation,
|
||||
const gchar *name,
|
||||
const gchar *menu_label,
|
||||
const gchar *tooltip,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id);
|
||||
|
||||
#endif /* __GIMP_GEGL_PROCEDURE_H__ */
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
#include "core/gimpcontainer.h"
|
||||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpdrawable-fill.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimpgrouplayer.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimpimage-merge.h"
|
||||
|
|
@ -48,6 +50,7 @@
|
|||
#include "core/gimplayerpropundo.h"
|
||||
#include "core/gimplayer-floating-selection.h"
|
||||
#include "core/gimplayer-new.h"
|
||||
#include "core/gimplist.h"
|
||||
#include "core/gimppickable.h"
|
||||
#include "core/gimppickable-auto-shrink.h"
|
||||
#include "core/gimptoolinfo.h"
|
||||
|
|
@ -811,6 +814,35 @@ layers_duplicate_cmd_callback (GimpAction *action,
|
|||
gimp_item_get_index (iter->data),
|
||||
TRUE);
|
||||
new_layers = g_list_prepend (new_layers, new_layer);
|
||||
|
||||
/* Import any attached layer effects */
|
||||
if (gimp_drawable_has_filters (GIMP_DRAWABLE (iter->data)))
|
||||
{
|
||||
GList *filter_list;
|
||||
GimpContainer *filters;
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (iter->data));
|
||||
|
||||
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
|
||||
filter_list = g_list_previous (filter_list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
|
||||
{
|
||||
GimpDrawableFilter *old_filter = filter_list->data;
|
||||
GimpDrawableFilter *filter;
|
||||
|
||||
filter =
|
||||
gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer),
|
||||
old_filter);
|
||||
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
|
||||
|
||||
gimp_drawable_filter_layer_mask_freeze (filter);
|
||||
g_object_unref (filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gimp_image_set_selected_layers (image, new_layers);
|
||||
|
|
|
|||
|
|
@ -1284,6 +1284,9 @@ gimp_undo_type_get_type (void)
|
|||
{ GIMP_UNDO_FOREGROUND_SELECT, "GIMP_UNDO_FOREGROUND_SELECT", "foreground-select" },
|
||||
{ GIMP_UNDO_PARASITE_ATTACH, "GIMP_UNDO_PARASITE_ATTACH", "parasite-attach" },
|
||||
{ GIMP_UNDO_PARASITE_REMOVE, "GIMP_UNDO_PARASITE_REMOVE", "parasite-remove" },
|
||||
{ GIMP_UNDO_FILTER_ADD, "GIMP_UNDO_FILTER_ADD", "filter-add" },
|
||||
{ GIMP_UNDO_FILTER_REMOVE, "GIMP_UNDO_FILTER_REMOVE", "filter-remove" },
|
||||
{ GIMP_UNDO_FILTER_REORDER, "GIMP_UNDO_FILTER_REORDER", "filter-reorder" },
|
||||
{ GIMP_UNDO_CANT, "GIMP_UNDO_CANT", "cant" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
|
@ -1393,6 +1396,9 @@ gimp_undo_type_get_type (void)
|
|||
{ GIMP_UNDO_FOREGROUND_SELECT, NC_("undo-type", "Select foreground"), NULL },
|
||||
{ GIMP_UNDO_PARASITE_ATTACH, NC_("undo-type", "Attach parasite"), NULL },
|
||||
{ GIMP_UNDO_PARASITE_REMOVE, NC_("undo-type", "Remove parasite"), NULL },
|
||||
{ GIMP_UNDO_FILTER_ADD, NC_("undo-type", "Add effect"), NULL },
|
||||
{ GIMP_UNDO_FILTER_REMOVE, NC_("undo-type", "Remove effect"), NULL },
|
||||
{ GIMP_UNDO_FILTER_REORDER, NC_("undo-type", "Reorder effect"), NULL },
|
||||
{ GIMP_UNDO_CANT, NC_("undo-type", "Not undoable"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ typedef enum /*< pdb-skip >*/
|
|||
GIMP_UNDO_ITEM_COLOR_TAG, /*< desc="Item color tag" >*/
|
||||
GIMP_UNDO_ITEM_LOCK_CONTENT, /*< desc="Lock/Unlock content" >*/
|
||||
GIMP_UNDO_ITEM_LOCK_POSITION, /*< desc="Lock/Unlock position" >*/
|
||||
GIMP_UNDO_ITEM_LOCK_VISIBILITY, /*< desc="Lock/Unlock visibility" >*/
|
||||
GIMP_UNDO_ITEM_LOCK_VISIBILITY, /*< desc="Lock/Unlock visibility" >*/
|
||||
GIMP_UNDO_LAYER_ADD, /*< desc="New layer" >*/
|
||||
GIMP_UNDO_LAYER_REMOVE, /*< desc="Delete layer" >*/
|
||||
GIMP_UNDO_LAYER_MODE, /*< desc="Set layer mode" >*/
|
||||
|
|
@ -638,6 +638,9 @@ typedef enum /*< pdb-skip >*/
|
|||
GIMP_UNDO_FOREGROUND_SELECT, /*< desc="Select foreground" >*/
|
||||
GIMP_UNDO_PARASITE_ATTACH, /*< desc="Attach parasite" >*/
|
||||
GIMP_UNDO_PARASITE_REMOVE, /*< desc="Remove parasite" >*/
|
||||
GIMP_UNDO_FILTER_ADD, /*< desc="Add effect" >*/
|
||||
GIMP_UNDO_FILTER_REMOVE, /*< desc="Remove effect" >*/
|
||||
GIMP_UNDO_FILTER_REORDER, /*< desc="Reorder effect" >*/
|
||||
|
||||
GIMP_UNDO_CANT /*< desc="Not undoable" >*/
|
||||
} GimpUndoType;
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ gimp_drawable_edit_fill (GimpDrawable *drawable,
|
|||
composite_mode);
|
||||
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
gimp_drawable_filter_commit (filter, NULL, FALSE);
|
||||
gimp_drawable_filter_commit (filter, FALSE, NULL, FALSE);
|
||||
|
||||
g_object_unref (filter);
|
||||
g_object_unref (operation);
|
||||
|
|
|
|||
|
|
@ -34,14 +34,18 @@
|
|||
#include "gimpdrawable.h"
|
||||
#include "gimpdrawable-filters.h"
|
||||
#include "gimpdrawable-private.h"
|
||||
#include "gimpdrawablefilter.h"
|
||||
#include "gimpdrawablefilterundo.h"
|
||||
#include "gimpfilter.h"
|
||||
#include "gimpfilterstack.h"
|
||||
#include "gimpimage.h"
|
||||
#include "gimpimage-undo.h"
|
||||
#include "core/gimpimage-undo-push.h"
|
||||
#include "gimplayer.h"
|
||||
#include "gimpprogress.h"
|
||||
#include "gimpprojection.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
GimpContainer *
|
||||
gimp_drawable_get_filters (GimpDrawable *drawable)
|
||||
|
|
@ -81,6 +85,8 @@ gimp_drawable_add_filter (GimpDrawable *drawable,
|
|||
|
||||
gimp_container_add (drawable->private->filter_stack,
|
||||
GIMP_OBJECT (filter));
|
||||
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -93,17 +99,120 @@ gimp_drawable_remove_filter (GimpDrawable *drawable,
|
|||
|
||||
gimp_container_remove (drawable->private->filter_stack,
|
||||
GIMP_OBJECT (filter));
|
||||
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_clear_filters (GimpDrawable *drawable)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
||||
|
||||
gimp_container_clear (drawable->private->filter_stack);
|
||||
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_remove_last_filter (GimpDrawable *drawable)
|
||||
{
|
||||
GimpDrawableFilter *filter = NULL;
|
||||
|
||||
if (! GIMP_IS_DRAWABLE (drawable))
|
||||
return;
|
||||
|
||||
if (gimp_drawable_has_filters (drawable))
|
||||
{
|
||||
filter = GIMP_LIST (drawable->private->filter_stack)->queue->head->data;
|
||||
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter))
|
||||
{
|
||||
gimp_drawable_remove_filter (drawable,
|
||||
GIMP_FILTER (filter));
|
||||
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_merge_filters (GimpDrawable *drawable)
|
||||
{
|
||||
GList *list;
|
||||
GeglBuffer *buffer = NULL;
|
||||
GeglBuffer *new_buffer = NULL;
|
||||
|
||||
if (! GIMP_IS_DRAWABLE (drawable))
|
||||
return;
|
||||
|
||||
gimp_image_undo_group_start (gimp_item_get_image (GIMP_ITEM (drawable)),
|
||||
GIMP_UNDO_GROUP_DRAWABLE,
|
||||
_("Rasterize filters"));
|
||||
|
||||
/* Save buffer with effects for later use */
|
||||
buffer = gimp_drawable_get_buffer_with_effects (drawable);
|
||||
if (buffer)
|
||||
{
|
||||
gint64 width = (gint64) gegl_buffer_get_width (buffer);
|
||||
gint64 height = (gint64) gegl_buffer_get_height (buffer);
|
||||
|
||||
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
||||
gegl_buffer_get_format (buffer));
|
||||
|
||||
gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
|
||||
new_buffer, NULL);
|
||||
g_clear_object (&buffer);
|
||||
}
|
||||
|
||||
for (list = GIMP_LIST (drawable->private->filter_stack)->queue->tail;
|
||||
list;
|
||||
list = g_list_previous (list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (list->data))
|
||||
{
|
||||
GimpDrawableFilter *filter = list->data;
|
||||
const Babl *format;
|
||||
|
||||
format = gimp_drawable_get_format (drawable);
|
||||
|
||||
gimp_image_undo_push_filter_remove (gimp_item_get_image (GIMP_ITEM (drawable)),
|
||||
_("Merge filter"),
|
||||
drawable, filter);
|
||||
|
||||
gimp_drawable_merge_filter (drawable,
|
||||
GIMP_FILTER (filter),
|
||||
NULL,
|
||||
_("Rasterize filters"),
|
||||
format,
|
||||
TRUE, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update with correct buffer */
|
||||
if (new_buffer)
|
||||
{
|
||||
gimp_drawable_set_buffer (drawable, TRUE, NULL, new_buffer);
|
||||
g_clear_object (&new_buffer);
|
||||
}
|
||||
|
||||
gimp_image_undo_group_end (gimp_item_get_image (GIMP_ITEM (drawable)));
|
||||
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gimp_drawable_has_filter (GimpDrawable *drawable,
|
||||
GimpFilter *filter)
|
||||
{
|
||||
gboolean filter_exists = FALSE;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
||||
g_return_val_if_fail (GIMP_IS_FILTER (filter), FALSE);
|
||||
|
||||
return gimp_container_have (drawable->private->filter_stack,
|
||||
GIMP_OBJECT (filter));
|
||||
filter_exists = gimp_container_have (drawable->private->filter_stack,
|
||||
GIMP_OBJECT (filter));
|
||||
|
||||
return filter_exists;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -339,5 +448,8 @@ gimp_drawable_merge_filter (GimpDrawable *drawable,
|
|||
rect.width, rect.height);
|
||||
}
|
||||
|
||||
if (success)
|
||||
gimp_drawable_filters_changed (drawable);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ void gimp_drawable_add_filter (GimpDrawable *drawable,
|
|||
GimpFilter *filter);
|
||||
void gimp_drawable_remove_filter (GimpDrawable *drawable,
|
||||
GimpFilter *filter);
|
||||
void gimp_drawable_clear_filters (GimpDrawable *drawable);
|
||||
void gimp_drawable_remove_last_filter
|
||||
(GimpDrawable *drawable);
|
||||
void gimp_drawable_merge_filters (GimpDrawable *drawable);
|
||||
|
||||
gboolean gimp_drawable_has_filter (GimpDrawable *drawable,
|
||||
GimpFilter *filter);
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ gimp_drawable_apply_operation_with_config (GimpDrawable *drawable,
|
|||
}
|
||||
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
gimp_drawable_filter_commit (filter, progress, TRUE);
|
||||
gimp_drawable_filter_commit (filter, FALSE, progress, TRUE);
|
||||
|
||||
g_object_unref (filter);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "gegl/gimp-gegl-apply-operation.h"
|
||||
#include "gegl/gimp-gegl-loops.h"
|
||||
#include "gegl/gimp-gegl-utils.h"
|
||||
#include "gegl/gimptilehandlervalidate.h"
|
||||
|
||||
#include "gimp-memsize.h"
|
||||
#include "gimp-utils.h"
|
||||
|
|
@ -38,15 +39,18 @@
|
|||
#include "gimpcontext.h"
|
||||
#include "gimpdrawable-combine.h"
|
||||
#include "gimpdrawable-fill.h"
|
||||
#include "gimpdrawable-filters.h"
|
||||
#include "gimpdrawable-floating-selection.h"
|
||||
#include "gimpdrawable-preview.h"
|
||||
#include "gimpdrawable-private.h"
|
||||
#include "gimpdrawable-shadow.h"
|
||||
#include "gimpdrawable-transform.h"
|
||||
#include "gimpdrawablefilter.h"
|
||||
#include "gimpfilterstack.h"
|
||||
#include "gimpimage.h"
|
||||
#include "gimpimage-colormap.h"
|
||||
#include "gimpimage-undo-push.h"
|
||||
#include "gimplayer.h"
|
||||
#include "gimpmarshal.h"
|
||||
#include "gimppickable.h"
|
||||
#include "gimpprogress.h"
|
||||
|
|
@ -66,6 +70,7 @@ enum
|
|||
FORMAT_CHANGED,
|
||||
ALPHA_CHANGED,
|
||||
BOUNDING_BOX_CHANGED,
|
||||
FILTERS_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
|
@ -270,6 +275,14 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
|
|||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
gimp_drawable_signals[FILTERS_CHANGED] =
|
||||
g_signal_new ("filters-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GimpDrawableClass, filters_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
object_class->dispose = gimp_drawable_dispose;
|
||||
object_class->finalize = gimp_drawable_finalize;
|
||||
object_class->set_property = gimp_drawable_set_property;
|
||||
|
|
@ -297,6 +310,7 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
|
|||
klass->format_changed = NULL;
|
||||
klass->alpha_changed = NULL;
|
||||
klass->bounding_box_changed = NULL;
|
||||
klass->filters_changed = NULL;
|
||||
klass->estimate_memsize = gimp_drawable_real_estimate_memsize;
|
||||
klass->update_all = gimp_drawable_real_update_all;
|
||||
klass->invalidate_boundary = NULL;
|
||||
|
|
@ -336,12 +350,13 @@ gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
|
|||
static void
|
||||
gimp_pickable_iface_init (GimpPickableInterface *iface)
|
||||
{
|
||||
iface->get_image = (GimpImage * (*) (GimpPickable *pickable)) gimp_item_get_image;
|
||||
iface->get_format = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format;
|
||||
iface->get_format_with_alpha = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format_with_alpha;
|
||||
iface->get_buffer = (GeglBuffer * (*) (GimpPickable *pickable)) gimp_drawable_get_buffer;
|
||||
iface->get_pixel_at = gimp_drawable_get_pixel_at;
|
||||
iface->get_pixel_average = gimp_drawable_get_pixel_average;
|
||||
iface->get_image = (GimpImage * (*) (GimpPickable *pickable)) gimp_item_get_image;
|
||||
iface->get_format = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format;
|
||||
iface->get_format_with_alpha = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format_with_alpha;
|
||||
iface->get_buffer = (GeglBuffer * (*) (GimpPickable *pickable)) gimp_drawable_get_buffer;
|
||||
iface->get_buffer_with_effects = (GeglBuffer * (*) (GimpPickable *pickable)) gimp_drawable_get_buffer_with_effects;
|
||||
iface->get_pixel_at = gimp_drawable_get_pixel_at;
|
||||
iface->get_pixel_average = gimp_drawable_get_pixel_average;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -554,6 +569,30 @@ gimp_drawable_scale (GimpItem *item,
|
|||
0, 0),
|
||||
TRUE);
|
||||
g_object_unref (new_buffer);
|
||||
|
||||
if (GIMP_IS_LAYER (drawable))
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = GIMP_LIST (drawable->private->filter_stack)->queue->tail;
|
||||
list; list = g_list_previous (list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (list->data))
|
||||
{
|
||||
GimpDrawableFilter *filter = list->data;
|
||||
GimpChannel *mask = gimp_drawable_filter_get_mask (filter);
|
||||
GeglRectangle *rect = GEGL_RECTANGLE (0, 0,
|
||||
new_width,
|
||||
new_height);
|
||||
|
||||
/* Don't resize partial layer effects */
|
||||
if (gimp_channel_is_empty (mask))
|
||||
gimp_drawable_filter_refresh_crop (filter, rect);
|
||||
}
|
||||
}
|
||||
if (list)
|
||||
g_list_free (list);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -637,6 +676,28 @@ gimp_drawable_resize (GimpItem *item,
|
|||
0, 0),
|
||||
TRUE);
|
||||
g_object_unref (new_buffer);
|
||||
|
||||
if (GIMP_IS_LAYER (drawable))
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = GIMP_LIST (drawable->private->filter_stack)->queue->tail;
|
||||
list; list = g_list_previous (list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (list->data))
|
||||
{
|
||||
GimpDrawableFilter *filter = list->data;
|
||||
GimpChannel *mask = gimp_drawable_filter_get_mask (filter);
|
||||
GeglRectangle rect = {0, 0, new_width, new_height};
|
||||
|
||||
/* Don't resize partial layer effects */
|
||||
if (gimp_channel_is_empty (mask))
|
||||
gimp_drawable_filter_refresh_crop (filter, &rect);
|
||||
}
|
||||
}
|
||||
if (list)
|
||||
g_list_free (list);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1439,6 +1500,55 @@ gimp_drawable_set_buffer_full (GimpDrawable *drawable,
|
|||
gimp_drawable_update (drawable, 0, 0, -1, -1);
|
||||
}
|
||||
|
||||
GeglBuffer *
|
||||
gimp_drawable_get_buffer_with_effects (GimpDrawable *drawable)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
||||
|
||||
if (drawable->private->paint_count == 0)
|
||||
{
|
||||
if (gimp_drawable_has_filters (drawable))
|
||||
{
|
||||
GeglNode *source = NULL;
|
||||
GeglBuffer *buffer;
|
||||
GimpTileHandlerValidate *validate;
|
||||
|
||||
source = gimp_drawable_get_source_node (drawable);
|
||||
buffer = GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
|
||||
|
||||
if (source)
|
||||
{
|
||||
buffer = gegl_buffer_new (gegl_buffer_get_extent (buffer),
|
||||
gegl_buffer_get_format (buffer));
|
||||
|
||||
validate =
|
||||
GIMP_TILE_HANDLER_VALIDATE (gimp_tile_handler_validate_new (source));
|
||||
|
||||
gimp_tile_handler_validate_assign (validate, buffer);
|
||||
|
||||
g_object_unref (validate);
|
||||
|
||||
gimp_tile_handler_validate_invalidate (validate,
|
||||
gegl_buffer_get_extent (buffer));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return drawable->private->paint_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_steal_buffer (GimpDrawable *drawable,
|
||||
GimpDrawable *src_drawable)
|
||||
|
|
@ -1936,6 +2046,16 @@ gimp_drawable_end_paint (GimpDrawable *drawable)
|
|||
|
||||
drawable->private->paint_count--;
|
||||
|
||||
/* Refresh filters after painting */
|
||||
if (gimp_drawable_has_filters (drawable) &&
|
||||
drawable->private->paint_count == 0)
|
||||
{
|
||||
gimp_item_set_visible (GIMP_ITEM (drawable), FALSE, FALSE);
|
||||
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable)));
|
||||
gimp_item_set_visible (GIMP_ITEM (drawable),TRUE, FALSE);
|
||||
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -2004,3 +2124,9 @@ gimp_drawable_is_painting (GimpDrawable *drawable)
|
|||
|
||||
return drawable->private->paint_count > 0;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_filters_changed (GimpDrawable *drawable)
|
||||
{
|
||||
g_signal_emit (drawable, gimp_drawable_signals[FILTERS_CHANGED], 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,160 +53,163 @@ struct _GimpDrawableClass
|
|||
void (* format_changed) (GimpDrawable *drawable);
|
||||
void (* alpha_changed) (GimpDrawable *drawable);
|
||||
void (* bounding_box_changed) (GimpDrawable *drawable);
|
||||
void (* filters_changed) (GimpDrawable *drawable);
|
||||
|
||||
/* virtual functions */
|
||||
gint64 (* estimate_memsize) (GimpDrawable *drawable,
|
||||
GimpComponentType component_type,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* update_all) (GimpDrawable *drawable);
|
||||
void (* invalidate_boundary) (GimpDrawable *drawable);
|
||||
void (* get_active_components) (GimpDrawable *drawable,
|
||||
gboolean *active);
|
||||
GimpComponentMask (* get_active_mask) (GimpDrawable *drawable);
|
||||
gboolean (* supports_alpha) (GimpDrawable *drawable);
|
||||
void (* convert_type) (GimpDrawable *drawable,
|
||||
GimpImage *dest_image,
|
||||
const Babl *new_format,
|
||||
GimpColorProfile *src_profile,
|
||||
GimpColorProfile *dest_profile,
|
||||
GeglDitherMethod layer_dither_type,
|
||||
GeglDitherMethod mask_dither_type,
|
||||
gboolean push_undo,
|
||||
GimpProgress *progress);
|
||||
void (* apply_buffer) (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *buffer_region,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
gdouble opacity,
|
||||
GimpLayerMode mode,
|
||||
GimpLayerColorSpace blend_space,
|
||||
GimpLayerColorSpace composite_space,
|
||||
GimpLayerCompositeMode composite_mode,
|
||||
GeglBuffer *base_buffer,
|
||||
gint base_x,
|
||||
gint base_y);
|
||||
GeglBuffer * (* get_buffer) (GimpDrawable *drawable);
|
||||
void (* set_buffer) (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *bounds);
|
||||
GeglRectangle (* get_bounding_box) (GimpDrawable *drawable);
|
||||
void (* push_undo) (GimpDrawable *drawable,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* swap_pixels) (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y);
|
||||
GeglNode * (* get_source_node) (GimpDrawable *drawable);
|
||||
gint64 (* estimate_memsize) (GimpDrawable *drawable,
|
||||
GimpComponentType component_type,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* update_all) (GimpDrawable *drawable);
|
||||
void (* invalidate_boundary) (GimpDrawable *drawable);
|
||||
void (* get_active_components) (GimpDrawable *drawable,
|
||||
gboolean *active);
|
||||
GimpComponentMask (* get_active_mask) (GimpDrawable *drawable);
|
||||
gboolean (* supports_alpha) (GimpDrawable *drawable);
|
||||
void (* convert_type) (GimpDrawable *drawable,
|
||||
GimpImage *dest_image,
|
||||
const Babl *new_format,
|
||||
GimpColorProfile *src_profile,
|
||||
GimpColorProfile *dest_profile,
|
||||
GeglDitherMethod layer_dither_type,
|
||||
GeglDitherMethod mask_dither_type,
|
||||
gboolean push_undo,
|
||||
GimpProgress *progress);
|
||||
void (* apply_buffer) (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *buffer_region,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
gdouble opacity,
|
||||
GimpLayerMode mode,
|
||||
GimpLayerColorSpace blend_space,
|
||||
GimpLayerColorSpace composite_space,
|
||||
GimpLayerCompositeMode composite_mode,
|
||||
GeglBuffer *base_buffer,
|
||||
gint base_x,
|
||||
gint base_y);
|
||||
GeglBuffer * (* get_buffer) (GimpDrawable *drawable);
|
||||
void (* set_buffer) (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *bounds);
|
||||
GeglBuffer * (* get_buffer_with_effects) (GimpDrawable *drawable);
|
||||
GeglRectangle (* get_bounding_box) (GimpDrawable *drawable);
|
||||
void (* push_undo) (GimpDrawable *drawable,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* swap_pixels) (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y);
|
||||
GeglNode * (* get_source_node) (GimpDrawable *drawable);
|
||||
};
|
||||
|
||||
|
||||
GType gimp_drawable_get_type (void) G_GNUC_CONST;
|
||||
GType gimp_drawable_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GimpDrawable * gimp_drawable_new (GType type,
|
||||
GimpImage *image,
|
||||
const gchar *name,
|
||||
gint offset_x,
|
||||
gint offset_y,
|
||||
gint width,
|
||||
gint height,
|
||||
const Babl *format);
|
||||
GimpDrawable * gimp_drawable_new (GType type,
|
||||
GimpImage *image,
|
||||
const gchar *name,
|
||||
gint offset_x,
|
||||
gint offset_y,
|
||||
gint width,
|
||||
gint height,
|
||||
const Babl *format);
|
||||
|
||||
gint64 gimp_drawable_estimate_memsize (GimpDrawable *drawable,
|
||||
GimpComponentType component_type,
|
||||
gint width,
|
||||
gint height);
|
||||
gint64 gimp_drawable_estimate_memsize (GimpDrawable *drawable,
|
||||
GimpComponentType component_type,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
void gimp_drawable_update (GimpDrawable *drawable,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void gimp_drawable_update_all (GimpDrawable *drawable);
|
||||
void gimp_drawable_update (GimpDrawable *drawable,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void gimp_drawable_update_all (GimpDrawable *drawable);
|
||||
|
||||
void gimp_drawable_invalidate_boundary (GimpDrawable *drawable);
|
||||
void gimp_drawable_get_active_components (GimpDrawable *drawable,
|
||||
gboolean *active);
|
||||
GimpComponentMask gimp_drawable_get_active_mask (GimpDrawable *drawable);
|
||||
void gimp_drawable_invalidate_boundary (GimpDrawable *drawable);
|
||||
void gimp_drawable_get_active_components (GimpDrawable *drawable,
|
||||
gboolean *active);
|
||||
GimpComponentMask gimp_drawable_get_active_mask (GimpDrawable *drawable);
|
||||
|
||||
gboolean gimp_drawable_supports_alpha (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_supports_alpha (GimpDrawable *drawable);
|
||||
|
||||
void gimp_drawable_convert_type (GimpDrawable *drawable,
|
||||
GimpImage *dest_image,
|
||||
GimpImageBaseType new_base_type,
|
||||
GimpPrecision new_precision,
|
||||
gboolean new_has_alpha,
|
||||
GimpColorProfile *src_profile,
|
||||
GimpColorProfile *dest_profile,
|
||||
GeglDitherMethod layer_dither_type,
|
||||
GeglDitherMethod mask_dither_type,
|
||||
gboolean push_undo,
|
||||
GimpProgress *progress);
|
||||
void gimp_drawable_convert_type (GimpDrawable *drawable,
|
||||
GimpImage *dest_image,
|
||||
GimpImageBaseType new_base_type,
|
||||
GimpPrecision new_precision,
|
||||
gboolean new_has_alpha,
|
||||
GimpColorProfile *src_profile,
|
||||
GimpColorProfile *dest_profile,
|
||||
GeglDitherMethod layer_dither_type,
|
||||
GeglDitherMethod mask_dither_type,
|
||||
gboolean push_undo,
|
||||
GimpProgress *progress);
|
||||
|
||||
void gimp_drawable_apply_buffer (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *buffer_rect,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
gdouble opacity,
|
||||
GimpLayerMode mode,
|
||||
GimpLayerColorSpace blend_space,
|
||||
GimpLayerColorSpace composite_space,
|
||||
GimpLayerCompositeMode composite_mode,
|
||||
GeglBuffer *base_buffer,
|
||||
gint base_x,
|
||||
gint base_y);
|
||||
void gimp_drawable_apply_buffer (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *buffer_rect,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
gdouble opacity,
|
||||
GimpLayerMode mode,
|
||||
GimpLayerColorSpace blend_space,
|
||||
GimpLayerColorSpace composite_space,
|
||||
GimpLayerCompositeMode composite_mode,
|
||||
GeglBuffer *base_buffer,
|
||||
gint base_x,
|
||||
gint base_y);
|
||||
|
||||
GeglBuffer * gimp_drawable_get_buffer (GimpDrawable *drawable);
|
||||
void gimp_drawable_set_buffer (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer);
|
||||
void gimp_drawable_set_buffer_full (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *bounds,
|
||||
gboolean update);
|
||||
GeglBuffer * gimp_drawable_get_buffer (GimpDrawable *drawable);
|
||||
void gimp_drawable_set_buffer (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer);
|
||||
void gimp_drawable_set_buffer_full (GimpDrawable *drawable,
|
||||
gboolean push_undo,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
const GeglRectangle *bounds,
|
||||
gboolean update);
|
||||
GeglBuffer * gimp_drawable_get_buffer_with_effects (GimpDrawable *drawable);
|
||||
|
||||
void gimp_drawable_steal_buffer (GimpDrawable *drawable,
|
||||
GimpDrawable *src_drawable);
|
||||
void gimp_drawable_steal_buffer (GimpDrawable *drawable,
|
||||
GimpDrawable *src_drawable);
|
||||
|
||||
void gimp_drawable_set_format (GimpDrawable *drawable,
|
||||
const Babl *format,
|
||||
gboolean copy_buffer,
|
||||
gboolean push_undo);
|
||||
void gimp_drawable_set_format (GimpDrawable *drawable,
|
||||
const Babl *format,
|
||||
gboolean copy_buffer,
|
||||
gboolean push_undo);
|
||||
|
||||
GeglNode * gimp_drawable_get_source_node (GimpDrawable *drawable);
|
||||
GeglNode * gimp_drawable_get_mode_node (GimpDrawable *drawable);
|
||||
GeglNode * gimp_drawable_get_source_node (GimpDrawable *drawable);
|
||||
GeglNode * gimp_drawable_get_mode_node (GimpDrawable *drawable);
|
||||
|
||||
GeglRectangle gimp_drawable_get_bounding_box (GimpDrawable *drawable);
|
||||
GeglRectangle gimp_drawable_get_bounding_box (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_update_bounding_box
|
||||
(GimpDrawable *drawable);
|
||||
(GimpDrawable *drawable);
|
||||
|
||||
void gimp_drawable_swap_pixels (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y);
|
||||
void gimp_drawable_swap_pixels (GimpDrawable *drawable,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
void gimp_drawable_push_undo (GimpDrawable *drawable,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void gimp_drawable_push_undo (GimpDrawable *drawable,
|
||||
const gchar *undo_desc,
|
||||
GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
void gimp_drawable_disable_resize_undo (GimpDrawable *drawable);
|
||||
void gimp_drawable_enable_resize_undo (GimpDrawable *drawable);
|
||||
void gimp_drawable_disable_resize_undo (GimpDrawable *drawable);
|
||||
void gimp_drawable_enable_resize_undo (GimpDrawable *drawable);
|
||||
|
||||
const Babl * gimp_drawable_get_space (GimpDrawable *drawable);
|
||||
const Babl * gimp_drawable_get_format (GimpDrawable *drawable);
|
||||
|
|
@ -234,5 +237,7 @@ gboolean gimp_drawable_end_paint (GimpDrawable *drawable)
|
|||
gboolean gimp_drawable_flush_paint (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_is_painting (GimpDrawable *drawable);
|
||||
|
||||
void gimp_drawable_filters_changed (GimpDrawable *drawable);
|
||||
|
||||
|
||||
#endif /* __GIMP_DRAWABLE_H__ */
|
||||
|
|
|
|||
|
|
@ -54,12 +54,19 @@ enum
|
|||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_MASK
|
||||
};
|
||||
|
||||
|
||||
struct _GimpDrawableFilter
|
||||
{
|
||||
GimpFilter parent_instance;
|
||||
|
||||
GimpDrawable *drawable;
|
||||
GimpChannel *mask;
|
||||
GeglNode *operation;
|
||||
|
||||
gboolean has_input;
|
||||
|
|
@ -94,7 +101,15 @@ struct _GimpDrawableFilter
|
|||
GimpApplicator *applicator;
|
||||
};
|
||||
|
||||
static void gimp_drawable_filter_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void gimp_drawable_filter_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_drawable_filter_dispose (GObject *object);
|
||||
static void gimp_drawable_filter_finalize (GObject *object);
|
||||
|
||||
|
|
@ -159,8 +174,16 @@ gimp_drawable_filter_class_init (GimpDrawableFilterClass *klass)
|
|||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
object_class->dispose = gimp_drawable_filter_dispose;
|
||||
object_class->finalize = gimp_drawable_filter_finalize;
|
||||
object_class->set_property = gimp_drawable_filter_set_property;
|
||||
object_class->get_property = gimp_drawable_filter_get_property;
|
||||
object_class->dispose = gimp_drawable_filter_dispose;
|
||||
object_class->finalize = gimp_drawable_filter_finalize;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_MASK,
|
||||
g_param_spec_object ("mask",
|
||||
NULL, NULL,
|
||||
GIMP_TYPE_CHANNEL,
|
||||
GIMP_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -179,6 +202,49 @@ gimp_drawable_filter_init (GimpDrawableFilter *drawable_filter)
|
|||
drawable_filter->composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpDrawableFilter *filter = GIMP_DRAWABLE_FILTER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MASK:
|
||||
g_set_object (&filter->mask, g_value_get_object (value));
|
||||
|
||||
if (filter->mask)
|
||||
gimp_drawable_filter_sync_mask (filter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpDrawableFilter *filter = GIMP_DRAWABLE_FILTER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MASK:
|
||||
g_value_set_object (value, gimp_drawable_filter_get_mask (filter));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_dispose (GObject *object)
|
||||
{
|
||||
|
|
@ -195,9 +261,10 @@ gimp_drawable_filter_finalize (GObject *object)
|
|||
{
|
||||
GimpDrawableFilter *drawable_filter = GIMP_DRAWABLE_FILTER (object);
|
||||
|
||||
g_clear_object (&drawable_filter->operation);
|
||||
g_clear_object (&drawable_filter->applicator);
|
||||
g_clear_object (&drawable_filter->drawable);
|
||||
g_clear_object (&drawable_filter->operation);
|
||||
g_clear_object (&drawable_filter->mask);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
|
@ -219,6 +286,7 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
|
|||
filter = g_object_new (GIMP_TYPE_DRAWABLE_FILTER,
|
||||
"name", undo_desc,
|
||||
"icon-name", icon_name,
|
||||
"mask", NULL,
|
||||
NULL);
|
||||
|
||||
filter->drawable = g_object_ref (drawable);
|
||||
|
|
@ -226,8 +294,11 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
|
|||
|
||||
node = gimp_filter_get_node (GIMP_FILTER (filter));
|
||||
|
||||
gegl_node_add_child (node, operation);
|
||||
gimp_gegl_node_set_underlying_operation (node, operation);
|
||||
if (! gegl_node_get_parent (operation))
|
||||
{
|
||||
gegl_node_add_child (node, operation);
|
||||
gimp_gegl_node_set_underlying_operation (node, operation);
|
||||
}
|
||||
|
||||
filter->applicator = gimp_applicator_new (node);
|
||||
|
||||
|
|
@ -281,6 +352,78 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
|
|||
return filter;
|
||||
}
|
||||
|
||||
GimpDrawableFilter *
|
||||
gimp_drawable_filter_duplicate (GimpDrawable *drawable,
|
||||
GimpDrawableFilter *prior_filter)
|
||||
{
|
||||
GimpDrawableFilter *filter;
|
||||
GimpChannel *mask;
|
||||
GeglNode *prior_node;
|
||||
GeglNode *node = gegl_node_new ();
|
||||
const gchar *operation;
|
||||
const gchar *undo_desc;
|
||||
const gchar *icon_name;
|
||||
GParamSpec **pspecs;
|
||||
guint n_pspecs;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (prior_filter), NULL);
|
||||
|
||||
prior_node = gimp_drawable_filter_get_operation (prior_filter);
|
||||
|
||||
g_object_get (prior_filter,
|
||||
"name", &undo_desc,
|
||||
"icon-name", &icon_name,
|
||||
NULL);
|
||||
|
||||
gegl_node_get (prior_node,
|
||||
"operation", &operation,
|
||||
NULL);
|
||||
|
||||
gegl_node_set (node,
|
||||
"operation", operation,
|
||||
NULL);
|
||||
|
||||
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
|
||||
|
||||
for (gint i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
gegl_node_get_property (prior_node, pspec->name,
|
||||
&value);
|
||||
|
||||
gegl_node_set_property (node, pspec->name,
|
||||
&value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
g_free (pspecs);
|
||||
|
||||
filter = gimp_drawable_filter_new (drawable, undo_desc, node, icon_name);
|
||||
g_object_unref (node);
|
||||
|
||||
gimp_drawable_filter_set_opacity (filter, prior_filter->opacity);
|
||||
gimp_drawable_filter_set_mode (filter,
|
||||
prior_filter->paint_mode,
|
||||
prior_filter->blend_space,
|
||||
prior_filter->composite_space,
|
||||
prior_filter->composite_mode);
|
||||
gimp_drawable_filter_set_region (filter,
|
||||
prior_filter->region);
|
||||
|
||||
mask = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (prior_filter->mask),
|
||||
GIMP_TYPE_CHANNEL));
|
||||
|
||||
g_object_set (filter,
|
||||
"mask", mask,
|
||||
NULL);
|
||||
g_object_unref (mask);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
GimpDrawable *
|
||||
gimp_drawable_filter_get_drawable (GimpDrawableFilter *filter)
|
||||
{
|
||||
|
|
@ -297,6 +440,62 @@ gimp_drawable_filter_get_operation (GimpDrawableFilter *filter)
|
|||
return filter->operation;
|
||||
}
|
||||
|
||||
GimpChannel *
|
||||
gimp_drawable_filter_get_mask (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
|
||||
|
||||
return filter->mask;
|
||||
}
|
||||
|
||||
gdouble
|
||||
gimp_drawable_filter_get_opacity (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0.0f);
|
||||
|
||||
return filter->opacity;
|
||||
}
|
||||
|
||||
GimpLayerMode
|
||||
gimp_drawable_filter_get_paint_mode (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0);
|
||||
|
||||
return filter->paint_mode;
|
||||
}
|
||||
|
||||
GimpLayerColorSpace
|
||||
gimp_drawable_filter_get_blend_space (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0);
|
||||
|
||||
return filter->blend_space;
|
||||
}
|
||||
|
||||
GimpLayerColorSpace
|
||||
gimp_drawable_filter_get_composite_space (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0);
|
||||
|
||||
return filter->composite_space;
|
||||
}
|
||||
|
||||
GimpLayerCompositeMode
|
||||
gimp_drawable_filter_get_composite_mode (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0);
|
||||
|
||||
return filter->composite_mode;
|
||||
}
|
||||
|
||||
GimpFilterRegion
|
||||
gimp_drawable_filter_get_region (GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), 0);
|
||||
|
||||
return filter->region;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
|
||||
gboolean clip)
|
||||
|
|
@ -307,6 +506,7 @@ gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
|
|||
{
|
||||
filter->clip = clip;
|
||||
|
||||
gimp_drawable_filter_sync_region (filter);
|
||||
gimp_drawable_filter_sync_clip (filter, TRUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -568,6 +768,7 @@ gimp_drawable_filter_apply (GimpDrawableFilter *filter,
|
|||
|
||||
gboolean
|
||||
gimp_drawable_filter_commit (GimpDrawableFilter *filter,
|
||||
gboolean non_destructive,
|
||||
GimpProgress *progress,
|
||||
gboolean cancellable)
|
||||
{
|
||||
|
|
@ -589,16 +790,25 @@ gimp_drawable_filter_commit (GimpDrawableFilter *filter,
|
|||
filter->preview_split_position);
|
||||
gimp_drawable_filter_set_preview (filter, TRUE);
|
||||
|
||||
success = gimp_drawable_merge_filter (filter->drawable,
|
||||
GIMP_FILTER (filter),
|
||||
progress,
|
||||
gimp_object_get_name (filter),
|
||||
format,
|
||||
filter->filter_clip,
|
||||
cancellable,
|
||||
FALSE);
|
||||
/* Only commit if filter is applied destructively */
|
||||
if (! non_destructive)
|
||||
{
|
||||
success = gimp_drawable_merge_filter (filter->drawable,
|
||||
GIMP_FILTER (filter),
|
||||
progress,
|
||||
gimp_object_get_name (filter),
|
||||
format,
|
||||
filter->filter_clip,
|
||||
cancellable,
|
||||
FALSE);
|
||||
|
||||
gimp_drawable_filter_remove_filter (filter);
|
||||
gimp_drawable_filter_remove_filter (filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gimp_viewable_preview_is_frozen (GIMP_VIEWABLE (filter->drawable)))
|
||||
gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
|
||||
}
|
||||
|
||||
if (! success)
|
||||
gimp_drawable_filter_update_drawable (filter, NULL);
|
||||
|
|
@ -620,6 +830,41 @@ gimp_drawable_filter_abort (GimpDrawableFilter *filter)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_filter_layer_mask_freeze (GimpDrawableFilter *filter)
|
||||
{
|
||||
GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
|
||||
GimpChannel *mask;
|
||||
|
||||
if (! filter->mask)
|
||||
{
|
||||
mask = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (gimp_image_get_mask (image)),
|
||||
GIMP_TYPE_CHANNEL));
|
||||
|
||||
g_set_object (&filter->mask, mask);
|
||||
g_object_unref (mask);
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
gimp_drawable_filter_mask_changed,
|
||||
filter);
|
||||
}
|
||||
|
||||
void gimp_drawable_filter_refresh_crop (GimpDrawableFilter *filter,
|
||||
GeglRectangle *rect)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
|
||||
|
||||
if (rect)
|
||||
{
|
||||
gimp_drawable_filter_set_clip (filter, TRUE);
|
||||
gimp_drawable_filter_set_clip (filter, FALSE);
|
||||
gimp_drawable_filter_set_region (filter, GIMP_FILTER_REGION_SELECTION);
|
||||
gimp_drawable_filter_set_region (filter, GIMP_FILTER_REGION_DRAWABLE);
|
||||
gimp_drawable_filter_set_crop (filter, NULL, FALSE);
|
||||
gimp_drawable_filter_set_crop (filter, rect, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
|
@ -642,10 +887,9 @@ gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
|
|||
|
||||
if (! clip)
|
||||
{
|
||||
GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
|
||||
GimpChannel *mask = gimp_image_get_mask (image);
|
||||
GimpChannel *mask = GIMP_CHANNEL (filter->mask);
|
||||
|
||||
if (! gimp_channel_is_empty (mask))
|
||||
if (mask && ! gimp_channel_is_empty (mask))
|
||||
clip = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -838,7 +1082,7 @@ gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
|
|||
|
||||
gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
|
||||
|
||||
if (update &&
|
||||
if (update &&
|
||||
gimp_drawable_filter_is_active (filter) &&
|
||||
! gegl_rectangle_equal (&old_rect, &new_rect))
|
||||
{
|
||||
|
|
@ -921,11 +1165,22 @@ static void
|
|||
gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter)
|
||||
{
|
||||
GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
|
||||
GimpChannel *mask = gimp_image_get_mask (image);
|
||||
GimpChannel *mask = NULL;
|
||||
|
||||
if (gimp_channel_is_empty (mask))
|
||||
if (! filter->mask)
|
||||
mask = gimp_image_get_mask (image);
|
||||
else
|
||||
mask = GIMP_CHANNEL (filter->mask);
|
||||
|
||||
if (! mask || gimp_channel_is_empty (mask))
|
||||
{
|
||||
gimp_applicator_set_mask_buffer (filter->applicator, NULL);
|
||||
|
||||
gimp_item_mask_intersect (GIMP_ITEM (filter->drawable),
|
||||
&filter->filter_area.x,
|
||||
&filter->filter_area.y,
|
||||
&filter->filter_area.width,
|
||||
&filter->filter_area.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -939,13 +1194,15 @@ gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter)
|
|||
gimp_applicator_set_mask_buffer (filter->applicator, mask_buffer);
|
||||
gimp_applicator_set_mask_offset (filter->applicator,
|
||||
-offset_x, -offset_y);
|
||||
}
|
||||
|
||||
gimp_item_mask_intersect (GIMP_ITEM (filter->drawable),
|
||||
&filter->filter_area.x,
|
||||
&filter->filter_area.y,
|
||||
&filter->filter_area.width,
|
||||
&filter->filter_area.height);
|
||||
/* Update filter crop */
|
||||
filter->filter_area.x = mask->x1;
|
||||
filter->filter_area.y = mask->y1;
|
||||
filter->filter_area.width = mask->x2 - mask->x1;
|
||||
filter->filter_area.height = mask->y2 - mask->y1;
|
||||
|
||||
gimp_drawable_filter_sync_region (filter);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1052,24 +1309,25 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
|
|||
g_signal_connect (image, "component-active-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_affect_changed),
|
||||
filter);
|
||||
g_signal_connect (image, "mask-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_mask_changed),
|
||||
filter);
|
||||
g_signal_connect (filter->drawable, "lock-position-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_lock_position_changed),
|
||||
filter);
|
||||
g_signal_connect (filter->drawable, "format-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_format_changed),
|
||||
filter);
|
||||
g_signal_connect (filter->drawable, "removed",
|
||||
G_CALLBACK (gimp_drawable_filter_drawable_removed),
|
||||
filter);
|
||||
if (! filter->mask)
|
||||
g_signal_connect_object (image, "mask-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_mask_changed),
|
||||
filter, 0);
|
||||
g_signal_connect_object (filter->drawable, "lock-position-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_lock_position_changed),
|
||||
filter, 0);
|
||||
g_signal_connect_object (filter->drawable, "format-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_format_changed),
|
||||
filter, 0);
|
||||
g_signal_connect_object (filter->drawable, "removed",
|
||||
G_CALLBACK (gimp_drawable_filter_drawable_removed),
|
||||
filter, 0);
|
||||
|
||||
if (GIMP_IS_LAYER (filter->drawable))
|
||||
{
|
||||
g_signal_connect (filter->drawable, "lock-alpha-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_lock_alpha_changed),
|
||||
filter);
|
||||
g_signal_connect_object (filter->drawable, "lock-alpha-changed",
|
||||
G_CALLBACK (gimp_drawable_filter_lock_alpha_changed),
|
||||
filter, 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -1101,9 +1359,7 @@ gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
|
|||
g_signal_handlers_disconnect_by_func (filter->drawable,
|
||||
gimp_drawable_filter_lock_position_changed,
|
||||
filter);
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
gimp_drawable_filter_mask_changed,
|
||||
filter);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
gimp_drawable_filter_affect_changed,
|
||||
filter);
|
||||
|
|
@ -1111,9 +1367,12 @@ gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
|
|||
gimp_drawable_remove_filter (filter->drawable,
|
||||
GIMP_FILTER (filter));
|
||||
|
||||
gimp_drawable_update_bounding_box (filter->drawable);
|
||||
if (filter->drawable &&
|
||||
GIMP_IS_DRAWABLE (filter->drawable))
|
||||
gimp_drawable_update_bounding_box (filter->drawable);
|
||||
|
||||
gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
|
||||
if (gimp_viewable_preview_is_frozen (GIMP_VIEWABLE (filter->drawable)))
|
||||
gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1181,13 +1440,22 @@ static void
|
|||
gimp_drawable_filter_mask_changed (GimpImage *image,
|
||||
GimpDrawableFilter *filter)
|
||||
{
|
||||
gimp_drawable_filter_update_drawable (filter, NULL);
|
||||
if (! filter->mask)
|
||||
{
|
||||
gimp_drawable_filter_update_drawable (filter, NULL);
|
||||
|
||||
gimp_drawable_filter_sync_mask (filter);
|
||||
gimp_drawable_filter_sync_clip (filter, FALSE);
|
||||
gimp_drawable_filter_sync_region (filter);
|
||||
gimp_drawable_filter_sync_mask (filter);
|
||||
gimp_drawable_filter_sync_clip (filter, FALSE);
|
||||
gimp_drawable_filter_sync_region (filter);
|
||||
|
||||
gimp_drawable_filter_update_drawable (filter, NULL);
|
||||
gimp_drawable_filter_update_drawable (filter, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
gimp_drawable_filter_mask_changed,
|
||||
filter);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1210,7 +1478,8 @@ static void
|
|||
gimp_drawable_filter_drawable_removed (GimpDrawable *drawable,
|
||||
GimpDrawableFilter *filter)
|
||||
{
|
||||
gimp_drawable_filter_remove_filter (filter);
|
||||
if (filter)
|
||||
gimp_drawable_filter_remove_filter (filter);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -54,10 +54,29 @@ GimpDrawableFilter *
|
|||
const gchar *undo_desc,
|
||||
GeglNode *operation,
|
||||
const gchar *icon_name);
|
||||
GimpDrawableFilter *
|
||||
gimp_drawable_filter_duplicate (GimpDrawable *drawable,
|
||||
GimpDrawableFilter *prior_filter);
|
||||
|
||||
GimpDrawable *
|
||||
gimp_drawable_filter_get_drawable (GimpDrawableFilter *filter);
|
||||
GeglNode * gimp_drawable_filter_get_operation (GimpDrawableFilter *filter);
|
||||
GimpChannel *
|
||||
gimp_drawable_filter_get_mask (GimpDrawableFilter *filter);
|
||||
gdouble gimp_drawable_filter_get_opacity (GimpDrawableFilter *filter);
|
||||
GimpLayerMode
|
||||
gimp_drawable_filter_get_paint_mode (GimpDrawableFilter *filter);
|
||||
GimpLayerColorSpace
|
||||
gimp_drawable_filter_get_blend_space
|
||||
(GimpDrawableFilter *filter);
|
||||
GimpLayerColorSpace
|
||||
gimp_drawable_filter_get_composite_space
|
||||
(GimpDrawableFilter *filter);
|
||||
GimpLayerCompositeMode
|
||||
gimp_drawable_filter_get_composite_mode
|
||||
(GimpDrawableFilter *filter);
|
||||
GimpFilterRegion
|
||||
gimp_drawable_filter_get_region (GimpDrawableFilter *filter);
|
||||
|
||||
void gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
|
||||
gboolean clip);
|
||||
|
|
@ -97,9 +116,15 @@ void gimp_drawable_filter_apply (GimpDrawableFilter *filter,
|
|||
const GeglRectangle *area);
|
||||
|
||||
gboolean gimp_drawable_filter_commit (GimpDrawableFilter *filter,
|
||||
gboolean non_destructive,
|
||||
GimpProgress *progress,
|
||||
gboolean cancellable);
|
||||
void gimp_drawable_filter_abort (GimpDrawableFilter *filter);
|
||||
|
||||
void gimp_drawable_filter_layer_mask_freeze
|
||||
(GimpDrawableFilter *filter);
|
||||
void gimp_drawable_filter_refresh_crop (GimpDrawableFilter *filter,
|
||||
GeglRectangle *rect);
|
||||
|
||||
|
||||
#endif /* __GIMP_DRAWABLE_FILTER_H__ */
|
||||
|
|
|
|||
228
app/core/gimpdrawablefilterundo.c
Normal file
228
app/core/gimpdrawablefilterundo.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 "gimpcontainer.h"
|
||||
#include "gimpdrawable-filters.h"
|
||||
#include "gimpdrawablefilter.h"
|
||||
#include "gimpdrawablefilterundo.h"
|
||||
#include "gimpimage.h"
|
||||
#include "gimpitem.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FILTER
|
||||
};
|
||||
|
||||
|
||||
static void gimp_drawable_filter_undo_constructed (GObject *object);
|
||||
static void gimp_drawable_filter_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_drawable_filter_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gint64 gimp_drawable_filter_undo_get_memsize (GimpObject *object,
|
||||
gint64 *gui_size);
|
||||
static void gimp_drawable_filter_undo_pop (GimpUndo *undo,
|
||||
GimpUndoMode undo_mode,
|
||||
GimpUndoAccumulator *accum);
|
||||
static void gimp_drawable_filter_undo_free (GimpUndo *undo,
|
||||
GimpUndoMode undo_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpDrawableFilterUndo, gimp_drawable_filter_undo, GIMP_TYPE_UNDO)
|
||||
|
||||
#define parent_class gimp_drawable_filter_undo_parent_class
|
||||
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_class_init (GimpDrawableFilterUndoClass *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_drawable_filter_undo_constructed;
|
||||
object_class->set_property = gimp_drawable_filter_undo_set_property;
|
||||
object_class->get_property = gimp_drawable_filter_undo_get_property;
|
||||
|
||||
gimp_object_class->get_memsize = gimp_drawable_filter_undo_get_memsize;
|
||||
|
||||
undo_class->pop = gimp_drawable_filter_undo_pop;
|
||||
undo_class->free = gimp_drawable_filter_undo_free;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILTER,
|
||||
g_param_spec_object ("filter", NULL, NULL,
|
||||
GIMP_TYPE_DRAWABLE_FILTER,
|
||||
GIMP_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_init (GimpDrawableFilterUndo *undo)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_constructed (GObject *object)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (object);
|
||||
GimpDrawable *drawable;
|
||||
GimpContainer *filter_stack;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
gimp_assert (GIMP_IS_DRAWABLE_FILTER (drawable_filter_undo->filter));
|
||||
|
||||
drawable = gimp_drawable_filter_get_drawable (drawable_filter_undo->filter);
|
||||
if (drawable)
|
||||
{
|
||||
filter_stack = gimp_drawable_get_filters (drawable);
|
||||
|
||||
drawable_filter_undo->row_index =
|
||||
gimp_container_get_child_index (filter_stack,
|
||||
GIMP_OBJECT (drawable_filter_undo->filter));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_FILTER:
|
||||
drawable_filter_undo->filter = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_FILTER:
|
||||
g_value_set_object (value, drawable_filter_undo->filter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gint64
|
||||
gimp_drawable_filter_undo_get_memsize (GimpObject *object,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (object);
|
||||
gint64 memsize = 0;
|
||||
|
||||
memsize += gimp_object_get_memsize (GIMP_OBJECT (drawable_filter_undo->filter),
|
||||
NULL);
|
||||
memsize += sizeof (guint32);
|
||||
|
||||
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
||||
gui_size);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_pop (GimpUndo *undo,
|
||||
GimpUndoMode undo_mode,
|
||||
GimpUndoAccumulator *accum)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (undo);
|
||||
GimpDrawableFilter *filter = GIMP_DRAWABLE_FILTER (drawable_filter_undo->filter);
|
||||
GimpDrawable *drawable = gimp_drawable_filter_get_drawable (filter);
|
||||
GimpContainer *filter_stack = gimp_drawable_get_filters (drawable);
|
||||
|
||||
GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
|
||||
|
||||
if ((undo_mode == GIMP_UNDO_MODE_UNDO &&
|
||||
undo->undo_type == GIMP_UNDO_FILTER_ADD) ||
|
||||
(undo_mode == GIMP_UNDO_MODE_REDO &&
|
||||
undo->undo_type == GIMP_UNDO_FILTER_REMOVE) )
|
||||
{
|
||||
if (drawable)
|
||||
{
|
||||
gimp_drawable_remove_filter (drawable, GIMP_FILTER (filter));
|
||||
|
||||
gimp_item_set_visible (GIMP_ITEM (drawable), FALSE, FALSE);
|
||||
gimp_image_flush (undo->image);
|
||||
gimp_item_set_visible (GIMP_ITEM (drawable), TRUE, FALSE);
|
||||
gimp_image_flush (undo->image);
|
||||
}
|
||||
}
|
||||
if ((undo_mode == GIMP_UNDO_MODE_UNDO &&
|
||||
undo->undo_type == GIMP_UNDO_FILTER_REMOVE) ||
|
||||
(undo_mode == GIMP_UNDO_MODE_REDO &&
|
||||
undo->undo_type == GIMP_UNDO_FILTER_ADD) )
|
||||
{
|
||||
if (drawable)
|
||||
{
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
gimp_container_reorder (filter_stack, GIMP_OBJECT (filter),
|
||||
drawable_filter_undo->row_index);
|
||||
}
|
||||
}
|
||||
else if (undo->undo_type == GIMP_UNDO_FILTER_REORDER)
|
||||
{
|
||||
gimp_container_reorder (filter_stack, GIMP_OBJECT (filter),
|
||||
drawable_filter_undo->row_index);
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_undo_free (GimpUndo *undo,
|
||||
GimpUndoMode undo_mode)
|
||||
{
|
||||
GimpDrawableFilterUndo *drawable_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (undo);
|
||||
|
||||
if (drawable_filter_undo->filter)
|
||||
g_clear_object (&drawable_filter_undo->filter);
|
||||
|
||||
GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode);
|
||||
}
|
||||
53
app/core/gimpdrawablefilterundo.h
Normal file
53
app/core/gimpdrawablefilterundo.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_DRAWABLE_FILTER_UNDO_H__
|
||||
#define __GIMP_DRAWABLE_FILTER_UNDO_H__
|
||||
|
||||
|
||||
#include "gimpundo.h"
|
||||
|
||||
|
||||
#define GIMP_TYPE_DRAWABLE_FILTER_UNDO (gimp_drawable_filter_undo_get_type ())
|
||||
#define GIMP_DRAWABLE_FILTER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DRAWABLE_FILTER_UNDO, GimpDrawableFilterUndo))
|
||||
#define GIMP_DRAWABLE_FILTER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_DRAWABLE_FILTER_UNDO, GimpDrawableFilterUndoClass))
|
||||
#define GIMP_IS_DRAWABLE_FILTER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DRAWABLE_FILTER_UNDO))
|
||||
#define GIMP_IS_DRAWABLE_FILTER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_DRAWABLE_FILTER_UNDO))
|
||||
#define GIMP_DRAWABLE_FILTER_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DRAWABLE_FILTER_UNDO, GimpDrawableFilterUndoClass))
|
||||
|
||||
|
||||
typedef struct _GimpDrawableFilterUndo GimpDrawableFilterUndo;
|
||||
typedef struct _GimpDrawableFilterUndoClass GimpDrawableFilterUndoClass;
|
||||
|
||||
struct _GimpDrawableFilterUndo
|
||||
{
|
||||
GimpUndo parent_instance;
|
||||
|
||||
GimpDrawableFilter *filter;
|
||||
guint32 row_index;
|
||||
};
|
||||
|
||||
struct _GimpDrawableFilterUndoClass
|
||||
{
|
||||
GimpUndoClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType gimp_drawable_filter_undo_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __GIMP_DRAWABLE_FILTER_UNDO_H__ */
|
||||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "gimp.h"
|
||||
#include "gimpchannel.h"
|
||||
#include "gimpdrawable-filters.h"
|
||||
#include "gimpdrawablefilter.h"
|
||||
#include "gimpguide.h"
|
||||
#include "gimpimage.h"
|
||||
#include "gimpimage-color-profile.h"
|
||||
|
|
@ -259,6 +261,36 @@ gimp_image_duplicate_layers (GimpImage *image,
|
|||
|
||||
gimp_image_add_layer (new_image, new_layer,
|
||||
NULL, count++, FALSE);
|
||||
|
||||
/* Import any attached layer effects */
|
||||
if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer)))
|
||||
{
|
||||
GList *filter_list;
|
||||
GimpContainer *filters;
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer));
|
||||
|
||||
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
|
||||
filter_list = g_list_previous (filter_list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
|
||||
{
|
||||
GimpDrawableFilter *old_filter = filter_list->data;
|
||||
GimpDrawableFilter *filter;
|
||||
|
||||
filter =
|
||||
gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer),
|
||||
old_filter);
|
||||
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
|
||||
|
||||
gimp_drawable_filter_layer_mask_freeze (filter);
|
||||
|
||||
g_object_unref (filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_item_stack = GIMP_ITEM_STACK (gimp_image_get_layers (new_image));
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "gimp.h"
|
||||
#include "gimpchannelpropundo.h"
|
||||
#include "gimpchannelundo.h"
|
||||
#include "gimpdrawablefilter.h"
|
||||
#include "gimpdrawablefilterundo.h"
|
||||
#include "gimpdrawablemodundo.h"
|
||||
#include "gimpdrawablepropundo.h"
|
||||
#include "gimpdrawableundo.h"
|
||||
|
|
@ -306,6 +308,58 @@ gimp_image_undo_push_drawable_format (GimpImage *image,
|
|||
}
|
||||
|
||||
|
||||
/***************************/
|
||||
/* Drawable Filter Undos */
|
||||
/***************************/
|
||||
GimpUndo *
|
||||
gimp_image_undo_push_filter_add (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
|
||||
|
||||
return gimp_image_undo_push (image, GIMP_TYPE_DRAWABLE_FILTER_UNDO,
|
||||
GIMP_UNDO_FILTER_ADD, undo_desc,
|
||||
GIMP_DIRTY_DRAWABLE,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GimpUndo *
|
||||
gimp_image_undo_push_filter_remove (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
|
||||
|
||||
return gimp_image_undo_push (image, GIMP_TYPE_DRAWABLE_FILTER_UNDO,
|
||||
GIMP_UNDO_FILTER_REMOVE, undo_desc,
|
||||
GIMP_DIRTY_DRAWABLE,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GimpUndo *
|
||||
gimp_image_undo_push_filter_reorder (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
|
||||
|
||||
return gimp_image_undo_push (image, GIMP_TYPE_DRAWABLE_FILTER_UNDO,
|
||||
GIMP_UNDO_FILTER_REORDER, undo_desc,
|
||||
GIMP_DIRTY_DRAWABLE,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Mask Undos */
|
||||
/****************/
|
||||
|
|
|
|||
|
|
@ -77,6 +77,26 @@ GimpUndo * gimp_image_undo_push_drawable_format (GimpImage *image,
|
|||
GimpDrawable *drawable);
|
||||
|
||||
|
||||
/* drawable filter undos */
|
||||
GimpUndo * gimp_image_undo_push_filter_add (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter
|
||||
*filter);
|
||||
|
||||
GimpUndo * gimp_image_undo_push_filter_remove (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter
|
||||
*filter);
|
||||
|
||||
GimpUndo * gimp_image_undo_push_filter_reorder (GimpImage *image,
|
||||
const gchar *undo_desc,
|
||||
GimpDrawable *drawable,
|
||||
GimpDrawableFilter
|
||||
*filter);
|
||||
|
||||
|
||||
/* mask undos */
|
||||
|
||||
GimpUndo * gimp_image_undo_push_mask (GimpImage *image,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "gimp-parasites.h"
|
||||
#include "gimp-utils.h"
|
||||
#include "gimpcontext.h"
|
||||
#include "gimpdrawable-filters.h"
|
||||
#include "gimpdrawable-floating-selection.h"
|
||||
#include "gimpdrawablestack.h"
|
||||
#include "gimpgrid.h"
|
||||
|
|
@ -2974,6 +2975,13 @@ gimp_image_get_xcf_version (GimpImage *image,
|
|||
"GIMP 3.0"));
|
||||
version = MAX (19, version);
|
||||
}
|
||||
|
||||
if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer)))
|
||||
{
|
||||
ADD_REASON (g_strdup_printf (_("Layer effects were added in %s"),
|
||||
"GIMP 3.0"));
|
||||
version = MAX (20, version);
|
||||
}
|
||||
}
|
||||
g_list_free (items);
|
||||
|
||||
|
|
@ -3141,6 +3149,7 @@ gimp_image_get_xcf_version (GimpImage *image,
|
|||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
if (gimp_version) *gimp_version = 300;
|
||||
if (version_string) *version_string = "GIMP 3.0";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -188,6 +188,23 @@ gimp_pickable_get_buffer (GimpPickable *pickable)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
GeglBuffer *
|
||||
gimp_pickable_get_buffer_with_effects (GimpPickable *pickable)
|
||||
{
|
||||
GimpPickableInterface *pickable_iface;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
|
||||
|
||||
pickable_iface = GIMP_PICKABLE_GET_IFACE (pickable);
|
||||
|
||||
if (pickable_iface->get_buffer_with_effects)
|
||||
return pickable_iface->get_buffer_with_effects (pickable);
|
||||
else if (pickable_iface->get_buffer)
|
||||
return pickable_iface->get_buffer (pickable);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gimp_pickable_get_pixel_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
|
|
|
|||
|
|
@ -30,74 +30,76 @@ struct _GimpPickableInterface
|
|||
GTypeInterface base_iface;
|
||||
|
||||
/* virtual functions */
|
||||
void (* flush) (GimpPickable *pickable);
|
||||
GimpImage * (* get_image) (GimpPickable *pickable);
|
||||
const Babl * (* get_format) (GimpPickable *pickable);
|
||||
const Babl * (* get_format_with_alpha) (GimpPickable *pickable);
|
||||
GeglBuffer * (* get_buffer) (GimpPickable *pickable);
|
||||
gboolean (* get_pixel_at) (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
gdouble (* get_opacity_at) (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y);
|
||||
void (* get_pixel_average) (GimpPickable *pickable,
|
||||
const GeglRectangle *rect,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void (* pixel_to_rgb) (GimpPickable *pickable,
|
||||
const Babl *format,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
void (* rgb_to_pixel) (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void (* flush) (GimpPickable *pickable);
|
||||
GimpImage * (* get_image) (GimpPickable *pickable);
|
||||
const Babl * (* get_format) (GimpPickable *pickable);
|
||||
const Babl * (* get_format_with_alpha) (GimpPickable *pickable);
|
||||
GeglBuffer * (* get_buffer) (GimpPickable *pickable);
|
||||
GeglBuffer * (* get_buffer_with_effects) (GimpPickable *pickable);
|
||||
gboolean (* get_pixel_at) (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
gdouble (* get_opacity_at) (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y);
|
||||
void (* get_pixel_average) (GimpPickable *pickable,
|
||||
const GeglRectangle *rect,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void (* pixel_to_rgb) (GimpPickable *pickable,
|
||||
const Babl *format,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
void (* rgb_to_pixel) (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
};
|
||||
|
||||
|
||||
void gimp_pickable_flush (GimpPickable *pickable);
|
||||
GimpImage * gimp_pickable_get_image (GimpPickable *pickable);
|
||||
const Babl * gimp_pickable_get_format (GimpPickable *pickable);
|
||||
const Babl * gimp_pickable_get_format_with_alpha (GimpPickable *pickable);
|
||||
GeglBuffer * gimp_pickable_get_buffer (GimpPickable *pickable);
|
||||
gboolean gimp_pickable_get_pixel_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
gboolean gimp_pickable_get_color_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
GimpRGB *color);
|
||||
gdouble gimp_pickable_get_opacity_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y);
|
||||
void gimp_pickable_get_pixel_average (GimpPickable *pickable,
|
||||
const GeglRectangle *rect,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void gimp_pickable_pixel_to_rgb (GimpPickable *pickable,
|
||||
const Babl *format,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
void gimp_pickable_rgb_to_pixel (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void gimp_pickable_srgb_to_image_color (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
GimpRGB *image_color);
|
||||
void gimp_pickable_flush (GimpPickable *pickable);
|
||||
GimpImage * gimp_pickable_get_image (GimpPickable *pickable);
|
||||
const Babl * gimp_pickable_get_format (GimpPickable *pickable);
|
||||
const Babl * gimp_pickable_get_format_with_alpha (GimpPickable *pickable);
|
||||
GeglBuffer * gimp_pickable_get_buffer (GimpPickable *pickable);
|
||||
GeglBuffer * gimp_pickable_get_buffer_with_effects (GimpPickable *pickable);
|
||||
gboolean gimp_pickable_get_pixel_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
gboolean gimp_pickable_get_color_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
GimpRGB *color);
|
||||
gdouble gimp_pickable_get_opacity_at (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y);
|
||||
void gimp_pickable_get_pixel_average (GimpPickable *pickable,
|
||||
const GeglRectangle *rect,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void gimp_pickable_pixel_to_rgb (GimpPickable *pickable,
|
||||
const Babl *format,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
void gimp_pickable_rgb_to_pixel (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
const Babl *format,
|
||||
gpointer pixel);
|
||||
void gimp_pickable_srgb_to_image_color (GimpPickable *pickable,
|
||||
const GimpRGB *color,
|
||||
GimpRGB *image_color);
|
||||
|
||||
gboolean gimp_pickable_pick_color (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean sample_average,
|
||||
gdouble average_radius,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
gboolean gimp_pickable_pick_color (GimpPickable *pickable,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean sample_average,
|
||||
gdouble average_radius,
|
||||
gpointer pixel,
|
||||
GimpRGB *color);
|
||||
|
||||
|
||||
#endif /* __GIMP_PICKABLE_H__ */
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ libappcore_sources = [
|
|||
'gimpdrawable-transform.c',
|
||||
'gimpdrawable.c',
|
||||
'gimpdrawablefilter.c',
|
||||
'gimpdrawablefilterundo.c',
|
||||
'gimpdrawablemodundo.c',
|
||||
'gimpdrawablepropundo.c',
|
||||
'gimpdrawablestack.c',
|
||||
|
|
|
|||
|
|
@ -141,15 +141,27 @@ gimp_gegl_progress_connect (GeglNode *node,
|
|||
g_return_if_fail (GIMP_IS_PROGRESS (progress));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
g_signal_connect (node, "progress",
|
||||
G_CALLBACK (gimp_gegl_progress_callback),
|
||||
progress);
|
||||
g_signal_connect_object (node, "progress",
|
||||
G_CALLBACK (gimp_gegl_progress_callback),
|
||||
progress, 0);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (node),
|
||||
"gimp-progress-text", g_strdup (text),
|
||||
(GDestroyNotify) g_free);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_gegl_progress_disconnect (GeglNode *node,
|
||||
GimpProgress *progress)
|
||||
{
|
||||
g_return_if_fail (GEGL_IS_NODE (node));
|
||||
g_return_if_fail (GIMP_IS_PROGRESS (progress));
|
||||
|
||||
g_signal_handlers_disconnect_by_func (node,
|
||||
gimp_gegl_progress_callback,
|
||||
progress);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gimp_gegl_node_is_source_operation (GeglNode *node)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ GeglColor * gimp_gegl_color_new (const GimpRGB *rgb,
|
|||
void gimp_gegl_progress_connect (GeglNode *node,
|
||||
GimpProgress *progress,
|
||||
const gchar *text);
|
||||
void gimp_gegl_progress_disconnect (GeglNode *node,
|
||||
GimpProgress *progress);
|
||||
|
||||
gboolean gimp_gegl_node_is_source_operation (GeglNode *node);
|
||||
gboolean gimp_gegl_node_is_point_operation (GeglNode *node);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/gimp.h"
|
||||
#include "core/gimpchannel-select.h"
|
||||
#include "core/gimpdrawable-fill.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawable-foreground-extract.h"
|
||||
#include "core/gimpdrawable-offset.h"
|
||||
#include "core/gimpdrawable-preview.h"
|
||||
|
|
@ -502,6 +503,35 @@ drawable_mask_intersect_invoker (GimpProcedure *procedure,
|
|||
return return_vals;
|
||||
}
|
||||
|
||||
static GimpValueArray *
|
||||
drawable_merge_filters_invoker (GimpProcedure *procedure,
|
||||
Gimp *gimp,
|
||||
GimpContext *context,
|
||||
GimpProgress *progress,
|
||||
const GimpValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
GimpDrawable *drawable;
|
||||
|
||||
drawable = g_value_get_object (gimp_value_array_index (args, 0));
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
|
||||
GIMP_PDB_ITEM_CONTENT, error) &&
|
||||
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
|
||||
{
|
||||
gimp_drawable_merge_filters (drawable);
|
||||
}
|
||||
else
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
return gimp_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
}
|
||||
|
||||
static GimpValueArray *
|
||||
drawable_merge_shadow_invoker (GimpProcedure *procedure,
|
||||
Gimp *gimp,
|
||||
|
|
@ -1348,6 +1378,29 @@ register_drawable_procs (GimpPDB *pdb)
|
|||
gimp_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* gimp-drawable-merge-filters
|
||||
*/
|
||||
procedure = gimp_procedure_new (drawable_merge_filters_invoker);
|
||||
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||
"gimp-drawable-merge-filters");
|
||||
gimp_procedure_set_static_help (procedure,
|
||||
"Merge the layer effect filters to the specified drawable.",
|
||||
"This procedure combines the contents of the drawable's filter stack (for export) with the specified drawable.",
|
||||
NULL);
|
||||
gimp_procedure_set_static_attribution (procedure,
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1996");
|
||||
gimp_procedure_add_argument (procedure,
|
||||
gimp_param_spec_drawable ("drawable",
|
||||
"drawable",
|
||||
"The drawable",
|
||||
FALSE,
|
||||
GIMP_PARAM_READWRITE));
|
||||
gimp_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* gimp-drawable-merge-shadow
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include "internal-procs.h"
|
||||
|
||||
|
||||
/* 781 procedures registered total */
|
||||
/* 782 procedures registered total */
|
||||
|
||||
void
|
||||
internal_procs_init (GimpPDB *pdb)
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ gimp_bucket_fill_tool_commit (GimpBucketFillTool *tool)
|
|||
{
|
||||
if (tool->priv->filter)
|
||||
{
|
||||
gimp_drawable_filter_commit (tool->priv->filter,
|
||||
gimp_drawable_filter_commit (tool->priv->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
gimp_image_flush (gimp_display_get_image (GIMP_TOOL (tool)->display));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1029,7 +1029,8 @@ gimp_cage_tool_commit (GimpCageTool *ct)
|
|||
|
||||
gimp_tool_control_push_preserve (tool->control, TRUE);
|
||||
|
||||
gimp_drawable_filter_commit (ct->filter, GIMP_PROGRESS (tool), FALSE);
|
||||
gimp_drawable_filter_commit (ct->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
g_clear_object (&ct->filter);
|
||||
|
||||
gimp_tool_control_pop_preserve (tool->control);
|
||||
|
|
|
|||
|
|
@ -46,12 +46,14 @@
|
|||
#include "core/gimp.h"
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpdrawable.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimperror.h"
|
||||
#include "core/gimpguide.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimpimage-guides.h"
|
||||
#include "core/gimpimage-pick-color.h"
|
||||
#include "core/gimpimage-undo-push.h"
|
||||
#include "core/gimplayer.h"
|
||||
#include "core/gimplist.h"
|
||||
#include "core/gimppickable.h"
|
||||
|
|
@ -153,7 +155,8 @@ static void gimp_filter_tool_real_config_notify
|
|||
const GParamSpec *pspec);
|
||||
|
||||
static void gimp_filter_tool_halt (GimpFilterTool *filter_tool);
|
||||
static void gimp_filter_tool_commit (GimpFilterTool *filter_tool);
|
||||
static void gimp_filter_tool_commit (GimpFilterTool *filter_tool,
|
||||
gboolean non_destructive);
|
||||
|
||||
static void gimp_filter_tool_dialog (GimpFilterTool *filter_tool);
|
||||
static void gimp_filter_tool_reset (GimpFilterTool *filter_tool);
|
||||
|
|
@ -331,7 +334,7 @@ gimp_filter_tool_initialize (GimpTool *tool,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gimp_filter_tool_get_operation (filter_tool);
|
||||
gimp_filter_tool_get_operation (filter_tool, NULL);
|
||||
|
||||
gimp_filter_tool_disable_color_picking (filter_tool);
|
||||
|
||||
|
|
@ -339,7 +342,7 @@ gimp_filter_tool_initialize (GimpTool *tool,
|
|||
g_list_free (tool->drawables);
|
||||
tool->drawables = drawables;
|
||||
|
||||
if (filter_tool->config)
|
||||
if (filter_tool->config && ! filter_tool->existing_filter)
|
||||
gimp_config_reset (GIMP_CONFIG (filter_tool->config));
|
||||
|
||||
if (! filter_tool->gui)
|
||||
|
|
@ -465,7 +468,8 @@ gimp_filter_tool_control (GimpTool *tool,
|
|||
GimpToolAction action,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
|
||||
GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
|
||||
gboolean non_destructive = TRUE;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
|
|
@ -478,7 +482,12 @@ gimp_filter_tool_control (GimpTool *tool,
|
|||
break;
|
||||
|
||||
case GIMP_TOOL_ACTION_COMMIT:
|
||||
gimp_filter_tool_commit (filter_tool);
|
||||
/* TODO: Expand non-destructive editing to other drawables
|
||||
* besides layers */
|
||||
if (! GIMP_IS_LAYER (tool->drawables->data))
|
||||
non_destructive = FALSE;
|
||||
|
||||
gimp_filter_tool_commit (filter_tool, non_destructive);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -994,10 +1003,17 @@ gimp_filter_tool_halt (GimpFilterTool *filter_tool)
|
|||
if (filter_tool->filter)
|
||||
{
|
||||
gimp_drawable_filter_abort (filter_tool->filter);
|
||||
g_signal_handlers_disconnect_by_func (filter_tool->filter,
|
||||
gimp_filter_tool_flush,
|
||||
filter_tool);
|
||||
g_clear_object (&filter_tool->filter);
|
||||
gimp_filter_tool_remove_guide (filter_tool);
|
||||
}
|
||||
|
||||
if (filter_tool->operation)
|
||||
gimp_gegl_progress_disconnect (filter_tool->operation,
|
||||
GIMP_PROGRESS (filter_tool));
|
||||
|
||||
g_clear_object (&filter_tool->operation);
|
||||
|
||||
if (filter_tool->config)
|
||||
|
|
@ -1022,16 +1038,80 @@ gimp_filter_tool_halt (GimpFilterTool *filter_tool)
|
|||
tool->display = NULL;
|
||||
g_list_free (tool->drawables);
|
||||
tool->drawables = NULL;
|
||||
|
||||
if (filter_tool->existing_filter)
|
||||
{
|
||||
gimp_filter_set_active (GIMP_FILTER (filter_tool->existing_filter), TRUE);
|
||||
|
||||
/* Restore buttons in layer tree view */
|
||||
gimp_drawable_filters_changed (gimp_drawable_filter_get_drawable (filter_tool->existing_filter));
|
||||
}
|
||||
|
||||
filter_tool->existing_filter = NULL;
|
||||
}
|
||||
|
||||
/* Add code to prevent creating new filter when editing */
|
||||
static void
|
||||
gimp_filter_tool_commit (GimpFilterTool *filter_tool)
|
||||
gimp_filter_tool_commit (GimpFilterTool *filter_tool,
|
||||
gboolean non_destructive)
|
||||
{
|
||||
GimpTool *tool = GIMP_TOOL (filter_tool);
|
||||
|
||||
if (filter_tool->gui)
|
||||
gimp_tool_gui_hide (filter_tool->gui);
|
||||
|
||||
/* Copy over filter info back to existing filter */
|
||||
if (filter_tool->existing_filter)
|
||||
{
|
||||
GeglNode *existing_node;
|
||||
gdouble opacity;
|
||||
GimpLayerMode paint_mode;
|
||||
GimpLayerColorSpace blend_space;
|
||||
GimpLayerColorSpace composite_space;
|
||||
GimpLayerCompositeMode composite_mode;
|
||||
GimpFilterRegion region;
|
||||
GParamSpec **pspecs;
|
||||
guint n_pspecs;
|
||||
gchar *name = NULL;
|
||||
|
||||
opacity = gimp_drawable_filter_get_opacity (filter_tool->filter);
|
||||
paint_mode = gimp_drawable_filter_get_paint_mode (filter_tool->filter);
|
||||
blend_space = gimp_drawable_filter_get_blend_space (filter_tool->filter);
|
||||
composite_space = gimp_drawable_filter_get_composite_space (filter_tool->filter);
|
||||
composite_mode = gimp_drawable_filter_get_composite_mode (filter_tool->filter);
|
||||
region = gimp_drawable_filter_get_region (filter_tool->filter);
|
||||
|
||||
existing_node = gimp_drawable_filter_get_operation (filter_tool->existing_filter);
|
||||
gegl_node_get (existing_node,
|
||||
"operation", &name,
|
||||
NULL);
|
||||
|
||||
pspecs = gegl_operation_list_properties (name, &n_pspecs);
|
||||
g_free (name);
|
||||
|
||||
for (gint i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
gegl_node_get_property (filter_tool->operation, pspec->name,
|
||||
&value);
|
||||
|
||||
gegl_node_set_property (existing_node, pspec->name,
|
||||
&value);
|
||||
}
|
||||
|
||||
gimp_drawable_filter_set_opacity (filter_tool->existing_filter, opacity);
|
||||
gimp_drawable_filter_set_mode (filter_tool->existing_filter,
|
||||
paint_mode, blend_space, composite_space,
|
||||
composite_mode);
|
||||
gimp_drawable_filter_set_region (filter_tool->existing_filter, region);
|
||||
|
||||
/* Restore buttons in layer tree view */
|
||||
gimp_drawable_filters_changed (gimp_drawable_filter_get_drawable (filter_tool->existing_filter));
|
||||
}
|
||||
|
||||
if (filter_tool->filter)
|
||||
{
|
||||
GimpFilterOptions *options = GIMP_FILTER_TOOL_GET_OPTIONS (tool);
|
||||
|
|
@ -1039,10 +1119,36 @@ gimp_filter_tool_commit (GimpFilterTool *filter_tool)
|
|||
if (! options->preview)
|
||||
gimp_drawable_filter_apply (filter_tool->filter, NULL);
|
||||
|
||||
gimp_drawable_filter_layer_mask_freeze (filter_tool->filter);
|
||||
|
||||
if (non_destructive)
|
||||
{
|
||||
gimp_drawable_filter_abort (filter_tool->filter);
|
||||
|
||||
if (! filter_tool->existing_filter)
|
||||
gimp_drawable_filter_apply (filter_tool->filter, NULL);
|
||||
}
|
||||
|
||||
gimp_tool_control_push_preserve (tool->control, TRUE);
|
||||
|
||||
gimp_drawable_filter_commit (filter_tool->filter,
|
||||
GIMP_PROGRESS (tool), TRUE);
|
||||
if (! filter_tool->existing_filter)
|
||||
gimp_drawable_filter_commit (filter_tool->filter, non_destructive,
|
||||
GIMP_PROGRESS (tool), non_destructive);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (filter_tool->filter,
|
||||
gimp_filter_tool_flush,
|
||||
filter_tool);
|
||||
|
||||
if (non_destructive && ! filter_tool->existing_filter)
|
||||
{
|
||||
GimpDrawable *drawable =
|
||||
gimp_drawable_filter_get_drawable (filter_tool->filter);
|
||||
|
||||
gimp_image_undo_push_filter_add (gimp_display_get_image (tool->display),
|
||||
_("Add filter"),
|
||||
drawable, filter_tool->filter);
|
||||
}
|
||||
|
||||
g_clear_object (&filter_tool->filter);
|
||||
|
||||
gimp_tool_control_pop_preserve (tool->control);
|
||||
|
|
@ -1059,6 +1165,11 @@ gimp_filter_tool_commit (GimpFilterTool *filter_tool)
|
|||
config->filter_tool_max_recent);
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_tool->existing_filter)
|
||||
gimp_filter_set_active (GIMP_FILTER (filter_tool->existing_filter), TRUE);
|
||||
|
||||
filter_tool->existing_filter = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1227,6 +1338,33 @@ gimp_filter_tool_create_filter (GimpFilterTool *filter_tool)
|
|||
|
||||
if (options->preview)
|
||||
gimp_drawable_filter_apply (filter_tool->filter, NULL);
|
||||
|
||||
/* If editing existing filter, shift into the right location
|
||||
* in the filter stack. */
|
||||
if (filter_tool->existing_filter)
|
||||
{
|
||||
GimpContainer *filters;
|
||||
GimpChannel *mask;
|
||||
gint index;
|
||||
const gchar *name = _("Editing filter...");
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (tool->drawables->data));
|
||||
|
||||
if (filters)
|
||||
{
|
||||
index = gimp_container_get_child_index (filters,
|
||||
GIMP_OBJECT (filter_tool->existing_filter));
|
||||
|
||||
gimp_container_reorder (filters, GIMP_OBJECT (filter_tool->filter),
|
||||
index);
|
||||
}
|
||||
|
||||
mask = gimp_drawable_filter_get_mask (filter_tool->existing_filter);
|
||||
g_object_set (filter_tool->filter,
|
||||
"name", name,
|
||||
"mask", mask,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1594,7 +1732,8 @@ gimp_filter_tool_set_has_settings (GimpFilterTool *filter_tool,
|
|||
/* public functions */
|
||||
|
||||
void
|
||||
gimp_filter_tool_get_operation (GimpFilterTool *filter_tool)
|
||||
gimp_filter_tool_get_operation (GimpFilterTool *filter_tool,
|
||||
GimpDrawableFilter *existing_filter)
|
||||
{
|
||||
GimpTool *tool;
|
||||
GimpFilterToolClass *klass;
|
||||
|
|
@ -1643,6 +1782,11 @@ gimp_filter_tool_get_operation (GimpFilterTool *filter_tool)
|
|||
filter_tool->operation = gegl_node_new_child (NULL,
|
||||
"operation", operation_name,
|
||||
NULL);
|
||||
if (existing_filter)
|
||||
{
|
||||
filter_tool->existing_filter = existing_filter;
|
||||
gimp_filter_set_active (GIMP_FILTER (filter_tool->existing_filter), FALSE);
|
||||
}
|
||||
|
||||
filter_tool->config =
|
||||
g_object_new (gimp_operation_config_get_type (tool->tool_info->gimp,
|
||||
|
|
@ -1651,6 +1795,55 @@ gimp_filter_tool_get_operation (GimpFilterTool *filter_tool)
|
|||
GIMP_TYPE_OPERATION_SETTINGS),
|
||||
NULL);
|
||||
|
||||
/* Update layer effect if we're editing it */
|
||||
if (filter_tool->existing_filter)
|
||||
{
|
||||
GeglNode *existing_node;
|
||||
gdouble opacity;
|
||||
GimpLayerMode paint_mode;
|
||||
GimpFilterRegion region;
|
||||
GParamSpec **pspecs;
|
||||
guint n_pspecs;
|
||||
const gchar *name;
|
||||
|
||||
opacity = gimp_drawable_filter_get_opacity (filter_tool->existing_filter);
|
||||
paint_mode = gimp_drawable_filter_get_paint_mode (filter_tool->existing_filter);
|
||||
region = gimp_drawable_filter_get_region (filter_tool->existing_filter);
|
||||
|
||||
existing_node = gimp_drawable_filter_get_operation (filter_tool->existing_filter);
|
||||
gegl_node_get (existing_node,
|
||||
"operation", &name,
|
||||
NULL);
|
||||
|
||||
if (! strcmp (gimp_object_get_name (tool->tool_info), "gimp-operation-tool"))
|
||||
{
|
||||
pspecs = gegl_operation_list_properties (operation_name, &n_pspecs);
|
||||
|
||||
for (gint i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GValue value = G_VALUE_INIT;
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
GParamSpec *gimp_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (filter_tool->config),
|
||||
pspec->name);
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
gegl_node_get_property (existing_node, pspec->name,
|
||||
&value);
|
||||
|
||||
g_object_set_property (G_OBJECT (filter_tool->config), gimp_pspec->name,
|
||||
&value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
g_free (pspecs);
|
||||
}
|
||||
|
||||
g_object_set (filter_tool->config,
|
||||
"gimp-opacity", opacity,
|
||||
"gimp-mode", paint_mode,
|
||||
"gimp-region", region,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gimp_operation_config_sync_node (filter_tool->config,
|
||||
filter_tool->operation);
|
||||
gimp_operation_config_connect_node (filter_tool->config,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct _GimpFilterTool
|
|||
GimpColorTool parent_instance;
|
||||
|
||||
GeglNode *operation;
|
||||
GimpDrawableFilter *existing_filter;
|
||||
GObject *config;
|
||||
GObject *default_config;
|
||||
GimpContainer *settings;
|
||||
|
|
@ -103,7 +104,8 @@ struct _GimpFilterToolClass
|
|||
|
||||
GType gimp_filter_tool_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gimp_filter_tool_get_operation (GimpFilterTool *filter_tool);
|
||||
void gimp_filter_tool_get_operation (GimpFilterTool *filter_tool,
|
||||
GimpDrawableFilter *existing_filter);
|
||||
|
||||
void gimp_filter_tool_set_config (GimpFilterTool *filter_tool,
|
||||
GimpConfig *config);
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ gimp_gegl_tool_halt (GimpGeglTool *gegl_tool)
|
|||
{
|
||||
GimpOperationTool *op_tool = GIMP_OPERATION_TOOL (gegl_tool);
|
||||
|
||||
gimp_operation_tool_set_operation (op_tool, NULL,
|
||||
gimp_operation_tool_set_operation (op_tool, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -272,10 +272,15 @@ gimp_gegl_tool_operation_changed (GtkWidget *widget,
|
|||
|
||||
if (operation)
|
||||
{
|
||||
const gchar *title;
|
||||
const gchar *description;
|
||||
|
||||
title = gegl_operation_get_key (operation, "title");
|
||||
description = gegl_operation_get_key (operation, "description");
|
||||
|
||||
if (! title)
|
||||
title = gegl_operation_get_key (operation, "name");
|
||||
|
||||
if (description)
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (tool->description_label), description);
|
||||
|
|
@ -287,9 +292,11 @@ gimp_gegl_tool_operation_changed (GtkWidget *widget,
|
|||
}
|
||||
|
||||
gimp_operation_tool_set_operation (GIMP_OPERATION_TOOL (tool),
|
||||
NULL,
|
||||
operation,
|
||||
_("GEGL Operation"),
|
||||
_("GEGL Operation"),
|
||||
title ?
|
||||
title : _("GEGL Operation"),
|
||||
NULL,
|
||||
GIMP_ICON_GEGL,
|
||||
GIMP_HELP_TOOL_GEGL);
|
||||
|
|
|
|||
|
|
@ -769,7 +769,7 @@ gimp_gradient_tool_commit (GimpGradientTool *gradient_tool)
|
|||
|
||||
gimp_tool_control_push_preserve (tool->control, TRUE);
|
||||
|
||||
gimp_drawable_filter_commit (gradient_tool->filter,
|
||||
gimp_drawable_filter_commit (gradient_tool->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
g_clear_object (&gradient_tool->filter);
|
||||
|
||||
|
|
|
|||
|
|
@ -810,13 +810,14 @@ gimp_operation_tool_relink_chains (GimpOperationTool *op_tool)
|
|||
/* public functions */
|
||||
|
||||
void
|
||||
gimp_operation_tool_set_operation (GimpOperationTool *op_tool,
|
||||
const gchar *operation,
|
||||
const gchar *title,
|
||||
const gchar *description,
|
||||
const gchar *undo_desc,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id)
|
||||
gimp_operation_tool_set_operation (GimpOperationTool *op_tool,
|
||||
GimpDrawableFilter *filter,
|
||||
const gchar *operation,
|
||||
const gchar *title,
|
||||
const gchar *description,
|
||||
const gchar *undo_desc,
|
||||
const gchar *icon_name,
|
||||
const gchar *help_id)
|
||||
{
|
||||
GimpTool *tool;
|
||||
GimpFilterTool *filter_tool;
|
||||
|
|
@ -855,7 +856,13 @@ gimp_operation_tool_set_operation (GimpOperationTool *op_tool,
|
|||
if (! operation)
|
||||
return;
|
||||
|
||||
gimp_filter_tool_get_operation (filter_tool);
|
||||
gimp_filter_tool_get_operation (filter_tool, filter);
|
||||
|
||||
/* Update filter name for GeglOperation tool presets */
|
||||
if (filter_tool->filter && description)
|
||||
g_object_set (filter_tool->filter,
|
||||
"name", description,
|
||||
NULL);
|
||||
|
||||
if (tool->drawables)
|
||||
gimp_operation_tool_sync_op (op_tool, TRUE);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ void gimp_operation_tool_register (GimpToolRegisterCallback callback,
|
|||
GType gimp_operation_tool_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gimp_operation_tool_set_operation (GimpOperationTool *op_tool,
|
||||
GimpDrawableFilter *filter,
|
||||
const gchar *operation,
|
||||
const gchar *title,
|
||||
const gchar *description,
|
||||
|
|
|
|||
|
|
@ -379,7 +379,8 @@ gimp_seamless_clone_tool_commit (GimpSeamlessCloneTool *sc)
|
|||
{
|
||||
gimp_tool_control_push_preserve (tool->control, TRUE);
|
||||
|
||||
gimp_drawable_filter_commit (sc->filter, GIMP_PROGRESS (tool), FALSE);
|
||||
gimp_drawable_filter_commit (sc->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
g_clear_object (&sc->filter);
|
||||
|
||||
gimp_tool_control_pop_preserve (tool->control);
|
||||
|
|
@ -528,7 +529,8 @@ gimp_seamless_clone_tool_key_press (GimpTool *tool,
|
|||
* rectangle each time (in the update function) or by
|
||||
* invalidating and re-rendering all now (expensive and
|
||||
* perhaps useless */
|
||||
gimp_drawable_filter_commit (sct->filter, GIMP_PROGRESS (tool), FALSE);
|
||||
gimp_drawable_filter_commit (sct->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
g_clear_object (&sct->filter);
|
||||
|
||||
gimp_tool_control_set_preserve (tool->control, FALSE);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include "core/gimpasyncset.h"
|
||||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpdatafactory.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimperror.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimp-palettes.h"
|
||||
|
|
@ -42,6 +44,7 @@
|
|||
#include "core/gimpimage-undo.h"
|
||||
#include "core/gimpimage-undo-push.h"
|
||||
#include "core/gimplayer-floating-selection.h"
|
||||
#include "core/gimplist.h"
|
||||
#include "core/gimptoolinfo.h"
|
||||
#include "core/gimpundostack.h"
|
||||
|
||||
|
|
@ -1089,6 +1092,26 @@ gimp_text_tool_frame_item (GimpTextTool *text_tool)
|
|||
gimp_tool_rectangle_frame_item (GIMP_TOOL_RECTANGLE (text_tool->widget),
|
||||
GIMP_ITEM (text_tool->layer));
|
||||
|
||||
/* Update crop of any filters applied to text */
|
||||
if (text_tool->layer)
|
||||
{
|
||||
GList *list;
|
||||
GimpDrawable *drawable = GIMP_DRAWABLE (text_tool->layer);
|
||||
GimpContainer *filters = gimp_drawable_get_filters (drawable);
|
||||
|
||||
for (list = GIMP_LIST (filters)->queue->tail;
|
||||
list; list = g_list_previous (list))
|
||||
{
|
||||
GimpDrawableFilter *filter = list->data;
|
||||
|
||||
/* TODO: Handle partial layer effect */
|
||||
gimp_drawable_filter_set_region (filter, GIMP_FILTER_REGION_SELECTION);
|
||||
gimp_drawable_filter_set_region (filter, GIMP_FILTER_REGION_DRAWABLE);
|
||||
}
|
||||
if (list)
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
text_tool->handle_rectangle_change_complete = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -982,7 +982,8 @@ gimp_warp_tool_commit (GimpWarpTool *wt)
|
|||
|
||||
gimp_warp_tool_set_sampler (wt, /* commit = */ TRUE);
|
||||
|
||||
gimp_drawable_filter_commit (wt->filter, GIMP_PROGRESS (tool), FALSE);
|
||||
gimp_drawable_filter_commit (wt->filter, FALSE,
|
||||
GIMP_PROGRESS (tool), FALSE);
|
||||
g_clear_object (&wt->filter);
|
||||
|
||||
gimp_tool_control_pop_preserve (tool->control);
|
||||
|
|
|
|||
|
|
@ -30,15 +30,23 @@
|
|||
|
||||
#include "widgets-types.h"
|
||||
|
||||
#include "actions/gimpgeglprocedure.h"
|
||||
#include "actions/filters-commands.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimp-filter-history.h"
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpcontainer.h"
|
||||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimpdrawablefilterundo.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimpimage-undo.h"
|
||||
#include "core/gimpimage-undo-push.h"
|
||||
#include "core/gimpitem-exclusive.h"
|
||||
#include "core/gimpitemundo.h"
|
||||
#include "core/gimplist.h"
|
||||
#include "core/gimptreehandler.h"
|
||||
#include "core/gimpundostack.h"
|
||||
|
||||
|
|
@ -50,6 +58,7 @@
|
|||
#include "gimpdnd.h"
|
||||
#include "gimpdocked.h"
|
||||
#include "gimpitemtreeview.h"
|
||||
#include "gimplayertreeview.h"
|
||||
#include "gimpmenufactory.h"
|
||||
#include "gimpviewrenderer.h"
|
||||
#include "gimpuimanager.h"
|
||||
|
|
@ -80,6 +89,21 @@ struct _GimpItemTreeViewPrivate
|
|||
GtkWidget *lock_popover;
|
||||
GtkWidget *lock_box;
|
||||
|
||||
GtkWidget *effects_popover;
|
||||
GtkWidget *effects_box;
|
||||
GtkWidget *effects_filters;
|
||||
GtkWidget *effects_options;
|
||||
|
||||
GtkWidget *effects_visible_button;
|
||||
GtkWidget *effects_edit_button;
|
||||
GtkWidget *effects_raise_button;
|
||||
GtkWidget *effects_lower_button;
|
||||
GtkWidget *effects_merge_button;
|
||||
GtkWidget *effects_remove_button;
|
||||
GimpDrawable *effects_drawable;
|
||||
GimpDrawableFilter
|
||||
*effects_filter;
|
||||
|
||||
GList *locks;
|
||||
|
||||
GtkWidget *new_button;
|
||||
|
|
@ -93,11 +117,14 @@ struct _GimpItemTreeViewPrivate
|
|||
gint model_column_locked;
|
||||
gint model_column_lock_icon;
|
||||
gint model_column_color_tag;
|
||||
gint model_column_effects;
|
||||
GtkCellRenderer *eye_cell;
|
||||
GtkCellRenderer *lock_cell;
|
||||
GtkCellRenderer *effects_cell;
|
||||
|
||||
GimpTreeHandler *visible_changed_handler;
|
||||
GimpTreeHandler *color_tag_changed_handler;
|
||||
GimpTreeHandler *filters_changed_handler;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
@ -200,6 +227,8 @@ static void gimp_item_tree_view_color_tag_changed (GimpItem *item,
|
|||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_lock_changed (GimpItem *item,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_filters_changed (GimpItem *item,
|
||||
GimpItemTreeView *view);
|
||||
|
||||
static void gimp_item_tree_view_eye_clicked (GtkCellRendererToggle *toggle,
|
||||
gchar *path,
|
||||
|
|
@ -209,9 +238,43 @@ static void gimp_item_tree_view_lock_clicked (GtkCellRendererToggle *togg
|
|||
gchar *path,
|
||||
GdkModifierType state,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_clicked (GtkCellRendererToggle *toggle,
|
||||
gchar *path,
|
||||
GdkModifierType state,
|
||||
GimpItemTreeView *view);
|
||||
static gboolean
|
||||
gimp_item_tree_view_effects_filters_selected
|
||||
(GimpContainerView *view,
|
||||
GList *filters,
|
||||
GList *paths,
|
||||
GimpItemTreeView *item_view);
|
||||
static void gimp_item_tree_view_effects_activate_filter
|
||||
(GtkWidget *widget,
|
||||
GimpViewable *viewable,
|
||||
gpointer insert_data,
|
||||
GimpItemTreeView *view);
|
||||
|
||||
static void gimp_item_tree_view_effects_visible_toggled
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_edited_clicked
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_raised_clicked
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_lowered_clicked
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_merged_clicked
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_effects_removed_clicked
|
||||
(GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static gboolean gimp_item_tree_view_lock_button_release (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GimpItemTreeView *view);
|
||||
GdkEvent *event,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_lock_toggled (GtkWidget *widget,
|
||||
GimpItemTreeView *view);
|
||||
static void gimp_item_tree_view_update_lock_box (GimpItemTreeView *view,
|
||||
|
|
@ -363,9 +426,16 @@ gimp_item_tree_view_init (GimpItemTreeView *view)
|
|||
&tree_view->n_model_columns,
|
||||
GDK_TYPE_RGBA);
|
||||
|
||||
view->priv->model_column_effects =
|
||||
gimp_container_tree_store_columns_add (tree_view->model_columns,
|
||||
&tree_view->n_model_columns,
|
||||
G_TYPE_BOOLEAN);
|
||||
|
||||
gimp_container_tree_view_set_dnd_drop_to_empty (tree_view, TRUE);
|
||||
|
||||
view->priv->image = NULL;
|
||||
view->priv->image = NULL;
|
||||
view->priv->effects_drawable = NULL;
|
||||
view->priv->effects_filter = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -377,6 +447,8 @@ gimp_item_tree_view_constructed (GObject *object)
|
|||
GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (object);
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
gchar *text;
|
||||
GtkIconSize button_icon_size = GTK_ICON_SIZE_SMALL_TOOLBAR;
|
||||
gint pixel_icon_size = 16;
|
||||
gint button_spacing;
|
||||
|
|
@ -462,6 +534,32 @@ gimp_item_tree_view_constructed (GObject *object)
|
|||
G_CALLBACK (gimp_item_tree_view_lock_clicked),
|
||||
item_view);
|
||||
|
||||
/* TODO: Expand layer effects to other drawable types */
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (object))
|
||||
{
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_insert_column (tree_view->view, column, 2);
|
||||
|
||||
item_view->priv->effects_cell = gimp_cell_renderer_toggle_new (GIMP_ICON_DISPLAY_FILTER);
|
||||
g_object_set (item_view->priv->effects_cell,
|
||||
"xpad", 0,
|
||||
"ypad", 0,
|
||||
"icon-size", pixel_icon_size,
|
||||
NULL);
|
||||
gtk_tree_view_column_pack_start (column, item_view->priv->effects_cell, FALSE);
|
||||
gtk_tree_view_column_set_attributes (column, item_view->priv->effects_cell,
|
||||
"active",
|
||||
item_view->priv->model_column_effects,
|
||||
NULL);
|
||||
|
||||
gimp_container_tree_view_add_toggle_cell (tree_view,
|
||||
item_view->priv->effects_cell);
|
||||
|
||||
g_signal_connect (item_view->priv->effects_cell, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_clicked),
|
||||
item_view);
|
||||
}
|
||||
|
||||
/* disable the default GimpContainerView drop handler */
|
||||
gimp_container_view_set_dnd_widget (GIMP_CONTAINER_VIEW (item_view), NULL);
|
||||
|
||||
|
|
@ -577,6 +675,120 @@ gimp_item_tree_view_constructed (GObject *object)
|
|||
item_view);
|
||||
gtk_container_add (GTK_CONTAINER (item_view->priv->lock_popover), item_view->priv->lock_box);
|
||||
gtk_widget_show (item_view->priv->lock_box);
|
||||
|
||||
/* Effects box. */
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (object))
|
||||
{
|
||||
item_view->priv->effects_filters = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing);
|
||||
item_view->priv->effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing);
|
||||
item_view->priv->effects_options = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing);
|
||||
|
||||
/* Effects Buttons */
|
||||
item_view->priv->effects_visible_button = gtk_toggle_button_new ();
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item_view->priv->effects_visible_button),
|
||||
TRUE);
|
||||
image = gtk_image_new_from_icon_name (GIMP_ICON_VISIBLE,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gtk_container_add (GTK_CONTAINER (item_view->priv->effects_visible_button), image);
|
||||
|
||||
gimp_help_set_help_data (item_view->priv->effects_visible_button,
|
||||
_("Toggle the visibility of all filters."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_visible_button, "toggled",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_visible_toggled),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_visible_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (image, TRUE);
|
||||
gtk_widget_set_visible (item_view->priv->effects_visible_button, TRUE);
|
||||
|
||||
item_view->priv->effects_edit_button =
|
||||
gtk_button_new_from_icon_name (GIMP_ICON_EDIT,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gimp_help_set_help_data (item_view->priv->effects_edit_button,
|
||||
_("Edit the selected filter."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_edit_button, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_edited_clicked),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_edit_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_edit_button, TRUE);
|
||||
|
||||
item_view->priv->effects_raise_button =
|
||||
gtk_button_new_from_icon_name (GIMP_ICON_GO_UP,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gimp_help_set_help_data (item_view->priv->effects_raise_button,
|
||||
_("Raise filter one step up in the stack."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_raise_button, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_raised_clicked),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_raise_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_raise_button, TRUE);
|
||||
|
||||
item_view->priv->effects_lower_button =
|
||||
gtk_button_new_from_icon_name (GIMP_ICON_GO_DOWN,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gimp_help_set_help_data (item_view->priv->effects_lower_button,
|
||||
_("Lower filter one step down in the stack."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_lower_button, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_lowered_clicked),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_lower_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_lower_button, TRUE);
|
||||
|
||||
item_view->priv->effects_merge_button =
|
||||
gtk_button_new_from_icon_name (GIMP_ICON_LAYER_MERGE_DOWN,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gimp_help_set_help_data (item_view->priv->effects_merge_button,
|
||||
_("Merge all active filters down."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_merge_button, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_merged_clicked),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_merge_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_merge_button, TRUE);
|
||||
|
||||
item_view->priv->effects_remove_button =
|
||||
gtk_button_new_from_icon_name (GIMP_ICON_EDIT_DELETE,
|
||||
GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
gimp_help_set_help_data (item_view->priv->effects_remove_button,
|
||||
_("Remove the selected filter."),
|
||||
NULL);
|
||||
g_signal_connect (item_view->priv->effects_remove_button, "clicked",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_removed_clicked),
|
||||
item_view);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_options),
|
||||
item_view->priv->effects_remove_button, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_remove_button, TRUE);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
text = g_strdup_printf ("<b>%s</b>",
|
||||
_("Layer Effects"));
|
||||
gtk_label_set_markup (GTK_LABEL (label), text);
|
||||
gtk_widget_set_visible (label, TRUE);
|
||||
g_free (text);
|
||||
|
||||
/* Effects popover. */
|
||||
item_view->priv->effects_popover = gtk_popover_new (GTK_WIDGET (tree_view->view));
|
||||
gtk_popover_set_modal (GTK_POPOVER (item_view->priv->effects_popover), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (item_view->priv->effects_popover),
|
||||
item_view->priv->effects_filters);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_filters), label,
|
||||
FALSE, FALSE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_filters),
|
||||
item_view->priv->effects_box, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (item_view->priv->effects_filters),
|
||||
item_view->priv->effects_options, FALSE, FALSE, 0);
|
||||
gtk_widget_set_visible (item_view->priv->effects_box, TRUE);
|
||||
gtk_widget_set_visible (item_view->priv->effects_options, TRUE);
|
||||
gtk_widget_set_visible (item_view->priv->effects_filters, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -606,6 +818,14 @@ gimp_item_tree_view_dispose (GObject *object)
|
|||
view->priv->locks = NULL;
|
||||
}
|
||||
|
||||
if (view->priv->effects_popover)
|
||||
{
|
||||
gtk_widget_destroy (view->priv->effects_popover);
|
||||
view->priv->effects_popover = NULL;
|
||||
}
|
||||
view->priv->effects_drawable = NULL;
|
||||
view->priv->effects_filter = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
@ -722,6 +942,12 @@ gimp_item_tree_view_style_updated (GtkWidget *widget)
|
|||
"icon-size", pixel_icon_size,
|
||||
NULL);
|
||||
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (view))
|
||||
g_object_set (view->priv->effects_cell,
|
||||
"icon-name", GIMP_ICON_DISPLAY_FILTER,
|
||||
"icon-size", pixel_icon_size,
|
||||
NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
||||
}
|
||||
|
||||
|
|
@ -1033,7 +1259,9 @@ gimp_item_tree_view_real_set_image (GimpItemTreeView *view,
|
|||
view);
|
||||
}
|
||||
|
||||
view->priv->image = image;
|
||||
view->priv->image = image;
|
||||
view->priv->effects_drawable = NULL;
|
||||
view->priv->effects_filter = NULL;
|
||||
|
||||
if (view->priv->image)
|
||||
{
|
||||
|
|
@ -1106,6 +1334,12 @@ gimp_item_tree_view_set_container (GimpContainerView *view,
|
|||
gimp_tree_handler_disconnect (item_view->priv->color_tag_changed_handler);
|
||||
item_view->priv->color_tag_changed_handler = NULL;
|
||||
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (item_view))
|
||||
{
|
||||
gimp_tree_handler_disconnect (item_view->priv->filters_changed_handler);
|
||||
item_view->priv->filters_changed_handler = NULL;
|
||||
}
|
||||
|
||||
for (list = item_view->priv->locks; list; list = list->next)
|
||||
{
|
||||
LockToggle *data = list->data;
|
||||
|
|
@ -1138,6 +1372,12 @@ gimp_item_tree_view_set_container (GimpContainerView *view,
|
|||
G_CALLBACK (gimp_item_tree_view_lock_changed),
|
||||
view);
|
||||
}
|
||||
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (item_view))
|
||||
item_view->priv->filters_changed_handler =
|
||||
gimp_tree_handler_connect (container, "filters-changed",
|
||||
G_CALLBACK (gimp_item_tree_view_filters_changed),
|
||||
view);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1236,6 +1476,20 @@ gimp_item_tree_view_insert_item (GimpContainerView *view,
|
|||
has_color ? (GdkRGBA *) &color : NULL,
|
||||
-1);
|
||||
|
||||
if (GIMP_IS_LAYER_TREE_VIEW (item_view))
|
||||
{
|
||||
GimpContainer *filters;
|
||||
gint n_filters;
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (item));
|
||||
n_filters = gimp_container_get_n_children (filters);
|
||||
|
||||
gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
|
||||
item_view->priv->model_column_effects,
|
||||
n_filters > 0,
|
||||
-1);
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
|
@ -1764,6 +2018,407 @@ gimp_item_tree_view_lock_clicked (GtkCellRendererToggle *toggle,
|
|||
}
|
||||
}
|
||||
|
||||
/* "Effects" callbacks */
|
||||
static void
|
||||
gimp_item_tree_view_effects_clicked (GtkCellRendererToggle *toggle,
|
||||
gchar *path_str,
|
||||
GdkModifierType state,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
GtkTreePath *path;
|
||||
GtkTreeIter iter;
|
||||
|
||||
path = gtk_tree_path_new_from_string (path_str);
|
||||
|
||||
if (gtk_tree_model_get_iter (GIMP_CONTAINER_TREE_VIEW (view)->model,
|
||||
&iter, path))
|
||||
{
|
||||
GimpViewRenderer *renderer;
|
||||
GimpContainerTreeStore *store;
|
||||
GimpItem *item;
|
||||
GimpContainer *filters;
|
||||
GdkRectangle rect;
|
||||
GtkWidget *filter_view;
|
||||
GList *filter_list;
|
||||
GList *children;
|
||||
gint n_children = 0;
|
||||
gboolean visible = TRUE;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (view->priv->effects_box));
|
||||
|
||||
/* Update the filter state. */
|
||||
store = GIMP_CONTAINER_TREE_STORE (GIMP_CONTAINER_TREE_VIEW (view)->model);
|
||||
renderer = gimp_container_tree_store_get_renderer (store, &iter);
|
||||
item = GIMP_ITEM (renderer->viewable);
|
||||
g_object_unref (renderer);
|
||||
|
||||
/* Get filters */
|
||||
if (children)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (children->data,
|
||||
gimp_item_tree_view_effects_filters_selected,
|
||||
view);
|
||||
g_signal_handlers_disconnect_by_func (children->data,
|
||||
gimp_item_tree_view_effects_activate_filter,
|
||||
view);
|
||||
gtk_widget_destroy (children->data);
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
view->priv->effects_drawable = GIMP_DRAWABLE (item);
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (item));
|
||||
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
|
||||
filter_list = g_list_previous (filter_list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
|
||||
{
|
||||
if (! gimp_filter_get_active (GIMP_FILTER (filter_list->data)))
|
||||
visible = FALSE;
|
||||
|
||||
n_children++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Revisit when we can set individual filter visiblity */
|
||||
g_signal_handlers_block_by_func (view->priv->effects_visible_button,
|
||||
gimp_item_tree_view_effects_visible_toggled,
|
||||
view);
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->effects_visible_button),
|
||||
visible);
|
||||
g_signal_handlers_unblock_by_func (view->priv->effects_visible_button,
|
||||
gimp_item_tree_view_effects_visible_toggled,
|
||||
view);
|
||||
|
||||
/* Only show if we have at least one active filter */
|
||||
if (n_children > 0)
|
||||
{
|
||||
filter_view = gimp_container_tree_view_new (filters,
|
||||
gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)),
|
||||
GIMP_VIEW_SIZE_SMALL, 0);
|
||||
g_signal_connect (GIMP_CONTAINER_TREE_VIEW (filter_view),
|
||||
"select-items",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_filters_selected),
|
||||
view);
|
||||
g_signal_connect_object (GIMP_CONTAINER_TREE_VIEW (filter_view),
|
||||
"activate-item",
|
||||
G_CALLBACK (gimp_item_tree_view_effects_activate_filter),
|
||||
view, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->effects_box), filter_view, TRUE, TRUE, 0);
|
||||
gtk_widget_set_visible (filter_view, TRUE);
|
||||
|
||||
gtk_widget_set_size_request (view->priv->effects_box, 200, 24 * (n_children + 1));
|
||||
|
||||
/* Change popover position. */
|
||||
gtk_tree_view_get_cell_area (GIMP_CONTAINER_TREE_VIEW (view)->view, path,
|
||||
gtk_tree_view_get_column (GIMP_CONTAINER_TREE_VIEW (view)->view, 2),
|
||||
&rect);
|
||||
gtk_tree_view_convert_bin_window_to_widget_coords (GIMP_CONTAINER_TREE_VIEW (view)->view,
|
||||
rect.x, rect.y, &rect.x, &rect.y);
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (view->priv->effects_popover), &rect);
|
||||
|
||||
gimp_item_tree_view_filters_changed (item, view);
|
||||
gtk_widget_show (view->priv->effects_popover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_item_tree_view_effects_filters_selected (GimpContainerView *view,
|
||||
GList *filters,
|
||||
GList *paths,
|
||||
GimpItemTreeView *item_view)
|
||||
{
|
||||
g_return_val_if_fail (g_list_length (filters) <= 1, FALSE);
|
||||
|
||||
if (filters &&
|
||||
item_view->priv->effects_drawable &&
|
||||
GIMP_IS_DRAWABLE (item_view->priv->effects_drawable))
|
||||
{
|
||||
GimpDrawableFilter *filter = filters->data;
|
||||
GimpContainer *container;
|
||||
gint index;
|
||||
gint n_children;
|
||||
|
||||
item_view->priv->effects_filter = filter;
|
||||
|
||||
container =
|
||||
gimp_drawable_get_filters (GIMP_DRAWABLE (item_view->priv->effects_drawable));
|
||||
|
||||
index = gimp_container_get_child_index (container,
|
||||
GIMP_OBJECT (filter));
|
||||
|
||||
n_children = gimp_container_get_n_children (container);
|
||||
|
||||
gtk_widget_set_sensitive (item_view->priv->effects_raise_button,
|
||||
(index != 0));
|
||||
gtk_widget_set_sensitive (item_view->priv->effects_lower_button,
|
||||
(index != n_children - 1));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_activate_filter (GtkWidget *widget,
|
||||
GimpViewable *viewable,
|
||||
gpointer insert_data,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (gtk_widget_get_sensitive (view->priv->effects_edit_button))
|
||||
gimp_item_tree_view_effects_edited_clicked (widget, view);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_visible_toggled (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
gboolean visible;
|
||||
GimpContainer *filter_stack;
|
||||
GList *list;
|
||||
GimpImage *image = view->priv->image;
|
||||
|
||||
visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
|
||||
filter_stack = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
|
||||
for (list = GIMP_LIST (filter_stack)->queue->head; list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (list->data))
|
||||
{
|
||||
GimpFilter *filter = list->data;
|
||||
|
||||
gimp_filter_set_active (filter, visible);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hack to make the effects visibly change */
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_edited_clicked (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (! view->priv->effects_filter ||
|
||||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
return;
|
||||
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
GimpImage *image = view->priv->image;
|
||||
GeglNode *op = gimp_drawable_filter_get_operation (view->priv->effects_filter);
|
||||
|
||||
if (op)
|
||||
{
|
||||
GimpProcedure *procedure;
|
||||
GVariant *variant;
|
||||
gchar *operation;
|
||||
gchar *name;
|
||||
|
||||
g_object_get (view->priv->effects_filter,
|
||||
"name", &name,
|
||||
NULL);
|
||||
g_object_get (op,
|
||||
"operation", &operation,
|
||||
NULL);
|
||||
|
||||
if (operation)
|
||||
{
|
||||
procedure = gimp_gegl_procedure_new (image->gimp,
|
||||
view->priv->effects_filter,
|
||||
GIMP_RUN_INTERACTIVE, NULL,
|
||||
operation,
|
||||
name,
|
||||
name,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
gimp_filter_history_add (image->gimp, procedure);
|
||||
|
||||
variant = g_variant_new_uint64 (GPOINTER_TO_SIZE (procedure));
|
||||
g_variant_take_ref (variant);
|
||||
filters_run_procedure (image->gimp,
|
||||
gimp_context_get_display (gimp_get_user_context (image->gimp)),
|
||||
procedure, GIMP_RUN_INTERACTIVE);
|
||||
|
||||
g_variant_unref (variant);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/* Disable buttons until we're done editing */
|
||||
gtk_widget_set_sensitive (view->priv->effects_box, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_visible_button, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_edit_button, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_raise_button, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_lower_button, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_merge_button, FALSE);
|
||||
gtk_widget_set_sensitive (view->priv->effects_remove_button, FALSE);
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
g_free (operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_raised_clicked (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (! view->priv->effects_filter ||
|
||||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
return;
|
||||
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
GimpImage *image = view->priv->image;
|
||||
GimpContainer *filters;
|
||||
gint index;
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
|
||||
index = gimp_container_get_child_index (filters,
|
||||
GIMP_OBJECT (view->priv->effects_filter));
|
||||
index--;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
gimp_image_undo_push_filter_reorder (image, _("Reorder filter"),
|
||||
view->priv->effects_drawable,
|
||||
view->priv->effects_filter);
|
||||
|
||||
gimp_container_reorder (filters, GIMP_OBJECT (view->priv->effects_filter),
|
||||
index);
|
||||
|
||||
if (gtk_widget_get_sensitive (view->priv->effects_edit_button))
|
||||
{
|
||||
gtk_widget_set_sensitive (view->priv->effects_lower_button, TRUE);
|
||||
if (index == 0)
|
||||
gtk_widget_set_sensitive (view->priv->effects_raise_button, FALSE);
|
||||
}
|
||||
|
||||
/* Hack to make the effects visibly change */
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_lowered_clicked (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (! view->priv->effects_filter ||
|
||||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
return;
|
||||
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
GimpImage *image = view->priv->image;
|
||||
GimpContainer *filters;
|
||||
gint index;
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
|
||||
index = gimp_container_get_child_index (filters,
|
||||
GIMP_OBJECT (view->priv->effects_filter));
|
||||
index++;
|
||||
|
||||
if (index < gimp_container_get_n_children (filters))
|
||||
{
|
||||
gimp_image_undo_push_filter_reorder (image, _("Reorder filter"),
|
||||
view->priv->effects_drawable,
|
||||
view->priv->effects_filter);
|
||||
|
||||
gimp_container_reorder (filters, GIMP_OBJECT (view->priv->effects_filter),
|
||||
index);
|
||||
|
||||
if (gtk_widget_get_sensitive (view->priv->effects_edit_button))
|
||||
{
|
||||
gtk_widget_set_sensitive (view->priv->effects_raise_button, TRUE);
|
||||
if (index == gimp_container_get_n_children (filters) - 1)
|
||||
gtk_widget_set_sensitive (view->priv->effects_lower_button, FALSE);
|
||||
}
|
||||
|
||||
/* Hack to make the effects visibly change */
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_merged_clicked (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (! view->priv->effects_filter ||
|
||||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
return;
|
||||
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
GimpImage *image = view->priv->image;
|
||||
GeglNode *op = gimp_drawable_filter_get_operation (view->priv->effects_filter);
|
||||
|
||||
if (op)
|
||||
{
|
||||
gimp_drawable_merge_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
gimp_drawable_clear_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
|
||||
/* Hack to make the effects visibly change */
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_effects_removed_clicked (GtkWidget *widget,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
if (view->priv->effects_drawable)
|
||||
{
|
||||
GimpImage *image = view->priv->image;
|
||||
GeglNode *op = NULL;
|
||||
|
||||
if (view->priv->effects_filter &&
|
||||
GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
op = gimp_drawable_filter_get_operation (view->priv->effects_filter);
|
||||
|
||||
if (op)
|
||||
{
|
||||
gimp_image_undo_push_filter_remove (image, _("Remove filter"),
|
||||
view->priv->effects_drawable,
|
||||
view->priv->effects_filter);
|
||||
|
||||
gimp_drawable_filter_abort (view->priv->effects_filter);
|
||||
|
||||
view->priv->effects_filter = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_drawable_remove_last_filter (GIMP_DRAWABLE (view->priv->effects_drawable));
|
||||
}
|
||||
|
||||
/* Hack to make the effects visibly change */
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* "Color Tag" callbacks */
|
||||
|
||||
|
|
@ -1836,6 +2491,68 @@ gimp_item_tree_view_lock_changed (GimpItem *item,
|
|||
gimp_item_tree_view_update_lock_box (view, item, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_item_tree_view_filters_changed (GimpItem *item,
|
||||
GimpItemTreeView *view)
|
||||
{
|
||||
GimpContainerView *container_view = GIMP_CONTAINER_VIEW (view);
|
||||
GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
|
||||
GtkTreeIter *iter;
|
||||
GimpContainer *filters;
|
||||
GList *filter_list = NULL;
|
||||
gint n_filters = 0;
|
||||
gboolean fs_disabled = FALSE;
|
||||
|
||||
iter = gimp_container_view_lookup (container_view,
|
||||
(GimpViewable *) item);
|
||||
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (item));
|
||||
/* Since floating selections are also stored in the filter stack,
|
||||
* we need to verify what's in there to get the correct count */
|
||||
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
|
||||
filter_list = g_list_previous (filter_list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
|
||||
n_filters++;
|
||||
else
|
||||
fs_disabled = TRUE;
|
||||
}
|
||||
|
||||
if (fs_disabled)
|
||||
view->priv->effects_filter = NULL;
|
||||
|
||||
if (iter)
|
||||
gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
|
||||
view->priv->model_column_effects,
|
||||
n_filters > 0,
|
||||
-1);
|
||||
|
||||
/* Re-enable buttons after editing */
|
||||
gtk_widget_set_sensitive (view->priv->effects_box, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_visible_button, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_edit_button, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_raise_button, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_lower_button, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_merge_button, ! fs_disabled);
|
||||
gtk_widget_set_sensitive (view->priv->effects_remove_button, ! fs_disabled);
|
||||
|
||||
if (view->priv->effects_popover &&
|
||||
view->priv->effects_filter &&
|
||||
! fs_disabled)
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
|
||||
{
|
||||
gint index = gimp_container_get_child_index (filters,
|
||||
GIMP_OBJECT (view->priv->effects_filter));
|
||||
|
||||
if (index == 0)
|
||||
gtk_widget_set_sensitive (view->priv->effects_raise_button, FALSE);
|
||||
else if (index == (n_filters - 1))
|
||||
gtk_widget_set_sensitive (view->priv->effects_lower_button, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_item_tree_view_lock_button_release (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,10 @@
|
|||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimpcontainer.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawable-private.h" /* eek */
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimpfilterstack.h"
|
||||
#include "core/gimpgrid.h"
|
||||
#include "core/gimpgrouplayer.h"
|
||||
#include "core/gimpimage.h"
|
||||
|
|
@ -85,8 +88,27 @@
|
|||
|
||||
/* #define GIMP_XCF_PATH_DEBUG */
|
||||
|
||||
/* Filters can not be created until a layer is attached
|
||||
* to an image, so we use this struct to store relevant
|
||||
* information until then */
|
||||
typedef struct
|
||||
{
|
||||
GeglNode *operation;
|
||||
gchar *name;
|
||||
gchar *icon_name;
|
||||
GimpChannel *mask;
|
||||
gboolean is_visible;
|
||||
gdouble opacity;
|
||||
GimpLayerMode paint_mode;
|
||||
GimpLayerColorSpace blend_space;
|
||||
GimpLayerColorSpace composite_space;
|
||||
GimpLayerCompositeMode composite_mode;
|
||||
GimpFilterRegion region;
|
||||
} FilterData;
|
||||
|
||||
static void xcf_load_add_masks (GimpImage *image);
|
||||
static void xcf_load_add_effects (XcfInfo *info,
|
||||
GimpImage *image);
|
||||
static gboolean xcf_load_image_props (XcfInfo *info,
|
||||
GimpImage *image);
|
||||
static gboolean xcf_load_layer_props (XcfInfo *info,
|
||||
|
|
@ -105,6 +127,8 @@ static gboolean xcf_check_layer_props (XcfInfo *info,
|
|||
static gboolean xcf_load_channel_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpChannel **channel);
|
||||
static gboolean xcf_load_effect_props (XcfInfo *info,
|
||||
FilterData *filter);
|
||||
static gboolean xcf_load_vectors_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpVectors **vectors);
|
||||
|
|
@ -116,6 +140,10 @@ static GimpLayer * xcf_load_layer (XcfInfo *info,
|
|||
GList **item_path);
|
||||
static GimpChannel * xcf_load_channel (XcfInfo *info,
|
||||
GimpImage *image);
|
||||
static FilterData * xcf_load_effect (XcfInfo *info,
|
||||
GimpDrawable *drawable);
|
||||
static void xcf_load_free_effect (FilterData *data);
|
||||
static void xcf_load_free_effects (GList *effects);
|
||||
static GimpVectors * xcf_load_vectors (XcfInfo *info,
|
||||
GimpImage *image);
|
||||
static GimpLayerMask * xcf_load_layer_mask (XcfInfo *info,
|
||||
|
|
@ -767,7 +795,10 @@ xcf_load_image (Gimp *gimp,
|
|||
}
|
||||
|
||||
if (n_broken_layers == 0 && n_broken_channels == 0)
|
||||
xcf_load_add_masks (image);
|
||||
{
|
||||
xcf_load_add_masks (image);
|
||||
xcf_load_add_effects (info, image);
|
||||
}
|
||||
|
||||
if (info->floating_sel && info->floating_sel_drawable)
|
||||
{
|
||||
|
|
@ -948,6 +979,7 @@ xcf_load_image (Gimp *gimp,
|
|||
"of it as I can, but it is incomplete."));
|
||||
|
||||
xcf_load_add_masks (image);
|
||||
xcf_load_add_effects (info, image);
|
||||
|
||||
gimp_image_undo_enable (image);
|
||||
|
||||
|
|
@ -1015,6 +1047,86 @@ xcf_load_add_masks (GimpImage *image)
|
|||
g_list_free (layers);
|
||||
}
|
||||
|
||||
static void
|
||||
xcf_load_add_effects (XcfInfo *info,
|
||||
GimpImage *image)
|
||||
{
|
||||
GList *layers;
|
||||
GList *list;
|
||||
|
||||
layers = gimp_image_get_layer_list (image);
|
||||
|
||||
for (list = layers; list; list = g_list_next (list))
|
||||
{
|
||||
GimpLayer *layer = list->data;
|
||||
GList *effects_nodes;
|
||||
|
||||
effects_nodes = g_object_get_data (G_OBJECT (layer), "gimp-layer-effects");
|
||||
|
||||
if (effects_nodes)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = effects_nodes; iter; iter = iter->next)
|
||||
{
|
||||
FilterData *data = iter->data;
|
||||
GSList *children;
|
||||
|
||||
if (! data->icon_name)
|
||||
data->icon_name = g_strdup ("gimp-gegl");
|
||||
|
||||
children = gegl_node_get_children (data->operation);
|
||||
|
||||
if (g_slist_length (children) == 1)
|
||||
{
|
||||
GimpDrawableFilter *filter = NULL;
|
||||
GeglNode *op;
|
||||
|
||||
op = g_object_ref (children->data);
|
||||
gegl_node_remove_child (data->operation, op);
|
||||
filter = gimp_drawable_filter_new (GIMP_DRAWABLE (layer),
|
||||
data->name, op,
|
||||
data->icon_name);
|
||||
|
||||
gimp_drawable_filter_set_opacity (filter, data->opacity);
|
||||
gimp_drawable_filter_set_mode (filter, data->paint_mode,
|
||||
data->blend_space,
|
||||
data->composite_space,
|
||||
data->composite_mode);
|
||||
gimp_drawable_filter_set_region (filter, data->region);
|
||||
|
||||
gimp_drawable_filter_apply (filter, NULL);
|
||||
|
||||
g_object_set (filter,
|
||||
"mask", data->mask,
|
||||
NULL);
|
||||
|
||||
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
|
||||
|
||||
gimp_drawable_filter_layer_mask_freeze (filter);
|
||||
|
||||
g_object_unref (op);
|
||||
g_object_unref (filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_message (info->gimp, G_OBJECT (info->progress),
|
||||
GIMP_MESSAGE_WARNING,
|
||||
"XCF Warning: failed loading filter \"%s\": "
|
||||
"node has %d children, 1 expected.",
|
||||
data->name, g_slist_length (children));
|
||||
}
|
||||
|
||||
g_slist_free (children);
|
||||
}
|
||||
|
||||
g_object_set_data (G_OBJECT (layer), "gimp-layer-effects", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (layers);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_load_image_props (XcfInfo *info,
|
||||
GimpImage *image)
|
||||
|
|
@ -2271,6 +2383,145 @@ xcf_load_channel_props (XcfInfo *info,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_load_effect_props (XcfInfo *info,
|
||||
FilterData *filter)
|
||||
{
|
||||
PropType prop_type;
|
||||
guint32 prop_size;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (! xcf_load_prop (info, &prop_type, &prop_size))
|
||||
return FALSE;
|
||||
|
||||
switch (prop_type)
|
||||
{
|
||||
case PROP_END:
|
||||
return TRUE;
|
||||
|
||||
case PROP_FILTER_NAME:
|
||||
{
|
||||
gchar *filter_name;
|
||||
goffset base = info->cp;
|
||||
|
||||
/* Go back so we can get the size of the string */
|
||||
xcf_seek_pos (info, base - sizeof (guint32), NULL);
|
||||
|
||||
xcf_read_string (info, &filter_name, 1);
|
||||
filter->name = filter_name;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILTER_ICON:
|
||||
{
|
||||
gchar *filter_icon;
|
||||
goffset base = info->cp;
|
||||
|
||||
/* Go back so we can get the size of the string */
|
||||
xcf_seek_pos (info, base - sizeof (guint32), NULL);
|
||||
|
||||
xcf_read_string (info, &filter_icon, 1);
|
||||
filter->icon_name = filter_icon;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_VISIBLE:
|
||||
{
|
||||
gboolean visible;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) &visible, 1);
|
||||
filter->is_visible = visible;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
{
|
||||
guint32 opacity;
|
||||
|
||||
xcf_read_int32 (info, &opacity, 1);
|
||||
filter->opacity = (gdouble) opacity / 255.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_MODE:
|
||||
{
|
||||
GimpLayerMode mode;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) &mode, 1);
|
||||
|
||||
if (mode == GIMP_LAYER_MODE_OVERLAY_LEGACY)
|
||||
mode = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY;
|
||||
|
||||
filter->paint_mode = mode;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_BLEND_SPACE:
|
||||
{
|
||||
gint32 blend_space;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) &blend_space, 1);
|
||||
|
||||
/* TODO: Revisit when blend space can be set
|
||||
* on filter effects */
|
||||
blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
||||
|
||||
filter->blend_space = blend_space;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_SPACE:
|
||||
{
|
||||
gint32 composite_space;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) &composite_space, 1);
|
||||
|
||||
/* TODO: Revisit when composite space can be set
|
||||
* on filter effects */
|
||||
composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
||||
|
||||
filter->composite_space = composite_space;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_MODE:
|
||||
{
|
||||
gint32 composite_mode;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) &composite_mode, 1);
|
||||
|
||||
/* TODO: Revisit when composite mode can be set
|
||||
* on filter effects */
|
||||
composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
|
||||
|
||||
filter->composite_mode = composite_mode;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILTER_REGION:
|
||||
{
|
||||
GimpFilterRegion region;
|
||||
|
||||
xcf_read_int32 (info, (guint32 *) ®ion, 1);
|
||||
|
||||
filter->region = region;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef GIMP_UNSTABLE
|
||||
g_printerr ("unexpected/unknown effect property: %d (skipping)\n",
|
||||
prop_type);
|
||||
#endif
|
||||
if (! xcf_skip_unknown_prop (info, prop_size))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_load_vectors_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
|
|
@ -2454,6 +2705,7 @@ xcf_load_layer (XcfInfo *info,
|
|||
GimpLayer *layer;
|
||||
GimpLayerMask *layer_mask;
|
||||
goffset hierarchy_offset;
|
||||
goffset effects_offset = 0;
|
||||
goffset layer_mask_offset;
|
||||
gboolean apply_mask = TRUE;
|
||||
gboolean edit_mask = FALSE;
|
||||
|
|
@ -2618,6 +2870,8 @@ xcf_load_layer (XcfInfo *info,
|
|||
cur_offset = info->cp;
|
||||
xcf_read_offset (info, &hierarchy_offset, 1);
|
||||
xcf_read_offset (info, &layer_mask_offset, 1);
|
||||
if (info->file_version >= 20)
|
||||
xcf_read_offset (info, &effects_offset, 1);
|
||||
|
||||
/* read in the hierarchy (ignore it for group layers, both as an
|
||||
* optimization and because the hierarchy's extents don't match
|
||||
|
|
@ -2650,6 +2904,8 @@ xcf_load_layer (XcfInfo *info,
|
|||
gimp_viewable_set_expanded (GIMP_VIEWABLE (layer), expanded);
|
||||
}
|
||||
|
||||
cur_offset += info->bytes_per_offset;
|
||||
|
||||
/* read in the layer mask */
|
||||
if (layer_mask_offset != 0)
|
||||
{
|
||||
|
|
@ -2665,6 +2921,8 @@ xcf_load_layer (XcfInfo *info,
|
|||
if (! layer_mask)
|
||||
goto error;
|
||||
|
||||
cur_offset += info->bytes_per_offset;
|
||||
|
||||
xcf_progress_update (info);
|
||||
|
||||
/* don't add the layer mask yet, that won't work for group
|
||||
|
|
@ -2682,6 +2940,89 @@ xcf_load_layer (XcfInfo *info,
|
|||
GINT_TO_POINTER (show_mask));
|
||||
}
|
||||
|
||||
/* read in any layer effects and effect masks */
|
||||
if (effects_offset != 0)
|
||||
{
|
||||
GList *filter_data_list = NULL;
|
||||
gint filter_count = 0;
|
||||
|
||||
cur_offset += info->bytes_per_offset;
|
||||
while (TRUE)
|
||||
{
|
||||
FilterData *filter_data;
|
||||
GimpChannel *effect_mask;
|
||||
|
||||
/* if the offset is 0 then we are at the end
|
||||
* of the effect list.
|
||||
*/
|
||||
if (effects_offset == 0)
|
||||
break;
|
||||
|
||||
if (effects_offset < cur_offset)
|
||||
{
|
||||
GIMP_LOG (XCF, "Invalid effect offset: %" G_GOFFSET_FORMAT
|
||||
" at offset: %" G_GOFFSET_FORMAT, effects_offset, cur_offset);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* seek to the effect offset */
|
||||
if (! xcf_seek_pos (info, effects_offset, NULL))
|
||||
goto error;
|
||||
|
||||
filter_data = xcf_load_effect (info, GIMP_DRAWABLE (layer));
|
||||
if (! filter_data)
|
||||
goto error;
|
||||
|
||||
xcf_progress_update (info);
|
||||
|
||||
/* restore the saved position so we'll be ready to
|
||||
* read the next offset.
|
||||
*/
|
||||
cur_offset += info->bytes_per_offset;
|
||||
if (! xcf_seek_pos (info, cur_offset, NULL))
|
||||
goto error;
|
||||
|
||||
/* read in the offset of the effect mask */
|
||||
xcf_read_offset (info, &effects_offset, 1);
|
||||
|
||||
if (effects_offset < cur_offset)
|
||||
{
|
||||
GIMP_LOG (XCF, "Invalid effect mask offset: %" G_GOFFSET_FORMAT
|
||||
" at offset: %" G_GOFFSET_FORMAT, effects_offset, cur_offset);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* seek to the effect mask offset */
|
||||
if (! xcf_seek_pos (info, effects_offset, NULL))
|
||||
goto error;
|
||||
|
||||
effect_mask = xcf_load_channel (info, image);
|
||||
if (! effect_mask)
|
||||
goto error;
|
||||
|
||||
filter_data->mask = effect_mask;
|
||||
|
||||
filter_data_list = g_list_prepend (filter_data_list, filter_data);
|
||||
filter_count++;
|
||||
|
||||
xcf_progress_update (info);
|
||||
|
||||
/* restore the saved position so we'll be ready to
|
||||
* read the next offset.
|
||||
*/
|
||||
cur_offset += info->bytes_per_offset;
|
||||
if (! xcf_seek_pos (info, cur_offset, NULL))
|
||||
goto error;
|
||||
|
||||
/* read in the offset of the next effect */
|
||||
xcf_read_offset (info, &effects_offset, 1);
|
||||
}
|
||||
|
||||
if (filter_count > 0)
|
||||
g_object_set_data_full (G_OBJECT (layer), "gimp-layer-effects", filter_data_list,
|
||||
(GDestroyNotify) xcf_load_free_effects);
|
||||
}
|
||||
|
||||
/* attach the floating selection... */
|
||||
if (is_fs_drawable)
|
||||
info->floating_sel_drawable = GIMP_DRAWABLE (layer);
|
||||
|
|
@ -2793,6 +3134,57 @@ xcf_load_channel (XcfInfo *info,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static FilterData *
|
||||
xcf_load_effect (XcfInfo *info,
|
||||
GimpDrawable *drawable)
|
||||
{
|
||||
FilterData *filter;
|
||||
GeglNode *operation;
|
||||
gchar *xml;
|
||||
|
||||
filter = g_new0 (FilterData, 1);
|
||||
|
||||
xcf_read_string (info, &xml, 1);
|
||||
|
||||
operation = gegl_node_new_from_xml (xml, NULL);
|
||||
g_free (xml);
|
||||
|
||||
if (! operation)
|
||||
goto error;
|
||||
|
||||
filter->operation = operation;
|
||||
|
||||
/* read in the effect properties */
|
||||
if (! xcf_load_effect_props (info, &(*filter)))
|
||||
goto error;
|
||||
|
||||
xcf_progress_update (info);
|
||||
|
||||
return filter;
|
||||
|
||||
error:
|
||||
|
||||
xcf_load_free_effect (filter);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
xcf_load_free_effect (FilterData *data)
|
||||
{
|
||||
g_free (data->name);
|
||||
g_free (data->icon_name);
|
||||
g_clear_object (&data->operation);
|
||||
g_clear_object (&data->mask);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
xcf_load_free_effects (GList *effects)
|
||||
{
|
||||
g_list_free_full (effects, (GDestroyNotify) xcf_load_free_effect);
|
||||
}
|
||||
|
||||
/* The new path structure since XCF 18. */
|
||||
static GimpVectors *
|
||||
xcf_load_vectors (XcfInfo *info,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ typedef enum
|
|||
PROP_ITEM_SET_ITEM = 41,
|
||||
PROP_LOCK_VISIBILITY = 42,
|
||||
PROP_SELECTED_PATH = 43,
|
||||
PROP_FILTER_NAME = 44,
|
||||
PROP_FILTER_ICON = 45,
|
||||
PROP_FILTER_REGION = 46,
|
||||
} PropType;
|
||||
|
||||
typedef enum
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "core/gimpcontainer.h"
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpdrawable.h"
|
||||
#include "core/gimpdrawable-filters.h"
|
||||
#include "core/gimpdrawablefilter.h"
|
||||
#include "core/gimpgrid.h"
|
||||
#include "core/gimpguide.h"
|
||||
#include "core/gimpimage.h"
|
||||
|
|
@ -51,6 +53,7 @@
|
|||
#include "core/gimpitemlist.h"
|
||||
#include "core/gimplayer.h"
|
||||
#include "core/gimplayermask.h"
|
||||
#include "core/gimplist.h"
|
||||
#include "core/gimpparasitelist.h"
|
||||
#include "core/gimpprogress.h"
|
||||
#include "core/gimpsamplepoint.h"
|
||||
|
|
@ -114,6 +117,10 @@ static gboolean xcf_save_channel_props (XcfInfo *info,
|
|||
GimpImage *image,
|
||||
GimpChannel *channel,
|
||||
GError **error);
|
||||
static gboolean xcf_save_effect_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpFilter *filter,
|
||||
GError **error);
|
||||
static gboolean xcf_save_path_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpVectors *vectors,
|
||||
|
|
@ -131,6 +138,10 @@ static gboolean xcf_save_channel (XcfInfo *info,
|
|||
GimpImage *image,
|
||||
GimpChannel *channel,
|
||||
GError **error);
|
||||
static gboolean xcf_save_effect (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpFilter *filter,
|
||||
GError **error);
|
||||
static gboolean xcf_save_path (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpVectors *vectors,
|
||||
|
|
@ -817,6 +828,44 @@ xcf_save_channel_props (XcfInfo *info,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_save_effect_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpFilter *filter,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *name;
|
||||
const gchar *icon;
|
||||
|
||||
g_object_get (filter,
|
||||
"name", &name,
|
||||
"icon-name", &icon,
|
||||
NULL);
|
||||
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_FILTER_NAME, error,
|
||||
name), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_FILTER_ICON, error,
|
||||
icon), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_VISIBLE, error,
|
||||
gimp_filter_get_active (filter)), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_OPACITY, error,
|
||||
gimp_drawable_filter_get_opacity (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_MODE, error,
|
||||
gimp_drawable_filter_get_paint_mode (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_BLEND_SPACE, error,
|
||||
gimp_drawable_filter_get_blend_space (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_COMPOSITE_SPACE, error,
|
||||
gimp_drawable_filter_get_composite_space (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_COMPOSITE_MODE, error,
|
||||
gimp_drawable_filter_get_composite_mode (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_FILTER_REGION, error,
|
||||
gimp_drawable_filter_get_region (GIMP_DRAWABLE_FILTER (filter))), ;);
|
||||
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_END, error), ;);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_save_path_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
|
|
@ -1620,6 +1669,37 @@ xcf_save_prop (XcfInfo *info,
|
|||
xcf_write_int32_check_error (info, &set_n, 1, va_end (args));
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILTER_NAME:
|
||||
{
|
||||
const gchar *filter_name = va_arg (args, gchar *);
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type, va_end (args));
|
||||
xcf_write_string_check_error (info, (gchar **) &filter_name, 1, va_end (args));
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILTER_ICON:
|
||||
{
|
||||
const gchar *filter_icon = va_arg (args, gchar *);
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type, va_end (args));
|
||||
xcf_write_string_check_error (info, (gchar **) &filter_icon, 1, va_end (args));
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILTER_REGION:
|
||||
{
|
||||
guint32 filter_region = va_arg (args, guint32);
|
||||
|
||||
size = 4;
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type, va_end (args));
|
||||
xcf_write_int32_check_error (info, &size, 1, va_end (args));
|
||||
|
||||
xcf_write_int32_check_error (info, &filter_region, 1, va_end (args));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
va_end (args);
|
||||
|
|
@ -1633,11 +1713,15 @@ xcf_save_layer (XcfInfo *info,
|
|||
GimpLayer *layer,
|
||||
GError **error)
|
||||
{
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 value;
|
||||
const gchar *string;
|
||||
GError *tmp_error = NULL;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 value;
|
||||
const gchar *string;
|
||||
GimpContainer *filters;
|
||||
GList *filter_list;
|
||||
guint32 num_effects = 0;
|
||||
GList *list;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
/* check and see if this is the drawable that the floating
|
||||
* selection is attached to.
|
||||
|
|
@ -1650,6 +1734,17 @@ xcf_save_layer (XcfInfo *info,
|
|||
xcf_check_error (xcf_seek_pos (info, saved_pos, error), ;);
|
||||
}
|
||||
|
||||
/* Get filter information */
|
||||
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer));
|
||||
/* Since floating selections are also stored in the filter stack,
|
||||
* we need to verify what's in there to get the correct count */
|
||||
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
|
||||
filter_list = g_list_previous (filter_list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
|
||||
num_effects++;
|
||||
}
|
||||
|
||||
/* write out the width, height and image type information for the layer */
|
||||
value = gimp_item_get_width (GIMP_ITEM (layer));
|
||||
xcf_write_int32_check_error (info, &value, 1, ;);
|
||||
|
|
@ -1667,8 +1762,8 @@ xcf_save_layer (XcfInfo *info,
|
|||
/* write out the layer properties */
|
||||
xcf_save_layer_props (info, image, layer, error);
|
||||
|
||||
/* write out the layer tile hierarchy */
|
||||
offset = info->cp + 2 * info->bytes_per_offset;
|
||||
/* write out the layer tile hierarchy and effects */
|
||||
offset = info->cp + (2 + (num_effects * 2) + 1) * info->bytes_per_offset;
|
||||
xcf_write_offset_check_error (info, &offset, 1, ;);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
|
@ -1676,6 +1771,10 @@ xcf_save_layer (XcfInfo *info,
|
|||
/* write a zero layer mask offset */
|
||||
xcf_write_zero_offset_check_error (info, 1, ;);
|
||||
|
||||
/* write out zero effect and effect mask offset(s) */
|
||||
for (gint i = 0; i <= (num_effects * 2); i++)
|
||||
xcf_write_zero_offset_check_error (info, 1, ;);
|
||||
|
||||
xcf_check_error (xcf_save_buffer (info, image,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
||||
error), ;);
|
||||
|
|
@ -1690,11 +1789,55 @@ xcf_save_layer (XcfInfo *info,
|
|||
xcf_check_error (xcf_seek_pos (info, saved_pos, error), ;);
|
||||
xcf_write_offset_check_error (info, &offset, 1, ;);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, offset, error), ;);
|
||||
xcf_check_error (xcf_save_channel (info, image, GIMP_CHANNEL (mask),
|
||||
error), ;);
|
||||
}
|
||||
|
||||
/* write out any layer effects and effect masks */
|
||||
if (num_effects > 0)
|
||||
{
|
||||
saved_pos += info->bytes_per_offset;
|
||||
|
||||
for (list = GIMP_LIST (filters)->queue->head; list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
if (GIMP_IS_DRAWABLE_FILTER (list->data))
|
||||
{
|
||||
GimpDrawableFilter *filter = list->data;
|
||||
GimpChannel *effect_mask;
|
||||
|
||||
offset = info->cp;
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error), ;);
|
||||
xcf_write_offset_check_error (info, &offset, 1, ;);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, offset, error), ;);
|
||||
xcf_check_error (xcf_save_effect (info, image, GIMP_FILTER (filter),
|
||||
error), ;);
|
||||
|
||||
/* write out effect mask */
|
||||
effect_mask = gimp_drawable_filter_get_mask (filter);
|
||||
|
||||
offset = info->cp;
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error), ;);
|
||||
xcf_write_offset_check_error (info, &offset, 1, ;);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, offset, error), ;);
|
||||
xcf_check_error (xcf_save_channel (info, image, effect_mask,
|
||||
error), ;);
|
||||
}
|
||||
}
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1746,6 +1889,60 @@ xcf_save_channel (XcfInfo *info,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_save_effect (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GimpFilter *filter,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *string;
|
||||
GimpDrawableFilter *filter_drawable;
|
||||
GeglNode *node;
|
||||
GeglNode *save_node = gegl_node_new ();
|
||||
const gchar *operation;
|
||||
GParamSpec **pspecs;
|
||||
guint n_pspecs;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
filter_drawable = GIMP_DRAWABLE_FILTER (filter);
|
||||
node = gimp_drawable_filter_get_operation (filter_drawable);
|
||||
|
||||
/* Create operation-only node */
|
||||
gegl_node_get (node,
|
||||
"operation", &operation,
|
||||
NULL);
|
||||
|
||||
gegl_node_set (save_node,
|
||||
"operation", operation,
|
||||
NULL);
|
||||
|
||||
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
|
||||
|
||||
for (gint i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
gegl_node_get_property (node, pspec->name,
|
||||
&value);
|
||||
|
||||
gegl_node_set_property (save_node, pspec->name,
|
||||
&value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
g_free (pspecs);
|
||||
|
||||
/* Write out GEGL xml */
|
||||
string = gegl_node_to_xml_full (save_node, save_node, "/");
|
||||
xcf_write_string_check_error (info, (gchar **) &string, 1, ;);
|
||||
|
||||
/* write out the effect properties */
|
||||
xcf_save_effect_props (info, image, filter, error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
xcf_calc_levels (gint size,
|
||||
gint tile_size)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ static GimpXcfLoaderFunc * const xcf_loaders[] =
|
|||
xcf_load_image, /* version 17 */
|
||||
xcf_load_image, /* version 18 */
|
||||
xcf_load_image, /* version 19 */
|
||||
xcf_load_image, /* version 20 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ EXPORTS
|
|||
gimp_drawable_levels_stretch
|
||||
gimp_drawable_mask_bounds
|
||||
gimp_drawable_mask_intersect
|
||||
gimp_drawable_merge_filters
|
||||
gimp_drawable_merge_shadow
|
||||
gimp_drawable_offset
|
||||
gimp_drawable_posterize
|
||||
|
|
|
|||
|
|
@ -592,6 +592,40 @@ gimp_drawable_mask_intersect (GimpDrawable *drawable,
|
|||
return non_empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_drawable_merge_filters:
|
||||
* @drawable: The drawable.
|
||||
*
|
||||
* Merge the layer effect filters to the specified drawable.
|
||||
*
|
||||
* This procedure combines the contents of the drawable's filter stack
|
||||
* (for export) with the specified drawable.
|
||||
*
|
||||
* Returns: TRUE on success.
|
||||
**/
|
||||
gboolean
|
||||
gimp_drawable_merge_filters (GimpDrawable *drawable)
|
||||
{
|
||||
GimpValueArray *args;
|
||||
GimpValueArray *return_vals;
|
||||
gboolean success = TRUE;
|
||||
|
||||
args = gimp_value_array_new_from_types (NULL,
|
||||
GIMP_TYPE_DRAWABLE, drawable,
|
||||
G_TYPE_NONE);
|
||||
|
||||
return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
|
||||
"gimp-drawable-merge-filters",
|
||||
args);
|
||||
gimp_value_array_unref (args);
|
||||
|
||||
success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
|
||||
|
||||
gimp_value_array_unref (return_vals);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_drawable_merge_shadow:
|
||||
* @drawable: The drawable.
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ gboolean gimp_drawable_mask_intersect (GimpDrawable
|
|||
gint *y,
|
||||
gint *width,
|
||||
gint *height);
|
||||
gboolean gimp_drawable_merge_filters (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_merge_shadow (GimpDrawable *drawable,
|
||||
gboolean undo);
|
||||
gboolean gimp_drawable_free_shadow (GimpDrawable *drawable);
|
||||
|
|
|
|||
|
|
@ -172,6 +172,21 @@ export_flatten (GimpImage *image,
|
|||
*drawables = g_list_prepend (NULL, flattened);
|
||||
}
|
||||
|
||||
static void
|
||||
export_merge_layer_effects (GimpImage *image,
|
||||
GList **drawables)
|
||||
{
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
|
||||
layers = gimp_image_list_layers (image);
|
||||
|
||||
for (iter = layers; iter; iter = g_list_next (iter))
|
||||
gimp_drawable_merge_filters (GIMP_DRAWABLE (iter->data));
|
||||
|
||||
g_list_free (layers);
|
||||
}
|
||||
|
||||
static void
|
||||
export_remove_alpha (GimpImage *image,
|
||||
GList **drawables)
|
||||
|
|
@ -379,6 +394,15 @@ static ExportAction export_action_flatten =
|
|||
0
|
||||
};
|
||||
|
||||
static ExportAction export_action_merge_layer_effects =
|
||||
{
|
||||
export_merge_layer_effects,
|
||||
NULL,
|
||||
N_("%s plug-in can't handle layer effects"),
|
||||
{ N_("Merge Layer Effects"), NULL },
|
||||
0
|
||||
};
|
||||
|
||||
static ExportAction export_action_remove_alpha =
|
||||
{
|
||||
export_remove_alpha,
|
||||
|
|
@ -870,6 +894,9 @@ gimp_export_image (GimpImage **image,
|
|||
return GIMP_EXPORT_CANCEL;
|
||||
}
|
||||
|
||||
/* Merge down layer effects for non-project file formats */
|
||||
if (! (capabilities & GIMP_EXPORT_CAN_HANDLE_LAYER_EFFECTS))
|
||||
actions = g_slist_prepend (actions, &export_action_merge_layer_effects);
|
||||
|
||||
/* check alpha and layer masks */
|
||||
layers = gimp_image_list_layers (*image);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ G_BEGIN_DECLS
|
|||
* @GIMP_EXPORT_CAN_HANDLE_ALPHA: Handles alpha channels
|
||||
* @GIMP_EXPORT_CAN_HANDLE_LAYERS: Handles layers
|
||||
* @GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION: Handles animation of layers
|
||||
* @GIMP_EXPORT_CAN_HANDLE_LAYER_EFFECTS: Handles layer effects
|
||||
* @GIMP_EXPORT_CAN_HANDLE_LAYER_MASKS: Handles layer masks
|
||||
* @GIMP_EXPORT_NEEDS_ALPHA: Needs alpha channels
|
||||
* @GIMP_EXPORT_NEEDS_CROP: Needs to crop content to image bounds
|
||||
|
|
@ -56,8 +57,9 @@ typedef enum
|
|||
GIMP_EXPORT_CAN_HANDLE_LAYERS = 1 << 5,
|
||||
GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION = 1 << 6,
|
||||
GIMP_EXPORT_CAN_HANDLE_LAYER_MASKS = 1 << 7,
|
||||
GIMP_EXPORT_NEEDS_ALPHA = 1 << 8,
|
||||
GIMP_EXPORT_NEEDS_CROP = 1 << 9
|
||||
GIMP_EXPORT_CAN_HANDLE_LAYER_EFFECTS = 1 << 8,
|
||||
GIMP_EXPORT_NEEDS_ALPHA = 1 << 9,
|
||||
GIMP_EXPORT_NEEDS_CROP = 1 << 10
|
||||
} GimpExportCapabilities;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,38 @@
|
|||
|
||||
# "Perlized" from C source by Manish Singh <yosh@gimp.org>
|
||||
|
||||
sub drawable_merge_filters {
|
||||
$blurb = 'Merge the layer effect filters to the specified drawable.';
|
||||
|
||||
$help = <<'HELP';
|
||||
This procedure combines the contents of the drawable's filter stack
|
||||
(for export) with the specified drawable.
|
||||
HELP
|
||||
|
||||
&std_pdb_misc;
|
||||
|
||||
@inargs = (
|
||||
{ name => 'drawable', type => 'drawable',
|
||||
desc => 'The drawable' }
|
||||
);
|
||||
|
||||
%invoke = (
|
||||
headers => [ qw("core/gimpdrawable-filters.h") ],
|
||||
code => <<'CODE'
|
||||
{
|
||||
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
|
||||
GIMP_PDB_ITEM_CONTENT, error) &&
|
||||
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
|
||||
{
|
||||
gimp_drawable_merge_filters (drawable);
|
||||
}
|
||||
else
|
||||
success = FALSE;
|
||||
}
|
||||
CODE
|
||||
);
|
||||
}
|
||||
|
||||
sub drawable_merge_shadow {
|
||||
$blurb = 'Merge the shadow buffer with the specified drawable.';
|
||||
|
||||
|
|
@ -899,6 +931,7 @@ CODE
|
|||
"gegl/gimp-babl-compat.h"
|
||||
"core/gimp.h"
|
||||
"core/gimpchannel-select.h"
|
||||
"core/gimpdrawable-filters.h"
|
||||
"core/gimpdrawable-offset.h"
|
||||
"core/gimpimage.h"
|
||||
"core/gimptempbuf.h"
|
||||
|
|
@ -920,10 +953,11 @@ CODE
|
|||
drawable_get_offsets
|
||||
drawable_mask_bounds
|
||||
drawable_mask_intersect
|
||||
drawable_merge_filters
|
||||
drawable_merge_shadow
|
||||
drawable_free_shadow
|
||||
drawable_update
|
||||
drawable_fill
|
||||
drawable_fill
|
||||
drawable_offset
|
||||
drawable_thumbnail
|
||||
drawable_sub_thumbnail
|
||||
|
|
|
|||
Loading…
Reference in a new issue