gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 #include <config.h> 00021 00022 #include <stdio.h> 00023 #include <math.h> 00024 #ifdef HAVE_STDLIB_H 00025 #include <stdlib.h> 00026 #endif 00027 00028 #include "gschem.h" 00029 #include <gdk/gdkkeysyms.h> 00030 00031 #ifdef HAVE_LIBDMALLOC 00032 #include <dmalloc.h> 00033 #endif 00034 00035 00036 /* used by mouse pan */ 00037 int start_pan_x, start_pan_y; 00038 int throttle = 0; 00039 00040 /* used for the stroke stuff */ 00041 #ifdef HAVE_LIBSTROKE 00042 static int DOING_STROKE = FALSE; 00043 #endif /* HAVE_LIBSTROKE */ 00044 00050 gint x_event_expose(GtkWidget *widget, GdkEventExpose *event, 00051 GSCHEM_TOPLEVEL *w_current) 00052 { 00053 GdkRectangle *rectangles; 00054 int n_rectangles; 00055 cairo_t *save_cr; 00056 PangoLayout *save_pl; 00057 00058 #if DEBUG 00059 printf("EXPOSE\n"); 00060 #endif 00061 00062 g_return_val_if_fail ((w_current != NULL), 0); 00063 00064 save_cr = w_current->cr; 00065 save_pl = w_current->pl; 00066 00067 w_current->cr = gdk_cairo_create( widget->window ); 00068 w_current->pl = pango_cairo_create_layout (w_current->cr); 00069 00070 gdk_region_get_rectangles (event->region, &rectangles, &n_rectangles); 00071 o_redraw_rects (w_current, rectangles, n_rectangles); 00072 g_free (rectangles); 00073 00074 /* raise the dialog boxes if this feature is enabled */ 00075 if (w_current->raise_dialog_boxes) { 00076 x_dialog_raise_all(w_current); 00077 } 00078 00079 g_object_unref (w_current->pl); 00080 cairo_destroy (w_current->cr); 00081 00082 w_current->cr = save_cr; 00083 w_current->pl = save_pl; 00084 00085 return(0); 00086 } 00087 00093 gint x_event_button_pressed(GtkWidget *widget, GdkEventButton *event, 00094 GSCHEM_TOPLEVEL *w_current) 00095 { 00096 TOPLEVEL *toplevel = w_current->toplevel; 00097 int w_x, w_y; 00098 int unsnapped_wx, unsnapped_wy; 00099 00100 g_return_val_if_fail ((w_current != NULL), 0); 00101 00102 scm_dynwind_begin (0); 00103 g_dynwind_window (w_current); 00104 00105 #if DEBUG 00106 printf("pressed button %d! \n", event->button); 00107 printf("event state: %d \n", event->state); 00108 printf("w_current state: %d \n", w_current->event_state); 00109 printf("Selection is:\n"); 00110 o_selection_print_all(&(toplevel->page_current->selection_list)); 00111 printf("\n"); 00112 #endif 00113 00114 SCREENtoWORLD (w_current, (int) event->x, (int) event->y, 00115 &unsnapped_wx, &unsnapped_wy); 00116 w_x = snap_grid (w_current, unsnapped_wx); 00117 w_y = snap_grid (w_current, unsnapped_wy); 00118 00119 if (event->type == GDK_2BUTTON_PRESS && 00120 (w_current->event_state == STARTSELECT || 00121 w_current->event_state == SELECT)) { 00122 o_find_object(w_current, w_x, w_y, TRUE); 00123 if (o_select_selected (w_current)) { 00124 o_edit(w_current, geda_list_get_glist( toplevel->page_current->selection_list )); 00125 i_set_state(w_current, SELECT); 00126 scm_dynwind_end (); 00127 return(0); 00128 } 00129 } 00130 00131 w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK ) ? 1 : 0; 00132 w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; 00133 w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; 00134 00135 /* Huge switch statement to evaluate state transitions. Jump to 00136 * end_button_pressed label to escape the state evaluation rather than 00137 * returning from the function directly. */ 00138 00139 if (event->button == 1) { 00140 switch(w_current->event_state) { 00141 00142 case(SELECT): 00143 /* look for grips or fall through if not enabled */ 00144 if (!o_grips_start(w_current, unsnapped_wx, unsnapped_wy)) { 00145 /* now go into normal SELECT */ 00146 w_current->event_state = STARTSELECT; 00147 w_current->first_wx = w_current->second_wx = unsnapped_wx; 00148 w_current->first_wy = w_current->second_wy = unsnapped_wy; 00149 } else { 00150 /* a grip was found */ 00151 w_current->event_state = GRIPS; 00152 w_current->inside_action = 1; 00153 } 00154 break; 00155 00156 case(STARTCOPY): 00157 if (o_select_selected(w_current)) { 00158 o_copy_start(w_current, w_x, w_y); 00159 w_current->event_state = COPY; 00160 w_current->inside_action = 1; 00161 } 00162 break; 00163 00164 case(STARTMCOPY): 00165 if (o_select_selected(w_current)) { 00166 o_copy_start(w_current, w_x, w_y); 00167 w_current->event_state = MCOPY; 00168 w_current->inside_action = 1; 00169 } 00170 break; 00171 00172 case(STARTMOVE): 00173 if (o_select_selected(w_current)) { 00174 o_move_start(w_current, w_x, w_y); 00175 w_current->event_state = MOVE; 00176 w_current->inside_action = 1; 00177 } 00178 break; 00179 00180 case(STARTPASTE): 00181 o_buffer_paste_start(w_current, w_x, w_y, w_current->buffer_number); 00182 w_current->event_state = ENDPASTE; 00183 w_current->inside_action = 1; 00184 break; 00185 00186 case(DRAWLINE): 00187 o_line_start(w_current, w_x, w_y); 00188 w_current->event_state = ENDLINE; 00189 w_current->inside_action = 1; 00190 break; 00191 00192 case(ENDLINE): 00193 o_line_end(w_current, w_x, w_y); 00194 w_current->inside_action = 0; 00195 w_current->event_state = DRAWLINE; 00196 break; 00197 00198 case(DRAWBOX): 00199 o_box_start(w_current, w_x, w_y); 00200 w_current->event_state = ENDBOX; 00201 w_current->inside_action = 1; 00202 break; 00203 00204 case(ENDBOX): 00205 o_box_end(w_current, w_x, w_y); 00206 w_current->inside_action = 0; 00207 w_current->event_state = DRAWBOX; 00208 break; 00209 00210 case(DRAWPICTURE): 00211 o_picture_start(w_current, w_x, w_y); 00212 w_current->event_state = ENDPICTURE; 00213 w_current->inside_action = 1; 00214 break; 00215 00216 case(ENDPICTURE): 00217 o_picture_end(w_current, w_x, w_y); 00218 w_current->inside_action = 0; 00219 w_current->event_state = DRAWPICTURE; 00220 break; 00221 00222 case(DRAWCIRCLE): 00223 o_circle_start(w_current, w_x, w_y); 00224 w_current->event_state = ENDCIRCLE; 00225 w_current->inside_action = 1; 00226 break; 00227 00228 case(ENDCIRCLE): 00229 o_circle_end(w_current, w_x, w_y); 00230 w_current->inside_action = 0; 00231 w_current->event_state = DRAWCIRCLE; 00232 break; 00233 00234 case(DRAWARC): 00235 o_arc_start(w_current, w_x, w_y); 00236 w_current->event_state = ENDARC; 00237 w_current->inside_action = 1; 00238 break; 00239 00240 case(ENDARC): 00241 o_arc_end1(w_current, w_x, w_y); 00242 w_current->inside_action = 0; 00243 w_current->event_state = DRAWARC; 00244 break; 00245 00246 case(DRAWPIN): 00247 o_pin_start(w_current, w_x, w_y); 00248 w_current->event_state = ENDPIN; 00249 w_current->inside_action = 1; 00250 break; 00251 00252 case(ENDPIN): 00253 o_pin_end(w_current, w_x, w_y); 00254 w_current->inside_action = 0; 00255 w_current->event_state = DRAWPIN; 00256 break; 00257 00258 case(STARTDRAWNET): 00259 o_net_start(w_current, w_x, w_y); 00260 w_current->inside_action = 1; 00261 w_current->event_state=DRAWNET; 00262 00263 break; 00264 00265 case(STARTDRAWBUS): 00266 o_bus_start(w_current, w_x, w_y); 00267 w_current->inside_action = 1; 00268 w_current->event_state=DRAWBUS; 00269 00270 break; 00271 00272 case(DRAWNET): 00273 case(NETCONT): 00274 /* Only continue the net if net end worked */ 00275 if (o_net_end(w_current, w_x, w_y)) { 00276 o_net_start(w_current, w_current->first_wx, w_current->first_wy); 00277 w_current->event_state=NETCONT; 00278 } else { /* cleanup and start a new net */ 00279 o_net_invalidate_rubber (w_current); 00280 o_net_reset(w_current); 00281 i_set_state(w_current, STARTDRAWNET); 00282 w_current->inside_action = 0; 00283 } 00284 break; 00285 00286 case(DRAWBUS): 00287 case(BUSCONT): 00288 /* Only continue the net if net end worked */ 00289 if (o_bus_end(w_current, w_x, w_y)) { 00290 o_bus_start(w_current, w_current->first_wx, w_current->first_wy); 00291 w_current->event_state=BUSCONT; 00292 } else { 00293 w_current->inside_action=0; 00294 i_set_state(w_current, STARTDRAWBUS); 00295 } 00296 break; 00297 case(ENDCOMP): 00298 o_place_end(w_current, w_x, w_y, w_current->continue_component_place, 00299 NULL, "%add-objects-hook"); 00300 if (!w_current->continue_component_place) { 00301 w_current->inside_action = 0; 00302 i_set_state(w_current, SELECT); 00303 i_update_toolbar(w_current); 00304 } 00305 break; 00306 00307 case(ENDPASTE): 00308 o_place_end(w_current, w_x, w_y, FALSE, NULL, "%paste-objects-hook"); 00309 w_current->inside_action = 0; 00310 i_set_state(w_current, SELECT); 00311 i_update_toolbar(w_current); 00312 break; 00313 00314 case(ENDROTATEP): 00315 o_rotate_world_update(w_current, w_x, w_y, 90, 00316 geda_list_get_glist(toplevel->page_current->selection_list )); 00317 00318 w_current->inside_action = 0; 00319 i_set_state(w_current, SELECT); 00320 i_update_toolbar(w_current); 00321 break; 00322 00323 case(ENDMIRROR): 00324 o_mirror_world_update(w_current, w_x, w_y, 00325 geda_list_get_glist( 00326 toplevel->page_current->selection_list )); 00327 00328 w_current->inside_action = 0; 00329 i_set_state(w_current, SELECT); 00330 i_update_toolbar(w_current); 00331 break; 00332 00333 case(ENDTEXT): 00334 o_place_end(w_current, w_x, w_y, FALSE, NULL, "%add-objects-hook"); 00335 w_current->inside_action = 0; 00336 i_set_state(w_current, SELECT); 00337 i_update_toolbar(w_current); 00338 break; 00339 00340 00341 case(STARTPAN): 00342 a_pan(w_current, w_x, w_y); 00343 i_set_state(w_current, SELECT); 00344 i_update_toolbar(w_current); 00345 break; 00346 00347 case(ZOOMBOXSTART): 00348 a_zoom_box_start(w_current, unsnapped_wx, unsnapped_wy); 00349 w_current->event_state = ZOOMBOXEND; 00350 w_current->inside_action = 1; 00351 break; 00352 00353 } 00354 } else if (event->button == 2) { 00355 00356 /* try this out and see how it behaves */ 00357 if (w_current->inside_action) { 00358 if (!(w_current->event_state == ENDCOMP || 00359 w_current->event_state == ENDTEXT || 00360 w_current->event_state == ENDMOVE || 00361 w_current->event_state == ENDCOPY || 00362 w_current->event_state == ENDMCOPY || 00363 w_current->event_state == ENDPASTE )) { 00364 i_callback_cancel(w_current, 0, NULL); 00365 } 00366 goto end_button_pressed; 00367 } 00368 00369 switch(w_current->middle_button) { 00370 00371 case(ACTION): 00372 /* determine here if copy or move */ 00373 /* for now do move only */ 00374 /* make sure the list is not empty */ 00375 if (o_select_selected(w_current)) { 00376 00377 /* don't want to search if shift */ 00378 /* key is depresed */ 00379 if (!w_current->SHIFTKEY) { 00380 o_find_object(w_current, unsnapped_wx, unsnapped_wy, TRUE); 00381 } 00382 } else { 00383 o_select_unselect_all(w_current); 00384 /* don't want to search if shift */ 00385 /* key is depresed */ 00386 if (!w_current->SHIFTKEY) { 00387 o_find_object(w_current, unsnapped_wx, unsnapped_wy, TRUE); 00388 } 00389 } 00390 00391 if (!o_select_selected(w_current)) { 00392 /* this means the above find did not 00393 * find anything */ 00394 w_current->inside_action = 0; 00395 i_set_state(w_current, SELECT); 00396 i_update_toolbar(w_current); 00397 goto end_button_pressed; 00398 } 00399 00400 if (w_current->ALTKEY) { 00401 o_copy_start(w_current, w_x, w_y); 00402 w_current->inside_action = 1; 00403 i_set_state(w_current, COPY); 00404 } else { 00405 o_move_start(w_current, w_x, w_y); 00406 w_current->inside_action = 1; 00407 i_set_state(w_current, MOVE); 00408 } 00409 break; 00410 00411 case(REPEAT): 00412 if (w_current->last_callback != NULL) { 00413 (*w_current->last_callback)(w_current, 0, NULL); 00414 } 00415 break; 00416 #ifdef HAVE_LIBSTROKE 00417 case(STROKE): 00418 DOING_STROKE=TRUE; 00419 break; 00420 #endif /* HAVE_LIBSTROKE */ 00421 00422 case(MID_MOUSEPAN_ENABLED): 00423 w_current->event_state = MOUSEPAN; /* start */ 00424 w_current->inside_action = 1; 00425 w_current->doing_pan = TRUE; 00426 start_pan_x = (int) event->x; 00427 start_pan_y = (int) event->y; 00428 throttle=0; 00429 break; 00430 } 00431 00432 } else if (event->button == 3) { 00433 if (!w_current->inside_action) { 00434 if (w_current->third_button == POPUP_ENABLED) { 00435 i_update_menus(w_current); /* update menus before popup */ 00436 do_popup(w_current, event); 00437 } else { 00438 w_current->event_state = MOUSEPAN; /* start */ 00439 w_current->inside_action = 1; 00440 w_current->doing_pan = TRUE; 00441 start_pan_x = (int) event->x; 00442 start_pan_y = (int) event->y; 00443 throttle=0; 00444 } 00445 } else { /* this is the default cancel */ 00446 switch (w_current->event_state) { 00447 case(STARTDRAWNET): 00448 case(DRAWNET): 00449 case(NETCONT): 00450 w_current->inside_action = 0; 00451 i_set_state(w_current, STARTDRAWNET); 00452 o_net_invalidate_rubber (w_current); 00453 o_net_reset(w_current); 00454 break; 00455 00456 case(STARTDRAWBUS): 00457 case(DRAWBUS): 00458 case(BUSCONT): 00459 w_current->inside_action = 0; 00460 i_set_state(w_current, STARTDRAWBUS); 00461 o_bus_invalidate_rubber (w_current); 00462 break; 00463 00464 case(DRAWPIN): 00465 case(ENDPIN): 00466 w_current->inside_action = 0; 00467 i_set_state(w_current, DRAWPIN); 00468 o_pin_invalidate_rubber (w_current); 00469 break; 00470 00471 case(DRAWLINE): 00472 case(ENDLINE): 00473 w_current->inside_action = 0; 00474 i_set_state(w_current, DRAWLINE); 00475 o_line_invalidate_rubber (w_current); 00476 break; 00477 00478 case(DRAWBOX): 00479 case(ENDBOX): 00480 w_current->inside_action = 0; 00481 i_set_state(w_current, DRAWBOX); 00482 o_box_invalidate_rubber (w_current); 00483 break; 00484 00485 case(DRAWPICTURE): 00486 case(ENDPICTURE): 00487 w_current->inside_action = 0; 00488 i_set_state(w_current, DRAWPICTURE); 00489 o_picture_invalidate_rubber (w_current); 00490 break; 00491 00492 case(DRAWCIRCLE): 00493 case(ENDCIRCLE): 00494 w_current->inside_action = 0; 00495 i_set_state(w_current, DRAWCIRCLE); 00496 o_circle_invalidate_rubber (w_current); 00497 break; 00498 00499 case(DRAWARC): 00500 case(ENDARC): 00501 w_current->inside_action = 0; 00502 i_set_state(w_current, DRAWARC); 00503 o_arc_invalidate_rubber (w_current); 00504 break; 00505 00506 default: 00507 i_callback_cancel(w_current, 0, NULL); 00508 break; 00509 } 00510 i_update_toolbar(w_current); 00511 } 00512 } 00513 00514 end_button_pressed: 00515 scm_dynwind_end (); 00516 00517 return(0); 00518 } 00519 00525 gint x_event_button_released(GtkWidget *widget, GdkEventButton *event, 00526 GSCHEM_TOPLEVEL *w_current) 00527 { 00528 int unsnapped_wx, unsnapped_wy; 00529 00530 g_return_val_if_fail ((w_current != NULL), 0); 00531 00532 #if DEBUG 00533 printf("released! %d \n", w_current->event_state); 00534 #endif 00535 00536 w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK ) ? 1 : 0; 00537 w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; 00538 w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; 00539 00540 SCREENtoWORLD (w_current, (int) event->x, (int) event->y, 00541 &unsnapped_wx, &unsnapped_wy); 00542 00543 /* Huge switch statement to evaluate state transitions. Jump to 00544 * end_button_released label to escape the state evaluation rather 00545 * than returning from the function directly. */ 00546 scm_dynwind_begin (0); 00547 g_dynwind_window (w_current); 00548 00549 if (event->button == 1) { 00550 switch(w_current->event_state) { 00551 case(SELECT): 00552 /* do nothing */ 00553 break; 00554 case(MOVE): 00555 w_current->event_state = ENDMOVE; 00556 break; 00557 00558 case(COPY): 00559 w_current->event_state = ENDCOPY; 00560 break; 00561 00562 case(MCOPY): 00563 w_current->event_state = ENDMCOPY; 00564 break; 00565 case(GRIPS): 00566 o_grips_end(w_current), 00567 w_current->inside_action = 0; 00568 i_set_state(w_current, SELECT); 00569 i_update_toolbar(w_current); 00570 break; 00571 case(ENDMOVE): 00572 o_move_end(w_current); 00573 /* having this stay in copy was driving me nuts*/ 00574 w_current->inside_action = 0; 00575 i_set_state(w_current, SELECT); 00576 i_update_toolbar(w_current); 00577 break; 00578 00579 case(ENDCOPY): 00580 o_copy_end(w_current); 00581 /* having this stay in copy was driving me nuts*/ 00582 w_current->inside_action = 0; 00583 i_set_state(w_current, SELECT); 00584 i_update_toolbar(w_current); 00585 break; 00586 00587 case(ENDMCOPY): 00588 o_copy_multiple_end(w_current); 00589 /* having this stay in copy was driving me nuts*/ 00590 w_current->inside_action = 1; 00591 /* Keep the state and the inside_action, as the copy has not finished. */ 00592 i_set_state(w_current, ENDMCOPY); 00593 i_update_toolbar(w_current); 00594 o_undo_savestate(w_current, UNDO_ALL); 00595 break; 00596 00597 case(SBOX): 00598 o_select_box_end(w_current, unsnapped_wx, unsnapped_wy); 00599 w_current->inside_action = 0; 00600 i_set_state(w_current, SELECT); 00601 i_update_toolbar(w_current); 00602 break; 00603 00604 case(ZOOMBOXEND): 00605 a_zoom_box_end(w_current, unsnapped_wx, unsnapped_wy); 00606 w_current->inside_action = 0; 00607 i_set_state(w_current, SELECT); 00608 i_update_toolbar(w_current); 00609 break; 00610 00611 case(STARTSELECT): 00612 /* first look for grips */ 00613 if (!o_grips_start(w_current, unsnapped_wx, unsnapped_wy)) { 00614 /* now go looking for objects to select */ 00615 o_find_object(w_current, unsnapped_wx, unsnapped_wy, TRUE); 00616 w_current->event_state = SELECT; 00617 w_current->inside_action = 0; 00618 } else { 00619 /* an grip was found */ 00620 w_current->event_state = GRIPS; 00621 w_current->inside_action = 1; 00622 } 00623 break; 00624 00625 } 00626 } else if (event->button == 2) { 00627 00628 if (w_current->inside_action) { 00629 if (w_current->event_state == ENDCOMP || 00630 w_current->event_state == ENDTEXT || 00631 w_current->event_state == ENDMOVE || 00632 w_current->event_state == ENDCOPY || 00633 w_current->event_state == ENDMCOPY || 00634 w_current->event_state == ENDPASTE ) { 00635 00636 if (w_current->event_state == ENDMOVE) { 00637 o_move_invalidate_rubber (w_current, FALSE); 00638 } else { 00639 o_place_invalidate_rubber (w_current, FALSE); 00640 } 00641 w_current->rubber_visible = 0; 00642 00643 o_place_rotate(w_current); 00644 00645 if (w_current->event_state == ENDCOMP) { 00646 o_complex_place_changed_run_hook (w_current); 00647 } 00648 00649 if (w_current->event_state == ENDMOVE) { 00650 o_move_invalidate_rubber (w_current, TRUE); 00651 } else { 00652 o_place_invalidate_rubber (w_current, TRUE); 00653 } 00654 w_current->rubber_visible = 1; 00655 goto end_button_released; 00656 } 00657 } 00658 00659 switch(w_current->middle_button) { 00660 case(ACTION): 00661 switch(w_current->event_state) { 00662 case(MOVE): 00663 o_move_end(w_current); 00664 w_current->inside_action = 0; 00665 i_set_state(w_current, SELECT); 00666 i_update_toolbar(w_current); 00667 break; 00668 00669 case(COPY): 00670 o_copy_end(w_current); 00671 w_current->inside_action = 0; 00672 i_set_state(w_current, SELECT); 00673 i_update_toolbar(w_current); 00674 break; 00675 } 00676 break; 00677 00678 #ifdef HAVE_LIBSTROKE 00679 case(STROKE): 00680 DOING_STROKE = FALSE; 00681 x_stroke_translate_and_execute (w_current); 00682 break; 00683 #endif /* HAVE_LIBSTROKE */ 00684 00685 case(MID_MOUSEPAN_ENABLED): 00686 w_current->doing_pan=FALSE; 00687 o_invalidate_all (w_current); 00688 if (w_current->undo_panzoom) { 00689 o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY); 00690 } 00691 /* this needs to be REDONE */ 00692 /* if you mouse pan, you will be thrown out of the current mode. */ 00693 /* not good */ 00694 w_current->inside_action = 0; 00695 i_set_state(w_current, SELECT); 00696 i_update_toolbar(w_current); 00697 break; 00698 } 00699 00700 } else if (event->button == 3) { 00701 if (w_current->doing_pan) { /* just for ending a mouse pan */ 00702 w_current->doing_pan=FALSE; 00703 o_invalidate_all (w_current); 00704 00705 if (w_current->undo_panzoom) { 00706 o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY); 00707 } 00708 /* this needs to be REDONE */ 00709 /* if you mouse pan, you will be thrown out of the current mode. */ 00710 /* not good */ 00711 w_current->inside_action = 0; 00712 i_set_state(w_current, SELECT); 00713 i_update_toolbar(w_current); 00714 } 00715 } 00716 end_button_released: 00717 scm_dynwind_end (); 00718 00719 return(0); 00720 } 00721 00727 gint x_event_motion(GtkWidget *widget, GdkEventMotion *event, 00728 GSCHEM_TOPLEVEL *w_current) 00729 { 00730 int pdiff_x, pdiff_y; 00731 int w_x, w_y; 00732 int unsnapped_wx, unsnapped_wy; 00733 int skip_event=0; 00734 GdkEvent *test_event; 00735 00736 g_return_val_if_fail ((w_current != NULL), 0); 00737 00738 w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK ) ? 1 : 0; 00739 w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; 00740 w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; 00741 00742 #if DEBUG 00743 /* printf("MOTION!\n");*/ 00744 #endif 00745 00746 #ifdef HAVE_LIBSTROKE 00747 if (DOING_STROKE == TRUE) { 00748 x_stroke_record (w_current, event->x, event->y); 00749 return(0); 00750 } 00751 #endif /* HAVE_LIBSTROKE */ 00752 00753 /* skip the moving event if there are other moving events in the 00754 gdk event queue (Werner) 00755 Only skip the event if is the same event and no buttons or modifier 00756 keys changed*/ 00757 if ((test_event = gdk_event_get()) != NULL) { 00758 if (test_event->type == GDK_MOTION_NOTIFY 00759 && ((GdkEventMotion *) test_event)->state == event->state) { 00760 skip_event= 1; 00761 } 00762 gdk_event_put(test_event); /* put it back in front of the queue */ 00763 gdk_event_free(test_event); 00764 if (skip_event == 1) 00765 return 0; 00766 } 00767 00768 SCREENtoWORLD (w_current, (int) event->x, (int) event->y, 00769 &unsnapped_wx, &unsnapped_wy); 00770 w_x = snap_grid (w_current, unsnapped_wx); 00771 w_y = snap_grid (w_current, unsnapped_wy); 00772 00773 if (w_current->cowindow) { 00774 coord_display_update(w_current, (int) event->x, (int) event->y); 00775 } 00776 if (w_current->third_button == MOUSEPAN_ENABLED || w_current->middle_button == MID_MOUSEPAN_ENABLED) { 00777 if((w_current->event_state == MOUSEPAN) && 00778 w_current->inside_action) { 00779 pdiff_x = (int) event->x - start_pan_x; 00780 pdiff_y = (int) event->y - start_pan_y; 00781 00782 if (!(throttle % 5)) { 00783 a_pan_mouse(w_current, pdiff_x*w_current->mousepan_gain, 00784 pdiff_y*w_current->mousepan_gain); 00785 00786 start_pan_x = (int) event->x; 00787 start_pan_y = (int) event->y; 00788 } 00789 throttle++; 00790 return(0); 00791 } 00792 } 00793 00794 /* Huge switch statement to evaluate state transitions. Jump to 00795 * end_motion label to escape the state evaluation rather 00796 * than returning from the function directly. */ 00797 scm_dynwind_begin (0); 00798 g_dynwind_window (w_current); 00799 00800 switch(w_current->event_state) { 00801 00802 case(SELECT): 00803 /* do nothing */ 00804 break; 00805 00806 case(GRIPS): 00807 o_grips_motion(w_current, w_x, w_y); 00808 break; 00809 00810 case(STARTSELECT): 00811 /* If the shift or control keys are pressed, that means the user definately wants to drag out a 00812 * selection box. Otherwise, if there is not a selected object under the cursor, look for one 00813 * that could be selected and start moving it. 00814 */ 00815 if (w_current->SHIFTKEY || w_current->CONTROLKEY 00816 || (!o_find_selected_object(w_current, w_current->first_wx, w_current->first_wy) 00817 && (!o_find_object(w_current, w_current->first_wx, w_current->first_wy, TRUE) 00818 || !o_select_selected(w_current)))) { 00819 if (o_select_box_start(w_current, unsnapped_wx, unsnapped_wy)) { 00820 w_current->event_state = SBOX; 00821 w_current->inside_action = 1; 00822 } 00823 break; 00824 } else { 00825 /* Start moving the selected object(s) */ 00826 o_move_start(w_current, w_x, w_y); 00827 w_current->event_state = ENDMOVE; 00828 w_current->inside_action = 1; 00829 /* Fall through bottom of case to finish the move */ 00830 } 00831 /* Fall through to handle move */ 00832 case(ENDMOVE): 00833 case(MOVE): 00834 if (w_current->inside_action) 00835 o_move_motion (w_current, w_x, w_y); 00836 break; 00837 00838 case(ENDLINE): 00839 if (w_current->inside_action) 00840 o_line_motion (w_current, w_x, w_y); 00841 break; 00842 00843 case(ENDBOX): 00844 if (w_current->inside_action) 00845 o_box_motion ( w_current, w_x, w_y); 00846 break; 00847 00848 case(ENDPICTURE): 00849 if (w_current->inside_action) 00850 o_picture_motion ( w_current, w_x, w_y); 00851 break; 00852 00853 case(ENDCIRCLE): 00854 if (w_current->inside_action) 00855 o_circle_motion (w_current, w_x, w_y); 00856 break; 00857 00858 case(ENDARC): 00859 if (w_current->inside_action) 00860 o_arc_motion (w_current, w_x, w_y, ARC_RADIUS); 00861 break; 00862 00863 00864 case(STARTDRAWNET): 00865 if(w_current->magneticnet_mode == 1) { 00866 o_net_start_magnetic(w_current, w_x, w_y); 00867 } 00868 break; 00869 00870 case(DRAWNET): 00871 case(NETCONT): 00872 if (w_current->inside_action) 00873 o_net_motion (w_current, w_x, w_y); 00874 break; 00875 00876 case(DRAWBUS): 00877 case(BUSCONT): 00878 if (w_current->inside_action) 00879 o_bus_motion (w_current, w_x, w_y); 00880 break; 00881 00882 case(ENDPIN): 00883 if (w_current->inside_action) 00884 o_pin_motion (w_current, w_x, w_y); 00885 break; 00886 00887 case(COPY): 00888 case(MCOPY): 00889 case(ENDCOPY): 00890 case(ENDMCOPY): 00891 case(ENDCOMP): 00892 case(ENDPASTE): 00893 case(ENDTEXT): 00894 o_place_motion (w_current, w_x, w_y); 00895 break; 00896 00897 case(SBOX): 00898 if (w_current->inside_action) 00899 o_select_box_motion (w_current, unsnapped_wx, unsnapped_wy); 00900 break; 00901 00902 case(ZOOMBOXEND): 00903 if (w_current->inside_action) 00904 a_zoom_box_motion (w_current, unsnapped_wx, unsnapped_wy); 00905 break; 00906 00907 } 00908 00909 scm_dynwind_end (); 00910 00911 return(0); 00912 } 00913 00932 gboolean 00933 x_event_configure (GtkWidget *widget, 00934 GdkEventConfigure *event, 00935 gpointer user_data) 00936 { 00937 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL*)user_data; 00938 TOPLEVEL *toplevel = w_current->toplevel; 00939 GList *iter; 00940 PAGE *old_page_current, *p_current; 00941 gint old_win_width, old_win_height, new_win_width, new_win_height; 00942 gdouble relativ_zoom_factor = 1.0; 00943 00944 g_assert (toplevel != NULL); 00945 00946 if (toplevel->page_current == NULL) { 00947 /* don't want to call this if the current page isn't setup yet */ 00948 return FALSE; 00949 } 00950 00951 old_win_width = w_current->win_width; 00952 old_win_height = w_current->win_height; 00953 new_win_width = event->width; 00954 new_win_height = event->height; 00955 00956 if (old_win_width == new_win_width && 00957 old_win_height == new_win_height) { 00958 /* the size of the drawing area has not changed */ 00959 /* nothing to do here */ 00960 return FALSE; 00961 } 00962 00963 w_current->drawable = w_current->window; 00964 00965 /* update the GSCHEM_TOPLEVEL with new size of drawing area */ 00966 w_current->win_width = toplevel->width = new_win_width; 00967 w_current->win_height = toplevel->height = new_win_height; 00968 00969 00970 /* in the case the user has maximised the window (hence the */ 00971 /* configure event) fit the view by playing with zoom level */ 00972 if (gdk_window_get_state ( 00973 (gtk_widget_get_toplevel ( 00974 widget))->window) & GDK_WINDOW_STATE_MAXIMIZED) { 00975 gdouble width_ratio, height_ratio; 00976 00977 /* tweak relative_zoom to better fit page in maximized window */ 00978 width_ratio = ((gdouble)new_win_width) / ((gdouble)old_win_width); 00979 height_ratio = ((gdouble)new_win_height) / ((gdouble)old_win_height); 00980 /* keep smallest ratio as relative zoom factor when panning */ 00981 relativ_zoom_factor = 00982 (width_ratio < height_ratio) ? width_ratio : height_ratio; 00983 00984 } 00985 00986 /* save current page */ 00987 old_page_current = toplevel->page_current; 00988 00989 /* re-pan each page of the TOPLEVEL */ 00990 for ( iter = geda_list_get_glist( toplevel->pages ); 00991 iter != NULL; 00992 iter = g_list_next( iter ) ) { 00993 00994 gdouble cx, cy; 00995 p_current = (PAGE *)iter->data; 00996 00997 /* doing this the aspectratio is kept when changing (hw)*/ 00998 cx = ((gdouble)(p_current->left + p_current->right)) / 2; 00999 cy = ((gdouble)(p_current->top + p_current->bottom)) / 2; 01000 s_page_goto (toplevel, p_current); 01001 a_pan_general (w_current, cx, cy, relativ_zoom_factor, A_PAN_DONT_REDRAW); 01002 01003 } 01004 /* restore current page to saved value */ 01005 s_page_goto (toplevel, old_page_current); 01006 01007 /* redraw the current page and update UI */ 01008 o_invalidate_all (w_current); 01009 x_scrollbars_update (w_current); 01010 01011 return FALSE; 01012 } 01013 01022 void x_manual_resize(GSCHEM_TOPLEVEL *w_current) 01023 { 01024 TOPLEVEL *toplevel = w_current->toplevel; 01025 01026 /* of the actual win window (drawing_area) */ 01027 w_current->win_width = w_current->drawing_area->allocation.width; 01028 w_current->win_height = w_current->drawing_area->allocation.height; 01029 01030 #if DEBUG 01031 printf("manual: %d %d\n", w_current->win_width, w_current->win_height); 01032 #endif 01033 01034 toplevel->width = w_current->win_width; 01035 toplevel->height = w_current->win_height; 01036 01037 /* need to do this every time you change width / height */ 01038 set_window(toplevel, toplevel->page_current, 01039 toplevel->page_current->left, 01040 toplevel->page_current->right, 01041 toplevel->page_current->top, 01042 toplevel->page_current->bottom); 01043 01044 #if DEBUG 01045 printf("Window aspect: %f\n", 01046 (float) w_current->win_width / (float) w_current->win_height); 01047 /* No longer used? 01048 printf("w: %d h: %d\n", width, height); */ 01049 printf("aw: %d ah: %d\n", w_current->win_width, w_current->win_height); 01050 #endif 01051 } 01052 01058 void x_event_hschanged (GtkAdjustment *adj, GSCHEM_TOPLEVEL *w_current) 01059 { 01060 TOPLEVEL *toplevel = w_current->toplevel; 01061 int current_left; 01062 int new_left; 01063 GtkAdjustment *hadjustment; 01064 01065 g_return_if_fail (w_current != NULL); 01066 01067 if (w_current->scrollbars_flag == FALSE) { 01068 return; 01069 } 01070 01071 hadjustment = 01072 gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar)); 01073 01074 current_left = toplevel->page_current->left; 01075 new_left = (int) hadjustment->value; 01076 01077 toplevel->page_current->left = new_left; 01078 toplevel->page_current->right = 01079 toplevel->page_current->right - 01080 (current_left - new_left); 01081 01082 o_invalidate_all (w_current); 01083 } 01084 01090 void x_event_vschanged (GtkAdjustment *adj, GSCHEM_TOPLEVEL *w_current) 01091 { 01092 TOPLEVEL *toplevel = w_current->toplevel; 01093 int current_bottom; 01094 int new_bottom; 01095 GtkAdjustment *vadjustment; 01096 01097 g_return_if_fail (w_current != NULL); 01098 01099 if (w_current->scrollbars_flag == FALSE) { 01100 return; 01101 } 01102 01103 vadjustment = gtk_range_get_adjustment( 01104 GTK_RANGE(w_current->v_scrollbar)); 01105 01106 current_bottom = toplevel->page_current->bottom; 01107 new_bottom = toplevel->init_bottom - (int) vadjustment->value; 01108 01109 toplevel->page_current->bottom = new_bottom; 01110 toplevel->page_current->top = 01111 toplevel->page_current->top - 01112 (current_bottom - new_bottom); 01113 01114 #if DEBUG 01115 printf("vrange %f %f\n", vadjustment->lower, vadjustment->upper); 01116 printf("vvalue %f\n", vadjustment->value); 01117 printf("actual: %d %d\n", toplevel->page_current->top, 01118 toplevel->page_current->bottom); 01119 #endif 01120 01121 o_invalidate_all (w_current); 01122 } 01123 01129 gint x_event_enter(GtkWidget *widget, GdkEventCrossing *event, 01130 GSCHEM_TOPLEVEL *w_current) 01131 { 01132 g_return_val_if_fail ((w_current != NULL), 0); 01133 /* do nothing or now */ 01134 return(0); 01135 } 01136 01147 static void get_snapped_pointer (GSCHEM_TOPLEVEL *w_current, int *wx, int *wy) 01148 { 01149 int sx, sy; 01150 int unsnapped_wx, unsnapped_wy; 01151 01152 gtk_widget_get_pointer (w_current->drawing_area, &sx, &sy); 01153 SCREENtoWORLD (w_current, sx, sy, &unsnapped_wx, &unsnapped_wy); 01154 *wx = snap_grid (w_current, unsnapped_wx); 01155 *wy = snap_grid (w_current, unsnapped_wy); 01156 } 01157 01163 gboolean x_event_key (GtkWidget *widget, GdkEventKey *event, 01164 GSCHEM_TOPLEVEL *w_current) 01165 { 01166 gboolean retval = FALSE; 01167 int wx, wy; 01168 int alt_key = 0; 01169 int shift_key = 0; 01170 int control_key = 0; 01171 int pressed; 01172 01173 #if DEBUG 01174 printf("x_event_key_pressed: Pressed key %i.\n", event->keyval); 01175 #endif 01176 01177 /* update the state of the modifiers */ 01178 w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; 01179 w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK) ? 1 : 0; 01180 w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; 01181 01182 pressed = (event->type == GDK_KEY_PRESS) ? 1 : 0; 01183 01184 switch (event->keyval) { 01185 case GDK_Alt_L: 01186 case GDK_Alt_R: 01187 alt_key = 1; 01188 w_current->ALTKEY = pressed; 01189 break; 01190 01191 case GDK_Shift_L: 01192 case GDK_Shift_R: 01193 shift_key = 1; 01194 w_current->SHIFTKEY = pressed; 01195 break; 01196 01197 case GDK_Control_L: 01198 case GDK_Control_R: 01199 control_key = 1; 01200 w_current->CONTROLKEY = pressed; 01201 break; 01202 } 01203 01204 01205 /* Huge switch statement to evaluate state transitions. Jump to 01206 * end_key label to escape the state evaluation rather 01207 * than returning from the function directly. */ 01208 scm_dynwind_begin (0); 01209 g_dynwind_window (w_current); 01210 01211 switch (w_current->event_state) { 01212 case ENDLINE: 01213 if (control_key) { 01214 get_snapped_pointer (w_current, &wx, &wy); 01215 o_line_motion (w_current, wx, wy); 01216 } 01217 break; 01218 case STARTDRAWNET: 01219 if (control_key) { 01220 get_snapped_pointer (w_current, &wx, &wy); 01221 o_net_start_magnetic(w_current, wx, wy); 01222 } 01223 break; 01224 case DRAWNET: 01225 case NETCONT: 01226 if (shift_key || control_key) { 01227 get_snapped_pointer (w_current, &wx, &wy); 01228 o_net_motion (w_current, wx, wy); 01229 } 01230 break; 01231 case DRAWBUS: 01232 case BUSCONT: 01233 if (control_key) { 01234 get_snapped_pointer (w_current, &wx, &wy); 01235 o_bus_motion (w_current, wx, wy); 01236 } 01237 break; 01238 case ENDMOVE: 01239 if (control_key) { 01240 get_snapped_pointer (w_current, &wx, &wy); 01241 o_move_motion (w_current, wx, wy); 01242 } 01243 break; 01244 case ENDCOMP: /* FIXME: This state shouldn't respond to modifier keys */ 01245 case ENDPASTE: /* FIXME: This state shouldn't respond to modifier keys */ 01246 case ENDTEXT: /* FIXME: This state shouldn't respond to modifier keys */ 01247 case ENDCOPY: 01248 case ENDMCOPY: 01249 if (control_key) { 01250 get_snapped_pointer (w_current, &wx, &wy); 01251 o_place_motion (w_current, wx, wy); 01252 } 01253 break; 01254 } 01255 01256 if (pressed) 01257 retval = g_keys_execute (w_current, event) ? TRUE : FALSE; 01258 01259 scm_dynwind_end (); 01260 01261 return retval; 01262 } 01263 01264 01270 gint x_event_scroll (GtkWidget *widget, GdkEventScroll *event, 01271 GSCHEM_TOPLEVEL *w_current) 01272 { 01273 GtkAdjustment *adj; 01274 gboolean pan_xaxis = FALSE; 01275 gboolean pan_yaxis = FALSE; 01276 gboolean zoom = FALSE; 01277 int pan_direction = 1; 01278 int zoom_direction = ZOOM_IN; 01279 01280 g_return_val_if_fail ((w_current != NULL), 0); 01281 01282 /* update the state of the modifiers */ 01283 w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK ) ? 1 : 0; 01284 w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; 01285 w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; 01286 01287 if (w_current->scroll_wheel == SCROLL_WHEEL_CLASSIC) { 01288 /* Classic gschem behaviour */ 01289 zoom = !w_current->CONTROLKEY && !w_current->SHIFTKEY; 01290 pan_yaxis = !w_current->CONTROLKEY && w_current->SHIFTKEY; 01291 pan_xaxis = w_current->CONTROLKEY && !w_current->SHIFTKEY; 01292 } else { 01293 /* GTK style behaviour */ 01294 zoom = w_current->CONTROLKEY && !w_current->SHIFTKEY; 01295 pan_yaxis = !w_current->CONTROLKEY && !w_current->SHIFTKEY; 01296 pan_xaxis = !w_current->CONTROLKEY && w_current->SHIFTKEY; 01297 } 01298 01299 /* If the user has a left/right scroll wheel, always scroll the y-axis */ 01300 if (event->direction == GDK_SCROLL_LEFT || 01301 event->direction == GDK_SCROLL_RIGHT) { 01302 zoom = FALSE; 01303 pan_yaxis = FALSE; 01304 pan_xaxis = TRUE; 01305 } 01306 01307 /* You must have scrollbars enabled if you want to use the scroll wheel to pan */ 01308 if (!w_current->scrollbars_flag) { 01309 pan_xaxis = FALSE; 01310 pan_yaxis = FALSE; 01311 } 01312 01313 switch (event->direction) { 01314 case GDK_SCROLL_UP: 01315 case GDK_SCROLL_LEFT: 01316 pan_direction = -1; 01317 zoom_direction = ZOOM_IN; 01318 break; 01319 case GDK_SCROLL_DOWN: 01320 case GDK_SCROLL_RIGHT: 01321 pan_direction = 1; 01322 zoom_direction = ZOOM_OUT; 01323 break; 01324 } 01325 01326 if (zoom) { 01328 a_zoom(w_current, zoom_direction, HOTKEY, 0); 01329 } 01330 01331 if (pan_xaxis) { 01332 adj = gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar)); 01333 gtk_adjustment_set_value(adj, min(adj->value + pan_direction * 01334 (adj->page_increment / 01335 w_current->scrollpan_steps), 01336 adj->upper - adj->page_size)); 01337 } 01338 01339 if (pan_yaxis) { 01340 adj = gtk_range_get_adjustment(GTK_RANGE(w_current->v_scrollbar)); 01341 gtk_adjustment_set_value(adj, min(adj->value + pan_direction * 01342 (adj->page_increment / 01343 w_current->scrollpan_steps), 01344 adj->upper - adj->page_size)); 01345 } 01346 01347 if (w_current->undo_panzoom && (zoom || pan_xaxis || pan_yaxis)) { 01348 o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY); 01349 } 01350 01351 return 0; 01352 } 01353 01354 01369 gboolean x_event_get_pointer_position (GSCHEM_TOPLEVEL *w_current, 01370 gboolean snapped, 01371 gint *wx, gint *wy) 01372 { 01373 int sx, sy, x, y; 01374 01375 gtk_widget_get_pointer(w_current->drawing_area, &sx, &sy); 01376 01377 /* check if we are inside the drawing area */ 01378 if (sx < 0 || sx >= w_current->win_width 01379 || sy <0 || sy >= w_current->win_height) 01380 return FALSE; 01381 01382 SCREENtoWORLD (w_current, sx, sy, &x, &y); 01383 if (snapped) { 01384 x = snap_grid (w_current, x); 01385 y = snap_grid (w_current, y); 01386 } 01387 *wx = x; 01388 *wy = y; 01389 01390 return TRUE; 01391 }