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