1 /***************************************************************************
2 SCED - Schematic Capture Editor
3 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
4 Copyright 1990 Regents of the University of California. All rights reserved.
5 Authors: 1981 Giles C. Billingsley (parts of KIC layout editor)
6 1992 Stephen R. Whiteley
7 ****************************************************************************/
8
9 /*
10 * The SCED selection code.
11 *
12 *
13 * The Selection code extensively uses the CD Info field. The following
14 * convention is used:
15 *
16 * Info = SQ_OLD (0) Object is unselected.
17 * *Info = SQ_OLDSEL (1) Object is selected and in SelectionQ.
18 * Info = SQ_GONE (2) Object is conditionally deleted and in SelectionQ.
19 * Info = SQ_NEW (3) Object is conditionally created and in SelectionQ.
20 * *Info = SQ_NEWSEL (4) Object is conditionally created and in SelectionQ.
21 * Info = SQ_INCMPLT (5) Object is being created.
22 *
23 * Info = 6-11 Reserved.
24 * *Info = 11-255 Object has conditionally new layer and is in
25 * SelectionQ. OldLayer = Info - 10.
26 *
27 * * means that SQShow will highlight these objects.
28 *
29 */
30
31 #include "spice.h"
32 #include "sced.h"
33 #include <string.h>
34
35
36
37 /***********************************************************************
38 *
39 * Current transform code.
40 *
41 ***********************************************************************/
42
43 extern char *MenuMX;
44 extern char *MenuMY;
45 extern char *Menu0;
46 extern char *Menu90;
47 extern char *Menu180;
48 extern char *Menu270;
49
50
51 void
MX()52 MX()
53
54 {
55 if (Parameters.kpMX) {
56 Parameters.kpMX = False;
57 MenuDeselect(MenuMX);
58 }
59 else {
60 Parameters.kpMX = True;
61 MenuSelect(MenuMX);
62 }
63 }
64
65
66 void
MY()67 MY()
68
69 {
70 if (Parameters.kpMY) {
71 Parameters.kpMY = False;
72 MenuDeselect(MenuMY);
73 }
74 else {
75 Parameters.kpMY = True;
76 MenuSelect(MenuMY);
77 }
78 }
79
80
81 void
Rotat0()82 Rotat0()
83
84 {
85 Parameters.kpRotationAngle = 90;
86 AlterMenuEntries(Menu0,Menu90);
87 MenuSelect(Menu90);
88 }
89
90
91 void
Rotat90()92 Rotat90()
93
94 {
95 Parameters.kpRotationAngle = 180;
96 AlterMenuEntries(Menu90,Menu180);
97 MenuSelect(Menu180);
98 }
99
100
101 void
Rotat180()102 Rotat180()
103
104 {
105 Parameters.kpRotationAngle = 270;
106 AlterMenuEntries(Menu180,Menu270);
107 MenuSelect(Menu270);
108 }
109
110
111 void
Rotat270()112 Rotat270()
113
114 {
115 Parameters.kpRotationAngle = 0;
116 AlterMenuEntries(Menu270,Menu0);
117 MenuDeselect(Menu0);
118 }
119
120
121
122 /***********************************************************************
123 *
124 * Selection operator code.
125 *
126 ***********************************************************************/
127
128 extern char *MenuAREA;
129 extern char *MenuDESEL;
130 extern char *MenuSELEC;
131 extern char *MenuUNDO;
132
133 #ifdef __STDC__
134 static struct ks *select_items(struct ka*,int);
135 static void sl_free(struct ks*);
136 static void sl_bb(struct ks*,struct ka*);
137 static void get_BB(struct o*,struct ka*);
138 static int is_BB_visible(struct o*);
139 static void redisplay_edges(struct ka*);
140 static struct ks *which_cell(struct ks*);
141 static void sq_set_NEW(struct o*);
142 static void sq_delete_dups(void);
143 static void sq_display_selected(struct o*);
144 static int overlap_path(struct p*,struct ka*);
145 static int overlap_line(struct ka*,struct ka*);
146 static int cross_line(struct ka*,struct ka*);
147 static int point_in_poly(int,struct p*,long,long);
148 #else
149 static struct ks *select_items();
150 static void sl_free();
151 static void sl_bb();
152 static void get_BB();
153 static int is_BB_visible();
154 static void redisplay_edges();
155 static struct ks *which_cell();
156 static void sq_set_NEW();
157 static void sq_delete_dups();
158 static void sq_display_selected();
159 static int overlap_path();
160 static int overlap_line();
161 static int cross_line();
162 static int point_in_poly();
163 #endif
164
165 #define UpdateBB(BB2,BB1) \
166 if (BB1.kaLeft < BB2.kaLeft) BB2.kaLeft = BB1.kaLeft; \
167 if (BB1.kaBottom < BB2.kaBottom) BB2.kaBottom = BB1.kaBottom; \
168 if (BB1.kaRight > BB2.kaRight) BB2.kaRight = BB1.kaRight; \
169 if (BB1.kaTop > BB2.kaTop) BB2.kaTop = BB1.kaTop;
170
171
172
173 void
Sel(LookedAhead)174 Sel(LookedAhead)
175
176 int *LookedAhead;
177 {
178 struct ka AOI;
179 int FirstTime = True;
180
181 MenuSelect(MenuSELEC);
182 ShowPrompt("Point to select.");
183 loop {
184 switch (PointLoop(LookedAhead)) {
185 case PL_CMD:
186 case PL_ESC:
187 goto quit;
188 case PL_UND:
189 if (FirstTime == True) goto quit;
190 MenuSelect(MenuUNDO);
191 Selection(&AOI);
192 MenuDeselect(MenuUNDO);
193 continue;
194 case PL_PCW:
195 AOI.kaLeft = AOI.kaRight = SCursor.kcRawX;
196 AOI.kaBottom = AOI.kaTop = SCursor.kcRawY;
197 ErasePrompt();
198 Selection(&AOI);
199 FirstTime = False;
200 }
201 }
202 quit:
203 MenuDeselect(MenuSELEC);
204 ErasePrompt();
205 }
206
207
208 void
Area(LookedAhead)209 Area(LookedAhead)
210
211 int *LookedAhead;
212 {
213 struct ka AOI;
214 long OldRawX,OldRawY;
215 int FirstTime = True;
216
217 MenuSelect(MenuAREA);
218 top:
219 loop {
220 ShowPrompt("Point to endpoints of diagonal.");
221 switch (PointLoop(LookedAhead)) {
222 case PL_ESC:
223 case PL_CMD:
224 goto quit;
225 case PL_UND:
226 if (FirstTime == True) goto quit;
227 MenuSelect(MenuUNDO);
228 Selection(&AOI);
229 MenuDeselect(MenuUNDO);
230 goto top;
231 case PL_PCW:
232 FBSetRubberBanding('R');
233 OldRawX = SCursor.kcRawX;
234 OldRawY = SCursor.kcRawY;
235 }
236 ShowPrompt("Point to second endpoint.");
237 switch (PointLoop(LookedAhead)) {
238 case PL_ESC:
239 case PL_CMD:
240 goto quit;
241 case PL_UND:
242 FBSetRubberBanding(0);
243 goto top;
244 case PL_PCW:
245 FBSetRubberBanding(0);
246 break;
247 }
248 AOI.kaLeft = Min(OldRawX,SCursor.kcRawX);
249 AOI.kaBottom = Min(OldRawY,SCursor.kcRawY);
250 AOI.kaRight = Max(OldRawX,SCursor.kcRawX);
251 AOI.kaTop = Max(OldRawY,SCursor.kcRawY);
252 Selection(&AOI);
253 FirstTime = False;
254 }
255
256 quit:
257 FBSetRubberBanding(0);
258 MenuDeselect(MenuAREA);
259 ErasePrompt();
260 }
261
262
263 void
Desel()264 Desel()
265
266 {
267 MenuSelect(MenuDESEL);
268 SQComputeBB();
269 if (SelectQHead != NULL) {
270 SQClear();
271 /* Take care of Instance markers */
272 OversizeBox(&SelectQBB,200);
273 EraseBox(&SelectQBB);
274 Redisplay(&SelectQBB);
275 }
276 MenuDeselect(MenuDESEL);
277 }
278
279
280 void
Selection(AOI)281 Selection(AOI)
282
283 /* Select items and link into SelectionQ, compute BB. */
284 struct ka *AOI;
285 {
286 struct ks *SList, *S;
287 struct ka BB,OldSelectQBB;
288
289 if (AOI->kaLeft == AOI->kaRight) {
290 /* Point selection. */
291
292 SList = select_items(AOI,True);
293 if (SList == NULL) return;
294 if (SList->ksPointer->oType == CDSYMBOLCALL) {
295 /* no geometry found, get one symbol */
296 S = which_cell(SList);
297 if (S) {
298 if (S->ksPointer->oInfo == SQ_OLDSEL) {
299 /* already selected, deselect and break */
300 S->ksPointer->oInfo = SQ_OLD;
301 SQDelete(S->ksPointer);
302 get_BB(S->ksPointer,&BB);
303 redisplay_edges(&BB);
304 }
305 else {
306 /* add to select Q */
307 S->ksPointer->oInfo = SQ_OLDSEL;
308 SQInsert(S->ksPointer);
309 sq_display_selected(S->ksPointer);
310 }
311 }
312 SQComputeBB();
313 sl_free(SList);
314 return;
315 }
316 for (S = SList; S != NULL; S = S->ksSucc) {
317 /* keep only geometry */
318 if (S->ksPointer->oType == CDSYMBOLCALL) break;
319
320 if (S->ksPointer->oInfo == SQ_OLDSEL) {
321 /* already selected, deselect and break */
322 S->ksPointer->oInfo = SQ_OLD;
323 SQDelete(S->ksPointer);
324 get_BB(S->ksPointer,&BB);
325 EraseBox(&BB);
326 Redisplay(&BB);
327 DevUpdate();
328 break;
329 }
330 else {
331 /* add to select Q */
332 S->ksPointer->oInfo = SQ_OLDSEL;
333 SQInsert(S->ksPointer);
334 sq_display_selected(S->ksPointer);
335 }
336 }
337 SQComputeBB();
338 }
339 else {
340
341 /* Area select. */
342 SList = select_items(AOI,False);
343 if (SList == NULL) return;
344 SQComputeBB();
345 OldSelectQBB = SelectQBB;
346
347 for (S = SList; S != NULL; S = S->ksSucc) {
348 if (S->ksPointer->oType == CDSYMBOLCALL &&
349 !is_BB_visible(S->ksPointer)) continue;
350
351 if (S->ksPointer->oInfo == SQ_OLDSEL) {
352 /* already selected, deselect */
353 S->ksPointer->oInfo = SQ_OLD;
354 SQDelete(S->ksPointer);
355 }
356 else {
357 /* add to select Q */
358 S->ksPointer->oInfo = SQ_OLDSEL;
359 SQInsert(S->ksPointer);
360 }
361 }
362 SQComputeBB();
363 UpdateBB(SelectQBB,OldSelectQBB);
364 if (SelectQBB.kaLeft == CDINFINITY) return;
365 EraseBox(&SelectQBB);
366 Redisplay(&SelectQBB);
367 DevUpdate();
368 }
369 sl_free(SList);
370 }
371
372
373 static struct ks *
select_items(AOI,PointSelect)374 select_items(AOI,PointSelect)
375
376 /* Return a list of visible objects in the neighborhood of AOI as returned
377 * from the generator. Only types in Parameters.kpSelectTypes are listed,
378 * all are listed if this is NULL. The flag PointSelect is set for
379 * a point selection.
380 */
381 struct ka *AOI;
382 int PointSelect;
383 {
384 struct g *GenDesc;
385 struct o *Pointer;
386 struct ka BB;
387 struct ks *SPointer = NULL, *S;
388 struct p *Path;
389 long Width;
390 int Delta,Layer;
391
392 if (PointSelect) {
393 /* expand the point to finite size */
394 if (SCursor.kcInFine == True)
395 Delta = 3.0/View->kvFineRatio;
396 else
397 Delta = 3.0/View->kvCoarseRatio;
398 OversizeBox(AOI,Delta);
399 }
400
401 if (Not CDInitGen(Parameters.kpCellDesc,1,AOI->kaLeft,AOI->kaBottom,
402 AOI->kaRight,AOI->kaTop,&GenDesc)) MallocFailed();
403 loop {
404 CDGen(Parameters.kpCellDesc,GenDesc,&Pointer);
405 if (Pointer == NULL) break;
406 if (Pointer->oInfo == SQ_GONE) continue;
407 if (Parameters.kpSelectTypes &&
408 !strchr(Parameters.kpSelectTypes,Pointer->oType)) continue;
409
410 switch (Pointer->oType) {
411 case CDWIRE:
412 CDWire(Pointer,&Layer,&Width,&Path);
413 if (PointSelect) {
414 if (InPath(Delta+(int)Width/2,Path,
415 AOI->kaLeft+Delta,AOI->kaBottom+Delta) != NULL)
416 break;
417 }
418 else {
419 if (overlap_path(Path,AOI)) break;
420 if (InBox(Path->pX,Path->pY,AOI)) break;
421 }
422 continue;
423
424 case CDPOLYGON:
425 CDPolygon(Pointer,&Layer,&Path);
426 if (PointSelect) {
427 if (point_in_poly(Delta,Path,
428 AOI->kaLeft+Delta,AOI->kaBottom+Delta))
429 break;
430 }
431 else {
432 if (point_in_poly(0,Path,AOI->kaLeft,AOI->kaBottom))
433 break;
434 if (overlap_path(Path,AOI)) break;
435 if (InBox(Path->pX,Path->pY,AOI)) break;
436 }
437 continue;
438
439 case CDLABEL:
440 case CDBOX:
441 break;
442
443 default:
444 continue;
445 }
446 if (SPointer == NULL)
447 S = SPointer = alloc(ks);
448 else {
449 S->ksSucc = alloc(ks);
450 S = S->ksSucc;
451 }
452 if (S == NULL) MallocFailed();
453 S->ksPointer = Pointer;
454 S->ksSucc = NULL;
455 }
456
457
458 /* Now for the instances... */
459
460 if (Parameters.kpSelectTypes &&
461 !strchr(Parameters.kpSelectTypes,CDSYMBOLCALL)) {
462 if (PointSelect) OversizeBox(AOI,-Delta);
463 return (SPointer);
464 }
465
466 if (Not CDInitGen(Parameters.kpCellDesc,0,AOI->kaLeft,AOI->kaBottom,
467 AOI->kaRight,AOI->kaTop,&GenDesc)) MallocFailed();
468 loop {
469 CDGen(Parameters.kpCellDesc,GenDesc,&Pointer);
470 if (Pointer == NULL) break;
471
472 if (Pointer->oInfo == SQ_GONE) continue;
473 if (SPointer == NULL)
474 S = SPointer = alloc(ks);
475 else {
476 S->ksSucc = alloc(ks);
477 S = S->ksSucc;
478 }
479 if (S == NULL) MallocFailed();
480 S->ksPointer = Pointer;
481 S->ksSucc = NULL;
482 }
483 if (PointSelect) OversizeBox(AOI,-Delta);
484 return (SPointer);
485 }
486
487
488 static void
sl_free(SList)489 sl_free(SList)
490
491 /* Free a list as returned from select_items(). */
492 struct ks *SList;
493 {
494 struct ks *SQDesc,*SQNext;
495
496 for (SQDesc = SList; SQDesc; SQDesc = SQNext) {
497 SQNext = SQDesc->ksSucc;
498 tfree(SQDesc);
499 }
500 }
501
502
503 static void
sl_bb(SList,BB)504 sl_bb(SList,BB)
505
506 /* Compute the BB of the objects in SList. */
507 struct ks *SList;
508 struct ka *BB;
509 {
510 struct ks *S;
511 struct ka NBB,OBB;
512
513 NBB.kaLeft = CDINFINITY;
514 NBB.kaBottom = CDINFINITY;
515 NBB.kaRight = -CDINFINITY;
516 NBB.kaTop = -CDINFINITY;
517
518 for (S = SList; S != NULL; S = S->ksSucc) {
519 get_BB(S->ksPointer,&OBB);
520 UpdateBB(NBB,OBB);
521 }
522 *BB = NBB;
523 }
524
525
526 static void
get_BB(Pointer,BB)527 get_BB(Pointer,BB)
528
529 struct o *Pointer;
530 struct ka *BB;
531 {
532 if (Pointer->oType == CDLABEL)
533 BBLabel(View->kvCoarseWindow,Pointer,BB);
534 else
535 CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,&BB->kaLeft,
536 &BB->kaBottom,&BB->kaRight,&BB->kaTop);
537 }
538
539
540 static int
is_BB_visible(Pointer)541 is_BB_visible(Pointer)
542
543 struct o *Pointer;
544 {
545 struct ka BB;
546
547 /* will edges show in coarse window? */
548 CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,
549 &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
550 if (BB.kaLeft <= View->kvCoarseWindow->kaLeft &&
551 BB.kaRight >= View->kvCoarseWindow->kaRight &&
552 BB.kaBottom <= View->kvCoarseWindow->kaBottom &&
553 BB.kaTop >= View->kvCoarseWindow->kaTop)
554 return (False);
555 return (True);
556 }
557
558
559 static void
redisplay_edges(BB)560 redisplay_edges(BB)
561
562 /* redisplay the edges of BB */
563 struct ka *BB;
564 {
565 struct ka EdgeOfBB;
566
567 /* Left edge. */
568 EdgeOfBB.kaLeft = BB->kaLeft-300;
569 EdgeOfBB.kaRight = BB->kaLeft+300;
570 EdgeOfBB.kaTop = BB->kaTop+300;
571 EdgeOfBB.kaBottom = BB->kaBottom-300;
572 EraseBox(&EdgeOfBB);
573 Redisplay(&EdgeOfBB);
574
575 /* Right edge. */
576 EdgeOfBB.kaRight = BB->kaRight+300;
577 EdgeOfBB.kaLeft = BB->kaRight-300;
578 EdgeOfBB.kaTop = BB->kaTop+300;
579 EdgeOfBB.kaBottom = BB->kaBottom-300;
580 EraseBox(&EdgeOfBB);
581 Redisplay(&EdgeOfBB);
582
583 /* Bottom edge. */
584 EdgeOfBB.kaBottom = BB->kaBottom-300;
585 EdgeOfBB.kaTop = BB->kaBottom+300;
586 EdgeOfBB.kaRight = BB->kaRight;
587 EdgeOfBB.kaLeft = BB->kaLeft;
588 EraseBox(&EdgeOfBB);
589 Redisplay(&EdgeOfBB);
590
591 /* Top edge. */
592 EdgeOfBB.kaBottom = BB->kaTop-300;
593 EdgeOfBB.kaTop = BB->kaTop+300;
594 EdgeOfBB.kaRight = BB->kaRight;
595 EdgeOfBB.kaLeft = BB->kaLeft;
596 EraseBox(&EdgeOfBB);
597 Redisplay(&EdgeOfBB);
598
599 DevUpdate();
600 }
601
602
603 static struct ks *
which_cell(SList)604 which_cell(SList)
605
606 /* Resolve ambiguity (multiple instances selected) */
607 struct ks *SList;
608 {
609 struct ks *S,*Sret;
610 char *SymbolName;
611 struct ka BB;
612 double A,Area;
613
614 /* find the smallest cell */
615 sl_bb(SList,&BB);
616 Area = BB.kaRight - BB.kaLeft;
617 Area *= BB.kaTop - BB.kaBottom;
618 Sret = SList;
619 for (S = SList; S != NULL; S = S->ksSucc) {
620 CDStatusInt = CDBB(Parameters.kpCellDesc,S->ksPointer,
621 &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
622 A = BB.kaRight - BB.kaLeft;
623 A *= BB.kaTop - BB.kaBottom;
624 if (A < Area) {
625 Sret = S;
626 Area = A;
627 }
628 }
629 if (!is_BB_visible(Sret->ksPointer)) return (NULL);
630
631 SymbolName = ((struct c *)Sret->ksPointer->oRep)->cMaster->mName;
632 sprintf(TypeOut,"You have selected an instance of %s.",SymbolName);
633 ShowPrompt(TypeOut);
634 return (Sret);
635 }
636
637
638 int
AreTypesInQ(Types)639 AreTypesInQ(Types)
640
641 /* Returns True if one of Types is in SelectionQ and is selected,
642 * or of anything selected is in the Q if Types is NULL.
643 */
644 char *Types;
645 {
646 struct ks *SQDesc;
647
648 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
649 if (Types == NULL || strchr(Types,SQDesc->ksPointer->oType))
650 if (SQDesc->ksPointer->oInfo == SQ_OLDSEL) return (True);
651 }
652 return (False);
653 }
654
655
656 void
SelectTypes(Types)657 SelectTypes(Types)
658
659 /* Perform a point select, selecting only Types, or anything if
660 * Types is NULL.
661 */
662 char *Types;
663 {
664 struct ka BB;
665 char TTmp[8];
666
667 BB.kaLeft = BB.kaRight = SCursor.kcRawX;
668 BB.kaBottom = BB.kaTop = SCursor.kcRawY;
669 if (Types == NULL) {
670 Selection(&BB);
671 return;
672 }
673 strcpy(TTmp,Parameters.kpSelectTypes);
674 strncpy(Parameters.kpSelectTypes,Types,8);
675 Parameters.kpSelectTypes[7] = '\0';
676 Selection(&BB);
677 strcpy(Parameters.kpSelectTypes,TTmp);
678 }
679
680
681 void
SQInit()682 SQInit()
683
684 {
685 SelectQHead = NULL;
686 }
687
688
689 void
SQClear()690 SQClear()
691
692 /* Clear the SelectionQ. */
693 {
694 struct ks *SQDesc,*SQNext;
695
696 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQNext) {
697 SQNext = SQDesc->ksSucc;
698 SQDesc->ksPointer->oInfo = SQ_OLD;
699 tfree(SQDesc);
700 }
701 SelectQHead = NULL;
702 }
703
704
705 void
SQInsert(Pointer)706 SQInsert(Pointer)
707
708 /* Insert Pointer into the SelectionQ (no checking for duplication). */
709 struct o *Pointer;
710 {
711 struct ks *SQDesc;
712
713 if ((SQDesc = alloc(ks)) == NULL) MallocFailed();
714
715 /* SelectQHead is most recent addition */
716 SQDesc->ksPointer = Pointer;
717 SQDesc->ksSucc = SelectQHead;
718 SelectQHead = SQDesc;
719 }
720
721
722 void
SQDelete(Pointer)723 SQDelete(Pointer)
724
725 /* Delete Pointer from SelectionQ if it is there. */
726 struct o *Pointer;
727 {
728 struct ks *SQDesc,*SQPrev,*SQNext;
729
730 SQPrev = NULL;
731
732 for (SQDesc = SelectQHead; SQDesc; SQPrev = SQDesc,SQDesc = SQNext) {
733 SQNext = SQDesc->ksSucc;
734
735 if (SQDesc->ksPointer != Pointer) continue;
736 Pointer->oInfo = SQ_OLD;
737
738 if (SQPrev == NULL)
739 SelectQHead = SQNext;
740 else
741 SQPrev->ksSucc = SQNext;
742 tfree(SQDesc);
743 return;
744 }
745 }
746
747
748 void
SQComputeBB()749 SQComputeBB()
750
751 /* Compute the BB of the queued and selected objects. */
752 {
753 struct ks *SQDesc;
754 struct ka BB;
755 int Info;
756
757 SelectQBB.kaLeft = CDINFINITY;
758 SelectQBB.kaBottom = CDINFINITY;
759 SelectQBB.kaRight = -CDINFINITY;
760 SelectQBB.kaTop = -CDINFINITY;
761
762 for (SQDesc = SelectQHead; SQDesc != NULL; SQDesc = SQDesc->ksSucc) {
763 Info = SQDesc->ksPointer->oInfo;
764 if (Info == SQ_OLDSEL || Info == SQ_NEWSEL ||
765 (Info > 10 && Info <= 255)) {
766 get_BB(SQDesc->ksPointer,&BB);
767 UpdateBB(SelectQBB,BB);
768 }
769 }
770 }
771
772
773 /* Theory behind SQRestore() and SQDesel();
774 *
775 * In commands which modify objects such as Move, the original object(s)
776 * are conditionally deleted, and new objects are conditionally created.
777 * All objects are left in the SelectionQ for a time to allow Undo.
778 * For example, suppose the SelectionQ is empty, and the user points at
779 * an object.
780 *
781 * operation: SelectionQ:
782 * select OLD (Info = SQ_OLDSEL)
783 * move NEW (Info = SQ_NEW), OLD (Info = SQ_GONE)
784 * User now selects newly moved object (the complicated case):
785 * select NEW NEW (Info = SQ_OLDSEL), NEW (Info = SQ_OLDSEL),
786 * OLD (Info = SQ_GONE)
787 * Now undo undoes the selection
788 * Undo (SQDesel()) NEW (Info = SQ_NEW), OLD (Info = SQ_GONE)
789 * Next undo undoes the move, leaving original item selected (conditionally).
790 * Undo (SQRestore(1)) OLD (Info = SQ_NEWSEL)
791 * Next undo undoes the selection
792 * Undo (SQDesel()) OLD (Info = SQ_NEW)
793 * The next undo repeats the move, etc.
794 *
795 * SQRestore(0) unsets the conditionality of objects in the SelectionQ
796 * and should be called when things are "final," i.e., before function
797 * exit or next operation.
798 */
799
800
801 void
SQRestore(Undo)802 SQRestore(Undo)
803
804 /* Restore the conditionally created objects in the SelectionQ
805 * and delete duplicates if Undo is False. Otherwise undo the
806 * last operation.
807 */
808
809 /* If Undo is True:
810 * Previously deleted objects become conditionally selected:
811 * Info = SQ_GONE -> Info = SQ_NEWSEL.
812 * New objects are deleted from SelectionQ and database:
813 * Info = SQ_NEW deleted from queue and database.
814 * Info = SQ_NEWSEL deleted from queue and database.
815 * Else
816 * Conditionally deleted objects are really deleted:
817 * Info = SQ_GONE deleted from queue and database.
818 * New objects are now Old objects, selected or otherwise:
819 * Info = SQ_NEW -> Info = SQ_OLD, deleted from queue.
820 * Info = SQ_NEWSEL -> Info = SQ_OLDSEL.
821 */
822
823 int Undo;
824 {
825 struct ks *SQDesc,*SQNext;
826 struct prpty *PDesc;
827 int Info;
828 struct o *Pointer;
829
830 /* Properties added have the Info field set to "new", so we can
831 * remove them during Undo.
832 */
833 PDesc = Parameters.kpCellDesc->sPrptyList;
834 if (Undo == True) {
835 while (PDesc) {
836 if (PDesc->prpty_Info &&
837 !strcmp(PDesc->prpty_Info,"new")) {
838 Parameters.kpCellDesc->sPrptyList =
839 PDesc->prpty_Succ;
840 free(PDesc->prpty_Data);
841 free(PDesc);
842 PDesc = Parameters.kpCellDesc->sPrptyList;
843 continue;
844 }
845 break;
846 }
847 }
848 else {
849 while (PDesc) {
850 if (PDesc->prpty_Info &&
851 !strcmp(PDesc->prpty_Info,"new")) {
852 PDesc->prpty_Info = NULL;
853 PDesc = PDesc->prpty_Succ;
854 continue;
855 }
856 break;
857 }
858 }
859
860 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQNext) {
861 SQNext = SQDesc->ksSucc;
862 Pointer = SQDesc->ksPointer;
863 Info = Pointer->oInfo;
864
865 if (Info == SQ_GONE) {
866 if (Undo == True)
867 Pointer->oInfo = SQ_NEWSEL;
868 else {
869 SQDelete(Pointer);
870 CDDelete(Parameters.kpCellDesc,Pointer);
871 }
872 continue;
873 }
874 if (Info == SQ_NEW) {
875 SQDelete(Pointer);
876 if (Undo == True) {
877 Pointer->oInfo = SQ_GONE;
878 CDDelete(Parameters.kpCellDesc,Pointer);
879 }
880 else
881 Pointer->oInfo = SQ_OLD;
882 continue;
883 }
884 if (Info == SQ_NEWSEL) {
885 if (Undo == True) {
886 SQDelete(Pointer);
887 Pointer->oInfo = SQ_GONE;
888 CDDelete(Parameters.kpCellDesc,Pointer);
889 }
890 else
891 Pointer->oInfo = SQ_OLDSEL;
892 }
893 }
894 if (Undo == False)
895 sq_delete_dups();
896 }
897
898
899 void
SQDesel(Types)900 SQDesel(Types)
901
902 /* Undo a selection operation. */
903
904 /* Info = SQ_OLDSEL deleted from queue, and duplicates set to Info = SQ_NEW.
905 * Info = SQ_NEWSEL -> Info = SQ_NEW.
906 * Ignores objects with type not listed in Types.
907 */
908
909 char *Types;
910 {
911 struct ks *SQDesc, *SQNext;
912 struct o *Pointer;
913 int Info;
914 char Type;
915
916 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQNext) {
917 SQNext = SQDesc->ksSucc;
918 Type = SQDesc->ksPointer->oType;
919 if (Types And !strchr(Types,Type)) continue;
920 Info = SQDesc->ksPointer->oInfo;
921
922 /* Have to be careful here. If selected object is already
923 * in queue have to reset Info of second entry to SQ_NEW.
924 */
925
926 if (Info == SQ_OLDSEL) {
927 Pointer = SQDesc->ksPointer;
928 Pointer->oInfo = SQ_OLD;
929 SQDelete(Pointer);
930 sq_set_NEW(Pointer);
931 continue;
932 }
933 if (Info == SQ_NEWSEL)
934 SQDesc->ksPointer->oInfo = SQ_NEW;
935 }
936 }
937
938
939 void
SQShow()940 SQShow()
941
942 /* Show selected objects by highlighting their BBs. */
943 {
944 struct ks *SQDesc;
945 int Info;
946
947 if (Not Parameters.kpEnableSelectQRedisplay) return;
948 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
949 Info = SQDesc->ksPointer->oInfo;
950 /* Test for user interrupt */
951 if (Parameters.kpSIGINTERRUPT) {
952 RedisplayAfterInterrupt();
953 return;
954 }
955 if (Info == SQ_OLDSEL || Info == SQ_NEWSEL ||
956 (Info > 10 && Info <= 255)) {
957 /* Show Selected Objects */
958 sq_display_selected(SQDesc->ksPointer);
959 }
960 }
961 }
962
963
964 static void
sq_set_NEW(Pointer)965 sq_set_NEW(Pointer)
966
967 /* If object is in queue, set Info to SQ_NEW. */
968 struct o *Pointer;
969 {
970 struct ks *SQDesc;
971 int Info;
972
973 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
974 if (SQDesc->ksPointer == Pointer) {
975 SQDesc->ksPointer->oInfo = SQ_NEW;
976 return;
977 }
978 }
979 }
980
981
982 static void
sq_delete_dups()983 sq_delete_dups()
984
985 /* Delete duplicate entries in selection queue. */
986 {
987 struct ks *SQDesc,*SQDesc1,*SQNext;
988 int Info;
989
990 for (SQDesc = SelectQHead; SQDesc; SQDesc = SQNext) {
991 SQNext = SQDesc->ksSucc;
992 Info = SQDesc->ksPointer->oInfo;
993 for (SQDesc1 = SQDesc->ksSucc; SQDesc1; SQDesc1 = SQDesc1->ksSucc)
994 if (SQDesc->ksPointer == SQDesc1->ksPointer) {
995 SQDelete(SQDesc->ksPointer);
996 /* SQDelete sets Info to SQ_OLD, have to undo this */
997 SQDesc1->ksPointer->oInfo = Info;
998 break;
999 }
1000 }
1001 }
1002
1003
1004 static void
sq_display_selected(Pointer)1005 sq_display_selected(Pointer)
1006
1007 struct o *Pointer;
1008 {
1009 int Layer;
1010 struct p *Path;
1011 long Width;
1012 char OldRD;
1013 struct ka BB;
1014
1015 if (Pointer->oType == CDWIRE) {
1016 CDWire(Pointer,&Layer,&Width,&Path);
1017 ShowWire(HighlightingColor,Width,Path);
1018 return;
1019 }
1020 if (Pointer->oType == CDSYMBOLCALL) {
1021 CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,
1022 &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
1023 ShowEmptyBox(HighlightingColor,&BB);
1024 return;
1025 }
1026 if (Pointer->oType == CDLABEL) {
1027
1028 /* BB of labels must be special-cased. Can't use CDBB. */
1029
1030 OldRD = Parameters.kpRedisplayControl;
1031 if (OldRD != FINEVIEWPORTONLY) {
1032 Parameters.kpRedisplayControl = COARSEVIEWPORTONLY;
1033 BBLabel(View->kvCoarseWindow,Pointer,&BB);
1034 ShowEmptyBox(HighlightingColor,&BB);
1035 }
1036 if (OldRD != COARSEVIEWPORTONLY) {
1037 Parameters.kpRedisplayControl = FINEVIEWPORTONLY;
1038 BBLabel(View->kvFineWindow,Pointer,&BB);
1039 ShowEmptyBox(HighlightingColor,&BB);
1040 }
1041 Parameters.kpRedisplayControl = OldRD;
1042 return;
1043 }
1044 if (Pointer->oType == CDPOLYGON) {
1045 CDPolygon(Pointer,&Layer,&Path);
1046 ShowPath(HighlightingColor,Path,True);
1047 return;
1048 }
1049 if (Pointer->oType == CDBOX) {
1050 CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,
1051 &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
1052 ShowEmptyBox(HighlightingColor,&BB);
1053 return;
1054 }
1055 }
1056
1057
1058 long *
InPath(Delta,Path,X,Y)1059 InPath(Delta,Path,X,Y)
1060
1061 /* Is (X,Y) on the path described by <Path>?
1062 * If yes, return a pointer to x,y that are exactly in path.
1063 */
1064 int Delta;
1065 struct p *Path;
1066 long X,Y;
1067 {
1068 struct p *Pair;
1069 struct ka BB;
1070 double x1,x2,y1,y2,d0,d1,d2,d3,w;
1071 static long xy[2];
1072
1073 if (Delta < 10) Delta = 10;
1074
1075 if (Path == NULL) return (False);
1076 for (Pair = Path; Pair->pSucc != NULL; Pair = Pair->pSucc) {
1077
1078 if (Pair->pX < Pair->pSucc->pX) {
1079 BB.kaLeft = Pair->pX;
1080 BB.kaRight = Pair->pSucc->pX;
1081 }
1082 else {
1083 BB.kaRight = Pair->pX;
1084 BB.kaLeft = Pair->pSucc->pX;
1085 }
1086 if (Pair->pY < Pair->pSucc->pY) {
1087 BB.kaBottom = Pair->pY;
1088 BB.kaTop = Pair->pSucc->pY;
1089 }
1090 else {
1091 BB.kaBottom = Pair->pSucc->pY;
1092 BB.kaTop = Pair->pY;
1093 }
1094 OversizeBox(&BB,Delta);
1095 if (!InBox(X,Y,&BB)) continue;
1096
1097 x1 = Pair->pX - Pair->pSucc->pX;
1098 y1 = Pair->pY - Pair->pSucc->pY;
1099 d0 = x1*x1 + y1*y1;
1100
1101 x1 = Pair->pX - X;
1102 y1 = Pair->pY - Y;
1103 d1 = x1*x1 + y1*y1;
1104 x2 = Pair->pSucc->pX - X;
1105 y2 = Pair->pSucc->pY - Y;
1106 d2 = x2*x2 + y2*y2;
1107
1108 d3 = (d2 - d1)/(2*sqrt(d0));
1109 w = (d1+d2)/2 - d0/4 - d3*d3;
1110
1111 if (w <= (long)Delta*Delta) {
1112 /* should be positive, fabs() just in case */
1113 d1 = sqrt(fabs(d1-w)/d0);
1114 xy[0] = Pair->pX + (Pair->pSucc->pX - Pair->pX)*d1;
1115 xy[1] = Pair->pY + (Pair->pSucc->pY - Pair->pY)*d1;
1116 return (xy);
1117 }
1118 }
1119 return (NULL);
1120 }
1121
1122
1123 static int
point_in_poly(Delta,Path,X,Y)1124 point_in_poly(Delta,Path,X,Y)
1125
1126 /* Return True if point is enclosed in polygon, or within Delta of a vertex.
1127 * Algorithm is to sum angle differences to reference point around
1128 * path. If the reference point is inside, the sum is 2*PI, otherwise
1129 * the sum is zero.
1130 */
1131 int Delta;
1132 struct p *Path;
1133 long X,Y;
1134 {
1135 struct p *p;
1136 double Xp,Yp,R,Theta,ThetaLast,Sum,zz;
1137
1138 Sum = 0;
1139
1140 for (p = Path; p != NULL; p = p->pSucc) {
1141
1142 Xp = p->pX - X;
1143 Yp = p->pY - Y;
1144 R = sqrt(Xp*Xp + Yp*Yp);
1145 if (R <= Delta) return (True);
1146 Theta = asin(Yp/R);
1147 if (Xp >= 0) {
1148 if (Yp < 0)
1149 Theta = 2*M_PI + Theta;
1150 }
1151 else
1152 Theta = M_PI - Theta;
1153 if (p != Path) {
1154 zz = (Theta - ThetaLast);
1155 if (zz > M_PI) zz -= 2*M_PI;
1156 if (zz < -M_PI) zz += 2*M_PI;
1157 Sum += zz;
1158 }
1159 ThetaLast = Theta;
1160 }
1161 if (fabs(Sum) >= 1.99*M_PI) return (True);
1162 return (False);
1163 }
1164
1165
1166 static int
overlap_path(Path,BB)1167 overlap_path(Path,BB)
1168
1169 /* return True if the path intersects the BB */
1170 struct p *Path;
1171 struct ka *BB;
1172 {
1173 struct ka Line;
1174
1175 Line.kaLeft = Path->pX;
1176 Line.kaBottom = Path->pY;
1177 Path = Path->pSucc;
1178 for (; Path != NULL; Path = Path->pSucc) {
1179 Line.kaRight = Path->pX;
1180 Line.kaTop = Path->pY;
1181 if (overlap_line(&Line,BB)) return (True);
1182 Line.kaLeft = Line.kaRight;
1183 Line.kaBottom = Line.kaTop;
1184 }
1185 return (False);
1186 }
1187
1188
1189 static int
overlap_line(Line,BB)1190 overlap_line(Line,BB)
1191
1192 /* return True if Line intersects BB */
1193 struct ka *Line,*BB;
1194 {
1195 struct ka LBB;
1196
1197 LBB.kaLeft = BB->kaLeft;
1198 LBB.kaRight = BB->kaLeft;
1199 LBB.kaBottom = BB->kaBottom;
1200 LBB.kaTop = BB->kaTop;
1201 if (cross_line(Line,&LBB)) return (True);
1202
1203 LBB.kaRight = BB->kaRight;
1204 LBB.kaBottom = BB->kaTop;
1205 if (cross_line(Line,&LBB)) return (True);
1206
1207 LBB.kaLeft = BB->kaRight;
1208 LBB.kaBottom = BB->kaBottom;
1209 if (cross_line(Line,&LBB)) return (True);
1210
1211 LBB.kaLeft = BB->kaLeft;
1212 LBB.kaTop = BB->kaBottom;
1213 if (cross_line(Line,&LBB)) return (True);
1214
1215 return (False);
1216 }
1217
1218
1219 static int
cross_line(Line,BB)1220 cross_line(Line,BB)
1221
1222 /* return True if line segments stored as diagonal of BB, Line
1223 * intersect. The line in BB is Manhattan.
1224 */
1225 struct ka *Line,*BB;
1226 {
1227 struct ka LineBB,MBB;
1228 long X,Y;
1229
1230 MBB = *BB;
1231 if (MBB.kaTop < MBB.kaBottom)
1232 SwapInts(MBB.kaTop,MBB.kaBottom);
1233 if (MBB.kaRight < MBB.kaLeft)
1234 SwapInts(MBB.kaRight,MBB.kaLeft);
1235 LineBB = *Line;
1236 if (LineBB.kaTop < LineBB.kaBottom)
1237 SwapInts(LineBB.kaTop,LineBB.kaBottom);
1238 if (LineBB.kaRight < LineBB.kaLeft)
1239 SwapInts(LineBB.kaRight,LineBB.kaLeft);
1240
1241 /* return False if BB's don't overlap */
1242 if (LineBB.kaLeft > MBB.kaRight ||
1243 LineBB.kaRight < MBB.kaLeft ||
1244 LineBB.kaBottom > MBB.kaTop ||
1245 LineBB.kaTop < MBB.kaBottom)
1246 return (False);
1247
1248 /* if Line is Manhattan, return True */
1249 if (Line->kaLeft == Line->kaRight || Line->kaBottom == Line->kaTop)
1250 return (True);
1251
1252 if (BB->kaBottom == BB->kaTop) {
1253
1254 X = (BB->kaBottom - Line->kaBottom)*
1255 ((double)(Line->kaRight - Line->kaLeft)/
1256 (Line->kaTop - Line->kaBottom)) +
1257 Line->kaLeft;
1258 if (X < BB->kaLeft || X > BB->kaRight) return (False);
1259 }
1260 else {
1261
1262 Y = (BB->kaLeft - Line->kaLeft)*
1263 ((double)(Line->kaTop - Line->kaBottom)/
1264 (Line->kaRight - Line->kaLeft))
1265 + Line->kaBottom;
1266 if (Y < BB->kaBottom || Y > BB->kaTop) return (False);
1267 }
1268 return (True);
1269 }
1270