4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* This file written by Bill Wilson for the PCB Gtk port */
35 #include "hid/common/hid_resource.h"
37 #include <gdk/gdkkeysyms.h>
40 #include "crosshair.h"
49 #ifdef HAVE_LIBDMALLOC
53 #define TOOLTIP_UPDATE_DELAY 200
56 ghid_port_ranges_changed (void)
58 GtkAdjustment
*h_adj
, *v_adj
;
60 h_adj
= gtk_range_get_adjustment (GTK_RANGE (ghidgui
->h_range
));
61 v_adj
= gtk_range_get_adjustment (GTK_RANGE (ghidgui
->v_range
));
62 gport
->view
.x0
= gtk_adjustment_get_value (h_adj
);
63 gport
->view
.y0
= gtk_adjustment_get_value (v_adj
);
65 ghid_invalidate_all ();
68 /* Do scrollbar scaling based on current port drawing area size and
69 | overall PCB board size.
72 ghid_port_ranges_scale (void)
77 /* Update the scrollbars with PCB units. So Scale the current
78 | drawing area size in pixels to PCB units and that will be
79 | the page size for the Gtk adjustment.
81 gport
->view
.width
= gport
->width
* gport
->view
.coord_per_px
;
82 gport
->view
.height
= gport
->height
* gport
->view
.coord_per_px
;
84 adj
= gtk_range_get_adjustment (GTK_RANGE (ghidgui
->h_range
));
85 page_size
= MIN (gport
->view
.width
, PCB
->MaxWidth
);
86 gtk_adjustment_configure (adj
,
87 gtk_adjustment_get_value (adj
), /* value */
88 -gport
->view
.width
, /* lower */
89 PCB
->MaxWidth
+ page_size
, /* upper */
90 page_size
/ 100.0, /* step_increment */
91 page_size
/ 10.0, /* page_increment */
92 page_size
); /* page_size */
94 adj
= gtk_range_get_adjustment (GTK_RANGE (ghidgui
->v_range
));
95 page_size
= MIN (gport
->view
.height
, PCB
->MaxHeight
);
96 gtk_adjustment_configure (adj
,
97 gtk_adjustment_get_value (adj
), /* value */
98 -gport
->view
.height
, /* lower */
99 PCB
->MaxHeight
+ page_size
, /* upper */
100 page_size
/ 100.0, /* step_increment */
101 page_size
/ 10.0, /* page_increment */
102 page_size
); /* page_size */
106 /* ----------------------------------------------------------------------
107 * handles all events from PCB drawing area
111 ghid_get_coords (const char *msg
, Coord
*x
, Coord
*y
)
113 if (!ghid_port
.has_entered
&& msg
)
114 ghid_get_user_xy (msg
);
115 if (ghid_port
.has_entered
)
123 ghid_note_event_location (GdkEventButton
* ev
)
125 gint event_x
, event_y
;
130 gdk_window_get_pointer (gtk_widget_get_window (ghid_port
.drawing_area
),
131 &event_x
, &event_y
, NULL
);
139 ghid_event_to_pcb_coords (event_x
, event_y
, &gport
->pcb_x
, &gport
->pcb_y
);
141 moved
= MoveCrosshairAbsolute (gport
->pcb_x
, gport
->pcb_y
);
144 AdjustAttachedObjects ();
145 notify_crosshair_change (true);
147 ghid_set_cursor_position_labels ();
152 ghid_idle_cb (gpointer data
)
154 if (Settings
.Mode
== NO_MODE
)
155 SetMode (ARROW_MODE
);
156 ghid_mode_cursor (Settings
.Mode
);
157 if (ghidgui
->settings_mode
!= Settings
.Mode
)
159 ghid_mode_buttons_update ();
161 ghidgui
->settings_mode
= Settings
.Mode
;
163 ghid_update_toggle_flags ();
168 ghid_port_key_release_cb (GtkWidget
* drawing_area
, GdkEventKey
* kev
,
171 gint ksym
= kev
->keyval
;
173 if (ghid_is_modifier_key_sym (ksym
))
174 ghid_note_event_location (NULL
);
176 AdjustAttachedObjects ();
177 ghid_invalidate_all ();
178 g_idle_add (ghid_idle_cb
, NULL
);
182 /* Handle user keys in the output drawing area.
183 * Note that the default is for all hotkeys to be handled by the
186 * Key presses not handled by the menus will show up here. This means
187 * the key press was either not defined in the menu resource file or
188 * that the key press is special in that gtk doesn't allow the normal
189 * menu code to ever see it. We capture those here (like Tab and the
190 * arrow keys) and feed it back to the normal menu callback.
194 ghid_port_key_press_cb (GtkWidget
* drawing_area
,
195 GdkEventKey
* kev
, gpointer data
)
197 ModifierKeysState mk
;
198 gint ksym
= kev
->keyval
;
200 extern void ghid_hotkey_cb (int);
201 GdkModifierType state
;
203 if (ghid_is_modifier_key_sym (ksym
))
204 ghid_note_event_location (NULL
);
206 state
= (GdkModifierType
) (kev
->state
);
207 mk
= ghid_modifier_keys_state (&state
);
209 handled
= TRUE
; /* Start off assuming we handle it */
219 case GDK_ISO_Level3_Shift
:
223 ghid_hotkey_cb (GHID_KEY_UP
);
227 ghid_hotkey_cb (GHID_KEY_DOWN
);
230 ghid_hotkey_cb (GHID_KEY_LEFT
);
233 ghid_hotkey_cb (GHID_KEY_RIGHT
);
236 case GDK_ISO_Left_Tab
:
237 case GDK_3270_BackTab
:
241 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
243 case CONTROL_PRESSED
:
244 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
247 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
250 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
252 case SHIFT_CONTROL_PRESSED
:
253 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
255 case SHIFT_MOD1_PRESSED
:
256 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
269 ghid_hotkey_cb (GHID_KEY_TAB
);
271 case CONTROL_PRESSED
:
272 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_TAB
);
275 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_TAB
);
278 ghid_hotkey_cb (GHID_KEY_SHIFT
| GHID_KEY_TAB
);
280 case SHIFT_CONTROL_PRESSED
:
281 ghid_hotkey_cb (GHID_KEY_CONTROL
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
283 case SHIFT_MOD1_PRESSED
:
284 ghid_hotkey_cb (GHID_KEY_ALT
| GHID_KEY_SHIFT
| GHID_KEY_TAB
);
301 ghid_port_button_press_cb (GtkWidget
* drawing_area
,
302 GdkEventButton
* ev
, gpointer data
)
304 ModifierKeysState mk
;
305 GdkModifierType state
;
307 /* Reject double and triple click events */
308 if (ev
->type
!= GDK_BUTTON_PRESS
) return TRUE
;
310 ghid_note_event_location (ev
);
311 state
= (GdkModifierType
) (ev
->state
);
312 mk
= ghid_modifier_keys_state (&state
);
314 do_mouse_action(ev
->button
, mk
);
316 ghid_invalidate_all ();
317 ghid_window_set_name_label (PCB
->Name
);
318 ghid_set_status_line_label ();
320 g_idle_add (ghid_idle_cb
, NULL
);
326 ghid_port_button_release_cb (GtkWidget
* drawing_area
,
327 GdkEventButton
* ev
, gpointer data
)
329 ModifierKeysState mk
;
330 GdkModifierType state
;
332 ghid_note_event_location (ev
);
333 state
= (GdkModifierType
) (ev
->state
);
334 mk
= ghid_modifier_keys_state (&state
);
336 do_mouse_action(ev
->button
, mk
+ M_Release
);
338 AdjustAttachedObjects ();
339 ghid_invalidate_all ();
341 ghid_window_set_name_label (PCB
->Name
);
342 ghid_set_status_line_label ();
343 g_idle_add (ghid_idle_cb
, NULL
);
349 ghid_port_drawing_area_configure_event_cb (GtkWidget
* widget
,
350 GdkEventConfigure
* ev
,
353 static gboolean first_time_done
;
355 gport
->width
= ev
->width
;
356 gport
->height
= ev
->height
;
359 gdk_pixmap_unref (gport
->pixmap
);
361 gport
->pixmap
= gdk_pixmap_new (gtk_widget_get_window (widget
),
362 gport
->width
, gport
->height
, -1);
363 gport
->drawable
= gport
->pixmap
;
365 if (!first_time_done
)
367 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
368 if (gdk_color_parse (Settings
.BackgroundColor
, &gport
->bg_color
))
369 gdk_color_alloc (gport
->colormap
, &gport
->bg_color
);
371 gdk_color_white (gport
->colormap
, &gport
->bg_color
);
373 if (gdk_color_parse (Settings
.OffLimitColor
, &gport
->offlimits_color
))
374 gdk_color_alloc (gport
->colormap
, &gport
->offlimits_color
);
376 gdk_color_white (gport
->colormap
, &gport
->offlimits_color
);
377 first_time_done
= TRUE
;
378 ghid_drawing_area_configure_hook (out
);
379 PCBChanged (0, NULL
, 0, 0);
383 ghid_drawing_area_configure_hook (out
);
386 ghid_port_ranges_scale ();
387 ghid_invalidate_all ();
393 describe_location (Coord X
, Coord Y
)
395 void *ptr1
, *ptr2
, *ptr3
;
400 char *netname
= NULL
;
403 /* check if there are any pins or pads at that position */
405 type
= SearchObjectByLocation (PIN_TYPE
| PAD_TYPE
,
406 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
410 /* don't mess with silk objects! */
411 if (type
& SILK_TYPE
&&
412 GetLayerNumber (PCB
->Data
, (LayerType
*) ptr1
) >= max_copper_layer
)
415 if (type
== PIN_TYPE
|| type
== PAD_TYPE
)
416 elename
= (char *)UNKNOWN (NAMEONPCB_NAME ((ElementType
*) ptr1
));
418 pinname
= ConnectionName (type
, ptr1
, ptr2
);
423 /* Find netlist entry */
424 MENU_LOOP (&PCB
->NetlistLib
);
431 if (!entry
->ListEntry
)
434 if (strcmp (entry
->ListEntry
, pinname
) == 0) {
435 netname
= g_strdup (menu
->Name
);
436 /* For some reason, the netname has spaces in front of it, strip them */
437 g_strstrip (netname
);
448 description
= g_strdup_printf ("Element name: %s\n"
452 (pinname
!= NULL
) ? pinname
: "--",
453 (netname
!= NULL
) ? netname
: "--");
461 static gboolean
check_object_tooltips (GHidPort
*out
)
465 /* check if there are any pins or pads at that position */
466 description
= describe_location (out
->crosshair_x
, out
->crosshair_y
);
468 if (description
== NULL
)
471 gtk_widget_set_tooltip_text (out
->drawing_area
, description
);
472 g_free (description
);
477 static int tooltip_update_timeout_id
= 0;
480 cancel_tooltip_update ()
482 if (tooltip_update_timeout_id
)
483 g_source_remove (tooltip_update_timeout_id
);
484 tooltip_update_timeout_id
= 0;
487 /* FIXME: If the GHidPort is ever destroyed, we must call
488 * cancel_tooltip_update (), otherwise the timeout might
489 * fire after the data it utilises has been free'd.
492 queue_tooltip_update (GHidPort
*out
)
494 /* Zap the old tool-tip text and force it to be removed from the screen */
495 gtk_widget_set_tooltip_text (out
->drawing_area
, NULL
);
496 gtk_widget_trigger_tooltip_query (out
->drawing_area
);
498 cancel_tooltip_update ();
500 tooltip_update_timeout_id
=
501 g_timeout_add (TOOLTIP_UPDATE_DELAY
,
502 (GSourceFunc
) check_object_tooltips
,
507 ghid_port_window_motion_cb (GtkWidget
* widget
,
508 GdkEventMotion
* ev
, GHidPort
* out
)
511 static gint x_prev
= -1, y_prev
= -1;
513 gdk_event_request_motions (ev
);
517 dx
= gport
->view
.coord_per_px
* (x_prev
- ev
->x
);
518 dy
= gport
->view
.coord_per_px
* (y_prev
- ev
->y
);
520 ghid_pan_view_rel (dx
, dy
);
525 x_prev
= y_prev
= -1;
526 ghid_note_event_location ((GdkEventButton
*)ev
);
528 queue_tooltip_update (out
);
534 ghid_port_window_enter_cb (GtkWidget
* widget
,
535 GdkEventCrossing
* ev
, GHidPort
* out
)
537 /* printf("enter: mode: %d detail: %d\n", ev->mode, ev->detail); */
539 /* See comment in ghid_port_window_leave_cb() */
541 if(ev
->mode
!= GDK_CROSSING_NORMAL
&& ev
->detail
!= GDK_NOTIFY_NONLINEAR
)
546 if (!ghidgui
->command_entry_status_line_active
)
548 out
->has_entered
= TRUE
;
549 /* Make sure drawing area has keyboard focus when we are in it.
551 gtk_widget_grab_focus (out
->drawing_area
);
553 ghidgui
->in_popup
= FALSE
;
555 /* Following expression is true if a you open a menu from the menu bar,
556 * move the mouse to the viewport and click on it. This closes the menu
557 * and moves the pointer to the viewport without the pointer going over
558 * the edge of the viewport */
559 if(ev
->mode
== GDK_CROSSING_UNGRAB
&& ev
->detail
== GDK_NOTIFY_NONLINEAR
)
561 ghid_screen_update ();
567 ghid_port_window_leave_cb (GtkWidget
* widget
,
568 GdkEventCrossing
* ev
, GHidPort
* out
)
570 /* printf("leave mode: %d detail: %d\n", ev->mode, ev->detail); */
572 /* Window leave events can also be triggered because of focus grabs. Some
573 * X applications occasionally grab the focus and so trigger this function.
574 * At least GNOME's window manager is known to do this on every mouse click.
576 * See http://bugzilla.gnome.org/show_bug.cgi?id=102209
579 if(ev
->mode
!= GDK_CROSSING_NORMAL
)
584 out
->has_entered
= FALSE
;
586 ghid_screen_update ();
592 /* Mouse scroll wheel events
595 ghid_port_window_mouse_scroll_cb (GtkWidget
* widget
,
596 GdkEventScroll
* ev
, GHidPort
* out
)
598 ModifierKeysState mk
;
599 GdkModifierType state
;
602 state
= (GdkModifierType
) (ev
->state
);
603 mk
= ghid_modifier_keys_state (&state
);
605 /* X11 gtk hard codes buttons 4, 5, 6, 7 as below in
606 * gtk+/gdk/x11/gdkevents-x11.c:1121, but quartz and windows have
607 * special mouse scroll events, so this may conflict with a mouse
608 * who has buttons 4 - 7 that aren't the scroll wheel?
610 switch(ev
->direction
)
612 case GDK_SCROLL_UP
: button
= 4; break;
613 case GDK_SCROLL_DOWN
: button
= 5; break;
614 case GDK_SCROLL_LEFT
: button
= 6; break;
615 case GDK_SCROLL_RIGHT
: button
= 7; break;
616 default: button
= -1;
619 do_mouse_action(button
, mk
);