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 display control code.
11 */
12
13 #include "spice.h"
14 #include "sced.h"
15 #include "scedmacs.h"
16
17
18
19 /***********************************************************************
20 *
21 * Window manipulation menu commands.
22 *
23 ***********************************************************************/
24
25 extern char *MenuPAN;
26 extern char *MenuZOOM;
27 extern char *MenuWINDO;
28 extern char *MenuLAST;
29
30 void
Pan(LookedAhead)31 Pan(LookedAhead)
32
33 int *LookedAhead;
34 {
35 MenuSelect(MenuPAN);
36 ShowPrompt("Point to center of new window.");
37 loop {
38 switch (PointLoopSafe(LookedAhead)) {
39 case PL_ESC:
40 case PL_CMD:
41 MenuDeselect(MenuPAN);
42 ErasePrompt();
43 return;
44 case PL_PCW:
45 SaveLastView();
46 InitCoarseWindow(SCursor.kcX,SCursor.kcY,
47 (long)View->kvCoarseWindow->kaWidth);
48 InitFineWindow(SCursor.kcX, SCursor.kcY);
49 EraseLargeCoarseViewport();
50 Redisplay(View->kvCoarseWindow);
51 }
52 }
53 }
54
55
56 void
Zoom(LookedAhead)57 Zoom(LookedAhead)
58
59 int *LookedAhead;
60 {
61 char *TypeIn;
62 long NewWindowWidth;
63 long X,Y;
64
65 MenuSelect(MenuZOOM);
66 sprintf(TypeOut,
67 "Enter window width (now %g) or RETURN for %s display: ",
68 View->kvCoarseWindow->kaWidth/RESOLUTION,
69 View->kvControl == SPLITSCREEN ? "full screen" : "split screen");
70 ShowPrompt(TypeOut);
71 TypeIn = FBEdit(NULL);
72 if (TypeIn == NULL) { /* esc entered */
73 MenuDeselect(MenuZOOM);
74 ErasePrompt();
75 return;
76 }
77 SaveLastView();
78 if ((sscanf(TypeIn,"%ld",&NewWindowWidth) < 1) Or NewWindowWidth <= 0) {
79 if (View->kvControl != FULLSCREEN) {
80 View->kvControl = FULLSCREEN;
81 Parameters.kpRedisplayControl = COARSEVIEWPORTONLY;
82 NewWindowWidth = View->kvFineWindow->kaWidth;
83 View->kvCoarseWindow->kaX = View->kvFineWindow->kaX;
84 View->kvCoarseWindow->kaY = View->kvFineWindow->kaY;
85 InitCoarseWindow(View->kvCoarseWindow->kaX,
86 View->kvCoarseWindow->kaY,NewWindowWidth);
87 SetPositioning();
88 }
89 else {
90 View->kvControl = SPLITSCREEN;
91 Parameters.kpRedisplayControl = SPLITSCREEN;
92 X = View->kvCoarseWindow->kaX;
93 Y = View->kvCoarseWindow->kaY;
94 NewWindowWidth = View->kvCoarseWindow->kaWidth;
95 SetPositioning();
96 CenterFullView();
97 if (NewWindowWidth > View->kvCoarseWindow->kaWidth)
98 NewWindowWidth = 3*View->kvCoarseWindow->kaWidth/4;
99 View->kvFineWindow->kaWidth = NewWindowWidth;
100 InitFineWindow(X,Y);
101 }
102 }
103 else {
104 NewWindowWidth *= RESOLUTION;
105 if (View->kvControl == FULLSCREEN)
106 InitCoarseWindow(View->kvCoarseWindow->kaX,
107 View->kvCoarseWindow->kaY,NewWindowWidth);
108 else
109 /* zoom from fine window position */
110 InitCoarseWindow(View->kvFineWindow->kaX,
111 View->kvFineWindow->kaY,NewWindowWidth);
112 SetPositioning();
113 }
114 EraseLargeCoarseViewport();
115 if (View->kvControl == FULLSCREEN)
116 Redisplay(View->kvCoarseWindow);
117 else {
118 /* make sure fine window is shown, if out of coarse clip range */
119 Parameters.kpRedisplayControl = COARSEVIEWPORTONLY;
120 Redisplay(View->kvCoarseWindow);
121 ShowEmptyBox(HighlightingColor,View->kvFineWindow);
122 Parameters.kpRedisplayControl = FINEVIEWPORTONLY;
123 Redisplay(View->kvFineWindow);
124 Parameters.kpRedisplayControl = SPLITSCREEN;
125 }
126 MenuDeselect(MenuZOOM);
127 *LookedAhead = False;
128 ErasePrompt();
129 return;
130 }
131
132
133 void
Windo(LookedAhead)134 Windo(LookedAhead)
135
136 int *LookedAhead;
137 {
138 long NewWindowWidth, Width, Height, Tmp;
139 MenuSelect(MenuWINDO);
140 loop{
141 ShowPrompt("Point to endpoints of diagonal.");
142 switch (PointLoopSafe(LookedAhead)) {
143 case PL_ESC:
144 case PL_CMD:
145 goto quit;
146 case PL_PCW:
147 break;
148 }
149 FBSetRubberBanding('R');
150 switch (PointLoopSafe(LookedAhead)) {
151 case PL_ESC:
152 case PL_CMD:
153 FBSetRubberBanding(0);
154 goto quit;
155 case PL_PCW:
156 FBSetRubberBanding(0);
157 break;
158 }
159 SaveLastView();
160 /*
161 * Coarse window height is smaller than its width.
162 * When user points to endpoints of diagonal to define new window,
163 * he expects to see everything in this window after redisplay.
164 * To make this happen, we have to EXPAND the width enough so that
165 * the height that InitCoarseWindow computes is equal to the height
166 * the user wants.
167 * The following lines compute the multiplier that expands the
168 * width by the right amount.
169 */
170
171 Width = SCursor.kcX - SCursor.kcPredX;
172 Height = SCursor.kcY - SCursor.kcPredY;
173 if (Width < 0) Width = -Width;
174 if (Height < 0) Height = -Height;
175
176 Tmp = Height * View->kvCoarseViewport->kaWidth/
177 View->kvCoarseViewport->kaHeight;
178 NewWindowWidth = Max(Width,Tmp);
179
180 Height /= 2;
181 Width /= 2;
182
183 if (NewWindowWidth <= 0) NewWindowWidth = RESOLUTION;
184 InitCoarseWindow( Min(SCursor.kcX,SCursor.kcPredX)+Width,
185 Min(SCursor.kcY,SCursor.kcPredY)+Height,NewWindowWidth);
186
187 InitFineWindow(Min(SCursor.kcX,SCursor.kcPredX)+Width,
188 Min(SCursor.kcY,SCursor.kcPredY)+Height);
189
190 SetPositioning();
191 EraseLargeCoarseViewport();
192 Redisplay(View->kvCoarseWindow);
193 }
194 quit:
195 MenuDeselect(MenuWINDO);
196 ErasePrompt();
197 }
198
199
200 void
LastView()201 LastView()
202
203 {
204 int i;
205 struct kw Last;
206 struct kw *Tmp;
207 char OldMenu;
208 int EscWasReturned = 0;
209
210 Last.kwLastWindowX = View->kvCoarseWindow->kaX;
211 Last.kwLastWindowY = View->kvCoarseWindow->kaY;
212 Last.kwLastFineWindowX = View->kvFineWindow->kaX;
213 Last.kwLastFineWindowY = View->kvFineWindow->kaY;
214 Last.kwLastWindowWidth = View->kvCoarseWindow->kaWidth;
215 Last.kwLastFineWindowWidth = View->kvFineWindow->kaWidth;
216 (Last.kwName)[5] = View->kvFineViewportOnBottom;
217 (Last.kwName)[6] = View->kvControl;
218
219 i = 0;
220 for (Tmp = Parameters.kpWindowStack; Tmp; Tmp = Tmp->kwNext)
221 AmbiguityMenu[i++].mEntry = Tmp->kwName;
222 AmbiguityMenu[i].mEntry = NULL;
223 FixMenuPrefix(AmbiguityMenu);
224
225 if (i > 1) {
226 /* Show ambiguity menu. */
227 OldMenu = Parameters.kpMenu;
228 Parameters.kpMenu = AMBIGUITYMENU;
229 ShowMenu(AmbiguityMenu);
230
231 /* Which viewport is user interested in? */
232 ShowPrompt("Point to the name of the desired view.");
233 loop {
234 int dummy;
235 switch (PointLoopSafe(&dummy)) {
236 case PL_ESC:
237 EscWasReturned = 1;
238 break;
239 case PL_CMD:
240 break;
241 case PL_PCW:
242 ShowPrompt("You aren't pointing at the menu.");
243 continue;
244 }
245 break;
246 }
247 Parameters.kpMenu = OldMenu;
248 ShowCommandMenu();
249 if (EscWasReturned) goto quit;
250
251 /* find new view */
252 for (Tmp = Parameters.kpWindowStack; Tmp; Tmp = Tmp->kwNext)
253 if (strncmp(Tmp->kwName,Parameters.kpCommand,
254 MenuViewport.kaRight-MenuViewport.kaLeft+1) == 0){
255 break;
256 }
257 }
258 else
259 Tmp = Parameters.kpWindowStack;
260
261 /* The status of the fine window positioning is stored in
262 * the name field, as is full screen mode flag.
263 */
264 View->kvFineViewportOnBottom = (Tmp->kwName)[5];
265 View->kvControl = (Tmp->kwName)[6];
266
267 InitViewport();
268
269 /* change to new viewport */
270 InitCoarseWindow(Tmp->kwLastWindowX,Tmp->kwLastWindowY,
271 Tmp->kwLastWindowWidth);
272
273 SetPositioning();
274
275 InitFineWindow(Tmp->kwLastFineWindowX,Tmp->kwLastFineWindowY);
276
277 Parameters.kpWindowStack->kwLastWindowX = Last.kwLastWindowX;
278 Parameters.kpWindowStack->kwLastWindowY = Last.kwLastWindowY;
279 Parameters.kpWindowStack->kwLastFineWindowX = Last.kwLastFineWindowX;
280 Parameters.kpWindowStack->kwLastFineWindowY = Last.kwLastFineWindowY;
281 Parameters.kpWindowStack->kwLastWindowWidth = Last.kwLastWindowWidth;
282 Parameters.kpWindowStack->kwLastFineWindowWidth = Last.kwLastFineWindowWidth;
283 Parameters.kpWindowStack->kwExpand = Last.kwExpand;
284 Parameters.kpWindowStack->kwExpandFineOnly = Last.kwExpandFineOnly;
285 (Parameters.kpWindowStack->kwName)[5] = (Last.kwName)[5];
286 (Parameters.kpWindowStack->kwName)[6] = (Last.kwName)[6];
287
288 EraseLargeCoarseViewport();
289 Redisplay(View->kvCoarseWindow);
290 quit:
291 MenuDeselect(MenuLAST);
292 ErasePrompt();
293 }
294
295
296 void
SaveLastView()297 SaveLastView()
298
299 {
300 /*
301 * Parameters.kpWindowStack is always the last view.
302 */
303 if (Parameters.kpWindowStack == NULL) {
304 if ((Parameters.kpWindowStack = alloc(kw)) == NULL)
305 MallocFailed();
306 strcpy(Parameters.kpWindowStack->kwName,"prev");
307 Parameters.kpWindowStack->kwNext = NULL;
308 }
309 Parameters.kpWindowStack->kwLastWindowX = View->kvCoarseWindow->kaX;
310 Parameters.kpWindowStack->kwLastWindowY = View->kvCoarseWindow->kaY;
311 Parameters.kpWindowStack->kwLastFineWindowX = View->kvFineWindow->kaX;
312 Parameters.kpWindowStack->kwLastFineWindowY = View->kvFineWindow->kaY;
313 Parameters.kpWindowStack->kwLastWindowWidth =
314 View->kvCoarseWindow->kaWidth;
315 Parameters.kpWindowStack->kwLastFineWindowWidth =
316 View->kvFineWindow->kaWidth;
317 (Parameters.kpWindowStack->kwName)[5] = View->kvFineViewportOnBottom;
318 (Parameters.kpWindowStack->kwName)[6] = View->kvControl;
319 }
320
321
322 void
SaveViewOnStack()323 SaveViewOnStack()
324
325 {
326 int i = 0;
327 char c, buf[32];
328 struct kw *New, *Tmp;
329
330 New = alloc(kw);
331 if (New == NULL) MallocFailed();
332
333 New->kwLastWindowX = View->kvCoarseWindow->kaX;
334 New->kwLastWindowY = View->kvCoarseWindow->kaY;
335 New->kwLastFineWindowX = View->kvFineWindow->kaX;
336 New->kwLastFineWindowY = View->kvFineWindow->kaY;
337 New->kwLastWindowWidth = View->kvCoarseWindow->kaWidth;
338 New->kwLastFineWindowWidth = View->kvFineWindow->kaWidth;
339 (New->kwName)[5] = View->kvFineViewportOnBottom;
340 (New->kwName)[6] = View->kvControl;
341
342 if (Parameters.kpWindowStack == NULL)
343 SaveLastView();
344
345 New->kwNext = NULL;
346 for (Tmp = Parameters.kpWindowStack; Tmp->kwNext; i++,Tmp = Tmp->kwNext) ;
347 Tmp->kwNext = New;
348 sprintf(buf,"Current view assigned to: %c",'A'+i);
349 ShowPrompt(buf);
350 New->kwName[0] = 'a'+ i;
351 New->kwName[1] = '\0';
352 }
353
354
355
356 /***********************************************************************
357 *
358 * Redisplay control code.
359 *
360 ***********************************************************************/
361
362 static int DisplayDepth, HierarchyLevel;
363
364 #ifdef __STDC__
365 static void redisplay_layer(struct s*,struct ka*);
366 #else
367 static void redisplay_layer();
368 #endif
369
370 #define ka_copy(BB1,BB2) BB1.kaLeft = BB2->kaLeft; \
371 BB1.kaRight = BB2->kaRight; \
372 BB1.kaBottom = BB2->kaBottom; \
373 BB1.kaTop = BB2->kaTop; \
374 TPoint(&BB1.kaLeft,&BB1.kaBottom); \
375 TPoint(&BB1.kaRight,&BB1.kaTop); \
376 if(BB.kaLeft > BB.kaRight) \
377 SwapInts(BB1.kaLeft,BB1.kaRight); \
378 if(BB.kaBottom > BB.kaTop) \
379 SwapInts(BB1.kaBottom,BB1.kaTop);
380
381
382 void
Redisplay(AOI)383 Redisplay(AOI)
384
385 struct ka *AOI;
386 {
387 struct s *CellDesc = Parameters.kpTopDesc;
388
389 SetCurrentAOI(AOI);
390
391 if (CurrentAOI.aInCoarse == 0 And CurrentAOI.aInFine == 0)
392 goto quit;
393
394 Parameters.kpNumGeometries = 0;
395
396 if (!Parameters.kpGridOnTop)
397 ShowGrid();
398
399 if (Parameters.kpCellDesc != NULL) {
400
401 TPush();
402 TLoad();
403
404 DisplayDepth = 0;
405 HierarchyLevel = 0;
406 if (CellDesc)
407 redisplay_layer(CellDesc,AOI);
408
409 TPop();
410 }
411
412 if (Parameters.kpGridOnTop)
413 ShowGrid();
414
415 /*
416 * Show fine positioning window in coarse window.
417 */
418 DevSetColor(HighlightingColor);
419 if (Parameters.kpRedisplayControl != COARSEVIEWPORTONLY) {
420
421 if (Parameters.kpRedisplayControl == SPLITSCREEN)
422 ShowEmptyBox(HighlightingColor,View->kvFineWindow);
423 OutlineBox(View->kvFineViewport);
424 }
425 else if (!Parameters.kpDoingHardcopy &&
426 View->kvControl == FULLSCREEN)
427 OutlineBox(View->kvLargeCoarseViewport);
428
429 /*
430 * Highlight selected objects.
431 */
432 SQShow();
433
434 /* SRW ** show markers */
435 ShowMarker(DISPLAY,HighlightingColor,0L,0L,0,0,0);
436
437 quit:
438 SetCurrentAOI(View->kvCoarseWindow);
439 }
440
441
442 static void
redisplay_layer(CellDesc,AOI)443 redisplay_layer(CellDesc,AOI)
444
445 struct s *CellDesc;
446 struct ka *AOI;
447 {
448 struct g *GenDesc;
449 struct o *Pointer;
450 struct p *Path;
451 struct ka BB;
452 struct ka MasterBB;
453 struct s *MasterDesc;
454 char Xform;
455 char *MasterName;
456 char *TypeIn;
457 char *Label;
458 int NumX,NumY;
459 int Int1,Int2;
460 int Layer;
461 int Expand;
462 long X,Y;
463 long Width;
464 long DX,DY;
465
466 if (Not CDInitGen(CellDesc,1,AOI->kaLeft,AOI->kaBottom,
467 AOI->kaRight,AOI->kaTop,&GenDesc)) MallocFailed();
468 loop {
469 /* Test for user interrupt */
470 if (Parameters.kpSIGINTERRUPT) return;
471
472 CDGen(CellDesc,GenDesc,&Pointer);
473 if (Pointer == NULL) break;
474 if (Pointer->oInfo == SQ_GONE) continue;
475
476 ++Parameters.kpNumGeometries;
477
478 if (Pointer->oType == CDWIRE) {
479 CDWire(Pointer,&Layer,&Width,&Path);
480 if (Pointer->oInfo == SQ_INCMPLT)
481 ShowPath(DrawingColor,Path,False);
482 else
483 ShowWire(DrawingColor,Width,Path);
484 continue;
485 }
486 if (Pointer->oType == CDPOLYGON) {
487 if (Parameters.kpShowDots) {
488 CDPolygon(Pointer,&Layer,&Path);
489 if (Pointer->oInfo == SQ_INCMPLT)
490 ShowPath(DrawingColor,Path,False);
491 else
492 ShowPolygon(DrawingColor,Path);
493 }
494 continue;
495 }
496 if (Pointer->oType == CDLABEL) {
497 CDLabel(Pointer,&Layer,&Label,&X,&Y,&Xform);
498 ShowLabel(DrawingColor,Label,X,Y,Xform,True);
499 continue;
500 }
501 }
502 if (TCheck()) return;
503
504 if (Not CDInitGen(CellDesc,0,AOI->kaLeft,AOI->kaBottom,AOI->kaRight,
505 AOI->kaTop,&GenDesc)) MallocFailed();
506
507 loop {
508 /* Test for user interrupt */
509 if (Parameters.kpSIGINTERRUPT) break;
510
511 CDGen(CellDesc,GenDesc,&Pointer);
512 if (Pointer == NULL) break;
513 if (Pointer->oInfo == SQ_GONE) continue;
514 CDCall(Pointer,&MasterName,&NumX,&DX,&NumY,&DY);
515
516 if (IsCellInLib(MasterName)) {
517
518 if (OpenCell(MasterName,&MasterDesc)) break;
519
520 if (Not CDBB(MasterDesc,(struct o *)NULL,&MasterBB.kaLeft,
521 &MasterBB.kaBottom,&MasterBB.kaRight,&MasterBB.kaTop))
522 MallocFailed();
523
524 SetTransform(Pointer);
525 TPremultiply();
526
527 for (Int1 = NumY-1; Int1 >= 0; --Int1) {
528 for (Int2 = 0; Int2 < NumX; ++Int2 ){
529 TPush();
530 TIdentity();
531 TTranslate(Int2*DX,Int1*DY);
532 TPremultiply();
533 /*
534 * Box test instance array element with AOI.
535 */
536 ka_copy(BB,(&MasterBB));
537 if (Not (BB.kaLeft > AOI->kaRight Or
538 BB.kaRight < AOI->kaLeft Or
539 BB.kaBottom > AOI->kaTop Or
540 BB.kaTop < AOI->kaBottom))
541 redisplay_layer(MasterDesc,AOI);
542 TPop();
543 }
544 }
545 TPop();
546 }
547 }
548
549 if (Not CDInitGen(CellDesc,0,AOI->kaLeft,AOI->kaBottom,AOI->kaRight,
550 AOI->kaTop,&GenDesc)) MallocFailed();
551
552 loop {
553 /* Test for user interrupt */
554 if (Parameters.kpSIGINTERRUPT) break;
555
556 CDGen(CellDesc,GenDesc,&Pointer);
557 if (Pointer == NULL) break;
558 if (Pointer->oInfo == SQ_GONE) continue;
559 CDCall(Pointer,&MasterName,&NumX,&DX,&NumY,&DY);
560 if (IsCellInLib(MasterName)) continue;
561
562 if (OpenCell(MasterName,&MasterDesc)) break;
563
564 if (CellDesc != Parameters.kpCellDesc ||
565 Parameters.kpExpandInstances) {
566
567 if (Not CDBB(MasterDesc,(struct o *)NULL,&MasterBB.kaLeft,
568 &MasterBB.kaBottom,&MasterBB.kaRight,&MasterBB.kaTop))
569 MallocFailed();
570
571 SetTransform(Pointer);
572 TPremultiply();
573
574 for (Int1 = NumY-1; Int1 >= 0; --Int1) {
575 for (Int2 = 0; Int2 < NumX; ++Int2 ){
576 TPush();
577 TIdentity();
578 TTranslate(Int2*DX,Int1*DY);
579 TPremultiply();
580 /*
581 * Box test instance array element with AOI.
582 */
583 ka_copy(BB,(&MasterBB));
584 if (Not (BB.kaLeft > AOI->kaRight Or
585 BB.kaRight < AOI->kaLeft Or
586 BB.kaBottom > AOI->kaTop Or
587 BB.kaTop < AOI->kaBottom))
588 redisplay_layer(MasterDesc,AOI);
589 TPop();
590 }
591 }
592 TPop();
593 }
594 else {
595 /*
596 * Unexpanded form of an instance array is its BB with the
597 * name of its master shown in its center.
598 * If it is not 1 by 1, tell the user its dimensions.
599 * CDBB will always return True if Pointer != NULL.
600 */
601 CDStatusInt = CDBB(CellDesc,Pointer,&BB.kaLeft,&BB.kaBottom,
602 &BB.kaRight,&BB.kaTop);
603
604 if (BB.kaRight < BB.kaLeft) SwapInts(BB.kaLeft,BB.kaRight);
605 if (BB.kaTop < BB.kaBottom) SwapInts(BB.kaBottom,BB.kaTop);
606
607 /*
608 * Outline BB of Instance.
609 */
610 ShowEmptyBox(InstanceBBColor,&BB);
611
612 if (NumX != 1 Or NumY != 1)
613 sprintf(TypeOut,"%d/%d %s",NumX,NumY,MasterName);
614 else sprintf(TypeOut,"%s",MasterName);
615 ShowLabel(InstanceNameColor,TypeOut,BB.kaLeft,
616 BB.kaBottom + (BB.kaTop-BB.kaBottom)/2,0,True);
617 }
618 }
619 }
620
621
622 void
RedisplayAfterInterrupt()623 RedisplayAfterInterrupt()
624
625 {
626 TInit();
627 ShowPrompt("Interrupted. Type Ctrl A to abort.");
628 InitSignals();
629 ShowCommandMenu();
630 }
631
632
633 int
TCheck()634 TCheck()
635
636 {
637 char *TypeIn;
638
639 if (TFull()) {
640 ShowPrompt("Cell hierarchy is too deep. MORE");
641 (void)FBGetchar(ERASE);
642 ShowPrompt("Probably you have a recursive hierarchy.");
643 TInit();
644 return (True);
645 }
646 return (False);
647 }
648
649
650 void
SetTransform(Pointer)651 SetTransform(Pointer)
652
653 struct o *Pointer;
654 {
655 struct t *TGen;
656 long X,Y;
657 char Type;
658
659 TPush();
660 TIdentity();
661 CDInitTGen(Pointer,&TGen);
662 loop {
663 CDTGen(&TGen,&Type,&X,&Y);
664 if (TGen == NULL) break;
665
666 if (Type == CDROTATE) TRotate(X,Y);
667 elif (Type == CDTRANSLATE) TTranslate(X,Y);
668 elif (Type == CDMIRRORX) TMX();
669 elif (Type == CDMIRRORY) TMY();
670 }
671 }
672
673