/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * 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 . */ #include "config.h" #include #include #include "core-types.h" #include "gegl/pika-babl.h" #include "pikaerror.h" #include "pikaimage.h" #include "pikalayer.h" #include "pikalayermask.h" #include "pika-intl.h" static void pika_layer_mask_preview_freeze (PikaViewable *viewable); static void pika_layer_mask_preview_thaw (PikaViewable *viewable); static gboolean pika_layer_mask_is_attached (PikaItem *item); static gboolean pika_layer_mask_is_content_locked (PikaItem *item, PikaItem **locked_item); static gboolean pika_layer_mask_is_position_locked (PikaItem *item, PikaItem **locked_item, gboolean check_children); static PikaItemTree * pika_layer_mask_get_tree (PikaItem *item); static PikaItem * pika_layer_mask_duplicate (PikaItem *item, GType new_type); static gboolean pika_layer_mask_rename (PikaItem *item, const gchar *new_name, const gchar *undo_desc, GError **error); static void pika_layer_mask_bounding_box_changed (PikaDrawable *drawable); static void pika_layer_mask_convert_type (PikaDrawable *drawable, PikaImage *dest_image, const Babl *new_format, PikaColorProfile *src_profile, PikaColorProfile *dest_profile, GeglDitherMethod layer_dither_type, GeglDitherMethod mask_dither_type, gboolean push_undo, PikaProgress *progress); G_DEFINE_TYPE (PikaLayerMask, pika_layer_mask, PIKA_TYPE_CHANNEL) #define parent_class pika_layer_mask_parent_class static void pika_layer_mask_class_init (PikaLayerMaskClass *klass) { PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass); PikaItemClass *item_class = PIKA_ITEM_CLASS (klass); PikaDrawableClass *drawable_class = PIKA_DRAWABLE_CLASS (klass); viewable_class->default_icon_name = "pika-layer-mask"; viewable_class->preview_freeze = pika_layer_mask_preview_freeze; viewable_class->preview_thaw = pika_layer_mask_preview_thaw; item_class->is_attached = pika_layer_mask_is_attached; item_class->is_content_locked = pika_layer_mask_is_content_locked; item_class->is_position_locked = pika_layer_mask_is_position_locked; item_class->get_tree = pika_layer_mask_get_tree; item_class->duplicate = pika_layer_mask_duplicate; item_class->rename = pika_layer_mask_rename; item_class->translate_desc = C_("undo-type", "Move Layer Mask"); item_class->to_selection_desc = C_("undo-type", "Layer Mask to Selection"); drawable_class->bounding_box_changed = pika_layer_mask_bounding_box_changed; drawable_class->convert_type = pika_layer_mask_convert_type; } static void pika_layer_mask_init (PikaLayerMask *layer_mask) { layer_mask->layer = NULL; } static void pika_layer_mask_preview_freeze (PikaViewable *viewable) { PikaLayerMask *mask = PIKA_LAYER_MASK (viewable); PikaLayer *layer = pika_layer_mask_get_layer (mask); if (layer) { PikaViewable *parent = pika_viewable_get_parent (PIKA_VIEWABLE (layer)); if (! parent && pika_item_is_attached (PIKA_ITEM (layer))) parent = PIKA_VIEWABLE (pika_item_get_image (PIKA_ITEM (layer))); if (parent) pika_viewable_preview_freeze (parent); } } static void pika_layer_mask_preview_thaw (PikaViewable *viewable) { PikaLayerMask *mask = PIKA_LAYER_MASK (viewable); PikaLayer *layer = pika_layer_mask_get_layer (mask); if (layer) { PikaViewable *parent = pika_viewable_get_parent (PIKA_VIEWABLE (layer)); if (! parent && pika_item_is_attached (PIKA_ITEM (layer))) parent = PIKA_VIEWABLE (pika_item_get_image (PIKA_ITEM (layer))); if (parent) pika_viewable_preview_thaw (parent); } } static gboolean pika_layer_mask_is_content_locked (PikaItem *item, PikaItem **locked_item) { PikaLayerMask *mask = PIKA_LAYER_MASK (item); PikaLayer *layer = pika_layer_mask_get_layer (mask); if (layer) return pika_item_is_content_locked (PIKA_ITEM (layer), locked_item); return FALSE; } static gboolean pika_layer_mask_is_position_locked (PikaItem *item, PikaItem **locked_item, gboolean check_children) { PikaLayerMask *mask = PIKA_LAYER_MASK (item); PikaLayer *layer = pika_layer_mask_get_layer (mask); if (layer) return pika_item_is_position_locked (PIKA_ITEM (layer), locked_item); return FALSE; } static gboolean pika_layer_mask_is_attached (PikaItem *item) { PikaLayerMask *mask = PIKA_LAYER_MASK (item); PikaLayer *layer = pika_layer_mask_get_layer (mask); return (PIKA_IS_IMAGE (pika_item_get_image (item)) && PIKA_IS_LAYER (layer) && pika_layer_get_mask (layer) == mask && pika_item_is_attached (PIKA_ITEM (layer))); } static PikaItemTree * pika_layer_mask_get_tree (PikaItem *item) { return NULL; } static PikaItem * pika_layer_mask_duplicate (PikaItem *item, GType new_type) { PikaItem *new_item; g_return_val_if_fail (g_type_is_a (new_type, PIKA_TYPE_DRAWABLE), NULL); new_item = PIKA_ITEM_CLASS (parent_class)->duplicate (item, new_type); return new_item; } static gboolean pika_layer_mask_rename (PikaItem *item, const gchar *new_name, const gchar *undo_desc, GError **error) { /* reject renaming, layer masks are always named " mask" */ g_set_error (error, PIKA_ERROR, PIKA_FAILED, _("Cannot rename layer masks.")); return FALSE; } static void pika_layer_mask_bounding_box_changed (PikaDrawable *drawable) { PikaLayerMask *mask = PIKA_LAYER_MASK (drawable); PikaLayer *layer = pika_layer_mask_get_layer (mask); if (PIKA_DRAWABLE_CLASS (parent_class)->bounding_box_changed) PIKA_DRAWABLE_CLASS (parent_class)->bounding_box_changed (drawable); if (layer) pika_drawable_update_bounding_box (PIKA_DRAWABLE (layer)); } static void pika_layer_mask_convert_type (PikaDrawable *drawable, PikaImage *dest_image, const Babl *new_format, PikaColorProfile *src_profile, PikaColorProfile *dest_profile, GeglDitherMethod layer_dither_type, GeglDitherMethod mask_dither_type, gboolean push_undo, PikaProgress *progress) { new_format = pika_babl_mask_format (pika_babl_format_get_precision (new_format)); PIKA_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image, new_format, src_profile, dest_profile, layer_dither_type, mask_dither_type, push_undo, progress); } PikaLayerMask * pika_layer_mask_new (PikaImage *image, gint width, gint height, const gchar *name, const PikaRGB *color) { PikaLayerMask *layer_mask; g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL); g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); g_return_val_if_fail (color != NULL, NULL); layer_mask = PIKA_LAYER_MASK (pika_drawable_new (PIKA_TYPE_LAYER_MASK, image, name, 0, 0, width, height, pika_image_get_mask_format (image))); /* set the layer_mask color and opacity */ pika_channel_set_color (PIKA_CHANNEL (layer_mask), color, FALSE); pika_channel_set_show_masked (PIKA_CHANNEL (layer_mask), TRUE); /* selection mask variables */ PIKA_CHANNEL (layer_mask)->x2 = width; PIKA_CHANNEL (layer_mask)->y2 = height; return layer_mask; } void pika_layer_mask_set_layer (PikaLayerMask *layer_mask, PikaLayer *layer) { g_return_if_fail (PIKA_IS_LAYER_MASK (layer_mask)); g_return_if_fail (layer == NULL || PIKA_IS_LAYER (layer)); layer_mask->layer = layer; if (layer) { gchar *mask_name; gint offset_x; gint offset_y; pika_item_get_offset (PIKA_ITEM (layer), &offset_x, &offset_y); pika_item_set_offset (PIKA_ITEM (layer_mask), offset_x, offset_y); mask_name = g_strdup_printf (_("%s mask"), pika_object_get_name (layer)); pika_object_take_name (PIKA_OBJECT (layer_mask), mask_name); } } PikaLayer * pika_layer_mask_get_layer (PikaLayerMask *layer_mask) { g_return_val_if_fail (PIKA_IS_LAYER_MASK (layer_mask), NULL); return layer_mask->layer; }