1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrhigh.c
6  * User interface tool: object highlighting
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 #include "tecart.h"
38 
39 #define DOTRADIUS 4				/* size of dots in nodes when highlighting networks */
40 
41 extern GRAPHICS us_box, us_arbit, us_hbox;
42 
43 /* working memory for "us_gethighlighted()" */
44 static GEOM   **us_gethighlist;
45 static INTBIG   us_gethighlistsize = 0;
46 static INTBIG   us_selectedtexttotal = 0;	/* size of selected text item list */
47 static CHAR   **us_selectedtextlist;		/* the selected text items */
48 
49 /* working memory for "us_getallhighlighted()" */
50 static INTBIG  *us_getallhighlist;
51 static INTBIG   us_getallhighlistsize = 0;
52 
53 /* working memory for "us_selectarea()" */
54 static void   *us_selectareastringarray = 0;
55 
56 /* prototypes for local routines */
57 static void       us_makecurrentobject(void);
58 static void       us_highlightverbose(GEOM*, PORTPROTO*, INTBIG, NODEPROTO*, POLYGON*);
59 static BOOLEAN    us_geommatchestype(GEOM *geom, INTBIG type);
60 
61 /*
62  * Routine to free all memory associated with this module.
63  */
us_freehighmemory(void)64 void us_freehighmemory(void)
65 {
66 	REGISTER INTBIG i;
67 
68 	if (us_gethighlistsize != 0) efree((CHAR *)us_gethighlist);
69 	if (us_getallhighlistsize != 0) efree((CHAR *)us_getallhighlist);
70 	if (us_selectareastringarray != 0) killstringarray(us_selectareastringarray);
71 	for(i=0; i<us_selectedtexttotal; i++)
72 		if (us_selectedtextlist[i] != 0) efree((CHAR *)us_selectedtextlist[i]);
73 	if (us_selectedtexttotal > 0) efree((CHAR *)us_selectedtextlist);
74 }
75 
76 /******************** MENU AND WINDOW HIGHLIGHTING ********************/
77 
78 /*
79  * routine to highlight a menu entry
80  */
us_highlightmenu(INTBIG x,INTBIG y,INTBIG color)81 void us_highlightmenu(INTBIG x, INTBIG y, INTBIG color)
82 {
83 	REGISTER INTBIG xl, yl;
84 	INTBIG swid, shei, pwid;
85 	WINDOWPART ww;
86 	static POLYGON *poly = NOPOLYGON;
87 
88 	if ((us_tool->toolstate&MENUON) == 0) return;
89 
90 	/* get polygon */
91 	(void)needstaticpolygon(&poly, 5, us_tool->cluster);
92 
93 	/* set drawing bounds to include menu */
94 	if (us_menuframe == NOWINDOWFRAME)
95 	{
96 		getpaletteparameters(&swid, &shei, &pwid);
97 		ww.frame = getwindowframe(TRUE);
98 	} else
99 	{
100 		getwindowframesize(us_menuframe, &swid, &shei);
101 		ww.frame = us_menuframe;
102 	}
103 	ww.screenlx = ww.screenly = ww.uselx = ww.usely = 0;
104 	ww.screenhx = ww.usehx = swid-1;
105 	ww.screenhy = ww.usehy = shei-1;
106 	ww.state = DISPWINDOW;
107 	computewindowscale(&ww);
108 
109 	xl = x * us_menuxsz + us_menulx;
110 	yl = y * us_menuysz + us_menuly;
111 	maketruerectpoly(xl, xl+us_menuxsz, yl, yl+us_menuysz, poly);
112 	poly->desc = &us_box;
113 	poly->style = CLOSEDRECT;
114 	us_box.col = color;
115 	us_showpoly(poly, &ww);
116 }
117 
118 /*
119  * routine to highlight window "w" and set current window to this.  If
120  * "force" is true, highlight this window even if it is already the
121  * current window.
122  */
us_highlightwindow(WINDOWPART * w,BOOLEAN force)123 void us_highlightwindow(WINDOWPART *w, BOOLEAN force)
124 {
125 	if (w == el_curwindowpart && !force) return;
126 
127 	if (el_curwindowpart != NOWINDOWPART) us_drawwindow(el_curwindowpart, el_colwinbor);
128 	if (w != NOWINDOWPART) us_drawwindow(w, el_colhwinbor);
129 
130 	/* set new window */
131 	el_curwindowpart = w;
132 }
133 
134 /******************** OBJECT HIGHLIGHTING ********************/
135 
136 /*
137  * routine to add "thishigh" to the list of objects that are highlighted.
138  */
us_addhighlight(HIGHLIGHT * thishigh)139 void us_addhighlight(HIGHLIGHT *thishigh)
140 {
141 	REGISTER CHAR *str, **list;
142 	REGISTER INTBIG i, len, rewritefirst;
143 	CHAR *onelist[1];
144 	REGISTER VARIABLE *var;
145 	HIGHLIGHT oldhigh;
146 
147 	/* see if anything is currently highlighted */
148 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
149 	if (var == NOVARIABLE)
150 	{
151 		/* nothing highlighted: add this one line */
152 		onelist[0] = us_makehighlightstring(thishigh);
153 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey, (INTBIG)onelist,
154 			VSTRING|VISARRAY|(1<<VLENGTHSH)|VDONTSAVE);
155 
156 #if SIMTOOL
157 		/* if current window is simulating, show equivalent elsewhere */
158 		if (el_curwindowpart != NOWINDOWPART && (el_curwindowpart->state&WINDOWSIMMODE) != 0 &&
159 			(thishigh->status&HIGHTYPE) == HIGHFROM)
160 		{
161 			onelist[0] = x_("show-equivalent");
162 			telltool(net_tool, 1, onelist);
163 		}
164 #endif
165 
166 		/* set the current node/arc */
167 		us_makecurrentobject();
168 		return;
169 	}
170 
171 	/* see if it is already highlighted */
172 	len = getlength(var);
173 	for(i=0; i<len; i++)
174 	{
175 		if (us_makehighlight(((CHAR **)var->addr)[i], &oldhigh)) continue;
176 		if ((oldhigh.status&HIGHTYPE) != (thishigh->status&HIGHTYPE)) continue;
177 		if (oldhigh.cell != thishigh->cell) continue;
178 		if ((oldhigh.status&HIGHTYPE) == HIGHLINE || (oldhigh.status&HIGHTYPE) == HIGHBBOX)
179 		{
180 			if (oldhigh.stalx != thishigh->stalx || oldhigh.stahx != thishigh->stahx ||
181 				oldhigh.staly != thishigh->staly || oldhigh.stahy != thishigh->stahy) continue;
182 		} else
183 		{
184 			if (oldhigh.fromgeom != thishigh->fromgeom) continue;
185 			if ((oldhigh.status&HIGHTYPE) == HIGHTEXT)
186 			{
187 				if (oldhigh.fromvar != thishigh->fromvar) continue;
188 				if (oldhigh.fromport != NOPORTPROTO && thishigh->fromport != NOPORTPROTO &&
189 					oldhigh.fromport != thishigh->fromport) continue;
190 			}
191 		}
192 		return;
193 	}
194 
195 	/* process tangent snap points */
196 	rewritefirst = 0;
197 	if (len == 1 && (oldhigh.status&HIGHSNAP) != 0 && (thishigh->status&HIGHSNAP) != 0 &&
198 		((oldhigh.status&HIGHSNAPTAN) != 0 || (thishigh->status&HIGHSNAPTAN) != 0))
199 	{
200 		us_adjusttangentsnappoints(&oldhigh, thishigh);
201 		if ((oldhigh.status&HIGHSNAPTAN) != 0) rewritefirst = 1;
202 	} else if (len == 1 && (oldhigh.status&HIGHSNAP) != 0 && (thishigh->status&HIGHSNAP) != 0 &&
203 		((oldhigh.status&HIGHSNAPPERP) != 0 || (thishigh->status&HIGHSNAPPERP) != 0))
204 	{
205 		us_adjustperpendicularsnappoints(&oldhigh, thishigh);
206 		if ((oldhigh.status&HIGHSNAPPERP) != 0) rewritefirst = 1;
207 	}
208 
209 	/* convert the highlight module to a string */
210 	str = us_makehighlightstring(thishigh);
211 
212 	/* things are highlighted: build a new list */
213 	list = (CHAR **)emalloc(((len+1) * (sizeof (CHAR *))), el_tempcluster);
214 	if (list == 0) return;
215 	for(i=0; i<len; i++)
216 	{
217 		if (i == 0 && rewritefirst != 0)
218 		{
219 			(void)allocstring(&list[i], us_makehighlightstring(&oldhigh), el_tempcluster);
220 		} else
221 		{
222 			(void)allocstring(&list[i], ((CHAR **)var->addr)[i], el_tempcluster);
223 		}
224 	}
225 	(void)allocstring(&list[len], str, el_tempcluster);
226 
227 	/* save the new list */
228 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey, (INTBIG)list,
229 		VSTRING|VISARRAY|((len+1)<<VLENGTHSH)|VDONTSAVE);
230 
231 	/* clean up */
232 	for(i=0; i<=len; i++) efree(list[i]);
233 	efree((CHAR *)list);
234 
235 	/* set the current node/arc */
236 	us_makecurrentobject();
237 }
238 
239 /*
240  * routine to delete "thishigh" from the list of objects that are highlighted.
241  */
us_delhighlight(HIGHLIGHT * thishigh)242 void us_delhighlight(HIGHLIGHT *thishigh)
243 {
244 	REGISTER CHAR **list;
245 	REGISTER INTBIG i, len, j, thish;
246 	REGISTER VARIABLE *var;
247 	HIGHLIGHT oldhigh;
248 
249 	/* see if anything is currently highlighted */
250 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
251 	if (var == NOVARIABLE) return;
252 
253 	/* see if it is highlighted */
254 	len = getlength(var);
255 	for(thish=0; thish<len; thish++)
256 	{
257 		if (us_makehighlight(((CHAR **)var->addr)[thish], &oldhigh)) continue;
258 		if ((oldhigh.status&HIGHTYPE) != (thishigh->status&HIGHTYPE)) continue;
259 		if (oldhigh.cell != thishigh->cell) continue;
260 		if ((oldhigh.status&HIGHTYPE) == HIGHLINE || (oldhigh.status&HIGHTYPE) == HIGHBBOX)
261 		{
262 			if (oldhigh.stalx != thishigh->stalx || oldhigh.stahx != thishigh->stahx ||
263 				oldhigh.staly != thishigh->staly || oldhigh.stahy != thishigh->stahy) continue;
264 		} else
265 		{
266 			if (oldhigh.fromgeom != thishigh->fromgeom) continue;
267 			if ((oldhigh.status&HIGHTYPE) == HIGHTEXT)
268 			{
269 				if (oldhigh.fromvar != thishigh->fromvar) continue;
270 				if (oldhigh.fromport != NOPORTPROTO && thishigh->fromport != NOPORTPROTO &&
271 					oldhigh.fromport != thishigh->fromport) continue;
272 			}
273 		}
274 		break;
275 	}
276 	if (thish >= len) return;
277 
278 	/* removing highlight: build a new list */
279 	if (len <= 1)
280 	{
281 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey);
282 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO);
283 		return;
284 	}
285 	list = (CHAR **)emalloc(((len-1) * (sizeof (CHAR *))), el_tempcluster);
286 	if (list == 0) return;
287 	for(j=i=0; i<len; i++)
288 	{
289 		if (i == thish) continue;
290 		(void)allocstring(&list[j], ((CHAR **)var->addr)[i], el_tempcluster);
291 		j++;
292 	}
293 
294 	/* save the new list */
295 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey, (INTBIG)list,
296 		VSTRING|VISARRAY|((len-1)<<VLENGTHSH)|VDONTSAVE);
297 	us_makecurrentobject();
298 
299 	/* clean up */
300 	for(i=0; i<len-1; i++) efree(list[i]);
301 	efree((CHAR *)list);
302 }
303 
us_clearhighlightcount(void)304 void us_clearhighlightcount(void)
305 {
306 	REGISTER VARIABLE *var;
307 
308 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
309 	if (var != NOVARIABLE)
310 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey);
311 	if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO);
312 }
313 
314 /*
315  * routine to add highlight module "newhigh" to the display.  If "findpoint" is nonzero,
316  * find the closest vertex/line to the cursor.  If "extrainfo" is nonzero, highlight
317  * with extra information.  If "findmore" is nonzero, add this highlight rather
318  * than replacing.  If "nobox" is nonzero, do not draw the basic box.
319  */
us_setfind(HIGHLIGHT * newhigh,INTBIG findpoint,INTBIG extrainfo,INTBIG findmore,INTBIG nobox)320 void us_setfind(HIGHLIGHT *newhigh, INTBIG findpoint, INTBIG extrainfo, INTBIG findmore, INTBIG nobox)
321 {
322 	REGISTER NODEINST *ni;
323 	REGISTER VARIABLE *var;
324 	REGISTER INTBIG x, y, d, bestdist, bestpoint, i, total;
325 	INTBIG xp, yp, xc, yc;
326 	XARRAY trans;
327 
328 	/* set to highlight only one one object */
329 	if (findmore == 0) us_clearhighlightcount();
330 
331 	/* find the vertex/line if this is a nodeinst and it was requested */
332 	if (findpoint != 0 && (newhigh->status&HIGHTYPE) != HIGHTEXT &&
333 		newhigh->fromgeom->entryisnode)
334 	{
335 		ni = newhigh->fromgeom->entryaddr.ni;
336 		var = gettrace(ni);
337 	} else var = NOVARIABLE;
338 	if (var == NOVARIABLE) bestpoint = 0; else
339 	{
340 		(void)getxy(&xc, &yc);
341 		makerot(ni, trans);
342 		total = getlength(var) / 2;
343 		x = (ni->highx + ni->lowx) / 2;   y = (ni->highy + ni->lowy) / 2;
344 		for(i=0; i<total; i++)
345 		{
346 			xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &xp, &yp, trans);
347 			d = abs(xp-xc) + abs(yp-yc);
348 			if (i == 0) bestdist = d + 1;
349 			if (d > bestdist) continue;
350 			bestdist = d;   bestpoint = i;
351 		}
352 		bestpoint++;
353 	}
354 
355 	/* load the highlight structure */
356 	newhigh->status |= extrainfo;
357 	newhigh->frompoint = bestpoint;
358 	if (nobox != 0) newhigh->status |= HIGHNOBOX;
359 
360 	/* show the highlighting */
361 	us_addhighlight(newhigh);
362 }
363 
364 /*
365  * Routine to select the area (slx <= X <= shx, sly <= Y <= shy) in cell "np".
366  * If "special" is nonzero, select "hard-to-select" items.
367  * If "selport" is nonzero, select ports.
368  * If "nobbox" is nonzero, do not show bounding box.
369  * Returns the number of things selected, and loads the string array "highlist"
370  * with the highlight information.
371  */
us_selectarea(NODEPROTO * np,INTBIG slx,INTBIG shx,INTBIG sly,INTBIG shy,INTBIG special,INTBIG selport,INTBIG nobbox,CHAR *** highlist)372 INTBIG us_selectarea(NODEPROTO *np, INTBIG slx, INTBIG shx, INTBIG sly, INTBIG shy,
373 	INTBIG special, INTBIG selport, INTBIG nobbox, CHAR ***highlist)
374 {
375 	REGISTER INTBIG i, j, k, search, slop, foundtext;
376 	INTBIG xcur, ycur, xc, yc, xw, yw, style, count;
377 	BOOLEAN checktext;
378 	REGISTER GEOM *geom;
379 	REGISTER NODEINST *ni;
380 	REGISTER ARCINST *ai;
381 	REGISTER BOOLEAN accept;
382 	PORTPROTO *port, *lastport;
383 	VARIABLE *var, *varnoeval, *lastvar;
384 	XARRAY trans;
385 	static POLYGON *poly = NOPOLYGON;
386 	HIGHLIGHT newhigh, newhightext;
387 
388 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
389 	if (us_selectareastringarray == 0) us_selectareastringarray = newstringarray(us_tool->cluster);
390 	clearstrings(us_selectareastringarray);
391 
392 	/* build a list of objects to highlight */
393 	newhigh.cell = np;
394 	newhigh.fromport = NOPORTPROTO;
395 	newhigh.fromvar = NOVARIABLE;
396 	newhigh.fromvarnoeval = NOVARIABLE;
397 	newhigh.frompoint = 0;
398 
399 	newhightext.status = HIGHTEXT;
400 	newhightext.cell = np;
401 	newhightext.fromvarnoeval = NOVARIABLE;
402 	newhightext.frompoint = 0;
403 
404 	if ((us_useroptions&HIDETXTCELL) == 0)
405 	{
406 		for(i=0; i<np->numvar; i++)
407 		{
408 			var = &np->firstvar[i];
409 			if ((var->type&VDISPLAY) == 0) continue;
410 			newhightext.fromgeom = NOGEOM;
411 			newhightext.fromport = NOPORTPROTO;
412 			newhightext.fromvarnoeval = var;
413 			newhightext.fromvar = evalvar(newhightext.fromvarnoeval, (INTBIG)np, VNODEPROTO);
414 			us_gethightextcenter(&newhightext, &xc, &yc, &style);
415 			us_gethightextsize(&newhightext, &xw, &yw, el_curwindowpart);
416 			if ((us_useroptions&MUSTENCLOSEALL) != 0)
417 			{
418 				/* accept if it is inside the area */
419 				if (xc-xw/2 < slx || xc+xw/2 > shx ||
420 					yc-yw/2 < sly || yc+yw/2 > shy) continue;
421 			} else
422 			{
423 				/* accept if it touches the area */
424 				if (xc+xw/2 < slx || xc-xw/2 > shx ||
425 					yc+yw/2 < sly || yc-yw/2 > shy) continue;
426 			}
427 			addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhightext));
428 		}
429 	}
430 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
431 	{
432 		if ((ni->userbits&NHASFARTEXT) == 0) continue;
433 		if (ni->proto == gen_invispinprim)
434 		{
435 			if ((us_useroptions&HIDETXTNONLAY) != 0) continue;
436 		} else
437 		{
438 			if ((us_useroptions&HIDETXTNODE) != 0) continue;
439 		}
440 		for(i=0; i<ni->numvar; i++)
441 		{
442 			var = &ni->firstvar[i];
443 			if ((var->type&VDISPLAY) == 0) continue;
444 			newhightext.fromgeom = ni->geom;
445 			newhightext.fromport = NOPORTPROTO;
446 			newhightext.fromvarnoeval = var;
447 			newhightext.fromvar = evalvar(newhightext.fromvarnoeval, (INTBIG)ni, VNODEINST);
448 			us_gethightextcenter(&newhightext, &xc, &yc, &style);
449 			us_gethightextsize(&newhightext, &xw, &yw, el_curwindowpart);
450 			if ((us_useroptions&MUSTENCLOSEALL) != 0)
451 			{
452 				/* accept if it is inside the area */
453 				if (xc-xw/2 < slx || xc+xw/2 > shx ||
454 					yc-yw/2 < sly || yc+yw/2 > shy) continue;
455 			} else
456 			{
457 				/* accept if it touches the area */
458 				if (xc+xw/2 < slx || xc-xw/2 > shx ||
459 					yc+yw/2 < sly || yc-yw/2 > shy) continue;
460 			}
461 			addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhightext));
462 		}
463 	}
464 	if ((us_useroptions&HIDETXTARC) == 0)
465 	{
466 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
467 		{
468 			if ((ai->userbits&AHASFARTEXT) == 0) continue;
469 			for(i=0; i<ai->numvar; i++)
470 			{
471 				var = &ai->firstvar[i];
472 				if ((var->type&VDISPLAY) == 0) continue;
473 				newhightext.fromgeom = ai->geom;
474 				newhightext.fromport = NOPORTPROTO;
475 				newhightext.fromvarnoeval = var;
476 				newhightext.fromvar = evalvar(newhightext.fromvarnoeval, (INTBIG)ai, VARCINST);
477 				us_gethightextcenter(&newhightext, &xc, &yc, &style);
478 				us_gethightextsize(&newhightext, &xw, &yw, el_curwindowpart);
479 				if ((us_useroptions&MUSTENCLOSEALL) != 0)
480 				{
481 					/* accept if it is inside the area */
482 					if (xc-xw/2 < slx || xc+xw/2 > shx ||
483 						yc-yw/2 < sly || yc+yw/2 > shy) continue;
484 				} else
485 				{
486 					/* accept if it touches the area */
487 					if (xc+xw/2 < slx || xc-xw/2 > shx ||
488 						yc+yw/2 < sly || yc-yw/2 > shy) continue;
489 				}
490 				addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhightext));
491 			}
492 		}
493 	}
494 	slop = FARTEXTLIMIT * lambdaofcell(np);
495 	search = initsearch(slx-slop, shx+slop, sly-slop, shy+slop, np);
496 	while ((geom = nextobject(search)) != NOGEOM)
497 	{
498 		if (geom->entryisnode)
499 		{
500 			ni = geom->entryaddr.ni;
501 
502 			/* don't find cells if not requested */
503 			if (special == 0 && (us_useroptions&NOINSTANCESELECT) != 0 &&
504 				ni->proto->primindex == 0) continue;
505 
506 			/* do not include hard-to-find nodes if not selecting specially */
507 			if (special == 0 && (ni->userbits&HARDSELECTN) != 0) continue;
508 
509 			/* do not include primitives that have all layers invisible */
510 			if (ni->proto->primindex != 0 && (ni->proto->userbits&NINVISIBLE) != 0)
511 				continue;
512 
513 			/* include all displayable variables */
514 			foundtext = 0;
515 
516 			/* ignore text if invisible */
517 			checktext = TRUE;
518 			if (ni->proto == gen_invispinprim)
519 			{
520 				if ((us_useroptions&HIDETXTNONLAY) != 0) checktext = FALSE;
521 			} else
522 			{
523 				if ((us_useroptions&HIDETXTNODE) != 0) checktext = FALSE;
524 			}
525 			if (checktext)
526 			{
527 				/* compute threshold for direct hits */
528 				lastvar = NOVARIABLE;
529 				lastport = NOPORTPROTO;
530 				if ((ni->userbits&NHASFARTEXT) == 0)
531 				{
532 					us_initnodetext(ni, special, el_curwindowpart);
533 					for(;;)
534 					{
535 						if (us_getnodetext(ni, el_curwindowpart, poly, &var, &varnoeval, &port)) break;
536 						accept = FALSE;
537 						if ((us_useroptions&MUSTENCLOSEALL) != 0)
538 						{
539 							/* accept if it is inside the area */
540 							for(k=0; k<poly->count; k++)
541 							{
542 								if (poly->xv[k] < slx || poly->xv[k] > shx ||
543 									poly->yv[k] < sly || poly->yv[k] > shy) break;
544 							}
545 							if (k >= poly->count) accept = TRUE;
546 						} else
547 						{
548 							/* accept if it touches the area */
549 							if (polyinrect(poly, slx, shx, sly, shy)) accept = TRUE;
550 						}
551 						if (accept)
552 						{
553 							if (varnoeval == lastvar && port == lastport) continue;
554 							lastvar = varnoeval;
555 							lastport = port;
556 							newhightext.fromgeom = geom;
557 							newhightext.fromport = port;
558 							newhightext.fromvarnoeval = varnoeval;
559 							newhightext.fromvar = var;
560 							addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhightext));
561 						}
562 						foundtext++;
563 					}
564 				}
565 			}
566 
567 			/* ignore invisible primitive if text on it was selected */
568 			if (foundtext != 0 && ni->proto == gen_invispinprim) continue;
569 
570 			/* do not include "edge select" primitives that are outside the area */
571 			if (ni->proto->primindex != 0 &&
572 				(ni->proto->userbits&NEDGESELECT) != 0)
573 			{
574 				i = nodepolys(ni, 0, NOWINDOWPART);
575 				makerot(ni, trans);
576 				for(j=0; j<i; j++)
577 				{
578 					shapenodepoly(ni, j, poly);
579 					if ((poly->desc->colstyle&INVISIBLE) == 0)
580 					{
581 						xformpoly(poly, trans);
582 						accept = FALSE;
583 						if ((us_useroptions&MUSTENCLOSEALL) != 0)
584 						{
585 							/* accept if it is inside the area */
586 							for(k=0; k<poly->count; k++)
587 							{
588 								if (poly->xv[k] < slx || poly->xv[k] > shx ||
589 									poly->yv[k] < sly || poly->yv[k] > shy) break;
590 							}
591 							if (k >= poly->count) accept = TRUE;
592 						} else
593 						{
594 							/* accept if it touches the area */
595 							if (polyinrect(poly, slx, shx, sly, shy)) accept = TRUE;
596 						}
597 						if (!accept) break;
598 					}
599 				}
600 				if (j < i) continue;
601 			}
602 		} else
603 		{
604 			ai = geom->entryaddr.ai;
605 
606 			/* do not include hard-to-find arcs if not selecting specially */
607 			if (special == 0 && (ai->userbits&HARDSELECTA) != 0) continue;
608 
609 			/* do not include arcs that have all layers invisible */
610 			if ((ai->proto->userbits&AINVISIBLE) != 0) continue;
611 
612 			/* include all displayable variables */
613 			if ((us_useroptions&HIDETXTARC) == 0)
614 			{
615 				if ((ai->userbits&AHASFARTEXT) == 0)
616 				{
617 					for(i=0; i<ai->numvar; i++)
618 					{
619 						var = &ai->firstvar[i];
620 						if ((var->type&VDISPLAY) == 0) continue;
621 						newhightext.fromgeom = geom;
622 						newhightext.fromport = NOPORTPROTO;
623 						newhightext.fromvarnoeval = var;
624 						newhightext.fromvar = evalvar(newhightext.fromvarnoeval, (INTBIG)ai, VARCINST);
625 						us_gethightextcenter(&newhightext, &xc, &yc, &style);
626 						us_gethightextsize(&newhightext, &xw, &yw, el_curwindowpart);
627 						if ((us_useroptions&MUSTENCLOSEALL) != 0)
628 						{
629 							/* accept if it is inside the area */
630 							if (xc-xw/2 < slx || xc+xw/2 > shx ||
631 								yc-yw/2 < sly || yc+yw/2 > shy) continue;
632 						} else
633 						{
634 							/* accept if it touches the area */
635 							if (xc+xw/2 < slx || xc-xw/2 > shx ||
636 								yc+yw/2 < sly || yc-yw/2 > shy) continue;
637 						}
638 						addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhightext));
639 					}
640 				}
641 			}
642 
643 			/* do not include "edge select" arcs that are outside the area */
644 			if ((ai->proto->userbits&AEDGESELECT) != 0)
645 			{
646 				ai = geom->entryaddr.ai;
647 				i = arcpolys(ai, NOWINDOWPART);
648 				for(j=0; j<i; j++)
649 				{
650 					shapearcpoly(ai, j, poly);
651 					if ((poly->desc->colstyle&INVISIBLE) == 0)
652 					{
653 						accept = FALSE;
654 						if ((us_useroptions&MUSTENCLOSEALL) != 0)
655 						{
656 							/* accept if it is inside the area */
657 							for(k=0; k<poly->count; k++)
658 							{
659 								if (poly->xv[k] < slx || poly->xv[k] > shx ||
660 									poly->yv[k] < sly || poly->yv[k] > shy) break;
661 							}
662 							if (k >= poly->count) accept = TRUE;
663 						} else
664 						{
665 							/* accept if it touches the area */
666 							if (polyinrect(poly, slx, shx, sly, shy)) accept = TRUE;
667 						}
668 						if (!accept) break;
669 					}
670 				}
671 				if (j < i) continue;
672 			}
673 		}
674 
675 		/* eliminate objects that aren't really in the selected area */
676 		if (!us_geominrect(geom, slx, shx, sly, shy)) continue;
677 
678 		newhigh.status = HIGHFROM;
679 		if (nobbox != 0) newhigh.status |= HIGHNOBOX;
680 		newhigh.fromgeom = geom;
681 
682 		/* add snapping information if requested */
683 		if ((us_state&SNAPMODE) != SNAPMODENONE)
684 		{
685 			(void)getxy(&xcur, &ycur);
686 			us_selectsnap(&newhigh, xcur, ycur);
687 		}
688 
689 		/* select the first port if ports are requested and node is artwork */
690 		newhigh.fromport = NOPORTPROTO;
691 		if (selport != 0 && geom->entryisnode &&
692 			geom->entryaddr.ni->proto->primindex != 0 &&
693 				geom->entryaddr.ni->proto->tech == art_tech)
694 					newhigh.fromport = geom->entryaddr.ni->proto->firstportproto;
695 		addtostringarray(us_selectareastringarray, us_makehighlightstring(&newhigh));
696 	}
697 	*highlist = getstringarray(us_selectareastringarray, &count);
698 	return(count);
699 }
700 
701 /*
702  * routine to demand a specified type of highlighted object (VNODEINST or
703  * VARCINST, according to "type") and return its address.  If "canbetext"
704  * is true, the highlighted object can be a text object on the requested
705  * type.  If the specified object is not currently highlighted, an error is
706  * printed and the routine returns -1.
707  */
us_getobject(INTBIG type,BOOLEAN canbetext)708 UINTBIG us_getobject(INTBIG type, BOOLEAN canbetext)
709 {
710 	HIGHLIGHT high;
711 	REGISTER VARIABLE *var;
712 	REGISTER INTBIG len, i;
713 	REGISTER BOOLEAN notone;
714 	REGISTER GEOM *onegeom;
715 
716 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
717 	if (var == NOVARIABLE) len = 0; else
718 		len = getlength(var);
719 	notone = FALSE;
720 	onegeom = NOGEOM;
721 	for(i=0; i<len; i++)
722 	{
723 		if (us_makehighlight(((CHAR **)var->addr)[i], &high))
724 		{
725 			us_abortcommand(_("Highlight unintelligible"));
726 			return((UINTBIG)-1);
727 		}
728 		if ((high.status&HIGHTYPE) == HIGHTEXT && !canbetext) continue;
729 		if (high.fromgeom == NOGEOM)
730 		{
731 			notone = TRUE;
732 			break;
733 		}
734 		if (onegeom == NOGEOM) onegeom = high.fromgeom;
735 		if (high.fromgeom != onegeom)
736 		{
737 			notone = TRUE;
738 			break;
739 		}
740 	}
741 	if (!notone && onegeom != NOGEOM)
742 	{
743 		if (onegeom->entryisnode)
744 		{
745 			if (type != VNODEINST) notone = TRUE;
746 		} else
747 		{
748 			if (type != VARCINST) notone = TRUE;
749 		}
750 	}
751 	if (notone || onegeom == NOGEOM)
752 	{
753 		if (type == VARCINST) us_abortcommand(_("Select an arc")); else
754 			us_abortcommand(_("Select a node"));
755 		return((UINTBIG)-1);
756 	}
757 
758 	/* set the current position */
759 	return((UINTBIG)onegeom->entryaddr.blind);
760 }
761 
762 /*
763  * routine to return the one object currently highlighted.  If no objects
764  * are highlighted or many are, an error is printed and the routine returns
765  * NOHIGHLIGHT.
766  */
us_getonehighlight(void)767 HIGHLIGHT *us_getonehighlight(void)
768 {
769 	static HIGHLIGHT high;
770 	REGISTER VARIABLE *var;
771 	REGISTER GEOM *onegeom;
772 	REGISTER INTBIG len, i;
773 	REGISTER BOOLEAN notone;
774 
775 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
776 	if (var == NOVARIABLE) len = 0; else
777 		len = getlength(var);
778 	notone = FALSE;
779 	onegeom = NOGEOM;
780 	for(i=0; i<len; i++)
781 	{
782 		if (us_makehighlight(((CHAR **)var->addr)[i], &high))
783 		{
784 			us_abortcommand(_("Highlight unintelligible"));
785 			return(NOHIGHLIGHT);
786 		}
787 		if (high.fromgeom == NOGEOM)
788 		{
789 			notone = TRUE;
790 			break;
791 		}
792 		if (onegeom == NOGEOM) onegeom = high.fromgeom;
793 		if (high.fromgeom != onegeom)
794 		{
795 			notone = TRUE;
796 			break;
797 		}
798 	}
799 	if (notone || onegeom == NOGEOM)
800 	{
801 		us_abortcommand(_("Must select one node or arc"));
802 		return(NOHIGHLIGHT);
803 	}
804 	return(&high);
805 }
806 
807 /*
808  * routine to get the two nodes that are selected and their ports.
809  * If there are not two nodes selected, the routine returns true.
810  */
us_gettwoobjects(GEOM ** firstgeom,PORTPROTO ** firstport,GEOM ** secondgeom,PORTPROTO ** secondport)811 BOOLEAN us_gettwoobjects(GEOM **firstgeom, PORTPROTO **firstport, GEOM **secondgeom,
812 	PORTPROTO **secondport)
813 {
814 	REGISTER VARIABLE *var;
815 	HIGHLIGHT newhigh;
816 	REGISTER INTBIG len, i;
817 
818 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
819 	if (var == NOVARIABLE) return(TRUE);
820 	len = getlength(var);
821 	*firstgeom = *secondgeom = NOGEOM;
822 	for(i=0; i<len; i++)
823 	{
824 		(void)us_makehighlight(((CHAR **)var->addr)[i], &newhigh);
825 		if ((newhigh.status&HIGHFROM) != 0)
826 		{
827 			if (*firstgeom == NOGEOM)
828 			{
829 				*firstgeom = newhigh.fromgeom;
830 				*firstport = newhigh.fromport;
831 			} else if (*secondgeom == NOGEOM)
832 			{
833 				*secondgeom = newhigh.fromgeom;
834 				*secondport = newhigh.fromport;
835 			} else return(TRUE);
836 		}
837 	}
838 	if (*firstgeom != NOGEOM && *secondgeom != NOGEOM) return(FALSE);
839 	return(TRUE);
840 }
841 
842 /*
843  * routine to get a list of all objects that are highlighted, build an array
844  * of them, and return the array.
845  * If "type" is WANTNODEINST, only the highlighted nodes are returned.
846  * If "type" is WANTARCINST, only the highlighted arcs are returned.
847  * if "type" is WANTNODEINST|WANTARCINST, all highlighted objects are returned.
848  * The list is terminated with the value NOGEOM.
849  * If "textcount" and "textinfo" are nonzero, they are set to the number of
850  * text objects that are highlighted (and the highlight descriptors for each).
851  * When text objects are requested, those on selected nodes or arcs are ignored.
852  *
853  * As an indication of the nodes that are selected, each node's "temp1" field is
854  * set to nonzero if it is selected (but not if text on it is selected).
855  * This is used by "usrtrack.c:us_finddoibegin()" and by "usrcomln.c:us_move()".
856  */
us_gethighlighted(INTBIG type,INTBIG * textcount,CHAR *** textinfo)857 GEOM **us_gethighlighted(INTBIG type, INTBIG *textcount, CHAR ***textinfo)
858 {
859 	HIGHLIGHT high;
860 	REGISTER VARIABLE *var;
861 	REGISTER INTBIG total, len, i, j, k, newcount, numtext, lx, hx, ly, hy,
862 		textonnode, search;
863 	REGISTER GEOM *geom;
864 	REGISTER NODEPROTO *np;
865 	REGISTER NODEINST *ni;
866 	REGISTER ARCINST *ai;
867 	REGISTER CHAR **newtext;
868 	static GEOM *nulllist[1];
869 	static POLYGON *poly = NOPOLYGON;
870 	XARRAY trans;
871 
872 	if (textcount != 0) *textcount = 0;
873 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
874 	if (var == NOVARIABLE)
875 	{
876 		nulllist[0] = NOGEOM;
877 		return(nulllist);
878 	}
879 
880 	/* first search to see how many objects there are */
881 	len = getlength(var);
882 	numtext = 0;
883 	total = 0;
884 	for(i=0; i<len; i++)
885 	{
886 		(void)us_makehighlight(((CHAR **)var->addr)[i], &high);
887 		if ((high.status&HIGHTYPE) == HIGHFROM)
888 			if (us_geommatchestype(high.fromgeom, type)) total++;
889 		if ((high.status&HIGHTYPE) == HIGHBBOX)
890 		{
891 			lx = high.stalx;   hx = high.stahx;
892 			ly = high.staly;   hy = high.stahy;
893 			search = initsearch(lx, hx, ly, hy, high.cell);
894 			while ((geom = nextobject(search)) != NOGEOM)
895 			{
896 				if (!us_geommatchestype(geom, type)) continue;
897 				if (!us_geominrect(geom, lx, hx, ly, hy)) continue;
898 				total++;
899 			}
900 		}
901 
902 		/* special case: include in node list if text tied to node and no text requested */
903 		if ((high.status&HIGHTYPE) == HIGHTEXT)
904 		{
905 			if (us_nodemoveswithtext(&high) && textcount == 0)
906 				total++;
907 		}
908 	}
909 
910 	/* get memory for array of these objects */
911 	if (total >= us_gethighlistsize)
912 	{
913 		if (us_gethighlistsize != 0) efree((CHAR *)us_gethighlist);
914 		us_gethighlist = (GEOM **)emalloc(((total+1) * (sizeof (GEOM *))),
915 			us_tool->cluster);
916 		if (us_gethighlist == 0)
917 		{
918 			ttyputnomemory();
919 			nulllist[0] = NOGEOM;
920 			return(nulllist);
921 		}
922 		us_gethighlistsize = total + 1;
923 	}
924 
925 	/* now place the objects in the list */
926 	total = 0;
927 	for(i=0; i<len; i++)
928 	{
929 		(void)us_makehighlight(((CHAR **)var->addr)[i], &high);
930 		if ((high.status&HIGHTYPE) == HIGHFROM)
931 			if (us_geommatchestype(high.fromgeom, type))
932 		{
933 			for(j=0; j<total; j++) if (us_gethighlist[j] == high.fromgeom) break;
934 			if (j >= total) us_gethighlist[total++] = high.fromgeom;
935 		}
936 		if ((high.status&HIGHTYPE) == HIGHBBOX)
937 		{
938 			lx = high.stalx;   hx = high.stahx;
939 			ly = high.staly;   hy = high.stahy;
940 			search = initsearch(lx, hx, ly, hy, high.cell);
941 			for(;;)
942 			{
943 				geom = nextobject(search);
944 				if (geom == NOGEOM) break;
945 
946 				/* make sure the object has the desired type */
947 				if (!us_geommatchestype(geom, type)) continue;
948 
949 				/* make sure the object is really in the selection area */
950 				if (!us_geominrect(geom, lx, hx, ly, hy)) continue;
951 
952 				/* make sure the object isn't already in the list */
953 				for(j=0; j<total; j++) if (us_gethighlist[j] == geom) break;
954 				if (j < total) continue;
955 
956 				/* check carefully for "edge select" primitives */
957 				if (geom->entryisnode)
958 				{
959 					ni = geom->entryaddr.ni;
960 					if (ni->proto->primindex != 0)
961 					{
962 						if ((ni->proto->userbits&NINVISIBLE) != 0) continue;
963 						if ((ni->proto->userbits&NEDGESELECT) != 0)
964 						{
965 							ni = geom->entryaddr.ni;
966 							k = nodepolys(ni, 0, NOWINDOWPART);
967 							(void)needstaticpolygon(&poly, 4, us_tool->cluster);
968 							makerot(ni, trans);
969 							for(j=0; j<k; j++)
970 							{
971 								shapenodepoly(ni, j, poly);
972 								if ((poly->desc->colstyle&INVISIBLE) == 0)
973 								{
974 									xformpoly(poly, trans);
975 									if (!polyinrect(poly, high.stalx, high.stahx,
976 										high.staly, high.stahy)) break;
977 								}
978 							}
979 							if (j < k) continue;
980 						}
981 					}
982 				} else
983 				{
984 					ai = geom->entryaddr.ai;
985 					if ((ai->proto->userbits&AINVISIBLE) != 0) continue;
986 					if ((ai->proto->userbits&AEDGESELECT) != 0)
987 					{
988 						k = arcpolys(ai, NOWINDOWPART);
989 						(void)needstaticpolygon(&poly, 4, us_tool->cluster);
990 						for(j=0; j<k; j++)
991 						{
992 							shapearcpoly(ai, j, poly);
993 							if ((poly->desc->colstyle&INVISIBLE) == 0)
994 							{
995 								if (!polyinrect(poly, high.stalx, high.stahx,
996 									high.staly, high.stahy)) break;
997 							}
998 						}
999 						if (j < k) continue;
1000 					}
1001 				}
1002 
1003 				/* add this object to the list */
1004 				us_gethighlist[total++] = geom;
1005 			}
1006 		}
1007 		if ((high.status&HIGHTYPE) == HIGHTEXT)
1008 		{
1009 			if (us_nodemoveswithtext(&high) && textcount == 0)
1010 			{
1011 				/* include in node list if text tied to node and no text requested */
1012 				us_gethighlist[total++] = high.fromgeom;
1013 			} else
1014 			{
1015 				if (textcount != 0)
1016 				{
1017 					if (numtext >= us_selectedtexttotal)
1018 					{
1019 						newcount = numtext + 5;
1020 						newtext = (CHAR **)emalloc(newcount * (sizeof (CHAR *)),
1021 							us_tool->cluster);
1022 						if (newtext == 0)
1023 						{
1024 							nulllist[0] = NOGEOM;
1025 							return(nulllist);
1026 						}
1027 						for(j=0; j<us_selectedtexttotal; j++)
1028 							newtext[j] = us_selectedtextlist[j];
1029 						for( ; j<newcount; j++) newtext[j] = 0;
1030 						if (us_selectedtexttotal > 0) efree((CHAR *)us_selectedtextlist);
1031 						us_selectedtextlist = newtext;
1032 						us_selectedtexttotal = newcount;
1033 					}
1034 					if (us_selectedtextlist[numtext] == 0)
1035 					{
1036 						(void)allocstring(&us_selectedtextlist[numtext],
1037 							((CHAR **)var->addr)[i], us_tool->cluster);
1038 					} else
1039 					{
1040 						(void)reallocstring(&us_selectedtextlist[numtext],
1041 							((CHAR **)var->addr)[i], us_tool->cluster);
1042 					}
1043 					numtext++;
1044 				}
1045 			}
1046 		}
1047 	}
1048 	us_gethighlist[total] = NOGEOM;
1049 	if (textcount != 0 && textinfo != 0)
1050 	{
1051 		/* mark all nodes (including those touched by highlighted arcs) */
1052 		if (us_gethighlist[0] != NOGEOM) np = geomparent(us_gethighlist[0]); else
1053 			np = el_curwindowpart->curnodeproto;
1054 		if (np != NONODEPROTO)
1055 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1056 				ni->temp1 = 0;
1057 		if (us_gethighlist[0] != NOGEOM)
1058 		{
1059 			for(i=0; us_gethighlist[i] != NOGEOM; i++)
1060 			{
1061 				if (!us_gethighlist[i]->entryisnode)
1062 				{
1063 					ai = us_gethighlist[i]->entryaddr.ai;
1064 					ai->end[0].nodeinst->temp1 = ai->end[1].nodeinst->temp1 = 1;
1065 				} else
1066 					us_gethighlist[i]->entryaddr.ni->temp1 = 1;
1067 			}
1068 		}
1069 
1070 		/* remove nodes listed as text objects */
1071 		for(i=0; i<numtext; i++)
1072 		{
1073 			(void)us_makehighlight(us_selectedtextlist[i], &high);
1074 
1075 			/* make sure we aren't moving text and object it resides on */
1076 			textonnode = 0;
1077 			if (high.fromgeom != NOGEOM)
1078 			{
1079 				if (high.fromgeom->entryisnode)
1080 				{
1081 					ni = high.fromgeom->entryaddr.ni;
1082 					if (ni->temp1 != 0) textonnode = 1;
1083 				} else
1084 				{
1085 					ai = high.fromgeom->entryaddr.ai;
1086 					for(j=0; us_gethighlist[j] != NOGEOM; j++)
1087 						if (us_gethighlist[j] == ai->geom) break;
1088 					if (us_gethighlist[j] != NOGEOM) textonnode = 1;
1089 				}
1090 			}
1091 			if (textonnode == 0) continue;
1092 			efree(us_selectedtextlist[i]);
1093 			for(j=i; j<numtext-1; j++)
1094 				us_selectedtextlist[j] = us_selectedtextlist[j+1];
1095 			us_selectedtextlist[numtext-1] = 0;
1096 			numtext--;
1097 			i--;
1098 		}
1099 
1100 		*textcount = numtext;
1101 		*textinfo = us_selectedtextlist;
1102 	}
1103 	return(us_gethighlist);
1104 }
1105 
us_geommatchestype(GEOM * geom,INTBIG type)1106 BOOLEAN us_geommatchestype(GEOM *geom, INTBIG type)
1107 {
1108 	if (geom->entryisnode)
1109 	{
1110 		if ((type&WANTNODEINST) != 0) return(TRUE);
1111 		return(FALSE);
1112 	}
1113 	if ((type&WANTARCINST) != 0) return(TRUE);
1114 	return(FALSE);
1115 }
1116 
1117 /*
1118  * routine to get a list of all objects that are highlighted (including nodes, arcs,
1119  * and ports), build an array that alternates address and type, and return the array.
1120  * The list is terminated with the type 0.
1121  */
us_getallhighlighted(void)1122 INTBIG *us_getallhighlighted(void)
1123 {
1124 	HIGHLIGHT high;
1125 	REGISTER VARIABLE *var;
1126 	REGISTER INTBIG total, len, i, j, k, lx, hx, ly, hy, search;
1127 	REGISTER GEOM *geom;
1128 	REGISTER NODEINST *ni;
1129 	REGISTER ARCINST *ai;
1130 	static INTBIG nulllist[2];
1131 	static POLYGON *poly = NOPOLYGON;
1132 	XARRAY trans;
1133 
1134 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1135 	if (var == NOVARIABLE)
1136 	{
1137 		nulllist[0] = nulllist[1] = 0;
1138 		return(nulllist);
1139 	}
1140 
1141 	/* first search to see how many objects there are */
1142 	len = getlength(var);
1143 	total = 0;
1144 	for(i=0; i<len; i++)
1145 	{
1146 		(void)us_makehighlight(((CHAR **)var->addr)[i], &high);
1147 		if ((high.status&HIGHTYPE) == HIGHFROM) total++;
1148 		if ((high.status&HIGHTYPE) == HIGHBBOX)
1149 		{
1150 			search = initsearch(high.stalx, high.stahx, high.staly, high.stahy, high.cell);
1151 			while ((geom = nextobject(search)) != NOGEOM) total++;
1152 		}
1153 
1154 		/* special case: accept ports and invisible node if it holds highlighted text */
1155 		if ((high.status&HIGHTYPE) == HIGHTEXT)
1156 		{
1157 			if (high.fromvar != NOVARIABLE && high.fromgeom != NOGEOM)
1158 			{
1159 				if (high.fromgeom->entryisnode &&
1160 					high.fromgeom->entryaddr.ni->proto == gen_invispinprim) total++;
1161 			}
1162 			if (high.fromvar == NOVARIABLE && high.fromport != NOPORTPROTO) total++;
1163 		}
1164 	}
1165 
1166 	/* get memory for array of these objects */
1167 	if (total*2 >= us_getallhighlistsize)
1168 	{
1169 		if (us_getallhighlistsize != 0) efree((CHAR *)us_getallhighlist);
1170 		us_getallhighlist = (INTBIG *)emalloc((total+1)*2 * SIZEOFINTBIG, us_tool->cluster);
1171 		if (us_getallhighlist == 0)
1172 		{
1173 			ttyputnomemory();
1174 			nulllist[0] = nulllist[1] = 0;
1175 			return(nulllist);
1176 		}
1177 		us_getallhighlistsize = (total+1)*2;
1178 	}
1179 
1180 	/* now place the objects in the list */
1181 	total = 0;
1182 	for(i=0; i<len; i++)
1183 	{
1184 		(void)us_makehighlight(((CHAR **)var->addr)[i], &high);
1185 		if ((high.status&HIGHTYPE) == HIGHFROM)
1186 		{
1187 			for(j=0; j<total; j += 2)
1188 				if (us_getallhighlist[j] == (INTBIG)high.fromgeom->entryaddr.blind) break;
1189 			if (j >= total)
1190 			{
1191 				us_getallhighlist[total++] = (INTBIG)high.fromgeom->entryaddr.blind;
1192 				if (high.fromgeom->entryisnode) us_getallhighlist[total++] = VNODEINST; else
1193 					us_getallhighlist[total++] = VARCINST;
1194 			}
1195 		}
1196 		if ((high.status&HIGHTYPE) == HIGHBBOX)
1197 		{
1198 			lx = high.stalx;   hx = high.stahx;
1199 			ly = high.staly;   hy = high.stahy;
1200 			search = initsearch(lx, hx, ly, hy, high.cell);
1201 			for(;;)
1202 			{
1203 				geom = nextobject(search);
1204 				if (geom == NOGEOM) break;
1205 				if (!us_geominrect(geom, lx, hx, ly, hy)) continue;
1206 
1207 				/* make sure it isn't already in the list */
1208 				for(j=0; j<total; j++)
1209 					if (us_getallhighlist[j] == (INTBIG)geom->entryaddr.blind) break;
1210 				if (j < total) continue;
1211 
1212 				/* check carefully for "edge select" primitives */
1213 				if (geom->entryisnode)
1214 				{
1215 					ni = geom->entryaddr.ni;
1216 					if (ni->proto->primindex != 0)
1217 					{
1218 						if ((ni->proto->userbits&NINVISIBLE) != 0) continue;
1219 						if ((ni->proto->userbits&NEDGESELECT) != 0)
1220 						{
1221 							ni = geom->entryaddr.ni;
1222 							k = nodepolys(ni, 0, NOWINDOWPART);
1223 							(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1224 							makerot(ni, trans);
1225 							for(j=0; j<k; j++)
1226 							{
1227 								shapenodepoly(ni, j, poly);
1228 								if ((poly->desc->colstyle&INVISIBLE) == 0)
1229 								{
1230 									xformpoly(poly, trans);
1231 									if (!polyinrect(poly, high.stalx, high.stahx, high.staly, high.stahy))
1232 										break;
1233 								}
1234 							}
1235 							if (j < k) continue;
1236 						}
1237 					}
1238 				} else
1239 				{
1240 					ai = geom->entryaddr.ai;
1241 					if ((ai->proto->userbits&AINVISIBLE) != 0) continue;
1242 					if ((ai->proto->userbits&AEDGESELECT) != 0)
1243 					{
1244 						k = arcpolys(ai, NOWINDOWPART);
1245 						(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1246 						for(j=0; j<k; j++)
1247 						{
1248 							shapearcpoly(ai, j, poly);
1249 							if ((poly->desc->colstyle&INVISIBLE) == 0)
1250 							{
1251 								if (!polyinrect(poly, high.stalx, high.stahx, high.staly, high.stahy))
1252 									break;
1253 							}
1254 						}
1255 						if (j < k) continue;
1256 					}
1257 				}
1258 
1259 				/* add this object to the list */
1260 				us_getallhighlist[total++] = (INTBIG)geom->entryaddr.blind;
1261 				if (geom->entryisnode) us_getallhighlist[total++] = VNODEINST; else
1262 					us_getallhighlist[total++] = VARCINST;
1263 			}
1264 		}
1265 		if ((high.status&HIGHTYPE) == HIGHTEXT)
1266 		{
1267 			if (high.fromvar != NOVARIABLE && high.fromgeom != NOGEOM)
1268 			{
1269 				if (high.fromgeom->entryisnode &&
1270 					high.fromgeom->entryaddr.ni->proto == gen_invispinprim)
1271 				{
1272 					us_getallhighlist[total++] = (INTBIG)high.fromgeom->entryaddr.blind;
1273 					us_getallhighlist[total++] = VNODEINST;
1274 				}
1275 			}
1276 			if (high.fromvar == NOVARIABLE && high.fromport != NOPORTPROTO)
1277 			{
1278 				us_getallhighlist[total++] = (INTBIG)high.fromport;
1279 				us_getallhighlist[total++] = VPORTPROTO;
1280 			}
1281 		}
1282 	}
1283 	us_getallhighlist[total++] = 0;
1284 	us_getallhighlist[total] = 0;
1285 	return(us_getallhighlist);
1286 }
1287 
1288 /*
1289  * routine to get the boundary of an area delimited by the highlight.
1290  * The bounds are put in the reference variables "lx", "hx", "ly", and "hy".
1291  * If there is no highlighted area, the routine returns with NONODEPROTO
1292  * Otherwise the routine returns the cell that contains the area.
1293  */
us_getareabounds(INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)1294 NODEPROTO *us_getareabounds(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
1295 {
1296 	HIGHLIGHT high;
1297 	REGISTER NODEINST *ni;
1298 	REGISTER BOOLEAN first;
1299 	REGISTER INTBIG len, pointlen, i, good, bad;
1300 	INTBIG tlx, thx, tly, thy, xc, yc;
1301 	XARRAY trans;
1302 	static POLYGON *poly = NOPOLYGON;
1303 	REGISTER NODEPROTO *thiscell;
1304 	REGISTER TECHNOLOGY *tech;
1305 	REGISTER VARIABLE *var;
1306 
1307 	/* get polygon */
1308 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1309 
1310 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1311 	if (var == NOVARIABLE) return(NONODEPROTO);
1312 
1313 	thiscell = getcurcell();
1314 	good = bad = 0;
1315 	(void)us_makehighlight(((CHAR **)var->addr)[0], &high);
1316 	len = getlength(var);
1317 	first = TRUE;
1318 	for(i=0; i<len; i++)
1319 	{
1320 		(void)us_makehighlight(((CHAR **)var->addr)[i], &high);
1321 		if (thiscell == NONODEPROTO) thiscell = high.cell;
1322 		if (high.cell == thiscell) good++; else
1323 		{
1324 			bad++;
1325 			continue;
1326 		}
1327 		if ((high.status&HIGHTYPE) == HIGHTEXT)
1328 		{
1329 			if (high.fromvar != NOVARIABLE)
1330 			{
1331 				if (high.fromgeom == NOGEOM) continue;
1332 				pointlen = 1;
1333 				ni = NONODEINST;
1334 				if (high.fromport != NOPORTPROTO) ni = high.fromport->subnodeinst; else
1335 					if (high.fromgeom != NOGEOM && high.fromgeom->entryisnode)
1336 				{
1337 					ni = high.fromgeom->entryaddr.ni;
1338 					if ((high.fromvar->type&VISARRAY) != 0)
1339 						pointlen = getlength(high.fromvar);
1340 				}
1341 				if (pointlen > 1)
1342 				{
1343 					makedisparrayvarpoly(high.fromgeom, el_curwindowpart, high.fromvar, poly);
1344 				} else
1345 				{
1346 					if (ni != NONODEINST) tech = ni->proto->tech; else
1347 					{
1348 						if (high.fromgeom != NOGEOM) tech = high.fromgeom->entryaddr.ai->proto->tech; else
1349 							tech = high.cell->tech;
1350 					}
1351 					us_maketextpoly(describevariable(high.fromvar, -1, -1), el_curwindowpart,
1352 						(high.fromgeom->lowx + high.fromgeom->highx) / 2,
1353 							(high.fromgeom->lowy + high.fromgeom->highy) / 2,
1354 								ni, tech, high.fromvar->textdescript, poly);
1355 				}
1356 				if (ni != NONODEINST)
1357 				{
1358 					makerot(ni, trans);
1359 					xformpoly(poly, trans);
1360 				}
1361 			} else if (high.fromport != NOPORTPROTO)
1362 			{
1363 				portposition(high.fromport->subnodeinst, high.fromport->subportproto, &xc, &yc);
1364 				us_maketextpoly(us_displayedportname(high.fromport, (us_useroptions&EXPORTLABELS) >> EXPORTLABELSSH),
1365 					el_curwindowpart, xc, yc, high.fromport->subnodeinst,
1366 						high.fromport->subnodeinst->proto->tech, high.fromport->textdescript, poly);
1367 			} else if (high.fromgeom->entryisnode)
1368 			{
1369 				ni = high.fromgeom->entryaddr.ni;
1370 				us_maketextpoly(describenodeproto(ni->proto), el_curwindowpart,
1371 					(ni->lowx + ni->highx) / 2, (ni->lowy + ni->highy) / 2,
1372 						ni, ni->proto->tech, ni->textdescript, poly);
1373 			}
1374 			getbbox(poly, &tlx, &thx, &tly, &thy);
1375 		}
1376 		if ((high.status&HIGHTYPE) == HIGHBBOX || (high.status&HIGHTYPE) == HIGHLINE)
1377 		{
1378 			tlx = high.stalx;   thx = high.stahx;
1379 			tly = high.staly;   thy = high.stahy;
1380 		}
1381 		if ((high.status&HIGHTYPE) == HIGHFROM)
1382 		{
1383 			if (high.fromgeom->entryisnode)
1384 			{
1385 				us_getnodebounds(high.fromgeom->entryaddr.ni, &tlx, &thx, &tly, &thy);
1386 			} else
1387 			{
1388 				us_getarcbounds(high.fromgeom->entryaddr.ai, &tlx, &thx, &tly, &thy);
1389 			}
1390 		}
1391 		if (first)
1392 		{
1393 			*lx = tlx;   *hx = thx;   *ly = tly;   *hy = thy;
1394 			first = FALSE;
1395 		} else
1396 		{
1397 			*lx = mini(*lx, tlx);   *hx = maxi(*hx, thx);
1398 			*ly = mini(*ly, tly);   *hy = maxi(*hy, thy);
1399 		}
1400 	}
1401 	if (good == 0 && bad != 0)
1402 	{
1403 		us_abortcommand(_("Highlighted areas must be in the current cell"));
1404 		return(NONODEPROTO);
1405 	}
1406 	return(thiscell);
1407 }
1408 
1409 /*
1410  * Routine to move the "numtexts" text objects described (as highlight strings)
1411  * in the array "textlist", by "odx" and "ody".  Geometry objects in "list" (NOGEOM-terminated)
1412  * and the "total" nodes in "nodelist" have already been moved, so don't move any text that
1413  * is on these objects.
1414  */
us_moveselectedtext(INTBIG numtexts,CHAR ** textlist,GEOM ** list,INTBIG odx,INTBIG ody)1415 void us_moveselectedtext(INTBIG numtexts, CHAR **textlist, GEOM **list, INTBIG odx, INTBIG ody)
1416 {
1417 	REGISTER INTBIG i, j, lambda;
1418 	INTBIG dx, dy, addr, type;
1419 	UINTBIG descript[TEXTDESCRIPTSIZE];
1420 	REGISTER NODEINST *ni;
1421 	XARRAY trans;
1422 	HIGHLIGHT high;
1423 
1424 	for(i=0; i<numtexts; i++)
1425 	{
1426 		dx = odx;   dy = ody;
1427 		(void)us_makehighlight(textlist[i], &high);
1428 		if ((high.status&HIGHTYPE) != HIGHTEXT) continue;
1429 
1430 		/* get object and movement amount */
1431 		us_gethighaddrtype(&high, &addr, &type);
1432 
1433 		/* undraw the text */
1434 		if (type == VPORTPROTO)
1435 		{
1436 			ni = ((PORTPROTO *)addr)->subnodeinst;
1437 			for(j=0; list[j] != NOGEOM; j++)
1438 				if (list[j]->entryisnode && list[j]->entryaddr.ni == ni) break;
1439 			if (list[j] != NOGEOM) continue;
1440 
1441 			startobjectchange((INTBIG)ni, VNODEINST);
1442 			if (us_nodemoveswithtext(&high))
1443 			{
1444 				modifynodeinst(ni, dx, dy, dx, dy, 0, 0);
1445 				endobjectchange((INTBIG)ni, VNODEINST);
1446 				continue;
1447 			}
1448 			if (ni->transpose != 0)
1449 				makeangle(ni->rotation, ni->transpose, trans); else
1450 					makeangle((3600-ni->rotation)%3600, 0, trans);
1451 			xform(dx, dy, &dx, &dy, trans);
1452 		} else
1453 		{
1454 			startobjectchange(addr, type);
1455 			if (type == VNODEINST)
1456 			{
1457 				ni = (NODEINST *)addr;
1458 				for(j=0; list[j] != NOGEOM; j++)
1459 					if (list[j]->entryisnode && list[j]->entryaddr.ni == ni) break;
1460 				if (list[j] != NOGEOM) continue;
1461 
1462 				if (us_nodemoveswithtext(&high))
1463 				{
1464 					modifynodeinst(ni, dx, dy, dx, dy, 0, 0);
1465 					endobjectchange((INTBIG)ni, VNODEINST);
1466 					continue;
1467 				}
1468 				if (ni->transpose != 0)
1469 					makeangle(ni->rotation, ni->transpose, trans); else
1470 						makeangle((3600-ni->rotation)%3600, 0, trans);
1471 				xform(dx, dy, &dx, &dy, trans);
1472 			}
1473 		}
1474 		if (type == VNODEPROTO && high.fromvar != NOVARIABLE)
1475 			us_undrawcellvariable(high.fromvar, (NODEPROTO *)addr);
1476 
1477 		/* set the new descriptor on the text */
1478 		lambda = el_curlib->lambda[us_hightech(&high)->techindex];
1479 		dx = dx*4/lambda;   dy = dy*4/lambda;
1480 		us_gethighdescript(&high, descript);
1481 		dx += TDGETXOFF(descript);
1482 		dy += TDGETYOFF(descript);
1483 		us_setdescriptoffset(descript, dx, dy);
1484 		us_modifytextdescript(&high, descript);
1485 
1486 		/* redisplay the text */
1487 		if (type == VNODEPROTO && high.fromvar != NOVARIABLE)
1488 			us_drawcellvariable(high.fromvar, (NODEPROTO *)addr);
1489 		if (type == VPORTPROTO)
1490 		{
1491 			endobjectchange((INTBIG)ni, VNODEINST);
1492 		} else
1493 		{
1494 			endobjectchange(addr, type);
1495 		}
1496 		us_addhighlight(&high);
1497 
1498 		/* modify all higher-level nodes if port moved */
1499 		if (high.fromvar == NOVARIABLE && high.fromport != NOPORTPROTO)
1500 		{
1501 			for(ni = high.fromport->parent->firstinst; ni != NONODEINST; ni = ni->nextinst)
1502 			{
1503 				if ((ni->userbits&NEXPAND) != 0 &&
1504 					(high.fromport->userbits&PORTDRAWN) == 0) continue;
1505 				startobjectchange((INTBIG)ni, VNODEINST);
1506 				endobjectchange((INTBIG)ni, VNODEINST);
1507 			}
1508 		}
1509 	}
1510 }
1511 
1512 /*
1513  * Routine to find a single selected snap point and return it in (x, y).
1514  * Returns false if there is not a single snap point.
1515  */
us_getonesnappoint(INTBIG * x,INTBIG * y)1516 BOOLEAN us_getonesnappoint(INTBIG *x, INTBIG *y)
1517 {
1518 	REGISTER INTBIG snapcount;
1519 	REGISTER VARIABLE *var;
1520 	REGISTER INTBIG len, i;
1521 	HIGHLIGHT thishigh;
1522 
1523 	snapcount = 0;
1524 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1525 	if (var != NOVARIABLE)
1526 	{
1527 		len = getlength(var);
1528 		for(i=0; i<len; i++)
1529 		{
1530 			if (!us_makehighlight(((CHAR **)var->addr)[i], &thishigh))
1531 			{
1532 				if ((thishigh.status&HIGHSNAP) != 0)
1533 				{
1534 					us_getsnappoint(&thishigh, x, y);
1535 					snapcount++;
1536 				}
1537 			}
1538 		}
1539 	}
1540 	if (snapcount == 1) return(TRUE);
1541 	return(FALSE);
1542 }
1543 
1544 /*
1545  * routine to draw the highlighting for module "high".  The highlighting is
1546  * drawn on if "on" is HIGHLIT, off if "on" is ALLOFF.
1547  */
us_sethighlight(HIGHLIGHT * high,INTBIG on)1548 void us_sethighlight(HIGHLIGHT *high, INTBIG on)
1549 {
1550 	INTBIG xw, yw, xc, yc, lx, hx, ly, hy, addr, type;
1551 	INTBIG style;
1552 	BOOLEAN verbose, nobbox;
1553 	REGISTER WINDOWPART *w;
1554 	static POLYGON *poly = NOPOLYGON;
1555 
1556 	/* get polygon */
1557 	(void)needstaticpolygon(&poly, 5, us_tool->cluster);
1558 
1559 	/* handle drawing bounding boxes */
1560 	if ((high->status&HIGHTYPE) == HIGHBBOX)
1561 	{
1562 		maketruerectpoly(high->stalx, high->stahx, high->staly, high->stahy, poly);
1563 		poly->desc = &us_hbox;
1564 		poly->style = CLOSEDRECT;
1565 		us_hbox.col = on;
1566 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1567 		{
1568 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1569 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1570 			if (w->curnodeproto != high->cell) continue;
1571 			us_showpoly(poly, w);
1572 		}
1573 		return;
1574 	}
1575 
1576 	/* handle drawing lines */
1577 	if ((high->status&HIGHTYPE) == HIGHLINE)
1578 	{
1579 		poly->xv[0] = high->stalx;   poly->yv[0] = high->staly;
1580 		poly->xv[1] = high->stahx;   poly->yv[1] = high->stahy;
1581 		poly->count = 2;
1582 		poly->desc = &us_hbox;
1583 		poly->style = VECTORS;
1584 		us_hbox.col = on;
1585 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1586 		{
1587 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1588 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1589 			if (w->curnodeproto != high->cell) continue;
1590 			us_showpoly(poly, w);
1591 		}
1592 		return;
1593 	}
1594 
1595 	/* handle text outlines */
1596 	if ((high->status&HIGHTYPE) == HIGHTEXT)
1597 	{
1598 		/* determine center of text */
1599 		us_gethightextcenter(high, &xc, &yc, &style);
1600 
1601 		/* initialize polygon */
1602 		poly->layer = -1;
1603 		poly->desc = &us_hbox;
1604 		us_hbox.col = on;
1605 
1606 		/* display in every appropriate window */
1607 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1608 		{
1609 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1610 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1611 			if (w->curnodeproto != high->cell) continue;
1612 
1613 			us_gethightextsize(high, &xw, &yw, w);
1614 
1615 			/* construct polygon */
1616 			us_gethighaddrtype(high, &addr, &type);
1617 			(void)us_getobjectinfo(addr, type, &lx, &hx, &ly, &hy);
1618 			us_buildtexthighpoly(lx, hx, ly, hy, xc, yc, xw, yw, style, poly);
1619 			us_showpoly(poly, w);
1620 		}
1621 		return;
1622 	}
1623 
1624 	/* quit if nothing to draw */
1625 	if ((high->status&HIGHFROM) == 0 || high->fromgeom == NOGEOM) return;
1626 
1627 	/* highlight "from" object */
1628 	if ((high->status&HIGHEXTRA) != 0) verbose = TRUE; else verbose = FALSE;
1629 	if ((high->status&HIGHNOBOX) != 0) nobbox = TRUE; else nobbox = FALSE;
1630 	us_highlighteverywhere(high->fromgeom, high->fromport, high->frompoint,
1631 		verbose, on, nobbox);
1632 
1633 	/* draw the snap point if set */
1634 	if ((high->status&HIGHSNAP) != 0)
1635 	{
1636 		us_getsnappoint(high, &poly->xv[0], &poly->yv[0]);
1637 		poly->count = 1;
1638 		poly->desc = &us_hbox;
1639 		poly->style = BIGCROSS;
1640 		us_hbox.col = on;
1641 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1642 		{
1643 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1644 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1645 			if (w->curnodeproto != high->cell) continue;
1646 			us_showpoly(poly, w);
1647 		}
1648 	}
1649 }
1650 
1651 /*
1652  * routine to build a polygon in "poly" that describes the highlighting of
1653  * a text object whose grab point is (xc,yc), size is (xw,yw), graphics
1654  * style is in "style" (either TEXTCENT, TEXTBOT, ...) and whose attached
1655  * object is "geom".
1656  */
us_buildtexthighpoly(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG xc,INTBIG yc,INTBIG xw,INTBIG yw,INTBIG style,POLYGON * poly)1657 void us_buildtexthighpoly(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy,
1658 	INTBIG xc, INTBIG yc, INTBIG xw, INTBIG yw, INTBIG style, POLYGON *poly)
1659 {
1660 	REGISTER INTBIG xsh, ysh;
1661 
1662 	/* compute appropriate highlight */
1663 	switch (style)
1664 	{
1665 		case TEXTCENT:
1666 		case TEXTBOX:
1667 			poly->xv[0] = xc - xw/2;   poly->yv[0] = yc - yw/2;
1668 			poly->xv[1] = xc + xw/2;   poly->yv[1] = yc + yw/2;
1669 			poly->xv[2] = xc - xw/2;   poly->yv[2] = yc + yw/2;
1670 			poly->xv[3] = xc + xw/2;   poly->yv[3] = yc - yw/2;
1671 			poly->style = VECTORS;     poly->count = 4;
1672 			if (style == TEXTCENT) break;
1673 			if (poly->limit < 12) (void)extendpolygon(poly, 12);
1674 			xsh = (hx - lx) / 6;
1675 			ysh = (hy - ly) / 6;
1676 			poly->xv[4] = lx + xsh;    poly->yv[4] = ly;
1677 			poly->xv[5] = hx - xsh;    poly->yv[5] = ly;
1678 			poly->xv[6] = lx + xsh;    poly->yv[6] = hy;
1679 			poly->xv[7] = hx - xsh;    poly->yv[7] = hy;
1680 			poly->xv[8] = lx;          poly->yv[8] = ly + ysh;
1681 			poly->xv[9] = lx;          poly->yv[9] = hy - ysh;
1682 			poly->xv[10] = hx;         poly->yv[10] = ly + ysh;
1683 			poly->xv[11] = hx;         poly->yv[11] = hy - ysh;
1684 			poly->count = 12;
1685 			break;
1686 		case TEXTBOT:
1687 			poly->xv[0] = xc - xw/2;   poly->yv[0] = yc + yw;
1688 			poly->xv[1] = xc - xw/2;   poly->yv[1] = yc;
1689 			poly->xv[2] = xc + xw/2;   poly->yv[2] = yc;
1690 			poly->xv[3] = xc + xw/2;   poly->yv[3] = yc + yw;
1691 			poly->style = OPENED;      poly->count = 4;
1692 			break;
1693 		case TEXTTOP:
1694 			poly->xv[0] = xc - xw/2;   poly->yv[0] = yc - yw;
1695 			poly->xv[1] = xc - xw/2;   poly->yv[1] = yc;
1696 			poly->xv[2] = xc + xw/2;   poly->yv[2] = yc;
1697 			poly->xv[3] = xc + xw/2;   poly->yv[3] = yc - yw;
1698 			poly->style = OPENED;      poly->count = 4;
1699 			break;
1700 		case TEXTLEFT:
1701 			poly->xv[0] = xc + xw;     poly->yv[0] = yc + yw/2;
1702 			poly->xv[1] = xc;          poly->yv[1] = yc + yw/2;
1703 			poly->xv[2] = xc;          poly->yv[2] = yc - yw/2;
1704 			poly->xv[3] = xc + xw;     poly->yv[3] = yc - yw/2;
1705 			poly->style = OPENED;      poly->count = 4;
1706 			break;
1707 		case TEXTRIGHT:
1708 			poly->xv[0] = xc - xw;     poly->yv[0] = yc + yw/2;
1709 			poly->xv[1] = xc;          poly->yv[1] = yc + yw/2;
1710 			poly->xv[2] = xc;          poly->yv[2] = yc - yw/2;
1711 			poly->xv[3] = xc - xw;     poly->yv[3] = yc - yw/2;
1712 			poly->style = OPENED;      poly->count = 4;
1713 			break;
1714 		case TEXTTOPLEFT:
1715 			poly->xv[0] = xc + xw;     poly->yv[0] = yc;
1716 			poly->xv[1] = xc;          poly->yv[1] = yc;
1717 			poly->xv[2] = xc;          poly->yv[2] = yc - yw;
1718 			poly->style = OPENED;      poly->count = 3;
1719 			break;
1720 		case TEXTBOTLEFT:
1721 			poly->xv[0] = xc;          poly->yv[0] = yc + yw;
1722 			poly->xv[1] = xc;          poly->yv[1] = yc;
1723 			poly->xv[2] = xc + xw;     poly->yv[2] = yc;
1724 			poly->style = OPENED;      poly->count = 3;
1725 			break;
1726 		case TEXTTOPRIGHT:
1727 			poly->xv[0] = xc - xw;     poly->yv[0] = yc;
1728 			poly->xv[1] = xc;          poly->yv[1] = yc;
1729 			poly->xv[2] = xc;          poly->yv[2] = yc - yw;
1730 			poly->style = OPENED;      poly->count = 3;
1731 			break;
1732 		case TEXTBOTRIGHT:
1733 			poly->xv[0] = xc - xw;     poly->yv[0] = yc;
1734 			poly->xv[1] = xc;          poly->yv[1] = yc;
1735 			poly->xv[2] = xc;          poly->yv[2] = yc + yw;
1736 			poly->style = OPENED;      poly->count = 3;
1737 			break;
1738 	}
1739 }
1740 
1741 /*
1742  * general routine to change the highlighting of an object.  Every displayed
1743  * occurrence of geometry module "look" will have its highlighting drawn.
1744  * The highlighting will be in color "color".
1745  * If "port" is not NOPORTPROTO and the geometry module points to
1746  * a nodeinst, that port will also be highlighted.  If "point" is nonzero,
1747  * then that point/line of the trace will be highlighted.  If "verbose" is
1748  * true, the object will be highlighted with extra information.  If
1749  * "nobbox" is true, don't draw the basic box around the object.
1750  */
us_highlighteverywhere(GEOM * look,PORTPROTO * port,INTBIG point,BOOLEAN verbose,INTBIG color,BOOLEAN nobbox)1751 void us_highlighteverywhere(GEOM *look, PORTPROTO *port, INTBIG point, BOOLEAN verbose, INTBIG color,
1752 	BOOLEAN nobbox)
1753 {
1754 	REGISTER NODEINST *ni;
1755 	REGISTER ARCINST *ai;
1756 	REGISTER NODEPROTO *par;
1757 	REGISTER INTBIG i, x, y;
1758 	REGISTER WINDOWPART *w;
1759 	REGISTER VARIABLE *var;
1760 	static POLYGON *poly = NOPOLYGON;
1761 	XARRAY trans;
1762 	INTBIG lx, hx, ly, hy;
1763 
1764 	/* get polygon */
1765 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1766 
1767 	/* sensibility check to prevent null highlighting */
1768 	if (look->entryisnode)
1769 	{
1770 		if (port == NOPORTPROTO && !verbose && point == 0) nobbox = FALSE;
1771 	} else
1772 	{
1773 		point = 0;
1774 		if (!verbose) nobbox = FALSE;
1775 	}
1776 
1777 	/* determine parent, compute polygon */
1778 	par = geomparent(look);
1779 	if (look->entryisnode)
1780 	{
1781 		ni = look->entryaddr.ni;
1782 		makerot(ni, trans);
1783 		nodesizeoffset(ni, &lx, &ly, &hx, &hy);
1784 		makerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, poly);
1785 		poly->style = FILLED;
1786 		xformpoly(poly, trans);
1787 	} else
1788 	{
1789 		ai = look->entryaddr.ai;
1790 		i = ai->width - arcwidthoffset(ai);
1791 		if (curvedarcoutline(ai, poly, CLOSED, i))
1792 			makearcpoly(ai->length, i, ai, poly, FILLED);
1793 	}
1794 
1795 	/* figure out the line type for this highlighting */
1796 	poly->desc = &us_hbox;
1797 	poly->desc->col = color;
1798 	poly->style = OPENEDO1;
1799 
1800 	/* if extra information is being un-drawn, show it now */
1801 	if (verbose && color == ALLOFF)
1802 		us_highlightverbose(look, port, color, par, poly);
1803 
1804 	/* add the final point to close the polygon */
1805 	if (poly->limit < poly->count+1) (void)extendpolygon(poly, poly->count+1);
1806 	poly->xv[poly->count] = poly->xv[0];
1807 	poly->yv[poly->count] = poly->yv[0];
1808 	poly->count++;
1809 
1810 	/* if all points are the same, draw as a cross */
1811 	for(i=1; i<poly->count; i++)
1812 		if (poly->xv[i-1] != poly->xv[i] || poly->yv[i-1] != poly->yv[i]) break;
1813 	if (i >= poly->count) poly->style = CROSS;
1814 
1815 	/* loop through windows and draw the highlighting */
1816 	if (!nobbox)
1817 	{
1818 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1819 		{
1820 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1821 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1822 			if (w->curnodeproto != par) continue;
1823 			us_showpoly(poly, w);
1824 		}
1825 	}
1826 
1827 	/* remove that point to make the polygon centered */
1828 	poly->count--;
1829 
1830 	/* if extra information is being drawn, show it now */
1831 	if (verbose && color != ALLOFF)
1832 		us_highlightverbose(look, port, color, par, poly);
1833 
1834 	/* draw the port prototype if requested */
1835 	if (look->entryisnode && port != NOPORTPROTO)
1836 	{
1837 		/* compute the port bounds */
1838 		shapeportpoly(ni, port, poly, FALSE);
1839 
1840 		/* compute graphics for the port outline */
1841 		poly->desc = &us_arbit;
1842 		us_arbit.bits = LAYERH;   us_arbit.col = color;
1843 
1844 		/* see if the polygon is a single point */
1845 		for(i=1; i<poly->count; i++)
1846 			if (poly->xv[i] != poly->xv[i-1] || poly->yv[i] != poly->yv[i-1]) break;
1847 		if (i < poly->count)
1848 		{
1849 			/* not a single point, draw its outline */
1850 			if (poly->style == FILLEDRECT) poly->style = CLOSEDRECT; else
1851 				if (poly->style == FILLED) poly->style = CLOSED; else
1852 					if (poly->style == DISC) poly->style = CIRCLE;
1853 		} else
1854 		{
1855 			/* single point port: make it a cross */
1856 			poly->count = 1;
1857 			poly->style = CROSS;
1858 		}
1859 
1860 		/* draw the port */
1861 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1862 		{
1863 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1864 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1865 			if (w->curnodeproto != par) continue;
1866 			us_showpoly(poly, w);
1867 		}
1868 	}
1869 
1870 	/* draw the point or line on the trace if requested */
1871 	if (point != 0)
1872 	{
1873 		var = gettrace(ni);
1874 		if (var == NOVARIABLE) return;
1875 		x = (ni->highx + ni->lowx) / 2;   y = (ni->highy + ni->lowy) / 2;
1876 
1877 		xform(((INTBIG *)var->addr)[(point-1)*2]+x, ((INTBIG *)var->addr)[(point-1)*2+1]+y,
1878 			&poly->xv[0], &poly->yv[0], trans);
1879 		poly->desc = &us_arbit;
1880 		us_arbit.bits = LAYERH;   us_arbit.col = color;
1881 		poly->count = 1;
1882 		poly->style = CROSS;
1883 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1884 		{
1885 			if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1886 				(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1887 			if (w->curnodeproto != par) continue;
1888 			us_showpoly(poly, w);
1889 		}
1890 
1891 		if (point*2 < getlength(var))
1892 		{
1893 			xform(((INTBIG *)var->addr)[point*2]+x, ((INTBIG *)var->addr)[point*2+1]+y,
1894 				&poly->xv[1], &poly->yv[1], trans);
1895 			poly->desc = &us_arbit;
1896 			us_arbit.bits = LAYERH;   us_arbit.col = color;
1897 			poly->count = 2;
1898 			poly->style = OPENED;
1899 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1900 			{
1901 				if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1902 					(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1903 				if (w->curnodeproto != par) continue;
1904 				us_showpoly(poly, w);
1905 			}
1906 		}
1907 	}
1908 }
1909 
1910 /*
1911  * Routine to draw extra verbose highlighting on object "look" (if it is a node, then
1912  * "pp" is the port on that node).  The color is "color", the parent cell is "par", and
1913  * if it is an arc, the polygon for that arc is "arcpoly".
1914  */
us_highlightverbose(GEOM * look,PORTPROTO * pp,INTBIG color,NODEPROTO * par,POLYGON * arcpoly)1915 void us_highlightverbose(GEOM *look, PORTPROTO *pp, INTBIG color, NODEPROTO *par, POLYGON *arcpoly)
1916 {
1917 	static POLYGON *poly = NOPOLYGON;
1918 	REGISTER NODEINST *ni, *hni;
1919 	REGISTER ARCINST *ai, *oai;
1920 	REGISTER WINDOWPART *w;
1921 	REGISTER PORTARCINST *pi;
1922 	REGISTER INTBIG i, thisend;
1923 
1924 	/* get polygon */
1925 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1926 	poly->desc = &us_hbox;
1927 	poly->desc->col = color;
1928 
1929 	if (look->entryisnode)
1930 	{
1931 		/* handle verbose highlighting of nodes */
1932 		if (pp == NOPORTPROTO) return;
1933 		if (pp->network == NONETWORK) return;
1934 
1935 		hni = look->entryaddr.ni;
1936 		for(ni = par->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1937 			ni->userbits &= ~NODEFLAGBIT;
1938 		for(ai = par->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1939 			ai->userbits &= ~ARCFLAGBIT;
1940 
1941 		/* determine which arcs should be highlighted */
1942 		for(pi = hni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1943 		{
1944 			if (pi->proto->network != pp->network) continue;
1945 			ai = pi->conarcinst;
1946 			ai->userbits |= ARCFLAGBIT;
1947 			if (ai->network != NONETWORK)
1948 			{
1949 				for(oai = par->firstarcinst; oai != NOARCINST; oai = oai->nextarcinst)
1950 				{
1951 					if (oai->network != ai->network) continue;
1952 					oai->userbits |= ARCFLAGBIT;
1953 					oai->end[0].nodeinst->userbits |= NODEFLAGBIT;
1954 					oai->end[1].nodeinst->userbits |= NODEFLAGBIT;
1955 				}
1956 			}
1957 		}
1958 
1959 		/* draw lines along all of the arcs on the network */
1960 		for(ai = par->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1961 		{
1962 			if ((ai->userbits&ARCFLAGBIT) == 0) continue;
1963 			poly->xv[0] = ai->end[0].xpos;
1964 			poly->yv[0] = ai->end[0].ypos;
1965 			poly->xv[1] = ai->end[1].xpos;
1966 			poly->yv[1] = ai->end[1].ypos;
1967 			poly->count = 2;
1968 			poly->style = OPENEDT2;
1969 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1970 			{
1971 				if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1972 					(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1973 				if (w->curnodeproto != par) continue;
1974 				us_showpoly(poly, w);
1975 			}
1976 		}
1977 
1978 		/* draw dots in all connected nodes */
1979 		for(ni = par->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1980 		{
1981 			if (ni == hni) continue;
1982 			if ((ni->userbits&NODEFLAGBIT) == 0) continue;
1983 			poly->xv[0] = (ni->lowx + ni->highx) / 2;
1984 			poly->yv[0] = (ni->lowy + ni->highy) / 2;
1985 			poly->xv[1] = poly->xv[0] + el_curlib->lambda[el_curtech->techindex]/4;
1986 			poly->yv[1] = poly->yv[0];
1987 			poly->count = 2;
1988 			poly->style = DISC;
1989 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1990 			{
1991 				if ((w->state&WINDOWTYPE) != DISPWINDOW &&
1992 					(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
1993 				if (w->curnodeproto != par) continue;
1994 				poly->xv[1] = poly->xv[0] + (INTBIG)(DOTRADIUS / w->scalex);
1995 				us_showpoly(poly, w);
1996 			}
1997 
1998 			/* connect the center dots to the input arcs */
1999 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2000 			{
2001 				ai = pi->conarcinst;
2002 				if ((ai->userbits&ARCFLAGBIT) == 0) continue;
2003 				if (ai->end[0].portarcinst == pi) thisend = 0; else thisend = 1;
2004 				if (ai->end[thisend].xpos != poly->xv[0] ||
2005 					ai->end[thisend].ypos != poly->yv[0])
2006 				{
2007 					poly->xv[1] = ai->end[thisend].xpos;
2008 					poly->yv[1] = ai->end[thisend].ypos;
2009 					poly->count = 2;
2010 					poly->style = OPENEDT1;
2011 					for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2012 					{
2013 						if ((w->state&WINDOWTYPE) != DISPWINDOW &&
2014 							(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
2015 						if (w->curnodeproto != par) continue;
2016 						us_showpoly(poly, w);
2017 					}
2018 				}
2019 			}
2020 		}
2021 		return;
2022 	}
2023 
2024 	/* handle verbose highlighting of arcs */
2025 	ai = look->entryaddr.ai;
2026 
2027 	/* get a description of the constraints on the arc */
2028 	poly->string = (CHAR *)(*(el_curconstraint->request))(x_("describearc"), (INTBIG)ai);
2029 
2030 	/* quit now if there is no verbose text to print */
2031 	if (poly->string == 0 || *poly->string == 0) return;
2032 
2033 	/* determine the location of this text */
2034 	if (arcpoly->count != 4)
2035 	{
2036 		/* presume curved arc outline and determine center four points */
2037 		i = arcpoly->count/2;
2038 		poly->xv[0] = (arcpoly->xv[i/2] + arcpoly->xv[arcpoly->count-i/2-1] +
2039 			arcpoly->xv[(i-1)/2] + arcpoly->xv[arcpoly->count-(i-1)/2-1]) / 4;
2040 		poly->yv[0] = (arcpoly->yv[i/2] + arcpoly->yv[arcpoly->count-i/2-1] +
2041 			arcpoly->yv[(i-1)/2] + arcpoly->yv[arcpoly->count-(i-1)/2-1]) / 4;
2042 	} else
2043 	{
2044 		/* use straight arc: simply get center */
2045 		poly->xv[0] = (ai->end[0].xpos + ai->end[1].xpos) / 2;
2046 		poly->yv[0] = (ai->end[0].ypos + ai->end[1].ypos) / 2;
2047 	}
2048 	poly->style = TEXTCENT;
2049 	if (ai->width == 0)
2050 	{
2051 		if (ai->end[0].ypos == ai->end[1].ypos) poly->style = TEXTBOT; else
2052 			if (ai->end[0].xpos == ai->end[1].xpos) poly->style = TEXTLEFT; else
2053 				if ((ai->end[0].xpos-ai->end[1].xpos) * (ai->end[0].ypos-ai->end[1].ypos) > 0)
2054 					poly->style = TEXTBOTRIGHT; else
2055 						poly->style = TEXTBOTLEFT;
2056 	}
2057 	poly->count = 1;
2058 	TDCLEAR(poly->textdescript);
2059 	TDSETSIZE(poly->textdescript, TXTSETQLAMBDA(4));
2060 	poly->tech = ai->parent->tech;
2061 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2062 	{
2063 		if ((w->state&WINDOWTYPE) != DISPWINDOW &&
2064 			(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
2065 		if (w->curnodeproto != par) continue;
2066 		(void)us_showpoly(poly, w);
2067 	}
2068 }
2069 
2070 /*
2071  * routine to push the currently highlighted configuration onto a stack
2072  */
us_pushhighlight(void)2073 void us_pushhighlight(void)
2074 {
2075 	REGISTER VARIABLE *var;
2076 	REGISTER INTBIG len, i;
2077 	REGISTER CHAR **list;
2078 	CHAR *one[1];
2079 	REGISTER void *infstr;
2080 
2081 	/* get what is highlighted */
2082 	infstr = initinfstr();
2083 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2084 	if (var != NOVARIABLE)
2085 	{
2086 		len = getlength(var);
2087 		for(i=0; i<len; i++)
2088 		{
2089 			if (i != 0) addtoinfstr(infstr, '\n');
2090 			addstringtoinfstr(infstr, ((CHAR **)var->addr)[i]);
2091 		}
2092 	}
2093 
2094 	/* now add this to the stack variable */
2095 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightstackkey);
2096 	if (var == NOVARIABLE)
2097 	{
2098 		one[0] = returninfstr(infstr);
2099 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightstackkey, (INTBIG)one,
2100 			VSTRING|VISARRAY|(1<<VLENGTHSH)|VDONTSAVE);
2101 		return;
2102 	}
2103 
2104 	len = getlength(var);
2105 	list = (CHAR **)emalloc(((len+1) * (sizeof (CHAR *))), el_tempcluster);
2106 	if (list == 0) return;
2107 	for(i=0; i<len; i++)
2108 		(void)allocstring(&list[i], ((CHAR **)var->addr)[i], el_tempcluster);
2109 	list[len] = returninfstr(infstr);
2110 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightstackkey, (INTBIG)list,
2111 		VSTRING|VISARRAY|((len+1)<<VLENGTHSH)|VDONTSAVE);
2112 	for(i=0; i<len; i++) efree(list[i]);
2113 	efree((CHAR *)list);
2114 }
2115 
2116 /*
2117  * routine to pop the stack onto the currently highlighted configuration.
2118  */
us_pophighlight(BOOLEAN clearsnap)2119 void us_pophighlight(BOOLEAN clearsnap)
2120 {
2121 	REGISTER VARIABLE *var;
2122 	REGISTER CHAR **vaddr;
2123 	REGISTER INTBIG len, i;
2124 	REGISTER CHAR **list;
2125 
2126 	/* get the stack variable */
2127 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightstackkey);
2128 	if (var == NOVARIABLE) return;
2129 	len = getlength(var);
2130 	vaddr = (CHAR **)var->addr;
2131 
2132 	/* set the configuration */
2133 	us_setmultiplehighlight(vaddr[len-1], clearsnap);
2134 
2135 	/* shorten the stack */
2136 	if (len == 1) (void)delvalkey((INTBIG)us_tool, VTOOL, us_highlightstackkey); else
2137 	{
2138 		len--;
2139 		list = (CHAR **)emalloc((len * (sizeof (CHAR *))), el_tempcluster);
2140 		if (list == 0) return;
2141 		for(i=0; i<len; i++)
2142 			(void)allocstring(&list[i], vaddr[i], el_tempcluster);
2143 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightstackkey, (INTBIG)list,
2144 			VSTRING|VISARRAY|(len<<VLENGTHSH)|VDONTSAVE);
2145 		for(i=0; i<len; i++) efree(list[i]);
2146 		efree((CHAR *)list);
2147 	}
2148 }
2149 
2150 /*
2151  * routine to highlight the multiple highlight information in "str".
2152  */
us_setmultiplehighlight(CHAR * str,BOOLEAN clearsnap)2153 void us_setmultiplehighlight(CHAR *str, BOOLEAN clearsnap)
2154 {
2155 	CHAR *pp;
2156 	REGISTER CHAR *line, **list;
2157 	REGISTER INTBIG total, i;
2158 	HIGHLIGHT high;
2159 	REGISTER void *infstr;
2160 
2161 	/* count the number of highlights */
2162 	pp = str;
2163 	for(total=0; ; total++)
2164 	{
2165 		line = getkeyword(&pp, x_("\n"));
2166 		if (line == NOSTRING) break;
2167 		if (*line == 0) break;
2168 		(void)tonextchar(&pp);
2169 	}
2170 	if (total == 0) return;
2171 
2172 	/* make space for all of the highlight strings */
2173 	list = (CHAR **)emalloc((total * (sizeof (CHAR *))), el_tempcluster);
2174 	if (list == 0) return;
2175 
2176 	/* fill the list */
2177 	pp = str;
2178 	for(total=0; ; )
2179 	{
2180 		line = getkeyword(&pp, x_("\n"));
2181 		if (line == NOSTRING) break;
2182 		if (*line == 0) break;
2183 
2184 		if (clearsnap)
2185 		{
2186 			infstr = initinfstr();
2187 			addstringtoinfstr(infstr, line);
2188 			if (!us_makehighlight(returninfstr(infstr), &high))
2189 			{
2190 				high.status &= ~(HIGHSNAP | HIGHSNAPTAN | HIGHSNAPPERP);
2191 				line = us_makehighlightstring(&high);
2192 				(void)allocstring(&list[total++], line, el_tempcluster);
2193 			}
2194 		} else
2195 		{
2196 			(void)allocstring(&list[total++], line, el_tempcluster);
2197 		}
2198 		if (tonextchar(&pp) != '\n') break;
2199 	}
2200 
2201 	/* set the multiple list */
2202 	if (total == 0) return;
2203 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey, (INTBIG)list,
2204 		VSTRING|VISARRAY|(total<<VLENGTHSH)|VDONTSAVE);
2205 
2206 	for(i=0; i<total; i++) efree(list[i]);
2207 	efree((CHAR *)list);
2208 	us_makecurrentobject();
2209 }
2210 
2211 /*
2212  * routine to set the current prototype from the current selection
2213  */
us_makecurrentobject(void)2214 void us_makecurrentobject(void)
2215 {
2216 	REGISTER NODEPROTO *np;
2217 	REGISTER GEOM *from;
2218 	HIGHLIGHT high;
2219 	REGISTER VARIABLE *var;
2220 
2221 	/* see what is highlighted */
2222 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2223 
2224 	/* there must be exactly 1 object highlighted */
2225 	if (var == NOVARIABLE || getlength(var) != 1)
2226 	{
2227 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO);
2228 		return;
2229 	}
2230 
2231 	/* get information about the highlighted object */
2232 	if (us_makehighlight(((CHAR **)var->addr)[0], &high)) return;
2233 	if ((high.status&HIGHTYPE) != HIGHFROM && (high.status&HIGHTYPE) != HIGHTEXT)
2234 	{
2235 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO);
2236 		return;
2237 	}
2238 	from = high.fromgeom;
2239 	if (from == NOGEOM)
2240 	{
2241 		us_setnodeproto(NONODEPROTO);
2242 		return;
2243 	}
2244 
2245 	/* if an arc is selected, show it */
2246 	if (!from->entryisnode)
2247 	{
2248 		us_setarcproto(from->entryaddr.ai->proto, TRUE);
2249 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO);
2250 		return;
2251 	}
2252 
2253 	/* a node is selected */
2254 	np = from->entryaddr.ni->proto;
2255 	us_setnodeproto(np);
2256 }
2257 
2258 /*
2259  * routine to convert the string in "str" into the highlight module "high".
2260  * returns true on error
2261  */
us_makehighlight(CHAR * str,HIGHLIGHT * high)2262 BOOLEAN us_makehighlight(CHAR *str, HIGHLIGHT *high)
2263 {
2264 	CHAR *pt;
2265 	REGISTER CHAR *keyword;
2266 	REGISTER INTBIG addr, type;
2267 
2268 	pt = str;
2269 
2270 	/* look for the "CELL=" keyword */
2271 	keyword = getkeyword(&pt, x_("="));
2272 	if (keyword == NOSTRING) return(TRUE);
2273 	if (namesame(keyword, x_("CELL")) != 0) return(TRUE);
2274 	if (tonextchar(&pt) != '=') return(TRUE);
2275 
2276 	/* get the cell name */
2277 	keyword = getkeyword(&pt, x_(" \t"));
2278 	if (keyword == NOSTRING) return(TRUE);
2279 	high->cell = getnodeproto(keyword);
2280 	if (high->cell == NONODEPROTO) return(TRUE);
2281 
2282 	/* get the type of highlight */
2283 	keyword = getkeyword(&pt, x_("="));
2284 	if (keyword == NOSTRING) return(TRUE);
2285 	if (tonextchar(&pt) != '=') return(TRUE);
2286 	if (namesame(keyword, x_("FROM")) == 0)
2287 	{
2288 		/* parse the three values: geom/port/point */
2289 		high->status = HIGHFROM;
2290 		high->fromvar = NOVARIABLE;
2291 		high->fromvarnoeval = NOVARIABLE;
2292 		keyword = getkeyword(&pt, x_(";"));
2293 		if (keyword == NOSTRING) return(TRUE);
2294 		high->fromgeom = (GEOM *)myatoi(keyword);
2295 		if (tonextchar(&pt) != ';') return(TRUE);
2296 		keyword = getkeyword(&pt, x_(";"));
2297 		if (keyword == NOSTRING) return(TRUE);
2298 		high->fromport = (PORTPROTO *)myatoi(keyword);
2299 		if (tonextchar(&pt) != ';') return(TRUE);
2300 		keyword = getkeyword(&pt, x_(";"));
2301 		if (keyword == NOSTRING) return(TRUE);
2302 		high->frompoint = myatoi(keyword);
2303 	} else if (namesame(keyword, x_("AREA")) == 0 || namesame(keyword, x_("LINE")) == 0)
2304 	{
2305 		if (namesame(keyword, x_("AREA")) == 0) high->status = HIGHBBOX; else
2306 			high->status = HIGHLINE;
2307 		keyword = getkeyword(&pt, x_(","));
2308 		if (keyword == NOSTRING) return(TRUE);
2309 		high->stalx = myatoi(keyword);
2310 		if (tonextchar(&pt) != ',') return(TRUE);
2311 		keyword = getkeyword(&pt, x_(","));
2312 		if (keyword == NOSTRING) return(TRUE);
2313 		high->stahx = myatoi(keyword);
2314 		if (tonextchar(&pt) != ',') return(TRUE);
2315 		keyword = getkeyword(&pt, x_(","));
2316 		if (keyword == NOSTRING) return(TRUE);
2317 		high->staly = myatoi(keyword);
2318 		if (tonextchar(&pt) != ',') return(TRUE);
2319 		keyword = getkeyword(&pt, x_(","));
2320 		if (keyword == NOSTRING) return(TRUE);
2321 		high->stahy = myatoi(keyword);
2322 	} else if (namesame(keyword, x_("TEXT")) == 0)
2323 	{
2324 		/* parse the three values: geom/port/var */
2325 		high->status = HIGHTEXT;
2326 		high->frompoint = 0;
2327 		keyword = getkeyword(&pt, x_(";"));
2328 		if (keyword == NOSTRING) return(TRUE);
2329 		high->fromgeom = (GEOM *)myatoi(keyword);
2330 		if (tonextchar(&pt) != ';') return(TRUE);
2331 		keyword = getkeyword(&pt, x_(";"));
2332 		if (keyword == NOSTRING) return(TRUE);
2333 		high->fromport = (PORTPROTO *)myatoi(keyword);
2334 		if (tonextchar(&pt) != ';') return(TRUE);
2335 		keyword = getkeyword(&pt, x_(";"));
2336 		if (keyword == NOSTRING) return(TRUE);
2337 		if (*keyword == '-') high->fromvarnoeval = high->fromvar = NOVARIABLE; else
2338 		{
2339 			if (high->fromport != NOPORTPROTO)
2340 			{
2341 				addr = (INTBIG)high->fromport;
2342 				type = VPORTPROTO;
2343 			} else if (high->fromgeom != NOGEOM)
2344 			{
2345 				if (high->fromgeom->entryisnode)
2346 				{
2347 					addr = (INTBIG)high->fromgeom->entryaddr.ni;
2348 					type = VNODEINST;
2349 				} else
2350 				{
2351 					addr = (INTBIG)high->fromgeom->entryaddr.ai;
2352 					type = VARCINST;
2353 				}
2354 			} else
2355 			{
2356 				addr = (INTBIG)high->cell;
2357 				type = VNODEPROTO;
2358 			}
2359 			high->fromvarnoeval = getvalnoeval(addr, type, -1, keyword);
2360 			high->fromvar = evalvar(high->fromvarnoeval, addr, type);
2361 		}
2362 	} else return(TRUE);
2363 
2364 	/* parse any additional keywords */
2365 	for(;;)
2366 	{
2367 		if (tonextchar(&pt) == 0) break;
2368 		keyword = getkeyword(&pt, x_(";,="));
2369 		if (keyword == NOSTRING) return(TRUE);
2370 		if ((namesame(keyword, x_("SNAP")) == 0 || namesame(keyword, x_("SNAPTAN")) == 0 ||
2371 			namesame(keyword, x_("SNAPPERP")) == 0) && tonextchar(&pt) == '=')
2372 		{
2373 			high->status |= HIGHSNAP;
2374 			if (namesame(keyword, x_("SNAPTAN")) == 0) high->status |= HIGHSNAPTAN;
2375 			if (namesame(keyword, x_("SNAPPERP")) == 0) high->status |= HIGHSNAPPERP;
2376 			keyword = getkeyword(&pt, x_(","));
2377 			if (keyword == NOSTRING) return(TRUE);
2378 			high->snapx = myatoi(keyword);
2379 			if (tonextchar(&pt) != ',') return(TRUE);
2380 			keyword = getkeyword(&pt, x_(";,"));
2381 			if (keyword == NOSTRING) return(TRUE);
2382 			high->snapy = myatoi(keyword);
2383 			continue;
2384 		}
2385 		if (namesame(keyword, x_("EXTRA")) == 0)
2386 		{
2387 			high->status |= HIGHEXTRA;
2388 			continue;
2389 		}
2390 		if (namesame(keyword, x_("NOBBOX")) == 0)
2391 		{
2392 			high->status |= HIGHNOBOX;
2393 			continue;
2394 		}
2395 		return(TRUE);
2396 	}
2397 	return(FALSE);
2398 }
2399 
2400 /*
2401  * routine to convert the highlight in "high" into a string which is returned.
2402  */
us_makehighlightstring(HIGHLIGHT * high)2403 CHAR *us_makehighlightstring(HIGHLIGHT *high)
2404 {
2405 	REGISTER void *infstr;
2406 
2407 	infstr = initinfstr();
2408 	formatinfstr(infstr, x_("CELL=%s"), describenodeproto(high->cell));
2409 	switch (high->status&HIGHTYPE)
2410 	{
2411 		case HIGHFROM:
2412 			formatinfstr(infstr, x_(" FROM=0%lo;"), (UINTBIG)high->fromgeom);
2413 			if (high->fromport == NOPORTPROTO) addstringtoinfstr(infstr, x_("-1;")); else
2414 				formatinfstr(infstr, x_("0%lo;"), (UINTBIG)high->fromport);
2415 			formatinfstr(infstr, x_("%ld"), high->frompoint);
2416 			if ((high->status&HIGHEXTRA) != 0) addstringtoinfstr(infstr, x_(";EXTRA"));
2417 			if ((high->status&HIGHNOBOX) != 0) addstringtoinfstr(infstr, x_(";NOBBOX"));
2418 			break;
2419 		case HIGHTEXT:
2420 			formatinfstr(infstr, x_(" TEXT=0%lo;"), (UINTBIG)high->fromgeom);
2421 			if (high->fromport == NOPORTPROTO) addstringtoinfstr(infstr, x_("-1;")); else
2422 				formatinfstr(infstr, x_("0%lo;"), (UINTBIG)high->fromport);
2423 			if (high->fromvar == NOVARIABLE) addstringtoinfstr(infstr, x_("-")); else
2424 				addstringtoinfstr(infstr, makename(high->fromvar->key));
2425 			break;
2426 		case HIGHBBOX:
2427 			formatinfstr(infstr, x_(" AREA=%ld,%ld,%ld,%ld"), high->stalx, high->stahx, high->staly, high->stahy);
2428 			break;
2429 		case HIGHLINE:
2430 			formatinfstr(infstr, x_(" LINE=%ld,%ld,%ld,%ld"), high->stalx, high->stahx, high->staly, high->stahy);
2431 			break;
2432 	}
2433 	if ((high->status&HIGHSNAP) != 0)
2434 	{
2435 		if ((high->status&HIGHSNAPTAN) != 0) addstringtoinfstr(infstr, x_(";SNAPTAN=")); else
2436 			if ((high->status&HIGHSNAPPERP) != 0) addstringtoinfstr(infstr, x_(";SNAPPERP=")); else
2437 				addstringtoinfstr(infstr, x_(";SNAP="));
2438 		formatinfstr(infstr, x_("%ld,%ld"), high->snapx, high->snapy);
2439 	}
2440 	return(returninfstr(infstr));
2441 }
2442 
2443 /*
2444  * routine to determine the center of the highlighted text described by
2445  * "high".  The coordinates are placed in (xc, yc), and the appropriate
2446  * polygon style is placed in "style".
2447  */
us_gethightextcenter(HIGHLIGHT * high,INTBIG * xc,INTBIG * yc,INTBIG * style)2448 void us_gethightextcenter(HIGHLIGHT *high, INTBIG *xc, INTBIG *yc, INTBIG *style)
2449 {
2450 	static POLYGON *poly = NOPOLYGON;
2451 	REGISTER NODEINST *ni;
2452 	REGISTER ARCINST *ai;
2453 	REGISTER NODEPROTO *cell;
2454 	XARRAY trans;
2455 	INTBIG newxc, newyc;
2456 	REGISTER INTSML saverot, savetrn;
2457 	REGISTER INTBIG lambda;
2458 	UINTBIG descript[TEXTDESCRIPTSIZE];
2459 
2460 	/* get polygon */
2461 	(void)needstaticpolygon(&poly, 1, us_tool->cluster);
2462 
2463 	poly->count = 1;
2464 	poly->style = FILLED;
2465 	if (high->fromvar != NOVARIABLE)
2466 	{
2467 		TDCOPY(descript, high->fromvar->textdescript);
2468 		if (high->fromport != NOPORTPROTO)
2469 		{
2470 			ni = high->fromport->subnodeinst;
2471 			saverot = ni->rotation;   savetrn = ni->transpose;
2472 			ni->rotation = ni->transpose = 0;
2473 			portposition(ni, high->fromport->subportproto,
2474 				&poly->xv[0], &poly->yv[0]);
2475 			ni->rotation = saverot;   ni->transpose = savetrn;
2476 			adjustdisoffset((INTBIG)high->fromport, VPORTPROTO, high->cell->tech,
2477 				poly, descript);
2478 			makerot(high->fromport->subnodeinst, trans);
2479 			xformpoly(poly, trans);
2480 		} else if (high->fromgeom != NOGEOM)
2481 		{
2482 			if (high->fromgeom->entryisnode)
2483 			{
2484 				ni = high->fromgeom->entryaddr.ni;
2485 				poly->xv[0] = (ni->lowx + ni->highx) / 2;
2486 				poly->yv[0] = (ni->lowy + ni->highy) / 2;
2487 				adjustdisoffset((INTBIG)ni, VNODEINST, ni->proto->tech, poly, descript);
2488 				makerot(ni, trans);
2489 				xformpoly(poly, trans);
2490 			} else
2491 			{
2492 				ai = high->fromgeom->entryaddr.ai;
2493 				poly->xv[0] = (ai->end[0].xpos + ai->end[1].xpos) / 2;
2494 				poly->yv[0] = (ai->end[0].ypos + ai->end[1].ypos) / 2;
2495 				adjustdisoffset((INTBIG)ai, VARCINST, ai->proto->tech, poly, descript);
2496 			}
2497 		} else
2498 		{
2499 			/* cell variables are offset from (0,0) */
2500 			poly->xv[0] = poly->yv[0] = 0;
2501 			adjustdisoffset((INTBIG)high->cell, VNODEPROTO, high->cell->tech,
2502 				poly, descript);
2503 		}
2504 		*style = poly->style;
2505 	} else if (high->fromport != NOPORTPROTO)
2506 	{
2507 		TDCOPY(descript, high->fromport->textdescript);
2508 		ni = high->fromgeom->entryaddr.ni;
2509 		portposition(high->fromport->subnodeinst, high->fromport->subportproto,
2510 			&poly->xv[0], &poly->yv[0]);
2511 		makeangle(ni->rotation, ni->transpose, trans);
2512 		cell = ni->parent;
2513 		lambda = cell->lib->lambda[cell->tech->techindex];
2514 		newxc = TDGETXOFF(descript);
2515 		newxc = newxc * lambda / 4;
2516 		newyc = TDGETYOFF(descript);
2517 		newyc = newyc * lambda / 4;
2518 		xform(newxc, newyc, &newxc, &newyc, trans);
2519 		poly->xv[0] += newxc;   poly->yv[0] += newyc;
2520 		switch (TDGETPOS(descript))
2521 		{
2522 			case VTPOSCENT:      *style = TEXTCENT;      break;
2523 			case VTPOSBOXED:     *style = TEXTBOX;       break;
2524 			case VTPOSUP:        *style = TEXTBOT;       break;
2525 			case VTPOSDOWN:      *style = TEXTTOP;       break;
2526 			case VTPOSLEFT:      *style = TEXTRIGHT;     break;
2527 			case VTPOSRIGHT:     *style = TEXTLEFT;      break;
2528 			case VTPOSUPLEFT:    *style = TEXTBOTRIGHT;  break;
2529 			case VTPOSUPRIGHT:   *style = TEXTBOTLEFT;   break;
2530 			case VTPOSDOWNLEFT:  *style = TEXTTOPRIGHT;  break;
2531 			case VTPOSDOWNRIGHT: *style = TEXTTOPLEFT;   break;
2532 		}
2533 		*style = rotatelabel(*style, TDGETROTATION(descript), trans);
2534 	} else if (high->fromgeom != NOGEOM && high->fromgeom->entryisnode)
2535 	{
2536 		/* instance name */
2537 		ni = high->fromgeom->entryaddr.ni;
2538 		TDCOPY(descript, ni->textdescript);
2539 		poly->xv[0] = (ni->lowx + ni->highx) / 2;
2540 		poly->yv[0] = (ni->lowy + ni->highy) / 2;
2541 		adjustdisoffset((INTBIG)ni, VNODEINST, ni->proto->tech, poly, descript);
2542 		makerot(ni, trans);
2543 		xformpoly(poly, trans);
2544 		*style = poly->style;
2545 	}
2546 	getcenter(poly, xc, yc);
2547 }
2548 
us_gethightextsize(HIGHLIGHT * high,INTBIG * xw,INTBIG * yw,WINDOWPART * w)2549 void us_gethightextsize(HIGHLIGHT *high, INTBIG *xw, INTBIG *yw, WINDOWPART *w)
2550 {
2551 	REGISTER INTBIG len;
2552 	REGISTER CHAR *str;
2553 	REGISTER TECHNOLOGY *tech;
2554 	REGISTER WINDOWPART *oldwin;
2555 	INTBIG lx, hx, ly, hy;
2556 	UINTBIG descript[TEXTDESCRIPTSIZE];
2557 	static POLYGON *poly = NOPOLYGON;
2558 
2559 	/* get polygon */
2560 	(void)needstaticpolygon(&poly, 5, us_tool->cluster);
2561 
2562 	/* determine number of lines of text */
2563 	len = 1;
2564 	if (high->fromvar != NOVARIABLE && (high->fromvar->type&VISARRAY) != 0)
2565 		len = getlength(high->fromvar);
2566 	if (len > 1)
2567 	{
2568 		/* get size of array of text */
2569 		makedisparrayvarpoly(high->fromgeom, w, high->fromvar, poly);
2570 		getbbox(poly, &lx, &hx, &ly, &hy);
2571 		*xw = hx - lx;
2572 		*yw = hy - ly;
2573 		return;
2574 	}
2575 
2576 	/* determine size of single line of text */
2577 	tech = us_hightech(high);
2578 	oldwin = setvariablewindow(w);
2579 	str = us_gethighstring(high);
2580 	us_gethighdescript(high, descript);
2581 	(void)setvariablewindow(oldwin);
2582 
2583 	us_gettextscreensize(str, descript, w, tech, high->fromgeom, xw, yw);
2584 }
2585 
2586 /*
2587  * Routine to return the text descriptor on highlight "high" in "descript".
2588  */
us_gethighdescript(HIGHLIGHT * high,UINTBIG * descript)2589 void us_gethighdescript(HIGHLIGHT *high, UINTBIG *descript)
2590 {
2591 	if (high->fromvar != NOVARIABLE)
2592 	{
2593 		TDCOPY(descript, high->fromvar->textdescript);
2594 		return;
2595 	}
2596 	if (high->fromport != NOPORTPROTO)
2597 	{
2598 		TDCOPY(descript, high->fromport->textdescript);
2599 		return;
2600 	}
2601 	if (high->fromgeom->entryisnode)
2602 	{
2603 		TDCOPY(descript, high->fromgeom->entryaddr.ni->textdescript);
2604 		return;
2605 	}
2606 	TDCLEAR(descript);
2607 }
2608 
2609 /*
2610  * Routine to return the text on highlight "high".
2611  */
us_gethighstring(HIGHLIGHT * high)2612 CHAR *us_gethighstring(HIGHLIGHT *high)
2613 {
2614 	REGISTER CHAR *str;
2615 	REGISTER VARIABLE *var;
2616 
2617 	var = high->fromvar;
2618 	if (var != NOVARIABLE)
2619 	{
2620 		if (high->fromvarnoeval != NOVARIABLE) var = evalvar(high->fromvarnoeval, 0, 0);
2621 		str = describedisplayedvariable(var, -1, -1);
2622 		return(str);
2623 	}
2624 	if (high->fromport != NOPORTPROTO)
2625 		return(us_displayedportname(high->fromport, (us_useroptions&EXPORTLABELS) >> EXPORTLABELSSH));
2626 	if (high->fromgeom->entryisnode)
2627 		return(describenodeproto(high->fromgeom->entryaddr.ni->proto));
2628 	return(x_(""));
2629 }
2630 
2631 /*
2632  * Routine to examine highlight "high" and return the address and type
2633  * of the object to which it refers.
2634  */
us_gethighaddrtype(HIGHLIGHT * high,INTBIG * addr,INTBIG * type)2635 void us_gethighaddrtype(HIGHLIGHT *high, INTBIG *addr, INTBIG *type)
2636 {
2637 	if ((high->status&HIGHTYPE) == HIGHTEXT)
2638 	{
2639 		if (high->fromvar != NOVARIABLE)
2640 		{
2641 			if (high->fromport != NOPORTPROTO)
2642 			{
2643 				*addr = (INTBIG)high->fromport;
2644 				*type = VPORTPROTO;
2645 				return;
2646 			}
2647 			if (high->fromgeom == NOGEOM)
2648 			{
2649 				*addr = (INTBIG)high->cell;
2650 				*type = VNODEPROTO;
2651 				return;
2652 			}
2653 
2654 			*addr = (INTBIG)high->fromgeom->entryaddr.blind;
2655 			if (high->fromgeom->entryisnode)
2656 			{
2657 				*type = VNODEINST;
2658 			} else
2659 			{
2660 				*type = VARCINST;
2661 			}
2662 			return;
2663 		}
2664 		if (high->fromport != NOPORTPROTO)
2665 		{
2666 			*addr = (INTBIG)high->fromport;
2667 			*type = VPORTPROTO;
2668 			return;
2669 		}
2670 		*addr = (INTBIG)high->fromgeom->entryaddr.blind;
2671 		if (high->fromgeom->entryisnode) *type = VNODEINST; else
2672 			*type = VARCINST;
2673 		return;
2674 	}
2675 }
2676 
2677 /*
2678  * Routine to return true if highlight "high" is text on a node that must move together.
2679  * This only happens for "nonlayout text" (a variable on an invisible node), for exports
2680  * on an invisible pin, or for any export when it is requested that the node move too.
2681  */
us_nodemoveswithtext(HIGHLIGHT * high)2682 BOOLEAN us_nodemoveswithtext(HIGHLIGHT *high)
2683 {
2684 	REGISTER NODEINST *ni;
2685 
2686 	if (high->status != HIGHTEXT) return(FALSE);
2687 	if (high->fromgeom == NOGEOM) return(FALSE);
2688 	if (!high->fromgeom->entryisnode) return(FALSE);
2689 	ni = high->fromgeom->entryaddr.ni;
2690 	if (ni == NONODEINST) return(FALSE);
2691 	if (high->fromvar != NOVARIABLE)
2692 	{
2693 		/* moving variable text */
2694 		if (ni->proto != gen_invispinprim) return(FALSE);
2695 		if (high->fromport == NOPORTPROTO) return(TRUE);
2696 	} else
2697 	{
2698 		/* moving export text */
2699 		if ((us_useroptions&MOVENODEWITHEXPORT) == 0 && ni->proto != gen_invispinprim)
2700 			return(FALSE);
2701 		if (high->fromport != NOPORTPROTO) return(TRUE);
2702 	}
2703 	return(FALSE);
2704 }
2705 
2706 /*
2707  * Routine to figure out the technology to use for highlight "high".
2708  */
us_hightech(HIGHLIGHT * high)2709 TECHNOLOGY *us_hightech(HIGHLIGHT *high)
2710 {
2711 	REGISTER NODEPROTO *cell;
2712 
2713 	cell = us_highcell(high);
2714 	if (cell == NONODEPROTO) return(el_curtech);
2715 	if (cell->tech == NOTECHNOLOGY)
2716 		cell->tech = whattech(cell);
2717 	return(cell->tech);
2718 }
2719 
2720 /*
2721  * Routine to figure out the cell to use for highlight "high".
2722  */
us_highcell(HIGHLIGHT * high)2723 NODEPROTO *us_highcell(HIGHLIGHT *high)
2724 {
2725 	if (high->fromvar != NOVARIABLE)
2726 	{
2727 		if (high->fromport != NOPORTPROTO)
2728 			return(high->fromport->subnodeinst->parent);
2729 		if (high->fromgeom == NOGEOM) return(high->cell);
2730 		if (high->fromgeom->entryisnode)
2731 			return(high->fromgeom->entryaddr.ni->parent);
2732 		return(high->fromgeom->entryaddr.ai->parent);
2733 	}
2734 	if (high->fromport != NOPORTPROTO)
2735 		return(high->fromgeom->entryaddr.ni->parent);
2736 	if (high->fromgeom->entryisnode)
2737 		return(high->fromgeom->entryaddr.ni->parent);
2738 	return(high->fromgeom->entryaddr.ai->parent);
2739 }
2740 
us_getobjectinfo(INTBIG addr,INTBIG type,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)2741 TECHNOLOGY *us_getobjectinfo(INTBIG addr, INTBIG type, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
2742 {
2743 	REGISTER NODEINST *ni;
2744 	REGISTER ARCINST *ai;
2745 	REGISTER PORTPROTO *pp;
2746 	REGISTER NODEPROTO *np;
2747 	INTBIG olx, ohx, oly, ohy;
2748 
2749 	switch (type)
2750 	{
2751 		case VNODEINST:
2752 			ni = (NODEINST *)addr;
2753 			nodesizeoffset(ni, &olx, &oly, &ohx, &ohy);
2754 			*lx = ni->geom->lowx+olx;   *hx = ni->geom->highx-ohx;
2755 			*ly = ni->geom->lowy+oly;   *hy = ni->geom->highy-ohy;
2756 			return(ni->parent->tech);
2757 		case VARCINST:
2758 			ai = (ARCINST *)addr;
2759 			*lx = ai->geom->lowx;   *hx = ai->geom->highx;
2760 			*ly = ai->geom->lowy;   *hy = ai->geom->highy;
2761 			return(ai->parent->tech);
2762 		case VPORTPROTO:
2763 			pp = (PORTPROTO *)addr;
2764 			ni = pp->subnodeinst;
2765 			*lx = ni->geom->lowx;   *hx = ni->geom->highx;
2766 			*ly = ni->geom->lowy;   *hy = ni->geom->highy;
2767 			return(pp->parent->tech);
2768 		case VNODEPROTO:
2769 			np = (NODEPROTO *)addr;
2770 			*lx = np->lowx;   *hx = np->highx;
2771 			*ly = np->lowy;   *hy = np->highy;
2772 			return(np->tech);
2773 	}
2774 	return(NOTECHNOLOGY);
2775 }
2776 
us_drawcellvariable(VARIABLE * var,NODEPROTO * np)2777 void us_drawcellvariable(VARIABLE *var, NODEPROTO *np)
2778 {
2779 	REGISTER INTBIG i, displaytotal;
2780 	REGISTER WINDOWPART *w;
2781 	static POLYGON *poly = NOPOLYGON;
2782 
2783 	/* get polygon */
2784 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
2785 
2786 	displaytotal = tech_displayablecellvars(np, NOWINDOWPART, &tech_oneprocpolyloop);
2787 	for(i = 0; i < displaytotal; i++)
2788 	{
2789 		(void)tech_filldisplayablecellvar(np, poly, NOWINDOWPART, 0, &tech_oneprocpolyloop);
2790 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2791 		{
2792 			if (w->curnodeproto != np) continue;
2793 			(*us_displayroutine)(poly, w);
2794 		}
2795 	}
2796 }
2797 
us_undrawcellvariable(VARIABLE * var,NODEPROTO * np)2798 void us_undrawcellvariable(VARIABLE *var, NODEPROTO *np)
2799 {
2800 	INTBIG x, y;
2801 	INTBIG tsx, tsy;
2802 	REGISTER INTBIG objwid, objhei, sea, slx, shx, sly, shy, nudge;
2803 	INTBIG lx, hx, ly, hy;
2804 	REGISTER TECHNOLOGY *tech;
2805 	REGISTER NODEINST *ni;
2806 	REGISTER ARCINST *ai;
2807 	REGISTER GEOM *geom;
2808 	REGISTER CHAR *str;
2809 	REGISTER WINDOWPART *w;
2810 	extern GRAPHICS us_ebox;
2811 
2812 	if ((var->type&VDISPLAY) == 0) return;
2813 	tech = np->tech;
2814 	str = describedisplayedvariable(var, -1, -1);
2815 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2816 	{
2817 		if ((w->state&WINDOWTYPE) != DISPWINDOW) continue;
2818 		if (w->curnodeproto != np) continue;
2819 		screensettextinfo(w, tech, var->textdescript);
2820 
2821 		getdisparrayvarlinepos((INTBIG)np, VNODEPROTO, tech,
2822 			w, var, 0, &x, &y, TRUE);
2823 		screengettextsize(w, str, &tsx, &tsy);
2824 		objwid = roundfloat((float)tsx / w->scalex);
2825 		objhei = roundfloat((float)tsy / w->scaley);
2826 		slx = x;   shx = slx + objwid;
2827 		sly = y;   shy = sly + objhei;
2828 
2829 		/* erase that area */
2830 		lx = slx;   hx = shx;
2831 		ly = sly;   hy = shy;
2832 		if ((w->state&INPLACEEDIT) != 0)
2833 			xformbox(&lx, &hx, &ly, &hy, w->outofcell);
2834 		if (us_makescreen(&lx, &ly, &hx, &hy, w)) continue;
2835 		screendrawbox(w, lx, hx, ly, hy, &us_ebox);
2836 
2837 		/* now redraw everything that touches this box */
2838 		nudge = (INTBIG)(1.0f/w->scalex);
2839 		slx -= nudge;
2840 		shx += nudge;
2841 		nudge = (INTBIG)(1.0f/w->scaley);
2842 		sly -= nudge;
2843 		shy += nudge;
2844 		sea = initsearch(slx, shx, sly, shy, np);
2845 		for(;;)
2846 		{
2847 			geom = nextobject(sea);
2848 			if (geom == NOGEOM) break;
2849 			if (geom->entryisnode)
2850 			{
2851 				ni = geom->entryaddr.ni;
2852 				(void)us_drawcell(ni, LAYERA, el_matid, 3, w);
2853 			} else
2854 			{
2855 				ai = geom->entryaddr.ai;
2856 				(void)us_drawarcinst(ai, LAYERA, el_matid, 3, w);
2857 			}
2858 		}
2859 	}
2860 }
2861