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