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 <stdlib.h>
21 #include <stdarg.h>
22
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 #include <gdk/gdkkeysyms.h>
26
27 #include "libgimpbase/gimpbase.h"
28 #include "libgimpmath/gimpmath.h"
29 #include "libgimpwidgets/gimpwidgets.h"
30
31 #include "tools-types.h"
32
33 #include "core/gimp.h"
34 #include "core/gimp-utils.h"
35 #include "core/gimpboundary.h"
36 #include "core/gimpgrouplayer.h"
37 #include "core/gimpimage.h"
38 #include "core/gimpimage-guides.h"
39 #include "core/gimpimage-item-list.h"
40 #include "core/gimpimage-undo.h"
41 #include "core/gimpitem-linked.h"
42 #include "core/gimplayer.h"
43 #include "core/gimplayermask.h"
44 #include "core/gimpprojection.h"
45 #include "core/gimpselection.h"
46 #include "core/gimpundostack.h"
47
48 #include "widgets/gimpwidgets-utils.h"
49
50 #include "display/gimpdisplay.h"
51 #include "display/gimpdisplayshell.h"
52 #include "display/gimpdisplayshell-appearance.h"
53 #include "display/gimpdisplayshell-selection.h"
54 #include "display/gimpdisplayshell-transform.h"
55
56 #include "gimpdrawtool.h"
57 #include "gimpeditselectiontool.h"
58 #include "gimptoolcontrol.h"
59 #include "gimptools-utils.h"
60 #include "tool_manager.h"
61
62 #include "gimp-intl.h"
63
64
65 #define ARROW_VELOCITY 25
66
67
68 typedef struct _GimpEditSelectionTool GimpEditSelectionTool;
69 typedef struct _GimpEditSelectionToolClass GimpEditSelectionToolClass;
70
71 struct _GimpEditSelectionTool
72 {
73 GimpDrawTool parent_instance;
74
75 gdouble start_x; /* Coords where button was pressed */
76 gdouble start_y;
77
78 gint last_x; /* Last x and y coords */
79 gint last_y;
80
81 gint current_x; /* Current x and y coords */
82 gint current_y;
83
84 gint cuml_x; /* Cumulative changes to x and y */
85 gint cuml_y;
86
87 gint sel_x; /* Bounding box of selection mask */
88 gint sel_y; /* Bounding box of selection mask */
89 gint sel_width;
90 gint sel_height;
91
92 gint num_segs_in; /* Num seg in selection boundary */
93 gint num_segs_out; /* Num seg in selection boundary */
94 GimpBoundSeg *segs_in; /* Pointer to the channel sel. segs */
95 GimpBoundSeg *segs_out; /* Pointer to the channel sel. segs */
96
97 gdouble center_x; /* Where to draw the mark of center */
98 gdouble center_y;
99
100 GimpTranslateMode edit_mode; /* Translate the mask or layer? */
101
102 GList *live_items; /* Items that are transformed live */
103 GList *delayed_items; /* Items that are transformed later */
104
105 gboolean first_move; /* Don't push undos after the first */
106
107 gboolean propagate_release;
108
109 gboolean constrain; /* Constrain the movement */
110
111 gdouble last_motion_x; /* Previous coords sent to _motion */
112 gdouble last_motion_y;
113 };
114
115 struct _GimpEditSelectionToolClass
116 {
117 GimpDrawToolClass parent_class;
118 };
119
120
121 static void gimp_edit_selection_tool_finalize (GObject *object);
122
123 static void gimp_edit_selection_tool_button_release (GimpTool *tool,
124 const GimpCoords *coords,
125 guint32 time,
126 GdkModifierType state,
127 GimpButtonReleaseType release_type,
128 GimpDisplay *display);
129 static void gimp_edit_selection_tool_motion (GimpTool *tool,
130 const GimpCoords *coords,
131 guint32 time,
132 GdkModifierType state,
133 GimpDisplay *display);
134 static void gimp_edit_selection_tool_active_modifier_key (GimpTool *tool,
135 GdkModifierType key,
136 gboolean press,
137 GdkModifierType state,
138 GimpDisplay *display);
139 static void gimp_edit_selection_tool_draw (GimpDrawTool *tool);
140
141 static GimpItem * gimp_edit_selection_tool_get_active_item (GimpEditSelectionTool *edit_select,
142 GimpImage *image);
143 static void gimp_edit_selection_tool_calc_coords (GimpEditSelectionTool *edit_select,
144 GimpImage *image,
145 gdouble x,
146 gdouble y);
147 static void gimp_edit_selection_tool_start_undo_group (GimpEditSelectionTool *edit_select,
148 GimpImage *image);
149
150
G_DEFINE_TYPE(GimpEditSelectionTool,gimp_edit_selection_tool,GIMP_TYPE_DRAW_TOOL)151 G_DEFINE_TYPE (GimpEditSelectionTool, gimp_edit_selection_tool,
152 GIMP_TYPE_DRAW_TOOL)
153
154 #define parent_class gimp_edit_selection_tool_parent_class
155
156
157 static void
158 gimp_edit_selection_tool_class_init (GimpEditSelectionToolClass *klass)
159 {
160 GObjectClass *object_class = G_OBJECT_CLASS (klass);
161 GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
162 GimpDrawToolClass *draw_class = GIMP_DRAW_TOOL_CLASS (klass);
163
164 object_class->finalize = gimp_edit_selection_tool_finalize;
165
166 tool_class->button_release = gimp_edit_selection_tool_button_release;
167 tool_class->motion = gimp_edit_selection_tool_motion;
168 tool_class->active_modifier_key = gimp_edit_selection_tool_active_modifier_key;
169
170 draw_class->draw = gimp_edit_selection_tool_draw;
171 }
172
173 static void
gimp_edit_selection_tool_init(GimpEditSelectionTool * edit_select)174 gimp_edit_selection_tool_init (GimpEditSelectionTool *edit_select)
175 {
176 GimpTool *tool = GIMP_TOOL (edit_select);
177
178 edit_select->first_move = TRUE;
179
180 gimp_tool_control_set_active_modifiers (tool->control,
181 GIMP_TOOL_ACTIVE_MODIFIERS_SEPARATE);
182 }
183
184 static void
gimp_edit_selection_tool_finalize(GObject * object)185 gimp_edit_selection_tool_finalize (GObject *object)
186 {
187 GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (object);
188
189 g_clear_pointer (&edit_select->segs_in, g_free);
190 edit_select->num_segs_in = 0;
191
192 g_clear_pointer (&edit_select->segs_out, g_free);
193 edit_select->num_segs_out = 0;
194
195 g_clear_pointer (&edit_select->live_items, g_list_free);
196 g_clear_pointer (&edit_select->delayed_items, g_list_free);
197
198 G_OBJECT_CLASS (parent_class)->finalize (object);
199 }
200
201 void
gimp_edit_selection_tool_start(GimpTool * parent_tool,GimpDisplay * display,const GimpCoords * coords,GimpTranslateMode edit_mode,gboolean propagate_release)202 gimp_edit_selection_tool_start (GimpTool *parent_tool,
203 GimpDisplay *display,
204 const GimpCoords *coords,
205 GimpTranslateMode edit_mode,
206 gboolean propagate_release)
207 {
208 GimpEditSelectionTool *edit_select;
209 GimpTool *tool;
210 GimpDisplayShell *shell;
211 GimpImage *image;
212 GimpItem *active_item;
213 GList *list;
214 gint off_x, off_y;
215
216 edit_select = g_object_new (GIMP_TYPE_EDIT_SELECTION_TOOL,
217 "tool-info", parent_tool->tool_info,
218 NULL);
219
220 edit_select->propagate_release = propagate_release;
221
222 tool = GIMP_TOOL (edit_select);
223
224 shell = gimp_display_get_shell (display);
225 image = gimp_display_get_image (display);
226
227 /* Make a check to see if it should be a floating selection translation */
228 if ((edit_mode == GIMP_TRANSLATE_MODE_MASK_TO_LAYER ||
229 edit_mode == GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER) &&
230 gimp_image_get_floating_selection (image))
231 {
232 edit_mode = GIMP_TRANSLATE_MODE_FLOATING_SEL;
233 }
234
235 if (edit_mode == GIMP_TRANSLATE_MODE_LAYER)
236 {
237 GimpLayer *layer = gimp_image_get_active_layer (image);
238
239 if (gimp_layer_is_floating_sel (layer))
240 edit_mode = GIMP_TRANSLATE_MODE_FLOATING_SEL;
241 }
242
243 edit_select->edit_mode = edit_mode;
244
245 gimp_edit_selection_tool_start_undo_group (edit_select, image);
246
247 /* Remember starting point for use in constrained movement */
248 edit_select->start_x = coords->x;
249 edit_select->start_y = coords->y;
250
251 active_item = gimp_edit_selection_tool_get_active_item (edit_select, image);
252
253 gimp_item_get_offset (active_item, &off_x, &off_y);
254
255 /* Manually set the last coords to the starting point */
256 edit_select->last_x = coords->x - off_x;
257 edit_select->last_y = coords->y - off_y;
258
259 edit_select->constrain = FALSE;
260
261 /* Find the active item's selection bounds */
262 {
263 GimpChannel *channel;
264 const GimpBoundSeg *segs_in;
265 const GimpBoundSeg *segs_out;
266
267 if (GIMP_IS_CHANNEL (active_item))
268 channel = GIMP_CHANNEL (active_item);
269 else
270 channel = gimp_image_get_mask (image);
271
272 gimp_channel_boundary (channel,
273 &segs_in, &segs_out,
274 &edit_select->num_segs_in,
275 &edit_select->num_segs_out,
276 0, 0, 0, 0);
277
278 edit_select->segs_in = g_memdup (segs_in,
279 edit_select->num_segs_in *
280 sizeof (GimpBoundSeg));
281
282 edit_select->segs_out = g_memdup (segs_out,
283 edit_select->num_segs_out *
284 sizeof (GimpBoundSeg));
285
286 if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_VECTORS)
287 {
288 edit_select->sel_x = 0;
289 edit_select->sel_y = 0;
290 edit_select->sel_width = gimp_image_get_width (image);
291 edit_select->sel_height = gimp_image_get_height (image);
292 }
293 else
294 {
295 /* find the bounding box of the selection mask - this is used
296 * for the case of a GIMP_TRANSLATE_MODE_MASK_TO_LAYER, where
297 * the translation will result in floating the selection mask
298 * and translating the resulting layer
299 */
300 gimp_item_mask_intersect (active_item,
301 &edit_select->sel_x,
302 &edit_select->sel_y,
303 &edit_select->sel_width,
304 &edit_select->sel_height);
305 }
306 }
307
308 gimp_edit_selection_tool_calc_coords (edit_select, image,
309 coords->x, coords->y);
310
311 {
312 gint x, y, w, h;
313
314 switch (edit_select->edit_mode)
315 {
316 case GIMP_TRANSLATE_MODE_CHANNEL:
317 case GIMP_TRANSLATE_MODE_MASK:
318 case GIMP_TRANSLATE_MODE_LAYER_MASK:
319 gimp_item_bounds (active_item, &x, &y, &w, &h);
320 x += off_x;
321 y += off_y;
322 break;
323
324 case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
325 case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
326 x = edit_select->sel_x + off_x;
327 y = edit_select->sel_y + off_y;
328 w = edit_select->sel_width;
329 h = edit_select->sel_height;
330 break;
331
332 case GIMP_TRANSLATE_MODE_LAYER:
333 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
334 case GIMP_TRANSLATE_MODE_VECTORS:
335 if (gimp_item_get_linked (active_item))
336 {
337 GList *linked;
338
339 linked = gimp_image_item_list_get_list (image,
340 GIMP_IS_LAYER (active_item) ?
341 GIMP_ITEM_TYPE_LAYERS :
342 GIMP_ITEM_TYPE_VECTORS,
343 GIMP_ITEM_SET_LINKED);
344 linked = gimp_image_item_list_filter (linked);
345
346 gimp_image_item_list_bounds (image, linked, &x, &y, &w, &h);
347
348 g_list_free (linked);
349 }
350 else
351 {
352 gimp_item_bounds (active_item, &x, &y, &w, &h);
353 x += off_x;
354 y += off_y;
355 }
356 break;
357 }
358
359 gimp_tool_control_set_snap_offsets (tool->control,
360 x - coords->x,
361 y - coords->y,
362 w, h);
363
364 /* Save where to draw the mark of the center */
365 edit_select->center_x = x + w / 2.0;
366 edit_select->center_y = y + h / 2.0;
367 }
368
369 if (gimp_item_get_linked (active_item))
370 {
371 switch (edit_select->edit_mode)
372 {
373 case GIMP_TRANSLATE_MODE_CHANNEL:
374 case GIMP_TRANSLATE_MODE_LAYER:
375 case GIMP_TRANSLATE_MODE_VECTORS:
376 edit_select->live_items =
377 gimp_image_item_list_get_list (image,
378 GIMP_ITEM_TYPE_LAYERS |
379 GIMP_ITEM_TYPE_VECTORS,
380 GIMP_ITEM_SET_LINKED);
381 edit_select->live_items =
382 gimp_image_item_list_filter (edit_select->live_items);
383
384 edit_select->delayed_items =
385 gimp_image_item_list_get_list (image,
386 GIMP_ITEM_TYPE_CHANNELS,
387 GIMP_ITEM_SET_LINKED);
388 edit_select->delayed_items =
389 gimp_image_item_list_filter (edit_select->delayed_items);
390 break;
391
392 default:
393 /* other stuff can't be linked so don't bother */
394 break;
395 }
396 }
397 else
398 {
399 switch (edit_select->edit_mode)
400 {
401 case GIMP_TRANSLATE_MODE_VECTORS:
402 case GIMP_TRANSLATE_MODE_LAYER:
403 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
404 edit_select->live_items = g_list_append (NULL, active_item);
405 break;
406
407 case GIMP_TRANSLATE_MODE_CHANNEL:
408 case GIMP_TRANSLATE_MODE_LAYER_MASK:
409 case GIMP_TRANSLATE_MODE_MASK:
410 edit_select->delayed_items = g_list_append (NULL, active_item);
411 break;
412
413 default:
414 /* MASK_TO_LAYER and MASK_COPY_TO_LAYER create a live_item later */
415 break;
416 }
417 }
418
419 for (list = edit_select->live_items; list; list = g_list_next (list))
420 {
421 GimpItem *item = list->data;
422
423 gimp_viewable_preview_freeze (GIMP_VIEWABLE (item));
424
425 gimp_item_start_transform (item, TRUE);
426 }
427
428 tool_manager_push_tool (display->gimp, tool);
429
430 gimp_tool_control_activate (tool->control);
431 tool->display = display;
432
433 /* pause the current selection */
434 gimp_display_shell_selection_pause (shell);
435
436 /* initialize the statusbar display */
437 gimp_tool_push_status_coords (tool, display,
438 gimp_tool_control_get_precision (tool->control),
439 _("Move: "), 0, ", ", 0, NULL);
440
441 gimp_draw_tool_start (GIMP_DRAW_TOOL (edit_select), display);
442 }
443
444
445 static void
gimp_edit_selection_tool_button_release(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonReleaseType release_type,GimpDisplay * display)446 gimp_edit_selection_tool_button_release (GimpTool *tool,
447 const GimpCoords *coords,
448 guint32 time,
449 GdkModifierType state,
450 GimpButtonReleaseType release_type,
451 GimpDisplay *display)
452 {
453 GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (tool);
454 GimpDisplayShell *shell = gimp_display_get_shell (display);
455 GimpImage *image = gimp_display_get_image (display);
456 GList *list;
457
458 /* resume the current selection */
459 gimp_display_shell_selection_resume (shell);
460
461 gimp_tool_pop_status (tool, display);
462
463 gimp_tool_control_halt (tool->control);
464
465 /* Stop and free the selection core */
466 gimp_draw_tool_stop (GIMP_DRAW_TOOL (edit_select));
467
468 tool_manager_pop_tool (display->gimp);
469
470 /* move the items -- whether there has been movement or not!
471 * (to ensure that there's something on the undo stack)
472 */
473 gimp_image_item_list_translate (image,
474 edit_select->delayed_items,
475 edit_select->cuml_x,
476 edit_select->cuml_y,
477 TRUE);
478
479 for (list = edit_select->live_items; list; list = g_list_next (list))
480 {
481 GimpItem *item = list->data;
482
483 gimp_item_end_transform (item, TRUE);
484
485 gimp_viewable_preview_thaw (GIMP_VIEWABLE (item));
486 }
487
488 gimp_image_undo_group_end (image);
489
490 if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
491 {
492 /* Operation cancelled - undo the undo-group! */
493 gimp_image_undo (image);
494 }
495
496 gimp_image_flush (image);
497
498 if (edit_select->propagate_release &&
499 tool_manager_get_active (display->gimp))
500 {
501 tool_manager_button_release_active (display->gimp,
502 coords, time, state,
503 display);
504 }
505
506 g_object_unref (edit_select);
507 }
508
509 static void
gimp_edit_selection_tool_update_motion(GimpEditSelectionTool * edit_select,gdouble new_x,gdouble new_y,GimpDisplay * display)510 gimp_edit_selection_tool_update_motion (GimpEditSelectionTool *edit_select,
511 gdouble new_x,
512 gdouble new_y,
513 GimpDisplay *display)
514 {
515 GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (edit_select);
516 GimpTool *tool = GIMP_TOOL (edit_select);
517 GimpImage *image = gimp_display_get_image (display);
518 gint dx;
519 gint dy;
520
521 gdk_flush ();
522
523 gimp_draw_tool_pause (draw_tool);
524
525 if (edit_select->constrain)
526 {
527 gimp_constrain_line (edit_select->start_x, edit_select->start_y,
528 &new_x, &new_y,
529 GIMP_CONSTRAIN_LINE_45_DEGREES, 0.0, 1.0, 1.0);
530 }
531
532 gimp_edit_selection_tool_calc_coords (edit_select, image,
533 new_x, new_y);
534
535 dx = edit_select->current_x - edit_select->last_x;
536 dy = edit_select->current_y - edit_select->last_y;
537
538 /* if there has been movement, move */
539 if (dx != 0 || dy != 0)
540 {
541 GimpItem *active_item;
542 GError *error = NULL;
543
544 active_item = gimp_edit_selection_tool_get_active_item (edit_select,
545 image);
546
547 edit_select->cuml_x += dx;
548 edit_select->cuml_y += dy;
549
550 switch (edit_select->edit_mode)
551 {
552 case GIMP_TRANSLATE_MODE_LAYER_MASK:
553 case GIMP_TRANSLATE_MODE_MASK:
554 case GIMP_TRANSLATE_MODE_VECTORS:
555 case GIMP_TRANSLATE_MODE_CHANNEL:
556 edit_select->last_x = edit_select->current_x;
557 edit_select->last_y = edit_select->current_y;
558
559 /* fallthru */
560
561 case GIMP_TRANSLATE_MODE_LAYER:
562 gimp_image_item_list_translate (image,
563 edit_select->live_items,
564 dx, dy,
565 edit_select->first_move);
566 break;
567
568 case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
569 case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
570 if (! gimp_selection_float (GIMP_SELECTION (gimp_image_get_mask (image)),
571 GIMP_DRAWABLE (active_item),
572 gimp_get_user_context (display->gimp),
573 edit_select->edit_mode ==
574 GIMP_TRANSLATE_MODE_MASK_TO_LAYER,
575 0, 0, &error))
576 {
577 /* no region to float, abort safely */
578 gimp_message_literal (display->gimp, G_OBJECT (display),
579 GIMP_MESSAGE_WARNING,
580 error->message);
581 g_clear_error (&error);
582 gimp_draw_tool_resume (draw_tool);
583
584 return;
585 }
586
587 edit_select->last_x -= edit_select->sel_x;
588 edit_select->last_y -= edit_select->sel_y;
589 edit_select->sel_x = 0;
590 edit_select->sel_y = 0;
591
592 edit_select->edit_mode = GIMP_TRANSLATE_MODE_FLOATING_SEL;
593
594 active_item = gimp_edit_selection_tool_get_active_item (edit_select,
595 image);
596
597 edit_select->live_items = g_list_prepend (NULL, active_item);
598
599 gimp_viewable_preview_freeze (GIMP_VIEWABLE (active_item));
600
601 gimp_item_start_transform (active_item, TRUE);
602
603 /* fallthru */
604
605 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
606 gimp_image_item_list_translate (image,
607 edit_select->live_items,
608 dx, dy,
609 edit_select->first_move);
610 break;
611 }
612
613 edit_select->first_move = FALSE;
614 }
615
616 gimp_projection_flush (gimp_image_get_projection (image));
617
618 gimp_tool_pop_status (tool, display);
619 gimp_tool_push_status_coords (tool, display,
620 gimp_tool_control_get_precision (tool->control),
621 _("Move: "),
622 edit_select->cuml_x,
623 ", ",
624 edit_select->cuml_y,
625 NULL);
626
627 gimp_draw_tool_resume (draw_tool);
628 }
629
630
631 static void
gimp_edit_selection_tool_motion(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpDisplay * display)632 gimp_edit_selection_tool_motion (GimpTool *tool,
633 const GimpCoords *coords,
634 guint32 time,
635 GdkModifierType state,
636 GimpDisplay *display)
637 {
638 GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (tool);
639
640 edit_select->last_motion_x = coords->x;
641 edit_select->last_motion_y = coords->y;
642
643 gimp_edit_selection_tool_update_motion (edit_select,
644 coords->x, coords->y,
645 display);
646 }
647
648 static void
gimp_edit_selection_tool_active_modifier_key(GimpTool * tool,GdkModifierType key,gboolean press,GdkModifierType state,GimpDisplay * display)649 gimp_edit_selection_tool_active_modifier_key (GimpTool *tool,
650 GdkModifierType key,
651 gboolean press,
652 GdkModifierType state,
653 GimpDisplay *display)
654 {
655 GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (tool);
656
657 edit_select->constrain = (state & gimp_get_constrain_behavior_mask () ?
658 TRUE : FALSE);
659
660 /* If we didn't came here due to a mouse release, immediately update
661 * the position of the thing we move.
662 */
663 if (state & GDK_BUTTON1_MASK)
664 {
665 gimp_edit_selection_tool_update_motion (edit_select,
666 edit_select->last_motion_x,
667 edit_select->last_motion_y,
668 display);
669 }
670 }
671
672 static void
gimp_edit_selection_tool_draw(GimpDrawTool * draw_tool)673 gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
674 {
675 GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (draw_tool);
676 GimpDisplay *display = GIMP_TOOL (draw_tool)->display;
677 GimpImage *image = gimp_display_get_image (display);
678 GimpItem *active_item;
679 gint off_x;
680 gint off_y;
681
682 active_item = gimp_edit_selection_tool_get_active_item (edit_select, image);
683
684 gimp_item_get_offset (active_item, &off_x, &off_y);
685
686 switch (edit_select->edit_mode)
687 {
688 case GIMP_TRANSLATE_MODE_CHANNEL:
689 case GIMP_TRANSLATE_MODE_LAYER_MASK:
690 case GIMP_TRANSLATE_MODE_MASK:
691 {
692 gboolean floating_sel = FALSE;
693
694 if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_MASK)
695 {
696 GimpLayer *layer = gimp_image_get_active_layer (image);
697
698 if (layer)
699 floating_sel = gimp_layer_is_floating_sel (layer);
700 }
701
702 if (! floating_sel && edit_select->segs_in)
703 {
704 gimp_draw_tool_add_boundary (draw_tool,
705 edit_select->segs_in,
706 edit_select->num_segs_in,
707 NULL,
708 edit_select->cuml_x + off_x,
709 edit_select->cuml_y + off_y);
710 }
711
712 if (edit_select->segs_out)
713 {
714 gimp_draw_tool_add_boundary (draw_tool,
715 edit_select->segs_out,
716 edit_select->num_segs_out,
717 NULL,
718 edit_select->cuml_x + off_x,
719 edit_select->cuml_y + off_y);
720 }
721 else if (edit_select->edit_mode != GIMP_TRANSLATE_MODE_MASK)
722 {
723 gimp_draw_tool_add_rectangle (draw_tool,
724 FALSE,
725 edit_select->cuml_x + off_x,
726 edit_select->cuml_y + off_y,
727 gimp_item_get_width (active_item),
728 gimp_item_get_height (active_item));
729 }
730 }
731 break;
732
733 case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
734 case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
735 gimp_draw_tool_add_rectangle (draw_tool,
736 FALSE,
737 edit_select->sel_x + off_x,
738 edit_select->sel_y + off_y,
739 edit_select->sel_width,
740 edit_select->sel_height);
741 break;
742
743 case GIMP_TRANSLATE_MODE_LAYER:
744 case GIMP_TRANSLATE_MODE_VECTORS:
745 {
746 gint x, y, w, h;
747
748 if (gimp_item_get_linked (active_item))
749 {
750 GList *linked;
751
752 linked = gimp_image_item_list_get_list (image,
753 GIMP_IS_LAYER (active_item) ?
754 GIMP_ITEM_TYPE_LAYERS :
755 GIMP_ITEM_TYPE_VECTORS,
756 GIMP_ITEM_SET_LINKED);
757 linked = gimp_image_item_list_filter (linked);
758
759 gimp_image_item_list_bounds (image, linked, &x, &y, &w, &h);
760
761 g_list_free (linked);
762 }
763 else
764 {
765 gimp_item_bounds (active_item, &x, &y, &w, &h);
766 x += off_x;
767 y += off_y;
768 }
769
770 gimp_draw_tool_add_rectangle (draw_tool, FALSE,
771 x, y, w, h);
772 }
773 break;
774
775 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
776 if (edit_select->segs_in)
777 {
778 gimp_draw_tool_add_boundary (draw_tool,
779 edit_select->segs_in,
780 edit_select->num_segs_in,
781 NULL,
782 edit_select->cuml_x,
783 edit_select->cuml_y);
784 }
785 break;
786 }
787
788 /* Mark the center because we snap to it */
789 gimp_draw_tool_add_handle (draw_tool,
790 GIMP_HANDLE_CROSS,
791 edit_select->center_x + edit_select->cuml_x,
792 edit_select->center_y + edit_select->cuml_y,
793 GIMP_TOOL_HANDLE_SIZE_SMALL,
794 GIMP_TOOL_HANDLE_SIZE_SMALL,
795 GIMP_HANDLE_ANCHOR_CENTER);
796
797 GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
798 }
799
800 static GimpItem *
gimp_edit_selection_tool_get_active_item(GimpEditSelectionTool * edit_select,GimpImage * image)801 gimp_edit_selection_tool_get_active_item (GimpEditSelectionTool *edit_select,
802 GimpImage *image)
803 {
804 GimpItem *active_item;
805
806 switch (edit_select->edit_mode)
807 {
808 case GIMP_TRANSLATE_MODE_VECTORS:
809 active_item = GIMP_ITEM (gimp_image_get_active_vectors (image));
810 break;
811
812 case GIMP_TRANSLATE_MODE_LAYER:
813 active_item = GIMP_ITEM (gimp_image_get_active_layer (image));
814 break;
815
816 case GIMP_TRANSLATE_MODE_MASK:
817 active_item = GIMP_ITEM (gimp_image_get_mask (image));
818 break;
819
820 default:
821 active_item = GIMP_ITEM (gimp_image_get_active_drawable (image));
822 break;
823 }
824
825 return active_item;
826 }
827
828 static void
gimp_edit_selection_tool_calc_coords(GimpEditSelectionTool * edit_select,GimpImage * image,gdouble x,gdouble y)829 gimp_edit_selection_tool_calc_coords (GimpEditSelectionTool *edit_select,
830 GimpImage *image,
831 gdouble x,
832 gdouble y)
833 {
834 GimpItem *active_item;
835 gint off_x, off_y;
836 gdouble x1, y1;
837 gdouble dx, dy;
838
839 active_item = gimp_edit_selection_tool_get_active_item (edit_select, image);
840
841 gimp_item_get_offset (active_item, &off_x, &off_y);
842
843 dx = (x - off_x) - edit_select->last_x;
844 dy = (y - off_y) - edit_select->last_y;
845
846 x1 = edit_select->sel_x + dx;
847 y1 = edit_select->sel_y + dy;
848
849 edit_select->current_x = ((gint) floor (x1) -
850 (edit_select->sel_x - edit_select->last_x));
851 edit_select->current_y = ((gint) floor (y1) -
852 (edit_select->sel_y - edit_select->last_y));
853 }
854
855 static void
gimp_edit_selection_tool_start_undo_group(GimpEditSelectionTool * edit_select,GimpImage * image)856 gimp_edit_selection_tool_start_undo_group (GimpEditSelectionTool *edit_select,
857 GimpImage *image)
858 {
859 GimpItem *active_item;
860 const gchar *undo_desc = NULL;
861
862 active_item = gimp_edit_selection_tool_get_active_item (edit_select, image);
863
864 switch (edit_select->edit_mode)
865 {
866 case GIMP_TRANSLATE_MODE_VECTORS:
867 case GIMP_TRANSLATE_MODE_CHANNEL:
868 case GIMP_TRANSLATE_MODE_LAYER_MASK:
869 case GIMP_TRANSLATE_MODE_MASK:
870 case GIMP_TRANSLATE_MODE_LAYER:
871 undo_desc = GIMP_ITEM_GET_CLASS (active_item)->translate_desc;
872 break;
873
874 case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
875 case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
876 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
877 undo_desc = _("Move Floating Selection");
878 break;
879
880 default:
881 g_return_if_reached ();
882 }
883
884 gimp_image_undo_group_start (image,
885 edit_select->edit_mode ==
886 GIMP_TRANSLATE_MODE_MASK ?
887 GIMP_UNDO_GROUP_MASK :
888 GIMP_UNDO_GROUP_ITEM_DISPLACE,
889 undo_desc);
890 }
891
892 static gint
process_event_queue_keys(GdkEventKey * kevent,...)893 process_event_queue_keys (GdkEventKey *kevent,
894 ... /* GdkKeyType, GdkModifierType, value ... 0 */)
895 {
896
897 #define FILTER_MAX_KEYS 50
898
899 va_list argp;
900 GdkEvent *event;
901 GList *event_list = NULL;
902 GList *list;
903 guint keys[FILTER_MAX_KEYS];
904 GdkModifierType modifiers[FILTER_MAX_KEYS];
905 gint values[FILTER_MAX_KEYS];
906 gint i = 0;
907 gint n_keys = 0;
908 gint value = 0;
909 gboolean done = FALSE;
910 GtkWidget *orig_widget;
911
912 va_start (argp, kevent);
913
914 while (n_keys < FILTER_MAX_KEYS &&
915 (keys[n_keys] = va_arg (argp, guint)) != 0)
916 {
917 modifiers[n_keys] = va_arg (argp, GdkModifierType);
918 values[n_keys] = va_arg (argp, gint);
919 n_keys++;
920 }
921
922 va_end (argp);
923
924 for (i = 0; i < n_keys; i++)
925 if (kevent->keyval == keys[i] &&
926 (kevent->state & modifiers[i]) == modifiers[i])
927 value += values[i];
928
929 orig_widget = gtk_get_event_widget ((GdkEvent *) kevent);
930
931 while (gdk_events_pending () > 0 && ! done)
932 {
933 gboolean discard_event = FALSE;
934
935 event = gdk_event_get ();
936
937 if (! event || orig_widget != gtk_get_event_widget (event))
938 {
939 done = TRUE;
940 }
941 else
942 {
943 if (event->any.type == GDK_KEY_PRESS)
944 {
945 for (i = 0; i < n_keys; i++)
946 if (event->key.keyval == keys[i] &&
947 (event->key.state & modifiers[i]) == modifiers[i])
948 {
949 discard_event = TRUE;
950 value += values[i];
951 }
952
953 if (! discard_event)
954 done = TRUE;
955 }
956 /* should there be more types here? */
957 else if (event->any.type != GDK_KEY_RELEASE &&
958 event->any.type != GDK_MOTION_NOTIFY &&
959 event->any.type != GDK_EXPOSE)
960 done = FALSE;
961 }
962
963 if (! event)
964 ; /* Do nothing */
965 else if (! discard_event)
966 event_list = g_list_prepend (event_list, event);
967 else
968 gdk_event_free (event);
969 }
970
971 event_list = g_list_reverse (event_list);
972
973 /* unget the unused events and free the list */
974 for (list = event_list; list; list = g_list_next (list))
975 {
976 gdk_event_put ((GdkEvent *) list->data);
977 gdk_event_free ((GdkEvent *) list->data);
978 }
979
980 g_list_free (event_list);
981
982 return value;
983
984 #undef FILTER_MAX_KEYS
985 }
986
987 gboolean
gimp_edit_selection_tool_key_press(GimpTool * tool,GdkEventKey * kevent,GimpDisplay * display)988 gimp_edit_selection_tool_key_press (GimpTool *tool,
989 GdkEventKey *kevent,
990 GimpDisplay *display)
991 {
992 GimpTransformType translate_type;
993
994 if (kevent->state & GDK_MOD1_MASK)
995 {
996 translate_type = GIMP_TRANSFORM_TYPE_SELECTION;
997 }
998 else if (kevent->state & gimp_get_toggle_behavior_mask ())
999 {
1000 translate_type = GIMP_TRANSFORM_TYPE_PATH;
1001 }
1002 else
1003 {
1004 translate_type = GIMP_TRANSFORM_TYPE_LAYER;
1005 }
1006
1007 return gimp_edit_selection_tool_translate (tool, kevent, translate_type,
1008 display, NULL);
1009 }
1010
1011 gboolean
gimp_edit_selection_tool_translate(GimpTool * tool,GdkEventKey * kevent,GimpTransformType translate_type,GimpDisplay * display,GtkWidget * type_box)1012 gimp_edit_selection_tool_translate (GimpTool *tool,
1013 GdkEventKey *kevent,
1014 GimpTransformType translate_type,
1015 GimpDisplay *display,
1016 GtkWidget *type_box)
1017 {
1018 gint inc_x = 0;
1019 gint inc_y = 0;
1020 GimpUndo *undo;
1021 gboolean push_undo = TRUE;
1022 GimpImage *image = gimp_display_get_image (display);
1023 GimpItem *item = NULL;
1024 GimpTranslateMode edit_mode = GIMP_TRANSLATE_MODE_MASK;
1025 GimpUndoType undo_type = GIMP_UNDO_GROUP_MASK;
1026 const gchar *undo_desc = NULL;
1027 GdkModifierType extend_mask = gimp_get_extend_selection_mask ();
1028 const gchar *null_message = NULL;
1029 const gchar *locked_message = NULL;
1030 gint velocity;
1031
1032 /* bail out early if it is not an arrow key event */
1033
1034 if (kevent->keyval != GDK_KEY_Left &&
1035 kevent->keyval != GDK_KEY_Right &&
1036 kevent->keyval != GDK_KEY_Up &&
1037 kevent->keyval != GDK_KEY_Down)
1038 return FALSE;
1039
1040 /* adapt arrow velocity to the zoom factor when holding <shift> */
1041 velocity = (ARROW_VELOCITY /
1042 gimp_zoom_model_get_factor (gimp_display_get_shell (display)->zoom));
1043 velocity = MAX (1.0, velocity);
1044
1045 /* check the event queue for key events with the same modifier mask
1046 * as the current event, allowing only extend_mask to vary between
1047 * them.
1048 */
1049 inc_x = process_event_queue_keys (kevent,
1050 GDK_KEY_Left,
1051 kevent->state | extend_mask,
1052 -1 * velocity,
1053
1054 GDK_KEY_Left,
1055 kevent->state & ~extend_mask,
1056 -1,
1057
1058 GDK_KEY_Right,
1059 kevent->state | extend_mask,
1060 1 * velocity,
1061
1062 GDK_KEY_Right,
1063 kevent->state & ~extend_mask,
1064 1,
1065
1066 0);
1067
1068 inc_y = process_event_queue_keys (kevent,
1069 GDK_KEY_Up,
1070 kevent->state | extend_mask,
1071 -1 * velocity,
1072
1073 GDK_KEY_Up,
1074 kevent->state & ~extend_mask,
1075 -1,
1076
1077 GDK_KEY_Down,
1078 kevent->state | extend_mask,
1079 1 * velocity,
1080
1081 GDK_KEY_Down,
1082 kevent->state & ~extend_mask,
1083 1,
1084
1085 0);
1086
1087 switch (translate_type)
1088 {
1089 case GIMP_TRANSFORM_TYPE_SELECTION:
1090 item = GIMP_ITEM (gimp_image_get_mask (image));
1091
1092 if (gimp_channel_is_empty (GIMP_CHANNEL (item)))
1093 item = NULL;
1094
1095 edit_mode = GIMP_TRANSLATE_MODE_MASK;
1096 undo_type = GIMP_UNDO_GROUP_MASK;
1097
1098 if (! item)
1099 {
1100 /* cannot happen, don't translate this message */
1101 null_message = "There is no selection to move.";
1102 }
1103 else if (gimp_item_is_position_locked (item))
1104 {
1105 /* cannot happen, don't translate this message */
1106 locked_message = "The selection's position is locked.";
1107 }
1108 break;
1109
1110 case GIMP_TRANSFORM_TYPE_PATH:
1111 item = GIMP_ITEM (gimp_image_get_active_vectors (image));
1112
1113 edit_mode = GIMP_TRANSLATE_MODE_VECTORS;
1114 undo_type = GIMP_UNDO_GROUP_ITEM_DISPLACE;
1115
1116 if (! item)
1117 {
1118 null_message = _("There is no path to move.");
1119 }
1120 else if (gimp_item_is_position_locked (item))
1121 {
1122 locked_message = _("The active path's position is locked.");
1123 }
1124 break;
1125
1126 case GIMP_TRANSFORM_TYPE_LAYER:
1127 item = GIMP_ITEM (gimp_image_get_active_drawable (image));
1128
1129 undo_type = GIMP_UNDO_GROUP_ITEM_DISPLACE;
1130
1131 if (! item)
1132 {
1133 null_message = _("There is no layer to move.");
1134 }
1135 else if (GIMP_IS_LAYER_MASK (item))
1136 {
1137 edit_mode = GIMP_TRANSLATE_MODE_LAYER_MASK;
1138
1139 if (gimp_item_is_position_locked (item))
1140 {
1141 locked_message = _("The active layer's position is locked.");
1142 }
1143 else if (gimp_item_is_content_locked (item))
1144 {
1145 locked_message = _("The active layer's pixels are locked.");
1146 }
1147 }
1148 else if (GIMP_IS_CHANNEL (item))
1149 {
1150 edit_mode = GIMP_TRANSLATE_MODE_CHANNEL;
1151
1152 if (gimp_item_is_position_locked (item))
1153 {
1154 locked_message = _("The active channel's position is locked.");
1155 }
1156 else if (gimp_item_is_content_locked (item))
1157 {
1158 locked_message = _("The active channel's pixels are locked.");
1159 }
1160 }
1161 else if (gimp_layer_is_floating_sel (GIMP_LAYER (item)))
1162 {
1163 edit_mode = GIMP_TRANSLATE_MODE_FLOATING_SEL;
1164
1165 if (gimp_item_is_position_locked (item))
1166 {
1167 locked_message = _("The active layer's position is locked.");
1168 }
1169 }
1170 else
1171 {
1172 edit_mode = GIMP_TRANSLATE_MODE_LAYER;
1173
1174 if (gimp_item_is_position_locked (item))
1175 {
1176 locked_message = _("The active layer's position is locked.");
1177 }
1178 }
1179
1180 break;
1181
1182 case GIMP_TRANSFORM_TYPE_IMAGE:
1183 g_return_val_if_reached (FALSE);
1184 }
1185
1186 if (! item)
1187 {
1188 gimp_tool_message_literal (tool, display, null_message);
1189 if (type_box)
1190 gimp_widget_blink (type_box);
1191 return TRUE;
1192 }
1193 else if (locked_message)
1194 {
1195 gimp_tool_message_literal (tool, display, locked_message);
1196 gimp_tools_blink_lock_box (display->gimp, item);
1197 return TRUE;
1198 }
1199
1200 if (inc_x == 0 && inc_y == 0)
1201 return TRUE;
1202
1203 switch (edit_mode)
1204 {
1205 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
1206 undo_desc = _("Move Floating Selection");
1207 break;
1208
1209 default:
1210 undo_desc = GIMP_ITEM_GET_CLASS (item)->translate_desc;
1211 break;
1212 }
1213
1214 /* compress undo */
1215 undo = gimp_image_undo_can_compress (image, GIMP_TYPE_UNDO_STACK, undo_type);
1216
1217 if (undo &&
1218 g_object_get_data (G_OBJECT (undo),
1219 "edit-selection-tool") == (gpointer) tool &&
1220 g_object_get_data (G_OBJECT (undo),
1221 "edit-selection-item") == (gpointer) item &&
1222 g_object_get_data (G_OBJECT (undo),
1223 "edit-selection-type") == GINT_TO_POINTER (edit_mode))
1224 {
1225 push_undo = FALSE;
1226 }
1227
1228 if (push_undo)
1229 {
1230 if (gimp_image_undo_group_start (image, undo_type, undo_desc))
1231 {
1232 undo = gimp_image_undo_can_compress (image,
1233 GIMP_TYPE_UNDO_STACK,
1234 undo_type);
1235
1236 if (undo)
1237 {
1238 g_object_set_data (G_OBJECT (undo), "edit-selection-tool",
1239 tool);
1240 g_object_set_data (G_OBJECT (undo), "edit-selection-item",
1241 item);
1242 g_object_set_data (G_OBJECT (undo), "edit-selection-type",
1243 GINT_TO_POINTER (edit_mode));
1244 }
1245 }
1246 }
1247
1248 switch (edit_mode)
1249 {
1250 case GIMP_TRANSLATE_MODE_LAYER_MASK:
1251 case GIMP_TRANSLATE_MODE_MASK:
1252 gimp_item_translate (item, inc_x, inc_y, push_undo);
1253 break;
1254
1255 case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
1256 case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
1257 /* this won't happen */
1258 break;
1259
1260 case GIMP_TRANSLATE_MODE_VECTORS:
1261 case GIMP_TRANSLATE_MODE_CHANNEL:
1262 case GIMP_TRANSLATE_MODE_LAYER:
1263 if (gimp_item_get_linked (item))
1264 {
1265 gimp_item_linked_translate (item, inc_x, inc_y, push_undo);
1266 }
1267 else
1268 {
1269 gimp_item_translate (item, inc_x, inc_y, push_undo);
1270 }
1271 break;
1272
1273 case GIMP_TRANSLATE_MODE_FLOATING_SEL:
1274 gimp_item_translate (item, inc_x, inc_y, push_undo);
1275 break;
1276 }
1277
1278 if (push_undo)
1279 gimp_image_undo_group_end (image);
1280 else
1281 gimp_undo_refresh_preview (undo,
1282 gimp_get_user_context (display->gimp));
1283
1284 gimp_image_flush (image);
1285
1286 return TRUE;
1287 }
1288