1 /* ellipse.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 ellipse and circle composition */
18 /*
19  * $Log: ellipse.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:30  moz
27  * CVS Import
28  *
29  * Revision 1.5  2000/03/08 00:43:42  moz
30  * Compile fixes.
31  *
32  * Revision 1.4  1999/11/15 02:11:10  moz
33  * Name change.
34  *
35  * Revision 1.3  1999/05/19 17:10:54  moz
36  * 1.0 Checkin.
37  *
38  * Revision 1.2  1999/04/29 00:13:11  moz
39  * In draw_ellipse, make sure it is this object we are scaling (test gc==blackxorgc).
40  *
41  * Revision 1.1  1999/03/30 00:04:48  moz
42  * Initial revision
43  *
44  */
45 
46 /* see mouse_button.c for general behaviour */
47 
48 #include "include/figurine.h"
49 #include "include/extern.h"
50 
51 static long x1=0; /* for boxellipse  */
52 static long y1=0;
53 static long cx=0;
54 static long cy=0;
55 static long xr=0;
56 static long yr=0;
57 
58 static Boolean held=FALSE;
59 
60 void
commit_ellipse(View * view,long x,long y)61 commit_ellipse(View *view, long x, long y)
62 {
63 	Object *ob;
64 
65 	if (state.current_icon==BOXELLIPSEICON)
66 		{
67 		if (view->gridon)
68 			{
69 			cx = (GXP2D(x,view) - x1)/2 + x1;
70 			cy = (GYP2D(y,view) - y1)/2 + y1;
71 			xr = abs(GXP2D(x,view) - x1)/2;
72 			yr = abs(GYP2D(y,view) - y1)/2;
73 			}
74 		else
75 			{
76 			cx = (XP2D(x,view) - x1)/2 + x1;
77 			cy = (YP2D(y,view) - y1)/2 + y1;
78 			xr = abs(XP2D(x,view) - x1)/2;
79 			yr = abs(YP2D(y,view) - y1)/2;
80 			};
81 		}
82 	else
83 		{
84 		if (view->gridon)
85 			{
86 			xr = abs(GXP2D(x, view) - cx);
87 			yr = abs(GYP2D(y, view) - cy);
88 			}
89 		else
90 			{
91 			xr = abs(XP2D(x, view) - cx);
92 			yr = abs(YP2D(y, view) - cy);
93 			};
94 		};
95 
96 	/* constrain */
97  	if (state.control_down)
98  		constrain_ellipse(&xr,&yr);
99 
100 	ob = (Object *)malloc(sizeof(Object));
101 	if (ob==NULL)
102 		return;
103 
104 	ob->type = ELLIPSE;
105 	ob->ticket = ob_ticket++;
106 	ob->derries = NULL;
107 	ob->depth = view->doc->ob_depth--;
108 	ob->ls = view->linestyle;
109 	ob->lw = view->linewidth;
110 	ob->colour = view->colour;
111 	ob->fillcolour = view->fillcolour;
112 	if (view->fillon)
113 		ob->fs = view->fillstyle;
114 	else
115 		ob->fs = NONE;
116 
117 	ob->dash = 5;
118 	ob->gap = 4;
119 	ob->bbox.x1 = cx - xr;
120 	ob->bbox.y1 = cy - yr;
121 	ob->bbox.x2 = cx + xr;
122 	ob->bbox.y2 = cy + yr;
123 	ob->ob.ellipse.centre.x = cx - ob->bbox.x1;
124 	ob->ob.ellipse.centre.y = cy - ob->bbox.y1;
125 	ob->ob.ellipse.xradius = xr;
126 	ob->ob.ellipse.yradius = yr;
127 	ob->farrow = NULL;
128 	ob->barrow = NULL;
129 
130  	normalise_rectangle(&ob->bbox.x1, &ob->bbox.y1, &ob->bbox.x2, &ob->bbox.y2);
131 	ob->bbox.x2 = cx + xr +1;
132 	ob->bbox.y2 = cy + yr +1;
133 
134 	view->doc->o = add_object(view->doc->o, &view->doc->lo, ob);
135 
136 	register_undo(UNDO_PASTE,ob,view->doc);
137 	send_redraw_object(view,ob);
138 }
139 
140 void
ellipse_button(BEvent * bev,View * view)141 ellipse_button(BEvent *bev, View *view)
142 {
143 
144 	if (((held && bev->button==Button2) || bev->button==Button3) && state.busy_drawing )
145 		{
146 		/* cancel the current ellipse */
147 		if (!held)
148 			XUngrabPointer(display,CurrentTime);
149 
150 		toggle_ellipse(view, bev->x, bev->y);
151 
152 		state.busy_drawing = FALSE;
153 		held = FALSE;
154 		}
155 	else if (bev->button==Button1)
156 		{
157 		if (!P_IN_DOC(bev->x, bev->y, view) && state.busy_drawing)
158 			{
159 			/* ok, cancel the ellipse  we're drawing  */
160 			state.busy_drawing = FALSE;
161 
162 			if (!held)
163 				XUngrabPointer(display,CurrentTime);
164 			else
165 				held = FALSE;
166 
167 			toggle_ellipse(view, bev->x, bev->y);
168 			}
169 		else
170 			{
171 			switch (bev->type)
172 				{
173 				case BUTTON_HELD:
174 
175 					if (!state.busy_drawing)
176 						{
177 						/* start drawing */
178 						state.busy_drawing = TRUE;
179 						held = TRUE;
180 						if (state.current_icon==BOXELLIPSEICON)
181 							{
182 							if (view->gridon)
183 								{
184 								x1 = GXP2D(bev->x,view);
185 								y1 = GYP2D(bev->y,view);
186 								}
187 							else
188 								{
189 								x1 = XP2D(bev->x,view);
190 								y1 = YP2D(bev->y,view);
191 								};
192 							};
193 
194 						if (view->gridon)
195 							{
196 							cx = GXP2D(bev->x,view);
197 							cy = GYP2D(bev->y,view);
198 							}
199 						else
200 							{
201 							cx = XP2D(bev->x,view);
202 							cy = YP2D(bev->y,view);
203 							};
204 
205 						xr = 1;
206 						yr = 1;
207 
208  						toggle_ellipse(view, bev->x, bev->y);
209 						};
210 
211 					break; /* BUTTON_HELD  */
212 
213 				case BUTTON_CLICKED:
214 
215 					if (held)
216 						{
217 						XGrabPointer(display, view->draw_window->win, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ButtonMotionMask
218 										 | Button1MotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
219 						}
220 					else
221 						{
222 						XUngrabPointer(display,CurrentTime);
223 						toggle_ellipse(view, bev->x, bev->y);
224 
225 						commit_ellipse(view, bev->x, bev->y);
226 
227 						state.busy_drawing=FALSE;
228 						};
229 
230 					held = FALSE;
231 					break;
232 
233 
234 				case BUTTON_RELEASED:
235 
236 					toggle_ellipse(view, bev->x, bev->y);
237 
238 					commit_ellipse(view, bev->x, bev->y);
239 					held = FALSE;
240 					state.busy_drawing=FALSE;
241 
242 					break;
243 				};
244 			};
245 		};
246 }
247 
248 void
toggle_ellipse(View * view,int x,int y)249 toggle_ellipse(View *view, int x, int y)
250 {
251 	if (state.current_icon==BOXELLIPSEICON)
252 		{
253 		if (view->gridon)
254 			{
255 			cx = (GXP2D(x,view) - x1)/2 + x1;
256 			cy = (GYP2D(y,view) - y1)/2 + y1;
257 			xr = abs(GXP2D(x,view) - x1)/2;
258 			yr = abs(GYP2D(y,view) - y1)/2;
259 			}
260 		else
261 			{
262 			cx = (XP2D(x,view) - x1)/2 + x1;
263 			cy = (YP2D(y,view) - y1)/2 + y1;
264 			xr = abs(XP2D(x,view) - x1)/2;
265 			yr = abs(YP2D(y,view) - y1)/2;
266 			};
267 		}
268 	else
269 		{
270 		if (view->gridon)
271 			{
272 			xr = abs(GXP2D(x, view) - cx);
273 			yr = abs(GYP2D(y, view) - cy);
274 			}
275 		else
276 			{
277 			xr = abs(XP2D(x, view) - cx);
278 			yr = abs(YP2D(y, view) - cy);
279 			};
280 		};
281 
282 	/* constrain */
283  	if (state.control_down)
284  		constrain_ellipse(&xr,&yr);
285 
286 	XDrawArc(display, view->draw_window->win, blackxorgc, XD2P(cx-xr,view), YD2P(cy-yr,view),
287 				(uint)D2P(2*xr,view), (uint)D2P(2*yr,view), 0, 360*64);
288 }
289 
290 void
draw_ellipse(Object * ob,View * view,GC gc,long x,long y,double rx,double ry)291 draw_ellipse(Object *ob, View *view, GC gc, long x,long y, double rx, double ry)
292 {
293 	GC tgc;
294 	int r;
295 
296 	if (gc==NULL)
297 		tgc = ugc;
298 	else
299 		tgc = gc;
300 
301 	if (gc==blackxorgc && state.tied_corner != NOTSCALING)
302 		{
303 		corner_magic(ob, &x, &y, rx, ry);
304 		r = ellipse_box(XD2P(x+ob->ob.ellipse.centre.x,view),YD2P(y+ob->ob.ellipse.centre.y,view),
305 				 D2P(ob->ob.ellipse.xradius,view), D2P(ob->ob.ellipse.yradius,view),
306 				 0, 0, (long)view->window.w, (long)view->window.h);
307 
308 		if (r!=NO_INTERSECT && r!=CONTAINS)
309 			{
310 			XDrawArc(display, view->draw_window->win, tgc,
311 					XD2P(x,view), YD2P(y,view),
312 					(uint)D2P(abs(R(2*ob->ob.ellipse.xradius,rx)),view),
313 					(uint)D2P(abs(R(2*ob->ob.ellipse.yradius,ry)),view),
314 					0, 360*64);
315 			};
316 		}
317 	else
318 		{
319 		r = ellipse_box(XD2P(x+ob->ob.ellipse.centre.x,view),YD2P(y+ob->ob.ellipse.centre.y,view),
320 				 D2P(ob->ob.ellipse.xradius,view), D2P(ob->ob.ellipse.yradius,view),
321 				 0, 0, (long)view->draw_window->w, (long)view->draw_window->h);
322 
323 		if (r==CONTAINED && ob->fs!=NONE && gc!=blackxorgc)
324 			{
325 			XFillArc(display, view->draw_window->win, fillgc,
326 					XD2P(x,view), YD2P(y,view),
327 					(uint)D2P(2*ob->ob.ellipse.xradius,view),
328 					(uint)D2P(2*ob->ob.ellipse.yradius,view),
329 					0, 360*64);
330 			};
331 
332 		if (r==CONTAINS && ob->fs!=NONE && gc!=blackxorgc)
333 			XFillRectangle(display,view->draw_window->win,fillgc,0,0,view->draw_window->w, view->draw_window->h);
334 
335 		if (r!=NO_INTERSECT && r!=CONTAINS && (gc==blackxorgc || ob->lw!=0))
336 			{
337 			XDrawArc(display, view->draw_window->win, tgc,
338 					XD2P(x,view), YD2P(y,view),
339 					(uint)D2P(2*ob->ob.ellipse.xradius,view),
340 					(uint)D2P(2*ob->ob.ellipse.yradius,view),
341 					0, 360*64);
342 			};
343 		};
344 
345 }
346