Bumped versions to 1.1.2/20070818/30:2:0 for the next development snapshot
[geda-gaf/whiteaudio.git] / gschem / src / o_grips.c
blob4a41fc6e629ef120c99ed1078c39fe0b570d65d8
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>
22 #include <stdio.h>
23 #include <math.h>
25 #include <libgeda/libgeda.h>
27 #include "../include/globals.h"
28 #include "../include/prototype.h"
30 #ifdef HAVE_LIBDMALLOC
31 #include <dmalloc.h>
32 #endif
34 #define GET_BOX_WIDTH(w) abs((w)->last_x - (w)->start_x)
35 #define GET_BOX_HEIGHT(w) abs((w)->last_y - (w)->start_y)
36 #define GET_BOX_LEFT(w) min((w)->start_x, (w)->last_x);
37 #define GET_BOX_TOP(w) min((w)->start_y, (w)->last_y);
39 #define GET_PICTURE_WIDTH(w) abs((w)->last_x - (w)->start_x)
40 #define GET_PICTURE_HEIGHT(w) (w)->pixbuf_wh_ratio == 0 ? 0 : \
41 abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio
42 #define GET_PICTURE_LEFT(w) min((w)->start_x, (w)->last_x);
43 #define GET_PICTURE_TOP(w) (w)->start_y < (w)->last_y ? (w)->start_y : \
44 (w)->start_y-abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio;
46 /*! \brief
47 * This variable holds the identifier of the grip currently under
48 * modification. Its range of values depends on the type of object.
50 static int whichone_changing = -1;
51 /*! \brief
52 * This variable holds a pointer on the object under modification.
54 static OBJECT *object_changing;
56 /*! \brief Check if point is inside grip.
57 * \par Function Description
58 * This function is used to determine if the (<B>x</B>,<B>y</B>) point is
59 * inside a grip of one of the selected object on the current sheet.
60 * The selected object are in a list starting at
61 * <B>w_current->page_current->selection2_head</B>.
62 * The <B>x</B> and <B>y</B> parameters are in world units.
63 * If the point is inside one grip, a pointer on the object it belongs to is
64 * returned and <B>*whichone</B> is set according to the position of the grip
65 * on the object.
66 * Else, <B>*whichone</B> is unchanged and the function returns <B>NULL</B>.
68 * A specific search function is provided for every kind of graphical object.
69 * The list of selected object is covered : each object is tested with the
70 * appropriate function.
72 * \param [in] w_current The TOPLEVEL object.
73 * \param [in] x Current x coordinate of pointer in world units.
74 * \param [in] y Current y coordinate of pointer in world units.
75 * \param [out] whichone Which grip point is selected.
76 * \return Pointer to OBJECT the grip is on, NULL otherwise.
78 OBJECT *o_grips_search_world(TOPLEVEL *w_current, int x, int y, int *whichone)
80 OBJECT *object=NULL;
81 OBJECT *found=NULL;
82 GList *s_current;
83 int size;
84 int w_size;
86 if (!whichone) {
87 return(NULL);
90 /* get the size of the grip according to zoom level */
91 size = o_grips_size(w_current);
92 w_size = WORLDabs( w_current, size );
94 s_current = geda_list_get_glist( w_current->page_current->selection_list );
95 while (s_current != NULL) {
96 object = (OBJECT *) s_current->data;
97 if (object) {
98 switch(object->type) {
99 case(OBJ_ARC):
100 /* check the grips of the arc object */
101 found = o_grips_search_arc_world(w_current, object,
102 x, y, w_size, whichone);
103 if(found != NULL) return found;
104 break;
106 case(OBJ_BOX):
107 /* check the grips of the box object */
108 found = o_grips_search_box_world(w_current, object,
109 x, y, w_size, whichone);
110 if(found != NULL) return found;
111 break;
113 case(OBJ_PICTURE):
114 /* check the grips of the picture object */
115 found = o_grips_search_picture_world(w_current, object,
116 x, y, w_size, whichone);
117 if(found != NULL) return found;
118 break;
120 case(OBJ_CIRCLE):
121 /* check the grips of the circle object */
122 found = o_grips_search_circle_world(w_current, object,
123 x, y, w_size, whichone);
124 if(found != NULL) return found;
125 break;
127 case(OBJ_LINE):
128 case(OBJ_PIN):
129 case(OBJ_NET):
130 case(OBJ_BUS):
131 /* check the grips of the line object */
132 /* the function is the same for line, pin, net, bus */
133 found = o_grips_search_line_world(w_current, object,
134 x, y, w_size, whichone);
135 if(found != NULL) return found;
136 break;
138 default:
139 break;
142 s_current = s_current->next;
145 return(NULL);
149 /*! \brief Check if pointer is inside the grip region.
151 * \par Function Description
152 * This function checks if the point (<B>x</B>,<B>y</B>) is
153 * inside the grip centered at (<B>grip_x</B>,<B>grip_y</B>).
155 * \param [in] x Current x coordinate of pointer in world units.
156 * \param [in] y Current y coordinate of pointer in world units.
157 * \param [in] grip_x Current x coordinate of grip center in world units.
158 * \param [in] grip_y Current y coordinate of grip center in world units.
159 * \param [in] size Half the width of the grip square in world units.
160 * \return True / False whether the mouse pointer is inside the grip.
162 static gboolean inside_grip( int x, int y, int grip_x, int grip_y, int size )
164 int xmin, ymin, xmax, ymax;
166 xmin = grip_x - size;
167 ymin = grip_y - size;
168 xmax = xmin + 2 * size;
169 ymax = ymin + 2 * size;
171 return inside_region(xmin, ymin, xmax, ymax, x, y);
174 /*! \brief Check if pointer is inside arc grip.
175 * \par Function Description
176 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
177 * inside one of the grips of an <B>o_current</B> pointed arc object. If so
178 * the <B>whichone</B> pointed integer is set to the number of this grip and
179 * the return pointer is a pointer on this object. If the point is not
180 * inside a grip the function returns a NULL pointer and the <B>whichone</B>
181 * pointed integer is unset.
183 * An arc object has three grips :
184 * <DL>
185 * <DT>*</DT><DD>one at the center of the arc. This grip is used to modify
186 * the radius of the arc. If this one is selected, the
187 * <B>whichone</B> pointed integer is set to <B>ARC_RADIUS</B>.
188 * <DT>*</DT><DD>one at one end of the arc. It corresponds to the starting
189 * angle of the arc. If this one is selected, the
190 * <B>whichone</B> pointed integer is set to <B>ARC_START_ANGLE</B>.
191 * <DT>*</DT><DD>one at the other end of the arc. It corresponds to the
192 * ending angle of the arc. If this one is selected, the
193 * <B>whichone</B> pointed integer is set to <B>ARC_END_ANGLE</B>.
194 * </DL>
196 * The <B>x</B> and <B>y</B> parameters are in world units.
198 * The <B>size</B> parameter is the width (and height) of the square
199 * representing a grip in world units.
201 * \param [in] w_current The TOPLEVEL object.
202 * \param [in] o_current Arc OBJECT to check.
203 * \param [in] x Current x coordinate of pointer in world units.
204 * \param [in] y Current y coordinate of pointer in world units.
205 * \param [in] size Half the width of the grip square in world units.
206 * \param [out] whichone Which grip point is selected.
207 * \return Pointer to OBJECT the grip is on, NULL otherwise.
209 OBJECT *o_grips_search_arc_world(TOPLEVEL *w_current, OBJECT *o_current,
210 int x, int y, int size, int *whichone)
212 int centerx, centery, radius, start_angle, end_angle;
213 double tmp;
215 centerx = o_current->arc->x;
216 centery = o_current->arc->y;
217 radius = o_current->arc->width / 2;
218 start_angle = o_current->arc->start_angle;
219 end_angle = o_current->arc->end_angle;
221 /* check the grip on the center of the arc */
222 if (inside_grip(x, y, centerx, centery, size)) {
223 *whichone = ARC_RADIUS;
224 return(o_current);
227 /* check the grip at the start angle of the arc */
228 tmp = ((double) start_angle) * M_PI / 180;
229 if (inside_grip(x, y,
230 centerx + radius * cos(tmp),
231 centery + radius * sin(tmp), size)) {
232 *whichone = ARC_START_ANGLE;
233 return(o_current);
236 /* check the grip at the end angle of the arc */
237 tmp = ((double) start_angle + end_angle) * M_PI / 180;
238 if (inside_grip(x, y,
239 centerx + radius * cos(tmp),
240 centery + radius * sin(tmp), size)) {
241 *whichone = ARC_END_ANGLE;
242 return(o_current);
245 return NULL;
248 /*! \brief Check if pointer is inside box grip.
249 * \par Function Description
250 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
251 * inside one of the grips of the <B>o_current</B> pointed box object.
252 * If so, the <B>whichone</B> pointed integer is set to the identifier of
253 * this grip and the returned pointer is a pointer on this object.
254 * If the point is not inside a grip the function returns a NULL pointer
255 * and the <B>whichone</B> pointed integer is unset.
257 * A box object has four grips : one at each corner of the box. The
258 * identifiers of each corner are <B>BOX_UPPER_LEFT</B>,
259 * <B>BOX_UPPER_RIGHT</B>, <B>BOX_LOWER_LEFT</B> and <B>BOX_LOWER_RIGHT</B>.
261 * The <B>x</B> and <B>y</B> parameters are in world units.
263 * The <B>size</B> parameter is half the width (and half the height) of
264 * the square representing a grip in world units.
266 * \param [in] w_current The TOPLEVEL object.
267 * \param [in] o_current Box OBJECT to check.
268 * \param [in] x Current x coordinate of pointer in world units.
269 * \param [in] y Current y coordinate of pointer in world units.
270 * \param [in] size Half the width of the grip square in world units.
271 * \param [out] whichone Which grip point is selected.
272 * \return Pointer to OBJECT the grip is on, NULL otherwise.
274 OBJECT *o_grips_search_box_world(TOPLEVEL *w_current, OBJECT *o_current,
275 int x, int y, int size, int *whichone)
277 /* inside upper left grip ? */
278 if (inside_grip(x, y,
279 o_current->box->upper_x,
280 o_current->box->upper_y, size)) {
281 *whichone = BOX_UPPER_LEFT;
282 return(o_current);
285 /* inside lower right grip ? */
286 if (inside_grip(x, y,
287 o_current->box->lower_x,
288 o_current->box->lower_y, size)) {
289 *whichone = BOX_LOWER_RIGHT;
290 return(o_current);
293 /* inside upper right grip ? */
294 if (inside_grip(x, y,
295 o_current->box->lower_x,
296 o_current->box->upper_y, size)) {
297 *whichone = BOX_UPPER_RIGHT;
298 return(o_current);
301 /* inside lower left grip ? */
302 if (inside_grip(x, y,
303 o_current->box->upper_x,
304 o_current->box->lower_y, size)) {
305 *whichone = BOX_LOWER_LEFT;
306 return(o_current);
309 return NULL;
312 /*! \brief Check if pointer is inside picture grip.
313 * \par Function Description
314 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>)
315 * is inside one of the grips of the <B>o_current</B> pointed picture object.
316 * If so, the <B>whichone</B> pointed integer is set to the identifier of
317 * this grip and the returned pointer is a pointer on this object.
318 * If the point is not inside a grip the function returns a NULL pointer
319 * and the <B>whichone</B> pointed integer is unset.
321 * A picture object has four grips : one at each corner of the picture.
322 * The identifiers of each corner are #PICTURE_UPPER_LEFT,
323 * #PICTURE_UPPER_RIGHT, #PICTURE_LOWER_LEFT and
324 * #PICTURE_LOWER_RIGHT.
326 * The <B>x</B> and <B>y</B> parameters are in world units.
328 * The <B>size</B> parameter is half the width (and half the height) of the
329 * square representing a grip in world units.
331 * \param [in] w_current The TOPLEVEL object.
332 * \param [in] o_current Picture OBJECT to check.
333 * \param [in] x Current x coordinate of pointer in world units.
334 * \param [in] y Current y coordinate of pointer in world units.
335 * \param [in] size Half the width of the grip square in world units.
336 * \param [out] whichone Which grip point is selected.
337 * \return Pointer to OBJECT the grip is on, NULL otherwise.
339 OBJECT *o_grips_search_picture_world(TOPLEVEL *w_current, OBJECT *o_current,
340 int x, int y, int size, int *whichone)
342 /* inside upper left grip ? */
343 if (inside_grip(x, y,
344 o_current->picture->upper_x,
345 o_current->picture->upper_y, size)) {
346 *whichone = PICTURE_UPPER_LEFT;
347 return(o_current);
350 /* inside lower right grip ? */
351 if (inside_grip(x, y,
352 o_current->picture->lower_x,
353 o_current->picture->lower_y, size)) {
354 *whichone = PICTURE_LOWER_RIGHT;
355 return(o_current);
358 /* inside upper right grip ? */
359 if (inside_grip(x, y,
360 o_current->picture->lower_x,
361 o_current->picture->upper_y, size)) {
362 *whichone = PICTURE_UPPER_RIGHT;
363 return(o_current);
366 /* inside lower left grip ? */
367 if (inside_grip(x, y,
368 o_current->picture->upper_x,
369 o_current->picture->lower_y, size)) {
370 *whichone = PICTURE_LOWER_LEFT;
371 return(o_current);
374 return NULL;
377 /*! \brief Check if pointer is inside circle grip.
378 * \par Function Description
379 * This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
380 * the grip of the circle object <B>o_current</B>.
381 * It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
382 * is in one of these areas.
383 * If the event occured in one of the grip, a pointer on the object is
384 * returned and <B>*whichone</B> is set to the identifier of the grip.
385 * If not, the function returns a <B>NULL</B> pointer and <B>*whichone</B>
386 * is unchanged.
388 * The parameter <B>size</B> is half the size of the grip in world units.
390 * A circle has only one grip on the lower right corner of the box it
391 * is inscribed in. Moving this grip change the radius of the circle.
392 * The identifier of this grip is <B>CIRCLE_RADIUS</B>.
394 * \param [in] w_current The TOPLEVEL object.
395 * \param [in] o_current Circle OBJECT to check.
396 * \param [in] x Current x coordinate of pointer in world units.
397 * \param [in] y Current y coordinate of pointer in world units.
398 * \param [in] size Half the width of the grip square in world units.
399 * \param [out] whichone Which grip point is selected.
400 * \return Pointer to OBJECT the grip is on, NULL otherwise.
402 OBJECT *o_grips_search_circle_world(TOPLEVEL *w_current, OBJECT *o_current,
403 int x, int y, int size, int *whichone)
405 /* check the grip for radius */
406 if (inside_grip(x, y,
407 o_current->circle->center_x + o_current->circle->radius,
408 o_current->circle->center_y - o_current->circle->radius,
409 size)) {
410 *whichone = CIRCLE_RADIUS;
411 return(o_current);
414 return NULL;
417 /*! \brief Check if pointer is inside line grip.
418 * \par Function Description
419 * This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
420 * the grip of the line object <B>o_current</B>.
421 * It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
422 * is in one of these areas.
423 * If the event occured in one of its grip, a pointer on the object is
424 * returned and <B>*whichone</B> is set to the identifier of the grip. If not,
425 * the function returns <B>NULL</B> pointer and <B>*whichone</B> is unchanged.
427 * The parameter <B>size</B> is half the size of the grip in world units.
429 * \param [in] w_current The TOPLEVEL object.
430 * \param [in] o_current Line OBJECT to check.
431 * \param [in] x Current x coordinate of pointer in world units.
432 * \param [in] y Current y coordinate of pointer in world units.
433 * \param [in] size Half the width of the grip square in world units.
434 * \param [out] whichone Which grip point is selected.
435 * \return Pointer to OBJECT the grip is on, NULL otherwise.
437 OBJECT *o_grips_search_line_world(TOPLEVEL *w_current, OBJECT *o_current,
438 int x, int y, int size, int *whichone)
440 /* check the grip on the end of line 1 */
441 if (inside_grip(x, y,
442 o_current->line->x[LINE_END1],
443 o_current->line->y[LINE_END1], size)) {
444 *whichone = LINE_END1;
445 return(o_current);
448 /* check the grip on the end of line 2 */
449 if (inside_grip(x, y,
450 o_current->line->x[LINE_END2],
451 o_current->line->y[LINE_END2], size)) {
452 *whichone = LINE_END2;
453 return(o_current);
456 return NULL;
459 /*! \brief Start process of modifiying one grip.
460 * \par Function Description
461 * This function starts the process of modifying one grip of an object
462 * on the current sheet. The event occured in (<B>x</B>,<B>y</B>) in screen unit.
463 * If this position is related to a grip of an object, the function
464 * prepares the modification of this grip thanks to the user input.
466 * The function returns <B>FALSE</B> if an error occured of if no grip
467 * have been found under (<B>x</B>,<B>y</B>). It returns <B>TRUE</B> if a grip
468 * has been found and modification of the object has been started.
470 * If a grip has been found, this function modifies the global variables
471 * <B>whichone_changing</B> and <B>object_changing</B> with respectively the
472 * identifier of the grip and the object it belongs to.
474 * \param [in] w_current The TOPLEVEL object.
475 * \param [in] x Current x coordinate of pointer in screen units.
476 * \param [in] y Current y coordinate of pointer in screen units.
477 * \return FALSE if an error occurred or no grip was found, TRUE otherwise.
479 int o_grips_start(TOPLEVEL *w_current, int x, int y)
481 int w_x, w_y;
482 OBJECT *object;
483 int whichone;
485 if (w_current->draw_grips == FALSE) {
486 return(FALSE);
489 SCREENtoWORLD( w_current, x, y, &w_x, &w_y );
491 /* search if there is a grip on a selected object at (x,y) */
492 object = o_grips_search_world(w_current, w_x, w_y, &whichone);
493 if (object) {
494 whichone_changing = whichone;
495 object_changing = object;
497 /* there is one */
498 /* depending on its type, start the modification process */
499 switch(object->type) {
500 case(OBJ_ARC):
501 /* start the modification of a grip on an arc */
502 o_grips_start_arc(w_current, object, x, y, whichone);
503 return(TRUE);
505 case(OBJ_BOX):
506 /* start the modification of a grip on a box */
507 o_grips_start_box(w_current, object, x, y, whichone);
508 return(TRUE);
510 case(OBJ_PICTURE):
511 /* start the modification of a grip on a picture */
512 o_grips_start_picture(w_current, object, x, y, whichone);
513 return(TRUE);
515 case(OBJ_CIRCLE):
516 /* start the modification of a grip on a circle */
517 o_grips_start_circle(w_current, object, x, y, whichone);
518 return(TRUE);
520 case(OBJ_LINE):
521 /* start the modification of a grip on a line */
522 o_grips_start_line(w_current, object, x, y, whichone);
523 return(TRUE);
525 case(OBJ_NET):
526 w_current->last_drawb_mode = -1;
527 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
528 &w_current->last_x, &w_current->last_y );
529 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
530 &w_current->start_x, &w_current->start_y );
532 o_net_erase(w_current, object);
533 gdk_gc_set_foreground(w_current->xor_gc,
534 x_get_darkcolor(w_current->select_color) );
535 gdk_draw_line(w_current->window, w_current->xor_gc,
536 w_current->start_x, w_current->start_y,
537 w_current->last_x, w_current->last_y);
538 o_line_erase_grips(w_current, object);
540 gdk_gc_set_foreground(w_current->gc,
541 x_get_color(w_current->background_color));
542 return(TRUE);
544 case(OBJ_PIN):
545 w_current->last_drawb_mode = -1;
546 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
547 &w_current->last_x, &w_current->last_y );
548 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
549 &w_current->start_x, &w_current->start_y );
551 o_pin_erase(w_current, object);
552 gdk_gc_set_foreground(w_current->xor_gc,
553 x_get_darkcolor(w_current->select_color) );
554 gdk_draw_line(w_current->window, w_current->xor_gc,
555 w_current->start_x, w_current->start_y,
556 w_current->last_x, w_current->last_y);
557 o_line_erase_grips(w_current, object);
558 return(TRUE);
560 case(OBJ_BUS):
561 w_current->last_drawb_mode = -1;
562 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
563 &w_current->last_x, &w_current->last_y );
564 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
565 &w_current->start_x, &w_current->start_y );
567 o_bus_erase(w_current, object);
568 gdk_gc_set_foreground(w_current->xor_gc,
569 x_get_darkcolor(w_current->select_color) );
570 gdk_draw_line(w_current->window, w_current->xor_gc,
571 w_current->start_x, w_current->start_y,
572 w_current->last_x, w_current->last_y);
573 o_line_erase_grips(w_current, object);
575 gdk_gc_set_foreground(w_current->gc,
576 x_get_color(w_current->background_color));
577 return(TRUE);
579 default:
580 /* object type unknown : error condition */
581 return(FALSE);
584 return(FALSE);
587 /*! \brief Initialize grip motion process for an arc.
588 * \par Function Description
589 * This function initializes the grip motion process for an arc.
590 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
591 * structure the coordinates of the center, the radius and the two angle
592 * that describes an arc. These variables are used in the grip process.
594 * The coordinates of the center of the arc on x- and y-axis are stored
595 * into the <B>loc_x</B> and <B>loc_y</B> fields of the TOPLEVEL structure
596 * in screen unit.
598 * The radius of the center is stored into the <B>distance</B> field of
599 * the TOPLEVEL structure in screen unit.
601 * The two angles describing the arc on a circle are stored into the
602 * <B>start_x</B> for the starting angle and <B>start_y</B> for the ending angle.
603 * These angles are expressed in degrees.
605 * Depending on which grips has been selected on the arc, the
606 * corresponding variables in its original state is duplicated in
607 * <B>last_x</B> and/or <B>last_y</B> of the TOPLEVEL structure.
609 * \param [in] w_current The TOPLEVEL object.
610 * \param [in] o_current Arc OBJECT to check.
611 * \param [in] x (unused)
612 * \param [in] y (unused)
613 * \param [out] whichone (unused)
615 void o_grips_start_arc(TOPLEVEL *w_current, OBJECT *o_current,
616 int x, int y, int whichone)
618 w_current->last_drawb_mode = -1;
620 /* erase the arc before */
621 o_arc_erase(w_current, o_current);
623 /* describe the arc with TOPLEVEL variables */
624 /* center */
625 WORLDtoSCREEN( w_current, o_current->arc->x, o_current->arc->y, &w_current->start_x, &w_current->start_y );
626 /* radius */
627 w_current->distance = SCREENabs( w_current, o_current->arc->width / 2 );
628 /* angles */
629 w_current->loc_x = o_current->arc->start_angle;
630 w_current->loc_y = o_current->arc->end_angle;
632 /* draw the first temporary arc */
633 o_arc_rubberarc_xor(w_current);
637 /*! \brief Initialize grip motion process for a box.
638 * \par Function Description
639 * This function initializes the grip motion process for a box. From the
640 * <B>o_current</B> pointed object, it stores into the TOPLEVEL structure
641 * the .... These variables are used in the grip process.
643 * The function first erases the grips.
645 * The coordinates of the selected corner are put in
646 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
648 * The coordinates of the opposite corner go in
649 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
650 * to change during the action.
652 * \param [in] w_current The TOPLEVEL object.
653 * \param [in] o_current Box OBJECT to check.
654 * \param [in] x (unused)
655 * \param [in] y (unused)
656 * \param [out] whichone Which coordinate to check.
658 void o_grips_start_box(TOPLEVEL *w_current, OBJECT *o_current,
659 int x, int y, int whichone)
661 w_current->last_drawb_mode = -1;
663 /* erase the box before */
664 o_box_erase(w_current, o_current);
666 /* (last_x,last_y) is the selected corner */
667 /* (start_x, start_y) is the opposite corner */
668 switch(whichone) {
669 case BOX_UPPER_LEFT:
670 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
671 &w_current->last_x, &w_current->last_y );
672 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
673 &w_current->start_x, &w_current->start_y );
674 break;
675 case BOX_LOWER_RIGHT:
676 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
677 &w_current->last_x, &w_current->last_y );
678 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
679 &w_current->start_x, &w_current->start_y );
680 break;
681 case BOX_UPPER_RIGHT:
682 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->upper_y,
683 &w_current->last_x, &w_current->last_y );
684 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->lower_y,
685 &w_current->start_x, &w_current->start_y );
686 break;
687 case BOX_LOWER_LEFT:
688 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->lower_y,
689 &w_current->last_x, &w_current->last_y );
690 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->upper_y,
691 &w_current->start_x, &w_current->start_y );
692 break;
693 default:
694 return; /* error */
697 /* draw the first temporary box */
698 o_box_rubberbox_xor(w_current);
702 /*! \brief Initialize grip motion process for a picture.
703 * \par Function Description
704 * This function initializes the grip motion process for a picture.
705 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
706 * structure the .... These variables are used in the grip process.
708 * The function first erases the grips.
710 * The coordinates of the selected corner are put in
711 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
713 * The coordinates of the opposite corner go in
714 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not
715 * suppose to change during the action.
717 * \param [in] w_current The TOPLEVEL object.
718 * \param [in] o_current Picture OBJECT to check.
719 * \param [in] x (unused)
720 * \param [in] y (unused)
721 * \param [out] whichone Which coordinate to check.
723 void o_grips_start_picture(TOPLEVEL *w_current, OBJECT *o_current,
724 int x, int y, int whichone)
726 w_current->last_drawb_mode = -1;
728 /* erase the picture before */
729 o_picture_erase(w_current, o_current);
730 w_current->current_pixbuf = o_current->picture->original_picture;
731 w_current->pixbuf_filename = o_current->picture->filename;
732 w_current->pixbuf_wh_ratio = o_current->picture->ratio;
734 /* (last_x,last_y) is the selected corner */
735 /* (start_x, start_y) is the opposite corner */
736 switch(whichone) {
737 case PICTURE_UPPER_LEFT:
738 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->upper_y,
739 &w_current->last_x, &w_current->last_y );
740 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->lower_y,
741 &w_current->start_x, &w_current->start_y );
742 break;
743 case PICTURE_LOWER_RIGHT:
744 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->lower_y,
745 &w_current->last_x, &w_current->last_y );
746 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->upper_y,
747 &w_current->start_x, &w_current->start_y );
748 break;
749 case PICTURE_UPPER_RIGHT:
750 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->upper_y,
751 &w_current->last_x, &w_current->last_y );
752 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->lower_y,
753 &w_current->start_x, &w_current->start_y );
754 break;
755 case PICTURE_LOWER_LEFT:
756 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->lower_y,
757 &w_current->last_x, &w_current->last_y );
758 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->upper_y,
759 &w_current->start_x, &w_current->start_y );
760 break;
761 default:
762 return; /* error */
765 /* draw the first temporary picture */
766 o_picture_rubberbox_xor(w_current);
770 /*! \brief Initialize grip motion process for a circle.
771 * \par Function Description
772 * This function initializes the grip motion process for a circle.
773 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
774 * structure the coordinate of the center and the radius. These variables
775 * are used in the grip process.
777 * The function first erases the grips.
779 * The coordinates of the center are put in
780 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
781 * to change during the action.
783 * The coordinates of the point on the circle to the right of the center
784 * go in (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
786 * \param [in] w_current The TOPLEVEL object.
787 * \param [in] o_current Circle OBJECT to check.
788 * \param [in] x (unused)
789 * \param [in] y (unused)
790 * \param [out] whichone Which coordinate to check.
792 void o_grips_start_circle(TOPLEVEL *w_current, OBJECT *o_current,
793 int x, int y, int whichone)
795 w_current->last_drawb_mode = -1;
797 /* erase the circle before */
798 o_circle_erase(w_current, o_current);
800 /* describe the circle with TOPLEVEL variables */
801 /* (start_x, start_y) is the center of the circle */
802 WORLDtoSCREEN( w_current, o_current->circle->center_x, o_current->circle->center_y,
803 &w_current->start_x, &w_current->start_y );
804 /* (last_x,last_y) is the point on circle on the right of center */
805 WORLDtoSCREEN( w_current, o_current->circle->center_x + o_current->circle->radius, o_current->circle->center_y,
806 &w_current->last_x, &w_current->last_y );
807 /* distance is the radius of the circle */
808 w_current->distance = SCREENabs( w_current, o_current->circle->radius );
810 /* draw the first temporary circle */
811 o_circle_rubbercircle_xor(w_current);
815 /*! \brief Initialize grip motion process for a line.
816 * This function starts the move of one of the two grips of the line
817 * object <B>o_current</B>.
818 * The line and its grips are first erased. The move of the grips is
819 * materializd with a temporary line in selection color drawn over the
820 * sheet with an xor-function.
822 * During the move of the grip, the line is described by
823 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and
824 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
826 * The line end that corresponds to the moving grip is in
827 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
829 * \param [in] w_current The TOPLEVEL object.
830 * \param [in] o_current Line OBJECT to check.
831 * \param [in] x (unused)
832 * \param [in] y (unused)
833 * \param [out] whichone Which coordinate to check.
835 void o_grips_start_line(TOPLEVEL *w_current, OBJECT *o_current,
836 int x, int y, int whichone)
838 w_current->last_drawb_mode = -1;
840 /* erase the line before */
841 o_line_erase(w_current, o_current);
843 /* describe the line with TOPLEVEL variables */
844 WORLDtoSCREEN( w_current, o_current->line->x[whichone], o_current->line->y[whichone],
845 &w_current->last_x, &w_current->last_y );
846 WORLDtoSCREEN( w_current, o_current->line->x[!whichone], o_current->line->y[!whichone],
847 &w_current->start_x, &w_current->start_y );
849 /* draw the first temporary line */
850 o_line_rubberline_xor(w_current);
853 /*! \brief Modify previously selected object according to mouse position.
854 * \par Function Description
855 * This function modify the previously selected
856 * object according to the mouse position in <B>x</B> and <B>y</B>.
857 * The grip under modification is updated and the temporary object displayed.
859 * The object under modification is <B>object_changing</B> and the grip
860 * concerned is <B>whichone_changing</B>.
862 * Depending on the object type, a specific function is used.
863 * It erases the temporary object, updates its internal representation,
864 * and draws it again.
866 * \param [in] w_current The TOPLEVEL object.
867 * \param [in] x Current x coordinate of pointer in screen units.
868 * \param [in] y Current y coordinate of pointer in screen units.
870 void o_grips_motion(TOPLEVEL *w_current, int x, int y)
873 if (w_current->inside_action == 0) {
874 o_redraw(w_current, w_current->page_current->object_head, TRUE);
875 return;
878 /* no object changing */
879 if (object_changing == NULL) {
880 /* stop grip process */
881 o_redraw(w_current, w_current->page_current->object_head, TRUE);
882 return;
885 switch(object_changing->type) {
886 case(OBJ_ARC):
887 /* erase, update and draw an arc */
888 o_grips_motion_arc(w_current, x, y, whichone_changing);
889 break;
891 case(OBJ_BOX):
892 /* erase, update and draw a box */
893 o_grips_motion_box(w_current, x, y, whichone_changing);
894 break;
896 case(OBJ_PICTURE):
897 /* erase, update and draw a box */
898 o_grips_motion_picture(w_current, x, y, whichone_changing);
899 break;
901 case(OBJ_CIRCLE):
902 /* erase, update and draw a circle */
903 o_grips_motion_circle(w_current, x, y, whichone_changing);
904 break;
906 case(OBJ_LINE):
907 case(OBJ_NET):
908 case(OBJ_PIN):
909 case(OBJ_BUS):
910 /* erase, update and draw a line */
911 /* same for net, pin and bus as they share the same internal rep. */
912 o_grips_motion_line(w_current, x, y, whichone_changing);
913 break;
915 default:
916 return; /* error condition */
920 /*! \brief Modify previously selected arc according to mouse position.
921 * \par Function Description
922 * This function is the refreshing part of the grip motion process.
923 * It is called whenever the position of the pointer is changed,
924 * therefore requiring the TOPLEVEL variables to be updated.
925 * Depending on the grip selected and moved, the temporary TOPLEVEL
926 * variables are changed according to the current position of the pointer.
928 * If the grip at the center of the arc has been moved - modifying the
929 * radius of the arc -, the <B>w_current->distance</B> field is updated.
930 * To increase the radius of the arc, the user must drag the grip to the
931 * right of the center. To decrease the radius of the arc, the user must
932 * drag the grip to the left of the center. Negative radius can not be
933 * obtained.
935 * If one of the end of arc grip has been moved - modifying the arc
936 * describing the arc -, the <B>w_current->start_x</B> or
937 * <B>w_current->start_y</B> are updated according to which of the grip
938 * has been selected.
940 * \param [in] w_current The TOPLEVEL object.
941 * \param [in] x Current x coordinate of pointer in screen units.
942 * \param [in] y Current y coordinate of pointer in screen units.
943 * \param [in] whichone Which grip to start motion with.
945 void o_grips_motion_arc(TOPLEVEL *w_current, int x, int y, int whichone)
947 o_arc_rubberarc(w_current, x, y, whichone);
950 /*! \brief Modify previously selected box according to mouse position.
951 * \par Function Description
952 * This function is the refreshing part of the grip motion process. It is
953 * called whenever the position of the pointer is changed, therefore
954 * requiring the TOPLEVEL variables to be updated.
955 * Depending on the grip selected and moved, the temporary TOPLEVEL
956 * variables are changed according to the current position of the pointer
957 * and the modifications temporary drawn.
959 * This function only makes a call to #o_box_rubberbox() that updates
960 * the TOPLEVEL variables, erase the previous temporary box and draw the
961 * new temporary box.
963 * \param [in] w_current The TOPLEVEL object.
964 * \param [in] x Current x coordinate of pointer in screen units.
965 * \param [in] y Current y coordinate of pointer in screen units.
966 * \param [in] whichone Which grip to start motion with.
968 void o_grips_motion_box(TOPLEVEL *w_current, int x, int y, int whichone)
970 /* erase, update and draw the temporary box */
971 o_box_rubberbox(w_current, x, y);
974 /*! \brief Modify previously selected picture according to mouse position.
975 * \par Function Description
976 * This function is the refreshing part of the grip motion process. It is
977 * called whenever the position of the pointer is changed, therefore
978 * requiring the TOPLEVEL variables to be updated.
979 * Depending on the grip selected and moved, the temporary TOPLEVEL
980 * variables are changed according to the current position of the pointer
981 * and the modifications temporary drawn.
983 * This function only makes a call to #o_picture_rubberbox() that
984 * updates the TOPLEVEL variables, erase the previous temporary picture
985 * and draw the new temporary picture.
987 * \param [in] w_current The TOPLEVEL object.
988 * \param [in] x Current x coordinate of pointer in screen units.
989 * \param [in] y Current y coordinate of pointer in screen units.
990 * \param [in] whichone Which grip to start motion with.
992 void o_grips_motion_picture(TOPLEVEL *w_current, int x, int y, int whichone)
994 /* erase, update and draw the temporary picture */
995 o_picture_rubberbox(w_current, x, y);
998 /*! \brief Modify previously selected circle according to mouse position.
999 * \par Function Description
1000 * This function is the refreshing part of the grip motion process. It is
1001 * called whenever the position of the pointer is changed, therefore
1002 * requiring the TOPLEVEL variables to be updated.
1003 * Depending on the grip selected and moved, the temporary TOPLEVEL
1004 * variables are changed according to the current position of the pointer
1005 * and the modifications temporary drawn.
1007 * This function only makes a call to #o_circle_rubbercircle() that updates
1008 * the TOPLEVEL variables, erase the previous temporary circle and draw
1009 * the new temporary circle.
1011 * \param [in] w_current The TOPLEVEL object.
1012 * \param [in] x Current x coordinate of pointer in screen units.
1013 * \param [in] y Current y coordinate of pointer in screen units.
1014 * \param [in] whichone Which grip to start motion with.
1016 void o_grips_motion_circle(TOPLEVEL *w_current, int x, int y, int whichone)
1018 /* erase, update and draw the temporary circle */
1019 o_circle_rubbercircle(w_current, x, y);
1022 /*! \brief Modify previously selected line according to mouse position.
1023 * \par Function Description
1024 * This function is called during the move of the grip to update the
1025 * temporary line drawn under the mouse pointer.
1026 * The current position of the mouse is in <B>x</B> and <B>y</B> in screen coords.
1028 * \param [in] w_current The TOPLEVEL object.
1029 * \param [in] x Current x coordinate of pointer in screen units.
1030 * \param [in] y Current y coordinate of pointer in screen units.
1031 * \param [in] whichone Which grip to start motion with.
1033 void o_grips_motion_line(TOPLEVEL *w_current, int x, int y, int whichone)
1035 /* erase, update and draw the temporary line */
1036 o_line_rubberline(w_current, x, y);
1039 /*! \brief End process of modifying object with grip.
1040 * \par Function Description
1041 * This function ends the process of modifying a parameter of an object
1042 * with a grip.
1043 * The temporary representation of the object is erased, the object is
1044 * modified and finally drawn.
1046 * The object under modification is <B>object_changing</B> and the grip
1047 * concerned is <B>whichone_changing</B>.
1049 * Depending on the object type, a specific function is used. It erases
1050 * the temporary object, updates the object and draws the modified object
1051 * normally.
1053 * \param [in,out] w_current The TOPLEVEL object.
1055 void o_grips_end(TOPLEVEL *w_current)
1057 OBJECT *object=NULL;
1058 int x, y;
1059 GList *other_objects = NULL;
1060 GList *connected_objects = NULL;
1061 int size;
1063 object = object_changing;
1065 if (!object) {
1066 /* actually this is an error condition hack */
1067 w_current->inside_action = 0;
1068 i_set_state(w_current, SELECT);
1069 return;
1072 switch(object->type) {
1074 case(OBJ_ARC):
1075 /* modify an arc object */
1076 o_grips_end_arc(w_current, object, whichone_changing);
1077 break;
1079 case(OBJ_BOX):
1080 /* modify a box object */
1081 o_grips_end_box(w_current, object, whichone_changing);
1082 break;
1084 case(OBJ_PICTURE):
1085 /* modify a picture object */
1086 o_grips_end_picture(w_current, object, whichone_changing);
1087 break;
1089 case(OBJ_CIRCLE):
1090 /* modify a circle object */
1091 o_grips_end_circle(w_current, object, whichone_changing);
1092 break;
1094 case(OBJ_LINE):
1095 /* modify a line object */
1096 o_grips_end_line(w_current, object, whichone_changing);
1097 break;
1099 case(OBJ_NET):
1100 /* don't allow zero length nets / lines / pins
1101 * this ends the net drawing behavior
1102 * we want this? hack */
1103 if ((w_current->start_x == w_current->last_x) &&
1104 (w_current->start_y == w_current->last_y)) {
1105 w_current->start_x = (-1);
1106 w_current->start_y = (-1);
1107 w_current->last_x = (-1);
1108 w_current->last_y = (-1);
1109 w_current->inside_action=0;
1110 i_set_state(w_current, SELECT);
1111 o_redraw_single(w_current, object);
1112 i_update_toolbar(w_current);
1113 return;
1116 SCREENtoWORLD(w_current,
1117 w_current->last_x,
1118 w_current->last_y, &x, &y);
1120 x = snap_grid(w_current, x);
1121 y = snap_grid(w_current, y);
1123 o_cue_undraw(w_current, object);
1124 o_net_erase(w_current, object);
1125 /* erase xor line */
1126 gdk_gc_set_foreground(w_current->xor_gc,
1127 x_get_darkcolor(w_current->select_color));
1128 gdk_draw_line(w_current->window, w_current->xor_gc,
1129 w_current->start_x, w_current->start_y,
1130 w_current->last_x, w_current->last_y);
1131 o_line_erase_grips(w_current, object);
1133 other_objects = s_conn_return_others(other_objects, object);
1134 s_conn_remove(w_current, object);
1136 o_net_modify(w_current, object, x, y, whichone_changing);
1138 s_conn_update_object(w_current, object);
1140 /* get the other connected objects and redraw them */
1141 connected_objects = s_conn_return_others(connected_objects,
1142 object);
1144 /* add bus rippers if necessary */
1145 if (o_net_add_busrippers(w_current, object, connected_objects)) {
1147 o_net_erase(w_current, object);
1148 /*o_line_erase_grips(w_current, object); */
1150 if (w_current->net_style == THICK ) {
1151 size = SCREENabs(w_current, 10);
1153 if (size < 0)
1154 size=0;
1156 gdk_gc_set_line_attributes(w_current->gc, size,
1157 GDK_LINE_SOLID,
1158 GDK_CAP_BUTT,
1159 GDK_JOIN_MITER);
1162 gdk_gc_set_foreground(w_current->gc,
1163 x_get_color(w_current->background_color));
1164 gdk_draw_line(w_current->window, w_current->gc,
1165 w_current->start_x, w_current->start_y,
1166 w_current->last_x, w_current->last_y);
1168 o_cue_undraw(w_current, object);
1169 o_net_draw(w_current, object);
1170 o_cue_draw_single(w_current, object);
1172 if (w_current->net_style == THICK ) {
1173 gdk_gc_set_line_attributes(w_current->gc, 0,
1174 GDK_LINE_SOLID,
1175 GDK_CAP_NOT_LAST,
1176 GDK_JOIN_MITER);
1180 /* draw the object objects */
1181 o_cue_undraw_list(w_current, other_objects);
1182 o_cue_draw_list(w_current, other_objects);
1184 o_redraw_single(w_current, object);
1186 if (connected_objects) {
1187 g_list_free(connected_objects);
1188 connected_objects = NULL;
1191 /* get the other connected objects and redraw them */
1192 connected_objects = s_conn_return_others(connected_objects,
1193 object);
1195 o_cue_undraw_list(w_current, connected_objects);
1196 o_cue_draw_list(w_current, connected_objects);
1197 /* finally draw this objects cues */
1198 o_cue_draw_single(w_current, object);
1199 break;
1201 case(OBJ_PIN):
1202 /* don't allow zero length nets / lines / pins
1203 * this ends the net drawing behavior
1204 * we want this? hack */
1205 if ((w_current->start_x == w_current->last_x) &&
1206 (w_current->start_y == w_current->last_y)) {
1207 w_current->start_x = (-1);
1208 w_current->start_y = (-1);
1209 w_current->last_x = (-1);
1210 w_current->last_y = (-1);
1211 o_redraw_single(w_current, object);
1212 w_current->inside_action=0;
1213 i_set_state(w_current, SELECT);
1214 i_update_toolbar(w_current);
1215 return;
1218 SCREENtoWORLD(w_current,
1219 w_current->last_x,
1220 w_current->last_y, &x, &y);
1222 x = snap_grid(w_current, x);
1223 y = snap_grid(w_current, y);
1225 o_cue_undraw(w_current, object);
1226 o_pin_erase(w_current, object);
1227 /* erase xor line */
1228 gdk_gc_set_foreground(w_current->xor_gc,
1229 x_get_darkcolor(w_current->select_color));
1230 gdk_draw_line(w_current->window, w_current->xor_gc,
1231 w_current->start_x, w_current->start_y,
1232 w_current->last_x, w_current->last_y);
1233 o_line_erase_grips(w_current, object);
1235 other_objects = s_conn_return_others(other_objects, object);
1236 s_conn_remove(w_current, object);
1238 o_pin_modify(w_current, object, x, y,
1239 whichone_changing);
1240 s_conn_update_object(w_current, object);
1241 o_redraw_single(w_current, object);
1243 /* draw the object objects */
1244 o_cue_undraw_list(w_current, other_objects);
1245 o_cue_draw_list(w_current, other_objects);
1247 /* get the other connected objects and redraw them */
1248 connected_objects = s_conn_return_others(connected_objects,
1249 object);
1250 o_cue_undraw_list(w_current, connected_objects);
1251 o_cue_draw_list(w_current, connected_objects);
1253 /* finally draw this objects cues */
1254 o_cue_draw_single(w_current, object);
1255 break;
1257 case(OBJ_BUS):
1258 /* don't allow zero length nets / lines / pins
1259 * this ends the net drawing behavior
1260 * we want this? hack */
1261 if ((w_current->start_x == w_current->last_x) &&
1262 (w_current->start_y == w_current->last_y)) {
1263 w_current->start_x = (-1);
1264 w_current->start_y = (-1);
1265 w_current->last_x = (-1);
1266 w_current->last_y = (-1);
1267 o_redraw_single(w_current, object);
1268 w_current->inside_action=0;
1269 i_set_state(w_current, SELECT);
1270 i_update_toolbar(w_current);
1271 return;
1274 SCREENtoWORLD(w_current,
1275 w_current->last_x,
1276 w_current->last_y, &x, &y);
1278 x = snap_grid(w_current, x);
1279 y = snap_grid(w_current, y);
1281 o_cue_undraw(w_current, object);
1282 o_bus_erase(w_current, object);
1283 /* erase xor line */
1284 gdk_gc_set_foreground(w_current->xor_gc,
1285 x_get_darkcolor(w_current->select_color));
1286 gdk_draw_line(w_current->window, w_current->xor_gc,
1287 w_current->start_x, w_current->start_y,
1288 w_current->last_x, w_current->last_y);
1289 o_line_erase_grips(w_current, object);
1291 other_objects = s_conn_return_others(other_objects, object);
1292 s_conn_remove(w_current, object);
1294 o_bus_modify(w_current, object, x, y,
1295 whichone_changing);
1296 s_conn_update_object(w_current, object);
1297 o_redraw_single(w_current, object);
1299 /* draw the object objects */
1300 o_cue_undraw_list(w_current, other_objects);
1301 o_cue_draw_list(w_current, other_objects);
1303 /* get the other connected objects and redraw them */
1304 connected_objects = s_conn_return_others(connected_objects,
1305 object);
1306 o_cue_undraw_list(w_current, connected_objects);
1307 o_cue_draw_list(w_current, connected_objects);
1309 /* finally draw this objects cues */
1310 o_cue_draw_single(w_current, object);
1311 break;
1313 default:
1314 return;
1317 w_current->page_current->CHANGED=1;
1319 g_list_free(other_objects);
1320 other_objects = NULL;
1321 g_list_free(connected_objects);
1322 connected_objects = NULL;
1324 /* reset global variables */
1325 whichone_changing = -1;
1326 object_changing = NULL;
1328 o_undo_savestate(w_current, UNDO_ALL);
1331 /*! \brief End process of modifying arc object with grip.
1332 * \par Function Description
1333 * This function ends the grips process specific to an arc object. It erases
1334 * the old arc and write back to the object the new parameters of the arc.
1335 * Depending on the grip selected and moved, the right fields are updated.
1336 * The function handles the conversion from screen unit to world unit before
1337 * updating and redrawing.
1339 * If the grip at the center of the arc has been moved - modifying the radius
1340 * of the arc -, the new radius is calculated expressed in world unit
1341 * (the center is unchanged). It is updated with the function #o_arc_modify().
1343 * If one of the end of arc grip has been moved - modifying one of the
1344 * angles describing the arc -, this angle is updated with the
1345 * #o_arc_modify() function.
1347 * \param [in] w_current The TOPLEVEL object.
1348 * \param [in] o_current Arc OBJECT to end modification on.
1349 * \param [in] whichone Which grip is pointed to.
1351 void o_grips_end_arc(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1353 int arg1, arg2;
1355 /* erase the temporary arc */
1356 o_arc_rubberarc_xor(w_current);
1358 /* determination of the parameters to give to o_arc_modify() */
1359 switch(whichone) {
1360 case ARC_RADIUS:
1361 /* convert the radius in world coords */
1362 arg1 = WORLDabs(w_current, w_current->distance);
1363 /* second parameter is not used */
1364 arg2 = -1;
1365 break;
1367 case ARC_START_ANGLE:
1368 /* get the start angle from w_current */
1369 arg1 = w_current->loc_x;
1370 /* second parameter is not used */
1371 arg2 = -1;
1372 break;
1374 case ARC_END_ANGLE:
1375 /* get the end angle from w_current */
1376 arg1 = w_current->loc_y;
1377 /* second parameter is not used */
1378 arg2 = -1;
1379 break;
1381 default:
1382 return;
1385 /* modify the arc with the parameters determined above */
1386 o_arc_modify(w_current, o_current, arg1, arg2, whichone);
1388 /* display the new arc */
1389 o_redraw_single(w_current, o_current);
1393 /*! \todo Finish function documentation!!!
1394 * \brief End process of modifying box object with grip.
1395 * \par Function Description
1397 * \param [in] w_current The TOPLEVEL object.
1398 * \param [in] o_current Box OBJECT to end modification on.
1399 * \param [in] whichone Which grip is pointed to.
1401 void o_grips_end_box(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1403 int box_width, box_height;
1404 int x, y;
1406 box_width = GET_BOX_WIDTH (w_current);
1407 box_height = GET_BOX_HEIGHT(w_current);
1409 /* don't allow zero width/height boxes
1410 * this ends the box drawing behavior
1411 * we want this? hack */
1412 if ((box_width == 0) && (box_height == 0)) {
1413 w_current->start_x = (-1);
1414 w_current->start_y = (-1);
1415 w_current->last_x = (-1);
1416 w_current->last_y = (-1);
1418 w_current->inside_action=0;
1419 i_set_state(w_current, SELECT);
1421 o_redraw_single(w_current, o_current);
1422 i_update_toolbar(w_current);
1424 return;
1427 SCREENtoWORLD(w_current,
1428 w_current->last_x, w_current->last_y,
1429 &x, &y);
1430 x = snap_grid(w_current, x);
1431 y = snap_grid(w_current, y);
1433 o_box_modify(w_current, o_current, x, y, whichone);
1435 /* erase the temporary box */
1436 o_box_rubberbox_xor(w_current);
1438 /* draw the modified box */
1439 o_redraw_single(w_current, o_current);
1442 /*! \todo Finish function documentation!!!
1443 * \brief End process of modifying picture object with grip.
1444 * \par Function Description
1446 * \param [in] w_current The TOPLEVEL object.
1447 * \param [in] o_current Picture OBJECT to end modification on.
1448 * \param [in] whichone Which grip is pointed to.
1450 void o_grips_end_picture(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1452 int picture_width, picture_height;
1453 int x, y;
1455 picture_width = GET_PICTURE_WIDTH (w_current);
1456 picture_height = GET_PICTURE_HEIGHT(w_current);
1458 /* don't allow zero width/height picturees
1459 * this ends the picture drawing behavior
1460 * we want this? hack */
1461 if ((picture_width == 0) && (picture_height == 0)) {
1462 w_current->start_x = (-1);
1463 w_current->start_y = (-1);
1464 w_current->last_x = (-1);
1465 w_current->last_y = (-1);
1467 w_current->inside_action=0;
1468 i_set_state(w_current, SELECT);
1470 o_redraw_single(w_current, o_current);
1471 i_update_toolbar(w_current);
1473 return;
1476 SCREENtoWORLD(w_current,
1477 w_current->last_x, w_current->last_y,
1478 &x, &y);
1479 x = snap_grid(w_current, x);
1480 y = snap_grid(w_current, y);
1482 o_picture_modify(w_current, o_current, x, y, whichone);
1484 /* erase the temporary picture */
1485 o_picture_rubberbox_xor(w_current);
1487 /* draw the modified picture */
1488 o_redraw_single(w_current, o_current);
1490 w_current->current_pixbuf = NULL;
1491 w_current->pixbuf_filename = NULL;
1492 w_current->pixbuf_wh_ratio = 0;
1495 /*! \brief End process of modifying circle object with grip.
1496 * \par Function Description
1497 * This function ends the process of modifying the radius of the circle
1498 * object <B>*o_current</B>.
1499 * The modified circle is finally normally drawn.
1501 * A circle with a null radius is not allowed. In this case, the process
1502 * is stopped and the circle is left unchanged.
1504 * The last value of the radius is in <B>w_current->distance</B> in screen units.
1506 * \param [in] w_current The TOPLEVEL object.
1507 * \param [in] o_current Circle OBJECT to end modification on.
1508 * \param [in] whichone Which grip is pointed to.
1510 void o_grips_end_circle(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1512 int radius;
1514 /* erase the temporary circle */
1515 o_circle_rubbercircle_xor(w_current);
1517 /* don't allow zero radius circles
1518 * this ends the circle drawing behavior
1519 * we want this? hack */
1520 if ((w_current->start_x == w_current->last_x) &&
1521 (w_current->start_y == w_current->last_y)) {
1522 w_current->start_x = (-1);
1523 w_current->start_y = (-1);
1524 w_current->last_x = (-1);
1525 w_current->last_y = (-1);
1527 /* return to select mode */
1528 w_current->inside_action = 0;
1529 i_set_state(w_current, SELECT);
1530 i_update_toolbar(w_current);
1532 o_redraw_single(w_current, o_current);
1533 return;
1536 /* convert the radius in world unit */
1537 radius = WORLDabs(w_current, w_current->distance);
1539 /* modify the radius of the circle */
1540 o_circle_modify(w_current, o_current, radius, -1, CIRCLE_RADIUS);
1542 /* display the new circle */
1543 o_redraw_single(w_current, o_current);
1546 /*! \brief End process of modifying line object with grip.
1547 * \par Function Description
1548 * This function ends the process of modifying one end of the line
1549 * object <B>*o_current</B>.
1550 * This end is identified by <B>whichone</B>. The line object is modified
1551 * according to the <B>whichone</B> parameter and the last position of the
1552 * line end.
1553 * The modified line is finally normally drawn.
1555 * A line with a null width, i.e. when both ends are identical, is not
1556 * allowed. In this case, the process is stopped and the line unchanged.
1558 * \param [in] w_current The TOPLEVEL object.
1559 * \param [in] o_current Circle OBJECT to end modification on.
1560 * \param [in] whichone Which grip is pointed to.
1562 void o_grips_end_line(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1564 int x, y;
1566 /* erase the temporary line */
1567 o_line_rubberline_xor(w_current);
1569 /* don't allow zero length nets / lines / pins
1570 * this ends the net drawing behavior
1571 * we want this? hack */
1572 if ((w_current->start_x == w_current->last_x) &&
1573 (w_current->start_y == w_current->last_y)) {
1574 w_current->start_x = (-1);
1575 w_current->start_y = (-1);
1576 w_current->last_x = (-1);
1577 w_current->last_y = (-1);
1579 /* return to select mode */
1580 w_current->inside_action=0;
1581 i_set_state(w_current, SELECT);
1582 i_update_toolbar(w_current);
1584 o_redraw_single(w_current, o_current);
1585 return;
1588 /* convert the line end coords in world unit */
1589 SCREENtoWORLD(w_current,
1590 w_current->last_x, w_current->last_y,
1591 &x, &y);
1592 x = snap_grid(w_current, x);
1593 y = snap_grid(w_current, y);
1595 /* modify the right line end according to whichone */
1596 o_line_modify(w_current, o_current, x, y, whichone);
1598 /* display the new line */
1599 o_redraw_single(w_current, o_current);
1602 /*! \brief Get half the width and height of grip in screen units.
1603 * \par Function Description
1604 * According to the current zoom level, the function returns half the width
1605 * and height of a grip in screen units.
1607 * <B>GRIP_SIZE1</B> and <B>GRIP_SIZE2</B> and <B>GRIP_SIZE3</B> are macros defined
1608 * in libgeda #defines.h. They are the half width/height of a grip in
1609 * world unit for a determined range of zoom factors.
1611 * \param [in] w_current The TOPLEVEL object.
1612 * \return Half grip size in screen units.
1614 int o_grips_size(TOPLEVEL *w_current)
1616 int factor, size;
1618 factor = (int) w_current->page_current->to_world_x_constant;
1619 if (factor > SMALL_ZOOMFACTOR1) {
1620 /* big zoom factor : small size converted to screen unit */
1621 size = SCREENabs(w_current, GRIP_SIZE1);
1622 } else if (factor > SMALL_ZOOMFACTOR2) {
1623 /* medium zoom factor : medium size converted to screen unit */
1624 size = SCREENabs(w_current, GRIP_SIZE2);
1625 } else {
1626 /* small zoom factor : big size converted to screen unit */
1627 size = SCREENabs(w_current, GRIP_SIZE3);
1630 return size;
1633 /*! \brief Draw grip centered at <B>x</B>, <B>y</B>
1634 * \par Function Description
1635 * This function draws a grip centered at (<B>x</B>,<B>y</B>). Its color is
1636 * either the selection color or the overriding color from
1637 * <B>w_current->override_color</B>.
1639 * The size of the grip depends on the current zoom factor.
1641 * <B>x</B> and <B>y</B> are in screen unit.
1643 * \param [in] w_current The TOPLEVEL object.
1644 * \param [in] x Center x screen coordinate for drawing grip.
1645 * \param [in] y Center y screen coordinate for drawing grip.
1647 void o_grips_draw(TOPLEVEL *w_current, int x, int y)
1649 GdkColor *color;
1650 int size, x2size;
1653 * Depending on the current zoom level, the size of the grip is
1654 * determined. <B>size</B> is half the width and height of the grip
1655 * and <B>x2size</B> is the full width and height of the grip.
1657 /* size is half the width of grip */
1658 size = o_grips_size(w_current);
1659 /* x2size is full width */
1660 x2size = 2 * size;
1663 * The grip can be displayed or erased : if <B>w_current->override_color</B>
1664 * is not set the grip is drawn with the selection color ; if
1665 * <B>w_current->override_color</B> is set then the color it refers it
1666 * is used. This way the grip can be erased if this color is the
1667 * background color.
1669 if (w_current->override_color != -1 ) {
1670 /* override : use the override_color instead */
1671 color = x_get_color(w_current->override_color);
1672 } else {
1673 /* use the normal selection color */
1674 color = x_get_color(w_current->select_color);
1676 /* set the color for the grip */
1677 gdk_gc_set_foreground(w_current->gc, color);
1679 /* set the line options for grip : solid, 1 pix wide */
1680 gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
1681 GDK_CAP_BUTT, GDK_JOIN_MITER);
1684 * A grip is a hollow square centered at (<B>x</B>,<B>y</B>) with a
1685 * width/height of <B>x2size</B>.
1687 if (w_current->DONT_REDRAW == 0) {
1688 /* draw the grip in window */
1689 gdk_draw_rectangle(w_current->window, w_current->gc, FALSE,
1690 x - size, y - size, x2size, x2size);
1691 /* draw the grip in backingstore */
1692 gdk_draw_rectangle(w_current->backingstore, w_current->gc, FALSE,
1693 x - size, y - size, x2size, x2size);
1697 /*! \brief Erase grip centered at <B>x</B>,<B>y</B>
1698 * \par Function Description
1699 * This function erases a grip centered at (<B>x</B>,<B>y</B>).
1700 * The size of the grip depends on the current zoom factor.
1702 * The grip is erased by drawing with the background color over the
1703 * visible grip.
1705 * \param [in] w_current The TOPLEVEL object.
1706 * \param [in] x Center x screen coordinate for drawing grip.
1707 * \param [in] y Center y screen coordinate for drawing grip.
1709 void o_grips_erase(TOPLEVEL *w_current, int x, int y)
1711 /* set overriding color */
1712 w_current->override_color = w_current->background_color;
1713 /* draw a grip with backgound color : erase grip */
1714 o_grips_draw(w_current, x, y);
1715 /* return to default */
1716 w_current->override_color = -1;