gschem

x_event.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines