1 /* Lepton EDA Schematic Capture
2  * Copyright (C) 1998-2010 Ales Hvezda
3  * Copyright (C) 1998-2016 gEDA Contributors
4  * Copyright (C) 2017-2021 Lepton EDA Contributors
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 #include <config.h>
21 
22 #include <stdio.h>
23 #include <math.h>
24 
25 #include "gschem.h"
26 
27 #define GET_BOX_WIDTH(w)  abs((w)->second_wx - (w)->first_wx)
28 #define GET_BOX_HEIGHT(w) abs((w)->second_wy - (w)->first_wy)
29 
30 #define GET_PICTURE_WIDTH(w)                    \
31   abs((w)->second_wx - (w)->first_wx)
32 #define GET_PICTURE_HEIGHT(w)                                           \
33   (w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio
34 #define GET_PICTURE_LEFT(w)                     \
35   MIN((w)->first_wx, (w)->second_wx)
36 #define GET_PICTURE_TOP(w)                                              \
37   (w)->first_wy > (w)->second_wy ? (w)->first_wy  :                     \
38   (w)->first_wy+abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio
39 
40 
41 /*! \brief Check if point is inside grip.
42  *  \par Function Description
43  *  This function is used to determine if the (<B>x</B>,<B>y</B>) point is
44  *  inside a grip of one of the selected object on the current sheet.
45  *  The <B>x</B> and <B>y</B> parameters are in world units.
46  *  If the point is inside one grip, a pointer on the object it belongs to is
47  *  returned and <B>*whichone</B> is set according to the position of the grip
48  *  on the object.
49  *  Else, <B>*whichone</B> is unchanged and the function returns <B>NULL</B>.
50  *
51  *  A specific search function is provided for every kind of graphical object.
52  *  The list of selected object is covered : each object is tested with the
53  *  appropriate function.
54  *
55  *  \param [in]  w_current  The GschemToplevel object.
56  *  \param [in]  x          Current x coordinate of pointer in world units.
57  *  \param [in]  y          Current y coordinate of pointer in world units.
58  *  \param [out] whichone   Which grip point is selected.
59  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
60  */
o_grips_search_world(GschemToplevel * w_current,int x,int y,int * whichone)61 LeptonObject *o_grips_search_world(GschemToplevel *w_current, int x, int y, int *whichone)
62 {
63   LeptonObject *object=NULL;
64   LeptonObject *found=NULL;
65   GList *s_current;
66   int size;
67   int w_size;
68 
69   GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
70   g_return_val_if_fail (page_view != NULL, NULL);
71 
72   LeptonPage *active_page = schematic_window_get_active_page (w_current);
73 
74   if (!whichone) {
75     return(NULL);
76   }
77 
78   /* get the size of the grip according to zoom level */
79   size = GRIP_SIZE / 2;
80   w_size = gschem_page_view_WORLDabs (page_view, size);
81 
82   s_current = lepton_list_get_glist (active_page->selection_list );
83   while (s_current != NULL) {
84     object = (LeptonObject *) s_current->data;
85     if (object) {
86       switch (lepton_object_get_type (object)) {
87         case(OBJ_ARC):
88           /* check the grips of the arc object */
89           found = o_grips_search_arc_world(w_current, object,
90                                            x, y, w_size, whichone);
91           if(found != NULL) return found;
92           break;
93 
94         case(OBJ_BOX):
95           /* check the grips of the box object */
96           found = o_grips_search_box_world(w_current, object,
97                                            x, y, w_size, whichone);
98           if(found != NULL) return found;
99           break;
100 
101         case(OBJ_PATH):
102           /* check the grips of the path object */
103           found = o_grips_search_path_world(w_current, object,
104                                             x, y, w_size, whichone);
105           if(found != NULL) return found;
106           break;
107 
108         case(OBJ_PICTURE):
109           /* check the grips of the picture object */
110           found = o_grips_search_picture_world(w_current, object,
111                                                x, y, w_size, whichone);
112           if(found != NULL) return found;
113           break;
114 
115         case(OBJ_CIRCLE):
116           /* check the grips of the circle object */
117           found = o_grips_search_circle_world(w_current, object,
118                                               x, y, w_size, whichone);
119           if(found != NULL) return found;
120           break;
121 
122         case(OBJ_LINE):
123         case(OBJ_PIN):
124         case(OBJ_NET):
125         case(OBJ_BUS):
126           /* check the grips of the line object */
127           /* the function is the same for line, pin, net, bus */
128           found = o_grips_search_line_world(w_current, object,
129                                             x, y, w_size, whichone);
130           if(found != NULL) return found;
131           break;
132 
133         default:
134           break;
135       }
136     }
137     s_current = g_list_next(s_current);
138   }
139 
140   return(NULL);
141 }
142 
143 
144 /*! \brief Check if pointer is inside the grip region.
145  *
146  *  \par Function Description
147  *  This function checks if the point (<B>x</B>,<B>y</B>) is
148  *  inside the grip centered at (<B>grip_x</B>,<B>grip_y</B>).
149  *
150  *  \param [in]  x          Current x coordinate of pointer in world units.
151  *  \param [in]  y          Current y coordinate of pointer in world units.
152  *  \param [in]  grip_x     Current x coordinate of grip center in world units.
153  *  \param [in]  grip_y     Current y coordinate of grip center in world units.
154  *  \param [in]  size       Half the width of the grip square in world units.
155  *  \return True / False whether the mouse pointer is inside the grip.
156  */
inside_grip(int x,int y,int grip_x,int grip_y,int size)157 static gboolean inside_grip( int x, int y, int grip_x, int grip_y, int size )
158 {
159   int xmin, ymin, xmax, ymax;
160 
161   xmin = grip_x - size;
162   ymin = grip_y - size;
163   xmax = xmin + 2 * size;
164   ymax = ymin + 2 * size;
165 
166   return inside_region(xmin, ymin, xmax, ymax, x, y);
167 }
168 
169 /*! \brief Check if pointer is inside arc grip.
170  *  \par Function Description
171  *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
172  *  inside one of the grips of an <B>o_current</B> pointed arc object. If so
173  *  the <B>whichone</B> pointed integer is set to the number of this grip and
174  *  the return pointer is a pointer on this object. If the point is not
175  *  inside a grip the function returns a NULL pointer and the <B>whichone</B>
176  *  pointed integer is unset.
177  *
178  *  An arc object has three grips :
179  *  <DL>
180  *    <DT>*</DT><DD>one at the center of the arc. This grip is used to modify
181  *                  the radius of the arc. If this one is selected, the
182  *                  <B>whichone</B> pointed integer is set to <B>ARC_RADIUS</B>.
183  *    <DT>*</DT><DD>one at one end of the arc. It corresponds to the starting
184  *                  angle of the arc. If this one is selected, the
185  *                  <B>whichone</B> pointed integer is set to <B>ARC_START_ANGLE</B>.
186  *    <DT>*</DT><DD>one at the other end of the arc. It corresponds to the
187  *                  ending angle of the arc. If this one is selected, the
188  *                  <B>whichone</B> pointed integer is set to <B>ARC_SWEEP_ANGLE</B>.
189  *  </DL>
190  *
191  *  The <B>x</B> and <B>y</B> parameters are in world units.
192  *
193  *  The <B>size</B> parameter is the width (and height) of the square
194  *  representing a grip in world units.
195  *
196  *  \param [in]  w_current  The GschemToplevel object.
197  *  \param [in]  o_current  Arc LeptonObject to check.
198  *  \param [in]  x          Current x coordinate of pointer in world units.
199  *  \param [in]  y          Current y coordinate of pointer in world units.
200  *  \param [in]  size       Half the width of the grip square in world units.
201  *  \param [out] whichone   Which grip point is selected.
202  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
203  */
o_grips_search_arc_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)204 LeptonObject *o_grips_search_arc_world(GschemToplevel *w_current, LeptonObject *o_current,
205                                  int x, int y, int size, int *whichone)
206 {
207   int centerx, centery, radius, start_angle, sweep_angle;
208   double tmp;
209 
210   centerx     = lepton_arc_object_get_center_x (o_current);
211   centery     = lepton_arc_object_get_center_y (o_current);
212   radius      = lepton_arc_object_get_radius (o_current);
213   start_angle = lepton_arc_object_get_start_angle (o_current);
214   sweep_angle = lepton_arc_object_get_sweep_angle (o_current);
215 
216   /* check the grip on the center of the arc */
217   if (inside_grip(x, y, centerx, centery, size)) {
218     *whichone = ARC_RADIUS;
219     return(o_current);
220   }
221 
222   /* check the grip at the end angle of the arc */
223   tmp = ((double) start_angle + sweep_angle) * M_PI / 180;
224   if (inside_grip(x, y,
225                   centerx + radius * cos(tmp),
226                   centery + radius * sin(tmp), size)) {
227     *whichone = ARC_SWEEP_ANGLE;
228     return(o_current);
229   }
230 
231   /* check the grip at the start angle of the arc */
232   tmp = ((double) start_angle) * M_PI / 180;
233   if (inside_grip(x, y,
234                   centerx + radius * cos(tmp),
235                   centery + radius * sin(tmp), size)) {
236     *whichone = ARC_START_ANGLE;
237     return(o_current);
238   }
239 
240   return NULL;
241 }
242 
243 /*! \brief Check if pointer is inside box grip.
244  *  \par Function Description
245  *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
246  *  inside one of the grips of the <B>o_current</B> pointed box object.
247  *  If so, the <B>whichone</B> pointed integer is set to the identifier of
248  *  this grip and the returned pointer is a pointer on this object.
249  *  If the point is not inside a grip the function returns a NULL pointer
250  *  and the <B>whichone</B> pointed integer is unset.
251  *
252  *  A box object has four grips : one at each corner of the box. The
253  *  identifiers of each corner are <B>BOX_UPPER_LEFT</B>,
254  *  <B>BOX_UPPER_RIGHT</B>, <B>BOX_LOWER_LEFT</B> and <B>BOX_LOWER_RIGHT</B>.
255  *
256  *  The <B>x</B> and <B>y</B> parameters are in world units.
257  *
258  *  The <B>size</B> parameter is half the width (and half the height) of
259  *  the square representing a grip in world units.
260  *
261  *  \param [in]  w_current  The GschemToplevel object.
262  *  \param [in]  o_current  Box LeptonObject to check.
263  *  \param [in]  x          Current x coordinate of pointer in world units.
264  *  \param [in]  y          Current y coordinate of pointer in world units.
265  *  \param [in]  size       Half the width of the grip square in world units.
266  *  \param [out] whichone   Which grip point is selected.
267  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
268  */
o_grips_search_box_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)269 LeptonObject *o_grips_search_box_world(GschemToplevel *w_current, LeptonObject *o_current,
270                                  int x, int y, int size, int *whichone)
271 {
272   int upper_x, upper_y, lower_x, lower_y;
273 
274   upper_x = lepton_box_object_get_upper_x (o_current);
275   upper_y = lepton_box_object_get_upper_y (o_current);
276   lower_x = lepton_box_object_get_lower_x (o_current);
277   lower_y = lepton_box_object_get_lower_y (o_current);
278 
279   /* inside upper left grip ? */
280   if (inside_grip (x, y, upper_x, upper_y, size))
281   {
282     *whichone = BOX_UPPER_LEFT;
283     return(o_current);
284   }
285 
286   /* inside lower right grip ? */
287   if (inside_grip (x, y, lower_x, lower_y, size))
288   {
289     *whichone = BOX_LOWER_RIGHT;
290     return(o_current);
291   }
292 
293   /* inside upper right grip ? */
294   if (inside_grip (x, y, lower_x, upper_y, size))
295   {
296     *whichone = BOX_UPPER_RIGHT;
297     return(o_current);
298   }
299 
300   /* inside lower left grip ? */
301   if (inside_grip (x, y, upper_x, lower_y, size))
302   {
303     *whichone = BOX_LOWER_LEFT;
304     return(o_current);
305   }
306 
307   return NULL;
308 }
309 
310 /*! \brief Check if pointer is inside path grip.
311  *  \par Function Description
312  *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>)
313  *  is inside one of the grips of the <B>o_current</B> pointed path object.
314  *  If so, the <B>whichone</B> pointed integer is set to the identifier of
315  *  this grip and the returned pointer is a pointer on this object.
316  *  If the point is not inside a grip the function returns a NULL pointer
317  *  and the <B>whichone</B> pointed integer is unset.
318  *
319  *  A path object has four grips : one at each corner of the path.
320  *  The identifiers of each corner are #PICTURE_UPPER_LEFT,
321  *  #PICTURE_UPPER_RIGHT, #PICTURE_LOWER_LEFT and
322  *  #PICTURE_LOWER_RIGHT.
323  *
324  *  The <B>x</B> and <B>y</B> parameters are in world units.
325  *
326  *  The <B>size</B> parameter is half the width (and half the height) of the
327  *  square representing a grip in world units.
328  *
329  *  \param [in]  w_current  The GschemToplevel object.
330  *  \param [in]  o_current  Picture LeptonObject to check.
331  *  \param [in]  x          Current x coordinate of pointer in world units.
332  *  \param [in]  y          Current y coordinate of pointer in world units.
333  *  \param [in]  size       Half the width of the grip square in world units.
334  *  \param [out] whichone   Which grip point is selected.
335  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
336  */
o_grips_search_path_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)337 LeptonObject *o_grips_search_path_world(GschemToplevel *w_current, LeptonObject *o_current,
338                                      int x, int y, int size, int *whichone)
339 {
340   LeptonPathSection *section;
341   int i;
342   int grip_no = 0;
343 
344   for (i = 0; i < lepton_path_object_get_num_sections (o_current); i++)
345   {
346     section = lepton_path_object_get_section (o_current, i);
347 
348     switch (section->code) {
349     case PATH_CURVETO:
350       /* inside first control grip ? */
351       if (inside_grip(x, y, section->x1, section->y1, size)) {
352         *whichone = grip_no;
353         return o_current;
354       }
355       grip_no ++;
356       /* inside second control grip ? */
357       if (inside_grip(x, y, section->x2, section->y2, size)) {
358         *whichone = grip_no;
359         return o_current;
360       }
361       grip_no ++;
362       /* Fall through */
363     case PATH_MOVETO:
364     case PATH_MOVETO_OPEN:
365     case PATH_LINETO:
366       /* inside destination control grip ? */
367       if (inside_grip(x, y, section->x3, section->y3, size)) {
368         *whichone = grip_no;
369         return o_current;
370       }
371       grip_no ++;
372       break;
373     case PATH_END:
374       break;
375     }
376   }
377 
378   return NULL;
379 }
380 
381 /*! \brief Check if pointer is inside picture grip.
382  *  \par Function Description
383  *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>)
384  *  is inside one of the grips of the <B>o_current</B> pointed picture object.
385  *  If so, the <B>whichone</B> pointed integer is set to the identifier of
386  *  this grip and the returned pointer is a pointer on this object.
387  *  If the point is not inside a grip the function returns a NULL pointer
388  *  and the <B>whichone</B> pointed integer is unset.
389  *
390  *  A picture object has four grips : one at each corner of the picture.
391  *  The identifiers of each corner are #PICTURE_UPPER_LEFT,
392  *  #PICTURE_UPPER_RIGHT, #PICTURE_LOWER_LEFT and
393  *  #PICTURE_LOWER_RIGHT.
394  *
395  *  The <B>x</B> and <B>y</B> parameters are in world units.
396  *
397  *  The <B>size</B> parameter is half the width (and half the height) of the
398  *  square representing a grip in world units.
399  *
400  *  \param [in]  w_current  The GschemToplevel object.
401  *  \param [in]  o_current  Picture LeptonObject to check.
402  *  \param [in]  x          Current x coordinate of pointer in world units.
403  *  \param [in]  y          Current y coordinate of pointer in world units.
404  *  \param [in]  size       Half the width of the grip square in world units.
405  *  \param [out] whichone   Which grip point is selected.
406  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
407  */
o_grips_search_picture_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)408 LeptonObject *o_grips_search_picture_world(GschemToplevel *w_current, LeptonObject *o_current,
409                                      int x, int y, int size, int *whichone)
410 {
411   int lower_x, lower_y, upper_x, upper_y;
412 
413   lower_x = lepton_picture_object_get_lower_x (o_current);
414   lower_y = lepton_picture_object_get_lower_y (o_current);
415   upper_x = lepton_picture_object_get_upper_x (o_current);
416   upper_y = lepton_picture_object_get_upper_y (o_current);
417 
418   /* inside upper left grip ? */
419   if (inside_grip (x, y, upper_x, upper_y, size))
420   {
421     *whichone = PICTURE_UPPER_LEFT;
422     return(o_current);
423   }
424 
425   /* inside lower right grip ? */
426   if (inside_grip (x, y, lower_x, lower_y, size))
427   {
428     *whichone = PICTURE_LOWER_RIGHT;
429     return(o_current);
430   }
431 
432   /* inside upper right grip ? */
433   if (inside_grip (x, y, lower_x, upper_y, size))
434   {
435     *whichone = PICTURE_UPPER_RIGHT;
436     return(o_current);
437   }
438 
439   /* inside lower left grip ? */
440   if (inside_grip (x, y, upper_x, lower_y, size))
441   {
442     *whichone = PICTURE_LOWER_LEFT;
443     return(o_current);
444   }
445 
446   return NULL;
447 }
448 
449 /*! \brief Check if pointer is inside circle grip.
450  *  \par Function Description
451  *  This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
452  *  the grip of the circle object <B>o_current</B>.
453  *  It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
454  *  is in one of these areas.
455  *  If the event occured in one of the grip, a pointer on the object is
456  *  returned and <B>*whichone</B> is set to the identifier of the grip.
457  *  If not, the function returns a <B>NULL</B> pointer and <B>*whichone</B>
458  *  is unchanged.
459  *
460  *  The parameter <B>size</B> is half the size of the grip in world units.
461  *
462  *  A circle has only one grip on the lower right corner of the box it
463  *  is inscribed in. Moving this grip change the radius of the circle.
464  *  The identifier of this grip is <B>CIRCLE_RADIUS</B>.
465  *
466  *  \param [in]  w_current  The GschemToplevel object.
467  *  \param [in]  o_current  Circle LeptonObject to check.
468  *  \param [in]  x          Current x coordinate of pointer in world units.
469  *  \param [in]  y          Current y coordinate of pointer in world units.
470  *  \param [in]  size       Half the width of the grip square in world units.
471  *  \param [out] whichone   Which grip point is selected.
472  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
473  */
o_grips_search_circle_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)474 LeptonObject *o_grips_search_circle_world(GschemToplevel *w_current, LeptonObject *o_current,
475                                     int x, int y, int size, int *whichone)
476 {
477   gint center_x = lepton_circle_object_get_center_x (o_current);
478   gint center_y = lepton_circle_object_get_center_y (o_current);
479   gint radius = lepton_circle_object_get_radius (o_current);
480 
481   /* check the grip for radius */
482   if (inside_grip(x, y,
483                   center_x + radius,
484                   center_y - radius,
485                   size)) {
486     *whichone = CIRCLE_RADIUS;
487     return(o_current);
488   }
489 
490   return NULL;
491 }
492 
493 /*! \brief Check if pointer is inside line grip.
494  *  \par Function Description
495  *  This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
496  *  the grip of the line object <B>o_current</B>.
497  *  It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
498  *  is in one of these areas.
499  *  If the event occured in one of its grip, a pointer on the object is
500  *  returned and <B>*whichone</B> is set to the identifier of the grip. If not,
501  *  the function returns <B>NULL</B> pointer and <B>*whichone</B> is unchanged.
502  *
503  *  The parameter <B>size</B> is half the size of the grip in world units.
504  *
505  *  \param [in]  w_current  The GschemToplevel object.
506  *  \param [in]  o_current  Line LeptonObject to check.
507  *  \param [in]  x          Current x coordinate of pointer in world units.
508  *  \param [in]  y          Current y coordinate of pointer in world units.
509  *  \param [in]  size       Half the width of the grip square in world units.
510  *  \param [out] whichone   Which grip point is selected.
511  *  \return Pointer to LeptonObject the grip is on, NULL otherwise.
512  */
o_grips_search_line_world(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int size,int * whichone)513 LeptonObject *o_grips_search_line_world(GschemToplevel *w_current, LeptonObject *o_current,
514                                   int x, int y, int size, int *whichone)
515 {
516   /* check the grip on the end of line 1 */
517   if (inside_grip(x, y,
518                   o_current->line->x[LINE_END1],
519                   o_current->line->y[LINE_END1], size)) {
520     *whichone = LINE_END1;
521     return(o_current);
522   }
523 
524   /* check the grip on the end of line 2 */
525   if (inside_grip(x, y,
526                   o_current->line->x[LINE_END2],
527                   o_current->line->y[LINE_END2], size)) {
528     *whichone = LINE_END2;
529     return(o_current);
530   }
531 
532   return NULL;
533 }
534 
535 /*! \brief Initialize grip motion process for an arc.
536  *  \par Function Description
537  *  This function initializes the grip motion process for an arc.
538  *  From the <B>o_current</B> pointed object, it stores into the
539  *  GschemToplevel structure the coordinates of the center, the radius
540  *  and the two angle that describes an arc. These variables are used in
541  *  the grip process.
542  *
543  *  The coordinates of the center of the arc on x- and y-axis are stored
544  *  into the <B>first_wx</B> and <B>first_wy</B> fields of the GschemToplevel
545  *  structure in screen units.
546  *
547  *  The radius of the center is stored into the <B>distance</B> field of
548  *  the GschemToplevel structure in screen units.
549  *
550  *  The two angles describing the arc on a circle are stored into the
551  *  <B>second_wx</B> for the starting angle and <B>second_wy</B> for the ending angle.
552  *  These angles are expressed in degrees.
553  *
554  *  \param [in]  w_current  The GschemToplevel object.
555  *  \param [in]  o_current  Arc LeptonObject to check.
556  *  \param [in]  x          (unused)
557  *  \param [in]  y          (unused)
558  *  \param [out] whichone   (unused)
559  */
o_grips_start_arc(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)560 static void o_grips_start_arc(GschemToplevel *w_current, LeptonObject *o_current,
561                               int x, int y, int whichone)
562 {
563   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
564 
565   /* describe the arc with GschemToplevel variables */
566   /* center */
567   w_current->first_wx = lepton_arc_object_get_center_x (o_current);
568   w_current->first_wy = lepton_arc_object_get_center_y (o_current);
569   /* radius */
570   w_current->distance = lepton_arc_object_get_radius (o_current);
571   /* angles */
572   w_current->second_wx = lepton_arc_object_get_start_angle (o_current);
573   w_current->second_wy = lepton_arc_object_get_sweep_angle (o_current);
574 
575   /* draw the first temporary arc */
576   /* o_arc_invalidate_rubber (w_current); */
577   w_current->rubber_visible = 1;
578 }
579 
580 /*! \brief Initialize grip motion process for a box.
581  *  \par Function Description
582  *  This function initializes the grip motion process for a box. From the
583  *  <B>o_current</B> pointed object, it stores into the GschemToplevel
584  *  structure the .... These variables are used in the grip process.
585  *
586  *  The function first erases the grips.
587  *
588  *  The coordinates of the selected corner are put in
589  *  (<B>w_current->second_wx</B>,<B>w_current->second_wx</B>).
590  *
591  *  The coordinates of the opposite corner go in
592  *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>). They are not suppose
593  *  to change during the action.
594  *
595  *  \param [in]  w_current  The GschemToplevel object.
596  *  \param [in]  o_current  Box LeptonObject to check.
597  *  \param [in]  x          (unused)
598  *  \param [in]  y          (unused)
599  *  \param [out] whichone   Which coordinate to check.
600  */
o_grips_start_box(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)601 static void o_grips_start_box(GschemToplevel *w_current, LeptonObject *o_current,
602                               int x, int y, int whichone)
603 {
604   int upper_x, upper_y, lower_x, lower_y;
605 
606   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
607 
608   upper_x = lepton_box_object_get_upper_x (o_current);
609   upper_y = lepton_box_object_get_upper_y (o_current);
610   lower_x = lepton_box_object_get_lower_x (o_current);
611   lower_y = lepton_box_object_get_lower_y (o_current);
612 
613   /* (second_wx, second_wy) is the selected corner */
614   /* (first_wx, first_wy) is the opposite corner */
615   switch(whichone) {
616     case BOX_UPPER_LEFT:
617       w_current->second_wx = upper_x;
618       w_current->second_wy = upper_y;
619       w_current->first_wx  = lower_x;
620       w_current->first_wy  = lower_y;
621       break;
622     case BOX_LOWER_RIGHT:
623       w_current->second_wx = lower_x;
624       w_current->second_wy = lower_y;
625       w_current->first_wx  = upper_x;
626       w_current->first_wy  = upper_y;
627       break;
628     case BOX_UPPER_RIGHT:
629       w_current->second_wx = lower_x;
630       w_current->second_wy = upper_y;
631       w_current->first_wx  = upper_x;
632       w_current->first_wy  = lower_y;
633       break;
634     case BOX_LOWER_LEFT:
635       w_current->second_wx = upper_x;
636       w_current->second_wy = lower_y;
637       w_current->first_wx  = lower_x;
638       w_current->first_wy  = upper_y;
639       break;
640     default:
641       return; /* error */
642   }
643 
644   /* draw the first temporary box */
645   /* o_box_invalidate_rubber (w_current); */
646   w_current->rubber_visible = 1;
647 }
648 
649 /*! \brief Initialize grip motion process for a path.
650  *  \par Function Description
651  *  This function initializes the grip motion process for a path.
652  *  From the <B>o_current</B> pointed object, it stores into the
653  *  GschemToplevel structure the ....
654  *  These variables are used in the grip process.
655  *
656  *  The function first erases the grips.
657  *
658  *  The coordinates of the selected corner are put in
659  *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
660  *
661  *  The coordinates of the opposite corner go in
662  *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>). They are not
663  *  suppose to change during the action.
664  *
665  *  \param [in]  w_current  The GschemToplevel object.
666  *  \param [in]  o_current  Picture LeptonObject to check.
667  *  \param [in]  x          (unused)
668  *  \param [in]  y          (unused)
669  *  \param [out] whichone   Which coordinate to check.
670  */
o_grips_start_path(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)671 static void o_grips_start_path(GschemToplevel *w_current, LeptonObject *o_current,
672                                int x, int y, int whichone)
673 {
674   LeptonPathSection *section;
675   int i;
676   int grip_no = 0;
677   int gx = -1;
678   int gy = -1;
679 
680   w_current->last_drawb_mode = -1;
681 
682   for (i = 0; i < lepton_path_object_get_num_sections (o_current); i++)
683   {
684     section = lepton_path_object_get_section (o_current, i);
685 
686     switch (section->code) {
687     case PATH_CURVETO:
688       /* Two control point grips */
689       if (whichone == grip_no++) {
690         gx = section->x1;
691         gy = section->y1;
692       }
693       if (whichone == grip_no++) {
694         gx = section->x2;
695         gy = section->y2;
696       }
697       /* Fall through */
698     case PATH_MOVETO:
699     case PATH_MOVETO_OPEN:
700     case PATH_LINETO:
701       /* Destination point grip */
702       if (whichone == grip_no++) {
703         gx = section->x3;
704         gy = section->y3;
705       }
706       break;
707     case PATH_END:
708       break;
709     }
710   }
711 
712   w_current->first_wx = w_current->second_wx = gx;
713   w_current->first_wy = w_current->second_wy = gy;
714 
715   /* draw the first temporary path */
716   /* o_path_invalidate_rubber_grips (w_current); */
717   w_current->rubber_visible = 1;
718 }
719 
720 /*! \brief Initialize grip motion process for a picture.
721  *  \par Function Description
722  *  This function initializes the grip motion process for a picture.
723  *  From the <B>o_current</B> pointed object, it stores into the
724  *  GschemToplevel structure the ....
725  *  These variables are used in the grip process.
726  *
727  *  The function first erases the grips.
728  *
729  *  The coordinates of the selected corner are put in
730  *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
731  *
732  *  The coordinates of the opposite corner go in
733  *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>). They are not
734  *  suppose to change during the action.
735  *
736  *  \param [in]  w_current  The GschemToplevel object.
737  *  \param [in]  o_current  Picture LeptonObject to check.
738  *  \param [in]  x          (unused)
739  *  \param [in]  y          (unused)
740  *  \param [out] whichone   Which coordinate to check.
741  */
o_grips_start_picture(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)742 static void o_grips_start_picture(GschemToplevel *w_current, LeptonObject *o_current,
743                                   int x, int y, int whichone)
744 {
745   int lower_x, lower_y, upper_x, upper_y;
746 
747   lower_x = lepton_picture_object_get_lower_x (o_current);
748   lower_y = lepton_picture_object_get_lower_y (o_current);
749   upper_x = lepton_picture_object_get_upper_x (o_current);
750   upper_y = lepton_picture_object_get_upper_y (o_current);
751 
752   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
753 
754   w_current->current_pixbuf = lepton_picture_object_get_pixbuf (o_current);
755   w_current->pixbuf_filename =
756     g_strdup (lepton_picture_object_get_filename (o_current));
757   w_current->pixbuf_wh_ratio = lepton_picture_object_get_real_ratio (o_current);
758 
759   /* (second_wx,second_wy) is the selected corner */
760   /* (first_wx, first_wy) is the opposite corner */
761   switch(whichone) {
762     case PICTURE_UPPER_LEFT:
763       w_current->second_wx = upper_x;
764       w_current->second_wy = upper_y;
765       w_current->first_wx  = lower_x;
766       w_current->first_wy  = lower_y;
767       break;
768     case PICTURE_LOWER_RIGHT:
769       w_current->second_wx = lower_x;
770       w_current->second_wy = lower_y;
771       w_current->first_wx  = upper_x;
772       w_current->first_wy  = upper_y;
773       break;
774     case PICTURE_UPPER_RIGHT:
775       w_current->second_wx = lower_x;
776       w_current->second_wy = upper_y;
777       w_current->first_wx  = upper_x;
778       w_current->first_wy  = lower_y;
779       break;
780     case PICTURE_LOWER_LEFT:
781       w_current->second_wx = upper_x;
782       w_current->second_wy = lower_y;
783       w_current->first_wx  = lower_x;
784       w_current->first_wy  = upper_y;
785       break;
786     default:
787       return; /* error */
788   }
789 
790   /* draw the first temporary picture */
791   /* o_picture_invalidate_rubber (w_current); */
792   w_current->rubber_visible = 1;
793 }
794 
795 /*! \brief Initialize grip motion process for a circle.
796  *  \par Function Description
797  *  This function initializes the grip motion process for a circle.
798  *  From the <B>o_current</B> pointed object, it stores into the
799  *  GschemToplevel structure the coordinate of the center and the radius.
800  *  These variables are used in the grip process.
801  *
802  *  The function first erases the grips.
803  *
804  *  The coordinates of the center are put in
805  *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>). They are not suppose
806  *  to change during the action.
807  *
808  *  The radius of the circle is stored in <B>w_current->distance</B>.
809  *
810  *  \param [in]  w_current  The GschemToplevel object.
811  *  \param [in]  o_current  Circle LeptonObject to check.
812  *  \param [in]  x          (unused)
813  *  \param [in]  y          (unused)
814  *  \param [out] whichone   Which coordinate to check.
815  */
o_grips_start_circle(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)816 static void o_grips_start_circle(GschemToplevel *w_current, LeptonObject *o_current,
817                                  int x, int y, int whichone)
818 {
819 
820   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
821 
822   /* store circle center and radius in GschemToplevel structure */
823   w_current->first_wx = lepton_circle_object_get_center_x (o_current);
824   w_current->first_wy = lepton_circle_object_get_center_y (o_current);
825   w_current->distance = lepton_circle_object_get_radius (o_current);
826 
827   /* draw the first temporary circle */
828   /* o_circle_invalidate_rubber (w_current); */
829   w_current->rubber_visible = 1;
830 }
831 
832 /*! \brief Initialize grip motion process for a line.
833  *  This function starts the move of one of the two grips of the line
834  *  object <B>o_current</B>.
835  *
836  *  During the move of the grip, the line is described by
837  *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) and
838  *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
839  *
840  *  The line end that corresponds to the moving grip is in
841  *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
842  *
843  *  \param [in]  w_current  The GschemToplevel object.
844  *  \param [in]  o_current  Line LeptonObject to check.
845  *  \param [in]  x          (unused)
846  *  \param [in]  y          (unused)
847  *  \param [out] whichone   Which coordinate to check.
848  */
o_grips_start_line(GschemToplevel * w_current,LeptonObject * o_current,int x,int y,int whichone)849 static void o_grips_start_line(GschemToplevel *w_current, LeptonObject *o_current,
850                                int x, int y, int whichone)
851 {
852   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
853 
854   /* describe the line with GschemToplevel variables */
855   w_current->second_wx = o_current->line->x[whichone];
856   w_current->second_wy = o_current->line->y[whichone];
857   w_current->first_wx = o_current->line->x[!whichone];
858   w_current->first_wy = o_current->line->y[!whichone];
859 
860   /* draw the first temporary line */
861   /* o_line_invalidate_rubber (w_current); */
862   w_current->rubber_visible = 1;
863 }
864 
865 /*! \brief Start process of modifiying one grip.
866  *  \par Function Description
867  *  This function starts the process of modifying one grip of an object
868  *  on the current sheet. The event occured in (<B>w_x</B>,<B>w_y</B>) in world unit.
869  *  If this position is related to a grip of an object, the function
870  *  prepares the modification of this grip thanks to the user input.
871  *
872  *  The function does nothing if an error occured or if no grip
873  *  have been found under (<B>w_x</B>,<B>w_y</B>). Otherwise, it
874  *  switches the GRIPS mode on if a grip has been found and
875  *  modification of the object has been started.
876  *
877  *  If a grip has been found, this function modifies the GschemToplevel
878  *  variables <B>which_grip</B> and <B>which_object</B> with the identifier
879  *  of the grip and the object it belongs to respectively.
880  *
881  *  If the \a draw-grips rc setting is "disabled", no grids are
882  *  displayed though the object is modified the same way.
883  *
884  *  \param [in]  w_current  The GschemToplevel object.
885  *  \param [in]  w_x        Current x coordinate of pointer in world units.
886  *  \param [in]  w_y        Current y coordinate of pointer in world units.
887  */
o_grips_start(GschemToplevel * w_current,int w_x,int w_y)888 void o_grips_start(GschemToplevel *w_current, int w_x, int w_y)
889 {
890   LeptonObject *object;
891   int whichone;
892   void (*func) (GschemToplevel*, LeptonObject*, int, int, int) = NULL;
893 
894   /* search if there is a grip on a selected object at (w_x,w_y) */
895   object = o_grips_search_world(w_current, w_x, w_y, &whichone);
896 
897   if (object != NULL) {
898     w_current->which_grip = whichone;
899     w_current->which_object = object;
900 
901     /* Switch off drawing for the object being modified */
902     object->dont_redraw = TRUE;
903     o_invalidate (w_current, object);
904 
905     /* there is one */
906     /* depending on its type, start the modification process */
907     switch (lepton_object_get_type (object)) {
908     case OBJ_ARC:     func = o_grips_start_arc;     break;
909     case OBJ_BOX:     func = o_grips_start_box;     break;
910     case OBJ_PATH:    func = o_grips_start_path;    break;
911     case OBJ_PICTURE: func = o_grips_start_picture; break;
912     case OBJ_CIRCLE:  func = o_grips_start_circle;  break;
913     case OBJ_LINE:
914     case OBJ_NET:
915     case OBJ_PIN:
916     case OBJ_BUS:     func = o_grips_start_line;    break;
917 
918     default: break;
919     }
920 
921     /* start the modification of a grip on the object */
922     if (func != NULL) {
923       (*func) (w_current, object, w_x, w_y, whichone);
924       i_set_state (w_current, GRIPS);
925       i_action_start (w_current);
926     }
927   }
928 }
929 
930 /*! \brief Modify previously selected object according to mouse position.
931  *  \par Function Description
932  *  This function modify the previously selected
933  *  object according to the mouse position in <B>w_x</B> and <B>w_y</B>.
934  *  The grip under modification is updated and the temporary object displayed.
935  *
936  *  The object under modification is <B>w_current->which_object</B> and
937  *  the grip concerned is <B>w_current->which_grip</B>.
938  *
939  *  Depending on the object type, a specific function is used.
940  *  It erases the temporary object, updates its internal representation,
941  *  and draws it again.
942  *
943  *  \param [in] w_current  The GschemToplevel object.
944  *  \param [in] w_x        Current x coordinate of pointer in world units.
945  *  \param [in] w_y        Current y coordinate of pointer in world units.
946  */
o_grips_motion(GschemToplevel * w_current,int w_x,int w_y)947 void o_grips_motion(GschemToplevel *w_current, int w_x, int w_y)
948 {
949   int grip = w_current->which_grip;
950 
951   g_assert( w_current->inside_action != 0 );
952   g_return_if_fail( w_current->which_object != NULL );
953 
954   switch (lepton_object_get_type (w_current->which_object)) {
955     case OBJ_ARC:
956       o_arc_motion (w_current, w_x, w_y, grip);
957       break;
958 
959     case OBJ_BOX:
960       o_box_motion (w_current, w_x, w_y);
961       break;
962 
963     case OBJ_PATH:
964       o_path_motion_grips (w_current, w_x, w_y);
965       break;
966 
967     case OBJ_PICTURE:
968       o_picture_motion (w_current, w_x, w_y);
969       break;
970 
971     case OBJ_CIRCLE:
972       o_circle_motion (w_current, w_x, w_y);
973       break;
974 
975     case OBJ_LINE:
976     case OBJ_NET:
977     case OBJ_PIN:
978     case OBJ_BUS:
979       o_line_motion (w_current, w_x, w_y);
980       break;
981 
982     default:
983     return; /* error condition */
984   }
985 }
986 
987 
988 /*! \brief Cancel process of modifying object with grip.
989  *
990  *  \par Function Description
991  *  This function cancels the process of modifying a parameter
992  *  of an object with a grip. It's main utility is to reset the
993  *  dont_redraw flag on the object which was being modified.
994  *
995  *  \param [in,out] w_current  The GschemToplevel object.
996  */
o_grips_cancel(GschemToplevel * w_current)997 void o_grips_cancel(GschemToplevel *w_current)
998 {
999   LeptonObject *object = w_current->which_object;
1000 
1001   /* reset global variables */
1002   w_current->which_grip = -1;
1003   w_current->which_object = NULL;
1004   w_current->rubber_visible = 0;
1005 
1006   /* Switch drawing of the object back on */
1007   g_return_if_fail (object != NULL);
1008   object->dont_redraw = FALSE;
1009 }
1010 
1011 
1012 /*! \brief End process of modifying arc object with grip.
1013  *  \par Function Description
1014  *  This function ends the grips process specific to an arc object. It erases
1015  *  the old arc and write back to the object the new parameters of the arc.
1016  *  Depending on the grip selected and moved, the right fields are updated.
1017  *  The function handles the conversion from screen unit to world unit before
1018  *  updating and redrawing.
1019  *
1020  *  If the grip at the center of the arc has been moved - modifying the radius
1021  *  of the arc -, the new radius is calculated expressed in world unit
1022  *  (the center is unchanged). It is updated with the function
1023  *  #lepton_arc_object_modify().
1024  *
1025  *  If one of the end of arc grip has been moved - modifying one of the
1026  *  angles describing the arc -, this angle is updated with the
1027  *  #lepton_arc_object_modify() function.
1028  *
1029  *  \param [in] w_current  The GschemToplevel object.
1030  *  \param [in] o_current  Arc LeptonObject to end modification on.
1031  *  \param [in] whichone   Which grip is pointed to.
1032  */
o_grips_end_arc(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1033 static void o_grips_end_arc(GschemToplevel *w_current, LeptonObject *o_current,
1034                             int whichone)
1035 {
1036   int arg1, arg2;
1037 
1038   /* erase the temporary arc */
1039   /* o_arc_invalidate_rubber (w_current); */
1040 
1041   /* determination of the parameters to give to o_arc_modify() */
1042   switch(whichone) {
1043     case ARC_RADIUS:
1044       /* get the radius from w_current */
1045       arg1 = w_current->distance;
1046       /* second parameter is not used */
1047       arg2 = -1;
1048       break;
1049 
1050     case ARC_START_ANGLE:
1051       /* get the start angle from w_current */
1052       arg1 = w_current->second_wx;
1053       /* second parameter is not used */
1054       arg2 = -1;
1055       break;
1056 
1057     case ARC_SWEEP_ANGLE:
1058       /* get the end angle from w_current */
1059       arg1 = w_current->second_wy;
1060       /* second parameter is not used */
1061       arg2 = -1;
1062       break;
1063 
1064     default:
1065       return;
1066   }
1067 
1068   /* modify the arc with the parameters determined above */
1069   lepton_arc_object_modify (o_current, arg1, arg2, whichone);
1070 }
1071 
1072 /*! \todo Finish function documentation!!!
1073  *  \brief End process of modifying box object with grip.
1074  *  \par Function Description
1075  *
1076  *  \param [in] w_current  The GschemToplevel object.
1077  *  \param [in] o_current  Box LeptonObject to end modification on.
1078  *  \param [in] whichone   Which grip is pointed to.
1079  */
o_grips_end_box(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1080 static void o_grips_end_box(GschemToplevel *w_current, LeptonObject *o_current,
1081                             int whichone)
1082 {
1083   int box_width, box_height;
1084 
1085   box_width  = GET_BOX_WIDTH (w_current);
1086   box_height = GET_BOX_HEIGHT(w_current);
1087 
1088   /* don't allow zero width/height boxes
1089    * this ends the box drawing behavior
1090    * we want this? hack */
1091   if ((box_width == 0) || (box_height == 0)) {
1092     o_box_invalidate_rubber (w_current);
1093     o_invalidate (w_current, o_current);
1094     return;
1095   }
1096 
1097   lepton_box_object_modify (o_current, w_current->second_wx, w_current->second_wy, whichone);
1098 }
1099 
1100 /*! \todo Finish function documentation!!!
1101  *  \brief End process of modifying path object with grip.
1102  *  \par Function Description
1103  *
1104  *  \param [in] w_current  The GschemToplevel object.
1105  *  \param [in] o_current  Picture LeptonObject to end modification on.
1106  *  \param [in] whichone   Which grip is pointed to.
1107  */
o_grips_end_path(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1108 static void o_grips_end_path(GschemToplevel *w_current, LeptonObject *o_current,
1109                              int whichone)
1110 {
1111   lepton_path_object_modify (o_current,
1112                              w_current->second_wx,
1113                              w_current->second_wy,
1114                              whichone);
1115 }
1116 
1117 /*! \todo Finish function documentation!!!
1118  *  \brief End process of modifying picture object with grip.
1119  *  \par Function Description
1120  *
1121  *  \param [in] w_current  The GschemToplevel object.
1122  *  \param [in] o_current  Picture LeptonObject to end modification on.
1123  *  \param [in] whichone   Which grip is pointed to.
1124  */
o_grips_end_picture(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1125 static void o_grips_end_picture(GschemToplevel *w_current, LeptonObject *o_current,
1126                                 int whichone)
1127 {
1128   /* don't allow zero width/height pictures
1129    * this ends the picture drawing behavior
1130    * we want this? hack */
1131   if ((GET_PICTURE_WIDTH(w_current) == 0) || (GET_PICTURE_HEIGHT(w_current) == 0)) {
1132     o_picture_invalidate_rubber (w_current);
1133     o_invalidate (w_current, o_current);
1134     return;
1135   }
1136 
1137   lepton_picture_object_modify (o_current,
1138                                 w_current->second_wx,
1139                                 w_current->second_wy,
1140                                 whichone);
1141 
1142   g_object_unref (w_current->current_pixbuf);
1143   w_current->current_pixbuf = NULL;
1144   g_free (w_current->pixbuf_filename);
1145   w_current->pixbuf_filename = NULL;
1146   w_current->pixbuf_wh_ratio = 0;
1147 }
1148 
1149 /*! \brief End process of modifying circle object with grip.
1150  *  \par Function Description
1151  *  This function ends the process of modifying the radius of the circle
1152  *  object <B>*o_current</B>.
1153  *  The modified circle is finally normally drawn.
1154  *
1155  *  A circle with a null radius is not allowed. In this case, the process
1156  *  is stopped and the circle is left unchanged.
1157  *
1158  *  The last value of the radius is in <B>w_current->distance</B> in screen units.
1159  *
1160  *  \param [in] w_current  The GschemToplevel object.
1161  *  \param [in] o_current  Circle LeptonObject to end modification on.
1162  *  \param [in] whichone   Which grip is pointed to.
1163  */
o_grips_end_circle(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1164 static void o_grips_end_circle(GschemToplevel *w_current, LeptonObject *o_current,
1165                                int whichone)
1166 {
1167   /* don't allow zero radius circles
1168    * this ends the circle drawing behavior
1169    * we want this? hack */
1170   if (w_current->distance == 0) {
1171     o_circle_invalidate_rubber (w_current);
1172     o_invalidate (w_current, o_current);
1173     return;
1174   }
1175 
1176   /* modify the radius of the circle */
1177   lepton_circle_object_modify (o_current, w_current->distance, -1, CIRCLE_RADIUS);
1178 }
1179 
1180 /*! \brief End process of modifying line object with grip.
1181  *  \par Function Description
1182  *  This function ends the process of modifying one end of the line
1183  *  object <B>*o_current</B>.
1184  *  This end is identified by <B>whichone</B>. The line object is modified
1185  *  according to the <B>whichone</B> parameter and the last position of the
1186  *  line end.
1187  *  The modified line is finally normally drawn.
1188  *
1189  *  A line with a null width, i.e. when both ends are identical, is not
1190  *  allowed. In this case, the process is stopped and the line unchanged.
1191  *
1192  *  \param [in] w_current  The GschemToplevel object.
1193  *  \param [in] o_current  Line LeptonObject to end modification on.
1194  *  \param [in] whichone   Which grip is pointed to.
1195  */
o_grips_end_line(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1196 static void o_grips_end_line(GschemToplevel *w_current, LeptonObject *o_current,
1197                              int whichone)
1198 {
1199   /* don't allow zero length nets / lines / pins
1200    * this ends the net drawing behavior
1201    * we want this? hack */
1202   if ((w_current->first_wx == w_current->second_wx) &&
1203       (w_current->first_wy == w_current->second_wy)) {
1204     o_box_invalidate_rubber (w_current);
1205     o_invalidate (w_current, o_current);
1206     return;
1207   }
1208 
1209   /* modify the right line end according to whichone */
1210   lepton_line_object_modify (o_current,
1211                              w_current->second_wx, w_current->second_wy, whichone);
1212 }
1213 
1214 
1215 /*! \brief End process of modifying net object with grip.
1216  *  \par Function Description
1217  *  This function ends the process of modifying one end of the net
1218  *  object <B>*o_current</B>.
1219  *  This end is identified by <B>whichone</B>. The line object is modified
1220  *  according to the <B>whichone</B> parameter and the last position of the
1221  *  line end.
1222  *  The connections to the modified net are checked and recreated if neccessary.
1223  *
1224  *  A net with zero length, i.e. when both ends are identical, is not
1225  *  allowed. In this case, the process is stopped and the line unchanged.
1226  *
1227  *  \param [in] w_current  The GschemToplevel object.
1228  *  \param [in] o_current  Net LeptonObject to end modification on.
1229  *  \param [in] whichone   Which grip is pointed to.
1230  */
o_grips_end_net(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1231 static void o_grips_end_net(GschemToplevel *w_current, LeptonObject *o_current,
1232                             int whichone)
1233 {
1234   GList *connected_objects;
1235 
1236   /* don't allow zero length net
1237    * this ends the net drawing behavior
1238    * we want this? hack */
1239   if ((w_current->first_wx == w_current->second_wx) &&
1240       (w_current->first_wy == w_current->second_wy)) {
1241     o_invalidate (w_current, o_current);
1242     return;
1243   }
1244 
1245   s_conn_remove_object_connections (o_current);
1246   lepton_net_object_modify (o_current, w_current->second_wx,
1247                             w_current->second_wy, w_current->which_grip);
1248   s_conn_update_object (o_current->page, o_current);
1249 
1250   /* add bus rippers if necessary */
1251   connected_objects = s_conn_return_others (NULL, o_current);
1252   o_net_add_busrippers (w_current, o_current, connected_objects);
1253   g_list_free (connected_objects);
1254 }
1255 
1256 /*! \brief End process of modifying pin object with grip.
1257  *  \par Function Description
1258  *  This function ends the process of modifying one end of the pin
1259  *  object <B>*o_current</B>.
1260  *  This end is identified by <B>whichone</B>. The pin object is modified
1261  *  according to the <B>whichone</B> parameter and the last position of the
1262  *  pin end.
1263  *  The connections to the modified pin are checked and recreated if neccessary.
1264  *
1265  *  A pin with zero length, i.e. when both ends are identical, is not
1266  *  allowed. In this case, the process is stopped and the line unchanged.
1267  *
1268  *  \param [in] w_current  The GschemToplevel object.
1269  *  \param [in] o_current  Net LeptonObject to end modification on.
1270  *  \param [in] whichone   Which grip is pointed to.
1271  */
o_grips_end_pin(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1272 static void o_grips_end_pin(GschemToplevel *w_current, LeptonObject *o_current,
1273                             int whichone)
1274 {
1275   /* don't allow zero length pin
1276    * this ends the pin changing behavior
1277    * we want this? hack */
1278   if ((w_current->first_wx == w_current->second_wx) &&
1279       (w_current->first_wy == w_current->second_wy)) {
1280     o_invalidate (w_current, o_current);
1281     return;
1282   }
1283 
1284   s_conn_remove_object_connections (o_current);
1285   lepton_pin_object_modify (o_current,
1286                             w_current->second_wx,
1287                             w_current->second_wy,
1288                             w_current->which_grip);
1289   s_conn_update_object (o_current->page, o_current);
1290 }
1291 
1292 /*! \brief End process of modifying bus object with grip.
1293  *  \par Function Description
1294  *  This function ends the process of modifying one end of the bus
1295  *  object <B>*o_current</B>.
1296  *  This end is identified by <B>whichone</B>. The line object is modified
1297  *  according to the <B>whichone</B> parameter and the last position of the
1298  *  bus end.
1299  *  The connections to the modified bus are checked and recreated if neccessary.
1300  *
1301  *  A bus with zero length, i.e. when both ends are identical, is not
1302  *  allowed. In this case, the process is stopped and the bus unchanged.
1303  *
1304  *  \param [in] w_current  The GschemToplevel object.
1305  *  \param [in] o_current  bus LeptonObject to end modification on.
1306  *  \param [in] whichone   Which grip is pointed to.
1307  */
o_grips_end_bus(GschemToplevel * w_current,LeptonObject * o_current,int whichone)1308 static void o_grips_end_bus(GschemToplevel *w_current, LeptonObject *o_current,
1309                             int whichone)
1310 {
1311   /* don't allow zero length bus
1312    * this ends the bus changing behavior
1313    * we want this? hack */
1314   if ((w_current->first_wx == w_current->second_wx) &&
1315       (w_current->first_wy == w_current->second_wy)) {
1316     o_invalidate (w_current, o_current);
1317     return;
1318   }
1319 
1320   s_conn_remove_object_connections (o_current);
1321   lepton_bus_object_modify (o_current, w_current->second_wx,
1322                             w_current->second_wy, w_current->which_grip);
1323   s_conn_update_object (o_current->page, o_current);
1324 }
1325 
1326 
1327 /*! \brief End process of modifying object with grip.
1328  *  \par Function Description
1329  *  This function ends the process of modifying a parameter of an object
1330  *  with a grip.
1331  *  The temporary representation of the object is erased, the object is
1332  *  modified and finally drawn.
1333  *
1334  *  The object under modification is <B>w_current->which_object</B> and
1335  *  the grip concerned is <B>w_current->which_grip</B>.
1336  *
1337  *  Depending on the object type, a specific function is used. It erases
1338  *  the temporary object, updates the object and draws the modified object
1339  *  normally.
1340  *
1341  *  \param [in,out] w_current  The GschemToplevel object.
1342  */
o_grips_end(GschemToplevel * w_current)1343 void o_grips_end(GschemToplevel *w_current)
1344 {
1345   LeptonObject *object;
1346   int grip;
1347 
1348   g_assert (w_current->inside_action != 0);
1349 
1350   object = w_current->which_object;
1351   grip = w_current->which_grip;
1352 
1353   if (!object) {
1354     /* actually this is an error condition hack */
1355     i_action_stop (w_current);
1356     i_set_state(w_current, SELECT);
1357     return;
1358   }
1359 
1360   switch (lepton_object_get_type (object)) {
1361 
1362     case(OBJ_ARC):
1363     /* modify an arc object */
1364     o_grips_end_arc(w_current, object, grip);
1365     break;
1366 
1367     case(OBJ_BOX):
1368     /* modify a box object */
1369     o_grips_end_box(w_current, object, grip);
1370     break;
1371 
1372     case(OBJ_PATH):
1373     /* modify a path object */
1374     o_grips_end_path(w_current, object, grip);
1375     break;
1376 
1377     case(OBJ_PICTURE):
1378     /* modify a picture object */
1379     o_grips_end_picture(w_current, object, grip);
1380     break;
1381 
1382     case(OBJ_CIRCLE):
1383     /* modify a circle object */
1384     o_grips_end_circle(w_current, object, grip);
1385     break;
1386 
1387     case(OBJ_LINE):
1388     /* modify a line object */
1389     o_grips_end_line(w_current, object, grip);
1390     break;
1391 
1392     case(OBJ_NET):
1393       /* modify a net object */
1394       o_grips_end_net(w_current, object, grip);
1395       break;
1396 
1397     case(OBJ_PIN):
1398       /* modify a pin object */
1399       o_grips_end_pin(w_current, object, grip);
1400       break;
1401 
1402     case(OBJ_BUS):
1403       /* modify a bus object */
1404       o_grips_end_bus(w_current, object, grip);
1405       break;
1406 
1407     default:
1408     return;
1409   }
1410 
1411   /* Switch drawing of the object back on */
1412   object->dont_redraw = FALSE;
1413   o_invalidate (w_current, object);
1414 
1415   /* reset global variables */
1416   w_current->which_grip = -1;
1417   w_current->which_object = NULL;
1418 
1419   w_current->rubber_visible = 0;
1420 
1421   schematic_window_active_page_changed (w_current);
1422   o_undo_savestate_old(w_current, UNDO_ALL);
1423 
1424   i_set_state(w_current, SELECT);
1425   i_action_stop (w_current);
1426 }
1427 
1428 
1429 /*! \brief Draw objects being grip maniuplated from GschemToplevel object.
1430  *
1431  *  \par Function Description
1432  *  This function draws the objects being grip manipulated.
1433  *
1434  *  \param [in] w_current  The GschemToplevel object.
1435  */
o_grips_draw_rubber(GschemToplevel * w_current,EdaRenderer * renderer)1436 void o_grips_draw_rubber (GschemToplevel *w_current, EdaRenderer *renderer)
1437 {
1438   g_return_if_fail (w_current->which_object != NULL);
1439 
1440   switch (lepton_object_get_type (w_current->which_object)) {
1441     case OBJ_ARC:
1442       o_arc_draw_rubber (w_current, renderer);
1443       break;
1444 
1445     case OBJ_BOX:
1446       o_box_draw_rubber (w_current, renderer);
1447       break;
1448 
1449     case OBJ_PATH:
1450       o_path_draw_rubber_grips (w_current, renderer);
1451       break;
1452 
1453     case OBJ_PICTURE:
1454       o_picture_draw_rubber (w_current, renderer);
1455       break;
1456 
1457     case OBJ_CIRCLE:
1458       o_circle_draw_rubber (w_current, renderer);
1459       break;
1460 
1461     case OBJ_LINE:
1462     case OBJ_NET:
1463     case OBJ_PIN:
1464     case OBJ_BUS:
1465       o_line_draw_rubber (w_current, renderer);
1466     break;
1467 
1468     default:
1469       g_return_if_reached ();
1470   }
1471 }
1472