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 <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpwidgets/gimpwidgets.h"
24
25 #include "tools-types.h"
26
27 #include "core/gimp.h"
28 #include "core/gimpimage.h"
29 #include "core/gimpimage-crop.h"
30 #include "core/gimpitem.h"
31 #include "core/gimptoolinfo.h"
32
33 #include "widgets/gimphelp-ids.h"
34
35 #include "display/gimpdisplay.h"
36 #include "display/gimpdisplayshell.h"
37 #include "display/gimptoolrectangle.h"
38
39 #include "gimpcropoptions.h"
40 #include "gimpcroptool.h"
41 #include "gimprectangleoptions.h"
42 #include "gimptoolcontrol.h"
43 #include "gimptools-utils.h"
44
45 #include "gimp-intl.h"
46
47
48 static void gimp_crop_tool_constructed (GObject *object);
49 static void gimp_crop_tool_dispose (GObject *object);
50
51 static void gimp_crop_tool_control (GimpTool *tool,
52 GimpToolAction action,
53 GimpDisplay *display);
54 static void gimp_crop_tool_button_press (GimpTool *tool,
55 const GimpCoords *coords,
56 guint32 time,
57 GdkModifierType state,
58 GimpButtonPressType press_type,
59 GimpDisplay *display);
60 static void gimp_crop_tool_button_release (GimpTool *tool,
61 const GimpCoords *coords,
62 guint32 time,
63 GdkModifierType state,
64 GimpButtonReleaseType release_type,
65 GimpDisplay *display);
66 static void gimp_crop_tool_motion (GimpTool *tool,
67 const GimpCoords *coords,
68 guint32 time,
69 GdkModifierType state,
70 GimpDisplay *display);
71 static void gimp_crop_tool_options_notify (GimpTool *tool,
72 GimpToolOptions *options,
73 const GParamSpec *pspec);
74
75 static void gimp_crop_tool_rectangle_changed (GimpToolWidget *rectangle,
76 GimpCropTool *crop_tool);
77 static void gimp_crop_tool_rectangle_response (GimpToolWidget *rectangle,
78 gint response_id,
79 GimpCropTool *crop_tool);
80 static void gimp_crop_tool_rectangle_change_complete (GimpToolRectangle *rectangle,
81 GimpCropTool *crop_tool);
82
83 static void gimp_crop_tool_start (GimpCropTool *crop_tool,
84 GimpDisplay *display);
85 static void gimp_crop_tool_commit (GimpCropTool *crop_tool);
86 static void gimp_crop_tool_halt (GimpCropTool *crop_tool);
87
88 static void gimp_crop_tool_update_option_defaults (GimpCropTool *crop_tool,
89 gboolean ignore_pending);
90 static GimpRectangleConstraint
91 gimp_crop_tool_get_constraint (GimpCropTool *crop_tool);
92
93 static void gimp_crop_tool_image_changed (GimpCropTool *crop_tool,
94 GimpImage *image,
95 GimpContext *context);
96 static void gimp_crop_tool_image_size_changed (GimpCropTool *crop_tool);
97 static void gimp_crop_tool_image_active_layer_changed (GimpCropTool *crop_tool);
98 static void gimp_crop_tool_layer_size_changed (GimpCropTool *crop_tool);
99
100 static void gimp_crop_tool_auto_shrink (GimpCropTool *crop_tool);
101
102
G_DEFINE_TYPE(GimpCropTool,gimp_crop_tool,GIMP_TYPE_DRAW_TOOL)103 G_DEFINE_TYPE (GimpCropTool, gimp_crop_tool, GIMP_TYPE_DRAW_TOOL)
104
105 #define parent_class gimp_crop_tool_parent_class
106
107
108 /* public functions */
109
110 void
111 gimp_crop_tool_register (GimpToolRegisterCallback callback,
112 gpointer data)
113 {
114 (* callback) (GIMP_TYPE_CROP_TOOL,
115 GIMP_TYPE_CROP_OPTIONS,
116 gimp_crop_options_gui,
117 GIMP_CONTEXT_PROP_MASK_FOREGROUND |
118 GIMP_CONTEXT_PROP_MASK_BACKGROUND |
119 GIMP_CONTEXT_PROP_MASK_PATTERN,
120 "gimp-crop-tool",
121 _("Crop"),
122 _("Crop Tool: Remove edge areas from image or layer"),
123 N_("_Crop"), "<shift>C",
124 NULL, GIMP_HELP_TOOL_CROP,
125 GIMP_ICON_TOOL_CROP,
126 data);
127 }
128
129 static void
gimp_crop_tool_class_init(GimpCropToolClass * klass)130 gimp_crop_tool_class_init (GimpCropToolClass *klass)
131 {
132 GObjectClass *object_class = G_OBJECT_CLASS (klass);
133 GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
134
135 object_class->constructed = gimp_crop_tool_constructed;
136 object_class->dispose = gimp_crop_tool_dispose;
137
138 tool_class->control = gimp_crop_tool_control;
139 tool_class->button_press = gimp_crop_tool_button_press;
140 tool_class->button_release = gimp_crop_tool_button_release;
141 tool_class->motion = gimp_crop_tool_motion;
142 tool_class->options_notify = gimp_crop_tool_options_notify;
143 }
144
145 static void
gimp_crop_tool_init(GimpCropTool * crop_tool)146 gimp_crop_tool_init (GimpCropTool *crop_tool)
147 {
148 GimpTool *tool = GIMP_TOOL (crop_tool);
149
150 gimp_tool_control_set_wants_click (tool->control, TRUE);
151 gimp_tool_control_set_active_modifiers (tool->control,
152 GIMP_TOOL_ACTIVE_MODIFIERS_SEPARATE);
153 gimp_tool_control_set_precision (tool->control,
154 GIMP_CURSOR_PRECISION_PIXEL_BORDER);
155 gimp_tool_control_set_cursor (tool->control,
156 GIMP_CURSOR_CROSSHAIR_SMALL);
157 gimp_tool_control_set_tool_cursor (tool->control,
158 GIMP_TOOL_CURSOR_CROP);
159
160 gimp_draw_tool_set_default_status (GIMP_DRAW_TOOL (tool),
161 _("Click-Drag to draw a crop rectangle"));
162 }
163
164 static void
gimp_crop_tool_constructed(GObject * object)165 gimp_crop_tool_constructed (GObject *object)
166 {
167 GimpCropTool *crop_tool = GIMP_CROP_TOOL (object);
168 GimpContext *context;
169 GimpToolInfo *tool_info;
170
171 G_OBJECT_CLASS (parent_class)->constructed (object);
172
173 tool_info = GIMP_TOOL (crop_tool)->tool_info;
174
175 context = gimp_get_user_context (tool_info->gimp);
176
177 g_signal_connect_object (context, "image-changed",
178 G_CALLBACK (gimp_crop_tool_image_changed),
179 crop_tool,
180 G_CONNECT_SWAPPED);
181
182 /* Make sure we are connected to "size-changed" for the initial
183 * image.
184 */
185 gimp_crop_tool_image_changed (crop_tool,
186 gimp_context_get_image (context),
187 context);
188 }
189
190 static void
gimp_crop_tool_dispose(GObject * object)191 gimp_crop_tool_dispose (GObject *object)
192 {
193 GimpCropTool *crop_tool = GIMP_CROP_TOOL (object);
194
195 /* Clean up current_image and current_layer. */
196 gimp_crop_tool_image_changed (crop_tool, NULL, NULL);
197
198 G_OBJECT_CLASS (parent_class)->dispose (object);
199 }
200
201 static void
gimp_crop_tool_control(GimpTool * tool,GimpToolAction action,GimpDisplay * display)202 gimp_crop_tool_control (GimpTool *tool,
203 GimpToolAction action,
204 GimpDisplay *display)
205 {
206 GimpCropTool *crop_tool = GIMP_CROP_TOOL (tool);
207
208 switch (action)
209 {
210 case GIMP_TOOL_ACTION_PAUSE:
211 case GIMP_TOOL_ACTION_RESUME:
212 break;
213
214 case GIMP_TOOL_ACTION_HALT:
215 gimp_crop_tool_halt (crop_tool);
216 break;
217
218 case GIMP_TOOL_ACTION_COMMIT:
219 gimp_crop_tool_commit (crop_tool);
220 break;
221 }
222
223 GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
224 }
225
226 static void
gimp_crop_tool_button_press(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonPressType press_type,GimpDisplay * display)227 gimp_crop_tool_button_press (GimpTool *tool,
228 const GimpCoords *coords,
229 guint32 time,
230 GdkModifierType state,
231 GimpButtonPressType press_type,
232 GimpDisplay *display)
233 {
234 GimpCropTool *crop_tool = GIMP_CROP_TOOL (tool);
235
236 if (tool->display && display != tool->display)
237 gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
238
239 if (! tool->display)
240 {
241 gimp_crop_tool_start (crop_tool, display);
242
243 gimp_tool_widget_hover (crop_tool->widget, coords, state, TRUE);
244
245 /* HACK: force CREATING on a newly created rectangle; otherwise,
246 * property bindings would cause the rectangle to start with the
247 * size from tool options.
248 */
249 gimp_tool_rectangle_set_function (GIMP_TOOL_RECTANGLE (crop_tool->widget),
250 GIMP_TOOL_RECTANGLE_CREATING);
251 }
252
253 if (gimp_tool_widget_button_press (crop_tool->widget, coords, time, state,
254 press_type))
255 {
256 crop_tool->grab_widget = crop_tool->widget;
257 }
258
259 gimp_tool_control_activate (tool->control);
260 }
261
262 static void
gimp_crop_tool_button_release(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonReleaseType release_type,GimpDisplay * display)263 gimp_crop_tool_button_release (GimpTool *tool,
264 const GimpCoords *coords,
265 guint32 time,
266 GdkModifierType state,
267 GimpButtonReleaseType release_type,
268 GimpDisplay *display)
269 {
270 GimpCropTool *crop_tool = GIMP_CROP_TOOL (tool);
271
272 gimp_tool_control_halt (tool->control);
273
274 if (crop_tool->grab_widget)
275 {
276 gimp_tool_widget_button_release (crop_tool->grab_widget,
277 coords, time, state, release_type);
278 crop_tool->grab_widget = NULL;
279 }
280
281 gimp_tool_push_status (tool, display, _("Click or press Enter to crop"));
282 }
283
284 static void
gimp_crop_tool_motion(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpDisplay * display)285 gimp_crop_tool_motion (GimpTool *tool,
286 const GimpCoords *coords,
287 guint32 time,
288 GdkModifierType state,
289 GimpDisplay *display)
290 {
291 GimpCropTool *crop_tool = GIMP_CROP_TOOL (tool);
292
293 if (crop_tool->grab_widget)
294 {
295 gimp_tool_widget_motion (crop_tool->grab_widget, coords, time, state);
296 }
297 }
298
299 static void
gimp_crop_tool_options_notify(GimpTool * tool,GimpToolOptions * options,const GParamSpec * pspec)300 gimp_crop_tool_options_notify (GimpTool *tool,
301 GimpToolOptions *options,
302 const GParamSpec *pspec)
303 {
304 GimpCropTool *crop_tool = GIMP_CROP_TOOL (tool);
305
306 if (! strcmp (pspec->name, "layer-only") ||
307 ! strcmp (pspec->name, "allow-growing"))
308 {
309 if (crop_tool->widget)
310 {
311 gimp_tool_rectangle_set_constraint (GIMP_TOOL_RECTANGLE (crop_tool->widget),
312 gimp_crop_tool_get_constraint (crop_tool));
313 }
314 else
315 {
316 gimp_crop_tool_update_option_defaults (crop_tool, FALSE);
317 }
318 }
319 }
320
321 static void
gimp_crop_tool_rectangle_changed(GimpToolWidget * rectangle,GimpCropTool * crop_tool)322 gimp_crop_tool_rectangle_changed (GimpToolWidget *rectangle,
323 GimpCropTool *crop_tool)
324 {
325 }
326
327 static void
gimp_crop_tool_rectangle_response(GimpToolWidget * rectangle,gint response_id,GimpCropTool * crop_tool)328 gimp_crop_tool_rectangle_response (GimpToolWidget *rectangle,
329 gint response_id,
330 GimpCropTool *crop_tool)
331 {
332 GimpTool *tool = GIMP_TOOL (crop_tool);
333
334 switch (response_id)
335 {
336 case GIMP_TOOL_WIDGET_RESPONSE_CONFIRM:
337 gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, tool->display);
338 break;
339
340 case GIMP_TOOL_WIDGET_RESPONSE_CANCEL:
341 gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
342 break;
343 }
344 }
345
346 static void
gimp_crop_tool_rectangle_change_complete(GimpToolRectangle * rectangle,GimpCropTool * crop_tool)347 gimp_crop_tool_rectangle_change_complete (GimpToolRectangle *rectangle,
348 GimpCropTool *crop_tool)
349 {
350 gimp_crop_tool_update_option_defaults (crop_tool, FALSE);
351 }
352
353 static void
gimp_crop_tool_start(GimpCropTool * crop_tool,GimpDisplay * display)354 gimp_crop_tool_start (GimpCropTool *crop_tool,
355 GimpDisplay *display)
356 {
357 static const gchar *properties[] =
358 {
359 "highlight",
360 "highlight-opacity",
361 "guide",
362 "x",
363 "y",
364 "width",
365 "height",
366 "fixed-rule-active",
367 "fixed-rule",
368 "desired-fixed-width",
369 "desired-fixed-height",
370 "desired-fixed-size-width",
371 "desired-fixed-size-height",
372 "aspect-numerator",
373 "aspect-denominator",
374 "fixed-center"
375 };
376
377 GimpTool *tool = GIMP_TOOL (crop_tool);
378 GimpDisplayShell *shell = gimp_display_get_shell (display);
379 GimpCropOptions *options = GIMP_CROP_TOOL_GET_OPTIONS (crop_tool);
380 GimpToolWidget *widget;
381 gint i;
382
383 tool->display = display;
384
385 crop_tool->widget = widget = gimp_tool_rectangle_new (shell);
386
387 g_object_set (widget,
388 "status-title", _("Crop to: "),
389 NULL);
390
391 gimp_draw_tool_set_widget (GIMP_DRAW_TOOL (tool), widget);
392
393 for (i = 0; i < G_N_ELEMENTS (properties); i++)
394 {
395 GBinding *binding =
396 g_object_bind_property (G_OBJECT (options), properties[i],
397 G_OBJECT (widget), properties[i],
398 G_BINDING_SYNC_CREATE |
399 G_BINDING_BIDIRECTIONAL);
400
401 crop_tool->bindings = g_list_prepend (crop_tool->bindings, binding);
402 }
403
404 gimp_rectangle_options_connect (GIMP_RECTANGLE_OPTIONS (options),
405 gimp_display_get_image (shell->display),
406 G_CALLBACK (gimp_crop_tool_auto_shrink),
407 crop_tool);
408
409 gimp_tool_rectangle_set_constraint (GIMP_TOOL_RECTANGLE (widget),
410 gimp_crop_tool_get_constraint (crop_tool));
411
412 g_signal_connect (widget, "changed",
413 G_CALLBACK (gimp_crop_tool_rectangle_changed),
414 crop_tool);
415 g_signal_connect (widget, "response",
416 G_CALLBACK (gimp_crop_tool_rectangle_response),
417 crop_tool);
418 g_signal_connect (widget, "change-complete",
419 G_CALLBACK (gimp_crop_tool_rectangle_change_complete),
420 crop_tool);
421
422 gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
423 }
424
425 static void
gimp_crop_tool_commit(GimpCropTool * crop_tool)426 gimp_crop_tool_commit (GimpCropTool *crop_tool)
427 {
428 GimpTool *tool = GIMP_TOOL (crop_tool);
429
430 if (tool->display)
431 {
432 GimpCropOptions *options = GIMP_CROP_TOOL_GET_OPTIONS (tool);
433 GimpImage *image = gimp_display_get_image (tool->display);
434 gdouble x, y;
435 gdouble x2, y2;
436 gint w, h;
437
438 gimp_tool_rectangle_get_public_rect (GIMP_TOOL_RECTANGLE (crop_tool->widget),
439 &x, &y, &x2, &y2);
440 w = x2 - x;
441 h = y2 - y;
442
443 gimp_tool_pop_status (tool, tool->display);
444
445 /* if rectangle exists, crop it */
446 if (w > 0 && h > 0)
447 {
448 if (options->layer_only)
449 {
450 GimpLayer *layer = gimp_image_get_active_layer (image);
451 gint off_x, off_y;
452
453 if (! layer)
454 {
455 gimp_tool_message_literal (tool, tool->display,
456 _("There is no active layer to crop."));
457 return;
458 }
459
460 if (gimp_item_is_content_locked (GIMP_ITEM (layer)))
461 {
462 gimp_tool_message_literal (tool, tool->display,
463 _("The active layer's pixels are locked."));
464 gimp_tools_blink_lock_box (tool->display->gimp,
465 GIMP_ITEM (layer));
466 return;
467 }
468
469 gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
470
471 off_x -= x;
472 off_y -= y;
473
474 gimp_item_resize (GIMP_ITEM (layer),
475 GIMP_CONTEXT (options), options->fill_type,
476 w, h, off_x, off_y);
477 }
478 else
479 {
480 gimp_image_crop (image,
481 GIMP_CONTEXT (options), GIMP_FILL_TRANSPARENT,
482 x, y, w, h, options->delete_pixels);
483 }
484
485 gimp_image_flush (image);
486 }
487 }
488 }
489
490 static void
gimp_crop_tool_halt(GimpCropTool * crop_tool)491 gimp_crop_tool_halt (GimpCropTool *crop_tool)
492 {
493 GimpTool *tool = GIMP_TOOL (crop_tool);
494 GimpCropOptions *options = GIMP_CROP_TOOL_GET_OPTIONS (crop_tool);
495
496 if (tool->display)
497 {
498 GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
499
500 gimp_display_shell_set_highlight (shell, NULL, 0.0);
501
502 gimp_rectangle_options_disconnect (GIMP_RECTANGLE_OPTIONS (options),
503 G_CALLBACK (gimp_crop_tool_auto_shrink),
504 crop_tool);
505 }
506
507 if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
508 gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
509
510 /* disconnect bindings manually so they are really gone *now*, we
511 * might be in the middle of a signal emission that keeps the
512 * widget and its bindings alive.
513 */
514 g_list_free_full (crop_tool->bindings, (GDestroyNotify) g_object_unref);
515 crop_tool->bindings = NULL;
516
517 gimp_draw_tool_set_widget (GIMP_DRAW_TOOL (tool), NULL);
518 g_clear_object (&crop_tool->widget);
519
520 tool->display = NULL;
521 tool->drawable = NULL;
522
523 gimp_crop_tool_update_option_defaults (crop_tool, TRUE);
524 }
525
526 /**
527 * gimp_crop_tool_update_option_defaults:
528 * @crop_tool:
529 * @ignore_pending: %TRUE to ignore any pending crop rectangle.
530 *
531 * Sets the default Fixed: Aspect ratio and Fixed: Size option
532 * properties.
533 */
534 static void
gimp_crop_tool_update_option_defaults(GimpCropTool * crop_tool,gboolean ignore_pending)535 gimp_crop_tool_update_option_defaults (GimpCropTool *crop_tool,
536 gboolean ignore_pending)
537 {
538 GimpTool *tool = GIMP_TOOL (crop_tool);
539 GimpToolRectangle *rectangle = GIMP_TOOL_RECTANGLE (crop_tool->widget);
540 GimpRectangleOptions *options;
541
542 options = GIMP_RECTANGLE_OPTIONS (GIMP_TOOL_GET_OPTIONS (tool));
543
544 if (rectangle && ! ignore_pending)
545 {
546 /* There is a pending rectangle and we should not ignore it, so
547 * set default Fixed: Aspect ratio to the same as the current
548 * pending rectangle width/height.
549 */
550
551 gimp_tool_rectangle_pending_size_set (rectangle,
552 G_OBJECT (options),
553 "default-aspect-numerator",
554 "default-aspect-denominator");
555
556 g_object_set (G_OBJECT (options),
557 "use-string-current", TRUE,
558 NULL);
559 }
560 else
561 {
562 /* There is no pending rectangle, set default Fixed: Aspect
563 * ratio to that of the current image/layer.
564 */
565
566 if (! rectangle)
567 {
568 /* ugly hack: if we don't have a widget, construct a temporary one
569 * so that we can use it to call
570 * gimp_tool_rectangle_constraint_size_set().
571 */
572
573 GimpContext *context = gimp_get_user_context (tool->tool_info->gimp);
574 GimpDisplay *display = gimp_context_get_display (context);
575
576 if (display)
577 {
578 GimpDisplayShell *shell = gimp_display_get_shell (display);
579
580 rectangle = GIMP_TOOL_RECTANGLE (gimp_tool_rectangle_new (shell));
581
582 gimp_tool_rectangle_set_constraint (
583 rectangle, gimp_crop_tool_get_constraint (crop_tool));
584 }
585 }
586
587 if (rectangle)
588 {
589 gimp_tool_rectangle_constraint_size_set (rectangle,
590 G_OBJECT (options),
591 "default-aspect-numerator",
592 "default-aspect-denominator");
593
594 if (! crop_tool->widget)
595 g_object_unref (rectangle);
596 }
597
598 g_object_set (G_OBJECT (options),
599 "use-string-current", FALSE,
600 NULL);
601 }
602 }
603
604 static GimpRectangleConstraint
gimp_crop_tool_get_constraint(GimpCropTool * crop_tool)605 gimp_crop_tool_get_constraint (GimpCropTool *crop_tool)
606 {
607 GimpCropOptions *crop_options = GIMP_CROP_TOOL_GET_OPTIONS (crop_tool);
608
609 if (crop_options->allow_growing)
610 {
611 return GIMP_RECTANGLE_CONSTRAIN_NONE;
612 }
613 else
614 {
615 return crop_options->layer_only ? GIMP_RECTANGLE_CONSTRAIN_DRAWABLE :
616 GIMP_RECTANGLE_CONSTRAIN_IMAGE;
617 }
618 }
619
620 static void
gimp_crop_tool_image_changed(GimpCropTool * crop_tool,GimpImage * image,GimpContext * context)621 gimp_crop_tool_image_changed (GimpCropTool *crop_tool,
622 GimpImage *image,
623 GimpContext *context)
624 {
625 if (crop_tool->current_image)
626 {
627 g_signal_handlers_disconnect_by_func (crop_tool->current_image,
628 gimp_crop_tool_image_size_changed,
629 NULL);
630 g_signal_handlers_disconnect_by_func (crop_tool->current_image,
631 gimp_crop_tool_image_active_layer_changed,
632 NULL);
633
634 g_object_remove_weak_pointer (G_OBJECT (crop_tool->current_image),
635 (gpointer) &crop_tool->current_image);
636 }
637
638 crop_tool->current_image = image;
639
640 if (crop_tool->current_image)
641 {
642 g_object_add_weak_pointer (G_OBJECT (crop_tool->current_image),
643 (gpointer) &crop_tool->current_image);
644
645 g_signal_connect_object (crop_tool->current_image, "size-changed",
646 G_CALLBACK (gimp_crop_tool_image_size_changed),
647 crop_tool,
648 G_CONNECT_SWAPPED);
649 g_signal_connect_object (crop_tool->current_image, "active-layer-changed",
650 G_CALLBACK (gimp_crop_tool_image_active_layer_changed),
651 crop_tool,
652 G_CONNECT_SWAPPED);
653 }
654
655 /* Make sure we are connected to "size-changed" for the initial
656 * layer.
657 */
658 gimp_crop_tool_image_active_layer_changed (crop_tool);
659
660 gimp_crop_tool_update_option_defaults (GIMP_CROP_TOOL (crop_tool), FALSE);
661 }
662
663 static void
gimp_crop_tool_image_size_changed(GimpCropTool * crop_tool)664 gimp_crop_tool_image_size_changed (GimpCropTool *crop_tool)
665 {
666 gimp_crop_tool_update_option_defaults (crop_tool, FALSE);
667 }
668
669 static void
gimp_crop_tool_image_active_layer_changed(GimpCropTool * crop_tool)670 gimp_crop_tool_image_active_layer_changed (GimpCropTool *crop_tool)
671 {
672 if (crop_tool->current_layer)
673 {
674 g_signal_handlers_disconnect_by_func (crop_tool->current_layer,
675 gimp_crop_tool_layer_size_changed,
676 NULL);
677
678 g_object_remove_weak_pointer (G_OBJECT (crop_tool->current_layer),
679 (gpointer) &crop_tool->current_layer);
680 }
681
682 if (crop_tool->current_image)
683 {
684 crop_tool->current_layer =
685 gimp_image_get_active_layer (crop_tool->current_image);
686 }
687 else
688 {
689 crop_tool->current_layer = NULL;
690 }
691
692 if (crop_tool->current_layer)
693 {
694 g_object_add_weak_pointer (G_OBJECT (crop_tool->current_layer),
695 (gpointer) &crop_tool->current_layer);
696
697 g_signal_connect_object (crop_tool->current_layer, "size-changed",
698 G_CALLBACK (gimp_crop_tool_layer_size_changed),
699 crop_tool,
700 G_CONNECT_SWAPPED);
701 }
702
703 gimp_crop_tool_update_option_defaults (crop_tool, FALSE);
704 }
705
706 static void
gimp_crop_tool_layer_size_changed(GimpCropTool * crop_tool)707 gimp_crop_tool_layer_size_changed (GimpCropTool *crop_tool)
708 {
709 gimp_crop_tool_update_option_defaults (crop_tool, FALSE);
710 }
711
712 static void
gimp_crop_tool_auto_shrink(GimpCropTool * crop_tool)713 gimp_crop_tool_auto_shrink (GimpCropTool *crop_tool)
714 {
715 gboolean shrink_merged ;
716
717 g_object_get (gimp_tool_get_options (GIMP_TOOL (crop_tool)),
718 "shrink-merged", &shrink_merged,
719 NULL);
720
721 gimp_tool_rectangle_auto_shrink (GIMP_TOOL_RECTANGLE (crop_tool->widget),
722 shrink_merged);
723 }
724