1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 /* magnetic options */
29 /* half size of the magnetic marker on the screen. */
30 #define MAGNETIC_HALFSIZE 6
32 /* define how far the cursor could be to activate magnetic */
33 #define MAGNETIC_PIN_REACH 50
34 #define MAGNETIC_NET_REACH 20
35 #define MAGNETIC_BUS_REACH 30
37 /* weighting factors to tell that a pin is more important than a net */
38 #define MAGNETIC_PIN_WEIGHT 5.0
39 #define MAGNETIC_NET_WEIGHT 2.0
40 #define MAGNETIC_BUS_WEIGHT 3.0
42 /* Bit definitions for the four quardrants of the direction guessing */
43 #define QUADRANT1 0x01
44 #define QUADRANT2 0x02
45 #define QUADRANT3 0x04
46 #define QUADRANT4 0x08
49 /*! \brief Reset all variables used for net drawing
50 * \par Function Description
51 * This function resets all variables from GschemToplevel that are used
52 * for net drawing. This function should be called when escaping from
53 * a net drawing action or before entering it.
55 void o_net_reset(GschemToplevel
*w_current
)
57 o_net_invalidate_rubber (w_current
);
58 w_current
->first_wx
= w_current
->first_wy
= -1;
59 w_current
->second_wx
= w_current
->second_wy
= -1;
60 w_current
->third_wx
= w_current
->third_wy
= -1;
61 w_current
->magnetic_wx
= w_current
->magnetic_wy
= -1;
62 w_current
->rubber_visible
= 0;
63 i_action_stop (w_current
);
66 /*! \brief guess the best direction for the next net drawing action
67 * \par Function Description
68 * This function checks all connectable objects at a starting point.
69 * It determines the best drawing direction for each quadrant of the
70 * possible net endpoint.
72 * The directions are stored in the GschemToplevel->net_direction variable
75 void o_net_guess_direction(GschemToplevel
*w_current
,
78 int up
=0, down
=0, left
=0, right
=0;
80 int xmin
, ymin
, xmax
, ymax
;
82 GList
*object_list
, *iter1
, *iter2
;
86 /* badness values {OVERWRITE, ORTHO, CONTINUE} */
87 const int pin_rules
[] = {100, 50, 0};
88 const int bus_rules
[] = {90, 0, 40};
89 const int net_rules
[] = {80, 30, 0};
91 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
92 g_return_if_fail (page_view
!= NULL
);
94 PAGE
*page
= gschem_page_view_get_page (page_view
);
95 g_return_if_fail (page
!= NULL
);
97 object_list
= g_list_append (NULL
, page
->connectible_list
);
99 for (iter1
= object_list
; iter1
!= NULL
; iter1
= g_list_next(iter1
)) {
100 for (iter2
= (GList
*) iter1
->data
; iter2
!= NULL
; iter2
= g_list_next(iter2
)) {
101 o_current
= (OBJECT
*) iter2
->data
;
103 if ((orientation
= o_net_orientation(o_current
)) == NEITHER
)
106 switch (o_current
->type
) {
108 current_rules
= (int*) net_rules
;
111 current_rules
= (int*) pin_rules
;
114 current_rules
= (int*) bus_rules
;
117 g_assert_not_reached ();
120 x1
= o_current
->line
->x
[0];
121 x2
= o_current
->line
->x
[1];
122 y1
= o_current
->line
->y
[0];
123 y2
= o_current
->line
->y
[1];
130 if (orientation
== HORIZONTAL
&& wy
== y1
) {
132 up
= max(up
, current_rules
[1]);
133 down
= max(down
, current_rules
[1]);
134 right
= max(right
, current_rules
[0]);
135 left
= max(left
, current_rules
[2]);
137 else if (wx
== xmax
) {
138 up
= max(up
, current_rules
[1]);
139 down
= max(down
, current_rules
[1]);
140 right
= max(right
, current_rules
[2]);
141 left
= max(left
, current_rules
[0]);
143 else if (xmin
< wx
&& wx
< xmax
) {
144 up
= max(up
, current_rules
[1]);
145 down
= max(down
, current_rules
[1]);
146 right
= max(right
, current_rules
[0]);
147 left
= max(left
, current_rules
[0]);
153 if (orientation
== VERTICAL
&& wx
== x1
) {
155 up
= max(up
, current_rules
[0]);
156 down
= max(down
, current_rules
[2]);
157 right
= max(right
, current_rules
[1]);
158 left
= max(left
, current_rules
[1]);
160 else if (wy
== ymax
) {
161 up
= max(up
, current_rules
[2]);
162 down
= max(down
, current_rules
[0]);
163 right
= max(right
, current_rules
[1]);
164 left
= max(left
, current_rules
[1]);
166 else if (ymin
< wy
&& wy
< ymax
) {
167 up
= max(up
, current_rules
[0]);
168 down
= max(down
, current_rules
[0]);
169 right
= max(right
, current_rules
[1]);
170 left
= max(left
, current_rules
[1]);
179 w_current
->net_direction
= 0;
180 w_current
->net_direction
|= up
>= right
? 0 : QUADRANT1
;
181 w_current
->net_direction
|= up
>= left
? 0 : QUADRANT2
;
182 w_current
->net_direction
|= down
>= left
? 0 : QUADRANT3
;
183 w_current
->net_direction
|= down
>= right
? 0 : QUADRANT4
;
186 printf("o_net_guess_direction: up=%d down=%d left=%d right=%d direction=%d\n",
187 up
, down
, left
, right
, w_current
->net_direction
);
189 g_list_free (object_list
);
192 /*! \brief find the closest possible location to connect to
193 * \par Function Description
194 * This function calculates the distance to all connectable objects
195 * and searches the closest connection point.
196 * It searches for pins, nets and busses.
198 * The connection point is stored in GschemToplevel->magnetic_wx and
199 * GschemToplevel->magnetic_wy. If no connection is found. Both variables
202 void o_net_find_magnetic(GschemToplevel
*w_current
,
205 int x1
, x2
, y1
, y2
, min_x
, min_y
;
206 double mindist
, minbest
, dist1
, dist2
;
207 double weight
, min_weight
;
208 int magnetic_reach
= 0;
210 OBJECT
*o_magnetic
= NULL
;
211 GList
*object_list
, *iter1
, *iter2
;
213 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
214 g_return_if_fail (page_view
!= NULL
);
216 PAGE
*page
= gschem_page_view_get_page (page_view
);
217 g_return_if_fail (page
!= NULL
);
219 minbest
= min_x
= min_y
= 0;
222 /* max distance of all the different reaches */
223 magnetic_reach
= max(MAGNETIC_PIN_REACH
, MAGNETIC_NET_REACH
);
224 magnetic_reach
= max(magnetic_reach
, MAGNETIC_BUS_REACH
);
226 object_list
= g_list_append (NULL
, page
->connectible_list
);
228 for (iter1
= object_list
; iter1
!= NULL
; iter1
= g_list_next(iter1
)) {
229 for (iter2
= (GList
*) iter1
->data
; iter2
!= NULL
; iter2
= g_list_next(iter2
)) {
230 int left
, top
, right
, bottom
;
231 o_current
= (OBJECT
*) iter2
->data
;
233 if (!world_get_single_object_bounds(page
->toplevel
, o_current
,
234 &left
, &top
, &right
, &bottom
) ||
235 !visible (w_current
, left
, top
, right
, bottom
))
236 continue; /* skip invisible objects */
238 if (o_current
->type
== OBJ_PIN
) {
239 min_x
= o_current
->line
->x
[o_current
->whichend
];
240 min_y
= o_current
->line
->y
[o_current
->whichend
];
242 mindist
= hypot(w_x
- min_x
, w_y
- min_y
);
243 weight
= mindist
/ MAGNETIC_PIN_WEIGHT
;
246 else if (o_current
->type
== OBJ_NET
247 || o_current
->type
== OBJ_BUS
) {
248 /* we have 3 possible points to connect:
249 2 endpoints and 1 midpoint point */
250 x1
= o_current
->line
->x
[0];
251 y1
= o_current
->line
->y
[0];
252 x2
= o_current
->line
->x
[1];
253 y2
= o_current
->line
->y
[1];
255 dist1
= hypot(w_x
- x1
, w_y
- y1
);
256 dist2
= hypot(w_x
- x2
, w_y
- y2
);
269 if ((x1
== x2
) /* vertical net */
270 && ((y1
>= w_y
&& w_y
>= y2
)
271 || (y2
>= w_y
&& w_y
>= y1
))) {
272 if (abs(w_x
- x1
) < mindist
) {
273 mindist
= abs(w_x
- x1
);
278 if ((y1
== y2
) /* horitontal net */
279 && ((x1
>= w_x
&& w_x
>= x2
)
280 || (x2
>= w_x
&& w_x
>= x1
))) {
281 if (abs(w_y
- y1
) < mindist
) {
282 mindist
= abs(w_y
- y1
);
288 if (o_current
->type
== OBJ_BUS
)
289 weight
= mindist
/ MAGNETIC_BUS_WEIGHT
;
291 weight
= mindist
/ MAGNETIC_NET_WEIGHT
;
293 else { /* neither pin nor net or bus */
297 if (o_magnetic
== NULL
298 || weight
< min_weight
) {
301 o_magnetic
= o_current
;
302 w_current
->magnetic_wx
= min_x
;
303 w_current
->magnetic_wy
= min_y
;
308 /* check whether we found an object and if it's close enough */
309 if (o_magnetic
!= NULL
) {
310 switch (o_magnetic
->type
) {
311 case (OBJ_PIN
): magnetic_reach
= MAGNETIC_PIN_REACH
; break;
312 case (OBJ_NET
): magnetic_reach
= MAGNETIC_NET_REACH
; break;
313 case (OBJ_BUS
): magnetic_reach
= MAGNETIC_BUS_REACH
; break;
315 if (minbest
> gschem_page_view_WORLDabs (page_view
, magnetic_reach
)) {
316 w_current
->magnetic_wx
= -1;
317 w_current
->magnetic_wy
= -1;
321 w_current
->magnetic_wx
= -1;
322 w_current
->magnetic_wy
= -1;
325 g_list_free (object_list
);
328 /*! \brief calcutates the net route to the magnetic marker
329 * \par Function Description
330 * Depending on the two rubbernet lines from start to last and from
331 * last to second, the 3 coordinates are manipulated to find
332 * a way to the magnetic marker.
334 void o_net_finishmagnetic(GschemToplevel
*w_current
)
336 int primary_zero_length
, secondary_zero_length
;
338 primary_zero_length
= ((w_current
->first_wx
== w_current
->second_wx
)
339 && (w_current
->first_wy
== w_current
->second_wy
));
341 secondary_zero_length
= ((w_current
->second_wx
== w_current
->third_wx
)
342 && (w_current
->second_wy
== w_current
->third_wy
));
344 if (!primary_zero_length
&& secondary_zero_length
) {
345 if (w_current
->first_wx
== w_current
->second_wx
) {
346 /* expand vertical line to magnetic_wy */
347 w_current
->second_wy
= w_current
->magnetic_wy
;
349 else if (w_current
->first_wy
== w_current
->second_wy
) {
350 /* expand horitontal line to vertical to magnetic_wx */
351 w_current
->second_wx
= w_current
->magnetic_wx
;
353 /* connect to magnetic */
354 w_current
->third_wx
= w_current
->magnetic_wx
;
355 w_current
->third_wy
= w_current
->magnetic_wy
;
358 if (primary_zero_length
&& !secondary_zero_length
) {
359 /* move second line to the first (empty line) */
360 w_current
->first_wx
= w_current
->second_wx
;
361 w_current
->first_wy
= w_current
->second_wy
;
362 if (w_current
->second_wx
== w_current
->third_wx
) {
363 /* expand vertical line to magnetic_wy */
364 w_current
->second_wy
= w_current
->magnetic_wy
;
366 else if (w_current
->second_wy
== w_current
->third_wy
) {
367 /* expand horitontal line to magnetic_wx */
368 w_current
->second_wx
= w_current
->magnetic_wx
;
370 /* connect to magnetic */
371 w_current
->third_wx
= w_current
->magnetic_wx
;
372 w_current
->third_wy
= w_current
->magnetic_wy
;
375 if (!primary_zero_length
&& !secondary_zero_length
) {
376 /* expand line in both directions */
377 if (w_current
->first_wx
== w_current
->second_wx
) {
378 w_current
->second_wy
= w_current
->magnetic_wy
;
381 w_current
->second_wx
= w_current
->magnetic_wx
;
383 w_current
->third_wx
= w_current
->magnetic_wx
;
384 w_current
->third_wy
= w_current
->magnetic_wy
;
388 /*! \brief callback function to draw a net marker in magnetic mode
389 * \par Function Description
390 * If the mouse is moved, this function is called to update the
391 * position of the magnetic marker.
392 * If the controllkey is pressed the magnetic marker follows the mouse.
394 void o_net_start_magnetic(GschemToplevel
*w_current
, int w_x
, int w_y
)
396 if (!(gschem_options_get_magnetic_net_mode (w_current
->options
))) {
400 o_net_invalidate_rubber (w_current
);
402 if (w_current
->CONTROLKEY
) {
403 w_current
->magnetic_wx
= w_x
;
404 w_current
->magnetic_wy
= w_y
;
407 o_net_find_magnetic(w_current
, w_x
, w_y
);
410 o_net_invalidate_rubber (w_current
);
411 w_current
->rubber_visible
= 1;
414 /*! \brief set the start point of a new net
415 * \par Function Description
416 * This function sets the start point of a new net at the position of the
417 * cursor. If we have a visible magnetic marker, we use that instead of
418 * the cursor position
420 void o_net_start(GschemToplevel
*w_current
, int w_x
, int w_y
)
422 i_action_start (w_current
);
424 if (w_current
->magnetic_wx
!= -1 && w_current
->magnetic_wy
!= -1) {
425 w_current
->first_wx
= w_current
->magnetic_wx
;
426 w_current
->first_wy
= w_current
->magnetic_wy
;
429 w_current
->first_wx
= w_x
;
430 w_current
->first_wy
= w_y
;
433 w_current
->second_wx
= w_current
->third_wx
= w_current
->first_wx
;
434 w_current
->second_wy
= w_current
->third_wy
= w_current
->first_wy
;
436 if (w_current
->first_wx
!= snap_grid (w_current
, w_current
->first_wx
)
437 || w_current
->first_wy
!= snap_grid (w_current
, w_current
->first_wy
))
438 s_log_message(_("Warning: Starting net at off grid coordinate\n"));
440 if (w_current
->net_direction_mode
)
441 o_net_guess_direction(w_current
, w_current
->first_wx
, w_current
->first_wy
);
444 /*! \brief finish a net drawing action
445 * \par Function Description
446 * This function finishes the drawing of a net. If we have a visible
447 * magnetic marker, we use that instead of the current cursor
450 * The rubber nets are removed, the nets and cues are drawn and the
451 * net is added to the TOPLEVEL structure.
453 * The function returns TRUE if it has drawn a net, FALSE otherwise.
455 void o_net_end(GschemToplevel
*w_current
, int w_x
, int w_y
)
457 int primary_zero_length
, secondary_zero_length
;
458 int found_primary_connection
= FALSE
;
459 int save_wx
, save_wy
;
461 GList
*prev_conn_objects
;
462 OBJECT
*new_net
= NULL
;
464 /* Save a list of added objects to run the %add-objects-hook later */
465 GList
*added_objects
= NULL
;
467 g_assert( w_current
->inside_action
!= 0 );
469 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
470 g_return_if_fail (page_view
!= NULL
);
472 PAGE
*page
= gschem_page_view_get_page (page_view
);
473 g_return_if_fail (page
!= NULL
);
475 o_net_invalidate_rubber (w_current
);
477 if (w_current
->magnetic_wx
!= -1 && w_current
->magnetic_wy
!= -1)
478 o_net_finishmagnetic(w_current
);
480 w_current
->rubber_visible
= 0;
482 /* See if either of the nets are zero length. We'll only add */
483 /* the non-zero ones */
484 primary_zero_length
= (w_current
->first_wx
== w_current
->second_wx
) &&
485 (w_current
->first_wy
== w_current
->second_wy
);
487 secondary_zero_length
= (w_current
->second_wx
== w_current
->third_wx
) &&
488 (w_current
->second_wy
== w_current
->third_wy
);
490 /* If both nets are zero length... */
491 /* this ends the net drawing behavior */
492 if ( primary_zero_length
&& secondary_zero_length
) {
493 o_net_reset(w_current
);
497 save_wx
= w_current
->third_wx
;
498 save_wy
= w_current
->third_wy
;
500 if (w_current
->third_wx
!= snap_grid (w_current
, w_current
->third_wx
)
501 || w_current
->third_wy
!= snap_grid (w_current
, w_current
->third_wy
))
502 s_log_message(_("Warning: Ending net at off grid coordinate\n"));
504 if (!primary_zero_length
) {
505 /* create primary net */
506 new_net
= o_net_new(page
->toplevel
, OBJ_NET
, NET_COLOR
,
507 w_current
->first_wx
, w_current
->first_wy
,
508 w_current
->second_wx
, w_current
->second_wy
);
509 s_page_append (page
->toplevel
, page
, new_net
);
511 added_objects
= g_list_prepend (added_objects
, new_net
);
515 prev_conn_objects
= s_conn_return_others (NULL
, new_net
);
516 o_net_add_busrippers (w_current
, new_net
, prev_conn_objects
);
517 g_list_free (prev_conn_objects
);
520 printf("primary:\n");
521 s_conn_print(new_net
->conn_list
);
524 /* Go off and search for valid connection on this newly created net */
525 found_primary_connection
= s_conn_net_search(new_net
, 1,
527 if (found_primary_connection
)
529 /* if a net connection is found, reset start point of next net */
530 save_wx
= w_current
->second_wx
;
531 save_wy
= w_current
->second_wy
;
536 /* If the second net is not zero length, add it as well */
537 /* Also, a valid net connection from the primary net was not found */
538 if (!secondary_zero_length
&& !found_primary_connection
) {
540 /* Add secondary net */
541 new_net
= o_net_new(page
->toplevel
, OBJ_NET
, NET_COLOR
,
542 w_current
->second_wx
, w_current
->second_wy
,
543 w_current
->third_wx
, w_current
->third_wy
);
544 s_page_append (page
->toplevel
, page
, new_net
);
546 added_objects
= g_list_prepend (added_objects
, new_net
);
550 prev_conn_objects
= s_conn_return_others (NULL
, new_net
);
551 o_net_add_busrippers (w_current
, new_net
, prev_conn_objects
);
552 g_list_free (prev_conn_objects
);
554 s_conn_print(new_net
->conn_list
);
558 /* Call add-objects-hook */
559 if (added_objects
!= NULL
) {
560 g_run_hook_object_list (w_current
, "%add-objects-hook", added_objects
);
561 g_list_free (added_objects
);
564 w_current
->first_wx
= save_wx
;
565 w_current
->first_wy
= save_wy
;
567 gschem_toplevel_page_content_changed (w_current
, page
);
568 o_undo_savestate_old (w_current
, UNDO_ALL
, _("Net"));
570 /* Continue net drawing */
571 o_net_start(w_current
, w_current
->first_wx
, w_current
->first_wy
);
574 /*! \brief erase and redraw the rubber lines when drawing a net
575 * \par Function Description
576 * This function draws the rubbernet lines when drawing a net.
578 void o_net_motion (GschemToplevel
*w_current
, int w_x
, int w_y
)
580 int ortho
, horizontal
, quadrant
;
581 gboolean magnetic_net_mode
;
583 g_return_if_fail (w_current
!= NULL
);
584 g_assert( w_current
->inside_action
!= 0 );
586 magnetic_net_mode
= gschem_options_get_magnetic_net_mode (w_current
->options
);
588 /* Orthognal mode enabled when Control Key is NOT pressed or
589 if we are using magnetic mode */
590 ortho
= !w_current
->CONTROLKEY
|| magnetic_net_mode
;
592 if (w_current
->rubber_visible
)
593 o_net_invalidate_rubber (w_current
);
595 if (magnetic_net_mode
) {
596 if (w_current
->CONTROLKEY
) {
597 /* set the magnetic marker position to current xy if the
598 controlkey is pressed. Thus the net will not connect to
599 the closest net if we finish the net drawing */
600 w_current
->magnetic_wx
= w_x
;
601 w_current
->magnetic_wy
= w_y
;
604 o_net_find_magnetic(w_current
, w_x
, w_y
);
608 w_current
->second_wx
= w_x
;
609 w_current
->second_wy
= w_y
;
611 /* In orthogonal mode secondary line is the same as the first */
613 w_current
->third_wx
= w_current
->second_wx
;
614 w_current
->third_wy
= w_current
->second_wy
;
616 /* If you press the control key then you can draw non-ortho nets */
618 if (w_current
->second_wy
> w_current
->first_wy
)
619 quadrant
= w_current
->second_wx
> w_current
->first_wx
? QUADRANT1
: QUADRANT2
;
621 quadrant
= w_current
->second_wx
> w_current
->first_wx
? QUADRANT4
: QUADRANT3
;
623 horizontal
= w_current
->net_direction
& quadrant
;
625 if (!w_current
->SHIFTKEY
)
626 horizontal
= !horizontal
;
628 /* calculate the co-ordinates necessary to draw the lines*/
629 /* Pressing the shift key will cause the vertical and horizontal lines to switch places */
631 w_current
->second_wy
= w_current
->first_wy
;
632 w_current
->third_wx
= w_current
->second_wx
;
633 w_current
->third_wy
= w_y
;
635 w_current
->second_wx
= w_current
->first_wx
;
636 w_current
->third_wx
= w_x
;
637 w_current
->third_wy
= w_current
->second_wy
;
641 o_net_invalidate_rubber (w_current
);
642 w_current
->rubber_visible
= 1;
645 /*! \brief draw rubbernet lines to the gc
646 * \par Function Description
647 * This function draws the rubbernets to the graphic context
650 o_net_draw_rubber(GschemToplevel
*w_current
, EdaRenderer
*renderer
)
652 int size
= NET_WIDTH
, w_magnetic_halfsize
;
653 cairo_t
*cr
= eda_renderer_get_cairo_context (renderer
);
654 GArray
*color_map
= eda_renderer_get_color_map (renderer
);
655 int flags
= eda_renderer_get_cairo_flags (renderer
);
656 gboolean magnetic_net_mode
;
658 g_return_if_fail (w_current
!= NULL
);
660 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
661 g_return_if_fail (page_view
!= NULL
);
663 eda_cairo_set_source_color (cr
, SELECT_COLOR
, color_map
);
665 magnetic_net_mode
= gschem_options_get_magnetic_net_mode (w_current
->options
);
667 if (magnetic_net_mode
) {
668 if (w_current
->magnetic_wx
!= -1 && w_current
->magnetic_wy
!= -1) {
669 w_magnetic_halfsize
= max (4 * size
,
670 gschem_page_view_WORLDabs (page_view
, MAGNETIC_HALFSIZE
));
671 eda_cairo_arc (cr
, flags
, size
,
672 w_current
->magnetic_wx
, w_current
->magnetic_wy
,
673 w_magnetic_halfsize
, 0, 360);
678 eda_cairo_line (cr
, flags
, END_NONE
, size
,
679 w_current
->first_wx
, w_current
->first_wy
,
680 w_current
->second_wx
, w_current
->second_wy
);
683 eda_cairo_line (cr
, flags
, END_NONE
, size
,
684 w_current
->second_wx
, w_current
->second_wy
,
685 w_current
->third_wx
, w_current
->third_wy
);
687 eda_cairo_stroke (cr
, flags
, TYPE_SOLID
, END_NONE
, size
, -1, -1);
691 /*! \todo Finish function documentation!!!
693 * \par Function Description
696 void o_net_invalidate_rubber (GschemToplevel
*w_current
)
698 int size
= 0, magnetic_halfsize
;
699 int magnetic_x
, magnetic_y
;
700 gboolean magnetic_net_mode
;
702 g_return_if_fail (w_current
!= NULL
);
704 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
705 g_return_if_fail (page_view
!= NULL
);
707 gschem_page_view_WORLDtoSCREEN (page_view
,
708 w_current
->magnetic_wx
, w_current
->magnetic_wy
,
709 &magnetic_x
, &magnetic_y
);
711 size
= gschem_page_view_SCREENabs (page_view
, NET_WIDTH
);
713 magnetic_net_mode
= gschem_options_get_magnetic_net_mode (w_current
->options
);
715 if (magnetic_net_mode
) {
716 if (w_current
->magnetic_wx
!= -1 && w_current
->magnetic_wy
!= -1) {
717 magnetic_halfsize
= max (4 * size
, MAGNETIC_HALFSIZE
);
719 o_invalidate_rect (w_current
, magnetic_x
- magnetic_halfsize
,
720 magnetic_y
- magnetic_halfsize
,
721 magnetic_x
+ magnetic_halfsize
,
722 magnetic_y
+ magnetic_halfsize
);
726 gschem_page_view_invalidate_world_rect (page_view
,
729 w_current
->second_wx
,
730 w_current
->second_wy
);
732 gschem_page_view_invalidate_world_rect (page_view
,
733 w_current
->second_wx
,
734 w_current
->second_wy
,
736 w_current
->third_wy
);
740 /*! \todo Finish function documentation!!!
742 * \par Function Description
745 int o_net_add_busrippers(GschemToplevel
*w_current
, OBJECT
*net_obj
,
746 GList
*prev_conn_objects
)
750 GList
*cl_current
= NULL
;
751 OBJECT
*bus_object
= NULL
;
752 CONN
*found_conn
= NULL
;
761 int ripper_count
= 0;
765 double distance1
, distance2
;
767 int made_changes
= FALSE
;
768 const int ripper_size
= w_current
->bus_ripper_size
;
769 const CLibSymbol
*rippersym
= NULL
;
771 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
772 g_return_val_if_fail (page_view
!= NULL
, FALSE
);
774 PAGE
*page
= gschem_page_view_get_page (page_view
);
775 g_return_val_if_fail (page
!= NULL
, FALSE
);
777 length
= o_line_length(net_obj
);
779 if (!prev_conn_objects
) {
783 if (length
<= ripper_size
) {
787 /* check for a bus connection and draw rippers if so */
788 cl_current
= prev_conn_objects
;
789 while (cl_current
!= NULL
) {
791 bus_object
= (OBJECT
*) cl_current
->data
;
792 if (bus_object
&& bus_object
->type
== OBJ_BUS
) {
793 /* yes, using the net routine is okay */
794 int bus_orientation
= o_net_orientation(bus_object
);
795 int net_orientation
= o_net_orientation(net_obj
);
797 /* find the CONN structure which is associated with this object */
798 GList
*cl_current2
= net_obj
->conn_list
;
800 while (cl_current2
!= NULL
&& !done
) {
801 CONN
*tmp_conn
= (CONN
*) cl_current2
->data
;
803 if (tmp_conn
&& tmp_conn
->other_object
&&
804 tmp_conn
->other_object
== bus_object
) {
806 found_conn
= tmp_conn
;
810 cl_current2
= g_list_next(cl_current2
);
817 otherone
= !found_conn
->whichone
;
819 /* now deal with the found connection */
820 if (bus_orientation
== HORIZONTAL
&& net_orientation
== VERTICAL
) {
821 /* printf("found horiz bus %s %d!\n", bus_object->name,
822 found_conn->whichone);*/
824 sign
= bus_object
->bus_ripper_direction
;
826 if (bus_object
->line
->x
[0] < bus_object
->line
->x
[1]) {
834 distance1
= abs(bus_object
->line
->x
[first
] -
835 net_obj
->line
->x
[found_conn
->whichone
]);
836 distance2
= abs(bus_object
->line
->x
[second
] -
837 net_obj
->line
->x
[found_conn
->whichone
]);
839 if (distance1
<= distance2
) {
844 bus_object
->bus_ripper_direction
= sign
;
846 /* printf("hor sign: %d\n", sign); */
848 if (net_obj
->line
->y
[otherone
] < bus_object
->line
->y
[0]) {
849 /* new net is below bus */
850 /*printf("below\n");*/
852 if (ripper_count
>= 2) {
853 /* try to exit gracefully */
854 fprintf(stderr
, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
855 made_changes
= FALSE
;
860 rippers
[ripper_count
].angle
= 0;
861 rippers
[ripper_count
].mirror
= sign
== 1 ? 0 : 1;
863 net_obj
->line
->y
[found_conn
->whichone
] -= ripper_size
;
864 net_obj
->w_bounds_valid_for
= NULL
;
865 rippers
[ripper_count
].x
[0] =
866 net_obj
->line
->x
[found_conn
->whichone
];
867 rippers
[ripper_count
].y
[0] =
868 net_obj
->line
->y
[found_conn
->whichone
];
869 rippers
[ripper_count
].x
[1] =
870 net_obj
->line
->x
[found_conn
->whichone
] + sign
*ripper_size
;
871 rippers
[ripper_count
].y
[1] =
872 net_obj
->line
->y
[found_conn
->whichone
] + ripper_size
;
874 /* printf("done\n"); */
878 /* new net is above bus */
879 /* printf("above\n"); */
881 if (ripper_count
>= 2) {
882 /* try to exit gracefully */
883 fprintf(stderr
, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
884 made_changes
= FALSE
;
888 /* down, right/left */
889 rippers
[ripper_count
].angle
= 180;
890 rippers
[ripper_count
].mirror
= sign
== 1 ? 1 : 0;
892 net_obj
->line
->y
[found_conn
->whichone
] += ripper_size
;
893 net_obj
->w_bounds_valid_for
= NULL
;
894 rippers
[ripper_count
].x
[0] =
895 net_obj
->line
->x
[found_conn
->whichone
];
896 rippers
[ripper_count
].y
[0] =
897 net_obj
->line
->y
[found_conn
->whichone
];
898 rippers
[ripper_count
].x
[1] =
899 net_obj
->line
->x
[found_conn
->whichone
] + sign
*ripper_size
;
900 rippers
[ripper_count
].y
[1] =
901 net_obj
->line
->y
[found_conn
->whichone
] - ripper_size
;
904 /* printf("done\n"); */
909 } else if (bus_orientation
== VERTICAL
&&
910 net_orientation
== HORIZONTAL
) {
912 /* printf("found vert bus %s %d!\n", bus_object->name,
913 found_conn->whichone); */
915 sign
= bus_object
->bus_ripper_direction
;
917 if (bus_object
->line
->y
[0] < bus_object
->line
->y
[1]) {
925 distance1
= abs(bus_object
->line
->y
[first
] -
926 net_obj
->line
->y
[found_conn
->whichone
]);
927 distance2
= abs(bus_object
->line
->y
[second
] -
928 net_obj
->line
->y
[found_conn
->whichone
]);
930 if (distance1
<= distance2
) {
935 bus_object
->bus_ripper_direction
= sign
;
937 /* printf("ver sign: %d\n", sign); */
940 if (net_obj
->line
->x
[otherone
] < bus_object
->line
->x
[0]) {
941 /* new net is to the left of the bus */
942 /* printf("left\n"); */
944 if (ripper_count
>= 2) {
945 /* try to exit gracefully */
946 fprintf(stderr
, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
947 made_changes
= FALSE
;
952 rippers
[ripper_count
].angle
= 270;
953 rippers
[ripper_count
].mirror
= sign
== 1 ? 1 : 0;
955 net_obj
->line
->x
[found_conn
->whichone
] -= ripper_size
;
956 net_obj
->w_bounds_valid_for
= NULL
;
957 rippers
[ripper_count
].x
[0] =
958 net_obj
->line
->x
[found_conn
->whichone
];
959 rippers
[ripper_count
].y
[0] =
960 net_obj
->line
->y
[found_conn
->whichone
];
961 rippers
[ripper_count
].x
[1] =
962 net_obj
->line
->x
[found_conn
->whichone
] + ripper_size
;
963 rippers
[ripper_count
].y
[1] =
964 net_obj
->line
->y
[found_conn
->whichone
] + sign
*ripper_size
;
969 /* new net is to the right of the bus */
970 /* printf("right\n"); */
972 if (ripper_count
>= 2) {
973 /* try to exit gracefully */
974 fprintf(stderr
, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
975 made_changes
= FALSE
;
980 rippers
[ripper_count
].angle
= 90;
981 rippers
[ripper_count
].mirror
= sign
== 1 ? 0 : 1;
983 net_obj
->line
->x
[found_conn
->whichone
] += ripper_size
;
984 net_obj
->w_bounds_valid_for
= NULL
;
985 rippers
[ripper_count
].x
[0] =
986 net_obj
->line
->x
[found_conn
->whichone
];
987 rippers
[ripper_count
].y
[0] =
988 net_obj
->line
->y
[found_conn
->whichone
];
989 rippers
[ripper_count
].x
[1] =
990 net_obj
->line
->x
[found_conn
->whichone
] - ripper_size
;
991 rippers
[ripper_count
].y
[1] =
992 net_obj
->line
->y
[found_conn
->whichone
] + sign
*ripper_size
;
1001 cl_current
= g_list_next(cl_current
);
1005 s_conn_remove_object_connections (page
->toplevel
, net_obj
);
1007 if (w_current
->bus_ripper_type
== COMP_BUS_RIPPER
) {
1009 s_clib_search (page
->toplevel
->bus_ripper_symname
, CLIB_EXACT
);
1010 if (symlist
!= NULL
) {
1011 rippersym
= (CLibSymbol
*) symlist
->data
;
1013 g_list_free (symlist
);
1016 for (i
= 0; i
< ripper_count
; i
++) {
1017 if (w_current
->bus_ripper_type
== NET_BUS_RIPPER
) {
1018 new_obj
= o_net_new(page
->toplevel
, OBJ_NET
, NET_COLOR
,
1019 rippers
[i
].x
[0], rippers
[i
].y
[0],
1020 rippers
[i
].x
[1], rippers
[i
].y
[1]);
1021 s_page_append (page
->toplevel
, page
, new_obj
);
1024 if (rippersym
!= NULL
) {
1025 new_obj
= o_complex_new (page
->toplevel
, OBJ_COMPLEX
, DEFAULT_COLOR
,
1026 rippers
[i
].x
[0], rippers
[i
].y
[0],
1027 rippers
[i
].angle
, rippers
[i
].mirror
,
1029 page
->toplevel
->bus_ripper_symname
, 1);
1030 s_page_append_list (page
->toplevel
, page
,
1031 o_complex_promote_attribs (page
->toplevel
, new_obj
));
1032 s_page_append (page
->toplevel
, page
, new_obj
);
1034 s_log_message(_("Bus ripper symbol [%s] was not found in any symbol library\n"),
1035 page
->toplevel
->bus_ripper_symname
);
1040 s_conn_update_object (page
, net_obj
);