Cleaned up and consolidated code which creates new pages.
[geda-gaf.git] / gschem / src / o_grips.c
blob783dd2b60cd46ccb823a7f28eeab4d558f78f953
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2000 Ales V. Hvezda
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
19 #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)
38 #define GET_BOX_LEFT(w) \
39 min((w)->start_x, (w)->last_x);
40 #define GET_BOX_TOP(w) \
41 min((w)->start_y, (w)->last_y);
43 #define GET_PICTURE_WIDTH(w) \
44 abs((w)->last_x - (w)->start_x)
45 #define GET_PICTURE_HEIGHT(w) \
46 (w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio
47 #define GET_PICTURE_LEFT(w) \
48 min((w)->start_x, (w)->last_x);
49 #define GET_PICTURE_TOP(w) \
50 (w)->start_y < (w)->last_y ? (w)->start_y : \
51 (w)->start_y-abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio;
53 /*! \brief
54 * This variable holds the identifier of the grip currently under
55 * modification. Its range of values depends on the type of object.
57 static int whichone_changing = -1;
58 /*! \brief
59 * This variable holds a pointer on the object under modification.
61 static OBJECT *object_changing;
63 /*! \brief Check if point is inside grip.
64 * \par Function Description
65 * This function is used to determine if the (<B>x</B>,<B>y</B>) point is
66 * inside a grip of one of the selected object on the current sheet.
67 * The selected object are in a list starting at
68 * <B>w_current->page_current->selection2_head</B>.
69 * The <B>x</B> and <B>y</B> parameters are in world units.
70 * If the point is inside one grip, a pointer on the object it belongs to is
71 * returned and <B>*whichone</B> is set according to the position of the grip
72 * on the object.
73 * Else, <B>*whichone</B> is unchanged and the function returns <B>NULL</B>.
75 * A specific search function is provided for every kind of graphical object.
76 * The list of selected object is covered : each object is tested with the
77 * appropriate function.
79 * \param [in] w_current The TOPLEVEL object.
80 * \param [in] x Current x coordinate of pointer in world units.
81 * \param [in] y Current y coordinate of pointer in world units.
82 * \param [out] whichone Which grip point is selected.
83 * \return Pointer to OBJECT the grip is on, NULL otherwise.
85 OBJECT *o_grips_search_world(TOPLEVEL *w_current, int x, int y, int *whichone)
87 OBJECT *object=NULL;
88 OBJECT *found=NULL;
89 GList *s_current;
90 int size, x2size;
91 int w_size;
93 if (!whichone) {
94 return(NULL);
97 /* get the size of the grip according to zoom level */
98 size = o_grips_size(w_current);
99 /* size is half the width of a grip, x2size is full width */
100 x2size = size * 2;
102 w_size = WORLDabs( w_current, size );
104 /* skip over head */
105 s_current = w_current->page_current->selection_list;
106 while (s_current != NULL) {
107 object = (OBJECT *) s_current->data;
108 if (object) {
109 switch(object->type) {
110 case(OBJ_ARC):
111 /* check the grips of the arc object */
112 found = o_grips_search_arc_world(w_current, object,
113 x, y, w_size, whichone);
114 if(found != NULL) return found;
115 break;
117 case(OBJ_BOX):
118 /* check the grips of the box object */
119 found = o_grips_search_box_world(w_current, object,
120 x, y, w_size, whichone);
121 if(found != NULL) return found;
122 break;
124 case(OBJ_PICTURE):
125 /* check the grips of the picture object */
126 found = o_grips_search_picture_world(w_current, object,
127 x, y, w_size, whichone);
128 if(found != NULL) return found;
129 break;
131 case(OBJ_CIRCLE):
132 /* check the grips of the circle object */
133 found = o_grips_search_circle_world(w_current, object,
134 x, y, w_size, whichone);
135 if(found != NULL) return found;
136 break;
138 case(OBJ_LINE):
139 case(OBJ_PIN):
140 case(OBJ_NET):
141 case(OBJ_BUS):
142 /* check the grips of the line object */
143 /* the function is the same for line, pin, net, bus */
144 found = o_grips_search_line_world(w_current, object,
145 x, y, w_size, whichone);
146 if(found != NULL) return found;
147 break;
149 #if 0
150 /* This code is wrong. Continue searching even if the object */
151 /* does not have grips */
152 default:
153 /* object type is unknown : error condition */
154 return NULL;
155 #endif
158 s_current = s_current->next;
161 return(NULL);
164 /*! \brief Check if pointer is inside arc grip.
165 * \par Function Description
166 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
167 * inside one of the grips of an <B>o_current</B> pointed arc object. If so
168 * the <B>whichone</B> pointed integer is set to the number of this grip and
169 * the return pointer is a pointer on this object. If the point is not
170 * inside a grip the function returns a NULL pointer and the <B>whichone</B>
171 * pointed integer is unset.
173 * An arc object has three grips :
174 * <DL>
175 * <DT>*</DT><DD>one at the center of the arc. This grip is used to modify
176 * the radius of the arc. If this one is selected, the
177 * <B>whichone</B> pointed integer is set to <B>ARC_RADIUS</B>.
178 * <DT>*</DT><DD>one at one end of the arc. It corresponds to the starting
179 * angle of the arc. If this one is selected, the
180 * <B>whichone</B> pointed integer is set to <B>ARC_START_ANGLE</B>.
181 * <DT>*</DT><DD>one at the other end of the arc. It corresponds to the
182 * ending angle of the arc. If this one is selected, the
183 * <B>whichone</B> pointed integer is set to <B>ARC_END_ANGLE</B>.
184 * </DL>
186 * The <B>x</B> and <B>y</B> parameters are in world units.
188 * The <B>size</B> parameter is the width (and height) of the square
189 * representing a grip in world units.
191 * \param [in] w_current The TOPLEVEL object.
192 * \param [in] o_current Arc OBJECT to check.
193 * \param [in] x Current x coordinate of pointer in world units.
194 * \param [in] y Current y coordinate of pointer in world units.
195 * \param [in] size Half the width of the grip square in world units.
196 * \param [out] whichone Which grip point is selected.
197 * \return Pointer to OBJECT the grip is on, NULL otherwise.
199 OBJECT *o_grips_search_arc_world(TOPLEVEL *w_current, OBJECT *o_current,
200 int x, int y, int size, int *whichone)
202 int centerx, centery, radius, start_angle, end_angle;
203 int xmin, ymin, xmax, ymax;
204 int x2size;
205 double tmp;
207 centerx = o_current->arc->x;
208 centery = o_current->arc->y;
209 radius = o_current->arc->width / 2;
210 start_angle = o_current->arc->start_angle;
211 end_angle = o_current->arc->end_angle;
213 /* width/height of the grip */
214 x2size = 2 * size;
216 /* check the grip on the center of the arc */
217 xmin = centerx - size;
218 ymin = centery - size;
219 xmax = xmin + x2size;
220 ymax = ymin + x2size;
221 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
222 *whichone = ARC_RADIUS;
223 return(o_current);
226 /* check the grip at the start angle of the arc */
227 tmp = ((double) start_angle) * M_PI / 180;
228 xmin = centerx + radius * cos(tmp) - size;
229 ymin = centery + radius * sin(tmp) - size;
230 xmax = xmin + x2size;
231 ymax = ymin + x2size;
232 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
233 *whichone = ARC_START_ANGLE;
234 return(o_current);
237 /* check the grip at the end angle of the arc */
238 tmp = ((double) start_angle + end_angle) * M_PI / 180;
239 xmin = centerx + radius * cos(tmp) - size;
240 ymin = centery + radius * sin(tmp) - size;
241 xmax = xmin + x2size;
242 ymax = ymin + x2size;
243 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
244 *whichone = ARC_END_ANGLE;
245 return(o_current);
248 return NULL;
251 /*! \brief Check if pointer is inside box grip.
252 * \par Function Description
253 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
254 * inside one of the grips of the <B>o_current</B> pointed box object.
255 * If so, the <B>whichone</B> pointed integer is set to the identifier of
256 * this grip and the returned pointer is a pointer on this object.
257 * If the point is not inside a grip the function returns a NULL pointer
258 * and the <B>whichone</B> pointed integer is unset.
260 * A box object has four grips : one at each corner of the box. The
261 * identifiers of each corner are <B>BOX_UPPER_LEFT</B>,
262 * <B>BOX_UPPER_RIGHT</B>, <B>BOX_LOWER_LEFT</B> and <B>BOX_LOWER_RIGHT</B>.
264 * The <B>x</B> and <B>y</B> parameters are in world units.
266 * The <B>size</B> parameter is half the width (and half the height) of
267 * the square representing a grip in world units.
269 * \param [in] w_current The TOPLEVEL object.
270 * \param [in] o_current Box OBJECT to check.
271 * \param [in] x Current x coordinate of pointer in world units.
272 * \param [in] y Current y coordinate of pointer in world units.
273 * \param [in] size Half the width of the grip square in world units.
274 * \param [out] whichone Which grip point is selected.
275 * \return Pointer to OBJECT the grip is on, NULL otherwise.
277 OBJECT *o_grips_search_box_world(TOPLEVEL *w_current, OBJECT *o_current,
278 int x, int y, int size, int *whichone)
280 int xmin, ymin, xmax, ymax;
281 int x2size;
283 /* width/height of the grip */
284 x2size = 2 * size;
286 /* inside upper left grip ? */
287 xmin = o_current->box->upper_x - size;
288 ymin = o_current->box->upper_y - size;
289 xmax = xmin + x2size;
290 ymax = ymin + x2size;
291 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
292 *whichone = BOX_UPPER_LEFT;
293 return(o_current);
296 /* inside lower right grip ? */
297 xmin = o_current->box->lower_x - size;
298 ymin = o_current->box->lower_y - size;
299 xmax = xmin + x2size;
300 ymax = ymin + x2size;
301 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
302 *whichone = BOX_LOWER_RIGHT;
303 return(o_current);
306 /* inside upper right grip ? */
307 xmin = o_current->box->lower_x - size;
308 ymin = o_current->box->upper_y - size;
309 xmax = xmin + x2size;
310 ymax = ymin + x2size;
311 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
312 *whichone = BOX_UPPER_RIGHT;
313 return(o_current);
316 /* inside lower left grip ? */
317 xmin = o_current->box->upper_x - size;
318 ymin = o_current->box->lower_y - size;
319 xmax = xmin + x2size;
320 ymax = ymin + x2size;
321 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
322 *whichone = BOX_LOWER_LEFT;
323 return(o_current);
326 return NULL;
329 /*! \brief Check if pointer is inside picture grip.
330 * \par Function Description
331 * This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>)
332 * is inside one of the grips of the <B>o_current</B> pointed picture object.
333 * If so, the <B>whichone</B> pointed integer is set to the identifier of
334 * this grip and the returned pointer is a pointer on this object.
335 * If the point is not inside a grip the function returns a NULL pointer
336 * and the <B>whichone</B> pointed integer is unset.
338 * A picture object has four grips : one at each corner of the picture.
339 * The identifiers of each corner are #PICTURE_UPPER_LEFT,
340 * #PICTURE_UPPER_RIGHT, #PICTURE_LOWER_LEFT and
341 * #PICTURE_LOWER_RIGHT.
343 * The <B>x</B> and <B>y</B> parameters are in world units.
345 * The <B>size</B> parameter is half the width (and half the height) of the
346 * square representing a grip in world units.
348 * \param [in] w_current The TOPLEVEL object.
349 * \param [in] o_current Picture OBJECT to check.
350 * \param [in] x Current x coordinate of pointer in world units.
351 * \param [in] y Current y coordinate of pointer in world units.
352 * \param [in] size Half the width of the grip square in world units.
353 * \param [out] whichone Which grip point is selected.
354 * \return Pointer to OBJECT the grip is on, NULL otherwise.
356 OBJECT *o_grips_search_picture_world(TOPLEVEL *w_current, OBJECT *o_current,
357 int x, int y, int size, int *whichone)
359 int xmin, xmax, ymin, ymax;
360 int x2size;
362 /* width/height of the grip */
363 x2size = 2 * size;
365 /* inside upper left grip ? */
366 xmin = o_current->picture->upper_x - size;
367 ymin = o_current->picture->upper_y - size;
368 xmax = xmin + x2size;
369 ymax = ymin + x2size;
370 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
371 *whichone = PICTURE_UPPER_LEFT;
372 return(o_current);
375 /* inside lower right grip ? */
376 xmin = o_current->picture->lower_x - size;
377 ymin = o_current->picture->lower_y - size;
378 xmax = xmin + x2size;
379 ymax = ymin + x2size;
380 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
381 *whichone = PICTURE_LOWER_RIGHT;
382 return(o_current);
385 /* inside upper right grip ? */
386 xmin = o_current->picture->lower_x - size;
387 ymin = o_current->picture->upper_y - size;
388 xmax = xmin + x2size;
389 ymax = ymin + x2size;
390 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
391 *whichone = PICTURE_UPPER_RIGHT;
392 return(o_current);
395 /* inside lower left grip ? */
396 xmin = o_current->picture->upper_x - size;
397 ymin = o_current->picture->lower_y - size;
398 xmax = xmin + x2size;
399 ymax = ymin + x2size;
400 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
401 *whichone = PICTURE_LOWER_LEFT;
402 return(o_current);
405 return NULL;
408 /*! \brief Check if pointer is inside circle grip.
409 * \par Function Description
410 * This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
411 * the grip of the circle object <B>o_current</B>.
412 * It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
413 * is in one of these areas.
414 * If the event occured in one of the grip, a pointer on the object is
415 * returned and <B>*whichone</B> is set to the identifier of the grip.
416 * If not, the function returns a <B>NULL</B> pointer and <B>*whichone</B>
417 * is unchanged.
419 * The parameter <B>size</B> is half the size of the grip in world units.
421 * A circle has only one grip on the lower right corner of the box it
422 * is inscribed in. Moving this grip change the radius of the circle.
423 * The identifier of this grip is <B>CIRCLE_RADIUS</B>.
425 * \param [in] w_current The TOPLEVEL object.
426 * \param [in] o_current Circle OBJECT to check.
427 * \param [in] x Current x coordinate of pointer in world units.
428 * \param [in] y Current y coordinate of pointer in world units.
429 * \param [in] size Half the width of the grip square in world units.
430 * \param [out] whichone Which grip point is selected.
431 * \return Pointer to OBJECT the grip is on, NULL otherwise.
433 OBJECT *o_grips_search_circle_world(TOPLEVEL *w_current, OBJECT *o_current,
434 int x, int y, int size, int *whichone)
436 int xmin, ymin, xmax, ymax;
437 int x1, y1;
438 int x2size;
440 /* width/height of the grip */
441 x2size = 2 * size;
443 /* check the grip for radius */
444 x1 = o_current->circle->center_x + o_current->circle->radius;
445 y1 = o_current->circle->center_y - o_current->circle->radius;
446 xmin = x1 - size;
447 ymin = y1 - size;
448 xmax = xmin + x2size;
449 ymax = ymin + x2size;
450 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
451 /* printf("found something 0!\n"); */
452 *whichone = CIRCLE_RADIUS;
453 return(o_current);
456 return NULL;
459 /*! \brief Check if pointer is inside line grip.
460 * \par Function Description
461 * This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
462 * the grip of the line object <B>o_current</B>.
463 * It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
464 * is in one of these areas.
465 * If the event occured in one of its grip, a pointer on the object is
466 * returned and <B>*whichone</B> is set to the identifier of the grip. If not,
467 * the function returns <B>NULL</B> pointer and <B>*whichone</B> is unchanged.
469 * The parameter <B>size</B> is half the size of the grip in world units.
471 * \param [in] w_current The TOPLEVEL object.
472 * \param [in] o_current Line OBJECT to check.
473 * \param [in] x Current x coordinate of pointer in world units.
474 * \param [in] y Current y coordinate of pointer in world units.
475 * \param [in] size Half the width of the grip square in world units.
476 * \param [out] whichone Which grip point is selected.
477 * \return Pointer to OBJECT the grip is on, NULL otherwise.
479 OBJECT *o_grips_search_line_world(TOPLEVEL *w_current, OBJECT *o_current,
480 int x, int y, int size, int *whichone)
482 int xmin, ymin, xmax, ymax;
483 int x2size;
485 /* width/height of the grip */
486 x2size = 2 * size;
488 /* check the grip on the end of line 1 */
489 xmin = o_current->line->x[LINE_END1] - size;
490 ymin = o_current->line->y[LINE_END1] - size;
491 xmax = xmin + x2size;
492 ymax = ymin + x2size;
493 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
494 *whichone = LINE_END1;
495 return(o_current);
498 /* check the grip on the end of line 2 */
499 xmin = o_current->line->x[LINE_END2] - size;
500 ymin = o_current->line->y[LINE_END2] - size;
501 xmax = xmin + x2size;
502 ymax = ymin + x2size;
503 if (inside_region(xmin, ymin, xmax, ymax, x, y)) {
504 *whichone = LINE_END2;
505 return(o_current);
508 return NULL;
511 /*! \brief Start process of modifiying one grip.
512 * \par Function Description
513 * This function starts the process of modifying one grip of an object
514 * on the current sheet. The event occured in (<B>x</B>,<B>y</B>) in screen unit.
515 * If this position is related to a grip of an object, the function
516 * prepares the modification of this grip thanks to the user input.
518 * The function returns <B>FALSE</B> if an error occured of if no grip
519 * have been found under (<B>x</B>,<B>y</B>). It returns <B>TRUE</B> if a grip
520 * has been found and modification of the object has been started.
522 * If a grip has been found, this function modifies the global variables
523 * <B>whichone_changing</B> and <B>object_changing</B> with respectively the
524 * identifier of the grip and the object it belongs to.
526 * \param [in] w_current The TOPLEVEL object.
527 * \param [in] x Current x coordinate of pointer in screen units.
528 * \param [in] y Current y coordinate of pointer in screen units.
529 * \return FALSE if an error occurred or no grip was found, TRUE otherwise.
531 int o_grips_start(TOPLEVEL *w_current, int x, int y)
533 int w_x, w_y;
534 OBJECT *object;
535 int whichone;
537 if (w_current->draw_grips == FALSE) {
538 return(FALSE);
541 SCREENtoWORLD( w_current, x, y, &w_x, &w_y );
543 /* search if there is a grip on a selected object at (x,y) */
544 object = o_grips_search_world(w_current, w_x, w_y, &whichone);
545 if (object) {
546 /* there is one */
547 /* depending on its type, start the modification process */
548 switch(object->type) {
549 case(OBJ_ARC):
550 /* start the modification of a grip on an arc */
551 o_grips_start_arc(w_current, object, x, y, whichone);
553 whichone_changing = whichone;
554 object_changing = object;
555 return(TRUE);
556 break;
558 case(OBJ_BOX):
559 /* start the modification of a grip on a box */
560 o_grips_start_box(w_current, object, x, y, whichone);
562 whichone_changing = whichone;
563 object_changing = object;
564 return(TRUE);
565 break;
567 case(OBJ_PICTURE):
568 /* start the modification of a grip on a picture */
569 o_grips_start_picture(w_current, object, x, y, whichone);
571 whichone_changing = whichone;
572 object_changing = object;
573 return(TRUE);
574 break;
576 case(OBJ_CIRCLE):
577 /* start the modification of a grip on a circle */
578 o_grips_start_circle(w_current, object, x, y, whichone);
580 whichone_changing = whichone;
581 object_changing = object;
582 return(TRUE);
583 break;
585 case(OBJ_LINE):
586 /* start the modification of a grip on a line */
587 o_grips_start_line(w_current, object, x, y, whichone);
589 whichone_changing = whichone;
590 object_changing = object;
591 return(TRUE);
592 break;
594 case(OBJ_NET):
595 w_current->last_drawb_mode = -1;
596 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
597 &w_current->last_x, &w_current->last_y );
598 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
599 &w_current->start_x, &w_current->start_y );
601 o_net_erase(w_current, object);
602 gdk_gc_set_foreground(w_current->xor_gc,
603 x_get_darkcolor(w_current->select_color) );
604 gdk_draw_line(w_current->window, w_current->xor_gc,
605 w_current->start_x, w_current->start_y,
606 w_current->last_x, w_current->last_y);
607 o_line_erase_grips(w_current, object);
609 whichone_changing = whichone;
610 object_changing = object;
611 gdk_gc_set_foreground(w_current->gc,
612 x_get_color(w_current->background_color));
613 return(TRUE);
615 break;
617 case(OBJ_PIN):
619 w_current->last_drawb_mode = -1;
620 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
621 &w_current->last_x, &w_current->last_y );
622 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
623 &w_current->start_x, &w_current->start_y );
625 o_pin_erase(w_current, object);
626 gdk_gc_set_foreground(w_current->xor_gc,
627 x_get_darkcolor(w_current->select_color) );
628 gdk_draw_line(w_current->window, w_current->xor_gc,
629 w_current->start_x, w_current->start_y,
630 w_current->last_x, w_current->last_y);
631 o_line_erase_grips(w_current, object);
633 whichone_changing = whichone;
634 object_changing = object;
635 return(TRUE);
637 break;
639 case(OBJ_BUS):
640 w_current->last_drawb_mode = -1;
641 WORLDtoSCREEN( w_current, object->line->x[whichone], object->line->y[whichone],
642 &w_current->last_x, &w_current->last_y );
643 WORLDtoSCREEN( w_current, object->line->x[!whichone], object->line->y[!whichone],
644 &w_current->start_x, &w_current->start_y );
646 o_bus_erase(w_current, object);
647 gdk_gc_set_foreground(w_current->xor_gc,
648 x_get_darkcolor(w_current->select_color) );
649 gdk_draw_line(w_current->window, w_current->xor_gc,
650 w_current->start_x, w_current->start_y,
651 w_current->last_x, w_current->last_y);
652 o_line_erase_grips(w_current, object);
654 whichone_changing = whichone;
655 object_changing = object;
656 gdk_gc_set_foreground(w_current->gc,
657 x_get_color(w_current->background_color));
658 return(TRUE);
660 break;
662 default:
663 /* object type unknown : error condition */
664 return(FALSE);
669 return(FALSE);
672 /*! \brief Initialize grip motion process for an arc.
673 * \par Function Description
674 * This function initializes the grip motion process for an arc.
675 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
676 * structure the coordinates of the center, the radius and the two angle
677 * that describes an arc. These variables are used in the grip process.
679 * The coordinates of the center of the arc on x- and y-axis are stored
680 * into the <B>loc_x</B> and <B>loc_y</B> fields of the TOPLEVEL structure
681 * in screen unit.
683 * The radius of the center is stored into the <B>distance</B> field of
684 * the TOPLEVEL structure in screen unit.
686 * The two angles describing the arc on a circle are stored into the
687 * <B>start_x</B> for the starting angle and <B>start_y</B> for the ending angle.
688 * These angles are expressed in degrees.
690 * Depending on which grips has been selected on the arc, the
691 * corresponding variables in its original state is duplicated in
692 * <B>last_x</B> and/or <B>last_y</B> of the TOPLEVEL structure.
694 * \param [in] w_current The TOPLEVEL object.
695 * \param [in] o_current Arc OBJECT to check.
696 * \param [in] x (unused)
697 * \param [in] y (unused)
698 * \param [out] whichone (unused)
700 void o_grips_start_arc(TOPLEVEL *w_current, OBJECT *o_current,
701 int x, int y, int whichone)
703 w_current->last_drawb_mode = -1;
705 /* erase the arc before */
706 o_arc_erase(w_current, o_current);
708 /* describe the arc with TOPLEVEL variables */
709 /* center */
710 WORLDtoSCREEN( w_current, o_current->arc->x, o_current->arc->y, &w_current->start_x, &w_current->start_y );
711 /* radius */
712 w_current->distance = SCREENabs( w_current, o_current->arc->width / 2 );
713 /* angles */
714 w_current->loc_x = o_current->arc->start_angle;
715 w_current->loc_y = o_current->arc->end_angle;
717 /* draw the first temporary arc */
718 o_arc_rubberarc_xor(w_current);
722 /*! \brief Initialize grip motion process for a box.
723 * \par Function Description
724 * This function initializes the grip motion process for a box. From the
725 * <B>o_current</B> pointed object, it stores into the TOPLEVEL structure
726 * the .... These variables are used in the grip process.
728 * The function first erases the grips.
730 * The coordinates of the selected corner are put in
731 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
733 * The coordinates of the opposite corner go in
734 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
735 * to change during the action.
737 * \param [in] w_current The TOPLEVEL object.
738 * \param [in] o_current Box OBJECT to check.
739 * \param [in] x (unused)
740 * \param [in] y (unused)
741 * \param [out] whichone Which coordinate to check.
743 void o_grips_start_box(TOPLEVEL *w_current, OBJECT *o_current,
744 int x, int y, int whichone)
746 w_current->last_drawb_mode = -1;
748 /* erase the box before */
749 o_box_erase(w_current, o_current);
751 /* (last_x,last_y) is the selected corner */
752 /* (start_x, start_y) is the opposite corner */
753 switch(whichone) {
754 case BOX_UPPER_LEFT:
755 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
756 &w_current->last_x, &w_current->last_y );
757 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
758 &w_current->start_x, &w_current->start_y );
759 break;
760 case BOX_LOWER_RIGHT:
761 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
762 &w_current->last_x, &w_current->last_y );
763 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
764 &w_current->start_x, &w_current->start_y );
765 break;
766 case BOX_UPPER_RIGHT:
767 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->upper_y,
768 &w_current->last_x, &w_current->last_y );
769 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->lower_y,
770 &w_current->start_x, &w_current->start_y );
771 break;
772 case BOX_LOWER_LEFT:
773 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->lower_y,
774 &w_current->last_x, &w_current->last_y );
775 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->upper_y,
776 &w_current->start_x, &w_current->start_y );
777 break;
778 default:
779 return; /* error */
782 /* draw the first temporary box */
783 o_box_rubberbox_xor(w_current);
787 /*! \brief Initialize grip motion process for a picture.
788 * \par Function Description
789 * This function initializes the grip motion process for a picture.
790 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
791 * structure the .... These variables are used in the grip process.
793 * The function first erases the grips.
795 * The coordinates of the selected corner are put in
796 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
798 * The coordinates of the opposite corner go in
799 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not
800 * suppose to change during the action.
802 * \param [in] w_current The TOPLEVEL object.
803 * \param [in] o_current Picture OBJECT to check.
804 * \param [in] x (unused)
805 * \param [in] y (unused)
806 * \param [out] whichone Which coordinate to check.
808 void o_grips_start_picture(TOPLEVEL *w_current, OBJECT *o_current,
809 int x, int y, int whichone)
811 w_current->last_drawb_mode = -1;
813 /* erase the picture before */
814 o_picture_erase(w_current, o_current);
815 w_current->current_pixbuf = o_current->picture->original_picture;
816 w_current->pixbuf_filename = o_current->picture->filename;
817 w_current->pixbuf_wh_ratio = o_current->picture->ratio;
819 /* (last_x,last_y) is the selected corner */
820 /* (start_x, start_y) is the opposite corner */
821 switch(whichone) {
822 case PICTURE_UPPER_LEFT:
823 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->upper_y,
824 &w_current->last_x, &w_current->last_y );
825 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->lower_y,
826 &w_current->start_x, &w_current->start_y );
827 break;
828 case PICTURE_LOWER_RIGHT:
829 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->lower_y,
830 &w_current->last_x, &w_current->last_y );
831 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->upper_y,
832 &w_current->start_x, &w_current->start_y );
833 break;
834 case PICTURE_UPPER_RIGHT:
835 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->upper_y,
836 &w_current->last_x, &w_current->last_y );
837 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->lower_y,
838 &w_current->start_x, &w_current->start_y );
839 break;
840 case PICTURE_LOWER_LEFT:
841 WORLDtoSCREEN( w_current, o_current->picture->upper_x, o_current->picture->lower_y,
842 &w_current->last_x, &w_current->last_y );
843 WORLDtoSCREEN( w_current, o_current->picture->lower_x, o_current->picture->upper_y,
844 &w_current->start_x, &w_current->start_y );
845 break;
846 default:
847 return; /* error */
850 /* draw the first temporary picture */
851 o_picture_rubberbox_xor(w_current);
855 /*! \brief Initialize grip motion process for a circle.
856 * \par Function Description
857 * This function initializes the grip motion process for a circle.
858 * From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
859 * structure the coordinate of the center and the radius. These variables
860 * are used in the grip process.
862 * The function first erases the grips.
864 * The coordinates of the center are put in
865 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
866 * to change during the action.
868 * The coordinates of the point on the circle to the right of the center
869 * go in (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
871 * \param [in] w_current The TOPLEVEL object.
872 * \param [in] o_current Circle OBJECT to check.
873 * \param [in] x (unused)
874 * \param [in] y (unused)
875 * \param [out] whichone Which coordinate to check.
877 void o_grips_start_circle(TOPLEVEL *w_current, OBJECT *o_current,
878 int x, int y, int whichone)
880 w_current->last_drawb_mode = -1;
882 /* erase the circle before */
883 o_circle_erase(w_current, o_current);
885 /* describe the circle with TOPLEVEL variables */
886 /* (start_x, start_y) is the center of the circle */
887 WORLDtoSCREEN( w_current, o_current->circle->center_x, o_current->circle->center_y,
888 &w_current->start_x, &w_current->start_y );
889 /* (last_x,last_y) is the point on circle on the right of center */
890 WORLDtoSCREEN( w_current, o_current->circle->center_x + o_current->circle->radius, o_current->circle->center_y,
891 &w_current->last_x, &w_current->last_y );
892 /* distance is the radius of the circle */
893 w_current->distance = SCREENabs( w_current, o_current->circle->radius );
895 /* draw the first temporary circle */
896 o_circle_rubbercircle_xor(w_current);
900 /*! \brief Initialize grip motion process for a line.
901 * This function starts the move of one of the two grips of the line
902 * object <B>o_current</B>.
903 * The line and its grips are first erased. The move of the grips is
904 * materializd with a temporary line in selection color drawn over the
905 * sheet with an xor-function.
907 * During the move of the grip, the line is described by
908 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and
909 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
911 * The line end that corresponds to the moving grip is in
912 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
914 * \param [in] w_current The TOPLEVEL object.
915 * \param [in] o_current Line OBJECT to check.
916 * \param [in] x (unused)
917 * \param [in] y (unused)
918 * \param [out] whichone Which coordinate to check.
920 void o_grips_start_line(TOPLEVEL *w_current, OBJECT *o_current,
921 int x, int y, int whichone)
923 w_current->last_drawb_mode = -1;
925 /* erase the line before */
926 o_line_erase(w_current, o_current);
928 /* describe the line with TOPLEVEL variables */
929 WORLDtoSCREEN( w_current, o_current->line->x[whichone], o_current->line->y[whichone],
930 &w_current->last_x, &w_current->last_y );
931 WORLDtoSCREEN( w_current, o_current->line->x[!whichone], o_current->line->y[!whichone],
932 &w_current->start_x, &w_current->start_y );
934 /* draw the first temporary line */
935 o_line_rubberline_xor(w_current);
938 /*! \brief Modify previously selected object according to mouse position.
939 * \par Function Description
940 * This function modify the previously selected
941 * object according to the mouse position in <B>x</B> and <B>y</B>.
942 * The grip under modification is updated and the temporary object displayed.
944 * The object under modification is <B>object_changing</B> and the grip
945 * concerned is <B>whichone_changing</B>.
947 * Depending on the object type, a specific function is used.
948 * It erases the temporary object, updates its internal representation,
949 * and draws it again.
951 * \param [in] w_current The TOPLEVEL object.
952 * \param [in] x Current x coordinate of pointer in screen units.
953 * \param [in] y Current y coordinate of pointer in screen units.
955 void o_grips_motion(TOPLEVEL *w_current, int x, int y)
958 if (w_current->inside_action == 0) {
959 o_redraw(w_current, w_current->page_current->object_head, TRUE);
960 return;
963 /* no object changing */
964 if (object_changing == NULL) {
965 /* stop grip process */
966 o_redraw(w_current, w_current->page_current->object_head, TRUE);
967 return;
970 switch(object_changing->type) {
971 case(OBJ_ARC):
972 /* erase, update and draw an arc */
973 o_grips_motion_arc(w_current, x, y, whichone_changing);
974 break;
976 case(OBJ_BOX):
977 /* erase, update and draw a box */
978 o_grips_motion_box(w_current, x, y, whichone_changing);
979 break;
981 case(OBJ_PICTURE):
982 /* erase, update and draw a box */
983 o_grips_motion_picture(w_current, x, y, whichone_changing);
984 break;
986 case(OBJ_CIRCLE):
987 /* erase, update and draw a circle */
988 o_grips_motion_circle(w_current, x, y, whichone_changing);
989 break;
991 case(OBJ_LINE):
992 case(OBJ_NET):
993 case(OBJ_PIN):
994 case(OBJ_BUS):
995 /* erase, update and draw a line */
996 /* same for net, pin and bus as they share the same internal rep. */
997 o_grips_motion_line(w_current, x, y, whichone_changing);
998 break;
1000 default:
1001 return; /* error condition */
1006 /*! \brief Modify previously selected arc according to mouse position.
1007 * \par Function Description
1008 * This function is the refreshing part of the grip motion process.
1009 * It is called whenever the position of the pointer is changed,
1010 * therefore requiring the TOPLEVEL variables to be updated.
1011 * Depending on the grip selected and moved, the temporary TOPLEVEL
1012 * variables are changed according to the current position of the pointer.
1014 * If the grip at the center of the arc has been moved - modifying the
1015 * radius of the arc -, the <B>w_current->distance</B> field is updated.
1016 * To increase the radius of the arc, the user must drag the grip to the
1017 * right of the center. To decrease the radius of the arc, the user must
1018 * drag the grip to the left of the center. Negative radius can not be
1019 * obtained.
1021 * If one of the end of arc grip has been moved - modifying the arc
1022 * describing the arc -, the <B>w_current->start_x</B> or
1023 * <B>w_current->start_y</B> are updated according to which of the grip
1024 * has been selected.
1026 * \param [in] w_current The TOPLEVEL object.
1027 * \param [in] x Current x coordinate of pointer in screen units.
1028 * \param [in] y Current y coordinate of pointer in screen units.
1029 * \param [in] whichone Which grip to start motion with.
1031 void o_grips_motion_arc(TOPLEVEL *w_current, int x, int y, int whichone)
1033 o_arc_rubberarc(w_current, x, y, whichone);
1036 /*! \brief Modify previously selected box according to mouse position.
1037 * \par Function Description
1038 * This function is the refreshing part of the grip motion process. It is
1039 * called whenever the position of the pointer is changed, therefore
1040 * requiring the TOPLEVEL variables to be updated.
1041 * Depending on the grip selected and moved, the temporary TOPLEVEL
1042 * variables are changed according to the current position of the pointer
1043 * and the modifications temporary drawn.
1045 * This function only makes a call to #o_box_rubberbox() that updates
1046 * the TOPLEVEL variables, erase the previous temporary box and draw the
1047 * new temporary box.
1049 * \param [in] w_current The TOPLEVEL object.
1050 * \param [in] x Current x coordinate of pointer in screen units.
1051 * \param [in] y Current y coordinate of pointer in screen units.
1052 * \param [in] whichone Which grip to start motion with.
1054 void o_grips_motion_box(TOPLEVEL *w_current, int x, int y, int whichone)
1056 /* erase, update and draw the temporary box */
1057 o_box_rubberbox(w_current, x, y);
1060 /*! \brief Modify previously selected picture according to mouse position.
1061 * \par Function Description
1062 * This function is the refreshing part of the grip motion process. It is
1063 * called whenever the position of the pointer is changed, therefore
1064 * requiring the TOPLEVEL variables to be updated.
1065 * Depending on the grip selected and moved, the temporary TOPLEVEL
1066 * variables are changed according to the current position of the pointer
1067 * and the modifications temporary drawn.
1069 * This function only makes a call to #o_picture_rubberbox() that
1070 * updates the TOPLEVEL variables, erase the previous temporary picture
1071 * and draw the new temporary picture.
1073 * \param [in] w_current The TOPLEVEL object.
1074 * \param [in] x Current x coordinate of pointer in screen units.
1075 * \param [in] y Current y coordinate of pointer in screen units.
1076 * \param [in] whichone Which grip to start motion with.
1078 void o_grips_motion_picture(TOPLEVEL *w_current, int x, int y, int whichone)
1080 /* erase, update and draw the temporary picture */
1081 o_picture_rubberbox(w_current, x, y);
1084 /*! \brief Modify previously selected circle according to mouse position.
1085 * \par Function Description
1086 * This function is the refreshing part of the grip motion process. It is
1087 * called whenever the position of the pointer is changed, therefore
1088 * requiring the TOPLEVEL variables to be updated.
1089 * Depending on the grip selected and moved, the temporary TOPLEVEL
1090 * variables are changed according to the current position of the pointer
1091 * and the modifications temporary drawn.
1093 * This function only makes a call to #o_circle_rubbercircle() that updates
1094 * the TOPLEVEL variables, erase the previous temporary circle and draw
1095 * the new temporary circle.
1097 * \param [in] w_current The TOPLEVEL object.
1098 * \param [in] x Current x coordinate of pointer in screen units.
1099 * \param [in] y Current y coordinate of pointer in screen units.
1100 * \param [in] whichone Which grip to start motion with.
1102 void o_grips_motion_circle(TOPLEVEL *w_current, int x, int y, int whichone)
1104 /* erase, update and draw the temporary circle */
1105 o_circle_rubbercircle(w_current, x, y);
1109 /*! \brief Modify previously selected line according to mouse position.
1110 * \par Function Description
1111 * This function is called during the move of the grip to update the
1112 * temporary line drawn under the mouse pointer.
1113 * The current position of the mouse is in <B>x</B> and <B>y</B> in screen coords.
1115 * \param [in] w_current The TOPLEVEL object.
1116 * \param [in] x Current x coordinate of pointer in screen units.
1117 * \param [in] y Current y coordinate of pointer in screen units.
1118 * \param [in] whichone Which grip to start motion with.
1120 void o_grips_motion_line(TOPLEVEL *w_current, int x, int y, int whichone)
1122 /* erase, update and draw the temporary line */
1123 o_line_rubberline(w_current, x, y);
1127 /*! \brief End process of modifying object with grip.
1128 * \par Function Description
1129 * This function ends the process of modifying a parameter of an object
1130 * with a grip.
1131 * The temporary representation of the object is erased, the object is
1132 * modified and finally drawn.
1134 * The object under modification is <B>object_changing</B> and the grip
1135 * concerned is <B>whichone_changing</B>.
1137 * Depending on the object type, a specific function is used. It erases
1138 * the temporary object, updates the object and draws the modified object
1139 * normally.
1141 * \param [in,out] w_current The TOPLEVEL object.
1143 void o_grips_end(TOPLEVEL *w_current)
1145 OBJECT *object=NULL;
1146 int x, y;
1147 GList *other_objects = NULL;
1148 GList *connected_objects = NULL;
1149 int size;
1151 object = object_changing;
1153 if (!object) {
1154 /* actually this is an error condition hack */
1155 w_current->inside_action = 0;
1156 i_set_state(w_current, SELECT);
1157 return;
1160 switch(object->type) {
1162 case(OBJ_ARC):
1163 /* modify an arc object */
1164 o_grips_end_arc(w_current, object, whichone_changing);
1165 break;
1167 case(OBJ_BOX):
1168 /* modify a box object */
1169 o_grips_end_box(w_current, object, whichone_changing);
1170 break;
1172 case(OBJ_PICTURE):
1173 /* modify a picture object */
1174 o_grips_end_picture(w_current, object, whichone_changing);
1175 break;
1177 case(OBJ_CIRCLE):
1178 /* modify a circle object */
1179 o_grips_end_circle(w_current, object, whichone_changing);
1180 break;
1182 case(OBJ_LINE):
1183 /* modify a line object */
1184 o_grips_end_line(w_current, object, whichone_changing);
1185 break;
1187 case(OBJ_NET):
1188 /* don't allow zero length nets / lines / pins
1189 * this ends the net drawing behavior
1190 * we want this? hack */
1191 if ((w_current->start_x == w_current->last_x) &&
1192 (w_current->start_y == w_current->last_y)) {
1193 w_current->start_x = (-1);
1194 w_current->start_y = (-1);
1195 w_current->last_x = (-1);
1196 w_current->last_y = (-1);
1197 w_current->inside_action=0;
1198 i_set_state(w_current, SELECT);
1199 o_net_eraserubber(w_current);
1200 o_redraw_single(w_current, object);
1201 i_update_toolbar(w_current);
1202 return;
1206 SCREENtoWORLD(w_current,
1207 w_current->last_x,
1208 w_current->last_y, &x, &y);
1210 x = snap_grid(w_current, x);
1211 y = snap_grid(w_current, y);
1213 o_cue_undraw(w_current, object);
1214 o_net_erase(w_current, object);
1215 /* erase xor line */
1216 gdk_gc_set_foreground(w_current->xor_gc,
1217 x_get_darkcolor(w_current->select_color));
1218 gdk_draw_line(w_current->window, w_current->xor_gc,
1219 w_current->start_x, w_current->start_y,
1220 w_current->last_x, w_current->last_y);
1221 o_line_erase_grips(w_current, object);
1223 other_objects = s_conn_return_others(other_objects, object);
1224 s_conn_remove(w_current, object);
1226 o_net_modify(w_current, object, x, y, whichone_changing);
1228 s_conn_update_object(w_current, object);
1230 /* get the other connected objects and redraw them */
1231 connected_objects = s_conn_return_others(connected_objects,
1232 object);
1234 /* add bus rippers if necessary */
1235 if (o_net_add_busrippers(w_current, object, connected_objects)) {
1237 o_net_erase(w_current, object);
1238 /*o_line_erase_grips(w_current, object); */
1240 if (w_current->net_style == THICK ) {
1241 size = SCREENabs(w_current, 10);
1243 if (size < 0)
1244 size=0;
1246 gdk_gc_set_line_attributes(w_current->gc, size,
1247 GDK_LINE_SOLID,
1248 GDK_CAP_BUTT,
1249 GDK_JOIN_MITER);
1252 gdk_gc_set_foreground(w_current->gc,
1253 x_get_color(w_current->background_color));
1254 gdk_draw_line(w_current->window, w_current->gc,
1255 w_current->start_x, w_current->start_y,
1256 w_current->last_x, w_current->last_y);
1258 o_cue_undraw(w_current, object);
1259 o_net_draw(w_current, object);
1260 o_cue_draw_single(w_current, object);
1262 if (w_current->net_style == THICK ) {
1263 gdk_gc_set_line_attributes(w_current->gc, 0,
1264 GDK_LINE_SOLID,
1265 GDK_CAP_NOT_LAST,
1266 GDK_JOIN_MITER);
1270 /* draw the object objects */
1271 o_cue_undraw_list(w_current, other_objects);
1272 o_cue_draw_list(w_current, other_objects);
1274 o_redraw_single(w_current, object);
1276 if (connected_objects) {
1277 g_list_free(connected_objects);
1278 connected_objects = NULL;
1281 /* get the other connected objects and redraw them */
1282 connected_objects = s_conn_return_others(connected_objects,
1283 object);
1285 o_cue_undraw_list(w_current, connected_objects);
1286 o_cue_draw_list(w_current, connected_objects);
1287 /* finally draw this objects cues */
1288 o_cue_draw_single(w_current, object);
1289 break;
1291 case(OBJ_PIN):
1292 /* don't allow zero length nets / lines / pins
1293 * this ends the net drawing behavior
1294 * we want this? hack */
1295 if ((w_current->start_x == w_current->last_x) &&
1296 (w_current->start_y == w_current->last_y)) {
1297 w_current->start_x = (-1);
1298 w_current->start_y = (-1);
1299 w_current->last_x = (-1);
1300 w_current->last_y = (-1);
1301 o_redraw_single(w_current, object);
1302 w_current->inside_action=0;
1303 i_set_state(w_current, SELECT);
1304 i_update_toolbar(w_current);
1305 return;
1309 SCREENtoWORLD(w_current,
1310 w_current->last_x,
1311 w_current->last_y, &x, &y);
1313 x = snap_grid(w_current, x);
1314 y = snap_grid(w_current, y);
1316 o_cue_undraw(w_current, object);
1317 o_pin_erase(w_current, object);
1318 /* erase xor line */
1319 gdk_gc_set_foreground(w_current->xor_gc,
1320 x_get_darkcolor(w_current->select_color));
1321 gdk_draw_line(w_current->window, w_current->xor_gc,
1322 w_current->start_x, w_current->start_y,
1323 w_current->last_x, w_current->last_y);
1324 o_line_erase_grips(w_current, object);
1326 other_objects = s_conn_return_others(other_objects, object);
1327 s_conn_remove(w_current, object);
1329 o_pin_modify(w_current, object, x, y,
1330 whichone_changing);
1331 s_conn_update_object(w_current, object);
1332 o_redraw_single(w_current, object);
1334 /* draw the object objects */
1335 o_cue_undraw_list(w_current, other_objects);
1336 o_cue_draw_list(w_current, other_objects);
1338 /* get the other connected objects and redraw them */
1339 connected_objects = s_conn_return_others(connected_objects,
1340 object);
1341 o_cue_undraw_list(w_current, connected_objects);
1342 o_cue_draw_list(w_current, connected_objects);
1344 /* finally draw this objects cues */
1345 o_cue_draw_single(w_current, object);
1346 break;
1348 case(OBJ_BUS):
1349 /* don't allow zero length nets / lines / pins
1350 * this ends the net drawing behavior
1351 * we want this? hack */
1352 if ((w_current->start_x == w_current->last_x) &&
1353 (w_current->start_y == w_current->last_y)) {
1354 w_current->start_x = (-1);
1355 w_current->start_y = (-1);
1356 w_current->last_x = (-1);
1357 w_current->last_y = (-1);
1358 o_net_eraserubber(w_current);
1359 o_redraw_single(w_current, object);
1360 w_current->inside_action=0;
1361 i_set_state(w_current, SELECT);
1362 i_update_toolbar(w_current);
1363 return;
1366 SCREENtoWORLD(w_current,
1367 w_current->last_x,
1368 w_current->last_y, &x, &y);
1370 x = snap_grid(w_current, x);
1371 y = snap_grid(w_current, y);
1373 o_cue_undraw(w_current, object);
1374 o_bus_erase(w_current, object);
1375 /* erase xor line */
1376 gdk_gc_set_foreground(w_current->xor_gc,
1377 x_get_darkcolor(w_current->select_color));
1378 gdk_draw_line(w_current->window, w_current->xor_gc,
1379 w_current->start_x, w_current->start_y,
1380 w_current->last_x, w_current->last_y);
1381 o_line_erase_grips(w_current, object);
1383 other_objects = s_conn_return_others(other_objects, object);
1384 s_conn_remove(w_current, object);
1386 o_bus_modify(w_current, object, x, y,
1387 whichone_changing);
1388 s_conn_update_object(w_current, object);
1389 o_redraw_single(w_current, object);
1391 /* draw the object objects */
1392 o_cue_undraw_list(w_current, other_objects);
1393 o_cue_draw_list(w_current, other_objects);
1395 /* get the other connected objects and redraw them */
1396 connected_objects = s_conn_return_others(connected_objects,
1397 object);
1398 o_cue_undraw_list(w_current, connected_objects);
1399 o_cue_draw_list(w_current, connected_objects);
1401 /* finally draw this objects cues */
1402 o_cue_draw_single(w_current, object);
1403 break;
1405 default:
1406 return;
1410 w_current->page_current->CHANGED=1;
1412 g_list_free(other_objects);
1413 other_objects = NULL;
1414 g_list_free(connected_objects);
1415 connected_objects = NULL;
1417 /* reset global variables */
1418 whichone_changing = -1;
1419 object_changing = NULL;
1421 o_undo_savestate(w_current, UNDO_ALL);
1424 /*! \brief End process of modifying arc object with grip.
1425 * \par Function Description
1426 * This function ends the grips process specific to an arc object. It erases
1427 * the old arc and write back to the object the new parameters of the arc.
1428 * Depending on the grip selected and moved, the right fields are updated.
1429 * The function handles the conversion from screen unit to world unit before
1430 * updating and redrawing.
1432 * If the grip at the center of the arc has been moved - modifying the radius
1433 * of the arc -, the new radius is calculated expressed in world unit
1434 * (the center is unchanged). It is updated with the function #o_arc_modify().
1436 * If one of the end of arc grip has been moved - modifying one of the
1437 * angles describing the arc -, this angle is updated with the
1438 * #o_arc_modify() function.
1440 * \param [in] w_current The TOPLEVEL object.
1441 * \param [in] o_current Arc OBJECT to end modification on.
1442 * \param [in] whichone Which grip is pointed to.
1444 void o_grips_end_arc(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1446 int arg1, arg2;
1448 /* erase the temporary arc */
1449 o_arc_rubberarc_xor(w_current);
1451 /* determination of the parameters to give to o_arc_modify() */
1452 switch(whichone) {
1453 case ARC_RADIUS:
1454 /* convert the radius in world coords */
1455 arg1 = WORLDabs(w_current, w_current->distance);
1456 /* second parameter is not used */
1457 arg2 = -1;
1458 break;
1460 case ARC_START_ANGLE:
1461 /* get the start angle from w_current */
1462 arg1 = w_current->loc_x;
1463 /* second parameter is not used */
1464 arg2 = -1;
1465 break;
1467 case ARC_END_ANGLE:
1468 /* get the end angle from w_current */
1469 arg1 = w_current->loc_y;
1470 /* second parameter is not used */
1471 arg2 = -1;
1472 break;
1474 default:
1475 return;
1478 /* modify the arc with the parameters determined above */
1479 o_arc_modify(w_current, o_current, arg1, arg2, whichone);
1481 /* display the new arc */
1482 o_redraw_single(w_current, o_current);
1486 /*! \todo Finish function documentation!!!
1487 * \brief End process of modifying box object with grip.
1488 * \par Function Description
1490 * \param [in] w_current The TOPLEVEL object.
1491 * \param [in] o_current Box OBJECT to end modification on.
1492 * \param [in] whichone Which grip is pointed to.
1494 void o_grips_end_box(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1496 int box_width, box_height;
1497 int x, y;
1499 box_width = GET_BOX_WIDTH (w_current);
1500 box_height = GET_BOX_HEIGHT(w_current);
1502 /* don't allow zero width/height boxes
1503 * this ends the box drawing behavior
1504 * we want this? hack */
1505 if ((box_width == 0) && (box_height == 0)) {
1506 w_current->start_x = (-1);
1507 w_current->start_y = (-1);
1508 w_current->last_x = (-1);
1509 w_current->last_y = (-1);
1511 w_current->inside_action=0;
1512 i_set_state(w_current, SELECT);
1514 o_redraw_single(w_current, o_current);
1515 i_update_toolbar(w_current);
1517 return;
1520 SCREENtoWORLD(w_current,
1521 w_current->last_x, w_current->last_y,
1522 &x, &y);
1523 x = snap_grid(w_current, x);
1524 y = snap_grid(w_current, y);
1526 o_box_modify(w_current, o_current, x, y, whichone);
1528 /* erase the temporary box */
1529 o_box_rubberbox_xor(w_current);
1531 /* draw the modified box */
1532 o_redraw_single(w_current, o_current);
1535 /*! \todo Finish function documentation!!!
1536 * \brief End process of modifying picture object with grip.
1537 * \par Function Description
1539 * \param [in] w_current The TOPLEVEL object.
1540 * \param [in] o_current Picture OBJECT to end modification on.
1541 * \param [in] whichone Which grip is pointed to.
1543 void o_grips_end_picture(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1545 int picture_width, picture_height;
1546 int x, y;
1548 picture_width = GET_PICTURE_WIDTH (w_current);
1549 picture_height = GET_PICTURE_HEIGHT(w_current);
1551 /* don't allow zero width/height picturees
1552 * this ends the picture drawing behavior
1553 * we want this? hack */
1554 if ((picture_width == 0) && (picture_height == 0)) {
1555 w_current->start_x = (-1);
1556 w_current->start_y = (-1);
1557 w_current->last_x = (-1);
1558 w_current->last_y = (-1);
1560 w_current->inside_action=0;
1561 i_set_state(w_current, SELECT);
1563 o_redraw_single(w_current, o_current);
1564 i_update_toolbar(w_current);
1566 return;
1569 SCREENtoWORLD(w_current,
1570 w_current->last_x, w_current->last_y,
1571 &x, &y);
1572 x = snap_grid(w_current, x);
1573 y = snap_grid(w_current, y);
1575 o_picture_modify(w_current, o_current, x, y, whichone);
1577 /* erase the temporary picture */
1578 o_picture_rubberbox_xor(w_current);
1580 /* draw the modified picture */
1581 o_redraw_single(w_current, o_current);
1583 w_current->current_pixbuf = NULL;
1584 w_current->pixbuf_filename = NULL;
1585 w_current->pixbuf_wh_ratio = 0;
1588 /*! \brief End process of modifying circle object with grip.
1589 * \par Function Description
1590 * This function ends the process of modifying the radius of the circle
1591 * object <B>*o_current</B>.
1592 * The modified circle is finally normally drawn.
1594 * A circle with a null radius is not allowed. In this case, the process
1595 * is stopped and the circle is left unchanged.
1597 * The last value of the radius is in <B>w_current->distance</B> in screen units.
1599 * \param [in] w_current The TOPLEVEL object.
1600 * \param [in] o_current Circle OBJECT to end modification on.
1601 * \param [in] whichone Which grip is pointed to.
1603 void o_grips_end_circle(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1605 int radius;
1607 /* erase the temporary circle */
1608 o_circle_rubbercircle_xor(w_current);
1610 /* don't allow zero radius circles
1611 * this ends the circle drawing behavior
1612 * we want this? hack */
1613 if ((w_current->start_x == w_current->last_x) &&
1614 (w_current->start_y == w_current->last_y)) {
1615 w_current->start_x = (-1);
1616 w_current->start_y = (-1);
1617 w_current->last_x = (-1);
1618 w_current->last_y = (-1);
1620 /* return to select mode */
1621 w_current->inside_action = 0;
1622 i_set_state(w_current, SELECT);
1623 i_update_toolbar(w_current);
1625 o_redraw_single(w_current, o_current);
1626 return;
1629 /* convert the radius in world unit */
1630 radius = WORLDabs(w_current, w_current->distance);
1632 /* modify the radius of the circle */
1633 o_circle_modify(w_current, o_current, radius, -1, CIRCLE_RADIUS);
1635 /* display the new circle */
1636 o_redraw_single(w_current, o_current);
1639 /*! \brief End process of modifying line object with grip.
1640 * \par Function Description
1641 * This function ends the process of modifying one end of the line
1642 * object <B>*o_current</B>.
1643 * This end is identified by <B>whichone</B>. The line object is modified
1644 * according to the <B>whichone</B> parameter and the last position of the
1645 * line end.
1646 * The modified line is finally normally drawn.
1648 * A line with a null width, i.e. when both ends are identical, is not
1649 * allowed. In this case, the process is stopped and the line unchanged.
1651 * \param [in] w_current The TOPLEVEL object.
1652 * \param [in] o_current Circle OBJECT to end modification on.
1653 * \param [in] whichone Which grip is pointed to.
1655 void o_grips_end_line(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
1657 int x, y;
1659 /* erase the temporary line */
1660 o_line_rubberline_xor(w_current);
1662 /* don't allow zero length nets / lines / pins
1663 * this ends the net drawing behavior
1664 * we want this? hack */
1665 if ((w_current->start_x == w_current->last_x) &&
1666 (w_current->start_y == w_current->last_y)) {
1667 w_current->start_x = (-1);
1668 w_current->start_y = (-1);
1669 w_current->last_x = (-1);
1670 w_current->last_y = (-1);
1672 /* return to select mode */
1673 w_current->inside_action=0;
1674 i_set_state(w_current, SELECT);
1675 i_update_toolbar(w_current);
1677 o_redraw_single(w_current, o_current);
1678 return;
1681 /* convert the line end coords in world unit */
1682 SCREENtoWORLD(w_current,
1683 w_current->last_x, w_current->last_y,
1684 &x, &y);
1685 x = snap_grid(w_current, x);
1686 y = snap_grid(w_current, y);
1688 /* modify the right line end according to whichone */
1689 o_line_modify(w_current, o_current, x, y, whichone);
1691 /* display the new line */
1692 o_redraw_single(w_current, o_current);
1695 /*! \brief Get half the width and height of grip in screen units.
1696 * \par Function Description
1697 * According to the current zoom level, the function returns half the width
1698 * and height of a grip in screen units.
1700 * <B>GRIP_SIZE1</B> and <B>GRIP_SIZE2</B> and <B>GRIP_SIZE3</B> are macros defined
1701 * in libgeda #defines.h. They are the half width/height of a grip in
1702 * world unit for a determined range of zoom factors.
1704 * \param [in] w_current The TOPLEVEL object.
1705 * \return Half grip size in screen units.
1707 int o_grips_size(TOPLEVEL *w_current)
1709 int factor, size;
1711 factor = (int) w_current->page_current->to_world_x_constant;
1712 if (factor > SMALL_ZOOMFACTOR1) {
1713 /* big zoom factor : small size converted to screen unit */
1714 size = SCREENabs(w_current, GRIP_SIZE1);
1715 } else if (factor > SMALL_ZOOMFACTOR2) {
1716 /* medium zoom factor : medium size converted to screen unit */
1717 size = SCREENabs(w_current, GRIP_SIZE2);
1718 } else {
1719 /* small zoom factor : big size converted to screen unit */
1720 size = SCREENabs(w_current, GRIP_SIZE3);
1723 return size;
1726 /*! \brief Draw grip centered at <B>x</B>, <B>y</B>
1727 * \par Function Description
1728 * This function draws a grip centered at (<B>x</B>,<B>y</B>). Its color is
1729 * either the selection color or the overriding color from
1730 * <B>w_current->override_color</B>.
1732 * The size of the grip depends on the current zoom factor.
1734 * <B>x</B> and <B>y</B> are in screen unit.
1736 * \param [in] w_current The TOPLEVEL object.
1737 * \param [in] x Center x screen coordinate for drawing grip.
1738 * \param [in] y Center y screen coordinate for drawing grip.
1740 void o_grips_draw(TOPLEVEL *w_current, int x, int y)
1742 GdkColor *color;
1743 int size, x2size;
1746 * Depending on the current zoom level, the size of the grip is
1747 * determined. <B>size</B> is half the width and height of the grip
1748 * and <B>x2size</B> is the full width and height of the grip.
1750 /* size is half the width of grip */
1751 size = o_grips_size(w_current);
1752 /* x2size is full width */
1753 x2size = 2 * size;
1756 * The grip can be displayed or erased : if <B>w_current->override_color</B>
1757 * is not set the grip is drawn with the selection color ; if
1758 * <B>w_current->override_color</B> is set then the color it refers it
1759 * is used. This way the grip can be erased if this color is the
1760 * background color.
1762 if (w_current->override_color != -1 ) {
1763 /* override : use the override_color instead */
1764 color = x_get_color(w_current->override_color);
1765 } else {
1766 /* use the normal selection color */
1767 color = x_get_color(w_current->select_color);
1769 /* set the color for the grip */
1770 gdk_gc_set_foreground(w_current->gc, color);
1772 /* set the line options for grip : solid, 1 pix wide */
1773 gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
1774 GDK_CAP_BUTT, GDK_JOIN_MITER);
1777 * A grip is a hollow square centered at (<B>x</B>,<B>y</B>) with a
1778 * width/height of <B>x2size</B>.
1780 if (w_current->DONT_REDRAW == 0) {
1781 /* draw the grip in window */
1782 gdk_draw_rectangle(w_current->window, w_current->gc, FALSE,
1783 x - size, y - size, x2size, x2size);
1784 /* draw the grip in backingstore */
1785 gdk_draw_rectangle(w_current->backingstore, w_current->gc, FALSE,
1786 x - size, y - size, x2size, x2size);
1790 /*! \brief Erase grip centered at <B>x</B>,<B>y</B>
1791 * \par Function Description
1792 * This function erases a grip centered at (<B>x</B>,<B>y</B>).
1793 * The size of the grip depends on the current zoom factor.
1795 * The grip is erased by drawing with the background color over the
1796 * visible grip.
1798 * \param [in] w_current The TOPLEVEL object.
1799 * \param [in] x Center x screen coordinate for drawing grip.
1800 * \param [in] y Center y screen coordinate for drawing grip.
1802 void o_grips_erase(TOPLEVEL *w_current, int x, int y)
1804 /* set overriding color */
1805 w_current->override_color = w_current->background_color;
1806 /* draw a grip with backgound color : erase grip */
1807 o_grips_draw(w_current, x, y);
1808 /* return to default */
1809 w_current->override_color = -1;