From 07ac78ef8dfe5e0936016a88d2baff514eadfd54 Mon Sep 17 00:00:00 2001 From: Ell Date: Mon, 8 May 2017 16:02:37 -0400 Subject: [PATCH] app: add GimpLayerStack A subclass of GimpDrawableStack, for layer stacks. Invalidates the layers' backdrop as/when necessary, according to the value of their excludes_backdrop property. Make gimp_drawable_stack_update() protected, instead of private, so that we can use it in GimpLayerStack. --- app/core/Makefile.am | 2 + app/core/core-types.h | 1 + app/core/gimpdrawablestack.c | 14 +-- app/core/gimpdrawablestack.h | 11 +- app/core/gimpgrouplayer.c | 4 +- app/core/gimpimage.c | 3 +- app/core/gimplayerstack.c | 233 +++++++++++++++++++++++++++++++++++ app/core/gimplayerstack.h | 51 ++++++++ 8 files changed, 308 insertions(+), 11 deletions(-) create mode 100644 app/core/gimplayerstack.c create mode 100644 app/core/gimplayerstack.h diff --git a/app/core/Makefile.am b/app/core/Makefile.am index 8e0aec02c4..9e99352349 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -308,6 +308,8 @@ libappcore_a_sources = \ gimplayermaskundo.h \ gimplayerpropundo.c \ gimplayerpropundo.h \ + gimplayerstack.c \ + gimplayerstack.h \ gimplayerundo.c \ gimplayerundo.h \ gimplist.c \ diff --git a/app/core/core-types.h b/app/core/core-types.h index 11eaa626fc..9ba95a4d03 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -98,6 +98,7 @@ typedef struct _GimpDrawableStack GimpDrawableStack; typedef struct _GimpFilteredContainer GimpFilteredContainer; typedef struct _GimpFilterStack GimpFilterStack; typedef struct _GimpItemStack GimpItemStack; +typedef struct _GimpLayerStack GimpLayerStack; typedef struct _GimpTaggedContainer GimpTaggedContainer; diff --git a/app/core/gimpdrawablestack.c b/app/core/gimpdrawablestack.c index 521f99cd4f..a98b31522f 100644 --- a/app/core/gimpdrawablestack.c +++ b/app/core/gimpdrawablestack.c @@ -49,11 +49,6 @@ static void gimp_drawable_stack_reorder (GimpContainer *container GimpObject *object, gint new_index); -static void gimp_drawable_stack_update (GimpDrawableStack *stack, - gint x, - gint y, - gint width, - gint height); static void gimp_drawable_stack_drawable_update (GimpItem *item, gint x, gint y, @@ -173,19 +168,24 @@ gimp_drawable_stack_new (GType drawable_type) } -/* private functions */ +/* protected functions */ -static void +void gimp_drawable_stack_update (GimpDrawableStack *stack, gint x, gint y, gint width, gint height) { + g_return_if_fail (GIMP_IS_DRAWABLE_STACK (stack)); + g_signal_emit (stack, stack_signals[UPDATE], 0, x, y, width, height); } + +/* private functions */ + static void gimp_drawable_stack_drawable_update (GimpItem *item, gint x, diff --git a/app/core/gimpdrawablestack.h b/app/core/gimpdrawablestack.h index 5197d132ee..eec46092ab 100644 --- a/app/core/gimpdrawablestack.h +++ b/app/core/gimpdrawablestack.h @@ -51,7 +51,16 @@ struct _GimpDrawableStackClass GType gimp_drawable_stack_get_type (void) G_GNUC_CONST; -GimpContainer * gimp_drawable_stack_new (GType drawable_type); +GimpContainer * gimp_drawable_stack_new (GType drawable_type); + + +/* protected */ + +void gimp_drawable_stack_update (GimpDrawableStack *stack, + gint x, + gint y, + gint width, + gint height); #endif /* __GIMP_DRAWABLE_STACK_H__ */ diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c index 3ac678bcc4..2be8de71a2 100644 --- a/app/core/gimpgrouplayer.c +++ b/app/core/gimpgrouplayer.c @@ -35,7 +35,7 @@ #include "gimpgrouplayer.h" #include "gimpimage.h" #include "gimpimage-undo-push.h" -#include "gimpdrawablestack.h" +#include "gimplayerstack.h" #include "gimppickable.h" #include "gimpprojectable.h" #include "gimpprojection.h" @@ -261,7 +261,7 @@ gimp_group_layer_init (GimpGroupLayer *group) { GimpGroupLayerPrivate *private = GET_PRIVATE (group); - private->children = gimp_drawable_stack_new (GIMP_TYPE_LAYER); + private->children = gimp_layer_stack_new (GIMP_TYPE_LAYER); private->expanded = TRUE; g_signal_connect (private->children, "add", diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index 853125329c..58749c9c33 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -64,6 +64,7 @@ #include "gimplayer.h" #include "gimplayer-floating-selection.h" #include "gimplayermask.h" +#include "gimplayerstack.h" #include "gimpmarshal.h" #include "gimpparasitelist.h" #include "gimppickable.h" @@ -728,7 +729,7 @@ gimp_image_init (GimpImage *image) private->sample_points = NULL; private->layers = gimp_item_tree_new (image, - GIMP_TYPE_DRAWABLE_STACK, + GIMP_TYPE_LAYER_STACK, GIMP_TYPE_LAYER); private->channels = gimp_item_tree_new (image, GIMP_TYPE_DRAWABLE_STACK, diff --git a/app/core/gimplayerstack.c b/app/core/gimplayerstack.c new file mode 100644 index 0000000000..7011bc7fc4 --- /dev/null +++ b/app/core/gimplayerstack.c @@ -0,0 +1,233 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * gimplayerstack.c + * Copyright (C) 2017 Ell + * + * 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 . + */ + +#include "config.h" + +#include +#include + +#include "core-types.h" + +#include "gimplayer.h" +#include "gimplayerstack.h" + + +/* local function prototypes */ + +static void gimp_layer_stack_constructed (GObject *object); + +static void gimp_layer_stack_add (GimpContainer *container, + GimpObject *object); +static void gimp_layer_stack_remove (GimpContainer *container, + GimpObject *object); +static void gimp_layer_stack_reorder (GimpContainer *container, + GimpObject *object, + gint new_index); + +static void gimp_layer_stack_layer_visible (GimpLayer *layer, + GimpLayerStack *stack); +static void gimp_layer_stack_layer_excludes_backdrop (GimpLayer *layer, + GimpLayerStack *stack); + +static void gimp_layer_stack_update_backdrop (GimpLayerStack *stack, + GimpLayer *layer, + gboolean ignore_visible, + gboolean ignore_excludes_backdrop); +static void gimp_layer_stack_update_range (GimpLayerStack *stack, + gint first, + gint last); + + +G_DEFINE_TYPE (GimpLayerStack, gimp_layer_stack, GIMP_TYPE_DRAWABLE_STACK) + +#define parent_class gimp_layer_stack_parent_class + + +static void +gimp_layer_stack_class_init (GimpLayerStackClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpContainerClass *container_class = GIMP_CONTAINER_CLASS (klass); + + object_class->constructed = gimp_layer_stack_constructed; + + container_class->add = gimp_layer_stack_add; + container_class->remove = gimp_layer_stack_remove; + container_class->reorder = gimp_layer_stack_reorder; +} + +static void +gimp_layer_stack_init (GimpLayerStack *stack) +{ +} + +static void +gimp_layer_stack_constructed (GObject *object) +{ + GimpContainer *container = GIMP_CONTAINER (object); + + G_OBJECT_CLASS (parent_class)->constructed (object); + + g_assert (g_type_is_a (gimp_container_get_children_type (container), + GIMP_TYPE_LAYER)); + + gimp_container_add_handler (container, "visibility-changed", + G_CALLBACK (gimp_layer_stack_layer_visible), + container); + gimp_container_add_handler (container, "excludes-backdrop-changed", + G_CALLBACK (gimp_layer_stack_layer_excludes_backdrop), + container); +} + +static void +gimp_layer_stack_add (GimpContainer *container, + GimpObject *object) +{ + GimpLayerStack *stack = GIMP_LAYER_STACK (container); + + GIMP_CONTAINER_CLASS (parent_class)->add (container, object); + + gimp_layer_stack_update_backdrop (stack, GIMP_LAYER (object), FALSE, FALSE); +} + +static void +gimp_layer_stack_remove (GimpContainer *container, + GimpObject *object) +{ + GimpLayerStack *stack = GIMP_LAYER_STACK (container); + + gimp_layer_stack_update_backdrop (stack, GIMP_LAYER (object), FALSE, FALSE); + + GIMP_CONTAINER_CLASS (parent_class)->remove (container, object); +} + +static void +gimp_layer_stack_reorder (GimpContainer *container, + GimpObject *object, + gint new_index) +{ + GimpLayerStack *stack = GIMP_LAYER_STACK (container); + gboolean excludes_backdrop; + gint index; + + excludes_backdrop = gimp_item_get_visible (GIMP_ITEM (object)) && + gimp_layer_get_excludes_backdrop (GIMP_LAYER (object)); + + if (excludes_backdrop) + index = gimp_container_get_child_index (container, object); + + GIMP_CONTAINER_CLASS (parent_class)->reorder (container, object, new_index); + + if (excludes_backdrop) + gimp_layer_stack_update_range (stack, index, new_index); +} + + +/* public functions */ + +GimpContainer * +gimp_layer_stack_new (GType layer_type) +{ + g_return_val_if_fail (g_type_is_a (layer_type, GIMP_TYPE_LAYER), NULL); + + return g_object_new (GIMP_TYPE_LAYER_STACK, + "name", g_type_name (layer_type), + "children-type", layer_type, + "policy", GIMP_CONTAINER_POLICY_STRONG, + NULL); +} + + +/* private functions */ + +static void +gimp_layer_stack_layer_visible (GimpLayer *layer, + GimpLayerStack *stack) +{ + gimp_layer_stack_update_backdrop (stack, layer, TRUE, FALSE); +} + +static void +gimp_layer_stack_layer_excludes_backdrop (GimpLayer *layer, + GimpLayerStack *stack) +{ + gimp_layer_stack_update_backdrop (stack, layer, FALSE, TRUE); +} + +static void +gimp_layer_stack_update_backdrop (GimpLayerStack *stack, + GimpLayer *layer, + gboolean ignore_visible, + gboolean ignore_excludes_backdrop) +{ + if ((ignore_visible || gimp_item_get_visible (GIMP_ITEM (layer))) && + (ignore_excludes_backdrop || gimp_layer_get_excludes_backdrop (layer))) + { + gint index; + + index = gimp_container_get_child_index (GIMP_CONTAINER (stack), + GIMP_OBJECT (layer)); + + gimp_layer_stack_update_range (stack, index, -1); + } +} + +static void +gimp_layer_stack_update_range (GimpLayerStack *stack, + gint first, + gint last) +{ + GList *iter; + + g_assert (first >= 0 && last >= -1); + + /* if the range is reversed, flip first and last; note that last == -1 is + * used to update all layers from first onward. + */ + if (last >= 0 && last < first) + { + gint temp = first; + + first = last + 1; + last = temp + 1; + } + + iter = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (stack)); + + for (iter = g_list_nth (iter, first); + iter && first != last; + iter = g_list_next (iter), first++) + { + GimpItem *item = iter->data; + + if (gimp_item_get_visible (item)) + { + gint offset_x; + gint offset_y; + + gimp_item_get_offset (item, &offset_x, &offset_y); + + gimp_drawable_stack_update (GIMP_DRAWABLE_STACK (stack), + offset_x, offset_y, + gimp_item_get_width (item), + gimp_item_get_height (item)); + } + } +} diff --git a/app/core/gimplayerstack.h b/app/core/gimplayerstack.h new file mode 100644 index 0000000000..00e8fcb7bc --- /dev/null +++ b/app/core/gimplayerstack.h @@ -0,0 +1,51 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * gimplayerstack.h + * Copyright (C) 2017 Ell + * + * 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 . + */ + +#ifndef __GIMP_LAYER_STACK_H__ +#define __GIMP_LAYER_STACK_H__ + +#include "gimpdrawablestack.h" + + +#define GIMP_TYPE_LAYER_STACK (gimp_layer_stack_get_type ()) +#define GIMP_LAYER_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LAYER_STACK, GimpLayerStack)) +#define GIMP_LAYER_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LAYER_STACK, GimpLayerStackClass)) +#define GIMP_IS_LAYER_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LAYER_STACK)) +#define GIMP_IS_LAYER_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LAYER_STACK)) + + +typedef struct _GimpLayerStackClass GimpLayerStackClass; + +struct _GimpLayerStack +{ + GimpDrawableStack parent_instance; +}; + +struct _GimpLayerStackClass +{ + GimpDrawableStackClass parent_class; +}; + + +GType gimp_layer_stack_get_type (void) G_GNUC_CONST; +GimpContainer * gimp_layer_stack_new (GType layer_type); + + +#endif /* __GIMP_LAYER_STACK_H__ */