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 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
284 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
288 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
292 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
293 || Crosshair
.AttachedBox
.State
== STATE_THIRD
)
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
);
314 draw_slanted_cross (GdkGC
*xor_gc
, gint x
, gint y
)
318 x0
= x
+ (gport
->height
- y
);
319 x0
= MAX(0, MIN (x0
, gport
->width
));
321 x1
= MAX(0, MIN (x1
, gport
->width
));
322 y0
= y
+ (gport
->width
- x
);
323 y0
= MAX(0, MIN (y0
, gport
->height
));
325 y1
= MAX(0, MIN (y1
, gport
->height
));
326 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
328 x0
= x
- (gport
->height
- y
);
329 x0
= MAX(0, MIN (x0
, gport
->width
));
331 x1
= MAX(0, MIN (x1
, gport
->width
));
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
,
341 draw_dozen_cross (GdkGC
*xor_gc
, gint x
, gint y
)
344 gdouble tan60
= sqrt (3);
346 x0
= x
+ (gport
->height
- y
) / tan60
;
347 x0
= MAX(0, MIN (x0
, gport
->width
));
349 x1
= MAX(0, MIN (x1
, gport
->width
));
350 y0
= y
+ (gport
->width
- x
) * tan60
;
351 y0
= MAX(0, MIN (y0
, gport
->height
));
353 y1
= MAX(0, MIN (y1
, gport
->height
));
354 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
357 x0
= x
+ (gport
->height
- y
) * tan60
;
358 x0
= MAX(0, MIN (x0
, gport
->width
));
360 x1
= MAX(0, MIN (x1
, gport
->width
));
361 y0
= y
+ (gport
->width
- x
) / tan60
;
362 y0
= MAX(0, MIN (y0
, gport
->height
));
364 y1
= MAX(0, MIN (y1
, gport
->height
));
365 gdk_draw_line (gport
->drawing_area
->window
, xor_gc
,
368 x0
= x
- (gport
->height
- y
) / tan60
;
369 x0
= MAX(0, MIN (x0
, gport
->width
));
371 x1
= MAX(0, MIN (x1
, gport
->width
));
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
,
379 x0
= x
- (gport
->height
- y
) * tan60
;
380 x0
= MAX(0, MIN (x0
, gport
->width
));
382 x1
= MAX(0, MIN (x1
, gport
->width
));
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
,
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
;
405 ghid_show_crosshair (gboolean show
)
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
)
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
);
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
);
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
);
462 x_prev
= y_prev
= -1;
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 ();
482 ghid_port_key_release_cb (GtkWidget
* drawing_area
, GdkEventKey
* kev
,
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
);
499 /* Handle user keys in the output drawing area.
500 * Note that the default is for all hotkeys to be handled by the
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.
511 ghid_port_key_press_cb (GtkWidget
* drawing_area
,
512 GdkEventKey
* kev
, GtkUIManager
* ui
)
514 ModifierKeysState mk
;
515 gint ksym
= kev
->keyval
;
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 */
541 ghid_hotkey_cb (GHID_KEY_UP
);
545 ghid_hotkey_cb (GHID_KEY_DOWN
);
548 ghid_hotkey_cb (GHID_KEY_LEFT
);
551 ghid_hotkey_cb (GHID_KEY_RIGHT
);
554 case GDK_ISO_Left_Tab
:
555 case GDK_3270_BackTab
:
559 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
561 case CONTROL_PRESSED
:
562 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
565 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
568 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
570 case SHIFT_CONTROL_PRESSED
:
571 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
573 case SHIFT_MOD1_PRESSED
:
574 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
587 ghid_hotkey_cb (GHID_KEY_TAB
);
589 case CONTROL_PRESSED
:
590 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_TAB
);
593 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_TAB
);
596 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
598 case SHIFT_CONTROL_PRESSED
:
599 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
601 case SHIFT_MOD1_PRESSED
:
602 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
619 ghid_port_button_press_cb (GtkWidget
* drawing_area
,
620 GdkEventButton
* ev
, GtkUIManager
* ui
)
622 ModifierKeysState mk
;
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
);
643 g_idle_add (ghid_idle_cb
, NULL
);
649 ghid_port_button_release_cb (GtkWidget
* drawing_area
,
650 GdkEventButton
* ev
, GtkUIManager
* ui
)
652 ModifierKeysState mk
;
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 ();
662 HideCrosshair (TRUE
);
664 do_mouse_action(ev
->button
, mk
+ M_Release
);
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
);
680 ghid_port_drawing_area_configure_event_cb (GtkWidget
* widget
,
681 GdkEventConfigure
* ev
,
684 static gboolean first_time_done
;
686 HideCrosshair (TRUE
);
687 gport
->width
= ev
->width
;
688 gport
->height
= ev
->height
;
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
);
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
);
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);
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
);
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
);
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
);
750 #if GTK_CHECK_VERSION(2,12,0)
751 # define ENABLE_TOOLTIPS 1
753 # define ENABLE_TOOLTIPS 0
758 describe_location (LocationType X
, LocationType Y
)
760 void *ptr1
, *ptr2
, *ptr3
;
765 char *netname
= NULL
;
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
);
775 /* don't mess with silk objects! */
776 if (type
& SILK_TYPE
&&
777 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
) >= max_layer
)
780 if (type
== PIN_TYPE
|| type
== PAD_TYPE
)
781 elename
= UNKNOWN (NAMEONPCB_NAME ((ElementTypePtr
) ptr1
));
783 pinname
= ConnectionName (type
, ptr1
, ptr2
);
788 /* Find netlist entry */
789 MENU_LOOP (&PCB
->NetlistLib
);
796 if (!entry
->ListEntry
)
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
);
813 description
= g_strdup_printf ("Element name: %s\n"
817 (pinname
!= NULL
) ? pinname
: "--",
818 (netname
!= NULL
) ? netname
: "--");
826 static gboolean
check_object_tooltips (GHidPort
*out
)
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
)
836 gtk_widget_set_tooltip_text (out
->drawing_area
, description
);
837 g_free (description
);
842 static int tooltip_update_timeout_id
= 0;
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.
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
,
873 ghid_port_window_motion_cb (GtkWidget
* widget
,
874 GdkEventButton
* ev
, GHidPort
* out
)
877 static gint x_prev
= -1, y_prev
= -1;
882 if (gtk_events_pending ())
884 dx
= gport
->zoom
* (x_prev
- ev
->x
);
885 dy
= gport
->zoom
* (y_prev
- ev
->y
);
887 ghid_port_ranges_pan (dx
, dy
, TRUE
);
892 x_prev
= y_prev
= -1;
893 moved
= ghid_note_event_location (ev
);
896 queue_tooltip_update (out
);
899 ghid_show_crosshair (TRUE
);
900 if (moved
&& have_crosshair_attachments ())
901 ghid_draw_area_update (gport
, NULL
);
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
)
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
;
946 ghid_pan_idle_cb (gpointer data
)
948 gdouble dx
= 0, dy
= 0;
950 if (gport
->has_entered
)
952 dy
= gport
->zoom
* y_pan_speed
;
953 dx
= gport
->zoom
* x_pan_speed
;
954 return (ghid_port_ranges_pan (dx
, dy
, TRUE
));
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
)
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
;
991 ghid_get_coords (NULL
, &x
, &y
);
1003 x_pan_speed
= y_pan_speed
= 2 * ghidgui
->auto_pan_speed
;
1007 x_pan_speed
= -x_pan_speed
;
1012 y_pan_speed
= -y_pan_speed
;
1018 y_pan_speed
= y_pan_speed
- (3 * dy
* y_pan_speed
) / h
;
1025 x_pan_speed
= x_pan_speed
- (3 * dx
* x_pan_speed
) / w
;
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 ();
1048 /* Mouse scroll wheel events
1051 ghid_port_window_mouse_scroll_cb (GtkWidget
* widget
,
1052 GdkEventScroll
* ev
, GHidPort
* out
)
1054 ModifierKeysState mk
;
1055 GdkModifierType state
;
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
);