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