refdes_renum: warn of possible number clash with non-conforming values
[geda-gaf/whiteaudio.git] / gschem / src / o_circle.c
blob2ee31f03ddd9ffa598d43838705b22401571917d
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2011 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
20 #include <config.h>
21 #include <stdio.h>
22 #include <math.h>
24 #include "gschem.h"
26 #ifdef HAVE_LIBDMALLOC
27 #include <dmalloc.h>
28 #endif
31 typedef void (*FILL_FUNC) (GSCHEM_TOPLEVEL *w_current,
32 COLOR *color, CIRCLE *circle,
33 gint fill_width, gint angle1, gint pitch1,
34 gint angle2, gint pitch2);
37 /*! \brief Placeholder filling function.
38 * \par Function Description
39 * This function does nothing. It has the same prototype as all the filling
40 * functions. It prevent from making a difference between filling in function
41 * #o_circle_draw().
43 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
44 * for <B>angle1</B> and <B>angle2</B> is degree.
46 * \param [in] w_current Schematic top level
47 * \param [in] color Circle fill color.
48 * \param [in] circle Circle to be drawn
49 * \param [in] fill_width
50 * \param [in] angle1 1st angle for pattern.
51 * \param [in] pitch1 1st pitch for pattern.
52 * \param [in] angle2 2nd angle for pattern.
53 * \param [in] pitch2 2nd pitch for pattern.
55 static void
56 o_circle_fill_hollow (GSCHEM_TOPLEVEL *w_current,
57 COLOR *color, CIRCLE *circle,
58 gint fill_width,
59 gint angle1, gint pitch1,
60 gint angle2, gint pitch2)
64 /*! \brief Fill inside of circle with a solid pattern.
65 * \par Function Description
66 * This function fills the inside of the circle with a solid pattern.
67 * Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>, <B>pitch2</B>
68 * and <B>width</B> are unused here but kept for compatibility with other
69 * circle filling functions.
71 * The circle is described by the coordinates of its center and its radius.
72 * Please not that it is not the way GDK take it. Translation is made
73 * afterward.
75 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
76 * for <B>angle1</B> and <B>angle2</B> is degree.
78 * \param [in] w_current Schematic top level
79 * \param [in] color Circle fill color.
80 * \param [in] circle Circle to be drawn
81 * \param [in] fill_width
82 * \param [in] angle1 (unused)
83 * \param [in] pitch1 (unused)
84 * \param [in] angle2 (unused)
85 * \param [in] pitch2 (unused)
87 static void
88 o_circle_fill_fill (GSCHEM_TOPLEVEL *w_current,
89 COLOR *color, CIRCLE *circle,
90 gint fill_width,
91 gint angle1, gint pitch1,
92 gint angle2, gint pitch2)
94 /* NOP: We'll fill it when we do the stroking */
97 /*! \brief Fill inside of circle with single line pattern.
98 * \par Function Description
99 * This function fills the inside of the circle with a pattern made of lines.
100 * The lines are drawn inside the circle with an angle <B>angle1</B> from the
101 * horizontal. The distance between two of these lines is given by
102 * <B>pitch1</B> and their width by <B>width</B>.
103 * Parameters <B>angle2</B>, <B>pitch2</B> are unused here but kept for
104 * compatibility with other circle filling functions.
106 * The circle is described by the coordinates of its center and its radius.
107 * Please not that it is not the way GDK take it. Translation is made
108 * afterward.
110 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
111 * for <B>angle1</B> and <B>angle2</B> is degree.
113 * The only attribute of line here is its width from the parameter <B>width</B>.
115 * Negative or null values for <B>pitch1</B> are not allowed as it leads to
116 * an endless loop.
118 * \param [in] w_current Schematic top level
119 * \param [in] color Circle fill color.
120 * \param [in] circle Circle to be drawn
121 * \param [in] fill_width
122 * \param [in] angle1 1st angle for pattern.
123 * \param [in] pitch1 1st pitch for pattern.
124 * \param [in] angle2 (unused)
125 * \param [in] pitch2 (unused)
127 static void
128 o_circle_fill_hatch (GSCHEM_TOPLEVEL *w_current,
129 COLOR *color, CIRCLE *circle,
130 gint fill_width,
131 gint angle1, gint pitch1,
132 gint angle2, gint pitch2)
134 int i;
135 GArray *lines;
137 gschem_cairo_set_source_color (w_current, color);
139 lines = g_array_new (FALSE, FALSE, sizeof (LINE));
140 m_hatch_circle (circle, angle1, pitch1, lines);
142 for (i=0; i < lines->len; i++) {
143 LINE *line = &g_array_index (lines, LINE, i);
145 gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0],
146 line->x[1], line->y[1]);
148 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1);
150 g_array_free (lines, TRUE);
153 /*! \brief Fill inside of circle with mesh pattern.
154 * \par Function Description
155 * This function fills the inside of the circle with a pattern made of set
156 * of parallel lines in two directions. The first set is drawn inside the
157 * circle with an angle <B>angle1</B> from the horizontal. The distance between
158 * two of these lines is given by <B>pitch1</B>.
159 * The second set is drawn inside the circle with an angle <B>angle2</B> from
160 * the horizontal. The distance between two of these lines is given by
161 * <B>pitch2</B>.
162 * Every lines have the same width given by <B>width</B>.
164 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
165 * for <B>angle1</B> and <B>angle2</B> is degree.
167 * This function simply makes two successive calls to the function
168 * #o_circle_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
169 * <B>angle2</B>, <B>pitch2</B> for parameters.
171 * \param [in] w_current Schematic top level
172 * \param [in] color Circle fill color.
173 * \param [in] circle Circle to be drawn
174 * \param [in] fill_width
175 * \param [in] angle1 1st angle for pattern.
176 * \param [in] pitch1 1st pitch for pattern.
177 * \param [in] angle2 2nd angle for pattern.
178 * \param [in] pitch2 2nd pitch for pattern.
180 static void
181 o_circle_fill_mesh (GSCHEM_TOPLEVEL *w_current,
182 COLOR *color, CIRCLE *circle,
183 gint fill_width,
184 gint angle1, gint pitch1,
185 gint angle2, gint pitch2)
187 o_circle_fill_hatch (w_current, color, circle,
188 fill_width, angle1, pitch1, -1, -1);
189 o_circle_fill_hatch (w_current, color, circle,
190 fill_width, angle2, pitch2, -1, -1);
195 /*! \brief Draw a circle on the screen.
196 * \par Function Description
197 * This function is used to draw a circle on screen. The circle is described
198 * by the OBJECT which is referred by <B>o_current</B>. The display is done
199 * according to the current state, given by the GSCHEM_TOPLEVEL object pointed by
200 * <B>w_current</B>.
202 * It first checks if the OBJECT pointed is valid or not. If not it
203 * returns and do not output anything. That should never happen though.
205 * \param [in] w_current The GSCHEM_TOPLEVEL object.
206 * \param [in] o_current Circle OBJECT to draw.
208 void o_circle_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
210 int angle1, pitch1, angle2, pitch2;
211 FILL_FUNC fill_func;
213 if (o_current->circle == NULL) {
214 return;
218 * The draw of the circle is divided in two steps : first step is to draw
219 * the outline, the second is to draw the filling pattern inside (if any).
221 * Finally the function takes care of the grips.
225 * The values needed for the fill operation are taken from the
226 * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
227 * width of the lines (if the fill use line) and angles and pitchs for hatch
228 * based filling.
230 * Once again the width of the line is important as if it is equal to 0 it
231 * may not be displayed. That is definetely not what we are looking for.
233 * Depending on the type of fill that has to be used inside the circle the
234 * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
235 * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
236 * possible functions are the following : #o_circle_fill_hollow(),
237 * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
239 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
240 * lead to an endless loop in function called after. It happens when the
241 * zoom factor is too small for two lines separated by the pitch to be
242 * distinct. If such a case is encountered the circle is filled hollow
243 * (e.q. not filled).
246 angle1 = o_current->fill_angle1;
247 pitch1 = o_current->fill_pitch1;
248 angle2 = o_current->fill_angle2;
249 pitch2 = o_current->fill_pitch2;
251 switch(o_current->fill_type) {
252 case FILLING_HOLLOW:
253 angle1 = -1; angle2 = -1;
254 pitch1 = 1; pitch2 = 1;
256 * this function is empty ! however if it do not use it we have to add
257 * a test before the call. Simply putting a return here instead is not
258 * possible as it would prevent any hollow circle from having its grips
260 fill_func = o_circle_fill_hollow;
261 break;
263 case FILLING_FILL:
264 angle1 = -1; angle2 = -1;
265 pitch1 = 1; pitch2 = 1;
266 fill_func = o_circle_fill_fill;
267 break;
269 case FILLING_MESH:
270 fill_func = o_circle_fill_mesh;
271 break;
273 case FILLING_HATCH:
274 angle2 = -1;
275 pitch2 = 1;
276 fill_func = o_circle_fill_hatch;
277 break;
279 case FILLING_VOID:
280 default:
281 angle1 = -1; angle2 = -1;
282 pitch1 = 1; pitch2 = 1;
283 fill_func = o_circle_fill_hollow;
284 fprintf (stderr, _("Unknown type for circle (fill)!\n"));
287 if ((pitch1 <= 0) || (pitch2 <= 0))
288 fill_func = o_circle_fill_fill;
290 (*fill_func) (w_current, o_drawing_color (w_current, o_current),
291 o_current->circle, o_current->fill_width,
292 angle1, pitch1, angle2, pitch2);
294 gschem_cairo_arc (w_current, o_current->line_width,
295 o_current->circle->center_x,
296 o_current->circle->center_y,
297 o_current->circle->radius, 0, 360);
299 gschem_cairo_set_source_color (w_current,
300 o_drawing_color (w_current, o_current));
301 if (o_current->fill_type == FILLING_FILL)
302 cairo_fill_preserve (w_current->cr);
303 gschem_cairo_stroke (w_current, o_current->line_type,
304 o_current->line_end,
305 o_current->line_width,
306 o_current->line_length,
307 o_current->line_space);
309 if (o_current->selected && w_current->draw_grips)
310 o_circle_draw_grips (w_current, o_current);
314 /*! \todo Finish function documentation!!!
315 * \brief
316 * \par Function Description
319 void o_circle_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
321 int cx, cy, radius;
323 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &cx, &cy);
324 radius = SCREENabs (w_current, w_current->distance);
326 o_invalidate_rect (w_current, cx - radius, cy - radius,
327 cx + radius, cy + radius);
330 /*! \brief Draw a circle described by OBJECT with translation
331 * \par Function Description
332 * This function draws the circle object described by <B>*o_current</B>
333 * translated by the vector (<B>dx</B>,<B>dy</B>).
334 * The translation vector is in world unit.
336 * The circle is displayed with the color of the object.
338 * \param [in] w_current The GSCHEM_TOPLEVEL object.
339 * \param [in] dx Delta x coordinate for circle.
340 * \param [in] dy Delta y coordinate for circle.
341 * \param [in] o_current Circle OBJECT to draw.
343 * \todo
344 * add in offsets, get rid of global diffs_x,y
346 void o_circle_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
348 g_return_if_fail (o_current->circle != NULL);
350 gschem_cairo_arc (w_current, 0, o_current->circle->center_x + dx,
351 o_current->circle->center_y + dy,
352 o_current->circle->radius, 0, 360);
354 gschem_cairo_set_source_color (w_current,
355 x_color_lookup_dark (o_current->color));
356 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
359 /*! \brief Start process to input a new circle.
360 * \par Function Description
361 * This function starts the process to input a new circle. Parameters for
362 * this circle are pu into/extracted from the <B>w_current</B> toplevel
363 * structure.
364 * <B>w_x</B> and <B>w_y</B> are current coordinates of the mouse pointer in
365 * world units.
367 * The first step of the circle input is to set the center of the arc.
368 * This center is kept in (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
370 * \param [in] w_current The GSCHEM_TOPLEVEL object.
371 * \param [in] w_x Current x coordinate of pointer in world units.
372 * \param [in] w_y Current y coordinate of pointer in world units.
374 void o_circle_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
376 /* center of circle */
377 w_current->first_wx = w_x;
378 w_current->first_wy = w_y;
380 /* radius */
381 w_current->distance = 0;
383 /* first temporary circle */
384 o_circle_invalidate_rubber (w_current);
385 w_current->rubber_visible = 1;
388 /*! \brief End the input of a circle.
389 * \par Function Description
390 * This function ends the input of the radius of the circle.
391 * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius
392 * segment, i.e. on the circle. The distance between this point and the
393 * center is the radius of the circle.
394 * <B>w_x</B> and <B>w_y</B> are in world coords.
396 * The center has previously been input and saved as
397 * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
399 * The temporary circle drawn during the input of the radius is erased.
400 * A new object is allocated, initialized and linked in the object list.
401 * This new object is finally drawn.
403 * \param [in] w_current The GSCHEM_TOPLEVEL object.
404 * \param [in] w_x (unused)
405 * \param [in] w_y (unused)
407 void o_circle_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
409 TOPLEVEL *toplevel = w_current->toplevel;
410 OBJECT *new_obj;
412 g_assert( w_current->inside_action != 0 );
414 /* erase the temporary circle */
415 /* o_circle_invalidate_rubber (w_current); */
416 w_current->rubber_visible = 0;
418 /* circle with null radius are not allowed */
419 if (w_current->distance == 0) {
420 /* cancel the object creation */
421 return;
424 /* create the object */
425 new_obj = o_circle_new (toplevel, OBJ_CIRCLE, GRAPHIC_COLOR,
426 w_current->first_wx, w_current->first_wy,
427 w_current->distance);
428 s_page_append (toplevel, toplevel->page_current, new_obj);
430 /* Call add-objects-hook */
431 g_run_hook_object (w_current, "%add-objects-hook", new_obj);
433 toplevel->page_current->CHANGED = 1;
434 o_undo_savestate(w_current, UNDO_ALL);
437 /*! \brief Draw temporary circle while dragging edge.
438 * \par Function Description
439 * This function draws a circle according to its internal representation and
440 * allows the modification of its radius. The radius is updated according to
441 * the current mouse position in <B>w_x</B> and <B>w_y</B>.
442 * It draws a full circle and the horizontal segment of the radius in the
443 * right half of the circle.
445 * The previous temporary circle is erased, the radius is then computed and
446 * updated and finally a new temporary circle is drawn.
448 * The arc is internally described by :
449 * <DL>
450 * <DT>*</DT><DD>(<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) as its
451 * center ;
452 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
453 * </DL>
455 * \param [in] w_current The GSCHEM_TOPLEVEL object.
456 * \param [in] w_x Current x coordinate of pointer in world units.
457 * \param [in] w_y Current y coordinate of pointer in world units.
459 void o_circle_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
461 int diff_x, diff_y;
463 g_assert( w_current->inside_action != 0 );
465 /* erase the previous temporary circle if it is visible */
466 if (w_current->rubber_visible)
467 o_circle_invalidate_rubber (w_current);
470 * The radius is taken as the biggest distance on the x and y axis between
471 * the center of the circle and the mouse position.
473 diff_x = abs(w_current->first_wx - w_x);
474 diff_y = abs(w_current->first_wy - w_y);
475 w_current->distance = max(diff_x, diff_y);
477 /* draw the new temporary circle */
478 o_circle_invalidate_rubber (w_current);
479 w_current->rubber_visible =1;
482 /*! \brief Draw circle from GSCHEM_TOPLEVEL object.
483 * \par Function Description
484 * This function draws the circle from the variables in the GSCHEM_TOPLEVEL
485 * structure <B>*w_current</B>.
486 * The center of the circle is at (<B>w_current->first_wx</B>,
487 * <B>w_current->first_wy</B>) and its radius is in <B>w_current->distance</B>.
489 * It draws a horizontal radius segment on the right half of the circle and
490 * the circle with the selection color.
492 * \param [in] w_current The GSCHEM_TOPLEVEL object.
494 void o_circle_draw_rubber (GSCHEM_TOPLEVEL *w_current)
496 gschem_cairo_arc (w_current, 0, w_current->first_wx,
497 w_current->first_wy,
498 w_current->distance, 0, 360);
500 gschem_cairo_line (w_current, END_NONE, 0,
501 w_current->first_wx,
502 w_current->first_wy,
503 w_current->first_wx + w_current->distance,
504 w_current->first_wy);
506 gschem_cairo_set_source_color (w_current,
507 x_color_lookup_dark (SELECT_COLOR));
508 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
511 /*! \brief Draw grip marks on circle.
512 * \par Function Description
513 * This function draws the grip that match the circle object <B>*o_current</B>.
515 * \param [in] w_current The GSCHEM_TOPLEVEL object.
516 * \param [in] o_current Circle OBJECT to draw grip points on.
518 void o_circle_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
520 if (w_current->draw_grips == FALSE)
521 return;
523 /* grip on lower right corner of the square */
524 o_grips_draw (w_current,
525 o_current->circle->center_x + o_current->circle->radius,
526 o_current->circle->center_y - o_current->circle->radius);