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