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
26 #ifdef HAVE_LIBDMALLOC
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
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.
56 o_circle_fill_hollow (GSCHEM_TOPLEVEL
*w_current
,
57 COLOR
*color
, CIRCLE
*circle
,
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
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)
88 o_circle_fill_fill (GSCHEM_TOPLEVEL
*w_current
,
89 COLOR
*color
, CIRCLE
*circle
,
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
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
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)
128 o_circle_fill_hatch (GSCHEM_TOPLEVEL
*w_current
,
129 COLOR
*color
, CIRCLE
*circle
,
131 gint angle1
, gint pitch1
,
132 gint angle2
, gint pitch2
)
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
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.
181 o_circle_fill_mesh (GSCHEM_TOPLEVEL
*w_current
,
182 COLOR
*color
, CIRCLE
*circle
,
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
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
;
213 if (o_current
->circle
== NULL
) {
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
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
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
) {
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
;
264 angle1
= -1; angle2
= -1;
265 pitch1
= 1; pitch2
= 1;
266 fill_func
= o_circle_fill_fill
;
270 fill_func
= o_circle_fill_mesh
;
276 fill_func
= o_circle_fill_hatch
;
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
,
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!!!
316 * \par Function Description
319 void o_circle_invalidate_rubber (GSCHEM_TOPLEVEL
*w_current
)
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.
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
364 * <B>w_x</B> and <B>w_y</B> are current coordinates of the mouse pointer in
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
;
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
;
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 */
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 :
450 * <DT>*</DT><DD>(<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) as its
452 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
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
)
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
,
498 w_current
->distance
, 0, 360);
500 gschem_cairo_line (w_current
, END_NONE
, 0,
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
)
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
);