1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 
25 #include "libgimpbase/gimpbase.h"
26 #include "libgimpcolor/gimpcolor.h"
27 #include "libgimpwidgets/gimpwidgets.h"
28 
29 #include "actions-types.h"
30 
31 #include "config/gimpdialogconfig.h"
32 
33 #include "core/gimp.h"
34 #include "core/gimpchannel.h"
35 #include "core/gimpchannel-select.h"
36 #include "core/gimpcontext.h"
37 #include "core/gimpdrawable-fill.h"
38 #include "core/gimpimage.h"
39 #include "core/gimpimage-undo.h"
40 
41 #include "widgets/gimpaction.h"
42 #include "widgets/gimpcolorpanel.h"
43 #include "widgets/gimpcomponenteditor.h"
44 #include "widgets/gimpdock.h"
45 #include "widgets/gimphelp-ids.h"
46 
47 #include "dialogs/dialogs.h"
48 #include "dialogs/channel-options-dialog.h"
49 
50 #include "actions.h"
51 #include "channels-commands.h"
52 #include "items-commands.h"
53 
54 #include "gimp-intl.h"
55 
56 
57 #define RGBA_EPSILON 1e-6
58 
59 
60 /*  local function prototypes  */
61 
62 static void   channels_new_callback             (GtkWidget     *dialog,
63                                                  GimpImage     *image,
64                                                  GimpChannel   *channel,
65                                                  GimpContext   *context,
66                                                  const gchar   *channel_name,
67                                                  const GimpRGB *channel_color,
68                                                  gboolean       save_selection,
69                                                  gboolean       channel_visible,
70                                                  gboolean       channel_linked,
71                                                  GimpColorTag   channel_color_tag,
72                                                  gboolean       channel_lock_content,
73                                                  gboolean       channel_lock_position,
74                                                  gpointer       user_data);
75 static void   channels_edit_attributes_callback (GtkWidget     *dialog,
76                                                  GimpImage     *image,
77                                                  GimpChannel   *channel,
78                                                  GimpContext   *context,
79                                                  const gchar   *channel_name,
80                                                  const GimpRGB *channel_color,
81                                                  gboolean       save_selection,
82                                                  gboolean       channel_visible,
83                                                  gboolean       channel_linked,
84                                                  GimpColorTag   channel_color_tag,
85                                                  gboolean       channel_lock_content,
86                                                  gboolean       channel_lock_position,
87                                                  gpointer       user_data);
88 
89 
90 /*  public functions  */
91 
92 void
channels_edit_attributes_cmd_callback(GimpAction * action,GVariant * value,gpointer data)93 channels_edit_attributes_cmd_callback (GimpAction *action,
94                                        GVariant   *value,
95                                        gpointer    data)
96 {
97   GimpImage   *image;
98   GimpChannel *channel;
99   GtkWidget   *widget;
100   GtkWidget   *dialog;
101   return_if_no_channel (image, channel, data);
102   return_if_no_widget (widget, data);
103 
104 #define EDIT_DIALOG_KEY "gimp-channel-edit-attributes-dialog"
105 
106   dialog = dialogs_get_dialog (G_OBJECT (channel), EDIT_DIALOG_KEY);
107 
108   if (! dialog)
109     {
110       GimpItem *item = GIMP_ITEM (channel);
111 
112       dialog = channel_options_dialog_new (image, channel,
113                                            action_data_get_context (data),
114                                            widget,
115                                            _("Channel Attributes"),
116                                            "gimp-channel-edit",
117                                            GIMP_ICON_EDIT,
118                                            _("Edit Channel Attributes"),
119                                            GIMP_HELP_CHANNEL_EDIT,
120                                            _("Edit Channel Color"),
121                                            _("_Fill opacity:"),
122                                            FALSE,
123                                            gimp_object_get_name (channel),
124                                            &channel->color,
125                                            gimp_item_get_visible (item),
126                                            gimp_item_get_linked (item),
127                                            gimp_item_get_color_tag (item),
128                                            gimp_item_get_lock_content (item),
129                                            gimp_item_get_lock_position (item),
130                                            channels_edit_attributes_callback,
131                                            NULL);
132 
133       dialogs_attach_dialog (G_OBJECT (channel), EDIT_DIALOG_KEY, dialog);
134     }
135 
136   gtk_window_present (GTK_WINDOW (dialog));
137 }
138 
139 void
channels_new_cmd_callback(GimpAction * action,GVariant * value,gpointer data)140 channels_new_cmd_callback (GimpAction *action,
141                            GVariant   *value,
142                            gpointer    data)
143 {
144   GimpImage *image;
145   GtkWidget *widget;
146   GtkWidget *dialog;
147   return_if_no_image (image, data);
148   return_if_no_widget (widget, data);
149 
150 #define NEW_DIALOG_KEY "gimp-channel-new-dialog"
151 
152   dialog = dialogs_get_dialog (G_OBJECT (image), NEW_DIALOG_KEY);
153 
154   if (! dialog)
155     {
156       GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
157 
158       dialog = channel_options_dialog_new (image, NULL,
159                                            action_data_get_context (data),
160                                            widget,
161                                            _("New Channel"),
162                                            "gimp-channel-new",
163                                            GIMP_ICON_CHANNEL,
164                                            _("Create a New Channel"),
165                                            GIMP_HELP_CHANNEL_NEW,
166                                            _("New Channel Color"),
167                                            _("_Fill opacity:"),
168                                            TRUE,
169                                            config->channel_new_name,
170                                            &config->channel_new_color,
171                                            TRUE,
172                                            FALSE,
173                                            GIMP_COLOR_TAG_NONE,
174                                            FALSE,
175                                            FALSE,
176                                            channels_new_callback,
177                                            NULL);
178 
179       dialogs_attach_dialog (G_OBJECT (image), NEW_DIALOG_KEY, dialog);
180     }
181 
182   gtk_window_present (GTK_WINDOW (dialog));
183 }
184 
185 void
channels_new_last_vals_cmd_callback(GimpAction * action,GVariant * value,gpointer data)186 channels_new_last_vals_cmd_callback (GimpAction *action,
187                                      GVariant   *value,
188                                      gpointer    data)
189 {
190   GimpImage        *image;
191   GimpChannel      *channel;
192   GimpDialogConfig *config;
193   return_if_no_image (image, data);
194 
195   config = GIMP_DIALOG_CONFIG (image->gimp->config);
196 
197   channel = gimp_channel_new (image,
198                               gimp_image_get_width (image),
199                               gimp_image_get_height (image),
200                               config->channel_new_name,
201                               &config->channel_new_color);
202 
203   gimp_drawable_fill (GIMP_DRAWABLE (channel),
204                       action_data_get_context (data),
205                       GIMP_FILL_TRANSPARENT);
206 
207   gimp_image_add_channel (image, channel,
208                           GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
209   gimp_image_flush (image);
210 }
211 
212 void
channels_raise_cmd_callback(GimpAction * action,GVariant * value,gpointer data)213 channels_raise_cmd_callback (GimpAction *action,
214                              GVariant   *value,
215                              gpointer    data)
216 {
217   GimpImage   *image;
218   GimpChannel *channel;
219   return_if_no_channel (image, channel, data);
220 
221   gimp_image_raise_item (image, GIMP_ITEM (channel), NULL);
222   gimp_image_flush (image);
223 }
224 
225 void
channels_raise_to_top_cmd_callback(GimpAction * action,GVariant * value,gpointer data)226 channels_raise_to_top_cmd_callback (GimpAction *action,
227                                     GVariant   *value,
228                                     gpointer    data)
229 {
230   GimpImage   *image;
231   GimpChannel *channel;
232   return_if_no_channel (image, channel, data);
233 
234   gimp_image_raise_item_to_top (image, GIMP_ITEM (channel));
235   gimp_image_flush (image);
236 }
237 
238 void
channels_lower_cmd_callback(GimpAction * action,GVariant * value,gpointer data)239 channels_lower_cmd_callback (GimpAction *action,
240                              GVariant   *value,
241                              gpointer    data)
242 {
243   GimpImage   *image;
244   GimpChannel *channel;
245   return_if_no_channel (image, channel, data);
246 
247   gimp_image_lower_item (image, GIMP_ITEM (channel), NULL);
248   gimp_image_flush (image);
249 }
250 
251 void
channels_lower_to_bottom_cmd_callback(GimpAction * action,GVariant * value,gpointer data)252 channels_lower_to_bottom_cmd_callback (GimpAction *action,
253                                        GVariant   *value,
254                                        gpointer    data)
255 {
256   GimpImage   *image;
257   GimpChannel *channel;
258   return_if_no_channel (image, channel, data);
259 
260   gimp_image_lower_item_to_bottom (image, GIMP_ITEM (channel));
261   gimp_image_flush (image);
262 }
263 
264 void
channels_duplicate_cmd_callback(GimpAction * action,GVariant * value,gpointer data)265 channels_duplicate_cmd_callback (GimpAction *action,
266                                  GVariant   *value,
267                                  gpointer    data)
268 {
269   GimpImage   *image;
270   GimpChannel *new_channel;
271   GimpChannel *parent = GIMP_IMAGE_ACTIVE_PARENT;
272 
273   if (GIMP_IS_COMPONENT_EDITOR (data))
274     {
275       GimpChannelType  component;
276       const gchar     *desc;
277       gchar           *name;
278       return_if_no_image (image, data);
279 
280       component = GIMP_COMPONENT_EDITOR (data)->clicked_component;
281 
282       gimp_enum_get_value (GIMP_TYPE_CHANNEL_TYPE, component,
283                            NULL, NULL, &desc, NULL);
284 
285       name = g_strdup_printf (_("%s Channel Copy"), desc);
286 
287       new_channel = gimp_channel_new_from_component (image, component,
288                                                      name, NULL);
289 
290       /*  copied components are invisible by default so subsequent copies
291        *  of components don't affect each other
292        */
293       gimp_item_set_visible (GIMP_ITEM (new_channel), FALSE, FALSE);
294 
295       g_free (name);
296     }
297   else
298     {
299       GimpChannel *channel;
300       return_if_no_channel (image, channel, data);
301 
302       new_channel =
303         GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (channel),
304                                            G_TYPE_FROM_INSTANCE (channel)));
305 
306       /*  use the actual parent here, not GIMP_IMAGE_ACTIVE_PARENT because
307        *  the latter would add a duplicated group inside itself instead of
308        *  above it
309        */
310       parent = gimp_channel_get_parent (channel);
311     }
312 
313   gimp_image_add_channel (image, new_channel, parent, -1, TRUE);
314   gimp_image_flush (image);
315 }
316 
317 void
channels_delete_cmd_callback(GimpAction * action,GVariant * value,gpointer data)318 channels_delete_cmd_callback (GimpAction *action,
319                               GVariant   *value,
320                               gpointer    data)
321 {
322   GimpImage   *image;
323   GimpChannel *channel;
324   return_if_no_channel (image, channel, data);
325 
326   gimp_image_remove_channel (image, channel, TRUE, NULL);
327   gimp_image_flush (image);
328 }
329 
330 void
channels_to_selection_cmd_callback(GimpAction * action,GVariant * value,gpointer data)331 channels_to_selection_cmd_callback (GimpAction *action,
332                                     GVariant   *value,
333                                     gpointer    data)
334 {
335   GimpChannelOps  op;
336   GimpImage      *image;
337 
338   op = (GimpChannelOps) g_variant_get_int32 (value);
339 
340   if (GIMP_IS_COMPONENT_EDITOR (data))
341     {
342       GimpChannelType component;
343       return_if_no_image (image, data);
344 
345       component = GIMP_COMPONENT_EDITOR (data)->clicked_component;
346 
347       gimp_channel_select_component (gimp_image_get_mask (image), component,
348                                      op, FALSE, 0.0, 0.0);
349     }
350   else
351     {
352       GimpChannel *channel;
353       return_if_no_channel (image, channel, data);
354 
355       gimp_item_to_selection (GIMP_ITEM (channel),
356                               op, TRUE, FALSE, 0.0, 0.0);
357     }
358 
359   gimp_image_flush (image);
360 }
361 
362 void
channels_visible_cmd_callback(GimpAction * action,GVariant * value,gpointer data)363 channels_visible_cmd_callback (GimpAction *action,
364                                GVariant   *value,
365                                gpointer    data)
366 {
367   GimpImage   *image;
368   GimpChannel *channel;
369   return_if_no_channel (image, channel, data);
370 
371   items_visible_cmd_callback (action, value, image, GIMP_ITEM (channel));
372 }
373 
374 void
channels_linked_cmd_callback(GimpAction * action,GVariant * value,gpointer data)375 channels_linked_cmd_callback (GimpAction *action,
376                               GVariant   *value,
377                               gpointer    data)
378 {
379   GimpImage   *image;
380   GimpChannel *channel;
381   return_if_no_channel (image, channel, data);
382 
383   items_linked_cmd_callback (action, value, image, GIMP_ITEM (channel));
384 }
385 
386 void
channels_lock_content_cmd_callback(GimpAction * action,GVariant * value,gpointer data)387 channels_lock_content_cmd_callback (GimpAction *action,
388                                     GVariant   *value,
389                                     gpointer    data)
390 {
391   GimpImage   *image;
392   GimpChannel *channel;
393   return_if_no_channel (image, channel, data);
394 
395   items_lock_content_cmd_callback (action, value, image, GIMP_ITEM (channel));
396 }
397 
398 void
channels_lock_position_cmd_callback(GimpAction * action,GVariant * value,gpointer data)399 channels_lock_position_cmd_callback (GimpAction *action,
400                                      GVariant   *value,
401                                      gpointer    data)
402 {
403   GimpImage   *image;
404   GimpChannel *channel;
405   return_if_no_channel (image, channel, data);
406 
407   items_lock_position_cmd_callback (action, value, image, GIMP_ITEM (channel));
408 }
409 
410 void
channels_color_tag_cmd_callback(GimpAction * action,GVariant * value,gpointer data)411 channels_color_tag_cmd_callback (GimpAction *action,
412                                  GVariant   *value,
413                                  gpointer    data)
414 {
415   GimpImage    *image;
416   GimpChannel  *channel;
417   GimpColorTag  color_tag;
418   return_if_no_channel (image, channel, data);
419 
420   color_tag = (GimpColorTag) g_variant_get_int32 (value);
421 
422   items_color_tag_cmd_callback (action, image, GIMP_ITEM (channel),
423                                 color_tag);
424 }
425 
426 void
channels_select_cmd_callback(GimpAction * action,GVariant * value,gpointer data)427 channels_select_cmd_callback (GimpAction *action,
428                               GVariant   *value,
429                               gpointer    data)
430 {
431   GimpImage            *image;
432   GimpChannel          *channel;
433   GimpChannel          *channel2;
434   GimpContainer        *container;
435   GimpActionSelectType  select_type;
436   return_if_no_channel (image, channel, data);
437 
438   select_type = (GimpActionSelectType) g_variant_get_int32 (value);
439 
440   container = gimp_image_get_channels (image);
441   channel2 = (GimpChannel *) action_select_object (select_type, container,
442                                                    (GimpObject *) channel);
443 
444   if (channel2 && channel2 != channel)
445     {
446       gimp_image_set_active_channel (image, channel2);
447       gimp_image_flush (image);
448     }
449 }
450 
451 /*  private functions  */
452 
453 static void
channels_new_callback(GtkWidget * dialog,GimpImage * image,GimpChannel * channel,GimpContext * context,const gchar * channel_name,const GimpRGB * channel_color,gboolean save_selection,gboolean channel_visible,gboolean channel_linked,GimpColorTag channel_color_tag,gboolean channel_lock_content,gboolean channel_lock_position,gpointer user_data)454 channels_new_callback (GtkWidget     *dialog,
455                        GimpImage     *image,
456                        GimpChannel   *channel,
457                        GimpContext   *context,
458                        const gchar   *channel_name,
459                        const GimpRGB *channel_color,
460                        gboolean       save_selection,
461                        gboolean       channel_visible,
462                        gboolean       channel_linked,
463                        GimpColorTag   channel_color_tag,
464                        gboolean       channel_lock_content,
465                        gboolean       channel_lock_position,
466                        gpointer       user_data)
467 {
468   GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
469 
470   g_object_set (config,
471                 "channel-new-name",  channel_name,
472                 "channel-new-color", channel_color,
473                 NULL);
474 
475   if (save_selection)
476     {
477       GimpChannel *selection = gimp_image_get_mask (image);
478 
479       channel = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (selection),
480                                                    GIMP_TYPE_CHANNEL));
481 
482       gimp_object_set_name (GIMP_OBJECT (channel),
483                             config->channel_new_name);
484       gimp_channel_set_color (channel, &config->channel_new_color, FALSE);
485     }
486   else
487     {
488       channel = gimp_channel_new (image,
489                                   gimp_image_get_width  (image),
490                                   gimp_image_get_height (image),
491                                   config->channel_new_name,
492                                   &config->channel_new_color);
493 
494       gimp_drawable_fill (GIMP_DRAWABLE (channel), context,
495                           GIMP_FILL_TRANSPARENT);
496     }
497 
498   gimp_item_set_visible (GIMP_ITEM (channel), channel_visible, FALSE);
499   gimp_item_set_linked (GIMP_ITEM (channel), channel_linked, FALSE);
500   gimp_item_set_color_tag (GIMP_ITEM (channel), channel_color_tag, FALSE);
501   gimp_item_set_lock_content (GIMP_ITEM (channel), channel_lock_content, FALSE);
502   gimp_item_set_lock_position (GIMP_ITEM (channel), channel_lock_position, FALSE);
503 
504   gimp_image_add_channel (image, channel,
505                           GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
506   gimp_image_flush (image);
507 
508   gtk_widget_destroy (dialog);
509 }
510 
511 static void
channels_edit_attributes_callback(GtkWidget * dialog,GimpImage * image,GimpChannel * channel,GimpContext * context,const gchar * channel_name,const GimpRGB * channel_color,gboolean save_selection,gboolean channel_visible,gboolean channel_linked,GimpColorTag channel_color_tag,gboolean channel_lock_content,gboolean channel_lock_position,gpointer user_data)512 channels_edit_attributes_callback (GtkWidget     *dialog,
513                                    GimpImage     *image,
514                                    GimpChannel   *channel,
515                                    GimpContext   *context,
516                                    const gchar   *channel_name,
517                                    const GimpRGB *channel_color,
518                                    gboolean       save_selection,
519                                    gboolean       channel_visible,
520                                    gboolean       channel_linked,
521                                    GimpColorTag   channel_color_tag,
522                                    gboolean       channel_lock_content,
523                                    gboolean       channel_lock_position,
524                                    gpointer       user_data)
525 {
526   GimpItem *item = GIMP_ITEM (channel);
527 
528   if (strcmp (channel_name, gimp_object_get_name (channel))              ||
529       gimp_rgba_distance (channel_color, &channel->color) > RGBA_EPSILON ||
530       channel_visible       != gimp_item_get_visible (item)              ||
531       channel_linked        != gimp_item_get_linked (item)               ||
532       channel_color_tag     != gimp_item_get_color_tag (item)            ||
533       channel_lock_content  != gimp_item_get_lock_content (item)         ||
534       channel_lock_position != gimp_item_get_lock_position (item))
535     {
536       gimp_image_undo_group_start (image,
537                                    GIMP_UNDO_GROUP_ITEM_PROPERTIES,
538                                    _("Channel Attributes"));
539 
540       if (strcmp (channel_name, gimp_object_get_name (channel)))
541         gimp_item_rename (GIMP_ITEM (channel), channel_name, NULL);
542 
543       if (gimp_rgba_distance (channel_color, &channel->color) > RGBA_EPSILON)
544         gimp_channel_set_color (channel, channel_color, TRUE);
545 
546       if (channel_visible != gimp_item_get_visible (item))
547         gimp_item_set_visible (item, channel_visible, TRUE);
548 
549       if (channel_linked != gimp_item_get_linked (item))
550         gimp_item_set_linked (item, channel_linked, TRUE);
551 
552       if (channel_color_tag != gimp_item_get_color_tag (item))
553         gimp_item_set_color_tag (item, channel_color_tag, TRUE);
554 
555       if (channel_lock_content != gimp_item_get_lock_content (item))
556         gimp_item_set_lock_content (item, channel_lock_content, TRUE);
557 
558       if (channel_lock_position != gimp_item_get_lock_position (item))
559         gimp_item_set_lock_position (item, channel_lock_position, TRUE);
560 
561       gimp_image_undo_group_end (image);
562 
563       gimp_image_flush (image);
564     }
565 
566   gtk_widget_destroy (dialog);
567 }
568