pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* 00002 * COPYRIGHT 00003 * 00004 * PCB, interactive printed circuit board design 00005 * Copyright (C) 1994,1995,1996 Thomas Nau 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License along 00018 * with this program; if not, write to the Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00020 * 00021 */ 00022 00023 /* This file was originally written by Bill Wilson for the PCB Gtk port */ 00024 00025 #ifdef HAVE_CONFIG_H 00026 #include "config.h" 00027 #endif 00028 00029 #include "global.h" 00030 #include "crosshair.h" 00031 #include "data.h" 00032 #include "misc.h" 00033 #include "action.h" 00034 #include "set.h" 00035 #include "pcb-printf.h" 00036 00037 #include "gui.h" 00038 #include <gdk/gdkkeysyms.h> 00039 00040 #ifdef HAVE_LIBDMALLOC 00041 #include <dmalloc.h> 00042 #endif 00043 00044 #define CUSTOM_CURSOR_CLOCKWISE (GDK_LAST_CURSOR + 10) 00045 #define CUSTOM_CURSOR_DRAG (GDK_LAST_CURSOR + 11) 00046 #define CUSTOM_CURSOR_LOCK (GDK_LAST_CURSOR + 12) 00047 00048 #define ICON_X_HOT 8 00049 #define ICON_Y_HOT 8 00050 00051 00052 GdkPixmap *XC_clock_source, *XC_clock_mask, 00053 *XC_hand_source, *XC_hand_mask, *XC_lock_source, *XC_lock_mask; 00054 00055 00056 static GdkCursorType oldCursor; 00057 00058 void 00059 ghid_status_line_set_text (const gchar * text) 00060 { 00061 if (ghidgui->command_entry_status_line_active) 00062 return; 00063 00064 ghid_label_set_markup (ghidgui->status_line_label, text); 00065 } 00066 00067 void 00068 ghid_cursor_position_label_set_text (gchar * text) 00069 { 00070 ghid_label_set_markup (ghidgui->cursor_position_absolute_label, text); 00071 } 00072 00073 void 00074 ghid_cursor_position_relative_label_set_text (gchar * text) 00075 { 00076 ghid_label_set_markup (ghidgui->cursor_position_relative_label, text); 00077 } 00078 00079 static GdkCursorType 00080 gport_set_cursor (GdkCursorType shape) 00081 { 00082 GdkWindow *window; 00083 GdkCursorType old_shape = gport->X_cursor_shape; 00084 GdkColor fg = { 0, 65535, 65535, 65535 }; /* white */ 00085 GdkColor bg = { 0, 0, 0, 0 }; /* black */ 00086 00087 if (gport->drawing_area == NULL) 00088 return GDK_X_CURSOR; 00089 00090 window = gtk_widget_get_window (gport->drawing_area); 00091 00092 if (gport->X_cursor_shape == shape) 00093 return shape; 00094 00095 /* check if window exists to prevent from fatal errors */ 00096 if (window == NULL) 00097 return GDK_X_CURSOR; 00098 00099 gport->X_cursor_shape = shape; 00100 if (shape > GDK_LAST_CURSOR) 00101 { 00102 if (shape == CUSTOM_CURSOR_CLOCKWISE) 00103 gport->X_cursor = 00104 gdk_cursor_new_from_pixmap (XC_clock_source, XC_clock_mask, &fg, 00105 &bg, ICON_X_HOT, ICON_Y_HOT); 00106 else if (shape == CUSTOM_CURSOR_DRAG) 00107 gport->X_cursor = 00108 gdk_cursor_new_from_pixmap (XC_hand_source, XC_hand_mask, &fg, 00109 &bg, ICON_X_HOT, ICON_Y_HOT); 00110 else if (shape == CUSTOM_CURSOR_LOCK) 00111 gport->X_cursor = 00112 gdk_cursor_new_from_pixmap (XC_lock_source, XC_lock_mask, &fg, 00113 &bg, ICON_X_HOT, ICON_Y_HOT); 00114 } 00115 else 00116 gport->X_cursor = gdk_cursor_new (shape); 00117 00118 gdk_window_set_cursor (window, gport->X_cursor); 00119 gdk_cursor_unref (gport->X_cursor); 00120 00121 return old_shape; 00122 } 00123 00124 void 00125 ghid_point_cursor (void) 00126 { 00127 oldCursor = gport_set_cursor (GDK_DRAPED_BOX); 00128 } 00129 00130 void 00131 ghid_hand_cursor (void) 00132 { 00133 oldCursor = gport_set_cursor (GDK_HAND2); 00134 } 00135 00136 void 00137 ghid_watch_cursor (void) 00138 { 00139 GdkCursorType tmp; 00140 00141 tmp = gport_set_cursor (GDK_WATCH); 00142 if (tmp != GDK_WATCH) 00143 oldCursor = tmp; 00144 } 00145 00146 void 00147 ghid_mode_cursor (int Mode) 00148 { 00149 switch (Mode) 00150 { 00151 case NO_MODE: 00152 gport_set_cursor ((GdkCursorType)CUSTOM_CURSOR_DRAG); 00153 break; 00154 00155 case VIA_MODE: 00156 gport_set_cursor (GDK_ARROW); 00157 break; 00158 00159 case LINE_MODE: 00160 gport_set_cursor (GDK_PENCIL); 00161 break; 00162 00163 case ARC_MODE: 00164 gport_set_cursor (GDK_QUESTION_ARROW); 00165 break; 00166 00167 case ARROW_MODE: 00168 gport_set_cursor (GDK_LEFT_PTR); 00169 break; 00170 00171 case POLYGON_MODE: 00172 case POLYGONHOLE_MODE: 00173 gport_set_cursor (GDK_SB_UP_ARROW); 00174 break; 00175 00176 case PASTEBUFFER_MODE: 00177 gport_set_cursor (GDK_HAND1); 00178 break; 00179 00180 case TEXT_MODE: 00181 gport_set_cursor (GDK_XTERM); 00182 break; 00183 00184 case RECTANGLE_MODE: 00185 gport_set_cursor (GDK_UL_ANGLE); 00186 break; 00187 00188 case THERMAL_MODE: 00189 gport_set_cursor (GDK_IRON_CROSS); 00190 break; 00191 00192 case REMOVE_MODE: 00193 gport_set_cursor (GDK_PIRATE); 00194 break; 00195 00196 case ROTATE_MODE: 00197 if (ghid_shift_is_pressed ()) 00198 gport_set_cursor ((GdkCursorType)CUSTOM_CURSOR_CLOCKWISE); 00199 else 00200 gport_set_cursor (GDK_EXCHANGE); 00201 break; 00202 00203 case COPY_MODE: 00204 case MOVE_MODE: 00205 gport_set_cursor (GDK_CROSSHAIR); 00206 break; 00207 00208 case INSERTPOINT_MODE: 00209 gport_set_cursor (GDK_DOTBOX); 00210 break; 00211 00212 case LOCK_MODE: 00213 gport_set_cursor ((GdkCursorType)CUSTOM_CURSOR_LOCK); 00214 } 00215 } 00216 00217 void 00218 ghid_corner_cursor (void) 00219 { 00220 GdkCursorType shape; 00221 00222 if (Crosshair.Y <= Crosshair.AttachedBox.Point1.Y) 00223 shape = (Crosshair.X >= Crosshair.AttachedBox.Point1.X) ? 00224 GDK_UR_ANGLE : GDK_UL_ANGLE; 00225 else 00226 shape = (Crosshair.X >= Crosshair.AttachedBox.Point1.X) ? 00227 GDK_LR_ANGLE : GDK_LL_ANGLE; 00228 if (gport->X_cursor_shape != shape) 00229 gport_set_cursor (shape); 00230 } 00231 00232 void 00233 ghid_restore_cursor (void) 00234 { 00235 gport_set_cursor (oldCursor); 00236 } 00237 00238 00239 00240 /* =============================================================== */ 00241 static gboolean got_location; 00242 00243 /* If user hits a key instead of the mouse button, we'll abort unless 00244 | it's the enter key (which accepts the current crosshair location). 00245 */ 00246 static gboolean 00247 loop_key_press_cb (GtkWidget * drawing_area, GdkEventKey * kev, 00248 GMainLoop ** loop) 00249 { 00250 gint ksym = kev->keyval; 00251 00252 if (ghid_is_modifier_key_sym (ksym)) 00253 return TRUE; 00254 00255 switch (ksym) 00256 { 00257 case GDK_Return: /* Accept cursor location */ 00258 if (g_main_loop_is_running (*loop)) 00259 g_main_loop_quit (*loop); 00260 break; 00261 00262 default: /* Abort */ 00263 got_location = FALSE; 00264 if (g_main_loop_is_running (*loop)) 00265 g_main_loop_quit (*loop); 00266 break; 00267 } 00268 return TRUE; 00269 } 00270 00271 /* User hit a mouse button in the Output drawing area, so quit the loop 00272 | and the cursor values when the button was pressed will be used. 00273 */ 00274 static gboolean 00275 loop_button_press_cb (GtkWidget * drawing_area, GdkEventButton * ev, 00276 GMainLoop ** loop) 00277 { 00278 if (g_main_loop_is_running (*loop)) 00279 g_main_loop_quit (*loop); 00280 ghid_note_event_location (ev); 00281 return TRUE; 00282 } 00283 00284 /* Run a glib GMainLoop which intercepts key and mouse button events from 00285 | the top level loop. When a mouse or key is hit in the Output drawing 00286 | area, quit the loop so the top level loop can continue and use the 00287 | the mouse pointer coordinates at the time of the mouse button event. 00288 */ 00289 static gboolean 00290 run_get_location_loop (const gchar * message) 00291 { 00292 GMainLoop *loop; 00293 gulong button_handler, key_handler; 00294 gint oldObjState, oldLineState, oldBoxState; 00295 00296 /* Make the text cue bold so it hides less and looks like command prompt */ 00297 GString *bold_message = g_string_new (message); 00298 g_string_prepend (bold_message, "<b>"); 00299 g_string_append (bold_message, "</b>"); 00300 00301 ghid_status_line_set_text (bold_message->str); 00302 00303 g_string_free (bold_message, TRUE); 00304 00305 oldObjState = Crosshair.AttachedObject.State; 00306 oldLineState = Crosshair.AttachedLine.State; 00307 oldBoxState = Crosshair.AttachedBox.State; 00308 notify_crosshair_change (false); 00309 Crosshair.AttachedObject.State = STATE_FIRST; 00310 Crosshair.AttachedLine.State = STATE_FIRST; 00311 Crosshair.AttachedBox.State = STATE_FIRST; 00312 ghid_hand_cursor (); 00313 notify_crosshair_change (true); 00314 00315 /* Stop the top level GMainLoop from getting user input from keyboard 00316 | and mouse so we can install our own handlers here. Also set the 00317 | control interface insensitive so all the user can do is hit a key 00318 | or mouse button in the Output drawing area. 00319 */ 00320 ghid_interface_input_signals_disconnect (); 00321 ghid_interface_set_sensitive (FALSE); 00322 00323 got_location = TRUE; /* Will be unset by hitting most keys */ 00324 button_handler = 00325 g_signal_connect (G_OBJECT (gport->drawing_area), 00326 "button_press_event", 00327 G_CALLBACK (loop_button_press_cb), &loop); 00328 key_handler = 00329 g_signal_connect (G_OBJECT (gport->top_window), 00330 "key_press_event", 00331 G_CALLBACK (loop_key_press_cb), &loop); 00332 00333 loop = g_main_loop_new (NULL, FALSE); 00334 00335 GDK_THREADS_LEAVE (); 00336 g_main_loop_run (loop); 00337 GDK_THREADS_ENTER (); 00338 00339 g_main_loop_unref (loop); 00340 00341 g_signal_handler_disconnect (gport->drawing_area, button_handler); 00342 g_signal_handler_disconnect (gport->top_window, key_handler); 00343 00344 ghid_interface_input_signals_connect (); /* return to normal */ 00345 ghid_interface_set_sensitive (TRUE); 00346 00347 notify_crosshair_change (false); 00348 Crosshair.AttachedObject.State = oldObjState; 00349 Crosshair.AttachedLine.State = oldLineState; 00350 Crosshair.AttachedBox.State = oldBoxState; 00351 notify_crosshair_change (true); 00352 ghid_restore_cursor (); 00353 00354 ghid_set_status_line_label (); 00355 00356 return got_location; 00357 } 00358 00359 00360 00361 /* ---------------------------------------------------------------------------*/ 00362 void 00363 ghid_get_user_xy (const char *msg) 00364 { 00365 run_get_location_loop (msg); 00366 } 00367 00368 /* XXX The abort dialog isn't implemented yet in the Gtk port 00369 */ 00370 void 00371 ghid_create_abort_dialog (char *msg) 00372 { 00373 } 00374 00375 gboolean 00376 ghid_check_abort (void) 00377 { 00378 return FALSE; /* Abort isn't implemented, so never abort */ 00379 } 00380 00381 void 00382 ghid_end_abort (void) 00383 { 00384 } 00385 00386 void 00387 ghid_get_pointer (int *x, int *y) 00388 { 00389 gint xp, yp; 00390 00391 gdk_window_get_pointer (gtk_widget_get_window (gport->drawing_area), 00392 &xp, &yp, NULL); 00393 if (x) 00394 *x = xp; 00395 if (y) 00396 *y = yp; 00397 } 00398 00399 /* --------------------------------------------------------------------------- 00400 * output of status line 00401 */ 00402 void 00403 ghid_set_status_line_label (void) 00404 { 00405 gchar *flag = TEST_FLAG (ALLDIRECTIONFLAG, PCB) 00406 ? "all" 00407 : (PCB->Clipping == 0 00408 ? "45" 00409 : (PCB->Clipping == 1 00410 ? "45_/" 00411 : "45\\_")); 00412 gchar *text = pcb_g_strdup_printf ( 00413 _("%m+<b>view</b>=%s " 00414 "<b>grid</b>=%$mS " 00415 "%s%s " 00416 "<b>line</b>=%mS " 00417 "<b>via</b>=%mS (%mS) %s" 00418 "<b>clearance</b>=%mS " 00419 "<b>text</b>=%i%% " 00420 "<b>buffer</b>=#%i"), 00421 Settings.grid_unit->allow, 00422 Settings.ShowBottomSide ? C_("status", "bottom") : C_("status", "top"), 00423 PCB->Grid, 00424 flag, TEST_FLAG (RUBBERBANDFLAG, PCB) ? ",R " : " ", 00425 Settings.LineThickness, 00426 Settings.ViaThickness, 00427 Settings.ViaDrillingHole, 00428 ghidgui->compact_horizontal ? "\n" : "", 00429 Settings.Keepaway, 00430 Settings.TextScale, Settings.BufferNumber + 1); 00431 00432 ghid_status_line_set_text (text); 00433 g_free (text); 00434 } 00435 00436 /* --------------------------------------------------------------------------- 00437 * output of cursor position 00438 */ 00439 void 00440 ghid_set_cursor_position_labels (void) 00441 { 00442 gchar *text; 00443 00444 if (Marked.status) 00445 { 00446 Coord dx = Crosshair.X - Marked.X; 00447 Coord dy = Crosshair.Y - Marked.Y; 00448 Coord r = Distance (Crosshair.X, Crosshair.Y, Marked.X, Marked.Y); 00449 double a = atan2 (dy, dx) * RAD_TO_DEG; 00450 00451 text = pcb_g_strdup_printf (_("%m+r %-mS;\nphi %-.1f;\n%-mS %-mS"), 00452 Settings.grid_unit->allow, 00453 r, a, dx, dy); 00454 ghid_cursor_position_relative_label_set_text (text); 00455 g_free (text); 00456 } 00457 else 00458 ghid_cursor_position_relative_label_set_text (_("r __.__;\nphi __._;\n__.__ __.__")); 00459 00460 00461 text = pcb_g_strdup_printf (_("%m+%-mS %-mS"), 00462 Settings.grid_unit->allow, 00463 Crosshair.X, Crosshair.Y); 00464 ghid_cursor_position_label_set_text (text); 00465 g_free (text); 00466 }