Change all Booleans to bool.
[geda-pcb/gde.git] / src / hid / gtk / gui-output-events.c
blobc82e067361e5929dc16abd9c9433ece77168bc6f
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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"
37 #include "hid/common/hid_resource.h"
39 #include <gdk/gdkkeysyms.h>
41 #include "action.h"
42 #include "crosshair.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "misc.h"
46 #include "set.h"
47 #include "find.h"
48 #include "search.h"
49 #include "rats.h"
51 #ifdef HAVE_LIBDMALLOC
52 #include <dmalloc.h>
53 #endif
55 #define TOOLTIP_UPDATE_DELAY 200
57 RCSID ("$Id$");
59 static gint x_pan_speed, y_pan_speed;
61 /* Set to true if cursor is currently in viewport. This is a hack to prevent
62 * Crosshair stack corruption due to unmatching window enter / leave events */
63 gboolean cursor_in_viewport = false;
65 void
66 ghid_port_ranges_changed (void)
68 GtkAdjustment *h_adj, *v_adj;
70 if (!ghidgui->combine_adjustments)
71 HideCrosshair (FALSE);
72 if (ghidgui->combine_adjustments)
74 ghidgui->combine_adjustments = FALSE;
75 return;
78 ghidgui->need_restore_crosshair = TRUE;
80 h_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
81 v_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
82 gport->view_x0 = h_adj->value;
83 gport->view_y0 = v_adj->value;
85 ghid_invalidate_all ();
88 gboolean
89 ghid_port_ranges_pan (gdouble x, gdouble y, gboolean relative)
91 GtkAdjustment *h_adj, *v_adj;
92 gdouble x0, y0, x1, y1;
94 h_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
95 v_adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
96 x0 = h_adj->value;
97 y0 = v_adj->value;
99 if (relative)
101 x1 = x0 + x;
102 y1 = y0 + y;
104 else
106 x1 = x;
107 y1 = y;
110 if (x1 < h_adj->lower)
111 x1 = h_adj->lower;
112 if (x1 > h_adj->upper - h_adj->page_size)
113 x1 = h_adj->upper - h_adj->page_size;
115 if (y1 < v_adj->lower)
116 y1 = v_adj->lower;
117 if (y1 > v_adj->upper - v_adj->page_size)
118 y1 = v_adj->upper - v_adj->page_size;
120 if (x0 != x1 && y0 != y1)
121 ghidgui->combine_adjustments = TRUE;
122 if (x0 != x1)
123 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), x1);
124 if (y0 != y1)
125 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), y1);
127 ghid_note_event_location (NULL);
128 return ((x0 != x1) || (y0 != y1));
131 /* Do scrollbar scaling based on current port drawing area size and
132 | overall PCB board size.
134 void
135 ghid_port_ranges_scale (gboolean emit_changed)
137 GtkAdjustment *adj;
139 /* Update the scrollbars with PCB units. So Scale the current
140 | drawing area size in pixels to PCB units and that will be
141 | the page size for the Gtk adjustment.
143 gport->view_width = gport->width * gport->zoom;
144 gport->view_height = gport->height * gport->zoom;
146 if (gport->view_width >= PCB->MaxWidth)
147 gport->view_width = PCB->MaxWidth;
148 if (gport->view_height >= PCB->MaxHeight)
149 gport->view_height = PCB->MaxHeight;
151 adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->h_range));
152 adj->page_size = gport->view_width;
153 adj->page_increment = adj->page_size/10.0;
154 adj->step_increment = adj->page_size/100.0;
155 adj->upper = PCB->MaxWidth;
156 if (emit_changed)
157 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
159 adj = gtk_range_get_adjustment (GTK_RANGE (ghidgui->v_range));
160 adj->page_size = gport->view_height;
161 adj->page_increment = adj->page_size/10.0;
162 adj->step_increment = adj->page_size/100.0;
163 adj->upper = PCB->MaxHeight;
164 if (emit_changed)
165 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
168 void
169 ghid_port_ranges_zoom (gdouble zoom)
171 gdouble xtmp, ytmp;
172 gint x0, y0;
174 /* figure out zoom values in that would just make the width fit and
175 * that would just make the height fit
177 xtmp = (gdouble) PCB->MaxWidth / gport->width;
178 ytmp = (gdouble) PCB->MaxHeight / gport->height;
180 /* if we've tried to zoom further out than what would make the
181 * entire board fit or we passed 0, then pick a zoom that just makes
182 * the board fit.
184 if ((zoom > xtmp && zoom > ytmp) || zoom == 0.0)
185 zoom = (xtmp > ytmp) ? xtmp : ytmp;
187 xtmp = (gport->view_x - gport->view_x0) / (gdouble) gport->view_width;
188 ytmp = (gport->view_y - gport->view_y0) / (gdouble) gport->view_height;
190 gport->zoom = zoom;
191 pixel_slop = zoom;
192 ghid_port_ranges_scale(FALSE);
194 x0 = gport->view_x - xtmp * gport->view_width;
195 if (x0 < 0)
196 x0 = 0;
197 gport->view_x0 = x0;
199 y0 = gport->view_y - ytmp * gport->view_height;
200 if (y0 < 0)
201 y0 = 0;
202 gport->view_y0 = y0;
204 ghidgui->adjustment_changed_holdoff = TRUE;
205 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), gport->view_x0);
206 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), gport->view_y0);
207 ghidgui->adjustment_changed_holdoff = FALSE;
209 ghid_port_ranges_changed();
213 /* ----------------------------------------------------------------------
214 * handles all events from PCB drawing area
217 static gint event_x, event_y;
219 void
220 ghid_get_coords (const char *msg, int *x, int *y)
222 if (!ghid_port.has_entered && msg)
223 ghid_get_user_xy (msg);
224 if (ghid_port.has_entered)
226 *x = SIDE_X (gport->view_x);
227 *y = SIDE_Y (gport->view_y);
231 gboolean
232 ghid_note_event_location (GdkEventButton * ev)
234 gint x, y;
235 gboolean moved;
237 if (!ev)
239 gdk_window_get_pointer (ghid_port.drawing_area->window, &x, &y, NULL);
240 event_x = x;
241 event_y = y;
243 else
245 event_x = ev->x;
246 event_y = ev->y;
248 gport->view_x = event_x * gport->zoom + gport->view_x0;
249 gport->view_y = event_y * gport->zoom + gport->view_y0;
251 moved = MoveCrosshairAbsolute (SIDE_X (gport->view_x),
252 SIDE_Y (gport->view_y));
253 if (moved)
255 AdjustAttachedObjects ();
256 RestoreCrosshair (false);
258 ghid_set_cursor_position_labels ();
259 return moved;
262 static gboolean
263 have_crosshair_attachments (void)
265 gboolean result = FALSE;
267 switch (Settings.Mode)
269 case COPY_MODE:
270 case MOVE_MODE:
271 case INSERTPOINT_MODE:
272 if (Crosshair.AttachedObject.Type != NO_TYPE)
273 result = TRUE;
274 break;
275 case PASTEBUFFER_MODE:
276 case VIA_MODE:
277 result = TRUE;
278 break;
279 case POLYGON_MODE:
280 if (Crosshair.AttachedLine.State != STATE_FIRST)
281 result = TRUE;
282 break;
283 case ARC_MODE:
284 if (Crosshair.AttachedBox.State != STATE_FIRST)
285 result = TRUE;
286 break;
287 case LINE_MODE:
288 if (Crosshair.AttachedLine.State != STATE_FIRST)
289 result = TRUE;
290 break;
291 default:
292 if (Crosshair.AttachedBox.State == STATE_SECOND
293 || Crosshair.AttachedBox.State == STATE_THIRD)
294 result = TRUE;
295 break;
297 return result;
301 #define VCW 16
302 #define VCD 8
304 static void
305 draw_right_cross (GdkGC *xor_gc, gint x, gint y)
307 gdk_draw_line (gport->drawing_area->window, xor_gc,
308 x, 0, x, gport->height);
309 gdk_draw_line (gport->drawing_area->window, xor_gc,
310 0, y, gport->width, y);
313 static void
314 draw_slanted_cross (GdkGC *xor_gc, gint x, gint y)
316 gint x0, y0, x1, y1;
318 x0 = x + (gport->height - y);
319 x0 = MAX(0, MIN (x0, gport->width));
320 x1 = x - y;
321 x1 = MAX(0, MIN (x1, gport->width));
322 y0 = y + (gport->width - x);
323 y0 = MAX(0, MIN (y0, gport->height));
324 y1 = y - x;
325 y1 = MAX(0, MIN (y1, gport->height));
326 gdk_draw_line (gport->drawing_area->window, xor_gc,
327 x0, y0, x1, y1);
328 x0 = x - (gport->height - y);
329 x0 = MAX(0, MIN (x0, gport->width));
330 x1 = x + y;
331 x1 = MAX(0, MIN (x1, gport->width));
332 y0 = y + x;
333 y0 = MAX(0, MIN (y0, gport->height));
334 y1 = y - (gport->width - x);
335 y1 = MAX(0, MIN (y1, gport->height));
336 gdk_draw_line (gport->drawing_area->window, xor_gc,
337 x0, y0, x1, y1);
340 static void
341 draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
343 gint x0, y0, x1, y1;
344 gdouble tan60 = sqrt (3);
346 x0 = x + (gport->height - y) / tan60;
347 x0 = MAX(0, MIN (x0, gport->width));
348 x1 = x - y / tan60;
349 x1 = MAX(0, MIN (x1, gport->width));
350 y0 = y + (gport->width - x) * tan60;
351 y0 = MAX(0, MIN (y0, gport->height));
352 y1 = y - x * tan60;
353 y1 = MAX(0, MIN (y1, gport->height));
354 gdk_draw_line (gport->drawing_area->window, xor_gc,
355 x0, y0, x1, y1);
357 x0 = x + (gport->height - y) * tan60;
358 x0 = MAX(0, MIN (x0, gport->width));
359 x1 = x - y * tan60;
360 x1 = MAX(0, MIN (x1, gport->width));
361 y0 = y + (gport->width - x) / tan60;
362 y0 = MAX(0, MIN (y0, gport->height));
363 y1 = y - x / tan60;
364 y1 = MAX(0, MIN (y1, gport->height));
365 gdk_draw_line (gport->drawing_area->window, xor_gc,
366 x0, y0, x1, y1);
368 x0 = x - (gport->height - y) / tan60;
369 x0 = MAX(0, MIN (x0, gport->width));
370 x1 = x + y / tan60;
371 x1 = MAX(0, MIN (x1, gport->width));
372 y0 = y + x * tan60;
373 y0 = MAX(0, MIN (y0, gport->height));
374 y1 = y - (gport->width - x) * tan60;
375 y1 = MAX(0, MIN (y1, gport->height));
376 gdk_draw_line (gport->drawing_area->window, xor_gc,
377 x0, y0, x1, y1);
379 x0 = x - (gport->height - y) * tan60;
380 x0 = MAX(0, MIN (x0, gport->width));
381 x1 = x + y * tan60;
382 x1 = MAX(0, MIN (x1, gport->width));
383 y0 = y + x / tan60;
384 y0 = MAX(0, MIN (y0, gport->height));
385 y1 = y - (gport->width - x) / tan60;
386 y1 = MAX(0, MIN (y1, gport->height));
387 gdk_draw_line (gport->drawing_area->window, xor_gc,
388 x0, y0, x1, y1);
391 static void
392 draw_crosshair (GdkGC *xor_gc, gint x, gint y)
394 static enum crosshair_shape prev = Basic_Crosshair_Shape;
396 draw_right_cross (xor_gc, x, y);
397 if (prev == Union_Jack_Crosshair_Shape)
398 draw_slanted_cross (xor_gc, x, y);
399 if (prev == Dozen_Crosshair_Shape)
400 draw_dozen_cross (xor_gc, x, y);
401 prev = Crosshair.shape;
404 void
405 ghid_show_crosshair (gboolean show)
407 gint x, y;
408 static gint x_prev = -1, y_prev = -1;
409 static GdkGC *xor_gc;
410 static GdkColor cross_color;
412 if (gport->x_crosshair < 0 || ghidgui->creating || !gport->has_entered)
413 return;
415 if (!xor_gc)
417 xor_gc = gdk_gc_new (ghid_port.drawing_area->window);
418 gdk_gc_copy (xor_gc, ghid_port.drawing_area->style->white_gc);
419 gdk_gc_set_function (xor_gc, GDK_XOR);
420 /* FIXME: when CrossColor changed from config */
421 ghid_map_color_string (Settings.CrossColor, &cross_color);
423 x = DRAW_X (gport->x_crosshair);
424 y = DRAW_Y (gport->y_crosshair);
426 gdk_gc_set_foreground (xor_gc, &cross_color);
428 if (x_prev >= 0)
430 draw_crosshair (xor_gc, x_prev, y_prev);
431 if (ghidgui->auto_pan_on && have_crosshair_attachments ())
433 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
434 0, y_prev - VCD, VCD, VCW);
435 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
436 gport->width - VCD, y_prev - VCD, VCD, VCW);
437 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
438 x_prev - VCD, 0, VCW, VCD);
439 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
440 x_prev - VCD, gport->height - VCD, VCW, VCD);
444 if (x >= 0 && show)
446 draw_crosshair (xor_gc, x, y);
447 if (ghidgui->auto_pan_on && have_crosshair_attachments ())
449 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
450 0, y - VCD, VCD, VCW);
451 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
452 gport->width - VCD, y - VCD, VCD, VCW);
453 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
454 x - VCD, 0, VCW, VCD);
455 gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
456 x - VCD, gport->height - VCD, VCW, VCD);
458 x_prev = x;
459 y_prev = y;
461 else
462 x_prev = y_prev = -1;
465 static gboolean
466 ghid_idle_cb (gpointer data)
468 if (Settings.Mode == NO_MODE)
469 SetMode (ARROW_MODE);
470 ghid_mode_cursor (Settings.Mode);
471 if (ghidgui->settings_mode != Settings.Mode)
473 ghid_mode_buttons_update ();
475 ghidgui->settings_mode = Settings.Mode;
477 ghid_update_toggle_flags ();
478 return FALSE;
481 gboolean
482 ghid_port_key_release_cb (GtkWidget * drawing_area, GdkEventKey * kev,
483 GtkUIManager * ui)
485 gint ksym = kev->keyval;
487 if (ghid_is_modifier_key_sym (ksym))
488 ghid_note_event_location (NULL);
490 HideCrosshair (TRUE);
491 AdjustAttachedObjects ();
492 ghid_invalidate_all ();
493 RestoreCrosshair (TRUE);
494 ghid_screen_update ();
495 g_idle_add (ghid_idle_cb, NULL);
496 return FALSE;
499 /* Handle user keys in the output drawing area.
500 * Note that the default is for all hotkeys to be handled by the
501 * menu accelerators.
503 * Key presses not handled by the menus will show up here. This means
504 * the key press was either not defined in the menu resource file or
505 * that the key press is special in that gtk doesn't allow the normal
506 * menu code to ever see it. We capture those here (like Tab and the
507 * arrow keys) and feed it back to the normal menu callback.
510 gboolean
511 ghid_port_key_press_cb (GtkWidget * drawing_area,
512 GdkEventKey * kev, GtkUIManager * ui)
514 ModifierKeysState mk;
515 gint ksym = kev->keyval;
516 gboolean handled;
517 extern void ghid_hotkey_cb (int);
518 GdkModifierType state;
520 if (ghid_is_modifier_key_sym (ksym))
521 ghid_note_event_location (NULL);
523 state = (GdkModifierType) (kev->state);
524 mk = ghid_modifier_keys_state (&state);
526 ghid_show_crosshair (FALSE);
528 handled = TRUE; /* Start off assuming we handle it */
529 switch (ksym)
531 case GDK_Alt_L:
532 case GDK_Alt_R:
533 case GDK_Control_L:
534 case GDK_Control_R:
535 case GDK_Shift_L:
536 case GDK_Shift_R:
537 case GDK_Shift_Lock:
538 break;
540 case GDK_Up:
541 ghid_hotkey_cb (GHID_KEY_UP);
542 break;
544 case GDK_Down:
545 ghid_hotkey_cb (GHID_KEY_DOWN);
546 break;
547 case GDK_Left:
548 ghid_hotkey_cb (GHID_KEY_LEFT);
549 break;
550 case GDK_Right:
551 ghid_hotkey_cb (GHID_KEY_RIGHT);
552 break;
554 case GDK_ISO_Left_Tab:
555 case GDK_3270_BackTab:
556 switch (mk)
558 case NONE_PRESSED:
559 ghid_hotkey_cb (GHID_KEY_SHIFT | GHID_KEY_TAB);
560 break;
561 case CONTROL_PRESSED:
562 ghid_hotkey_cb (GHID_KEY_CONTROL | GHID_KEY_SHIFT | GHID_KEY_TAB);
563 break;
564 case MOD1_PRESSED:
565 ghid_hotkey_cb (GHID_KEY_ALT | GHID_KEY_SHIFT | GHID_KEY_TAB);
566 break;
567 case SHIFT_PRESSED:
568 ghid_hotkey_cb (GHID_KEY_SHIFT | GHID_KEY_TAB);
569 break;
570 case SHIFT_CONTROL_PRESSED:
571 ghid_hotkey_cb (GHID_KEY_CONTROL | GHID_KEY_SHIFT | GHID_KEY_TAB);
572 break;
573 case SHIFT_MOD1_PRESSED:
574 ghid_hotkey_cb (GHID_KEY_ALT | GHID_KEY_SHIFT | GHID_KEY_TAB);
575 break;
577 default:
578 handled = FALSE;
579 break;
581 break;
583 case GDK_Tab:
584 switch (mk)
586 case NONE_PRESSED:
587 ghid_hotkey_cb (GHID_KEY_TAB);
588 break;
589 case CONTROL_PRESSED:
590 ghid_hotkey_cb (GHID_KEY_CONTROL | GHID_KEY_TAB);
591 break;
592 case MOD1_PRESSED:
593 ghid_hotkey_cb (GHID_KEY_ALT | GHID_KEY_TAB);
594 break;
595 case SHIFT_PRESSED:
596 ghid_hotkey_cb (GHID_KEY_SHIFT | GHID_KEY_TAB);
597 break;
598 case SHIFT_CONTROL_PRESSED:
599 ghid_hotkey_cb (GHID_KEY_CONTROL | GHID_KEY_SHIFT | GHID_KEY_TAB);
600 break;
601 case SHIFT_MOD1_PRESSED:
602 ghid_hotkey_cb (GHID_KEY_ALT | GHID_KEY_SHIFT | GHID_KEY_TAB);
603 break;
605 default:
606 handled = FALSE;
607 break;
609 break;
611 default:
612 handled = FALSE;
615 return handled;
618 gboolean
619 ghid_port_button_press_cb (GtkWidget * drawing_area,
620 GdkEventButton * ev, GtkUIManager * ui)
622 ModifierKeysState mk;
623 gboolean drag;
624 GdkModifierType state;
626 /* Reject double and triple click events */
627 if (ev->type != GDK_BUTTON_PRESS) return TRUE;
629 ghid_note_event_location (ev);
630 state = (GdkModifierType) (ev->state);
631 mk = ghid_modifier_keys_state (&state);
632 ghid_show_crosshair (FALSE);
633 HideCrosshair (TRUE);
634 drag = have_crosshair_attachments ();
636 do_mouse_action(ev->button, mk);
638 ghid_invalidate_all ();
639 RestoreCrosshair (TRUE);
640 ghid_set_status_line_label ();
641 ghid_show_crosshair (TRUE);
642 if (!gport->panning)
643 g_idle_add (ghid_idle_cb, NULL);
644 return TRUE;
648 gboolean
649 ghid_port_button_release_cb (GtkWidget * drawing_area,
650 GdkEventButton * ev, GtkUIManager * ui)
652 ModifierKeysState mk;
653 gboolean drag;
654 GdkModifierType state;
656 ghid_note_event_location (ev);
657 state = (GdkModifierType) (ev->state);
658 mk = ghid_modifier_keys_state (&state);
660 drag = have_crosshair_attachments ();
661 if (drag)
662 HideCrosshair (TRUE);
664 do_mouse_action(ev->button, mk + M_Release);
666 if (drag)
668 AdjustAttachedObjects ();
669 ghid_invalidate_all ();
670 RestoreCrosshair (TRUE);
671 ghid_screen_update ();
673 ghid_set_status_line_label ();
674 g_idle_add (ghid_idle_cb, NULL);
675 return TRUE;
679 gboolean
680 ghid_port_drawing_area_configure_event_cb (GtkWidget * widget,
681 GdkEventConfigure * ev,
682 GHidPort * out)
684 static gboolean first_time_done;
686 HideCrosshair (TRUE);
687 gport->width = ev->width;
688 gport->height = ev->height;
690 if (gport->pixmap)
691 gdk_pixmap_unref (gport->pixmap);
693 gport->pixmap = gdk_pixmap_new (widget->window,
694 gport->width, gport->height, -1);
695 gport->drawable = gport->pixmap;
697 if (!first_time_done)
699 gport->colormap = gtk_widget_get_colormap (gport->top_window);
700 gport->bg_gc = gdk_gc_new (gport->drawable);
701 if (gdk_color_parse (Settings.BackgroundColor, &gport->bg_color))
702 gdk_color_alloc (gport->colormap, &gport->bg_color);
703 else
704 gdk_color_white (gport->colormap, &gport->bg_color);
705 gdk_gc_set_foreground (gport->bg_gc, &gport->bg_color);
707 gport->offlimits_gc = gdk_gc_new (gport->drawable);
708 if (gdk_color_parse (Settings.OffLimitColor, &gport->offlimits_color))
709 gdk_color_alloc (gport->colormap, &gport->offlimits_color);
710 else
711 gdk_color_white (gport->colormap, &gport->offlimits_color);
712 gdk_gc_set_foreground (gport->offlimits_gc, &gport->offlimits_color);
713 first_time_done = TRUE;
714 PCBChanged (0, NULL, 0, 0);
716 if (gport->mask)
718 gdk_pixmap_unref (gport->mask);
719 gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
721 ghid_port_ranges_scale (FALSE);
722 ghid_invalidate_all ();
723 RestoreCrosshair (TRUE);
724 return 0;
728 void
729 ghid_screen_update (void)
732 ghid_show_crosshair (FALSE);
733 gdk_draw_drawable (gport->drawing_area->window, gport->bg_gc, gport->pixmap,
734 0, 0, 0, 0, gport->width, gport->height);
735 ghid_show_crosshair (TRUE);
738 gboolean
739 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
740 GdkEventExpose * ev, GHidPort * port)
742 ghid_show_crosshair (FALSE);
743 gdk_draw_drawable (widget->window, port->bg_gc, port->pixmap,
744 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
745 ev->area.width, ev->area.height);
746 ghid_show_crosshair (TRUE);
747 return FALSE;
750 #if GTK_CHECK_VERSION(2,12,0)
751 # define ENABLE_TOOLTIPS 1
752 #else
753 # define ENABLE_TOOLTIPS 0
754 #endif
756 #if ENABLE_TOOLTIPS
757 static char *
758 describe_location (LocationType X, LocationType Y)
760 void *ptr1, *ptr2, *ptr3;
761 int type;
762 int Range = 0;
763 char *elename = "";
764 char *pinname;
765 char *netname = NULL;
766 char *description;
768 /* check if there are any pins or pads at that position */
770 type = SearchObjectByLocation (PIN_TYPE | PAD_TYPE,
771 &ptr1, &ptr2, &ptr3, X, Y, Range);
772 if (type == NO_TYPE)
773 return NULL;
775 /* don't mess with silk objects! */
776 if (type & SILK_TYPE &&
777 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1) >= max_layer)
778 return NULL;
780 if (type == PIN_TYPE || type == PAD_TYPE)
781 elename = UNKNOWN (NAMEONPCB_NAME ((ElementTypePtr) ptr1));
783 pinname = ConnectionName (type, ptr1, ptr2);
785 if (pinname == NULL)
786 return NULL;
788 /* Find netlist entry */
789 MENU_LOOP (&PCB->NetlistLib);
791 if (!menu->Name)
792 continue;
794 ENTRY_LOOP (menu);
796 if (!entry->ListEntry)
797 continue;
799 if (strcmp (entry->ListEntry, pinname) == 0) {
800 netname = g_strdup (menu->Name);
801 /* For some reason, the netname has spaces in front of it, strip them */
802 g_strstrip (netname);
803 break;
806 END_LOOP;
808 if (netname != NULL)
809 break;
811 END_LOOP;
813 description = g_strdup_printf ("Element name: %s\n"
814 "Pinname : %s\n"
815 "Netname : %s",
816 elename,
817 (pinname != NULL) ? pinname : "--",
818 (netname != NULL) ? netname : "--");
820 g_free (netname);
822 return description;
826 static gboolean check_object_tooltips (GHidPort *out)
828 char *description;
830 /* check if there are any pins or pads at that position */
831 description = describe_location (out->x_crosshair, out->y_crosshair);
833 if (description == NULL)
834 return FALSE;
836 gtk_widget_set_tooltip_text (out->drawing_area, description);
837 g_free (description);
839 return FALSE;
842 static int tooltip_update_timeout_id = 0;
844 static void
845 cancel_tooltip_update ()
847 if (tooltip_update_timeout_id)
848 g_source_remove (tooltip_update_timeout_id);
849 tooltip_update_timeout_id = 0;
852 /* FIXME: If the GHidPort is ever destroyed, we must call
853 * cancel_tooltip_update (), otherwise the timeout might
854 * fire after the data it utilises has been free'd.
856 static void
857 queue_tooltip_update (GHidPort *out)
859 /* Zap the old tool-tip text and force it to be removed from the screen */
860 gtk_widget_set_tooltip_text (out->drawing_area, NULL);
861 gtk_widget_trigger_tooltip_query (out->drawing_area);
863 cancel_tooltip_update ();
865 tooltip_update_timeout_id =
866 g_timeout_add (TOOLTIP_UPDATE_DELAY,
867 (GSourceFunc) check_object_tooltips,
868 out);
870 #endif
872 gint
873 ghid_port_window_motion_cb (GtkWidget * widget,
874 GdkEventButton * ev, GHidPort * out)
876 gdouble dx, dy;
877 static gint x_prev = -1, y_prev = -1;
878 gboolean moved;
880 if (out->panning)
882 if (gtk_events_pending ())
883 return FALSE;
884 dx = gport->zoom * (x_prev - ev->x);
885 dy = gport->zoom * (y_prev - ev->y);
886 if (x_prev > 0)
887 ghid_port_ranges_pan (dx, dy, TRUE);
888 x_prev = ev->x;
889 y_prev = ev->y;
890 return FALSE;
892 x_prev = y_prev = -1;
893 moved = ghid_note_event_location (ev);
895 #if ENABLE_TOOLTIPS
896 queue_tooltip_update (out);
897 #endif
899 ghid_show_crosshair (TRUE);
900 if (moved && have_crosshair_attachments ())
901 ghid_draw_area_update (gport, NULL);
902 return FALSE;
905 gint
906 ghid_port_window_enter_cb (GtkWidget * widget,
907 GdkEventCrossing * ev, GHidPort * out)
909 /* printf("enter: mode: %d detail: %d\n", ev->mode, ev->detail); */
911 /* See comment in ghid_port_window_leave_cb() */
913 if(ev->mode != GDK_CROSSING_NORMAL && ev->detail != GDK_NOTIFY_NONLINEAR)
915 return FALSE;
918 if (!ghidgui->command_entry_status_line_active)
920 out->has_entered = TRUE;
921 /* Make sure drawing area has keyboard focus when we are in it.
923 gtk_widget_grab_focus (out->drawing_area);
925 ghidgui->in_popup = FALSE;
927 /* Following expression is true if a you open a menu from the menu bar,
928 * move the mouse to the viewport and click on it. This closes the menu
929 * and moves the pointer to the viewport without the pointer going over
930 * the edge of the viewport */
931 if(ev->mode == GDK_CROSSING_UNGRAB && ev->detail == GDK_NOTIFY_NONLINEAR)
933 ghid_screen_update ();
936 if(! cursor_in_viewport)
938 RestoreCrosshair (TRUE);
939 cursor_in_viewport = TRUE;
942 return FALSE;
945 static gboolean
946 ghid_pan_idle_cb (gpointer data)
948 gdouble dx = 0, dy = 0;
950 if (gport->has_entered)
951 return FALSE;
952 dy = gport->zoom * y_pan_speed;
953 dx = gport->zoom * x_pan_speed;
954 return (ghid_port_ranges_pan (dx, dy, TRUE));
957 gint
958 ghid_port_window_leave_cb (GtkWidget * widget,
959 GdkEventCrossing * ev, GHidPort * out)
961 gint x0, y0, x, y, dx, dy, w, h;
963 /* printf("leave mode: %d detail: %d\n", ev->mode, ev->detail); */
965 /* Window leave events can also be triggered because of focus grabs. Some
966 * X applications occasionally grab the focus and so trigger this function.
967 * At least GNOME's window manager is known to do this on every mouse click.
969 * See http://bugzilla.gnome.org/show_bug.cgi?id=102209
972 if(ev->mode != GDK_CROSSING_NORMAL)
974 return FALSE;
977 if(out->has_entered && !ghidgui->in_popup)
979 /* if actively drawing, start scrolling */
981 if (have_crosshair_attachments () && ghidgui->auto_pan_on)
983 /* GdkEvent coords are set to 0,0 at leave events, so must figure
984 | out edge the cursor left.
986 w = ghid_port.width * gport->zoom;
987 h = ghid_port.height * gport->zoom;
989 x0 = VIEW_X (0);
990 y0 = VIEW_Y (0);
991 ghid_get_coords (NULL, &x, &y);
992 x -= x0;
993 y -= y0;
995 if (ghid_flip_x )
996 x = -x;
997 if (ghid_flip_y )
998 y = -y;
1000 dx = w - x;
1001 dy = h - y;
1003 x_pan_speed = y_pan_speed = 2 * ghidgui->auto_pan_speed;
1005 if (x < dx)
1007 x_pan_speed = -x_pan_speed;
1008 dx = x;
1010 if (y < dy)
1012 y_pan_speed = -y_pan_speed;
1013 dy = y;
1015 if (dx < dy)
1017 if (dy < h / 3)
1018 y_pan_speed = y_pan_speed - (3 * dy * y_pan_speed) / h;
1019 else
1020 y_pan_speed = 0;
1022 else
1024 if (dx < w / 3)
1025 x_pan_speed = x_pan_speed - (3 * dx * x_pan_speed) / w;
1026 else
1027 x_pan_speed = 0;
1029 g_idle_add (ghid_pan_idle_cb, NULL);
1033 if(cursor_in_viewport)
1035 HideCrosshair (TRUE);
1036 cursor_in_viewport = FALSE;
1039 ghid_show_crosshair (FALSE);
1040 out->has_entered = FALSE;
1042 ghid_screen_update ();
1044 return FALSE;
1048 /* Mouse scroll wheel events
1050 gint
1051 ghid_port_window_mouse_scroll_cb (GtkWidget * widget,
1052 GdkEventScroll * ev, GHidPort * out)
1054 ModifierKeysState mk;
1055 GdkModifierType state;
1056 int button;
1058 state = (GdkModifierType) (ev->state);
1059 mk = ghid_modifier_keys_state (&state);
1061 /* X11 gtk hard codes buttons 4, 5, 6, 7 as below in
1062 * gtk+/gdk/x11/gdkevents-x11.c:1121, but quartz and windows have
1063 * special mouse scroll events, so this may conflict with a mouse
1064 * who has buttons 4 - 7 that aren't the scroll wheel?
1066 switch(ev->direction)
1068 case GDK_SCROLL_UP: button = 4; break;
1069 case GDK_SCROLL_DOWN: button = 5; break;
1070 case GDK_SCROLL_LEFT: button = 6; break;
1071 case GDK_SCROLL_RIGHT: button = 7; break;
1072 default: button = -1;
1075 do_mouse_action(button, mk);
1077 return TRUE;