Log name of expander function.
[geda-gaf/berndj.git] / gschem / src / o_circle.c
blob087368fec23b730cb96fde7d00ee48a882f92173
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 "gschem.h"
26 #ifdef HAVE_LIBDMALLOC
27 #include <dmalloc.h>
28 #endif
31 typedef void (*DRAW_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
32 GdkCapStyle cap, gint x, gint y, gint radius,
33 gint angle1, gint angle2,
34 gint arc_width, gint length, gint space );
36 typedef void (*FILL_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
37 gint x, gint y, gint radius,
38 gint fill_width, gint angle1, gint pitch1,
39 gint angle2, gint pitch2 );
41 /*! \brief Draw a circle on the screen.
42 * \par Function Description
43 * This function is used to draw a circle on screen. The circle is described
44 * by the OBJECT which is referred by <B>o_current</B>. The display is done
45 * according to the current state, given by the GSCHEM_TOPLEVEL object pointed by
46 * <B>w_current</B>.
48 * It first checks if the OBJECT pointed is valid or not. If not it
49 * returns and do not output anything. That should never happen though.
51 * \param [in] w_current The GSCHEM_TOPLEVEL object.
52 * \param [in] o_current Circle OBJECT to draw.
54 void o_circle_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
56 TOPLEVEL *toplevel = w_current->toplevel;
57 PAGE *page = toplevel->page_current;
58 int wleft, wright, wtop, wbottom; /* world bounds */
59 int s_x, s_y, w_x, w_y;
60 int radius;
61 int circle_width, length, space;
62 int fill_width, angle1, pitch1, angle2, pitch2;
63 GdkCapStyle circle_end;
64 GdkColor *color;
65 DRAW_FUNC draw_func = NULL;
66 FILL_FUNC fill_func;
68 if (o_current->circle == NULL) {
69 return;
73 * Get read to check for visibility of this line by using it's
74 * bounding box
76 world_get_single_object_bounds(o_current, &wleft, &wtop, &wright, &wbottom);
78 if ( (toplevel->DONT_REDRAW == 1) ||
79 (!visible(page, wleft, wtop, wright, wbottom)) ) {
80 return;
83 if (GEDA_DEBUG) {
84 printf("drawing circle\n\n");
88 * The draw of the circle is divided in two steps : first step is to draw
89 * the outline, the second is to draw the filling pattern inside (if any).
91 * Finally the function takes care of the grips.
93 if (toplevel->override_color != -1 ) {
94 color = x_get_color(toplevel->override_color);
95 } else {
96 color = x_get_color(o_current->color);
99 radius = SCREENabs(page, o_circle_get_radius(o_current));
102 * The values describing the line type are extracted from the
103 * <B>o_current</B> pointed structure. These are the width of the line, the
104 * field called length and the field called space and the desired end type
105 * for the line.
107 * Depending on the type of the line that has to be used to draw the circle
108 * the appropriate function is called. Values of space and length are
109 * adapted to the type of line. The possible functions are the following :
110 * #o_arc_draw_solid(), #o_arc_draw_dotted(), #o_arc_draw_dashed() and
111 * #o_arc_draw_phantom(). Therefore it reuses the code from arc primitive.
113 * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it lead
114 * to an endless loop in function called after. If such a case is encountered
115 * the circle is drawn as a solid circle independently of its initial type.
117 circle_width = SCREENabs(page, o_current->line_width);
118 if(circle_width <= 0) {
119 circle_width = 1;
122 length = SCREENabs(page, o_current->line_length);
123 space = SCREENabs(page, o_current->line_space);
125 switch(o_current->line_end) {
126 case END_NONE: circle_end = GDK_CAP_BUTT; break;
127 case END_SQUARE: circle_end = GDK_CAP_PROJECTING; break;
128 case END_ROUND: circle_end = GDK_CAP_ROUND; break;
129 default: fprintf(stderr, _("Unknown end for circle\n"));
130 circle_end = GDK_CAP_BUTT;
131 break;
134 switch(o_current->line_type) {
135 case TYPE_SOLID:
136 length = -1;
137 space = -1;
138 draw_func = o_arc_draw_solid;
139 break;
141 case TYPE_DOTTED:
142 length = -1; /* ..._draw_dotted only space used */
143 draw_func = o_arc_draw_dotted;
144 break;
146 case TYPE_DASHED:
147 draw_func = o_arc_draw_dashed;
148 break;
150 case TYPE_CENTER:
151 draw_func = o_arc_draw_center;
152 break;
154 case TYPE_PHANTOM:
155 draw_func = o_arc_draw_phantom;
156 break;
158 case TYPE_ERASE:
159 break;
161 default:
162 length = -1;
163 space = -1;
164 circle_width = 0; /* just to be careful */
165 fprintf(stderr, _("Unknown type for circle!\n"));
166 draw_func = o_arc_draw_solid;
167 break;
170 if((length == 0) || (space == 0))
171 draw_func = o_arc_draw_solid;
173 s_basic_get_grip(o_current, GRIP_CIRCLE_CENTER, &w_x, &w_y);
174 WORLDtoSCREEN(page, w_x, w_y, &s_x, &s_y);
176 (*draw_func)(w_current->backingstore, w_current->gc, color,
177 circle_end,
178 s_x, s_y,
179 radius,
180 0, FULL_CIRCLE / 64,
181 circle_width, length, space);
184 * The values needed for the fill operation are taken from the
185 * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
186 * width of the lines (if the fill use line) and angles and pitchs for hatch
187 * based filling.
189 * Once again the width of the line is important as if it is equal to 0 it
190 * may not be displayed. That is definitely not what we are looking for.
192 * Depending on the type of fill that has to be used inside the circle the
193 * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
194 * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
195 * possible functions are the following : #o_circle_fill_hollow(),
196 * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
198 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
199 * lead to an endless loop in function called after. It happens when the
200 * zoom factor is too small for two lines separated by the pitch to be
201 * distinct. If such a case is encountered the circle is filled hollow
202 * (e.q. not filled).
204 fill_width = SCREENabs(page, o_current->fill_width);
205 if( fill_width <= 0) {
206 fill_width = 1;
209 angle1 = o_current->fill_angle1;
210 pitch1 = SCREENabs(page, o_current->fill_pitch1);
211 angle2 = o_current->fill_angle2;
212 pitch2 = SCREENabs(page, o_current->fill_pitch2);
214 switch(o_current->fill_type) {
215 case FILLING_HOLLOW:
216 angle1 = -1; angle2 = -1;
217 pitch1 = 1; pitch2 = 1;
219 * this function is empty ! however if it do not use it we have to add
220 * a test before the call. Simply putting a return here instead is not
221 * possible as it would prevent any hollow circle from having its grips
223 fill_func = o_circle_fill_hollow;
224 break;
226 case FILLING_FILL:
227 angle1 = -1; angle2 = -1;
228 pitch1 = 1; pitch2 = 1;
229 fill_func = o_circle_fill_fill;
230 break;
232 case FILLING_MESH:
233 fill_func = o_circle_fill_mesh;
234 break;
236 case FILLING_HATCH:
237 angle2 = -1;
238 pitch2 = 1;
239 fill_func = o_circle_fill_hatch;
240 break;
242 case FILLING_VOID:
243 default:
244 angle1 = -1; angle2 = -1;
245 pitch1 = 1; pitch2 = 1;
246 fill_func = o_circle_fill_hollow;
247 fprintf(stderr, _("Unknown type for circle (fill)!\n"));
250 if((pitch1 <= 0) || (pitch2 <= 0)) {
251 fill_func = o_circle_fill_fill;
254 (*fill_func)(w_current->backingstore, w_current->gc, color,
255 s_x, s_y,
256 radius,
257 fill_width, angle1, pitch1, angle2, pitch2);
259 if (GEDA_DEBUG) {
260 printf("drawing circle\n");
264 /*! \brief Placeholder filling function.
265 * \par Function Description
266 * This function does nothing. It has the same prototype as all the filling
267 * functions. It prevent from making a difference between filling in function
268 * #o_circle_draw().
270 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
271 * for <B>angle1</B> and <B>angle2</B> is degree.
273 * \param [in] w GdkDrawable to draw in.
274 * \param [in] gc GdkGC graphics context to draw on.
275 * \param [in] color Circle fill color.
276 * \param [in] x Center x coordinate of Circle.
277 * \param [in] y Center y coordinate of Circle.
278 * \param [in] radius Radius of Circle.
279 * \param [in] width Circle pattern fill width.
280 * \param [in] angle1 1st angle for pattern.
281 * \param [in] pitch1 1st pitch for pattern.
282 * \param [in] angle2 2nd angle for pattern.
283 * \param [in] pitch2 2nd pitch for pattern.
285 void o_circle_fill_hollow(GdkDrawable *w, GdkGC *gc, GdkColor *color,
286 gint x, gint y, gint radius,
287 gint width,
288 gint angle1, gint pitch1, gint angle2, gint pitch2)
293 /*! \brief Fill inside of circle with a solid pattern.
294 * \par Function Description
295 * This function fills the inside of the circle with a solid pattern.
296 * Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>, <B>pitch2</B>
297 * and <B>width</B> are unused here but kept for compatibility with other
298 * circle filling functions.
300 * The circle is described by the coordinates of its center and its radius.
301 * Please not that it is not the way GDK take it. Translation is made
302 * afterward.
304 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
305 * for <B>angle1</B> and <B>angle2</B> is degree.
307 * The solid fill is done with the #gdk_draw_arc() function and its
308 * parameters <B>filled</B> set. The circle is filled with the color
309 * <B>color</B> given as a parameter to the function.
311 * \param [in] w GdkDrawable to draw in.
312 * \param [in] gc GdkGC graphics context to draw on.
313 * \param [in] color Circle fill color.
314 * \param [in] x Center x coordinate of Circle.
315 * \param [in] y Center y coordinate of Circle.
316 * \param [in] radius Radius of Circle.
317 * \param [in] width (unused)
318 * \param [in] angle1 (unused)
319 * \param [in] pitch1 (unused)
320 * \param [in] angle2 (unused)
321 * \param [in] pitch2 (unused)
323 void o_circle_fill_fill(GdkDrawable *w, GdkGC *gc, GdkColor *color,
324 gint x, gint y, gint radius,
325 gint width,
326 gint angle1, gint pitch1, gint angle2, gint pitch2)
328 gdk_gc_set_foreground(gc, color);
329 gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID,
330 GDK_CAP_BUTT, GDK_JOIN_MITER);
332 gdk_draw_arc(w, gc,
333 TRUE, x-radius, y-radius, 2*radius, 2*radius, 0, FULL_CIRCLE);
337 /*! \brief Fill inside of circle with single line pattern.
338 * \par Function Description
339 * This function fills the inside of the circle with a pattern made of lines.
340 * The lines are drawn inside the circle with an angle <B>angle1</B> from the
341 * horizontal. The distance between two of these lines is given by
342 * <B>pitch1</B> and their width by <B>width</B>.
343 * Parameters <B>angle2</B>, <B>pitch2</B> are unused here but kept for
344 * compatibility with other circle filling functions.
346 * The circle is described by the coordinates of its center and its radius.
347 * Please not that it is not the way GDK take it. Translation is made
348 * afterward.
350 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
351 * for <B>angle1</B> and <B>angle2</B> is degree.
353 * The only attribute of line here is its width from the parameter <B>width</B>.
355 * Negative or null values for <B>pitch1</B> are not allowed as it leads to
356 * an endless loop.
358 * \param [in] w GdkDrawable to draw in.
359 * \param [in] gc GdkGC graphics context to draw on.
360 * \param [in] color Circle fill color.
361 * \param [in] x Center x coordinate of Circle.
362 * \param [in] y Center y coordinate of Circle.
363 * \param [in] radius Radius of Circle.
364 * \param [in] width Circle pattern fill width.
365 * \param [in] angle1 1st angle for pattern.
366 * \param [in] pitch1 1st pitch for pattern.
367 * \param [in] angle2 (unused)
368 * \param [in] pitch2 (unused)
370 void o_circle_fill_hatch(GdkDrawable *w, GdkGC *gc, GdkColor *color,
371 gint x, gint y, gint radius,
372 gint width,
373 gint angle1, gint pitch1, gint angle2, gint pitch2)
375 double x0, y0, x1, y1, x2, y2;
376 double cos_a_, sin_a_;
378 gdk_gc_set_line_attributes(gc, width, GDK_LINE_SOLID,
379 GDK_CAP_BUTT, GDK_JOIN_MITER);
382 * The function use a matrix. Its elements are obtained from the sinus and
383 * cosinus of the angle <B>angle1</B>. It represent the rotation matrix that
384 * when applied to a point, rotate it of <B>angle1</B>.
386 cos_a_ = cos(((double) angle1) * M_PI/180);
387 sin_a_ = sin(((double) angle1) * M_PI/180);
390 * When drawing a line in a circle there is two intersections. It looks for
391 * the coordinates of one of these points when the line is horizontal.
392 * The second one can be easily obtained by symmetry in relation to the
393 * vertical axis going through the centre of the circle.
395 * These two points are then rotated of angle <B>angle1</B> using the
396 * elements of the rotation matrix previously computed.
398 * The corresponding line can be drawn providing that the coordinates
399 * are rounded.
401 * These operations are repeated for every horizontal line that can fit
402 * in the upper half of the circle (using and incrementing the variable
403 * <B>y0</B>).
405 y0 = 0;
406 while(y0 < (double) radius) {
407 x0 = pow((double) radius, 2) - pow(y0, 2);
408 x0 = sqrt(x0);
410 x1 = (x0*cos_a_ - y0*sin_a_) + x;
411 y1 = y - (x0*sin_a_ + y0*cos_a_);
412 x2 = ((-x0)*cos_a_ - y0*sin_a_) + x;
413 y2 = y - ((-x0)*sin_a_ + y0*cos_a_);
415 gdk_draw_line(w, gc,
416 (int) x1, (int) y1, (int) x2, (int) y2);
419 * The function use the symmetry in relation to the centre of the circle.
420 * It avoid repetitive computation for the second half of the surface
421 * of the circle.
423 x1 = (x0*cos_a_ - (-y0)*sin_a_) + x;
424 y1 = y- (x0*sin_a_ + (-y0)*cos_a_);
425 x2 = ((-x0)*cos_a_ - (-y0)*sin_a_) + x;
426 y2 = y- ((-x0)*sin_a_ + (-y0)*cos_a_);
428 gdk_draw_line(w, gc, (int) x1, (int) y1, (int) x2, (int) y2);
430 y0 = y0 + pitch1;
434 /*! \brief Fill inside of circle with mesh pattern.
435 * \par Function Description
436 * This function fills the inside of the circle with a pattern made of set
437 * of parallel lines in two directions. The first set is drawn inside the
438 * circle with an angle <B>angle1</B> from the horizontal. The distance between
439 * two of these lines is given by <B>pitch1</B>.
440 * The second set is drawn inside the circle with an angle <B>angle2</B> from
441 * the horizontal. The distance between two of these lines is given by
442 * <B>pitch2</B>.
443 * Every lines have the same width given by <B>width</B>.
445 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
446 * for <B>angle1</B> and <B>angle2</B> is degree.
448 * This function simply makes two successive calls to the function
449 * #o_circle_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
450 * <B>angle2</B>, <B>pitch2</B> for parameters.
452 * \param [in] w GdkDrawable to draw in.
453 * \param [in] gc GdkGC graphics context to draw on.
454 * \param [in] color Circle fill color.
455 * \param [in] x Center x coordinate of Circle.
456 * \param [in] y Center y coordinate of Circle.
457 * \param [in] radius Radius of Circle.
458 * \param [in] width Circle pattern fill width.
459 * \param [in] angle1 1st angle for pattern.
460 * \param [in] pitch1 1st pitch for pattern.
461 * \param [in] angle2 2nd angle for pattern.
462 * \param [in] pitch2 2nd pitch for pattern.
464 void o_circle_fill_mesh(GdkDrawable *w, GdkGC *gc, GdkColor *color,
465 gint x, gint y, gint radius,
466 gint width,
467 gint angle1, gint pitch1, gint angle2, gint pitch2)
469 o_circle_fill_hatch(w, gc, color,
470 x, y, radius,
471 width, angle1, pitch1, -1, -1);
472 o_circle_fill_hatch(w, gc, color,
473 x, y, radius,
474 width, angle2, pitch2, -1, -1);
479 /*! \todo Finish function documentation!!!
480 * \brief
481 * \par Function Description
484 void o_circle_eraserubber(GSCHEM_TOPLEVEL *w_current)
486 o_draw_rubbersubject_xor(w_current);
489 /*! \brief Draw a circle described by OBJECT with translation
490 * \par Function Description
491 * This function draws the circle object described by <B>*o_current</B>
492 * translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
493 * the current sheet.
494 * The translation vector is in world unit.
496 * The circle is displayed with the color of the object.
498 * \param [in] w_current The GSCHEM_TOPLEVEL object.
499 * \param [in] dx Delta x coordinate for circle.
500 * \param [in] dy Delta y coordinate for circle.
501 * \param [in] o_current Circle OBJECT to draw.
503 * \todo
504 * add in offsets, get rid of global diffs_x,y
506 void o_circle_draw_xor(GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
508 TOPLEVEL *toplevel = w_current->toplevel;
509 PAGE *page = toplevel->page_current;
510 int w_x, w_y;
511 int screen_x1, screen_y1, screen_x2, screen_y2;
512 int w_radius;
513 int color;
515 if (o_current->circle == NULL) {
516 return;
519 if (o_current->saved_color != -1) {
520 color = o_current->saved_color;
521 } else {
522 color = o_current->color;
525 w_radius = o_circle_get_radius(o_current);
526 s_basic_get_grip(o_current, GRIP_CIRCLE_CENTER, &w_x, &w_y);
529 * Get bounding rectangle in screen coords. Converting the bounding box
530 * to screen coords is more immune to rounding errors than adding and
531 * subtracting radius in screen coords.
533 WORLDtoSCREEN(page, w_x - w_radius + dx, w_y + w_radius + dy,
534 &screen_x1, &screen_y1);
535 WORLDtoSCREEN(page, w_x + w_radius + dx, w_y - w_radius + dy,
536 &screen_x2, &screen_y2);
538 /* To draw be sure to setup width height */
539 gdk_gc_set_foreground(w_current->outline_xor_gc,
540 x_get_darkcolor(color));
541 gdk_draw_arc(w_current->backingstore, w_current->outline_xor_gc,
542 FALSE,
543 screen_x1, screen_y1,
544 screen_x2 - screen_x1, screen_y2 - screen_y1,
545 0, FULL_CIRCLE);
547 /* backing store ? not appropriate here */
550 /*! \brief Start process to input a new circle.
551 * \par Function Description
552 * This function starts the process to input a new circle. Parameters for
553 * this circle are pu into/extracted from the <B>w_current</B> toplevel
554 * structure.
555 * <B>w_x</B> and <B>w_y</B> are current coordinates of the mouse pointer in
556 * world units.
558 * The first step of the circle input is to set the center of the arc.
559 * This center is kept in (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
561 * \param [in] w_current The GSCHEM_TOPLEVEL object.
562 * \param [in] w_x Current x coordinate of pointer in world units.
563 * \param [in] w_y Current y coordinate of pointer in world units.
565 void o_circle_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
567 w_current->which_object = o_circle_new_at_xy(w_current->toplevel, OBJ_CIRCLE,
568 w_current->graphic_color, 0, 0);
569 w_current->subject_is_new = 1;
570 w_current->which_grip = s_basic_move_grip(w_current->which_object,
571 GRIP_NONE, w_x, w_y);
573 /* start the rubberbanding process of the radius */
574 o_draw_rubbersubject_xor(w_current);
575 w_current->rubber_visible = 1;
578 /*! \brief End the input of a circle.
579 * \par Function Description
580 * This function ends the input of the radius of the circle.
581 * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius
582 * segment, i.e. on the circle. The distance between this point and the
583 * center is the radius of the circle.
584 * <B>w_x</B> and <B>w_y</B> are in world coords.
586 * The center has previously been input and saved as
587 * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
589 * The temporary circle drawn during the input of the radius is erased.
590 * A new object is allocated, initialized and linked in the object list.
591 * This new object is finally drawn.
593 * \param [in] w_current The GSCHEM_TOPLEVEL object.
594 * \param [in] w_x (unused)
595 * \param [in] w_y (unused)
597 void o_circle_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
599 TOPLEVEL *toplevel = w_current->toplevel;
601 g_assert( w_current->inside_action != 0 );
603 /* erase the temporary circle */
604 o_draw_rubbersubject_xor(w_current);
605 w_current->rubber_visible = 0;
607 s_basic_move_grip(w_current->which_object, w_current->which_grip, w_x, w_y);
609 if (w_current->subject_is_new) {
610 /* Link a permanent copy of the drawing subject into the object list. */
611 s_page_append(toplevel->page_current, w_current->which_object);
613 o_redraw_single(w_current, w_current->which_object);
614 w_current->which_object = NULL;
616 toplevel->page_current->CHANGED = 1;
618 o_undo_savestate(w_current, UNDO_ALL);
621 /*! \brief Draw temporary circle while dragging edge.
622 * \par Function Description
623 * This function draws a circle according to its internal representation and
624 * allows the modification of its radius. The radius is updated according to
625 * the current mouse position in <B>w_x</B> and <B>w_y</B>.
626 * It draws a full circle and the horizontal segment of the radius in the
627 * right half of the circle.
629 * The previous temporary circle is erased, the radius is then computed and
630 * updated and finally a new temporary circle is drawn.
632 * The arc is internally described by :
633 * <DL>
634 * <DT>*</DT><DD>(<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) as its
635 * center ;
636 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
637 * </DL>
639 * \param [in] w_current The GSCHEM_TOPLEVEL object.
640 * \param [in] w_x Current x coordinate of pointer in world units.
641 * \param [in] w_y Current y coordinate of pointer in world units.
643 void o_circle_rubbercircle(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
645 g_assert( w_current->inside_action != 0 );
647 /* erase the previous temporary circle if it is visible */
648 if (w_current->rubber_visible)
649 o_draw_rubbersubject_xor(w_current);
651 /* Kick the currently moving grip to the new pointer location. */
652 s_basic_move_grip(w_current->which_object, w_current->which_grip, w_x, w_y);
654 /* draw the new temporary circle */
655 o_draw_rubbersubject_xor(w_current);
656 w_current->rubber_visible =1;