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)
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <config.h>
21 
22 #include <stdio.h>
23 #include <string.h>
24 #include <math.h> /* For M_PI */
25 
26 #include "gschem.h"
27 
28 #ifdef HAVE_LIBDMALLOC
29 #include <dmalloc.h>
30 #endif
31 
32 /*! \todo Finish function documentation!!!
33  *  \brief
34  *  \par Function Description
35  *
36  */
o_cue_redraw_all(GSCHEM_TOPLEVEL * w_current,GList * list,gboolean draw_selected)37 void o_cue_redraw_all (GSCHEM_TOPLEVEL *w_current, GList *list, gboolean draw_selected)
38 {
39   OBJECT *o_current;
40   GList *iter;
41 
42   iter = list;
43   while (iter != NULL) {
44     o_current = (OBJECT *)iter->data;
45     switch(o_current->type) {
46       case(OBJ_NET):
47       case(OBJ_BUS):
48       case(OBJ_PIN):
49 	if (!(o_current->dont_redraw ||
50               (o_current->selected && !draw_selected))) {
51           o_cue_draw_single(w_current, o_current);
52           if (o_current->selected && w_current->draw_grips) {
53             o_line_draw_grips (w_current, o_current);
54           }
55         }
56         break;
57 
58       case(OBJ_COMPLEX):
59       case(OBJ_PLACEHOLDER):
60 	if (!(o_current->dont_redraw ||
61               (o_current->selected && !draw_selected))) {
62           o_cue_redraw_all(w_current, o_current->complex->prim_objs,
63                            draw_selected);
64         }
65         break;
66     }
67 
68     iter = g_list_next (iter);
69   }
70 }
71 
72 
73 /*!
74  *  \brief Set the color on the gc depending on the passed in color id
75  */
o_cue_set_color(GSCHEM_TOPLEVEL * w_current,int color)76 static void o_cue_set_color(GSCHEM_TOPLEVEL *w_current, int color)
77 {
78   if (w_current->toplevel->override_color != -1 ) {
79     gschem_cairo_set_source_color (w_current, x_color_lookup (w_current->toplevel->override_color));
80   } else {
81     gschem_cairo_set_source_color (w_current, x_color_lookup (color));
82   }
83 }
84 
85 
86 /*! \brief Draws a circular junction cue
87  *
88  *  \par Function Description
89  *  Draws a cue at the given world coordinate, picking the size based
90  *  on whether a bus forms a part of the connection.
91  *
92  *  The cue's drawn position is hinted to align with the widht a net or
93  *  bus would be drawn on screen. This helps to keep the cue looking
94  *  central when lines being hinted onto the pixel grid.
95  *
96  *  \param [in] w_current     The GSCHEM_TOPLEVEL object
97  *  \param [in] x             The X coordinate of the cue (world units)
98  *  \param [in] y             The Y coordinate of the cue (world units)
99  *  \param [in] bus_involved  If a bus forms part of the connection (TRUE/FALSE)
100  */
draw_junction_cue(GSCHEM_TOPLEVEL * w_current,int x,int y,int bus_involved)101 static void draw_junction_cue (GSCHEM_TOPLEVEL *w_current,
102                                int x, int y, int bus_involved)
103 {
104   int size;
105   int line_width;
106 
107   if (bus_involved) {
108     size = JUNCTION_CUE_SIZE_BUS / 2;
109     line_width = BUS_WIDTH;
110   } else {
111     size = JUNCTION_CUE_SIZE_NET / 2;
112     line_width = NET_WIDTH;
113   }
114 
115   gschem_cairo_center_arc (w_current, line_width, -1, x, y, size, 0, 360);
116   o_cue_set_color (w_current, JUNCTION_COLOR);
117   cairo_fill (w_current->cr);
118 }
119 
120 
121 /*! \todo Finish function documentation!!!
122  *  \brief
123  *  \par Function Description
124  *
125  */
o_cue_draw_lowlevel(GSCHEM_TOPLEVEL * w_current,OBJECT * object,int whichone)126 void o_cue_draw_lowlevel(GSCHEM_TOPLEVEL *w_current, OBJECT *object, int whichone)
127 {
128   int x, y;
129   GList *cl_current;
130   CONN *conn;
131   int type, count = 0;
132   int done = FALSE;
133   int size;
134   int bus_involved = FALSE;
135 
136   g_return_if_fail (whichone == 0 || whichone == 1);
137 
138   x = object->line->x[whichone];
139   y = object->line->y[whichone];
140 
141   type = CONN_ENDPOINT;
142 
143   if (object->type == OBJ_BUS ||
144        (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_BUS))
145     bus_involved = TRUE;
146 
147   cl_current = object->conn_list;
148   while (cl_current != NULL && !done) {
149     conn = (CONN *) cl_current->data;
150 
151     if (conn->x == x && conn->y == y) {
152 
153       if (conn->other_object &&
154            (conn->other_object->type == OBJ_BUS ||
155              (conn->other_object->type == OBJ_PIN &&
156               conn->other_object->pin_type == PIN_TYPE_BUS)))
157         bus_involved=TRUE;
158 
159       switch(conn->type) {
160 
161         case(CONN_ENDPOINT):
162           count++;
163           break;
164 
165         case(CONN_MIDPOINT):
166           type = CONN_MIDPOINT;
167           done = TRUE;
168           count = 0;
169           break;
170       }
171     }
172 
173     cl_current = g_list_next(cl_current);
174   }
175 
176 #if DEBUG
177   printf("type: %d count: %d\n", type, count);
178 #endif
179 
180   switch(type) {
181 
182     case(CONN_ENDPOINT):
183       if (object->type == OBJ_NET || object->type == OBJ_PIN) {
184         if (count < 1) { /* Didn't find anything connected directly there */
185           if ((object->type == OBJ_NET)
186               && o_net_is_fully_connected (w_current->toplevel, object)) {
187             /* Probably connected, so draw friendly arrow */
188             /* Here we compute a transformation so that the arrow is
189                aligned with the net segment.
190 
191                FIXME This probably isn't efficient, unfortunately. */
192             cairo_save (w_current->cr);
193 
194             int s_x, s_y;
195             WORLDtoSCREEN (w_current, x, y, &s_x, &s_y);
196             double s_size = SCREENabs (w_current, CUE_BOX_SIZE);
197 
198             cairo_matrix_t mtx;
199             double dx = object->line->x[whichone] - object->line->x[!whichone];
200             double dy = object->line->y[whichone] - object->line->y[!whichone];
201             double len = hypot (dx, dy);
202             if (len != 0) {
203               dx /= len;
204               dy /= len;
205 
206               cairo_matrix_init (&mtx, dx, -dy, dy, dx, s_x, s_y);
207             } else {
208               cairo_matrix_init_translate (&mtx, s_x, s_y);
209             }
210             cairo_transform (w_current->cr, &mtx);
211 
212             cairo_move_to (w_current->cr, -s_size, -s_size);
213             cairo_line_to (w_current->cr, -s_size, s_size);
214             cairo_line_to (w_current->cr, s_size, 0);
215             cairo_close_path (w_current->cr);
216             o_cue_set_color (w_current, JUNCTION_COLOR);
217             cairo_fill (w_current->cr);
218 
219             cairo_restore (w_current->cr);
220           } else {
221             /* Not properly connected, so draw warning box */
222             size = CUE_BOX_SIZE;
223             gschem_cairo_center_box (w_current, -1, -1, x, y, size, size);
224             o_cue_set_color (w_current, NET_ENDPOINT_COLOR);
225             cairo_fill (w_current->cr);
226           }
227         } else if (count >= 2) {
228           draw_junction_cue (w_current, x, y, bus_involved);
229         }
230       }
231       break;
232 
233     case(CONN_MIDPOINT):
234       draw_junction_cue (w_current, x, y, bus_involved);
235       break;
236 
237       /* here is where you draw bus rippers */
238 
239   }
240 
241 }
242 
243 
244 /*! \todo Finish function documentation!!!
245  *  \brief
246  *  \par Function Description
247  *
248  */
o_cue_draw_lowlevel_midpoints(GSCHEM_TOPLEVEL * w_current,OBJECT * object)249 void o_cue_draw_lowlevel_midpoints(GSCHEM_TOPLEVEL *w_current, OBJECT *object)
250 {
251   GList *iter;
252   int bus_involved;
253 
254   for (iter = object->conn_list; iter != NULL; iter = g_list_next (iter)) {
255     CONN *conn = iter->data;
256 
257     if (conn->type == CONN_MIDPOINT) {
258       bus_involved = (object->type == OBJ_BUS ||
259                        (conn->other_object &&
260                         conn->other_object->type == OBJ_BUS));
261       draw_junction_cue (w_current, conn->x, conn->y, bus_involved);
262     }
263   }
264 }
265 
266 
267 /*! \todo Finish function documentation!!!
268  *  \brief
269  *  \par Function Description
270  *
271  */
o_cue_draw_single(GSCHEM_TOPLEVEL * w_current,OBJECT * object)272 void o_cue_draw_single(GSCHEM_TOPLEVEL *w_current, OBJECT *object)
273 {
274   if (!object) {
275     return;
276   }
277 
278   if (object->type != OBJ_NET && object->type != OBJ_PIN &&
279       object->type != OBJ_BUS) {
280         return;
281       }
282 
283   if (object->type != OBJ_PIN) {
284     o_cue_draw_lowlevel(w_current, object, 0);
285     o_cue_draw_lowlevel(w_current, object, 1);
286     o_cue_draw_lowlevel_midpoints(w_current, object);
287   } else {
288     o_cue_draw_lowlevel(w_current, object, object->whichend);
289   }
290 }
291 
292 
293 /*! \todo Finish function documentation!!!
294  *  \brief
295  *  \par Function Description
296  *
297  */
o_cue_draw_list(GSCHEM_TOPLEVEL * w_current,GList * object_list)298 void o_cue_draw_list(GSCHEM_TOPLEVEL *w_current, GList *object_list)
299 {
300   OBJECT *object;
301   GList *ol_current;
302 
303   ol_current = object_list;
304   while(ol_current != NULL) {
305     object = (OBJECT *) ol_current->data;
306 
307     o_cue_draw_single(w_current, object);
308 
309     ol_current = g_list_next(ol_current);
310   }
311 }
312