4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 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
23 /* This file was originally written by Bill Wilson for the PCB Gtk port */
30 #include "crosshair.h"
35 #include "pcb-printf.h"
38 #include <gdk/gdkkeysyms.h>
40 #ifdef HAVE_LIBDMALLOC
44 #define CUSTOM_CURSOR_CLOCKWISE (GDK_LAST_CURSOR + 10)
45 #define CUSTOM_CURSOR_DRAG (GDK_LAST_CURSOR + 11)
46 #define CUSTOM_CURSOR_LOCK (GDK_LAST_CURSOR + 12)
52 GdkPixmap
*XC_clock_source
, *XC_clock_mask
,
53 *XC_hand_source
, *XC_hand_mask
, *XC_lock_source
, *XC_lock_mask
;
56 static GdkCursorType oldCursor
;
59 ghid_status_line_set_text (const gchar
* text
)
61 if (ghidgui
->command_entry_status_line_active
)
64 ghid_label_set_markup (ghidgui
->status_line_label
, text
);
68 ghid_cursor_position_label_set_text (gchar
* text
)
70 ghid_label_set_markup (ghidgui
->cursor_position_absolute_label
, text
);
74 ghid_cursor_position_relative_label_set_text (gchar
* text
)
76 ghid_label_set_markup (ghidgui
->cursor_position_relative_label
, text
);
80 gport_set_cursor (GdkCursorType shape
)
83 GdkCursorType old_shape
= gport
->X_cursor_shape
;
84 GdkColor fg
= { 0, 65535, 65535, 65535 }; /* white */
85 GdkColor bg
= { 0, 0, 0, 0 }; /* black */
87 if (gport
->drawing_area
== NULL
)
90 window
= gtk_widget_get_window (gport
->drawing_area
);
92 if (gport
->X_cursor_shape
== shape
)
95 /* check if window exists to prevent from fatal errors */
99 gport
->X_cursor_shape
= shape
;
100 if (shape
> GDK_LAST_CURSOR
)
102 if (shape
== CUSTOM_CURSOR_CLOCKWISE
)
104 gdk_cursor_new_from_pixmap (XC_clock_source
, XC_clock_mask
, &fg
,
105 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
106 else if (shape
== CUSTOM_CURSOR_DRAG
)
108 gdk_cursor_new_from_pixmap (XC_hand_source
, XC_hand_mask
, &fg
,
109 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
110 else if (shape
== CUSTOM_CURSOR_LOCK
)
112 gdk_cursor_new_from_pixmap (XC_lock_source
, XC_lock_mask
, &fg
,
113 &bg
, ICON_X_HOT
, ICON_Y_HOT
);
116 gport
->X_cursor
= gdk_cursor_new (shape
);
118 gdk_window_set_cursor (window
, gport
->X_cursor
);
119 gdk_cursor_unref (gport
->X_cursor
);
125 ghid_point_cursor (void)
127 oldCursor
= gport_set_cursor (GDK_DRAPED_BOX
);
131 ghid_hand_cursor (void)
133 oldCursor
= gport_set_cursor (GDK_HAND2
);
137 ghid_watch_cursor (void)
141 tmp
= gport_set_cursor (GDK_WATCH
);
142 if (tmp
!= GDK_WATCH
)
147 ghid_mode_cursor (int Mode
)
152 gport_set_cursor ((GdkCursorType
)CUSTOM_CURSOR_DRAG
);
156 gport_set_cursor (GDK_ARROW
);
160 gport_set_cursor (GDK_PENCIL
);
164 gport_set_cursor (GDK_QUESTION_ARROW
);
168 gport_set_cursor (GDK_LEFT_PTR
);
172 case POLYGONHOLE_MODE
:
173 gport_set_cursor (GDK_SB_UP_ARROW
);
176 case PASTEBUFFER_MODE
:
177 gport_set_cursor (GDK_HAND1
);
181 gport_set_cursor (GDK_XTERM
);
185 gport_set_cursor (GDK_UL_ANGLE
);
189 gport_set_cursor (GDK_IRON_CROSS
);
193 gport_set_cursor (GDK_PIRATE
);
197 if (ghid_shift_is_pressed ())
198 gport_set_cursor ((GdkCursorType
)CUSTOM_CURSOR_CLOCKWISE
);
200 gport_set_cursor (GDK_EXCHANGE
);
205 gport_set_cursor (GDK_CROSSHAIR
);
208 case INSERTPOINT_MODE
:
209 gport_set_cursor (GDK_DOTBOX
);
213 gport_set_cursor ((GdkCursorType
)CUSTOM_CURSOR_LOCK
);
218 ghid_corner_cursor (void)
222 if (Crosshair
.Y
<= Crosshair
.AttachedBox
.Point1
.Y
)
223 shape
= (Crosshair
.X
>= Crosshair
.AttachedBox
.Point1
.X
) ?
224 GDK_UR_ANGLE
: GDK_UL_ANGLE
;
226 shape
= (Crosshair
.X
>= Crosshair
.AttachedBox
.Point1
.X
) ?
227 GDK_LR_ANGLE
: GDK_LL_ANGLE
;
228 if (gport
->X_cursor_shape
!= shape
)
229 gport_set_cursor (shape
);
233 ghid_restore_cursor (void)
235 gport_set_cursor (oldCursor
);
240 /* =============================================================== */
241 static gboolean got_location
;
243 /* If user hits a key instead of the mouse button, we'll abort unless
244 | it's the enter key (which accepts the current crosshair location).
247 loop_key_press_cb (GtkWidget
* drawing_area
, GdkEventKey
* kev
,
250 gint ksym
= kev
->keyval
;
252 if (ghid_is_modifier_key_sym (ksym
))
257 case GDK_Return
: /* Accept cursor location */
258 if (g_main_loop_is_running (*loop
))
259 g_main_loop_quit (*loop
);
263 got_location
= FALSE
;
264 if (g_main_loop_is_running (*loop
))
265 g_main_loop_quit (*loop
);
271 /* User hit a mouse button in the Output drawing area, so quit the loop
272 | and the cursor values when the button was pressed will be used.
275 loop_button_press_cb (GtkWidget
* drawing_area
, GdkEventButton
* ev
,
278 if (g_main_loop_is_running (*loop
))
279 g_main_loop_quit (*loop
);
280 ghid_note_event_location (ev
);
284 /* Run a glib GMainLoop which intercepts key and mouse button events from
285 | the top level loop. When a mouse or key is hit in the Output drawing
286 | area, quit the loop so the top level loop can continue and use the
287 | the mouse pointer coordinates at the time of the mouse button event.
290 run_get_location_loop (const gchar
* message
)
293 gulong button_handler
, key_handler
;
294 gint oldObjState
, oldLineState
, oldBoxState
;
296 ghid_status_line_set_text (message
);
298 oldObjState
= Crosshair
.AttachedObject
.State
;
299 oldLineState
= Crosshair
.AttachedLine
.State
;
300 oldBoxState
= Crosshair
.AttachedBox
.State
;
301 notify_crosshair_change (false);
302 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
303 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
304 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
306 notify_crosshair_change (true);
308 /* Stop the top level GMainLoop from getting user input from keyboard
309 | and mouse so we can install our own handlers here. Also set the
310 | control interface insensitive so all the user can do is hit a key
311 | or mouse button in the Output drawing area.
313 ghid_interface_input_signals_disconnect ();
314 ghid_interface_set_sensitive (FALSE
);
316 got_location
= TRUE
; /* Will be unset by hitting most keys */
318 g_signal_connect (G_OBJECT (gport
->drawing_area
),
319 "button_press_event",
320 G_CALLBACK (loop_button_press_cb
), &loop
);
322 g_signal_connect (G_OBJECT (gport
->top_window
),
324 G_CALLBACK (loop_key_press_cb
), &loop
);
326 loop
= g_main_loop_new (NULL
, FALSE
);
328 GDK_THREADS_LEAVE ();
329 g_main_loop_run (loop
);
330 GDK_THREADS_ENTER ();
332 g_main_loop_unref (loop
);
334 g_signal_handler_disconnect (gport
->drawing_area
, button_handler
);
335 g_signal_handler_disconnect (gport
->top_window
, key_handler
);
337 ghid_interface_input_signals_connect (); /* return to normal */
338 ghid_interface_set_sensitive (TRUE
);
340 notify_crosshair_change (false);
341 Crosshair
.AttachedObject
.State
= oldObjState
;
342 Crosshair
.AttachedLine
.State
= oldLineState
;
343 Crosshair
.AttachedBox
.State
= oldBoxState
;
344 notify_crosshair_change (true);
345 ghid_restore_cursor ();
347 ghid_set_status_line_label ();
354 /* ---------------------------------------------------------------------------*/
356 ghid_get_user_xy (const char *msg
)
358 run_get_location_loop (msg
);
361 /* XXX The abort dialog isn't implemented yet in the Gtk port
364 ghid_create_abort_dialog (char *msg
)
369 ghid_check_abort (void)
371 return FALSE
; /* Abort isn't implemented, so never abort */
375 ghid_end_abort (void)
380 ghid_get_pointer (int *x
, int *y
)
384 gdk_window_get_pointer (gtk_widget_get_window (gport
->drawing_area
),
392 /* ---------------------------------------------------------------------------
393 * output of status line
396 ghid_set_status_line_label (void)
398 gchar
*flag
= TEST_FLAG (ALLDIRECTIONFLAG
, PCB
)
400 : (PCB
->Clipping
== 0
402 : (PCB
->Clipping
== 1
405 gchar
*text
= pcb_g_strdup_printf (
406 _("%m+<b>view</b>=%s "
410 "<b>via</b>=%mS (%mS) %s"
411 "<b>clearance</b>=%mS "
413 "<b>buffer</b>=#%i"),
414 Settings
.grid_unit
->allow
,
415 Settings
.ShowSolderSide
? _("bottom") : _("top"),
417 flag
, TEST_FLAG (RUBBERBANDFLAG
, PCB
) ? ",R " : " ",
418 Settings
.LineThickness
,
419 Settings
.ViaThickness
,
420 Settings
.ViaDrillingHole
,
421 ghidgui
->compact_horizontal
? "\n" : "",
423 Settings
.TextScale
, Settings
.BufferNumber
+ 1);
425 ghid_status_line_set_text (text
);
429 /* ---------------------------------------------------------------------------
430 * output of cursor position
433 ghid_set_cursor_position_labels (void)
439 Coord dx
= Crosshair
.X
- Marked
.X
;
440 Coord dy
= Crosshair
.Y
- Marked
.Y
;
441 Coord r
= Distance (Crosshair
.X
, Crosshair
.Y
, Marked
.X
, Marked
.Y
);
442 double a
= atan2 (dy
, dx
) * RAD_TO_DEG
;
444 text
= pcb_g_strdup_printf ("%m+r %-mS; phi %-.1f; %-mS %-mS",
445 Settings
.grid_unit
->allow
,
447 ghid_cursor_position_relative_label_set_text (text
);
451 ghid_cursor_position_relative_label_set_text ("r __.__; phi __._; __.__ __.__");
454 text
= pcb_g_strdup_printf ("%m+%-mS %-mS",
455 Settings
.grid_unit
->allow
,
456 Crosshair
.X
, Crosshair
.Y
);
457 ghid_cursor_position_label_set_text (text
);