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