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 */ 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 }