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 "core/gimpchannel.h"
31 #include "core/gimpdrawable.h"
32 #include "core/gimpdrawablefilter.h"
33 #include "core/gimpimage.h"
34 #include "core/gimplayer.h"
35 #include "core/gimplayermask.h"
36
37 #include "widgets/gimphelp-ids.h"
38
39 #include "display/gimpdisplay.h"
40 #include "display/gimptoolgui.h"
41
42 #include "gimpoffsettool.h"
43 #include "gimpfilteroptions.h"
44 #include "gimptoolcontrol.h"
45
46 #include "gimp-intl.h"
47
48
49 static gboolean gimp_offset_tool_initialize (GimpTool *tool,
50 GimpDisplay *display,
51 GError **error);
52 static void gimp_offset_tool_control (GimpTool *tool,
53 GimpToolAction action,
54 GimpDisplay *display);
55 static void gimp_offset_tool_button_press (GimpTool *tool,
56 const GimpCoords *coords,
57 guint32 time,
58 GdkModifierType state,
59 GimpButtonPressType press_type,
60 GimpDisplay *display);
61 static void gimp_offset_tool_button_release (GimpTool *tool,
62 const GimpCoords *coords,
63 guint32 time,
64 GdkModifierType state,
65 GimpButtonReleaseType release_type,
66 GimpDisplay *display);
67 static void gimp_offset_tool_motion (GimpTool *tool,
68 const GimpCoords *coords,
69 guint32 time,
70 GdkModifierType state,
71 GimpDisplay *display);
72 static void gimp_offset_tool_oper_update (GimpTool *tool,
73 const GimpCoords *coords,
74 GdkModifierType state,
75 gboolean proximity,
76 GimpDisplay *display);
77 static void gimp_offset_tool_cursor_update (GimpTool *tool,
78 const GimpCoords *coords,
79 GdkModifierType state,
80 GimpDisplay *display);
81
82 static gchar * gimp_offset_tool_get_operation (GimpFilterTool *filter_tool,
83 gchar **description);
84 static void gimp_offset_tool_dialog (GimpFilterTool *filter_tool);
85 static void gimp_offset_tool_config_notify (GimpFilterTool *filter_tool,
86 GimpConfig *config,
87 const GParamSpec *pspec);
88 static void gimp_offset_tool_region_changed (GimpFilterTool *filter_tool);
89
90 static void gimp_offset_tool_offset_changed (GimpSizeEntry *se,
91 GimpOffsetTool *offset_tool);
92
93 static void gimp_offset_tool_half_xy_clicked (GtkButton *button,
94 GimpOffsetTool *offset_tool);
95 static void gimp_offset_tool_half_x_clicked (GtkButton *button,
96 GimpOffsetTool *offset_tool);
97 static void gimp_offset_tool_half_y_clicked (GtkButton *button,
98 GimpOffsetTool *offset_tool);
99
100 static void gimp_offset_tool_edge_behavior_toggled (GtkToggleButton *toggle,
101 GimpOffsetTool *offset_tool);
102
103 static void gimp_offset_tool_background_changed (GimpContext *context,
104 const GimpRGB *color,
105 GimpOffsetTool *offset_tool);
106
107 static gint gimp_offset_tool_get_width (GimpOffsetTool *offset_tool);
108 static gint gimp_offset_tool_get_height (GimpOffsetTool *offset_tool);
109
110 static void gimp_offset_tool_update (GimpOffsetTool *offset_tool);
111
112 static void gimp_offset_tool_halt (GimpOffsetTool *offset_tool);
113
114
G_DEFINE_TYPE(GimpOffsetTool,gimp_offset_tool,GIMP_TYPE_FILTER_TOOL)115 G_DEFINE_TYPE (GimpOffsetTool, gimp_offset_tool,
116 GIMP_TYPE_FILTER_TOOL)
117
118 #define parent_class gimp_offset_tool_parent_class
119
120
121 void
122 gimp_offset_tool_register (GimpToolRegisterCallback callback,
123 gpointer data)
124 {
125 (* callback) (GIMP_TYPE_OFFSET_TOOL,
126 GIMP_TYPE_FILTER_OPTIONS, NULL,
127 GIMP_CONTEXT_PROP_MASK_BACKGROUND,
128 "gimp-offset-tool",
129 _("Offset"),
130 _("Shift the pixels, optionally wrapping them at the borders"),
131 N_("_Offset..."), NULL,
132 NULL, GIMP_HELP_TOOL_OFFSET,
133 GIMP_ICON_TOOL_OFFSET,
134 data);
135 }
136
137 static void
gimp_offset_tool_class_init(GimpOffsetToolClass * klass)138 gimp_offset_tool_class_init (GimpOffsetToolClass *klass)
139 {
140 GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
141 GimpFilterToolClass *filter_tool_class = GIMP_FILTER_TOOL_CLASS (klass);
142
143 tool_class->initialize = gimp_offset_tool_initialize;
144 tool_class->control = gimp_offset_tool_control;
145 tool_class->button_press = gimp_offset_tool_button_press;
146 tool_class->button_release = gimp_offset_tool_button_release;
147 tool_class->motion = gimp_offset_tool_motion;
148 tool_class->oper_update = gimp_offset_tool_oper_update;
149 tool_class->cursor_update = gimp_offset_tool_cursor_update;
150
151 filter_tool_class->get_operation = gimp_offset_tool_get_operation;
152 filter_tool_class->dialog = gimp_offset_tool_dialog;
153 filter_tool_class->config_notify = gimp_offset_tool_config_notify;
154 filter_tool_class->region_changed = gimp_offset_tool_region_changed;
155 }
156
157 static void
gimp_offset_tool_init(GimpOffsetTool * offset_tool)158 gimp_offset_tool_init (GimpOffsetTool *offset_tool)
159 {
160 GimpTool *tool = GIMP_TOOL (offset_tool);
161
162 gimp_tool_control_set_scroll_lock (tool->control, TRUE);
163 gimp_tool_control_set_precision (tool->control,
164 GIMP_CURSOR_PRECISION_PIXEL_CENTER);
165 }
166
167 static gboolean
gimp_offset_tool_initialize(GimpTool * tool,GimpDisplay * display,GError ** error)168 gimp_offset_tool_initialize (GimpTool *tool,
169 GimpDisplay *display,
170 GError **error)
171 {
172 GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
173 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (tool);
174 GimpContext *context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool));
175 GimpImage *image;
176 gdouble xres;
177 gdouble yres;
178
179 if (! GIMP_TOOL_CLASS (parent_class)->initialize (tool, display, error))
180 return FALSE;
181
182 image = gimp_item_get_image (GIMP_ITEM (tool->drawable));
183
184 gimp_image_get_resolution (image, &xres, &yres);
185
186 g_signal_handlers_block_by_func (offset_tool->offset_se,
187 gimp_offset_tool_offset_changed,
188 offset_tool);
189
190 gimp_size_entry_set_resolution (
191 GIMP_SIZE_ENTRY (offset_tool->offset_se), 0,
192 xres, FALSE);
193 gimp_size_entry_set_resolution (
194 GIMP_SIZE_ENTRY (offset_tool->offset_se), 1,
195 yres, FALSE);
196
197 if (GIMP_IS_LAYER (tool->drawable))
198 gimp_tool_gui_set_description (filter_tool->gui, _("Offset Layer"));
199 else if (GIMP_IS_LAYER_MASK (tool->drawable))
200 gimp_tool_gui_set_description (filter_tool->gui, _("Offset Layer Mask"));
201 else if (GIMP_IS_CHANNEL (tool->drawable))
202 gimp_tool_gui_set_description (filter_tool->gui, _("Offset Channel"));
203 else
204 g_warning ("%s: unexpected drawable type", G_STRFUNC);
205
206 gtk_widget_set_sensitive (offset_tool->transparent_radio,
207 gimp_drawable_has_alpha (tool->drawable));
208
209 g_signal_handlers_unblock_by_func (offset_tool->offset_se,
210 gimp_offset_tool_offset_changed,
211 offset_tool);
212
213 gegl_node_set (
214 filter_tool->operation,
215 "context", context,
216 NULL);
217
218 g_signal_connect (context, "background-changed",
219 G_CALLBACK (gimp_offset_tool_background_changed),
220 offset_tool);
221
222 gimp_offset_tool_update (offset_tool);
223
224 return TRUE;
225 }
226
227 static void
gimp_offset_tool_control(GimpTool * tool,GimpToolAction action,GimpDisplay * display)228 gimp_offset_tool_control (GimpTool *tool,
229 GimpToolAction action,
230 GimpDisplay *display)
231 {
232 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (tool);
233
234 switch (action)
235 {
236 case GIMP_TOOL_ACTION_PAUSE:
237 case GIMP_TOOL_ACTION_RESUME:
238 break;
239
240 case GIMP_TOOL_ACTION_HALT:
241 gimp_offset_tool_halt (offset_tool);
242 break;
243
244 case GIMP_TOOL_ACTION_COMMIT:
245 break;
246 }
247
248 GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
249 }
250
251 static gchar *
gimp_offset_tool_get_operation(GimpFilterTool * filter_tool,gchar ** description)252 gimp_offset_tool_get_operation (GimpFilterTool *filter_tool,
253 gchar **description)
254 {
255 return g_strdup ("gimp:offset");
256 }
257
258 static void
gimp_offset_tool_button_press(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonPressType press_type,GimpDisplay * display)259 gimp_offset_tool_button_press (GimpTool *tool,
260 const GimpCoords *coords,
261 guint32 time,
262 GdkModifierType state,
263 GimpButtonPressType press_type,
264 GimpDisplay *display)
265 {
266 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (tool);
267
268 offset_tool->dragging = ! gimp_filter_tool_on_guide (GIMP_FILTER_TOOL (tool),
269 coords, display);
270
271 if (! offset_tool->dragging)
272 {
273 GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
274 press_type, display);
275 }
276 else
277 {
278 offset_tool->x = coords->x;
279 offset_tool->y = coords->y;
280
281 g_object_get (GIMP_FILTER_TOOL (tool)->config,
282 "x", &offset_tool->offset_x,
283 "y", &offset_tool->offset_y,
284 NULL);
285
286 tool->display = display;
287
288 gimp_tool_control_activate (tool->control);
289
290 gimp_tool_pop_status (tool, display);
291
292 gimp_tool_push_status_coords (tool, display,
293 GIMP_CURSOR_PRECISION_PIXEL_CENTER,
294 _("Offset: "),
295 0,
296 ", ",
297 0,
298 NULL);
299 }
300 }
301
302 static void
gimp_offset_tool_button_release(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonReleaseType release_type,GimpDisplay * display)303 gimp_offset_tool_button_release (GimpTool *tool,
304 const GimpCoords *coords,
305 guint32 time,
306 GdkModifierType state,
307 GimpButtonReleaseType release_type,
308 GimpDisplay *display)
309 {
310 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (tool);
311
312 if (! offset_tool->dragging)
313 {
314 GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
315 release_type, display);
316 }
317 else
318 {
319 gimp_tool_control_halt (tool->control);
320
321 offset_tool->dragging = FALSE;
322
323 if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
324 {
325 g_object_set (GIMP_FILTER_TOOL (tool)->config,
326 "x", offset_tool->offset_x,
327 "y", offset_tool->offset_y,
328 NULL);
329 }
330 }
331 }
332
333 static void
gimp_offset_tool_motion(GimpTool * tool,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpDisplay * display)334 gimp_offset_tool_motion (GimpTool *tool,
335 const GimpCoords *coords,
336 guint32 time,
337 GdkModifierType state,
338 GimpDisplay *display)
339 {
340 GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
341 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (tool);
342
343 if (! offset_tool->dragging)
344 {
345 GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
346 display);
347 }
348 else
349 {
350 GimpOffsetType type;
351 gint offset_x;
352 gint offset_y;
353 gint x;
354 gint y;
355 gint width;
356 gint height;
357
358 g_object_get (filter_tool->config,
359 "type", &type,
360 NULL);
361
362 offset_x = RINT (coords->x - offset_tool->x);
363 offset_y = RINT (coords->y - offset_tool->y);
364
365 x = offset_tool->offset_x + offset_x;
366 y = offset_tool->offset_y + offset_y;
367
368 width = gimp_offset_tool_get_width (offset_tool);
369 height = gimp_offset_tool_get_height (offset_tool);
370
371 if (type == GIMP_OFFSET_WRAP_AROUND)
372 {
373 x %= MAX (width, 1);
374 y %= MAX (height, 1);
375 }
376 else
377 {
378 x = CLAMP (x, -width, +width);
379 y = CLAMP (y, -height, +height);
380 }
381
382 g_object_set (filter_tool->config,
383 "x", x,
384 "y", y,
385 NULL);
386
387 gimp_tool_pop_status (tool, display);
388
389 gimp_tool_push_status_coords (tool, display,
390 GIMP_CURSOR_PRECISION_PIXEL_CENTER,
391 _("Offset: "),
392 offset_x,
393 ", ",
394 offset_y,
395 NULL);
396 }
397 }
398
399 static void
gimp_offset_tool_oper_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,gboolean proximity,GimpDisplay * display)400 gimp_offset_tool_oper_update (GimpTool *tool,
401 const GimpCoords *coords,
402 GdkModifierType state,
403 gboolean proximity,
404 GimpDisplay *display)
405 {
406 if (! tool->drawable ||
407 gimp_filter_tool_on_guide (GIMP_FILTER_TOOL (tool),
408 coords, display))
409 {
410 GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
411 proximity, display);
412 }
413 else
414 {
415 gimp_tool_pop_status (tool, display);
416
417 gimp_tool_push_status (tool, display, "%s",
418 _("Click-Drag to offset drawable"));
419 }
420 }
421
422 static void
gimp_offset_tool_cursor_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,GimpDisplay * display)423 gimp_offset_tool_cursor_update (GimpTool *tool,
424 const GimpCoords *coords,
425 GdkModifierType state,
426 GimpDisplay *display)
427 {
428 if (! tool->drawable ||
429 gimp_filter_tool_on_guide (GIMP_FILTER_TOOL (tool),
430 coords, display))
431 {
432 GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
433 display);
434 }
435 else
436 {
437 gimp_tool_set_cursor (tool, display,
438 GIMP_CURSOR_MOUSE,
439 GIMP_TOOL_CURSOR_MOVE,
440 GIMP_CURSOR_MODIFIER_NONE);
441 }
442 }
443
444 static void
gimp_offset_tool_dialog(GimpFilterTool * filter_tool)445 gimp_offset_tool_dialog (GimpFilterTool *filter_tool)
446 {
447 GimpOffsetTool *offset_tool = GIMP_OFFSET_TOOL (filter_tool);
448 GtkWidget *main_vbox;
449 GtkWidget *vbox;
450 GtkWidget *hbox;
451 GtkWidget *button;
452 GtkWidget *spinbutton;
453 GtkWidget *frame;
454 GtkAdjustment *adjustment;
455
456 main_vbox = gimp_filter_tool_dialog_get_vbox (filter_tool);
457
458 /* The offset frame */
459 frame = gimp_frame_new (_("Offset"));
460 gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
461 gtk_widget_show (frame);
462
463 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
464 gtk_container_add (GTK_CONTAINER (frame), vbox);
465 gtk_widget_show (vbox);
466
467 adjustment = (GtkAdjustment *)
468 gtk_adjustment_new (1, 1, 1, 1, 10, 0);
469 spinbutton = gimp_spin_button_new (adjustment, 1.0, 2);
470 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
471 gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
472
473 offset_tool->offset_se = gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a",
474 TRUE, TRUE, FALSE, 10,
475 GIMP_SIZE_ENTRY_UPDATE_SIZE);
476
477 gtk_table_set_col_spacing (GTK_TABLE (offset_tool->offset_se), 0, 4);
478 gtk_table_set_col_spacing (GTK_TABLE (offset_tool->offset_se), 1, 4);
479 gtk_table_set_row_spacing (GTK_TABLE (offset_tool->offset_se), 0, 2);
480
481 gimp_size_entry_add_field (GIMP_SIZE_ENTRY (offset_tool->offset_se),
482 GTK_SPIN_BUTTON (spinbutton), NULL);
483 gtk_table_attach_defaults (GTK_TABLE (offset_tool->offset_se), spinbutton,
484 1, 2, 0, 1);
485 gtk_widget_show (spinbutton);
486
487 gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (offset_tool->offset_se),
488 _("_X:"), 0, 0, 0.0);
489 gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (offset_tool->offset_se),
490 _("_Y:"), 1, 0, 0.0);
491
492 gtk_box_pack_start (GTK_BOX (vbox), offset_tool->offset_se, FALSE, FALSE, 0);
493 gtk_widget_show (offset_tool->offset_se);
494
495 gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (offset_tool->offset_se),
496 GIMP_UNIT_PIXEL);
497
498 g_signal_connect (offset_tool->offset_se, "refval-changed",
499 G_CALLBACK (gimp_offset_tool_offset_changed),
500 offset_tool);
501 g_signal_connect (offset_tool->offset_se, "value-changed",
502 G_CALLBACK (gimp_offset_tool_offset_changed),
503 offset_tool);
504
505 button = gtk_button_new_with_mnemonic (_("By width/_2, height/2"));
506 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
507 gtk_widget_show (button);
508
509 g_signal_connect (button, "clicked",
510 G_CALLBACK (gimp_offset_tool_half_xy_clicked),
511 offset_tool);
512
513 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
514 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
515 gtk_widget_show (hbox);
516
517 button = gtk_button_new_with_mnemonic (_("By _width/2"));
518 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
519 gtk_widget_show (button);
520
521 g_signal_connect (button, "clicked",
522 G_CALLBACK (gimp_offset_tool_half_x_clicked),
523 offset_tool);
524
525 button = gtk_button_new_with_mnemonic (_("By _height/2"));
526 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
527 gtk_widget_show (button);
528
529 g_signal_connect (button, "clicked",
530 G_CALLBACK (gimp_offset_tool_half_y_clicked),
531 offset_tool);
532
533 /* The edge behavior frame */
534 frame = gimp_int_radio_group_new (TRUE, _("Edge Behavior"),
535
536 G_CALLBACK (gimp_offset_tool_edge_behavior_toggled),
537 offset_tool,
538
539 GIMP_OFFSET_WRAP_AROUND,
540
541 _("W_rap around"),
542 GIMP_OFFSET_WRAP_AROUND, NULL,
543
544 _("Fill with _background color"),
545 GIMP_OFFSET_BACKGROUND, NULL,
546
547 _("Make _transparent"),
548 GIMP_OFFSET_TRANSPARENT,
549 &offset_tool->transparent_radio,
550 NULL);
551
552 gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
553 gtk_widget_show (frame);
554 }
555
556 static void
gimp_offset_tool_config_notify(GimpFilterTool * filter_tool,GimpConfig * config,const GParamSpec * pspec)557 gimp_offset_tool_config_notify (GimpFilterTool *filter_tool,
558 GimpConfig *config,
559 const GParamSpec *pspec)
560 {
561 gimp_offset_tool_update (GIMP_OFFSET_TOOL (filter_tool));
562
563 GIMP_FILTER_TOOL_CLASS (parent_class)->config_notify (filter_tool,
564 config, pspec);
565 }
566
567 static void
gimp_offset_tool_region_changed(GimpFilterTool * filter_tool)568 gimp_offset_tool_region_changed (GimpFilterTool *filter_tool)
569 {
570 gimp_offset_tool_update (GIMP_OFFSET_TOOL (filter_tool));
571 }
572
573 static void
gimp_offset_tool_offset_changed(GimpSizeEntry * se,GimpOffsetTool * offset_tool)574 gimp_offset_tool_offset_changed (GimpSizeEntry *se,
575 GimpOffsetTool *offset_tool)
576 {
577 g_object_set (GIMP_FILTER_TOOL (offset_tool)->config,
578 "x", (gint) gimp_size_entry_get_refval (se, 0),
579 "y", (gint) gimp_size_entry_get_refval (se, 1),
580 NULL);
581 }
582
583 static void
gimp_offset_tool_half_xy_clicked(GtkButton * button,GimpOffsetTool * offset_tool)584 gimp_offset_tool_half_xy_clicked (GtkButton *button,
585 GimpOffsetTool *offset_tool)
586 {
587 g_object_set (GIMP_FILTER_TOOL (offset_tool)->config,
588 "x", gimp_offset_tool_get_width (offset_tool) / 2,
589 "y", gimp_offset_tool_get_height (offset_tool) / 2,
590 NULL);
591 }
592
593 static void
gimp_offset_tool_half_x_clicked(GtkButton * button,GimpOffsetTool * offset_tool)594 gimp_offset_tool_half_x_clicked (GtkButton *button,
595 GimpOffsetTool *offset_tool)
596 {
597 g_object_set (GIMP_FILTER_TOOL (offset_tool)->config,
598 "x", gimp_offset_tool_get_width (offset_tool) / 2,
599 NULL);
600 }
601
602 static void
gimp_offset_tool_half_y_clicked(GtkButton * button,GimpOffsetTool * offset_tool)603 gimp_offset_tool_half_y_clicked (GtkButton *button,
604 GimpOffsetTool *offset_tool)
605 {
606 g_object_set (GIMP_FILTER_TOOL (offset_tool)->config,
607 "y", gimp_offset_tool_get_height (offset_tool) / 2,
608 NULL);
609 }
610
611 static void
gimp_offset_tool_edge_behavior_toggled(GtkToggleButton * toggle,GimpOffsetTool * offset_tool)612 gimp_offset_tool_edge_behavior_toggled (GtkToggleButton *toggle,
613 GimpOffsetTool *offset_tool)
614 {
615 if (gtk_toggle_button_get_active (toggle))
616 {
617 GimpOffsetType type;
618
619 type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toggle),
620 "gimp-item-data"));
621
622 g_object_set (GIMP_FILTER_TOOL (offset_tool)->config,
623 "type", type,
624 NULL);
625 }
626 }
627
628 static void
gimp_offset_tool_background_changed(GimpContext * context,const GimpRGB * color,GimpOffsetTool * offset_tool)629 gimp_offset_tool_background_changed (GimpContext *context,
630 const GimpRGB *color,
631 GimpOffsetTool *offset_tool)
632 {
633 GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (offset_tool);
634 GimpOffsetType type;
635
636 g_object_get (filter_tool->config,
637 "type", &type,
638 NULL);
639
640 if (type == GIMP_OFFSET_BACKGROUND)
641 {
642 gegl_node_set (filter_tool->operation,
643 "context", context,
644 NULL);
645
646 gimp_drawable_filter_apply (filter_tool->filter, NULL);
647 }
648 }
649
650 static gint
gimp_offset_tool_get_width(GimpOffsetTool * offset_tool)651 gimp_offset_tool_get_width (GimpOffsetTool *offset_tool)
652 {
653 GeglRectangle drawable_area;
654 gint drawable_offset_x;
655 gint drawable_offset_y;
656
657 if (gimp_filter_tool_get_drawable_area (GIMP_FILTER_TOOL (offset_tool),
658 &drawable_offset_x,
659 &drawable_offset_y,
660 &drawable_area) &&
661 ! gegl_rectangle_is_empty (&drawable_area))
662 {
663 return drawable_area.width;
664 }
665
666 return 0;
667 }
668
669 static gint
gimp_offset_tool_get_height(GimpOffsetTool * offset_tool)670 gimp_offset_tool_get_height (GimpOffsetTool *offset_tool)
671 {
672 GeglRectangle drawable_area;
673 gint drawable_offset_x;
674 gint drawable_offset_y;
675
676 if (gimp_filter_tool_get_drawable_area (GIMP_FILTER_TOOL (offset_tool),
677 &drawable_offset_x,
678 &drawable_offset_y,
679 &drawable_area) &&
680 ! gegl_rectangle_is_empty (&drawable_area))
681 {
682 return drawable_area.height;
683 }
684
685 return 0;
686 }
687
688 static void
gimp_offset_tool_update(GimpOffsetTool * offset_tool)689 gimp_offset_tool_update (GimpOffsetTool *offset_tool)
690 {
691 GimpTool *tool = GIMP_TOOL (offset_tool);
692 GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (offset_tool);
693 GimpOffsetType orig_type;
694 gint orig_x;
695 gint orig_y;
696 GimpOffsetType type;
697 gint x;
698 gint y;
699 gint width;
700 gint height;
701
702 g_object_get (filter_tool->config,
703 "type", &orig_type,
704 "x", &orig_x,
705 "y", &orig_y,
706 NULL);
707
708 width = gimp_offset_tool_get_width (offset_tool);
709 height = gimp_offset_tool_get_height (offset_tool);
710
711 x = CLAMP (orig_x, -width, +width);
712 y = CLAMP (orig_y, -height, +height);
713
714 type = orig_type;
715
716 if (tool->drawable &&
717 ! gimp_drawable_has_alpha (tool->drawable) &&
718 type == GIMP_OFFSET_TRANSPARENT)
719 {
720 type = GIMP_OFFSET_BACKGROUND;
721 }
722
723 if (x != orig_x ||
724 y != orig_y ||
725 type != orig_type)
726 {
727 g_object_set (filter_tool->config,
728 "type", type,
729 "x", x,
730 "y", y,
731 NULL);
732 }
733
734 if (offset_tool->offset_se)
735 {
736 gint width = gimp_offset_tool_get_width (offset_tool);
737 gint height = gimp_offset_tool_get_height (offset_tool);
738
739 g_signal_handlers_block_by_func (offset_tool->offset_se,
740 gimp_offset_tool_offset_changed,
741 offset_tool);
742
743 gimp_size_entry_set_refval_boundaries (
744 GIMP_SIZE_ENTRY (offset_tool->offset_se), 0,
745 -width, +width);
746 gimp_size_entry_set_refval_boundaries (
747 GIMP_SIZE_ENTRY (offset_tool->offset_se), 1,
748 -height, +height);
749
750 gimp_size_entry_set_size (
751 GIMP_SIZE_ENTRY (offset_tool->offset_se), 0,
752 0, width);
753 gimp_size_entry_set_size (
754 GIMP_SIZE_ENTRY (offset_tool->offset_se), 1,
755 0, height);
756
757 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (offset_tool->offset_se), 0,
758 x);
759 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (offset_tool->offset_se), 1,
760 y);
761
762 g_signal_handlers_unblock_by_func (offset_tool->offset_se,
763 gimp_offset_tool_offset_changed,
764 offset_tool);
765 }
766
767 if (offset_tool->transparent_radio)
768 {
769 gimp_int_radio_group_set_active (
770 GTK_RADIO_BUTTON (offset_tool->transparent_radio),
771 type);
772 }
773 }
774
775 static void
gimp_offset_tool_halt(GimpOffsetTool * offset_tool)776 gimp_offset_tool_halt (GimpOffsetTool *offset_tool)
777 {
778 GimpContext *context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (offset_tool));
779
780 offset_tool->offset_se = NULL;
781 offset_tool->transparent_radio = NULL;
782
783 g_signal_handlers_disconnect_by_func (
784 context,
785 gimp_offset_tool_background_changed,
786 offset_tool);
787 }
788