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