1 /* arc.c */
2 /* COPYRIGHT (C) 2000 THE VICTORIA UNIVERSITY OF MANCHESTER and John Levon
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License as published by the Free
5 * Software Foundation; either version 2 of the License, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307, USA.
16 */
17 /* contains functions assoc. with drawing of labelled lines */
18 /*
19 * $Log: arc.c,v $
20 * Revision 1.2 2000/12/06 20:56:01 moz
21 * GPL stuff.
22 *
23 * Revision 1.1.1.1 2000/08/21 01:05:30 moz
24 *
25 *
26 * Revision 1.1.1.1 2000/07/19 22:45:29 moz
27 * CVS Import
28 *
29 * Revision 1.7 2000/03/10 00:29:17 moz
30 * Use new_text() not text_button() for starting label.
31 *
32 * Revision 1.6 2000/03/09 23:32:10 moz
33 * Joinstyle should always be JoinRound.
34 *
35 * Revision 1.5 2000/02/18 02:45:14 moz
36 * Compile fixes.
37 *
38 * Revision 1.4 2000/01/29 20:59:47 moz
39 * Fixes to get_nearest_point call.
40 *
41 * Revision 1.3 1999/11/15 00:45:13 moz
42 * Name change.
43 *
44 * Revision 1.2 1999/05/19 17:05:56 moz
45 * 1.0 Checkin.
46 *
47 * Revision 1.1 1999/03/30 00:03:48 moz
48 * Initial revision
49 *
50 */
51
52 /* see mouse_button.c for general behaviour */
53
54 #include <math.h>
55 #include "include/figurine.h"
56 #include "include/extern.h"
57
58
59 static Boolean held = FALSE; /* mouse button down */
60 static Boolean intext = FALSE; /* when we've drawn the line */
61 static long orig_x=0; /* started from here */
62 static long orig_y=0;
63 static Boolean orig_derried = FALSE; /* derrying of start/end */
64 static Boolean end_derried = FALSE;
65 static Object *rob=NULL; /* for derrying */
66 static Object *endrob=NULL;
67
68 void
unselect_arc(View * view)69 unselect_arc(View *view)
70 {
71 intext = FALSE;
72 set_window_cursor(view->draw_window->win,XC_crosshair);
73 }
74
75 /* this takes document coordinates */
76 void
commit_arc(View * view,long x,long y)77 commit_arc(View *view, long x, long y)
78 {
79 Object *ob;
80 SPoint *p1,*p2,*p3;
81 short mx,my;
82
83 ob = (Object *)malloc(sizeof(Object));
84 p1 = (SPoint *)malloc(sizeof(SPoint));
85 p2 = (SPoint *)malloc(sizeof(SPoint));
86 p3 = (SPoint *)malloc(sizeof(SPoint));
87 p1->x = orig_x;
88 p1->y = orig_y;
89 p1->derried = orig_derried;
90 p1->s = 0.0;
91 p3->x = x;
92 p3->y = y;
93 p3->derried = end_derried;
94 p3->s = 0.0;
95 /* calc midpoint */
96 bent_midpoint(p1->x,p1->y,p3->x,p3->y,0.261799388,&mx,&my);
97 p2->x = mx;
98 p2->y = my;
99 p2->derried = FALSE;
100 p2->s = -1.0; /* interpolated */
101 ob->type = ARC;
102 ob->ob.spline.closed = FALSE;
103 ob->bbox.x1 = orig_x;
104 ob->bbox.y1 = orig_y;
105 ob->bbox.x2 = orig_x;
106 ob->bbox.y2 = orig_y;
107 p1->x -= ob->bbox.x1;
108 p1->y -= ob->bbox.y1;
109 p2->x -= ob->bbox.x1;
110 p2->y -= ob->bbox.y1;
111 p3->x -= ob->bbox.x1;
112 p3->y -= ob->bbox.y1;
113 ob->ls = view->linestyle;
114 ob->lw = view->linewidth;
115 ob->es = view->endstyle;
116 ob->js = JoinRound;
117 if (view->barrow_on)
118 ob->barrow = make_arrow(view->barrow);
119 else
120 ob->barrow = NULL;
121 if (view->farrow_on)
122 ob->farrow = make_arrow(view->farrow);
123 else
124 ob->farrow = NULL;
125 ob->colour = view->colour;
126 if (view->fillon)
127 ob->fs = view->fillstyle;
128 else
129 ob->fs = NONE;
130 ob->fillcolour = view->fillcolour;
131 ob->ticket = ob_ticket++;
132 ob->derries = NULL;
133 ob->depth = view->doc->ob_depth--;
134 ob->ob.spline.points = create_list(0,0,(void *)p1);
135 ob->ob.spline.points = add_to_list(ob->ob.spline.points,1,0,(void *)p2);
136 ob->ob.spline.points = add_to_list(ob->ob.spline.points,2,0,(void *)p3);
137 ob->ob.spline.cache = compute_spline_segment(ob->ob.spline.points, FALSE);
138 recalc_polyline_bbox(ob,TRUE);
139 view->doc->o = add_object(view->doc->o, &view->doc->lo, ob);
140 register_undo(UNDO_PASTE,ob,view->doc);
141 /* add derries if set */
142 if (orig_derried)
143 add_derry(rob,ob,(VPoint *)p1);
144 orig_derried = FALSE;
145 if (end_derried)
146 add_derry(endrob,ob,(VPoint *)p3);
147 end_derried = FALSE;
148 send_redraw_object(view,ob);
149 }
150
151 Boolean
arc_key(View * view,XKeyPressedEvent * report)152 arc_key(View *view, XKeyPressedEvent *report)
153 {
154 if (intext)
155 {
156 text_key(view,report);
157 return TRUE;
158 }
159 else
160 return FALSE; /* not interested if not typing */
161 }
162
163 void
arc_button(BEvent * bev,View * view)164 arc_button(BEvent *bev, View *view)
165 {
166 BEvent b;
167 short bx,by;
168 long x,y;
169 long ax,ay;
170
171 if (bev->button==Button2)
172 return;
173
174 if (bev->button==Button3 && state.busy_drawing)
175 {
176 if (!intext)
177 {
178 /* cancel the current line */
179 if (!held)
180 XUngrabPointer(display,CurrentTime);
181
182 toggle_arc(view, bev->x, bev->y);
183
184 state.busy_drawing = FALSE;
185 held = FALSE;
186 }
187 else
188 {
189 /* pass event over to text.c */
190 text_button(bev,view);
191 intext = FALSE;
192 };
193 }
194 else if (bev->button==Button1)
195 {
196 if (intext)
197 {
198 /* pass event over to text.c */
199 text_button(bev,view);
200 }
201 else
202 {
203 if (!P_IN_DOC(bev->x, bev->y, view) && state.busy_drawing)
204 {
205 /* ok, cancel the particular line we're drawing */
206 state.busy_drawing = FALSE;
207
208 if (!held)
209 XUngrabPointer(display,CurrentTime);
210 else
211 held = FALSE;
212
213 toggle_arc(view, bev->x, bev->y);
214 }
215 else
216 {
217 switch (bev->type)
218 {
219 case BUTTON_HELD:
220 if (!state.busy_drawing)
221 {
222 /* start drawing */
223 state.busy_drawing = TRUE;
224 held = TRUE;
225 if (state.shift_down &&
226 get_nearest_point(view,view->doc->o, XP2D(bev->x,view),YP2D(bev->y,view),&x,&y,&rob))
227 {
228 if (view->guide_lines && view->guide_lines_displayed)
229 {
230 toggle_guidelines(view);
231 view->guide_lines_displayed = FALSE;
232 };
233
234 orig_x = x;
235 orig_y = y;
236 orig_derried = TRUE;
237 bev->x = XD2P(x,view);
238 bev->y = YD2P(y,view);
239 mouse_x = bev->x;
240 mouse_y = bev->y;
241 XWarpPointer(display, None, view->draw_window->win, 0, 0, 1, 1,
242 bev->x,bev->y);
243 }
244 else
245 {
246 orig_derried = FALSE;
247 if (view->gridon)
248 {
249 orig_x = GXP2D(bev->x,view);
250 orig_y = GYP2D(bev->y,view);
251 }
252 else
253 {
254 orig_x = XP2D(bev->x,view);
255 orig_y = YP2D(bev->y,view);
256 };
257 };
258
259 toggle_arc(view, bev->x, bev->y);
260 /* start drawing the line */
261 };
262 break;
263
264 case BUTTON_CLICKED:
265 if (held)
266 {
267 XGrabPointer(display, view->draw_window->win, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask
268 | ButtonMotionMask | Button1MotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
269 }
270 else
271 {
272 ax = XP2D(bev->x,view);
273 ay = YP2D(bev->y,view);
274 end_derried = FALSE;
275 /* finished the line, see if derried */
276 if (state.shift_down && get_nearest_point(view,view->doc->o, XP2D(bev->x,view),YP2D(bev->y,view),&ax,&ay,&endrob))
277 {
278 if (view->guide_lines && view->guide_lines_displayed)
279 {
280 toggle_guidelines(view);
281 view->guide_lines_displayed = FALSE;
282 };
283
284 bev->x = XD2P(ax,view);
285 bev->y = YD2P(ay,view);
286 mouse_x = bev->x;
287 mouse_y = bev->y;
288 end_derried = TRUE;
289 XWarpPointer(display, None, view->draw_window->win, 0, 0, 1, 1,
290 bev->x,bev->y);
291 };
292 toggle_arc(view, bev->x, bev->y);
293 commit_arc(view, ax,ay);
294 /* ok, we're done with the line now */
295 state.busy_drawing = FALSE;
296 intext=TRUE;
297 /* fake a button event to start text label */
298 b.type = BUTTON_RELEASED;
299 b.button = Button1;
300 if ((XD2P(orig_x,view)-x)*(YD2P(orig_y,view)-y)>0)
301 bent_midpoint(XD2P(orig_x,view),YD2P(orig_y,view),bev->x,bev->y,0.161799388,&bx,&by);
302 else
303 bent_midpoint(XD2P(orig_x,view),YD2P(orig_y,view),bev->x,bev->y,-0.161799388,&bx,&by);
304 b.x = bx-D2P(I2D(view->fontsize/72.0,view),view);
305 b.y = by-D2P(I2D(view->fontsize/72.0,view),view);
306 set_window_cursor(view->draw_window->win,XC_xterm);
307 new_text(&b, view);
308 };
309
310 if (!held)
311 XUngrabPointer(display,CurrentTime);
312 held = FALSE;
313 break;
314
315 case BUTTON_RELEASED:
316 ax = XP2D(bev->x,view);
317 ay = YP2D(bev->y,view);
318 end_derried = FALSE;
319 if (state.shift_down && get_nearest_point(view,view->doc->o, XP2D(bev->x,view),YP2D(bev->y,view),&ax,&ay,&endrob))
320 {
321 if (view->guide_lines && view->guide_lines_displayed)
322 {
323 toggle_guidelines(view);
324 view->guide_lines_displayed = FALSE;
325 };
326
327 bev->x = XD2P(ax,view);
328 bev->y = YD2P(ay,view);
329 end_derried = TRUE;
330 mouse_x = bev->x;
331 mouse_y = bev->y;
332 XWarpPointer(display, None, view->draw_window->win, 0, 0, 1, 1,
333 bev->x,bev->y);
334 };
335 toggle_arc(view, bev->x, bev->y);
336 commit_arc(view, ax,ay);
337 state.busy_drawing = FALSE;
338 held = FALSE;
339 intext=TRUE;
340 /* fake a button event to start text label */
341 b.type = BUTTON_RELEASED;
342 b.button = Button1;
343 if ((XD2P(orig_x,view)-x)*(YD2P(orig_y,view)-y)>0)
344 bent_midpoint(XD2P(orig_x,view),YD2P(orig_y,view),bev->x,bev->y,0.161799388,&bx,&by);
345 else
346 bent_midpoint(XD2P(orig_x,view),YD2P(orig_y,view),bev->x,bev->y,-0.161799388,&bx,&by);
347 b.x = bx-D2P(I2D(view->fontsize/72.0,view),view);
348 b.y = by-D2P(I2D(view->fontsize/72.0,view),view);
349 set_window_cursor(view->draw_window->win,XC_xterm);
350 new_text(&b, view);
351 break;
352 };
353 };
354 };
355 };
356 }
357
358 void
toggle_arc(View * view,int x,int y)359 toggle_arc(View *view, int x, int y)
360 {
361 VLine *pl;
362 VLine line;
363 Boolean clipped;
364
365 line.x1 = XD2P(orig_x,view);
366 line.y1 = YD2P(orig_y,view);
367
368 if (view->gridon)
369 {
370 line.x2 = XD2P(GXP2D(x,view),view);
371 line.y2 = YD2P(GYP2D(y,view),view);
372 }
373 else
374 {
375 line.x2 = x;
376 line.y2 = y;
377 };
378
379 pl = clip_line(0,0,(signed long)view->draw_window->w,(signed long)view->draw_window->h, &line, &clipped, 1);
380
381 if (pl!=NULL)
382 XDrawLine(display,view->draw_window->win, blackxorgc, pl->x1, pl->y1, pl->x2, pl->y2);
383 }
384