1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpmath/gimpmath.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "tools-types.h"
27
28 #include "config/gimpguiconfig.h"
29
30 #include "core/gimp.h"
31 #include "core/gimpdrawable-transform.h"
32 #include "core/gimperror.h"
33 #include "core/gimpimage.h"
34 #include "core/gimpimage-item-list.h"
35 #include "core/gimpimage-transform.h"
36 #include "core/gimpimage-undo.h"
37 #include "core/gimpitem-linked.h"
38 #include "core/gimplayer.h"
39 #include "core/gimplayermask.h"
40 #include "core/gimpprogress.h"
41 #include "core/gimp-transform-resize.h"
42
43 #include "vectors/gimpvectors.h"
44
45 #include "display/gimpdisplay.h"
46 #include "display/gimpdisplayshell.h"
47
48 #include "widgets/gimpmessagedialog.h"
49 #include "widgets/gimpmessagebox.h"
50 #include "widgets/gimpwidgets-utils.h"
51
52 #include "gimptoolcontrol.h"
53 #include "gimptools-utils.h"
54 #include "gimptransformoptions.h"
55 #include "gimptransformtool.h"
56
57 #include "gimp-intl.h"
58
59
60 /* the minimal ratio between the transformed item size and the image size,
61 * above which confirmation is required.
62 */
63 #define MIN_CONFIRMATION_RATIO 10
64
65
66 /* local function prototypes */
67
68 static void gimp_transform_tool_control (GimpTool *tool,
69 GimpToolAction action,
70 GimpDisplay *display);
71
72 static gchar * gimp_transform_tool_real_get_undo_desc (GimpTransformTool *tr_tool);
73 static GimpTransformDirection gimp_transform_tool_real_get_direction (GimpTransformTool *tr_tool);
74 static GeglBuffer * gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
75 GimpObject *object,
76 GeglBuffer *orig_buffer,
77 gint orig_offset_x,
78 gint orig_offset_y,
79 GimpColorProfile **buffer_profile,
80 gint *new_offset_x,
81 gint *new_offset_y);
82
83 static void gimp_transform_tool_halt (GimpTransformTool *tr_tool);
84
85 static gboolean gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
86 GimpDisplay *display);
87
88
G_DEFINE_TYPE(GimpTransformTool,gimp_transform_tool,GIMP_TYPE_DRAW_TOOL)89 G_DEFINE_TYPE (GimpTransformTool, gimp_transform_tool, GIMP_TYPE_DRAW_TOOL)
90
91 #define parent_class gimp_transform_tool_parent_class
92
93
94 /* private functions */
95
96
97 static void
98 gimp_transform_tool_class_init (GimpTransformToolClass *klass)
99 {
100 GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
101
102 tool_class->control = gimp_transform_tool_control;
103
104 klass->recalc_matrix = NULL;
105 klass->get_undo_desc = gimp_transform_tool_real_get_undo_desc;
106 klass->get_direction = gimp_transform_tool_real_get_direction;
107 klass->transform = gimp_transform_tool_real_transform;
108
109 klass->undo_desc = _("Transform");
110 klass->progress_text = _("Transforming");
111 }
112
113 static void
gimp_transform_tool_init(GimpTransformTool * tr_tool)114 gimp_transform_tool_init (GimpTransformTool *tr_tool)
115 {
116 gimp_matrix3_identity (&tr_tool->transform);
117 tr_tool->transform_valid = TRUE;
118
119 tr_tool->restore_type = FALSE;
120 }
121
122 static void
gimp_transform_tool_control(GimpTool * tool,GimpToolAction action,GimpDisplay * display)123 gimp_transform_tool_control (GimpTool *tool,
124 GimpToolAction action,
125 GimpDisplay *display)
126 {
127 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
128
129 switch (action)
130 {
131 case GIMP_TOOL_ACTION_PAUSE:
132 case GIMP_TOOL_ACTION_RESUME:
133 break;
134
135 case GIMP_TOOL_ACTION_HALT:
136 gimp_transform_tool_halt (tr_tool);
137 break;
138
139 case GIMP_TOOL_ACTION_COMMIT:
140 break;
141 }
142
143 GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
144 }
145
146 static gchar *
gimp_transform_tool_real_get_undo_desc(GimpTransformTool * tr_tool)147 gimp_transform_tool_real_get_undo_desc (GimpTransformTool *tr_tool)
148 {
149 return g_strdup (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->undo_desc);
150 }
151
152 static GimpTransformDirection
gimp_transform_tool_real_get_direction(GimpTransformTool * tr_tool)153 gimp_transform_tool_real_get_direction (GimpTransformTool *tr_tool)
154 {
155 GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
156
157 return options->direction;
158 }
159
160 static GeglBuffer *
gimp_transform_tool_real_transform(GimpTransformTool * tr_tool,GimpObject * object,GeglBuffer * orig_buffer,gint orig_offset_x,gint orig_offset_y,GimpColorProfile ** buffer_profile,gint * new_offset_x,gint * new_offset_y)161 gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
162 GimpObject *object,
163 GeglBuffer *orig_buffer,
164 gint orig_offset_x,
165 gint orig_offset_y,
166 GimpColorProfile **buffer_profile,
167 gint *new_offset_x,
168 gint *new_offset_y)
169 {
170 GimpTransformToolClass *klass = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool);
171 GimpTool *tool = GIMP_TOOL (tr_tool);
172 GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
173 GimpContext *context = GIMP_CONTEXT (options);
174 GeglBuffer *ret = NULL;
175 GimpTransformResize clip = options->clip;
176 GimpTransformDirection direction;
177 GimpProgress *progress;
178
179 direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (tr_tool);
180
181 progress = gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
182 "%s", klass->progress_text);
183
184 if (orig_buffer)
185 {
186 /* this happens when transforming a selection cut out of a
187 * normal drawable
188 */
189
190 g_return_val_if_fail (GIMP_IS_DRAWABLE (object), NULL);
191
192 ret = gimp_drawable_transform_buffer_affine (GIMP_DRAWABLE (object),
193 context,
194 orig_buffer,
195 orig_offset_x,
196 orig_offset_y,
197 &tr_tool->transform,
198 direction,
199 options->interpolation,
200 clip,
201 buffer_profile,
202 new_offset_x,
203 new_offset_y,
204 progress);
205 }
206 else if (GIMP_IS_ITEM (object))
207 {
208 /* this happens for entire drawables, paths and layer groups */
209
210 GimpItem *item = GIMP_ITEM (object);
211
212 if (gimp_item_get_linked (item))
213 {
214 gimp_item_linked_transform (item, context,
215 &tr_tool->transform,
216 direction,
217 options->interpolation,
218 clip,
219 progress);
220 }
221 else
222 {
223 clip = gimp_item_get_clip (item, clip);
224
225 gimp_item_transform (item, context,
226 &tr_tool->transform,
227 direction,
228 options->interpolation,
229 clip,
230 progress);
231 }
232 }
233 else
234 {
235 /* this happens for images */
236
237 g_return_val_if_fail (GIMP_IS_IMAGE (object), NULL);
238
239 gimp_image_transform (GIMP_IMAGE (object), context,
240 &tr_tool->transform,
241 direction,
242 options->interpolation,
243 clip,
244 progress);
245 }
246
247 if (progress)
248 gimp_progress_end (progress);
249
250 return ret;
251 }
252
253 static void
gimp_transform_tool_halt(GimpTransformTool * tr_tool)254 gimp_transform_tool_halt (GimpTransformTool *tr_tool)
255 {
256 GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
257
258 tr_tool->x1 = 0;
259 tr_tool->y1 = 0;
260 tr_tool->x2 = 0;
261 tr_tool->y2 = 0;
262
263 if (tr_tool->restore_type)
264 {
265 g_object_set (options,
266 "type", tr_tool->saved_type,
267 NULL);
268
269 tr_tool->restore_type = FALSE;
270 }
271 }
272
273 static gboolean
gimp_transform_tool_confirm(GimpTransformTool * tr_tool,GimpDisplay * display)274 gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
275 GimpDisplay *display)
276 {
277 GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
278 GimpDisplayShell *shell = gimp_display_get_shell (display);
279 GimpImage *image = gimp_display_get_image (display);
280 GimpObject *active_object;
281 gdouble max_ratio = 0.0;
282 GimpObject *max_ratio_object = NULL;
283
284 active_object = gimp_transform_tool_get_active_object (tr_tool, display);
285
286 if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
287 {
288 GimpMatrix3 transform;
289 GimpTransformDirection direction;
290 GeglRectangle selection_bounds;
291 gboolean selection_empty = TRUE;
292 GList *objects;
293 GList *iter;
294
295 transform = tr_tool->transform;
296 direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (
297 tr_tool);
298
299 if (direction == GIMP_TRANSFORM_BACKWARD)
300 gimp_matrix3_invert (&transform);
301
302 if (options->type == GIMP_TRANSFORM_TYPE_LAYER &&
303 ! gimp_viewable_get_children (GIMP_VIEWABLE (active_object)))
304 {
305 selection_empty = ! gimp_item_bounds (
306 GIMP_ITEM (gimp_image_get_mask (image)),
307 &selection_bounds.x, &selection_bounds.y,
308 &selection_bounds.width, &selection_bounds.height);
309 }
310
311 if (selection_empty &&
312 GIMP_IS_ITEM (active_object) &&
313 gimp_item_get_linked (GIMP_ITEM (active_object)))
314 {
315 objects = gimp_image_item_list_get_list (image,
316 GIMP_ITEM_TYPE_ALL,
317 GIMP_ITEM_SET_LINKED);
318 }
319 else
320 {
321 objects = g_list_append (NULL, active_object);
322 }
323
324 if (options->type == GIMP_TRANSFORM_TYPE_IMAGE)
325 {
326 objects = g_list_concat (
327 objects,
328 gimp_image_item_list_get_list (image,
329 GIMP_ITEM_TYPE_ALL,
330 GIMP_ITEM_SET_ALL));
331 }
332
333 for (iter = objects; iter; iter = g_list_next (iter))
334 {
335 GimpObject *object = iter->data;
336 GimpTransformResize clip = options->clip;
337 GeglRectangle orig_bounds;
338 GeglRectangle new_bounds;
339 gdouble ratio = 0.0;
340
341 if (GIMP_IS_DRAWABLE (object))
342 {
343 if (selection_empty)
344 {
345 GimpItem *item = GIMP_ITEM (object);
346
347 gimp_item_get_offset (item, &orig_bounds.x, &orig_bounds.y);
348
349 orig_bounds.width = gimp_item_get_width (item);
350 orig_bounds.height = gimp_item_get_height (item);
351
352 clip = gimp_item_get_clip (item, clip);
353 }
354 else
355 {
356 orig_bounds = selection_bounds;
357 }
358 }
359 else if (GIMP_IS_ITEM (object))
360 {
361 GimpItem *item = GIMP_ITEM (object);
362
363 gimp_item_bounds (item,
364 &orig_bounds.x, &orig_bounds.y,
365 &orig_bounds.width, &orig_bounds.height);
366
367 clip = gimp_item_get_clip (item, clip);
368 }
369 else
370 {
371 GimpImage *image;
372
373 g_return_val_if_fail (GIMP_IS_IMAGE (object), FALSE);
374
375 image = GIMP_IMAGE (object);
376
377 orig_bounds.x = 0;
378 orig_bounds.y = 0;
379 orig_bounds.width = gimp_image_get_width (image);
380 orig_bounds.height = gimp_image_get_height (image);
381 }
382
383 gimp_transform_resize_boundary (&transform, clip,
384
385 orig_bounds.x,
386 orig_bounds.y,
387 orig_bounds.x + orig_bounds.width,
388 orig_bounds.y + orig_bounds.height,
389
390 &new_bounds.x,
391 &new_bounds.y,
392 &new_bounds.width,
393 &new_bounds.height);
394
395 new_bounds.width -= new_bounds.x;
396 new_bounds.height -= new_bounds.y;
397
398 if (new_bounds.width > orig_bounds.width)
399 {
400 ratio = MAX (ratio,
401 (gdouble) new_bounds.width /
402 (gdouble) gimp_image_get_width (image));
403 }
404
405 if (new_bounds.height > orig_bounds.height)
406 {
407 ratio = MAX (ratio,
408 (gdouble) new_bounds.height /
409 (gdouble) gimp_image_get_height (image));
410 }
411
412 if (ratio > max_ratio)
413 {
414 max_ratio = ratio;
415 max_ratio_object = object;
416 }
417 }
418
419 g_list_free (objects);
420 }
421
422 if (max_ratio > MIN_CONFIRMATION_RATIO)
423 {
424 GtkWidget *dialog;
425 gint response;
426
427 dialog = gimp_message_dialog_new (_("Confirm Transformation"),
428 GIMP_ICON_DIALOG_WARNING,
429 GTK_WIDGET (shell),
430 GTK_DIALOG_MODAL |
431 GTK_DIALOG_DESTROY_WITH_PARENT,
432 gimp_standard_help_func, NULL,
433
434 _("_Cancel"), GTK_RESPONSE_CANCEL,
435 _("_Transform"), GTK_RESPONSE_OK,
436
437 NULL);
438
439 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
440 GTK_RESPONSE_OK,
441 GTK_RESPONSE_CANCEL,
442 -1);
443
444 if (GIMP_IS_ITEM (max_ratio_object))
445 {
446 gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
447 _("Transformation creates "
448 "a very large item."));
449
450 gimp_message_box_set_text (
451 GIMP_MESSAGE_DIALOG (dialog)->box,
452 _("Applying the transformation will result "
453 "in an item that is over %g times larger "
454 "than the image."),
455 floor (max_ratio));
456 }
457 else
458 {
459 gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
460 _("Transformation creates "
461 "a very large image."));
462
463 gimp_message_box_set_text (
464 GIMP_MESSAGE_DIALOG (dialog)->box,
465 _("Applying the transformation will enlarge "
466 "the image by a factor of %g."),
467 floor (max_ratio));
468 }
469
470 response = gtk_dialog_run (GTK_DIALOG (dialog));
471
472 gtk_widget_destroy (dialog);
473
474 if (response != GTK_RESPONSE_OK)
475 return FALSE;
476 }
477
478 return TRUE;
479 }
480
481
482 /* public functions */
483
484
485 gboolean
gimp_transform_tool_bounds(GimpTransformTool * tr_tool,GimpDisplay * display)486 gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
487 GimpDisplay *display)
488 {
489 GimpTransformOptions *options;
490 GimpDisplayShell *shell;
491 GimpImage *image;
492 gboolean non_empty = TRUE;
493
494 g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), FALSE);
495
496 options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
497 image = gimp_display_get_image (display);
498 shell = gimp_display_get_shell (display);
499
500 g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
501
502 switch (options->type)
503 {
504 case GIMP_TRANSFORM_TYPE_LAYER:
505 {
506 GimpDrawable *drawable;
507 gint offset_x;
508 gint offset_y;
509 gint x, y;
510 gint width, height;
511
512 drawable = gimp_image_get_active_drawable (image);
513
514 gimp_item_get_offset (GIMP_ITEM (drawable), &offset_x, &offset_y);
515
516 non_empty = gimp_item_mask_intersect (GIMP_ITEM (drawable),
517 &x, &y, &width, &height);
518 tr_tool->x1 = x + offset_x;
519 tr_tool->y1 = y + offset_y;
520 tr_tool->x2 = x + width + offset_x;
521 tr_tool->y2 = y + height + offset_y;
522 }
523 break;
524
525 case GIMP_TRANSFORM_TYPE_SELECTION:
526 {
527 gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
528 &tr_tool->x1, &tr_tool->y1,
529 &tr_tool->x2, &tr_tool->y2);
530 tr_tool->x2 += tr_tool->x1;
531 tr_tool->y2 += tr_tool->y1;
532 }
533 break;
534
535 case GIMP_TRANSFORM_TYPE_PATH:
536 {
537 GimpChannel *selection = gimp_image_get_mask (image);
538
539 /* if selection is not empty, use its bounds to perform the
540 * transformation of the path
541 */
542
543 if (! gimp_channel_is_empty (selection))
544 {
545 gimp_item_bounds (GIMP_ITEM (selection),
546 &tr_tool->x1, &tr_tool->y1,
547 &tr_tool->x2, &tr_tool->y2);
548 }
549 else
550 {
551 /* without selection, test the emptiness of the path bounds :
552 * if empty, use the canvas bounds
553 * else use the path bounds
554 */
555
556 if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_active_vectors (image)),
557 &tr_tool->x1, &tr_tool->y1,
558 &tr_tool->x2, &tr_tool->y2))
559 {
560 tr_tool->x1 = 0;
561 tr_tool->y1 = 0;
562 tr_tool->x2 = gimp_image_get_width (image);
563 tr_tool->y2 = gimp_image_get_height (image);
564 }
565 }
566
567 tr_tool->x2 += tr_tool->x1;
568 tr_tool->y2 += tr_tool->y1;
569 }
570
571 break;
572
573 case GIMP_TRANSFORM_TYPE_IMAGE:
574 if (! shell->show_all)
575 {
576 tr_tool->x1 = 0;
577 tr_tool->y1 = 0;
578 tr_tool->x2 = gimp_image_get_width (image);
579 tr_tool->y2 = gimp_image_get_height (image);
580 }
581 else
582 {
583 GeglRectangle bounding_box;
584
585 bounding_box = gimp_display_shell_get_bounding_box (shell);
586
587 tr_tool->x1 = bounding_box.x;
588 tr_tool->y1 = bounding_box.y;
589 tr_tool->x2 = bounding_box.x + bounding_box.width;
590 tr_tool->y2 = bounding_box.y + bounding_box.height;
591 }
592 break;
593 }
594
595 return non_empty;
596 }
597
598 void
gimp_transform_tool_recalc_matrix(GimpTransformTool * tr_tool,GimpDisplay * display)599 gimp_transform_tool_recalc_matrix (GimpTransformTool *tr_tool,
600 GimpDisplay *display)
601 {
602 g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
603 g_return_if_fail (GIMP_IS_DISPLAY (display));
604
605 if (tr_tool->x1 == tr_tool->x2 && tr_tool->y1 == tr_tool->y2)
606 gimp_transform_tool_bounds (tr_tool, display);
607
608 if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
609 GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix (tr_tool);
610 }
611
612 GimpObject *
gimp_transform_tool_get_active_object(GimpTransformTool * tr_tool,GimpDisplay * display)613 gimp_transform_tool_get_active_object (GimpTransformTool *tr_tool,
614 GimpDisplay *display)
615 {
616 GimpTransformOptions *options;
617 GimpImage *image;
618 GimpObject *object = NULL;
619
620 g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), NULL);
621 g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
622
623 options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
624
625 image = gimp_display_get_image (display);
626
627 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
628
629 if (tr_tool->object)
630 return tr_tool->object;
631
632 switch (options->type)
633 {
634 case GIMP_TRANSFORM_TYPE_LAYER:
635 object = GIMP_OBJECT (gimp_image_get_active_drawable (image));
636 break;
637
638 case GIMP_TRANSFORM_TYPE_SELECTION:
639 object = GIMP_OBJECT (gimp_image_get_mask (image));
640
641 if (gimp_channel_is_empty (GIMP_CHANNEL (object)))
642 object = NULL;
643 break;
644
645 case GIMP_TRANSFORM_TYPE_PATH:
646 object = GIMP_OBJECT (gimp_image_get_active_vectors (image));
647 break;
648
649 case GIMP_TRANSFORM_TYPE_IMAGE:
650 object = GIMP_OBJECT (image);
651 break;
652 }
653
654 return object;
655 }
656
657 GimpObject *
gimp_transform_tool_check_active_object(GimpTransformTool * tr_tool,GimpDisplay * display,GError ** error)658 gimp_transform_tool_check_active_object (GimpTransformTool *tr_tool,
659 GimpDisplay *display,
660 GError **error)
661 {
662 GimpTransformOptions *options;
663 GimpObject *object;
664 const gchar *null_message = NULL;
665 const gchar *locked_message = NULL;
666 GimpGuiConfig *config = GIMP_GUI_CONFIG (display->gimp->config);
667
668 g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), NULL);
669 g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
670 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
671
672 options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
673
674 object = gimp_transform_tool_get_active_object (tr_tool, display);
675
676 switch (options->type)
677 {
678 case GIMP_TRANSFORM_TYPE_LAYER:
679 null_message = _("There is no layer to transform.");
680
681 if (object)
682 {
683 GimpItem *item = GIMP_ITEM (object);
684
685 if (gimp_item_is_content_locked (item))
686 locked_message = _("The active layer's pixels are locked.");
687 else if (gimp_item_is_position_locked (item))
688 locked_message = _("The active layer's position and size are locked.");
689
690 if (! gimp_item_is_visible (item) &&
691 ! config->edit_non_visible &&
692 object != tr_tool->object) /* see bug #759194 */
693 {
694 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
695 _("The active layer is not visible."));
696 return NULL;
697 }
698
699 if (! gimp_transform_tool_bounds (tr_tool, display))
700 {
701 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
702 _("The selection does not intersect with the layer."));
703 return NULL;
704 }
705 }
706 break;
707
708 case GIMP_TRANSFORM_TYPE_SELECTION:
709 null_message = _("There is no selection to transform.");
710
711 if (object)
712 {
713 GimpItem *item = GIMP_ITEM (object);
714
715 /* cannot happen, so don't translate these messages */
716 if (gimp_item_is_content_locked (item))
717 locked_message = "The selection's pixels are locked.";
718 else if (gimp_item_is_position_locked (item))
719 locked_message = "The selection's position and size are locked.";
720 }
721 break;
722
723 case GIMP_TRANSFORM_TYPE_PATH:
724 null_message = _("There is no path to transform.");
725
726 if (object)
727 {
728 GimpItem *item = GIMP_ITEM (object);
729
730 if (gimp_item_is_content_locked (item))
731 locked_message = _("The active path's strokes are locked.");
732 else if (gimp_item_is_position_locked (item))
733 locked_message = _("The active path's position is locked.");
734 else if (! gimp_vectors_get_n_strokes (GIMP_VECTORS (item)))
735 locked_message = _("The active path has no strokes.");
736 }
737 break;
738
739 case GIMP_TRANSFORM_TYPE_IMAGE:
740 /* cannot happen, so don't translate this message */
741 null_message = "There is no image to transform.";
742 break;
743 }
744
745 if (! object)
746 {
747 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, null_message);
748 if (error)
749 gimp_widget_blink (options->type_box);
750 return NULL;
751 }
752
753 if (locked_message)
754 {
755 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, locked_message);
756 if (error)
757 gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (object));
758 return NULL;
759 }
760
761 return object;
762 }
763
764 gboolean
gimp_transform_tool_transform(GimpTransformTool * tr_tool,GimpDisplay * display)765 gimp_transform_tool_transform (GimpTransformTool *tr_tool,
766 GimpDisplay *display)
767 {
768 GimpTool *tool;
769 GimpTransformOptions *options;
770 GimpContext *context;
771 GimpImage *image;
772 GimpObject *active_object;
773 GeglBuffer *orig_buffer = NULL;
774 gint orig_offset_x = 0;
775 gint orig_offset_y = 0;
776 GeglBuffer *new_buffer;
777 gint new_offset_x;
778 gint new_offset_y;
779 GimpColorProfile *buffer_profile;
780 gchar *undo_desc = NULL;
781 gboolean new_layer = FALSE;
782 GError *error = NULL;
783
784 g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), FALSE);
785 g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
786
787 tool = GIMP_TOOL (tr_tool);
788 options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
789 context = GIMP_CONTEXT (options);
790 image = gimp_display_get_image (display);
791
792 g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
793
794 active_object = gimp_transform_tool_check_active_object (tr_tool, display,
795 &error);
796
797 if (! active_object)
798 {
799 gimp_tool_message_literal (tool, display, error->message);
800 g_clear_error (&error);
801 return FALSE;
802 }
803
804 gimp_transform_tool_recalc_matrix (tr_tool, display);
805
806 if (! tr_tool->transform_valid)
807 {
808 gimp_tool_message_literal (tool, display,
809 _("The current transform is invalid"));
810 return FALSE;
811 }
812
813 if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix &&
814 gimp_matrix3_is_identity (&tr_tool->transform))
815 {
816 /* No need to commit an identity transformation! */
817 return TRUE;
818 }
819
820 if (! gimp_transform_tool_confirm (tr_tool, display))
821 return FALSE;
822
823 gimp_set_busy (display->gimp);
824
825 /* We're going to dirty this image, but we want to keep the tool around */
826 gimp_tool_control_push_preserve (tool->control, TRUE);
827
828 undo_desc = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_undo_desc (tr_tool);
829 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM, undo_desc);
830 g_free (undo_desc);
831
832 switch (options->type)
833 {
834 case GIMP_TRANSFORM_TYPE_LAYER:
835 if (! gimp_viewable_get_children (GIMP_VIEWABLE (active_object)) &&
836 ! gimp_channel_is_empty (gimp_image_get_mask (image)))
837 {
838 orig_buffer = gimp_drawable_transform_cut (
839 GIMP_DRAWABLE (active_object),
840 context,
841 &orig_offset_x,
842 &orig_offset_y,
843 &new_layer);
844 }
845 break;
846
847 case GIMP_TRANSFORM_TYPE_SELECTION:
848 case GIMP_TRANSFORM_TYPE_PATH:
849 case GIMP_TRANSFORM_TYPE_IMAGE:
850 break;
851 }
852
853 /* Send the request for the transformation to the tool...
854 */
855 new_buffer = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->transform (
856 tr_tool,
857 active_object,
858 orig_buffer,
859 orig_offset_x,
860 orig_offset_y,
861 &buffer_profile,
862 &new_offset_x,
863 &new_offset_y);
864
865 if (orig_buffer)
866 g_object_unref (orig_buffer);
867
868 switch (options->type)
869 {
870 case GIMP_TRANSFORM_TYPE_LAYER:
871 if (new_buffer)
872 {
873 /* paste the new transformed image to the image...also implement
874 * undo...
875 */
876 gimp_drawable_transform_paste (GIMP_DRAWABLE (active_object),
877 new_buffer, buffer_profile,
878 new_offset_x, new_offset_y,
879 new_layer);
880 g_object_unref (new_buffer);
881 }
882 break;
883
884 case GIMP_TRANSFORM_TYPE_SELECTION:
885 case GIMP_TRANSFORM_TYPE_PATH:
886 case GIMP_TRANSFORM_TYPE_IMAGE:
887 /* Nothing to be done */
888 break;
889 }
890
891 gimp_image_undo_group_end (image);
892
893 /* We're done dirtying the image, and would like to be restarted if
894 * the image gets dirty while the tool exists
895 */
896 gimp_tool_control_pop_preserve (tool->control);
897
898 gimp_unset_busy (display->gimp);
899
900 gimp_image_flush (image);
901
902 return TRUE;
903 }
904
905 void
gimp_transform_tool_set_type(GimpTransformTool * tr_tool,GimpTransformType type)906 gimp_transform_tool_set_type (GimpTransformTool *tr_tool,
907 GimpTransformType type)
908 {
909 GimpTransformOptions *options;
910
911 g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
912
913 options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
914
915 if (! tr_tool->restore_type)
916 tr_tool->saved_type = options->type;
917
918 tr_tool->restore_type = FALSE;
919
920 g_object_set (options,
921 "type", type,
922 NULL);
923
924 tr_tool->restore_type = TRUE;
925 }
926