1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2007 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  *
7  * Any party obtaining a copy of these files is granted, free of charge, a
8  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9  * nonexclusive right and license to deal in this software and documentation
10  * files (the "Software"), including without limitation the rights to use,
11  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
12  * the Software, and to permit persons who receive copies from any such
13  * party to do so, with the only requirement being that the above copyright
14  * and this permission notice remain intact.
15  *
16  */
17 
18 #include "fig.h"
19 #include "resources.h"
20 #include "object.h"
21 #include "mode.h"
22 #include "u_list.h"
23 #include "u_search.h"
24 #include "w_drawprim.h"
25 #include "w_layers.h"
26 #include "w_setup.h"
27 #include "w_zoom.h"
28 #include "w_snap.h"
29 
30 #include "u_geom.h"
31 #include "u_markers.h"
32 
33 #define TOLERANCE ((int)((display_zoomscale < 20.0? 10: 14) * \
34 			PIX_PER_INCH/DISPLAY_PIX_PER_INCH/display_zoomscale))
35 
36 static void	(*manipulate) ();
37 static void	(*handlerproc_left) ();
38 static void	(*handlerproc_middle) ();
39 static void	(*handlerproc_right) ();
40 static int	type;
41 static long	objectcount;
42 static long	n;
43 static int	csr_x, csr_y;
44 
45 static F_point	point1, point2;
46 
47 static F_arc      *a;
48 static F_ellipse  *e;
49 static F_line     *l;
50 static F_spline   *s;
51 static F_text     *t;
52 static F_compound *c;
53 
54 /*
55  * (px, py) is the control point on the
56  * circumference of an arc which is the
57  * closest to (x, y)
58  */
59 
60 
61 void toggle_objecthighlight (void);
62 
63 Boolean
next_arc_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)64 next_arc_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
65 {
66     int		    i;
67 
68     if (!arc_in_mask())
69 	return False;
70     if (a == NULL)
71 	if (shift)
72 	    a = last_arc(objects.arcs);
73 	else
74 	    a = objects.arcs;
75     else if (shift)
76 	a = prev_arc(objects.arcs, a);
77 
78     for (; a != NULL; a = (shift? prev_arc(objects.arcs, a): a->next), n++) {
79 	if (!active_layer(a->depth))
80 	    continue;
81 	for (i = 0; i < 3; i++) {
82 	    if ((abs(a->point[i].x - x) <= tolerance) &&
83 		(abs(a->point[i].y - y) <= tolerance)) {
84 		*px = a->point[i].x;
85 		*py = a->point[i].y;
86 		return True;
87 	    }
88 	}
89 	{
90 	  /* still nothing */
91 
92 	  /* check if we're at the arc radius from the arc center */
93 
94 	  double dist   = hypot((double)y - (double)(a->center.y),
95 				(double)x - (double)(a->center.x));
96 	  double radius =  hypot((double)(a->point[1].y) - (double)(a->center.y),
97 				 (double)(a->point[1].x) - (double)(a->center.x));
98 	  if (fabs(radius - dist) < (double)tolerance) {
99 	    /* ok, we're somewhere on the circle the arc is part of	*/
100 	    /* now, check if we're on the arc itself */
101 	    if (True == is_point_on_arc(a, x, y)) {
102 	      /* yep, we're on the actual arc */
103 	      /* now we find the closest control point */
104 	      double mind = HUGE_VAL;
105 	      int pp;
106 	      for (i = 0; i < 3; i++) {
107 		dist = hypot((double)y - (double)(a->point[i].y),
108 			     (double)x - (double)(a->point[i].x));
109 		if (dist < mind) {
110 		  mind = dist;
111 		  pp = i;
112 		}
113 	      }
114 	      *px = a->point[pp].x;
115 	      *py = a->point[pp].y;
116 	      return True;
117 	    }
118 	  }
119 	}
120     }
121     return False;
122 }
123 
124 /*
125  * (px, py) is the point on the circumference
126  * of an ellipse which is the closest to (x, y)
127  */
128 
129 /* this rotates (x, y) into a coordinate system orthogonal to the ellipse semi-axes */
130 
131 inline static void
vector_rotate(a,b,angle)132 vector_rotate(a, b, angle)
133      double * a;
134      double * b;
135      float angle;
136 {
137   double x = fabs((*a * cos((double)angle)) - (*b * sin((double)angle)));
138   double y = fabs((*a * sin((double)angle)) + (*b * cos((double)angle)));
139   *a = x;
140   *b = y;
141 }
142 
143 Boolean
next_ellipse_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)144 next_ellipse_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
145 {
146     double	    a, b, dx, dy;
147     double	    dis, r, tol;
148 
149     if (!ellipse_in_mask())
150 	return False;
151     if (e == NULL)
152 	if (shift)
153 	    e = last_ellipse(objects.ellipses);
154 	else
155 	    e = objects.ellipses;
156     else if (shift)
157 	e = prev_ellipse(objects.ellipses, e);
158 
159     tol = (double) tolerance;
160     for (; e != NULL; e = (shift? prev_ellipse(objects.ellipses, e): e->next), n++) {
161 	if (!active_layer(e->depth))
162 	    continue;
163 	dx = x - e->center.x;
164 	dy = y - e->center.y;
165 	a = e->radiuses.x;
166 	b = e->radiuses.y;
167 	/* prevent sqrt(0) core dumps */
168 	if (dx == 0 && dy == 0)
169 	    dis = 0.0;		/* so we return below */
170 	else
171 	    dis = sqrt(dx * dx + dy * dy);
172 	if (dis < tol) {
173 	    *px = e->center.x;
174 	    *py = e->center.y;
175 	    return True;
176 	}
177 	if (abs(x - e->start.x) <= tolerance && abs(y - e->start.y) <= tolerance) {
178 	    *px = e->start.x;
179 	    *py = e->start.y;
180 	    return True;
181 	}
182 	if (abs(x - e->end.x) <= tolerance && abs(y - e->end.y) <= tolerance) {
183 	    *px = e->end.x;
184 	    *py = e->end.y;
185 	    return True;
186 	}
187 	if (a * dy == 0 && b * dx == 0)
188 	    r = 0.0;		/* prevent core dumps */
189 	else {
190 	    vector_rotate(&dx, &dy, (double)(e->angle));
191 	    r = a * b * dis / sqrt(1.0 * b * b * dx * dx + 1.0 * a * a * dy * dy);
192 	}
193 	if (fabs(dis - r) <= tol) {
194 	    *px = round(r * dx / dis + (double)e->center.x);
195 	    *py = round(r * dy / dis + (double)e->center.y);
196 	    return True;
197 	}
198     }
199     return False;
200 }
201 
202 /*
203  * Return the pointer to lines object if the
204  * search is successful otherwise return
205  * NULL.  The value returned via (px, py) is
206  * the closest point on the vector to point (x, y)
207  */
208 
209 Boolean
next_line_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)210 next_line_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
211 {
212     F_point	   *point;
213     int		    x1, y1, x2, y2;
214     float	    tol2;
215 
216     tol2 = (float) tolerance *tolerance;
217 
218     if (!anyline_in_mask())
219 	return False;
220     if (l == NULL)
221 	if (shift)
222 	    l = last_line(objects.lines);
223 	else
224 	    l = objects.lines;
225     else if (shift)
226 	l = prev_line(objects.lines, l);
227 
228     for (; l != NULL; l = (shift? prev_line(objects.lines, l): l->next), n++) {
229 	if (!active_layer(l->depth))
230 	    continue;
231 	if (validline_in_mask(l)) {
232 	    point = l->points;
233 	    x1 = point->x;
234 	    y1 = point->y;
235 	    if (abs(x - x1) <= tolerance && abs(y - y1) <= tolerance) {
236 		*px = x1;
237 		*py = y1;
238 		return True;
239 	    }
240 	    for (point = point->next; point != NULL; point = point->next) {
241 		x2 = point->x;
242 		y2 = point->y;
243 		if (close_to_vector(x1, y1, x2, y2, x, y, tolerance, tol2, px, py)) {
244 		    return True;
245 		}
246 		x1 = x2;
247 		y1 = y2;
248 	    }
249 	}
250     }
251     return False;
252 }
253 
254 /*
255  * Return the pointer to lines object if the
256  * search is successful otherwise return NULL.
257  */
258 
259 Boolean
next_spline_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)260 next_spline_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
261 {
262     F_point	   *point;
263     int		    x1, y1, x2, y2;
264     float	    tol2;
265 
266     if (!anyspline_in_mask())
267 	return False;
268     if (s == NULL)
269 	if (shift)
270 	    s = last_spline(objects.splines);
271 	else
272 	    s = objects.splines;
273     else if (shift)
274 	s = prev_spline(objects.splines, s);
275 
276     tol2 = (float) tolerance *tolerance;
277 
278     for (; s != NULL; s = (shift? prev_spline(objects.splines, s): s->next), n++) {
279 	if (!active_layer(s->depth))
280 	    continue;
281 	if (validspline_in_mask(s)) {
282 	    point = s->points;
283 	    x1 = point->x;
284 	    y1 = point->y;
285 	    for (point = point->next; point != NULL; point = point->next) {
286 		x2 = point->x;
287 		y2 = point->y;
288 		if (close_to_vector(x1, y1, x2, y2, x, y, tolerance, tol2,
289 				    px, py))
290 		    return True;
291 		x1 = x2;
292 		y1 = y2;
293 	    }
294 	}
295     }
296     return False;
297 }
298 
299 Boolean
next_text_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)300 next_text_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
301 {
302     int		    dum;
303 
304     if (!anytext_in_mask())
305 	return False;
306     if (t == NULL)
307 	if (shift)
308 	    t = last_text(objects.texts);
309 	else
310 	    t = objects.texts;
311     else if (shift)
312 	t = prev_text(objects.texts, t);
313 
314     for (; t != NULL; t = (shift? prev_text(objects.texts, t): t->next), n++) {
315 	if (!active_layer(t->depth))
316 	    continue;
317 	if (validtext_in_mask(t)) {
318 	    if (in_text_bound(t, x, y, &dum, False)) {
319 		*px = x;
320 		*py = y;
321 		return True;
322 	    }
323 	}
324     }
325     return False;
326 }
327 
328 Boolean
next_compound_found(int x,int y,int tolerance,int * px,int * py,unsigned int shift)329 next_compound_found(int x, int y, int tolerance, int *px, int *py, unsigned int shift)
330 {
331     float	    tol2;
332 
333     if (!compound_in_mask())
334 	return False;
335     if (c == NULL)
336 	if (shift)
337 	    c = last_compound(objects.compounds);
338 	else
339 	    c = objects.compounds;
340     else if (shift)
341 	c = prev_compound(objects.compounds, c);
342 
343     tol2 = tolerance * tolerance;
344 
345     for (; c != NULL; c = (shift? prev_compound(objects.compounds, c): c->next), n++) {
346 	if (!any_active_in_compound(c))
347 		continue;
348 	if (close_to_vector(c->nwcorner.x, c->nwcorner.y, c->nwcorner.x,
349 			    c->secorner.y, x, y, tolerance, tol2, px, py))
350 	    return True;
351 	if (close_to_vector(c->secorner.x, c->secorner.y, c->nwcorner.x,
352 			    c->secorner.y, x, y, tolerance, tol2, px, py))
353 	    return True;
354 	if (close_to_vector(c->secorner.x, c->secorner.y, c->secorner.x,
355 			    c->nwcorner.y, x, y, tolerance, tol2, px, py))
356 	    return True;
357 	if (close_to_vector(c->nwcorner.x, c->nwcorner.y, c->secorner.x,
358 			    c->nwcorner.y, x, y, tolerance, tol2, px, py))
359 	    return True;
360     }
361     return False;
362 }
363 
show_objecthighlight(void)364 void show_objecthighlight(void)
365 {
366     if (highlighting)
367 	return;
368     highlighting = 1;
369     toggle_objecthighlight();
370 }
371 
erase_objecthighlight(void)372 void erase_objecthighlight(void)
373 {
374     if (!highlighting)
375 	return;
376     highlighting = 0;
377     toggle_objecthighlight();
378     if (type == -1) {
379 	e = NULL;
380 	type = O_ELLIPSE;
381     }
382 }
383 
toggle_objecthighlight(void)384 void toggle_objecthighlight(void)
385 {
386     switch (type) {
387     case O_ELLIPSE:
388 	toggle_ellipsehighlight(e);
389 	break;
390     case O_POLYLINE:
391 	toggle_linehighlight(l);
392 	break;
393     case O_SPLINE:
394 	toggle_splinehighlight(s);
395 	break;
396     case O_TXT:
397 	toggle_texthighlight(t);
398 	break;
399     case O_ARC:
400 	toggle_archighlight(a);
401 	break;
402     case O_COMPOUND:
403 	toggle_compoundhighlight(c);
404 	break;
405     default:
406 	toggle_csrhighlight(csr_x, csr_y);
407     }
408 }
409 
410 static void
init_search(void)411 init_search(void)
412 {
413     if (highlighting)
414 	erase_objecthighlight();
415     else {
416 	objectcount = 0;
417 	if (ellipse_in_mask())
418 	    for (e = objects.ellipses; e != NULL; e = e->next)
419 		objectcount++;
420 	if (anyline_in_mask())
421 	    for (l = objects.lines; l != NULL; l = l->next)
422 		if (validline_in_mask(l))
423 		    objectcount++;
424 	if (anyspline_in_mask())
425 	    for (s = objects.splines; s != NULL; s = s->next)
426 		if (validspline_in_mask(s))
427 		    objectcount++;
428 	if (anytext_in_mask())
429 	    for (t = objects.texts; t != NULL; t = t->next)
430 		if (validtext_in_mask(t))
431 		    objectcount++;
432 	if (arc_in_mask())
433 	    for (a = objects.arcs; a != NULL; a = a->next)
434 		objectcount++;
435 	if (compound_in_mask())
436 	    for (c = objects.compounds; c != NULL; c = c->next)
437 		objectcount++;
438 	e = NULL;
439 	type = O_ELLIPSE;
440     }
441 }
442 
443 void
do_object_search(int x,int y,unsigned int shift)444 do_object_search(int x, int y, unsigned int shift)
445 
446 				/* Shift Key Status from XEvent */
447 {
448     int		    px, py;
449     Boolean	    found = False;
450 
451     init_search();
452     for (n = 0; n < objectcount;) {
453 	switch (type) {
454 	  case O_ELLIPSE:
455 	    found = next_ellipse_found(x, y, TOLERANCE, &px, &py, shift);
456 	    break;
457 	  case O_POLYLINE:
458 	    found = next_line_found(x, y, TOLERANCE, &px, &py, shift);
459 	    break;
460 	  case O_SPLINE:
461 	    found = next_spline_found(x, y, TOLERANCE, &px, &py, shift);
462 	    break;
463 	  case O_TXT:
464 	    found = next_text_found(x, y, TOLERANCE, &px, &py, shift);
465 	    break;
466 	  case O_ARC:
467 	    found = next_arc_found(x, y, TOLERANCE, &px, &py, shift);
468 	    break;
469 	  case O_COMPOUND:
470 	    found = next_compound_found(x, y, TOLERANCE, &px, &py, shift);
471 	    break;
472 	}
473 
474 	if (found)
475 	    break;
476 
477 	switch (type) {
478 	  case O_ELLIPSE:
479 	    type = O_POLYLINE;
480 	    l = NULL;
481 	    break;
482 	  case O_POLYLINE:
483 	    type = O_SPLINE;
484 	    s = NULL;
485 	    break;
486 	  case O_SPLINE:
487 	    type = O_TXT;
488 	    t = NULL;
489 	    break;
490 	  case O_TXT:
491 	    type = O_ARC;
492 	    a = NULL;
493 	    break;
494 	  case O_ARC:
495 	    type = O_COMPOUND;
496 	    c = NULL;
497 	    break;
498 	  case O_COMPOUND:
499 	    type = O_ELLIPSE;
500 	    e = NULL;
501 	    break;
502 	}
503     }
504     if (!found) {		/* nothing found */
505 	csr_x = x;
506 	csr_y = y;
507 	type = -1;
508 	show_objecthighlight();
509     } else if (shift) {		/* show selected object */
510 	show_objecthighlight();
511     } else if (manipulate) {	/* user selected an object */
512 	erase_objecthighlight();
513 	switch (type) {
514 	  case O_ELLIPSE:
515 	    manipulate(e, type, x, y, (int) px, py);
516 	    break;
517 	  case O_POLYLINE:
518 	    manipulate(l, type, x, y, px, py);
519 	    break;
520 	  case O_SPLINE:
521 	    manipulate(s, type, x, y, px, py);
522 	    break;
523 	  case O_TXT:
524 	    manipulate(t, type, x, y, px, py);
525 	    break;
526 	  case O_ARC:
527 	    manipulate(a, type, x, y, (int) px, py);
528 	    break;
529 	  case O_COMPOUND:
530 	    manipulate(c, type, x, y, px, py);
531 	    break;
532 	}
533     }
534 }
535 
536 void
object_search_left(int x,int y,unsigned int shift)537 object_search_left(int x, int y, unsigned int shift)
538 
539 				/* Shift Key Status from XEvent */
540 {
541     manipulate = handlerproc_left;
542     do_object_search(x, y, shift);
543 }
544 
545 void
object_search_middle(int x,int y,unsigned int shift)546 object_search_middle(int x, int y, unsigned int shift)
547 
548 				/* Shift Key Status from XEvent */
549 {
550     manipulate = handlerproc_middle;
551     do_object_search(x, y, shift);
552 }
553 
554 void
object_search_right(int x,int y,unsigned int shift)555 object_search_right(int x, int y, unsigned int shift)
556 
557 				/* Shift Key Status from XEvent */
558 {
559     manipulate = handlerproc_right;
560     do_object_search(x, y, shift);
561 }
562 
563 Boolean
next_arc_point_found(int x,int y,int tol,int * point_num,unsigned int shift)564 next_arc_point_found(int x, int y, int tol, int *point_num, unsigned int shift)
565 
566 {
567     int		    i;
568 
569     if (!arc_in_mask())
570 	return False;
571     if (a == NULL)
572 	if (shift)
573 	    a = last_arc(objects.arcs);
574 	else
575 	    a = objects.arcs;
576     else if (shift)
577 	a = prev_arc(objects.arcs, a);
578 
579     for (; a != NULL; a = (shift? prev_arc(objects.arcs, a): a->next), n++) {
580 	if (!active_layer(a->depth))
581 	    continue;
582 	for (i = 0; i < 3; i++) {
583 	    if (abs(a->point[i].x - x) <= tol &&
584 		abs(a->point[i].y - y) <= tol) {
585 		*point_num = i;
586 		return True;
587 	    }
588 	}
589     }
590     return False;
591 }
592 
593 Boolean
next_ellipse_point_found(int x,int y,int tol,int * point_num,unsigned int shift)594 next_ellipse_point_found(int x, int y, int tol, int *point_num, unsigned int shift)
595 
596 {
597 
598     if (!ellipse_in_mask())
599 	return False;
600     if (e == NULL)
601 	if (shift)
602 	    e = last_ellipse(objects.ellipses);
603 	else
604 	    e = objects.ellipses;
605     else if (shift)
606 	e = prev_ellipse(objects.ellipses, e);
607 
608     for (; e != NULL; e = (shift? prev_ellipse(objects.ellipses, e): e->next), n++) {
609 	if (!active_layer(e->depth))
610 	    continue;
611 	if (abs(e->start.x - x) <= tol && abs(e->start.y - y) <= tol) {
612 	    *point_num = 0;
613 	    return True;
614 	}
615 	if (abs(e->end.x - x) <= tol && abs(e->end.y - y) <= tol) {
616 	    *point_num = 1;
617 	    return True;
618 	}
619     }
620     return False;
621 }
622 
623 Boolean
next_line_point_found(int x,int y,int tol,F_point ** p,F_point ** q,unsigned int shift)624 next_line_point_found(int x, int y, int tol, F_point **p, F_point **q, unsigned int shift)
625 {
626     F_point	   *a, *b;
627 
628     if (!anyline_in_mask())
629 	return False;
630     if (l == NULL)
631 	if (shift)
632 	    l = last_line(objects.lines);
633 	else
634 	    l = objects.lines;
635     else if (shift)
636 	l = prev_line(objects.lines, l);
637 
638     for (; l != NULL; l = (shift? prev_line(objects.lines, l): l->next)) {
639 	if (!active_layer(l->depth))
640 	    continue;
641 	if (validline_in_mask(l)) {
642 	    n++;
643 	    for (a = NULL, b = l->points; b != NULL; a = b, b = b->next) {
644 		if (abs(b->x - x) <= tol && abs(b->y - y) <= tol) {
645 		    *p = a;
646 		    *q = b;
647 		    return True;
648 		}
649 	    }
650 	}
651     }
652     return False;
653 }
654 
655 Boolean
next_spline_point_found(int x,int y,int tol,F_point ** p,F_point ** q,unsigned int shift)656 next_spline_point_found(int x, int y, int tol, F_point **p, F_point **q, unsigned int shift)
657 {
658     if (!anyspline_in_mask())
659 	return False;
660     if (s == NULL)
661 	if (shift)
662 	    s = last_spline(objects.splines);
663 	else
664 	    s = objects.splines;
665     else if (shift)
666 	s = prev_spline(objects.splines, s);
667 
668     for (; s != NULL; s = (shift? prev_spline(objects.splines, s): s->next)) {
669 	if (!active_layer(s->depth))
670 	    continue;
671 	if (validspline_in_mask(s)) {
672 	    n++;
673 	    *p = NULL;
674 	    for (*q = s->points; *q != NULL; *p = *q, *q = (*q)->next) {
675 		if ((abs((*q)->x - x) <= tol) && (abs((*q)->y - y) <= tol))
676 		    return True;
677 	    }
678 	}
679     }
680     return False;
681 }
682 
683 Boolean
next_compound_point_found(int x,int y,int tol,int * p,int * q,unsigned int shift)684 next_compound_point_found(int x, int y, int tol, int *p, int *q, unsigned int shift)
685 
686 /* dirty trick - p and q are called with type `F_point' */
687 {
688     if (!compound_in_mask())
689 	return False;
690     if (c == NULL)
691 	if (shift)
692 	    c = last_compound(objects.compounds);
693 	else
694 	    c = objects.compounds;
695     else if (shift)
696 	c = prev_compound(objects.compounds, c);
697 
698     for (; c != NULL; c = (shift? prev_compound(objects.compounds, c): c->next), n++) {
699 	if (!any_active_in_compound(c))
700 		continue;
701 	if (abs(c->nwcorner.x - x) <= tol &&
702 	    abs(c->nwcorner.y - y) <= tol) {
703 	    *p = c->nwcorner.x;
704 	    *q = c->nwcorner.y;
705 	    return True;
706 	}
707 	if (abs(c->nwcorner.x - x) <= tol &&
708 	    abs(c->secorner.y - y) <= tol) {
709 	    *p = c->nwcorner.x;
710 	    *q = c->secorner.y;
711 	    return True;
712 	}
713 	if (abs(c->secorner.x - x) <= tol &&
714 	    abs(c->nwcorner.y - y) <= tol) {
715 	    *p = c->secorner.x;
716 	    *q = c->nwcorner.y;
717 	    return True;
718 	}
719 	if (abs(c->secorner.x - x) <= tol &&
720 	    abs(c->secorner.y - y) <= tol) {
721 	    *p = c->secorner.x;
722 	    *q = c->secorner.y;
723 	    return True;
724 	}
725     }
726     return False;
727 }
728 
729 void
init_searchproc_left(void (* handlerproc)())730 init_searchproc_left(void (*handlerproc) (/* ??? */))
731 {
732     handlerproc_left = handlerproc;
733 }
734 
735 void
init_searchproc_middle(void (* handlerproc)())736 init_searchproc_middle(void (*handlerproc) (/* ??? */))
737 {
738     handlerproc_middle = handlerproc;
739 }
740 
741 void
init_searchproc_right(void (* handlerproc)())742 init_searchproc_right(void (*handlerproc) (/* ??? */))
743 {
744     handlerproc_right = handlerproc;
745 }
746 
747 void
do_point_search(int x,int y,unsigned int shift)748 do_point_search(int x, int y, unsigned int shift)
749 
750 				/* Shift Key Status from XEvent */
751 {
752     F_point	   *px, *py;
753     char	    found = 0;
754     int		    pnum = 0;
755 
756     px = &point1;
757     py = &point2;
758     init_search();
759     for (n = 0; n < objectcount;) {
760 	switch (type) {
761 	case O_ELLIPSE:
762 	    found = next_ellipse_point_found(x, y, TOLERANCE, &pnum, shift);
763 	    break;
764 	case O_POLYLINE:
765 	    found = next_line_point_found(x, y, TOLERANCE, &px, &py, shift);
766 	    break;
767 	case O_SPLINE:
768 	    found = next_spline_point_found(x, y, TOLERANCE, &px, &py, shift);
769 	    break;
770 	case O_ARC:
771 	    found = next_arc_point_found(x, y, TOLERANCE, &pnum, shift);
772 	    break;
773 	case O_COMPOUND:
774 	    found = next_compound_point_found(x, y, TOLERANCE, (int *)&px, (int *)&py, shift);
775 	    break;
776 	}
777 	if (found) {
778 	    if (shift)
779 		show_objecthighlight();
780 	    break;
781 	}
782 	switch (type) {
783 	case O_ELLIPSE:
784 	    type = O_POLYLINE;
785 	    l = NULL;
786 	    break;
787 	case O_POLYLINE:
788 	    type = O_SPLINE;
789 	    s = NULL;
790 	    break;
791 	case O_SPLINE:
792 	    type = O_ARC;
793 	    a = NULL;
794 	    break;
795 	case O_ARC:
796 	    type = O_COMPOUND;
797 	    c = NULL;
798 	    break;
799 	case O_COMPOUND:
800 	    type = O_ELLIPSE;
801 	    e = NULL;
802 	    break;
803 	}
804     }
805     if (!found) {
806 	csr_x = x;
807 	csr_y = y;
808 	type = -1;
809 	show_objecthighlight();
810     } else if (shift) {
811 	show_objecthighlight();
812     } else if (manipulate) {
813 	erase_objecthighlight();
814 	switch (type) {
815 	  case O_ELLIPSE:
816 	    manipulate(e, type, x, y, px, py, pnum);
817 	    break;
818 	  case O_POLYLINE:
819 	    manipulate(l, type, x, y, px, py);
820 	    break;
821 	  case O_SPLINE:
822 	    manipulate(s, type, x, y, px, py);
823 	    break;
824 	  case O_ARC:
825 	    manipulate(a, type, x, y, px, py, pnum);
826 	    break;
827 	  case O_COMPOUND:
828 	    manipulate(c, type, x, y, px, py);
829 	    break;
830 	}
831     }
832 }
833 
834 void
point_search_left(int x,int y,unsigned int shift)835 point_search_left(int x, int y, unsigned int shift)
836 
837 				/* Shift Key Status from XEvent */
838 {
839     manipulate = handlerproc_left;
840     do_point_search(x, y, shift);
841 }
842 
843 void
point_search_middle(int x,int y,unsigned int shift)844 point_search_middle(int x, int y, unsigned int shift)
845 
846 				/* Shift Key Status from XEvent */
847 {
848     manipulate = handlerproc_middle;
849     do_point_search(x, y, shift);
850 }
851 
852 void
point_search_right(int x,int y,unsigned int shift)853 point_search_right(int x, int y, unsigned int shift)
854 
855 				/* Shift Key Status from XEvent */
856 {
857     manipulate = handlerproc_right;
858     do_point_search(x, y, shift);
859 }
860 
861 F_text	       *
text_search(int x,int y,int * posn)862 text_search(int x, int y, int *posn)
863 {
864     F_text	   *t;
865 
866     for (t = objects.texts; t != NULL; t = t->next) {
867 	if (active_layer(t->depth) && in_text_bound(t, x, y, posn, False))
868 		return(t);
869     }
870     return (NULL);
871 }
872 
873 /* return true if (x,y) is in the text rectangle by rotating the point (x,y)
874    around the text base point by it's negative angle and seeing if that is
875    in the rectangle.
876    Additionally, set posn to the pixel position of the mouse from the beginning
877    of the string
878    Call with extra = True to consider small distance on either end of string as
879    "inside" the bounds.  This is used by the text select tracker (track_text_select).
880  */
881 
882 Boolean
in_text_bound(F_text * t,int x,int y,int * posn,Boolean extra)883 in_text_bound(F_text *t, int x, int y, int *posn, Boolean extra)
884 {
885     double	    cost, sint;
886     int		    xo,yo, xr,yr;
887     int		    x0, x1,y1, x2,y2;
888     int		    l, h;
889 
890     cost = cos((double) -t->angle);
891     sint = sin((double) -t->angle);
892     xo = t->base_x;
893     yo = t->base_y;
894 
895     /* rotate the point (x,y) about (xo,yo) giving (xr,yr) */
896     xr = xo + (x-xo)*cost - (yo-y)*sint;
897     yr = yo - (yo-y)*cost - (x-xo)*sint;
898     /* now see if that point is in the text bounds of the unrotated text */
899     l = text_length(t);
900     /* add 5 char widths to length if extra wanted */
901     if (extra)
902 	l += 5*char_width(t->fontstruct);
903     h = t->ascent+t->descent;
904     x1 = t->base_x;
905     /* use x0 for left bound comparison but use x1 for char position in string of x,y */
906     x0 = x1;
907     /* subtract 4 char widths before start of string */
908     if (extra)
909 	x0 -= 4*char_width(t->fontstruct);
910     y1 = t->base_y+t->descent;
911     if (t->type == T_CENTER_JUSTIFIED) {
912 	x2 = x1 + l/2;
913 	x1 = x1 - l/2;
914 	x0 = x0 - l/2;
915 	y2 = y1 - h;
916     }
917     else if (t->type == T_RIGHT_JUSTIFIED) {
918 	x2 = x1;
919 	x1 = x1 - l;
920 	x0 = x0 - l;
921 	y2 = y1 - h;
922     }
923     else {
924 	x2 = x1 + l;
925 	y2 = y1 - h;
926     }
927     if (xr >= x0 && xr <= x2 && yr <= y1 && yr >= y2) {
928 	/* return the pixel position from the beginning of the string */
929 	*posn = xr-x1;
930 	if (*posn < 0)
931 	    *posn = 0;
932 	else if (*posn > text_length(t))
933 	    *posn = text_length(t);
934 	return True;
935     }
936     return False;
937 }
938 
939 F_compound     *
compound_search(int x,int y,int tolerance,int * px,int * py)940 compound_search(int x, int y, int tolerance, int *px, int *py)
941 {
942     F_compound	   *c;
943     float	    tol2;
944 
945     tol2 = tolerance * tolerance;
946 
947     for (c = objects.compounds; c != NULL; c = c->next) {
948 	if (close_to_vector(c->nwcorner.x, c->nwcorner.y, c->nwcorner.x,
949 			    c->secorner.y, x, y, tolerance, tol2, px, py))
950 	    return (c);
951 	if (close_to_vector(c->secorner.x, c->secorner.y, c->nwcorner.x,
952 			    c->secorner.y, x, y, tolerance, tol2, px, py))
953 	    return (c);
954 	if (close_to_vector(c->secorner.x, c->secorner.y, c->secorner.x,
955 			    c->nwcorner.y, x, y, tolerance, tol2, px, py))
956 	    return (c);
957 	if (close_to_vector(c->nwcorner.x, c->nwcorner.y, c->secorner.x,
958 			    c->nwcorner.y, x, y, tolerance, tol2, px, py))
959 	    return (c);
960     }
961     return (NULL);
962 }
963 
964 F_compound     *
compound_point_search(int x,int y,int tol,int * cx,int * cy,int * fx,int * fy)965 compound_point_search(int x, int y, int tol, int *cx, int *cy, int *fx, int *fy)
966 {
967     F_compound	   *c;
968 
969     for (c = objects.compounds; c != NULL; c = c->next) {
970 	if (abs(c->nwcorner.x - x) <= tol &&
971 	    abs(c->nwcorner.y - y) <= tol) {
972 	    *cx = c->nwcorner.x;
973 	    *cy = c->nwcorner.y;
974 	    *fx = c->secorner.x;
975 	    *fy = c->secorner.y;
976 	    return (c);
977 	}
978 	if (abs(c->nwcorner.x - x) <= tol &&
979 	    abs(c->secorner.y - y) <= tol) {
980 	    *cx = c->nwcorner.x;
981 	    *cy = c->secorner.y;
982 	    *fx = c->secorner.x;
983 	    *fy = c->nwcorner.y;
984 	    return (c);
985 	}
986 	if (abs(c->secorner.x - x) <= tol &&
987 	    abs(c->nwcorner.y - y) <= tol) {
988 	    *cx = c->secorner.x;
989 	    *cy = c->nwcorner.y;
990 	    *fx = c->nwcorner.x;
991 	    *fy = c->secorner.y;
992 	    return (c);
993 	}
994 	if (abs(c->secorner.x - x) <= tol &&
995 	    abs(c->secorner.y - y) <= tol) {
996 	    *cx = c->secorner.x;
997 	    *cy = c->secorner.y;
998 	    *fx = c->nwcorner.x;
999 	    *fy = c->nwcorner.y;
1000 	    return (c);
1001 	}
1002     }
1003     return (NULL);
1004 }
1005 
1006 
1007 
1008 F_spline   *
get_spline_point(int x,int y,F_point ** p,F_point ** q)1009 get_spline_point(int x, int y, F_point **p, F_point **q)
1010 {
1011     F_spline *spline;
1012     spline = last_spline(objects.splines);
1013     for (; spline != NULL; spline = prev_spline(objects.splines, spline))
1014 	if (validspline_in_mask(spline)) {
1015 	    n++;
1016 	    *p = NULL;
1017 	    for (*q = spline->points; *q != NULL; *p = *q, *q = (*q)->next) {
1018 		if ((abs((*q)->x - x) <= TOLERANCE) &&
1019 		    (abs((*q)->y - y) <= TOLERANCE))
1020 		    return spline;
1021 	    }
1022 	}
1023     return (NULL);
1024 }
1025 
1026