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