1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrdisp.c
6 * User interface tool: miscellaneous display control
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "egraphics.h"
34 #include "usr.h"
35 #include "tech.h"
36 #include "tecgen.h"
37
38 static INTBIG us_stopevent = 0;
39
40 /* for drawing cell name, outline or instance name (color changes) */
41 GRAPHICS us_cellgra = {LAYERO, 0, SOLIDC, SOLIDC,
42 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
43
44 /* for drawing outlines (color changes) */
45 GRAPHICS us_box = {LAYERA, 0, SOLIDC, SOLIDC,
46 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
47
48 /* for drawing highlight layer (color changes) */
49 GRAPHICS us_hbox = {LAYERH, 0, SOLIDC, SOLIDC,
50 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
51
52 /* for drawing normal menu border on (nothing changes) */
53 GRAPHICS us_nmbox = {LAYERA, MENBOR, SOLIDC, SOLIDC,
54 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
55
56 /* for drawing arbitrary graphics (bits and color change) */
57 GRAPHICS us_arbit = {0, 0, SOLIDC, SOLIDC,
58 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
59
60 /* for erasing polygons (nothing changes) */
61 GRAPHICS us_ebox = {LAYERA, ALLOFF, SOLIDC, SOLIDC,
62 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
63
64 /* for drawing grid lines (nothing changes) */
65 GRAPHICS us_gbox = {LAYERG, GRID, SOLIDC, SOLIDC,
66 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
67
68 /* for erasing grid layer (nothing changes) */
69 GRAPHICS us_egbox = {LAYERG, ALLOFF, SOLIDC, SOLIDC,
70 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
71
72 /* for drawing patterned cell contents (when resolution is too small, color changes) */
73 static GRAPHICS us_graybox = {LAYERO, GRAY, PATTERNED, PATTERNED,
74 {0x0000, /* */
75 0x0303, /* XX XX */
76 0x4848, /* X X X X */
77 0x0303, /* XX XX */
78 0x0000, /* */
79 0x3030, /* XX XX */
80 0x8484, /* X X X X */
81 0x3030, /* XX XX */
82 0x0000, /* */
83 0x0303, /* XX XX */
84 0x4848, /* X X X X */
85 0x0303, /* XX XX */
86 0x0000, /* */
87 0x3030, /* XX XX */
88 0x8484, /* X X X X */
89 0x3030}, /* XX XX */
90 NOVARIABLE, 0};
91
92 /* for drawing dimmed background (when editing in-place) */
93 static GRAPHICS us_dimbox = {LAYERH, HIGHLIT, PATTERNED, PATTERNED,
94 {0x0404, /* X X */
95 0x0000, /* */
96 0x4040, /* X X */
97 0x0000, /* */
98 0x0404, /* X X */
99 0x0000, /* */
100 0x4040, /* X X */
101 0x0000, /* */
102 0x0404, /* X X */
103 0x0000, /* */
104 0x4040, /* X X */
105 0x0000, /* */
106 0x0404, /* X X */
107 0x0000, /* */
108 0x4040, /* X X */
109 0x0000}, /* */
110 NOVARIABLE, 0};
111
112 #define MAXGRID 75
113 #define MINGRID 4 /* the minimum grid has 4 pixels spacing */
114 #define TXTMAXCELLSIZE 36 /* maximum point size of cell text */
115
116 /* prototypes for local routines */
117 static void us_showemptywindow(WINDOWPART*);
118 static void us_graphicsarcs(PORTPROTO*, INTBIG*, INTBIG*);
119 static void us_combinelayers(ARCINST*, INTBIG*, INTBIG*);
120 static INTBIG us_drawall(INTBIG, INTBIG, INTBIG, INTBIG, NODEPROTO*, XARRAY, INTBIG, BOOLEAN);
121 static INTBIG us_drawarcinstpeek(ARCINST*, XARRAY, INTBIG);
122 static INTBIG us_drawnodeinstpeek(NODEINST*, XARRAY, INTBIG);
123 static void us_drawcellcontents(NODEPROTO *cell, WINDOWPART *w, BOOLEAN now);
124 static int us_sortshownports(const void *e1, const void *e2);
125
126 /******************** WINDOW CONTROL ********************/
127
128 /*
129 * routine to draw the border of window "w"
130 */
us_drawwindow(WINDOWPART * w,INTBIG color)131 void us_drawwindow(WINDOWPART *w, INTBIG color)
132 {
133 WINDOWPART ww;
134 static POLYGON *poly = NOPOLYGON;
135 INTBIG lx, hx, ly, hy;
136
137 /* get polygon */
138 (void)needstaticpolygon(&poly, 5, us_tool->cluster);
139
140 /* don't draw window border if it is a whole-screen window */
141 if (estrcmp(w->location, x_("entire")) == 0) return;
142
143 /* don't draw window border around popup text editors */
144 if ((w->state & WINDOWTYPE) == POPTEXTWINDOW) return;
145
146 us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
147 lx--; hx++;
148 ly--; hy++;
149
150 ww.screenlx = ww.uselx = lx;
151 ww.screenhx = ww.usehx = hx;
152 ww.screenly = ww.usely = ly;
153 ww.screenhy = ww.usehy = hy;
154 ww.frame = w->frame;
155 ww.state = DISPWINDOW;
156 computewindowscale(&ww);
157 maketruerectpoly(ww.uselx, ww.usehx, ww.usely, ww.usehy, poly);
158 poly->desc = &us_box;
159 poly->style = CLOSEDRECT;
160 us_box.col = color;
161 us_showpoly(poly, &ww);
162 }
163
164 /*
165 * Routine to get the actual drawing area in window "w". This excludes borders and
166 * sliders. The bounds are returned in (lx/hx/ly/hy).
167 */
us_gettruewindowbounds(WINDOWPART * w,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)168 void us_gettruewindowbounds(WINDOWPART *w, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
169 {
170 *lx = w->uselx; *hx = w->usehx;
171 *ly = w->usely; *hy = w->usehy;
172 if ((w->state&WINDOWMODE) != 0)
173 {
174 *lx -= WINDOWMODEBORDERSIZE; *hx += WINDOWMODEBORDERSIZE;
175 *ly -= WINDOWMODEBORDERSIZE; *hy += WINDOWMODEBORDERSIZE;
176 }
177 if ((w->state&WINDOWTYPE) == DISPWINDOW)
178 {
179 *hx += DISPLAYSLIDERSIZE;
180 *ly -= DISPLAYSLIDERSIZE;
181 }
182 if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
183 {
184 *lx -= DISPLAYSLIDERSIZE;
185 *ly -= DISPLAYSLIDERSIZE;
186 }
187 }
188
189 /*
190 * routine to adjust screen boundaries to fill the view
191 */
us_fullview(NODEPROTO * np,INTBIG * screenlx,INTBIG * screenhx,INTBIG * screenly,INTBIG * screenhy)192 void us_fullview(NODEPROTO *np, INTBIG *screenlx, INTBIG *screenhx, INTBIG *screenly,
193 INTBIG *screenhy)
194 {
195 INTBIG fsx, fsy, nlx, nhx, nly, nhy, xc, yc, tsx, tsy;
196 REGISTER INTBIG lambda, first, oldlx, oldhx, oldly, oldhy, i, xw, yw, frameinfo;
197 REGISTER NODEINST *ni;
198 REGISTER ARCINST *ai;
199 REGISTER VARIABLE *var;
200 REGISTER WINDOWPART *oldwin;
201 REGISTER CHAR *str;
202 static POLYGON *poly = NOPOLYGON;
203
204 /* only one size allowed in windows with frames */
205 frameinfo = framesize(&fsx, &fsy, np);
206 if (frameinfo == 0)
207 {
208 *screenlx = -fsx/2;
209 *screenly = -fsy/2;
210 *screenhx = fsx/2;
211 *screenhy = fsy/2;
212 return;
213 }
214
215 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
216 lambda = el_curlib->lambda[el_curtech->techindex];
217 if (el_curwindowpart != NOWINDOWPART)
218 {
219 oldlx = el_curwindowpart->screenlx;
220 oldhx = el_curwindowpart->screenhx;
221 oldly = el_curwindowpart->screenly;
222 oldhy = el_curwindowpart->screenhy;
223 el_curwindowpart->screenlx = np->lowx;
224 el_curwindowpart->screenhx = np->highx;
225 if (el_curwindowpart->screenlx == el_curwindowpart->screenhx)
226 {
227 el_curwindowpart->screenlx -= lambda;
228 el_curwindowpart->screenhx += lambda;
229 }
230 el_curwindowpart->screenly = np->lowy;
231 el_curwindowpart->screenhy = np->highy;
232 if (el_curwindowpart->screenly == el_curwindowpart->screenhy)
233 {
234 el_curwindowpart->screenly -= lambda;
235 el_curwindowpart->screenhy += lambda;
236 }
237 us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE,
238 &el_curwindowpart->screenlx, &el_curwindowpart->screenhx,
239 &el_curwindowpart->screenly, &el_curwindowpart->screenhy, 1);
240 computewindowscale(el_curwindowpart);
241 }
242
243 /* must recompute this by hand because cell bounds don't include cell-centers or big text */
244 first = 1;
245 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
246 {
247 us_getnodebounds(ni, &nlx, &nhx, &nly, &nhy);
248 if (first != 0)
249 {
250 *screenlx = nlx;
251 *screenhx = nhx;
252 *screenly = nly;
253 *screenhy = nhy;
254 first = 0;
255 } else
256 {
257 *screenlx = mini(*screenlx, nlx);
258 *screenhx = maxi(*screenhx, nhx);
259 *screenly = mini(*screenly, nly);
260 *screenhy = maxi(*screenhy, nhy);
261 }
262 }
263
264 /* include all arcs in the cell */
265 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
266 {
267 us_getarcbounds(ai, &nlx, &nhx, &nly, &nhy);
268 *screenlx = mini(*screenlx, nlx);
269 *screenhx = maxi(*screenhx, nhx);
270 *screenly = mini(*screenly, nly);
271 *screenhy = maxi(*screenhy, nhy);
272 }
273
274 /* include all displayed cell variables */
275 oldwin = setvariablewindow(el_curwindowpart);
276 for(i = 0; i < np->numvar; i++)
277 {
278 var = &np->firstvar[i];
279 if ((var->type&VDISPLAY) == 0) continue;
280 str = describedisplayedvariable(var, -1, -1);
281
282 /* determine center of text (cell variables are offset from (0,0)) */
283 poly->xv[0] = poly->yv[0] = 0;
284 poly->count = 1;
285 poly->style = FILLED;
286 adjustdisoffset((INTBIG)np, VNODEPROTO, np->tech, poly, var->textdescript);
287 getcenter(poly, &xc, &yc);
288
289 /* determine size from text */
290 screensettextinfo(el_curwindowpart, np->tech, var->textdescript);
291 screengettextsize(el_curwindowpart, str, &tsx, &tsy);
292 xw = muldiv(tsx, el_curwindowpart->screenhx-el_curwindowpart->screenlx,
293 el_curwindowpart->usehx-el_curwindowpart->uselx);
294 yw = muldiv(tsy, el_curwindowpart->screenhy-el_curwindowpart->screenly,
295 el_curwindowpart->usehy-el_curwindowpart->usely);
296 us_buildtexthighpoly(0, 0, 0, 0, xc, yc, xw, yw, poly->style, poly);
297 getbbox(poly, &nlx, &nhx, &nly, &nhy);
298 if (first != 0)
299 {
300 *screenlx = nlx;
301 *screenhx = nhx;
302 *screenly = nly;
303 *screenhy = nhy;
304 first = 0;
305 } else
306 {
307 *screenlx = mini(*screenlx, nlx);
308 *screenhx = maxi(*screenhx, nhx);
309 *screenly = mini(*screenly, nly);
310 *screenhy = maxi(*screenhy, nhy);
311 }
312 }
313 (void)setvariablewindow(oldwin);
314
315 /* set default size if nothing is there */
316 if (first != 0)
317 {
318 *screenlx = np->lowx;
319 *screenhx = np->highx;
320 *screenly = np->lowy;
321 *screenhy = np->highy;
322 }
323
324 /* if there is frame information, include it */
325 if (frameinfo == 1)
326 {
327 *screenlx = mini(*screenlx, -fsx/2);
328 *screenhx = maxi(*screenhx, fsx/2);
329 *screenly = mini(*screenly, -fsy/2);
330 *screenhy = maxi(*screenhy, fsy/2);
331 }
332
333 if (*screenlx >= *screenhx && *screenly >= *screenhy)
334 {
335 *screenlx -= 25 * lambda;
336 *screenhx += 25 * lambda;
337 *screenly -= 25 * lambda;
338 *screenhy += 25 * lambda;
339 }
340 if (el_curwindowpart != NOWINDOWPART)
341 {
342 el_curwindowpart->screenlx = oldlx;
343 el_curwindowpart->screenhx = oldhx;
344 el_curwindowpart->screenly = oldly;
345 el_curwindowpart->screenhy = oldhy;
346 computewindowscale(el_curwindowpart);
347 }
348 }
349
350 /*
351 * Routine to determine the bounds of node "ni" and return it in "nlx", "nhx",
352 * "nly", and "nhy".
353 */
us_getnodebounds(NODEINST * ni,INTBIG * nlx,INTBIG * nhx,INTBIG * nly,INTBIG * nhy)354 void us_getnodebounds(NODEINST *ni, INTBIG *nlx, INTBIG *nhx, INTBIG *nly, INTBIG *nhy)
355 {
356 REGISTER INTBIG i, nodexfvalid, lambda, shei, swid, portstyle;
357 INTBIG lx, hx, ly, hy, xp, yp, newxc, newyc;
358 INTBIG wid, hei;
359 REGISTER VARIABLE *var;
360 XARRAY trans;
361 REGISTER PORTEXPINST *pe;
362 REGISTER PORTPROTO *pp;
363 static POLYGON *poly = NOPOLYGON;
364
365 *nlx = ni->geom->lowx;
366 *nhx = ni->geom->highx;
367 *nly = ni->geom->lowy;
368 *nhy = ni->geom->highy;
369
370 /* include any displayable variables with an offset or array */
371 if (el_curwindowpart != NOWINDOWPART)
372 {
373 for(i=0; i<ni->numvar; i++)
374 {
375 var = &ni->firstvar[i];
376 if ((var->type&VDISPLAY) == 0) continue;
377
378 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
379 makedisparrayvarpoly(ni->geom, el_curwindowpart, var, poly);
380 getbbox(poly, &lx, &hx, &ly, &hy);
381 *nlx = mini(*nlx, lx);
382 *nhx = maxi(*nhx, hx);
383 *nly = mini(*nly, ly);
384 *nhy = maxi(*nhy, hy);
385 }
386 }
387
388 /* include exports */
389 nodexfvalid = 0;
390 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
391 {
392 pp = pe->exportproto;
393 if (nodexfvalid == 0)
394 {
395 nodexfvalid = 1;
396 makeangle(ni->rotation, ni->transpose, trans);
397 lambda = figurelambda(ni->geom);
398 }
399 newxc = TDGETXOFF(pp->textdescript);
400 newxc = newxc * lambda / 4;
401 newyc = TDGETYOFF(pp->textdescript);
402 newyc = newyc * lambda / 4;
403 xform(newxc, newyc, &newxc, &newyc, trans);
404 portposition(ni, pe->proto, &xp, &yp);
405 xp += newxc;
406 yp += newyc;
407 lx = hx = xp; ly = hy = yp;
408 portstyle = us_useroptions & EXPORTLABELS;
409 if (el_curwindowpart != NOWINDOWPART &&
410 (portstyle == EXPORTSFULL || portstyle == EXPORTSSHORT))
411 {
412 /* adjust for size of port text */
413 screensettextinfo(el_curwindowpart, pp->parent->tech, pp->textdescript);
414 screengettextsize(el_curwindowpart,
415 us_displayedportname(pp, portstyle >> EXPORTLABELSSH), &wid, &hei);
416 swid = roundfloat((float)wid / el_curwindowpart->scalex);
417 shei = roundfloat((float)hei / el_curwindowpart->scaley);
418 switch (TDGETPOS(pp->textdescript))
419 {
420 case VTPOSCENT: case VTPOSDOWN: case VTPOSUP:
421 lx -= swid/2; hx += swid/2; break;
422 case VTPOSRIGHT: case VTPOSDOWNRIGHT: case VTPOSUPRIGHT:
423 hx += swid; break;
424 case VTPOSLEFT: case VTPOSDOWNLEFT: case VTPOSUPLEFT:
425 lx -= swid; break;
426 }
427 switch (TDGETPOS(pp->textdescript))
428 {
429 case VTPOSCENT: case VTPOSRIGHT: case VTPOSLEFT:
430 ly -= shei/2; hy += shei/2; break;
431 case VTPOSDOWN: case VTPOSDOWNRIGHT: case VTPOSDOWNLEFT:
432 ly -= shei; break;
433 case VTPOSUP: case VTPOSUPRIGHT: case VTPOSUPLEFT:
434 hy += shei; break;
435 }
436 }
437 *nlx = mini(*nlx, lx);
438 *nhx = maxi(*nhx, hx);
439 *nly = mini(*nly, ly);
440 *nhy = maxi(*nhy, hy);
441 }
442 }
443
444 /*
445 * Routine to determine the bounds of node "ni" and return it in "nlx", "nhx",
446 * "nly", and "nhy".
447 */
us_getarcbounds(ARCINST * ai,INTBIG * nlx,INTBIG * nhx,INTBIG * nly,INTBIG * nhy)448 void us_getarcbounds(ARCINST *ai, INTBIG *nlx, INTBIG *nhx, INTBIG *nly, INTBIG *nhy)
449 {
450 REGISTER INTBIG i;
451 INTBIG lx, hx, ly, hy;
452 REGISTER VARIABLE *var;
453 static POLYGON *poly = NOPOLYGON;
454
455 *nlx = ai->geom->lowx;
456 *nhx = ai->geom->highx;
457 *nly = ai->geom->lowy;
458 *nhy = ai->geom->highy;
459
460 /* include any displayable variables with an offset */
461 if (el_curwindowpart != NOWINDOWPART)
462 {
463 for(i=0; i<ai->numvar; i++)
464 {
465 var = &ai->firstvar[i];
466 if ((var->type&VDISPLAY) == 0) continue;
467 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
468 makedisparrayvarpoly(ai->geom, el_curwindowpart, var, poly);
469 getbbox(poly, &lx, &hx, &ly, &hy);
470 *nlx = mini(*nlx, lx);
471 *nhx = maxi(*nhx, hx);
472 *nly = mini(*nly, ly);
473 *nhy = maxi(*nhy, hy);
474 }
475 }
476 }
477
478 /*
479 * routine to adjust "screenlx/hx/ly/hy" for window "w" so that it defines
480 * a square screen and leaves some extra space around the values.
481 * If "formerw" is a valid window, this is the former window from which
482 * a new one in "w" was created, so adjust without scaling.
483 * Scaling a window means that one dimension gets bigger or the other
484 * gets smaller to make the square relationship hold. If "largescale" is
485 * true, the new window will use the larger of the two scales rather
486 * than the smaller.
487 */
us_squarescreen(WINDOWPART * w,WINDOWPART * formerw,BOOLEAN largescale,INTBIG * screenlx,INTBIG * screenhx,INTBIG * screenly,INTBIG * screenhy,INTBIG exact)488 void us_squarescreen(WINDOWPART *w, WINDOWPART *formerw, BOOLEAN largescale, INTBIG *screenlx,
489 INTBIG *screenhx, INTBIG *screenly, INTBIG *screenhy, INTBIG exact)
490 {
491 REGISTER INTBIG i, units, image, design, lambda;
492 float prod1, prod2, prodswap, fslx, fshx, fsly, fshy, bump, ysize, xsize;
493
494 if (formerw != NOWINDOWPART)
495 {
496 *screenlx = muldiv(((formerw->usehx-formerw->uselx) - (w->usehx-w->uselx))/2,
497 formerw->screenhx-formerw->screenlx, formerw->usehx-formerw->uselx) + formerw->screenlx;
498 *screenly = muldiv(((formerw->usehy-formerw->usely) - (w->usehy-w->usely))/2,
499 formerw->screenhy-formerw->screenly, formerw->usehy-formerw->usely) + formerw->screenly;
500 *screenhx = w->screenlx + muldiv(w->usehx-w->uselx, formerw->screenhx-formerw->screenlx,
501 formerw->usehx-formerw->uselx);
502 *screenhy = w->screenly + muldiv(w->usehy-w->usely, formerw->screenhy-formerw->screenly,
503 formerw->usehy-formerw->usely);
504 return;
505 }
506
507 fslx = (float)*screenlx; fshx = (float)*screenhx;
508 fsly = (float)*screenly; fshy = (float)*screenhy;
509 xsize = (float)(w->usehx - w->uselx);
510 ysize = (float)(w->usehy - w->usely);
511 prod1 = (fshx - fslx) * ysize;
512 prod2 = (fshy - fsly) * xsize;
513 if (prod1 != prod2)
514 {
515 /* reverse the sense if the larger scale is desired */
516 if (largescale)
517 {
518 prodswap = prod1; prod1 = prod2; prod2 = prodswap;
519 }
520
521 /* adjust the scale */
522 if (prod1 > prod2)
523 {
524 /* screen extent is too wide for window */
525 if (exact != 0) bump = 0.0; else
526 {
527 bump = (fshx - fslx) / 20.0f;
528 if (bump == 0.0) bump = 1.0;
529 fshx += bump; fslx -= bump;
530 }
531 bump = (fshx - fslx) * ysize / xsize - (fshy - fsly);
532 fsly -= bump/2.0f;
533 fshy += bump/2.0f;
534 } else
535 {
536 /* screen extent is too tall for window */
537 if (exact != 0) bump = 0.0; else
538 {
539 bump = (fshy - fsly) / 20.0f;
540 if (bump == 0.0) bump = 1.0;
541 fshy += bump; fsly -= bump;
542 }
543 bump = (fshy - fsly) * xsize / ysize - (fshx - fslx);
544 fslx -= bump/2;
545 fshx += bump/2;
546 }
547
548 /* put it back into the integer extent fields */
549 if (fslx < -MAXINTBIG/2) *screenlx = -MAXINTBIG/2; else *screenlx = (INTBIG)fslx;
550 if (fshx > MAXINTBIG/2) *screenhx = MAXINTBIG/2; else *screenhx = (INTBIG)fshx;
551 if (fsly < -MAXINTBIG/2) *screenly = -MAXINTBIG/2; else *screenly = (INTBIG)fsly;
552 if (fshy > MAXINTBIG/2) *screenhy = MAXINTBIG/2; else *screenhy = (INTBIG)fshy;
553 }
554
555 if ((us_tool->toolstate&INTEGRAL) != 0)
556 {
557 /* adjust window so that it matches well with screen pixels */
558 if (*screenhx == *screenlx) return;
559 if (w->curnodeproto == NONODEPROTO)
560 lambda = el_curlib->lambda[el_curtech->techindex]; else
561 lambda = lambdaofcell(w->curnodeproto);
562 design = (*screenhx - *screenlx) / lambda;
563 if (design <= 0) design = 1;
564 image = w->usehx - w->uselx;
565 if (image > design)
566 {
567 /* force integral number of pixels per lambda unit */
568 i = (muldiv(image, lambda, image / design) - (*screenhx - *screenlx)) / 2;
569 (*screenhx) += i; (*screenlx) -= i;
570 i = muldiv(*screenhx - *screenlx, w->usehy - w->usely,
571 w->usehx - w->uselx) - (*screenhy - *screenly);
572 (*screenly) -= i/2;
573 (*screenhy) += i/2;
574 } else
575 {
576 /* force integral number of lambda units per pixel */
577 units = muldiv(design, lambda, image);
578 i = ((units * (w->usehx - w->uselx)) - (*screenhx - *screenlx)) / 2;
579 (*screenhx) += i; (*screenlx) -= i;
580 i = muldiv(*screenhx - *screenlx, w->usehy - w->usely,
581 w->usehx - w->uselx) - (*screenhy - *screenly);
582 (*screenly) -= i/2;
583 (*screenhy) += i/2;
584 }
585 }
586 }
587
588 /*
589 * routine to redisplay everything (all the way down to the bottom) in the
590 * window "w"
591 */
us_subwindow(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,WINDOWPART * w)592 WINDOWPART *us_subwindow(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, WINDOWPART *w)
593 {
594 static WINDOWPART ww;
595
596 /* redefine the window to clip to this boundary */
597 ww.uselx = applyxscale(w, lx-w->screenlx) + w->uselx;
598 ww.usely = applyyscale(w, ly-w->screenly) + w->usely;
599 ww.usehx = applyxscale(w, hx-w->screenlx) + w->uselx;
600 ww.usehy = applyyscale(w, hy-w->screenly) + w->usely;
601 ww.screenlx = muldiv(w->screenhx-w->screenlx, ww.uselx-w->uselx, w->usehx-w->uselx) +
602 w->screenlx;
603 ww.screenhx = muldiv(w->screenhx-w->screenlx, ww.usehx-w->uselx, w->usehx-w->uselx) +
604 w->screenlx;
605 ww.screenly = muldiv(w->screenhy-w->screenly, ww.usely-w->usely, w->usehy-w->usely) +
606 w->screenly;
607 ww.screenhy = muldiv(w->screenhy-w->screenly, ww.usehy-w->usely, w->usehy-w->usely) +
608 w->screenly;
609 ww.frame = w->frame;
610 ww.curnodeproto = w->curnodeproto;
611 ww.state = DISPWINDOW;
612 computewindowscale(&ww);
613 return(&ww);
614 }
615
us_showwindowmode(WINDOWPART * w)616 void us_showwindowmode(WINDOWPART *w)
617 {
618 REGISTER INTBIG x, y, numcolors, colorindex, high;
619 INTBIG lx, hx, ly, hy, colors[5];
620
621 us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
622 numcolors = 0;
623 if ((w->state&WINDOWSIMMODE) != 0) colors[numcolors++] = RED;
624 if ((w->state&WINDOWTECEDMODE) != 0) colors[numcolors++] = YELLOW;
625 if ((w->state&WINDOWOUTLINEEDMODE) != 0) colors[numcolors++] = BLUE;
626 if (numcolors == 0) return;
627 if (numcolors == 1)
628 {
629 /* just 1 border color: draw it simply */
630 us_box.col = colors[0];
631 screendrawbox(w, lx, hx, ly, ly+WINDOWMODEBORDERSIZE-1, &us_box);
632 screendrawbox(w, lx, hx, hy-WINDOWMODEBORDERSIZE+1, hy, &us_box);
633 screendrawbox(w, lx, lx+WINDOWMODEBORDERSIZE-1, ly, hy, &us_box);
634 screendrawbox(w, hx-WINDOWMODEBORDERSIZE+1, hx, ly, hy, &us_box);
635 return;
636 }
637
638 /* multiple border colors: interleave them */
639 colorindex = 0;
640 for(x = lx; x<hx; x += 30)
641 {
642 us_box.col = colors[colorindex++];
643 if (colorindex >= numcolors) colorindex = 0;
644 high = x + 30;
645 if (high > hx) high = hx;
646 screendrawbox(w, x, high, ly, ly+WINDOWMODEBORDERSIZE-1, &us_box);
647 screendrawbox(w, x, high, hy-WINDOWMODEBORDERSIZE+1, hy, &us_box);
648 }
649 colorindex = 0;
650 for(y=ly; y<hy; y += 30)
651 {
652 us_box.col = colors[colorindex++];
653 if (colorindex >= numcolors) colorindex = 0;
654 high = y + 30;
655 if (high > hy) high = hy;
656 screendrawbox(w, lx, lx+WINDOWMODEBORDERSIZE-1, y, high, &us_box);
657 screendrawbox(w, hx-WINDOWMODEBORDERSIZE+1, hx, y, high, &us_box);
658 }
659 }
660
661 /*
662 * routine to erase window "w" and draw everything that should be in it.
663 */
us_redisplay(WINDOWPART * w)664 void us_redisplay(WINDOWPART *w)
665 {
666 WINDOWPART ww;
667 static POLYGON *poly = NOPOLYGON;
668 INTBIG lx, hx, ly, hy, numicons;
669 REGISTER BOOLEAN drawexplorericon;
670
671 /* get polygon */
672 (void)needstaticpolygon(&poly, 7, us_tool->cluster);
673
674 /* draw fat colored border if in a mode */
675 if ((w->state&WINDOWMODE) != 0)
676 {
677 us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
678 ww.screenlx = ww.uselx = lx;
679 ww.screenhx = ww.usehx = hx;
680 ww.screenly = ww.usely = ly;
681 ww.screenhy = ww.usehy = hy;
682 ww.frame = w->frame;
683 ww.state = DISPWINDOW;
684 computewindowscale(&ww);
685 poly->desc = &us_box;
686 us_box.col = RED;
687 poly->style = FILLEDRECT;
688
689 us_showwindowmode(w);
690 }
691
692 /* draw sliders if a display window */
693 if ((w->state&WINDOWTYPE) == DISPWINDOW)
694 {
695 lx = w->uselx; hx = w->usehx;
696 ly = w->usely; hy = w->usehy;
697
698 /* the slider on the bottom and right */
699 numicons = 0;
700 drawexplorericon = us_windowgetsexploericon(w);
701 if (drawexplorericon) numicons++;
702 w->usehx += DISPLAYSLIDERSIZE;
703 w->usely -= DISPLAYSLIDERSIZE;
704 us_drawverticalslider(w, hx, ly, hy, FALSE);
705 us_drawhorizontalslider(w, ly, lx, hx, numicons);
706 w->usehx -= DISPLAYSLIDERSIZE;
707 w->usely += DISPLAYSLIDERSIZE;
708
709 /* the corner */
710 us_drawslidercorner(w, hx+1, hx+DISPLAYSLIDERSIZE, ly-DISPLAYSLIDERSIZE, ly-1, FALSE);
711
712 /* fill in the current slider positions */
713 us_drawdispwindowsliders(w);
714 }
715
716 if ((us_state&NONOVERLAPPABLEDISPLAY) != 0) us_redisplaynow(w, TRUE); else
717 us_redisplaynow(w, FALSE);
718 }
719
720 /*
721 * Routine to return TRUE if an "explorer icon" should be drawn in this window.
722 */
us_windowgetsexploericon(WINDOWPART * w)723 BOOLEAN us_windowgetsexploericon(WINDOWPART *w)
724 {
725 REGISTER WINDOWPART *ow;
726
727 if ((w->state&WINDOWTYPE) == EXPLORERWINDOW) return(TRUE);
728 if ((w->state&WINDOWTYPE) != DISPWINDOW) return(FALSE);
729 for(ow = el_topwindowpart; ow != NOWINDOWPART; ow = ow->nextwindowpart)
730 {
731 if (ow->frame != w->frame) continue;
732 if ((ow->state&WINDOWTYPE) == EXPLORERWINDOW) return(FALSE);
733 }
734 return(TRUE);
735 }
736
737 /*
738 * Routine to draw a grey box in the corner where two sliders meet.
739 */
us_drawslidercorner(WINDOWPART * win,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,BOOLEAN drawtopright)740 void us_drawslidercorner(WINDOWPART *win, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, BOOLEAN drawtopright)
741 {
742 static POLYGON *poly = NOPOLYGON;
743 WINDOWPART ww;
744
745 /* get polygon */
746 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
747
748 ww.screenlx = ww.uselx = lx;
749 ww.screenhx = ww.usehx = hx;
750 ww.screenly = ww.usely = ly;
751 ww.screenhy = ww.usehy = hy;
752 ww.frame = win->frame;
753 ww.state = DISPWINDOW;
754 computewindowscale(&ww);
755 poly->desc = &us_box;
756 us_box.col = DGRAY;
757 poly->style = FILLEDRECT;
758 maketruerectpoly(lx, hx, ly, hy, poly);
759 us_showpoly(poly, &ww);
760
761 /* draw the top and right edge */
762 if (drawtopright)
763 {
764 us_box.col = BLACK;
765 gra_drawbox(win, lx, lx+11, ly+11, ly+11, &us_box);
766 gra_drawbox(win, lx+11, lx+11, ly, ly+11, &us_box);
767 }
768 }
769
770 /*
771 * Routine to determine the location of the thumb in the sliders of window "w"
772 * and to draw those thumbs.
773 */
us_drawdispwindowsliders(WINDOWPART * w)774 void us_drawdispwindowsliders(WINDOWPART *w)
775 {
776 REGISTER INTBIG lx, hx, ly, hy, numicons;
777 REGISTER NODEPROTO *np;
778 INTBIG cellsizex, cellsizey;
779 REGISTER INTBIG screensizex, screensizey,
780 thumbsizex, thumbsizey, thumbareax, thumbareay, thumbposx, thumbposy;
781
782 if ((w->state&WINDOWTYPE) != DISPWINDOW) return;
783
784 /* default: no thumb drawn in sliders */
785 w->thumblx = 0; w->thumbhx = -1;
786 w->thumbly = 0; w->thumbhy = -1;
787
788 /* see how many icons appear on the left side of the horizontal slider */
789 numicons = 0;
790 if (us_windowgetsexploericon(w)) numicons++;
791
792 np = w->curnodeproto;
793 lx = w->uselx + numicons*DISPLAYSLIDERSIZE;
794 hx = w->usehx;
795 ly = w->usely;
796 hy = w->usehy;
797 if (np != NONODEPROTO)
798 {
799 /* determine amount of the cell that is shown */
800 cellsizex = np->highx - np->lowx;
801 cellsizey = np->highy - np->lowy;
802 if (cellsizex > 0 && cellsizey >= 0)
803 {
804 screensizex = w->screenhx - w->screenlx;
805 screensizey = w->screenhy - w->screenly;
806 thumbareax = (hx - lx - DISPLAYSLIDERSIZE*2-4) / 2;
807 thumbareay = (hy - ly - DISPLAYSLIDERSIZE*2-4) / 2;
808 if (cellsizex <= screensizex)
809 {
810 thumbsizex = thumbareax;
811 thumbposx = muldiv(w->screenhx - (np->highx + np->lowx)/2, thumbareax,
812 w->screenhx-w->screenlx) + (hx - lx - thumbareax) / 2 + lx;
813 } else
814 {
815 thumbsizex = thumbareax * screensizex / cellsizex;
816 if (thumbsizex < 20) thumbsizex = 20;
817 thumbposx = muldiv((w->screenhx + w->screenlx)/2 - np->lowx, thumbareax,
818 np->highx-np->lowx) + (hx - lx - thumbareax) / 2 + lx;
819 }
820 if (cellsizey <= screensizey)
821 {
822 thumbsizey = thumbareay;
823 thumbposy = muldiv(w->screenhy - (np->highy + np->lowy)/2, thumbareay,
824 w->screenhy-w->screenly) + (hy - ly - thumbareay) / 2 + ly;
825 } else
826 {
827 thumbsizey = thumbareay * screensizey / cellsizey;
828 if (thumbsizey < 20) thumbsizey = 20;
829 thumbposy = muldiv((w->screenhy + w->screenly)/2 - np->lowy, thumbareay,
830 np->highy-np->lowy) + (hy - ly - thumbareay) / 2 + ly;
831 }
832 w->thumblx = thumbposx-thumbsizex/2; w->thumbhx = thumbposx+thumbsizex/2;
833 w->thumbly = thumbposy-thumbsizey/2; w->thumbhy = thumbposy+thumbsizey/2;
834 if (w->thumblx < lx + DISPLAYSLIDERSIZE + 2) w->thumblx = lx + DISPLAYSLIDERSIZE + 2;
835 if (w->thumbhx < lx + DISPLAYSLIDERSIZE + 20) w->thumbhx = lx + DISPLAYSLIDERSIZE + 20;
836 if (w->thumbhx > hx - DISPLAYSLIDERSIZE - 2) w->thumbhx = hx - DISPLAYSLIDERSIZE - 2;
837 if (w->thumblx > hx - DISPLAYSLIDERSIZE - 20) w->thumblx = hx - DISPLAYSLIDERSIZE - 20;
838
839 if (w->thumbly < ly + DISPLAYSLIDERSIZE + 2) w->thumbly = ly + DISPLAYSLIDERSIZE + 2;
840 if (w->thumbhy < ly + DISPLAYSLIDERSIZE + 20) w->thumbhy = ly + DISPLAYSLIDERSIZE + 20;
841 if (w->thumbhy > hy - DISPLAYSLIDERSIZE - 2) w->thumbhy = hy - DISPLAYSLIDERSIZE - 2;
842 if (w->thumbly > hy - DISPLAYSLIDERSIZE - 20) w->thumbly = hy - DISPLAYSLIDERSIZE - 20;
843 }
844 }
845
846 /* prepare a window in which to draw the thumbs */
847 lx = w->uselx; hx = w->usehx;
848 ly = w->usely; hy = w->usehy;
849
850 /* now draw the thumbs */
851 w->usehx += DISPLAYSLIDERSIZE;
852 w->usely -= DISPLAYSLIDERSIZE;
853 us_drawverticalsliderthumb(w, hx, ly, hy, w->thumbly, w->thumbhy);
854 us_drawhorizontalsliderthumb(w, ly, lx, hx, w->thumblx, w->thumbhx, numicons);
855 if (numicons > 0)
856 us_drawexplorericon(w, lx, w->usely);
857 w->usehx -= DISPLAYSLIDERSIZE;
858 w->usely += DISPLAYSLIDERSIZE;
859 }
860
861 #define ARROWPOINTS 7
862 static INTBIG us_xarrowpoint[] = {1, DISPLAYSLIDERSIZE/2, DISPLAYSLIDERSIZE/2, DISPLAYSLIDERSIZE-1,
863 DISPLAYSLIDERSIZE-1, DISPLAYSLIDERSIZE/2, DISPLAYSLIDERSIZE/2};
864 static INTBIG us_yarrowpoint[] = {1+DISPLAYSLIDERSIZE/2, DISPLAYSLIDERSIZE,
865 1+DISPLAYSLIDERSIZE/3*2, 1+DISPLAYSLIDERSIZE/3*2, 2+DISPLAYSLIDERSIZE/3,
866 2+DISPLAYSLIDERSIZE/3, 2};
867
868 /*
869 * Routine to draw a vertical slider in window "w" whose left edge is "lx" and which
870 * runs vertically from "ly" to "hy". The slider has arrows and borders, but no thumb.
871 * If "onleft" is true, this slider is on the left.
872 */
us_drawverticalslider(WINDOWPART * w,INTBIG lx,INTBIG ly,INTBIG hy,BOOLEAN onleft)873 void us_drawverticalslider(WINDOWPART *w, INTBIG lx, INTBIG ly, INTBIG hy, BOOLEAN onleft)
874 {
875 static POLYGON *poly = NOPOLYGON;
876 REGISTER INTBIG i;
877 WINDOWPART ww;
878
879 /* get polygon */
880 (void)needstaticpolygon(&poly, 7, us_tool->cluster);
881
882 ww.screenlx = ww.uselx = w->uselx;
883 ww.screenhx = ww.usehx = w->usehx;
884 ww.screenly = ww.usely = w->usely;
885 ww.screenhy = ww.usehy = w->usehy;
886 ww.frame = w->frame;
887 ww.state = DISPWINDOW;
888 computewindowscale(&ww);
889
890 /* erase the area */
891 poly->desc = &us_box;
892 us_box.col = WHITE;
893 poly->style = FILLEDRECT;
894 maketruerectpoly(lx+1, lx+DISPLAYSLIDERSIZE, ly-1, hy, poly);
895 us_showpoly(poly, &ww);
896
897 /* draw arrows */
898 poly->count = ARROWPOINTS;
899 us_box.col = BLACK;
900 poly->style = FILLED;
901 for(i=0; i<ARROWPOINTS; i++)
902 {
903 poly->xv[i] = lx + us_yarrowpoint[i];
904 poly->yv[i] = ly + us_xarrowpoint[i];
905 }
906 us_showpoly(poly, &ww);
907 for(i=0; i<ARROWPOINTS; i++)
908 {
909 poly->xv[i] = lx + us_yarrowpoint[i];
910 poly->yv[i] = hy - us_xarrowpoint[i];
911 }
912 us_showpoly(poly, &ww);
913
914 /* draw border lines */
915 poly->count = 2;
916 us_box.col = BLACK;
917 poly->style = OPENED;
918 if (!onleft)
919 {
920 poly->xv[0] = lx+1; poly->yv[0] = ly-DISPLAYSLIDERSIZE;
921 poly->xv[1] = lx+1; poly->yv[1] = hy;
922 us_showpoly(poly, &ww);
923 } else
924 {
925 poly->xv[0] = lx+DISPLAYSLIDERSIZE+1; poly->yv[0] = ly-DISPLAYSLIDERSIZE;
926 poly->xv[1] = lx+DISPLAYSLIDERSIZE+1; poly->yv[1] = hy;
927 us_showpoly(poly, &ww);
928 }
929
930 /* draw borders enclosing vertical arrows */
931 poly->xv[0] = lx+1; poly->yv[0] = hy-DISPLAYSLIDERSIZE-1;
932 poly->xv[1] = lx+DISPLAYSLIDERSIZE; poly->yv[1] = hy-DISPLAYSLIDERSIZE-1;
933 us_showpoly(poly, &ww);
934 poly->xv[0] = lx+1; poly->yv[0] = ly+DISPLAYSLIDERSIZE+1;
935 poly->xv[1] = lx+DISPLAYSLIDERSIZE; poly->yv[1] = ly+DISPLAYSLIDERSIZE+1;
936 us_showpoly(poly, &ww);
937 }
938
939 /*
940 * Routine to draw a horizontal slider in window "w" whose top edge is "hy" and which
941 * runs horizontally from "lx" to "hx". The slider has arrows and borders, but no thumb.
942 */
us_drawhorizontalslider(WINDOWPART * w,INTBIG hy,INTBIG lx,INTBIG hx,INTBIG numicons)943 void us_drawhorizontalslider(WINDOWPART *w, INTBIG hy, INTBIG lx, INTBIG hx, INTBIG numicons)
944 {
945 static POLYGON *poly = NOPOLYGON;
946 REGISTER INTBIG i;
947 WINDOWPART ww;
948
949 /* get polygon */
950 (void)needstaticpolygon(&poly, 7, us_tool->cluster);
951
952 ww.screenlx = ww.uselx = w->uselx;
953 ww.screenhx = ww.usehx = w->usehx;
954 ww.screenly = ww.usely = w->usely;
955 ww.screenhy = ww.usehy = w->usehy;
956 ww.frame = w->frame;
957 ww.state = DISPWINDOW;
958 computewindowscale(&ww);
959
960 /* erase the area */
961 lx += numicons * DISPLAYSLIDERSIZE;
962 poly->desc = &us_box;
963 us_box.col = WHITE;
964 poly->style = FILLEDRECT;
965 maketruerectpoly(lx, hx+1, hy-DISPLAYSLIDERSIZE, hy-1, poly);
966 us_showpoly(poly, &ww);
967
968 /* draw arrows */
969 poly->count = ARROWPOINTS;
970 us_box.col = BLACK;
971 poly->style = FILLED;
972 for(i=0; i<ARROWPOINTS; i++)
973 {
974 poly->xv[i] = lx + us_xarrowpoint[i];
975 poly->yv[i] = hy - us_yarrowpoint[i];
976 }
977 us_showpoly(poly, &ww);
978 for(i=0; i<ARROWPOINTS; i++)
979 {
980 poly->xv[i] = hx - us_xarrowpoint[i];
981 poly->yv[i] = hy - us_yarrowpoint[i];
982 }
983 us_showpoly(poly, &ww);
984
985 /* draw border lines */
986 poly->count = 2;
987 us_box.col = BLACK;
988 poly->style = OPENED;
989 poly->xv[0] = lx; poly->yv[0] = hy-1;
990 poly->xv[1] = hx+DISPLAYSLIDERSIZE; poly->yv[1] = hy-1;
991 us_showpoly(poly, &ww);
992
993 /* draw borders enclosing vertical arrows */
994 poly->xv[0] = lx+DISPLAYSLIDERSIZE+1; poly->yv[0] = hy-DISPLAYSLIDERSIZE;
995 poly->xv[1] = lx+DISPLAYSLIDERSIZE+1; poly->yv[1] = hy-1;
996 us_showpoly(poly, &ww);
997 poly->xv[0] = hx-DISPLAYSLIDERSIZE-1; poly->yv[0] = hy-DISPLAYSLIDERSIZE;
998 poly->xv[1] = hx-DISPLAYSLIDERSIZE-1; poly->yv[1] = hy-1;
999 us_showpoly(poly, &ww);
1000 }
1001
1002 /*
1003 * Routine to draw the thumb in the vertical slider of window "w". The slider has
1004 * its left edge at "hx" and runs from "ly" to "hy". The thumb runs from
1005 * "lt" to "ht" (if "lt" is greater than "ht", don't draw a thumb).
1006 */
us_drawverticalsliderthumb(WINDOWPART * w,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG lt,INTBIG ht)1007 void us_drawverticalsliderthumb(WINDOWPART *w, INTBIG hx, INTBIG ly, INTBIG hy,
1008 INTBIG lt, INTBIG ht)
1009 {
1010 static POLYGON *poly = NOPOLYGON;
1011 WINDOWPART ww;
1012
1013 /* get polygon */
1014 (void)needstaticpolygon(&poly, 7, us_tool->cluster);
1015
1016 ww.screenlx = ww.uselx = w->uselx;
1017 ww.screenhx = ww.usehx = w->usehx;
1018 ww.screenly = ww.usely = w->usely;
1019 ww.screenhy = ww.usehy = w->usehy;
1020 ww.frame = w->frame;
1021 ww.state = DISPWINDOW;
1022 computewindowscale(&ww);
1023
1024 poly->desc = &us_box;
1025
1026 /* erase the vertical slider on the right */
1027 us_box.col = LGRAY;
1028 poly->style = FILLEDRECT;
1029 maketruerectpoly(hx+2, hx+DISPLAYSLIDERSIZE, ly+DISPLAYSLIDERSIZE+2, hy-DISPLAYSLIDERSIZE-2, poly);
1030 us_showpoly(poly, &ww);
1031
1032 /* stop now if no thumb requested */
1033 if (lt > ht) return;
1034
1035 /* draw the vertical thumb */
1036 us_box.col = BLACK;
1037 maketruerectpoly(hx+2, hx+DISPLAYSLIDERSIZE, lt, ht, poly);
1038 us_showpoly(poly, &ww);
1039
1040 /* draw lines around the vertical thumb */
1041 poly->count = 4;
1042 poly->style = CLOSED;
1043 us_box.col = WHITE;
1044 poly->xv[0] = hx+3; poly->yv[0] = lt+1;
1045 poly->xv[1] = hx+3; poly->yv[1] = ht-1;
1046 poly->xv[2] = hx+DISPLAYSLIDERSIZE-1; poly->yv[2] = ht-1;
1047 poly->xv[3] = hx+DISPLAYSLIDERSIZE-1; poly->yv[3] = lt+1;
1048 us_showpoly(poly, &ww);
1049 }
1050
1051 /*
1052 * Routine to draw the thumb in the horizontal slider of window "w". The slider has
1053 * its top edge at "ly" and runs from "lx" to "hx". The thumb runs from
1054 * "lt" to "ht" (if "lt" is greater than "ht", don't draw a thumb).
1055 * "numicons" is the number of icons on the left that will be drawn.
1056 */
us_drawhorizontalsliderthumb(WINDOWPART * w,INTBIG ly,INTBIG lx,INTBIG hx,INTBIG lt,INTBIG ht,INTBIG numicons)1057 void us_drawhorizontalsliderthumb(WINDOWPART *w, INTBIG ly, INTBIG lx, INTBIG hx, INTBIG lt, INTBIG ht, INTBIG numicons)
1058 {
1059 static POLYGON *poly = NOPOLYGON;
1060 WINDOWPART ww;
1061
1062 /* get polygon */
1063 (void)needstaticpolygon(&poly, 7, us_tool->cluster);
1064
1065 ww.screenlx = ww.uselx = w->uselx;
1066 ww.screenhx = ww.usehx = w->usehx;
1067 ww.screenly = ww.usely = w->usely;
1068 ww.screenhy = ww.usehy = w->usehy;
1069 ww.frame = w->frame;
1070 ww.state = DISPWINDOW;
1071 computewindowscale(&ww);
1072
1073 poly->desc = &us_box;
1074 lx += numicons * DISPLAYSLIDERSIZE;
1075
1076 /* erase the horizontal slider on the bottom */
1077 us_box.col = LGRAY;
1078 poly->style = FILLEDRECT;
1079 maketruerectpoly(lx+DISPLAYSLIDERSIZE+2, hx-DISPLAYSLIDERSIZE-2, ly-DISPLAYSLIDERSIZE, ly-2, poly);
1080 us_showpoly(poly, &ww);
1081
1082 /* stop now if no thumb requested */
1083 if (lt > ht) return;
1084
1085 /* draw the horizontal thumb */
1086 us_box.col = BLACK;
1087 maketruerectpoly(lt, ht, ly-DISPLAYSLIDERSIZE, ly-2, poly);
1088 us_showpoly(poly, &ww);
1089
1090 /* draw lines around the horizontal thumb */
1091 poly->count = 4;
1092 poly->style = CLOSED;
1093 us_box.col = WHITE;
1094 poly->xv[0] = lt+1; poly->yv[0] = ly-DISPLAYSLIDERSIZE+1;
1095 poly->xv[1] = lt+1; poly->yv[1] = ly-3;
1096 poly->xv[2] = ht-1; poly->yv[2] = ly-3;
1097 poly->xv[3] = ht-1; poly->yv[3] = ly-DISPLAYSLIDERSIZE+1;
1098 us_showpoly(poly, &ww);
1099 }
1100
1101 /*
1102 * routine to erase window "w" and draw everything that should be in it.
1103 * If "now" is true, draw everything immediately. Otherwise, draw
1104 * overlapping layers first and queue opaque layers for later.
1105 */
us_redisplaynow(WINDOWPART * w,BOOLEAN now)1106 void us_redisplaynow(WINDOWPART *w, BOOLEAN now)
1107 {
1108 REGISTER NODEPROTO *cell;
1109 REGISTER VARIABLE *var;
1110 REGISTER TECHNOLOGY *tech;
1111 REGISTER INTBIG i, j, lambda, alignment;
1112 INTBIG cenx, ceny, dummy;
1113 static POLYGON *poly = NOPOLYGON;
1114
1115 /* begin accumulation of polygons if doing 3D drawing */
1116 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dstartdrawing(w);
1117
1118 /* erase the window */
1119 us_erasewindow(w);
1120 cell = w->curnodeproto;
1121 if (cell == NONODEPROTO)
1122 {
1123 us_showemptywindow(w);
1124 return;
1125 }
1126
1127 /* set the environment window for hierarchy traversal */
1128 (void)setvariablewindow(w);
1129
1130 /* show the background if editing in place */
1131 if ((w->state&INPLACEEDIT) != 0 && w->topnodeproto != NONODEPROTO)
1132 {
1133 /* indicate that the in-place surround is being drawn */
1134 w->state = (w->state & ~INPLACEEDIT) | SURROUNDINPLACEEDIT;
1135
1136 /* draw the surround */
1137 us_drawcellcontents(w->topnodeproto, w, TRUE);
1138
1139 /* dim the entire cell */
1140 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1141 maketruerectpoly(w->screenlx, w->screenhx, w->screenly, w->screenhy, poly);
1142 poly->desc = &us_dimbox;
1143 poly->style = FILLEDRECT;
1144 (*us_displayroutine)(poly, w);
1145
1146 /* clear the area of the cell */
1147 makerectpoly(cell->lowx, cell->highx, cell->lowy, cell->highy, poly);
1148 poly->style = FILLED;
1149 xformpoly(poly, w->outofcell);
1150 poly->desc = &us_hbox; us_hbox.col = 0;
1151 (*us_displayroutine)(poly, w);
1152
1153 /* go back to drawing in-place */
1154 w->state = (w->state & ~SURROUNDINPLACEEDIT) | INPLACEEDIT;
1155 }
1156
1157 /* draw the frame if there is one */
1158 if ((w->state&WINDOWTYPE) != DISP3DWINDOW)
1159 {
1160 j = framepolys(cell);
1161 if (j != 0)
1162 {
1163 /* get polygon */
1164 (void)needstaticpolygon(&poly, 6, us_tool->cluster);
1165 for(i=0; i<j; i++)
1166 {
1167 framepoly(i, poly, cell);
1168 (*us_displayroutine)(poly, w);
1169 }
1170 }
1171 }
1172
1173 us_drawcellcontents(cell, w, now);
1174
1175 /* show this cell and export variables */
1176 us_drawnodeprotovariables(cell, el_matid, w, FALSE);
1177
1178 /* re-draw grid if on */
1179 if ((w->state&(GRIDON|GRIDTOOSMALL)) == GRIDON &&
1180 (w->state&WINDOWTYPE) != DISP3DWINDOW)
1181 {
1182 /* get polygon */
1183 (void)needstaticpolygon(&poly, 6, us_tool->cluster);
1184
1185 /* grid spacing */
1186 lambda = lambdaofcell(cell);
1187 poly->xv[0] = muldiv(w->gridx, lambda, WHOLE);
1188 poly->yv[0] = muldiv(w->gridy, lambda, WHOLE);
1189
1190 /* initial grid location */
1191 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_gridfloatskey);
1192 if (var == NOVARIABLE || var->addr == 0)
1193 {
1194 poly->xv[1] = w->screenlx / poly->xv[0] * poly->xv[0];
1195 poly->yv[1] = w->screenly / poly->yv[0] * poly->yv[0];
1196 } else
1197 {
1198 grabpoint(cell, &cenx, &ceny);
1199 tech = cell->tech;
1200 if (tech == NOTECHNOLOGY) tech = el_curtech;
1201 alignment = muldiv(us_alignment_ratio, el_curlib->lambda[tech->techindex], WHOLE);
1202 poly->xv[1] = us_alignvalue(cenx, alignment, &dummy);
1203 poly->xv[1] += (w->screenlx-poly->xv[1]) / poly->xv[0] * poly->xv[0];
1204 poly->yv[1] = us_alignvalue(ceny, alignment, &dummy);
1205 poly->yv[1] += (w->screenly-poly->yv[1]) / poly->yv[0] * poly->yv[0];
1206 }
1207
1208 /* display screen extent */
1209 poly->xv[2] = w->uselx; poly->yv[2] = w->usely;
1210 poly->xv[3] = w->usehx; poly->yv[3] = w->usehy;
1211
1212 /* object space extent */
1213 poly->xv[4] = w->screenlx; poly->yv[4] = w->screenly;
1214 poly->xv[5] = w->screenhx; poly->yv[5] = w->screenhy;
1215 poly->count = 6;
1216 poly->style = GRIDDOTS;
1217 poly->desc = &us_gbox;
1218 (*us_displayroutine)(poly, w);
1219 flushscreen();
1220 }
1221
1222 /* reset environment window for hierarchy traversal */
1223 (void)setvariablewindow(NOWINDOWPART);
1224
1225 /* end accumulation of polygons if doing 3D drawing */
1226 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3denddrawing();
1227 }
1228
1229 /*
1230 * Routine to draw the nodes and arcs in cell "cell". Draw it in 1 pass if "now" is TRUE.
1231 */
us_drawcellcontents(NODEPROTO * cell,WINDOWPART * w,BOOLEAN now)1232 void us_drawcellcontents(NODEPROTO *cell, WINDOWPART *w, BOOLEAN now)
1233 {
1234 REGISTER NODEINST *ni;
1235 REGISTER ARCINST *ai;
1236 REGISTER INTBIG ret;
1237
1238 /* initialize hierarchy traversal */
1239 begintraversehierarchy();
1240
1241 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1242 {
1243 if (now)
1244 {
1245 if (us_drawcell(ni, LAYERA, el_matid, 3, w) < 0) break;
1246 } else
1247 {
1248 ret = us_drawcell(ni, LAYERA, el_matid, 1, w);
1249 if (ret < 0) break;
1250 if (ret == 2) us_queueopaque(ni->geom, FALSE);
1251 }
1252 }
1253
1254 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1255 {
1256 if (now)
1257 {
1258 if (us_drawarcinst(ai, LAYERA, el_matid, 3, w) < 0) break;
1259 } else
1260 {
1261 ret = us_drawarcinst(ai, LAYERA, el_matid, 1, w);
1262 if (ret < 0) break;
1263 if (ret == 2) us_queueopaque(ai->geom, FALSE);
1264 }
1265 }
1266
1267 /* stop hierarchy traversal */
1268 endtraversehierarchy();
1269 }
1270
1271 /* erase the screen area in window frame "mw" (all windows if "mw" is zero) */
us_erasescreen(WINDOWFRAME * mw)1272 void us_erasescreen(WINDOWFRAME *mw)
1273 {
1274 WINDOWPART ww;
1275 static POLYGON *poly = NOPOLYGON;
1276 INTBIG swid, shei;
1277 REGISTER WINDOWFRAME *frame;
1278
1279 /* get polygon */
1280 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1281
1282 for(frame = el_firstwindowframe; frame != NOWINDOWFRAME; frame = frame->nextwindowframe)
1283 {
1284 if (mw != NOWINDOWFRAME && frame != mw) continue;
1285 getwindowframesize(frame, &swid, &shei);
1286 ww.screenlx = ww.uselx = 0; ww.screenhx = ww.usehx = swid-1;
1287 ww.screenly = ww.usely = 0; ww.screenhy = ww.usehy = shei-1;
1288 ww.frame = frame;
1289 ww.state = DISPWINDOW;
1290 computewindowscale(&ww);
1291 maketruerectpoly(0, swid-1, 0, shei-1, poly);
1292 poly->desc = &us_ebox;
1293 poly->style = FILLEDRECT;
1294 (*us_displayroutine)(poly, &ww);
1295 }
1296 }
1297
1298 /*
1299 * Routine to display a message in windows with no cell
1300 */
us_showemptywindow(WINDOWPART * w)1301 void us_showemptywindow(WINDOWPART *w)
1302 {
1303 static POLYGON *poly = NOPOLYGON;
1304
1305 /* get polygon */
1306 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1307
1308 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) return;
1309 makerectpoly(w->screenlx, w->screenhx, w->screenly, w->screenhy, poly);
1310 if ((w->state&INPLACEEDIT) != 0)
1311 xformpoly(poly, w->outofcell);
1312 poly->style = TEXTBOX;
1313 poly->string = _("No cell in this window");
1314 TDCLEAR(poly->textdescript);
1315 TDSETSIZE(poly->textdescript, TXTSETPOINTS(20));
1316 poly->tech = el_curtech;
1317 poly->desc = &us_box;
1318 us_box.col = MENTXT;
1319 (*us_displayroutine)(poly, w);
1320 }
1321
1322 /******************** GRID CONTROL ********************/
1323
1324 /*
1325 * routine to turn the grid on or off in window "w", according to "state"
1326 */
us_gridset(WINDOWPART * w,INTBIG state)1327 void us_gridset(WINDOWPART *w, INTBIG state)
1328 {
1329 REGISTER NODEPROTO *np;
1330 REGISTER INTBIG x0, y0, lambda;
1331
1332 if (stopping(STOPREASONDISPLAY)) return;
1333
1334 if ((state&GRIDON) == 0)
1335 {
1336 (void)setval((INTBIG)w, VWINDOWPART, x_("state"), w->state & ~GRIDON, VINTEGER);
1337 return;
1338 }
1339
1340 if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
1341 {
1342 (void)setval((INTBIG)w, VWINDOWPART, x_("state"), (w->state & ~GRIDTOOSMALL) | GRIDON, VINTEGER);
1343 return;
1344 }
1345
1346 np = w->curnodeproto;
1347 if (np == NONODEPROTO)
1348 {
1349 ttyputmsg(_("Edit a cell before manipulating the grid"));
1350 return;
1351 }
1352
1353 np = w->curnodeproto;
1354 if (np != NONODEPROTO)
1355 {
1356 lambda = np->lib->lambda[np->tech->techindex];
1357 x0 = applyxscale(w, muldiv(w->gridx, lambda, WHOLE));
1358 y0 = applyxscale(w, muldiv(w->gridy, lambda, WHOLE));
1359 if (x0 <= 2 || y0 <= 2)
1360 {
1361 if ((w->state&GRIDTOOSMALL) == 0)
1362 {
1363 ttyputverbose(M_("Grid too small, turned off"));
1364 (void)setval((INTBIG)w, VWINDOWPART, x_("state"), w->state | GRIDTOOSMALL | GRIDON, VINTEGER);
1365 }
1366 return;
1367 }
1368 }
1369
1370 if ((w->state&GRIDTOOSMALL) != 0) ttyputverbose(M_("Grid turned back on"));
1371 (void)setval((INTBIG)w, VWINDOWPART, x_("state"), (w->state & ~GRIDTOOSMALL) | GRIDON, VINTEGER);
1372 }
1373
1374 /******************** PORT SELECTION ******************/
1375
1376 typedef struct
1377 {
1378 INTBIG portx, porty;
1379 PORTPROTO *portpp;
1380 INTBIG portangle;
1381 } SHOWNPORTS;
1382
1383 /*
1384 * routine to identify the port locations by number in a nodeinst. If "count" is
1385 * nonzero, identify "count" nodes in the list "nilist". Otherwise identify the
1386 * exports of cell "np". Draw these ports in layer "on" and use numbers instead
1387 * of names if "usenumbers" is true.
1388 */
us_identifyports(INTBIG count,NODEINST ** nilist,NODEPROTO * np,INTBIG on,BOOLEAN usenumbers)1389 void us_identifyports(INTBIG count, NODEINST **nilist, NODEPROTO *np, INTBIG on, BOOLEAN usenumbers)
1390 {
1391 REGISTER PORTPROTO *pp, *subpp;
1392 REGISTER NODEPROTO *parent;
1393 REGISTER NODEINST *subni, *ni;
1394 REGISTER INTBIG digitindentx, digitindenty, total, *portx, *porty, numperside,
1395 leftsidecount, topsidecount, rightsidecount, botsidecount, bestoff,
1396 i, j, dist, bestdist, ignored, halfsizex, halfsizey;
1397 INTBIG x, y, xout, yout, tsx, tsy, sidex[4], sidey[4];
1398 CHAR line[80];
1399 REGISTER WINDOWPART *w;
1400 REGISTER SHOWNPORTS *portlist;
1401 static POLYGON *poly = NOPOLYGON;
1402
1403 /* get polygon */
1404 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1405
1406 /* determine the window to use */
1407 if (count == 0) parent = np; else parent = nilist[0]->parent;
1408 if (parent == getcurcell()) w = el_curwindowpart; else
1409 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1410 if (parent == w->curnodeproto) break;
1411 if (w == NOWINDOWPART) return;
1412
1413 /* determine spacing of lines from edge of window */
1414 digitindentx = (w->screenhx - w->screenlx) / 15;
1415 digitindenty = (w->screenhy - w->screenly) / 15;
1416
1417 /* count the ports */
1418 total = ignored = 0;
1419 if (count == 0)
1420 {
1421 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1422 {
1423 subni = pp->subnodeinst;
1424 subpp = pp->subportproto;
1425 portposition(subni, subpp, &x, &y);
1426 if ((w->state&INPLACEEDIT) != 0)
1427 xform(x, y, &x, &y, w->outofcell);
1428 if (x < w->screenlx || x > w->screenhx ||
1429 y < w->screenly || y > w->screenhy) ignored++; else
1430 total++;
1431 }
1432 } else
1433 {
1434 for(i=0; i<count; i++)
1435 {
1436 ni = nilist[i];
1437 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1438 {
1439 portposition(ni, pp, &x, &y);
1440 if ((w->state&INPLACEEDIT) != 0)
1441 xform(x, y, &x, &y, w->outofcell);
1442 if (x < w->screenlx || x > w->screenhx ||
1443 y < w->screenly || y > w->screenhy) ignored++; else
1444 total++;
1445 }
1446 }
1447 }
1448 if (total == 0)
1449 {
1450 if (ignored <= 0)
1451 {
1452 if (count == 0)
1453 ttyputmsg(_("There are no ports on cell %s"), describenodeproto(np)); else
1454 ttyputmsg(_("There are no ports on the node(s)"));
1455 } else
1456 {
1457 ttyputmsg(_("All %ld ports are outside of the window"), ignored);
1458 }
1459 return;
1460 }
1461
1462 /* allocate space for the port information */
1463 portx = (INTBIG *)emalloc(total * SIZEOFINTBIG, el_tempcluster);
1464 if (portx == 0) return;
1465 porty = (INTBIG *)emalloc(total * SIZEOFINTBIG, el_tempcluster);
1466 if (porty == 0) return;
1467 portlist = (SHOWNPORTS *)emalloc(total * (sizeof (SHOWNPORTS)), el_tempcluster);
1468 if (portlist == 0) return;
1469 numperside = (total + 3) / 4;
1470 leftsidecount = topsidecount = rightsidecount = botsidecount = numperside;
1471 if (leftsidecount + topsidecount + rightsidecount + botsidecount > total)
1472 botsidecount--;
1473 if (leftsidecount + topsidecount + rightsidecount + botsidecount > total)
1474 topsidecount--;
1475 if (leftsidecount + topsidecount + rightsidecount + botsidecount > total)
1476 rightsidecount--;
1477 j = 0;
1478 for(i=0; i<leftsidecount; i++)
1479 {
1480 portx[j] = w->screenlx + digitindentx;
1481 porty[j] = (w->screenhy - w->screenly) / (leftsidecount+1) * (i+1) + w->screenly;
1482 j++;
1483 }
1484 for(i=0; i<topsidecount; i++)
1485 {
1486 portx[j] = (w->screenhx - w->screenlx) / (topsidecount+1) * (i+1) + w->screenlx;
1487 porty[j] = w->screenhy - digitindenty;
1488 j++;
1489 }
1490 for(i=0; i<rightsidecount; i++)
1491 {
1492 portx[j] = w->screenhx - digitindentx;
1493 porty[j] = w->screenhy - (w->screenhy - w->screenly) / (rightsidecount+1) * (i+1);
1494 j++;
1495 }
1496 for(i=0; i<botsidecount; i++)
1497 {
1498 portx[j] = w->screenhx - (w->screenhx - w->screenlx) / (botsidecount+1) * (i+1);
1499 porty[j] = w->screenly + digitindenty;
1500 j++;
1501 }
1502 for(i=0; i<total; i++)
1503 {
1504 if ((w->state&INPLACEEDIT) != 0)
1505 xform(portx[i], porty[i], &portx[i], &porty[i], w->intocell);
1506 }
1507
1508 /* associate ports with display locations */
1509 if (count == 0)
1510 {
1511 i = 0;
1512 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1513 {
1514 subni = pp->subnodeinst;
1515 subpp = pp->subportproto;
1516 portposition(subni, subpp, &x, &y);
1517 xout = x; yout = y;
1518 if ((w->state&INPLACEEDIT) != 0)
1519 xform(xout, yout, &xout, &yout, w->outofcell);
1520 if (xout < w->screenlx || xout > w->screenhx ||
1521 yout < w->screenly || yout > w->screenhy) continue;
1522
1523 portlist[i].portx = x;
1524 portlist[i].porty = y;
1525 portlist[i].portpp = pp;
1526 i++;
1527 }
1528 } else
1529 {
1530 i = 0;
1531 for(j=0; j<count; j++)
1532 {
1533 ni = nilist[j];
1534 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1535 {
1536 portposition(ni, pp, &x, &y);
1537 xout = x; yout = y;
1538 if ((w->state&INPLACEEDIT) != 0)
1539 xform(xout, yout, &xout, &yout, w->outofcell);
1540 if (xout < w->screenlx || xout > w->screenhx ||
1541 yout < w->screenly || yout > w->screenhy) continue;
1542
1543 portlist[i].portx = x;
1544 portlist[i].porty = y;
1545 portlist[i].portpp = pp;
1546 i++;
1547 }
1548 }
1549 }
1550
1551 /* build a sorted list of ports around the center */
1552 x = y = 0;
1553 for(i=0; i<total; i++)
1554 {
1555 x += portlist[i].portx;
1556 y += portlist[i].porty;
1557 }
1558 x /= total; y /= total;
1559 for(i=0; i<total; i++)
1560 {
1561 if (x == portlist[i].portx && y == portlist[i].porty)
1562 portlist[i].portangle = 0; else
1563 portlist[i].portangle = -figureangle(x, y, portlist[i].portx, portlist[i].porty);
1564 }
1565 esort(portlist, total, sizeof(SHOWNPORTS), us_sortshownports);
1566
1567 /* figure out the best rotation offset */
1568 bestdist = 0;
1569 for(i=0; i<total; i++)
1570 {
1571 dist = 0;
1572 for(j=0; j<total; j++)
1573 dist += computedistance(portx[j],porty[j],
1574 portlist[(j+i)%total].portx,portlist[(j+i)%total].porty);
1575 if (dist < bestdist || i == 0)
1576 {
1577 bestoff = i;
1578 bestdist = dist;
1579 }
1580 }
1581
1582 /* show the ports */
1583 for(i=0; i<total; i++)
1584 {
1585 if (usenumbers)
1586 {
1587 (void)esnprintf(line, 80, x_("%ld"), i);
1588 poly->string = line;
1589 } else
1590 {
1591 poly->string = portlist[(bestoff+i)%total].portpp->protoname;
1592 }
1593
1594 /* draw the port index number */
1595 poly->xv[0] = portx[i]; poly->yv[0] = porty[i]; poly->count = 1;
1596 poly->desc = &us_hbox;
1597 poly->style = TEXTCENT;
1598 TDCLEAR(poly->textdescript);
1599 TDSETSIZE(poly->textdescript, TXTSETPOINTS(20));
1600 poly->tech = el_curtech;
1601 us_hbox.col = HIGHLIT&on;
1602 us_showpoly(poly, w);
1603 (void)estrcpy(line, x_(""));
1604
1605 /* draw the line from the port to the index number */
1606 poly->xv[0] = portlist[(bestoff+i)%total].portx;
1607 poly->yv[0] = portlist[(bestoff+i)%total].porty;
1608 screensettextinfo(w, el_curtech, poly->textdescript);
1609 screengettextsize(w, poly->string, &tsx, &tsy);
1610 halfsizex = (INTBIG)((tsx+2) / w->scalex / 2.0f + 0.5f);
1611 halfsizey = (INTBIG)((tsy+2) / w->scaley / 2.0f + 0.5f);
1612 sidex[0] = portx[i]-halfsizex; sidey[0] = porty[i];
1613 sidex[1] = portx[i]+halfsizex; sidey[1] = porty[i];
1614 sidex[2] = portx[i]; sidey[2] = porty[i]-halfsizey;
1615 sidex[3] = portx[i]; sidey[3] = porty[i]+halfsizey;
1616 for(j=0; j<4; j++)
1617 {
1618 dist = computedistance(poly->xv[0], poly->yv[0], sidex[j], sidey[j]);
1619 if (j != 0 && dist >= bestdist) continue;
1620 bestdist = dist;
1621 poly->xv[1] = sidex[j]; poly->yv[1] = sidey[j];
1622 }
1623 poly->count = 2;
1624 poly->desc = &us_arbit;
1625 poly->style = VECTORS;
1626 us_arbit.bits = LAYERH; us_arbit.col = HIGHLIT&on;
1627 us_showpoly(poly, w);
1628 }
1629 flushscreen();
1630 efree((CHAR *)portx);
1631 efree((CHAR *)porty);
1632 efree((CHAR *)portlist);
1633 if (ignored > 0)
1634 ttyputmsg(_("Could not display %ld %s (outside of the window)"), ignored,
1635 makeplural(_("port"), ignored));
1636 }
1637
1638 /*
1639 * Helper routine for "esort" that makes shown ports go in proper circular order.
1640 */
us_sortshownports(const void * e1,const void * e2)1641 int us_sortshownports(const void *e1, const void *e2)
1642 {
1643 REGISTER SHOWNPORTS *s1, *s2;
1644
1645 s1 = (SHOWNPORTS *)e1;
1646 s2 = (SHOWNPORTS *)e2;
1647 return(s1->portangle - s2->portangle);
1648 }
1649
1650 /******************** NODE/ARC DISPLAY ********************/
1651
1652 /*
1653 * routine to draw nodeinst "ni" when transformed through "prevtrans".
1654 * If "on" is nonzero, draw it, otherwise erase it. If "layers" is
1655 * 1, only transparent layers are drawn. If "layers" is 2, only
1656 * opaque layers are drawn. If "layers" is 3, all layers are drawn.
1657 * The nodeinst is drawin in window "w". The routine returns a layers code
1658 * to indicate any other layers that must be drawn. It returns negative
1659 * if the display has been interrupted. It is assumed that this
1660 * nodeinst is in the current cell and must be transformed properly first.
1661 */
us_drawcell(NODEINST * ni,INTBIG on,XARRAY prevtrans,INTBIG layers,WINDOWPART * w)1662 INTBIG us_drawcell(NODEINST *ni, INTBIG on, XARRAY prevtrans, INTBIG layers, WINDOWPART *w)
1663 {
1664 XARRAY localtran, trans;
1665 REGISTER INTBIG res;
1666
1667 /* make transformation matrix within the current nodeinst */
1668 if (ni->rotation == 0 && ni->transpose == 0)
1669 {
1670 res = us_drawnodeinst(ni, on, prevtrans, layers, w);
1671 } else
1672 {
1673 makerot(ni, localtran);
1674 transmult(localtran, prevtrans, trans);
1675 res = us_drawnodeinst(ni, on, trans, layers, w);
1676 }
1677 if (res == -2) return(-1);
1678 if (res == -1) res = 0;
1679 return(res);
1680 }
1681
1682 /*
1683 * routine to draw nodeinst "ni" when transformed through "prevtrans".
1684 * If "on" is nonzero, draw it, otherwise erase it. The parameter
1685 * "layers" determines which parts of the nodeinst to draw: 1 for
1686 * transparent layers, 2 for opaque layers, and 3 for both.
1687 * No assumptions about the location of the nodeinst are made: it is
1688 * displayed exactly as it is transformed. The routine returns
1689 * -2 if display has been interrupted, -1 if the nodeinst is off the screen,
1690 * 1 if there are transparent layers to be drawn, 2 if there are opaque layers
1691 * to be drawn, and 0 if nothing else needs to be drawn.
1692 */
us_drawnodeinst(NODEINST * ni,INTBIG on,XARRAY prevtrans,INTBIG layers,WINDOWPART * w)1693 INTBIG us_drawnodeinst(NODEINST *ni, INTBIG on, XARRAY prevtrans, INTBIG layers, WINDOWPART *w)
1694 {
1695 REGISTER INTBIG i, j, res, displaytotal, low, high, cutsizex, cutsizey, portstyle,
1696 ratio, swap, lambda, size;
1697 INTBIG color, bits, moretodo;
1698 XARRAY localtran, subrot, trans, *xptr, cliptrans;
1699 INTBIG bx, by, ux, uy, portcliplx, portcliphx, portcliply, portcliphy, drawport,
1700 reasonable;
1701 static POLYGON *poly = NOPOLYGON;
1702 REGISTER GRAPHICS *gra;
1703 REGISTER NODEPROTO *np;
1704 REGISTER PORTPROTO *pp;
1705 REGISTER PORTARCINST *pi;
1706 REGISTER PORTEXPINST *pe;
1707 REGISTER NODEINST *ino;
1708 REGISTER ARCINST *iar;
1709 REGISTER VARIABLE *var;
1710
1711 /* initialize for drawing of cells */
1712 us_stopevent++;
1713 if ((us_stopevent%25) == 0)
1714 if (stopping(STOPREASONDISPLAY)) return(-2);
1715
1716 /* get polygon */
1717 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1718
1719 moretodo = 0;
1720 np = ni->proto;
1721
1722 /* get outline of nodeinst in the window */
1723 if ((w->state&INPLACEEDIT) == 0) transcpy(prevtrans, cliptrans); else
1724 transmult(prevtrans, w->outofcell, cliptrans);
1725 if (ismanhattan(cliptrans))
1726 {
1727 /* manhattan orientation, so only examine 2 diagonal corner points */
1728 xform(ni->lowx, ni->lowy, &bx, &by, cliptrans);
1729 xform(ni->highx, ni->highy, &ux, &uy, cliptrans);
1730 if (bx > ux) { swap = bx; bx = ux; ux = swap; }
1731 if (by > uy) { swap = by; by = uy; uy = swap; }
1732 } else
1733 {
1734 /* nonmanhattan orientation, must examine all 4 corner points */
1735 bx = ni->lowx; ux = ni->highx;
1736 by = ni->lowy; uy = ni->highy;
1737 xformbox(&bx, &ux, &by, &uy, cliptrans);
1738 }
1739
1740 /* check for being off screen and return error message */
1741 if (bx > w->screenhx || ux < w->screenlx || by > w->screenhy || uy < w->screenly)
1742 return(-1);
1743
1744 /* primitive nodeinst: ask the technology how to draw it */
1745 if (np->primindex != 0)
1746 {
1747 i = nodepolys(ni, &reasonable, w);
1748
1749 /* if the amount of geometry can be reduced, do so at large scales */
1750 if (i != reasonable)
1751 {
1752 cutsizex = applyxscale(w, ni->highx - ni->lowx);
1753 cutsizey = applyyscale(w, ni->highy - ni->lowy);
1754 if (cutsizex*cutsizey < i * 75) i = reasonable;
1755 }
1756 if ((us_state&NONOVERLAPPABLEDISPLAY) != 0)
1757 {
1758 /* no overlappable display: just draw everything */
1759 low = 0; high = i;
1760 } else
1761 {
1762 if ((np->userbits&NHASOPA) == 0) j = i; else
1763 {
1764 j = (np->userbits&NFIRSTOPA) >> NFIRSTOPASH;
1765 if (i < j) j = i;
1766 }
1767 if ((layers&1) != 0) low = 0; else low = j;
1768 if ((layers&2) != 0) high = i; else high = j;
1769 if (low > 0) moretodo |= 1;
1770 if (high < i) moretodo |= 2;
1771 }
1772
1773 /* don't draw invisible pins to alternative output */
1774 if (us_displayroutine != us_showpoly)
1775 if (np == gen_invispinprim && low == 0) low++;
1776
1777 for(j=low; j<high; j++)
1778 {
1779 /* get description of this layer */
1780 shapenodepoly(ni, j, poly);
1781
1782 /* ignore if this layer is not being displayed */
1783 gra = poly->desc;
1784 if ((gra->colstyle&INVISIBLE) != 0) continue;
1785
1786 /* ignore if no bits are to be drawn */
1787 if ((on&gra->col) == 0 && on != 0) continue;
1788
1789 /* draw the nodeinst */
1790 xformpoly(poly, prevtrans);
1791
1792 /* save the color information and update it */
1793 i = gra->col;
1794 gra->col &= on;
1795 /* draw the nodeinst and restore the color */
1796 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
1797 (*us_displayroutine)(poly, w);
1798 gra->col = i;
1799 }
1800 } else
1801 {
1802 /* draw a cell */
1803 if (on == 0)
1804 {
1805 /* cell off: undraw the cell center if it is defined */
1806 poly->desc = &us_cellgra; us_cellgra.col = ALLOFF;
1807 var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
1808 if (var != NOVARIABLE)
1809 {
1810 poly->xv[0] = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
1811 (ni->proto->lowx+ni->proto->highx)/2;
1812 poly->yv[0] = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
1813 (ni->proto->lowy+ni->proto->highy)/2;
1814 poly->count = 1;
1815 poly->style = CROSS;
1816 xformpoly(poly, prevtrans);
1817 (*us_displayroutine)(poly, w);
1818 }
1819
1820 /* cell is off, so simply blank the area */
1821 us_getnodebounds(ni, &bx, &ux, &by, &uy);
1822
1823 /* extend the bounds by 1 pixel */
1824 i = roundfloat(1.0f / w->scalex);
1825 if (i <= 0) i = 1;
1826 maketruerectpoly(bx-i, ux+i, by-i, uy+i, poly);
1827 xformpoly(poly, prevtrans);
1828
1829 /* because "us_getnodebounds()" returns rotated area, "prevtrans" over-rotates */
1830 if (ni->rotation != 0 || ni->transpose != 0)
1831 {
1832 makerotI(ni, localtran);
1833 xformpoly(poly, localtran);
1834 }
1835 poly->style = FILLEDRECT;
1836 (*us_displayroutine)(poly, w);
1837 return(0);
1838 }
1839
1840 /* if drawing in-place surround, do not draw the cell being edited */
1841 if ((w->state&SURROUNDINPLACEEDIT) != 0)
1842 {
1843 NODEINST **nilist;
1844 INTBIG *indexlist, depth, inplacedepth;
1845 gettraversalpath(ni->parent, w, &nilist, &indexlist, &depth, 0);
1846 inplacedepth = w->inplacedepth-1;
1847 if (ni == w->inplacestack[inplacedepth])
1848 {
1849 if (depth >= inplacedepth)
1850 {
1851 for(i=0; i<inplacedepth; i++)
1852 if (w->inplacestack[i] != nilist[depth-inplacedepth+i]) break;
1853 if (i >= inplacedepth) return(0);
1854 }
1855 }
1856 }
1857
1858 /* transform into the nodeinst for display of its guts */
1859 maketrans(ni, localtran);
1860 transmult(localtran, prevtrans, subrot);
1861
1862 /* get cell rectangle */
1863 maketruerectpoly(ni->lowx, ni->highx, ni->lowy, ni->highy, poly);
1864 poly->style = CLOSEDRECT;
1865 xformpoly(poly, prevtrans);
1866 getbbox(poly, &portcliplx, &portcliphx, &portcliply, &portcliphy);
1867 (void)us_makescreen(&portcliplx, &portcliply, &portcliphx, &portcliphy, w);
1868
1869 /* if cell is not expanded, draw its outline, name and ports */
1870 if ((ni->userbits & NEXPAND) == 0)
1871 {
1872 /* draw the unexpanded cell */
1873 if ((layers&2) != 0)
1874 {
1875 /* draw the cell outline as four vectors */
1876 poly->desc = &us_cellgra; us_cellgra.col = el_colcell;
1877 poly->layer = -1;
1878 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
1879 {
1880 (*us_displayroutine)(poly, w);
1881 }
1882
1883 /* write the cell name */
1884 if (TDGETPOS(ni->textdescript) == VTPOSBOXED)
1885 {
1886 makerectpoly(ni->lowx, ni->highx, ni->lowy, ni->highy, poly);
1887 poly->style = FILLED;
1888 } else
1889 {
1890 poly->count = 1;
1891 poly->xv[0] = (ni->lowx + ni->highx) / 2;
1892 poly->yv[0] = (ni->lowy + ni->highy) / 2;
1893 }
1894 adjustdisoffset((INTBIG)ni, VNODEINST, ni->proto->tech, poly, ni->textdescript);
1895 xformpoly(poly, prevtrans);
1896 poly->desc = &us_cellgra; us_cellgra.col = el_colcelltxt;
1897 poly->string = describenodeproto(ni->proto);
1898 size = TDGETSIZE(poly->textdescript);
1899 if (TXTGETQLAMBDA(size) != 0)
1900 {
1901 size = truefontsize(size, w, poly->tech);
1902 if (size > TXTMAXCELLSIZE) size = TXTMAXCELLSIZE;
1903 TDSETSIZE(poly->textdescript, TXTSETPOINTS(size));
1904 }
1905 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
1906 (*us_displayroutine)(poly, w);
1907
1908 /* see if there are displayable variables on the cell */
1909 displaytotal = tech_displayablenvars(ni, w, &tech_oneprocpolyloop);
1910 for(i = 0; i < displaytotal; i++)
1911 {
1912 (void)tech_filldisplayablenvar(ni, poly, w, 0, &tech_oneprocpolyloop);
1913 xformpoly(poly, prevtrans);
1914 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
1915 (*us_displayroutine)(poly, w);
1916 }
1917
1918 /* draw the cell center if it is defined */
1919 var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
1920 if (var != NOVARIABLE)
1921 {
1922 poly->xv[0] = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
1923 (ni->proto->lowx+ni->proto->highx)/2;
1924 poly->yv[0] = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
1925 (ni->proto->lowy+ni->proto->highy)/2;
1926 poly->count = 1;
1927 poly->style = CROSS;
1928 xformpoly(poly, prevtrans);
1929 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
1930 (*us_displayroutine)(poly, w);
1931 }
1932 } else moretodo |= 2;
1933 if (ni->parent == w->curnodeproto)
1934 {
1935 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1936 {
1937 portstyle = (us_useroptions&PORTLABELS) >> PORTLABELSSH;
1938 if ((pp->userbits&PORTDRAWN) == 0)
1939 {
1940 /* if there is an arc or further export on this port, don't draw it */
1941 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1942 if (pi->proto == pp) break;
1943 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1944 if (pe->proto == pp) break;
1945 if (pi != NOPORTARCINST || pe != NOPORTEXPINST) continue;
1946 }
1947
1948 /* don't bother plotting if no bits are to be drawn */
1949 us_graphicsarcs(pp, &bits, &color);
1950 if ((bits&LAYEROE) != 0 && (layers&2) == 0)
1951 { moretodo |= 2; continue; }
1952 if ((bits&LAYEROE) == 0 && (layers&1) == 0)
1953 { moretodo |= 1; continue; }
1954
1955 if (pp->subnodeinst->rotation == 0 && pp->subnodeinst->transpose == 0)
1956 {
1957 us_writeprotoname(pp, LAYERA, subrot, bits, color, w, portcliplx,
1958 portcliphx, portcliply, portcliphy, portstyle);
1959 } else
1960 {
1961 makerot(pp->subnodeinst, localtran);
1962 transmult(localtran, subrot, trans);
1963 us_writeprotoname(pp, LAYERA, trans, bits, color, w, portcliplx,
1964 portcliphx, portcliply, portcliphy, portstyle);
1965 }
1966 }
1967 }
1968 } else
1969 {
1970 /* if the resolution is too fine, just draw texture pattern */
1971 if ((us_useroptions&DRAWTINYCELLS) == 0 && (w->state&WINDOWTYPE) != DISP3DWINDOW)
1972 {
1973 lambda = lambdaofcell(ni->parent);
1974 ratio = lambda * us_tinyratio / WHOLE;
1975 if ((w->screenhx - w->screenlx) / ratio > w->usehx - w->uselx &&
1976 (w->screenhy - w->screenly) / ratio > w->usehy - w->usely)
1977 {
1978 /* cannot sensibly draw the contents at this resolution: just draw a pattern */
1979 poly->desc = &us_graybox; us_graybox.col = el_colcell;
1980 poly->style = FILLEDRECT;
1981 (*us_displayroutine)(poly, w);
1982 poly->desc = &us_cellgra; us_cellgra.col = el_colcell;
1983 if (poly->style == FILLEDRECT) poly->style = CLOSEDRECT; else
1984 poly->style = CLOSED;
1985 (*us_displayroutine)(poly, w);
1986 return(0);
1987 }
1988 }
1989
1990 /* write cell that is expanded */
1991 if ((layers&2) == 0) moretodo |= 2; else
1992 {
1993 /* write ports that must always be displayed */
1994 if (ni->parent == w->curnodeproto)
1995 {
1996 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1997 {
1998 drawport = 0;
1999 portstyle = (us_useroptions&PORTLABELS) >> PORTLABELSSH;
2000 if ((pp->userbits&PORTDRAWN) != 0) drawport = 1;
2001 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2002 if (pi->proto == pp) break;
2003 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2004 if (pe->proto == pp) break;
2005 if (pi == NOPORTARCINST && pe == NOPORTEXPINST)
2006 drawport = 1;
2007
2008 /* determine the transformation for the instance */
2009 ino = pp->subnodeinst;
2010 if (ino->rotation == 0 && ino->transpose == 0)
2011 {
2012 xptr = (XARRAY *)subrot;
2013 } else
2014 {
2015 makerot(ino, localtran);
2016 transmult(localtran, subrot, trans);
2017 xptr = (XARRAY *)trans;
2018 }
2019
2020 /* draw the export if requested */
2021 if (drawport != 0)
2022 us_writeprotoname(pp, LAYERA, *xptr, LAYERO, el_colcelltxt, w,
2023 portcliplx, portcliphx, portcliply, portcliphy, portstyle);
2024
2025 /* draw attributes on exported ports */
2026 us_drawportprotovariables(pp, LAYERA, *xptr, w, TRUE);
2027 }
2028 }
2029 }
2030
2031 /* descend hierarchy to this node */
2032 downhierarchy(ni, ni->proto, 0);
2033
2034 /* search through cell */
2035 for(ino = np->firstnodeinst; ino != NONODEINST; ino = ino->nextnodeinst)
2036 {
2037 if ((ino->userbits&NVISIBLEINSIDE) != 0) continue;
2038 res = us_drawcell(ino, LAYERA, subrot, layers, w);
2039 if (res < 0) break;
2040 moretodo |= res;
2041 }
2042 for(iar = np->firstarcinst; iar != NOARCINST; iar = iar->nextarcinst)
2043 {
2044 res = us_drawarcinst(iar, LAYERA, subrot, layers, w);
2045 if (res < 0) { res = 0; break; }
2046 moretodo |= res;
2047 }
2048 uphierarchy();
2049
2050 /* draw text */
2051 if ((layers&2) != 0)
2052 {
2053 /* see if there are displayable variables on the cell instance */
2054 displaytotal = tech_displayablenvars(ni, w, &tech_oneprocpolyloop);
2055 for(i = 0; i < displaytotal; i++)
2056 {
2057 (void)tech_filldisplayablenvar(ni, poly, w, 0, &tech_oneprocpolyloop);
2058 xformpoly(poly, prevtrans);
2059 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
2060 (*us_displayroutine)(poly, w);
2061 }
2062
2063 /* draw cell variables on expanded cells */
2064 us_drawnodeprotovariables(ni->proto, subrot, w, TRUE);
2065 }
2066 }
2067 }
2068
2069 /* write export names if appropriate */
2070 if ((us_useroptions&HIDETXTEXPORT) == 0)
2071 {
2072 if (ni->firstportexpinst != NOPORTEXPINST && ni->parent == w->curnodeproto)
2073 {
2074 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2075 {
2076 if (on == 0)
2077 {
2078 us_writeprotoname(pe->exportproto, on, prevtrans, LAYERO,
2079 el_colcelltxt&on, w, 0, 0, 0, 0,
2080 (us_useroptions&EXPORTLABELS)>>EXPORTLABELSSH);
2081 us_drawportprotovariables(pe->exportproto, on, prevtrans, w, FALSE);
2082 } else
2083 {
2084 us_queueexport(pe->exportproto);
2085 }
2086 }
2087 }
2088 }
2089 return(moretodo);
2090 }
2091
2092 /*
2093 * Routine to draw all attributes on cell "np". The cell is in window "w"
2094 * and is transformed by "trans". If "ignoreinherit" is true, ignore inheritable
2095 * attributes (because this is a subcell, and the inherited instance attributes are to be
2096 * shown).
2097 */
us_drawnodeprotovariables(NODEPROTO * np,XARRAY trans,WINDOWPART * w,BOOLEAN ignoreinherit)2098 void us_drawnodeprotovariables(NODEPROTO *np, XARRAY trans, WINDOWPART *w, BOOLEAN ignoreinherit)
2099 {
2100 REGISTER INTBIG i, displaytotal;
2101 REGISTER VARIABLE *var;
2102 static POLYGON *poly = NOPOLYGON;
2103
2104 /* get polygon */
2105 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2106
2107 displaytotal = tech_displayablecellvars(np, w, &tech_oneprocpolyloop);
2108 for(i = 0; i < displaytotal; i++)
2109 {
2110 var = tech_filldisplayablecellvar(np, poly, w, 0, &tech_oneprocpolyloop);
2111 if (ignoreinherit && TDGETINHERIT(var->textdescript) != 0) continue;
2112 xformpoly(poly, trans);
2113 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
2114 (*us_displayroutine)(poly, w);
2115 }
2116 }
2117
2118 /*
2119 * Routine to draw all attributes on port "pp" with color "on". The port is in window "w"
2120 * and is transformed by "trans". If "ignoreinherit" is true, ignore inheritable
2121 * attributes (because this is a subcell, and the inherited instance attributes are to be
2122 * shown).
2123 */
us_drawportprotovariables(PORTPROTO * pp,INTBIG on,XARRAY trans,WINDOWPART * w,BOOLEAN ignoreinherit)2124 void us_drawportprotovariables(PORTPROTO *pp, INTBIG on, XARRAY trans, WINDOWPART *w, BOOLEAN ignoreinherit)
2125 {
2126 REGISTER INTBIG i, displaytotal;
2127 REGISTER VARIABLE *var;
2128 static POLYGON *poly = NOPOLYGON;
2129
2130 /* get polygon */
2131 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2132
2133 displaytotal = tech_displayableportvars(pp, w, &tech_oneprocpolyloop);
2134 for(i = 0; i < displaytotal; i++)
2135 {
2136 var = tech_filldisplayableportvar(pp, poly, w, 0, &tech_oneprocpolyloop);
2137 if (ignoreinherit && TDGETINHERIT(var->textdescript) != 0) continue;
2138 xformpoly(poly, trans);
2139 if (on == 0)
2140 {
2141 us_arbit = *poly->desc;
2142 us_arbit.col = 0;
2143 poly->desc = &us_arbit;
2144 }
2145 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
2146 (*us_displayroutine)(poly, w);
2147 }
2148 }
2149
2150 /*
2151 * routine to determine the color of port "pp" by combining the colors
2152 * of all arcs that can connect to that port into the integers
2153 * "bitplanes" and "color". The arcs under consideration are kept
2154 * in the array "connections"
2155 */
us_graphicsarcs(PORTPROTO * pp,INTBIG * bitplanes,INTBIG * color)2156 void us_graphicsarcs(PORTPROTO *pp, INTBIG *bitplanes, INTBIG *color)
2157 {
2158 REGISTER INTBIG i;
2159 REGISTER ARCPROTO *outside;
2160 REGISTER ARCINST *ai;
2161 ARCINST arc;
2162 REGISTER TECHNOLOGY *tech;
2163
2164 *bitplanes = *color = 0;
2165 outside = NOARCPROTO;
2166 ai = &arc; initdummyarc(ai);
2167 ai->width = ai->length = 2000;
2168 ai->end[0].xpos = ai->end[0].ypos = ai->end[1].xpos = 0;
2169 ai->end[1].ypos = 2000;
2170 tech = NOTECHNOLOGY;
2171 for(i=0; pp->connects[i] != NOARCPROTO; i++)
2172 {
2173 ai->proto = pp->connects[i];
2174 if (tech != NOTECHNOLOGY && ai->proto->tech != tech)
2175 {
2176 outside = ai->proto;
2177 continue;
2178 }
2179 tech = ai->proto->tech;
2180 us_combinelayers(ai, bitplanes, color);
2181 }
2182 if (*bitplanes == 0 && outside != NOARCPROTO)
2183 {
2184 ai->proto = outside;
2185 us_combinelayers(ai, bitplanes, color);
2186 }
2187 }
2188
2189 /*
2190 * helper routine for "us_graphicsarcs" that builds the integer "bitplanes"
2191 * and "color" with the layers in arcinst "ai".
2192 */
us_combinelayers(ARCINST * ai,INTBIG * bitplanes,INTBIG * color)2193 void us_combinelayers(ARCINST *ai, INTBIG *bitplanes, INTBIG *color)
2194 {
2195 REGISTER INTBIG j, k;
2196 REGISTER INTBIG b, c;
2197 static POLYGON *poly = NOPOLYGON;
2198
2199 /* get polygon */
2200 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2201
2202 k = arcpolys(ai, NOWINDOWPART);
2203 for(j=0; j<k; j++)
2204 {
2205 shapearcpoly(ai, j, poly);
2206 b = poly->desc->bits;
2207 c = poly->desc->col;
2208 *bitplanes |= b;
2209 if (b == LAYERO) *color = c; else *color |= c;
2210 }
2211 }
2212
2213 /*
2214 * routine to draw an arcinst. Returns indicator of what else needs to
2215 * be drawn. Returns negative if display interrupted
2216 */
us_drawarcinst(ARCINST * ai,INTBIG on,XARRAY trans,INTBIG layers,WINDOWPART * w)2217 INTBIG us_drawarcinst(ARCINST *ai, INTBIG on, XARRAY trans, INTBIG layers, WINDOWPART *w)
2218 {
2219 REGISTER INTBIG i, j, low, high;
2220 REGISTER INTBIG moretodo;
2221 REGISTER ARCPROTO *ap;
2222 static POLYGON *poly = NOPOLYGON;
2223
2224 /* ask the technology how to draw the arcinst */
2225 us_stopevent++;
2226 if ((us_stopevent%25) == 0)
2227 if (stopping(STOPREASONDISPLAY)) return(-1);
2228
2229 /* get polygon */
2230 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2231
2232 ap = ai->proto;
2233 i = arcpolys(ai, NOWINDOWPART);
2234 moretodo = 0;
2235 if ((us_state&NONOVERLAPPABLEDISPLAY) != 0)
2236 {
2237 /* no overlappable display: just draw everything */
2238 low = 0; high = i;
2239 } else
2240 {
2241 if ((ap->userbits&AHASOPA) == 0) j = i; else
2242 j = mini((ap->userbits&AFIRSTOPA) >> AFIRSTOPASH, i);
2243 if (layers&1) low = 0; else low = j;
2244 if (layers&2) high = i; else high = j;
2245 if (low > 0) moretodo |= 1;
2246 if (high < i) moretodo |= 2;
2247 }
2248
2249 /* get the endpoints of the arcinst */
2250 for(j=low; j<high; j++)
2251 {
2252 shapearcpoly(ai, j, poly);
2253
2254 /* ignore if this layer is not to be drawn */
2255 if ((poly->desc->colstyle&INVISIBLE) != 0) continue;
2256
2257 /* don't bother plotting if no bits are to be drawn */
2258 if ((on&poly->desc->col) == 0 && on != 0) continue;
2259
2260 /* draw the arcinst */
2261 xformpoly(poly, trans);
2262
2263 /* save the color information and update it */
2264 i = poly->desc->col;
2265 poly->desc->col &= on;
2266
2267 /* draw the nodeinst and restore the color */
2268 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
2269 (*us_displayroutine)(poly, w);
2270 poly->desc->col = i;
2271 }
2272 return(moretodo);
2273 }
2274
2275 /*
2276 * routine to write the name of portproto "pp" at the appropriate location,
2277 * transformed through "prevtrans". The color of the text is "color" and
2278 * the bit planes in which to write the text is in "bits". The text is
2279 * written if "on" is nonzero, erased if zero. The port is written in window
2280 * "w". If "portcliplx" is not equal to "portcliphx", then clip the port text
2281 * to within that range in X and to "portcliply/portcliphy" in Y.
2282 * The "dispstyle" of the port is:
2283 * 0 full port name written
2284 * 1 port drawn as a cross
2285 * 2 no port indication drawn
2286 * 3 short port name written
2287 */
us_writeprotoname(PORTPROTO * pp,INTBIG on,XARRAY prevtrans,INTBIG bits,INTBIG color,WINDOWPART * w,INTBIG portcliplx,INTBIG portcliphx,INTBIG portcliply,INTBIG portcliphy,INTBIG dispstyle)2288 void us_writeprotoname(PORTPROTO *pp, INTBIG on, XARRAY prevtrans, INTBIG bits,
2289 INTBIG color, WINDOWPART *w, INTBIG portcliplx, INTBIG portcliphx, INTBIG portcliply,
2290 INTBIG portcliphy, INTBIG dispstyle)
2291 {
2292 XARRAY localtran, tempt1, tempt2, *t1, *t2, *swapt;
2293 INTBIG px, py;
2294 INTBIG wid, hei;
2295 REGISTER INTBIG sx, sy, lambda;
2296 static POLYGON *poly = NOPOLYGON;
2297 REGISTER NODEINST *ni;
2298 REGISTER NODEPROTO *cell;
2299 REGISTER PORTPROTO *rpp;
2300 REGISTER TECHNOLOGY *tech;
2301
2302 /* quit now if labels are off */
2303 if (dispstyle == 2) return;
2304
2305 /* get polygon */
2306 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2307
2308 /* get technology and lambda */
2309 cell = pp->subnodeinst->parent;
2310 tech = cell->tech;
2311 lambda = cell->lib->lambda[tech->techindex];
2312
2313 /* account for port offset */
2314 t1 = (XARRAY *)tempt1; t2 = (XARRAY *)tempt2;
2315 if (dispstyle != 1 &&
2316 (TDGETXOFF(pp->textdescript) != 0 || TDGETYOFF(pp->textdescript) != 0))
2317 {
2318 transid(localtran);
2319 localtran[2][0] = TDGETXOFF(pp->textdescript);
2320 localtran[2][0] = localtran[2][0] * lambda / 4;
2321 localtran[2][1] = TDGETYOFF(pp->textdescript);
2322 localtran[2][1] = localtran[2][1] * lambda / 4;
2323 transmult(localtran, prevtrans, *t1);
2324 } else transcpy(prevtrans, *t1);
2325
2326 /* build the rest of the transformation to the bottom */
2327 ni = pp->subnodeinst;
2328 rpp = pp->subportproto;
2329 while (ni->proto->primindex == 0)
2330 {
2331 maketrans(ni, localtran);
2332 transmult(localtran, *t1, *t2);
2333 swapt = t1; t1 = t2; t2 = swapt;
2334 ni = rpp->subnodeinst;
2335 rpp = rpp->subportproto;
2336 if (ni->rotation != 0 || ni->transpose != 0)
2337 {
2338 makerot(ni, localtran);
2339 transmult(localtran, *t1, *t2);
2340 swapt = t1; t1 = t2; t2 = swapt;
2341 }
2342 if (dispstyle != 1 && ni->proto->primindex == 0 &&
2343 (TDGETXOFF(rpp->textdescript) != 0 || TDGETYOFF(rpp->textdescript) != 0))
2344 {
2345 transid(localtran);
2346 localtran[2][0] = TDGETXOFF(rpp->textdescript);
2347 localtran[2][0] = localtran[2][0] * lambda / 4;
2348 localtran[2][1] = TDGETYOFF(rpp->textdescript);
2349 localtran[2][1] = localtran[2][1] * lambda / 4;
2350 transmult(localtran, *t1, *t2);
2351 swapt = t1; t1 = t2; t2 = swapt;
2352 }
2353 }
2354
2355 /* get the center position of the port */
2356 shapetransportpoly(ni, rpp, poly, *t1);
2357 if (dispstyle == 1 || TDGETPOS(pp->textdescript) != VTPOSBOXED)
2358 {
2359 getcenter(poly, &px, &py);
2360 poly->xv[0] = px; poly->yv[0] = py; poly->count = 1;
2361 }
2362
2363 /* simple description if only drawing ports as crosses */
2364 if (dispstyle == 1) poly->style = CROSS; else
2365 {
2366 /* writing text name: setup polygon */
2367 TDCOPY(poly->textdescript, pp->textdescript);
2368 poly->tech = pp->parent->tech;
2369
2370 /* convert text description to polygon description */
2371 switch (TDGETPOS(pp->textdescript))
2372 {
2373 case VTPOSCENT: poly->style = TEXTCENT; break;
2374 case VTPOSBOXED: poly->style = TEXTBOX; break;
2375 case VTPOSUP: poly->style = TEXTBOT; break;
2376 case VTPOSDOWN: poly->style = TEXTTOP; break;
2377 case VTPOSLEFT: poly->style = TEXTRIGHT; break;
2378 case VTPOSRIGHT: poly->style = TEXTLEFT; break;
2379 case VTPOSUPLEFT: poly->style = TEXTBOTRIGHT; break;
2380 case VTPOSUPRIGHT: poly->style = TEXTBOTLEFT; break;
2381 case VTPOSDOWNLEFT: poly->style = TEXTTOPRIGHT; break;
2382 case VTPOSDOWNRIGHT: poly->style = TEXTTOPLEFT; break;
2383 }
2384
2385 /* get shortened name if requested */
2386 poly->string = us_displayedportname(pp, dispstyle);
2387
2388 /* acount for node rotation, which port position */
2389 poly->style = rotatelabel(poly->style, TDGETROTATION(poly->textdescript), prevtrans);
2390
2391 /* clip the port text to the cell bounds, if requested */
2392 if (portcliplx != portcliphx)
2393 {
2394 sx = applyxscale(w, px-w->screenlx) + w->uselx;
2395 sy = applyyscale(w, py-w->screenly) + w->usely;
2396 if (sx < portcliplx || sx > portcliphx || sy < portcliply || sy > portcliphy)
2397 return;
2398 screensettextinfo(w, tech, poly->textdescript);
2399 screengettextsize(w, poly->string, &wid, &hei); wid++; hei++;
2400 switch (poly->style)
2401 {
2402 case TEXTCENT:
2403 case TEXTBOT:
2404 case TEXTTOP:
2405 if (portcliphx - portcliplx < wid) poly->style = CROSS; else
2406 {
2407 if (sx-wid/2 < portcliplx) sx = portcliplx + wid/2;
2408 if (sx+wid/2 > portcliphx) sx = portcliphx - wid/2;
2409 }
2410 break;
2411 case TEXTRIGHT:
2412 case TEXTBOTRIGHT:
2413 case TEXTTOPRIGHT:
2414 if (portcliphx - portcliplx < wid) poly->style = CROSS; else
2415 {
2416 if (sx-wid < portcliplx) sx = portcliplx + wid;
2417 if (sx > portcliphx) sx = portcliphx;
2418 }
2419 break;
2420 case TEXTLEFT:
2421 case TEXTBOTLEFT:
2422 case TEXTTOPLEFT:
2423 if (portcliphx - portcliplx < wid) poly->style = CROSS; else
2424 {
2425 if (sx < portcliplx) sx = portcliplx;
2426 if (sx+wid > portcliphx) sx = portcliphx - wid;
2427 }
2428 break;
2429 }
2430 switch (poly->style)
2431 {
2432 case TEXTCENT:
2433 case TEXTRIGHT:
2434 case TEXTLEFT:
2435 if (portcliphy - portcliply < hei) poly->style = CROSS; else
2436 {
2437 if (sy-hei/2 < portcliply) sy = portcliply + hei/2;
2438 if (sy+hei/2 > portcliphy) sy = portcliphy - hei/2;
2439 }
2440 break;
2441 case TEXTBOT:
2442 case TEXTBOTRIGHT:
2443 case TEXTBOTLEFT:
2444 if (portcliphy - portcliply < hei) poly->style = CROSS; else
2445 {
2446 if (sy < portcliply) sy = portcliply;
2447 if (sy+hei > portcliphy) sy = portcliphy - hei;
2448 }
2449 break;
2450 case TEXTTOP:
2451 case TEXTTOPRIGHT:
2452 case TEXTTOPLEFT:
2453 if (portcliphy - portcliply < hei) poly->style = CROSS; else
2454 {
2455 if (sy-hei < portcliply) sy = portcliply + hei;
2456 if (sy > portcliphy) sy = portcliphy;
2457 }
2458 break;
2459 }
2460 poly->xv[0] = muldiv(sx - w->uselx, w->screenhx - w->screenlx,
2461 w->usehx - w->uselx) + w->screenlx;
2462 poly->yv[0] = muldiv(sy - w->usely, w->screenhy - w->screenly,
2463 w->usehy - w->usely) + w->screenly;
2464 }
2465 }
2466
2467 /* set the graphics information */
2468 poly->desc = &us_arbit;
2469 poly->desc->col = color&on;
2470 poly->desc->bits = bits;
2471 poly->layer = -1;
2472 if ((w->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, w); else
2473 (*us_displayroutine)(poly, w);
2474 }
2475
2476 /*
2477 * routine to return the displayed port name for port "pp", given a style of "dispstyle"
2478 * (0: full, 1: crosses, 2: nothing, 3: short)
2479 */
us_displayedportname(PORTPROTO * pp,INTBIG dispstyle)2480 CHAR *us_displayedportname(PORTPROTO *pp, INTBIG dispstyle)
2481 {
2482 REGISTER CHAR *pt;
2483 REGISTER void *infstr;
2484
2485 if (dispstyle == 3)
2486 {
2487 for(pt = pp->protoname; *pt != 0; pt++) if (ispunct(*pt)) break;
2488 if (*pt != 0)
2489 {
2490 infstr = initinfstr();
2491 for(pt = pp->protoname; !ispunct(*pt); pt++) addtoinfstr(infstr, *pt);
2492 return(returninfstr(infstr));
2493 }
2494 }
2495 return(pp->protoname);
2496 }
2497
2498 /******************** PEEK DISPLAY ********************/
2499
2500 static WINDOWPART *us_peekwindow;
2501
us_dopeek(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,NODEPROTO * np,WINDOWPART * w)2502 void us_dopeek(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, NODEPROTO *np, WINDOWPART *w)
2503 {
2504 REGISTER INTBIG ret;
2505
2506 us_peekwindow = w;
2507
2508 /* draw everything in this area */
2509 begintraversehierarchy();
2510 ret = us_drawall(lx, hx, ly, hy, np, el_matid, 1, TRUE);
2511 endtraversehierarchy();
2512
2513 if (ret == 2)
2514 {
2515 begintraversehierarchy();
2516 (void)us_drawall(lx, hx, ly, hy, np, el_matid, 2, TRUE);
2517 endtraversehierarchy();
2518 }
2519 }
2520
2521 /*
2522 * routine to draw everything between "lx" and "hx" in X and between "ly"
2523 * and "hy" in Y of cell "np", given a transformation matrix of "trans".
2524 * If "layers" is 1 then only the transparent layers will be drawn and if
2525 * "layers" is 2 then only the opaque layers will be drawn. Drawing is done
2526 * in window "w". The routine returns the other layers that need to be drawn
2527 * (1 or 2). If it returns -1, the display has been aborted.
2528 */
us_drawall(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,NODEPROTO * np,XARRAY trans,INTBIG layers,BOOLEAN toplevel)2529 INTBIG us_drawall(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, NODEPROTO *np, XARRAY trans,
2530 INTBIG layers, BOOLEAN toplevel)
2531 {
2532 XARRAY localtrans, localrot, thist, subrot, bound, *tbound, *tthis;
2533 INTBIG newlx, newhx, newly, newhy;
2534 REGISTER NODEINST *ni;
2535 REGISTER NODEPROTO *subnt;
2536 REGISTER ARCINST *ai;
2537 REGISTER INTBIG search;
2538 REGISTER INTBIG i, moretodo;
2539 REGISTER GEOM *look;
2540
2541 moretodo = 0;
2542 search = initsearch(lx, hx, ly, hy, np);
2543 for(;;)
2544 {
2545 /* check for interrupts */
2546 us_stopevent++;
2547 if ((us_stopevent%25) == 0)
2548 if (stopping(STOPREASONDISPLAY)) { termsearch(search); break; }
2549
2550 /* get the next object to draw */
2551 look = nextobject(search);
2552 if (look == NOGEOM) break;
2553 if (!look->entryisnode)
2554 {
2555 ai = look->entryaddr.ai;
2556 i = us_drawarcinstpeek(ai, trans, layers);
2557 if (i != -1) moretodo |= i;
2558 } else
2559 {
2560 ni = look->entryaddr.ni;
2561 if (ni->rotation == 0 && ni->transpose == 0)
2562 {
2563 transcpy(trans, thist);
2564 tthis = (XARRAY *)thist;
2565 } else
2566 {
2567 makerot(ni, localrot); transmult(localrot, trans, thist);
2568 tthis = (XARRAY *)thist;
2569 }
2570 if (ni->proto->primindex != 0)
2571 {
2572 /* node is primitive: draw it */
2573 if (toplevel || (ni->userbits&NVISIBLEINSIDE) == 0)
2574 {
2575 i = us_drawnodeinstpeek(ni, *tthis, layers);
2576 if (i != -1) moretodo |= i;
2577 }
2578 } else
2579 {
2580 /* node is complex: recurse */
2581 subnt = ni->proto;
2582 downhierarchy(ni, subnt, 0);
2583 maketransI(ni, localtrans);
2584 if (ni->rotation == 0 && ni->transpose == 0)
2585 tbound = (XARRAY *)localtrans; else
2586 {
2587 makerotI(ni, localrot);
2588 transmult(localrot, localtrans, bound);
2589 tbound = (XARRAY *)bound;
2590 }
2591
2592 /* compute bounding area inside of sub-cell */
2593 newlx = lx; newly = ly; newhx = hx; newhy = hy;
2594 xformbox(&newlx, &newhx, &newly, &newhy, *tbound);
2595
2596 /* compute new matrix for sub-cell display */
2597 localtrans[2][0] = -localtrans[2][0];
2598 localtrans[2][1] = -localtrans[2][1];
2599 transmult(localtrans, *tthis, subrot);
2600 i = us_drawall(newlx, newhx, newly, newhy, subnt, subrot, layers, FALSE);
2601 if (i != -1) moretodo |= i;
2602 uphierarchy();
2603 }
2604 }
2605 }
2606 if (stopping(STOPREASONDISPLAY)) return(-1);
2607 return(moretodo);
2608 }
2609
us_drawarcinstpeek(ARCINST * ai,XARRAY trans,INTBIG layers)2610 INTBIG us_drawarcinstpeek(ARCINST *ai, XARRAY trans, INTBIG layers)
2611 {
2612 REGISTER INTBIG i, j, low, high;
2613 REGISTER INTBIG moretodo;
2614 REGISTER ARCPROTO *ap;
2615 REGISTER GRAPHICS *gra;
2616 static POLYGON *poly = NOPOLYGON;
2617
2618 /* get polygon */
2619 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2620
2621 /* determine which polygons to draw */
2622 ap = ai->proto;
2623 i = arcpolys(ai, us_peekwindow);
2624 moretodo = 0;
2625 if ((us_state&NONOVERLAPPABLEDISPLAY) != 0)
2626 {
2627 /* no overlappable display: just draw everything */
2628 low = 0; high = i;
2629 } else
2630 {
2631 if ((ap->userbits&AHASOPA) == 0) j = i; else
2632 {
2633 j = (ap->userbits&AFIRSTOPA) >> AFIRSTOPASH;
2634 if (i < j) j = i;
2635 }
2636 if (layers&1) low = 0; else low = j;
2637 if (layers&2) high = i; else high = j;
2638 if (low > 0) moretodo |= 1;
2639 if (high < i) moretodo |= 2;
2640 }
2641
2642 /* get the polygons of the arcinst */
2643 for(j=low; j<high; j++)
2644 {
2645 shapearcpoly(ai, j, poly);
2646
2647 /* ignore if this layer is not to be drawn */
2648 gra = poly->desc;
2649 if ((gra->colstyle&INVISIBLE) != 0) continue;
2650
2651 /* don't bother plotting if nothing to be drawn */
2652 if (gra->col == ALLOFF || gra->bits == LAYERN) continue;
2653
2654 /* transform the polygon */
2655 xformpoly(poly, trans);
2656
2657 /* draw the polygon */
2658 if ((us_peekwindow->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, us_peekwindow); else
2659 (*us_displayroutine)(poly, us_peekwindow);
2660 }
2661 return(moretodo);
2662 }
2663
us_drawnodeinstpeek(NODEINST * ni,XARRAY prevtrans,INTBIG layers)2664 INTBIG us_drawnodeinstpeek(NODEINST *ni, XARRAY prevtrans, INTBIG layers)
2665 {
2666 REGISTER INTBIG i, j, low, high, cutsizex, cutsizey;
2667 INTBIG moretodo;
2668 INTBIG reasonable;
2669 static POLYGON *poly = NOPOLYGON;
2670 REGISTER GRAPHICS *gra;
2671 REGISTER NODEPROTO *np;
2672
2673 /* get polygon */
2674 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2675
2676 np = ni->proto;
2677
2678 /* determine which polygons to draw */
2679 i = nodepolys(ni, &reasonable, us_peekwindow);
2680
2681 /* if the amount of geometry can be reduced, do so at large scales */
2682 if (i != reasonable)
2683 {
2684 cutsizex = applyxscale(us_peekwindow, ni->highx - ni->lowx);
2685 cutsizey = applyyscale(us_peekwindow, ni->highy - ni->lowy);
2686 if (cutsizex*cutsizey < i * 75) i = reasonable;
2687 }
2688 moretodo = 0;
2689 if ((us_state&NONOVERLAPPABLEDISPLAY) != 0)
2690 {
2691 /* no overlappable display: just draw everything */
2692 low = 0; high = i;
2693 } else
2694 {
2695 if ((np->userbits&NHASOPA) == 0) j = i; else
2696 {
2697 j = (np->userbits&NFIRSTOPA) >> NFIRSTOPASH;
2698 if (i < j) j = i;
2699 }
2700 if ((layers&1) != 0) low = 0; else low = j;
2701 if ((layers&2) != 0) high = i; else high = j;
2702 if (low > 0) moretodo |= 1;
2703 if (high < i) moretodo |= 2;
2704 }
2705
2706 /* don't draw invisible pins to alternative output */
2707 if (np == gen_invispinprim && low == 0) low++;
2708
2709 /* get the polygons of the nodeinst */
2710 for(j=low; j<high; j++)
2711 {
2712 /* get description of this layer */
2713 shapenodepoly(ni, j, poly);
2714
2715 /* ignore if this layer is not being displayed */
2716 gra = poly->desc;
2717 if ((gra->colstyle&INVISIBLE) != 0) continue;
2718
2719 /* ignore if no bits are to be drawn */
2720 if (gra->col == ALLOFF || gra->bits == LAYERN) continue;
2721
2722 /* transform the polygon */
2723 xformpoly(poly, prevtrans);
2724
2725 /* draw the polygon */
2726 if ((us_peekwindow->state&WINDOWTYPE) == DISP3DWINDOW) us_3dshowpoly(poly, us_peekwindow); else
2727 (*us_displayroutine)(poly, us_peekwindow);
2728 }
2729 return(moretodo);
2730 }
2731