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 */
37 #include "hid/common/hid_resource.h"
39 #include <gdk/gdkkeysyms.h>
42 #include "crosshair.h"
51 #ifdef HAVE_LIBDMALLOC
55 #define TOOLTIP_UPDATE_DELAY 200
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;
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
;
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 ();
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
));
110 if (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
)
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
;
123 gtk_range_set_value (GTK_RANGE (ghidgui
->h_range
), x1
);
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.
135 ghid_port_ranges_scale (gboolean emit_changed
)
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
;
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
;
165 gtk_signal_emit_by_name (GTK_OBJECT (adj
), "changed");
169 ghid_port_ranges_zoom (gdouble zoom
)
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
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
;
192 ghid_port_ranges_scale(FALSE
);
194 x0
= gport
->view_x
- xtmp
* gport
->view_width
;
199 y0
= gport
->view_y
- ytmp
* gport
->view_height
;
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
;
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
);
232 ghid_note_event_location (GdkEventButton
* ev
)
239 gdk_window_get_pointer (ghid_port
.drawing_area
->window
, &x
, &y
, NULL
);
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
));
255 AdjustAttachedObjects ();
256 RestoreCrosshair (false);
258 ghid_set_cursor_position_labels ();
263 have_crosshair_attachments (void)
265 gboolean result
= FALSE
;
267 switch (Settings
.Mode
)
271 case INSERTPOINT_MODE
:
272 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
275 case PASTEBUFFER_MODE
:
280 case POLYGONHOLE_MODE
:
281 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
285 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
289 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
293 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
294 || Crosshair
.AttachedBox
.State
== STATE_THIRD
)
306 draw_right_cross (GdkGC
*xor_gc
, gint x
, gint y
)
308 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
309 x
, 0, x
, gport
->height
);
310 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
311 0, y
, gport
->width
, y
);
315 draw_slanted_cross (GdkGC
*xor_gc
, gint x
, gint y
)
319 x0
= x
+ (gport
->height
- y
);
320 x0
= MAX(0, MIN (x0
, gport
->width
));
322 x1
= MAX(0, MIN (x1
, gport
->width
));
323 y0
= y
+ (gport
->width
- x
);
324 y0
= MAX(0, MIN (y0
, gport
->height
));
326 y1
= MAX(0, MIN (y1
, gport
->height
));
327 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
329 x0
= x
- (gport
->height
- y
);
330 x0
= MAX(0, MIN (x0
, gport
->width
));
332 x1
= MAX(0, MIN (x1
, gport
->width
));
334 y0
= MAX(0, MIN (y0
, gport
->height
));
335 y1
= y
- (gport
->width
- x
);
336 y1
= MAX(0, MIN (y1
, gport
->height
));
337 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
342 draw_dozen_cross (GdkGC
*xor_gc
, gint x
, gint y
)
345 gdouble tan60
= sqrt (3);
347 x0
= x
+ (gport
->height
- y
) / tan60
;
348 x0
= MAX(0, MIN (x0
, gport
->width
));
350 x1
= MAX(0, MIN (x1
, gport
->width
));
351 y0
= y
+ (gport
->width
- x
) * tan60
;
352 y0
= MAX(0, MIN (y0
, gport
->height
));
354 y1
= MAX(0, MIN (y1
, gport
->height
));
355 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
358 x0
= x
+ (gport
->height
- y
) * tan60
;
359 x0
= MAX(0, MIN (x0
, gport
->width
));
361 x1
= MAX(0, MIN (x1
, gport
->width
));
362 y0
= y
+ (gport
->width
- x
) / tan60
;
363 y0
= MAX(0, MIN (y0
, gport
->height
));
365 y1
= MAX(0, MIN (y1
, gport
->height
));
366 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
369 x0
= x
- (gport
->height
- y
) / tan60
;
370 x0
= MAX(0, MIN (x0
, gport
->width
));
372 x1
= MAX(0, MIN (x1
, gport
->width
));
374 y0
= MAX(0, MIN (y0
, gport
->height
));
375 y1
= y
- (gport
->width
- x
) * tan60
;
376 y1
= MAX(0, MIN (y1
, gport
->height
));
377 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
380 x0
= x
- (gport
->height
- y
) * tan60
;
381 x0
= MAX(0, MIN (x0
, gport
->width
));
383 x1
= MAX(0, MIN (x1
, gport
->width
));
385 y0
= MAX(0, MIN (y0
, gport
->height
));
386 y1
= y
- (gport
->width
- x
) / tan60
;
387 y1
= MAX(0, MIN (y1
, gport
->height
));
388 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
393 draw_crosshair (GdkGC
*xor_gc
, gint x
, gint y
)
395 static enum crosshair_shape prev
= Basic_Crosshair_Shape
;
397 draw_right_cross (xor_gc
, x
, y
);
398 if (prev
== Union_Jack_Crosshair_Shape
)
399 draw_slanted_cross (xor_gc
, x
, y
);
400 if (prev
== Dozen_Crosshair_Shape
)
401 draw_dozen_cross (xor_gc
, x
, y
);
402 prev
= Crosshair
.shape
;
406 ghid_show_crosshair (gboolean show
)
409 static gint x_prev
= -1, y_prev
= -1;
410 static GdkGC
*xor_gc
;
411 static GdkColor cross_color
;
413 if (gport
->x_crosshair
< 0 || ghidgui
->creating
|| !gport
->has_entered
)
418 xor_gc
= gdk_gc_new (ghid_port
.drawing_area
->window
);
419 gdk_gc_copy (xor_gc
, ghid_port
.drawing_area
->style
->white_gc
);
420 gdk_gc_set_function (xor_gc
, GDK_XOR
);
421 /* FIXME: when CrossColor changed from config */
422 ghid_map_color_string (Settings
.CrossColor
, &cross_color
);
424 x
= DRAW_X (gport
->x_crosshair
);
425 y
= DRAW_Y (gport
->y_crosshair
);
427 gdk_gc_set_foreground (xor_gc
, &cross_color
);
431 draw_crosshair (xor_gc
, x_prev
, y_prev
);
432 if (ghidgui
->auto_pan_on
&& have_crosshair_attachments ())
434 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
435 0, y_prev
- VCD
, VCD
, VCW
);
436 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
437 gport
->width
- VCD
, y_prev
- VCD
, VCD
, VCW
);
438 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
439 x_prev
- VCD
, 0, VCW
, VCD
);
440 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
441 x_prev
- VCD
, gport
->height
- VCD
, VCW
, VCD
);
447 draw_crosshair (xor_gc
, x
, y
);
448 if (ghidgui
->auto_pan_on
&& have_crosshair_attachments ())
450 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
451 0, y
- VCD
, VCD
, VCW
);
452 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
453 gport
->width
- VCD
, y
- VCD
, VCD
, VCW
);
454 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
455 x
- VCD
, 0, VCW
, VCD
);
456 gdk_draw_rectangle (gport
->drawing_area
->window
, xor_gc
, TRUE
,
457 x
- VCD
, gport
->height
- VCD
, VCW
, VCD
);
463 x_prev
= y_prev
= -1;
467 ghid_idle_cb (gpointer data
)
469 if (Settings
.Mode
== NO_MODE
)
470 SetMode (ARROW_MODE
);
471 ghid_mode_cursor (Settings
.Mode
);
472 if (ghidgui
->settings_mode
!= Settings
.Mode
)
474 ghid_mode_buttons_update ();
476 ghidgui
->settings_mode
= Settings
.Mode
;
478 ghid_update_toggle_flags ();
483 ghid_port_key_release_cb (GtkWidget
* drawing_area
, GdkEventKey
* kev
,
486 gint ksym
= kev
->keyval
;
488 if (ghid_is_modifier_key_sym (ksym
))
489 ghid_note_event_location (NULL
);
491 HideCrosshair (TRUE
);
492 AdjustAttachedObjects ();
493 ghid_invalidate_all ();
494 RestoreCrosshair (TRUE
);
495 ghid_screen_update ();
496 g_idle_add (ghid_idle_cb
, NULL
);
500 /* Handle user keys in the output drawing area.
501 * Note that the default is for all hotkeys to be handled by the
504 * Key presses not handled by the menus will show up here. This means
505 * the key press was either not defined in the menu resource file or
506 * that the key press is special in that gtk doesn't allow the normal
507 * menu code to ever see it. We capture those here (like Tab and the
508 * arrow keys) and feed it back to the normal menu callback.
512 ghid_port_key_press_cb (GtkWidget
* drawing_area
,
513 GdkEventKey
* kev
, GtkUIManager
* ui
)
515 ModifierKeysState mk
;
516 gint ksym
= kev
->keyval
;
518 extern void ghid_hotkey_cb (int);
519 GdkModifierType state
;
521 if (ghid_is_modifier_key_sym (ksym
))
522 ghid_note_event_location (NULL
);
524 state
= (GdkModifierType
) (kev
->state
);
525 mk
= ghid_modifier_keys_state (&state
);
527 ghid_show_crosshair (FALSE
);
529 handled
= TRUE
; /* Start off assuming we handle it */
542 ghid_hotkey_cb (GHID_KEY_UP
);
546 ghid_hotkey_cb (GHID_KEY_DOWN
);
549 ghid_hotkey_cb (GHID_KEY_LEFT
);
552 ghid_hotkey_cb (GHID_KEY_RIGHT
);
555 case GDK_ISO_Left_Tab
:
556 case GDK_3270_BackTab
:
560 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
562 case CONTROL_PRESSED
:
563 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
566 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
569 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
571 case SHIFT_CONTROL_PRESSED
:
572 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
574 case SHIFT_MOD1_PRESSED
:
575 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
588 ghid_hotkey_cb (GHID_KEY_TAB
);
590 case CONTROL_PRESSED
:
591 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_TAB
);
594 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_TAB
);
597 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
599 case SHIFT_CONTROL_PRESSED
:
600 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
602 case SHIFT_MOD1_PRESSED
:
603 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
620 ghid_port_button_press_cb (GtkWidget
* drawing_area
,
621 GdkEventButton
* ev
, GtkUIManager
* ui
)
623 ModifierKeysState mk
;
625 GdkModifierType state
;
627 /* Reject double and triple click events */
628 if (ev
->type
!= GDK_BUTTON_PRESS
) return TRUE
;
630 ghid_note_event_location (ev
);
631 state
= (GdkModifierType
) (ev
->state
);
632 mk
= ghid_modifier_keys_state (&state
);
633 ghid_show_crosshair (FALSE
);
634 HideCrosshair (TRUE
);
635 drag
= have_crosshair_attachments ();
637 do_mouse_action(ev
->button
, mk
);
639 ghid_invalidate_all ();
640 RestoreCrosshair (TRUE
);
641 ghid_set_status_line_label ();
642 ghid_show_crosshair (TRUE
);
644 g_idle_add (ghid_idle_cb
, NULL
);
650 ghid_port_button_release_cb (GtkWidget
* drawing_area
,
651 GdkEventButton
* ev
, GtkUIManager
* ui
)
653 ModifierKeysState mk
;
655 GdkModifierType state
;
657 ghid_note_event_location (ev
);
658 state
= (GdkModifierType
) (ev
->state
);
659 mk
= ghid_modifier_keys_state (&state
);
661 drag
= have_crosshair_attachments ();
663 HideCrosshair (TRUE
);
665 do_mouse_action(ev
->button
, mk
+ M_Release
);
669 AdjustAttachedObjects ();
670 ghid_invalidate_all ();
671 RestoreCrosshair (TRUE
);
672 ghid_screen_update ();
674 ghid_set_status_line_label ();
675 g_idle_add (ghid_idle_cb
, NULL
);
681 ghid_port_drawing_area_configure_event_cb (GtkWidget
* widget
,
682 GdkEventConfigure
* ev
,
685 static gboolean first_time_done
;
687 HideCrosshair (TRUE
);
688 gport
->width
= ev
->width
;
689 gport
->height
= ev
->height
;
692 gdk_pixmap_unref (gport
->pixmap
);
694 gport
->pixmap
= gdk_pixmap_new (widget
->window
,
695 gport
->width
, gport
->height
, -1);
696 gport
->drawable
= gport
->pixmap
;
698 if (!first_time_done
)
700 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
701 gport
->bg_gc
= gdk_gc_new (gport
->drawable
);
702 if (gdk_color_parse (Settings
.BackgroundColor
, &gport
->bg_color
))
703 gdk_color_alloc (gport
->colormap
, &gport
->bg_color
);
705 gdk_color_white (gport
->colormap
, &gport
->bg_color
);
706 gdk_gc_set_foreground (gport
->bg_gc
, &gport
->bg_color
);
708 gport
->offlimits_gc
= gdk_gc_new (gport
->drawable
);
709 if (gdk_color_parse (Settings
.OffLimitColor
, &gport
->offlimits_color
))
710 gdk_color_alloc (gport
->colormap
, &gport
->offlimits_color
);
712 gdk_color_white (gport
->colormap
, &gport
->offlimits_color
);
713 gdk_gc_set_foreground (gport
->offlimits_gc
, &gport
->offlimits_color
);
714 first_time_done
= TRUE
;
715 PCBChanged (0, NULL
, 0, 0);
719 gdk_pixmap_unref (gport
->mask
);
720 gport
->mask
= gdk_pixmap_new (0, gport
->width
, gport
->height
, 1);
722 ghid_port_ranges_scale (FALSE
);
723 ghid_invalidate_all ();
724 RestoreCrosshair (TRUE
);
730 ghid_screen_update (void)
733 ghid_show_crosshair (FALSE
);
734 gdk_draw_drawable (gport
->drawing_area
->window
, gport
->bg_gc
, gport
->pixmap
,
735 0, 0, 0, 0, gport
->width
, gport
->height
);
736 ghid_show_crosshair (TRUE
);
740 ghid_port_drawing_area_expose_event_cb (GtkWidget
* widget
,
741 GdkEventExpose
* ev
, GHidPort
* port
)
743 ghid_show_crosshair (FALSE
);
744 gdk_draw_drawable (widget
->window
, port
->bg_gc
, port
->pixmap
,
745 ev
->area
.x
, ev
->area
.y
, ev
->area
.x
, ev
->area
.y
,
746 ev
->area
.width
, ev
->area
.height
);
747 ghid_show_crosshair (TRUE
);
751 #if GTK_CHECK_VERSION(2,12,0)
752 # define ENABLE_TOOLTIPS 1
754 # define ENABLE_TOOLTIPS 0
759 describe_location (LocationType X
, LocationType Y
)
761 void *ptr1
, *ptr2
, *ptr3
;
766 char *netname
= NULL
;
769 /* check if there are any pins or pads at that position */
771 type
= SearchObjectByLocation (PIN_TYPE
| PAD_TYPE
,
772 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
776 /* don't mess with silk objects! */
777 if (type
& SILK_TYPE
&&
778 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
) >= max_layer
)
781 if (type
== PIN_TYPE
|| type
== PAD_TYPE
)
782 elename
= UNKNOWN (NAMEONPCB_NAME ((ElementTypePtr
) ptr1
));
784 pinname
= ConnectionName (type
, ptr1
, ptr2
);
789 /* Find netlist entry */
790 MENU_LOOP (&PCB
->NetlistLib
);
797 if (!entry
->ListEntry
)
800 if (strcmp (entry
->ListEntry
, pinname
) == 0) {
801 netname
= g_strdup (menu
->Name
);
802 /* For some reason, the netname has spaces in front of it, strip them */
803 g_strstrip (netname
);
814 description
= g_strdup_printf ("Element name: %s\n"
818 (pinname
!= NULL
) ? pinname
: "--",
819 (netname
!= NULL
) ? netname
: "--");
827 static gboolean
check_object_tooltips (GHidPort
*out
)
831 /* check if there are any pins or pads at that position */
832 description
= describe_location (out
->x_crosshair
, out
->y_crosshair
);
834 if (description
== NULL
)
837 gtk_widget_set_tooltip_text (out
->drawing_area
, description
);
838 g_free (description
);
843 static int tooltip_update_timeout_id
= 0;
846 cancel_tooltip_update ()
848 if (tooltip_update_timeout_id
)
849 g_source_remove (tooltip_update_timeout_id
);
850 tooltip_update_timeout_id
= 0;
853 /* FIXME: If the GHidPort is ever destroyed, we must call
854 * cancel_tooltip_update (), otherwise the timeout might
855 * fire after the data it utilises has been free'd.
858 queue_tooltip_update (GHidPort
*out
)
860 /* Zap the old tool-tip text and force it to be removed from the screen */
861 gtk_widget_set_tooltip_text (out
->drawing_area
, NULL
);
862 gtk_widget_trigger_tooltip_query (out
->drawing_area
);
864 cancel_tooltip_update ();
866 tooltip_update_timeout_id
=
867 g_timeout_add (TOOLTIP_UPDATE_DELAY
,
868 (GSourceFunc
) check_object_tooltips
,
874 ghid_port_window_motion_cb (GtkWidget
* widget
,
875 GdkEventButton
* ev
, GHidPort
* out
)
878 static gint x_prev
= -1, y_prev
= -1;
883 if (gtk_events_pending ())
885 dx
= gport
->zoom
* (x_prev
- ev
->x
);
886 dy
= gport
->zoom
* (y_prev
- ev
->y
);
888 ghid_port_ranges_pan (dx
, dy
, TRUE
);
893 x_prev
= y_prev
= -1;
894 moved
= ghid_note_event_location (ev
);
897 queue_tooltip_update (out
);
900 ghid_show_crosshair (TRUE
);
901 if (moved
&& have_crosshair_attachments ())
902 ghid_draw_area_update (gport
, NULL
);
907 ghid_port_window_enter_cb (GtkWidget
* widget
,
908 GdkEventCrossing
* ev
, GHidPort
* out
)
910 /* printf("enter: mode: %d detail: %d\n", ev->mode, ev->detail); */
912 /* See comment in ghid_port_window_leave_cb() */
914 if(ev
->mode
!= GDK_CROSSING_NORMAL
&& ev
->detail
!= GDK_NOTIFY_NONLINEAR
)
919 if (!ghidgui
->command_entry_status_line_active
)
921 out
->has_entered
= TRUE
;
922 /* Make sure drawing area has keyboard focus when we are in it.
924 gtk_widget_grab_focus (out
->drawing_area
);
926 ghidgui
->in_popup
= FALSE
;
928 /* Following expression is true if a you open a menu from the menu bar,
929 * move the mouse to the viewport and click on it. This closes the menu
930 * and moves the pointer to the viewport without the pointer going over
931 * the edge of the viewport */
932 if(ev
->mode
== GDK_CROSSING_UNGRAB
&& ev
->detail
== GDK_NOTIFY_NONLINEAR
)
934 ghid_screen_update ();
937 if(! cursor_in_viewport
)
939 RestoreCrosshair (TRUE
);
940 cursor_in_viewport
= TRUE
;
947 ghid_pan_idle_cb (gpointer data
)
949 gdouble dx
= 0, dy
= 0;
951 if (gport
->has_entered
)
953 dy
= gport
->zoom
* y_pan_speed
;
954 dx
= gport
->zoom
* x_pan_speed
;
955 return (ghid_port_ranges_pan (dx
, dy
, TRUE
));
959 ghid_port_window_leave_cb (GtkWidget
* widget
,
960 GdkEventCrossing
* ev
, GHidPort
* out
)
962 gint x0
, y0
, x
, y
, dx
, dy
, w
, h
;
964 /* printf("leave mode: %d detail: %d\n", ev->mode, ev->detail); */
966 /* Window leave events can also be triggered because of focus grabs. Some
967 * X applications occasionally grab the focus and so trigger this function.
968 * At least GNOME's window manager is known to do this on every mouse click.
970 * See http://bugzilla.gnome.org/show_bug.cgi?id=102209
973 if(ev
->mode
!= GDK_CROSSING_NORMAL
)
978 if(out
->has_entered
&& !ghidgui
->in_popup
)
980 /* if actively drawing, start scrolling */
982 if (have_crosshair_attachments () && ghidgui
->auto_pan_on
)
984 /* GdkEvent coords are set to 0,0 at leave events, so must figure
985 | out edge the cursor left.
987 w
= ghid_port
.width
* gport
->zoom
;
988 h
= ghid_port
.height
* gport
->zoom
;
992 ghid_get_coords (NULL
, &x
, &y
);
1004 x_pan_speed
= y_pan_speed
= 2 * ghidgui
->auto_pan_speed
;
1008 x_pan_speed
= -x_pan_speed
;
1013 y_pan_speed
= -y_pan_speed
;
1019 y_pan_speed
= y_pan_speed
- (3 * dy
* y_pan_speed
) / h
;
1026 x_pan_speed
= x_pan_speed
- (3 * dx
* x_pan_speed
) / w
;
1030 g_idle_add (ghid_pan_idle_cb
, NULL
);
1034 if(cursor_in_viewport
)
1036 HideCrosshair (TRUE
);
1037 cursor_in_viewport
= FALSE
;
1040 ghid_show_crosshair (FALSE
);
1041 out
->has_entered
= FALSE
;
1043 ghid_screen_update ();
1049 /* Mouse scroll wheel events
1052 ghid_port_window_mouse_scroll_cb (GtkWidget
* widget
,
1053 GdkEventScroll
* ev
, GHidPort
* out
)
1055 ModifierKeysState mk
;
1056 GdkModifierType state
;
1059 state
= (GdkModifierType
) (ev
->state
);
1060 mk
= ghid_modifier_keys_state (&state
);
1062 /* X11 gtk hard codes buttons 4, 5, 6, 7 as below in
1063 * gtk+/gdk/x11/gdkevents-x11.c:1121, but quartz and windows have
1064 * special mouse scroll events, so this may conflict with a mouse
1065 * who has buttons 4 - 7 that aren't the scroll wheel?
1067 switch(ev
->direction
)
1069 case GDK_SCROLL_UP
: button
= 4; break;
1070 case GDK_SCROLL_DOWN
: button
= 5; break;
1071 case GDK_SCROLL_LEFT
: button
= 6; break;
1072 case GDK_SCROLL_RIGHT
: button
= 7; break;
1073 default: button
= -1;
1076 do_mouse_action(button
, mk
);