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 <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpcolor/gimpcolor.h"
24 #include "libgimpmath/gimpmath.h"
25 #include "libgimpwidgets/gimpwidgets.h"
26
27 #include "widgets-types.h"
28
29 #include "config/gimpcoreconfig.h"
30
31 #include "core/gimp.h"
32 #include "core/gimpchannel-select.h"
33 #include "core/gimpcontainer.h"
34 #include "core/gimpimage.h"
35 #include "core/gimpimage-pick-color.h"
36 #include "core/gimpselection.h"
37 #include "core/gimptoolinfo.h"
38
39 /* FIXME: #include "tools/tools-types.h" */
40 #include "tools/tools-types.h"
41 #include "tools/gimpregionselectoptions.h"
42
43 #include "gimpselectioneditor.h"
44 #include "gimpdnd.h"
45 #include "gimpdocked.h"
46 #include "gimpmenufactory.h"
47 #include "gimpview.h"
48 #include "gimpviewrenderer.h"
49 #include "gimpwidgets-utils.h"
50
51 #include "gimp-intl.h"
52
53
54 static void gimp_selection_editor_docked_iface_init (GimpDockedInterface *iface);
55
56 static void gimp_selection_editor_constructed (GObject *object);
57
58 static void gimp_selection_editor_set_image (GimpImageEditor *editor,
59 GimpImage *image);
60
61 static void gimp_selection_editor_set_context (GimpDocked *docked,
62 GimpContext *context);
63
64 static gboolean gimp_selection_view_button_press (GtkWidget *widget,
65 GdkEventButton *bevent,
66 GimpSelectionEditor *editor);
67 static void gimp_selection_editor_drop_color (GtkWidget *widget,
68 gint x,
69 gint y,
70 const GimpRGB *color,
71 gpointer data);
72
73 static void gimp_selection_editor_mask_changed (GimpImage *image,
74 GimpSelectionEditor *editor);
75
76
77 G_DEFINE_TYPE_WITH_CODE (GimpSelectionEditor, gimp_selection_editor,
78 GIMP_TYPE_IMAGE_EDITOR,
79 G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
80 gimp_selection_editor_docked_iface_init))
81
82 #define parent_class gimp_selection_editor_parent_class
83
84 static GimpDockedInterface *parent_docked_iface = NULL;
85
86
87 static void
gimp_selection_editor_class_init(GimpSelectionEditorClass * klass)88 gimp_selection_editor_class_init (GimpSelectionEditorClass *klass)
89 {
90 GObjectClass *object_class = G_OBJECT_CLASS (klass);
91 GimpImageEditorClass *image_editor_class = GIMP_IMAGE_EDITOR_CLASS (klass);
92
93 object_class->constructed = gimp_selection_editor_constructed;
94
95 image_editor_class->set_image = gimp_selection_editor_set_image;
96 }
97
98 static void
gimp_selection_editor_docked_iface_init(GimpDockedInterface * iface)99 gimp_selection_editor_docked_iface_init (GimpDockedInterface *iface)
100 {
101 parent_docked_iface = g_type_interface_peek_parent (iface);
102
103 if (! parent_docked_iface)
104 parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
105
106 iface->set_context = gimp_selection_editor_set_context;
107 }
108
109 static void
gimp_selection_editor_init(GimpSelectionEditor * editor)110 gimp_selection_editor_init (GimpSelectionEditor *editor)
111 {
112 GtkWidget *frame;
113
114 frame = gtk_frame_new (NULL);
115 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
116 gtk_box_pack_start (GTK_BOX (editor), frame, TRUE, TRUE, 0);
117 gtk_widget_show (frame);
118
119 editor->view = gimp_view_new_by_types (NULL,
120 GIMP_TYPE_VIEW,
121 GIMP_TYPE_SELECTION,
122 GIMP_VIEW_SIZE_HUGE,
123 0, TRUE);
124 gimp_view_renderer_set_background (GIMP_VIEW (editor->view)->renderer,
125 GIMP_ICON_TEXTURE);
126 gtk_widget_set_size_request (editor->view,
127 GIMP_VIEW_SIZE_HUGE, GIMP_VIEW_SIZE_HUGE);
128 gimp_view_set_expand (GIMP_VIEW (editor->view), TRUE);
129 gtk_container_add (GTK_CONTAINER (frame), editor->view);
130 gtk_widget_show (editor->view);
131
132 g_signal_connect (editor->view, "button-press-event",
133 G_CALLBACK (gimp_selection_view_button_press),
134 editor);
135
136 gimp_dnd_color_dest_add (editor->view,
137 gimp_selection_editor_drop_color,
138 editor);
139
140 gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE);
141 }
142
143 static void
gimp_selection_editor_constructed(GObject * object)144 gimp_selection_editor_constructed (GObject *object)
145 {
146 GimpSelectionEditor *editor = GIMP_SELECTION_EDITOR (object);
147
148 G_OBJECT_CLASS (parent_class)->constructed (object);
149
150 editor->all_button =
151 gimp_editor_add_action_button (GIMP_EDITOR (editor), "select",
152 "select-all", NULL);
153
154 editor->none_button =
155 gimp_editor_add_action_button (GIMP_EDITOR (editor), "select",
156 "select-none", NULL);
157
158 editor->invert_button =
159 gimp_editor_add_action_button (GIMP_EDITOR (editor), "select",
160 "select-invert", NULL);
161
162 editor->save_button =
163 gimp_editor_add_action_button (GIMP_EDITOR (editor), "select",
164 "select-save", NULL);
165
166 editor->path_button =
167 gimp_editor_add_action_button (GIMP_EDITOR (editor), "vectors",
168 "vectors-selection-to-vectors",
169 "vectors-selection-to-vectors-advanced",
170 GDK_SHIFT_MASK,
171 NULL);
172
173 editor->stroke_button =
174 gimp_editor_add_action_button (GIMP_EDITOR (editor), "select",
175 "select-stroke",
176 "select-stroke-last-values",
177 GDK_SHIFT_MASK,
178 NULL);
179 }
180
181 static void
gimp_selection_editor_set_image(GimpImageEditor * image_editor,GimpImage * image)182 gimp_selection_editor_set_image (GimpImageEditor *image_editor,
183 GimpImage *image)
184 {
185 GimpSelectionEditor *editor = GIMP_SELECTION_EDITOR (image_editor);
186
187 if (image_editor->image)
188 {
189 g_signal_handlers_disconnect_by_func (image_editor->image,
190 gimp_selection_editor_mask_changed,
191 editor);
192 }
193
194 GIMP_IMAGE_EDITOR_CLASS (parent_class)->set_image (image_editor, image);
195
196 if (image)
197 {
198 g_signal_connect (image, "mask-changed",
199 G_CALLBACK (gimp_selection_editor_mask_changed),
200 editor);
201
202 gimp_view_set_viewable (GIMP_VIEW (editor->view),
203 GIMP_VIEWABLE (gimp_image_get_mask (image)));
204 }
205 else
206 {
207 gimp_view_set_viewable (GIMP_VIEW (editor->view), NULL);
208 }
209 }
210
211 static void
gimp_selection_editor_set_context(GimpDocked * docked,GimpContext * context)212 gimp_selection_editor_set_context (GimpDocked *docked,
213 GimpContext *context)
214 {
215 GimpSelectionEditor *editor = GIMP_SELECTION_EDITOR (docked);
216
217 parent_docked_iface->set_context (docked, context);
218
219 gimp_view_renderer_set_context (GIMP_VIEW (editor->view)->renderer,
220 context);
221 }
222
223
224 /* public functions */
225
226 GtkWidget *
gimp_selection_editor_new(GimpMenuFactory * menu_factory)227 gimp_selection_editor_new (GimpMenuFactory *menu_factory)
228 {
229 g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
230
231 return g_object_new (GIMP_TYPE_SELECTION_EDITOR,
232 "menu-factory", menu_factory,
233 "menu-identifier", "<Selection>",
234 "ui-path", "/selection-popup",
235 NULL);
236 }
237
238 static gboolean
gimp_selection_view_button_press(GtkWidget * widget,GdkEventButton * bevent,GimpSelectionEditor * editor)239 gimp_selection_view_button_press (GtkWidget *widget,
240 GdkEventButton *bevent,
241 GimpSelectionEditor *editor)
242 {
243 GimpImageEditor *image_editor = GIMP_IMAGE_EDITOR (editor);
244 GimpViewRenderer *renderer;
245 GimpToolInfo *tool_info;
246 GimpSelectionOptions *sel_options;
247 GimpRegionSelectOptions *options;
248 GimpDrawable *drawable;
249 GimpChannelOps operation;
250 gint x, y;
251 GimpRGB color;
252
253 if (! image_editor->image)
254 return TRUE;
255
256 renderer = GIMP_VIEW (editor->view)->renderer;
257
258 tool_info = gimp_get_tool_info (image_editor->image->gimp,
259 "gimp-by-color-select-tool");
260
261 if (! tool_info)
262 return TRUE;
263
264 sel_options = GIMP_SELECTION_OPTIONS (tool_info->tool_options);
265 options = GIMP_REGION_SELECT_OPTIONS (tool_info->tool_options);
266
267 drawable = gimp_image_get_active_drawable (image_editor->image);
268
269 if (! drawable)
270 return TRUE;
271
272 operation = gimp_modifiers_to_channel_op (bevent->state);
273
274 x = gimp_image_get_width (image_editor->image) * bevent->x / renderer->width;
275 y = gimp_image_get_height (image_editor->image) * bevent->y / renderer->height;
276
277 if (gimp_image_pick_color (image_editor->image, drawable, x, y,
278 FALSE, options->sample_merged,
279 FALSE, 0.0,
280 NULL,
281 NULL, &color))
282 {
283 gimp_channel_select_by_color (gimp_image_get_mask (image_editor->image),
284 drawable,
285 options->sample_merged,
286 &color,
287 options->threshold,
288 options->select_transparent,
289 options->select_criterion,
290 operation,
291 sel_options->antialias,
292 sel_options->feather,
293 sel_options->feather_radius,
294 sel_options->feather_radius);
295 gimp_image_flush (image_editor->image);
296 }
297
298 return TRUE;
299 }
300
301 static void
gimp_selection_editor_drop_color(GtkWidget * widget,gint x,gint y,const GimpRGB * color,gpointer data)302 gimp_selection_editor_drop_color (GtkWidget *widget,
303 gint x,
304 gint y,
305 const GimpRGB *color,
306 gpointer data)
307 {
308 GimpImageEditor *editor = GIMP_IMAGE_EDITOR (data);
309 GimpToolInfo *tool_info;
310 GimpSelectionOptions *sel_options;
311 GimpRegionSelectOptions *options;
312 GimpDrawable *drawable;
313
314 if (! editor->image)
315 return;
316
317 tool_info = gimp_get_tool_info (editor->image->gimp,
318 "gimp-by-color-select-tool");
319 if (! tool_info)
320 return;
321
322 sel_options = GIMP_SELECTION_OPTIONS (tool_info->tool_options);
323 options = GIMP_REGION_SELECT_OPTIONS (tool_info->tool_options);
324
325 drawable = gimp_image_get_active_drawable (editor->image);
326
327 if (! drawable)
328 return;
329
330 gimp_channel_select_by_color (gimp_image_get_mask (editor->image),
331 drawable,
332 options->sample_merged,
333 color,
334 options->threshold,
335 options->select_transparent,
336 options->select_criterion,
337 sel_options->operation,
338 sel_options->antialias,
339 sel_options->feather,
340 sel_options->feather_radius,
341 sel_options->feather_radius);
342 gimp_image_flush (editor->image);
343 }
344
345 static void
gimp_selection_editor_mask_changed(GimpImage * image,GimpSelectionEditor * editor)346 gimp_selection_editor_mask_changed (GimpImage *image,
347 GimpSelectionEditor *editor)
348 {
349 gimp_view_renderer_invalidate (GIMP_VIEW (editor->view)->renderer);
350 }
351