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 <cairo.h>
21 #include <gegl.h>
22 #include <gdk-pixbuf/gdk-pixbuf.h>
23
24 #include "libgimpcolor/gimpcolor.h"
25
26 #include "core-types.h"
27
28 #include "gimp.h"
29 #include "gimpchannel.h"
30 #include "gimpimage.h"
31 #include "gimpimage-private.h"
32 #include "gimpimage-quick-mask.h"
33 #include "gimpimage-undo.h"
34 #include "gimpimage-undo-push.h"
35 #include "gimplayer.h"
36 #include "gimplayer-floating-selection.h"
37
38 #include "gimp-intl.h"
39
40
41 #define CHANNEL_WAS_ACTIVE (0x2)
42
43
44 /* public functions */
45
46 void
gimp_image_set_quick_mask_state(GimpImage * image,gboolean active)47 gimp_image_set_quick_mask_state (GimpImage *image,
48 gboolean active)
49 {
50 GimpImagePrivate *private;
51 GimpChannel *selection;
52 GimpChannel *mask;
53 gboolean channel_was_active;
54
55 g_return_if_fail (GIMP_IS_IMAGE (image));
56
57 if (active == gimp_image_get_quick_mask_state (image))
58 return;
59
60 private = GIMP_IMAGE_GET_PRIVATE (image);
61
62 /* Keep track of the state so that we can make the right drawable
63 * active again when deactiviting quick mask (see bug #134371).
64 */
65 if (private->quick_mask_state)
66 channel_was_active = (private->quick_mask_state & CHANNEL_WAS_ACTIVE) != 0;
67 else
68 channel_was_active = gimp_image_get_active_channel (image) != NULL;
69
70 /* Set private->quick_mask_state early so we can return early when
71 * being called recursively.
72 */
73 private->quick_mask_state = (active
74 ? TRUE | (channel_was_active ?
75 CHANNEL_WAS_ACTIVE : 0)
76 : FALSE);
77
78 selection = gimp_image_get_mask (image);
79 mask = gimp_image_get_quick_mask (image);
80
81 if (active)
82 {
83 if (! mask)
84 {
85 GimpLayer *floating_sel;
86
87 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK,
88 C_("undo-type", "Enable Quick Mask"));
89
90 floating_sel = gimp_image_get_floating_selection (image);
91
92 if (floating_sel)
93 floating_sel_to_layer (floating_sel, NULL);
94
95 mask = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (selection),
96 GIMP_TYPE_CHANNEL));
97
98 if (! gimp_channel_is_empty (selection))
99 gimp_channel_clear (selection, NULL, TRUE);
100
101 gimp_channel_set_color (mask, &private->quick_mask_color, FALSE);
102 gimp_item_rename (GIMP_ITEM (mask), GIMP_IMAGE_QUICK_MASK_NAME,
103 NULL);
104
105 if (private->quick_mask_inverted)
106 gimp_channel_invert (mask, FALSE);
107
108 gimp_image_add_channel (image, mask, NULL, 0, TRUE);
109
110 gimp_image_undo_group_end (image);
111 }
112 }
113 else
114 {
115 if (mask)
116 {
117 GimpLayer *floating_sel = gimp_image_get_floating_selection (image);
118
119 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK,
120 C_("undo-type", "Disable Quick Mask"));
121
122 if (private->quick_mask_inverted)
123 gimp_channel_invert (mask, TRUE);
124
125 if (floating_sel &&
126 gimp_layer_get_floating_sel_drawable (floating_sel) == GIMP_DRAWABLE (mask))
127 floating_sel_anchor (floating_sel);
128
129 gimp_item_to_selection (GIMP_ITEM (mask),
130 GIMP_CHANNEL_OP_REPLACE,
131 TRUE, FALSE, 0.0, 0.0);
132 gimp_image_remove_channel (image, mask, TRUE, NULL);
133
134 if (! channel_was_active)
135 gimp_image_unset_active_channel (image);
136
137 gimp_image_undo_group_end (image);
138 }
139 }
140
141 gimp_image_quick_mask_changed (image);
142 }
143
144 gboolean
gimp_image_get_quick_mask_state(GimpImage * image)145 gimp_image_get_quick_mask_state (GimpImage *image)
146 {
147 g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
148
149 return GIMP_IMAGE_GET_PRIVATE (image)->quick_mask_state;
150 }
151
152 void
gimp_image_set_quick_mask_color(GimpImage * image,const GimpRGB * color)153 gimp_image_set_quick_mask_color (GimpImage *image,
154 const GimpRGB *color)
155 {
156 GimpChannel *quick_mask;
157
158 g_return_if_fail (GIMP_IS_IMAGE (image));
159 g_return_if_fail (color != NULL);
160
161 GIMP_IMAGE_GET_PRIVATE (image)->quick_mask_color = *color;
162
163 quick_mask = gimp_image_get_quick_mask (image);
164 if (quick_mask)
165 gimp_channel_set_color (quick_mask, color, TRUE);
166 }
167
168 void
gimp_image_get_quick_mask_color(GimpImage * image,GimpRGB * color)169 gimp_image_get_quick_mask_color (GimpImage *image,
170 GimpRGB *color)
171 {
172 g_return_if_fail (GIMP_IS_IMAGE (image));
173 g_return_if_fail (color != NULL);
174
175 *color = GIMP_IMAGE_GET_PRIVATE (image)->quick_mask_color;
176 }
177
178 GimpChannel *
gimp_image_get_quick_mask(GimpImage * image)179 gimp_image_get_quick_mask (GimpImage *image)
180 {
181 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
182
183 return gimp_image_get_channel_by_name (image, GIMP_IMAGE_QUICK_MASK_NAME);
184 }
185
186 void
gimp_image_quick_mask_invert(GimpImage * image)187 gimp_image_quick_mask_invert (GimpImage *image)
188 {
189 GimpImagePrivate *private;
190
191 g_return_if_fail (GIMP_IS_IMAGE (image));
192
193 private = GIMP_IMAGE_GET_PRIVATE (image);
194
195 if (private->quick_mask_state)
196 {
197 GimpChannel *quick_mask = gimp_image_get_quick_mask (image);
198
199 if (quick_mask)
200 gimp_channel_invert (quick_mask, TRUE);
201 }
202
203 private->quick_mask_inverted = ! private->quick_mask_inverted;
204 }
205
206 gboolean
gimp_image_get_quick_mask_inverted(GimpImage * image)207 gimp_image_get_quick_mask_inverted (GimpImage *image)
208 {
209 g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
210
211 return GIMP_IMAGE_GET_PRIVATE (image)->quick_mask_inverted;
212 }
213