1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * GimpNavigationView Widget
5  * Copyright (C) 2001-2002 Michael Natterer <mitch@gimp.org>
6  *
7  * partly based on app/nav_window
8  * Copyright (C) 1999 Andy Thomas <alt@gimp.org>
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include "config.h"
25 
26 #include <math.h>
27 
28 #include <gegl.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
31 
32 #include "libgimpmath/gimpmath.h"
33 
34 #include "widgets-types.h"
35 
36 #include "core/gimpimage.h"
37 #include "core/gimpmarshal.h"
38 
39 #include "display/gimpcanvas-style.h"
40 
41 #include "gimpnavigationview.h"
42 #include "gimpviewrenderer.h"
43 #include "gimpwidgets-utils.h"
44 
45 
46 #define BORDER_WIDTH 2
47 
48 
49 enum
50 {
51   MARKER_CHANGED,
52   ZOOM,
53   SCROLL,
54   LAST_SIGNAL
55 };
56 
57 
58 struct _GimpNavigationView
59 {
60   GimpView     parent_instance;
61 
62   /*  values in image coordinates  */
63   gdouble      center_x;
64   gdouble      center_y;
65   gdouble      width;
66   gdouble      height;
67   gboolean     flip_horizontally;
68   gboolean     flip_vertically;
69   gdouble      rotate_angle;
70 
71   gboolean     canvas_visible;
72   gdouble      canvas_x;
73   gdouble      canvas_y;
74   gdouble      canvas_width;
75   gdouble      canvas_height;
76 
77   /*  values in view coordinates  */
78   gint         p_center_x;
79   gint         p_center_y;
80   gint         p_width;
81   gint         p_height;
82 
83   gint         p_canvas_x;
84   gint         p_canvas_y;
85   gint         p_canvas_width;
86   gint         p_canvas_height;
87 
88   gint         motion_offset_x;
89   gint         motion_offset_y;
90   gboolean     has_grab;
91 };
92 
93 
94 static void     gimp_navigation_view_size_allocate   (GtkWidget      *widget,
95                                                       GtkAllocation  *allocation);
96 static gboolean gimp_navigation_view_expose          (GtkWidget      *widget,
97                                                       GdkEventExpose *event);
98 static gboolean gimp_navigation_view_button_press    (GtkWidget      *widget,
99                                                       GdkEventButton *bevent);
100 static gboolean gimp_navigation_view_button_release  (GtkWidget      *widget,
101                                                       GdkEventButton *bevent);
102 static gboolean gimp_navigation_view_scroll          (GtkWidget      *widget,
103                                                       GdkEventScroll *sevent);
104 static gboolean gimp_navigation_view_motion_notify   (GtkWidget      *widget,
105                                                       GdkEventMotion *mevent);
106 static gboolean gimp_navigation_view_key_press       (GtkWidget      *widget,
107                                                       GdkEventKey    *kevent);
108 
109 static void     gimp_navigation_view_transform       (GimpNavigationView *nav_view);
110 static void     gimp_navigation_view_draw_marker     (GimpNavigationView *nav_view,
111                                                       cairo_t            *cr);
112 static void     gimp_navigation_view_move_to         (GimpNavigationView *nav_view,
113                                                       gint                tx,
114                                                       gint                ty);
115 static void     gimp_navigation_view_get_ratio       (GimpNavigationView *nav_view,
116                                                       gdouble            *ratiox,
117                                                       gdouble            *ratioy);
118 static gboolean gimp_navigation_view_point_in_marker (GimpNavigationView *nav_view,
119                                                       gint                x,
120                                                       gint                y);
121 
122 
123 G_DEFINE_TYPE (GimpNavigationView, gimp_navigation_view, GIMP_TYPE_VIEW)
124 
125 #define parent_class gimp_navigation_view_parent_class
126 
127 static guint view_signals[LAST_SIGNAL] = { 0 };
128 
129 
130 static void
gimp_navigation_view_class_init(GimpNavigationViewClass * klass)131 gimp_navigation_view_class_init (GimpNavigationViewClass *klass)
132 {
133   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
134 
135   view_signals[MARKER_CHANGED] =
136     g_signal_new ("marker-changed",
137                   G_TYPE_FROM_CLASS (klass),
138                   G_SIGNAL_RUN_FIRST,
139                   G_STRUCT_OFFSET (GimpNavigationViewClass, marker_changed),
140                   NULL, NULL,
141                   gimp_marshal_VOID__DOUBLE_DOUBLE_DOUBLE_DOUBLE,
142                   G_TYPE_NONE, 4,
143                   G_TYPE_DOUBLE,
144                   G_TYPE_DOUBLE,
145                   G_TYPE_DOUBLE,
146                   G_TYPE_DOUBLE);
147 
148   view_signals[ZOOM] =
149     g_signal_new ("zoom",
150                   G_TYPE_FROM_CLASS (klass),
151                   G_SIGNAL_RUN_FIRST,
152                   G_STRUCT_OFFSET (GimpNavigationViewClass, zoom),
153                   NULL, NULL,
154                   gimp_marshal_VOID__ENUM,
155                   G_TYPE_NONE, 1,
156                   GIMP_TYPE_ZOOM_TYPE);
157 
158   view_signals[SCROLL] =
159     g_signal_new ("scroll",
160                   G_TYPE_FROM_CLASS (klass),
161                   G_SIGNAL_RUN_FIRST,
162                   G_STRUCT_OFFSET (GimpNavigationViewClass, scroll),
163                   NULL, NULL,
164                   gimp_marshal_VOID__ENUM,
165                   G_TYPE_NONE, 1,
166                   GDK_TYPE_SCROLL_DIRECTION);
167 
168   widget_class->size_allocate        = gimp_navigation_view_size_allocate;
169   widget_class->expose_event         = gimp_navigation_view_expose;
170   widget_class->button_press_event   = gimp_navigation_view_button_press;
171   widget_class->button_release_event = gimp_navigation_view_button_release;
172   widget_class->scroll_event         = gimp_navigation_view_scroll;
173   widget_class->motion_notify_event  = gimp_navigation_view_motion_notify;
174   widget_class->key_press_event      = gimp_navigation_view_key_press;
175 }
176 
177 static void
gimp_navigation_view_init(GimpNavigationView * view)178 gimp_navigation_view_init (GimpNavigationView *view)
179 {
180   gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE);
181   gtk_widget_add_events (GTK_WIDGET (view),
182                          GDK_POINTER_MOTION_MASK |
183                          GDK_KEY_PRESS_MASK);
184 
185   view->center_x          = 0.0;
186   view->center_y          = 0.0;
187   view->width             = 0.0;
188   view->height            = 0.0;
189   view->flip_horizontally = FALSE;
190   view->flip_vertically   = FALSE;
191   view->rotate_angle      = 0.0;
192 
193   view->canvas_visible    = FALSE;
194   view->canvas_x          = 0.0;
195   view->canvas_y          = 0.0;
196   view->canvas_width      = 0.0;
197   view->canvas_height     = 0.0;
198 
199   view->p_center_x      = 0;
200   view->p_center_y      = 0;
201   view->p_width         = 0;
202   view->p_height        = 0;
203 
204   view->p_canvas_x      = 0;
205   view->p_canvas_y      = 0;
206   view->p_canvas_width  = 0;
207   view->p_canvas_height = 0;
208 
209   view->motion_offset_x = 0;
210   view->motion_offset_y = 0;
211   view->has_grab        = FALSE;
212 }
213 
214 static void
gimp_navigation_view_size_allocate(GtkWidget * widget,GtkAllocation * allocation)215 gimp_navigation_view_size_allocate (GtkWidget     *widget,
216                                     GtkAllocation *allocation)
217 {
218   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
219 
220   if (GIMP_VIEW (widget)->renderer->viewable)
221     gimp_navigation_view_transform (GIMP_NAVIGATION_VIEW (widget));
222 }
223 
224 static gboolean
gimp_navigation_view_expose(GtkWidget * widget,GdkEventExpose * event)225 gimp_navigation_view_expose (GtkWidget      *widget,
226                              GdkEventExpose *event)
227 {
228   if (gtk_widget_is_drawable (widget))
229     {
230       cairo_t *cr;
231 
232       GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
233 
234       cr = gdk_cairo_create (gtk_widget_get_window (widget));
235 
236       gdk_cairo_region (cr, event->region);
237       cairo_clip (cr);
238 
239       gimp_navigation_view_draw_marker (GIMP_NAVIGATION_VIEW (widget), cr);
240 
241       cairo_destroy (cr);
242     }
243 
244   return TRUE;
245 }
246 
247 void
gimp_navigation_view_grab_pointer(GimpNavigationView * nav_view)248 gimp_navigation_view_grab_pointer (GimpNavigationView *nav_view)
249 {
250   GtkWidget  *widget = GTK_WIDGET (nav_view);
251   GdkDisplay *display;
252   GdkCursor  *cursor;
253   GdkWindow  *window;
254 
255   nav_view->has_grab = TRUE;
256 
257   gtk_grab_add (widget);
258 
259   display = gtk_widget_get_display (widget);
260   cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
261 
262   window = GIMP_VIEW (nav_view)->event_window;
263 
264   gdk_pointer_grab (window, FALSE,
265                     GDK_BUTTON_RELEASE_MASK      |
266                     GDK_POINTER_MOTION_HINT_MASK |
267                     GDK_BUTTON_MOTION_MASK       |
268                     GDK_EXTENSION_EVENTS_ALL,
269                     NULL, cursor, GDK_CURRENT_TIME);
270 
271   gdk_cursor_unref (cursor);
272 }
273 
274 static gboolean
gimp_navigation_view_button_press(GtkWidget * widget,GdkEventButton * bevent)275 gimp_navigation_view_button_press (GtkWidget      *widget,
276                                    GdkEventButton *bevent)
277 {
278   GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
279   gint                tx, ty;
280   GdkDisplay         *display;
281 
282   tx = bevent->x;
283   ty = bevent->y;
284 
285   if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1)
286     {
287       if (! gimp_navigation_view_point_in_marker (nav_view, tx, ty))
288         {
289           GdkCursor *cursor;
290 
291           nav_view->motion_offset_x = 0;
292           nav_view->motion_offset_y = 0;
293 
294           gimp_navigation_view_move_to (nav_view, tx, ty);
295 
296           display = gtk_widget_get_display (widget);
297           cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
298           gdk_window_set_cursor (GIMP_VIEW (widget)->event_window, cursor);
299           gdk_cursor_unref (cursor);
300         }
301       else
302         {
303           nav_view->motion_offset_x = tx - nav_view->p_center_x;
304           nav_view->motion_offset_y = ty - nav_view->p_center_y;
305         }
306 
307       gimp_navigation_view_grab_pointer (nav_view);
308     }
309 
310   return TRUE;
311 }
312 
313 static gboolean
gimp_navigation_view_button_release(GtkWidget * widget,GdkEventButton * bevent)314 gimp_navigation_view_button_release (GtkWidget      *widget,
315                                      GdkEventButton *bevent)
316 {
317   GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
318 
319   if (bevent->button == 1 && nav_view->has_grab)
320     {
321       nav_view->has_grab = FALSE;
322 
323       gtk_grab_remove (widget);
324       gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
325                                   GDK_CURRENT_TIME);
326     }
327 
328   return TRUE;
329 }
330 
331 static gboolean
gimp_navigation_view_scroll(GtkWidget * widget,GdkEventScroll * sevent)332 gimp_navigation_view_scroll (GtkWidget      *widget,
333                              GdkEventScroll *sevent)
334 {
335   if (sevent->state & gimp_get_toggle_behavior_mask ())
336     {
337       switch (sevent->direction)
338         {
339         case GDK_SCROLL_UP:
340           g_signal_emit (widget, view_signals[ZOOM], 0, GIMP_ZOOM_IN);
341           break;
342 
343         case GDK_SCROLL_DOWN:
344           g_signal_emit (widget, view_signals[ZOOM], 0, GIMP_ZOOM_OUT);
345           break;
346 
347         default:
348           break;
349         }
350     }
351   else
352     {
353       GdkScrollDirection direction = sevent->direction;
354 
355       if (sevent->state & GDK_SHIFT_MASK)
356         switch (direction)
357           {
358           case GDK_SCROLL_UP:    direction = GDK_SCROLL_LEFT;  break;
359           case GDK_SCROLL_DOWN:  direction = GDK_SCROLL_RIGHT; break;
360           case GDK_SCROLL_LEFT:  direction = GDK_SCROLL_UP;    break;
361           case GDK_SCROLL_RIGHT: direction = GDK_SCROLL_DOWN;  break;
362           }
363 
364       g_signal_emit (widget, view_signals[SCROLL], 0, direction);
365     }
366 
367   return TRUE;
368 }
369 
370 static gboolean
gimp_navigation_view_motion_notify(GtkWidget * widget,GdkEventMotion * mevent)371 gimp_navigation_view_motion_notify (GtkWidget      *widget,
372                                     GdkEventMotion *mevent)
373 {
374   GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
375   GimpView           *view     = GIMP_VIEW (widget);
376 
377   if (! nav_view->has_grab)
378     {
379       GdkDisplay *display = gtk_widget_get_display (widget);
380       GdkCursor  *cursor;
381 
382       if (nav_view->p_center_x == view->renderer->width  / 2 &&
383           nav_view->p_center_y == view->renderer->height / 2 &&
384           nav_view->p_width    == view->renderer->width      &&
385           nav_view->p_height   == view->renderer->height)
386         {
387           gdk_window_set_cursor (view->event_window, NULL);
388           return FALSE;
389         }
390       else if (gimp_navigation_view_point_in_marker (nav_view,
391                                                      mevent->x, mevent->y))
392         {
393           cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
394         }
395       else
396         {
397           cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
398         }
399 
400       gdk_window_set_cursor (view->event_window, cursor);
401       gdk_cursor_unref (cursor);
402 
403       return FALSE;
404     }
405 
406   gimp_navigation_view_move_to (nav_view,
407                                 mevent->x - nav_view->motion_offset_x,
408                                 mevent->y - nav_view->motion_offset_y);
409 
410   gdk_event_request_motions (mevent);
411 
412   return TRUE;
413 }
414 
415 static gboolean
gimp_navigation_view_key_press(GtkWidget * widget,GdkEventKey * kevent)416 gimp_navigation_view_key_press (GtkWidget   *widget,
417                                 GdkEventKey *kevent)
418 {
419   GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
420   gint                scroll_x = 0;
421   gint                scroll_y = 0;
422 
423   switch (kevent->keyval)
424     {
425     case GDK_KEY_Up:
426       scroll_y = -1;
427       break;
428 
429     case GDK_KEY_Left:
430       scroll_x = -1;
431       break;
432 
433     case GDK_KEY_Right:
434       scroll_x = 1;
435       break;
436 
437     case GDK_KEY_Down:
438       scroll_y = 1;
439       break;
440 
441     default:
442       break;
443     }
444 
445   if (scroll_x || scroll_y)
446     {
447       gimp_navigation_view_move_to (nav_view,
448                                     nav_view->p_center_x + scroll_x,
449                                     nav_view->p_center_y + scroll_y);
450       return TRUE;
451     }
452 
453   return FALSE;
454 }
455 
456 
457 /*  public functions  */
458 
459 void
gimp_navigation_view_set_marker(GimpNavigationView * nav_view,gdouble center_x,gdouble center_y,gdouble width,gdouble height,gboolean flip_horizontally,gboolean flip_vertically,gdouble rotate_angle)460 gimp_navigation_view_set_marker (GimpNavigationView *nav_view,
461                                  gdouble             center_x,
462                                  gdouble             center_y,
463                                  gdouble             width,
464                                  gdouble             height,
465                                  gboolean            flip_horizontally,
466                                  gboolean            flip_vertically,
467                                  gdouble             rotate_angle)
468 {
469   GimpView *view;
470 
471   g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (nav_view));
472 
473   view = GIMP_VIEW (nav_view);
474 
475   g_return_if_fail (view->renderer->viewable);
476 
477   nav_view->center_x          = center_x;
478   nav_view->center_y          = center_y;
479   nav_view->width             = MAX (1.0, width);
480   nav_view->height            = MAX (1.0, height);
481   nav_view->flip_horizontally = flip_horizontally ? TRUE : FALSE;
482   nav_view->flip_vertically   = flip_vertically   ? TRUE : FALSE;
483   nav_view->rotate_angle      = rotate_angle;
484 
485   gimp_navigation_view_transform (nav_view);
486 
487   /* Marker changed, redraw */
488   gtk_widget_queue_draw (GTK_WIDGET (view));
489 }
490 
491 void
gimp_navigation_view_set_canvas(GimpNavigationView * nav_view,gboolean visible,gdouble x,gdouble y,gdouble width,gdouble height)492 gimp_navigation_view_set_canvas (GimpNavigationView *nav_view,
493                                  gboolean            visible,
494                                  gdouble             x,
495                                  gdouble             y,
496                                  gdouble             width,
497                                  gdouble             height)
498 {
499   GimpView *view;
500 
501   g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (nav_view));
502 
503   view = GIMP_VIEW (nav_view);
504 
505   g_return_if_fail (view->renderer->viewable);
506 
507   nav_view->canvas_visible = visible;
508   nav_view->canvas_x       = x;
509   nav_view->canvas_y       = y;
510   nav_view->canvas_width   = MAX (1.0, width);
511   nav_view->canvas_height  = MAX (1.0, height);
512 
513   gimp_navigation_view_transform (nav_view);
514 
515   /* Marker changed, redraw */
516   gtk_widget_queue_draw (GTK_WIDGET (view));
517 }
518 
519 void
gimp_navigation_view_set_motion_offset(GimpNavigationView * view,gint motion_offset_x,gint motion_offset_y)520 gimp_navigation_view_set_motion_offset (GimpNavigationView *view,
521                                         gint                motion_offset_x,
522                                         gint                motion_offset_y)
523 {
524   g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (view));
525 
526   view->motion_offset_x = motion_offset_x;
527   view->motion_offset_y = motion_offset_y;
528 }
529 
530 void
gimp_navigation_view_get_local_marker(GimpNavigationView * view,gint * center_x,gint * center_y,gint * width,gint * height)531 gimp_navigation_view_get_local_marker (GimpNavigationView *view,
532                                        gint               *center_x,
533                                        gint               *center_y,
534                                        gint               *width,
535                                        gint               *height)
536 {
537   g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (view));
538 
539   if (center_x) *center_x = view->p_center_x;
540   if (center_y) *center_y = view->p_center_y;
541   if (width)    *width    = view->p_width;
542   if (height)   *height   = view->p_height;
543 }
544 
545 
546 /*  private functions  */
547 
548 static void
gimp_navigation_view_transform(GimpNavigationView * nav_view)549 gimp_navigation_view_transform (GimpNavigationView *nav_view)
550 {
551   gdouble ratiox, ratioy;
552 
553   gimp_navigation_view_get_ratio (nav_view, &ratiox, &ratioy);
554 
555   nav_view->p_center_x = RINT (nav_view->center_x * ratiox);
556   nav_view->p_center_y = RINT (nav_view->center_y * ratioy);
557 
558   nav_view->p_width  = ceil (nav_view->width  * ratiox);
559   nav_view->p_height = ceil (nav_view->height * ratioy);
560 
561   nav_view->p_canvas_x = RINT (nav_view->canvas_x * ratiox);
562   nav_view->p_canvas_y = RINT (nav_view->canvas_y * ratioy);
563 
564   nav_view->p_canvas_width  = ceil (nav_view->canvas_width  * ratiox);
565   nav_view->p_canvas_height = ceil (nav_view->canvas_height * ratioy);
566 }
567 
568 static void
gimp_navigation_view_draw_marker(GimpNavigationView * nav_view,cairo_t * cr)569 gimp_navigation_view_draw_marker (GimpNavigationView *nav_view,
570                                   cairo_t            *cr)
571 {
572   GimpView *view = GIMP_VIEW (nav_view);
573 
574   if (view->renderer->viewable && nav_view->width && nav_view->height)
575     {
576       GtkWidget      *widget = GTK_WIDGET (view);
577       GtkAllocation   allocation;
578       cairo_matrix_t  matrix;
579       gint            p_width_2;
580       gint            p_height_2;
581       gdouble         angle;
582 
583       p_width_2  = nav_view->p_width  / 2;
584       p_height_2 = nav_view->p_height / 2;
585 
586       angle = G_PI * nav_view->rotate_angle / 180.0;
587       if (nav_view->flip_horizontally != nav_view->flip_vertically)
588         angle = -angle;
589 
590       gtk_widget_get_allocation (widget, &allocation);
591 
592       cairo_translate (cr, allocation.x, allocation.y);
593 
594       cairo_get_matrix (cr, &matrix);
595 
596       cairo_rectangle (cr,
597                        0, 0,
598                        allocation.width, allocation.height);
599       cairo_translate (cr, nav_view->p_center_x, nav_view->p_center_y);
600       cairo_rotate (cr, -angle);
601       cairo_rectangle (cr,
602                        -p_width_2, -p_height_2,
603                        nav_view->p_width, nav_view->p_height);
604 
605       cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
606       cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
607       cairo_fill (cr);
608 
609       if (nav_view->canvas_visible &&
610           nav_view->canvas_width && nav_view->canvas_height)
611         {
612           cairo_save (cr);
613 
614           cairo_set_matrix (cr, &matrix);
615 
616           cairo_rectangle (cr,
617                            nav_view->p_canvas_x      + 0.5,
618                            nav_view->p_canvas_y      + 0.5,
619                            nav_view->p_canvas_width  - 1.0,
620                            nav_view->p_canvas_height - 1.0);
621           gimp_canvas_set_canvas_style (GTK_WIDGET (nav_view), cr, 0, 0);
622           cairo_stroke (cr);
623 
624           cairo_restore (cr);
625         }
626 
627       cairo_rectangle (cr,
628                        -p_width_2, -p_height_2,
629                        nav_view->p_width, nav_view->p_height);
630 
631       cairo_set_source_rgb (cr, 1, 1, 1);
632       cairo_set_line_width (cr, BORDER_WIDTH);
633       cairo_stroke (cr);
634     }
635 }
636 
637 static void
gimp_navigation_view_move_to(GimpNavigationView * nav_view,gint tx,gint ty)638 gimp_navigation_view_move_to (GimpNavigationView *nav_view,
639                               gint                tx,
640                               gint                ty)
641 {
642   GimpView  *view = GIMP_VIEW (nav_view);
643   gdouble    ratiox, ratioy;
644   gdouble    x, y;
645 
646   if (! view->renderer->viewable)
647     return;
648 
649   gimp_navigation_view_get_ratio (nav_view, &ratiox, &ratioy);
650 
651   x = tx / ratiox;
652   y = ty / ratioy;
653 
654   g_signal_emit (view, view_signals[MARKER_CHANGED], 0,
655                  x, y, nav_view->width, nav_view->height);
656 }
657 
658 static void
gimp_navigation_view_get_ratio(GimpNavigationView * nav_view,gdouble * ratiox,gdouble * ratioy)659 gimp_navigation_view_get_ratio (GimpNavigationView *nav_view,
660                                 gdouble            *ratiox,
661                                 gdouble            *ratioy)
662 {
663   GimpView  *view = GIMP_VIEW (nav_view);
664   gint       width;
665   gint       height;
666 
667   gimp_viewable_get_size (view->renderer->viewable, &width, &height);
668 
669   *ratiox = (gdouble) view->renderer->width  / (gdouble) width;
670   *ratioy = (gdouble) view->renderer->height / (gdouble) height;
671 }
672 
673 static gboolean
gimp_navigation_view_point_in_marker(GimpNavigationView * nav_view,gint x,gint y)674 gimp_navigation_view_point_in_marker (GimpNavigationView *nav_view,
675                                       gint                x,
676                                       gint                y)
677 {
678   gint    p_width_2, p_height_2;
679   gdouble angle;
680   gdouble tx, ty;
681 
682   p_width_2  = nav_view->p_width  / 2;
683   p_height_2 = nav_view->p_height / 2;
684 
685   angle = G_PI * nav_view->rotate_angle / 180.0;
686   if (nav_view->flip_horizontally != nav_view->flip_vertically)
687     angle = -angle;
688 
689   x -= nav_view->p_center_x;
690   y -= nav_view->p_center_y;
691 
692   tx = cos (angle) * x - sin (angle) * y;
693   ty = sin (angle) * x + cos (angle) * y;
694 
695   return tx >= -p_width_2  && tx < p_width_2 &&
696          ty >= -p_height_2 && ty < p_height_2;
697 }
698