/* 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 "libpikawidgets/pikawidgets.h" #include "actions-types.h" #include "core/pika.h" #include "core/pikadrawable-equalize.h" #include "core/pikadrawable-levels.h" #include "core/pikadrawable-operation.h" #include "core/pikaimage.h" #include "core/pikaimage-undo.h" #include "core/pikaitemundo.h" #include "core/pikalayermask.h" #include "core/pikaprogress.h" #include "dialogs/dialogs.h" #include "actions.h" #include "drawable-commands.h" #include "pika-intl.h" /* public functions */ void drawable_equalize_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; return_if_no_drawables (image, drawables, data); if (g_list_length (drawables) > 1) pika_image_undo_group_start (image, PIKA_UNDO_GROUP_DRAWABLE_MOD, _("Equalize")); for (iter = drawables; iter; iter = iter->next) pika_drawable_equalize (iter->data, TRUE); if (g_list_length (drawables) > 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_levels_stretch_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; PikaDisplay *display; GtkWidget *widget; return_if_no_drawables (image, drawables, data); return_if_no_display (display, data); return_if_no_widget (widget, data); for (iter = drawables; iter; iter = iter->next) { if (! pika_drawable_is_rgb (iter->data)) { pika_message_literal (image->pika, G_OBJECT (widget), PIKA_MESSAGE_WARNING, _("White Balance operates only on RGB color " "layers.")); return; } } if (g_list_length (drawables) > 1) pika_image_undo_group_start (image, PIKA_UNDO_GROUP_DRAWABLE_MOD, _("Levels")); for (iter = drawables; iter; iter = iter->next) pika_drawable_levels_stretch (iter->data, PIKA_PROGRESS (display)); if (g_list_length (drawables) > 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_visible_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; PikaUndo *undo; gboolean push_undo = TRUE; gboolean visible; return_if_no_drawables (image, drawables, data); visible = g_variant_get_boolean (value); if (PIKA_IS_LAYER_MASK (drawables->data)) { PikaLayerMask *mask = PIKA_LAYER_MASK (drawables->data); g_list_free (drawables); drawables = g_list_prepend (NULL, pika_layer_mask_get_layer (mask)); } for (iter = drawables; iter; iter = iter->next) { if (visible && pika_item_get_visible (iter->data)) { /* If any of the drawables are already visible, we don't * toggle the selection visibility. This prevents the * SET_ACTIVE() in drawables-actions.c to toggle visibility * unexpectedly. */ g_list_free (drawables); return; } } for (iter = drawables; iter; iter = iter->next) if (visible != pika_item_get_visible (iter->data)) break; if (! iter) { g_list_free (drawables); return; } if (g_list_length (drawables) == 1) { undo = pika_image_undo_can_compress (image, PIKA_TYPE_ITEM_UNDO, PIKA_UNDO_ITEM_VISIBILITY); if (undo && PIKA_ITEM_UNDO (undo)->item == PIKA_ITEM (drawables->data)) push_undo = FALSE; } else { /* TODO: undo groups cannot be compressed so far. */ pika_image_undo_group_start (image, PIKA_UNDO_GROUP_ITEM_VISIBILITY, "Item visibility"); } for (; iter; iter = iter->next) pika_item_set_visible (iter->data, visible, push_undo); if (g_list_length (drawables) != 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_lock_content_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; gboolean locked; gboolean push_undo = TRUE; return_if_no_drawables (image, drawables, data); locked = g_variant_get_boolean (value); if (PIKA_IS_LAYER_MASK (drawables->data)) { PikaLayerMask *mask = PIKA_LAYER_MASK (drawables->data); g_list_free (drawables); drawables = g_list_prepend (NULL, pika_layer_mask_get_layer (mask)); } for (iter = drawables; iter; iter = iter->next) { if (! locked && ! pika_item_get_lock_content (iter->data)) { /* If any of the drawables are already unlocked, we don't toggle the * lock. This prevents the SET_ACTIVE() in drawables-actions.c to * toggle locks unexpectedly. */ g_list_free (drawables); return; } } for (iter = drawables; iter; iter = iter->next) if (locked != pika_item_get_lock_content (iter->data)) break; if (g_list_length (drawables) == 1) { PikaUndo *undo; undo = pika_image_undo_can_compress (image, PIKA_TYPE_ITEM_UNDO, PIKA_UNDO_ITEM_LOCK_CONTENT); if (undo && PIKA_ITEM_UNDO (undo)->item == PIKA_ITEM (drawables->data)) push_undo = FALSE; } else { /* TODO: undo groups cannot be compressed so far. */ pika_image_undo_group_start (image, PIKA_UNDO_GROUP_ITEM_LOCK_CONTENTS, _("Lock/Unlock content")); } for (; iter; iter = iter->next) pika_item_set_lock_content (iter->data, locked, push_undo); if (g_list_length (drawables) != 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_lock_position_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; gboolean locked; gboolean push_undo = TRUE; return_if_no_drawables (image, drawables, data); locked = g_variant_get_boolean (value); if (PIKA_IS_LAYER_MASK (drawables->data)) { PikaLayerMask *mask = PIKA_LAYER_MASK (drawables->data); g_list_free (drawables); drawables = g_list_prepend (NULL, pika_layer_mask_get_layer (mask)); } for (iter = drawables; iter; iter = iter->next) { if (! locked && ! pika_item_get_lock_position (iter->data)) { /* If any of the drawables are already unlocked, we don't toggle the * lock. This prevents the SET_ACTIVE() in drawables-actions.c to * toggle locks unexpectedly. */ g_list_free (drawables); return; } } for (iter = drawables; iter; iter = iter->next) if (locked != pika_item_get_lock_position (iter->data)) break; if (g_list_length (drawables) == 1) { PikaUndo *undo; undo = pika_image_undo_can_compress (image, PIKA_TYPE_ITEM_UNDO, PIKA_UNDO_ITEM_LOCK_POSITION); if (undo && PIKA_ITEM_UNDO (undo)->item == PIKA_ITEM (drawables->data)) push_undo = FALSE; } else { /* TODO: undo groups cannot be compressed so far. */ pika_image_undo_group_start (image, PIKA_UNDO_GROUP_ITEM_LOCK_POSITION, _("Lock/Unlock position")); } for (; iter; iter = iter->next) pika_item_set_lock_position (iter->data, locked, push_undo); if (g_list_length (drawables) != 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_flip_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; PikaContext *context; gint off_x, off_y; gdouble axis = 0.0; PikaOrientationType orientation; return_if_no_drawables (image, drawables, data); return_if_no_context (context, data); orientation = (PikaOrientationType) g_variant_get_int32 (value); if (g_list_length (drawables) > 1) pika_image_undo_group_start (image, PIKA_UNDO_GROUP_DRAWABLE_MOD, _("Flip Drawables")); for (iter = drawables; iter; iter = iter->next) { PikaItem *item; item = PIKA_ITEM (iter->data); pika_item_get_offset (item, &off_x, &off_y); switch (orientation) { case PIKA_ORIENTATION_HORIZONTAL: axis = ((gdouble) off_x + (gdouble) pika_item_get_width (item) / 2.0); break; case PIKA_ORIENTATION_VERTICAL: axis = ((gdouble) off_y + (gdouble) pika_item_get_height (item) / 2.0); break; default: break; } pika_item_flip (item, context, orientation, axis, pika_item_get_clip (item, FALSE)); } if (g_list_length (drawables) > 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); } void drawable_rotate_cmd_callback (PikaAction *action, GVariant *value, gpointer data) { PikaImage *image; GList *drawables; GList *iter; PikaContext *context; PikaRotationType rotation_type; return_if_no_drawables (image, drawables, data); return_if_no_context (context, data); rotation_type = (PikaRotationType) g_variant_get_int32 (value); if (g_list_length (drawables) > 1) pika_image_undo_group_start (image, PIKA_UNDO_GROUP_DRAWABLE_MOD, _("Rotate Drawables")); for (iter = drawables; iter; iter = iter->next) { PikaItem *item; gint off_x, off_y; gdouble center_x, center_y; item = PIKA_ITEM (iter->data); pika_item_get_offset (item, &off_x, &off_y); center_x = ((gdouble) off_x + (gdouble) pika_item_get_width (item) / 2.0); center_y = ((gdouble) off_y + (gdouble) pika_item_get_height (item) / 2.0); pika_item_rotate (item, context, rotation_type, center_x, center_y, pika_item_get_clip (item, FALSE)); } if (g_list_length (drawables) > 1) pika_image_undo_group_end (image); pika_image_flush (image); g_list_free (drawables); }