1 /*-------------------------------------------------------------------------*/
2 /* selection.c --- xcircuit routines handling element selection etc. */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 /*-------------------------------------------------------------------------*/
7 /* written by Tim Edwards, 8/13/93 */
8 /*-------------------------------------------------------------------------*/
16 #include <X11/Intrinsic.h>
17 #include <X11/StringDefs.h>
28 /*-------------------------------------------------------------------------*/
30 /*-------------------------------------------------------------------------*/
33 #include "colordefs.h"
35 /*----------------------------------------------------------------------*/
36 /* Function prototype declarations */
37 /*----------------------------------------------------------------------*/
38 #include "prototypes.h"
40 /*----------------------------------------------------------------------*/
41 /* Exported Variable definitions */
42 /*----------------------------------------------------------------------*/
45 extern Cursor appcursors
[NUM_CURSORS
];
46 extern XCWindowData
*areawin
;
47 extern Globaldata xobjs
;
48 extern char _STR
[150];
49 extern int number_colors
;
50 extern colorindex
*colorlist
;
53 extern Tcl_Interp
*xcinterp
;
56 /*----------------------------------------------------------------------*/
57 /* Prevent a list of elements from being selected. */
58 /*----------------------------------------------------------------------*/
60 void disable_selects(objectptr thisobject
, short *selectlist
, int selects
)
65 for (i
= selectlist
; i
< selectlist
+ selects
; i
++) {
66 genptr
= *(thisobject
->plist
+ *i
);
67 genptr
->type
|= SELECT_HIDE
;
71 /*----------------------------------------------------------------------*/
72 /* Allow a list of elements to be selected, if they were disabled using */
73 /* the disable_selects() routine. */
74 /*----------------------------------------------------------------------*/
76 void enable_selects(objectptr thisobject
, short *selectlist
, int selects
)
81 for (i
= selectlist
; i
< selectlist
+ selects
; i
++) {
82 genptr
= *(thisobject
->plist
+ *i
);
83 genptr
->type
&= ~(SELECT_HIDE
);
87 /*----------------------------------------------------------------------*/
88 /* Change filter to determine what types can be selected */
89 /*----------------------------------------------------------------------*/
91 void selectfilter(xcWidget w
, pointertype value
, caddr_t calldata
)
93 short bitwise
= (short)value
;
94 Boolean bval
= (areawin
->filter
& bitwise
) ? True
: False
;
97 areawin
->filter
&= ~bitwise
;
99 areawin
->filter
|= bitwise
;
102 toggle(w
, (pointertype
)&bval
, calldata
);
106 /*----------------------------------------------------------------------*/
107 /* Look at select stack to see if there are any selects; call select, */
108 /* if not. If draw_selected is True, then the selected items are drawn */
109 /* in the select color. Otherwise, they are not redrawn. */
110 /*----------------------------------------------------------------------*/
112 Boolean
checkselect_draw(short value
, Boolean draw_selected
)
116 value
&= areawin
->filter
; /* apply the selection filter */
118 if (areawin
->selects
== 0) {
120 select_element(value
);
122 Boolean save_redraw
= areawin
->redraw_needed
;
123 select_element(value
);
124 areawin
->redraw_needed
= save_redraw
;
127 if (areawin
->selects
== 0) return False
;
128 for (check
= areawin
->selectlist
; check
< areawin
->selectlist
+
129 areawin
->selects
; check
++)
130 if (SELECTTYPE(check
) & value
) break;
131 if (check
== areawin
->selectlist
+ areawin
->selects
) return False
;
135 /*----------------------------------------------------------------------------*/
136 /* Look at select stack to see if there are any selects; call select, if not. */
137 /*----------------------------------------------------------------------------*/
139 Boolean
checkselect(short value
)
141 return checkselect_draw(value
, False
);
144 /*--------------------------------------------------------------*/
145 /* Select list numbering revision when an element is deleted */
146 /* from an object. */
147 /*--------------------------------------------------------------*/
149 void reviseselect(short *slist
, int selects
, short *removed
)
153 for (chkselect
= slist
; chkselect
< slist
+ selects
; chkselect
++)
154 if (*chkselect
> *removed
) (*chkselect
)--;
157 /*----------------------*/
158 /* Draw a selected item */
159 /*----------------------*/
161 void geneasydraw(short instance
, int mode
, objectptr curobj
, objinstptr curinst
)
163 genericptr elementptr
= *(curobj
->plist
+ instance
);
166 cairo_save(areawin
->cr
);
167 cairo_reset_clip(areawin
->cr
);
169 // Note: Setting areawin->clipped to -1 prevents the clipmask from being
170 // applied to elements,
171 areawin
->clipped
= -1;
172 #endif /* HAVE_CAIRO */
174 switch (ELEMENTTYPE(*(curobj
->plist
+ instance
))) {
176 UDrawArc((arcptr
)elementptr
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
179 UDrawPolygon((polyptr
)elementptr
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
182 UDrawSpline((splineptr
)elementptr
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
185 UDrawPath((pathptr
)elementptr
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
188 UDrawString((labelptr
)elementptr
, mode
, curinst
);
191 UDrawObject((objinstptr
)elementptr
, SINGLE
, mode
,
192 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
195 UDrawGraphic((graphicptr
)elementptr
);
199 cairo_restore(areawin
->cr
);
201 areawin
->clipped
= 0;
202 #endif /* HAVE_CAIRO */
205 /*-------------------------------------------------*/
206 /* Draw a selected item, including selection color */
207 /*-------------------------------------------------*/
209 void gendrawselected(short *newselect
, objectptr curobj
, objinstptr curinst
)
211 if (*newselect
>= curobj
->parts
) return; // Safety check
213 XcSetForeground(SELECTCOLOR
);
214 geneasydraw(*newselect
, DOFORALL
, curobj
, curinst
);
216 SetForeground(dpy
, areawin
->gc
, AUXCOLOR
);
217 indicateparams(*(curobj
->plist
+ *newselect
));
219 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
222 /*---------------------------------------------------*/
223 /* Allocate or reallocate memory for a new selection */
224 /*---------------------------------------------------*/
230 if (areawin
->selects
== 0)
231 areawin
->selectlist
= (short *) malloc(sizeof(short));
233 areawin
->selectlist
= (short *) realloc(areawin
->selectlist
,
234 (areawin
->selects
+ 1) * sizeof(short));
236 newselect
= areawin
->selectlist
+ areawin
->selects
;
242 /*-------------------------------------------------*/
243 /* Set Options menu according to 1st selection */
244 /*-------------------------------------------------*/
251 if (areawin
->selects
== 0) {
252 setallstylemarks(areawin
->style
);
253 setcolormark(areawin
->color
);
254 setdefaultfontmarks();
259 for (mselect
= areawin
->selectlist
; mselect
< areawin
->selectlist
+
260 areawin
->selects
; mselect
++) {
261 setcolormark(SELTOCOLOR(mselect
));
262 setparammarks(SELTOGENERIC(mselect
));
263 switch(SELECTTYPE(mselect
)) {
265 setallstylemarks(SELTOARC(mselect
)->style
);
268 setallstylemarks(SELTOPOLY(mselect
)->style
);
271 setallstylemarks(SELTOSPLINE(mselect
)->style
);
274 setallstylemarks(SELTOPATH(mselect
)->style
);
277 mlabel
= SELTOLABEL(mselect
);
278 setfontmarks(mlabel
->string
->data
.font
, mlabel
->anchor
);
284 /*-------------------------------------*/
285 /* Test of point being inside of a box */
286 /*-------------------------------------*/
288 int test_insideness(int tx
, int ty
, XPoint
*boxpoints
)
294 for (i
= 0; i
< 4; i
++) {
296 pt2
= boxpoints
+ ((i
+ 1) % 4);
297 stdir
= (pt2
->x
- pt1
->x
) * (ty
- pt1
->y
)
298 - (pt2
->y
- pt1
->y
) * (tx
- pt1
->x
);
299 stval
+= sign(stdir
);
301 return (abs(stval
) == 4) ? 1 : 0;
304 /*--------------------------------------------*/
305 /* Search for selection among path components */
306 /*--------------------------------------------*/
308 #define RANGE_NARROW 11.5
309 #define RANGE_WIDE 50
311 Boolean
pathselect(genericptr
*curgen
, short class, float range
)
313 /*----------------------------------------------------------------------*/
314 /* wirelim is the distance, in user-space units, at which an element is */
315 /* considered for selection. */
317 /* wirelim = A + B / (scale + C) */
319 /* where A = minimum possible distance (expands range at close scale) */
320 /* C = minimum possible scale (contract range at far scale) */
321 /* B makes wirelim approx. 25 at default scale of 0.5, which */
322 /* is an empirical result. */
323 /*----------------------------------------------------------------------*/
325 float wirelim
= 2 + range
/ (areawin
->vscale
+ 0.05);
326 long sqrwirelim
= (int)(wirelim
* wirelim
);
329 Boolean selected
= False
;
331 class &= areawin
->filter
; /* apply the selection filter */
333 if ((*curgen
)->type
== (class & ARC
)) {
335 /* look among the arcs */
337 fpointlist currentpt
;
340 nearpt
[2].x
= nearpt
[0].x
= (short)(TOARC(curgen
)->points
[0].x
);
341 nearpt
[2].y
= nearpt
[0].y
= (short)(TOARC(curgen
)->points
[0].y
);
342 for (currentpt
= TOARC(curgen
)->points
+ 1; currentpt
< TOARC(curgen
)->points
343 + TOARC(curgen
)->number
; currentpt
++) {
344 nearpt
[1].x
= nearpt
[0].x
;
345 nearpt
[1].y
= nearpt
[0].y
;
346 nearpt
[0].x
= (short)(currentpt
->x
);
347 nearpt
[0].y
= (short)(currentpt
->y
);
348 newdist
= finddist(&nearpt
[0], &nearpt
[1], &areawin
->save
);
349 if (newdist
<= sqrwirelim
) break;
351 if ((!(TOARC(curgen
)->style
& UNCLOSED
)) && (newdist
> sqrwirelim
))
352 newdist
= finddist(&nearpt
[0], &nearpt
[2], &areawin
->save
);
354 if (newdist
<= sqrwirelim
) selected
= True
;
357 else if ((*curgen
)->type
== (class & SPLINE
)) {
359 /* look among the splines --- look at polygon representation */
361 fpointlist currentpt
;
364 nearpt
[0].x
= (short)(TOSPLINE(curgen
)->points
[0].x
);
365 nearpt
[0].y
= (short)(TOSPLINE(curgen
)->points
[0].y
);
366 newdist
= finddist(&(TOSPLINE(curgen
)->ctrl
[0]), &(nearpt
[0]),
368 if (newdist
> sqrwirelim
) {
369 for (currentpt
= TOSPLINE(curgen
)->points
; currentpt
<
370 TOSPLINE(curgen
)->points
+ INTSEGS
; currentpt
++) {
371 nearpt
[1].x
= nearpt
[0].x
;
372 nearpt
[1].y
= nearpt
[0].y
;
373 nearpt
[0].x
= (short)(currentpt
->x
);
374 nearpt
[0].y
= (short)(currentpt
->y
);
375 newdist
= finddist(&nearpt
[0], &nearpt
[1], &areawin
->save
);
376 if (newdist
<= sqrwirelim
) break;
378 if (newdist
> sqrwirelim
) {
379 newdist
= finddist(&nearpt
[0], &(TOSPLINE(curgen
)->ctrl
[3]),
381 if ((!(TOSPLINE(curgen
)->style
& UNCLOSED
)) && (newdist
> sqrwirelim
))
382 newdist
= finddist(&(TOSPLINE(curgen
)->ctrl
[0]),
383 &(TOSPLINE(curgen
)->ctrl
[3]), &areawin
->save
);
387 if (newdist
<= sqrwirelim
) selected
= True
;
390 else if ((*curgen
)->type
== (class & POLYGON
)) {
392 /* finally, look among the polygons */
396 for (currentpt
= TOPOLY(curgen
)->points
; currentpt
< TOPOLY(curgen
)
397 ->points
+ TOPOLY(curgen
)->number
- 1; currentpt
++) {
398 newdist
= finddist(currentpt
, currentpt
+ 1, &areawin
->save
);
399 if (newdist
<= sqrwirelim
) break;
401 if ((!(TOPOLY(curgen
)->style
& UNCLOSED
)) && (newdist
> sqrwirelim
))
402 newdist
= finddist(currentpt
, TOPOLY(curgen
)->points
,
405 if (newdist
<= sqrwirelim
) selected
= True
;
410 /*------------------------------------------------------*/
411 /* Check to see if any selection has registered cycles */
412 /*------------------------------------------------------*/
414 Boolean
checkforcycles(short *selectlist
, int selects
)
420 for (ssel
= selectlist
; ssel
< selectlist
+ selects
; ssel
++) {
421 pgen
= SELTOGENERIC(ssel
);
424 cycptr
= ((polyptr
)pgen
)->cycle
;
427 cycptr
= ((arcptr
)pgen
)->cycle
;
430 cycptr
= ((splineptr
)pgen
)->cycle
;
433 cycptr
= ((labelptr
)pgen
)->cycle
;
437 if (cycptr
->number
!= -1)
443 /*--------------------------------------------------------------*/
444 /* Copy a cycle selection list from one element to another */
445 /*--------------------------------------------------------------*/
447 void copycycles(pointselect
**new, pointselect
**old
)
457 for (pptr
= *old
; !(pptr
->flags
& LASTENTRY
); pptr
++, cycles
++);
459 *new = (pointselect
*)malloc(cycles
* sizeof(pointselect
));
460 memcpy(*new, *old
, cycles
* sizeof(pointselect
));
463 /*--------------------------------------------------------------*/
464 /* Create a selection record of selected points in an element. */
465 /* If a record already exists, and "cycle" is not already in */
466 /* the list, add it. */
467 /* "flags" may be set to EDITX or EDITY. If "flags" is zero, */
468 /* then flags = EDITX | EDITY is assumed. */
469 /*--------------------------------------------------------------*/
471 pointselect
*addcycle(genericptr
*pgen
, short cycle
, u_char flags
)
477 pointselect
*pptr
, **cycptr
;
480 switch((*pgen
)->type
) {
482 ppoly
= TOPOLY(pgen
);
483 cycptr
= &ppoly
->cycle
;
487 cycptr
= &parc
->cycle
;
490 pspline
= TOSPLINE(pgen
);
491 cycptr
= &pspline
->cycle
;
494 plabel
= TOLABEL(pgen
);
495 cycptr
= &plabel
->cycle
;
499 switch((*pgen
)->type
) {
503 case LABEL
: // To-do: Handle labels separately
505 if (*cycptr
== NULL
) {
506 *cycptr
= (pointselect
*)malloc(sizeof(pointselect
));
508 pptr
->number
= cycle
;
509 pptr
->flags
= (flags
== 0) ? EDITX
| EDITY
: flags
;
510 pptr
->flags
|= LASTENTRY
;
513 for (pptr
= *cycptr
; !(pptr
->flags
& LASTENTRY
); pptr
++, cycles
++) {
514 if (pptr
->number
== cycle
)
516 pptr
->flags
&= ~LASTENTRY
;
518 if (pptr
->number
!= cycle
) {
519 pptr
->flags
&= ~LASTENTRY
;
520 *cycptr
= (pointselect
*)realloc(*cycptr
,
521 (cycles
+ 2) * sizeof(pointselect
));
522 pptr
= *cycptr
+ cycles
+ 1;
523 pptr
->number
= cycle
;
524 pptr
->flags
= (flags
== 0) ? EDITX
| EDITY
: flags
;
525 pptr
->flags
|= LASTENTRY
;
528 pptr
->flags
|= (flags
== 0) ? EDITX
| EDITY
: flags
;
536 /*--------------------------------------------------------------*/
537 /* If we edit the position of a control point, and the global */
538 /* pathedit mode is set to TANGENTS, then we track the angle of */
539 /* the adjoining curve, if there is one, by settings its cycle */
540 /* flags to ANTIXY. */
541 /*--------------------------------------------------------------*/
543 void addanticycle(pathptr thispath
, splineptr thisspline
, short cycle
)
545 genericptr
*ggen
, *rgen
;
546 splineptr otherspline
;
548 if (areawin
->pathedit
== TANGENTS
) {
549 for (ggen
= thispath
->plist
; ggen
< thispath
->plist
+ thispath
->parts
;
551 if (*ggen
== (genericptr
)thisspline
) break;
553 if (*ggen
!= (genericptr
)thisspline
) return; /* Something went wrong */
556 if (ggen
> thispath
->plist
) {
557 if (ELEMENTTYPE(*(ggen
- 1)) == SPLINE
) {
558 addcycle(ggen
- 1, 2, ANTIXY
);
561 else if (!(thispath
->style
& UNCLOSED
)) {
562 rgen
= thispath
->plist
+ thispath
->parts
- 1;
563 if (ELEMENTTYPE(*rgen
) == SPLINE
) {
564 otherspline
= TOSPLINE(rgen
);
565 if (thisspline
->ctrl
[0].x
== otherspline
->ctrl
[3].x
&&
566 thisspline
->ctrl
[0].y
== otherspline
->ctrl
[3].y
)
567 addcycle(rgen
, 2, ANTIXY
);
571 else if (cycle
== 2) { /* cycle should be only 1 or 2 */
572 if (ggen
< thispath
->plist
+ thispath
->parts
- 1) {
573 if (ELEMENTTYPE(*(ggen
+ 1)) == SPLINE
) {
574 addcycle(ggen
+ 1, 1, ANTIXY
);
577 else if (!(thispath
->style
& UNCLOSED
)) {
578 rgen
= thispath
->plist
;
579 if (ELEMENTTYPE(*rgen
) == SPLINE
) {
580 otherspline
= TOSPLINE(rgen
);
581 if (thisspline
->ctrl
[3].x
== otherspline
->ctrl
[0].x
&&
582 thisspline
->ctrl
[3].y
== otherspline
->ctrl
[0].y
)
583 addcycle(rgen
, 1, ANTIXY
);
590 /*--------------------------------------------------------------*/
591 /* Find the cycle numbered "cycle", and mark it as the */
592 /* reference point. */
593 /*--------------------------------------------------------------*/
595 void makerefcycle(pointselect
*cycptr
, short cycle
)
597 pointselect
*pptr
, *sptr
;
599 for (pptr
= cycptr
;; pptr
++) {
600 if (pptr
->flags
& REFERENCE
) {
601 pptr
->flags
&= ~REFERENCE
;
604 if (pptr
->flags
& LASTENTRY
) break;
607 for (sptr
= cycptr
;; sptr
++) {
608 if (sptr
->number
== cycle
) {
609 sptr
->flags
|= REFERENCE
;
612 if (sptr
->flags
& LASTENTRY
) break;
615 /* If something went wrong, revert to the original reference */
617 if (!(sptr
->flags
& REFERENCE
)) {
618 pptr
->flags
|= REFERENCE
;
622 /* Original routine, used 1st entry as reference (deprecated) */
624 void makefirstcycle(pointselect
*cycptr
, short cycle
)
626 pointselect
*pptr
, tmpp
;
628 for (pptr
= cycptr
;; pptr
++) {
629 if (pptr
->number
== cycle
) {
630 /* swap with first entry */
634 if (cycptr
->flags
& LASTENTRY
) {
635 cycptr
->flags
&= ~LASTENTRY
;
636 pptr
->flags
|= LASTENTRY
;
640 if (pptr
->flags
& LASTENTRY
) break;
644 /*------------------------------------------------------------------------------*/
645 /* Advance a cycle (point) selection from value "cycle" to value "newvalue" */
646 /* If "newvalue" is < 0 then remove the cycle. */
648 /* If there is only one cycle point on the element, then advance its point */
649 /* number. If there are multiple points on the element, then change the */
650 /* reference point by moving the last item in the list to the front. */
651 /*------------------------------------------------------------------------------*/
653 void advancecycle(genericptr
*pgen
, short newvalue
)
659 pointselect
*pptr
, *endptr
, *fcycle
, **cycptr
, tmpcyc
;
667 switch((*pgen
)->type
) {
669 ppoly
= TOPOLY(pgen
);
670 cycptr
= &ppoly
->cycle
;
674 cycptr
= &parc
->cycle
;
677 pspline
= TOSPLINE(pgen
);
678 cycptr
= &pspline
->cycle
;
681 plabel
= TOLABEL(pgen
);
682 cycptr
= &plabel
->cycle
;
685 if (*cycptr
== NULL
) return;
687 /* Remove any cycles that have only X or Y flags set. */
688 /* "Remove" them by shuffling them to the end of the list, */
689 /* and marking the one in front as the last entry. */
691 for (endptr
= *cycptr
; !(endptr
->flags
& LASTENTRY
); endptr
++);
693 while (pptr
< endptr
) {
694 if ((pptr
->flags
& (EDITX
| EDITY
)) != (EDITX
| EDITY
)) {
698 pptr
->flags
&= ~LASTENTRY
;
701 endptr
->flags
|= LASTENTRY
;
707 if (pptr
->flags
& LASTENTRY
) {
708 if ((pptr
->flags
& (EDITX
| EDITY
)) != (EDITX
| EDITY
)) {
709 pptr
->flags
&= ~LASTENTRY
;
712 endptr
->flags
|= LASTENTRY
;
716 /* Now advance the cycle */
719 if (pptr
->flags
& LASTENTRY
) {
720 pptr
->number
= newvalue
;
724 for (pptr
= fcycle
+ 1;; pptr
++) {
725 if (pptr
->flags
& (EDITX
| EDITY
))
727 if (pptr
->flags
& LASTENTRY
) break;
729 makerefcycle(*cycptr
, fcycle
->number
);
733 /*--------------------------------------*/
734 /* Remove a cycle (point) selection */
735 /*--------------------------------------*/
737 void removecycle(genericptr
*pgen
)
744 pointselect
*pptr
, **cycptr
= NULL
;
747 switch((*pgen
)->type
) {
749 ppoly
= TOPOLY(pgen
);
750 cycptr
= &ppoly
->cycle
;
754 cycptr
= &parc
->cycle
;
757 pspline
= TOSPLINE(pgen
);
758 cycptr
= &pspline
->cycle
;
761 plabel
= TOLABEL(pgen
);
762 cycptr
= &plabel
->cycle
;
765 ppath
= TOPATH(pgen
);
766 for (pathgen
= ppath
->plist
; pathgen
< ppath
->plist
+ ppath
->parts
;
768 removecycle(pathgen
);
771 if (cycptr
== NULL
) return;
772 if (*cycptr
== NULL
) return;
777 /*--------------------------------------*/
778 /* Remove cycles from all parts of a */
779 /* path other than the one passed */
780 /*--------------------------------------*/
782 void removeothercycles(pathptr ppath
, genericptr pathpart
)
785 for (pathgen
= ppath
->plist
; pathgen
< ppath
->plist
+ ppath
->parts
;
787 if (*pathgen
!= pathpart
)
788 removecycle(pathgen
);
791 /*--------------------------------------*/
792 /* Select one of the elements on-screen */
793 /*--------------------------------------*/
795 selection
*genselectelement(short class, u_char mode
, objectptr selobj
,
798 selection
*rselect
= NULL
;
799 /* short *newselect; (jdk) */
803 float range
= RANGE_NARROW
;
805 if (mode
== MODE_RECURSE_WIDE
)
808 /* Loop through all elements found underneath the cursor */
810 for (curgen
= selobj
->plist
; curgen
< selobj
->plist
+ selobj
->parts
; curgen
++) {
814 /* Check among polygons, arcs, and curves */
816 if (((*curgen
)->type
== (class & POLYGON
)) ||
817 ((*curgen
)->type
== (class & ARC
)) ||
818 ((*curgen
)->type
== (class & SPLINE
))) {
819 selected
= pathselect(curgen
, class, range
);
822 else if ((*curgen
)->type
== (class & LABEL
)) {
824 /* Look among the labels */
826 labelptr curlab
= TOLABEL(curgen
);
828 /* Don't select temporary labels from schematic capture system */
829 if (curlab
->string
->type
!= FONT_NAME
) continue;
831 labelbbox(curlab
, newboxpts
, selinst
);
833 /* Need to check for zero-size boxes or test_insideness() */
834 /* fails. Zero-size boxes happen when labels are parameters */
835 /* set to a null string. */
837 if ((newboxpts
[0].x
!= newboxpts
[1].x
) || (newboxpts
[0].y
!=
840 /* check for point inside bounding box, as for objects */
842 selected
= test_insideness(areawin
->save
.x
, areawin
->save
.y
,
844 if (selected
) areawin
->textpos
= areawin
->textend
= 0;
848 else if ((*curgen
)->type
== (class & GRAPHIC
)) {
850 /* Look among the graphic images */
852 graphicptr curg
= TOGRAPHIC(curgen
);
853 graphicbbox(curg
, newboxpts
);
855 /* check for point inside bounding box, as for objects */
856 selected
= test_insideness(areawin
->save
.x
, areawin
->save
.y
,
860 else if ((*curgen
)->type
== (class & PATH
)) {
862 /* Check among the paths */
866 /* Accept path if any subcomponent of the path is accepted */
868 for (pathp
= TOPATH(curgen
)->plist
; pathp
< TOPATH(curgen
)->plist
+
869 TOPATH(curgen
)->parts
; pathp
++)
870 if (pathselect(pathp
, SPLINE
|ARC
|POLYGON
, range
)) {
876 else if ((*curgen
)->type
== (class & OBJINST
)) {
878 objinstbbox(TOOBJINST(curgen
), newboxpts
, range
);
880 /* Look for an intersect of the boundingbox and pointer position. */
881 /* This is a simple matter of rotating the pointer position with */
882 /* respect to the origin of the bounding box segment, as if the */
883 /* segment were rotated to 0 degrees. The sign of the resulting */
884 /* point's y-position is the same for all bbox segments if the */
885 /* pointer position is inside the bounding box. */
887 selected
= test_insideness(areawin
->save
.x
, areawin
->save
.y
,
891 /* Add this object to the list of things found under the cursor */
894 if (rselect
== NULL
) {
895 rselect
= (selection
*)malloc(sizeof(selection
));
896 rselect
->selectlist
= (short *)malloc(sizeof(short));
897 rselect
->selects
= 0;
898 rselect
->thisinst
= selinst
;
899 rselect
->next
= NULL
;
902 rselect
->selectlist
= (short *)realloc(rselect
->selectlist
,
903 (rselect
->selects
+ 1) * sizeof(short));
905 *(rselect
->selectlist
+ rselect
->selects
) = (short)(curgen
-
913 /*----------------------------------------------------------------*/
914 /* select arc, curve, and polygon objects from a defined box area */
915 /*----------------------------------------------------------------*/
917 Boolean
areaelement(genericptr
*curgen
, XPoint
*boxpts
, Boolean is_path
, short level
)
923 switch(ELEMENTTYPE(*curgen
)) {
926 /* check center of arcs */
928 selected
= test_insideness(TOARC(curgen
)->position
.x
,
929 TOARC(curgen
)->position
.y
, boxpts
);
933 /* check each point of the polygons */
937 for (currentpt
= TOPOLY(curgen
)->points
; currentpt
<
938 TOPOLY(curgen
)->points
+ TOPOLY(curgen
)->number
;
939 currentpt
++, cycle
++) {
940 if (test_insideness(currentpt
->x
, currentpt
->y
, boxpts
)) {
942 if (level
== 0) addcycle(curgen
, cycle
, 0);
948 /* check each control point of the spline */
951 if (test_insideness(TOSPLINE(curgen
)->ctrl
[0].x
,
952 TOSPLINE(curgen
)->ctrl
[0].y
, boxpts
)) {
954 if (level
== 0) addcycle(curgen
, 0, 0);
957 if (test_insideness(TOSPLINE(curgen
)->ctrl
[3].x
,
958 TOSPLINE(curgen
)->ctrl
[3].y
, boxpts
)) {
960 if (level
== 0) addcycle(curgen
, 3, 0);
967 /*--------------------------------------------*/
968 /* select all objects from a defined box area */
969 /*--------------------------------------------*/
971 Boolean
selectarea(objectptr selobj
, XPoint
*boxpts
, short level
)
974 genericptr
*curgen
, *pathgen
;
977 int locpos
, cx
, cy
, hwidth
, hheight
;
981 if (selobj
== topobject
) {
982 areawin
->textpos
= areawin
->textend
= 0;
985 for (curgen
= selobj
->plist
; curgen
< selobj
->plist
+ selobj
->parts
; curgen
++) {
987 /* apply the selection filter */
988 if (!((*curgen
)->type
& areawin
->filter
)) continue;
990 switch(ELEMENTTYPE(*curgen
)) {
992 curinst
= TOOBJINST(curgen
);
994 /* An object instance is selected if any part of it is */
995 /* selected on a recursive area search. */
997 InvTransformPoints(boxpts
, newboxpts
, 4, curinst
->position
,
998 curinst
->scale
, curinst
->rotation
);
999 selected
= selectarea(curinst
->thisobject
, newboxpts
, level
+ 1);
1003 /* check for graphic image center point inside area box */
1004 selected
= test_insideness(TOGRAPHIC(curgen
)->position
.x
,
1005 TOGRAPHIC(curgen
)->position
.y
, boxpts
);
1010 labelptr slab
= TOLABEL(curgen
);
1011 short j
, state
, isect
, tmpl1
, tmpl2
;
1014 TextLinesInfo tlinfo
;
1018 /* Ignore temporary labels created by the netlist generator */
1019 if (slab
->string
->type
!= FONT_NAME
) break;
1021 /* Ignore info and pin labels that are not on the top level */
1022 if ((selobj
!= topobject
) && (slab
->pin
!= False
)) break;
1024 /* translate select box into the coordinate system of the label */
1025 InvTransformPoints(boxpts
, newboxpts
, 4, slab
->position
,
1026 slab
->scale
, slab
->rotation
);
1029 for (j
= 0; j
< 4; j
++)
1030 pinadjust(slab
->anchor
, &(newboxpts
[j
].x
),
1031 &(newboxpts
[j
].y
), -1);
1035 tlinfo
.tbreak
= NULL
;
1036 tlinfo
.padding
= NULL
;
1038 tmpext
= ULength(slab
, areawin
->topinstance
, &tlinfo
);
1039 adj
.x
= (slab
->anchor
& NOTLEFT
? (slab
->anchor
& RIGHT
?
1040 tmpext
.maxwidth
: tmpext
.maxwidth
>> 1) : 0);
1041 adj
.y
= (slab
->anchor
& NOTBOTTOM
? (slab
->anchor
& TOP
?
1042 tmpext
.ascent
: (tmpext
.ascent
+ tmpext
.base
) >> 1)
1045 /* Label selection: For each character in the label string, */
1046 /* do an insideness test with the select box. */
1049 for (j
= 0; j
< stringlength(slab
->string
, True
, areawin
->topinstance
); j
++) {
1050 strptr
= findstringpart(j
, &locpos
, slab
->string
, areawin
->topinstance
);
1051 if (locpos
< 0) continue; /* only look at printable characters */
1052 if (strptr
->type
== RETURN
) tmpl2
= 0;
1054 tlinfo
.dostop
= j
+ 1;
1055 tmpext
= ULength(slab
, areawin
->topinstance
, &tlinfo
);
1056 tmpl2
= tmpext
.maxwidth
;
1057 if ((slab
->anchor
& JUSTIFYRIGHT
) && tlinfo
.padding
)
1058 padding
= (int)tlinfo
.padding
[tlinfo
.line
];
1059 else if ((slab
->anchor
& TEXTCENTERED
) && tlinfo
.padding
)
1060 padding
= (int)(0.5 * tlinfo
.padding
[tlinfo
.line
]);
1063 isect
= test_insideness(((tmpl1
+ tmpl2
) >> 1) - adj
.x
+ padding
,
1064 (tmpext
.base
+ (BASELINE
>> 1)) - adj
.y
, newboxpts
);
1066 /* tiny state machine */
1071 areawin
->textend
= j
;
1072 if ((areawin
->textend
> 1) && strptr
->type
!= TEXT_STRING
)
1078 areawin
->textpos
= j
;
1084 if (state
== 1) areawin
->textpos
= j
; /* selection goes to end of string */
1086 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
1088 /* If a label happens to be empty (can happen in the case of */
1089 /* a label with parameters that are all empty strings), then */
1090 /* check if the bounding box surrounds the label position. */
1092 else if (tmpext
.width
== 0) {
1093 isect
= test_insideness(0, 0, newboxpts
);
1096 areawin
->textend
= 1;
1103 /* check position point of each subpart of the path */
1106 for (pathgen
= TOPATH(curgen
)->plist
; pathgen
< TOPATH(curgen
)->plist
1107 + TOPATH(curgen
)->parts
; pathgen
++) {
1108 if (areaelement(pathgen
, boxpts
, True
, level
)) selected
= True
;
1113 selected
= areaelement(curgen
, boxpts
, False
, level
);
1117 /* on recursive searches, return as soon as we find something */
1119 if ((selobj
!= topobject
) && selected
) return TRUE
;
1121 /* check if this part has already been selected */
1124 for (newselect
= areawin
->selectlist
; newselect
<
1125 areawin
->selectlist
+ areawin
->selects
; newselect
++)
1126 if (*newselect
== (short)(curgen
- topobject
->plist
))
1129 /* add to list of selections */
1132 newselect
= allocselect();
1133 *newselect
= (short)(curgen
- topobject
->plist
);
1136 if (selobj
!= topobject
) return FALSE
;
1139 /* if none or > 1 label has been selected, cancel any textpos placement */
1141 if (!checkselect(LABEL
) || areawin
->selects
!= 1 ||
1142 (areawin
->selects
== 1 && SELECTTYPE(areawin
->selectlist
) != LABEL
)) {
1143 areawin
->textpos
= areawin
->textend
= 0;
1146 /* Register the selection as an undo event */
1147 register_for_undo(XCF_Select
, UNDO_DONE
, areawin
->topinstance
,
1148 areawin
->selectlist
, areawin
->selects
);
1150 /* Drawing of selected objects will take place when drawarea() is */
1151 /* executed after the button release. */
1154 if (xobjs
.suspend
< 0)
1155 XcInternalTagCall(xcinterp
, 2, "select", "here");
1161 /*------------------------*/
1162 /* start deselection mode */
1163 /*------------------------*/
1165 void startdesel(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
1167 if (eventmode
== NORMAL_MODE
) {
1168 if (areawin
->selects
== 0)
1169 Wprintf("Nothing to deselect!");
1170 else if (areawin
->selects
== 1)
1175 /*------------------------------------------------------*/
1176 /* Redraw all the selected objects in the select color. */
1177 /*------------------------------------------------------*/
1179 void draw_all_selected()
1183 if (areawin
->hierstack
!= NULL
) return;
1185 for (j
= 0; j
< areawin
->selects
; j
++)
1186 gendrawselected(areawin
->selectlist
+ j
, topobject
, areawin
->topinstance
);
1189 /*---------------------------------------------------------*/
1190 /* Redraw all the selected objects in their normal colors. */
1191 /*---------------------------------------------------------*/
1193 void draw_normal_selected(objectptr thisobj
, objinstptr thisinst
)
1197 if (areawin
->selects
== 0) return;
1198 else if (areawin
->hierstack
!= NULL
) return;
1200 saveselects
= areawin
->selects
;
1202 areawin
->selects
= 0;
1203 drawarea(NULL
, NULL
, NULL
);
1204 areawin
->selects
= saveselects
;
1207 /*----------------------------------------------------------------------*/
1208 /* Free a selection linked-list structure */
1209 /* (don't confuse with freeselects) */
1210 /*----------------------------------------------------------------------*/
1212 static void freeselection(selection
*rselect
)
1214 selection
*nextselect
;
1216 while (rselect
!= NULL
) {
1217 nextselect
= rselect
->next
;
1218 free(rselect
->selectlist
);
1220 rselect
= nextselect
;
1224 /*--------------------------------------------------------------*/
1225 /* Free memory from the previous selection list, copy the */
1226 /* current selection list to the previous selection list, and */
1227 /* zero out the current selection list. */
1228 /* Normally one would use clearselects(); use freeselects() */
1229 /* only if the menu/toolbars are going to be updated later in */
1231 /*--------------------------------------------------------------*/
1235 if (areawin
->selects
> 0) {
1236 free(areawin
->selectlist
);
1237 areawin
->redraw_needed
=True
;
1239 areawin
->selects
= 0;
1240 free_stack(&areawin
->hierstack
);
1243 /*--------------------------------------------------------------*/
1244 /* Free memory from the selection list and set menu/toolbar */
1245 /* items back to default values. */
1246 /*--------------------------------------------------------------*/
1248 void clearselects_noundo()
1250 if (areawin
->selects
> 0) {
1253 if (xobjs
.suspend
< 0) {
1254 setallstylemarks(areawin
->style
);
1255 setcolormark(areawin
->color
);
1256 setdefaultfontmarks();
1257 setparammarks(NULL
);
1261 if (xobjs
.suspend
< 0)
1262 XcInternalTagCall(xcinterp
, 2, "unselect", "all");
1267 /*--------------------------------------------------------------*/
1268 /* Same as above, but registers an undo event. */
1269 /*--------------------------------------------------------------*/
1273 if (areawin
->selects
> 0) {
1274 register_for_undo(XCF_Select
, UNDO_DONE
, areawin
->topinstance
,
1276 clearselects_noundo();
1280 /*--------------------------------------------------------------*/
1281 /* Unselect all the selected elements and free memory from the */
1282 /* selection list. */
1283 /*--------------------------------------------------------------*/
1287 if (xobjs
.suspend
< 0)
1288 draw_normal_selected(topobject
, areawin
->topinstance
);
1292 /*----------------------------------------------------------------------*/
1293 /* Select the nearest element, searching the hierarchy if necessary. */
1294 /* Return an pushlist pointer to a linked list containing the */
1295 /* hierarchy of objects, with the topmost pushlist also containing a */
1296 /* pointer to the polygon found. */
1297 /* Allocates memory for the returned linked list which must be freed by */
1298 /* the calling routine. */
1299 /*----------------------------------------------------------------------*/
1301 selection
*recurselect(short class, u_char mode
, pushlistptr
*seltop
)
1303 selection
*rselect
, *rcheck
, *lastselect
;
1308 XPoint savesave
, tmppt
;
1311 u_char locmode
= (mode
== MODE_CONNECT
) ? UNDO_DONE
: mode
;
1312 u_char recmode
= (mode
!= MODE_CONNECT
) ? MODE_RECURSE_WIDE
: MODE_RECURSE_NARROW
;
1314 if (*seltop
== NULL
) {
1315 Fprintf(stderr
, "Error: recurselect called with NULL pushlist pointer\n");
1319 selinst
= (*seltop
)->thisinst
;
1320 selobj
= selinst
->thisobject
;
1322 class &= areawin
->filter
; /* apply the selection filter */
1325 rselect
= genselectelement(class, locmode
, selobj
, selinst
);
1326 if (rselect
== NULL
) return NULL
;
1328 for (i
= 0; i
< rselect
->selects
; i
++) {
1329 rgen
= *(selobj
->plist
+ (*(rselect
->selectlist
+ i
)));
1330 if (rgen
->type
== OBJINST
) {
1331 selinst
= TOOBJINST(selobj
->plist
+ (*(rselect
->selectlist
+ i
)));
1333 /* Link hierarchy information to the pushlist linked list */
1334 selnew
= (pushlistptr
)malloc(sizeof(pushlist
));
1335 selnew
->thisinst
= selinst
;
1336 selnew
->next
= NULL
;
1337 (*seltop
)->next
= selnew
;
1339 /* Translate areawin->save into object's own coordinate system */
1340 savesave
.x
= areawin
->save
.x
;
1341 savesave
.y
= areawin
->save
.y
;
1342 InvTransformPoints(&areawin
->save
, &tmppt
, 1, selinst
->position
,
1343 selinst
->scale
, selinst
->rotation
);
1344 areawin
->save
.x
= tmppt
.x
;
1345 areawin
->save
.y
= tmppt
.y
;
1346 /* Fprintf(stdout, "objinst %s found in object %s; searching recursively\n",
1347 selinst->thisobject->name, selobj->name); */
1348 /* Fprintf(stdout, "cursor position originally (%d, %d); "
1349 "in new object is (%d, %d)\n",
1350 savesave.x, savesave.y,
1351 areawin->save.x, areawin->save.y); */
1353 rcheck
= recurselect(ALL_TYPES
, recmode
, &selnew
);
1354 areawin
->save
.x
= savesave
.x
;
1355 areawin
->save
.y
= savesave
.y
;
1357 /* If rgen is NULL, remove selected object from the list, and */
1358 /* remove the last entry from the pushlist stack. */
1360 if (rcheck
== NULL
) {
1361 *(rselect
->selectlist
+ i
) = -1;
1363 (*seltop
)->next
= NULL
;
1364 if (selnew
->next
!= NULL
)
1365 Fprintf(stderr
, "Error: pushstack was freed, but was not empty!\n");
1369 for (lastselect
= rselect
; lastselect
->next
!= NULL
; lastselect
=
1371 lastselect
->next
= rcheck
;
1376 /* Modify the selection list */
1378 for (i
= 0, j
= 0; i
< rselect
->selects
; i
++) {
1379 if (*(rselect
->selectlist
+ i
) >= 0) {
1381 *(rselect
->selectlist
+ j
) = *(rselect
->selectlist
+ i
);
1385 rselect
->selects
-= unselects
;
1386 if (rselect
->selects
== 0) {
1387 freeselection(rselect
);
1393 /*----------------------------------*/
1394 /* Start drawing a select area box. */
1395 /*----------------------------------*/
1399 eventmode
= SELAREA_MODE
;
1400 areawin
->origin
.x
= areawin
->save
.x
;
1401 areawin
->origin
.y
= areawin
->save
.y
;
1402 selarea_mode_draw(xcDRAW_INIT
, NULL
);
1405 Tk_CreateEventHandler(areawin
->area
, ButtonMotionMask
|
1406 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
,
1409 xcAddEventHandler(areawin
->area
, ButtonMotionMask
|
1410 PointerMotionMask
, False
, (xcEventHandler
)xlib_drag
,
1416 /*-------------------------*/
1417 /* Track a select area box */
1418 /*-------------------------*/
1423 /* u_int nullui; (jdk) */
1425 newpos
= UGetCursorPos();
1426 if (newpos
.x
== areawin
->save
.x
&& newpos
.y
== areawin
->save
.y
) return;
1428 areawin
->save
.x
= newpos
.x
;
1429 areawin
->save
.y
= newpos
.y
;
1430 selarea_mode_draw(xcDRAW_EDIT
, NULL
);
1433 /*----------------------*/
1434 /* Track a rescale box */
1435 /*----------------------*/
1441 newpos
= UGetCursorPos();
1442 if (newpos
.x
== areawin
->save
.x
&& newpos
.y
== areawin
->save
.y
) return;
1444 areawin
->save
.x
= newpos
.x
;
1445 areawin
->save
.y
= newpos
.y
;
1446 rescale_mode_draw(xcDRAW_EDIT
, NULL
);
1449 /*----------------------------------------------------------------------*/
1450 /* Polygon distance comparison function for qsort */
1451 /*----------------------------------------------------------------------*/
1453 int dcompare(const void *a
, const void *b
)
1456 genericptr agen
, bgen
;
1457 short j
, k
, adist
, bdist
;
1459 cpt
.x
= areawin
->save
.x
;
1460 cpt
.y
= areawin
->save
.y
;
1465 agen
= *(topobject
->plist
+ j
);
1466 bgen
= *(topobject
->plist
+ k
);
1468 if (agen
->type
!= POLYGON
|| bgen
->type
!= POLYGON
) return 0;
1470 adist
= closedistance((polyptr
)agen
, &cpt
);
1471 bdist
= closedistance((polyptr
)bgen
, &cpt
);
1473 if (adist
== bdist
) return 0;
1474 return (adist
< bdist
) ? 1 : -1;
1477 /*----------------------------------------------------------------------*/
1478 /* Compare two selection linked lists */
1479 /*----------------------------------------------------------------------*/
1481 Boolean
compareselection(selection
*sa
, selection
*sb
)
1486 if ((sa
== NULL
) || (sb
== NULL
)) return False
;
1487 if (sa
->selects
!= sb
->selects
) return False
;
1489 for (i
= 0; i
< sa
->selects
; i
++) {
1490 n1
= *(sa
->selectlist
+ i
);
1491 for (j
= 0; j
< sb
->selects
; j
++) {
1492 n2
= *(sb
->selectlist
+ j
);
1499 return (match
== sa
->selects
) ? True
: False
;
1502 /*----------------------------------------------------------------------*/
1503 /* Add pin cycles connected to selected labels */
1504 /*----------------------------------------------------------------------*/
1506 void label_connect_cycles(labelptr thislab
)
1509 Boolean is_selected
;
1512 short *stest
, cycle
;
1514 if (thislab
->pin
== LOCAL
|| thislab
->pin
== GLOBAL
) {
1515 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
1516 topobject
->parts
; pgen
++) {
1517 /* Ignore any wires that are already selected */
1518 is_selected
= FALSE
;
1519 for (stest
= areawin
->selectlist
; stest
< areawin
->selectlist
+
1520 areawin
->selects
; stest
++) {
1521 if (SELTOGENERIC(stest
) == *pgen
) {
1526 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
1527 cpoly
= TOPOLY(pgen
);
1530 for (testpt
= cpoly
->points
; testpt
< cpoly
->points
+
1531 cpoly
->number
; testpt
++) {
1532 if (testpt
->x
== thislab
->position
.x
1533 && testpt
->y
== thislab
->position
.y
) {
1534 addcycle(pgen
, cycle
, 0);
1542 /* Make sure that this polygon's cycle is not set! */
1550 /*----------------------------------------------------------------------*/
1551 /* Add pin cycles connected to selected instances */
1552 /*----------------------------------------------------------------------*/
1554 void inst_connect_cycles(objinstptr thisinst
)
1556 genericptr
*ggen
, *pgen
;
1557 Boolean is_selected
;
1558 XPoint refpoint
, *testpt
;
1561 short *stest
, cycle
;
1562 objectptr thisobj
= thisinst
->thisobject
;
1564 for (ggen
= thisobj
->plist
; ggen
< thisobj
->plist
+ thisobj
->parts
; ggen
++) {
1565 if (ELEMENTTYPE(*ggen
) == LABEL
) {
1566 clab
= TOLABEL(ggen
);
1567 if (clab
->pin
== LOCAL
|| clab
->pin
== GLOBAL
) {
1568 ReferencePosition(thisinst
, &clab
->position
, &refpoint
);
1569 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
1570 topobject
->parts
; pgen
++) {
1571 /* Ignore any wires that are already selected */
1572 is_selected
= FALSE
;
1573 for (stest
= areawin
->selectlist
; stest
< areawin
->selectlist
+
1574 areawin
->selects
; stest
++) {
1575 if (SELTOGENERIC(stest
) == *pgen
) {
1580 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
1581 cpoly
= TOPOLY(pgen
);
1584 for (testpt
= cpoly
->points
; testpt
< cpoly
->points
+
1585 cpoly
->number
; testpt
++) {
1586 if (testpt
->x
== refpoint
.x
&& testpt
->y
== refpoint
.y
) {
1587 addcycle(pgen
, cycle
, 0);
1595 /* Make sure that this polygon's cycle is not set! */
1605 /*----------------------------------------------------------------------*/
1606 /* Select connected pins on all selected object instances and labels */
1607 /*----------------------------------------------------------------------*/
1609 void select_connected_pins()
1615 if (!areawin
->pinattach
) return;
1617 for (selptr
= areawin
->selectlist
; selptr
< areawin
->selectlist
+
1618 areawin
->selects
; selptr
++) {
1619 switch (SELECTTYPE(selptr
)) {
1621 sellab
= SELTOLABEL(selptr
);
1622 label_connect_cycles(sellab
);
1625 selinst
= SELTOOBJINST(selptr
);
1626 inst_connect_cycles(selinst
);
1632 /*----------------------------------------------------------------------*/
1633 /* Reset all polygon cycles flagged during a move (polygon wires */
1634 /* connected to pins of an object instance). */
1635 /*----------------------------------------------------------------------*/
1642 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
1643 topobject
->parts
; pgen
++)
1647 /*----------------------------------------------------------------------*/
1648 /* Recursive selection mechanism */
1649 /*----------------------------------------------------------------------*/
1651 short *recurse_select_element(short class, u_char mode
) {
1652 pushlistptr seltop
, nextptr
;
1654 short *newselect
, localpick
; /* *desel, (jdk) */
1655 static short pick
= 0;
1656 static selection
*saveselect
= NULL
;
1657 int i
, j
, k
, ilast
, jlast
;
1658 Boolean unselect
= False
;
1660 seltop
= (pushlistptr
)malloc(sizeof(pushlist
));
1661 seltop
->thisinst
= areawin
->topinstance
;
1662 seltop
->next
= NULL
;
1664 /* Definition for unselecting an element */
1670 rselect
= recurselect(class, mode
, &seltop
);
1673 /* Order polygons according to nearest point distance. */
1674 qsort((void *)rselect
->selectlist
, (size_t)rselect
->selects
,
1675 sizeof(short), dcompare
);
1677 if (compareselection(rselect
, saveselect
))
1682 localpick
= pick
% rselect
->selects
;
1685 /* Mechanism for unselecting elements under the cursor */
1686 /* (Unselect all picked objects) */
1688 if (rselect
&& unselect
) {
1692 for (i
= 0; i
< rselect
->selects
; i
++) {
1693 for (j
= 0; j
< areawin
->selects
; j
++) {
1694 if (*(areawin
->selectlist
+ j
) == *(rselect
->selectlist
+ i
)) {
1697 if (++k
== localpick
)
1701 if (j
< areawin
->selects
) break;
1704 newselect
= rselect
->selectlist
+ ilast
;
1705 areawin
->redraw_needed
= True
;
1707 for (k
= jlast
; k
< areawin
->selects
; k
++)
1708 *(areawin
->selectlist
+ k
) = *(areawin
->selectlist
+ k
+ 1);
1710 if (areawin
->selects
== 0) freeselects();
1712 /* Register the selection as an undo event */
1713 register_for_undo(XCF_Select
, mode
, areawin
->topinstance
,
1714 areawin
->selectlist
, areawin
->selects
);
1720 /* Mechanism for selecting objects: */
1721 /* Count all elements from rselect that are part of */
1722 /* the current selection. Pick the "pick"th item (modulo */
1723 /* total number of items). */
1727 for (i
= 0; i
< rselect
->selects
; i
++) {
1728 for (j
= 0; j
< areawin
->selects
; j
++) {
1729 if (*(areawin
->selectlist
+ j
) == *(rselect
->selectlist
+ i
))
1732 if (j
== areawin
->selects
) {
1734 if (++k
== localpick
)
1740 newselect
= allocselect();
1741 *newselect
= *(rselect
->selectlist
+ ilast
);
1742 areawin
->redraw_needed
= True
;
1744 u2u_snap(&areawin
->save
);
1746 /* Register the selection as an undo event */
1747 /* (only if selection changed) */
1749 register_for_undo(XCF_Select
, mode
, areawin
->topinstance
,
1750 areawin
->selectlist
, areawin
->selects
);
1756 while (seltop
!= NULL
) {
1757 nextptr
= seltop
->next
;
1762 freeselection(saveselect
);
1763 saveselect
= rselect
;
1766 if (xobjs
.suspend
< 0)
1767 XcInternalTagCall(xcinterp
, 2, "select", "here");
1770 return areawin
->selectlist
;