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