gschem

o_select.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  */
00031 #include <config.h>
00032 
00033 #include <math.h>
00034 #include <stdio.h>
00035 #ifdef HAVE_STRING_H
00036 #include <string.h>
00037 #endif
00038 
00039 #include "gschem.h"
00040 
00041 #ifdef HAVE_LIBDMALLOC
00042 #include <dmalloc.h>
00043 #endif
00044 
00050 void o_select_run_hooks(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current, int flag)
00051 {
00052   switch (flag) {
00053   /* If flag == 0, then we are deselecting something. */
00054   case 0:
00055     g_run_hook_object (w_current, "%deselect-objects-hook", o_current);
00056     break;
00057   /* If flag == 1, then we are selecting something. */
00058   case 1:
00059     g_run_hook_object (w_current, "%select-objects-hook", o_current);
00060     break;
00061   default:
00062     g_assert_not_reached ();
00063   }
00064 }
00065 
00074 void o_select_object(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
00075              int type, int count)
00076 {
00077   TOPLEVEL *toplevel = w_current->toplevel;
00078   int SHIFTKEY;
00079   int CONTROLKEY;
00080   int removing_obj = 0;
00081 
00082   SHIFTKEY = w_current->SHIFTKEY;
00083   CONTROLKEY = w_current->CONTROLKEY;
00084 
00085 #if DEBUG 
00086   printf("OBJECT id: %d\n", o_current->sid);
00087 #endif
00088 
00089   switch(o_current->selected) {
00090 
00091     case(FALSE): /* object not selected */
00092 
00093       switch(SHIFTKEY) { /* shift key pressed? */
00094 
00095         case(TRUE): /* shift key pressed */
00096           /* just fall through */
00097           break;
00098 
00099         case(FALSE):
00100 
00101           /* condition: first object being added */
00102           /* condition: control key not pressed */
00103           /* condition: for both multiple and single object added */
00104           /* result: remove all objects from selection */
00105           if (count == 0 && !CONTROLKEY) {
00106             o_select_unselect_all(w_current);
00107           }
00108           break;
00109 
00110       } /* end shift key switch */
00111 
00112       /* object not select, add it to the selection list */
00113       o_select_run_hooks( w_current, o_current, 1 );
00114       o_selection_add (toplevel,
00115                        toplevel->page_current->selection_list, o_current);
00116 
00117       break;
00118 
00119 
00120     case(TRUE): /* object was already selected */
00121 
00122       switch(SHIFTKEY) { /* shift key pressed ? */
00123 
00124         case(TRUE): /* shift key pressed */
00125 
00126           /* condition: not doing multiple */
00127           /* result: remove object from selection */
00128           if (type != MULTIPLE) {
00129             o_select_run_hooks( w_current, o_current, 0 );
00130             o_selection_remove (toplevel, toplevel->page_current->
00131                                             selection_list, o_current);
00132             removing_obj = 1;
00133           }
00134 
00135           break;
00136 
00137         case(FALSE): /* shift key not pressed */
00138 
00139           /* condition: doing multiple */
00140           /* condition: first object being added */
00141           /* condition: control key not pressed */
00142           /* 1st result: remove all objects from selection */
00143           /* 2nd result: add object to selection */
00144           if (type == MULTIPLE && count == 0 && !CONTROLKEY) {
00145             o_select_unselect_all (w_current);
00146 
00147             o_select_run_hooks( w_current, o_current, 1 );
00148             o_selection_add (toplevel,
00149                              toplevel->page_current->selection_list, o_current);
00150           } 
00151 
00152           /* condition: doing single object add */
00153           /* condition: control key not pressed */
00154           /* 1st result: remove all objects from selection */
00155           /* 2nd result: add object to selection list */
00156           if (type == SINGLE && !CONTROLKEY) {
00157             o_select_unselect_all (w_current);
00158 
00159             o_select_run_hooks (w_current, o_current, 1);
00160             o_selection_add (toplevel, toplevel->page_current->
00161                                          selection_list, o_current);
00162           }
00163 
00164           if (CONTROLKEY) {
00165             o_select_run_hooks(w_current, o_current, 0);
00166             o_selection_remove (toplevel, toplevel->page_current->
00167                                             selection_list, o_current);
00168             removing_obj = 1;
00169           }
00170 
00171           break;
00172       } 
00173       break; /* end object selected switch */
00174   }
00175 
00176   /* do the attributes */
00177   if (removing_obj) {
00178     /* Remove the invisible attributes from the object list as well,
00179      * so they don't remain selected without the user knowing.
00180      */
00181     o_attrib_deselect_invisible (w_current,
00182                                  toplevel->page_current->selection_list,
00183                                  o_current);
00184   } else {
00185     /* If the type is MULTIPLE (meaning a select box was/is being used), only
00186      * select invisible attributes on objects.  Otherwise attributes will be
00187      * "double selected", causing them to remain unselected if using
00188      * invert-selection (CONTROLKEY is pressed)
00189      */
00190     if( type == MULTIPLE) {
00191       o_attrib_select_invisible (w_current,
00192                                  toplevel->page_current->selection_list,
00193                                  o_current);
00194     } else {
00195       /* Select all attributes of the object for a single click select */
00196       o_attrib_add_selected (w_current, toplevel->page_current->selection_list,
00197                              o_current);
00198     }
00199   }
00200 }
00201 
00207 int o_select_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00208 {
00209   int diff_x, diff_y;
00210 
00211   diff_x = abs(w_current->first_wx - w_x);
00212   diff_y = abs(w_current->first_wy - w_y);
00213 
00214   /* if we are still close to the button press location,
00215      then don't enter the selection box mode */
00216   if (SCREENabs (w_current, max(diff_x, diff_y)) < 10) {
00217     return FALSE;
00218   }
00219 
00220   w_current->second_wx = w_x;
00221   w_current->second_wy = w_y;
00222   return TRUE;
00223 }
00224 
00230 void o_select_box_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00231 {
00232   o_select_box_invalidate_rubber (w_current);
00233   w_current->rubber_visible = 0;
00234 
00235   o_select_box_search(w_current);
00236 }
00237 
00243 void o_select_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00244 {
00245   if (w_current->rubber_visible)
00246     o_select_box_invalidate_rubber (w_current);
00247     
00248   w_current->second_wx = w_x; 
00249   w_current->second_wy = w_y;
00250 
00251   o_select_box_invalidate_rubber (w_current);
00252   w_current->rubber_visible = 1;
00253 }
00254 
00259 void o_select_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
00260 {
00261   int x1, y1, x2, y2;
00262 
00263   WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1);
00264   WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2);
00265 
00266   o_invalidate_rect (w_current, x1, y1, x2, y1);
00267   o_invalidate_rect (w_current, x1, y1, x1, y2);
00268   o_invalidate_rect (w_current, x2, y1, x2, y2);
00269   o_invalidate_rect (w_current, x1, y2, x2, y2);
00270 }
00271 
00277 void o_select_box_draw_rubber (GSCHEM_TOPLEVEL *w_current)
00278 {
00279   gschem_cairo_box (w_current, 0,
00280                     w_current->first_wx, w_current->first_wy,
00281                     w_current->second_wx, w_current->second_wy);
00282 
00283   gschem_cairo_set_source_color (w_current,
00284                                  x_color_lookup_dark (SELECT_COLOR));
00285   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
00286 }
00287 
00293 void o_select_box_search(GSCHEM_TOPLEVEL *w_current)
00294 {
00295   TOPLEVEL *toplevel = w_current->toplevel;
00296   OBJECT *o_current=NULL;
00297   int count = 0; /* object count */
00298   int SHIFTKEY = w_current->SHIFTKEY;
00299   int CONTROLKEY = w_current->CONTROLKEY;
00300   int left, right, top, bottom;
00301   const GList *iter;
00302     
00303   left = min(w_current->first_wx, w_current->second_wx);
00304   right = max(w_current->first_wx, w_current->second_wx);
00305   top = min(w_current->first_wy, w_current->second_wy);
00306   bottom = max(w_current->first_wy, w_current->second_wy);
00307 
00308   iter = s_page_objects (toplevel->page_current);
00309   while (iter != NULL) {
00310     o_current = iter->data;
00311     /* only select visible objects */
00312     if (o_is_visible (toplevel, o_current) || toplevel->show_hidden_text) {
00313 
00314       if ( o_current->w_left   >= left &&
00315            o_current->w_right  <= right  &&
00316            o_current->w_top    >= top  &&
00317            o_current->w_bottom <= bottom ) {
00318 
00319         o_select_object(w_current, o_current, MULTIPLE, count);
00320         count++;
00321       }
00322     }
00323     iter = g_list_next (iter);
00324   }
00325 
00326   /* if there were no objects to be found in select box, count will be */
00327   /* zero, and you need to deselect anything remaining (except when the */
00328   /* shift or control keys are pressed) */
00329   if (count == 0 && !SHIFTKEY && !CONTROLKEY) {
00330     o_select_unselect_all (w_current);
00331   }
00332   i_update_menus(w_current);
00333 }
00334 
00343 void o_select_connected_nets(GSCHEM_TOPLEVEL *w_current, OBJECT* o_net)
00344 {
00345   TOPLEVEL *toplevel = w_current->toplevel;
00346   const GList *o_iter;
00347   GList *iter1;
00348   OBJECT *o_current;
00349   int count=0;
00350   gchar* netname;
00351 
00352   GList *netstack = NULL;
00353   GList *netnamestack = NULL;
00354   GList *netnameiter;
00355 
00356   g_assert(o_net->type == OBJ_NET);
00357 
00358   if (!o_net->selected) {
00359     w_current->net_selection_state = 1;
00360   }
00361 
00362   /* the current net is the startpoint for the stack */
00363   netstack = g_list_prepend(netstack, o_net);
00364 
00365   count = 0; 
00366   while (1) {
00367     netnameiter = g_list_last(netnamestack);
00368     for (iter1 = g_list_last(netstack);
00369      iter1 != NULL; 
00370      iter1 = g_list_previous(iter1), count++) {
00371       o_current = iter1->data;
00372       if (o_current->type == OBJ_NET && 
00373       (!o_current->selected || count == 0)) {
00374     o_select_object (w_current, o_current, SINGLE, count);
00375     if (w_current->net_selection_state > 1) {
00376       /* collect nets */
00377       netstack = g_list_concat(s_conn_return_others(NULL, o_current), netstack);
00378     }
00379     if (w_current->net_selection_state > 2) {
00380       /* collect netnames */
00381       netname = o_attrib_search_object_attribs_by_name (o_current, "netname", 0);
00382       if (netname != NULL) {
00383         if (g_list_find_custom(netnamestack, netname, (GCompareFunc) strcmp) == NULL) {
00384           netnamestack = g_list_append(netnamestack, netname);
00385         }
00386         else {
00387           g_free(netname);
00388         }
00389       }
00390     }
00391       }
00392     }
00393     g_list_free(netstack);
00394     netstack = NULL;
00395 
00396     if (netnameiter == g_list_last(netnamestack))
00397       break; /* no new netnames in the stack --> finished */
00398 
00399     /* get all the nets of the stacked netnames */
00400     for (o_iter = s_page_objects (toplevel->page_current);
00401          o_iter != NULL;
00402          o_iter = g_list_next (o_iter)) {
00403       o_current = o_iter->data;
00404       if (o_current->type == OBJ_TEXT
00405       && o_current->attached_to != NULL) {
00406     if (o_current->attached_to->type == OBJ_NET) {
00407       netname = o_attrib_search_object_attribs_by_name (o_current->attached_to, "netname", 0);
00408       if (netname != NULL) {
00409         if (g_list_find_custom(netnamestack, netname, (GCompareFunc) strcmp) != NULL) {
00410           netstack = g_list_prepend(netstack, o_current->attached_to);
00411         }
00412         g_free(netname);
00413       }
00414     }
00415       }
00416     }
00417   }
00418 
00419   w_current->net_selection_state += 1;
00420   if (w_current->net_selection_state > w_current->net_selection_mode)
00421     w_current->net_selection_state = 1;
00422 
00423   for (iter1 = netnamestack; iter1 != NULL; iter1 = g_list_next(iter1))
00424     g_free(iter1->data);
00425   g_list_free(netnamestack);
00426 }
00427 
00428 /* This is a wrapper for o_selection_return_first_object */
00429 /* This function always looks at the current page selection list */ 
00430 OBJECT *o_select_return_first_object(GSCHEM_TOPLEVEL *w_current)
00431 {
00432   TOPLEVEL *toplevel = w_current->toplevel;
00433   if (! (w_current && toplevel->page_current && geda_list_get_glist( toplevel->page_current->selection_list )))
00434     return NULL;
00435   else
00436     return (OBJECT *)g_list_first( geda_list_get_glist( toplevel->page_current->selection_list ))->data;
00437 }
00438 
00446 int o_select_selected(GSCHEM_TOPLEVEL *w_current)
00447 {
00448   TOPLEVEL *toplevel = w_current->toplevel;
00449   if ( geda_list_get_glist( toplevel->page_current->selection_list )) {
00450     return(TRUE);
00451   }
00452   return(FALSE);
00453 }
00454 
00455 
00461 void o_select_unselect_all(GSCHEM_TOPLEVEL *w_current)
00462 {
00463   TOPLEVEL *toplevel = w_current->toplevel;
00464   SELECTION *selection = toplevel->page_current->selection_list;
00465   GList *removed = NULL;
00466   GList *iter;
00467 
00468   removed = g_list_copy (geda_list_get_glist (selection));
00469   for (iter = removed; iter != NULL; iter = g_list_next (iter)) {
00470     o_selection_remove (toplevel, selection, (OBJECT *) iter->data);
00471   }
00472 
00473   /* Call hooks */
00474   if (removed != NULL) {
00475     g_run_hook_object_list (w_current, "%deselect-objects-hook", removed);
00476   }
00477 }
00478 
00487 void
00488 o_select_visible_unlocked (GSCHEM_TOPLEVEL *w_current)
00489 {
00490   TOPLEVEL *toplevel = w_current->toplevel;
00491   SELECTION *selection = toplevel->page_current->selection_list;
00492   const GList *iter;
00493   GList *added;
00494 
00495   o_select_unselect_all (w_current);
00496   for (iter = s_page_objects (toplevel->page_current);
00497        iter != NULL;
00498        iter = g_list_next (iter)) {
00499     OBJECT *obj = (OBJECT *) iter->data;
00500 
00501     /* Skip invisible objects. */
00502     if (!o_is_visible (toplevel, obj) && !toplevel->show_hidden_text)
00503       continue;
00504 
00505     /* Skip locked objects. */
00506     if (!obj->selectable) continue;
00507 
00508     /* Add object to selection. */
00514     o_selection_add (toplevel, selection, obj);
00515 
00516     /* Add any attributes of object to selection as well. */
00517     o_attrib_add_selected (w_current, selection, obj);
00518   }
00519 
00520   /* Run hooks for all items selected */
00521   added = geda_list_get_glist (selection);
00522   if (added != NULL) {
00523     g_run_hook_object_list (w_current, "%select-objects-hook", added);
00524   }
00525 }
00526 
00532 void
00533 o_select_move_to_place_list(GSCHEM_TOPLEVEL *w_current)
00534 {
00535   TOPLEVEL *toplevel = w_current->toplevel;
00536   GList *selection;
00537   GList *selection_copy;
00538 
00539   /* remove the old place list if it exists */
00540   s_delete_object_glist(toplevel, toplevel->page_current->place_list);
00541   toplevel->page_current->place_list = NULL;
00542 
00543   selection = geda_list_get_glist( toplevel->page_current->selection_list );
00544   selection_copy = g_list_copy( selection );
00545   toplevel->page_current->place_list = selection_copy;
00546 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines