1 /* gEDA - GPL Electronic Design Automation
2  * gschem - gEDA Schematic Capture
3  * Copyright (C) 1998-2010 Ales Hvezda
4  * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details)
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 #ifdef HAVE_LIBDMALLOC
28 #include <dmalloc.h>
29 #endif
30 
31 /*! \brief Draw a line on screen.
32  *  \par Function Description
33  *  This function is used to draw a line on screen. The line is described
34  *  in the object which is referred by <B>o_current</B>. The line is displayed
35  *  according to the current state, described in the GSCHEM_TOPLEVEL object pointed
36  *  by <B>w_current</B>.
37  *
38  *  It first checks if the object is valid or not. If not it returns and do
39  *  not output anything. That should never happen though.
40  *
41  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
42  *  \param [in] o_current  The line OBJECT to draw.
43  */
o_line_draw(GSCHEM_TOPLEVEL * w_current,OBJECT * o_current)44 void o_line_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
45 {
46   int x1, y1, x2, y2;
47 
48   if (o_current->line == NULL) {
49     return;
50   }
51 
52   if (!o_line_visible (w_current, o_current->line, &x1, &y1, &x2, &y2)) {
53     return;
54   }
55 
56   gschem_cairo_line (w_current, o_current->line_end,
57                                 o_current->line_width,
58                                 x1, y1, x2, y2);
59 
60   gschem_cairo_set_source_color (w_current,
61                                  o_drawing_color (w_current, o_current));
62   gschem_cairo_stroke (w_current, o_current->line_type,
63                                   o_current->line_end,
64                                   o_current->line_width,
65                                   o_current->line_length,
66                                   o_current->line_space);
67 
68   if (o_current->selected && w_current->draw_grips) {
69     o_line_draw_grips (w_current, o_current);
70   }
71 }
72 
73 
74 /*! \todo Finish function documentation
75  *  \brief
76  *  \par Function Description
77  */
o_line_invalidate_rubber(GSCHEM_TOPLEVEL * w_current)78 void o_line_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
79 {
80   int x1, y1, x2, y2;
81 
82   WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1);
83   WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2);
84 
85   o_invalidate_rect (w_current, x1, y1, x2, y2);
86 }
87 
88 /*! \brief Draw a line object after applying translation.
89  *  \par Function Description
90  *  This function is used to draw the line object described by
91  *  <B>*o_current</B> after applying a translation on the two directions of
92  *  <B>dx</B> and <B>dy</B> in world units.
93  *
94  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
95  *  \param [in] dx         Delta x coordinate for line.
96  *  \param [in] dy         Delta y coordinate for line.
97  *  \param [in] o_current  Line OBJECT to draw.
98  */
o_line_draw_place(GSCHEM_TOPLEVEL * w_current,int dx,int dy,OBJECT * o_current)99 void o_line_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
100 {
101   if (o_current->line == NULL) {
102     return;
103   }
104 
105   gschem_cairo_line (w_current, END_NONE, 0,
106                      o_current->line->x[0] + dx, o_current->line->y[0] + dy,
107                      o_current->line->x[1] + dx, o_current->line->y[1] + dy);
108   gschem_cairo_set_source_color (w_current,
109                                  x_color_lookup_dark (o_current->color));
110   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
111 }
112 
113 /*! \brief Start process to input a new line.
114  *  \par Function Description
115  *  This function starts the process of interactively adding a line to
116  *  the current sheet.
117  *
118  *  During all the process, the line is internally represented by the two
119  *  ends of the line as (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) and
120  *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
121  *
122  *  A temporary line is drawn during the process with the selection color
123  *  and changed according to the position of the mouse pointer.
124  *
125  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
126  *  \param [in] w_x        Current x coordinate of pointer in world units.
127  *  \param [in] w_y        Current y coordinate of pointer in world units.
128  */
o_line_start(GSCHEM_TOPLEVEL * w_current,int w_x,int w_y)129 void o_line_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
130 {
131   /* init first_w[x|y], second_w[x|y] to describe line */
132   w_current->first_wx = w_current->second_wx = w_x;
133   w_current->first_wy = w_current->second_wy = w_y;
134 
135   o_line_invalidate_rubber (w_current);
136   w_current->rubber_visible = 1;
137 }
138 
139 /*! \brief End the input of a line.
140  *  \par Function Description
141  *  This function ends the process of interactively adding a line to the
142  *  current sheet.
143  *
144  *  It first erases the last temporary line displayed, calculates the
145  *  corresponding world coordinates of the two ends of the line and finally
146  *  adds a new initialized line object to the list of object of the current
147  *  sheet.
148  *
149  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
150  *  \param [in] w_x        (unused)
151  *  \param [in] w_y        (unused)
152  */
o_line_end(GSCHEM_TOPLEVEL * w_current,int w_x,int w_y)153 void o_line_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
154 {
155   TOPLEVEL *toplevel = w_current->toplevel;
156   OBJECT *new_obj;
157 
158   g_assert( w_current->inside_action != 0 );
159 
160   /* Don't bother.. the real object is invalidated, its in the same place */
161   /* o_line_invalidate_rubber (w_current); */
162   w_current->rubber_visible = 0;
163 
164   /* don't allow zero length lines */
165   if ( (w_current->first_wx == w_current->second_wx) &&
166        (w_current->first_wy == w_current->second_wy) ) {
167     return;
168   }
169 
170   /* create the line object and draw it */
171   new_obj = o_line_new (toplevel, OBJ_LINE, GRAPHIC_COLOR,
172                         w_current->first_wx, w_current->first_wy,
173                         w_current->second_wx, w_current->second_wy);
174   s_page_append (toplevel, toplevel->page_current, new_obj);
175 
176   /* Call add-objects-hook */
177   g_run_hook_object (w_current, "%add-objects-hook", new_obj);
178 
179   toplevel->page_current->CHANGED=1;
180   o_undo_savestate(w_current, UNDO_ALL);
181 }
182 
183 /*! \brief Draw temporary line while dragging end.
184  *  \par Function Description
185  *  This function manages the erase/update/draw process of temporary line
186  *  when modifying one end of the line.
187  *  The line is described by four <B>*w_current</B> variables : the first end
188  *  of the line is (<B>first_wx</B>,<B>first_wy</B>), the second end is
189  *  (<B>second_wx</B>,<B>second_wy</B>).
190  *  The first end is constant. The second end is updated to the (<B>w_x</B>,<B>w_y</B>).
191  *
192  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
193  *  \param [in] w_x        Current x coordinate of pointer in world units.
194  *  \param [in] w_y        Current y coordinate of pointer in world units.
195  */
o_line_motion(GSCHEM_TOPLEVEL * w_current,int w_x,int w_y)196 void o_line_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
197 {
198   int diff_x, diff_y;
199 
200   g_assert( w_current->inside_action != 0 );
201 
202   if (w_current->rubber_visible)
203     o_line_invalidate_rubber (w_current);
204 
205   /*
206    * The coordinates of the moving end of the line are updated. Its new
207    * coordinates are in <B>w_x</B> and <B>w_y</B> parameters and saved to
208    * <B>w_current->second_wx</B> and <B>w_current->second_wy</B> respectively.
209    */
210   w_current->second_wx = w_x;
211   w_current->second_wy = w_y;
212 
213   /* if the control key was pressed then draw ortho lines */
214   if (w_current->CONTROLKEY) {
215     diff_x = abs(w_current->second_wx - w_current->first_wx);
216     diff_y = abs(w_current->second_wy - w_current->first_wy);
217 
218     if (diff_x >= diff_y) {
219       w_current->second_wy = w_current->first_wy;
220     } else {
221       w_current->second_wx = w_current->first_wx;
222     }
223   }
224 
225   o_line_invalidate_rubber (w_current);
226   w_current->rubber_visible = 1;
227 }
228 
229 /*! \brief Draw line from GSCHEM_TOPLEVEL object.
230  *  \par Function Description
231  *  This function draws a line with an exclusive or function over the sheet.
232  *  The color of the box is <B>SELECT_COLOR</B>. The line is
233  *  described by the two points (<B>w_current->first_wx</B>,
234  *  <B>w_current->first_wy</B>) and (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>).
235  *
236  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
237  */
o_line_draw_rubber(GSCHEM_TOPLEVEL * w_current)238 void o_line_draw_rubber (GSCHEM_TOPLEVEL *w_current)
239 {
240   gschem_cairo_line (w_current, END_NONE, 0,
241                      w_current->first_wx, w_current->first_wy,
242                      w_current->second_wx, w_current->second_wy);
243 
244   gschem_cairo_set_source_color (w_current,
245                                  x_color_lookup_dark (SELECT_COLOR));
246   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
247 }
248 
249 /*! \brief Draw grip marks on line.
250  *  \par Function Description
251  *  This function draws the grips on the line object <B>o_current</B>.
252  *
253  *  A line has a grip at each end.
254  *
255  *  \param [in] w_current  The GSCHEM_TOPLEVEL object.
256  *  \param [in] o_current  Line OBJECT to draw grip points on.
257  */
o_line_draw_grips(GSCHEM_TOPLEVEL * w_current,OBJECT * o_current)258 void o_line_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
259 {
260   if (w_current->draw_grips == FALSE)
261     return;
262 
263   /* draw the grip on line end 1 */
264   o_grips_draw(w_current, o_current->line->x[0], o_current->line->y[0]);
265 
266   /* draw the grip on line end 2 */
267   o_grips_draw(w_current, o_current->line->x[1], o_current->line->y[1]);
268 }
269 
270 
271 /*! \brief
272  *  \par Function Description
273  *
274  *  \param [in] w_current  The TOPLEVEL object.
275  *  \param [in] line
276  *  \param [in] x1
277  *  \param [in] y1
278  *  \param [in] x2
279  *  \param [in] y2
280  *  \return int
281  */
o_line_visible(GSCHEM_TOPLEVEL * w_current,LINE * line,int * x1,int * y1,int * x2,int * y2)282 int o_line_visible (GSCHEM_TOPLEVEL *w_current, LINE *line,
283                     int *x1, int *y1, int *x2, int *y2)
284 {
285   *x1 = line->x[0];  *y1 = line->y[0];
286   *x2 = line->x[1];  *y2 = line->y[1];
287 
288   /* Do we want to skip clipping? */
289   if (!w_current->toplevel->object_clipping)
290     return TRUE;
291 
292   return WORLDclip_change (w_current, x1, y1, x2, y2);
293 }
294