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 <string.h>
21 
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 
25 #include "libgimpmath/gimpmath.h"
26 
27 #include "tools-types.h"
28 
29 #include "core/gimpimage.h"
30 #include "core/gimppickable.h"
31 
32 #include "display/gimpcanvas.h"
33 #include "display/gimpcanvasarc.h"
34 #include "display/gimpcanvasboundary.h"
35 #include "display/gimpcanvasgroup.h"
36 #include "display/gimpcanvasguide.h"
37 #include "display/gimpcanvashandle.h"
38 #include "display/gimpcanvasitem-utils.h"
39 #include "display/gimpcanvasline.h"
40 #include "display/gimpcanvaspen.h"
41 #include "display/gimpcanvaspolygon.h"
42 #include "display/gimpcanvasrectangle.h"
43 #include "display/gimpcanvassamplepoint.h"
44 #include "display/gimpcanvastextcursor.h"
45 #include "display/gimpcanvastransformpreview.h"
46 #include "display/gimpdisplay.h"
47 #include "display/gimpdisplayshell.h"
48 #include "display/gimpdisplayshell-items.h"
49 #include "display/gimpdisplayshell-transform.h"
50 #include "display/gimptoolwidget.h"
51 
52 #include "gimpdrawtool.h"
53 #include "gimptoolcontrol.h"
54 
55 
56 #define USE_TIMEOUT
57 #define DRAW_FPS              120
58 #define DRAW_TIMEOUT          (1000 /* milliseconds */ / (2 * DRAW_FPS))
59 #define MINIMUM_DRAW_INTERVAL (G_TIME_SPAN_SECOND / DRAW_FPS)
60 
61 
62 static void          gimp_draw_tool_dispose       (GObject          *object);
63 
64 static gboolean      gimp_draw_tool_has_display   (GimpTool         *tool,
65                                                    GimpDisplay      *display);
66 static GimpDisplay * gimp_draw_tool_has_image     (GimpTool         *tool,
67                                                    GimpImage        *image);
68 static void          gimp_draw_tool_control       (GimpTool         *tool,
69                                                    GimpToolAction    action,
70                                                    GimpDisplay      *display);
71 static gboolean      gimp_draw_tool_key_press     (GimpTool         *tool,
72                                                    GdkEventKey      *kevent,
73                                                    GimpDisplay      *display);
74 static gboolean      gimp_draw_tool_key_release   (GimpTool         *tool,
75                                                    GdkEventKey      *kevent,
76                                                    GimpDisplay      *display);
77 static void          gimp_draw_tool_modifier_key  (GimpTool         *tool,
78                                                    GdkModifierType   key,
79                                                    gboolean          press,
80                                                    GdkModifierType   state,
81                                                    GimpDisplay      *display);
82 static void          gimp_draw_tool_active_modifier_key
83                                                   (GimpTool         *tool,
84                                                    GdkModifierType   key,
85                                                    gboolean          press,
86                                                    GdkModifierType   state,
87                                                    GimpDisplay      *display);
88 static void          gimp_draw_tool_oper_update   (GimpTool         *tool,
89                                                    const GimpCoords *coords,
90                                                    GdkModifierType   state,
91                                                    gboolean          proximity,
92                                                    GimpDisplay      *display);
93 static void          gimp_draw_tool_cursor_update (GimpTool         *tool,
94                                                    const GimpCoords *coords,
95                                                    GdkModifierType   state,
96                                                    GimpDisplay      *display);
97 
98 static void          gimp_draw_tool_widget_status (GimpToolWidget   *widget,
99                                                    const gchar      *status,
100                                                    GimpTool         *tool);
101 static void          gimp_draw_tool_widget_status_coords
102                                                   (GimpToolWidget   *widget,
103                                                    const gchar      *title,
104                                                    gdouble           x,
105                                                    const gchar      *separator,
106                                                    gdouble           y,
107                                                    const gchar      *help,
108                                                    GimpTool         *tool);
109 static void          gimp_draw_tool_widget_message
110                                                   (GimpToolWidget   *widget,
111                                                    const gchar      *message,
112                                                    GimpTool         *tool);
113 static void          gimp_draw_tool_widget_snap_offsets
114                                                   (GimpToolWidget   *widget,
115                                                    gint              offset_x,
116                                                    gint              offset_y,
117                                                    gint              width,
118                                                    gint              height,
119                                                    GimpTool         *tool);
120 
121 static void          gimp_draw_tool_draw          (GimpDrawTool     *draw_tool);
122 static void          gimp_draw_tool_undraw        (GimpDrawTool     *draw_tool);
123 static void          gimp_draw_tool_real_draw     (GimpDrawTool     *draw_tool);
124 
125 
G_DEFINE_TYPE(GimpDrawTool,gimp_draw_tool,GIMP_TYPE_TOOL)126 G_DEFINE_TYPE (GimpDrawTool, gimp_draw_tool, GIMP_TYPE_TOOL)
127 
128 #define parent_class gimp_draw_tool_parent_class
129 
130 
131 static void
132 gimp_draw_tool_class_init (GimpDrawToolClass *klass)
133 {
134   GObjectClass  *object_class = G_OBJECT_CLASS (klass);
135   GimpToolClass *tool_class   = GIMP_TOOL_CLASS (klass);
136 
137   object_class->dispose           = gimp_draw_tool_dispose;
138 
139   tool_class->has_display         = gimp_draw_tool_has_display;
140   tool_class->has_image           = gimp_draw_tool_has_image;
141   tool_class->control             = gimp_draw_tool_control;
142   tool_class->key_press           = gimp_draw_tool_key_press;
143   tool_class->key_release         = gimp_draw_tool_key_release;
144   tool_class->modifier_key        = gimp_draw_tool_modifier_key;
145   tool_class->active_modifier_key = gimp_draw_tool_active_modifier_key;
146   tool_class->oper_update         = gimp_draw_tool_oper_update;
147   tool_class->cursor_update       = gimp_draw_tool_cursor_update;
148 
149   klass->draw                     = gimp_draw_tool_real_draw;
150 }
151 
152 static void
gimp_draw_tool_init(GimpDrawTool * draw_tool)153 gimp_draw_tool_init (GimpDrawTool *draw_tool)
154 {
155   draw_tool->display      = NULL;
156   draw_tool->paused_count = 0;
157   draw_tool->preview      = NULL;
158   draw_tool->item         = NULL;
159 }
160 
161 static void
gimp_draw_tool_dispose(GObject * object)162 gimp_draw_tool_dispose (GObject *object)
163 {
164   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (object);
165 
166   if (draw_tool->draw_timeout)
167     {
168       g_source_remove (draw_tool->draw_timeout);
169       draw_tool->draw_timeout = 0;
170     }
171 
172   gimp_draw_tool_set_widget (draw_tool, NULL);
173   gimp_draw_tool_set_default_status (draw_tool, NULL);
174 
175   G_OBJECT_CLASS (parent_class)->dispose (object);
176 }
177 
178 static gboolean
gimp_draw_tool_has_display(GimpTool * tool,GimpDisplay * display)179 gimp_draw_tool_has_display (GimpTool    *tool,
180                             GimpDisplay *display)
181 {
182   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
183 
184   return (display == draw_tool->display ||
185           GIMP_TOOL_CLASS (parent_class)->has_display (tool, display));
186 }
187 
188 static GimpDisplay *
gimp_draw_tool_has_image(GimpTool * tool,GimpImage * image)189 gimp_draw_tool_has_image (GimpTool  *tool,
190                           GimpImage *image)
191 {
192   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
193   GimpDisplay  *display;
194 
195   display = GIMP_TOOL_CLASS (parent_class)->has_image (tool, image);
196 
197   if (! display && draw_tool->display)
198     {
199       if (image && gimp_display_get_image (draw_tool->display) == image)
200         display = draw_tool->display;
201 
202       /*  NULL image means any display  */
203       if (! image)
204         display = draw_tool->display;
205     }
206 
207   return display;
208 }
209 
210 static void
gimp_draw_tool_control(GimpTool * tool,GimpToolAction action,GimpDisplay * display)211 gimp_draw_tool_control (GimpTool       *tool,
212                         GimpToolAction  action,
213                         GimpDisplay    *display)
214 {
215   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
216 
217   switch (action)
218     {
219     case GIMP_TOOL_ACTION_PAUSE:
220     case GIMP_TOOL_ACTION_RESUME:
221       break;
222 
223     case GIMP_TOOL_ACTION_HALT:
224       if (gimp_draw_tool_is_active (draw_tool))
225         gimp_draw_tool_stop (draw_tool);
226       gimp_draw_tool_set_widget (draw_tool, NULL);
227       break;
228 
229     case GIMP_TOOL_ACTION_COMMIT:
230       break;
231     }
232 
233   GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
234 }
235 
236 static gboolean
gimp_draw_tool_key_press(GimpTool * tool,GdkEventKey * kevent,GimpDisplay * display)237 gimp_draw_tool_key_press (GimpTool    *tool,
238                           GdkEventKey *kevent,
239                           GimpDisplay *display)
240 {
241   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
242 
243   if (draw_tool->widget && display == draw_tool->display)
244     {
245       return gimp_tool_widget_key_press (draw_tool->widget, kevent);
246     }
247 
248   return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
249 }
250 
251 static gboolean
gimp_draw_tool_key_release(GimpTool * tool,GdkEventKey * kevent,GimpDisplay * display)252 gimp_draw_tool_key_release (GimpTool    *tool,
253                             GdkEventKey *kevent,
254                             GimpDisplay *display)
255 {
256   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
257 
258   if (draw_tool->widget && display == draw_tool->display)
259     {
260       return gimp_tool_widget_key_release (draw_tool->widget, kevent);
261     }
262 
263   return GIMP_TOOL_CLASS (parent_class)->key_release (tool, kevent, display);
264 }
265 
266 static void
gimp_draw_tool_modifier_key(GimpTool * tool,GdkModifierType key,gboolean press,GdkModifierType state,GimpDisplay * display)267 gimp_draw_tool_modifier_key (GimpTool        *tool,
268                              GdkModifierType  key,
269                              gboolean         press,
270                              GdkModifierType  state,
271                              GimpDisplay     *display)
272 {
273   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
274 
275   if (draw_tool->widget && display == draw_tool->display)
276     {
277       gimp_tool_widget_hover_modifier (draw_tool->widget, key, press, state);
278     }
279 
280   GIMP_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, state,
281                                                 display);
282 }
283 
284 static void
gimp_draw_tool_active_modifier_key(GimpTool * tool,GdkModifierType key,gboolean press,GdkModifierType state,GimpDisplay * display)285 gimp_draw_tool_active_modifier_key (GimpTool        *tool,
286                                     GdkModifierType  key,
287                                     gboolean         press,
288                                     GdkModifierType  state,
289                                     GimpDisplay     *display)
290 {
291   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
292 
293   if (draw_tool->widget && display == draw_tool->display)
294     {
295       gimp_tool_widget_motion_modifier (draw_tool->widget, key, press, state);
296     }
297 
298   GIMP_TOOL_CLASS (parent_class)->active_modifier_key (tool, key, press, state,
299                                                        display);
300 }
301 
302 static void
gimp_draw_tool_oper_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,gboolean proximity,GimpDisplay * display)303 gimp_draw_tool_oper_update (GimpTool         *tool,
304                             const GimpCoords *coords,
305                             GdkModifierType   state,
306                             gboolean          proximity,
307                             GimpDisplay      *display)
308 {
309   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
310 
311   if (draw_tool->widget && display == draw_tool->display)
312     {
313       gimp_tool_widget_hover (draw_tool->widget, coords, state, proximity);
314     }
315   else if (proximity && draw_tool->default_status)
316     {
317       gimp_tool_replace_status (tool, display, "%s", draw_tool->default_status);
318     }
319   else if (! proximity)
320     {
321       gimp_tool_pop_status (tool, display);
322     }
323   else
324     {
325       GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
326                                                    proximity, display);
327     }
328 }
329 
330 static void
gimp_draw_tool_cursor_update(GimpTool * tool,const GimpCoords * coords,GdkModifierType state,GimpDisplay * display)331 gimp_draw_tool_cursor_update (GimpTool         *tool,
332                               const GimpCoords *coords,
333                               GdkModifierType   state,
334                               GimpDisplay      *display)
335 {
336   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
337 
338   if (draw_tool->widget && display == draw_tool->display)
339     {
340       GimpCursorType     cursor;
341       GimpToolCursorType tool_cursor;
342       GimpCursorModifier modifier;
343 
344       cursor      = gimp_tool_control_get_cursor (tool->control);
345       tool_cursor = gimp_tool_control_get_tool_cursor (tool->control);
346       modifier    = gimp_tool_control_get_cursor_modifier (tool->control);
347 
348       if (gimp_tool_widget_get_cursor (draw_tool->widget, coords, state,
349                                        &cursor, &tool_cursor, &modifier))
350         {
351           gimp_tool_set_cursor (tool, display,
352                                 cursor, tool_cursor, modifier);
353           return;
354         }
355     }
356 
357   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
358                                                  display);
359 }
360 
361 static void
gimp_draw_tool_widget_status(GimpToolWidget * widget,const gchar * status,GimpTool * tool)362 gimp_draw_tool_widget_status (GimpToolWidget *widget,
363                               const gchar    *status,
364                               GimpTool       *tool)
365 {
366   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
367 
368   if (gimp_draw_tool_is_active (draw_tool))
369     {
370       if (status)
371         gimp_tool_replace_status (tool, draw_tool->display, "%s", status);
372       else
373         gimp_tool_pop_status (tool, draw_tool->display);
374     }
375 }
376 
377 static void
gimp_draw_tool_widget_status_coords(GimpToolWidget * widget,const gchar * title,gdouble x,const gchar * separator,gdouble y,const gchar * help,GimpTool * tool)378 gimp_draw_tool_widget_status_coords (GimpToolWidget *widget,
379                                      const gchar    *title,
380                                      gdouble         x,
381                                      const gchar    *separator,
382                                      gdouble         y,
383                                      const gchar    *help,
384                                      GimpTool       *tool)
385 {
386   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
387 
388   if (gimp_draw_tool_is_active (draw_tool))
389     {
390       gimp_tool_pop_status (tool, draw_tool->display);
391       gimp_tool_push_status_coords (tool, draw_tool->display,
392                                     gimp_tool_control_get_precision (
393                                       tool->control),
394                                     title, x, separator, y, help);
395     }
396 }
397 
398 static void
gimp_draw_tool_widget_message(GimpToolWidget * widget,const gchar * message,GimpTool * tool)399 gimp_draw_tool_widget_message (GimpToolWidget *widget,
400                                const gchar    *message,
401                                GimpTool       *tool)
402 {
403   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
404 
405   if (gimp_draw_tool_is_active (draw_tool))
406     gimp_tool_message_literal (tool, draw_tool->display, message);
407 }
408 
409 static void
gimp_draw_tool_widget_snap_offsets(GimpToolWidget * widget,gint offset_x,gint offset_y,gint width,gint height,GimpTool * tool)410 gimp_draw_tool_widget_snap_offsets (GimpToolWidget   *widget,
411                                     gint              offset_x,
412                                     gint              offset_y,
413                                     gint              width,
414                                     gint              height,
415                                     GimpTool         *tool)
416 {
417   gimp_tool_control_set_snap_offsets (tool->control,
418                                       offset_x, offset_y,
419                                       width, height);
420 }
421 
422 #ifdef USE_TIMEOUT
423 static gboolean
gimp_draw_tool_draw_timeout(GimpDrawTool * draw_tool)424 gimp_draw_tool_draw_timeout (GimpDrawTool *draw_tool)
425 {
426   guint64 now = g_get_monotonic_time ();
427 
428   /* keep the timeout running if the last drawing just happened */
429   if ((now - draw_tool->last_draw_time) <= MINIMUM_DRAW_INTERVAL)
430     return TRUE;
431 
432   draw_tool->draw_timeout = 0;
433 
434   gimp_draw_tool_draw (draw_tool);
435 
436   return FALSE;
437 }
438 #endif
439 
440 static void
gimp_draw_tool_draw(GimpDrawTool * draw_tool)441 gimp_draw_tool_draw (GimpDrawTool *draw_tool)
442 {
443   guint64 now = g_get_monotonic_time ();
444 
445   if (draw_tool->display &&
446       draw_tool->paused_count == 0 &&
447       (! draw_tool->draw_timeout ||
448        (now - draw_tool->last_draw_time) > MINIMUM_DRAW_INTERVAL))
449     {
450       GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
451 
452       if (draw_tool->draw_timeout)
453         {
454           g_source_remove (draw_tool->draw_timeout);
455           draw_tool->draw_timeout = 0;
456         }
457 
458       gimp_draw_tool_undraw (draw_tool);
459 
460       GIMP_DRAW_TOOL_GET_CLASS (draw_tool)->draw (draw_tool);
461 
462       if (draw_tool->group_stack)
463         {
464           g_warning ("%s: draw_tool->group_stack not empty after calling "
465                      "GimpDrawTool::draw() of %s",
466                      G_STRFUNC,
467                      g_type_name (G_TYPE_FROM_INSTANCE (draw_tool)));
468 
469           while (draw_tool->group_stack)
470             gimp_draw_tool_pop_group (draw_tool);
471         }
472 
473       if (draw_tool->preview)
474         gimp_display_shell_add_preview_item (shell, draw_tool->preview);
475 
476       if (draw_tool->item)
477         gimp_display_shell_add_tool_item (shell, draw_tool->item);
478 
479 #if 0
480       gimp_display_shell_flush (shell, TRUE);
481 #endif
482 
483       draw_tool->last_draw_time = g_get_monotonic_time ();
484 
485 #if 0
486       g_printerr ("drawing tool stuff took %f seconds\n",
487                   (draw_tool->last_draw_time - now) / 1000000.0);
488 #endif
489     }
490 }
491 
492 static void
gimp_draw_tool_undraw(GimpDrawTool * draw_tool)493 gimp_draw_tool_undraw (GimpDrawTool *draw_tool)
494 {
495   if (draw_tool->display)
496     {
497       GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
498 
499       if (draw_tool->preview)
500         {
501           gimp_display_shell_remove_preview_item (shell, draw_tool->preview);
502           g_clear_object (&draw_tool->preview);
503         }
504 
505       if (draw_tool->item)
506         {
507           gimp_display_shell_remove_tool_item (shell, draw_tool->item);
508           g_clear_object (&draw_tool->item);
509         }
510     }
511 }
512 
513 static void
gimp_draw_tool_real_draw(GimpDrawTool * draw_tool)514 gimp_draw_tool_real_draw (GimpDrawTool *draw_tool)
515 {
516   if (draw_tool->widget)
517     {
518       GimpCanvasItem *item = gimp_tool_widget_get_item (draw_tool->widget);
519 
520       gimp_draw_tool_add_item (draw_tool, item);
521     }
522 }
523 
524 void
gimp_draw_tool_start(GimpDrawTool * draw_tool,GimpDisplay * display)525 gimp_draw_tool_start (GimpDrawTool *draw_tool,
526                       GimpDisplay  *display)
527 {
528   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
529   g_return_if_fail (GIMP_IS_DISPLAY (display));
530   g_return_if_fail (gimp_draw_tool_is_active (draw_tool) == FALSE);
531 
532   draw_tool->display = display;
533 
534   gimp_draw_tool_draw (draw_tool);
535 }
536 
537 void
gimp_draw_tool_stop(GimpDrawTool * draw_tool)538 gimp_draw_tool_stop (GimpDrawTool *draw_tool)
539 {
540   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
541   g_return_if_fail (gimp_draw_tool_is_active (draw_tool) == TRUE);
542 
543   gimp_draw_tool_undraw (draw_tool);
544 
545   if (draw_tool->draw_timeout)
546     {
547       g_source_remove (draw_tool->draw_timeout);
548       draw_tool->draw_timeout = 0;
549     }
550 
551   draw_tool->last_draw_time = 0;
552 
553   draw_tool->display = NULL;
554 }
555 
556 gboolean
gimp_draw_tool_is_active(GimpDrawTool * draw_tool)557 gimp_draw_tool_is_active (GimpDrawTool *draw_tool)
558 {
559   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);
560 
561   return draw_tool->display != NULL;
562 }
563 
564 void
gimp_draw_tool_pause(GimpDrawTool * draw_tool)565 gimp_draw_tool_pause (GimpDrawTool *draw_tool)
566 {
567   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
568 
569   draw_tool->paused_count++;
570 
571   if (draw_tool->draw_timeout)
572     {
573       g_source_remove (draw_tool->draw_timeout);
574       draw_tool->draw_timeout = 0;
575     }
576 }
577 
578 void
gimp_draw_tool_resume(GimpDrawTool * draw_tool)579 gimp_draw_tool_resume (GimpDrawTool *draw_tool)
580 {
581   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
582   g_return_if_fail (draw_tool->paused_count > 0);
583 
584   draw_tool->paused_count--;
585 
586   if (draw_tool->paused_count == 0)
587     {
588 #ifdef USE_TIMEOUT
589       /* Don't install the timeout if the draw tool isn't active, so
590        * suspend()/resume() can always be called, and have no side
591        * effect on an inactive tool. See bug #687851.
592        */
593       if (gimp_draw_tool_is_active (draw_tool) && ! draw_tool->draw_timeout)
594         {
595           draw_tool->draw_timeout =
596             gdk_threads_add_timeout_full (G_PRIORITY_HIGH_IDLE,
597                                           DRAW_TIMEOUT,
598                                           (GSourceFunc) gimp_draw_tool_draw_timeout,
599                                           draw_tool, NULL);
600         }
601 #endif
602 
603       /* call draw() anyway, it will do nothing if the timeout is
604        * running, but will additionally check the drawing times to
605        * ensure the minimum framerate
606        */
607       gimp_draw_tool_draw (draw_tool);
608     }
609 }
610 
611 /**
612  * gimp_draw_tool_calc_distance:
613  * @draw_tool: a #GimpDrawTool
614  * @display:   a #GimpDisplay
615  * @x1:        start point X in image coordinates
616  * @y1:        start point Y in image coordinates
617  * @x2:        end point X in image coordinates
618  * @y2:        end point Y in image coordinates
619  *
620  * If you just need to compare distances, consider to use
621  * gimp_draw_tool_calc_distance_square() instead.
622  *
623  * Returns: the distance between the given points in display coordinates
624  **/
625 gdouble
gimp_draw_tool_calc_distance(GimpDrawTool * draw_tool,GimpDisplay * display,gdouble x1,gdouble y1,gdouble x2,gdouble y2)626 gimp_draw_tool_calc_distance (GimpDrawTool *draw_tool,
627                               GimpDisplay  *display,
628                               gdouble       x1,
629                               gdouble       y1,
630                               gdouble       x2,
631                               gdouble       y2)
632 {
633   return sqrt (gimp_draw_tool_calc_distance_square (draw_tool, display,
634                                                     x1, y1, x2, y2));
635 }
636 
637 /**
638  * gimp_draw_tool_calc_distance_square:
639  * @draw_tool: a #GimpDrawTool
640  * @display:   a #GimpDisplay
641  * @x1:        start point X in image coordinates
642  * @y1:        start point Y in image coordinates
643  * @x2:        end point X in image coordinates
644  * @y2:        end point Y in image coordinates
645  *
646  * This function is more effective than gimp_draw_tool_calc_distance()
647  * as it doesn't perform a sqrt(). Use this if you just need to compare
648  * distances.
649  *
650  * Returns: the square of the distance between the given points in
651  *          display coordinates
652  **/
653 gdouble
gimp_draw_tool_calc_distance_square(GimpDrawTool * draw_tool,GimpDisplay * display,gdouble x1,gdouble y1,gdouble x2,gdouble y2)654 gimp_draw_tool_calc_distance_square (GimpDrawTool *draw_tool,
655                                      GimpDisplay  *display,
656                                      gdouble       x1,
657                                      gdouble       y1,
658                                      gdouble       x2,
659                                      gdouble       y2)
660 {
661   GimpDisplayShell *shell;
662   gdouble           tx1, ty1;
663   gdouble           tx2, ty2;
664 
665   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), 0.0);
666   g_return_val_if_fail (GIMP_IS_DISPLAY (display), 0.0);
667 
668   shell = gimp_display_get_shell (display);
669 
670   gimp_display_shell_transform_xy_f (shell, x1, y1, &tx1, &ty1);
671   gimp_display_shell_transform_xy_f (shell, x2, y2, &tx2, &ty2);
672 
673   return SQR (tx2 - tx1) + SQR (ty2 - ty1);
674 }
675 
676 void
gimp_draw_tool_set_widget(GimpDrawTool * draw_tool,GimpToolWidget * widget)677 gimp_draw_tool_set_widget (GimpDrawTool   *draw_tool,
678                            GimpToolWidget *widget)
679 {
680   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
681   g_return_if_fail (widget == NULL || GIMP_IS_TOOL_WIDGET (widget));
682 
683   if (widget == draw_tool->widget)
684     return;
685 
686   if (draw_tool->widget)
687     {
688       gimp_tool_widget_set_focus (draw_tool->widget, FALSE);
689 
690       g_signal_handlers_disconnect_by_func (draw_tool->widget,
691                                             gimp_draw_tool_widget_status,
692                                             draw_tool);
693       g_signal_handlers_disconnect_by_func (draw_tool->widget,
694                                             gimp_draw_tool_widget_status_coords,
695                                             draw_tool);
696       g_signal_handlers_disconnect_by_func (draw_tool->widget,
697                                             gimp_draw_tool_widget_message,
698                                             draw_tool);
699       g_signal_handlers_disconnect_by_func (draw_tool->widget,
700                                             gimp_draw_tool_widget_snap_offsets,
701                                             draw_tool);
702 
703       if (gimp_draw_tool_is_active (draw_tool))
704         {
705           GimpCanvasItem *item = gimp_tool_widget_get_item (draw_tool->widget);
706 
707           gimp_draw_tool_remove_item (draw_tool, item);
708         }
709 
710       g_object_unref (draw_tool->widget);
711     }
712 
713   draw_tool->widget = widget;
714 
715   if (draw_tool->widget)
716     {
717       g_object_ref (draw_tool->widget);
718 
719       if (gimp_draw_tool_is_active (draw_tool))
720         {
721           GimpCanvasItem *item = gimp_tool_widget_get_item (draw_tool->widget);
722 
723           gimp_draw_tool_add_item (draw_tool, item);
724         }
725 
726       g_signal_connect (draw_tool->widget, "status",
727                         G_CALLBACK (gimp_draw_tool_widget_status),
728                         draw_tool);
729       g_signal_connect (draw_tool->widget, "status-coords",
730                         G_CALLBACK (gimp_draw_tool_widget_status_coords),
731                         draw_tool);
732       g_signal_connect (draw_tool->widget, "message",
733                         G_CALLBACK (gimp_draw_tool_widget_message),
734                         draw_tool);
735       g_signal_connect (draw_tool->widget, "snap-offsets",
736                         G_CALLBACK (gimp_draw_tool_widget_snap_offsets),
737                         draw_tool);
738 
739       gimp_tool_widget_set_focus (draw_tool->widget, TRUE);
740     }
741 }
742 
743 void
gimp_draw_tool_set_default_status(GimpDrawTool * draw_tool,const gchar * status)744 gimp_draw_tool_set_default_status (GimpDrawTool *draw_tool,
745                                    const gchar  *status)
746 {
747   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
748 
749   if (draw_tool->default_status)
750     g_free (draw_tool->default_status);
751 
752   draw_tool->default_status = g_strdup (status);
753 }
754 
755 void
gimp_draw_tool_add_preview(GimpDrawTool * draw_tool,GimpCanvasItem * item)756 gimp_draw_tool_add_preview (GimpDrawTool   *draw_tool,
757                             GimpCanvasItem *item)
758 {
759   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
760   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
761 
762   if (! draw_tool->preview)
763     draw_tool->preview =
764       gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
765 
766   gimp_canvas_group_add_item (GIMP_CANVAS_GROUP (draw_tool->preview), item);
767 }
768 
769 void
gimp_draw_tool_remove_preview(GimpDrawTool * draw_tool,GimpCanvasItem * item)770 gimp_draw_tool_remove_preview (GimpDrawTool   *draw_tool,
771                                GimpCanvasItem *item)
772 {
773   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
774   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
775   g_return_if_fail (draw_tool->preview != NULL);
776 
777   gimp_canvas_group_remove_item (GIMP_CANVAS_GROUP (draw_tool->preview), item);
778 }
779 
780 void
gimp_draw_tool_add_item(GimpDrawTool * draw_tool,GimpCanvasItem * item)781 gimp_draw_tool_add_item (GimpDrawTool   *draw_tool,
782                          GimpCanvasItem *item)
783 {
784   GimpCanvasGroup *group;
785 
786   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
787   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
788 
789   if (! draw_tool->item)
790     draw_tool->item =
791       gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
792 
793   group = GIMP_CANVAS_GROUP (draw_tool->item);
794 
795   if (draw_tool->group_stack)
796     group = draw_tool->group_stack->data;
797 
798   gimp_canvas_group_add_item (group, item);
799 }
800 
801 void
gimp_draw_tool_remove_item(GimpDrawTool * draw_tool,GimpCanvasItem * item)802 gimp_draw_tool_remove_item (GimpDrawTool   *draw_tool,
803                             GimpCanvasItem *item)
804 {
805   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
806   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
807   g_return_if_fail (draw_tool->item != NULL);
808 
809   gimp_canvas_group_remove_item (GIMP_CANVAS_GROUP (draw_tool->item), item);
810 }
811 
812 GimpCanvasGroup *
gimp_draw_tool_add_stroke_group(GimpDrawTool * draw_tool)813 gimp_draw_tool_add_stroke_group (GimpDrawTool *draw_tool)
814 {
815   GimpCanvasItem *item;
816 
817   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
818 
819   item = gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
820   gimp_canvas_group_set_group_stroking (GIMP_CANVAS_GROUP (item), TRUE);
821 
822   gimp_draw_tool_add_item (draw_tool, item);
823   g_object_unref (item);
824 
825   return GIMP_CANVAS_GROUP (item);
826 }
827 
828 GimpCanvasGroup *
gimp_draw_tool_add_fill_group(GimpDrawTool * draw_tool)829 gimp_draw_tool_add_fill_group (GimpDrawTool *draw_tool)
830 {
831   GimpCanvasItem *item;
832 
833   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
834 
835   item = gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
836   gimp_canvas_group_set_group_filling (GIMP_CANVAS_GROUP (item), TRUE);
837 
838   gimp_draw_tool_add_item (draw_tool, item);
839   g_object_unref (item);
840 
841   return GIMP_CANVAS_GROUP (item);
842 }
843 
844 void
gimp_draw_tool_push_group(GimpDrawTool * draw_tool,GimpCanvasGroup * group)845 gimp_draw_tool_push_group (GimpDrawTool    *draw_tool,
846                            GimpCanvasGroup *group)
847 {
848   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
849   g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
850 
851   draw_tool->group_stack = g_list_prepend (draw_tool->group_stack, group);
852 }
853 
854 void
gimp_draw_tool_pop_group(GimpDrawTool * draw_tool)855 gimp_draw_tool_pop_group (GimpDrawTool *draw_tool)
856 {
857   g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
858   g_return_if_fail (draw_tool->group_stack != NULL);
859 
860   draw_tool->group_stack = g_list_remove (draw_tool->group_stack,
861                                           draw_tool->group_stack->data);
862 }
863 
864 /**
865  * gimp_draw_tool_add_line:
866  * @draw_tool:   the #GimpDrawTool
867  * @x1:          start point X in image coordinates
868  * @y1:          start point Y in image coordinates
869  * @x2:          end point X in image coordinates
870  * @y2:          end point Y in image coordinates
871  *
872  * This function takes image space coordinates and transforms them to
873  * screen window coordinates, then draws a line between the resulting
874  * coordindates.
875  **/
876 GimpCanvasItem *
gimp_draw_tool_add_line(GimpDrawTool * draw_tool,gdouble x1,gdouble y1,gdouble x2,gdouble y2)877 gimp_draw_tool_add_line (GimpDrawTool *draw_tool,
878                          gdouble       x1,
879                          gdouble       y1,
880                          gdouble       x2,
881                          gdouble       y2)
882 {
883   GimpCanvasItem *item;
884 
885   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
886 
887   item = gimp_canvas_line_new (gimp_display_get_shell (draw_tool->display),
888                                x1, y1, x2, y2);
889 
890   gimp_draw_tool_add_item (draw_tool, item);
891   g_object_unref (item);
892 
893   return item;
894 }
895 
896 /**
897  * gimp_draw_tool_add_guide:
898  * @draw_tool:   the #GimpDrawTool
899  * @orientation: the orientation of the guide line
900  * @position:    the position of the guide line in image coordinates
901  *
902  * This function draws a guide line across the canvas.
903  **/
904 GimpCanvasItem *
gimp_draw_tool_add_guide(GimpDrawTool * draw_tool,GimpOrientationType orientation,gint position,GimpGuideStyle style)905 gimp_draw_tool_add_guide (GimpDrawTool        *draw_tool,
906                           GimpOrientationType  orientation,
907                           gint                 position,
908                           GimpGuideStyle       style)
909 {
910   GimpCanvasItem *item;
911 
912   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
913 
914   item = gimp_canvas_guide_new (gimp_display_get_shell (draw_tool->display),
915                                 orientation, position,
916                                 style);
917 
918   gimp_draw_tool_add_item (draw_tool, item);
919   g_object_unref (item);
920 
921   return item;
922 }
923 
924 /**
925  * gimp_draw_tool_add_crosshair:
926  * @draw_tool:  the #GimpDrawTool
927  * @position_x: the position of the vertical guide line in image coordinates
928  * @position_y: the position of the horizontal guide line in image coordinates
929  *
930  * This function draws two crossing guide lines across the canvas.
931  **/
932 GimpCanvasItem *
gimp_draw_tool_add_crosshair(GimpDrawTool * draw_tool,gint position_x,gint position_y)933 gimp_draw_tool_add_crosshair (GimpDrawTool *draw_tool,
934                               gint          position_x,
935                               gint          position_y)
936 {
937   GimpCanvasGroup *group;
938 
939   group = gimp_draw_tool_add_stroke_group (draw_tool);
940 
941   gimp_draw_tool_push_group (draw_tool, group);
942   gimp_draw_tool_add_guide (draw_tool,
943                             GIMP_ORIENTATION_VERTICAL, position_x,
944                             GIMP_GUIDE_STYLE_NONE);
945   gimp_draw_tool_add_guide (draw_tool,
946                             GIMP_ORIENTATION_HORIZONTAL, position_y,
947                             GIMP_GUIDE_STYLE_NONE);
948   gimp_draw_tool_pop_group (draw_tool);
949 
950   return GIMP_CANVAS_ITEM (group);
951 }
952 
953 /**
954  * gimp_draw_tool_add_sample_point:
955  * @draw_tool: the #GimpDrawTool
956  * @x:         X position of the sample point
957  * @y:         Y position of the sample point
958  * @index:     Index of the sample point
959  *
960  * This function draws a sample point
961  **/
962 GimpCanvasItem *
gimp_draw_tool_add_sample_point(GimpDrawTool * draw_tool,gint x,gint y,gint index)963 gimp_draw_tool_add_sample_point (GimpDrawTool *draw_tool,
964                                  gint          x,
965                                  gint          y,
966                                  gint          index)
967 {
968   GimpCanvasItem *item;
969 
970   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
971 
972   item = gimp_canvas_sample_point_new (gimp_display_get_shell (draw_tool->display),
973                                        x, y, index, TRUE);
974 
975   gimp_draw_tool_add_item (draw_tool, item);
976   g_object_unref (item);
977 
978   return item;
979 }
980 
981 /**
982  * gimp_draw_tool_add_rectangle:
983  * @draw_tool:   the #GimpDrawTool
984  * @filled:      whether to fill the rectangle
985  * @x:           horizontal image coordinate
986  * @y:           vertical image coordinate
987  * @width:       width in image coordinates
988  * @height:      height in image coordinates
989  *
990  * This function takes image space coordinates and transforms them to
991  * screen window coordinates, then draws the resulting rectangle.
992  **/
993 GimpCanvasItem *
gimp_draw_tool_add_rectangle(GimpDrawTool * draw_tool,gboolean filled,gdouble x,gdouble y,gdouble width,gdouble height)994 gimp_draw_tool_add_rectangle (GimpDrawTool *draw_tool,
995                               gboolean      filled,
996                               gdouble       x,
997                               gdouble       y,
998                               gdouble       width,
999                               gdouble       height)
1000 {
1001   GimpCanvasItem *item;
1002 
1003   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1004 
1005   item = gimp_canvas_rectangle_new (gimp_display_get_shell (draw_tool->display),
1006                                     x, y, width, height, filled);
1007 
1008   gimp_draw_tool_add_item (draw_tool, item);
1009   g_object_unref (item);
1010 
1011   return item;
1012 }
1013 
1014 GimpCanvasItem *
gimp_draw_tool_add_arc(GimpDrawTool * draw_tool,gboolean filled,gdouble x,gdouble y,gdouble width,gdouble height,gdouble start_angle,gdouble slice_angle)1015 gimp_draw_tool_add_arc (GimpDrawTool *draw_tool,
1016                         gboolean      filled,
1017                         gdouble       x,
1018                         gdouble       y,
1019                         gdouble       width,
1020                         gdouble       height,
1021                         gdouble       start_angle,
1022                         gdouble       slice_angle)
1023 {
1024   GimpCanvasItem *item;
1025 
1026   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1027 
1028   item = gimp_canvas_arc_new (gimp_display_get_shell (draw_tool->display),
1029                               x + width  / 2.0,
1030                               y + height / 2.0,
1031                               width  / 2.0,
1032                               height / 2.0,
1033                               start_angle,
1034                               slice_angle,
1035                               filled);
1036 
1037   gimp_draw_tool_add_item (draw_tool, item);
1038   g_object_unref (item);
1039 
1040   return item;
1041 }
1042 
1043 GimpCanvasItem *
gimp_draw_tool_add_handle(GimpDrawTool * draw_tool,GimpHandleType type,gdouble x,gdouble y,gint width,gint height,GimpHandleAnchor anchor)1044 gimp_draw_tool_add_handle (GimpDrawTool     *draw_tool,
1045                            GimpHandleType    type,
1046                            gdouble           x,
1047                            gdouble           y,
1048                            gint              width,
1049                            gint              height,
1050                            GimpHandleAnchor  anchor)
1051 {
1052   GimpCanvasItem *item;
1053 
1054   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1055 
1056   item = gimp_canvas_handle_new (gimp_display_get_shell (draw_tool->display),
1057                                  type, anchor, x, y, width, height);
1058 
1059   gimp_draw_tool_add_item (draw_tool, item);
1060   g_object_unref (item);
1061 
1062   return item;
1063 }
1064 
1065 GimpCanvasItem *
gimp_draw_tool_add_lines(GimpDrawTool * draw_tool,const GimpVector2 * points,gint n_points,GimpMatrix3 * transform,gboolean filled)1066 gimp_draw_tool_add_lines (GimpDrawTool      *draw_tool,
1067                           const GimpVector2 *points,
1068                           gint               n_points,
1069                           GimpMatrix3       *transform,
1070                           gboolean           filled)
1071 {
1072   GimpCanvasItem *item;
1073 
1074   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1075 
1076   if (points == NULL || n_points < 2)
1077     return NULL;
1078 
1079   item = gimp_canvas_polygon_new (gimp_display_get_shell (draw_tool->display),
1080                                   points, n_points, transform, filled);
1081 
1082   gimp_draw_tool_add_item (draw_tool, item);
1083   g_object_unref (item);
1084 
1085   return item;
1086 }
1087 
1088 GimpCanvasItem *
gimp_draw_tool_add_strokes(GimpDrawTool * draw_tool,const GimpCoords * points,gint n_points,GimpMatrix3 * transform,gboolean filled)1089 gimp_draw_tool_add_strokes (GimpDrawTool     *draw_tool,
1090                             const GimpCoords *points,
1091                             gint              n_points,
1092                             GimpMatrix3      *transform,
1093                             gboolean          filled)
1094 {
1095   GimpCanvasItem *item;
1096 
1097   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1098 
1099   if (points == NULL || n_points < 2)
1100     return NULL;
1101 
1102   item = gimp_canvas_polygon_new_from_coords (gimp_display_get_shell (draw_tool->display),
1103                                               points, n_points, transform, filled);
1104 
1105   gimp_draw_tool_add_item (draw_tool, item);
1106   g_object_unref (item);
1107 
1108   return item;
1109 }
1110 
1111 GimpCanvasItem *
gimp_draw_tool_add_pen(GimpDrawTool * draw_tool,const GimpVector2 * points,gint n_points,GimpContext * context,GimpActiveColor color,gint width)1112 gimp_draw_tool_add_pen (GimpDrawTool      *draw_tool,
1113                         const GimpVector2 *points,
1114                         gint               n_points,
1115                         GimpContext       *context,
1116                         GimpActiveColor    color,
1117                         gint               width)
1118 {
1119   GimpCanvasItem *item;
1120 
1121   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1122 
1123   if (points == NULL || n_points < 2)
1124     return NULL;
1125 
1126   item = gimp_canvas_pen_new (gimp_display_get_shell (draw_tool->display),
1127                               points, n_points, context, color, width);
1128 
1129   gimp_draw_tool_add_item (draw_tool, item);
1130   g_object_unref (item);
1131 
1132   return item;
1133 }
1134 
1135 /**
1136  * gimp_draw_tool_add_boundary:
1137  * @draw_tool:    a #GimpDrawTool
1138  * @bound_segs:   the sorted brush outline
1139  * @n_bound_segs: the number of segments in @bound_segs
1140  * @matrix:       transform matrix for the boundary
1141  * @offset_x:     x offset
1142  * @offset_y:     y offset
1143  *
1144  * Draw the boundary of the brush that @draw_tool uses. The boundary
1145  * should be sorted with sort_boundary(), and @n_bound_segs should
1146  * include the sentinel segments inserted by sort_boundary() that
1147  * indicate the end of connected segment sequences (groups) .
1148  */
1149 GimpCanvasItem *
gimp_draw_tool_add_boundary(GimpDrawTool * draw_tool,const GimpBoundSeg * bound_segs,gint n_bound_segs,GimpMatrix3 * transform,gdouble offset_x,gdouble offset_y)1150 gimp_draw_tool_add_boundary (GimpDrawTool       *draw_tool,
1151                              const GimpBoundSeg *bound_segs,
1152                              gint                n_bound_segs,
1153                              GimpMatrix3        *transform,
1154                              gdouble             offset_x,
1155                              gdouble             offset_y)
1156 {
1157   GimpCanvasItem *item;
1158 
1159   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1160   g_return_val_if_fail (n_bound_segs > 0, NULL);
1161   g_return_val_if_fail (bound_segs != NULL, NULL);
1162 
1163   item = gimp_canvas_boundary_new (gimp_display_get_shell (draw_tool->display),
1164                                    bound_segs, n_bound_segs,
1165                                    transform,
1166                                    offset_x, offset_y);
1167 
1168   gimp_draw_tool_add_item (draw_tool, item);
1169   g_object_unref (item);
1170 
1171   return item;
1172 }
1173 
1174 GimpCanvasItem *
gimp_draw_tool_add_text_cursor(GimpDrawTool * draw_tool,PangoRectangle * cursor,gboolean overwrite,GimpTextDirection direction)1175 gimp_draw_tool_add_text_cursor (GimpDrawTool     *draw_tool,
1176                                 PangoRectangle   *cursor,
1177                                 gboolean          overwrite,
1178                                 GimpTextDirection direction)
1179 {
1180   GimpCanvasItem *item;
1181 
1182   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1183 
1184   item = gimp_canvas_text_cursor_new (gimp_display_get_shell (draw_tool->display),
1185                                       cursor, overwrite, direction);
1186 
1187   gimp_draw_tool_add_item (draw_tool, item);
1188   g_object_unref (item);
1189 
1190   return item;
1191 }
1192 
1193 GimpCanvasItem *
gimp_draw_tool_add_transform_preview(GimpDrawTool * draw_tool,GimpPickable * pickable,const GimpMatrix3 * transform,gdouble x1,gdouble y1,gdouble x2,gdouble y2)1194 gimp_draw_tool_add_transform_preview (GimpDrawTool      *draw_tool,
1195                                       GimpPickable      *pickable,
1196                                       const GimpMatrix3 *transform,
1197                                       gdouble            x1,
1198                                       gdouble            y1,
1199                                       gdouble            x2,
1200                                       gdouble            y2)
1201 {
1202   GimpCanvasItem *item;
1203 
1204   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
1205   g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
1206   g_return_val_if_fail (transform != NULL, NULL);
1207 
1208   item = gimp_canvas_transform_preview_new (gimp_display_get_shell (draw_tool->display),
1209                                             pickable, transform,
1210                                             x1, y1, x2, y2);
1211 
1212   gimp_draw_tool_add_preview (draw_tool, item);
1213   g_object_unref (item);
1214 
1215   return item;
1216 }
1217 
1218 gboolean
gimp_draw_tool_on_handle(GimpDrawTool * draw_tool,GimpDisplay * display,gdouble x,gdouble y,GimpHandleType type,gdouble handle_x,gdouble handle_y,gint width,gint height,GimpHandleAnchor anchor)1219 gimp_draw_tool_on_handle (GimpDrawTool     *draw_tool,
1220                           GimpDisplay      *display,
1221                           gdouble           x,
1222                           gdouble           y,
1223                           GimpHandleType    type,
1224                           gdouble           handle_x,
1225                           gdouble           handle_y,
1226                           gint              width,
1227                           gint              height,
1228                           GimpHandleAnchor  anchor)
1229 {
1230   GimpDisplayShell *shell;
1231   gdouble           tx, ty;
1232   gdouble           handle_tx, handle_ty;
1233 
1234   g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);
1235   g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
1236 
1237   shell = gimp_display_get_shell (display);
1238 
1239   gimp_display_shell_zoom_xy_f (shell,
1240                                 x, y,
1241                                 &tx, &ty);
1242   gimp_display_shell_zoom_xy_f (shell,
1243                                 handle_x, handle_y,
1244                                 &handle_tx, &handle_ty);
1245 
1246   switch (type)
1247     {
1248     case GIMP_HANDLE_SQUARE:
1249     case GIMP_HANDLE_FILLED_SQUARE:
1250     case GIMP_HANDLE_CROSS:
1251     case GIMP_HANDLE_CROSSHAIR:
1252       gimp_canvas_item_shift_to_north_west (anchor,
1253                                             handle_tx, handle_ty,
1254                                             width, height,
1255                                             &handle_tx, &handle_ty);
1256 
1257       return (tx == CLAMP (tx, handle_tx, handle_tx + width) &&
1258               ty == CLAMP (ty, handle_ty, handle_ty + height));
1259 
1260     case GIMP_HANDLE_CIRCLE:
1261     case GIMP_HANDLE_FILLED_CIRCLE:
1262       gimp_canvas_item_shift_to_center (anchor,
1263                                         handle_tx, handle_ty,
1264                                         width, height,
1265                                         &handle_tx, &handle_ty);
1266 
1267       /* FIXME */
1268       if (width != height)
1269         width = (width + height) / 2;
1270 
1271       width /= 2;
1272 
1273       return ((SQR (handle_tx - tx) + SQR (handle_ty - ty)) < SQR (width));
1274 
1275     default:
1276       g_warning ("%s: invalid handle type %d", G_STRFUNC, type);
1277       break;
1278     }
1279 
1280   return FALSE;
1281 }
1282