Bumped versions to 1.1.2/20070818/30:2:0 for the next development snapshot
[geda-gaf/whiteaudio.git] / gschem / src / o_circle.c
blob3295fcb9560ef97b7cf45899f483de1a5bdac8c1
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
21 #include <stdio.h>
22 #include <math.h>
24 #include <libgeda/libgeda.h>
26 #include "../include/globals.h"
27 #include "../include/prototype.h"
29 #ifdef HAVE_LIBDMALLOC
30 #include <dmalloc.h>
31 #endif
33 /* Kazu on July 16, 1999 - Added these macros to simplify the code */
34 #define GET_BOX_WIDTH(w) \
35 abs((w)->last_x - (w)->start_x)
36 #define GET_BOX_HEIGHT(w) \
37 abs((w)->last_y - (w)->start_y)
39 typedef void (*DRAW_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
40 GdkCapStyle cap, gint x, gint y, gint radius,
41 gint angle1, gint angle2,
42 gint arc_width, gint length, gint space );
44 typedef void (*FILL_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
45 gint x, gint y, gint radius,
46 gint fill_width, gint angle1, gint pitch1,
47 gint angle2, gint pitch2 );
49 /*! \brief Draw a circle on the screen.
50 * \par Function Description
51 * This function is used to draw a circle on screen. The circle is described
52 * by the OBJECT which is referred by <B>o_current</B>. The display is done
53 * according to the current state, given by the TOPLEVEL object pointed by
54 * <B>w_current</B>.
56 * It first checks if the OBJECT pointed is valid or not. If not it
57 * returns and do not output anything. That should never happen though.
59 * \param [in] w_current The TOPLEVEL object.
60 * \param [in] o_current Circle OBJECT to draw.
62 void o_circle_draw(TOPLEVEL *w_current, OBJECT *o_current)
64 int wleft, wright, wtop, wbottom; /* world bounds */
65 int s_x, s_y;
66 int radius;
67 int circle_width, length, space;
68 int fill_width, angle1, pitch1, angle2, pitch2;
69 GdkCapStyle circle_end;
70 GdkColor *color;
71 DRAW_FUNC draw_func = NULL;
72 FILL_FUNC fill_func;
74 if (o_current->circle == NULL) {
75 return;
79 * Get read to check for visibility of this line by using it's
80 * bounding box
82 world_get_circle_bounds(w_current, o_current,
83 &wleft, &wtop, &wright, &wbottom);
85 if ( (w_current->DONT_REDRAW == 1) ||
86 (!visible(w_current, wleft, wtop, wright, wbottom)) ) {
87 return;
90 #if DEBUG
91 printf("drawing circle\n\n");
92 #endif
95 * The draw of the circle is divided in two steps : first step is to draw
96 * the outline, the second is to draw the filling pattern inside (if any).
98 * Finally the function takes care of the grips.
100 if (w_current->override_color != -1 ) {
101 color = x_get_color(w_current->override_color);
102 } else {
103 color = x_get_color(o_current->color);
106 radius = SCREENabs( w_current, o_current->circle->radius );
109 * The values describing the line type are extracted from the
110 * <B>o_current</B> pointed structure. These are the width of the line, the
111 * field called length and the field called space and the desired end type
112 * for the line.
114 * Depending on the type of the line that has to be used to draw the circle
115 * the appropriate function is called. Values of space and length are
116 * adapted to the type of line. The possible functions are the following :
117 * #o_arc_draw_solid(), #o_arc_draw_dotted(), #o_arc_draw_dashed() and
118 * #o_arc_draw_phantom(). Therefore it reuses the code from arc primitive.
120 * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it lead
121 * to an endless loop in function called after. If such a case is encountered
122 * the circle is drawn as a solid circle independently of its initial type.
124 circle_width = SCREENabs( w_current, o_current->line_width );
125 if(circle_width <= 0) {
126 circle_width = 1;
129 length = SCREENabs( w_current, o_current->line_length );
130 space = SCREENabs( w_current, o_current->line_space );
132 switch(o_current->line_end) {
133 case END_NONE: circle_end = GDK_CAP_BUTT; break;
134 case END_SQUARE: circle_end = GDK_CAP_PROJECTING; break;
135 case END_ROUND: circle_end = GDK_CAP_ROUND; break;
136 default: fprintf(stderr, _("Unknown end for circle\n"));
137 circle_end = GDK_CAP_BUTT;
138 break;
141 switch(o_current->line_type) {
142 case TYPE_SOLID:
143 length = -1;
144 space = -1;
145 draw_func = o_arc_draw_solid;
146 break;
148 case TYPE_DOTTED:
149 length = -1; /* ..._draw_dotted only space used */
150 draw_func = o_arc_draw_dotted;
151 break;
153 case TYPE_DASHED:
154 draw_func = o_arc_draw_dashed;
155 break;
157 case TYPE_CENTER:
158 draw_func = o_arc_draw_center;
159 break;
161 case TYPE_PHANTOM:
162 draw_func = o_arc_draw_phantom;
163 break;
165 case TYPE_ERASE:
166 break;
168 default:
169 length = -1;
170 space = -1;
171 circle_width = 0; /* just to be careful */
172 fprintf(stderr, _("Unknown type for circle!\n"));
173 draw_func = o_arc_draw_solid;
174 break;
177 if((length == 0) || (space == 0))
178 draw_func = o_arc_draw_solid;
180 WORLDtoSCREEN( w_current, o_current->circle->center_x, o_current->circle->center_y,
181 &s_x, &s_y );
183 (*draw_func)(w_current->window, w_current->gc, color,
184 circle_end,
185 s_x, s_y,
186 radius,
187 0, FULL_CIRCLE / 64,
188 circle_width, length, space);
189 (*draw_func)(w_current->backingstore, w_current->gc, color,
190 circle_end,
191 s_x, s_y,
192 radius,
193 0, FULL_CIRCLE / 64,
194 circle_width, length, space);
197 * The values needed for the fill operation are taken from the
198 * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
199 * width of the lines (if the fill use line) and angles and pitchs for hatch
200 * based filling.
202 * Once again the width of the line is important as if it is equal to 0 it
203 * may not be displayed. That is definetely not what we are looking for.
205 * Depending on the type of fill that has to be used inside the circle the
206 * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
207 * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
208 * possible functions are the following : #o_circle_fill_hollow(),
209 * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
211 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
212 * lead to an endless loop in function called after. It happens when the
213 * zoom factor is too small for two lines separated by the pitch to be
214 * distinct. If such a case is encountered the circle is filled hollow
215 * (e.q. not filled).
217 fill_width = SCREENabs( w_current, o_current->fill_width );
218 if( fill_width <= 0) {
219 fill_width = 1;
222 angle1 = o_current->fill_angle1;
223 pitch1 = SCREENabs( w_current, o_current->fill_pitch1 );
224 angle2 = o_current->fill_angle2;
225 pitch2 = SCREENabs( w_current, o_current->fill_pitch2 );
227 switch(o_current->fill_type) {
228 case FILLING_HOLLOW:
229 angle1 = -1; angle2 = -1;
230 pitch1 = 1; pitch2 = 1;
232 * this function is empty ! however if it do not use it we have to add
233 * a test before the call. Simply putting a return here instead is not
234 * possible as it would prevent any hollow circle from having its grips
236 fill_func = o_circle_fill_hollow;
237 break;
239 case FILLING_FILL:
240 angle1 = -1; angle2 = -1;
241 pitch1 = 1; pitch2 = 1;
242 fill_func = o_circle_fill_fill;
243 break;
245 case FILLING_MESH:
246 fill_func = o_circle_fill_mesh;
247 break;
249 case FILLING_HATCH:
250 angle2 = -1;
251 pitch2 = 1;
252 fill_func = o_circle_fill_hatch;
253 break;
255 case FILLING_VOID:
256 default:
257 angle1 = -1; angle2 = -1;
258 pitch1 = 1; pitch2 = 1;
259 fill_func = o_circle_fill_hollow;
260 fprintf(stderr, _("Unknown type for circle (fill)!\n"));
263 if((pitch1 <= 0) || (pitch2 <= 0)) {
264 fill_func = o_circle_fill_fill;
267 (*fill_func)(w_current->window, w_current->gc, color,
268 s_x, s_y,
269 radius,
270 fill_width, angle1, pitch1, angle2, pitch2);
271 (*fill_func)(w_current->backingstore, w_current->gc, color,
272 s_x, s_y,
273 radius,
274 fill_width, angle1, pitch1, angle2, pitch2);
276 #if DEBUG
277 printf("drawing circle\n");
278 #endif
280 if (o_current->draw_grips && w_current->draw_grips == TRUE) {
282 /* pb20011010 - modified to use the new o_circle_[draw|erase]_grips() */
283 if (!o_current->selected) {
284 /* object is no more selected, erase the grips */
285 o_current->draw_grips = FALSE;
286 o_circle_erase_grips(w_current, o_current);
287 } else {
288 /* object is selected, draw the grips */
289 o_circle_draw_grips(w_current, o_current);
294 /*! \brief Placeholder filling function.
295 * \par Function Description
296 * This function does nothing. It has the same prototype as all the filling
297 * functions. It prevent from making a difference between filling in function
298 * #o_circle_draw().
300 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
301 * for <B>angle1</B> and <B>angle2</B> is degree.
303 * \param [in] w GdkDrawable to draw in.
304 * \param [in] gc GdkGC graphics context to draw on.
305 * \param [in] color Circle fill color.
306 * \param [in] x Center x coordinate of Circle.
307 * \param [in] y Center y coordinate of Circle.
308 * \param [in] radius Radius of Circle.
309 * \param [in] width Circle pattern fill width.
310 * \param [in] angle1 1st angle for pattern.
311 * \param [in] pitch1 1st pitch for pattern.
312 * \param [in] angle2 2nd angle for pattern.
313 * \param [in] pitch2 2nd pitch for pattern.
315 void o_circle_fill_hollow(GdkDrawable *w, GdkGC *gc, GdkColor *color,
316 gint x, gint y, gint radius,
317 gint width,
318 gint angle1, gint pitch1, gint angle2, gint pitch2)
323 /*! \brief Fill inside of circle with a solid pattern.
324 * \par Function Description
325 * This function fills the inside of the circle with a solid pattern.
326 * Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>, <B>pitch2</B>
327 * and <B>width</B> are unused here but kept for compatibility with other
328 * circle filling functions.
330 * The circle is described by the coordinates of its center and its radius.
331 * Please not that it is not the way GDK take it. Translation is made
332 * afterward.
334 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
335 * for <B>angle1</B> and <B>angle2</B> is degree.
337 * The solid fill is done with the #gdk_draw_arc() function and its
338 * parameters <B>filled</B> set. The circle is filled with the color
339 * <B>color</B> given as a parameter to the function.
341 * \param [in] w GdkDrawable to draw in.
342 * \param [in] gc GdkGC graphics context to draw on.
343 * \param [in] color Circle fill color.
344 * \param [in] x Center x coordinate of Circle.
345 * \param [in] y Center y coordinate of Circle.
346 * \param [in] radius Radius of Circle.
347 * \param [in] width (unused)
348 * \param [in] angle1 (unused)
349 * \param [in] pitch1 (unused)
350 * \param [in] angle2 (unused)
351 * \param [in] pitch2 (unused)
353 void o_circle_fill_fill(GdkDrawable *w, GdkGC *gc, GdkColor *color,
354 gint x, gint y, gint radius,
355 gint width,
356 gint angle1, gint pitch1, gint angle2, gint pitch2)
358 gdk_gc_set_foreground(gc, color);
359 gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID,
360 GDK_CAP_BUTT, GDK_JOIN_MITER);
362 gdk_draw_arc(w, gc,
363 TRUE, x-radius, y-radius, 2*radius, 2*radius, 0, FULL_CIRCLE);
367 /*! \brief Fill inside of circle with single line pattern.
368 * \par Function Description
369 * This function fills the inside of the circle with a pattern made of lines.
370 * The lines are drawn inside the circle with an angle <B>angle1</B> from the
371 * horizontal. The distance between two of these lines is given by
372 * <B>pitch1</B> and their width by <B>width</B>.
373 * Parameters <B>angle2</B>, <B>pitch2</B> are unused here but kept for
374 * compatibility with other circle filling functions.
376 * The circle is described by the coordinates of its center and its radius.
377 * Please not that it is not the way GDK take it. Translation is made
378 * afterward.
380 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
381 * for <B>angle1</B> and <B>angle2</B> is degree.
383 * The only attribute of line here is its width from the parameter <B>width</B>.
385 * Negative or null values for <B>pitch1</B> are not allowed as it leads to
386 * an endless loop.
388 * \param [in] w GdkDrawable to draw in.
389 * \param [in] gc GdkGC graphics context to draw on.
390 * \param [in] color Circle fill color.
391 * \param [in] x Center x coordinate of Circle.
392 * \param [in] y Center y coordinate of Circle.
393 * \param [in] radius Radius of Circle.
394 * \param [in] width Circle pattern fill width.
395 * \param [in] angle1 1st angle for pattern.
396 * \param [in] pitch1 1st pitch for pattern.
397 * \param [in] angle2 (unused)
398 * \param [in] pitch2 (unused)
400 void o_circle_fill_hatch(GdkDrawable *w, GdkGC *gc, GdkColor *color,
401 gint x, gint y, gint radius,
402 gint width,
403 gint angle1, gint pitch1, gint angle2, gint pitch2)
405 double x0, y0, x1, y1, x2, y2;
406 double cos_a_, sin_a_;
408 gdk_gc_set_line_attributes(gc, width, GDK_LINE_SOLID,
409 GDK_CAP_BUTT, GDK_JOIN_MITER);
412 * The function use a matrix. Its elements are obtained from the sinus and
413 * cosinus of the angle <B>angle1</B>. It represent the rotation matrix that
414 * when applied to a point, rotate it of <B>angle1</B>.
416 cos_a_ = cos(((double) angle1) * M_PI/180);
417 sin_a_ = sin(((double) angle1) * M_PI/180);
420 * When drawing a line in a circle there is two intersections. It looks for
421 * the coordinates of one of these points when the line is horizontal.
422 * The second one can be easily obtained by symmetry in relation to the
423 * vertical axis going through the centre of the circle.
425 * These two points are then rotated of angle <B>angle1</B> using the
426 * elements of the rotation matrix previously computed.
428 * The corresponding line can be drawn providing that the coordinates
429 * are rounded.
431 * These operations are repeated for every horizontal line that can fit
432 * in the upper half of the circle (using and incrementing the variable
433 * <B>y0</B>).
435 y0 = 0;
436 while(y0 < (double) radius) {
437 x0 = pow((double) radius, 2) - pow(y0, 2);
438 x0 = sqrt(x0);
440 x1 = (x0*cos_a_ - y0*sin_a_) + x;
441 y1 = y - (x0*sin_a_ + y0*cos_a_);
442 x2 = ((-x0)*cos_a_ - y0*sin_a_) + x;
443 y2 = y - ((-x0)*sin_a_ + y0*cos_a_);
445 gdk_draw_line(w, gc,
446 (int) x1, (int) y1, (int) x2, (int) y2);
449 * The function use the symetry in relation to the centre of the circle.
450 * It avoid repetitive computation for the second half of the surface
451 * of the circle.
453 x1 = (x0*cos_a_ - (-y0)*sin_a_) + x;
454 y1 = y- (x0*sin_a_ + (-y0)*cos_a_);
455 x2 = ((-x0)*cos_a_ - (-y0)*sin_a_) + x;
456 y2 = y- ((-x0)*sin_a_ + (-y0)*cos_a_);
458 gdk_draw_line(w, gc, (int) x1, (int) y1, (int) x2, (int) y2);
460 y0 = y0 + pitch1;
464 /*! \brief Fill inside of circle with mesh pattern.
465 * \par Function Description
466 * This function fills the inside of the circle with a pattern made of set
467 * of parallel lines in two directions. The first set is drawn inside the
468 * circle with an angle <B>angle1</B> from the horizontal. The distance between
469 * two of these lines is given by <B>pitch1</B>.
470 * The second set is drawn inside the circle with an angle <B>angle2</B> from
471 * the horizontal. The distance between two of these lines is given by
472 * <B>pitch2</B>.
473 * Every lines have the same width given by <B>width</B>.
475 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
476 * for <B>angle1</B> and <B>angle2</B> is degree.
478 * This function simply makes two successive calls to the function
479 * #o_circle_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
480 * <B>angle2</B>, <B>pitch2</B> for parameters.
482 * \param [in] w GdkDrawable to draw in.
483 * \param [in] gc GdkGC graphics context to draw on.
484 * \param [in] color Circle fill color.
485 * \param [in] x Center x coordinate of Circle.
486 * \param [in] y Center y coordinate of Circle.
487 * \param [in] radius Radius of Circle.
488 * \param [in] width Circle pattern fill width.
489 * \param [in] angle1 1st angle for pattern.
490 * \param [in] pitch1 1st pitch for pattern.
491 * \param [in] angle2 2nd angle for pattern.
492 * \param [in] pitch2 2nd pitch for pattern.
494 void o_circle_fill_mesh(GdkDrawable *w, GdkGC *gc, GdkColor *color,
495 gint x, gint y, gint radius,
496 gint width,
497 gint angle1, gint pitch1, gint angle2, gint pitch2)
499 o_circle_fill_hatch(w, gc, color,
500 x, y, radius,
501 width, angle1, pitch1, -1, -1);
502 o_circle_fill_hatch(w, gc, color,
503 x, y, radius,
504 width, angle2, pitch2, -1, -1);
508 /*! \brief Erase a circle described by OBJECT
509 * \par Function Description
510 * This function erases a circle described in a #OBJECT structure
511 * pointed by <B>o_current</B>.
513 * It makes a call to the function #o_circle_draw() after setting the
514 * special color. Therefore a circle is drawn with background color over
515 * the previous one.
517 * \param [in] w_current The TOPLEVEL object.
518 * \param [in] o_current Circle OBJECT to erase.
520 void o_circle_erase(TOPLEVEL *w_current, OBJECT *o_current)
522 w_current->override_color = w_current->background_color;
523 o_circle_draw(w_current, o_current);
524 w_current->override_color = -1;
527 /*! \todo Finish function documentation!!!
528 * \brief
529 * \par Function Description
532 void o_circle_eraserubber(TOPLEVEL *w_current)
534 o_circle_rubbercircle_xor(w_current);
537 /*! \brief Draw a circle described by OBJECT with translation
538 * \par Function Description
539 * This function draws the circle object described by <B>*o_current</B>
540 * translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
541 * the current sheet.
542 * The translation vector is in screen unit.
544 * The circle is displayed with the color of the object.
546 * \param [in] w_current The TOPLEVEL object.
547 * \param [in] dx Delta x coordinate for circle.
548 * \param [in] dy Delta y coordinate for circle.
549 * \param [in] o_current Circle OBJECT to draw.
551 * \todo
552 * add in offsets, get rid of global diffs_x,y
554 void o_circle_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
556 int x, y, radius;
557 int color;
559 if (o_current->circle == NULL) {
560 return;
563 if (o_current->saved_color != -1) {
564 color = o_current->saved_color;
565 } else {
566 color = o_current->color;
569 /* radius of the circle */
570 radius = SCREENabs( w_current, o_current->circle->radius );
571 /* upper left corner of the square the circle is inscribed in */
572 /* gdk coords system */
573 WORLDtoSCREEN( w_current,
574 o_current->circle->center_x - o_current->circle->radius,
575 o_current->circle->center_y + o_current->circle->radius,
576 &x, &y );
578 /* translate the upper left corner */
579 x = x + dx;
580 y = y + dy;
582 /* To draw be sure to setup width height */
583 gdk_gc_set_foreground(w_current->outline_xor_gc,
584 x_get_darkcolor(color));
585 gdk_draw_arc(w_current->window, w_current->outline_xor_gc,
586 FALSE,
587 x, y,
588 2 * radius, 2 * radius,
589 0, FULL_CIRCLE);
591 /* backing store ? not appropriate here */
594 /*! \brief Start process to input a new circle.
595 * \par Function Description
596 * This function starts the process to input a new circle. Parameters for
597 * this circle are pu into/extracted from the <B>w_current</B> toplevel
598 * structure.
599 * <B>x</B> and <B>y</B> are current coordinates of the mouse pointer in
600 * screen units.
602 * The first step of the circle input is to set the center of the arc.
603 * This center is kept in (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
605 * \param [in] w_current The TOPLEVEL object.
606 * \param [in] x Current x coordinate of pointer in screen units.
607 * \param [in] y Current y coordinate of pointer in screen units.
609 void o_circle_start(TOPLEVEL *w_current, int x, int y)
611 /* center of circle */
612 w_current->last_x = w_current->start_x = fix_x(w_current, x);
613 w_current->last_y = w_current->start_y = fix_y(w_current, y);
614 /* radius */
615 w_current->distance = 0;
617 /* first temporary circle */
618 o_circle_rubbercircle_xor(w_current);
622 /*! \brief End the input of a circle.
623 * \par Function Description
624 * This function ends the input of the radius of the circle.
625 * The (<B>x</B>,<B>y</B>) point is taken as the other end of the radius
626 * segment, i.e. on the circle. The distance between this point and the
627 * center is the radius of the circle.
628 * <B>x</B> and <B>y</B> are in screen coords.
630 * The center has previously been input and saved as
631 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
633 * The temporary circle drawn during the input of the radius is erased.
634 * A new object is allocated, initialized and linked in the object list.
635 * This new object is finally drawn.
637 * \param [in] w_current The TOPLEVEL object.
638 * \param [in] x Current x coordinate of pointer in screen units.
639 * \param [in] y Current y coordinate of pointer in screen units.
641 void o_circle_end(TOPLEVEL *w_current, int x, int y)
643 int center_x, center_y;
644 int fx, fy;
645 int radius;
647 if (w_current->inside_action == 0) {
648 o_redraw(w_current, w_current->page_current->object_head, TRUE);
649 return;
652 /* erase the temporary circle */
653 o_circle_rubbercircle_xor(w_current);
655 /* get the last coords of the pointer */
656 fx = fix_x(w_current, x);
657 fy = fix_y(w_current, y);
658 /* compute the radius in screen unit */
659 w_current->distance = dist(w_current->start_x, w_current->start_y,
660 fx, fy);
662 /* circle with null radius are not allowed */
663 if (w_current->distance == 0) {
664 /* cancel the object creation */
665 w_current->start_x = -1;
666 w_current->start_y = -1;
667 w_current->last_x = -1;
668 w_current->last_y = -1;
669 w_current->distance = -1;
670 return;
673 /* get center coords in world unit */
674 SCREENtoWORLD(w_current,
675 w_current->start_x, w_current->start_y,
676 &center_x, &center_y);
677 /* get radius in world unit */
678 radius = snap_grid(w_current,
679 WORLDabs(w_current, w_current->distance));
681 /* create the object */
682 w_current->page_current->object_tail =
683 o_circle_add(w_current,
684 w_current->page_current->object_tail,
685 OBJ_CIRCLE, w_current->graphic_color,
686 center_x, center_y, radius);
688 /* draw it */
689 o_redraw_single(w_current, w_current->page_current->object_tail);
691 w_current->start_x = (-1);
692 w_current->start_y = (-1);
693 w_current->last_x = (-1);
694 w_current->last_y = (-1);
695 w_current->loc_x = (-1);
696 w_current->loc_y = (-1);
697 w_current->distance = (-1);
699 w_current->page_current->CHANGED = 1;
701 o_undo_savestate(w_current, UNDO_ALL);
704 /*! \brief Draw temporary circle while dragging edge.
705 * \par Function Description
706 * This function draws a circle according to its internal representation and
707 * allows the modification of its radius. The radius is updated according to
708 * the current mouse position in <B>x</B> and <B>y</B>.
709 * It draws a full circle and the horizontal segment of the radius in the
710 * right half of the circle.
712 * The previous temporary circle is erased, the radius is then computed and
713 * updated and finally a new temporary circle is drawn.
715 * The arc is internally described by :
716 * <DL>
717 * <DT>*</DT><DD>(<B>w_current->start_x</B>,<B>w_current->start_y</B>) as its
718 * center ;
719 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
720 * </DL>
722 * \param [in] w_current The TOPLEVEL object.
723 * \param [in] x Current x coordinate of pointer in screen units.
724 * \param [in] y Current y coordinate of pointer in screen units.
726 void o_circle_rubbercircle(TOPLEVEL *w_current, int x, int y)
728 int diff_x, diff_y;
730 if (w_current->inside_action == 0) {
731 o_redraw(w_current, w_current->page_current->object_head, TRUE);
732 return;
735 /* erase the previous temporary circle */
736 o_circle_rubbercircle_xor(w_current);
739 * The radius is taken as the biggest distance on the x and y axis between
740 * the center of the circle and the mouse position.
742 /* update the radius */
743 w_current->last_x = fix_x(w_current, x);
744 w_current->last_y = fix_y(w_current, y);
746 diff_x = GET_BOX_WIDTH (w_current);
747 diff_y = GET_BOX_HEIGHT(w_current);
748 if (diff_x >= diff_y) {
749 w_current->last_y = w_current->start_y;
750 w_current->distance = diff_x;
751 } else {
752 w_current->last_x = w_current->start_x;
753 w_current->distance = diff_y;
756 /* draw the new temporary circle */
757 o_circle_rubbercircle_xor(w_current);
761 /*! \brief Draw circle from TOPLEVEL object.
762 * \par Function Description
763 * This function draws the circle from the variables in the toplevel
764 * structure <B>*w_current</B>.
765 * The center of the circle is at (<B>w_current->start_x</B>,
766 * <B>w_current->start_y</B>) and its radius is in <B>w_current->distance</B>.
768 * It draws a horizontal radius segment on the right half of the circle and
769 * the circle with the selection color and an xor-function over the current
770 * sheet..
772 * \param [in] w_current The TOPLEVEL object.
774 void o_circle_rubbercircle_xor(TOPLEVEL *w_current)
776 /* draw the circle from the w_current variables */
777 gdk_gc_set_foreground(w_current->xor_gc,
778 x_get_darkcolor(w_current->select_color));
779 gdk_draw_line(w_current->window, w_current->xor_gc,
780 w_current->start_x, w_current->start_y,
781 w_current->start_x + w_current->distance,
782 w_current->start_y);
783 gdk_draw_arc(w_current->window, w_current->xor_gc, FALSE,
784 w_current->start_x - w_current->distance,
785 w_current->start_y - w_current->distance,
786 w_current->distance * 2,
787 w_current->distance * 2,
788 0, FULL_CIRCLE);
791 /*! \brief Draw grip marks on circle.
792 * \par Function Description
793 * This function draws the grip that match the circle object <B>*o_current</B>.
795 * \param [in] w_current The TOPLEVEL object.
796 * \param [in] o_current Circle OBJECT to draw grip points on.
798 void o_circle_draw_grips(TOPLEVEL *w_current, OBJECT *o_current)
800 int x, y;
802 if (w_current->draw_grips == FALSE)
803 return;
805 /* coords of the lower right corner of the square */
806 WORLDtoSCREEN( w_current,
807 o_current->circle->center_x + o_current->circle->radius,
808 o_current->circle->center_y - o_current->circle->radius,
809 &x, &y );
811 /* grip on lower right corner of the square */
812 o_grips_draw(w_current, x, y);
816 /*! \brief Erase grip marks from circle.
817 * \par Function Description
818 * The function erases the grips displayed on a circle object.
820 * A circle has a single grip on the lower right corner of the square it
821 * is inscribed in.
823 * \param [in] w_current The TOPLEVEL object.
824 * \param [in] o_current Circle OBJECT to erase grip marks from.
826 void o_circle_erase_grips(TOPLEVEL *w_current, OBJECT *o_current)
828 int x, y;
830 if (w_current->draw_grips == FALSE)
831 return;
833 /* coords of the lower right corner of square */
834 WORLDtoSCREEN( w_current,
835 o_current->circle->center_x + o_current->circle->radius,
836 o_current->circle->center_y - o_current->circle->radius,
837 &x, &y );
839 /* grip on lower right corner of the square */
840 o_grips_erase(w_current, x, y);