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 <string.h>
21 
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 
25 #include "libgimpmath/gimpmath.h"
26 #include "libgimpwidgets/gimpwidgets.h"
27 
28 #include "tools-types.h"
29 
30 #include "config/gimpdisplayconfig.h"
31 #include "config/gimpguiconfig.h"
32 
33 #include "core/gimp.h"
34 #include "core/gimp-cairo.h"
35 #include "core/gimp-utils.h"
36 #include "core/gimpguide.h"
37 #include "core/gimpimage.h"
38 #include "core/gimpimage-pick-item.h"
39 #include "core/gimplayer.h"
40 #include "core/gimpimage-undo.h"
41 #include "core/gimplayermask.h"
42 #include "core/gimplayer-floating-selection.h"
43 #include "core/gimpundostack.h"
44 
45 #include "widgets/gimphelp-ids.h"
46 #include "widgets/gimpwidgets-utils.h"
47 
48 #include "display/gimpcanvasitem.h"
49 #include "display/gimpdisplay.h"
50 #include "display/gimpdisplayshell.h"
51 #include "display/gimpdisplayshell-appearance.h"
52 #include "display/gimpdisplayshell-selection.h"
53 #include "display/gimpdisplayshell-transform.h"
54 
55 #include "gimpeditselectiontool.h"
56 #include "gimpguidetool.h"
57 #include "gimpmoveoptions.h"
58 #include "gimpmovetool.h"
59 #include "gimptoolcontrol.h"
60 #include "gimptools-utils.h"
61 
62 #include "gimp-intl.h"
63 
64 
65 /*  local function prototypes  */
66 
67 static void   gimp_move_tool_finalize       (GObject               *object);
68 
69 static void   gimp_move_tool_button_press   (GimpTool              *tool,
70                                              const GimpCoords      *coords,
71                                              guint32                time,
72                                              GdkModifierType        state,
73                                              GimpButtonPressType    press_type,
74                                              GimpDisplay           *display);
75 static void   gimp_move_tool_button_release (GimpTool              *tool,
76                                              const GimpCoords      *coords,
77                                              guint32                time,
78                                              GdkModifierType        state,
79                                              GimpButtonReleaseType  release_type,
80                                              GimpDisplay           *display);
81 static gboolean gimp_move_tool_key_press    (GimpTool              *tool,
82                                              GdkEventKey           *kevent,
83                                              GimpDisplay           *display);
84 static void   gimp_move_tool_modifier_key   (GimpTool              *tool,
85                                              GdkModifierType        key,
86                                              gboolean               press,
87                                              GdkModifierType        state,
88                                              GimpDisplay           *display);
89 static void   gimp_move_tool_oper_update    (GimpTool              *tool,
90                                              const GimpCoords      *coords,
91                                              GdkModifierType        state,
92                                              gboolean               proximity,
93                                              GimpDisplay           *display);
94 static void   gimp_move_tool_cursor_update  (GimpTool              *tool,
95                                              const GimpCoords      *coords,
96                                              GdkModifierType        state,
97                                              GimpDisplay           *display);
98 
99 static void   gimp_move_tool_draw           (GimpDrawTool          *draw_tool);
100 
101 
G_DEFINE_TYPE(GimpMoveTool,gimp_move_tool,GIMP_TYPE_DRAW_TOOL)102 G_DEFINE_TYPE (GimpMoveTool, gimp_move_tool, GIMP_TYPE_DRAW_TOOL)
103 
104 #define parent_class gimp_move_tool_parent_class
105 
106 
107 void
108 gimp_move_tool_register (GimpToolRegisterCallback  callback,
109                          gpointer                  data)
110 {
111   (* callback) (GIMP_TYPE_MOVE_TOOL,
112                 GIMP_TYPE_MOVE_OPTIONS,
113                 gimp_move_options_gui,
114                 0,
115                 "gimp-move-tool",
116                 C_("tool", "Move"),
117                 _("Move Tool: Move layers, selections, and other objects"),
118                 N_("_Move"), "M",
119                 NULL, GIMP_HELP_TOOL_MOVE,
120                 GIMP_ICON_TOOL_MOVE,
121                 data);
122 }
123 
124 static void
gimp_move_tool_class_init(GimpMoveToolClass * klass)125 gimp_move_tool_class_init (GimpMoveToolClass *klass)
126 {
127   GObjectClass      *object_class    = G_OBJECT_CLASS (klass);
128   GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
129   GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
130 
131   object_class->finalize     = gimp_move_tool_finalize;
132 
133   tool_class->button_press   = gimp_move_tool_button_press;
134   tool_class->button_release = gimp_move_tool_button_release;
135   tool_class->key_press      = gimp_move_tool_key_press;
136   tool_class->modifier_key   = gimp_move_tool_modifier_key;
137   tool_class->oper_update    = gimp_move_tool_oper_update;
138   tool_class->cursor_update  = gimp_move_tool_cursor_update;
139 
140   draw_tool_class->draw      = gimp_move_tool_draw;
141 }
142 
143 static void
gimp_move_tool_init(GimpMoveTool * move_tool)144 gimp_move_tool_init (GimpMoveTool *move_tool)
145 {
146   GimpTool *tool = GIMP_TOOL (move_tool);
147 
148   gimp_tool_control_set_snap_to            (tool->control, FALSE);
149   gimp_tool_control_set_handle_empty_image (tool->control, TRUE);
150   gimp_tool_control_set_tool_cursor        (tool->control,
151                                             GIMP_TOOL_CURSOR_MOVE);
152 
153   move_tool->floating_layer     = NULL;
154   move_tool->guides             = NULL;
155 
156   move_tool->saved_type         = GIMP_TRANSFORM_TYPE_LAYER;
157 
158   move_tool->old_active_layer   = NULL;
159   move_tool->old_active_vectors = NULL;
160 }
161 
162 static void
gimp_move_tool_finalize(GObject * object)163 gimp_move_tool_finalize (GObject *object)
164 {
165   GimpMoveTool *move = GIMP_MOVE_TOOL (object);
166 
167   g_clear_pointer (&move->guides, g_list_free);
168 
169   G_OBJECT_CLASS (parent_class)->finalize (object);
170 }
171 
172 static void
gimp_move_tool_button_press(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonPressType press_type,GimpDisplay * display)173 gimp_move_tool_button_press (GimpTool            *tool,
174                              const GimpCoords    *coords,
175                              guint32              time,
176                              GdkModifierType      state,
177                              GimpButtonPressType  press_type,
178                              GimpDisplay         *display)
179 {
180   GimpMoveTool      *move           = GIMP_MOVE_TOOL (tool);
181   GimpMoveOptions   *options        = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
182   GimpDisplayShell  *shell          = gimp_display_get_shell (display);
183   GimpImage         *image          = gimp_display_get_image (display);
184   GimpItem          *active_item    = NULL;
185   GimpTranslateMode  translate_mode = GIMP_TRANSLATE_MODE_MASK;
186   const gchar       *null_message   = NULL;
187   const gchar       *locked_message = NULL;
188 
189   tool->display = display;
190 
191   move->floating_layer = NULL;
192 
193   g_clear_pointer (&move->guides, g_list_free);
194 
195   if (! options->move_current)
196     {
197       const gint snap_distance = display->config->snap_distance;
198 
199       if (options->move_type == GIMP_TRANSFORM_TYPE_PATH)
200         {
201           GimpVectors *vectors;
202 
203           vectors = gimp_image_pick_vectors (image,
204                                              coords->x, coords->y,
205                                              FUNSCALEX (shell, snap_distance),
206                                              FUNSCALEY (shell, snap_distance));
207           if (vectors)
208             {
209               move->old_active_vectors =
210                 gimp_image_get_active_vectors (image);
211 
212               gimp_image_set_active_vectors (image, vectors);
213             }
214           else
215             {
216               /*  no path picked  */
217               return;
218             }
219         }
220       else if (options->move_type == GIMP_TRANSFORM_TYPE_LAYER)
221         {
222           GList     *guides;
223           GimpLayer *layer;
224 
225           if (gimp_display_shell_get_show_guides (shell) &&
226               (guides = gimp_image_pick_guides (image,
227                                                 coords->x, coords->y,
228                                                 FUNSCALEX (shell, snap_distance),
229                                                 FUNSCALEY (shell, snap_distance))))
230             {
231               move->guides = guides;
232 
233               gimp_guide_tool_start_edit_many (tool, display, guides);
234 
235               return;
236             }
237           else if ((layer = gimp_image_pick_layer (image,
238                                                    coords->x,
239                                                    coords->y,
240                                                    NULL)))
241             {
242               if (gimp_image_get_floating_selection (image) &&
243                   ! gimp_layer_is_floating_sel (layer))
244                 {
245                   /*  If there is a floating selection, and this aint it,
246                    *  use the move tool to anchor it.
247                    */
248                   move->floating_layer =
249                     gimp_image_get_floating_selection (image);
250 
251                   gimp_tool_control_activate (tool->control);
252 
253                   return;
254                 }
255               else
256                 {
257                   move->old_active_layer = gimp_image_get_active_layer (image);
258 
259                   gimp_image_set_active_layer (image, layer);
260                 }
261             }
262           else
263             {
264               /*  no guide and no layer picked  */
265 
266               return;
267             }
268         }
269     }
270 
271   switch (options->move_type)
272     {
273     case GIMP_TRANSFORM_TYPE_PATH:
274       {
275         active_item = GIMP_ITEM (gimp_image_get_active_vectors (image));
276 
277         translate_mode = GIMP_TRANSLATE_MODE_VECTORS;
278 
279         if (! active_item)
280           {
281             null_message = _("There is no path to move.");
282           }
283         else if (gimp_item_is_position_locked (active_item))
284           {
285             locked_message = _("The active path's position is locked.");
286           }
287       }
288       break;
289 
290     case GIMP_TRANSFORM_TYPE_SELECTION:
291       {
292         active_item = GIMP_ITEM (gimp_image_get_mask (image));
293 
294         if (gimp_channel_is_empty (GIMP_CHANNEL (active_item)))
295           active_item = NULL;
296 
297         translate_mode = GIMP_TRANSLATE_MODE_MASK;
298 
299         if (! active_item)
300           {
301             /* cannot happen, don't translate this message */
302             null_message  = "There is no selection to move.";
303           }
304         else if (gimp_item_is_position_locked (active_item))
305           {
306             locked_message = "The selection's position is locked.";
307           }
308       }
309       break;
310 
311     case GIMP_TRANSFORM_TYPE_LAYER:
312       {
313         active_item = GIMP_ITEM (gimp_image_get_active_drawable (image));
314 
315         if (! active_item)
316           {
317             null_message = _("There is no layer to move.");
318           }
319         else if (GIMP_IS_LAYER_MASK (active_item))
320           {
321             translate_mode = GIMP_TRANSLATE_MODE_LAYER_MASK;
322 
323             if (gimp_item_is_position_locked (active_item))
324               locked_message = _("The active layer's position is locked.");
325             else if (gimp_item_is_content_locked (active_item))
326               locked_message = _("The active layer's pixels are locked.");
327           }
328         else if (GIMP_IS_CHANNEL (active_item))
329           {
330             translate_mode = GIMP_TRANSLATE_MODE_CHANNEL;
331 
332             if (gimp_item_is_position_locked (active_item))
333               locked_message = _("The active channel's position is locked.");
334             else if (gimp_item_is_content_locked (active_item))
335               locked_message = _("The active channel's pixels are locked.");
336           }
337         else
338           {
339             translate_mode = GIMP_TRANSLATE_MODE_LAYER;
340 
341             if (gimp_item_is_position_locked (active_item))
342               locked_message = _("The active layer's position is locked.");
343           }
344       }
345       break;
346 
347     case GIMP_TRANSFORM_TYPE_IMAGE:
348       g_return_if_reached ();
349     }
350 
351   if (! active_item)
352     {
353       gimp_tool_message_literal (tool, display, null_message);
354       gimp_widget_blink (options->type_box);
355       gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
356       return;
357     }
358   else if (locked_message)
359     {
360       gimp_tool_message_literal (tool, display, locked_message);
361       gimp_tools_blink_lock_box (display->gimp, active_item);
362       gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
363       return;
364     }
365 
366   gimp_tool_control_activate (tool->control);
367 
368   gimp_edit_selection_tool_start (tool, display, coords,
369                                   translate_mode,
370                                   TRUE);
371 }
372 
373 static void
gimp_move_tool_button_release(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonReleaseType release_type,GimpDisplay * display)374 gimp_move_tool_button_release (GimpTool              *tool,
375                                const GimpCoords      *coords,
376                                guint32                time,
377                                GdkModifierType        state,
378                                GimpButtonReleaseType  release_type,
379                                GimpDisplay           *display)
380 {
381   GimpMoveTool  *move   = GIMP_MOVE_TOOL (tool);
382   GimpGuiConfig *config = GIMP_GUI_CONFIG (display->gimp->config);
383   GimpImage     *image  = gimp_display_get_image (display);
384   gboolean       flush  = FALSE;
385 
386   gimp_tool_control_halt (tool->control);
387 
388   if (! config->move_tool_changes_active ||
389       (release_type == GIMP_BUTTON_RELEASE_CANCEL))
390     {
391       if (move->old_active_layer)
392         {
393           gimp_image_set_active_layer (image, move->old_active_layer);
394           move->old_active_layer = NULL;
395 
396           flush = TRUE;
397         }
398 
399       if (move->old_active_vectors)
400         {
401           gimp_image_set_active_vectors (image, move->old_active_vectors);
402           move->old_active_vectors = NULL;
403 
404           flush = TRUE;
405         }
406     }
407 
408   if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
409     {
410       if (move->floating_layer)
411         {
412           floating_sel_anchor (move->floating_layer);
413 
414           flush = TRUE;
415         }
416     }
417 
418   if (flush)
419     gimp_image_flush (image);
420 }
421 
422 static gboolean
gimp_move_tool_key_press(GimpTool * tool,GdkEventKey * kevent,GimpDisplay * display)423 gimp_move_tool_key_press (GimpTool    *tool,
424                           GdkEventKey *kevent,
425                           GimpDisplay *display)
426 {
427   GimpMoveOptions *options = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
428 
429   return gimp_edit_selection_tool_translate (tool, kevent,
430                                              options->move_type,
431                                              display,
432                                              options->type_box);
433 }
434 
435 static void
gimp_move_tool_modifier_key(GimpTool * tool,GdkModifierType key,gboolean press,GdkModifierType state,GimpDisplay * display)436 gimp_move_tool_modifier_key (GimpTool        *tool,
437                              GdkModifierType  key,
438                              gboolean         press,
439                              GdkModifierType  state,
440                              GimpDisplay     *display)
441 {
442   GimpMoveTool    *move    = GIMP_MOVE_TOOL (tool);
443   GimpMoveOptions *options = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
444 
445   if (key == gimp_get_extend_selection_mask ())
446     {
447       g_object_set (options, "move-current", ! options->move_current, NULL);
448     }
449   else if (key == GDK_MOD1_MASK ||
450            key == gimp_get_toggle_behavior_mask ())
451     {
452       GimpTransformType button_type;
453 
454       button_type = options->move_type;
455 
456       if (press)
457         {
458           if (key == (state & (GDK_MOD1_MASK |
459                                gimp_get_toggle_behavior_mask ())))
460             {
461               /*  first modifier pressed  */
462 
463               move->saved_type = options->move_type;
464             }
465         }
466       else
467         {
468           if (! (state & (GDK_MOD1_MASK |
469                           gimp_get_toggle_behavior_mask ())))
470             {
471               /*  last modifier released  */
472 
473               button_type = move->saved_type;
474             }
475         }
476 
477       if (state & GDK_MOD1_MASK)
478         {
479           button_type = GIMP_TRANSFORM_TYPE_SELECTION;
480         }
481       else if (state & gimp_get_toggle_behavior_mask ())
482         {
483           button_type = GIMP_TRANSFORM_TYPE_PATH;
484         }
485 
486       if (button_type != options->move_type)
487         {
488           g_object_set (options, "move-type", button_type, NULL);
489         }
490     }
491 }
492 
493 static void
gimp_move_tool_oper_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,gboolean proximity,GimpDisplay * display)494 gimp_move_tool_oper_update (GimpTool         *tool,
495                             const GimpCoords *coords,
496                             GdkModifierType   state,
497                             gboolean          proximity,
498                             GimpDisplay      *display)
499 {
500   GimpMoveTool     *move    = GIMP_MOVE_TOOL (tool);
501   GimpMoveOptions  *options = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
502   GimpDisplayShell *shell   = gimp_display_get_shell (display);
503   GimpImage        *image   = gimp_display_get_image (display);
504   GList            *guides  = NULL;
505 
506   if (options->move_type == GIMP_TRANSFORM_TYPE_LAYER &&
507       ! options->move_current                         &&
508       gimp_display_shell_get_show_guides (shell)      &&
509       proximity)
510     {
511       gint snap_distance = display->config->snap_distance;
512 
513       guides = gimp_image_pick_guides (image, coords->x, coords->y,
514                                        FUNSCALEX (shell, snap_distance),
515                                        FUNSCALEY (shell, snap_distance));
516     }
517 
518   if (gimp_g_list_compare (guides, move->guides))
519     {
520       GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
521 
522       gimp_draw_tool_pause (draw_tool);
523 
524       if (gimp_draw_tool_is_active (draw_tool) &&
525           draw_tool->display != display)
526         gimp_draw_tool_stop (draw_tool);
527 
528       g_clear_pointer (&move->guides, g_list_free);
529 
530       move->guides = guides;
531 
532       if (! gimp_draw_tool_is_active (draw_tool))
533         gimp_draw_tool_start (draw_tool, display);
534 
535       gimp_draw_tool_resume (draw_tool);
536     }
537   else
538     {
539       g_list_free (guides);
540     }
541 }
542 
543 static void
gimp_move_tool_cursor_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,GimpDisplay * display)544 gimp_move_tool_cursor_update (GimpTool         *tool,
545                               const GimpCoords *coords,
546                               GdkModifierType   state,
547                               GimpDisplay      *display)
548 {
549   GimpMoveOptions    *options       = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
550   GimpDisplayShell   *shell         = gimp_display_get_shell (display);
551   GimpImage          *image         = gimp_display_get_image (display);
552   GimpCursorType      cursor        = GIMP_CURSOR_MOUSE;
553   GimpToolCursorType  tool_cursor   = GIMP_TOOL_CURSOR_MOVE;
554   GimpCursorModifier  modifier      = GIMP_CURSOR_MODIFIER_NONE;
555   gint                snap_distance = display->config->snap_distance;
556 
557   if (options->move_type == GIMP_TRANSFORM_TYPE_PATH)
558     {
559       tool_cursor = GIMP_TOOL_CURSOR_PATHS;
560       modifier    = GIMP_CURSOR_MODIFIER_MOVE;
561 
562       if (options->move_current)
563         {
564           GimpItem *item = GIMP_ITEM (gimp_image_get_active_vectors (image));
565 
566           if (! item || gimp_item_is_position_locked (item))
567             modifier = GIMP_CURSOR_MODIFIER_BAD;
568         }
569       else
570         {
571           if (gimp_image_pick_vectors (image,
572                                        coords->x, coords->y,
573                                        FUNSCALEX (shell, snap_distance),
574                                        FUNSCALEY (shell, snap_distance)))
575             {
576               tool_cursor = GIMP_TOOL_CURSOR_HAND;
577             }
578           else
579             {
580               modifier = GIMP_CURSOR_MODIFIER_BAD;
581             }
582         }
583     }
584   else if (options->move_type == GIMP_TRANSFORM_TYPE_SELECTION)
585     {
586       tool_cursor = GIMP_TOOL_CURSOR_RECT_SELECT;
587       modifier    = GIMP_CURSOR_MODIFIER_MOVE;
588 
589       if (gimp_channel_is_empty (gimp_image_get_mask (image)))
590         modifier = GIMP_CURSOR_MODIFIER_BAD;
591     }
592   else if (options->move_current)
593     {
594       GimpItem *item = GIMP_ITEM (gimp_image_get_active_drawable (image));
595 
596       if (! item || gimp_item_is_position_locked (item))
597         modifier = GIMP_CURSOR_MODIFIER_BAD;
598     }
599   else
600     {
601       GimpLayer  *layer;
602 
603       if (gimp_display_shell_get_show_guides (shell) &&
604           gimp_image_pick_guide (image, coords->x, coords->y,
605                                  FUNSCALEX (shell, snap_distance),
606                                  FUNSCALEY (shell, snap_distance)))
607         {
608           tool_cursor = GIMP_TOOL_CURSOR_HAND;
609           modifier    = GIMP_CURSOR_MODIFIER_MOVE;
610         }
611       else if ((layer = gimp_image_pick_layer (image,
612                                                coords->x, coords->y,
613                                                NULL)))
614         {
615           /*  if there is a floating selection, and this aint it...  */
616           if (gimp_image_get_floating_selection (image) &&
617               ! gimp_layer_is_floating_sel (layer))
618             {
619               tool_cursor = GIMP_TOOL_CURSOR_MOVE;
620               modifier    = GIMP_CURSOR_MODIFIER_ANCHOR;
621             }
622           else if (gimp_item_is_position_locked (GIMP_ITEM (layer)))
623             {
624               modifier = GIMP_CURSOR_MODIFIER_BAD;
625             }
626           else if (layer != gimp_image_get_active_layer (image))
627             {
628               tool_cursor = GIMP_TOOL_CURSOR_HAND;
629               modifier    = GIMP_CURSOR_MODIFIER_MOVE;
630             }
631         }
632       else
633         {
634           modifier = GIMP_CURSOR_MODIFIER_BAD;
635         }
636     }
637 
638   gimp_tool_control_set_cursor          (tool->control, cursor);
639   gimp_tool_control_set_tool_cursor     (tool->control, tool_cursor);
640   gimp_tool_control_set_cursor_modifier (tool->control, modifier);
641 
642   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
643 }
644 
645 static void
gimp_move_tool_draw(GimpDrawTool * draw_tool)646 gimp_move_tool_draw (GimpDrawTool *draw_tool)
647 {
648   GimpMoveTool *move = GIMP_MOVE_TOOL (draw_tool);
649   GList        *iter;
650 
651   for (iter = move->guides; iter; iter = g_list_next (iter))
652     {
653       GimpGuide      *guide = iter->data;
654       GimpCanvasItem *item;
655       GimpGuideStyle  style;
656 
657       style = gimp_guide_get_style (guide);
658 
659       item = gimp_draw_tool_add_guide (draw_tool,
660                                        gimp_guide_get_orientation (guide),
661                                        gimp_guide_get_position (guide),
662                                        style);
663       gimp_canvas_item_set_highlight (item, TRUE);
664     }
665 }
666