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
28 * the count == 0 stuff really only applies to when you are coming from a
41 #ifdef HAVE_LIBDMALLOC
45 /*! \todo Finish function documentation!!!
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
)
60 scm_run_hook(deselect_all_hook
,
61 scm_cons (g_make_attrib_smob_list(w_current
, o_current
),
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
)
72 && (o_current
->type
== OBJ_COMPLEX
)
75 scm_run_hook(select_component_hook
,
76 scm_cons (g_make_attrib_smob_list(w_current
, o_current
),
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
)
87 && (o_current
->type
== OBJ_COMPLEX
)
90 scm_run_hook(deselect_component_hook
,
91 scm_cons (g_make_attrib_smob_list(w_current
, o_current
),
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
)
102 && (o_current
->type
== OBJ_NET
)
105 scm_run_hook(select_net_hook
,
106 scm_cons (g_make_attrib_smob_list(w_current
, o_current
),
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
)
117 && (o_current
->type
== OBJ_NET
)
120 scm_run_hook(deselect_net_hook
,
121 scm_cons (g_make_attrib_smob_list(w_current
, o_current
),
126 /*! \todo Finish function documentation!!!
128 * \par Function Description
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
,
137 TOPLEVEL
*toplevel
= w_current
->toplevel
;
140 int removing_obj
= 0;
142 SHIFTKEY
= w_current
->SHIFTKEY
;
143 CONTROLKEY
= w_current
->CONTROLKEY
;
146 printf("OBJECT id: %d\n", o_current
->sid
);
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 */
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
);
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
);
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
);
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
);
228 o_select_run_hooks(w_current
, o_current
, 0);
229 o_selection_remove (toplevel
, toplevel
->page_current
->
230 selection_list
, o_current
);
236 break; /* end object selected switch */
239 /* do the attributes */
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
,
248 o_attrib_add_selected (w_current
, toplevel
->page_current
->selection_list
,
252 /* finally redraw object */
253 o_invalidate (w_current
, o_current
);
256 /*! \todo Finish function documentation!!!
258 * \par Function Description
261 int o_select_box_start(GSCHEM_TOPLEVEL
*w_current
, int w_x
, int w_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) {
274 w_current
->second_wx
= w_x
;
275 w_current
->second_wy
= w_y
;
279 /*! \todo Finish function documentation!!!
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!!!
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!!!
311 * \par Function Description
313 void o_select_box_invalidate_rubber (GSCHEM_TOPLEVEL
*w_current
)
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!!!
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!!!
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
;
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
);
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
;
406 GList
*netstack
= NULL
;
407 GList
*netnamestack
= NULL
;
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
);
421 netnameiter
= g_list_last(netnamestack
);
422 for (iter1
= g_list_last(netstack
);
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) {
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
);
447 g_list_free(netstack
);
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
);
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
);
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
))
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
)))
490 return (OBJECT
*)g_list_first( geda_list_get_glist( toplevel
->page_current
->selection_list
))->data
;
493 /*! \todo Finish function documentation!!!
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
)) {
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!!!
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!!!
544 * \par Function Description
548 o_select_move_to_place_list(GSCHEM_TOPLEVEL
*w_current
)
550 TOPLEVEL
*toplevel
= w_current
->toplevel
;
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
;