Merge the usermenu branch. This reworks how the menus and hotkeys
[geda-pcb/pcjc2.git] / src / hid / gtk / gui-output-events.c
blob42538e4333a02dd5d03d8e6d5a78d4c08050a902
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* This file written by Bill Wilson for the PCB Gtk port */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include "gui.h"
36 #include "gtkhid.h"
38 #include <gdk/gdkkeysyms.h>
40 #include "action.h"
41 #include "crosshair.h"
42 #include "draw.h"
43 #include "error.h"
44 #include "misc.h"
45 #include "set.h"
47 #ifdef HAVE_LIBDMALLOC
48 #include <dmalloc.h>
49 #endif
51 RCSID ("$Id$");
53 static gint x_pan_speed, y_pan_speed;
55 void
56 ghid_port_ranges_changed (void)
58 GtkAdjustment *h_adj, *v_adj;
60 if (!ghidgui->combine_adjustments)
61 HideCrosshair (FALSE);
62 if (ghidgui->combine_adjustments)
64 ghidgui->combine_adjustments = FALSE;
65 return;
68 ghidgui->need_restore_crosshair = TRUE;
70 h_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
71 v_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
72 gport->view_x0 = h_adj->value;
73 gport->view_y0 = v_adj->value;
75 ghid_invalidate_all ();
78 gboolean
79 ghid_port_ranges_pan (gdouble x, gdouble y, gboolean relative)
81 GtkAdjustment *h_adj, *v_adj;
82 gdouble x0, y0, x1, y1;
84 h_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
85 v_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
86 x0 = h_adj->value;
87 y0 = v_adj->value;
89 if (relative)
91 x1 = x0 + x;
92 y1 = y0 + y;
94 else
96 x1 = x;
97 y1 = y;
100 if (x1 < h_adj->lower)
101 x1 = h_adj->lower;
102 if (x1 > h_adj->upper - h_adj->page_size)
103 x1 = h_adj->upper - h_adj->page_size;
105 if (y1 < v_adj->lower)
106 y1 = v_adj->lower;
107 if (y1 > v_adj->upper - v_adj->page_size)
108 y1 = v_adj->upper - v_adj->page_size;
110 if (x0 != x1 && y0 != y1)
111 ghidgui->combine_adjustments = TRUE;
112 if (x0 != x1)
113 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), x1);
114 if (y0 != y1)
115 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), y1);
117 ghid_note_event_location (NULL);
118 return ((x0 != x1) || (y0 != y1));
121 /* Do scrollbar scaling based on current port drawing area size and
122 | overall PCB board size.
124 void
125 ghid_port_ranges_scale (gboolean emit_changed)
127 GtkAdjustment *adj;
129 /* Update the scrollbars with PCB units. So Scale the current
130 | drawing area size in pixels to PCB units and that will be
131 | the page size for the Gtk adjustment.
133 gport->view_width = gport->width * gport->zoom;
134 gport->view_height = gport->height * gport->zoom;
136 if (gport->view_width >= PCB->MaxWidth)
137 gport->view_width = PCB->MaxWidth;
138 if (gport->view_height >= PCB->MaxHeight)
139 gport->view_height = PCB->MaxHeight;
141 adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
142 adj->page_size = gport->view_width;
143 adj->upper = PCB->MaxWidth;
144 if (emit_changed)
145 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
147 adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
148 adj->page_size = gport->view_height;
149 adj->upper = PCB->MaxHeight;
150 if (emit_changed)
151 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
154 void
155 ghid_port_ranges_zoom (gdouble zoom)
157 gdouble xtmp, ytmp;
158 gint x0, y0;
160 /* figure out zoom values in that would just make the width fit and
161 * that would just make the height fit
163 xtmp = (gdouble) PCB->MaxWidth / gport->width;
164 ytmp = (gdouble) PCB->MaxHeight / gport->height;
166 /* if we've tried to zoom further out than what would make the
167 * entire board fit or we passed 0, then pick a zoom that just makes
168 * the board fit.
170 if ((zoom > xtmp && zoom > ytmp) || zoom == 0.0)
171 zoom = (xtmp > ytmp) ? xtmp : ytmp;
173 xtmp = (gport->view_x - gport->view_x0) / (gdouble) gport->view_width;
174 ytmp = (gport->view_y - gport->view_y0) / (gdouble) gport->view_height;
176 gport->zoom = zoom;
177 pixel_slop = zoom;
178 ghid_port_ranges_scale(FALSE);
180 x0 = gport->view_x - xtmp * gport->view_width;
181 if (x0 < 0)
182 x0 = 0;
183 gport->view_x0 = x0;
185 y0 = gport->view_y - ytmp * gport->view_height;
186 if (y0 < 0)
187 y0 = 0;
188 gport->view_y0 = y0;
190 ghidgui->adjustment_changed_holdoff = TRUE;
191 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), gport->view_x0);
192 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), gport->view_y0);
193 ghidgui->adjustment_changed_holdoff = FALSE;
195 ghid_port_ranges_changed();
199 /* ----------------------------------------------------------------------
200 * handles all events from PCB drawing area
203 static gint event_x, event_y;
205 void
206 ghid_get_coords (const char *msg, int *x, int *y)
208 if (!ghid_port.has_entered)
209 ghid_get_user_xy (msg);
210 *x = SIDE_X (gport->view_x);
211 *y = SIDE_Y (gport->view_y);
214 gboolean
215 ghid_note_event_location (GdkEventButton * ev)
217 gint x, y;
218 gboolean moved;
220 if (!ev)
222 gdk_window_get_pointer (ghid_port.drawing_area->window, &x, &y, NULL);
223 event_x = x;
224 event_y = y;
226 else
228 event_x = ev->x;
229 event_y = ev->y;
231 gport->view_x = event_x * gport->zoom + gport->view_x0;
232 gport->view_y = event_y * gport->zoom + gport->view_y0;
234 moved = MoveCrosshairAbsolute (SIDE_X (gport->view_x),
235 SIDE_Y (gport->view_y));
236 if (moved)
238 AdjustAttachedObjects ();
239 RestoreCrosshair (False);
241 ghid_set_cursor_position_labels ();
242 return moved;
245 static gboolean
246 have_crosshair_attachments (void)
248 gboolean result = FALSE;
250 switch (Settings.Mode)
252 case COPY_MODE:
253 case MOVE_MODE:
254 case INSERTPOINT_MODE:
255 if (Crosshair.AttachedObject.Type != NO_TYPE)
256 result = TRUE;
257 break;
258 case PASTEBUFFER_MODE:
259 case VIA_MODE:
260 result = TRUE;
261 break;
262 case POLYGON_MODE:
263 if (Crosshair.AttachedLine.State != STATE_FIRST)
264 result = TRUE;
265 break;
266 case ARC_MODE:
267 if (Crosshair.AttachedBox.State != STATE_FIRST)
268 result = TRUE;
269 break;
270 case LINE_MODE:
271 if (Crosshair.AttachedLine.State != STATE_FIRST)
272 result = TRUE;
273 break;
274 default:
275 if (Crosshair.AttachedBox.State == STATE_SECOND
276 || Crosshair.AttachedBox.State == STATE_THIRD)
277 result = TRUE;
278 break;
280 return result;
284 #define VCW 16
285 #define VCD 8
287 void
288 ghid_show_crosshair (gboolean show)
290 gint x, y;
291 static gint x_prev = -1, y_prev = -1;
292 static GdkGC *xor_gc;
293 static GdkColor cross_color;
295 if (gport->x_crosshair < 0 || ghidgui->creating || !gport->has_entered)
296 return;
298 if (!xor_gc)
300 xor_gc = gdk_gc_new (ghid_port.drawing_area->window);
301 gdk_gc_copy (xor_gc, ghid_port.drawing_area->style->white_gc);
302 gdk_gc_set_function (xor_gc, GDK_XOR);
303 /* FIXME: when CrossColor changed from config */
304 ghid_map_color_string (Settings.CrossColor, &cross_color);
306 x = DRAW_X (gport->x_crosshair);
307 y = DRAW_Y (gport->y_crosshair);
309 gdk_gc_set_foreground (xor_gc, &cross_color);
311 if (x_prev >= 0)
313 gdk_draw_line (gport->drawing_area->window, xor_gc,
314 x_prev, 0, x_prev, gport->height);
315 gdk_draw_line (gport->drawing_area->window, xor_gc,
316 0, y_prev, gport->width, y_prev);
317 if (ghidgui->auto_pan_on && have_crosshair_attachments ())
319 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
320 0, y_prev - VCD, VCD, VCW);
321 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
322 gport->width - VCD, y_prev - VCD, VCD, VCW);
323 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
324 x_prev - VCD, 0, VCW, VCD);
325 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
326 x_prev - VCD, gport->height - VCD, VCW, VCD);
330 if (x >= 0 && show)
332 gdk_draw_line (gport->drawing_area->window, xor_gc,
333 x, 0, x, gport->height);
334 gdk_draw_line (gport->drawing_area->window, xor_gc,
335 0, y, gport->width, y);
336 if (ghidgui->auto_pan_on && have_crosshair_attachments ())
338 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
339 0, y - VCD, VCD, VCW);
340 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
341 gport->width - VCD, y - VCD, VCD, VCW);
342 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
343 x - VCD, 0, VCW, VCD);
344 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
345 x - VCD, gport->height - VCD, VCW, VCD);
347 x_prev = x;
348 y_prev = y;
350 else
351 x_prev = y_prev = -1;
354 static gboolean
355 ghid_idle_cb (gpointer data)
357 if (Settings.Mode == NO_MODE)
358 SetMode (ARROW_MODE);
359 ghid_mode_cursor (Settings.Mode);
360 if (ghidgui->settings_mode != Settings.Mode)
362 ghid_mode_buttons_update ();
364 ghidgui->settings_mode = Settings.Mode;
366 ghid_update_toggle_flags ();
367 return FALSE;
370 gboolean
371 ghid_port_key_release_cb (GtkWidget * drawing_area, GdkEventKey * kev,
372 GtkUIManager * ui)
374 gint ksym = kev->keyval;
376 if (ghid_is_modifier_key_sym (ksym))
377 ghid_note_event_location (NULL);
379 HideCrosshair (TRUE);
380 AdjustAttachedObjects ();
381 ghid_invalidate_all ();
382 RestoreCrosshair (TRUE);
383 ghid_screen_update ();
384 g_idle_add (ghid_idle_cb, NULL);
385 return FALSE;
388 /* Handle user keys in the output drawing area.
389 * Note that the default is for all hotkeys to be handled by the
390 * menu accelerators.
392 * Key presses not handled by the menus will show up here.
395 gboolean
396 ghid_port_key_press_cb (GtkWidget * drawing_area,
397 GdkEventKey * kev, GtkUIManager * ui)
399 ModifierKeysState mk;
400 gchar *arg, *units;
401 gdouble value;
402 gint tmp, ksym = kev->keyval;
403 gboolean handled;
405 if (ghid_is_modifier_key_sym (ksym))
406 ghid_note_event_location (NULL);
408 mk = ghid_modifier_keys_state ((GdkModifierType *) &kev->state);
410 ghid_show_crosshair (FALSE);
412 handled = TRUE; /* Start off assuming we handle it */
413 switch (ksym)
415 case GDK_Alt_L:
416 case GDK_Alt_R:
417 case GDK_Control_L:
418 case GDK_Control_R:
419 case GDK_Shift_L:
420 case GDK_Shift_R:
421 case GDK_Shift_Lock:
422 break;
424 default:
425 gui->log ("keysym %d (0x%x) has not been defined\n", ksym, ksym);
426 handled = FALSE;
429 /* FIXME -- since we usually don't make it here, does this code need
430 to go somewhere else?
432 HideCrosshair (TRUE);
433 AdjustAttachedObjects ();
434 ghid_invalidate_all ();
435 RestoreCrosshair (TRUE);
436 /* ghid_show_crosshair(TRUE); */
437 ghid_screen_update ();
438 ghid_set_status_line_label ();
439 g_idle_add (ghid_idle_cb, NULL);
440 return handled;
443 static gboolean
444 in_draw_state (void)
446 if ((Settings.Mode == LINE_MODE
447 && Crosshair.AttachedLine.State != STATE_FIRST)
448 || (Settings.Mode == ARC_MODE
449 && Crosshair.AttachedBox.State != STATE_FIRST)
450 || (Settings.Mode == RECTANGLE_MODE
451 && Crosshair.AttachedBox.State != STATE_FIRST)
452 || (Settings.Mode == POLYGON_MODE
453 && Crosshair.AttachedLine.State != STATE_FIRST))
454 return TRUE;
455 return FALSE;
458 static gboolean draw_state_reset;
459 static gint x_press, y_press;
461 gboolean
462 ghid_port_button_press_cb (GtkWidget * drawing_area,
463 GdkEventButton * ev, GtkUIManager * ui)
465 GtkWidget *menu = gtk_ui_manager_get_widget (ui, "/Popup1");
466 ModifierKeysState mk;
467 gboolean drag, start_pan = FALSE;
469 x_press = ev->x;
470 y_press = ev->y;
472 ghid_note_event_location (ev);
473 mk = ghid_modifier_keys_state ((GdkModifierType *) &ev->state);
474 ghid_show_crosshair (FALSE);
475 HideCrosshair (TRUE);
476 drag = have_crosshair_attachments ();
477 draw_state_reset = FALSE;
479 switch (ev->button)
481 case 1:
482 if (mk == NONE_PRESSED || mk == SHIFT_PRESSED)
483 hid_actionl ("Mode", "Notify", NULL);
484 else if (mk == CONTROL_PRESSED)
486 hid_actionl ("Mode", "Save", NULL);
487 hid_actionl ("Mode", "None", NULL);
488 hid_actionl ("Mode", "Restore", NULL);
489 hid_actionl ("Mode", "Notify", NULL);
491 else if (mk == SHIFT_CONTROL_PRESSED)
493 hid_actionl ("Mode", "Save", NULL);
494 hid_actionl ("Mode", "Remove", NULL);
495 hid_actionl ("Mode", "Notify", NULL);
496 hid_actionl ("Mode", "Restore", NULL);
498 break;
500 case 2:
501 if (mk == NONE_PRESSED && in_draw_state ())
503 if (Settings.Mode == LINE_MODE)
504 hid_actionl ("Mode", "Line", NULL);
505 else if (Settings.Mode == ARC_MODE)
506 hid_actionl ("Mode", "Arc", NULL);
507 else if (Settings.Mode == RECTANGLE_MODE)
508 hid_actionl ("Mode", "Rectangle", NULL);
509 else if (Settings.Mode == POLYGON_MODE)
510 hid_actionl ("Mode", "Polygon", NULL);
512 hid_actionl ("Mode", "Notify", NULL);
513 draw_state_reset = TRUE;
515 else if (mk == NONE_PRESSED)
517 hid_actionl ("Mode", "Save", NULL);
518 hid_actionl ("Mode", "Stroke", NULL);
520 else if (mk == CONTROL_PRESSED)
522 hid_actionl ("Mode", "Save", NULL);
523 hid_actionl ("Mode", "Copy", NULL);
524 hid_actionl ("Mode", "Notify", NULL);
526 else if (mk == SHIFT_CONTROL_PRESSED)
528 hid_actionl ("Display", "ToggleRubberbandMode", NULL);
529 hid_actionl ("Mode", "Save", NULL);
530 hid_actionl ("Mode", "Move", NULL);
531 hid_actionl ("Mode", "Notify", NULL);
533 break;
535 case 3:
536 if (mk == NONE_PRESSED)
538 ghid_mode_cursor (PAN_MODE);
539 start_pan = TRUE;
541 else if (mk == SHIFT_PRESSED
542 && !ghidgui->command_entry_status_line_active)
544 ghidgui->in_popup = TRUE;
545 gtk_widget_grab_focus (drawing_area);
546 if (GTK_IS_MENU (menu))
547 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL,
548 drawing_area, 3, ev->time);
551 break;
553 ghid_invalidate_all ();
554 RestoreCrosshair (TRUE);
555 ghid_set_status_line_label ();
556 ghid_show_crosshair (TRUE);
557 if (!start_pan)
558 g_idle_add (ghid_idle_cb, NULL);
559 return TRUE;
563 gboolean
564 ghid_port_button_release_cb (GtkWidget * drawing_area,
565 GdkEventButton * ev, GtkUIManager * ui)
567 ModifierKeysState mk;
568 gboolean drag;
570 ghid_note_event_location (ev);
571 mk = ghid_modifier_keys_state ((GdkModifierType *) &ev->state);
573 drag = have_crosshair_attachments ();
574 if (drag)
575 HideCrosshair (TRUE);
577 switch (ev->button)
579 case 1:
580 hid_actionl ("Mode", "Release", NULL); /* For all modifier states */
581 break;
583 case 2:
584 if (mk == NONE_PRESSED && !draw_state_reset)
586 hid_actionl ("Mode", "Release", NULL);
587 hid_actionl ("Mode", "Restore", NULL);
589 else if (mk == CONTROL_PRESSED)
591 hid_actionl ("Mode", "Notify", NULL);
592 hid_actionl ("Mode", "Restore", NULL);
594 else if (mk == SHIFT_CONTROL_PRESSED)
596 hid_actionl ("Mode", "Notify", NULL);
597 hid_actionl ("Mode", "Restore", NULL);
598 hid_actionl ("Display", "ToggleRubberbandMode", NULL);
600 break;
602 case 3:
603 if (mk == SHIFT_PRESSED)
605 hid_actionl ("Display", "Center", NULL);
606 hid_actionl ("Display", "Restore", NULL);
608 else if (ev->x == x_press && ev->y == y_press)
610 ghid_show_crosshair (FALSE);
611 ghidgui->auto_pan_on = !ghidgui->auto_pan_on;
612 ghid_show_crosshair (TRUE);
614 break;
616 if (drag)
618 AdjustAttachedObjects ();
619 ghid_invalidate_all ();
620 RestoreCrosshair (TRUE);
621 ghid_screen_update ();
623 ghid_set_status_line_label ();
624 g_idle_add (ghid_idle_cb, NULL);
625 return TRUE;
629 gboolean
630 ghid_port_drawing_area_configure_event_cb (GtkWidget * widget,
631 GdkEventConfigure * ev,
632 GHidPort * out)
634 static gboolean first_time_done;
636 HideCrosshair (TRUE);
637 gport->width = ev->width;
638 gport->height = ev->height;
640 if (gport->pixmap)
641 gdk_pixmap_unref (gport->pixmap);
643 gport->pixmap = gdk_pixmap_new (widget->window,
644 gport->width, gport->height, -1);
645 gport->drawable = gport->pixmap;
647 if (!first_time_done)
649 gport->colormap = gtk_widget_get_colormap (gport->top_window);
650 gport->bg_gc = gdk_gc_new (gport->drawable);
651 if (gdk_color_parse (Settings.BackgroundColor, &gport->bg_color))
652 gdk_color_alloc (gport->colormap, &gport->bg_color);
653 else
654 gdk_color_white (gport->colormap, &gport->bg_color);
655 gdk_gc_set_foreground (gport->bg_gc, &gport->bg_color);
657 gport->offlimits_gc = gdk_gc_new (gport->drawable);
658 if (gdk_color_parse (Settings.OffLimitColor, &gport->offlimits_color))
659 gdk_color_alloc (gport->colormap, &gport->offlimits_color);
660 else
661 gdk_color_white (gport->colormap, &gport->offlimits_color);
662 gdk_gc_set_foreground (gport->offlimits_gc, &gport->offlimits_color);
663 first_time_done = TRUE;
664 PCBChanged (0, NULL, 0, 0);
666 if (gport->mask)
668 gdk_pixmap_unref (gport->mask);
669 gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
671 ghid_port_ranges_scale (FALSE);
672 ghid_invalidate_all ();
673 RestoreCrosshair (TRUE);
674 return 0;
678 void
679 ghid_screen_update (void)
682 ghid_show_crosshair (FALSE);
683 gdk_draw_drawable (gport->drawing_area->window, gport->bg_gc, gport->pixmap,
684 0, 0, 0, 0, gport->width, gport->height);
685 ghid_show_crosshair (TRUE);
688 gboolean
689 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
690 GdkEventExpose * ev, GHidPort * port)
692 ghid_show_crosshair (FALSE);
693 gdk_draw_drawable (widget->window, port->bg_gc, port->pixmap,
694 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
695 ev->area.width, ev->area.height);
696 ghid_show_crosshair (TRUE);
697 return FALSE;
700 gint
701 ghid_port_window_motion_cb (GtkWidget * widget,
702 GdkEventButton * ev, GHidPort * out)
704 ModifierKeysState mk = ghid_modifier_keys_state ((GdkModifierType *) &ev->state);
705 gdouble dx, dy;
706 static gint x_prev, y_prev;
707 gboolean moved;
709 if ((ev->state & GDK_BUTTON3_MASK) == GDK_BUTTON3_MASK
710 && mk == NONE_PRESSED)
712 if (gtk_events_pending ())
713 return FALSE;
714 dx = gport->zoom * (x_prev - ev->x);
715 dy = gport->zoom * (y_prev - ev->y);
716 if (x_prev > 0)
717 ghid_port_ranges_pan (dx, dy, TRUE);
718 x_prev = ev->x;
719 y_prev = ev->y;
720 return FALSE;
722 x_prev = y_prev = -1;
723 moved = ghid_note_event_location (ev);
724 ghid_show_crosshair (TRUE);
725 if (moved && have_crosshair_attachments ())
726 ghid_draw_area_update (gport, NULL);
727 return FALSE;
730 gint
731 ghid_port_window_enter_cb (GtkWidget * widget,
732 GdkEventCrossing * ev, GHidPort * out)
734 /* printf("mode: %d type: %d\n", ev->mode, ev->detail); */
736 /* See comment in ghid_port_window_leave_cb() */
738 if(ev->mode != GDK_CROSSING_NORMAL && ev->detail != GDK_NOTIFY_NONLINEAR)
740 return FALSE;
744 if (!ghidgui->command_entry_status_line_active)
746 out->has_entered = TRUE;
747 /* Make sure drawing area has keyboard focus when we are in it.
749 gtk_widget_grab_focus (out->drawing_area);
751 ghidgui->in_popup = FALSE;
752 RestoreCrosshair (TRUE);
754 /* Following expression is true if a you open a menu from the menu bar,
755 * move the mouse to the viewport and click on it. This closes the menu
756 * and moves the pointer to the viewport without the pointer going over
757 * the edge of the viewport */
758 if(ev->mode == GDK_CROSSING_UNGRAB && GDK_NOTIFY_NONLINEAR)
760 ghid_screen_update ();
763 return FALSE;
766 static gboolean
767 ghid_pan_idle_cb (gpointer data)
769 gdouble dx = 0, dy = 0;
771 if (gport->has_entered)
772 return FALSE;
773 dy = gport->zoom * y_pan_speed;
774 dx = gport->zoom * x_pan_speed;
775 return (ghid_port_ranges_pan (dx, dy, TRUE));
778 gint
779 ghid_port_window_leave_cb (GtkWidget * widget,
780 GdkEventCrossing * ev, GHidPort * out)
782 gint x0, y0, x, y, dx, dy, w, h;
784 /* printf("mode: %d type: %d\n", ev->mode, ev->detail); */
786 /* Window leave events can also be triggered because of focus grabs. Some
787 * X applications occasionally grab the focus and so trigger this function.
788 * At least GNOME's window manager is known to do this on every mouse click.
790 * See http://bugzilla.gnome.org/show_bug.cgi?id=102209
793 if(ev->mode != GDK_CROSSING_NORMAL)
795 return FALSE;
798 if (out->has_entered && !ghidgui->in_popup)
800 /* if actively drawing, start scrolling */
802 if (have_crosshair_attachments () && ghidgui->auto_pan_on)
804 /* GdkEvent coords are set to 0,0 at leave events, so must figure
805 | out edge the cursor left.
807 w = ghid_port.width * gport->zoom;
808 h = ghid_port.height * gport->zoom;
810 x0 = VIEW_X (0);
811 y0 = VIEW_Y (0);
812 ghid_get_coords (NULL, &x, &y);
813 x -= x0;
814 y -= y0;
816 dx = w - x;
817 dy = h - y;
819 x_pan_speed = y_pan_speed = 2 * ghidgui->auto_pan_speed;
821 if (x < dx)
823 x_pan_speed = -x_pan_speed;
824 dx = x;
826 if (y < dy)
828 y_pan_speed = -y_pan_speed;
829 dy = y;
831 if (dx < dy)
833 if (dy < h / 3)
834 y_pan_speed = y_pan_speed - (3 * dy * y_pan_speed) / h;
835 else
836 y_pan_speed = 0;
838 else
840 if (dx < w / 3)
841 x_pan_speed = x_pan_speed - (3 * dx * x_pan_speed) / w;
842 else
843 x_pan_speed = 0;
845 g_idle_add (ghid_pan_idle_cb, NULL);
849 ghid_show_crosshair (FALSE);
850 out->has_entered = FALSE;
852 ghid_screen_update ();
854 return FALSE;
858 /* Mouse scroll wheel events
860 gint
861 ghid_port_window_mouse_scroll_cb (GtkWidget * widget,
862 GdkEventScroll * ev, GHidPort * out)
864 ModifierKeysState mk = ghid_modifier_keys_state ((GdkModifierType *) &ev->state);
865 gdouble dx = 0.0, dy = 0.0, zoom_factor;
867 if (mk == NONE_PRESSED)
869 zoom_factor = (ev->direction == GDK_SCROLL_UP) ? 0.8 : 1.25;
870 ghid_port_ranges_zoom (gport->zoom * zoom_factor);
871 return TRUE;
874 if (mk == SHIFT_PRESSED)
875 dy = ghid_port.height * gport->zoom / 40;
876 else
877 dx = ghid_port.width * gport->zoom / 40;
879 if (ev->direction == GDK_SCROLL_UP)
881 dx = -dx;
882 dy = -dy;
885 HideCrosshair (FALSE);
886 ghid_port_ranges_pan (dx, dy, TRUE);
887 MoveCrosshairRelative (dx, dy);
888 AdjustAttachedObjects ();
889 RestoreCrosshair (FALSE);
891 return TRUE;