void layers_actions_update (GimpActionGroup *group, gpointer data) { GimpImage *image = action_data_get_image (data); GimpLayer *layer = NULL; GimpLayerMask *mask = NULL; /* layer mask */ gboolean fs = FALSE; /* floating sel */ gboolean ac = FALSE; /* active channel */ gboolean sel = FALSE; gboolean alpha = FALSE; /* alpha channel present */ gboolean indexed = FALSE; /* is indexed */ gboolean lock_alpha = FALSE; gboolean text_layer = FALSE; GList *next = NULL; GList *prev = NULL; if (image) { fs = (gimp_image_floating_sel (image) != NULL); ac = (gimp_image_get_active_channel (image) != NULL); sel = ! gimp_channel_is_empty (gimp_image_get_mask (image)); indexed = (gimp_image_base_type (image) == GIMP_INDEXED); layer = gimp_image_get_active_layer (image); if (layer) { GList *list; mask = gimp_layer_get_mask (layer); lock_alpha = gimp_layer_get_lock_alpha (layer); alpha = gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)); list = g_list_find (GIMP_LIST (image->layers)->list, layer); if (list) { prev = g_list_previous (list); next = g_list_next (list); } if (layer) text_layer = gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer)); } } #define SET_VISIBLE(action,condition) \ gimp_action_group_set_action_visible (group, action, (condition) != 0) #define SET_SENSITIVE(action,condition) \ gimp_action_group_set_action_sensitive (group, action, (condition) != 0) #define SET_ACTIVE(action,condition) \ gimp_action_group_set_action_active (group, action, (condition) != 0) SET_VISIBLE ("layers-text-tool", text_layer && !ac); SET_SENSITIVE ("layers-edit-attributes", layer && !fs && !ac); SET_SENSITIVE ("layers-new", image); SET_SENSITIVE ("layers-new-last-values", image); SET_SENSITIVE ("layers-duplicate", layer && !fs && !ac); SET_SENSITIVE ("layers-delete", layer && !ac); SET_SENSITIVE ("layers-select-top", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-select-bottom", layer && !fs && !ac && next); SET_SENSITIVE ("layers-select-previous", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-select-next", layer && !fs && !ac && next); SET_SENSITIVE ("layers-raise", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-raise-to-top", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-lower", layer && !fs && !ac && next); SET_SENSITIVE ("layers-lower-to-bottom", layer && !fs && !ac && next); SET_SENSITIVE ("layers-anchor", layer && fs && !ac); SET_SENSITIVE ("layers-merge-down", layer && !fs && !ac && next); SET_SENSITIVE ("layers-merge-layers", layer && !fs && !ac); SET_SENSITIVE ("layers-flatten-image", layer && !fs && !ac); SET_VISIBLE ("layers-text-discard", text_layer && !ac); SET_VISIBLE ("layers-text-to-vectors", text_layer && !ac); SET_VISIBLE ("layers-text-along-vectors", text_layer && !ac); SET_VISIBLE ("layers-text-selection-replace", text_layer && !ac); SET_VISIBLE ("layers-text-selection-add", text_layer && !ac); SET_VISIBLE ("layers-text-selection-subtract", text_layer && !ac); SET_VISIBLE ("layers-text-selection-intersect", text_layer && !ac); SET_SENSITIVE ("layers-resize", layer && !ac); SET_SENSITIVE ("layers-resize-to-image", layer && !ac); SET_SENSITIVE ("layers-scale", layer && !ac); SET_SENSITIVE ("layers-crop", layer && sel); SET_SENSITIVE ("layers-alpha-add", layer && !fs && !alpha); SET_SENSITIVE ("layers-alpha-remove", layer && !fs && alpha); SET_SENSITIVE ("layers-lock-alpha", layer); SET_ACTIVE ("layers-lock-alpha", lock_alpha); SET_SENSITIVE ("layers-mask-add", layer && !fs && !ac && !mask); SET_SENSITIVE ("layers-mask-apply", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-delete", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-edit", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-show", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-disable", layer && !fs && !ac && mask); SET_ACTIVE ("layers-mask-edit", mask && gimp_layer_mask_get_edit (mask)); SET_ACTIVE ("layers-mask-show", mask && gimp_layer_mask_get_show (mask)); SET_ACTIVE ("layers-mask-disable", mask && !gimp_layer_mask_get_apply (mask)); SET_SENSITIVE ("layers-mask-selection-replace", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-add", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-subtract", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-intersect", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-alpha-selection-replace", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-add", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-subtract", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-intersect", layer && !fs && !ac); #undef SET_VISIBLE #undef SET_SENSITIVE #undef SET_ACTIVE }
static GimpLayer * gimp_image_merge_layers (GimpImage *image, GSList *merge_list, GimpContext *context, GimpMergeType merge_type, const gchar *undo_desc) { GList *list; GSList *reverse_list = NULL; PixelRegion src1PR, src2PR, maskPR; PixelRegion *mask; GimpLayer *merge_layer; GimpLayer *layer; GimpLayer *bottom_layer; GimpImageType type; gint count; gint x1, y1, x2, y2; gint x3, y3, x4, y4; CombinationMode operation; gint position; gboolean active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE }; gint off_x, off_y; gchar *name; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); layer = NULL; type = GIMP_RGBA_IMAGE; x1 = y1 = 0; x2 = y2 = 0; bottom_layer = NULL; /* Get the layer extents */ count = 0; while (merge_list) { layer = merge_list->data; gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); switch (merge_type) { case GIMP_EXPAND_AS_NECESSARY: case GIMP_CLIP_TO_IMAGE: if (! count) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } else { if (off_x < x1) x1 = off_x; if (off_y < y1) y1 = off_y; if ((off_x + gimp_item_width (GIMP_ITEM (layer))) > x2) x2 = (off_x + gimp_item_width (GIMP_ITEM (layer))); if ((off_y + gimp_item_height (GIMP_ITEM (layer))) > y2) y2 = (off_y + gimp_item_height (GIMP_ITEM (layer))); } if (merge_type == GIMP_CLIP_TO_IMAGE) { x1 = CLAMP (x1, 0, gimp_image_get_width (image)); y1 = CLAMP (y1, 0, gimp_image_get_height (image)); x2 = CLAMP (x2, 0, gimp_image_get_width (image)); y2 = CLAMP (y2, 0, gimp_image_get_height (image)); } break; case GIMP_CLIP_TO_BOTTOM_LAYER: if (merge_list->next == NULL) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } break; case GIMP_FLATTEN_IMAGE: if (merge_list->next == NULL) { x1 = 0; y1 = 0; x2 = gimp_image_get_width (image); y2 = gimp_image_get_height (image); } break; } count ++; reverse_list = g_slist_prepend (reverse_list, layer); merge_list = g_slist_next (merge_list); } if ((x2 - x1) == 0 || (y2 - y1) == 0) return NULL; /* Start a merge undo group. */ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, undo_desc); name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); if (merge_type == GIMP_FLATTEN_IMAGE || gimp_drawable_type (GIMP_DRAWABLE (layer)) == GIMP_INDEXED_IMAGE) { guchar bg[4] = { 0, 0, 0, 0 }; type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image)); merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), type, gimp_object_get_name (GIMP_OBJECT (layer)), GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (! merge_layer) { g_warning ("%s: could not allocate merge layer.", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* get the background for compositing */ gimp_image_get_background (image, context, gimp_drawable_type (GIMP_DRAWABLE (merge_layer)), bg); /* init the pixel region */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); /* set the region to the background color */ color_region (&src1PR, bg); position = 0; } else { /* The final merged layer inherits the name of the bottom most layer * and the resulting layer has an alpha channel whether or not the * original did. Opacity is set to 100% and the MODE is set to normal. */ merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), "merged layer", GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (!merge_layer) { g_warning ("%s: could not allocate merge layer", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* clear the layer */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); clear_region (&src1PR); /* Find the index in the layer list of the bottom layer--we need this * in order to add the final, merged layer to the layer list correctly */ layer = reverse_list->data; position = gimp_container_num_children (image->layers) - gimp_container_get_child_index (image->layers, GIMP_OBJECT (layer)); } bottom_layer = layer; /* Copy the tattoo and parasites of the bottom layer to the new layer */ gimp_item_set_tattoo (GIMP_ITEM (merge_layer), gimp_item_get_tattoo (GIMP_ITEM (bottom_layer))); g_object_unref (GIMP_ITEM (merge_layer)->parasites); GIMP_ITEM (merge_layer)->parasites = gimp_parasite_list_copy (GIMP_ITEM (bottom_layer)->parasites); while (reverse_list) { GimpLayerModeEffects mode; layer = reverse_list->data; /* determine what sort of operation is being attempted and * if it's actually legal... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); if (operation == -1) { gimp_layer_add_alpha (layer); /* try again ... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); } if (operation == -1) { g_warning ("%s: attempting to merge incompatible layers.", G_STRFUNC); return NULL; } gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); x3 = CLAMP (off_x, x1, x2); y3 = CLAMP (off_y, y1, y2); x4 = CLAMP (off_x + gimp_item_width (GIMP_ITEM (layer)), x1, x2); y4 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y1, y2); /* configure the pixel regions */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), TRUE); pixel_region_init (&src2PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)), (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); if (gimp_layer_get_mask (layer) && gimp_layer_mask_get_apply (layer->mask)) { TileManager *tiles; tiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (layer->mask)); pixel_region_init (&maskPR, tiles, (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); mask = &maskPR; } else { mask = NULL; } /* DISSOLVE_MODE is special since it is the only mode that does not * work on the projection with the lower layer, but only locally on * the layers alpha channel. */ mode = gimp_layer_get_mode (layer); if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE) mode = GIMP_NORMAL_MODE; combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, gimp_layer_get_opacity (layer) * 255.999, mode, active, operation); gimp_image_remove_layer (image, layer); reverse_list = g_slist_next (reverse_list); } g_slist_free (reverse_list); /* if the type is flatten, remove all the remaining layers */ if (merge_type == GIMP_FLATTEN_IMAGE) { list = GIMP_LIST (image->layers)->list; while (list) { layer = list->data; list = g_list_next (list); gimp_image_remove_layer (image, layer); } gimp_image_add_layer (image, merge_layer, position); } else { /* Add the layer to the image */ gimp_image_add_layer (image, merge_layer, gimp_container_num_children (image->layers) - position + 1); } /* set the name after the original layers have been removed so we * don't end up with #2 appended to the name */ gimp_object_take_name (GIMP_OBJECT (merge_layer), name); gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, TRUE); /* End the merge undo group */ gimp_image_undo_group_end (image); gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_item_width (GIMP_ITEM (merge_layer)), gimp_item_height (GIMP_ITEM (merge_layer))); return merge_layer; }
void layers_actions_update (GimpActionGroup *group, gpointer data) { GimpImage *image = action_data_get_image (data); GimpLayer *layer = NULL; GimpLayerMask *mask = NULL; /* layer mask */ gboolean fs = FALSE; /* floating sel */ gboolean ac = FALSE; /* active channel */ gboolean sel = FALSE; gboolean alpha = FALSE; /* alpha channel present */ gboolean indexed = FALSE; /* is indexed */ gboolean lock_alpha = FALSE; gboolean can_lock_alpha = FALSE; gboolean text_layer = FALSE; gboolean writable = FALSE; gboolean children = FALSE; GList *next = NULL; GList *next_visible = NULL; GList *prev = NULL; if (image) { fs = (gimp_image_get_floating_selection (image) != NULL); ac = (gimp_image_get_active_channel (image) != NULL); sel = ! gimp_channel_is_empty (gimp_image_get_mask (image)); indexed = (gimp_image_base_type (image) == GIMP_INDEXED); layer = gimp_image_get_active_layer (image); if (layer) { GList *layer_list; GList *list; mask = gimp_layer_get_mask (layer); lock_alpha = gimp_layer_get_lock_alpha (layer); can_lock_alpha = gimp_layer_can_lock_alpha (layer); alpha = gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)); writable = ! gimp_item_is_content_locked (GIMP_ITEM (layer)); if (gimp_viewable_get_children (GIMP_VIEWABLE (layer))) children = TRUE; layer_list = gimp_item_get_container_iter (GIMP_ITEM (layer)); list = g_list_find (layer_list, layer); if (list) { prev = g_list_previous (list); next = g_list_next (list); for (next_visible = next; next_visible; next_visible = g_list_next (next_visible)) { if (gimp_item_get_visible (next_visible->data)) { /* "next_visible" is actually "next_visible" and * "writable" and "not group" */ if (gimp_item_is_content_locked (next_visible->data) || gimp_viewable_get_children (next_visible->data)) next_visible = NULL; break; } } } text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer)); } } #define SET_VISIBLE(action,condition) \ gimp_action_group_set_action_visible (group, action, (condition) != 0) #define SET_SENSITIVE(action,condition) \ gimp_action_group_set_action_sensitive (group, action, (condition) != 0) #define SET_ACTIVE(action,condition) \ gimp_action_group_set_action_active (group, action, (condition) != 0) #define SET_LABEL(action,label) \ gimp_action_group_set_action_label (group, action, label) SET_VISIBLE ("layers-text-tool", text_layer && !ac); SET_SENSITIVE ("layers-edit-attributes", layer && !fs && !ac); if (layer && gimp_layer_is_floating_sel (layer)) { SET_LABEL ("layers-new", C_("layers-action", "To _New Layer")); SET_LABEL ("layers-new-last-values", C_("layers-action", "To _New Layer")); } else { SET_LABEL ("layers-new", C_("layers-action", "_New Layer...")); SET_LABEL ("layers-new-last-values", C_("layers-action", "_New Layer")); } SET_SENSITIVE ("layers-new", image); SET_SENSITIVE ("layers-new-last-values", image); SET_SENSITIVE ("layers-new-from-visible", image); SET_SENSITIVE ("layers-new-group", image && !indexed); SET_SENSITIVE ("layers-duplicate", layer && !fs && !ac); SET_SENSITIVE ("layers-delete", layer && !ac); SET_SENSITIVE ("layers-select-top", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-select-bottom", layer && !fs && !ac && next); SET_SENSITIVE ("layers-select-previous", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-select-next", layer && !fs && !ac && next); SET_SENSITIVE ("layers-raise", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-raise-to-top", layer && !fs && !ac && prev); SET_SENSITIVE ("layers-lower", layer && !fs && !ac && next); SET_SENSITIVE ("layers-lower-to-bottom", layer && !fs && !ac && next); SET_SENSITIVE ("layers-anchor", layer && fs && !ac); SET_SENSITIVE ("layers-merge-down", layer && !fs && !ac && next_visible); SET_VISIBLE ("layers-merge-group", children); SET_SENSITIVE ("layers-merge-group", layer && !fs && !ac && children); SET_SENSITIVE ("layers-merge-layers", layer && !fs && !ac); SET_SENSITIVE ("layers-flatten-image", layer && !fs && !ac); SET_VISIBLE ("layers-text-discard", text_layer && !ac); SET_VISIBLE ("layers-text-to-vectors", text_layer && !ac); SET_VISIBLE ("layers-text-along-vectors", text_layer && !ac); SET_SENSITIVE ("layers-resize", writable && !ac); SET_SENSITIVE ("layers-resize-to-image", writable && !ac); SET_SENSITIVE ("layers-scale", writable && !ac); SET_SENSITIVE ("layers-crop", writable && sel); SET_SENSITIVE ("layers-alpha-add", writable && !children && !fs && !alpha); SET_SENSITIVE ("layers-alpha-remove", writable && !children && !fs && alpha); SET_SENSITIVE ("layers-lock-alpha", can_lock_alpha); SET_ACTIVE ("layers-lock-alpha", lock_alpha); SET_SENSITIVE ("layers-mask-add", layer && !fs && !ac && !mask && !children); SET_SENSITIVE ("layers-mask-apply", writable && !fs && !ac && mask && !children); SET_SENSITIVE ("layers-mask-delete", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-edit", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-show", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-disable", layer && !fs && !ac && mask); SET_ACTIVE ("layers-mask-edit", mask && gimp_layer_mask_get_edit (mask)); SET_ACTIVE ("layers-mask-show", mask && gimp_layer_mask_get_show (mask)); SET_ACTIVE ("layers-mask-disable", mask && !gimp_layer_mask_get_apply (mask)); SET_SENSITIVE ("layers-mask-selection-replace", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-add", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-subtract", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-mask-selection-intersect", layer && !fs && !ac && mask); SET_SENSITIVE ("layers-alpha-selection-replace", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-add", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-subtract", layer && !fs && !ac); SET_SENSITIVE ("layers-alpha-selection-intersect", layer && !fs && !ac); #undef SET_VISIBLE #undef SET_SENSITIVE #undef SET_ACTIVE #undef SET_LABEL }