Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / o_select.c
blobf598444c6c1a690533ddff788ccbf152defc05f1
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 /*! The code in this file is sometimes not obvious, especially
21 * o_select_object (which implements the selection of objects either
22 * when doing a single or multi select)
24 * Also, there are cases where it looks like there is redundant code, which
25 * could be removed/merged, but I purposely didn't do so to keep the code
26 * readable
28 * the count == 0 stuff really only applies to when you are coming from a
29 * multi select case
31 #include <config.h>
33 #include <math.h>
34 #include <stdio.h>
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
39 #include "gschem.h"
41 #ifdef HAVE_LIBDMALLOC
42 #include <dmalloc.h>
43 #endif
45 /*! \todo Finish function documentation!!!
46 * \brief
47 * \par Function Description
50 void o_select_run_hooks(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current, int flag)
53 * Run the select_component_hook if the hook has been defined and we
54 * are selecting a component. This will likely be used for cross probing
55 * between schematics and PCB layout or schematics and simulation results.
57 if ( (scm_hook_empty_p(deselect_all_hook) == SCM_BOOL_F)
58 && flag == 2 )
60 scm_run_hook(deselect_all_hook,
61 scm_cons (g_make_attrib_smob_list(w_current, o_current),
62 SCM_EOL));
66 * Run the select_component_hook if the hook has been defined and we
67 * are selecting a component. This will likely be used for cross probing
68 * between schematics and PCB layout or schematics and simulation results.
70 if ( (scm_hook_empty_p(select_component_hook) == SCM_BOOL_F)
71 && o_current
72 && (o_current->type == OBJ_COMPLEX)
73 && flag == 1 )
75 scm_run_hook(select_component_hook,
76 scm_cons (g_make_attrib_smob_list(w_current, o_current),
77 SCM_EOL));
81 * Run the deselect_component_hook if the hook has been defined and we
82 * are deselecting a component. This will likely be used for cross probing
83 * between schematics and PCB layout or schematics and simulation results.
85 if ( (scm_hook_empty_p(deselect_component_hook) == SCM_BOOL_F)
86 && o_current
87 && (o_current->type == OBJ_COMPLEX)
88 && flag == 0 )
90 scm_run_hook(deselect_component_hook,
91 scm_cons (g_make_attrib_smob_list(w_current, o_current),
92 SCM_EOL));
96 * Run the select_net_hook if the hook has been defined and we
97 * are selecting a net. This will likely be used for cross probing
98 * between schematics and PCB layout or schematics and simulation results.
100 if ( (scm_hook_empty_p(select_net_hook) == SCM_BOOL_F)
101 && o_current
102 && (o_current->type == OBJ_NET)
103 && flag == 1)
105 scm_run_hook(select_net_hook,
106 scm_cons (g_make_attrib_smob_list(w_current, o_current),
107 SCM_EOL));
111 * Run the deselect_net_hook if the hook has been defined and we
112 * are deselecting a net. This will likely be used for cross probing
113 * between schematics and PCB layout or schematics and simulation results.
115 if ( (scm_hook_empty_p(select_net_hook) == SCM_BOOL_F)
116 && o_current
117 && (o_current->type == OBJ_NET)
118 && flag == 0)
120 scm_run_hook(deselect_net_hook,
121 scm_cons (g_make_attrib_smob_list(w_current, o_current),
122 SCM_EOL));
126 /*! \todo Finish function documentation!!!
127 * \brief
128 * \par Function Description
130 * \note
131 * type can be either SINGLE meaning selection is a single mouse click
132 * or it can be MULTIPLE meaning selection is a selection box
134 void o_select_object(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
135 int type, int count)
137 TOPLEVEL *toplevel = w_current->toplevel;
138 int SHIFTKEY;
139 int CONTROLKEY;
140 int removing_obj = 0;
142 SHIFTKEY = w_current->SHIFTKEY;
143 CONTROLKEY = w_current->CONTROLKEY;
145 #if DEBUG
146 printf("OBJECT id: %d\n", o_current->sid);
147 #endif
149 switch(o_current->selected) {
151 case(FALSE): /* object not selected */
153 switch(SHIFTKEY) { /* shift key pressed? */
155 case(TRUE): /* shift key pressed */
156 /* just fall through */
157 break;
159 case(FALSE):
161 /* condition: first object being added */
162 /* condition: control key not pressed */
163 /* condition: for both multiple and single object added */
164 /* result: remove all objects from selection */
165 if (count == 0 && !CONTROLKEY) {
166 o_select_run_hooks( w_current, NULL, 2 );
167 o_select_unselect_list( w_current, toplevel->page_current->selection_list );
169 break;
171 } /* end shift key switch */
173 /* object not select, add it to the selection list */
174 o_select_run_hooks( w_current, o_current, 1 );
175 o_selection_add (toplevel,
176 toplevel->page_current->selection_list, o_current);
178 break;
181 case(TRUE): /* object was already selected */
183 switch(SHIFTKEY) { /* shift key pressed ? */
185 case(TRUE): /* shift key pressed */
187 /* condition: not doing multiple */
188 /* result: remove object from selection */
189 if (type != MULTIPLE) {
190 o_select_run_hooks( w_current, o_current, 0 );
191 o_selection_remove (toplevel, toplevel->page_current->
192 selection_list, o_current);
193 removing_obj = 1;
196 break;
198 case(FALSE): /* shift key not pressed */
200 /* condition: doing multiple */
201 /* condition: first object being added */
202 /* condition: control key not pressed */
203 /* 1st result: remove all objects from selection */
204 /* 2nd result: add object to selection */
205 if (type == MULTIPLE && count == 0 && !CONTROLKEY) {
206 o_select_run_hooks( w_current, NULL, 2 );
207 o_select_unselect_list( w_current, toplevel->page_current->selection_list );
209 o_select_run_hooks( w_current, o_current, 1 );
210 o_selection_add (toplevel,
211 toplevel->page_current->selection_list, o_current);
214 /* condition: doing single object add */
215 /* condition: control key not pressed */
216 /* 1st result: remove all objects from selection */
217 /* 2nd result: add object to selection list */
218 if (type == SINGLE && !CONTROLKEY) {
219 o_select_run_hooks( w_current, NULL, 2 );
220 o_select_unselect_list( w_current, toplevel->page_current->selection_list );
222 o_select_run_hooks (w_current, o_current, 1);
223 o_selection_add (toplevel, toplevel->page_current->
224 selection_list, o_current);
227 if (CONTROLKEY) {
228 o_select_run_hooks(w_current, o_current, 0);
229 o_selection_remove (toplevel, toplevel->page_current->
230 selection_list, o_current);
231 removing_obj = 1;
234 break;
236 break; /* end object selected switch */
239 /* do the attributes */
240 if (removing_obj) {
241 /* Remove the invisible attributes from the object list as well,
242 * so they don't remain selected without the user knowing.
244 o_attrib_remove_selected_invisible (w_current,
245 toplevel->page_current->selection_list,
246 o_current);
247 } else {
248 o_attrib_add_selected (w_current, toplevel->page_current->selection_list,
249 o_current);
252 /* finally redraw object */
253 o_invalidate (w_current, o_current);
256 /*! \todo Finish function documentation!!!
257 * \brief
258 * \par Function Description
261 int o_select_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
263 int diff_x, diff_y;
265 diff_x = abs(w_current->first_wx - w_x);
266 diff_y = abs(w_current->first_wy - w_y);
268 /* if we are still close to the button press location,
269 then don't enter the selection box mode */
270 if (SCREENabs (w_current, max(diff_x, diff_y)) < 10) {
271 return FALSE;
274 w_current->second_wx = w_x;
275 w_current->second_wy = w_y;
276 return TRUE;
279 /*! \todo Finish function documentation!!!
280 * \brief
281 * \par Function Description
284 void o_select_box_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
286 o_select_box_invalidate_rubber (w_current);
287 w_current->rubber_visible = 0;
289 o_select_box_search(w_current);
292 /*! \todo Finish function documentation!!!
293 * \brief
294 * \par Function Description
297 void o_select_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
299 if (w_current->rubber_visible)
300 o_select_box_invalidate_rubber (w_current);
302 w_current->second_wx = w_x;
303 w_current->second_wy = w_y;
305 o_select_box_invalidate_rubber (w_current);
306 w_current->rubber_visible = 1;
309 /*! \todo Finish function documentation!!!
310 * \brief
311 * \par Function Description
313 void o_select_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
315 int x1, y1, x2, y2;
317 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1);
318 WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2);
320 o_invalidate_rect (w_current, x1, y1, x2, y1);
321 o_invalidate_rect (w_current, x1, y1, x1, y2);
322 o_invalidate_rect (w_current, x2, y1, x2, y2);
323 o_invalidate_rect (w_current, x1, y2, x2, y2);
326 /*! \todo Finish function documentation!!!
327 * \brief
328 * \par Function Description
331 void o_select_box_draw_rubber (GSCHEM_TOPLEVEL *w_current)
333 gschem_cairo_box (w_current, 0,
334 w_current->first_wx, w_current->first_wy,
335 w_current->second_wx, w_current->second_wy);
337 gschem_cairo_set_source_color (w_current,
338 x_color_lookup_dark (SELECT_COLOR));
339 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
342 /*! \todo Finish function documentation!!!
343 * \brief
344 * \par Function Description
347 void o_select_box_search(GSCHEM_TOPLEVEL *w_current)
349 TOPLEVEL *toplevel = w_current->toplevel;
350 OBJECT *o_current=NULL;
351 int count = 0; /* object count */
352 int SHIFTKEY = w_current->SHIFTKEY;
353 int left, right, top, bottom;
354 const GList *iter;
356 left = min(w_current->first_wx, w_current->second_wx);
357 right = max(w_current->first_wx, w_current->second_wx);
358 top = min(w_current->first_wy, w_current->second_wy);
359 bottom = max(w_current->first_wy, w_current->second_wy);
361 iter = s_page_objects (toplevel->page_current);
362 while (iter != NULL) {
363 o_current = iter->data;
364 /* only select visible objects */
365 if (o_current->visibility == VISIBLE || toplevel->show_hidden_text) {
367 if ( o_current->w_left >= left &&
368 o_current->w_right <= right &&
369 o_current->w_top >= top &&
370 o_current->w_bottom <= bottom ) {
372 o_select_object(w_current, o_current, MULTIPLE, count);
373 count++;
376 iter = g_list_next (iter);
379 /* if there were no objects to be found in select box, count will be */
380 /* zero, and you need to deselect anything remaining (unless the shift */
381 /* key was pressed */
382 if (count == 0 && !SHIFTKEY) {
383 o_select_run_hooks( w_current, NULL, 2 );
384 o_select_unselect_list( w_current, toplevel->page_current->selection_list );
386 i_update_menus(w_current);
389 /*! \brief Select all nets connected to the current net
390 * \par Depending on the state of the w_current->net_selection_mode variable
391 * and the net_selection_state of the current net this function will either
392 * select the single net, all directly connected nets or all nets connected
393 * with netname labels.
394 * \param [in] w_current GSCHEM_TOPLEVEL struct.
395 * \param [in] o_net Pointer to a single net object
397 void o_select_connected_nets(GSCHEM_TOPLEVEL *w_current, OBJECT* o_net)
399 TOPLEVEL *toplevel = w_current->toplevel;
400 const GList *o_iter;
401 GList *iter1;
402 OBJECT *o_current;
403 int count=0;
404 gchar* netname;
406 GList *netstack = NULL;
407 GList *netnamestack = NULL;
408 GList *netnameiter;
410 g_assert(o_net->type == OBJ_NET);
412 if (!o_net->selected) {
413 w_current->net_selection_state = 1;
416 /* the current net is the startpoint for the stack */
417 netstack = g_list_prepend(netstack, o_net);
419 count = 0;
420 while (1) {
421 netnameiter = g_list_last(netnamestack);
422 for (iter1 = g_list_last(netstack);
423 iter1 != NULL;
424 iter1 = g_list_previous(iter1), count++) {
425 o_current = iter1->data;
426 if (o_current->type == OBJ_NET &&
427 (!o_current->selected || count == 0)) {
428 (*o_current->sel_func)(w_current, o_current, SINGLE, count);
429 if (w_current->net_selection_state > 1) {
430 /* collect nets */
431 netstack = g_list_concat(s_conn_return_others(NULL, o_current), netstack);
433 if (w_current->net_selection_state > 2) {
434 /* collect netnames */
435 netname = o_attrib_search_object_attribs_by_name (o_current, "netname", 0);
436 if (netname != NULL) {
437 if (g_list_find_custom(netnamestack, netname, (GCompareFunc) strcmp) == NULL) {
438 netnamestack = g_list_append(netnamestack, netname);
440 else {
441 g_free(netname);
447 g_list_free(netstack);
448 netstack = NULL;
450 if (netnameiter == g_list_last(netnamestack))
451 break; /* no new netnames in the stack --> finished */
453 /* get all the nets of the stacked netnames */
454 for (o_iter = s_page_objects (toplevel->page_current);
455 o_iter != NULL;
456 o_iter = g_list_next (o_iter)) {
457 o_current = o_iter->data;
458 if (o_current->type == OBJ_TEXT
459 && o_current->attached_to != NULL) {
460 if (o_current->attached_to->type == OBJ_NET) {
461 netname = o_attrib_search_object_attribs_by_name (o_current->attached_to, "netname", 0);
462 if (netname != NULL) {
463 if (g_list_find_custom(netnamestack, netname, (GCompareFunc) strcmp) != NULL) {
464 netstack = g_list_prepend(netstack, o_current->attached_to);
466 g_free(netname);
473 w_current->net_selection_state += 1;
474 if (w_current->net_selection_state > w_current->net_selection_mode)
475 w_current->net_selection_state = 1;
477 for (iter1 = netnamestack; iter1 != NULL; iter1 = g_list_next(iter1))
478 g_free(iter1->data);
479 g_list_free(netnamestack);
482 /* This is a wrapper for o_selection_return_first_object */
483 /* This function always looks at the current page selection list */
484 OBJECT *o_select_return_first_object(GSCHEM_TOPLEVEL *w_current)
486 TOPLEVEL *toplevel = w_current->toplevel;
487 if (! (w_current && toplevel->page_current && geda_list_get_glist( toplevel->page_current->selection_list )))
488 return NULL;
489 else
490 return (OBJECT *)g_list_first( geda_list_get_glist( toplevel->page_current->selection_list ))->data;
493 /*! \todo Finish function documentation!!!
494 * \brief
495 * \par Function Description
497 * \return TRUE if the selection list is not empty, otherwise false.
498 * also make sure item is valid
500 int o_select_selected(GSCHEM_TOPLEVEL *w_current)
502 TOPLEVEL *toplevel = w_current->toplevel;
503 if ( geda_list_get_glist( toplevel->page_current->selection_list )) {
504 return(TRUE);
506 return(FALSE);
510 /*! \brief Unselects all the objects in the given list.
511 * \par Unselects all objects in the given list, does the
512 * needed work to make the objects visually unselected, and redraw them.
513 * \param [in] w_current GSCHEM_TOPLEVEL struct.
514 * \param [in] selection Pointer to the selection list
516 void o_select_unselect_list(GSCHEM_TOPLEVEL *w_current, SELECTION *selection)
518 const GList *list = geda_list_get_glist( selection );
520 while ( list != NULL ) {
521 o_selection_unselect (w_current->toplevel, (OBJECT *)list->data);
522 o_invalidate (w_current, (OBJECT *)list->data);
523 list = g_list_next( list );
526 geda_list_remove_all( (GedaList *)selection );
530 /*! \todo Finish function documentation!!!
531 * \brief
532 * \par Function Description
535 void o_select_unselect_all(GSCHEM_TOPLEVEL *w_current)
537 TOPLEVEL *toplevel = w_current->toplevel;
538 o_select_run_hooks( w_current, NULL, 2 );
539 o_select_unselect_list( w_current, toplevel->page_current->selection_list );
542 /*! \todo Finish function documentation!!!
543 * \brief
544 * \par Function Description
547 void
548 o_select_move_to_place_list(GSCHEM_TOPLEVEL *w_current)
550 TOPLEVEL *toplevel = w_current->toplevel;
551 GList *selection;
552 GList *selection_copy;
554 /* remove the old place list if it exists */
555 s_delete_object_glist(toplevel, toplevel->page_current->place_list);
556 toplevel->page_current->place_list = NULL;
558 selection = geda_list_get_glist( toplevel->page_current->selection_list );
559 selection_copy = g_list_copy( selection );
560 toplevel->page_current->place_list = selection_copy;