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  * SCED copy and move selection operators.
11  */
12 
13 #include "spice.h"
14 #include "sced.h"
15 #include "scedmacs.h"
16 
17 #define MOVE 1
18 #define COPY 0
19 
20 extern char *MenuCOPY;
21 extern char *MenuMOVE;
22 extern char *MenuUNDO;
23 
24 #ifdef __STDC__
25 static void restore_color(void);
26 static void show_device(struct s*,struct ka*);
27 static void free_path(struct p*);
28 static void show_move(struct ka*,struct ka*);
29 static int  copy_OK(long,long);
30 static void do_copy(long,long,long,long,struct ka*,int);
31 static char fix_xform(int);
32 static void do_copy_call(long,long,long,long,struct o*,struct o**);
33 #else
34 static void restore_color();
35 static void show_device();
36 static void free_path();
37 static void show_move();
38 static int  copy_OK();
39 static void do_copy();
40 static char fix_xform();
41 static void do_copy_call();
42 #endif
43 
44 
45 void
Copy(LookedAhead)46 Copy(LookedAhead)
47 
48 int *LookedAhead;
49 {
50     struct ka BB;
51     long RefX,RefY,CopX,CopY;
52     int i;
53     int Undo = False;
54     int FirstTime = True;
55     int GotOne = False;
56     int Modified = 0;
57 
58     MenuSelect(MenuCOPY);
59 
60     if (SelectQHead != NULL)
61         GotOne = True;
62 top:
63 
64     if (Not GotOne) {
65         ShowPrompt("Point to object to copy.");
66         switch (PointLoop(LookedAhead)) {
67             case PL_ESC:
68             case PL_CMD:
69             case PL_UND:
70                 goto quit;
71             case PL_PCW:
72                 BB.kaLeft = BB.kaRight = SCursor.kcRawX;
73                 BB.kaBottom = BB.kaTop = SCursor.kcRawY;
74                 Selection(&BB);
75                 if (SelectQHead == NULL)
76                 goto top;
77         }
78     }
79 
80 Next:
81     ShowPrompt("Point to the reference point.");
82 
83     switch (PointLoop(LookedAhead)) {
84         case PL_ESC:
85         case PL_CMD:
86             goto quit;
87         case PL_UND:
88             if (Not GotOne) {
89                 SQComputeBB();
90                 SQDesel((char*)NULL);
91                 EraseBox(&SelectQBB);
92                 Redisplay(&SelectQBB);
93                 goto top;
94             }
95             goto quit;
96     }
97 
98     restore_color();
99     FBSetRubberBanding('m');
100     RefX = SCursor.kcX;
101     RefY = SCursor.kcY;
102     ShowPrompt("Point to locations where the selected items will be copied.");
103 
104     loop {
105         switch (PointLoop(LookedAhead)) {
106             case PL_ESC:
107             case PL_CMD:
108                 goto quit;
109             case PL_UND:
110                 MenuSelect(MenuUNDO);
111                 if (FirstTime) {
112                     MenuDeselect(MenuUNDO);
113                     FBSetRubberBanding(0);
114                     goto Next;
115                 }
116                 if (Undo == False) {
117                     SQRestore(True);
118                     EraseBox(&BB);
119                     Redisplay(&BB);
120                     Modified--;
121                     Undo = True;
122                 }
123                 else {
124                     do_copy(RefX,RefY,CopX,CopY,&BB,COPY);
125                     Redisplay(&BB);
126                     Modified++;
127                     Undo = False;
128                 }
129                 MenuDeselect(MenuUNDO);
130                 continue;
131             case PL_PCW:
132                 CopX = SCursor.kcX;
133                 CopY = SCursor.kcY;
134                 i = copy_OK(CopX-RefX,CopY-RefY);
135                 if (i == -1) goto quit;
136                 if (i == 0)  continue;
137                 SQRestore(False);
138                 do_copy(RefX,RefY,CopX,CopY,&BB,COPY);
139                 FirstTime = False;
140                 Undo = False;
141                 Modified++;
142                 Redisplay(&BB);
143                 continue;
144         }
145     }
146 
147 quit:
148     FBSetRubberBanding(0);
149     SQRestore(False);
150     if (Not GotOne And AreTypesInQ((char*)NULL)) {
151         SQComputeBB();
152         SQDesel((char*)NULL);
153         EraseBox(&SelectQBB);
154         Redisplay(&SelectQBB);
155     }
156     if (Modified)
157         Parameters.kpModified = True;
158     ErasePrompt();
159     MenuDeselect(MenuUNDO);
160     MenuDeselect(MenuCOPY);
161 }
162 
163 
164 void
Move(LookedAhead)165 Move(LookedAhead)
166 
167 int *LookedAhead;
168 {
169     struct ka OldBB,NewBB;
170     long LastRefX,LastRefY;
171     long RefX,RefY,MovX,MovY;
172     int  FirstTime = True;
173     int GotOne = False;
174     int Modified = 0;
175     int Undo = False;
176 
177     MenuSelect(MenuMOVE);
178 
179     if (SelectQHead != NULL)
180         GotOne = True;
181 
182     loop {
183 top:
184         if (Not GotOne) {
185             ShowPrompt("Point to object to move.");
186             switch (PointLoop(LookedAhead)) {
187                 case PL_ESC:
188                 case PL_CMD:
189                     goto quit;
190                 case PL_UND:
191                     if (FirstTime) goto quit;
192                     MenuSelect(MenuUNDO);
193                     if (Undo == False) {
194                         if (Parameters.kpShowTerminals)
195                             DisplayTerminals(ERASE);
196                         UndoReferenceTransform();
197                         HYundoTransform();
198                         SQRestore(True);
199                         /* restored objects have Info = SQ_NEWSEL */
200                         show_move(&NewBB,&OldBB);
201                         if (Parameters.kpShowTerminals)
202                             DisplayTerminals(DISPLAY);
203                         Modified--;
204                         Undo = True;
205                         MenuDeselect(MenuUNDO);
206                         break;
207                     }
208                     else {
209                         if (Parameters.kpShowTerminals)
210                             DisplayTerminals(ERASE);
211                         /* should have only Info = SQ_NEW objects here */
212                         do_copy(RefX,RefY,MovX,MovY,&NewBB,MOVE);
213                         SQDesel((char*)NULL);
214                         show_move(&OldBB,&NewBB);
215                         if (Parameters.kpShowTerminals)
216                             DisplayTerminals(DISPLAY);
217                         Modified++;
218                         Undo = False;
219                         MenuDeselect(MenuUNDO);
220                         continue;
221                     }
222                 case PL_PCW:
223                     SelectTypes((char*)NULL);
224                     if (Not AreTypesInQ((char*)NULL))
225                         goto top;
226             }
227         }
228 
229 next:
230         ShowPrompt("Point to the reference point.");
231         switch (PointLoop(LookedAhead)) {
232             case PL_ESC:
233             case PL_CMD:
234                 goto quit;
235             case PL_UND:
236                 MenuSelect(MenuUNDO);
237                 if (Not GotOne) {
238                     SQComputeBB();
239                     SQDesel((char*)NULL);
240                     /* newly selected objects deleted, restored objects
241                      * have Info = SQ_NEW.
242                      */
243                     EraseBox(&SelectQBB);
244                     Redisplay(&SelectQBB);
245                 }
246                 else {
247                     if (FirstTime) {
248                         MenuDeselect(MenuUNDO);
249                         goto quit;
250                     }
251                     if (Undo == False) {
252                         if (Parameters.kpShowTerminals)
253                             DisplayTerminals(ERASE);
254                         UndoReferenceTransform();
255                         HYundoTransform();
256                         SQRestore(True);
257                         /* restored objects have Info = SQ_NEWSEL */
258                         show_move(&OldBB,&NewBB);
259                         if (Parameters.kpShowTerminals)
260                             DisplayTerminals(DISPLAY);
261                         Modified--;
262                         Undo = True;
263                     }
264                     else {
265                         if (Parameters.kpShowTerminals)
266                             DisplayTerminals(ERASE);
267                         /* should have only Info = SQ_NEWSEL objects here */
268                         do_copy(RefX,RefY,MovX,MovY,&NewBB,MOVE);
269                         show_move(&OldBB,&NewBB);
270                         if (Parameters.kpShowTerminals)
271                             DisplayTerminals(DISPLAY);
272                         Modified++;
273                         Undo = False;
274                     }
275                 }
276                 MenuDeselect(MenuUNDO);
277                 goto top;
278         }
279 
280         restore_color();
281         FBSetRubberBanding('m');
282         LastRefX = RefX;
283         LastRefY = RefY;
284         RefX = SCursor.kcX;
285         RefY = SCursor.kcY;
286         ShowPrompt("Point to where the selected items will be moved.");
287 
288         switch (PointLoop(LookedAhead)) {
289             case PL_ESC:
290             case PL_CMD:
291                 goto quit;
292             case PL_UND:
293                 MenuSelect(MenuUNDO);
294                 RefX = LastRefX;
295                 RefY = LastRefY;
296                 MenuDeselect(MenuUNDO);
297                 FBSetRubberBanding(0);
298                 goto next;
299         }
300 
301         FBSetRubberBanding(0);
302         SQComputeBB();
303         OldBB = SelectQBB;
304         MovX = SCursor.kcX;
305         MovY = SCursor.kcY;
306         SQRestore(False);
307         if (Parameters.kpShowTerminals) DisplayTerminals(ERASE);
308         do_copy(RefX,RefY,MovX,MovY,&NewBB,MOVE);
309         FirstTime = False;
310         Modified++;
311         Undo = False;
312         if (Not GotOne)
313             SQDesel((char*)NULL);
314         show_move(&OldBB,&NewBB);
315         if (Parameters.kpShowTerminals) DisplayTerminals(DISPLAY);
316     }
317 quit:
318     FBSetRubberBanding(0);
319     ClearReferenceUndoFlags();
320     HYclearUndoFlags();
321     SQRestore(False);
322     if (Not GotOne And AreTypesInQ((char*)NULL)) {
323         SQComputeBB();
324         SQDesel((char*)NULL);
325         EraseBox(&SelectQBB);
326         Redisplay(&SelectQBB);
327     }
328     if (Modified)
329         Parameters.kpModified = True;
330     ErasePrompt();
331     MenuDeselect(MenuUNDO);
332     MenuDeselect(MenuMOVE);
333 }
334 
335 
336 void
ShowGhost(NewX,NewY,RefX,RefY)337 ShowGhost(NewX,NewY,RefX,RefY)
338 
339 /* Called from rubber banding routine. */
340 long NewX,NewY,RefX,RefY;
341 {
342     struct ks *SQDesc;
343     struct p *Path;
344     struct ka BB;
345     struct s *MasterDesc;
346     int  Layer;
347     int NumX,NumY,Int1,Int2;
348     long Width;
349     long TFold[9], TFnew[9], TFtemp[9];
350     long DX,DY;
351     char *MasterName;
352 
353 
354     TCurrent(TFold);
355     TPush();
356     TIdentity();
357     SetNewTransform(RefX,RefY,NewX,NewY);
358     TCurrent(TFnew);
359     TPop();
360 
361     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
362         if (SQDesc->ksPointer->oInfo != SQ_OLDSEL &&
363             SQDesc->ksPointer->oInfo != SQ_NEWSEL) continue;
364         /* prevent drawing duplicate entries twice */
365         SQDesc->ksPointer->oInfo += 20;
366 
367         switch (SQDesc->ksPointer->oType) {
368 
369             case CDSYMBOLCALL:
370                 CDCall(SQDesc->ksPointer,&MasterName,&NumX,&DX,&NumY,&DY);
371                 if (IsCellInLib(MasterName)) {
372 
373                     if (OpenCell(MasterName,&MasterDesc)) break;
374 
375                     SetTransform(SQDesc->ksPointer);
376                     SetNewTransform(RefX,RefY,NewX,NewY);
377                     TPremultiply();
378 
379                     for (Int1 = NumY-1; Int1 >= 0; --Int1) {
380                         for (Int2 = 0; Int2 < NumX; ++Int2 ){
381                             TPush();
382                             TIdentity();
383                             TTranslate(Int2*DX,Int1*DY);
384                             TPremultiply();
385                             ShowTransformed(MasterDesc,View->kvCoarseWindow,
386                                 TFold);
387                             TPop();
388                         }
389                     }
390                     TPop();
391                     break;
392                 }
393 
394             case CDLABEL:
395                 if (SQDesc->ksPointer->oType == CDLABEL)
396                     BBLabel(View->kvCoarseWindow,SQDesc->ksPointer,&BB);
397                 else
398                     CDStatusInt = CDBB(Parameters.kpCellDesc,
399                         SQDesc->ksPointer,&BB.kaLeft,
400                         &BB.kaBottom,&BB.kaRight,&BB.kaTop);
401                 TLoadCurrent(TFnew);
402                 TPoint(&BB.kaLeft,&BB.kaBottom);
403                 TPoint(&BB.kaRight,&BB.kaTop);
404                 TLoadCurrent(TFold);
405                 ShowEmptyBox(HighlightingColor,&BB);
406                 break;
407 
408             case CDWIRE:
409                 CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
410                 TLoadCurrent(TFnew);
411                 CopyPathWithXForm(&Path);
412                 TLoadCurrent(TFold);
413                 ShowWire(HighlightingColor,Width,Path);
414                 free_path(Path);
415                 break;
416 
417             case CDPOLYGON:
418                 CDPolygon(SQDesc->ksPointer,&Layer,&Path);
419                 TLoadCurrent(TFnew);
420                 CopyPathWithXForm(&Path);
421                 TLoadCurrent(TFold);
422                 ShowPath(HighlightingColor,Path,True);
423                 free_path(Path);
424                 break;
425         }
426     }
427     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc)
428         if (SQDesc->ksPointer->oInfo > 20)
429             SQDesc->ksPointer->oInfo -= 20;
430 }
431 
432 
433 void
CopyPathWithXForm(Path)434 CopyPathWithXForm(Path)
435 
436 struct p **Path;
437 {
438     struct p *OldPair,*NewPair;
439     /*
440      * Copy Path with transform and return pointer to new path
441      */
442     OldPair = *Path;
443     if ((NewPair = alloc(p)) == NULL)
444         MallocFailed();
445     *Path = NewPair;
446     NewPair->pX = OldPair->pX;
447     NewPair->pY = OldPair->pY;
448     TPoint(&NewPair->pX,&NewPair->pY);
449     NewPair->pSucc = NULL;
450     OldPair = OldPair->pSucc;
451     while(OldPair != NULL) {
452         if ((NewPair->pSucc = alloc(p)) == NULL)
453             MallocFailed();
454         NewPair = NewPair->pSucc;
455         NewPair->pX = OldPair->pX;
456         NewPair->pY = OldPair->pY;
457         NewPair->pSucc = NULL;
458         TPoint(&NewPair->pX,&NewPair->pY);
459         OldPair = OldPair->pSucc;
460     }
461 }
462 
463 
464 static void
restore_color()465 restore_color()
466 
467 /* repaint with drawing color */
468 {
469     struct ks *SQDesc;
470     struct p *Path;
471     struct ka BB;
472     struct s *MasterDesc;
473     int  Layer;
474     int NumX,NumY,Int1,Int2;
475     long Width;
476     long DX,DY;
477     char *MasterName;
478 
479     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
480         if (SQDesc->ksPointer->oInfo != SQ_OLDSEL &&
481             SQDesc->ksPointer->oInfo != SQ_NEWSEL) continue;
482 
483         switch (SQDesc->ksPointer->oType) {
484 
485             case CDSYMBOLCALL:
486                 CDCall(SQDesc->ksPointer,&MasterName,&NumX,&DX,&NumY,&DY);
487                 if (IsCellInLib(MasterName)) {
488 
489                     if (OpenCell(MasterName,&MasterDesc)) break;
490 
491                     SetTransform(SQDesc->ksPointer);
492                     TPremultiply();
493 
494                     for (Int1 = NumY-1; Int1 >= 0; --Int1) {
495                         for (Int2 = 0; Int2 < NumX; ++Int2 ){
496                             TPush();
497                             TIdentity();
498                             TTranslate(Int2*DX,Int1*DY);
499                             TPremultiply();
500                             show_device(MasterDesc,View->kvCoarseWindow);
501                             TPop();
502                         }
503                     }
504                     TPop();
505                     break;
506                 }
507 
508             case CDLABEL:
509                 if (SQDesc->ksPointer->oType == CDLABEL)
510                     BBLabel(View->kvCoarseWindow,SQDesc->ksPointer,&BB);
511                 else
512                     CDStatusInt = CDBB(Parameters.kpCellDesc,
513                         SQDesc->ksPointer,&BB.kaLeft,
514                         &BB.kaBottom,&BB.kaRight,&BB.kaTop);
515                 ShowEmptyBox(DrawingColor,&BB);
516                 break;
517 
518             case CDWIRE:
519                 CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
520                 ShowWire(DrawingColor,Width,Path);
521                 break;
522 
523             case CDPOLYGON:
524                 CDPolygon(SQDesc->ksPointer,&Layer,&Path);
525                 ShowPath(DrawingColor,Path,True);
526                 break;
527         }
528     }
529 }
530 
531 
532 static void
show_device(CellDesc,AOI)533 show_device(CellDesc,AOI)
534 
535 struct s *CellDesc;
536 struct ka *AOI;
537 {
538     struct g *GenDesc;
539     struct o *Pointer;
540     struct p *Path;
541     int Layer;
542     long Width;
543 
544     if (Not CDInitGen(CellDesc,1,AOI->kaLeft,AOI->kaBottom,
545         AOI->kaRight,AOI->kaTop,&GenDesc)) MallocFailed();
546 
547     loop {
548         CDGen(CellDesc,GenDesc,&Pointer);
549         if (Pointer == NULL) break;
550         if (Pointer->oInfo == SQ_GONE) continue;
551 
552         switch (Pointer->oType) {
553 
554             case CDLABEL:
555                 /*
556                 BBLabel(View->kvCoarseWindow,Pointer,&BB);
557                 ShowEmptyBox(BackgroundColor,&BB);
558                 */
559                 break;
560 
561             case CDWIRE:
562                 CDWire(Pointer,&Layer,&Width,&Path);
563                 ShowWire(DrawingColor,Width,Path);
564                 break;
565 
566             case CDPOLYGON:
567                 CDPolygon(Pointer,&Layer,&Path);
568                 ShowPath(DrawingColor,Path,True);
569                 break;
570         }
571     }
572 }
573 
574 
575 void
ShowTransformed(CellDesc,AOI,TFold)576 ShowTransformed(CellDesc,AOI,TFold)
577 
578 struct s *CellDesc;
579 struct ka *AOI;
580 long *TFold;
581 {
582     struct g *GenDesc;
583     struct o *Pointer;
584     struct p *Path;
585     struct ka BB;
586     int Layer;
587     long Width;
588     long TFtmp[9];
589 
590     if (Not CDInitGen(CellDesc,1,AOI->kaLeft,AOI->kaBottom,
591         AOI->kaRight,AOI->kaTop,&GenDesc)) MallocFailed();
592 
593     TCurrent(TFtmp);
594     loop {
595         CDGen(CellDesc,GenDesc,&Pointer);
596         if (Pointer == NULL) break;
597         if (Pointer->oInfo == SQ_GONE) continue;
598 
599         switch (Pointer->oType) {
600 
601             case CDLABEL:
602                 BBLabel(View->kvCoarseWindow,Pointer,&BB);
603                 TPoint(&BB.kaLeft,&BB.kaBottom);
604                 TPoint(&BB.kaRight,&BB.kaTop);
605                 TLoadCurrent(TFold);
606                 ShowEmptyBox(HighlightingColor,&BB);
607                 TLoadCurrent(TFtmp);
608                 break;
609 
610             case CDWIRE:
611                 CDWire(Pointer,&Layer,&Width,&Path);
612                 CopyPathWithXForm(&Path);
613                 TLoadCurrent(TFold);
614                 ShowWire(HighlightingColor,Width,Path);
615                 TLoadCurrent(TFtmp);
616                 free_path(Path);
617                 break;
618 
619             case CDPOLYGON:
620                 CDPolygon(Pointer,&Layer,&Path);
621                 CopyPathWithXForm(&Path);
622                 TLoadCurrent(TFold);
623                 ShowPath(HighlightingColor,Path,True);
624                 TLoadCurrent(TFtmp);
625                 free_path(Path);
626                 break;
627         }
628     }
629 }
630 
631 
632 static void
free_path(Path)633 free_path(Path)
634 
635 struct p *Path;
636 {
637     struct p *Next;
638 
639     for (; Path; Path = Next) {
640         Next = Path->pSucc;
641         free(Path);
642     }
643 }
644 
645 
646 static void
show_move(OBB,NBB)647 show_move(OBB,NBB)
648 
649 struct ka *OBB,*NBB;
650 {
651     long L1,R1,B1,T1,L2,R2,B2,T2;
652     struct ka BB;
653 
654     L1 = NBB->kaLeft;
655     R1 = NBB->kaRight;
656     B1 = NBB->kaBottom;
657     T1 = NBB->kaTop;
658     L2 = OBB->kaLeft;
659     R2 = OBB->kaRight;
660     B2 = OBB->kaBottom;
661     T2 = OBB->kaTop;
662     if (L1 > R1) SwapInts(L1,R1);
663     if (B1 > T1) SwapInts(B1,T1);
664     if (L2 > R2) SwapInts(L2,R2);
665     if (B2 > T2) SwapInts(B2,T2);
666     if (L1 > R2 Or L2 > R1 Or B1 > T2 Or B2 > T1) {
667         /*
668          * Old BB is not within the new BB
669          * So, redisplay twice.
670          */
671         EraseBox(OBB);
672         Redisplay(OBB);
673         EraseBox(NBB);
674         Redisplay(NBB);
675         return;
676     }
677     /*
678      * Old BB intersects new BB
679      */
680     BB.kaLeft   = Min(L1,L2);
681     BB.kaRight  = Max(R1,R2);
682     BB.kaBottom = Min(B1,B2);
683     BB.kaTop    = Max(T1,T2);
684     EraseBox(&BB);
685     Redisplay(&BB);
686 }
687 
688 
689 static int
copy_OK(X,Y)690 copy_OK(X,Y)
691 
692 long X,Y;
693 {
694     char *TypeIn;
695 
696     if (Not Parameters.kpMX And Not Parameters.kpMY And
697         Parameters.kpRotationAngle == 0 And
698         X == 0 And Y == 0 ) {
699 
700         ShowPrompt(
701          "This will copy objects directly over themselves.  Continue(N)?");
702         TypeIn = FBEdit(NULL);
703         if (TypeIn == NULL) return (-1);
704         if ((TypeIn[0] != 'Y' And TypeIn[0] != 'y'))
705             return (0);
706     }
707     return (1);
708 }
709 
710 
711 static void
do_copy(RefX,RefY,NewX,NewY,NewBB,MoveOrCopy)712 do_copy(RefX,RefY,NewX,NewY,NewBB,MoveOrCopy)
713 
714 long RefX,RefY,NewX,NewY;
715 struct ka *NewBB;
716 int MoveOrCopy;
717 {
718     struct ks *SQDesc;
719     struct p *Path;
720     struct ka BB;
721     struct o *Pointer;
722     struct prpty *PDesc;
723     long X,Y,Length,Width;
724     int  Layer;
725     char *Label;
726     char Xform;
727 
728     BB.kaLeft = BB.kaRight = NewX;
729     BB.kaTop = BB.kaBottom = NewY;
730     NewBB->kaLeft = NewBB->kaRight = NewX;
731     NewBB->kaTop = NewBB->kaBottom = NewY;
732 
733     if (MoveOrCopy == COPY) {
734         /* identify mutual inductors */
735         PDesc = Parameters.kpCellDesc->sPrptyList;
736         for (; PDesc; PDesc = PDesc->prpty_Succ) {
737             if (PDesc->prpty_Value != P_MUT) continue;
738             if (MutSelected(PDesc)) {
739                 CDCopyProperty(Parameters.kpCellDesc,(struct o*)NULL,
740                     PDesc);
741                 Parameters.kpCellDesc->sPrptyList->prpty_Info = "new";
742             }
743         }
744     }
745 
746     TPush();
747     TIdentity();
748     SetNewTransform(RefX,RefY,NewX,NewY);
749 
750     if (MoveOrCopy == COPY) {
751         /* transform mutual inductors */
752         PDesc = Parameters.kpCellDesc->sPrptyList;
753         for (; PDesc; PDesc = PDesc->prpty_Succ) {
754             if (PDesc->prpty_Value != P_MUT) break;
755             if (PDesc->prpty_Info && !strcmp(PDesc->prpty_Info,"new")) {
756                 TPoint((long*)&PDesc->prpty_Data->p_mut.x1,
757                     (long*)&PDesc->prpty_Data->p_mut.y1);
758                 TPoint((long*)&PDesc->prpty_Data->p_mut.x2,
759                     (long*)&PDesc->prpty_Data->p_mut.y2);
760                 continue;
761             }
762             break;
763         }
764     }
765 
766     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
767         if (SQDesc->ksPointer->oInfo == SQ_GONE) continue;
768 
769         switch (SQDesc->ksPointer->oType) {
770             case CDLABEL:
771 
772                 CDLabel(SQDesc->ksPointer,&Layer,&Label,&X,&Y,&Xform);
773                 TPoint(&X,&Y);
774 
775                 if (Not CDMakeLabel(Parameters.kpCellDesc,Layer,Label,
776                     X,Y,fix_xform(Xform),&Pointer)) MallocFailed();
777                 break;
778 
779             case CDWIRE:
780                 CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
781                 CopyPathWithXForm(&Path);
782                 if (Not CDMakeWire(Parameters.kpCellDesc,Layer,Width,Path,
783                     &Pointer)) MallocFailed();
784                 AssignWireProperties(Pointer);
785                 break;
786 
787             case CDPOLYGON:
788                 CDPolygon(SQDesc->ksPointer,&Layer,&Path);
789                 CopyPathWithXForm(&Path);
790                 if (Not CDMakePolygon(Parameters.kpCellDesc,Layer,Path,
791                     &Pointer)) MallocFailed();
792                 break;
793 
794             case CDSYMBOLCALL:
795                 do_copy_call(RefX,RefY,NewX,NewY,SQDesc->ksPointer,&Pointer);
796                 break;
797 
798             default:
799                 continue;
800         }
801 
802         if (SQDesc->ksPointer->oType == CDLABEL)
803             BBLabel(View->kvCoarseWindow,Pointer,&BB);
804         else
805             CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,&BB.kaLeft,
806                 &BB.kaBottom,&BB.kaRight,&BB.kaTop);
807         if (MoveOrCopy == MOVE)
808             Pointer->oInfo = SQ_NEWSEL;
809         else
810             Pointer->oInfo = SQ_NEW;
811         SQInsert(Pointer);
812 
813         if (BB.kaLeft   < NewBB->kaLeft)   NewBB->kaLeft   = BB.kaLeft;
814         if (BB.kaRight  > NewBB->kaRight)  NewBB->kaRight  = BB.kaRight;
815         if (BB.kaBottom < NewBB->kaBottom) NewBB->kaBottom = BB.kaBottom;
816         if (BB.kaTop    > NewBB->kaTop)    NewBB->kaTop    = BB.kaTop;
817 
818         if (MoveOrCopy == MOVE) {
819             TransformReferences(SQDesc->ksPointer);
820             HYtransform(SQDesc->ksPointer,Pointer);
821             SQDesc->ksPointer->oInfo = SQ_GONE;
822         }
823     }
824     TPop();
825 }
826 
827 
828 static char
fix_xform(Xform)829 fix_xform(Xform)
830 
831 char Xform;
832 {
833     long TF[9];
834 
835     TPush();
836     TIdentity();
837     if (Parameters.kpMX) TMX();
838     if (Parameters.kpMY) TMY();
839     if (Parameters.kpRotationAngle != 0) {
840         if (Parameters.kpRotationAngle == 180)   TRotate(-1L,0L);
841         elif (Parameters.kpRotationAngle == 90)  TRotate(0L,1L);
842         elif (Parameters.kpRotationAngle == 270) TRotate(0L,-1L);
843     }
844     if (Xform & 4) TMY();
845     if (Xform & 8) TMX();
846     Xform &= 3;
847     if (Xform != 0) {
848         if (Xform == 1)   TRotate(0L,1L);
849         elif (Xform == 2) TRotate(-1L,0L);
850         elif (Xform == 3) TRotate(0L,-1L);
851     }
852     TCurrent(TF);
853     Xform = SetXform(TF);
854     TPop();
855     return (Xform);
856 }
857 
858 
859 static void
do_copy_call(RefX,RefY,NewX,NewY,OPointer,NPointer)860 do_copy_call(RefX,RefY,NewX,NewY,OPointer,NPointer)
861 
862 long RefX,RefY,NewX,NewY;
863 struct o *OPointer;
864 struct o **NPointer;
865 {
866     char *SymbolName;
867     int NumX,NumY;
868     long DX,DY;
869     long TF[9];
870     struct o *Pointer;
871     struct prpty *PDesc;
872 
873     CDCall(OPointer,&SymbolName,&NumX,&DX,&NumY,&DY);
874     /* only possible error is CDMALLOCFAILED */
875     if (Not CDBeginMakeCall(Parameters.kpCellDesc,SymbolName,
876         NumX,DX,NumY,DY,&Pointer))
877         MallocFailed();
878 
879     SetTransform(OPointer);
880     SetNewTransform(RefX,RefY,NewX,NewY);
881     TCurrent(TF);
882     AddResultingTransform(Pointer,TF);
883     if (Not CDEndMakeCall(Parameters.kpCellDesc,Pointer))
884         MallocFailed();
885 
886     /* remove any default user properties */
887     CDRemoveProperty(Parameters.kpCellDesc,Pointer,P_VALUE);
888     CDRemoveProperty(Parameters.kpCellDesc,Pointer,P_MODEL);
889     CDRemoveProperty(Parameters.kpCellDesc,Pointer,P_INITC);
890     CDRemoveProperty(Parameters.kpCellDesc,Pointer,P_OTHER);
891 
892     /* add the user properties */
893     for (PDesc = OPointer->oPrptyList; PDesc; PDesc = PDesc->prpty_Succ) {
894         if (PDesc->prpty_Value == P_VALUE ||
895             PDesc->prpty_Value == P_MODEL ||
896             PDesc->prpty_Value == P_INITC ||
897             PDesc->prpty_Value == P_OTHER) {
898             CDCopyProperty(Parameters.kpCellDesc,Pointer,PDesc);
899         }
900     }
901 
902     *NPointer = Pointer;
903     TPop();
904 }
905 
906 
907 void
SetNewTransform(RefX,RefY,NewX,NewY)908 SetNewTransform(RefX,RefY,NewX,NewY)
909 
910 long RefX,RefY,NewX,NewY;
911 {
912     TTranslate(-RefX,-RefY);
913     if (Parameters.kpMX) TMX();
914     if (Parameters.kpMY) TMY();
915     if (Parameters.kpRotationAngle != 0) {
916         if (Parameters.kpRotationAngle == 90)    TRotate(0L,1L);
917         elif (Parameters.kpRotationAngle == 180) TRotate(-1L,0L);
918         elif (Parameters.kpRotationAngle == 270) TRotate(0L,-1L);
919     }
920     TTranslate(NewX,NewY);
921 }
922 
923 
924 void
AddResultingTransform(Pointer,TF)925 AddResultingTransform(Pointer,TF)
926 
927 struct o *Pointer;
928 long *TF;
929 {
930     long A,B,C,D,TX,TY;
931     int ret;
932     /*
933      * Take the transformation defined in TF and add
934      * it to the symbol call currently being created.
935      *
936      *                  | a    c    0  |
937      * Transform = TM = | b    d    0  |
938      *                  | TX   TY   1  |
939      *
940      * A = TM[0][0] = TF[0];
941      * B = TM[1][0] = TF[3];
942      * C = TM[0][1] = TF[1];
943      * D = TM[1][1] = TF[4];
944      * TX = TM[2][0] = TF[6];
945      * TY = TM[2][1] = TF[7];
946      */
947     A = TF[0]; B = TF[3]; C = TF[1]; D = TF[4];
948     TX = TF[6]; TY = TF[7];
949     if (A == 0 And B == 1 And C == 1 And D == 0) {
950         /* MX R 0 -1 T tx,ty */
951         ret = CDT(Pointer,CDMIRRORX,0L,0L);
952         ret &= CDT(Pointer,CDROTATE,0L,-1L);
953         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
954     }
955     elif (A == 0 And B == -1 And C == -1 And D == 0) {
956         /* MX R 0 1 T tx,ty */
957         ret = CDT(Pointer,CDMIRRORX,0L,0L);
958         ret &= CDT(Pointer,CDROTATE,0L,1L);
959         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
960     }
961     elif (A == 0 And B == 1 And C == -1 And D == 0) {
962         /* R 0 -1 T tx,ty */
963         ret = CDT(Pointer,CDROTATE,0L,-1L);
964         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
965     }
966     elif (A == 0 And B == -1 And C == 1 And D == 0) {
967         /* R 0 1 T tx,ty */
968         ret = CDT(Pointer,CDROTATE,0L,1L);
969         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
970     }
971     elif (A == 1 And B == 0 And C == 0 And D == 1) {
972         /* T tx,ty */
973         ret = CDT(Pointer,CDTRANSLATE,TX,TY);
974     }
975     elif (A == -1 And B == 0 And C == 0 And D == -1) {
976         /* R -1 0 T tx,ty */
977         ret = CDT(Pointer,CDROTATE,-1L,0L);
978         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
979     }
980     elif (A == -1 And B == 0 And C == 0 And D == 1) {
981         /* MX T tx,ty */
982         ret = CDT(Pointer,CDMIRRORX,0L,0L);
983         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
984     }
985     else{
986         /* MY T tx,ty */
987         ret = CDT(Pointer,CDMIRRORY,0L,0L);
988         ret &= CDT(Pointer,CDTRANSLATE,TX,TY);
989     }
990     if (Not ret)
991         MallocFailed();
992 }
993 
994