6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 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
25 /* This file was originally written by Bill Wilson for the PCB Gtk port */
32 #include "crosshair.h"
39 #include <gdk/gdkkeysyms.h>
41 #ifdef HAVE_LIBDMALLOC
47 #define DEFAULT_CURSORSHAPE GDK_CROSSHAIR
49 #define CUSTOM_CURSOR_CLOCKWISE (GDK_LAST_CURSOR + 10)
50 #define CUSTOM_CURSOR_DRAG (GDK_LAST_CURSOR + 11)
51 #define CUSTOM_CURSOR_LOCK (GDK_LAST_CURSOR + 12)
57 GdkPixmap
*XC_clock_source
, *XC_clock_mask
,
58 *XC_hand_source
, *XC_hand_mask
, *XC_lock_source
, *XC_lock_mask
;
61 static GdkCursorType oldCursor
;
64 ghid_status_line_set_text (const gchar
* text
)
66 if (ghidgui
->command_entry_status_line_active
)
69 ghid_label_set_markup (ghidgui
->status_line_label
, text
);
73 ghid_cursor_position_label_set_text (gchar
* text
)
75 ghid_label_set_markup (ghidgui
->cursor_position_absolute_label
, text
);
79 ghid_cursor_position_relative_label_set_text (gchar
* text
)
81 ghid_label_set_markup (ghidgui
->cursor_position_relative_label
, text
);
85 ghid_size_increment_get_value (const gchar
* saction
, gchar
** value
,
90 static gchar s_buf
[64];
92 increment
= Settings
.grid_units_mm
93 ? Settings
.size_increment_mm
: Settings
.size_increment_mil
;
94 fmt
= (*saction
== '+') ? "+%f" : "-%f";
95 snprintf (s_buf
, sizeof (s_buf
), fmt
, increment
);
97 *units
= Settings
.grid_units_mm
? "mm" : "mil";
101 ghid_line_increment_get_value (const gchar
* saction
, gchar
** value
,
106 static gchar s_buf
[64];
108 increment
= Settings
.grid_units_mm
109 ? Settings
.line_increment_mm
: Settings
.line_increment_mil
;
110 fmt
= (*saction
== '+') ? "+%f" : "-%f";
111 snprintf (s_buf
, sizeof (s_buf
), fmt
, increment
);
113 *units
= Settings
.grid_units_mm
? "mm" : "mil";
117 ghid_clear_increment_get_value (const gchar
* saction
, gchar
** value
,
122 static gchar s_buf
[64];
124 increment
= Settings
.grid_units_mm
125 ? Settings
.clear_increment_mm
: Settings
.clear_increment_mil
;
126 fmt
= (*saction
== '+') ? "+%f" : "-%f";
127 snprintf (s_buf
, sizeof (s_buf
), fmt
, increment
);
129 *units
= Settings
.grid_units_mm
? "mm" : "mil";
134 gport_set_cursor (GdkCursorType shape
)
136 GdkCursorType old_shape
= gport
->X_cursor_shape
;
137 GdkColor fg
= { 0, 65535, 65535, 65535 }; /* white */
138 GdkColor bg
= { 0, 0, 0, 0 }; /* black */
140 if (!gport
->drawing_area
|| !gport
->drawing_area
->window
)
142 if (gport
->X_cursor_shape
== shape
)
145 /* check if window exists to prevent from fatal errors */
146 if (gport
->drawing_area
->window
)
148 gport
->X_cursor_shape
= shape
;
149 if (shape
> GDK_LAST_CURSOR
)
151 if (shape
== CUSTOM_CURSOR_CLOCKWISE
)
153 gdk_cursor_new_from_pixmap (XC_clock_source
, XC_clock_mask
, &fg
,
154 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
155 else if (shape
== CUSTOM_CURSOR_DRAG
)
157 gdk_cursor_new_from_pixmap (XC_hand_source
, XC_hand_mask
, &fg
,
158 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
159 else if (shape
== CUSTOM_CURSOR_LOCK
)
161 gdk_cursor_new_from_pixmap (XC_lock_source
, XC_lock_mask
, &fg
,
162 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
165 gport
->X_cursor
= gdk_cursor_new (shape
);
167 gdk_window_set_cursor (gport
->drawing_area
->window
, gport
->X_cursor
);
168 gdk_cursor_unref (gport
->X_cursor
);
172 return (DEFAULT_CURSORSHAPE
);
176 ghid_point_cursor (void)
178 oldCursor
= gport_set_cursor (GDK_DRAPED_BOX
);
182 ghid_hand_cursor (void)
184 oldCursor
= gport_set_cursor (GDK_HAND2
);
188 ghid_watch_cursor (void)
192 tmp
= gport_set_cursor (GDK_WATCH
);
193 if (tmp
!= GDK_WATCH
)
198 ghid_mode_cursor (int Mode
)
203 gport_set_cursor (CUSTOM_CURSOR_DRAG
);
207 gport_set_cursor (GDK_ARROW
);
211 gport_set_cursor (GDK_PENCIL
);
215 gport_set_cursor (GDK_QUESTION_ARROW
);
219 gport_set_cursor (GDK_LEFT_PTR
);
223 case POLYGONHOLE_MODE
:
224 gport_set_cursor (GDK_SB_UP_ARROW
);
227 case PASTEBUFFER_MODE
:
228 gport_set_cursor (GDK_HAND1
);
232 gport_set_cursor (GDK_XTERM
);
236 gport_set_cursor (GDK_UL_ANGLE
);
240 gport_set_cursor (GDK_IRON_CROSS
);
244 gport_set_cursor (GDK_PIRATE
);
248 if (ghid_shift_is_pressed ())
249 gport_set_cursor (CUSTOM_CURSOR_CLOCKWISE
);
251 gport_set_cursor (GDK_EXCHANGE
);
256 gport_set_cursor (GDK_CROSSHAIR
);
259 case INSERTPOINT_MODE
:
260 gport_set_cursor (GDK_DOTBOX
);
264 gport_set_cursor (CUSTOM_CURSOR_LOCK
);
269 ghid_corner_cursor (void)
273 if (Crosshair
.Y
<= Crosshair
.AttachedBox
.Point1
.Y
)
274 shape
= (Crosshair
.X
>= Crosshair
.AttachedBox
.Point1
.X
) ?
275 GDK_UR_ANGLE
: GDK_UL_ANGLE
;
277 shape
= (Crosshair
.X
>= Crosshair
.AttachedBox
.Point1
.X
) ?
278 GDK_LR_ANGLE
: GDK_LL_ANGLE
;
279 if (gport
->X_cursor_shape
!= shape
)
280 gport_set_cursor (shape
);
284 ghid_restore_cursor (void)
286 gport_set_cursor (oldCursor
);
291 /* =============================================================== */
292 static gboolean got_location
;
294 /* If user hits a key instead of the mouse button, we'll abort unless
295 | it's one of the cursor keys. Move the layout if a cursor key.
298 loop_key_press_cb (GtkWidget
* drawing_area
, GdkEventKey
* kev
,
301 ModifierKeysState mk
;
302 GdkModifierType state
;
303 gint ksym
= kev
->keyval
;
305 if (ghid_is_modifier_key_sym (ksym
))
307 state
= (GdkModifierType
) (kev
->state
);
308 mk
= ghid_modifier_keys_state (&state
);
310 /* Duplicate the cursor key actions in gui-output-events.c
315 if (mk
== CONTROL_PRESSED
)
317 hid_actionl ("Display", "Scroll", "8", NULL
);
318 hid_actionl ("Display", "Scroll", "0", NULL
);
320 else if (mk
== SHIFT_PRESSED
)
321 hid_actionl ("MovePointer", "0", "-10", NULL
);
322 else if (mk
== NONE_PRESSED
)
323 hid_actionl ("MovePointer", "0", "-1", NULL
);
327 if (mk
== CONTROL_PRESSED
)
329 hid_actionl ("Display", "Scroll", "2", NULL
);
330 hid_actionl ("Display", "Scroll", "0", NULL
);
332 else if (mk
== SHIFT_PRESSED
)
333 hid_actionl ("MovePointer", "0", "10", NULL
);
334 else if (mk
== NONE_PRESSED
)
335 hid_actionl ("MovePointer", "0", "1", NULL
);
339 if (mk
== CONTROL_PRESSED
)
341 hid_actionl ("Display", "Scroll", "4", NULL
);
342 hid_actionl ("Display", "Scroll", "0", NULL
);
344 else if (mk
== SHIFT_PRESSED
)
345 hid_actionl ("MovePointer", "-10", "0", NULL
);
346 else if (mk
== NONE_PRESSED
)
347 hid_actionl ("MovePointer", "-1", "0", NULL
);
351 if (mk
== CONTROL_PRESSED
)
353 hid_actionl ("Display", "Scroll", "6", NULL
);
354 hid_actionl ("Display", "Scroll", "0", NULL
);
356 else if (mk
== SHIFT_PRESSED
)
357 hid_actionl ("MovePointer", "10", "0", NULL
);
358 else if (mk
== NONE_PRESSED
)
359 hid_actionl ("MovePointer", "1", "0", NULL
);
362 case GDK_Return
: /* Accept cursor location */
363 if (g_main_loop_is_running (*loop
))
364 g_main_loop_quit (*loop
);
368 got_location
= FALSE
;
369 if (g_main_loop_is_running (*loop
))
370 g_main_loop_quit (*loop
);
376 /* User hit a mouse button in the Output drawing area, so quit the loop
377 | and the cursor values when the button was pressed will be used.
380 loop_button_press_cb (GtkWidget
* drawing_area
, GdkEventButton
* ev
,
383 if (g_main_loop_is_running (*loop
))
384 g_main_loop_quit (*loop
);
385 ghid_note_event_location (ev
);
389 /* Run a glib GMainLoop which intercepts key and mouse button events from
390 | the top level loop. When a mouse or key is hit in the Output drawing
391 | area, quit the loop so the top level loop can continue and use the
392 | the mouse pointer coordinates at the time of the mouse button event.
395 run_get_location_loop (const gchar
* message
)
398 gulong button_handler
, key_handler
;
399 gint oldObjState
, oldLineState
, oldBoxState
;
401 ghid_status_line_set_text (message
);
403 oldObjState
= Crosshair
.AttachedObject
.State
;
404 oldLineState
= Crosshair
.AttachedLine
.State
;
405 oldBoxState
= Crosshair
.AttachedBox
.State
;
406 HideCrosshair (true);
407 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
408 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
409 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
411 RestoreCrosshair (true);
413 /* Stop the top level GMainLoop from getting user input from keyboard
414 | and mouse so we can install our own handlers here. Also set the
415 | control interface insensitive so all the user can do is hit a key
416 | or mouse button in the Output drawing area.
418 ghid_interface_input_signals_disconnect ();
419 ghid_interface_set_sensitive (FALSE
);
421 got_location
= TRUE
; /* Will be unset by hitting most keys */
423 g_signal_connect (G_OBJECT (gport
->drawing_area
),
424 "button_press_event",
425 G_CALLBACK (loop_button_press_cb
), &loop
);
427 g_signal_connect (G_OBJECT (gport
->top_window
),
429 G_CALLBACK (loop_key_press_cb
), &loop
);
431 loop
= g_main_loop_new (NULL
, FALSE
);
432 g_main_loop_run (loop
);
434 g_main_loop_unref (loop
);
436 g_signal_handler_disconnect (gport
->drawing_area
, button_handler
);
437 g_signal_handler_disconnect (gport
->top_window
, key_handler
);
439 ghid_interface_input_signals_connect (); /* return to normal */
440 ghid_interface_set_sensitive (TRUE
);
442 HideCrosshair (true);
443 Crosshair
.AttachedObject
.State
= oldObjState
;
444 Crosshair
.AttachedLine
.State
= oldLineState
;
445 Crosshair
.AttachedBox
.State
= oldBoxState
;
446 RestoreCrosshair (true);
447 ghid_restore_cursor ();
449 ghid_set_status_line_label ();
456 /* ---------------------------------------------------------------------------*/
458 ghid_get_user_xy (const char *msg
)
460 run_get_location_loop (msg
);
463 /* XXX The abort dialog isn't implemented yet in the Gtk port
466 ghid_create_abort_dialog (char *msg
)
471 ghid_check_abort (void)
473 return FALSE
; /* Abort isn't implemented, so never abort */
477 ghid_end_abort (void)
482 ghid_get_pointer (int *x
, int *y
)
486 gdk_window_get_pointer (gport
->drawing_area
->window
, &xp
, &yp
, NULL
);
493 /* ---------------------------------------------------------------------------
494 * output of status line
497 ghid_set_status_line_label (void)
501 if (!Settings
.grid_units_mm
)
502 snprintf (text
, sizeof (text
),
503 _("<b>%c view</b>=%s "
504 "<b>grid</b>=%.1f:%i "
507 "<b>via</b>=%.1f(%.1f) %s"
508 "<b>clearance</b>=%.1f "
510 "<b>buffer</b>=#%i"),
511 PCB
->Changed
? '*' : ' ',
512 Settings
.ShowSolderSide
? _("solder") : _("component"),
514 (int) Settings
.GridFactor
,
515 TEST_FLAG (ALLDIRECTIONFLAG
, PCB
) ? "all" :
516 (PCB
->Clipping
== 0 ? "45" :
517 (PCB
->Clipping
== 1 ? "45_/" : "45\\_")),
518 TEST_FLAG (RUBBERBANDFLAG
, PCB
) ? ",R " : " ",
519 Settings
.LineThickness
/ 100.0,
520 Settings
.ViaThickness
/ 100.0,
521 Settings
.ViaDrillingHole
/ 100.0,
522 ghidgui
->compact_horizontal
? "\n" : "",
523 Settings
.Keepaway
/ 100.0,
524 Settings
.TextScale
, Settings
.BufferNumber
+ 1);
526 snprintf (text
, sizeof (text
),
527 _("<b>%c view</b>=%s "
528 "<b>grid</b>=%5.3f:%i "
531 "<b>via</b>=%5.3f(%5.3f) %s"
532 "<b>clearance</b>=%5.3f "
534 "<b>buffer</b>=#%i"),
535 PCB
->Changed
? '*' : ' ',
536 Settings
.ShowSolderSide
? _("solder") : _("component"),
537 PCB
->Grid
* COOR_TO_MM
, (int) Settings
.GridFactor
,
538 TEST_FLAG (ALLDIRECTIONFLAG
, PCB
) ? "all" :
539 (PCB
->Clipping
== 0 ? "45" :
540 (PCB
->Clipping
== 1 ? "45_/" : "45\\_")),
541 TEST_FLAG (RUBBERBANDFLAG
, PCB
) ? ",R " : " ",
542 Settings
.LineThickness
* COOR_TO_MM
,
543 Settings
.ViaThickness
* COOR_TO_MM
,
544 Settings
.ViaDrillingHole
* COOR_TO_MM
,
545 ghidgui
->compact_horizontal
? "\n" : "",
546 Settings
.Keepaway
* COOR_TO_MM
,
547 Settings
.TextScale
, Settings
.BufferNumber
+ 1);
549 ghid_status_line_set_text (text
);
552 /* ---------------------------------------------------------------------------
553 * output of cursor position
556 ghid_set_cursor_position_labels (void)
561 {double scale
, dx
, dy
, r
, a
;
562 scale
= Settings
.grid_units_mm
? COOR_TO_MM
: 1. / 100;
563 dx
= (Crosshair
.X
- Marked
.X
) * scale
;
564 dy
= (Marked
.Y
- Crosshair
.Y
) * scale
;
565 r
= sqrt( dx
* dx
+ dy
* dy
);
566 a
= atan2(dy
, dx
) * 180 / M_PI
;
567 if (Settings
.grid_units_mm
)
568 snprintf (text
, sizeof (text
), "r %-.4f; phi %-.1f; %-.4f %-.4f",
572 snprintf (text
, sizeof (text
), "r %-.2f; phi %-.1f; %-.2f %-.2f",
574 ghid_cursor_position_relative_label_set_text (text
);
577 ghid_cursor_position_relative_label_set_text ("r __.__; phi __._; __.__ __.__");
579 if (Settings
.grid_units_mm
)
580 snprintf (text
, sizeof (text
), "%-.4f %-.4f",
581 COOR_TO_MM
* Crosshair
.X
, COOR_TO_MM
* Crosshair
.Y
);
583 snprintf (text
, sizeof (text
), "%-.2f %-.2f",
584 Crosshair
.X
/ 100., Crosshair
.Y
/ 100.);
586 ghid_cursor_position_label_set_text (text
);