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 <gdk-pixbuf/gdk-pixbuf.h>
21 #include <gegl.h>
22
23 #include "libgimpmath/gimpmath.h"
24
25 #include "core-types.h"
26
27 #include "gimpgrouplayer.h"
28 #include "gimpguide.h"
29 #include "gimpimage.h"
30 #include "gimpimage-pick-item.h"
31 #include "gimpimage-private.h"
32 #include "gimppickable.h"
33 #include "gimpsamplepoint.h"
34
35 #include "text/gimptextlayer.h"
36
37 #include "vectors/gimpstroke.h"
38 #include "vectors/gimpvectors.h"
39
40
41 GimpLayer *
gimp_image_pick_layer(GimpImage * image,gint x,gint y,GimpLayer * previously_picked)42 gimp_image_pick_layer (GimpImage *image,
43 gint x,
44 gint y,
45 GimpLayer *previously_picked)
46 {
47 GList *all_layers;
48 GList *list;
49 gint off_x, off_y;
50 gint tries = 1;
51
52 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
53
54 all_layers = gimp_image_get_layer_list (image);
55
56 if (previously_picked)
57 {
58 gimp_item_get_offset (GIMP_ITEM (previously_picked), &off_x, &off_y);
59 if (gimp_pickable_get_opacity_at (GIMP_PICKABLE (previously_picked),
60 x - off_x, y - off_y) <= 0.25)
61 previously_picked = NULL;
62 else
63 tries++;
64 }
65
66 while (tries)
67 {
68 for (list = all_layers; list; list = g_list_next (list))
69 {
70 GimpLayer *layer = list->data;
71
72 if (previously_picked)
73 {
74 /* Take the first layer with a pixel at given coordinates
75 * after the previously picked one.
76 */
77 if (layer == previously_picked)
78 previously_picked = NULL;
79 continue;
80 }
81
82 gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
83
84 if (gimp_pickable_get_opacity_at (GIMP_PICKABLE (layer),
85 x - off_x, y - off_y) > 0.25)
86 {
87 g_list_free (all_layers);
88
89 return layer;
90 }
91 }
92 tries--;
93 }
94
95 g_list_free (all_layers);
96
97 return NULL;
98 }
99
100 GimpLayer *
gimp_image_pick_layer_by_bounds(GimpImage * image,gint x,gint y)101 gimp_image_pick_layer_by_bounds (GimpImage *image,
102 gint x,
103 gint y)
104 {
105 GList *all_layers;
106 GList *list;
107
108 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
109
110 all_layers = gimp_image_get_layer_list (image);
111
112 for (list = all_layers; list; list = g_list_next (list))
113 {
114 GimpLayer *layer = list->data;
115
116 if (gimp_item_is_visible (GIMP_ITEM (layer)))
117 {
118 gint off_x, off_y;
119 gint width, height;
120
121 gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
122 width = gimp_item_get_width (GIMP_ITEM (layer));
123 height = gimp_item_get_height (GIMP_ITEM (layer));
124
125 if (x >= off_x &&
126 y >= off_y &&
127 x < off_x + width &&
128 y < off_y + height)
129 {
130 g_list_free (all_layers);
131
132 return layer;
133 }
134 }
135 }
136
137 g_list_free (all_layers);
138
139 return NULL;
140 }
141
142 GimpTextLayer *
gimp_image_pick_text_layer(GimpImage * image,gint x,gint y)143 gimp_image_pick_text_layer (GimpImage *image,
144 gint x,
145 gint y)
146 {
147 GList *all_layers;
148 GList *list;
149
150 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
151
152 all_layers = gimp_image_get_layer_list (image);
153
154 for (list = all_layers; list; list = g_list_next (list))
155 {
156 GimpLayer *layer = list->data;
157 gint off_x, off_y;
158
159 gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
160
161 if (GIMP_IS_TEXT_LAYER (layer) &&
162 x >= off_x &&
163 y >= off_y &&
164 x < off_x + gimp_item_get_width (GIMP_ITEM (layer)) &&
165 y < off_y + gimp_item_get_height (GIMP_ITEM (layer)) &&
166 gimp_item_is_visible (GIMP_ITEM (layer)))
167 {
168 g_list_free (all_layers);
169
170 return GIMP_TEXT_LAYER (layer);
171 }
172 else if (gimp_pickable_get_opacity_at (GIMP_PICKABLE (layer),
173 x - off_x, y - off_y) > 0.25)
174 {
175 /* a normal layer covers any possible text layers below,
176 * bail out
177 */
178
179 break;
180 }
181 }
182
183 g_list_free (all_layers);
184
185 return NULL;
186 }
187
188 GimpVectors *
gimp_image_pick_vectors(GimpImage * image,gdouble x,gdouble y,gdouble epsilon_x,gdouble epsilon_y)189 gimp_image_pick_vectors (GimpImage *image,
190 gdouble x,
191 gdouble y,
192 gdouble epsilon_x,
193 gdouble epsilon_y)
194 {
195 GimpVectors *ret = NULL;
196 GList *all_vectors;
197 GList *list;
198 gdouble mindist = G_MAXDOUBLE;
199
200 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
201
202 all_vectors = gimp_image_get_vectors_list (image);
203
204 for (list = all_vectors; list; list = g_list_next (list))
205 {
206 GimpVectors *vectors = list->data;
207
208 if (gimp_item_is_visible (GIMP_ITEM (vectors)))
209 {
210 GimpStroke *stroke = NULL;
211 GimpCoords coords = GIMP_COORDS_DEFAULT_VALUES;
212
213 while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
214 {
215 gdouble dist;
216
217 coords.x = x;
218 coords.y = y;
219
220 dist = gimp_stroke_nearest_point_get (stroke, &coords, 1.0,
221 NULL, NULL, NULL, NULL);
222
223 if (dist >= 0.0 &&
224 dist < MIN (epsilon_y, mindist))
225 {
226 mindist = dist;
227 ret = vectors;
228 }
229 }
230 }
231 }
232
233 g_list_free (all_vectors);
234
235 return ret;
236 }
237
238 static GimpGuide *
gimp_image_pick_guide_internal(GimpImage * image,gdouble x,gdouble y,gdouble epsilon_x,gdouble epsilon_y,GimpOrientationType orientation)239 gimp_image_pick_guide_internal (GimpImage *image,
240 gdouble x,
241 gdouble y,
242 gdouble epsilon_x,
243 gdouble epsilon_y,
244 GimpOrientationType orientation)
245 {
246 GList *list;
247 GimpGuide *ret = NULL;
248 gdouble mindist = G_MAXDOUBLE;
249
250 for (list = GIMP_IMAGE_GET_PRIVATE (image)->guides;
251 list;
252 list = g_list_next (list))
253 {
254 GimpGuide *guide = list->data;
255 gint position = gimp_guide_get_position (guide);
256 gdouble dist;
257
258 switch (gimp_guide_get_orientation (guide))
259 {
260 case GIMP_ORIENTATION_HORIZONTAL:
261 if (orientation == GIMP_ORIENTATION_HORIZONTAL ||
262 orientation == GIMP_ORIENTATION_UNKNOWN)
263 {
264 dist = ABS (position - y);
265 if (dist < MIN (epsilon_y, mindist))
266 {
267 mindist = dist;
268 ret = guide;
269 }
270 }
271 break;
272
273 /* mindist always is in vertical resolution to make it comparable */
274 case GIMP_ORIENTATION_VERTICAL:
275 if (orientation == GIMP_ORIENTATION_VERTICAL ||
276 orientation == GIMP_ORIENTATION_UNKNOWN)
277 {
278 dist = ABS (position - x);
279 if (dist < MIN (epsilon_x, mindist / epsilon_y * epsilon_x))
280 {
281 mindist = dist * epsilon_y / epsilon_x;
282 ret = guide;
283 }
284 }
285 break;
286
287 default:
288 continue;
289 }
290 }
291
292 return ret;
293 }
294
295 GimpGuide *
gimp_image_pick_guide(GimpImage * image,gdouble x,gdouble y,gdouble epsilon_x,gdouble epsilon_y)296 gimp_image_pick_guide (GimpImage *image,
297 gdouble x,
298 gdouble y,
299 gdouble epsilon_x,
300 gdouble epsilon_y)
301 {
302 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
303 g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
304
305 return gimp_image_pick_guide_internal (image, x, y, epsilon_x, epsilon_y,
306 GIMP_ORIENTATION_UNKNOWN);
307 }
308
309 GList *
gimp_image_pick_guides(GimpImage * image,gdouble x,gdouble y,gdouble epsilon_x,gdouble epsilon_y)310 gimp_image_pick_guides (GimpImage *image,
311 gdouble x,
312 gdouble y,
313 gdouble epsilon_x,
314 gdouble epsilon_y)
315 {
316 GimpGuide *guide;
317 GList *result = NULL;
318
319 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
320 g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
321
322 guide = gimp_image_pick_guide_internal (image, x, y, epsilon_x, epsilon_y,
323 GIMP_ORIENTATION_HORIZONTAL);
324
325 if (guide)
326 result = g_list_append (result, guide);
327
328 guide = gimp_image_pick_guide_internal (image, x, y, epsilon_x, epsilon_y,
329 GIMP_ORIENTATION_VERTICAL);
330
331 if (guide)
332 result = g_list_append (result, guide);
333
334 return result;
335 }
336
337 GimpSamplePoint *
gimp_image_pick_sample_point(GimpImage * image,gdouble x,gdouble y,gdouble epsilon_x,gdouble epsilon_y)338 gimp_image_pick_sample_point (GimpImage *image,
339 gdouble x,
340 gdouble y,
341 gdouble epsilon_x,
342 gdouble epsilon_y)
343 {
344 GList *list;
345 GimpSamplePoint *ret = NULL;
346 gdouble mindist = G_MAXDOUBLE;
347
348 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
349 g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
350
351 if (x < 0 || x >= gimp_image_get_width (image) ||
352 y < 0 || y >= gimp_image_get_height (image))
353 {
354 return NULL;
355 }
356
357 for (list = GIMP_IMAGE_GET_PRIVATE (image)->sample_points;
358 list;
359 list = g_list_next (list))
360 {
361 GimpSamplePoint *sample_point = list->data;
362 gint sp_x;
363 gint sp_y;
364 gdouble dist;
365
366 gimp_sample_point_get_position (sample_point, &sp_x, &sp_y);
367
368 if (sp_x < 0 || sp_y < 0)
369 continue;
370
371 dist = hypot ((sp_x + 0.5) - x,
372 (sp_y + 0.5) - y);
373 if (dist < MIN (epsilon_y, mindist))
374 {
375 mindist = dist;
376 ret = sample_point;
377 }
378 }
379
380 return ret;
381 }
382