1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrmisc.c
6 * User interface tool: miscellaneous control
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "egraphics.h"
34 #include "efunction.h"
35 #include "edialogs.h"
36 #include "usr.h"
37 #include "usreditemacs.h"
38 #include "usreditpac.h"
39 #include "usrtrack.h"
40 #include "tecgen.h"
41 #include "tecart.h"
42 #include "sim.h"
43 #include <math.h>
44
45 #define ALLTEXTWIDTH 70 /* width of side menu when it is all text */
46
47 /******************** INITIALIZATION ********************/
48
49 #define INITIALMENUX 18 /* default height of component menu */
50 #define INITIALMENUY 2 /* default width of component menu */
51
52 /*
53 * default tablet state: the table below shows the set of commands
54 * that will be bound to the tablet buttons. If there is a button
55 * with the name in "us_tablet[i].but[0]" or "us_tablet[i].but[1]"
56 * then that button will be bound to the command "us_tablet[i].com".
57 * If no tablet button exists for an entry "i", then the command
58 * there will be bound to the key "us_tablet[i].key". Thus, tablets
59 * with varying numbers of buttons can be handled by placing commands
60 * on the keys if they don't fit on the buttons.
61 */
62 typedef struct
63 {
64 CHAR *but[3]; /* the button names for this command */
65 CHAR *key; /* the key name for this command */
66 CHAR *com; /* the actual command */
67 INTBIG count; /* number of parameters to the command */
68 CHAR *args[2]; /* parameters to the command */
69 BOOLEAN used; /* set when the command is bound */
70 } INITBUTTONS;
71
72 static INITBUTTONS us_initialbutton[] =
73 {
74 /* left/middle/right (white/yellow/blue) are basic commands */
75 {{x_("LEFT"),x_("WHITE"),x_("BUTTON")},x_("f"), x_("find"), 2, {x_("port"), x_("extra-info")}, FALSE},
76 {{x_("RIGHT"),x_("YELLOW"),x_("")}, x_("m"), x_("move"), 0, {x_(""), x_("")}, FALSE},
77 {{x_("MIDDLE"),x_("BLUE"),x_("")}, x_("n"), x_("create"), 0, {x_(""), x_("")}, FALSE},
78
79 /* on four-button puck, add one more basic command */
80 {{x_("GREEN"),x_(""),x_("")}, x_("o"), x_("find"), 2, {x_("another"), x_("port")}, FALSE},
81
82 /* on mice with shift-buttons, add in others still */
83 {{x_("SLEFT"),x_(""),x_("")}, x_(""), x_("find"), 1, {x_("more"), x_("")}, FALSE},
84 {{x_("SRIGHT"),x_(""),x_("")}, x_(""), x_("var"), 2, {x_("textedit"), x_("~")}, FALSE},
85 {{x_("SMIDDLE"),x_(""),x_("")}, x_(""), x_("create"), 1, {x_("join-angle"), x_("")}, FALSE},
86 {{NULL, NULL, NULL}, NULL, NULL, 0, {NULL, NULL}, FALSE} /* 0 */
87 };
88
89 /*
90 * default keyboard state: the table below shows the set of commands
91 * that will be bound to the keyboard keys.
92 */
93 typedef struct
94 {
95 CHAR *key;
96 CHAR *command;
97 INTBIG count;
98 CHAR *args[2];
99 } INITKEYS;
100
101 static INITKEYS us_initialkeyboard[] =
102 {
103 {x_("-"), x_("telltool"), 1, {x_("user"), x_("")}},
104 {NULL, NULL, 0, {NULL, NULL}} /* 0 */
105 };
106
107 /*
108 * When information, detected during broadcast, evokes a reaction that causes
109 * change, that change must be queued until the next slice. For example:
110 * deletion of the variable associated with a text window.
111 * These routines queue the changes and then execute them when requested
112 */
113 #define NOUBCHANGE ((UBCHANGE *)-1)
114 #define UBKILLFM 1 /* remove cell_message variable */
115 #define UBNEWFC 2 /* add cell-center */
116 #define UBSPICEPARTS 3 /* check for new spice parts package */
117 #define UBTECEDDELLAYER 4 /* deleted a technology-edit layer cell */
118 #define UBTECEDDELNODE 5 /* deleted a technology-edit node cell */
119 #define UBTECEDRENAME 6 /* renamed a technology-edit cell */
120 #define UBTOOLISON 7 /* tool was turned on */
121
122 typedef struct Iubchange
123 {
124 INTBIG change; /* type of change */
125 void *object; /* object that is being changed */
126 void *parameter; /* parameter that is being changed */
127 struct Iubchange *nextubchange;
128 } UBCHANGE;
129 static UBCHANGE *us_ubchangefree = NOUBCHANGE;
130 static UBCHANGE *us_ubchanges = NOUBCHANGE;
131
132 static NODEPROTO *us_layouttextprim;
133 static INTBIG *us_printcolordata = 0;
134
135 /* prototypes for local routines */
136 static void us_splitwindownames(CHAR*, CHAR*, CHAR*, CHAR*, CHAR*);
137 static BOOLEAN us_newubchange(INTBIG change, void *object, void *parameter);
138 static void us_freeubchange(UBCHANGE*);
139 static BOOLEAN us_pointonexparc(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, INTBIG x, INTBIG y);
140 static void us_rotatedescriptArb(GEOM *geom, UINTBIG *descript, BOOLEAN invert);
141 static void us_scanquickkeys(POPUPMENU *pm, CHAR **quickkeylist, INTBIG quickkeycount, BOOLEAN *warnofchanges);
142 static void us_layouttextpolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
143 static INTBIG us_inheritaddress(INTBIG addr, INTBIG type, VARIABLE *var);
144 static NODEPROTO *us_findcellinotherlib(NODEPROTO *cell, LIBRARY *lib);
145 static void us_correctxlibref(VARIABLE **firstvar, INTSML *numvar, LIBRARY *oldlib, LIBRARY *newlib);
146 static void us_adjustpopupmenu(POPUPMENU *pm, INTBIG pindex);
147 static void us_inheritexportattributes(PORTPROTO *pp, NODEINST *ni, NODEPROTO *np);
148 static void us_inheritcellattribute(VARIABLE *var, NODEINST *ni, NODEPROTO *np, NODEINST *icon);
149 static void us_advancecircuittext(CHAR *search, INTBIG bits);
150 static INTBIG us_stringinstring(CHAR *string, CHAR *search, INTBIG bits);
151
152 /*
153 * Routine to free all memory associated with this module.
154 */
us_freemiscmemory(void)155 void us_freemiscmemory(void)
156 {
157 UBCHANGE *ubc;
158
159 if (us_printcolordata != 0)
160 efree((CHAR *)us_printcolordata);
161 while(us_ubchanges != NOUBCHANGE)
162 {
163 ubc = us_ubchanges;
164 us_ubchanges = ubc->nextubchange;
165 us_freeubchange(ubc);
166 }
167 while(us_ubchangefree != NOUBCHANGE)
168 {
169 ubc = us_ubchangefree;
170 us_ubchangefree = ubc->nextubchange;
171 efree((CHAR *)ubc);
172 }
173 }
174
175 /*
176 * initialization routine to bind keys and buttons to functions
177 * returns true upon error
178 */
us_initialbinding(void)179 BOOLEAN us_initialbinding(void)
180 {
181 REGISTER INTBIG i, k, menusave, menux, menuy;
182 INTBIG j;
183 CHAR si[50], sj[20], *par[MAXPARS+7];
184 REGISTER CHAR **temp;
185
186 /* make the variables with the bindings */
187 i = maxi(maxi(NUMKEYS, NUMBUTS), INITIALMENUX*INITIALMENUY);
188 temp = (CHAR **)emalloc(i * (sizeof (CHAR *)), el_tempcluster);
189 if (temp == 0) return(TRUE);
190 temp[0] = x_("a/");
191 (void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)temp,
192 VSTRING|VISARRAY|VDONTSAVE|(1<<VLENGTHSH));
193 for(j=0; j<i; j++) temp[j] = x_("");
194 (void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_buttons_key, (INTBIG)temp,
195 VSTRING|VISARRAY|VDONTSAVE|(NUMBUTS<<VLENGTHSH));
196 (void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_menu_key, (INTBIG)temp,
197 VSTRING|VISARRAY|VDONTSAVE|((INITIALMENUX*INITIALMENUY)<<VLENGTHSH));
198 efree((CHAR *)temp);
199
200 /* bind the keys */
201 for(i=0; us_initialkeyboard[i].key != 0; i++)
202 {
203 par[0] = x_("set"); par[1] = x_("key");
204 par[2] = us_initialkeyboard[i].key;
205 par[3] = us_initialkeyboard[i].command;
206 for(j=0; j<us_initialkeyboard[i].count; j++)
207 par[j+4] = us_initialkeyboard[i].args[j];
208 us_bind(us_initialkeyboard[i].count+4, par);
209 }
210
211 /* bind the mouse commands that fit on the mouse */
212 for(i=0; i<buttoncount(); i++)
213 {
214 (void)estrcpy(si, buttonname(i, &j));
215 for(j=0; us_initialbutton[j].but[0] != 0; j++)
216 if (!us_initialbutton[j].used)
217 {
218 for(k=0; k<3; k++)
219 if (namesame(si, us_initialbutton[j].but[k]) == 0)
220 {
221 par[0] = x_("set"); par[1] = x_("button"); par[2] = si;
222 par[3] = us_initialbutton[j].com;
223 for(k=0; k<us_initialbutton[j].count; k++)
224 par[k+4] = us_initialbutton[j].args[k];
225 us_bind(us_initialbutton[j].count+4, par);
226 us_initialbutton[j].used = TRUE;
227 break;
228 }
229 }
230 }
231
232 /* now bind those mouse commands that can't fit on the mouse */
233 for(j=0; us_initialbutton[j].but[0] != 0; j++)
234 if (!us_initialbutton[j].used && *us_initialbutton[j].key != 0)
235 {
236 par[0] = x_("set"); par[1] = x_("key"); par[2] = us_initialbutton[j].key;
237 par[3] = us_initialbutton[j].com;
238 for(k=0; k<us_initialbutton[j].count; k++)
239 par[k+4] = us_initialbutton[j].args[k];
240 us_bind(us_initialbutton[j].count+4, par);
241 }
242
243 /* bind the component menu entries to all "getproto" */
244 if (us_menupos <= 1)
245 {
246 menux = INITIALMENUX;
247 menuy = INITIALMENUY;
248 } else
249 {
250 menux = INITIALMENUY;
251 menuy = INITIALMENUX;
252 }
253 us_setmenusize(menux, menuy, us_menupos, FALSE);
254 menusave = us_tool->toolstate&MENUON; us_tool->toolstate &= ~MENUON;
255 for(i=0; i<(INITIALMENUX*INITIALMENUY); i++)
256 {
257 par[0] = x_("set"); par[1] = x_("menu");
258 (void)esnprintf(si, 50, x_("%ld"), i%INITIALMENUX);
259 (void)esnprintf(sj, 20, x_("%ld"), i/INITIALMENUX);
260 if (us_menupos <= 1)
261 {
262 par[2] = sj; par[3] = si;
263 } else
264 {
265 par[2] = si; par[3] = sj;
266 }
267 par[4] = x_("rem");
268 par[5] = x_("getproto");
269 us_bind(6, par);
270 }
271
272 /* now fill in the "getproto" commands properly */
273 us_setmenunodearcs();
274
275 if (menusave != 0) us_tool->toolstate |= MENUON; else
276 us_tool->toolstate &= ~MENUON;
277 return(FALSE);
278 }
279
280 /*
281 * routine to determine for technology "tech" which node and arc prototypes
282 * have opaque layers and set the bits in the prototype->userbits.
283 * The rules for layer orderings are that the transparent layers
284 * must come first followed by the opaque layers. The field that is
285 * set in the "userbits" is then the index of the first opaque layer.
286 */
us_figuretechopaque(TECHNOLOGY * tech)287 void us_figuretechopaque(TECHNOLOGY *tech)
288 {
289 REGISTER INTBIG j, k;
290 REGISTER NODEPROTO *np;
291 REGISTER ARCPROTO *ap;
292 REGISTER NODEINST *ni;
293 NODEINST node;
294 REGISTER ARCINST *ai;
295 ARCINST arc;
296 static POLYGON *poly = NOPOLYGON;
297
298 /* get polygon */
299 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
300
301 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
302 {
303 if ((np->userbits&NHASOPA) != 0) continue;
304 np->userbits &= ~NHASOPA;
305 ni = &node; initdummynode(ni);
306 ni->proto = np;
307 ni->lowx = np->lowx; ni->highx = np->highx;
308 ni->lowy = np->lowy; ni->highy = np->highy;
309 j = nodepolys(ni, 0, NOWINDOWPART);
310 for(k=0; k<j; k++)
311 {
312 shapenodepoly(ni, k, poly);
313 if (poly->desc->bits == LAYERN) continue;
314 if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
315 {
316 /* transparent layer found, make sure it is at start */
317 if ((np->userbits&NHASOPA) != 0)
318 ttyputerr(_("%s: node %s has layers out of order!"), tech->techname, np->protoname);
319 continue;
320 }
321
322 /* opaque layer found, mark its index if it is the first */
323 if ((np->userbits&NHASOPA) == 0)
324 np->userbits = (np->userbits & ~NFIRSTOPA) | (k << NFIRSTOPASH);
325 np->userbits |= NHASOPA;
326 }
327 }
328 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
329 {
330 ap->userbits &= ~AHASOPA;
331 ai = &arc; initdummyarc(ai);
332 ai->proto = ap;
333 ai->userbits = ISDIRECTIONAL;
334 j = arcpolys(ai, NOWINDOWPART);
335 for(k=0; k<j; k++)
336 {
337 shapearcpoly(ai, k, poly);
338 if (poly->desc->bits == LAYERN) continue;
339 if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
340 {
341 /* transparent layer found, make sure it is at start */
342 if ((ap->userbits&AHASOPA) != 0)
343 ttyputerr(_("Arc %s:%s has layers out of order!"), tech->techname, ap->protoname);
344 continue;
345 }
346
347 /* opaque layer found, mark its index if it is the first */
348 if ((ap->userbits&AHASOPA) == 0)
349 ap->userbits = (ap->userbits & ~AFIRSTOPA) | (k << AFIRSTOPASH);
350 ap->userbits |= AHASOPA;
351 }
352 }
353 }
354
355 /*
356 * Routine to recompute the "NINVISIBLE" and "AINVISIBLE" bits on node and arc protos
357 * according to whether or not all layers are invisible.
358 */
us_figuretechselectability(void)359 void us_figuretechselectability(void)
360 {
361 REGISTER INTBIG j, k;
362 REGISTER TECHNOLOGY *tech;
363 REGISTER NODEPROTO *np;
364 REGISTER ARCPROTO *ap;
365 REGISTER NODEINST *ni;
366 NODEINST node;
367 REGISTER ARCINST *ai;
368 ARCINST arc;
369 static POLYGON *poly = NOPOLYGON;
370
371 /* get polygon */
372 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
373
374 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
375 {
376 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
377 {
378 np->userbits &= ~NINVISIBLE;
379 ni = &node; initdummynode(ni);
380 ni->proto = np;
381 ni->lowx = np->lowx; ni->highx = np->highx;
382 ni->lowy = np->lowy; ni->highy = np->highy;
383 j = nodepolys(ni, 0, NOWINDOWPART);
384 for(k=0; k<j; k++)
385 {
386 shapenodepoly(ni, k, poly);
387 if (poly->desc->bits == LAYERN) continue;
388 if ((poly->desc->colstyle&INVISIBLE) == 0) break;
389 }
390 if (k >= j) np->userbits |= NINVISIBLE;
391 }
392 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
393 {
394 ap->userbits &= ~AINVISIBLE;
395 ai = &arc; initdummyarc(ai);
396 ai->proto = ap;
397 j = arcpolys(ai, NOWINDOWPART);
398 for(k=0; k<j; k++)
399 {
400 shapearcpoly(ai, k, poly);
401 if (poly->desc->bits == LAYERN) continue;
402 if ((poly->desc->colstyle&INVISIBLE) == 0) break;
403 }
404 if (k >= j) ap->userbits |= AINVISIBLE;
405 }
406 }
407 }
408
409 /*
410 * routine to examine the current window structure and fit their sizes
411 * to the screen. If "placemenu" is nonzero, set the menu location too.
412 */
us_windowfit(WINDOWFRAME * whichframe,BOOLEAN placemenu,INTBIG scaletofit)413 void us_windowfit(WINDOWFRAME *whichframe, BOOLEAN placemenu, INTBIG scaletofit)
414 {
415 REGISTER WINDOWPART *w;
416 REGISTER INTBIG lowy, highy, ulx, uhx, uly, uhy, drawlx, drawhx, drawly, drawhy,
417 mtop, mleft, alltext;
418 INTBIG swid, shei, mwid, mhei, pwid;
419 REGISTER INTBIG i, total, newwid, newhei, offx, offy;
420 INTBIG slx, shx, sly, shy;
421 REGISTER WINDOWFRAME *frame;
422 REGISTER VARIABLE *var;
423 COMMANDBINDING commandbinding;
424
425 for(frame = el_firstwindowframe; frame != NOWINDOWFRAME; frame = frame->nextwindowframe)
426 {
427 if (whichframe != NOWINDOWFRAME && whichframe != frame) continue;
428 getwindowframesize(frame, &swid, &shei);
429 lowy = 0; highy = shei - 1;
430
431 /* presume that there is no menu */
432 drawlx = 0; drawhx = swid-1;
433 drawly = lowy; drawhy = highy;
434
435 /* if there is a menu, figure it out */
436 if ((us_tool->toolstate&MENUON) != 0)
437 {
438 /* see if the menu is all text */
439 alltext = 0;
440 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
441 if (var != NOVARIABLE)
442 {
443 total = us_menux*us_menuy;
444 for(i=0; i<total; i++)
445 {
446 us_parsebinding(((CHAR **)var->addr)[i], &commandbinding);
447 if (*commandbinding.command == 0 || commandbinding.nodeglyph != NONODEPROTO ||
448 commandbinding.arcglyph != NOARCPROTO)
449 {
450 us_freebindingparse(&commandbinding);
451 break;
452 }
453 us_freebindingparse(&commandbinding);
454 }
455 if (i >= total) alltext = 1;
456 }
457 if (us_menuframe == NOWINDOWFRAME)
458 {
459 /* menus come out of the only editor window */
460 switch (us_menupos)
461 {
462 case 0: /* menu at top */
463 us_menuxsz = us_menuysz = swid / us_menux;
464 us_menulx = (swid - us_menux*us_menuxsz)/2;
465 us_menuhx = swid - us_menulx;
466 us_menuly = highy - us_menuysz*us_menuy;
467 us_menuhy = highy;
468 drawlx = 0; drawhx = swid-1;
469 drawly = lowy; drawhy = us_menuly-1;
470 break;
471 case 1: /* menu at bottom */
472 us_menuxsz = us_menuysz = swid / us_menux;
473 us_menulx = (swid - us_menux*us_menuxsz)/2;
474 us_menuhx = swid - us_menulx;
475 us_menuly = lowy;
476 us_menuhy = lowy + us_menuysz * us_menuy;
477 drawlx = 0; drawhx = swid-1;
478 drawly = us_menuhy+1; drawhy = highy;
479 break;
480 case 2: /* menu on left */
481 us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
482
483 /* if the menu is all text, allow nonsquare menus */
484 if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
485
486 us_menulx = 0;
487 us_menuhx = us_menuxsz * us_menux;
488 us_menuly = ((highy-lowy) - us_menuy*us_menuysz)/2 + lowy;
489 us_menuhy = us_menuly + us_menuy*us_menuysz;
490 drawlx = us_menuhx+1; drawhx = swid-1;
491 drawly = lowy; drawhy = highy;
492 break;
493 case 3: /* menu on right */
494 us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
495
496 /* if the menu is all text, allow nonsquare menus */
497 if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
498
499 us_menulx = swid - us_menuxsz * us_menux;
500 us_menuhx = swid-1;
501 us_menuly = ((highy-lowy) - us_menuy*us_menuysz)/2 + lowy;
502 us_menuhy = us_menuly + us_menuy*us_menuysz;
503 drawlx = 0; drawhx = us_menulx-1;
504 drawly = lowy; drawhy = highy;
505 break;
506 }
507 } else
508 {
509 /* floating menu window */
510 if (frame == us_menuframe && placemenu)
511 {
512 getpaletteparameters(&mwid, &mhei, &pwid);
513 switch (us_menupos)
514 {
515 case 0: /* menu at top */
516 case 1: /* menu at bottom */
517 us_menuxsz = us_menuysz = mwid / us_menux;
518 if (us_menuysz * us_menuy > pwid)
519 us_menuxsz = us_menuysz = pwid / us_menuy;
520 us_menulx = 0;
521 us_menuhx = us_menux * us_menuxsz;
522 us_menuly = 0;
523 us_menuhy = us_menuy * us_menuysz;
524 mleft = 0;
525 if (us_menupos == 0)
526 {
527 /* menu on the top */
528 mtop = 1;
529 } else
530 {
531 /* menu on the bottom */
532 mtop = mhei - us_menuysz*us_menuy - 3;
533 }
534 break;
535
536 case 2: /* menu on left */
537 case 3: /* menu on right */
538 /* determine size of menu entries */
539 us_menuxsz = us_menuysz = mhei / us_menuy;
540 if (us_menuxsz * us_menux > pwid)
541 us_menuxsz = us_menuysz = pwid / us_menux;
542
543 /* if the menu is all text, allow nonsquare menus */
544 if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
545
546 /* compute menu parameters */
547 us_menuly = 0;
548 us_menuhy = us_menuy * us_menuysz;
549 us_menulx = 0;
550 us_menuhx = us_menux * us_menuxsz;
551 mtop = 0;
552 if (us_menupos == 2)
553 {
554 /* menu on the left */
555 mleft = 0;
556 } else
557 {
558 /* menu on the right */
559 mleft = mwid - us_menuxsz * us_menux - 2;
560 }
561 break;
562 default:
563 mtop = mleft = 0;
564 }
565 sizewindowframe(us_menuframe, us_menuhx-us_menulx, us_menuhy-us_menuly);
566 movewindowframe(us_menuframe, mleft, mtop);
567 }
568 }
569 }
570
571 /* now fit the windows in the remaining space */
572 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
573 {
574 /* this window must be on the right frame */
575 if (w->frame != frame) continue;
576
577 /* entire window is handled simply */
578 if (estrcmp(w->location, x_("entire")) == 0)
579 {
580 ulx = drawlx; uhx = drawhx;
581 uly = drawly; uhy = drawhy;
582 } else if (estrncmp(w->location, x_("top"), 3) == 0)
583 {
584 ulx = drawlx; uhx = drawhx;
585 uly = (drawhy-drawly)*(100-w->vratio)/100;
586 uhy = drawhy;
587 } else if (estrncmp(w->location, x_("bot"), 3) == 0)
588 {
589 ulx = drawlx; uhx = drawhx;
590 uly = drawly; uhy = (drawhy-drawly)*w->vratio/100;
591 } else if (estrcmp(w->location, x_("left")) == 0)
592 {
593 ulx = drawlx; uhx = (drawhx-drawlx)*w->hratio/100;
594 uly = drawly; uhy = drawhy;
595 } else if (estrcmp(w->location, x_("right")) == 0)
596 {
597 ulx = (drawhx-drawlx)*(100-w->hratio)/100;
598 uhx = drawhx;
599 uly = drawly; uhy = drawhy;
600 } else ulx = uhx = uly = uhy = 0;
601
602 /* subdivide for fractions of half windows */
603 i = 3;
604 while (w->location[i] == '-')
605 {
606 switch (w->location[i+1])
607 {
608 case 'l': uhx = (uhx - ulx)*w->hratio/100; break;
609 case 'r': ulx = (uhx - ulx)*(100-w->hratio)/100; break;
610 case 't': uly = (uhy - uly)*(100-w->vratio)/100; break;
611 case 'b': uhy = (uhy - uly)*w->vratio/100; break;
612 }
613 i += 2;
614 }
615 if (estrcmp(w->location, x_("entire")) != 0)
616 {
617 ulx++; uhx--; uly++; uhy--;
618 }
619
620 /* make sure window has some size */
621 if (ulx >= uhx) uhx = ulx + 1;
622 if (uly >= uhy) uhy = uly + 1;
623
624 /* make room for border if in a mode */
625 if ((w->state&WINDOWMODE) != 0)
626 {
627 ulx += WINDOWMODEBORDERSIZE; uhx -= WINDOWMODEBORDERSIZE;
628 uly += WINDOWMODEBORDERSIZE; uhy -= WINDOWMODEBORDERSIZE;
629 }
630
631 /* make room for sliders if a display window */
632 if ((w->state&WINDOWTYPE) == DISPWINDOW)
633 {
634 uhx -= DISPLAYSLIDERSIZE;
635 uly += DISPLAYSLIDERSIZE;
636 }
637 if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
638 {
639 ulx += DISPLAYSLIDERSIZE;
640 uly += DISPLAYSLIDERSIZE;
641 }
642
643 /* update if the extent changed */
644 if (w->uselx != ulx || w->usehx != uhx ||
645 w->usely != uly || w->usehy != uhy)
646 {
647 /* set the window extent */
648 w->uselx = ulx; w->usehx = uhx;
649 w->usely = uly; w->usehy = uhy;
650
651 /* now adjust the database extents of the window */
652 slx = w->screenlx; shx = w->screenhx;
653 sly = w->screenly; shy = w->screenhy;
654 if (scaletofit > 0)
655 {
656 us_squarescreen(w, NOWINDOWPART, FALSE, &slx, &shx, &sly, ­, 0);
657 } else if (scaletofit < 0)
658 {
659 newwid = (INTBIG)(((float)(uhx - ulx)) / w->scalex + 0.5);
660 newhei = (INTBIG)(((float)(uhy - uly)) / w->scaley + 0.5);
661 offx = newwid - (shx - slx);
662 offy = newhei - (shy - sly);
663 slx -= offx / 2;
664 shx = slx + newwid;
665 sly -= offy / 2;
666 shy = sly + newhei;
667 }
668 w->screenlx = slx; w->screenhx = shx;
669 w->screenly = sly; w->screenhy = shy;
670 computewindowscale(w);
671 }
672 }
673 }
674 }
675
676 /*
677 * routine to adjust the actual drawing area of window "win" to account for
678 * the appearance or disappearance of the red simulation border
679 */
us_setwindowmode(WINDOWPART * win,INTBIG oldstate,INTBIG newstate)680 void us_setwindowmode(WINDOWPART *win, INTBIG oldstate, INTBIG newstate)
681 {
682 if ((oldstate&WINDOWMODE) != 0)
683 {
684 /* was in a mode: remove border */
685 win->uselx -= WINDOWMODEBORDERSIZE; win->usehx += WINDOWMODEBORDERSIZE;
686 win->usely -= WINDOWMODEBORDERSIZE; win->usehy += WINDOWMODEBORDERSIZE;
687 }
688 if ((newstate&WINDOWMODE) != 0)
689 {
690 /* now in a mode: add border */
691 win->uselx += WINDOWMODEBORDERSIZE; win->usehx -= WINDOWMODEBORDERSIZE;
692 win->usely += WINDOWMODEBORDERSIZE; win->usehy -= WINDOWMODEBORDERSIZE;
693 }
694 win->state = newstate;
695 }
696
697 /*
698 * routine to tell the names of the windows that result when the window
699 * with name "w" is split. The strings "hwind1" and "hwind2" are filled
700 * with the names if the window is split horizontally. The strings "vwind1"
701 * and "vwind2" are filled with the names if the window is split verticaly.
702 */
us_splitwindownames(CHAR * w,CHAR * hwind1,CHAR * hwind2,CHAR * vwind1,CHAR * vwind2)703 void us_splitwindownames(CHAR *w, CHAR *hwind1, CHAR *hwind2, CHAR *vwind1, CHAR *vwind2)
704 {
705 REGISTER INTBIG i;
706
707 if (estrcmp(w, x_("entire")) == 0)
708 {
709 (void)estrcpy(hwind1, x_("top")); (void)estrcpy(hwind2, x_("bottom"));
710 (void)estrcpy(vwind1, x_("left")); (void)estrcpy(vwind2, x_("right"));
711 return;
712 }
713 if (estrcmp(w, x_("top")) == 0)
714 {
715 (void)estrcpy(hwind1, x_("top-l")); (void)estrcpy(hwind2, x_("top-r"));
716 (void)estrcpy(vwind1, x_("")); (void)estrcpy(vwind2, x_(""));
717 return;
718 }
719 if (estrcmp(w, x_("bottom")) == 0)
720 {
721 (void)estrcpy(hwind1, x_("bot-l")); (void)estrcpy(hwind2, x_("bot-r"));
722 (void)estrcpy(vwind1, x_("")); (void)estrcpy(vwind2, x_(""));
723 return;
724 }
725 if (estrcmp(w, x_("left")) == 0)
726 {
727 (void)estrcpy(vwind1, x_("top-l")); (void)estrcpy(vwind2, x_("bot-l"));
728 (void)estrcpy(hwind1, x_("")); (void)estrcpy(hwind2, x_(""));
729 return;
730 }
731 if (estrcmp(w, x_("right")) == 0)
732 {
733 (void)estrcpy(vwind1, x_("top-r")); (void)estrcpy(vwind2, x_("bot-r"));
734 (void)estrcpy(hwind1, x_("")); (void)estrcpy(hwind2, x_(""));
735 return;
736 }
737 (void)estrcpy(hwind1, w); (void)estrcpy(hwind2, w);
738 (void)estrcpy(vwind1, w); (void)estrcpy(vwind2, w);
739 i = w[estrlen(w)-1];
740 if (i == 'l' || i == 'r')
741 {
742 (void)estrcat(vwind1, x_("-t")); (void)estrcat(vwind2, x_("-b"));
743 (void)estrcpy(hwind1, x_("")); (void)estrcpy(hwind2, x_(""));
744 } else
745 {
746 (void)estrcat(hwind1, x_("-l")); (void)estrcat(hwind2, x_("-r"));
747 (void)estrcpy(vwind1, x_("")); (void)estrcpy(vwind2, x_(""));
748 }
749 }
750
751 /*
752 * Routine to create a new window with whatever method is available on the
753 * current machine (new window in its own frame or just a split of the current
754 * window). If "orientation" is 1, make it a horizontal window; if 2,
755 * make it vertical. Otherwise use any configuration. Prints an error and
756 * returns NOWINDOWPART on failure.
757 */
us_wantnewwindow(INTBIG orientation)758 WINDOWPART *us_wantnewwindow(INTBIG orientation)
759 {
760 REGISTER WINDOWPART *w;
761 WINDOWFRAME *wf;
762
763 if (graphicshas(CANUSEFRAMES) && orientation == 0)
764 {
765 /* create a default window space on this frame */
766 wf = newwindowframe(FALSE, 0);
767 if (wf == NOWINDOWFRAME) wf = getwindowframe(FALSE);
768 w = newwindowpart(x_("entire"), NOWINDOWPART);
769 if (w == NOWINDOWPART)
770 {
771 us_abortcommand(_("Cannot create new window"));
772 return(NOWINDOWPART);
773 }
774 w->frame = wf;
775 w->buttonhandler = DEFAULTBUTTONHANDLER;
776 w->charhandler = DEFAULTCHARHANDLER;
777 w->changehandler = DEFAULTCHANGEHANDLER;
778 w->termhandler = DEFAULTTERMHANDLER;
779 w->redisphandler = DEFAULTREDISPHANDLER;
780 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
781 VWINDOWPART|VDONTSAVE);
782
783 /* now draw everything */
784 us_drawmenu(0, wf);
785 return(w);
786 }
787
788 if (us_needwindow()) return(NOWINDOWPART);
789 w = us_splitcurrentwindow(orientation, FALSE, 0, 50);
790 return(w);
791 }
792
793 /*
794 * routine to split the current window into two windows. If "splitkey" is zero,
795 * nature of split is unspecified. If "splitkey" is 1, split horizontally
796 * (only when splitting top window). If "splitkey" is 2, split vertically.
797 * If "fillboth" is true, fill both windows with the contents of the
798 * old one. Otherwise, leave the new current window empty. Returns the address
799 * of the new current window, and the other half in "other" (NOWINDOWPART on error).
800 * The partitions are divided according to "percentage" of coverage.
801 */
us_splitcurrentwindow(INTBIG splitkey,BOOLEAN fillboth,WINDOWPART ** other,INTBIG percentage)802 WINDOWPART *us_splitcurrentwindow(INTBIG splitkey, BOOLEAN fillboth, WINDOWPART **other,
803 INTBIG percentage)
804 {
805 CHAR wind1[40], wind2[40], vwind1[40], vwind2[40];
806 REGISTER CHAR *win1, *win2;
807 WINDOWPART windowsave;
808 REGISTER WINDOWPART *w2, *w3, *w, *retwin;
809 REGISTER INTBIG curwx, curwy, horizsplit;
810 REGISTER INTBIG x, y, l;
811 REGISTER NODEPROTO *np;
812
813 /* figure out new name of windows */
814 if (other != 0) *other = NOWINDOWPART;
815 horizsplit = 1;
816 us_splitwindownames(el_curwindowpart->location, wind1, wind2, vwind1, vwind2);
817
818 /* use the horizontal window split unless there is none */
819 if (*wind1 == 0) win1 = vwind1; else win1 = wind1;
820 if (*wind2 == 0) win2 = vwind2; else win2 = wind2;
821
822 /* special case when splitting just one window: which way to split */
823 if (estrcmp(el_curwindowpart->location, x_("entire")) == 0)
824 {
825 /* see if a "horizontal" or "vertical" parameter was given */
826 if (splitkey == 2)
827 {
828 /* vertical window specified explicitly */
829 win1 = vwind1; win2 = vwind2;
830 horizsplit = 0;
831 } else if (splitkey == 0)
832 {
833 /* make a guess about window splitting */
834 switch (el_curwindowpart->state&WINDOWTYPE)
835 {
836 case EXPLORERWINDOW:
837 win1 = vwind2; win2 = vwind1;
838 horizsplit = 0;
839 break;
840 default:
841 np = el_curwindowpart->curnodeproto;
842 if (np != NONODEPROTO)
843 {
844 curwx = el_curwindowpart->usehx - el_curwindowpart->uselx;
845 curwy = el_curwindowpart->usehy - el_curwindowpart->usely;
846 x = np->highx - np->lowx;
847 y = np->highy - np->lowy;
848 l = el_curlib->lambda[el_curtech->techindex];
849 if (muldiv(x, curwy/2, l) + muldiv(y, curwx, l) >=
850 muldiv(x, curwy, l) + muldiv(y, curwx/2, l))
851 {
852 /* vertical window makes more sense */
853 win1 = vwind1; win2 = vwind2;
854 horizsplit = 0;
855 }
856 }
857 break;
858 }
859 }
860 } else
861 {
862 l = estrlen(wind1) - 1;
863 if (wind1[l] == 'l' || wind1[l] == 'r') horizsplit = 0;
864 }
865
866 /* turn off object and window highlighting */
867 us_pushhighlight();
868 us_clearhighlightcount();
869 w = el_curwindowpart;
870 copywindowpart(&windowsave, el_curwindowpart);
871
872 /* make two new windows in "w2" and "w3" to replace "el_curwindowpart" */
873 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)NOWINDOWPART,
874 VWINDOWPART|VDONTSAVE);
875 startobjectchange((INTBIG)us_tool, VTOOL);
876 w2 = newwindowpart(win1, w);
877 w3 = newwindowpart(win2, w);
878 if (w2 == NOWINDOWPART || w3 == NOWINDOWPART)
879 {
880 ttyputnomemory();
881 return(NOWINDOWPART);
882 }
883
884 /* make sure the split is even in the split direction */
885 if (horizsplit != 0)
886 {
887 w2->vratio = percentage;
888 w3->vratio = 100 - percentage;
889 } else
890 {
891 w2->hratio = percentage;
892 w3->hratio = 100 - percentage;
893 }
894
895 /* if splitting an editor window, move the editor and explorer structure */
896 if ((w->state&WINDOWTYPE) == TEXTWINDOW || (w->state&WINDOWTYPE) == POPTEXTWINDOW)
897 {
898 (void)setval((INTBIG)w3, VWINDOWPART, x_("editor"), (INTBIG)w->editor, VADDRESS);
899 (void)setval((INTBIG)w, VWINDOWPART, x_("editor"), -1, VADDRESS);
900 }
901 if ((w->state&WINDOWTYPE) == EXPLORERWINDOW)
902 {
903 (void)setval((INTBIG)w3, VWINDOWPART, x_("expwindow"), (INTBIG)w->expwindow, VADDRESS);
904 (void)setval((INTBIG)w, VWINDOWPART, x_("expwindow"), -1, VADDRESS);
905 }
906
907 /* free the current window */
908 killwindowpart(w);
909
910 /* zap the returned window if both are not to be filled */
911 retwin = w2;
912 if (other != 0) *other = w3;
913 if ((windowsave.state&WINDOWTYPE) != DISPWINDOW) fillboth = FALSE;
914 if (!fillboth)
915 {
916 retwin->state = (retwin->state & ~(WINDOWTYPE|GRIDON|WINDOWMODE)) | DISPWINDOW;
917 retwin->buttonhandler = DEFAULTBUTTONHANDLER;
918 retwin->charhandler = DEFAULTCHARHANDLER;
919 retwin->changehandler = DEFAULTCHANGEHANDLER;
920 retwin->termhandler = DEFAULTTERMHANDLER;
921 retwin->redisphandler = DEFAULTREDISPHANDLER;
922 retwin->curnodeproto = NONODEPROTO;
923 retwin->editor = NOEDITOR;
924 retwin->expwindow = (void *)-1;
925 }
926
927 /* set the window extents */
928 us_windowfit(w2->frame, FALSE, 1);
929
930 /* use former window for scaling */
931 w = &windowsave;
932
933 /* windows might have got bigger: see if grid can be drawn */
934 if ((w2->state&GRIDTOOSMALL) != 0) us_gridset(w2, GRIDON);
935 if ((w2->state&GRIDTOOSMALL) != 0) us_gridset(w3, GRIDON);
936
937 endobjectchange((INTBIG)us_tool, VTOOL);
938 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w2,
939 VWINDOWPART|VDONTSAVE);
940
941 /* restore all highlighting */
942 us_pophighlight(FALSE);
943 return(retwin);
944 }
945
946 /*
947 * routine to kill a window. Kills the current window if "thisw" is true.
948 * Kills the other window, making the current one larger, if "thisw" is false.
949 */
us_killcurrentwindow(BOOLEAN thisw)950 void us_killcurrentwindow(BOOLEAN thisw)
951 {
952 REGISTER WINDOWPART *w1, *w2, *wnew, *w;
953 WINDOWPART windowsave;
954 REGISTER INTBIG windows;
955 CHAR windcomb[40], windother[40], wind1[40], wind2[40], vwind1[40], vwind2[40];
956 REGISTER WINDOWFRAME *wf;
957
958 w1 = el_curwindowpart;
959
960 /* if this is the only partition, see if the window frame can be deleted */
961 if (estrcmp(w1->location, x_("entire")) == 0)
962 {
963 if (!graphicshas(CANHAVENOWINDOWS))
964 {
965 /* disallow deletion if this is the last window */
966 windows = 0;
967 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
968 if (wf->floating == 0) windows++;
969 if (windows <= 1)
970 {
971 ttyputerr(_("Sorry, cannot delete the last window"));
972 return;
973 }
974 }
975 if (graphicshas(CANUSEFRAMES))
976 {
977 /* save highlighting and turn it off */
978 us_pushhighlight();
979 us_clearhighlightcount();
980
981 /* kill the window */
982 startobjectchange((INTBIG)us_tool, VTOOL);
983 us_killwindowpickanother(w1);
984 endobjectchange((INTBIG)us_tool, VTOOL);
985
986 /* restore highlighting */
987 us_pophighlight(FALSE);
988 return;
989 }
990 }
991
992 /* figure out which other window to merge this with */
993 if (estrcmp(w1->location, x_("top")) == 0 || estrcmp(w1->location, x_("bottom")) == 0 ||
994 estrcmp(w1->location, x_("left")) == 0 || estrcmp(w1->location, x_("right")) == 0)
995 (void)estrcpy(windcomb, x_("entire")); else
996 {
997 (void)estrcpy(windcomb, w1->location);
998 windcomb[estrlen(windcomb)-2] = 0;
999 if (estrcmp(windcomb, x_("bot")) == 0) (void)estrcpy(windcomb, x_("bottom"));
1000 }
1001
1002 /* see what divisions this higher window typically makes */
1003 us_splitwindownames(windcomb, wind1, wind2, vwind1, vwind2);
1004
1005 /* look for the other window of the typical split */
1006 (void)estrcpy(windother, x_(""));
1007 if (estrcmp(wind2, w1->location) == 0) (void)estrcpy(windother, wind1);
1008 if (estrcmp(wind1, w1->location) == 0) (void)estrcpy(windother, wind2);
1009 if (estrcmp(vwind2, w1->location) == 0) (void)estrcpy(windother, vwind1);
1010 if (estrcmp(vwind1, w1->location) == 0) (void)estrcpy(windother, vwind2);
1011
1012 /* see if there is a window with that name */
1013 for(w2 = el_topwindowpart; w2 != NOWINDOWPART; w2 = w2->nextwindowpart)
1014 if (estrcmp(w2->location, windother) == 0) break;
1015
1016 /* if the other window can't be found, try one more hack */
1017 if (w2 == NOWINDOWPART)
1018 {
1019 /* special case for quadrants that get split strangely */
1020 if ((estrncmp(w1->location, x_("top-"), 4) == 0 || estrncmp(w1->location, x_("bot-"), 4) == 0) &&
1021 estrlen(w1->location) == 5)
1022 {
1023 if (*w1->location == 't') (void)estrcpy(windother, x_("bot-l")); else
1024 (void)estrcpy(windother, x_("top-l"));
1025 windother[4] = w1->location[4];
1026 if (windother[4] == 'l') (void)estrcpy(windcomb, x_("left")); else
1027 (void)estrcpy(windcomb, x_("right"));
1028 for(w2 = el_topwindowpart; w2 != NOWINDOWPART; w2 = w2->nextwindowpart)
1029 if (estrcmp(w2->location, windother) == 0) break;
1030 }
1031 }
1032 if (w2 == NOWINDOWPART)
1033 {
1034 us_abortcommand(_("Cannot kill the current window"));
1035 return;
1036 }
1037
1038 /* if the other window is to be killed, swap them */
1039 if (!thisw)
1040 {
1041 w = w1; w1 = w2; w2 = w;
1042 }
1043
1044 /* turn off highlighting */
1045 us_pushhighlight();
1046 us_clearhighlightcount();
1047
1048 /* create a new window to cover both */
1049 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)NOWINDOWPART,
1050 VWINDOWPART|VDONTSAVE);
1051 startobjectchange((INTBIG)us_tool, VTOOL);
1052 wnew = newwindowpart(windcomb, w2);
1053 if (wnew == NOWINDOWPART) return;
1054
1055 /* save information from the old window */
1056 copywindowpart(&windowsave, w2);
1057
1058 /* if merging an editor or explorer window, move the structure */
1059 if ((w2->state&WINDOWTYPE) == TEXTWINDOW || (w2->state&WINDOWTYPE) == POPTEXTWINDOW)
1060 {
1061 (void)setval((INTBIG)wnew, VWINDOWPART, x_("editor"), (INTBIG)w2->editor, VADDRESS);
1062 (void)setval((INTBIG)w2, VWINDOWPART, x_("editor"), -1, VADDRESS);
1063 }
1064 if ((w2->state&WINDOWTYPE) == EXPLORERWINDOW)
1065 {
1066 (void)setval((INTBIG)wnew, VWINDOWPART, x_("expwindow"), (INTBIG)w2->expwindow, VADDRESS);
1067 (void)setval((INTBIG)w2, VWINDOWPART, x_("expwindow"), -1, VADDRESS);
1068 }
1069
1070 /* remove old windows */
1071 killwindowpart(w1);
1072 killwindowpart(w2);
1073
1074 /* set window extents */
1075 us_windowfit(wnew->frame, FALSE, 1);
1076
1077 /* use former window for scaling */
1078 w = &windowsave;
1079
1080 /* window might have got bigger: see if grid can be drawn */
1081 if ((wnew->state&GRIDTOOSMALL) != 0) us_gridset(wnew, GRIDON);
1082
1083 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)wnew->curnodeproto,
1084 VNODEPROTO);
1085 endobjectchange((INTBIG)us_tool, VTOOL);
1086 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)wnew,
1087 VWINDOWPART|VDONTSAVE);
1088
1089 /* restore highlighting */
1090 us_pophighlight(FALSE);
1091 }
1092
1093 /*
1094 * routine to determine whether the division of window "w1" into windows
1095 * "w2" and "w3" can be done with block transfer. This requires that
1096 * the windows have identical aspect ratios in one axis
1097 */
us_windowcansplit(WINDOWPART * w1,WINDOWPART * w2,WINDOWPART * w3)1098 BOOLEAN us_windowcansplit(WINDOWPART *w1, WINDOWPART *w2, WINDOWPART *w3)
1099 {
1100 REGISTER INTBIG new2l, new2h;
1101
1102 if (w2->usehx-w2->uselx == w3->usehx-w3->uselx &&
1103 w2->screenhx-w2->screenlx == w3->screenhx-w3->screenlx)
1104 {
1105 /* first see if it is an obvious split */
1106 if (w2->usehx-w2->uselx == w1->usehx-w1->uselx &&
1107 w2->screenhx-w2->screenlx == w1->screenhx-w1->screenlx)
1108 return(TRUE);
1109
1110 /* now see if it is a relative fit for changed window size */
1111 new2l = muldiv(((w1->usehx-w1->uselx) - (w2->usehx-w2->uselx))/2,
1112 w1->screenhx-w1->screenlx, w1->usehx-w1->uselx) + w1->screenlx;
1113 new2h = w2->screenlx + muldiv(w2->usehx-w2->uselx,
1114 w1->screenhx-w1->screenlx, w1->usehx-w1->uselx);
1115 if (new2l == w2->screenlx && new2h == w2->screenhx) return(TRUE);
1116 }
1117 if (w2->usehy-w2->usely == w3->usehy-w3->usely &&
1118 w2->screenhy-w2->screenly == w3->screenhy-w3->screenly)
1119 {
1120 /* first see if it is an obvious split */
1121 if (w2->usehy-w2->usely == w1->usehy-w1->usely &&
1122 w2->screenhy-w2->screenly == w1->screenhy-w1->screenly)
1123 return(TRUE);
1124
1125 /* now see if it is a relative fit for changed window size */
1126 new2l = muldiv(((w1->usehy-w1->usely) - (w2->usehy-w2->usely))/2,
1127 w1->screenhy-w1->screenly, w1->usehy-w1->usely) + w1->screenly;
1128 new2h = w2->screenly + muldiv(w2->usehy-w2->usely,
1129 w1->screenhy-w1->screenly, w1->usehy-w1->usely);
1130 if (new2l == w2->screenly && new2h == w2->screenhy) return(TRUE);
1131 }
1132 return(FALSE);
1133 }
1134
1135 /*
1136 * routine to ensure that the cell "np"
1137 * is displayed somewhere on the screen. If not, it
1138 * is displayed in the current window
1139 */
us_ensurewindow(NODEPROTO * np)1140 void us_ensurewindow(NODEPROTO *np)
1141 {
1142 REGISTER WINDOWPART *w;
1143 CHAR *par[1];
1144
1145 /* if nothing specified, quit */
1146 if (np == NONODEPROTO) return;
1147
1148 /* see if that cell is in a window */
1149 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1150 if (w->curnodeproto == np) break;
1151
1152 /* if the cell is not in a window, put it there */
1153 if (w == NOWINDOWPART)
1154 {
1155 par[0] = describenodeproto(np);
1156 us_editcell(1, par);
1157 us_endchanges(NOWINDOWPART);
1158 }
1159 }
1160
1161 /*
1162 * Routine to kill window "w" and set the current window to some other.
1163 */
us_killwindowpickanother(WINDOWPART * w)1164 void us_killwindowpickanother(WINDOWPART *w)
1165 {
1166 REGISTER NODEPROTO *np;
1167
1168 killwindowpart(w);
1169
1170 if (w != el_curwindowpart) return;
1171
1172 w = el_topwindowpart;
1173 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1174 VWINDOWPART|VDONTSAVE);
1175 if (w != NOWINDOWPART) np = w->curnodeproto; else np = NONODEPROTO;
1176 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
1177 }
1178
1179 /*
1180 * routine to adjust the coordinate values in (x, y) from screen space to
1181 * the space of window "w"
1182 */
us_scaletowindow(INTBIG * x,INTBIG * y,WINDOWPART * w)1183 void us_scaletowindow(INTBIG *x, INTBIG *y, WINDOWPART *w)
1184 {
1185 *x = muldiv(*x - w->uselx, w->screenhx - w->screenlx, w->usehx - w->uselx) + w->screenlx;
1186 *y = muldiv(*y - w->usely, w->screenhy - w->screenly, w->usehy - w->usely) + w->screenly;
1187 }
1188
1189 /******************** TEXT EDITING ********************/
1190
1191 EDITORTABLE us_editortable[] =
1192 {
1193 /* the point-and-click editor */
1194 {x_("Point-and-click"),
1195 us_editpacmakeeditor, us_editpacterminate, us_editpactotallines, us_editpacgetline,
1196 us_editpacaddline, us_editpacreplaceline, us_editpacdeleteline, us_editpachighlightline,
1197 us_editpacsuspendgraphics, us_editpacresumegraphics,
1198 us_editpacwritetextfile, us_editpacreadtextfile,
1199 us_editpaceditorterm, us_editpacshipchanges, us_editpacgotchar,
1200 us_editpaccut, us_editpaccopy, us_editpacpaste,
1201 us_editpacundo, us_editpacsearch, us_editpacpan},
1202
1203 /* the EMACS-like editor */
1204 {x_("EMACS-like"),
1205 us_editemacsmakeeditor, us_editemacsterminate, us_editemacstotallines, us_editemacsgetline,
1206 us_editemacsaddline, us_editemacsreplaceline, us_editemacsdeleteline, us_editemacshighlightline,
1207 us_editemacssuspendgraphics, us_editemacsresumegraphics,
1208 us_editemacswritetextfile, us_editemacsreadtextfile,
1209 us_editemacseditorterm, us_editemacsshipchanges, us_editemacsgotchar,
1210 us_editemacscut, us_editemacscopy, us_editemacspaste,
1211 us_editemacsundo, us_editemacssearch, us_editemacspan},
1212
1213 {NULL,
1214 NULL, NULL, NULL, NULL,
1215 NULL, NULL, NULL, NULL,
1216 NULL, NULL,
1217 NULL, NULL,
1218 NULL, NULL, NULL,
1219 NULL, NULL, NULL,
1220 NULL, NULL, NULL}
1221 };
1222
1223 /*
1224 * dispatch routine to describe this editor
1225 */
us_describeeditor(CHAR ** name)1226 void us_describeeditor(CHAR **name)
1227 {
1228 *name = us_editortable[us_currenteditor].editorname;
1229 }
1230
1231 /*
1232 * dispatch routine for creating a new editor
1233 */
us_makeeditor(WINDOWPART * oriwin,CHAR * header,INTBIG * chars,INTBIG * lines)1234 WINDOWPART *us_makeeditor(WINDOWPART *oriwin, CHAR *header, INTBIG *chars, INTBIG *lines)
1235 {
1236 return((*us_editortable[us_currenteditor].makeeditor)(oriwin,header,chars,lines));
1237 }
1238
1239 /*
1240 * dispatch routine to return the total number of valid lines in the edit buffer
1241 */
us_totallines(WINDOWPART * win)1242 INTBIG us_totallines(WINDOWPART *win)
1243 {
1244 return((*us_editortable[us_currenteditor].totallines)(win));
1245 }
1246
1247 /*
1248 * dispatch routine to get the string on line "lindex" (0 based). A negative line
1249 * returns the current line. Returns -1 if the index is beyond the file limit
1250 */
us_getline(WINDOWPART * win,INTBIG lindex)1251 CHAR *us_getline(WINDOWPART *win, INTBIG lindex)
1252 {
1253 return((*us_editortable[us_currenteditor].getline)(win, lindex));
1254 }
1255
1256 /*
1257 * dispatch routine to add line "str" to the text cell to become line "lindex"
1258 */
us_addline(WINDOWPART * win,INTBIG lindex,CHAR * str)1259 void us_addline(WINDOWPART *win, INTBIG lindex, CHAR *str)
1260 {
1261 (*us_editortable[us_currenteditor].addline)(win, lindex, str);
1262 }
1263
1264 /*
1265 * dispatch routine to replace the line number "lindex" with the string "str".
1266 */
us_replaceline(WINDOWPART * win,INTBIG lindex,CHAR * str)1267 void us_replaceline(WINDOWPART *win, INTBIG lindex, CHAR *str)
1268 {
1269 (*us_editortable[us_currenteditor].replaceline)(win, lindex, str);
1270 }
1271
1272 /*
1273 * dispatch routine to delete line number "lindex"
1274 */
us_deleteline(WINDOWPART * win,INTBIG lindex)1275 void us_deleteline(WINDOWPART *win, INTBIG lindex)
1276 {
1277 (*us_editortable[us_currenteditor].deleteline)(win, lindex);
1278 }
1279
1280 /*
1281 * dispatch routine to highlight lines "lindex" to "hindex" in the text window
1282 */
us_highlightline(WINDOWPART * win,INTBIG lindex,INTBIG hindex)1283 void us_highlightline(WINDOWPART *win, INTBIG lindex, INTBIG hindex)
1284 {
1285 (*us_editortable[us_currenteditor].highlightline)(win, lindex, hindex);
1286 }
1287
1288 /*
1289 * dispatch routine to stop the graphic display of changes (for batching)
1290 */
us_suspendgraphics(WINDOWPART * win)1291 void us_suspendgraphics(WINDOWPART *win)
1292 {
1293 (*us_editortable[us_currenteditor].suspendgraphics)(win);
1294 }
1295
1296 /*
1297 * dispatch routine to restart the graphic display of changes and redisplay (for batching)
1298 */
us_resumegraphics(WINDOWPART * win)1299 void us_resumegraphics(WINDOWPART *win)
1300 {
1301 (*us_editortable[us_currenteditor].resumegraphics)(win);
1302 }
1303
1304 /*
1305 * dispatch routine to write the text file to "file"
1306 */
us_writetextfile(WINDOWPART * win,CHAR * file)1307 void us_writetextfile(WINDOWPART *win, CHAR *file)
1308 {
1309 (*us_editortable[us_currenteditor].writetextfile)(win, file);
1310 }
1311
1312 /*
1313 * dispatch routine to read the text file "file"
1314 */
us_readtextfile(WINDOWPART * win,CHAR * file)1315 void us_readtextfile(WINDOWPART *win, CHAR *file)
1316 {
1317 (*us_editortable[us_currenteditor].readtextfile)(win, file);
1318 }
1319
1320 /*
1321 * dispatch routine to get the next character
1322 */
us_editorterm(WINDOWPART * w)1323 void us_editorterm(WINDOWPART *w)
1324 {
1325 (*us_editortable[us_currenteditor].editorterm)(w);
1326 }
1327
1328 /*
1329 * dispatch routine to force changes from the editor in window "w"
1330 */
us_shipchanges(WINDOWPART * w)1331 void us_shipchanges(WINDOWPART *w)
1332 {
1333 (*us_editortable[us_currenteditor].shipchanges)(w);
1334 }
1335
1336 /*
1337 * dispatch routine to get the next character
1338 */
us_gotchar(WINDOWPART * w,INTSML i,INTBIG special)1339 BOOLEAN us_gotchar(WINDOWPART *w, INTSML i, INTBIG special)
1340 {
1341 return((*us_editortable[us_currenteditor].gotchar)(w, i, special));
1342 }
1343
1344 /*
1345 * dispatch routine to cut text
1346 */
us_cuttext(WINDOWPART * w)1347 void us_cuttext(WINDOWPART *w)
1348 {
1349 (*us_editortable[us_currenteditor].cut)(w);
1350 }
1351
1352 /*
1353 * dispatch routine to copy text
1354 */
us_copytext(WINDOWPART * w)1355 void us_copytext(WINDOWPART *w)
1356 {
1357 (*us_editortable[us_currenteditor].copy)(w);
1358 }
1359
1360 /*
1361 * dispatch routine to paste text
1362 */
us_pastetext(WINDOWPART * w)1363 void us_pastetext(WINDOWPART *w)
1364 {
1365 (*us_editortable[us_currenteditor].paste)(w);
1366 }
1367
1368 /*
1369 * dispatch routine to undo text changes
1370 */
us_undotext(WINDOWPART * w)1371 void us_undotext(WINDOWPART *w)
1372 {
1373 (*us_editortable[us_currenteditor].undo)(w);
1374 }
1375
1376 /*
1377 * dispatch routine to search and/or replace text. If "replace" is nonzero, this is
1378 * a replace. The meaning of "bits" is as follows:
1379 * 1 search from top
1380 * 2 replace all
1381 * 4 case sensitive
1382 * 8 search upwards
1383 */
us_searchtext(WINDOWPART * w,CHAR * str,CHAR * replace,INTBIG bits)1384 void us_searchtext(WINDOWPART *w, CHAR *str, CHAR *replace, INTBIG bits)
1385 {
1386 (*us_editortable[us_currenteditor].search)(w, str, replace, bits);
1387 }
1388
1389 /*
1390 * dispatch routine to pan the text window by (dx, dy)
1391 */
us_pantext(WINDOWPART * w,INTBIG dx,INTBIG dy)1392 void us_pantext(WINDOWPART *w, INTBIG dx, INTBIG dy)
1393 {
1394 (*us_editortable[us_currenteditor].pan)(w, dx, dy);
1395 }
1396
1397 /*
1398 * support routine to allocate a new editor from the pool (if any) or memory
1399 * routine returns NOEDITOR upon error
1400 */
us_alloceditor(void)1401 EDITOR *us_alloceditor(void)
1402 {
1403 REGISTER EDITOR *e;
1404
1405 e = (EDITOR *)emalloc((sizeof (EDITOR)), us_tool->cluster);
1406 if (e == 0) return(NOEDITOR);
1407 e->state = 0;
1408 e->nexteditor = NOEDITOR;
1409 e->editobjvar = NOVARIABLE;
1410 return(e);
1411 }
1412
1413 /*
1414 * support routine to return editor "e" to the pool of free editors
1415 */
us_freeeditor(EDITOR * e)1416 void us_freeeditor(EDITOR *e)
1417 {
1418 if (e == 0 || e == NOEDITOR) return;
1419 efree(e->header);
1420 (*us_editortable[us_currenteditor].terminate)(e);
1421 efree((CHAR *)e);
1422 }
1423
1424 /******************** SPECIAL WINDOW HANDLERS ********************/
1425
1426 /*
1427 * routine to accept changes in an edit window examining a variable. If "nature" is:
1428 * REPLACETEXTLINE line "changed" goes from "oldline" to "newline"
1429 * DELETETEXTLINE line "changed deleted (was "oldline")
1430 * INSERTTEXTLINE line "newline" inserted before line "changed"
1431 * REPLACEALLTEXT "changed" lines "newline" replace all text
1432 */
us_varchanges(WINDOWPART * w,INTBIG nature,CHAR * oldline,CHAR * newline,INTBIG changed)1433 void us_varchanges(WINDOWPART *w, INTBIG nature, CHAR *oldline, CHAR *newline, INTBIG changed)
1434 {
1435 REGISTER INTBIG j, l, save;
1436 REGISTER BOOLEAN res;
1437 REGISTER INTBIG newval, i, len;
1438 REGISTER CHAR **newlist, *pt;
1439 float newfloat;
1440 REGISTER EDITOR *ed;
1441 Q_UNUSED( oldline );
1442
1443 ed = w->editor;
1444 if (ed->editobjvar == NOVARIABLE) return;
1445 if ((ed->editobjvar->type&VCANTSET) != 0)
1446 {
1447 ttyputerr(M_("This variable cannot be changed"));
1448 ed->editobjvar = NOVARIABLE;
1449 return;
1450 }
1451 len = getlength(ed->editobjvar);
1452
1453 /* when replacing the entire text, reduce to individual calls */
1454 if (nature == REPLACEALLTEXT)
1455 {
1456 newlist = (CHAR **)newline;
1457 for(i=0; i<changed; i++)
1458 us_varchanges(w, REPLACETEXTLINE, x_(""), newlist[i], i);
1459 for(i=len-1; i>=changed; i--)
1460 us_varchanges(w, DELETETEXTLINE, x_(""), x_(""), i);
1461 return;
1462 }
1463
1464 if (nature == DELETETEXTLINE && len == 1)
1465 {
1466 /* delete of last entry: instead, replace it with a null */
1467 newline = x_("");
1468 nature = REPLACETEXTLINE;
1469 } else if (nature == REPLACETEXTLINE && changed >= len)
1470 {
1471 /* change of line beyond end: instead make an insert */
1472 nature = INSERTTEXTLINE;
1473 }
1474
1475 /* disallow deletions and insertions if the number of lines is fixed */
1476 if (nature == DELETETEXTLINE || nature == INSERTTEXTLINE)
1477 {
1478 if ((ed->state&LINESFIXED) != 0) return;
1479 }
1480
1481 /* get the value */
1482 j = 0;
1483 save = 0;
1484 newval = 0;
1485 if (nature == REPLACETEXTLINE || nature == INSERTTEXTLINE)
1486 {
1487 pt = newline;
1488 while (*pt == ' ' || *pt == '\t') pt++;
1489 switch (ed->editobjvar->type&VTYPE)
1490 {
1491 case VINTEGER:
1492 case VSHORT:
1493 case VBOOLEAN:
1494 case VADDRESS:
1495 newval = myatoi(pt);
1496 break;
1497 case VFRACT:
1498 newval = atofr(pt);
1499 break;
1500 case VFLOAT:
1501 case VDOUBLE:
1502 newfloat = (float)eatof(pt);
1503 newval = castint(newfloat);
1504 break;
1505 case VSTRING:
1506 j = l = estrlen(newline);
1507 if (estrcmp(&newline[l-3], x_(" */")) == 0)
1508 {
1509 for(j = l-5; j >= 0; j--)
1510 if (estrncmp(&newline[j], x_("/* "), 3) == 0) break;
1511 while (j > 0 && newline[j-1] == ' ') j--;
1512 if (j < 0) j = l;
1513 }
1514 save = newline[j];
1515 newline[j] = 0;
1516 newval = (INTBIG)newline;
1517 break;
1518 default:
1519 ttyputmsg(_("Cannot update this type of variable (0%o)"), ed->editobjvar->type);
1520 break;
1521 }
1522 }
1523
1524 /* make the change */
1525 res = TRUE;
1526 switch (nature)
1527 {
1528 case REPLACETEXTLINE:
1529 if (changed < 0 || changed >= len) return;
1530 res = setind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1531 break;
1532 case DELETETEXTLINE:
1533 if (changed < 0 || changed >= len) return;
1534 res = delind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed);
1535 break;
1536 case INSERTTEXTLINE:
1537 if (changed <= 0 || changed > len) return;
1538 res = insind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1539
1540 /* why is this next line necessary? */
1541 ed->editobjvar = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
1542 break;
1543 }
1544
1545 /* clean-up string if one was passed */
1546 if ((nature == REPLACETEXTLINE || nature == INSERTTEXTLINE) &&
1547 (ed->editobjvar->type&VTYPE) == VSTRING) newline[j] = (CHAR)save;
1548
1549 if (res)
1550 {
1551 ttyputerr(_("Error changing variable: ignoring further changes"));
1552 ed->editobjvar = NOVARIABLE;
1553 }
1554 }
1555
1556 /*
1557 * routine to accept changes in an edit window examining a textual cell. If "nature" is:
1558 * REPLACETEXTLINE line "changed" goes from "oldline" to "newline"
1559 * DELETETEXTLINE line "changed" deleted (was "oldline")
1560 * INSERTTEXTLINE line "newline" inserted before line "changed"
1561 * REPLACEALLTEXT "changed" lines "newline" replace all text
1562 */
us_textcellchanges(WINDOWPART * w,INTBIG nature,CHAR * oldline,CHAR * newline,INTBIG changed)1563 void us_textcellchanges(WINDOWPART *w, INTBIG nature, CHAR *oldline, CHAR *newline, INTBIG changed)
1564 {
1565 REGISTER INTBIG len;
1566 REGISTER BOOLEAN res;
1567 REGISTER EDITOR *ed;
1568 Q_UNUSED( oldline );
1569
1570 ed = w->editor;
1571 if (ed->editobjvar == NOVARIABLE) return;
1572 if ((ed->editobjvar->type&VTYPE) != VSTRING) return;
1573 if ((ed->editobjvar->type&VCANTSET) != 0) return;
1574 len = getlength(ed->editobjvar);
1575
1576 if (nature == DELETETEXTLINE && len == 1)
1577 {
1578 /* delete of last line: instead, replace it with a blank */
1579 newline = x_("");
1580 nature = REPLACETEXTLINE;
1581 } else if (nature == REPLACETEXTLINE && changed >= len)
1582 {
1583 /* change of line one beyond end: instead make an insert */
1584 nature = INSERTTEXTLINE;
1585 }
1586
1587 res = TRUE;
1588 switch (nature)
1589 {
1590 case REPLACETEXTLINE:
1591 if (changed < 0 || changed >= len) return;
1592 res = setindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_cell_message_key,
1593 changed, (INTBIG)newline);
1594 break;
1595 case DELETETEXTLINE:
1596 if (changed < 0 || changed >= len) return;
1597 res = delindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_cell_message_key,
1598 changed);
1599 break;
1600 case INSERTTEXTLINE:
1601 res = insindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_cell_message_key,
1602 changed, (INTBIG)newline);
1603 break;
1604 case REPLACEALLTEXT:
1605 if (setvalkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_cell_message_key,
1606 (INTBIG)newline, VSTRING | VISARRAY | (changed << VLENGTHSH)) != NOVARIABLE)
1607 res = FALSE;
1608 break;
1609 }
1610
1611 if (res)
1612 {
1613 ttyputerr(_("Error changing variable: ignoring further changes"));
1614 ed->editobjvar = NOVARIABLE;
1615 }
1616 }
1617
1618 /*
1619 * private character handler for the text window. This routine normally
1620 * passes all commands to the editor's character handler. However, it
1621 * interprets M(=) which is for editing the cell on the current line
1622 */
us_celledithandler(WINDOWPART * w,INTSML ch,INTBIG special)1623 BOOLEAN us_celledithandler(WINDOWPART *w, INTSML ch, INTBIG special)
1624 {
1625 CHAR *newpar[2], *str;
1626 REGISTER INTBIG i;
1627 REGISTER BOOLEAN meta;
1628 REGISTER EDITOR *ed;
1629 extern INTBIG us_lastemacschar;
1630
1631 /* the EMACS text editor must be running */
1632 us_describeeditor(&str);
1633 if (namesame(str, x_("emacs")) != 0) return(us_gotchar(w, ch, special));
1634
1635 /* see if the meta key is held down (serious black magic) */
1636 meta = FALSE;
1637 if ((special&ACCELERATORDOWN) != 0) meta = TRUE;
1638 if ((us_lastemacschar&2) != 0) meta = TRUE;
1639
1640 /* pass character on to the editor if not M(=) */
1641 if (!meta || ch != '=') return(us_gotchar(w, ch, special));
1642
1643 /* M(=) typed: parse current line to edit named cell */
1644 ed = w->editor;
1645 (void)allocstring(&str, us_getline(w, ed->curline), el_tempcluster);
1646
1647 /* first drop everything past the first space character */
1648 for(i=0; str[i] != 0; i++) if (str[i] == ' ') break;
1649 if (str[i] != 0) str[i] = 0;
1650
1651 if (str[0] == 0) ttyputerr(_("No cell specified on this line")); else
1652 {
1653 /* issue the "editcell" command */
1654 newpar[0] = x_("editcell");
1655 newpar[1] = str;
1656 telltool(us_tool, 2, newpar);
1657 setactivity(_("Cell Selection"));
1658 }
1659
1660 /* clean up */
1661 efree(str);
1662 return(FALSE);
1663 }
1664
1665 /******************** COMMAND SUPPORT ********************/
1666
us_demandxy(INTBIG * x,INTBIG * y)1667 BOOLEAN us_demandxy(INTBIG *x, INTBIG *y)
1668 {
1669 BOOLEAN ret;
1670
1671 ret = getxy(x, y);
1672 if (ret) ttyputmsg(_("Cursor must be in an editing window"));
1673 return(ret);
1674 }
1675
1676 static INTBIG us_curx, us_cury;
1677
1678 /*
1679 * routine to get the co-ordinates of the cursor into the reference parameters
1680 * "x" and "y". If "GOTXY" is set in the global variable "us_state" then
1681 * this has already been done. The routine returns true if there is not a
1682 * valid cursor position.
1683 */
getxy(INTBIG * x,INTBIG * y)1684 BOOLEAN getxy(INTBIG *x, INTBIG *y)
1685 {
1686 INTBIG gx, gy;
1687 REGISTER BOOLEAN ret;
1688
1689 if ((us_state&GOTXY) == 0)
1690 {
1691 readtablet(&gx, &gy);
1692 ret = us_setxy(gx, gy);
1693 } else ret = FALSE;
1694 *x = us_curx;
1695 *y = us_cury;
1696 return(ret);
1697 }
1698
1699 /*
1700 * routine to take the values (realx, realy) from the tablet and store
1701 * them in the variables (us_curx, us_cury) which are in design-space
1702 * co-ordinates. "GOTXY" in the global variable "us_state" is set to indicate
1703 * that the co-ordinates are valid. The current window is set according
1704 * to the cursor position. The routine returns true if the position
1705 * is not in a window.
1706 */
us_setxy(INTBIG x,INTBIG y)1707 BOOLEAN us_setxy(INTBIG x, INTBIG y)
1708 {
1709 REGISTER WINDOWPART *w;
1710 REGISTER WINDOWFRAME *wf;
1711
1712 us_curx = x; us_cury = y;
1713
1714 /* figure out which window it is in */
1715 wf = getwindowframe(TRUE);
1716 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1717 {
1718 if (w->frame != wf) continue;
1719 if (x >= w->uselx && x <= w->usehx && y >= w->usely && y <= w->usehy)
1720 {
1721 /* make this window the current one */
1722 if (w != el_curwindowpart)
1723 {
1724 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1725 VWINDOWPART|VDONTSAVE);
1726 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
1727 (INTBIG)w->curnodeproto, VNODEPROTO);
1728 }
1729 us_scaletowindow(&us_curx, &us_cury, w);
1730 xform(us_curx, us_cury, &us_curx, &us_cury, w->intocell);
1731 us_state |= GOTXY;
1732 return(FALSE);
1733 }
1734 }
1735 return(TRUE);
1736 }
1737
1738 /*
1739 * routine to force the parameters "xcur" and "ycur" to align to the
1740 * nearest "alignment" units
1741 */
gridalign(INTBIG * xcur,INTBIG * ycur,INTBIG alignmentdivisor,NODEPROTO * cell)1742 void gridalign(INTBIG *xcur, INTBIG *ycur, INTBIG alignmentdivisor, NODEPROTO *cell)
1743 {
1744 INTBIG otheralign;
1745 REGISTER INTBIG val, alignment;
1746 REGISTER TECHNOLOGY *tech;
1747
1748 tech = NOTECHNOLOGY;
1749 if (cell != NONODEPROTO) tech = cell->tech;
1750 if (tech == NOTECHNOLOGY) tech = el_curtech;
1751 alignment = muldiv(us_alignment_ratio, el_curlib->lambda[tech->techindex], WHOLE) /
1752 alignmentdivisor;
1753 val = us_alignvalue(*xcur, alignment, &otheralign);
1754 if (abs(*xcur-val) < abs(*xcur-otheralign)) *xcur = val; else
1755 *xcur = otheralign;
1756 val = us_alignvalue(*ycur, alignment, &otheralign);
1757 if (abs(*ycur-val) < abs(*ycur-otheralign)) *ycur = val; else
1758 *ycur = otheralign;
1759 }
1760
1761 /*
1762 * routine to return "value", aligned to the nearest "alignment" units.
1763 * The next closest alignment value (if "value" is not on the grid)
1764 * is returned in "otheralign".
1765 */
us_alignvalue(INTBIG value,INTBIG alignment,INTBIG * otheralign)1766 INTBIG us_alignvalue(INTBIG value, INTBIG alignment, INTBIG *otheralign)
1767 {
1768 REGISTER INTBIG i, v1, v2;
1769 REGISTER INTBIG sign;
1770
1771 /* determine the sign of the value */
1772 if (value < 0) { sign = -1; value = -value; } else sign = 1;
1773
1774 /* compute the two aligned values */
1775 if (alignment == 0) v1 = value; else
1776 v1 = value / alignment * alignment;
1777 if (v1 == value) v2 = value; else v2 = v1 + alignment;
1778 v1 *= sign; v2 *= sign;
1779
1780 /* make sure "v1" is the closest aligned value */
1781 if (abs(v1-value) > abs(v2-value)) { i = v1; v1 = v2; v2 = i; }
1782
1783 *otheralign = v2;
1784 return(v1);
1785 }
1786
1787 /* routine to ensure that a current window exists */
us_needwindow(void)1788 BOOLEAN us_needwindow(void)
1789 {
1790 if (el_curwindowpart != NOWINDOWPART) return(FALSE);
1791 us_abortcommand(_("No current window"));
1792 return(TRUE);
1793 }
1794
1795 /* routine to ensure that a cell exists in the current window */
us_needcell(void)1796 NODEPROTO *us_needcell(void)
1797 {
1798 REGISTER NODEPROTO *np;
1799
1800 np = getcurcell();
1801 if (np != NONODEPROTO) return(np);
1802 if (el_curwindowpart == NOWINDOWPART)
1803 {
1804 us_abortcommand(_("No current window (select one with Cells/Edit Cell)"));
1805 } else
1806 {
1807 if ((us_tool->toolstate&NODETAILS) != 0)
1808 us_abortcommand(_("No cell in this window (select one with Cells/Edit Cell)")); else
1809 us_abortcommand(_("No cell in this window (select one with '-editcell')"));
1810 }
1811 return(NONODEPROTO);
1812 }
1813
1814 /*
1815 * Routine to ensure that node "item" can be modified in cell "cell".
1816 * If "item" is NONODEINST, check that cell "cell" can be modified at all.
1817 * Returns true if the edit cannot be done.
1818 */
us_cantedit(NODEPROTO * cell,NODEINST * item,BOOLEAN giveerror)1819 BOOLEAN us_cantedit(NODEPROTO *cell, NODEINST *item, BOOLEAN giveerror)
1820 {
1821 REGISTER INTBIG count;
1822 extern COMCOMP us_noyesalwaysp;
1823 CHAR *pars[5];
1824 REGISTER void *infstr;
1825
1826 /* if an instance is specified, check it */
1827 if (item != NONODEINST)
1828 {
1829 if ((item->userbits&NILOCKED) != 0)
1830 {
1831 if (!giveerror) return(TRUE);
1832 infstr = initinfstr();
1833 formatinfstr(infstr, _("Changes to locked node %s are disallowed. Change anyway?"),
1834 describenodeinst(item));
1835 count = ttygetparam(returninfstr(infstr), &us_noyesalwaysp, 5, pars);
1836 if (count <= 0 || namesamen(pars[0], x_("no"), estrlen(pars[0])) == 0) return(TRUE);
1837 if (namesamen(pars[0], x_("always"), estrlen(pars[0])) == 0)
1838 (void)setval((INTBIG)item, VNODEINST, x_("userbits"),
1839 item->userbits & ~NILOCKED, VINTEGER);
1840 }
1841 if (item->proto->primindex != 0)
1842 {
1843 /* see if a primitive is locked */
1844 if ((item->proto->userbits&LOCKEDPRIM) != 0 &&
1845 (us_useroptions&NOPRIMCHANGES) != 0)
1846 {
1847 if (!giveerror) return(TRUE);
1848 infstr = initinfstr();
1849 formatinfstr(infstr, _("Changes to locked primitives (such as %s) are disallowed. Change anyway?"),
1850 describenodeinst(item));
1851 count = ttygetparam(returninfstr(infstr), &us_noyesalwaysp, 5, pars);
1852 if (count <= 0 || namesamen(pars[0], x_("no"), estrlen(pars[0])) == 0) return(TRUE);
1853 if (namesamen(pars[0], x_("always"), estrlen(pars[0])) == 0)
1854 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
1855 us_useroptions & ~NOPRIMCHANGES, VINTEGER);
1856 }
1857 } else
1858 {
1859 /* see if this type of cell is locked */
1860 if ((cell->userbits&NPILOCKED) != 0)
1861 {
1862 if (!giveerror) return(TRUE);
1863 infstr = initinfstr();
1864 formatinfstr(infstr, _("Instances in cell %s are locked. You cannot move %s. Change anyway?"),
1865 describenodeproto(cell), describenodeinst(item));
1866 count = ttygetparam(returninfstr(infstr), &us_noyesalwaysp, 5, pars);
1867 if (count <= 0 || namesamen(pars[0], x_("no"), estrlen(pars[0])) == 0) return(TRUE);
1868 if (namesamen(pars[0], x_("always"), estrlen(pars[0])) == 0)
1869 setval((INTBIG)cell, VNODEPROTO, x_("userbits"),
1870 cell->userbits & ~NPILOCKED, VINTEGER);
1871 }
1872 }
1873 }
1874
1875 /* check for general changes to the cell */
1876 if ((cell->userbits&NPLOCKED) != 0)
1877 {
1878 if (!giveerror) return(TRUE);
1879 infstr = initinfstr();
1880 formatinfstr(infstr, _("Changes to cell %s are locked. Change anyway?"),
1881 describenodeproto(cell));
1882 count = ttygetparam(returninfstr(infstr), &us_noyesalwaysp, 5, pars);
1883 if (count <= 0 || namesamen(pars[0], x_("no"), estrlen(pars[0])) == 0) return(TRUE);
1884 if (namesamen(pars[0], x_("always"), estrlen(pars[0])) == 0)
1885 setval((INTBIG)cell, VNODEPROTO, x_("userbits"), cell->userbits & ~NPLOCKED, VINTEGER);
1886 }
1887 return(FALSE);
1888 }
1889
1890 /*
1891 * routine to determine the proper position of the cursor given that
1892 * it must adjust to the nearest "angle" tenth-degree radial coming out of
1893 * the point (tx,ty) and that it is currently at (nx, ny). The
1894 * adjusted point is placed into (fx, fy) and the proper radial starting
1895 * point in "poly" is placed in (tx, ty).
1896 */
us_getslide(INTBIG angle,INTBIG tx,INTBIG ty,INTBIG nx,INTBIG ny,INTBIG * fx,INTBIG * fy)1897 void us_getslide(INTBIG angle, INTBIG tx, INTBIG ty, INTBIG nx, INTBIG ny, INTBIG *fx,
1898 INTBIG *fy)
1899 {
1900 REGISTER INTBIG ang;
1901 INTBIG ix, iy;
1902
1903 /* if angle is unconstrained, use the exact cursor position */
1904 if (angle <= 0)
1905 {
1906 *fx = nx; *fy = ny;
1907 return;
1908 }
1909
1910 /* check all permissable angles */
1911 for(ang = 0; ang < 3600; ang += angle)
1912 {
1913 /* get close point to (nx,ny) on "ang" tenth-degree radial from (tx,ty) */
1914 (void)intersect(tx, ty, ang, nx, ny, (ang+900)%3600, &ix, &iy);
1915
1916 /* accumulate the intersection closest to the cursor */
1917 if (ang != 0 && abs(*fx-nx) + abs(*fy-ny) < abs(ix-nx) + abs(iy-ny)) continue;
1918 *fx = ix; *fy = iy;
1919 }
1920 }
1921
1922 /*
1923 * routine to convert command interpreter letter "letter" to the full
1924 * variable name on the user tool object
1925 */
us_commandvarname(INTSML letter)1926 CHAR *us_commandvarname(INTSML letter)
1927 {
1928 static CHAR varname[20];
1929
1930 if (isupper(letter))
1931 {
1932 (void)estrcpy(varname, x_("USER_local_capX"));
1933 varname[14] = tolower(letter);
1934 } else
1935 {
1936 (void)estrcpy(varname, x_("USER_local_X"));
1937 varname[11] = (CHAR)letter;
1938 }
1939 return(varname);
1940 }
1941
1942 /*
1943 * routine to parse the variable path in "str" and return the object address
1944 * and type on which this variable resides along with the variable name.
1945 * The object address and type are placed in "objaddr" and "objtype";
1946 * the variable name is placed in "varname". "comvar" is set to true
1947 * if the variable is a command-interpreter variable (as opposed to a
1948 * database variable). If an array index specification is given (a "[]")
1949 * then the index value is returned in "aindex" (otherwise the value is set
1950 * to -1). The routine returns true if the variable path is invalid.
1951 */
us_getvar(CHAR * str,INTBIG * objaddr,INTBIG * objtype,CHAR ** varname,BOOLEAN * comvar,INTBIG * aindex)1952 BOOLEAN us_getvar(CHAR *str, INTBIG *objaddr, INTBIG *objtype, CHAR **varname,
1953 BOOLEAN *comvar, INTBIG *aindex)
1954 {
1955 REGISTER INTBIG i;
1956 static CHAR fullvarname[50];
1957
1958 /* see if an array index is specified */
1959 *aindex = -1;
1960 i = estrlen(str);
1961 if (str[i-1] == ']') for(i--; i >= 0; i--) if (str[i] == '[')
1962 {
1963 *aindex = myatoi(&str[i+1]);
1964 break;
1965 }
1966
1967 /* see if this is a command interpreter variable */
1968 *comvar = FALSE;
1969 if (str[1] == 0 || str[1] == '[')
1970 {
1971 if (str[0] >= 'a' && str[0] <= 'z') *comvar = TRUE;
1972 if (str[0] >= 'A' && str[0] <= 'Z') *comvar = TRUE;
1973 }
1974
1975 /* replace the actual name for command interpreter variables */
1976 if (*comvar)
1977 {
1978 (void)esnprintf(fullvarname, 50, x_("tool:user.%s"), us_commandvarname(str[0]));
1979 str = fullvarname;
1980 }
1981
1982 /* pick apart the variable path */
1983 return(us_evaluatevariable(str, objaddr, objtype, varname));
1984 }
1985
1986 #define LINELIMIT 300
1987
1988 /*
1989 * Routine to dump the copyright information to file "f". Each line of the copyright
1990 * is prefixed by "prefix" and postfixed by "postfix".
1991 */
us_emitcopyright(FILE * f,CHAR * prefix,CHAR * postfix)1992 void us_emitcopyright(FILE *f, CHAR *prefix, CHAR *postfix)
1993 {
1994 REGISTER VARIABLE *var;
1995 REGISTER FILE *io;
1996 CHAR *dummy, buffer[LINELIMIT];
1997
1998 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_copyright_file_key);
1999 if (var == NOVARIABLE) return;
2000 io = xopen((CHAR *)var->addr, el_filetypetext, el_libdir, &dummy);
2001 if (io == 0) return;
2002 for(;;)
2003 {
2004 if (xfgets(buffer, LINELIMIT, io)) break;
2005 fprintf(f, x_("%s%s%s\n"), prefix, buffer, postfix);
2006 }
2007 xclose(io);
2008 }
2009
2010 /******************** QUICK-KEY BINDING ********************/
2011
2012 /*
2013 * Routine to find the entry in the key binding variable ("USER_binding_keys")
2014 * that corresponds to key "key", special code "special". Returns negative if
2015 * the key is not in the variable. If the key is found, the binding string
2016 * is returned in "binding".
2017 */
us_findboundkey(INTSML key,INTBIG special,CHAR ** binding)2018 INTBIG us_findboundkey(INTSML key, INTBIG special, CHAR **binding)
2019 {
2020 REGISTER INTBIG i, len;
2021 INTSML boundkey;
2022 INTBIG boundspecial;
2023 REGISTER VARIABLE *var;
2024 REGISTER CHAR *thisbinding, *pt;
2025
2026 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2027 if (var == NOVARIABLE) return(-1);
2028 len = getlength(var);
2029 pt = NOSTRING;
2030 for(i=0; i<len; i++)
2031 {
2032 thisbinding = ((CHAR **)var->addr)[i];
2033 pt = us_getboundkey(thisbinding, &boundkey, &boundspecial);
2034 if (pt == 0) continue;
2035 if (us_samekey(key, special, boundkey, boundspecial)) break;
2036 }
2037 if (i >= len) return(-1);
2038 *binding = pt;
2039 return(i);
2040 }
2041
2042 /*
2043 * Routine to set the binding of key "key", special code "special" to the string
2044 * "binding". If "quietly" is true, do this without change control.
2045 */
us_setkeybinding(CHAR * binding,INTSML key,INTBIG special,BOOLEAN quietly)2046 void us_setkeybinding(CHAR *binding, INTSML key, INTBIG special, BOOLEAN quietly)
2047 {
2048 CHAR *pt, *justone[1], **bigger, *str;
2049 REGISTER INTBIG i, j, len, inserted;
2050 INTSML boundkey;
2051 INTBIG boundspecial;
2052 REGISTER VARIABLE *var;
2053
2054 if ((special&ACCELERATORDOWN) != 0) key = toupper(key);
2055 i = us_findboundkey(key, special, &pt);
2056 if (i >= 0)
2057 {
2058 if (quietly) nextchangequiet();
2059 (void)setindkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, i, (INTBIG)binding);
2060 return;
2061 }
2062
2063 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2064 if (var == NOVARIABLE)
2065 {
2066 justone[0] = binding;
2067 if (quietly) nextchangequiet();
2068 (void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)justone,
2069 VSTRING|VDONTSAVE|VISARRAY|(1<<VLENGTHSH));
2070 } else
2071 {
2072 len = getlength(var);
2073 bigger = (CHAR **)emalloc((len+1) * (sizeof (CHAR *)), el_tempcluster);
2074 if (bigger == 0) return;
2075 j = 0;
2076 inserted = 0;
2077 for(i=0; i<len; i++)
2078 {
2079 pt = ((CHAR **)var->addr)[i];
2080 str = us_getboundkey(pt, &boundkey, &boundspecial);
2081 if (str == 0) continue;
2082 if (namesame(str, x_("command=")) == 0) continue;
2083 if (inserted == 0)
2084 {
2085 if (boundspecial > special || (boundspecial == special && boundkey > key))
2086 {
2087 (void)allocstring(&bigger[j++], binding, el_tempcluster);
2088 inserted = 1;
2089 }
2090 }
2091 (void)allocstring(&bigger[j++], pt, el_tempcluster);
2092 }
2093 if (inserted == 0)
2094 (void)allocstring(&bigger[j++], binding, el_tempcluster);
2095 if (quietly) nextchangequiet();
2096 (void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)bigger,
2097 VSTRING|VDONTSAVE|VISARRAY|(j<<VLENGTHSH));
2098 for(i=0; i<j; i++) efree((CHAR *)bigger[i]);
2099 efree((CHAR *)bigger);
2100 }
2101 }
2102
2103 /*
2104 * Routine to describe key "boundkey"/"boundspecial". Formats it according to
2105 * "readable":
2106 * -1 for end of menu ("/A")
2107 * 0 for beginning of menu storage ("A/")
2108 * 1 for display ("Ctrl-A")
2109 */
us_describeboundkey(INTSML boundkey,INTBIG boundspecial,INTBIG readable)2110 CHAR *us_describeboundkey(INTSML boundkey, INTBIG boundspecial, INTBIG readable)
2111 {
2112 CHAR *acceleratorstring, *acceleratorprefix, *shiftprefix, *accprefix;
2113 REGISTER void *infstr;
2114
2115 getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2116 if (readable > 0)
2117 {
2118 accprefix = acceleratorprefix;
2119 shiftprefix = x_("S-");
2120 } else
2121 {
2122 accprefix = x_("m-");
2123 shiftprefix = x_("S");
2124 }
2125 infstr = initinfstr();
2126 if ((boundspecial&SPECIALKEYDOWN) != 0)
2127 {
2128 if (readable < 0) addtoinfstr(infstr, '/');
2129 switch ((boundspecial&SPECIALKEY)>>SPECIALKEYSH)
2130 {
2131 case SPECIALKEYF1: addstringtoinfstr(infstr, x_("F1")); break;
2132 case SPECIALKEYF2: addstringtoinfstr(infstr, x_("F2")); break;
2133 case SPECIALKEYF3: addstringtoinfstr(infstr, x_("F3")); break;
2134 case SPECIALKEYF4: addstringtoinfstr(infstr, x_("F4")); break;
2135 case SPECIALKEYF5: addstringtoinfstr(infstr, x_("F5")); break;
2136 case SPECIALKEYF6: addstringtoinfstr(infstr, x_("F6")); break;
2137 case SPECIALKEYF7: addstringtoinfstr(infstr, x_("F7")); break;
2138 case SPECIALKEYF8: addstringtoinfstr(infstr, x_("F8")); break;
2139 case SPECIALKEYF9: addstringtoinfstr(infstr, x_("F9")); break;
2140 case SPECIALKEYF10: addstringtoinfstr(infstr, x_("F10")); break;
2141 case SPECIALKEYF11: addstringtoinfstr(infstr, x_("F11")); break;
2142 case SPECIALKEYF12: addstringtoinfstr(infstr, x_("F12")); break;
2143 case SPECIALKEYARROWL:
2144 if ((boundspecial&ACCELERATORDOWN) != 0)
2145 addstringtoinfstr(infstr, accprefix);
2146 if ((boundspecial&SHIFTDOWN) != 0)
2147 addstringtoinfstr(infstr, shiftprefix);
2148 addstringtoinfstr(infstr, x_("LEFT"));
2149 break;
2150 case SPECIALKEYARROWR:
2151 if ((boundspecial&ACCELERATORDOWN) != 0)
2152 addstringtoinfstr(infstr, accprefix);
2153 if ((boundspecial&SHIFTDOWN) != 0)
2154 addstringtoinfstr(infstr, shiftprefix);
2155 addstringtoinfstr(infstr, x_("RIGHT"));
2156 break;
2157 case SPECIALKEYARROWU:
2158 if ((boundspecial&ACCELERATORDOWN) != 0)
2159 addstringtoinfstr(infstr, accprefix);
2160 if ((boundspecial&SHIFTDOWN) != 0)
2161 addstringtoinfstr(infstr, shiftprefix);
2162 addstringtoinfstr(infstr, x_("UP"));
2163 break;
2164 case SPECIALKEYARROWD:
2165 if ((boundspecial&ACCELERATORDOWN) != 0)
2166 addstringtoinfstr(infstr, accprefix);
2167 if ((boundspecial&SHIFTDOWN) != 0)
2168 addstringtoinfstr(infstr, shiftprefix);
2169 addstringtoinfstr(infstr, x_("DOWN"));
2170 break;
2171 }
2172 if (readable == 0) addtoinfstr(infstr, '/');
2173 } else
2174 {
2175 if ((boundspecial&ACCELERATORDOWN) != 0)
2176 {
2177 if (readable < 0) addtoinfstr(infstr, '/');
2178 if (readable > 0) addstringtoinfstr(infstr, accprefix);
2179 if (boundkey > 0 && boundkey < 033) formatinfstr(infstr, x_("^%c"), boundkey + 0100); else
2180 addtoinfstr(infstr, (CHAR)boundkey);
2181 if (readable == 0) addtoinfstr(infstr, '/');
2182 } else
2183 {
2184 if (readable < 0) addtoinfstr(infstr, '\\');
2185 if (boundkey > 0 && boundkey < 033) formatinfstr(infstr, x_("^%c"), boundkey + 0100); else
2186 if (boundkey == 0177) addstringtoinfstr(infstr, x_("DEL")); else
2187 addtoinfstr(infstr, (CHAR)boundkey);
2188 if (readable == 0) addtoinfstr(infstr, '\\');
2189 }
2190 }
2191 return(returninfstr(infstr));
2192 }
2193
2194 /*
2195 * Returns true if the keys "key1"/"special1" is the same as "key2"/"special2"
2196 */
us_samekey(INTSML key1,INTBIG special1,INTSML key2,INTBIG special2)2197 BOOLEAN us_samekey(INTSML key1, INTBIG special1, INTSML key2, INTBIG special2)
2198 {
2199 if (special1 != special2) return(FALSE);
2200 if ((special1&SPECIALKEYDOWN) == 0)
2201 {
2202 if ((special1&ACCELERATORDOWN) != 0)
2203 {
2204 key1 = toupper(key1);
2205 key2 = toupper(key2);
2206 }
2207 if (key1 != key2) return(FALSE);
2208 }
2209 return(TRUE);
2210 }
2211
2212 /*
2213 * Routine to parse the key binding string in "origbinding" (an entry in "USER_binding_keys")
2214 * Extracts the key information from the start of the string and returns it in
2215 * "boundkey" and "boundspecial". Then returns the rest of the string.
2216 * Returns zero on error.
2217 */
us_getboundkey(CHAR * origbinding,INTSML * boundkey,INTBIG * boundspecial)2218 CHAR *us_getboundkey(CHAR *origbinding, INTSML *boundkey, INTBIG *boundspecial)
2219 {
2220 REGISTER CHAR *pt, save, *word;
2221 REGISTER INTBIG offset, len;
2222 CHAR binding[200], *acceleratorstring, *acceleratorprefix;
2223
2224 estrcpy(binding, origbinding);
2225 *boundspecial = 0;
2226 if (binding[0] != 0 && binding[1] == 0)
2227 {
2228 *boundkey = binding[0];
2229 return(x_(""));
2230 }
2231 if (*binding == '/' || *binding == '\\')
2232 {
2233 pt = binding;
2234 save = *pt;
2235 word = binding + 1;
2236 } else
2237 {
2238 for(pt = binding; *pt != 0; pt++)
2239 if (*pt == '/' || *pt == '\\') break;
2240 save = *pt;
2241 *pt = 0;
2242 word = binding;
2243 }
2244
2245 getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2246 len = estrlen(acceleratorprefix);
2247 if (namesamen(word, acceleratorprefix, len) == 0)
2248 {
2249 word += len;
2250 *boundspecial |= ACCELERATORDOWN;
2251 } else if (word[0] == 'm' && word[1] == '-')
2252 {
2253 word += 2;
2254 *boundspecial |= ACCELERATORDOWN;
2255 }
2256
2257 /* handle single keystrokes */
2258 if (word[1] == 0)
2259 {
2260 *boundkey = word[0];
2261 if (save == '/') *boundspecial |= ACCELERATORDOWN;
2262 } else
2263 {
2264 /* look for special names */
2265 if (word[0] == '^')
2266 {
2267 if (word[1] == '^')
2268 {
2269 *boundkey = '^';
2270 } else if (isdigit(word[1]) != 0)
2271 {
2272 *boundkey = (INTSML)myatoi(&word[1]);
2273 } else
2274 {
2275 *boundkey = toupper(word[1]) - 0100;
2276 }
2277 } else
2278 {
2279 if (namesame(word, x_("del")) == 0) *boundkey = 0177; else
2280 if (namesame(word, x_("left")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH); else
2281 if (namesame(word, x_("sleft")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH)|SHIFTDOWN; else
2282 if (namesame(word, x_("right")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH); else
2283 if (namesame(word, x_("sright")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH)|SHIFTDOWN; else
2284 if (namesame(word, x_("up")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH); else
2285 if (namesame(word, x_("sup")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH)|SHIFTDOWN; else
2286 if (namesame(word, x_("down")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH); else
2287 if (namesame(word, x_("sdown")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH)|SHIFTDOWN; else
2288 if (namesame(word, x_("f1")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF1<<SPECIALKEYSH); else
2289 if (namesame(word, x_("f2")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF2<<SPECIALKEYSH); else
2290 if (namesame(word, x_("f3")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF3<<SPECIALKEYSH); else
2291 if (namesame(word, x_("f4")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF4<<SPECIALKEYSH); else
2292 if (namesame(word, x_("f5")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF5<<SPECIALKEYSH); else
2293 if (namesame(word, x_("f6")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF6<<SPECIALKEYSH); else
2294 if (namesame(word, x_("f7")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF7<<SPECIALKEYSH); else
2295 if (namesame(word, x_("f8")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF8<<SPECIALKEYSH); else
2296 if (namesame(word, x_("f9")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF9<<SPECIALKEYSH); else
2297 if (namesame(word, x_("f10")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF10<<SPECIALKEYSH); else
2298 if (namesame(word, x_("f11")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF11<<SPECIALKEYSH); else
2299 if (namesame(word, x_("f12")) == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF12<<SPECIALKEYSH);
2300 }
2301 }
2302 *pt++ = save;
2303 offset = pt - binding;
2304 return(origbinding+offset);
2305 }
2306
2307 /*
2308 * Routine to recursively replace all mention of popup menu "oldpm" with "newpm".
2309 */
us_recursivelyreplacemenu(POPUPMENU * pm,POPUPMENU * oldpm,POPUPMENU * newpm)2310 void us_recursivelyreplacemenu(POPUPMENU *pm, POPUPMENU *oldpm, POPUPMENU *newpm)
2311 {
2312 REGISTER INTBIG i;
2313 REGISTER POPUPMENUITEM *mi;
2314 REGISTER USERCOM *uc;
2315 REGISTER VARIABLE *var;
2316 CHAR varname[200], **strings;
2317
2318 for(i=0; i<pm->total; i++)
2319 {
2320 mi = &pm->list[i];
2321 uc = mi->response;
2322 if (uc->menu == NOPOPUPMENU) continue;
2323
2324 if (uc->menu == oldpm)
2325 {
2326 esnprintf(varname, 200, x_("USER_binding_popup_%s"), pm->name);
2327 var = getval((INTBIG)us_tool, VTOOL, -1, varname);
2328 strings = (CHAR **)var->addr;
2329 setind((INTBIG)us_tool, VTOOL, varname, i+1, (INTBIG)strings[i+1]);
2330 }
2331 us_recursivelyreplacemenu(uc->menu, oldpm, newpm);
2332 }
2333 }
2334
2335 /*
2336 * Routine to adjust the quick keys according to the variable "var".
2337 */
us_adjustquickkeys(VARIABLE * var,BOOLEAN warnofchanges)2338 void us_adjustquickkeys(VARIABLE *var, BOOLEAN warnofchanges)
2339 {
2340 REGISTER INTBIG len, i, j, clen, elen;
2341 INTSML key;
2342 INTBIG special;
2343 REGISTER CHAR *keybinding, *menuname, *menucommand, *pt, **quickkeylist,
2344 *expected;
2345 REGISTER POPUPMENU *pm;
2346 REGISTER POPUPMENUITEM *mi;
2347 REGISTER void *infstr;
2348
2349 /* first scan all existing menus and make sure they are still in the quick key list */
2350 len = getlength(var);
2351 quickkeylist = (CHAR **)var->addr;
2352 for(i=0; i<us_pulldownmenucount; i++)
2353 us_scanquickkeys(us_pulldowns[i], quickkeylist, len, &warnofchanges);
2354
2355 /* next scan the list of quick keys and make sure they are attached to menus */
2356 for(i=0; i<len; i++)
2357 {
2358 keybinding = quickkeylist[i];
2359 menuname = us_getboundkey(keybinding, &key, &special);
2360 for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
2361 if (*pt == 0) continue;
2362 *pt = 0;
2363 pm = us_getpopupmenu(menuname);
2364 *pt = '/';
2365 if (pm == NOPOPUPMENU) continue;
2366 menucommand = pt + 1;
2367 mi = NOPOPUPMENUITEM;
2368 for(j=0; j<pm->total; j++)
2369 {
2370 mi = &pm->list[j];
2371 if (namesame(us_removeampersand(mi->attribute), menucommand) == 0) break;
2372 }
2373 if (j >= pm->total) continue;
2374
2375 /* see if this menu item has the quick key */
2376 expected = us_describeboundkey(key, special, -1);
2377 elen = estrlen(expected);
2378 clen = estrlen(mi->attribute);
2379 if (mi->attribute[clen-1] == '<') clen--;
2380 if (clen-elen > 0 &&
2381 namesamen(&mi->attribute[clen-elen], expected, elen) == 0) continue;
2382
2383 /* not there: see if there is another key bound */
2384 infstr = initinfstr();
2385 for(pt = mi->attribute; *pt != 0; pt++)
2386 {
2387 if (*pt == '/' || *pt == '\\' || *pt == '<') break;
2388 addtoinfstr(infstr, *pt);
2389 }
2390 addstringtoinfstr(infstr, us_describeboundkey(key, special, -1));
2391 clen = estrlen(mi->attribute) - 1;
2392 if (mi->attribute[clen] == '<') addstringtoinfstr(infstr, x_("<"));
2393 pt = returninfstr(infstr);
2394 (void)reallocstring(&mi->attribute, pt, us_tool->cluster);
2395 nativemenurename(pm, j);
2396 us_adjustpopupmenu(pm, j);
2397
2398 /* make it the Meta key */
2399 infstr = initinfstr();
2400 addstringtoinfstr(infstr, us_describeboundkey(key, special, 0));
2401 addstringtoinfstr(infstr, x_("command="));
2402 addstringtoinfstr(infstr, mi->response->comname);
2403 us_appendargs(infstr, mi->response);
2404 us_setkeybinding(returninfstr(infstr), key, special, TRUE);
2405
2406 if (warnofchanges)
2407 {
2408 warnofchanges = FALSE;
2409 ttyputmsg(_("Warning: key bindings have been changed by this library"));
2410 ttyputmsg(_(" (for example, the '%s' key is now bound to '%s')"),
2411 us_describeboundkey(key, special, 1), us_removeampersand(mi->attribute));
2412 }
2413 }
2414 }
2415
2416 /*
2417 * Helper routine for "us_quickkeydlog" to recursively examine menu "pm" and
2418 * load the quick keys tables.
2419 */
us_scanquickkeys(POPUPMENU * pm,CHAR ** quickkeylist,INTBIG quickkeycount,BOOLEAN * warnofchanges)2420 void us_scanquickkeys(POPUPMENU *pm, CHAR **quickkeylist, INTBIG quickkeycount, BOOLEAN *warnofchanges)
2421 {
2422 REGISTER INTBIG j, i, checked, len;
2423 INTBIG special;
2424 REGISTER POPUPMENUITEM *mi;
2425 REGISTER USERCOM *uc;
2426 REGISTER POPUPMENU *thispm;
2427 CHAR *pt, menuline[200], menukey[50];
2428 REGISTER CHAR *mname, *menuname;
2429 INTSML key;
2430
2431 for(i=0; i<pm->total; i++)
2432 {
2433 mi = &pm->list[i];
2434 uc = mi->response;
2435 if (uc->menu != NOPOPUPMENU)
2436 {
2437 us_scanquickkeys(uc->menu, quickkeylist, quickkeycount, warnofchanges);
2438 continue;
2439 }
2440 if (uc->active < 0 && *mi->attribute == 0) continue;
2441
2442 /* see if this item has a quick key */
2443 estrcpy(menuline, mi->attribute);
2444 j = estrlen(menuline) - 1;
2445 checked = 0;
2446 if (menuline[j] == '<')
2447 {
2448 menuline[j] = 0;
2449 checked = 1;
2450 }
2451 for(mname = menuline; *mname != 0; mname++)
2452 if (*mname == '/' || *mname == '\\') break;
2453 if (*mname == 0) continue;
2454 estrcpy(menukey, &mname[1]);
2455 mname[1] = 0;
2456 estrcat(menukey, mname);
2457 len = estrlen(menukey);
2458
2459 /* item has a quick key: see if it is in the list */
2460 for(j=0; j<quickkeycount; j++)
2461 {
2462 if (estrncmp(quickkeylist[j], menukey, len) != 0) continue;
2463 menuname = us_getboundkey(quickkeylist[j], &key, &special);
2464 for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
2465 if (*pt == 0) continue;
2466 *pt = 0;
2467 thispm = us_getpopupmenu(menuname);
2468 *pt = '/';
2469 if (thispm != pm) continue;
2470 if (estrncmp(quickkeylist[j], menukey, len) != 0) continue;
2471 if (namesame(&pt[1], us_removeampersand(mi->attribute)) == 0) break;
2472 }
2473 if (j < quickkeycount) continue;
2474
2475 /* remove the Meta key */
2476 (void)us_getboundkey(menukey, &key, &special);
2477 us_setkeybinding(x_(""), key, special, TRUE);
2478
2479 /* this menu entry is not in the quick key list: remove its quick key */
2480 for(mname = mi->attribute; *mname != 0; mname++)
2481 if (*mname == '/' || *mname == '\\') break;
2482 if (*mname != 0)
2483 {
2484 if (checked != 0) *mname++ = '<';
2485 *mname = 0;
2486 }
2487 nativemenurename(pm, i);
2488 us_adjustpopupmenu(pm, i);
2489 if (*warnofchanges)
2490 {
2491 *warnofchanges = FALSE;
2492 ttyputmsg(_("Warning: key bindings have been changed by this library"));
2493 pt = us_removeampersand(mi->attribute);
2494 if (*pt == '>') pt++;
2495 ttyputmsg(_(" (for example, the '%s' command is no longer attached to key '%s')"),
2496 pt, us_describeboundkey(key, special, 1));
2497 }
2498 }
2499 }
2500
2501 /*
2502 * Helper routine to remove special characters from menu item "name".
2503 */
us_removeampersand(CHAR * name)2504 CHAR *us_removeampersand(CHAR *name)
2505 {
2506 REGISTER CHAR *pt;
2507 REGISTER INTBIG len;
2508 REGISTER void *infstr;
2509
2510 len = estrlen(name);
2511 if (name[len-1] == '<' && name[0] == '>') name++;
2512 infstr = initinfstr();
2513 for(pt = name; *pt != 0; pt++)
2514 {
2515 if (*pt == '/' || *pt == '\\') break;
2516 if (*pt == '<' || *pt == '&') continue;
2517 addtoinfstr(infstr, *pt);
2518 }
2519 return(returninfstr(infstr));
2520 }
2521
2522 /*
2523 * Routine to search all of the pulldown menus and find the entry named "name".
2524 * Returns the variable key for that menu and the item index.
2525 */
us_findnamedmenu(CHAR * name,INTBIG * key,INTBIG * item)2526 void us_findnamedmenu(CHAR *name, INTBIG *key, INTBIG *item)
2527 {
2528 REGISTER POPUPMENU *pm;
2529 REGISTER INTBIG i;
2530 REGISTER void *infstr;
2531
2532 for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
2533 {
2534 for(i=0; i<pm->total; i++)
2535 if (us_matchpurecommand(pm->list[i].attribute, name)) break;
2536 if (i < pm->total)
2537 {
2538 infstr = initinfstr();
2539 formatinfstr(infstr, x_("USER_binding_popup_%s"), pm->name);
2540 *key = makekey(returninfstr(infstr));
2541 *item = i+1;
2542 break;
2543 }
2544 }
2545 }
2546
2547 /*
2548 * Routine to take item "menuitem" of the popup at variable "menukey" and substitute "command"
2549 * for the text there (preserving quick-key bindings).
2550 */
us_plugincommand(INTBIG menukey,INTBIG menuitem,CHAR * command)2551 CHAR *us_plugincommand(INTBIG menukey, INTBIG menuitem, CHAR *command)
2552 {
2553 REGISTER VARIABLE *var;
2554 REGISTER CHAR *pt;
2555 REGISTER INTBIG i;
2556 REGISTER void *infstr;
2557
2558 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, menukey);
2559 if (var == NOVARIABLE) return(x_(""));
2560 if (menuitem >= getlength(var)) return(x_(""));
2561 pt = ((CHAR **)var->addr)[menuitem];
2562
2563 /* look for "message=" and substitute the result */
2564 infstr = initinfstr();
2565 for(i=0; pt[i] != 0; i++)
2566 {
2567 if (namesamen(&pt[i], x_("message=\""), 9) == 0) break;
2568 addtoinfstr(infstr, pt[i]);
2569 }
2570 if (pt[i] != 0)
2571 {
2572 /* do the substitution */
2573 formatinfstr(infstr, x_("message=\"%s\""), command);
2574 pt += 9;
2575 while (*pt != 0 && *pt != '"') pt++;
2576 if (*pt == '"') pt++;
2577 addstringtoinfstr(infstr, pt);
2578 }
2579 return(returninfstr(infstr));
2580 }
2581
2582 /*
2583 * Routine to compare command "command" from the pulldown menus with "purecommand" that doesn't
2584 * have any menu control information. Returns TRUE if they are the same.
2585 */
us_matchpurecommand(CHAR * command,CHAR * purecommand)2586 BOOLEAN us_matchpurecommand(CHAR *command, CHAR *purecommand)
2587 {
2588 CHAR c, pc;
2589
2590 for(;;)
2591 {
2592 if (*command == '&') command++;
2593 c = *command++;
2594 if (c == '/' || c == '\\') c = 0;
2595 pc = *purecommand++;
2596 if (c != pc) return(FALSE);
2597 if (c == 0) break;
2598 }
2599 return(TRUE);
2600 }
2601
2602 /*
2603 * routine to determine whether the command bound to key "key" is the
2604 * last instance of the "telltool user" command that is bound to a key.
2605 * This is important to know because if the last "telltool user" is unbound,
2606 * there is no way to execute any long commands!
2607 */
us_islasteval(INTSML key,INTBIG special)2608 BOOLEAN us_islasteval(INTSML key, INTBIG special)
2609 {
2610 REGISTER INTBIG i, j, keytotal, foundanother;
2611 REGISTER BOOLEAN retval;
2612 INTBIG boundspecial;
2613 INTSML boundkey;
2614 REGISTER VARIABLE *var;
2615 CHAR *pt;
2616 COMMANDBINDING commandbindingthis, commandbindingother;
2617
2618 /* get the command on this key */
2619 retval = FALSE;
2620 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2621 if (var == NOVARIABLE) return(FALSE);
2622 i = us_findboundkey(key, special, &pt);
2623 if (i < 0) return(FALSE);
2624 us_parsebinding(pt, &commandbindingthis);
2625 if (*commandbindingthis.command != 0)
2626 {
2627 /* see if it is "telltool user" */
2628 if (namesame(commandbindingthis.command, x_("telltool user")) == 0)
2629 {
2630 /* this is "telltool user"...check all other keys for this command */
2631 keytotal = getlength(var);
2632 foundanother = 0;
2633 for(j=0; j<keytotal; j++)
2634 {
2635 pt = us_getboundkey(((CHAR **)var->addr)[j], &boundkey, &boundspecial);
2636 if (us_samekey(key, special, boundkey, boundspecial)) continue;
2637 us_parsebinding(pt, &commandbindingother);
2638 if (*commandbindingother.command != 0 &&
2639 namesame(commandbindingother.command, x_("telltool user")) == 0) foundanother++;
2640 us_freebindingparse(&commandbindingother);
2641 if (foundanother != 0) break;
2642 }
2643 if (foundanother == 0) retval = TRUE;
2644 }
2645 }
2646 us_freebindingparse(&commandbindingthis);
2647 return(retval);
2648 }
2649
2650 /*
2651 * routine to parse the binding string in "st" and fill in the binding structure
2652 * in "commandbinding".
2653 */
us_parsebinding(CHAR * st,COMMANDBINDING * commandbinding)2654 void us_parsebinding(CHAR *st, COMMANDBINDING *commandbinding)
2655 {
2656 CHAR *pt;
2657 REGISTER CHAR *str;
2658 REGISTER void *infstr;
2659
2660 commandbinding->nodeglyph = NONODEPROTO;
2661 commandbinding->arcglyph = NOARCPROTO;
2662 commandbinding->backgroundcolor = 0;
2663 commandbinding->menumessagesize = TXTSETPOINTS(20);
2664 commandbinding->menumessage = 0;
2665 commandbinding->popup = NOPOPUPMENU;
2666 commandbinding->inputpopup = FALSE;
2667 commandbinding->command = 0;
2668
2669 pt = st;
2670 for(;;)
2671 {
2672 str = getkeyword(&pt, x_("= "));
2673 if (str == NOSTRING || *str == 0) break;
2674 (void)tonextchar(&pt);
2675
2676 if (namesame(str, x_("node")) == 0)
2677 {
2678 str = getkeyword(&pt, x_(" "));
2679 if (str == NOSTRING) break;
2680 commandbinding->nodeglyph = getnodeproto(str);
2681 continue;
2682 }
2683 if (namesame(str, x_("arc")) == 0)
2684 {
2685 str = getkeyword(&pt, x_(" "));
2686 if (str == NOSTRING) break;
2687 commandbinding->arcglyph = getarcproto(str);
2688 continue;
2689 }
2690 if (namesame(str, x_("background")) == 0)
2691 {
2692 str = getkeyword(&pt, x_(" "));
2693 if (str == NOSTRING) break;
2694 commandbinding->backgroundcolor = myatoi(str);
2695 continue;
2696 }
2697 if (namesame(str, x_("popup")) == 0)
2698 {
2699 str = getkeyword(&pt, x_(" "));
2700 if (str == NOSTRING) break;
2701 commandbinding->popup = us_getpopupmenu(str);
2702 continue;
2703 }
2704 if (namesame(str, x_("inputpopup")) == 0)
2705 {
2706 str = getkeyword(&pt, x_(" "));
2707 if (str == NOSTRING) break;
2708 commandbinding->popup = us_getpopupmenu(str);
2709 commandbinding->inputpopup = TRUE;
2710 continue;
2711 }
2712 if (namesame(str, x_("message")) == 0)
2713 {
2714 (void)tonextchar(&pt);
2715 infstr = initinfstr();
2716 for(str = pt; *str != 0; str++)
2717 {
2718 if (*str == '"') break;
2719 if (*str == '^') str++;
2720 addtoinfstr(infstr, *str);
2721 }
2722 pt = str+1;
2723 (void)allocstring(&commandbinding->menumessage, returninfstr(infstr), us_tool->cluster);
2724 continue;
2725 }
2726 if (namesame(str, x_("messagesize")) == 0)
2727 {
2728 str = getkeyword(&pt, x_(" "));
2729 if (str == NOSTRING) break;
2730 commandbinding->menumessagesize = myatoi(str);
2731 }
2732 if (namesame(str, x_("command")) == 0) break;
2733 }
2734 (void)allocstring(&commandbinding->command, pt, us_tool->cluster);
2735 }
2736
2737 /*
2738 * routine to free any allocated things in the "commandbinding" structure that was filled-in
2739 * by "us_parsebinding()".
2740 */
us_freebindingparse(COMMANDBINDING * commandbinding)2741 void us_freebindingparse(COMMANDBINDING *commandbinding)
2742 {
2743 if (commandbinding->menumessage != 0) efree(commandbinding->menumessage);
2744 commandbinding->menumessage = 0;
2745 if (commandbinding->command != 0) efree(commandbinding->command);
2746 commandbinding->command = 0;
2747 }
2748
2749 /*
2750 * routine to set the trace information in the "size" coordinate pairs in
2751 * "newlist" onto the node "ni".
2752 */
us_settrace(NODEINST * ni,INTBIG * newlist,INTBIG size)2753 void us_settrace(NODEINST *ni, INTBIG *newlist, INTBIG size)
2754 {
2755 REGISTER INTBIG lx, hx, ly, hy, x, y, i;
2756 INTBIG lxo, hxo, lyo, hyo;
2757
2758 /* get the extent of the data */
2759 lx = hx = newlist[0]; ly = hy = newlist[1];
2760 for(i=1; i<size; i++)
2761 {
2762 x = newlist[i*2];
2763 y = newlist[i*2+1];
2764 lx = mini(lx, x); hx = maxi(hx, x);
2765 ly = mini(ly, y); hy = maxi(hy, y);
2766 }
2767
2768 /* make these co-ordinates relative to the center */
2769 x = (hx+lx) / 2; y = (hy+ly) / 2;
2770 for(i=0; i<size; i++)
2771 {
2772 newlist[i*2] = newlist[i*2] - x;
2773 newlist[i*2+1] = newlist[i*2+1] - y;
2774 }
2775
2776 /* adjust size for node size offset */
2777 nodesizeoffset(ni, &lxo, &lyo, &hxo, &hyo);
2778 lx -= lxo; hx += hxo;
2779 ly -= lyo; hy += hyo;
2780
2781 /* erase the node instance */
2782 startobjectchange((INTBIG)ni, VNODEINST);
2783
2784 /* change the trace data */
2785 (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2786 VINTEGER|VISARRAY|((size*2)<<VLENGTHSH));
2787
2788 /* scale the node (which redraws too) */
2789 if (ni->proto->primindex != 0 && (lx != ni->lowx || hx != ni->highx || ly != ni->lowy ||
2790 hy != ni->highy || ni->rotation != 0 || ni->transpose != 0))
2791 modifynodeinst(ni, lx-ni->lowx, ly-ni->lowy, hx-ni->highx, hy-ni->highy,
2792 -ni->rotation, ni->transpose);
2793
2794 /* redisplay */
2795 endobjectchange((INTBIG)ni, VNODEINST);
2796
2797 /* restore original data */
2798 for(i=0; i<size; i++)
2799 {
2800 newlist[i*2] = newlist[i*2] + x;
2801 newlist[i*2+1] = newlist[i*2+1] + y;
2802 }
2803 }
2804
2805 /*
2806 * routine to scale the trace information on node "ni" given that it will change
2807 * in size to "nlx"->"nhx" and "nly"->"nhy".
2808 */
us_scaletraceinfo(NODEINST * ni,INTBIG nlx,INTBIG nhx,INTBIG nly,INTBIG nhy)2809 void us_scaletraceinfo(NODEINST *ni, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy)
2810 {
2811 REGISTER VARIABLE *var;
2812 REGISTER INTBIG *newlist, oldx, oldy, denx, deny, len, i;
2813
2814 /* stop now if no trace information */
2815 var = gettrace(ni);
2816 if (var == NOVARIABLE) return;
2817
2818 /* get new array for new trace */
2819 len = getlength(var);
2820 newlist = (INTBIG *)emalloc(len * SIZEOFINTBIG, el_tempcluster);
2821 if (newlist == 0) return;
2822
2823 /* copy the data and scale it */
2824 denx = ni->highx - ni->lowx;
2825 if (denx == 0) denx = nhx - nlx;
2826 deny = ni->highy - ni->lowy;
2827 if (deny == 0) deny = nhy - nly;
2828 for(i=0; i<len; i += 2)
2829 {
2830 oldx = ((INTBIG *)var->addr)[i];
2831 oldy = ((INTBIG *)var->addr)[i+1];
2832 oldx = muldiv(oldx, nhx - nlx, denx);
2833 oldy = muldiv(oldy, nhy - nly, deny);
2834 newlist[i] = oldx; newlist[i+1] = oldy;
2835 }
2836
2837 /* store the new list */
2838 (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2839 VINTEGER|VISARRAY|(len<<VLENGTHSH));
2840 efree((CHAR *)newlist);
2841 }
2842
2843 /*
2844 * Routine to fillet the two highlighted objects
2845 */
us_dofillet(void)2846 void us_dofillet(void)
2847 {
2848 REGISTER VARIABLE *var;
2849 HIGHLIGHT thishigh, otherhigh;
2850 REGISTER NODEINST *ni1, *ni2, *swapni;
2851 double startoffset, endangle, srot, erot, newangle, dx, dy;
2852 INTBIG ix, iy, ix1, iy1, ix2, iy2;
2853 REGISTER BOOLEAN on1, on2;
2854 REGISTER INTBIG ang1, ang2, size1, size2, arc1, arc2, swapsize, icount, newrot;
2855 REGISTER INTBIG *newlist1, *newlist2, *line1xs, *line1ys, *line1xe, *line1ye,
2856 *line2xs, *line2ys, *line2xe, *line2ye, x, y, i, *swaplist;
2857 XARRAY trans;
2858
2859 /* must be exactly two nodes selected */
2860 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2861 if (var == NOVARIABLE)
2862 {
2863 us_abortcommand(_("Must select two nodes before filleting"));
2864 return;
2865 }
2866 if (getlength(var) != 2)
2867 {
2868 us_abortcommand(_("Must select two nodes before filleting"));
2869 return;
2870 }
2871
2872 if (us_makehighlight(((CHAR **)var->addr)[0], &thishigh) ||
2873 us_makehighlight(((CHAR **)var->addr)[1], &otherhigh)) return;
2874
2875 /* get the two objects */
2876 if ((thishigh.status&HIGHTYPE) != HIGHFROM || (otherhigh.status&HIGHTYPE) != HIGHFROM)
2877 {
2878 us_abortcommand(_("Must select two nodes before filleting"));
2879 return;
2880 }
2881
2882 if (!thishigh.fromgeom->entryisnode || !otherhigh.fromgeom->entryisnode)
2883 {
2884 us_abortcommand(_("Must select two nodes before filleting"));
2885 return;
2886 }
2887
2888 /* get description of first node */
2889 ni1 = thishigh.fromgeom->entryaddr.ni;
2890 if (ni1->proto == art_circleprim || ni1->proto == art_thickcircleprim)
2891 {
2892 getarcdegrees(ni1, &startoffset, &endangle);
2893 if (startoffset == 0.0 && endangle == 0.0)
2894 {
2895 us_abortcommand(_("Must select arcs, not circles before filleting"));
2896 return;
2897 }
2898 newlist1 = emalloc((6*SIZEOFINTBIG), el_tempcluster);
2899 if (newlist1 == 0) return;
2900 newlist1[0] = (ni1->lowx + ni1->highx) / 2;
2901 newlist1[1] = (ni1->lowy + ni1->highy) / 2;
2902 getarcendpoints(ni1, startoffset, endangle, &newlist1[2], &newlist1[3],
2903 &newlist1[4], &newlist1[5]);
2904 size1 = 0;
2905 arc1 = 1;
2906 } else if (ni1->proto == art_openedpolygonprim || ni1->proto == art_openeddottedpolygonprim ||
2907 ni1->proto == art_openeddashedpolygonprim || ni1->proto == art_openedthickerpolygonprim ||
2908 ni1->proto == art_closedpolygonprim)
2909 {
2910 var = gettrace(ni1);
2911 if (var == NOVARIABLE)
2912 {
2913 us_abortcommand(_("Must select nodes with outline information before filleting"));
2914 return;
2915 }
2916
2917 /* transform the traces */
2918 size1 = getlength(var) / 2;
2919 newlist1 = emalloc((size1*2*SIZEOFINTBIG), el_tempcluster);
2920 if (newlist1 == 0) return;
2921 makerot(ni1, trans);
2922 x = (ni1->highx + ni1->lowx) / 2;
2923 y = (ni1->highy + ni1->lowy) / 2;
2924 for(i=0; i<size1; i++)
2925 xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &newlist1[i*2],
2926 &newlist1[i*2+1], trans);
2927 arc1 = 0;
2928 } else
2929 {
2930 us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni1));
2931 return;
2932 }
2933
2934 /* get description of second node */
2935 ni2 = otherhigh.fromgeom->entryaddr.ni;
2936 if (ni2->proto == art_circleprim || ni2->proto == art_thickcircleprim)
2937 {
2938 getarcdegrees(ni2, &startoffset, &endangle);
2939 if (startoffset == 0.0 && endangle == 0.0)
2940 {
2941 us_abortcommand(_("Must select arcs, not circles before filleting"));
2942 return;
2943 }
2944 newlist2 = emalloc((6*SIZEOFINTBIG), el_tempcluster);
2945 if (newlist2 == 0) return;
2946 newlist2[0] = (ni2->lowx + ni2->highx) / 2;
2947 newlist2[1] = (ni2->lowy + ni2->highy) / 2;
2948 getarcendpoints(ni2, startoffset, endangle, &newlist2[2], &newlist2[3],
2949 &newlist2[4], &newlist2[5]);
2950 size2 = 0;
2951 x = y = 0;
2952 arc2 = 1;
2953 } else if (ni2->proto == art_openedpolygonprim || ni2->proto == art_openeddottedpolygonprim ||
2954 ni2->proto == art_openeddashedpolygonprim || ni2->proto == art_openedthickerpolygonprim ||
2955 ni2->proto == art_closedpolygonprim)
2956 {
2957 var = gettrace(ni2);
2958 if (var == NOVARIABLE)
2959 {
2960 us_abortcommand(_("Must select nodes with outline information before filleting"));
2961 return;
2962 }
2963
2964 /* transform the traces */
2965 size2 = getlength(var) / 2;
2966 newlist2 = emalloc((size2*2*SIZEOFINTBIG), el_tempcluster);
2967 if (newlist2 == 0) return;
2968 makerot(ni2, trans);
2969 x = (ni2->highx + ni2->lowx) / 2;
2970 y = (ni2->highy + ni2->lowy) / 2;
2971 for(i=0; i<size2; i++)
2972 xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &newlist2[i*2],
2973 &newlist2[i*2+1], trans);
2974 arc2 = 0;
2975 } else
2976 {
2977 us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni2));
2978 return;
2979 }
2980
2981 /* handle different types of filleting */
2982 if (arc1 != 0 && arc2 != 0)
2983 {
2984 /* cannot handle arc-to-arc filleting */
2985 us_abortcommand(_("Cannot fillet two curves"));
2986 } else if (arc1 == 0 && arc2 == 0)
2987 {
2988 /* handle line-to-line filleting: find out which endpoints are closest */
2989 if (computedistance(x,y, newlist1[0],newlist1[1]) <
2990 computedistance(x,y, newlist1[size1*2-2],newlist1[size1*2-1]))
2991 {
2992 line1xs = &newlist1[0];
2993 line1ys = &newlist1[1];
2994 line1xe = &newlist1[2];
2995 line1ye = &newlist1[3];
2996 } else
2997 {
2998 line1xs = &newlist1[size1*2-2];
2999 line1ys = &newlist1[size1*2-1];
3000 line1xe = &newlist1[size1*2-4];
3001 line1ye = &newlist1[size1*2-3];
3002 }
3003 if (computedistance(*line1xs,*line1ys, newlist2[0],newlist2[1]) <
3004 computedistance(*line1xs,*line1ys, newlist2[size2*2-2],newlist2[size2*2-1]))
3005 {
3006 line2xs = &newlist2[0];
3007 line2ys = &newlist2[1];
3008 line2xe = &newlist2[2];
3009 line2ye = &newlist2[3];
3010 } else
3011 {
3012 line2xs = &newlist2[size2*2-2];
3013 line2ys = &newlist2[size2*2-1];
3014 line2xe = &newlist2[size2*2-4];
3015 line2ye = &newlist2[size2*2-3];
3016 }
3017
3018 /* compute intersection point */
3019 ang1 = figureangle(*line1xs, *line1ys, *line1xe, *line1ye);
3020 ang2 = figureangle(*line2xs, *line2ys, *line2xe, *line2ye);
3021 if (intersect(*line1xs, *line1ys, ang1, *line2xs, *line2ys, ang2, &ix, &iy) != 0)
3022 us_abortcommand(_("Lines do not intersect")); else
3023 {
3024 *line1xs = ix; *line1ys = iy;
3025 *line2xs = ix; *line2ys = iy;
3026 us_pushhighlight();
3027 us_clearhighlightcount();
3028 us_settrace(ni1, newlist1, size1);
3029 us_settrace(ni2, newlist2, size2);
3030 us_pophighlight(TRUE);
3031 }
3032 } else
3033 {
3034 /* handle arc-to-line filleting */
3035 if (arc1 == 0)
3036 {
3037 swaplist = newlist1; newlist1 = newlist2; newlist2 = swaplist;
3038 swapsize = size1; size1 = size2; size2 = swapsize;
3039 swapni = ni1; ni1 = ni2; ni2 = swapni;
3040 }
3041
3042 /* "newlist1" describes the arc, "newlist2" describes the line */
3043 if (computedistance(newlist1[0],newlist1[1], newlist2[0],newlist2[1]) <
3044 computedistance(newlist1[0],newlist1[1], newlist2[size2*2-2],newlist2[size2*2-1]))
3045 {
3046 line2xs = &newlist2[0];
3047 line2ys = &newlist2[1];
3048 line2xe = &newlist2[2];
3049 line2ye = &newlist2[3];
3050 } else
3051 {
3052 line2xs = &newlist2[size2*2-2];
3053 line2ys = &newlist2[size2*2-1];
3054 line2xe = &newlist2[size2*2-4];
3055 line2ye = &newlist2[size2*2-3];
3056 }
3057 icount = circlelineintersection(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
3058 *line2xs, *line2ys, *line2xe, *line2ye, &ix1, &iy1, &ix2, &iy2, 0);
3059 if (icount == 0)
3060 {
3061 us_abortcommand(_("Line does not intersect arc: cannot fillet"));
3062 } else
3063 {
3064 if (icount == 2)
3065 {
3066 on1 = us_pointonexparc(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
3067 newlist1[4],newlist1[5], ix1, iy1);
3068 on2 = us_pointonexparc(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
3069 newlist1[4],newlist1[5], ix2, iy2);
3070 if (!on1 && on2)
3071 {
3072 icount = 1;
3073 ix1 = ix2; iy1 = iy2;
3074 } else if (on1 && !on2)
3075 {
3076 icount = 1;
3077 }
3078 }
3079 if (icount == 2)
3080 {
3081 x = (*line2xs + *line2xe) / 2;
3082 y = (*line2ys + *line2ye) / 2;
3083 if (computedistance(ix1,iy1, x,y) > computedistance(ix2,iy2, x,y))
3084 {
3085 ix1 = ix2; iy1 = iy2;
3086 }
3087 }
3088
3089 /* make them fillet at (ix1,iy1) */
3090 us_pushhighlight();
3091 us_clearhighlightcount();
3092
3093 /* adjust the arc (node ni1) */
3094 dx = (double)(newlist1[2]-newlist1[0]); dy = (double)(newlist1[3]-newlist1[1]);
3095 if (dx == 0.0 && dy == 0.0)
3096 {
3097 us_abortcommand(_("Domain error during fillet"));
3098 return;
3099 }
3100 srot = atan2(dy, dx);
3101 if (srot < 0.0) srot += EPI*2.0;
3102
3103 dx = (double)(newlist1[4]-newlist1[0]); dy = (double)(newlist1[5]-newlist1[1]);
3104 if (dx == 0.0 && dy == 0.0)
3105 {
3106 us_abortcommand(_("Domain error during fillet"));
3107 return;
3108 }
3109 erot = atan2(dy, dx);
3110 if (erot < 0.0) erot += EPI*2.0;
3111
3112 dx = (double)(ix1-newlist1[0]); dy = (double)(iy1-newlist1[1]);
3113 if (dx == 0.0 && dy == 0.0)
3114 {
3115 us_abortcommand(_("Domain error during fillet"));
3116 return;
3117 }
3118 newangle = atan2(dy, dx);
3119 if (newangle < 0.0) newangle += EPI*2.0;
3120 if (computedistance(ix1,iy1, newlist1[2],newlist1[3]) <
3121 computedistance(ix1,iy1, newlist1[4],newlist1[5])) srot = newangle; else
3122 erot = newangle;
3123 erot -= srot;
3124 if (erot < 0.0) erot += EPI*2.0;
3125 newrot = rounddouble(srot * 1800.0 / EPI);
3126 srot -= ((double)newrot) * EPI / 1800.0;
3127 startobjectchange((INTBIG)ni1, VNODEINST);
3128 modifynodeinst(ni1, 0, 0, 0, 0, newrot - ni1->rotation, 0);
3129 setarcdegrees(ni1, srot, erot);
3130 endobjectchange((INTBIG)ni1, VNODEINST);
3131
3132 /* adjust the line (node ni2) */
3133 *line2xs = ix1; *line2ys = iy1;
3134 us_settrace(ni2, newlist2, size2);
3135
3136 /* restore highlighting */
3137 us_pophighlight(TRUE);
3138 }
3139 }
3140 efree((CHAR *)newlist1);
3141 efree((CHAR *)newlist2);
3142 }
3143
3144 /*
3145 * Houtine to convert the text in "msg" to bits on the display.
3146 */
us_layouttext(CHAR * layer,INTBIG tsize,INTBIG scale,INTBIG font,INTBIG italic,INTBIG bold,INTBIG underline,INTBIG separation,CHAR * msg)3147 void us_layouttext(CHAR *layer, INTBIG tsize, INTBIG scale, INTBIG font, INTBIG italic,
3148 INTBIG bold, INTBIG underline, INTBIG separation, CHAR *msg)
3149 {
3150 REGISTER NODEPROTO *np;
3151 REGISTER INTBIG x, y;
3152 REGISTER NODEINST *ni, **nodelist;
3153 REGISTER BOOLEAN err;
3154 REGISTER INTBIG cx, cy, lambda, gridsize, i;
3155 INTBIG wid, hei, bx, by, count;
3156 UINTBIG descript[TEXTDESCRIPTSIZE];
3157 HIGHLIGHT high;
3158 UCHAR1 **rowstart, *data;
3159 REGISTER void *merge=0;
3160 LISTINTBIG *linodes;
3161 static POLYGON *poly = NOPOLYGON;
3162
3163 np = us_needcell();
3164 if (np == NONODEPROTO) return;
3165
3166 /* convert the text to bits */
3167 TDCLEAR(descript);
3168 if (tsize < 4) tsize = 4;
3169 if (tsize > TXTMAXPOINTS) tsize = TXTMAXPOINTS;
3170 TDSETSIZE(descript, TXTSETPOINTS(tsize));
3171 TDSETFACE(descript, font);
3172 if (italic != 0) TDSETITALIC(descript, VTITALIC);
3173 if (bold != 0) TDSETBOLD(descript, VTBOLD);
3174 if (underline != 0) TDSETUNDERLINE(descript, VTUNDERLINE);
3175 screensettextinfo(el_curwindowpart, NOTECHNOLOGY, descript);
3176 err = gettextbits(el_curwindowpart, msg, &wid, &hei, &rowstart);
3177 if (err)
3178 {
3179 us_abortcommand(_("Sorry, this system cannot layout text"));
3180 return;
3181 }
3182
3183 /* determine the primitive to use for the layout */
3184 for(us_layouttextprim = el_curtech->firstnodeproto; us_layouttextprim != NONODEPROTO;
3185 us_layouttextprim = us_layouttextprim->nextnodeproto)
3186 if (namesame(us_layouttextprim->protoname, layer) == 0) break;
3187 if (us_layouttextprim == NONODEPROTO)
3188 {
3189 us_abortcommand(_("Cannot find '%s' node"), layer);
3190 return;
3191 }
3192
3193 lambda = el_curlib->lambda[el_curtech->techindex];
3194 separation = separation * lambda / 2;
3195 gridsize = lambda * scale;
3196 bx = (el_curwindowpart->screenlx+el_curwindowpart->screenhx -
3197 wid * gridsize) / 2;
3198 by = (el_curwindowpart->screenly+el_curwindowpart->screenhy -
3199 hei * gridsize) / 2;
3200 gridalign(&bx, &by, 1, np);
3201 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
3202 if (separation == 0) merge = mergenew(us_tool->cluster); else
3203 linodes = newintlistobj(us_tool->cluster);
3204
3205 for(y=0; y<hei; y++)
3206 {
3207 cy = by - y * gridsize;
3208 data = rowstart[y];
3209 for(x=0; x<wid; x++)
3210 {
3211 cx = bx + x * gridsize;
3212 if (*data != 0)
3213 {
3214 poly->xv[0] = cx;
3215 poly->yv[0] = cy;
3216 poly->xv[1] = cx + gridsize;
3217 poly->yv[1] = cy + gridsize;
3218 poly->style = FILLEDRECT;
3219 poly->count = 2;
3220 if (separation == 0) mergeaddpolygon(merge, 0, el_curtech, poly); else
3221 {
3222 /* place the node now */
3223 ni = newnodeinst(us_layouttextprim, poly->xv[0]+separation,
3224 poly->xv[1]-separation, poly->yv[0]+separation,
3225 poly->yv[1]-separation, 0, 0, np);
3226 if (ni != NONODEINST)
3227 addtointlistobj(linodes, (INTBIG)ni, FALSE);
3228 }
3229 }
3230 data++;
3231 }
3232 }
3233 us_clearhighlightcount();
3234 if (separation == 0)
3235 {
3236 mergeextract(merge, us_layouttextpolygon);
3237 mergedelete(merge);
3238 } else
3239 {
3240 nodelist = (NODEINST **)getintlistobj(linodes, &count);
3241 for(i=0; i<count; i++)
3242 {
3243 ni = nodelist[i];
3244 endobjectchange((INTBIG)ni, VNODEINST);
3245 high.status = HIGHFROM;
3246 high.fromgeom = ni->geom;
3247 high.fromport = NOPORTPROTO;
3248 high.frompoint = 0;
3249 high.cell = np;
3250 us_addhighlight(&high);
3251 }
3252 }
3253 }
3254
3255 /*
3256 * Helper routine for "us_layouttext" to process a polygon and convert it to layout.
3257 */
us_layouttextpolygon(INTBIG layer,TECHNOLOGY * tech,INTBIG * x,INTBIG * y,INTBIG count)3258 void us_layouttextpolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
3259 {
3260 REGISTER NODEPROTO *cell;
3261 REGISTER NODEINST *ni;
3262 REGISTER INTBIG lx, hx, ly, hy, cx, cy, *newlist;
3263 REGISTER INTBIG i;
3264 HIGHLIGHT high;
3265 Q_UNUSED( layer );
3266 Q_UNUSED( tech );
3267
3268 cell = us_needcell();
3269 if (cell == NONODEPROTO) return;
3270 lx = hx = x[0];
3271 ly = hy = y[0];
3272 for(i=1; i<count; i++)
3273 {
3274 if (x[i] < lx) lx = x[i];
3275 if (x[i] > hx) hx = x[i];
3276 if (y[i] < ly) ly = y[i];
3277 if (y[i] > hy) hy = y[i];
3278 }
3279 cx = (lx+hx) / 2; cy = (ly+hy) / 2;
3280 ni = newnodeinst(us_layouttextprim, lx, hx, ly, hy, 0, 0, cell);
3281 newlist = (INTBIG *)emalloc(count * 2 * SIZEOFINTBIG, el_tempcluster);
3282 if (newlist == 0) return;
3283 for(i=0; i<count; i++)
3284 {
3285 newlist[i*2] = x[i] - cx;
3286 newlist[i*2+1] = y[i] - cy;
3287 }
3288 (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
3289 VINTEGER|VISARRAY|((count*2)<<VLENGTHSH));
3290 endobjectchange((INTBIG)ni, VNODEINST);
3291 high.status = HIGHFROM;
3292 high.fromgeom = ni->geom;
3293 high.fromport = NOPORTPROTO;
3294 high.frompoint = 0;
3295 high.cell = cell;
3296 us_addhighlight(&high);
3297 }
3298
3299 /*
3300 * Routine to determine whether the point (x,y) is on the arc centered at (cx,cy), starting
3301 * at (sx,sy), and ending at (ex,ey). Returns true if on the arc.
3302 */
us_pointonexparc(INTBIG cx,INTBIG cy,INTBIG sx,INTBIG sy,INTBIG ex,INTBIG ey,INTBIG x,INTBIG y)3303 BOOLEAN us_pointonexparc(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, INTBIG x, INTBIG y)
3304 {
3305 REGISTER INTBIG as, ae, a;
3306
3307 as = figureangle(cx, cy, sx, sy);
3308 ae = figureangle(cx, cy, ex, ey);
3309 a = figureangle(cx, cy, x, y);
3310
3311 if (ae > as)
3312 {
3313 if (a >= as && a <= ae) return(TRUE);
3314 } else
3315 {
3316 if (a >= as || a <= ae) return(TRUE);
3317 }
3318 return(FALSE);
3319 }
3320
3321 /*
3322 * routine to recursively check sub-cell revision times
3323 * P. Attfield
3324 */
us_check_cell_date(NODEPROTO * np,UINTBIG rev_time)3325 void us_check_cell_date(NODEPROTO *np, UINTBIG rev_time)
3326 {
3327 REGISTER NODEPROTO *np2;
3328 REGISTER NODEINST *ni;
3329
3330 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3331 {
3332 np2 = ni->proto;
3333 if (np2->primindex != 0) continue; /* ignore if primitive */
3334
3335 /* ignore recursive references (showing icon in contents) */
3336 if (isiconof(np2, np)) continue;
3337 if (np2->temp1 != 0) continue; /* ignore if already seen */
3338 us_check_cell_date(np2, rev_time); /* recurse */
3339 }
3340
3341 /* check this cell */
3342 np->temp1++; /* flag that we have seen this one */
3343 if (np->revisiondate <= rev_time) return;
3344
3345 /* possible error in hierarchy */
3346 ttyputerr(_("WARNING: sub-cell '%s' has been edited"), describenodeproto(np));
3347 ttyputmsg(_(" since the last revision to the current cell"));
3348 }
3349
3350 /*
3351 * routine to switch to library "lib"
3352 */
us_switchtolibrary(LIBRARY * lib)3353 void us_switchtolibrary(LIBRARY *lib)
3354 {
3355 CHAR *newpar[2];
3356 REGISTER INTBIG oldlam;
3357 REGISTER WINDOWPART *w;
3358
3359 /* select the new library */
3360 us_clearhighlightcount();
3361 oldlam = el_curlib->lambda[el_curtech->techindex];
3362 selectlibrary(lib, TRUE);
3363 us_setlambda(NOWINDOWFRAME);
3364 if ((us_curnodeproto == NONODEPROTO || us_curnodeproto->primindex == 0) &&
3365 (us_state&NONPERSISTENTCURNODE) == 0)
3366 us_setnodeproto(el_curtech->firstnodeproto);
3367 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3368 us_setcellname(w);
3369
3370 /* if nothing displayed and new library has top cell, show it */
3371 if (el_curwindowpart == NOWINDOWPART ||
3372 el_curwindowpart->curnodeproto == NONODEPROTO)
3373 {
3374 if (el_curlib->curnodeproto != NONODEPROTO)
3375 {
3376 newpar[0] = describenodeproto(el_curlib->curnodeproto);
3377 us_editcell(1, newpar);
3378 }
3379 }
3380
3381 /* redo the explorer window (if it is up) */
3382 us_redoexplorerwindow();
3383 }
3384
3385 /*
3386 * Routine to replace all cross-library references that point into
3387 * "oldlib" with equivalent ones that point to "newlib". This is called
3388 * when a library is re-read from disk ("oldlib" is the former one).
3389 */
us_replacelibraryreferences(LIBRARY * oldlib,LIBRARY * newlib)3390 void us_replacelibraryreferences(LIBRARY *oldlib, LIBRARY *newlib)
3391 {
3392 REGISTER LIBRARY *lib;
3393 REGISTER NODEPROTO *np, *newnp;
3394 REGISTER NODEINST *ni, *nextni, *newni;
3395 REGISTER ARCINST *ai;
3396 REGISTER PORTARCINST *pi;
3397 REGISTER PORTEXPINST *pe;
3398
3399 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
3400 {
3401 if (lib == oldlib || lib == newlib) continue;
3402
3403 /* look for cross-library references to "oldlib" */
3404 us_correctxlibref(&lib->firstvar, &lib->numvar, oldlib, newlib);
3405 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3406 {
3407 us_correctxlibref(&np->firstvar, &np->numvar, oldlib, newlib);
3408 for(ni = np->firstnodeinst; ni != NONODEINST; ni = nextni)
3409 {
3410 nextni = ni->nextnodeinst;
3411
3412 /* correct variables */
3413 us_correctxlibref(&ni->firstvar, &ni->numvar, oldlib, newlib);
3414 us_correctxlibref(&ni->geom->firstvar, &ni->geom->numvar, oldlib, newlib);
3415 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3416 us_correctxlibref(&pi->firstvar, &pi->numvar, oldlib, newlib);
3417 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
3418 us_correctxlibref(&pe->firstvar, &pe->numvar, oldlib, newlib);
3419
3420 if (ni->proto->primindex != 0) continue;
3421 if (ni->proto->lib == oldlib)
3422 {
3423 /* find the equivalent name in the new library */
3424 newnp = us_findcellinotherlib(ni->proto, newlib);
3425 if (newnp == NONODEPROTO)
3426 {
3427 ttyputerr(_("Error: cell %s{%s};%ld no longer present in library %s"),
3428 ni->proto->protoname, ni->proto->cellview->sviewname,
3429 ni->proto->version, newlib->libname);
3430 continue;
3431 }
3432 newni = replacenodeinst(ni, newnp, FALSE, TRUE);
3433 if (newni == NONODEINST)
3434 {
3435 ttyputerr(_("Error: node %s{%s};%ld could not be replaced with equivalent in library %s"),
3436 ni->proto->protoname, ni->proto->cellview->sviewname,
3437 ni->proto->version, newlib->libname);
3438 continue;
3439 }
3440 }
3441 }
3442 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3443 {
3444 us_correctxlibref(&ai->firstvar, &ai->numvar, oldlib, newlib);
3445 us_correctxlibref(&ai->geom->firstvar, &ai->geom->numvar, oldlib, newlib);
3446 }
3447 }
3448 }
3449 }
3450
3451 /*
3452 * Helper routine to search "numvar" variables in "firstvar" and replace references
3453 * to anything in library "oldlib" to point to an equivalent in "newlib".
3454 */
us_correctxlibref(VARIABLE ** firstvar,INTSML * numvar,LIBRARY * oldlib,LIBRARY * newlib)3455 void us_correctxlibref(VARIABLE **firstvar, INTSML *numvar, LIBRARY *oldlib, LIBRARY *newlib)
3456 {
3457 REGISTER INTBIG i, j, checkcell;
3458 REGISTER VARIABLE *var, *svar, *dvar;
3459 REGISTER NODEPROTO *np, *newnp;
3460 REGISTER NODEINST *ni;
3461 REGISTER ARCINST *ai;
3462 REGISTER PORTPROTO *pp;
3463 REGISTER PORTARCINST *pi;
3464 REGISTER PORTEXPINST *pe;
3465 REGISTER LIBRARY *lib;
3466 REGISTER NETWORK *net;
3467 REGISTER GEOM *geom;
3468
3469 for(i=0; i < *numvar; i++)
3470 {
3471 var = &(*firstvar)[i];
3472 if ((var->type&VISARRAY) != 0) continue;
3473 checkcell = 0;
3474 np = NONODEPROTO;
3475 switch (var->type&VTYPE)
3476 {
3477 case VNODEINST:
3478 ni = (NODEINST *)var->addr;
3479 np = ni->parent;
3480 checkcell = 1;
3481 break;
3482 case VNODEPROTO:
3483 np = (NODEPROTO *)var->addr;
3484 if (np->primindex != 0) break;
3485 if (np->lib != oldlib) break;
3486 newnp = us_findcellinotherlib(np, newlib);
3487 var->addr = (INTBIG)newnp;
3488 break;
3489 case VPORTARCINST:
3490 pi = (PORTARCINST *)var->addr;
3491 np = pi->conarcinst->parent;
3492 checkcell = 1;
3493 break;
3494 case VPORTEXPINST:
3495 pe = (PORTEXPINST *)var->addr;
3496 np = pe->exportproto->parent;
3497 checkcell = 1;
3498 break;
3499 case VPORTPROTO:
3500 pp = (PORTPROTO *)var->addr;
3501 np = pp->parent;
3502 checkcell = 1;
3503 break;
3504 case VARCINST:
3505 ai = (ARCINST *)var->addr;
3506 np = ai->parent;
3507 checkcell = 1;
3508 break;
3509 case VGEOM:
3510 geom = (GEOM *)var->addr;
3511 np = geomparent(geom);
3512 checkcell = 1;
3513 break;
3514 case VLIBRARY:
3515 lib = (LIBRARY *)var->addr;
3516 if (lib != oldlib) break;
3517 var->addr = (INTBIG)newlib;
3518 break;
3519 case VNETWORK:
3520 net = (NETWORK *)var->addr;
3521 np = net->parent;
3522 checkcell = 1;
3523 break;
3524 }
3525 if (checkcell != 0)
3526 {
3527 if (np->primindex != 0) continue;
3528 if (np->lib != oldlib) continue;
3529
3530 /* cannot correct the reference: delete the variable */
3531 for(j=i+1; j < *numvar; j++)
3532 {
3533 svar = &(*firstvar)[j];
3534 dvar = &(*firstvar)[j-1];
3535 *dvar = *svar;
3536 }
3537 (*numvar)--;
3538 i--;
3539 }
3540 }
3541 }
3542
3543 /*
3544 * Helper routine to find the equivalent to cell "cell" in library "lib".
3545 */
us_findcellinotherlib(NODEPROTO * cell,LIBRARY * lib)3546 NODEPROTO *us_findcellinotherlib(NODEPROTO *cell, LIBRARY *lib)
3547 {
3548 REGISTER NODEPROTO *newnp;
3549
3550 for(newnp = lib->firstnodeproto; newnp != NONODEPROTO; newnp = newnp->nextnodeproto)
3551 {
3552 if (namesame(cell->protoname, newnp->protoname) != 0) continue;
3553 if (cell->cellview != newnp->cellview) continue;
3554 if (cell->version != newnp->version) continue;
3555 break;
3556 }
3557 return(newnp);
3558 }
3559
3560 /******************** TEXT OBJECTS ********************/
3561
3562 /*
3563 * routine to recompute the text descriptor in "descript" to change the
3564 * grab-point according to the location of (xcur, ycur), given that the
3565 * text centers at (xc, yc) and is "xw" by "yw" in size.
3566 */
us_figuregrabpoint(UINTBIG * descript,INTBIG xcur,INTBIG ycur,INTBIG xc,INTBIG yc,INTBIG xw,INTBIG yw)3567 void us_figuregrabpoint(UINTBIG *descript, INTBIG xcur, INTBIG ycur, INTBIG xc,
3568 INTBIG yc, INTBIG xw, INTBIG yw)
3569 {
3570 if (xcur < xc - xw/2)
3571 {
3572 /* grab-point is on the bottom left */
3573 if (ycur < yc - yw/2)
3574 {
3575 TDSETPOS(descript, VTPOSUPRIGHT);
3576 return;
3577 }
3578
3579 /* grab-point is on the top left */
3580 if (ycur > yc + yw/2)
3581 {
3582 TDSETPOS(descript, VTPOSDOWNRIGHT);
3583 return;
3584 }
3585
3586 /* grab-point is on the left */
3587 TDSETPOS(descript, VTPOSRIGHT);
3588 return;
3589 }
3590
3591 if (xcur > xc + xw/2)
3592 {
3593 /* grab-point is on the bottom right */
3594 if (ycur < yc - yw/2)
3595 {
3596 TDSETPOS(descript, VTPOSUPLEFT);
3597 return;
3598 }
3599
3600 /* grab-point is on the top right */
3601 if (ycur > yc + yw/2)
3602 {
3603 TDSETPOS(descript, VTPOSDOWNLEFT);
3604 return;
3605 }
3606
3607 /* grab-point is on the right */
3608 TDSETPOS(descript, VTPOSLEFT);
3609 return;
3610 }
3611
3612 /* grab-point is on the bottom */
3613 if (ycur < yc - yw/2)
3614 {
3615 TDSETPOS(descript, VTPOSUP);
3616 return;
3617 }
3618
3619 /* grab-point is on the top */
3620 if (ycur > yc + yw/2)
3621 {
3622 TDSETPOS(descript, VTPOSDOWN);
3623 return;
3624 }
3625
3626 /* grab-point is in the center: check for VERY center */
3627 if (ycur >= yc - yw/6 && ycur <= yc + yw/6 && xcur >= xc - xw/6 &&
3628 xcur <= xc + xw/6)
3629 {
3630 TDSETPOS(descript, VTPOSBOXED);
3631 return;
3632 }
3633
3634 /* grab-point is simply centered */
3635 TDSETPOS(descript, VTPOSCENT);
3636 }
3637
3638 /*
3639 * routine to return the new text descriptor field, given that the old is in
3640 * "formerdesc". The instructions for changing this variable are in "count"
3641 * and "par", where "count" where the first two values are the X and Y offset,
3642 * and the third value is the text position. Returns -1 on error.
3643 */
us_figurevariableplace(UINTBIG * formerdesc,INTBIG count,CHAR * par[])3644 void us_figurevariableplace(UINTBIG *formerdesc, INTBIG count, CHAR *par[])
3645 {
3646 INTBIG xval, yval;
3647 REGISTER INTBIG grab;
3648
3649 if (count >= 2)
3650 {
3651 xval = atofr(par[0]) * 4 / WHOLE;
3652 yval = atofr(par[1]) * 4 / WHOLE;
3653 us_setdescriptoffset(formerdesc, xval, yval);
3654 }
3655 if (count >= 3)
3656 {
3657 grab = us_gettextposition(par[2]);
3658 TDSETPOS(formerdesc, grab);
3659 }
3660 }
3661
3662 /*
3663 * routine to change the X and Y offset factors in the text descriptor
3664 * "formerdesc" to "xval" and "yval". Returns the new text descriptor.
3665 */
us_setdescriptoffset(UINTBIG * formerdesc,INTBIG xval,INTBIG yval)3666 void us_setdescriptoffset(UINTBIG *formerdesc, INTBIG xval, INTBIG yval)
3667 {
3668 REGISTER INTBIG oldx, oldy;
3669
3670 /* make sure the range is proper */
3671 oldx = xval; oldy = yval;
3672 propervaroffset(&xval, &yval);
3673 if (xval != oldx || yval != oldy)
3674 ttyputmsg(_("Text offset adjusted"));
3675
3676 TDSETOFF(formerdesc, xval, yval);
3677 }
3678
3679 /*
3680 * routine to rotate the text descriptor in "descript" to account for
3681 * the rotation of the object on which it resides: "geom". The new
3682 * text descriptor is returned.
3683 */
us_rotatedescript(GEOM * geom,UINTBIG * descript)3684 void us_rotatedescript(GEOM *geom, UINTBIG *descript)
3685 {
3686 us_rotatedescriptArb(geom, descript, FALSE);
3687 }
3688
3689 /*
3690 * routine to undo the rotation of the text descriptor in "descript" to account for
3691 * the rotation of the object on which it resides: "geom". The new
3692 * text descriptor is returned.
3693 */
us_rotatedescriptI(GEOM * geom,UINTBIG * descript)3694 void us_rotatedescriptI(GEOM *geom, UINTBIG *descript)
3695 {
3696 us_rotatedescriptArb(geom, descript, TRUE);
3697 }
3698
3699 /*
3700 * routine to rotate the text descriptor in "descript" to account for
3701 * the rotation of the object on which it resides: "geom". Inverts the
3702 * sense of the rotation if "invert" is true. The new
3703 * text descriptor is returned.
3704 */
us_rotatedescriptArb(GEOM * geom,UINTBIG * descript,BOOLEAN invert)3705 void us_rotatedescriptArb(GEOM *geom, UINTBIG *descript, BOOLEAN invert)
3706 {
3707 REGISTER INTBIG style;
3708 REGISTER NODEINST *ni;
3709 XARRAY trans;
3710
3711 /* arcs do not rotate */
3712 if (!geom->entryisnode) return;
3713
3714 switch (TDGETPOS(descript))
3715 {
3716 case VTPOSCENT:
3717 case VTPOSBOXED: return;
3718 case VTPOSUP: style = TEXTBOT; break;
3719 case VTPOSDOWN: style = TEXTTOP; break;
3720 case VTPOSLEFT: style = TEXTRIGHT; break;
3721 case VTPOSRIGHT: style = TEXTLEFT; break;
3722 case VTPOSUPLEFT: style = TEXTBOTRIGHT; break;
3723 case VTPOSUPRIGHT: style = TEXTBOTLEFT; break;
3724 case VTPOSDOWNLEFT: style = TEXTTOPRIGHT; break;
3725 case VTPOSDOWNRIGHT: style = TEXTTOPLEFT; break;
3726 default: return;
3727 }
3728 ni = geom->entryaddr.ni;
3729 if (invert)
3730 {
3731 if (ni->transpose == 0) makeangle((3600 - ni->rotation)%3600, 0, trans); else
3732 makeangle(ni->rotation, ni->transpose, trans);
3733 } else
3734 {
3735 makeangle(ni->rotation, ni->transpose, trans);
3736 }
3737 style = rotatelabel(style, TDGETROTATION(descript), trans);
3738 switch (style)
3739 {
3740 case TEXTBOT: TDSETPOS(descript, VTPOSUP); break;
3741 case TEXTTOP: TDSETPOS(descript, VTPOSDOWN); break;
3742 case TEXTRIGHT: TDSETPOS(descript, VTPOSLEFT); break;
3743 case TEXTLEFT: TDSETPOS(descript, VTPOSRIGHT); break;
3744 case TEXTBOTRIGHT: TDSETPOS(descript, VTPOSUPLEFT); break;
3745 case TEXTBOTLEFT: TDSETPOS(descript, VTPOSUPRIGHT); break;
3746 case TEXTTOPRIGHT: TDSETPOS(descript, VTPOSDOWNLEFT); break;
3747 case TEXTTOPLEFT: TDSETPOS(descript, VTPOSDOWNRIGHT); break;
3748 }
3749 }
3750
3751 /*
3752 * routine to adjust the displayable text on node "ni" to account for new
3753 * size/rotation factors in the node. This is only done for invisible pins
3754 * in the generic technology, where the displayable text must track the node.
3755 */
us_adjustdisplayabletext(NODEINST * ni)3756 void us_adjustdisplayabletext(NODEINST *ni)
3757 {
3758 REGISTER INTBIG i;
3759 REGISTER INTBIG halfx, halfy, lambda;
3760 UINTBIG descript[TEXTDESCRIPTSIZE];
3761 REGISTER VARIABLE *var;
3762
3763 /* make sure this is the invisible pin */
3764 if (ni->proto != gen_invispinprim) return;
3765
3766 /* search for displayable text */
3767 for(i=0; i<ni->numvar; i++)
3768 {
3769 var = &ni->firstvar[i];
3770 if ((var->type&VDISPLAY) == 0) continue;
3771
3772 /* compute the proper display offset */
3773 TDCOPY(descript, var->textdescript);
3774 lambda = lambdaofnode(ni);
3775 halfx = (ni->highx - ni->lowx) * 2 / lambda;
3776 halfy = (ni->highy - ni->lowy) * 2 / lambda;
3777 switch (TDGETPOS(descript))
3778 {
3779 case VTPOSCENT:
3780 case VTPOSBOXED:
3781 us_setdescriptoffset(descript, 0, 0);
3782 break;
3783 case VTPOSUP:
3784 us_setdescriptoffset(descript, 0, -halfy);
3785 break;
3786 case VTPOSDOWN:
3787 us_setdescriptoffset(descript, 0, halfy);
3788 break;
3789 case VTPOSLEFT:
3790 us_setdescriptoffset(descript, halfx, 0);
3791 break;
3792 case VTPOSRIGHT:
3793 us_setdescriptoffset(descript, -halfx, 0);
3794 break;
3795 case VTPOSUPLEFT:
3796 us_setdescriptoffset(descript, halfx, -halfy);
3797 break;
3798 case VTPOSUPRIGHT:
3799 us_setdescriptoffset(descript, -halfx, -halfy);
3800 break;
3801 case VTPOSDOWNLEFT:
3802 us_setdescriptoffset(descript, halfx, halfy);
3803 break;
3804 case VTPOSDOWNRIGHT:
3805 us_setdescriptoffset(descript, -halfx, halfy);
3806 break;
3807 }
3808 modifydescript((INTBIG)ni, VNODEINST, var, descript);
3809 }
3810 }
3811
3812 /*
3813 * routine to parse the "grab-point" specification in "pp" and return the
3814 * code. Prints an error message on error.
3815 */
us_gettextposition(CHAR * pp)3816 INTBIG us_gettextposition(CHAR *pp)
3817 {
3818 REGISTER INTBIG l;
3819
3820 l = estrlen(pp);
3821 if (namesamen(pp, x_("centered"), l) == 0 && l >= 1) return(VTPOSCENT);
3822 if (namesamen(pp, x_("boxed"), l) == 0 && l >= 1) return(VTPOSBOXED);
3823 if (namesame(pp, x_("up")) == 0) return(VTPOSUP);
3824 if (namesame(pp, x_("down")) == 0) return(VTPOSDOWN);
3825 if (namesamen(pp, x_("left"), l) == 0 && l >= 1) return(VTPOSLEFT);
3826 if (namesamen(pp, x_("right"), l) == 0 && l >= 1) return(VTPOSRIGHT);
3827 if (namesamen(pp, x_("up-left"), l) == 0 && l >= 4) return(VTPOSUPLEFT);
3828 if (namesamen(pp, x_("up-right"), l) == 0 && l >= 4) return(VTPOSUPRIGHT);
3829 if (namesamen(pp, x_("down-left"), l) == 0 && l >= 6) return(VTPOSDOWNLEFT);
3830 if (namesamen(pp, x_("down-right"), l) == 0 && l >= 6) return(VTPOSDOWNRIGHT);
3831 us_abortcommand(_("Unrecognized grab-point: %s"), pp);
3832 return(VTPOSCENT);
3833 }
3834
3835 /*
3836 * routine to parse the "text size" specification in "pp" and return the
3837 * code. Prints an error message and returns -1 on error.
3838 */
us_gettextsize(CHAR * pp,INTBIG old)3839 INTBIG us_gettextsize(CHAR *pp, INTBIG old)
3840 {
3841 REGISTER INTBIG i, l;
3842
3843 l = estrlen(pp);
3844 if (tolower(pp[l-1]) == 'p')
3845 {
3846 l = eatoi(pp);
3847 if (l <= 0) l = 8;
3848 if (l > TXTMAXPOINTS) l = TXTMAXPOINTS;
3849 return(TXTSETPOINTS(l));
3850 }
3851 if (tolower(pp[l-1]) == 'l')
3852 {
3853 l = atofr(pp) * 4 / WHOLE;
3854 if (l <= 0) l = 4;
3855 if (l > TXTMAXQLAMBDA) l = TXTMAXQLAMBDA;
3856 return(TXTSETQLAMBDA(l));
3857 }
3858 if (namesamen(pp, x_("up"), l) == 0 && l >= 1)
3859 {
3860 i = TXTGETPOINTS(old);
3861 if (i > 0 && i < TXTMAXPOINTS) old = TXTSETPOINTS(i+1); else
3862 {
3863 i = TXTGETQLAMBDA(old);
3864 if (i > 0 && i < TXTMAXQLAMBDA) old = TXTSETQLAMBDA(i+1);
3865 }
3866 return(old);
3867 } else if (namesamen(pp, x_("down"), l) == 0 && l >= 1)
3868 {
3869 i = TXTGETPOINTS(old);
3870 if (i > 1) old = TXTSETPOINTS(i-1); else
3871 {
3872 i = TXTGETQLAMBDA(old);
3873 if (i > 1) old = TXTSETQLAMBDA(i-1);
3874 }
3875 return(old);
3876 }
3877 us_abortcommand(_("Unrecognized text size: %s"), pp);
3878 return(-1);
3879 }
3880
3881 static NODEINST *us_searchcircuittextni;
3882 static ARCINST *us_searchcircuittextai;
3883 static PORTPROTO *us_searchcircuittextpp;
3884 static INTBIG us_searchcircuittextvarnum; /* number of the variable on this text */
3885 static INTBIG us_searchcircuittextline; /* line number (in multiline text) */
3886 static INTBIG us_searchcircuittextstart; /* starting character position */
3887 static INTBIG us_searchcircuittextend; /* ending character position */
3888 static BOOLEAN us_searchcircuittextfound; /* true if text is selected */
3889
3890 /*
3891 * Routine to initialize text searching in edit window "win".
3892 */
us_initsearchcircuittext(WINDOWPART * win)3893 void us_initsearchcircuittext(WINDOWPART *win)
3894 {
3895 REGISTER NODEPROTO *np;
3896
3897 np = win->curnodeproto;
3898 if (np == NONODEPROTO) return;
3899 us_searchcircuittextni = np->firstnodeinst;
3900 us_searchcircuittextai = np->firstarcinst;
3901 us_searchcircuittextpp = np->firstportproto;
3902 us_searchcircuittextvarnum = 0;
3903 us_searchcircuittextfound = FALSE;
3904 }
3905
us_advancecircuittext(CHAR * search,INTBIG bits)3906 void us_advancecircuittext(CHAR *search, INTBIG bits)
3907 {
3908 REGISTER NODEINST *ni;
3909 REGISTER ARCINST *ai;
3910 REGISTER PORTPROTO *pp;
3911 REGISTER CHAR *pt;
3912 REGISTER INTBIG len;
3913 REGISTER VARIABLE *var;
3914 HIGHLIGHT newhigh;
3915
3916 /* look for a node with this string */
3917 while (us_searchcircuittextni != NONODEINST)
3918 {
3919 ni = us_searchcircuittextni;
3920 while (us_searchcircuittextvarnum < ni->numvar)
3921 {
3922 var = &ni->firstvar[us_searchcircuittextvarnum];
3923 us_searchcircuittextvarnum++;
3924 if ((var->type&VDISPLAY) == 0) continue;
3925 if ((var->type&VTYPE) != VSTRING) continue;
3926 if ((var->type&VISARRAY) == 0)
3927 {
3928 pt = (CHAR *)var->addr;
3929 us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3930 if (us_searchcircuittextstart < 0) continue;
3931 us_searchcircuittextend = us_searchcircuittextstart + estrlen(search);
3932
3933 /* show the text */
3934 us_clearhighlightcount();
3935 newhigh.status = HIGHTEXT;
3936 newhigh.cell = ni->parent;
3937 newhigh.fromgeom = ni->geom;
3938 newhigh.fromport = NOPORTPROTO;
3939 newhigh.frompoint = 0;
3940 newhigh.fromvar = var;
3941 newhigh.fromvarnoeval = NOVARIABLE;
3942 us_addhighlight(&newhigh);
3943 us_showallhighlight();
3944 us_endchanges(NOWINDOWPART);
3945 us_searchcircuittextfound = TRUE;
3946 return;
3947 } else
3948 {
3949 len = getlength(var);
3950 for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
3951 {
3952 pt = ((CHAR **)var->addr)[us_searchcircuittextline];
3953 us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3954 if (us_searchcircuittextstart < 0) continue;
3955 us_searchcircuittextend = us_searchcircuittextstart + estrlen(search);
3956
3957 /* show the text */
3958 us_clearhighlightcount();
3959 newhigh.status = HIGHTEXT;
3960 newhigh.cell = ni->parent;
3961 newhigh.fromgeom = ni->geom;
3962 newhigh.fromport = NOPORTPROTO;
3963 newhigh.frompoint = 0;
3964 newhigh.fromvar = var;
3965 newhigh.fromvarnoeval = NOVARIABLE;
3966 us_addhighlight(&newhigh);
3967 us_showallhighlight();
3968 us_endchanges(NOWINDOWPART);
3969 us_searchcircuittextfound = TRUE;
3970 return;
3971 }
3972 }
3973 }
3974 us_searchcircuittextni = ni->nextnodeinst;
3975 us_searchcircuittextvarnum = 0;
3976 }
3977
3978 /* look for an arc with this string */
3979 while (us_searchcircuittextai != NOARCINST)
3980 {
3981 ai = us_searchcircuittextai;
3982 while (us_searchcircuittextvarnum < ai->numvar)
3983 {
3984 var = &ai->firstvar[us_searchcircuittextvarnum];
3985 us_searchcircuittextvarnum++;
3986 if ((var->type&VDISPLAY) == 0) continue;
3987 if ((var->type&VTYPE) != VSTRING) continue;
3988 if ((var->type&VISARRAY) == 0)
3989 {
3990 pt = (CHAR *)var->addr;
3991 us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3992 if (us_searchcircuittextstart < 0) continue;
3993 us_searchcircuittextend = us_searchcircuittextstart + estrlen(search);
3994
3995 /* show the text */
3996 us_clearhighlightcount();
3997 newhigh.status = HIGHTEXT;
3998 newhigh.cell = ai->parent;
3999 newhigh.fromgeom = ai->geom;
4000 newhigh.fromport = NOPORTPROTO;
4001 newhigh.frompoint = 0;
4002 newhigh.fromvar = var;
4003 newhigh.fromvarnoeval = NOVARIABLE;
4004 us_addhighlight(&newhigh);
4005 us_showallhighlight();
4006 us_endchanges(NOWINDOWPART);
4007 us_searchcircuittextfound = TRUE;
4008 return;
4009 } else
4010 {
4011 len = getlength(var);
4012 for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
4013 {
4014 pt = ((CHAR **)var->addr)[us_searchcircuittextline];
4015 us_searchcircuittextstart = us_stringinstring(pt, search, bits);
4016 if (us_searchcircuittextstart < 0) continue;
4017 us_searchcircuittextend = us_searchcircuittextstart + estrlen(search);
4018
4019 /* show the text */
4020 us_clearhighlightcount();
4021 newhigh.status = HIGHTEXT;
4022 newhigh.cell = ai->parent;
4023 newhigh.fromgeom = ai->geom;
4024 newhigh.fromport = NOPORTPROTO;
4025 newhigh.frompoint = 0;
4026 newhigh.fromvar = var;
4027 newhigh.fromvarnoeval = NOVARIABLE;
4028 us_addhighlight(&newhigh);
4029 us_showallhighlight();
4030 us_endchanges(NOWINDOWPART);
4031 us_searchcircuittextfound = TRUE;
4032 return;
4033 }
4034 }
4035 }
4036 us_searchcircuittextai = ai->nextarcinst;
4037 us_searchcircuittextvarnum = 0;
4038 }
4039
4040 /* look for an export with this string */
4041 while (us_searchcircuittextpp != NOPORTPROTO)
4042 {
4043 pp = us_searchcircuittextpp;
4044 us_searchcircuittextpp = pp->nextportproto;
4045 us_searchcircuittextstart = us_stringinstring(pp->protoname, search, bits);
4046 if (us_searchcircuittextstart < 0) continue;
4047 us_searchcircuittextend = us_searchcircuittextstart + estrlen(search);
4048
4049 /* show the text */
4050 us_clearhighlightcount();
4051 newhigh.status = HIGHTEXT;
4052 newhigh.cell = pp->parent;
4053 newhigh.fromgeom = pp->subnodeinst->geom;
4054 newhigh.fromport = pp;
4055 newhigh.frompoint = 0;
4056 newhigh.fromvar = NOVARIABLE;
4057 newhigh.fromvarnoeval = NOVARIABLE;
4058 us_addhighlight(&newhigh);
4059 us_showallhighlight();
4060 us_endchanges(NOWINDOWPART);
4061 us_searchcircuittextfound = TRUE;
4062 return;
4063 }
4064 us_searchcircuittextfound = FALSE;
4065 }
4066
4067 /*
4068 * Routine to look for the substring "search" inside of the larger string "string".
4069 * if "bits" has 4 in it, the search is case sensitive. Returns the character
4070 * position in "string" of where "search" is found (-1 if not found).
4071 */
us_stringinstring(CHAR * string,CHAR * search,INTBIG bits)4072 INTBIG us_stringinstring(CHAR *string, CHAR *search, INTBIG bits)
4073 {
4074 REGISTER INTBIG stringlen, searchlen, searchwid, i;
4075
4076 stringlen = estrlen(string);
4077 searchlen = estrlen(search);
4078 searchwid = stringlen - searchlen;
4079 if (searchwid < 0) return(-1);
4080 if ((bits&4) == 0)
4081 {
4082 for(i=0; i<=searchwid; i++)
4083 if (namesamen(&string[i], search, searchlen) == 0) return(i);
4084 } else
4085 {
4086 for(i=0; i<=searchwid; i++)
4087 if (estrncmp(&string[i], search, searchlen) == 0) return(i);
4088 }
4089 return(-1);
4090 }
4091
4092 /*
4093 * Routine to find the string "search" in the circuit in window "win". "bits" is:
4094 * 2 replace all with "replaceall"
4095 * 4 case sensitive
4096 * 8 find reverse
4097 */
us_searchcircuittext(WINDOWPART * win,CHAR * search,CHAR * replaceall,INTBIG bits)4098 void us_searchcircuittext(WINDOWPART *win, CHAR *search, CHAR *replaceall, INTBIG bits)
4099 {
4100 REGISTER NODEPROTO *np;
4101 REGISTER INTBIG total;
4102
4103 np = win->curnodeproto;
4104 if (np == NONODEPROTO) return;
4105
4106 if ((bits&2) != 0)
4107 {
4108 total = 0;
4109 for(;;)
4110 {
4111 /* advance to the next circuit text */
4112 us_advancecircuittext(search, bits);
4113 if (!us_searchcircuittextfound) break;
4114 us_replacecircuittext(win, replaceall);
4115 total++;
4116 }
4117 if (total == 0) ttybeep(SOUNDBEEP, TRUE); else
4118 ttyputmsg(_("Replaced %ld times"), total);
4119 return;
4120 }
4121 us_advancecircuittext(search, bits);
4122 if (!us_searchcircuittextfound) ttybeep(SOUNDBEEP, TRUE);
4123 }
4124
4125 /*
4126 * Routine to replace the text last selected with "us_searchcircuittext()" with
4127 * the string "replace".
4128 */
us_replacecircuittext(WINDOWPART * win,CHAR * replace)4129 void us_replacecircuittext(WINDOWPART *win, CHAR *replace)
4130 {
4131 REGISTER HIGHLIGHT *high;
4132 REGISTER INTBIG i, len, addr, type;
4133 REGISTER VARIABLE *var;
4134 REGISTER NODEINST *ni;
4135 REGISTER PORTPROTO *pp;
4136 REGISTER CHAR *pt;
4137 CHAR *newname;
4138 REGISTER void *infstr;
4139 Q_UNUSED( win );
4140
4141 if (!us_searchcircuittextfound) return;
4142 high = us_getonehighlight();
4143 if (high->status != HIGHTEXT) return;
4144 if (high->fromgeom->entryisnode && high->fromvar == NOVARIABLE)
4145 {
4146 /* export text */
4147 ni = high->fromgeom->entryaddr.ni;
4148 pp = high->fromport;
4149 infstr = initinfstr();
4150 for(i=0; i<us_searchcircuittextstart; i++)
4151 addtoinfstr(infstr, pp->protoname[i]);
4152 addstringtoinfstr(infstr, replace);
4153 len = estrlen(pp->protoname);
4154 for(i=us_searchcircuittextend; i<len; i++)
4155 addtoinfstr(infstr, pp->protoname[i]);
4156 us_pushhighlight();
4157 us_clearhighlightcount();
4158 us_renameport(pp, returninfstr(infstr));
4159 us_pophighlight(FALSE);
4160 us_endchanges(NOWINDOWPART);
4161 return;
4162 }
4163
4164 /* rename variable */
4165 var = high->fromvar;
4166 if (var == NOVARIABLE) return;
4167 addr = (INTBIG)high->fromgeom->entryaddr.blind;
4168 if (high->fromgeom->entryisnode) type = VNODEINST; else
4169 type = VARCINST;
4170 us_pushhighlight();
4171 us_clearhighlightcount();
4172 startobjectchange(addr, type);
4173 if ((var->type&VISARRAY) != 0)
4174 {
4175 pt = ((CHAR **)var->addr)[us_searchcircuittextline];
4176 infstr = initinfstr();
4177 for(i=0; i<us_searchcircuittextstart; i++)
4178 addtoinfstr(infstr, pt[i]);
4179 addstringtoinfstr(infstr, replace);
4180 len = estrlen(pt);
4181 for(i=us_searchcircuittextend; i<len; i++)
4182 addtoinfstr(infstr, pt[i]);
4183 allocstring(&newname, returninfstr(infstr), el_tempcluster);
4184 (void)setindkey(addr, type, var->key, us_searchcircuittextline,
4185 (INTBIG)newname);
4186 efree(newname);
4187 } else
4188 {
4189 pt = (CHAR *)var->addr;
4190 infstr = initinfstr();
4191 for(i=0; i<us_searchcircuittextstart; i++)
4192 addtoinfstr(infstr, pt[i]);
4193 addstringtoinfstr(infstr, replace);
4194 len = estrlen(pt);
4195 for(i=us_searchcircuittextend; i<len; i++)
4196 addtoinfstr(infstr, pt[i]);
4197 allocstring(&newname, returninfstr(infstr), el_tempcluster);
4198 (void)setvalkey(addr, type, var->key, (INTBIG)newname,
4199 var->type);
4200 efree(newname);
4201 }
4202 endobjectchange(addr, type);
4203 us_pophighlight(FALSE);
4204 us_endchanges(NOWINDOWPART);
4205 }
4206
4207 /************************ IN-PLACE VARIABLE EDITING ************************/
4208
4209 static INTBIG us_editvarstartline, us_editvarstartchar;
4210 static INTBIG us_editvarlabellen;
4211 static INTBIG us_editvarendline, us_editvarendchar;
4212 static INTBIG us_editvarclickline, us_editvarclickchar;
4213 static VARIABLE *us_editvariable;
4214 static INTBIG us_editvarlength;
4215 static INTBIG us_editvarlineheight;
4216 static INTBIG us_editvarobjtype;
4217 static INTBIG us_editvarobjaddr;
4218 static BOOLEAN us_editvariabledoubleclick;
4219 static CHAR **us_editvarlines;
4220 static CHAR *us_editvaroneline[1];
4221 static CHAR *us_editvarvarname = 0;
4222 static TECHNOLOGY *us_editvartech;
4223
4224 static void us_editvariabletexthighlight(void);
4225 static BOOLEAN us_editvariabletexteachdown(INTBIG x, INTBIG y);
4226 static BOOLEAN us_editvariabletextfindpos(INTBIG x, INTBIG y, INTBIG *line, INTBIG *chr);
4227 static void us_editvariableforcefullwords(INTBIG *startline, INTBIG *startchar, INTBIG *endline, INTBIG *endchar);
4228 static BOOLEAN us_editvariabletexthandlebutton(INTBIG x, INTBIG y, INTBIG but);
4229 static BOOLEAN us_editvariabletexthandlechar(INTSML chr, INTBIG special);
4230 static void us_editvariabletextreplacetext(CHAR *replace);
4231
us_editvariabletext(VARIABLE * var,INTBIG objtype,INTBIG objaddr,CHAR * varname)4232 void us_editvariabletext(VARIABLE *var, INTBIG objtype, INTBIG objaddr, CHAR *varname)
4233 {
4234 INTBIG tsx, tsy, newtype, newvalue, units;
4235 UINTBIG textdescript[TEXTDESCRIPTSIZE];
4236
4237 /* preserve information in globals */
4238 us_editvariable = var;
4239 us_editvarobjtype = objtype & VTYPE;
4240 us_editvarobjaddr = objaddr;
4241 if (us_editvarvarname == 0) (void)allocstring(&us_editvarvarname, varname, us_tool->cluster); else
4242 (void)reallocstring(&us_editvarvarname, varname, us_tool->cluster);
4243 us_editvarlabellen = 0;
4244 if ((us_editvariable->type&VISARRAY) == 0)
4245 {
4246 us_editvarlength = 1;
4247 (void)allocstring(&us_editvaroneline[0], describedisplayedvariable(var, -1, -1), us_tool->cluster);
4248 if (TDGETDISPPART(var->textdescript) != VTDISPLAYVALUE)
4249 {
4250 TDCOPY(textdescript, var->textdescript);
4251 TDSETDISPPART(var->textdescript, VTDISPLAYVALUE);
4252 us_editvarlabellen = estrlen(us_editvaroneline[0]) - estrlen(describedisplayedvariable(var, -1, -1));
4253 TDCOPY(var->textdescript, textdescript);
4254 }
4255 us_editvarlines = us_editvaroneline;
4256 } else
4257 {
4258 us_editvarlength = getlength(var);
4259 us_editvarlines = (CHAR **)var->addr;
4260 }
4261 switch (objtype)
4262 {
4263 case VNODEINST:
4264 us_editvartech = ((NODEINST *)objaddr)->parent->tech;
4265 break;
4266 case VARCINST:
4267 us_editvartech = ((ARCINST *)objaddr)->parent->tech;
4268 break;
4269 case VPORTPROTO:
4270 us_editvartech = ((PORTPROTO *)objaddr)->subnodeinst->parent->tech;
4271 break;
4272 case VNODEPROTO:
4273 us_editvartech = ((NODEPROTO *)objaddr)->tech;
4274 break;
4275 }
4276
4277 /* flush graphics */
4278 us_endchanges(NOWINDOWPART);
4279
4280 /* determine height of a line of text */
4281 screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4282 screengettextsize(el_curwindowpart, x_("Xy"), &tsx, &tsy);
4283 us_editvarlineheight = tsy;
4284
4285 /* set highlighting to cover all text */
4286 us_editvarstartline = 0;
4287 us_editvarstartchar = us_editvarlabellen;
4288 us_editvarendline = us_editvarlength-1;
4289 us_editvarendchar = estrlen(us_editvarlines[us_editvarendline]);
4290 us_editvariabletexthighlight();
4291
4292 /* loop while editing text */
4293 modalloop(us_editvariabletexthandlechar, us_editvariabletexthandlebutton, IBEAMCURSOR);
4294
4295 /* remove highlighting */
4296 us_editvariabletexthighlight();
4297
4298 /* recalculate the proper type now that editing is done */
4299 if ((us_editvariable->type&VISARRAY) == 0)
4300 {
4301 units = TDGETUNITS(us_editvariable->textdescript);
4302 getsimpletype(&us_editvarlines[0][us_editvarlabellen], &newtype, &newvalue, units);
4303 newtype = (us_editvariable->type & ~VTYPE) | newtype;
4304 if (us_editvarobjtype != VPORTPROTO)
4305 startobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4306 startobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4307 if (us_editvarobjtype == VNODEPROTO)
4308 us_undrawcellvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4309 var = setval(us_editvarobjaddr, us_editvarobjtype,
4310 us_editvarvarname, newvalue, newtype);
4311 if (var != NOVARIABLE) us_editvariable = var;
4312 if (us_editvarobjtype == VNODEPROTO)
4313 us_drawcellvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4314 if (us_editvarobjtype != VPORTPROTO)
4315 endobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4316 endobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4317 us_endchanges(NOWINDOWPART);
4318 }
4319 }
4320
us_editvariabletexthandlebutton(INTBIG x,INTBIG y,INTBIG but)4321 static BOOLEAN us_editvariabletexthandlebutton(INTBIG x, INTBIG y, INTBIG but)
4322 {
4323 INTBIG line, chr;
4324
4325 us_editvariabledoubleclick = doublebutton(but);
4326 if (!us_editvariabletextfindpos(x, y, &line, &chr)) return(TRUE);
4327 us_editvariabletexthighlight();
4328 if (line == 0 && chr < us_editvarlabellen) chr = us_editvarlabellen;
4329 if (shiftbutton(but))
4330 {
4331 if (line < us_editvarstartline || (line == us_editvarstartline &&
4332 chr < us_editvarstartchar))
4333 {
4334 us_editvarstartline = line;
4335 us_editvarstartchar = chr;
4336 } else if (line > us_editvarendline || (line == us_editvarendline &&
4337 chr > us_editvarendchar))
4338 {
4339 us_editvarendline = line;
4340 us_editvarendchar = chr;
4341 }
4342 } else
4343 {
4344 us_editvarstartline = line;
4345 us_editvarstartchar = chr;
4346 us_editvarendline = line;
4347 us_editvarendchar = chr;
4348 }
4349 us_editvarclickline = line;
4350 us_editvarclickchar = chr;
4351 if (us_editvariabledoubleclick)
4352 us_editvariableforcefullwords(&us_editvarstartline, &us_editvarstartchar,
4353 &us_editvarendline, &us_editvarendchar);
4354 us_editvariabletexthighlight();
4355
4356 trackcursor(FALSE, us_ignoreup, us_nullvoid, us_editvariabletexteachdown, us_stoponchar,
4357 us_nullvoid, TRACKNORMAL);
4358 return(FALSE);
4359 }
4360
us_editvariabletexthandlechar(INTSML chr,INTBIG special)4361 BOOLEAN us_editvariabletexthandlechar(INTSML chr, INTBIG special)
4362 {
4363 CHAR replace[2], *pt;
4364 REGISTER INTBIG startchar, endchar, i, j;
4365 REGISTER void *infstr;
4366
4367 if ((special&SPECIALKEYDOWN) != 0)
4368 {
4369 switch ((special&SPECIALKEY)>>SPECIALKEYSH)
4370 {
4371 case SPECIALKEYARROWL:
4372 us_editvariabletexthighlight();
4373 if (us_editvarstartline == us_editvarendline &&
4374 us_editvarstartchar == us_editvarendchar)
4375 {
4376 if (us_editvarstartchar > 0)
4377 {
4378 if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4379 us_editvarstartchar--;
4380 } else
4381 {
4382 if (us_editvarstartline > 0)
4383 {
4384 us_editvarstartline--;
4385 us_editvarstartchar = estrlen(us_editvarlines[us_editvarstartline]);
4386 }
4387 }
4388 }
4389 us_editvarendline = us_editvarstartline;
4390 us_editvarendchar = us_editvarstartchar;
4391 us_editvariabletexthighlight();
4392 return(FALSE);
4393 case SPECIALKEYARROWR:
4394 us_editvariabletexthighlight();
4395 if (us_editvarstartline == us_editvarendline &&
4396 us_editvarstartchar == us_editvarendchar)
4397 {
4398 if (us_editvarendchar < (INTBIG)estrlen(us_editvarlines[us_editvarendline]))
4399 us_editvarendchar++; else
4400 {
4401 if (us_editvarendline < us_editvarlength-1)
4402 {
4403 us_editvarendline++;
4404 us_editvarendchar = 0;
4405 }
4406 }
4407 }
4408 us_editvarstartline = us_editvarendline;
4409 us_editvarstartchar = us_editvarendchar;
4410 us_editvariabletexthighlight();
4411 return(FALSE);
4412 case SPECIALKEYARROWU:
4413 us_editvariabletexthighlight();
4414 if (us_editvarstartline > 0)
4415 {
4416 us_editvarstartline--;
4417 if (us_editvarstartchar > (INTBIG)estrlen(us_editvarlines[us_editvarstartline]))
4418 us_editvarstartchar = estrlen(us_editvarlines[us_editvarstartline]);
4419 }
4420 us_editvarendline = us_editvarstartline;
4421 us_editvarendchar = us_editvarstartchar;
4422 us_editvariabletexthighlight();
4423 return(FALSE);
4424 case SPECIALKEYARROWD:
4425 us_editvariabletexthighlight();
4426 if (us_editvarendline < us_editvarlength-1)
4427 {
4428 us_editvarendline++;
4429 if (us_editvarendchar > (INTBIG)estrlen(us_editvarlines[us_editvarendline]))
4430 us_editvarendchar = estrlen(us_editvarlines[us_editvarendline]);
4431 }
4432 us_editvarstartline = us_editvarendline;
4433 us_editvarstartchar = us_editvarendchar;
4434 us_editvariabletexthighlight();
4435 return(FALSE);
4436 }
4437 }
4438
4439 /* handle paste */
4440 if ((special&ACCELERATORDOWN) != 0)
4441 {
4442 if (chr == 'v' || chr == 'V')
4443 {
4444 pt = getcutbuffer();
4445 us_editvariabletexthighlight();
4446 us_editvariabletextreplacetext(pt);
4447 if ((us_editvariable->type&VISARRAY) == 0)
4448 {
4449 (void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4450 us_tool->cluster);
4451 us_editvarlines = us_editvaroneline;
4452 } else
4453 {
4454 us_editvarlength = getlength(us_editvariable);
4455 us_editvarlines = (CHAR **)us_editvariable->addr;
4456 }
4457 us_editvariabletexthighlight();
4458 return(FALSE);
4459 }
4460
4461 /* handle copy/cut */
4462 if (chr == 'c' || chr == 'C' ||
4463 chr == 'x' || chr == 'X')
4464 {
4465 infstr = initinfstr();
4466 for(i=us_editvarstartline; i<=us_editvarendline; i++)
4467 {
4468 if (i > us_editvarstartline) addtoinfstr(infstr, '\n');
4469 startchar = 0;
4470 endchar = estrlen(us_editvarlines[i]);
4471 if (i == us_editvarstartline) startchar = us_editvarstartchar;
4472 if (i == us_editvarendline) endchar = us_editvarendchar;
4473 for(j=startchar; j<endchar; j++)
4474 addtoinfstr(infstr, us_editvarlines[i][j]);
4475 }
4476 setcutbuffer(returninfstr(infstr));
4477 if (chr == 'c' || chr == 'C') return(FALSE);
4478 chr = 0;
4479 }
4480 }
4481
4482 /* delete what is selected and insert what was typed */
4483 if (chr == '\n' || chr == '\r')
4484 {
4485 /* cannot insert second line if text is not an array */
4486 if ((us_editvariable->type&VISARRAY) == 0) return(TRUE);
4487 }
4488 us_editvariabletexthighlight();
4489 if (chr == DELETEKEY || chr == BACKSPACEKEY)
4490 {
4491 chr = 0;
4492 if (us_editvarstartline == us_editvarendline &&
4493 us_editvarstartchar == us_editvarendchar)
4494 {
4495 if (us_editvarstartchar > 0)
4496 {
4497 if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4498 us_editvarstartchar--;
4499 } else
4500 {
4501 if (us_editvarstartline > 0)
4502 {
4503 us_editvarstartline--;
4504 us_editvarstartchar = estrlen(us_editvarlines[us_editvarstartline]);
4505 }
4506 }
4507 }
4508 }
4509 replace[0] = (CHAR)chr;
4510 replace[1] = 0;
4511 us_editvariabletextreplacetext(replace);
4512 if ((us_editvariable->type&VISARRAY) == 0)
4513 {
4514 (void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4515 us_tool->cluster);
4516 us_editvarlines = us_editvaroneline;
4517 } else
4518 {
4519 us_editvarlength = getlength(us_editvariable);
4520 us_editvarlines = (CHAR **)us_editvariable->addr;
4521 }
4522 us_editvariabletexthighlight();
4523 return(FALSE);
4524 }
4525
us_editvariabletextreplacetext(CHAR * replace)4526 void us_editvariabletextreplacetext(CHAR *replace)
4527 {
4528 void *stringarray;
4529 REGISTER INTBIG i, newline, newchar;
4530 CHAR **newtext;
4531 REGISTER VARIABLE *var;
4532 INTBIG newtype, newvalue, count;
4533 REGISTER void *infstr;
4534
4535 stringarray = newstringarray(el_tempcluster);
4536
4537 /* add all lines before the start of selection */
4538 newline = 0;
4539 for(i=0; i<us_editvarstartline; i++)
4540 {
4541 if (i != 0) addtostringarray(stringarray, us_editvarlines[i]); else
4542 addtostringarray(stringarray, &us_editvarlines[i][us_editvarlabellen]);
4543 newline++;
4544 }
4545
4546 /* build the line with the selection start */
4547 if (newline == 0) newchar = us_editvarlabellen; else newchar = 0;
4548 infstr = initinfstr();
4549 for(i=newchar; i<us_editvarstartchar; i++)
4550 {
4551 addtoinfstr(infstr, us_editvarlines[us_editvarstartline][i]);
4552 newchar++;
4553 }
4554
4555 /* now add the replacement text */
4556 for(i=0; i<(INTBIG)estrlen(replace); i++)
4557 {
4558 if (replace[i] == '\n' || replace[i] == '\r')
4559 {
4560 addtostringarray(stringarray, returninfstr(infstr));
4561 infstr = initinfstr();
4562 newline++;
4563 newchar = 0;
4564 } else
4565 {
4566 addtoinfstr(infstr, replace[i]);
4567 newchar++;
4568 }
4569 }
4570
4571 /* now add the line with the selection end */
4572 for(i=us_editvarendchar; i<(INTBIG)estrlen(us_editvarlines[us_editvarendline]); i++)
4573 addtoinfstr(infstr, us_editvarlines[us_editvarendline][i]);
4574 addtostringarray(stringarray, returninfstr(infstr));
4575
4576 /* add all lines after the end of selection */
4577 for(i=us_editvarendline+1; i<us_editvarlength; i++)
4578 addtostringarray(stringarray, us_editvarlines[i]);
4579
4580 /* get the new text and put it on the object */
4581 newtext = getstringarray(stringarray, &count);
4582 if (us_editvarobjtype != VPORTPROTO)
4583 startobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4584 startobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4585 if (us_editvarobjtype == VNODEPROTO)
4586 us_undrawcellvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4587 if ((us_editvariable->type&VISARRAY) == 0)
4588 {
4589 /* presume a string for now: recompute type when done editing */
4590 newvalue = (INTBIG)newtext[0];
4591 newtype = (us_editvariable->type & ~VTYPE) | VSTRING;
4592 var = setval(us_editvarobjaddr, us_editvarobjtype,
4593 us_editvarvarname, newvalue, newtype);
4594 } else
4595 {
4596 newtype = (us_editvariable->type & ~VLENGTH) | (count << VLENGTHSH);
4597 var = setval(us_editvarobjaddr, us_editvarobjtype,
4598 us_editvarvarname, (INTBIG)newtext, newtype);
4599 }
4600 if (var != NOVARIABLE) us_editvariable = var;
4601 if (us_editvarobjtype == VNODEPROTO)
4602 us_drawcellvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4603 if (us_editvarobjtype != VPORTPROTO)
4604 endobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4605 endobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4606 us_endchanges(NOWINDOWPART);
4607 killstringarray(stringarray);
4608
4609 /* set the new selection point */
4610 us_editvarstartline = us_editvarendline = newline;
4611 us_editvarstartchar = us_editvarendchar = newchar;
4612 }
4613
us_editvariabletexteachdown(INTBIG x,INTBIG y)4614 BOOLEAN us_editvariabletexteachdown(INTBIG x, INTBIG y)
4615 {
4616 INTBIG line, chr, startline, startchar, endline, endchar;
4617
4618 if (!us_editvariabletextfindpos(x, y, &line, &chr)) return(FALSE);
4619 if (line == 0 && chr < us_editvarlabellen) chr = us_editvarlabellen;
4620 startline = us_editvarstartline;
4621 startchar = us_editvarstartchar;
4622 endline = us_editvarendline;
4623 endchar = us_editvarendchar;
4624 if (line > us_editvarclickline || (line == us_editvarclickline && chr > us_editvarclickchar))
4625 {
4626 startline = us_editvarclickline;
4627 startchar = us_editvarclickchar;
4628 endline = line;
4629 endchar = chr;
4630 if (us_editvariabledoubleclick)
4631 us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4632 }
4633 if (line < us_editvarclickline || (line == us_editvarclickline && chr < us_editvarclickchar))
4634 {
4635 startline = line;
4636 startchar = chr;
4637 endline = us_editvarclickline;
4638 endchar = us_editvarclickchar;
4639 if (us_editvariabledoubleclick)
4640 us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4641 }
4642 if (startline != us_editvarstartline || startchar != us_editvarstartchar ||
4643 endline != us_editvarendline || endchar != us_editvarendchar)
4644 {
4645 us_editvariabletexthighlight();
4646 us_editvarstartline = startline;
4647 us_editvarstartchar = startchar;
4648 us_editvarendline = endline;
4649 us_editvarendchar = endchar;
4650 us_editvariabletexthighlight();
4651 }
4652 return(FALSE);
4653 }
4654
us_editvariableforcefullwords(INTBIG * startline,INTBIG * startchar,INTBIG * endline,INTBIG * endchar)4655 void us_editvariableforcefullwords(INTBIG *startline, INTBIG *startchar, INTBIG *endline, INTBIG *endchar)
4656 {
4657 CHAR *pt;
4658 INTBIG len;
4659
4660 pt = us_editvarlines[*startline];
4661 while (*startchar > 0 && isalnum(pt[*startchar - 1]))
4662 (*startchar)--;
4663
4664 pt = us_editvarlines[*endline];
4665 len = estrlen(pt);
4666 while (*endchar < len && isalnum(pt[*endchar]))
4667 (*endchar)++;
4668 }
4669
us_editvariabletextfindpos(INTBIG xp,INTBIG yp,INTBIG * line,INTBIG * chr)4670 BOOLEAN us_editvariabletextfindpos(INTBIG xp, INTBIG yp, INTBIG *line, INTBIG *chr)
4671 {
4672 REGISTER INTBIG i, j, screenlx, screenhx, screenly, screenhy;
4673 CHAR save;
4674 INTBIG x, y;
4675 INTBIG tsx, tsy;
4676 REGISTER INTBIG lasttsx, charwid;
4677
4678 /* determine text size */
4679 screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4680 for(i = 0; i < us_editvarlength; i++)
4681 {
4682 getdisparrayvarlinepos(us_editvarobjaddr, us_editvarobjtype, us_editvartech,
4683 el_curwindowpart, us_editvariable, i, &x, &y, TRUE);
4684 screenlx = applyxscale(el_curwindowpart, x - el_curwindowpart->screenlx) +
4685 el_curwindowpart->uselx;
4686 screenly = applyyscale(el_curwindowpart, y - el_curwindowpart->screenly) +
4687 el_curwindowpart->usely;
4688 screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4689 screenhx = screenlx + tsx;
4690 screenhy = screenly + us_editvarlineheight;
4691 if (yp < screenly || yp > screenhy) continue;
4692 if (xp < screenlx-us_editvarlineheight ||
4693 xp > screenhx+us_editvarlineheight) continue;
4694 *line = i;
4695 lasttsx = 0;
4696 for(j=1; j<=(INTBIG)estrlen(us_editvarlines[i]); j++)
4697 {
4698 save = us_editvarlines[i][j];
4699 us_editvarlines[i][j] = 0;
4700 screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4701 charwid = tsx - lasttsx;
4702 lasttsx = tsx;
4703 us_editvarlines[i][j] = save;
4704 if (xp < screenlx + tsx - charwid/2) break;
4705 }
4706 *chr = j-1;
4707 return(TRUE);
4708 }
4709 return(FALSE);
4710 }
4711
us_editvariabletexthighlight(void)4712 void us_editvariabletexthighlight(void)
4713 {
4714 REGISTER INTBIG i, j, startch;
4715 CHAR save;
4716 INTBIG x, y, screenlx, screenhx, screenly, screenhy;
4717 INTBIG tsx, tsy;
4718
4719 /* determine text size */
4720 screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4721 for(i = us_editvarstartline; i <= us_editvarendline; i++)
4722 {
4723 getdisparrayvarlinepos(us_editvarobjaddr, us_editvarobjtype, us_editvartech,
4724 el_curwindowpart, us_editvariable, i, &x, &y, TRUE);
4725 screenlx = applyxscale(el_curwindowpart, x - el_curwindowpart->screenlx) +
4726 el_curwindowpart->uselx;
4727 screenly = applyyscale(el_curwindowpart, y - el_curwindowpart->screenly) +
4728 el_curwindowpart->usely;
4729 startch = 0;
4730 if (i == us_editvarstartline && us_editvarstartchar != 0)
4731 {
4732 save = us_editvarlines[i][us_editvarstartchar];
4733 us_editvarlines[i][us_editvarstartchar] = 0;
4734 screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4735 screenlx += tsx;
4736 us_editvarlines[i][us_editvarstartchar] = save;
4737 startch = us_editvarstartchar;
4738 }
4739 if (i == us_editvarendline) j = us_editvarendchar; else
4740 j = estrlen(us_editvarlines[i]);
4741 save = us_editvarlines[i][j];
4742 us_editvarlines[i][j] = 0;
4743 screengettextsize(el_curwindowpart, &us_editvarlines[i][startch], &tsx, &tsy);
4744 screenhx = screenlx + tsx;
4745 us_editvarlines[i][j] = save;
4746 screenhy = screenly + us_editvarlineheight;
4747 if (screenlx <= el_curwindowpart->uselx) screenlx = el_curwindowpart->uselx+1;
4748 if (screenhx > el_curwindowpart->usehx) screenhx = el_curwindowpart->usehx;
4749 if (screenly < el_curwindowpart->usely) screenly = el_curwindowpart->usely;
4750 if (screenhy > el_curwindowpart->usehy) screenhy = el_curwindowpart->usehy;
4751 if ((el_curwindowpart->state&INPLACEEDIT) != 0)
4752 xformbox(&screenlx, &screenhx, &screenly, &screenhy, el_curwindowpart->outofcell);
4753 screeninvertbox(el_curwindowpart, screenlx-1, screenhx-1,
4754 screenly, screenhy-1);
4755 }
4756 }
4757
4758 /******************** USER-BROADCAST CHANGES ********************/
4759
4760 /*
4761 * routine to allocate a new ubchange from the pool (if any) or memory,
4762 * fill in the "cell", "change", "x", and "y" fields, and link it to the
4763 * global list. Returns true on error.
4764 */
us_newubchange(INTBIG change,void * object,void * parameter)4765 BOOLEAN us_newubchange(INTBIG change, void *object, void *parameter)
4766 {
4767 REGISTER UBCHANGE *d;
4768
4769 if (us_ubchangefree == NOUBCHANGE)
4770 {
4771 d = (UBCHANGE *)emalloc((sizeof (UBCHANGE)), us_tool->cluster);
4772 if (d == 0) return(TRUE);
4773 } else
4774 {
4775 /* take ubchange from free list */
4776 d = us_ubchangefree;
4777 us_ubchangefree = (UBCHANGE *)d->nextubchange;
4778 }
4779 d->object = object;
4780 d->parameter = parameter;
4781 d->change = change;
4782 d->nextubchange = us_ubchanges;
4783 us_ubchanges = d;
4784 return(FALSE);
4785 }
4786
4787 /*
4788 * routine to return ubchange "d" to the pool of free ubchanges
4789 */
us_freeubchange(UBCHANGE * d)4790 void us_freeubchange(UBCHANGE *d)
4791 {
4792 d->nextubchange = us_ubchangefree;
4793 us_ubchangefree = d;
4794 }
4795
4796 /*
4797 * routine to remove all queued user broadcast changes to cell "np"
4798 * because it was deleted
4799 */
us_removeubchange(NODEPROTO * np)4800 void us_removeubchange(NODEPROTO *np)
4801 {
4802 REGISTER UBCHANGE *d, *lastd, *nextd;
4803 REGISTER NODEPROTO *thisnp;
4804
4805 lastd = NOUBCHANGE;
4806 for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4807 {
4808 nextd = d->nextubchange;
4809 if (d->change == UBNEWFC) thisnp = ((NODEINST *)d->object)->parent; else
4810 if (d->change == UBKILLFM) thisnp = (NODEPROTO *)d->object; else
4811 thisnp = NONODEPROTO;
4812 if (thisnp == np)
4813 {
4814 if (lastd == NOUBCHANGE) us_ubchanges = nextd; else
4815 lastd->nextubchange = nextd;
4816 us_freeubchange(d);
4817 continue;
4818 }
4819 lastd = d;
4820 }
4821 }
4822
4823 /*
4824 * routine to remove variable "FACET_message" from cell "np".
4825 */
us_delcellmessage(NODEPROTO * np)4826 void us_delcellmessage(NODEPROTO *np)
4827 {
4828 (void)us_newubchange(UBKILLFM, np, 0);
4829 }
4830
4831 /*
4832 * routine to add a cell-center to cell "np"
4833 */
us_addcellcenter(NODEINST * ni)4834 void us_addcellcenter(NODEINST *ni)
4835 {
4836 (void)us_newubchange(UBNEWFC, ni, 0);
4837 }
4838
4839 /*
4840 * Routine to queue a check of the SPICE parts.
4841 */
us_checkspiceparts(void)4842 void us_checkspiceparts(void)
4843 {
4844 (void)us_newubchange(UBSPICEPARTS, 0, 0);
4845 }
4846
4847 /*
4848 * Routine to queue a deletion of a technology-edit layer cell.
4849 */
us_deltecedlayercell(NODEPROTO * np)4850 void us_deltecedlayercell(NODEPROTO *np)
4851 {
4852 (void)us_newubchange(UBTECEDDELLAYER, np, 0);
4853 }
4854
4855 /*
4856 * Routine to queue a deletion of a technology-edit node cell.
4857 */
us_deltecednodecell(NODEPROTO * np)4858 void us_deltecednodecell(NODEPROTO *np)
4859 {
4860 (void)us_newubchange(UBTECEDDELNODE, np, 0);
4861 }
4862
4863 /*
4864 * Routine to queue a rename of a technology-edit cell.
4865 */
us_renametecedcell(NODEPROTO * np,CHAR * oldname)4866 void us_renametecedcell(NODEPROTO *np, CHAR *oldname)
4867 {
4868 (void)us_newubchange(UBTECEDRENAME, np, oldname);
4869 }
4870
4871 /*
4872 * Routine to queue a turn-on of a tool.
4873 */
us_toolturnedon(TOOL * tool)4874 void us_toolturnedon(TOOL *tool)
4875 {
4876 (void)us_newubchange(UBTOOLISON, tool, 0);
4877 }
4878
4879 /*
4880 * routine to implement all user broadcast changes queued during the last broadcast
4881 */
us_doubchanges(void)4882 void us_doubchanges(void)
4883 {
4884 REGISTER UBCHANGE *d, *nextd;
4885 REGISTER WINDOWPART *w;
4886 REGISTER NODEPROTO *np;
4887 REGISTER NODEINST *ni, *oni;
4888 REGISTER EDITOR *ed;
4889 REGISTER INTBIG bit;
4890 REGISTER LIBRARY *lib;
4891 REGISTER VARIABLE *var;
4892 REGISTER TOOL *tool;
4893 REGISTER CHAR *partsname;
4894 CHAR *par[1];
4895 REGISTER void *infstr;
4896
4897 for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4898 {
4899 nextd = d->nextubchange;
4900
4901 switch (d->change)
4902 {
4903 case UBKILLFM: /* remove cell_message */
4904 np = (NODEPROTO *)d->object;
4905 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4906 {
4907 if (w->curnodeproto != np) continue;
4908 if ((w->state&WINDOWTYPE) != TEXTWINDOW) continue;
4909
4910 /* see if the window still has a valid variable */
4911 ed = w->editor;
4912 if (ed->editobjvar == NOVARIABLE) continue;
4913 var = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
4914 if (var == NOVARIABLE)
4915 {
4916 (void)newwindowpart(w->location, w);
4917 killwindowpart(w);
4918 }
4919 }
4920 break;
4921 case UBNEWFC: /* added cell-center */
4922 ni = (NODEINST *)d->object;
4923 np = ni->parent;
4924 for(oni = np->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
4925 {
4926 if (oni == ni) continue;
4927 if (oni->proto == gen_cellcenterprim)
4928 {
4929 ttyputerr(_("Can only be one cell-center in a cell: new one deleted"));
4930 us_clearhighlightcount();
4931 startobjectchange((INTBIG)ni, VNODEINST);
4932 (void)killnodeinst(ni);
4933 us_setnodeprotocenter(oni->lowx, oni->lowy, np);
4934 break;
4935 }
4936 }
4937 if (oni == NONODEINST)
4938 us_setnodeprotocenter(ni->lowx, ni->lowy, np);
4939 break;
4940 case UBSPICEPARTS: /* check for new spice parts */
4941 var = getvalkey((INTBIG)sim_tool, VTOOL, VSTRING, sim_spice_partskey);
4942 if (var == NOVARIABLE) break;
4943 partsname = (CHAR *)var->addr;
4944 if (namesame(partsname, sim_spice_parts) == 0) break;
4945 (void)reallocstring(&sim_spice_parts, partsname, sim_tool->cluster);
4946
4947 /* invoke the command file */
4948 infstr = initinfstr();
4949 addstringtoinfstr(infstr, el_libdir);
4950 addstringtoinfstr(infstr, sim_spice_parts);
4951 par[0] = returninfstr(infstr);
4952 us_commandfile(1, par);
4953 break;
4954 case UBTECEDDELLAYER: /* tell technology edit that layer cell was deleted */
4955 us_teceddeletelayercell((NODEPROTO *)d->object);
4956 break;
4957 case UBTECEDDELNODE: /* tell technology edit that node cell was deleted */
4958 us_teceddeletenodecell((NODEPROTO *)d->object);
4959 break;
4960 case UBTECEDRENAME: /* tell technology edit that cell was renamed */
4961 np = (NODEPROTO *)d->object;
4962 us_tecedrenamecell((CHAR *)d->parameter, np->protoname);
4963 break;
4964 case UBTOOLISON:
4965 /* look through all cells and update those that need it */
4966 tool = (TOOL *)d->object;
4967 bit = 1 << tool->toolindex;
4968 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
4969 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
4970 {
4971 if ((np->adirty & bit) != 0)
4972 {
4973 if (tool->examinenodeproto != 0)
4974 (*tool->examinenodeproto)(np);
4975 }
4976 np->adirty &= ~bit;
4977 }
4978 break;
4979 }
4980
4981 /* cleanup */
4982 us_freeubchange(d);
4983 }
4984 us_ubchanges = NOUBCHANGE;
4985 }
4986
4987 /******************** COLOR ********************/
4988
4989 /*
4990 * setup the color map for the graphics of technology "tech". "style" is:
4991 * COLORSEXISTING continue existing colors
4992 * COLORSDEFAULT use default opaque colors
4993 * COLORSBLACK use black background colors
4994 * COLORSWHITE use white background colors
4995 * A set of transparent colors is obtained from technology "tech", combined
4996 * with the appropriate opaque colors, and set into the proper
4997 * variables on the "user" tool (and subsequently displayed).
4998 * The 256 entries are organized thusly:
4999 * Bit 0 is for highlighting; bit 1 is an escape for
5000 * opaque colors, the next 5 bits are the transparent colors (if the opaque
5001 * escape is off) or the opaque value (if the bit is set).
5002 * The last bit is for the grid, although it may not appear if there are 128 entries.
5003 * This routine uses the database variable "USER_color_map" on the
5004 * technologies.
5005 */
us_getcolormap(TECHNOLOGY * tech,INTBIG style,BOOLEAN broadcast)5006 void us_getcolormap(TECHNOLOGY *tech, INTBIG style, BOOLEAN broadcast)
5007 {
5008 static TECH_COLORMAP colmap[38] =
5009 {
5010 {255,255,255}, /* 4(0004) WHITE: white */
5011 { 0, 0, 0}, /* 12(0014) BLACK: black */
5012 {255, 0, 0}, /* 20(0024) RED: red */
5013 { 0, 0,255}, /* 28(0034) BLUE: blue */
5014 { 0,255, 0}, /* 36(0044) GREEN: green */
5015 { 0,255,255}, /* 44(0054) CYAN: cyan */
5016 {255, 0,255}, /* 52(0064) MAGENTA: magenta */
5017 {255,255, 0}, /* 60(0074) YELLOW: yellow */
5018 { 0, 0, 0}, /* 68(0104) CELLTXT: cell and port names */
5019 { 0, 0, 0}, /* 76(0114) CELLOUT: cell outline */
5020 { 0, 0, 0}, /* 84(0124) WINBOR: window border color */
5021 { 0,255, 0}, /* 92(0134) HWINBOR: highlighted window border color */
5022 { 0, 0, 0}, /* 100(0144) MENBOR: menu border color */
5023 {255,255,255}, /* 108(0154) HMENBOR: highlighted menu border color */
5024 { 0, 0, 0}, /* 116(0164) MENTXT: menu text color */
5025 { 0, 0, 0}, /* 124(0174) MENGLY: menu glyph color */
5026 { 0, 0, 0}, /* 132(0204) CURSOR: cursor color */
5027 {180,180,180}, /* 140(0214) GRAY: gray */
5028 {255,190, 6}, /* 148(0224) ORANGE: orange */
5029 {186, 0,255}, /* 156(0234) PURPLE: purple */
5030 {139, 99, 46}, /* 164(0244) BROWN: brown */
5031 {230,230,230}, /* 172(0254) LGRAY: light gray */
5032 {100,100,100}, /* 180(0264) DGRAY: dark gray */
5033 {255,150,150}, /* 188(0274) LRED: light red */
5034 {159, 80, 80}, /* 196(0304) DRED: dark red */
5035 {175,255,175}, /* 204(0314) LGREEN: light green */
5036 { 89,159, 85}, /* 212(0324) DGREEN: dark green */
5037 {150,150,255}, /* 220(0334) LBLUE: light blue */
5038 { 2, 15,159}, /* 228(0344) DBLUE: dark blue */
5039 { 0, 0, 0}, /* 236(0354) unassigned */
5040 { 0, 0, 0}, /* 244(0364) unassigned */
5041 { 0, 0, 0}, /* 252(0374) unassigned */
5042 { 0, 0, 0}, /* grid */
5043 {255,255,255}, /* highlight */
5044 {255, 0, 0}, /* black background highlight */
5045 {255, 0, 0}, /* white background highlight */
5046 {255,255,255}, /* black background cursor */
5047 { 0, 0, 0} /* white background cursor */
5048 };
5049 static TECH_COLORMAP default_colmap[32] =
5050 { /* transpar4 transpar3 transpar2 transpar1 transpar0 */
5051 {200,200,200}, /* 0: */
5052 { 0, 0,200}, /* 1: transpar0 */
5053 {220, 0,120}, /* 2: transpar1 */
5054 { 80, 0,160}, /* 3: transpar1+transpar0 */
5055 { 70,250, 70}, /* 4: transpar2 */
5056 { 0,140,140}, /* 5: transpar2+ transpar0 */
5057 {180,130, 0}, /* 6: transpar2+transpar1 */
5058 { 55, 70,140}, /* 7: transpar2+transpar1+transpar0 */
5059 {250,250, 0}, /* 8: transpar3 */
5060 { 85,105,160}, /* 9: transpar3+ transpar0 */
5061 {190, 80,100}, /* 10: transpar3+ transpar1 */
5062 { 70, 50,150}, /* 11: transpar3+ transpar1+transpar0 */
5063 { 80,210, 0}, /* 12: transpar3+transpar2 */
5064 { 50,105,130}, /* 13: transpar3+transpar2+ transpar0 */
5065 {170,110, 0}, /* 14: transpar3+transpar2+transpar1 */
5066 { 60, 60,130}, /* 15: transpar3+transpar2+transpar1+transpar0 */
5067 {180,180,180}, /* 16: transpar4+ */
5068 { 0, 0,180}, /* 17: transpar4+ transpar0 */
5069 {200, 0,100}, /* 18: transpar4+ transpar1 */
5070 { 60, 0,140}, /* 19: transpar4+ transpar1+transpar0 */
5071 { 50,230, 50}, /* 20: transpar4+ transpar2 */
5072 { 0,120,120}, /* 21: transpar4+ transpar2+ transpar0 */
5073 {160,110, 0}, /* 22: transpar4+ transpar2+transpar1 */
5074 { 35, 50,120}, /* 23: transpar4+ transpar2+transpar1+transpar0 */
5075 {230,230, 0}, /* 24: transpar4+transpar3 */
5076 { 65, 85,140}, /* 25: transpar4+transpar3+ transpar0 */
5077 {170, 60, 80}, /* 26: transpar4+transpar3+ transpar1 */
5078 { 50, 30,130}, /* 27: transpar4+transpar3+ transpar1+transpar0 */
5079 { 60,190, 0}, /* 28: transpar4+transpar3+transpar2 */
5080 { 30, 85,110}, /* 29: transpar4+transpar3+transpar2+ transpar0 */
5081 {150, 90, 0}, /* 30: transpar4+transpar3+transpar2+transpar1 */
5082 { 40, 40,110}, /* 31: transpar4+transpar3+transpar2+transpar1+transpar0 */
5083 };
5084
5085 TECH_COLORMAP *mapptr, *thisptr;
5086 REGISTER INTBIG i;
5087 REGISTER VARIABLE *var, *rvar, *gvar, *bvar;
5088 static INTBIG USER_color_map_key = 0;
5089 INTBIG red[256], green[256], blue[256];
5090 extern GRAPHICS us_gbox;
5091
5092 /* get the technology's color information */
5093 if (USER_color_map_key == 0) USER_color_map_key = makekey(x_("USER_color_map"));
5094 var = getvalkey((INTBIG)tech, VTECHNOLOGY, VCHAR|VISARRAY, USER_color_map_key);
5095 if (var != NOVARIABLE) mapptr = (TECH_COLORMAP *)var->addr; else mapptr = 0;
5096
5097 /* get existing color information */
5098 rvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
5099 gvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
5100 bvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
5101
5102 /* must have some colors */
5103 if (rvar == NOVARIABLE && gvar == NOVARIABLE && bvar == NOVARIABLE && var == NOVARIABLE)
5104 {
5105 mapptr = default_colmap;
5106 }
5107
5108 if (style == COLORSEXISTING)
5109 {
5110 /* not resetting, get the old color values */
5111 for(i=0; i<256; i++)
5112 {
5113 red[i] = ((INTBIG *)rvar->addr)[i];
5114 green[i] = ((INTBIG *)gvar->addr)[i];
5115 blue[i] = ((INTBIG *)bvar->addr)[i];
5116 if ((i&(LAYERH|LAYERG|LAYEROE)) != 0) continue;
5117 if (mapptr == 0) continue;
5118 if (i == 0) continue;
5119 thisptr = &mapptr[i>>2];
5120 red[i] = thisptr->red; green[i] = thisptr->green;
5121 blue[i] = thisptr->blue;
5122 }
5123 } else
5124 {
5125 #if SIMTOOL
5126 /* update simulation window colors */
5127 switch (style)
5128 {
5129 case COLORSWHITE:
5130 case COLORSDEFAULT:
5131 sim_window_setdisplaycolor(OFF_STRENGTH, BLUE);
5132 sim_window_setdisplaycolor(NODE_STRENGTH, GREEN);
5133 sim_window_setdisplaycolor(GATE_STRENGTH, MAGENTA);
5134 sim_window_setdisplaycolor(VDD_STRENGTH, BLACK);
5135 sim_window_setdisplaycolor(LOGIC_LOW, BLUE);
5136 sim_window_setdisplaycolor(LOGIC_HIGH, MAGENTA);
5137 sim_window_setdisplaycolor(LOGIC_X, BLACK);
5138 sim_window_setdisplaycolor(LOGIC_Z, LGRAY);
5139 break;
5140 case COLORSBLACK:
5141 sim_window_setdisplaycolor(OFF_STRENGTH, GREEN);
5142 sim_window_setdisplaycolor(NODE_STRENGTH, CYAN);
5143 sim_window_setdisplaycolor(GATE_STRENGTH, MAGENTA);
5144 sim_window_setdisplaycolor(VDD_STRENGTH, LRED);
5145 sim_window_setdisplaycolor(LOGIC_LOW, GREEN);
5146 sim_window_setdisplaycolor(LOGIC_HIGH, MAGENTA);
5147 sim_window_setdisplaycolor(LOGIC_X, LRED);
5148 sim_window_setdisplaycolor(LOGIC_Z, DGRAY);
5149 break;
5150 }
5151 #endif
5152
5153 /* resetting: load entirely new color map */
5154 for(i=0; i<256; i++)
5155 {
5156 if ((i&LAYERH) != 0)
5157 {
5158 switch (style)
5159 {
5160 case COLORSDEFAULT: thisptr = &colmap[33]; break; /* white */
5161 case COLORSBLACK: thisptr = &colmap[34]; break; /* red */
5162 case COLORSWHITE: thisptr = &colmap[35]; break; /* red */
5163 }
5164 } else if ((i&LAYERG) != 0)
5165 {
5166 switch (style)
5167 {
5168 case COLORSDEFAULT: thisptr = &colmap[32]; break; /* black */
5169 case COLORSBLACK: thisptr = &colmap[33]; break; /* white */
5170 case COLORSWHITE: thisptr = &colmap[32]; break; /* black */
5171 }
5172 } else if ((i&LAYEROE) != 0)
5173 {
5174 thisptr = &colmap[i>>2];
5175
5176 if (i == HMENBOR) switch (style)
5177 {
5178 case COLORSBLACK: thisptr = &colmap[2]; break; /* red */
5179 case COLORSWHITE: thisptr = &colmap[2]; break; /* red */
5180 }
5181 if (i == CURSOR) switch (style)
5182 {
5183 case COLORSDEFAULT: thisptr = &colmap[16]; break; /* default */
5184 case COLORSBLACK: thisptr = &colmap[36]; break; /* white */
5185 case COLORSWHITE: thisptr = &colmap[37]; break; /* black */
5186 }
5187
5188 /* reverse black and white when using black background */
5189 if (style == COLORSBLACK)
5190 {
5191 switch (i)
5192 {
5193 case CELLTXT:
5194 case CELLOUT:
5195 case WINBOR:
5196 case MENBOR:
5197 case MENTXT:
5198 case MENGLY:
5199 case BLACK: thisptr = &colmap[33]; break; /* white */
5200 case WHITE: thisptr = &colmap[37]; break; /* black */
5201 }
5202 }
5203 } else
5204 {
5205 if (rvar != NOVARIABLE) red[i] = ((INTBIG *)rvar->addr)[i];
5206 if (gvar != NOVARIABLE) green[i] = ((INTBIG *)gvar->addr)[i];
5207 if (bvar != NOVARIABLE) blue[i] = ((INTBIG *)bvar->addr)[i];
5208 if (mapptr != 0) thisptr = &mapptr[i>>2]; else thisptr = 0;
5209 if (i == ALLOFF) switch (style)
5210 {
5211 case COLORSDEFAULT: thisptr = &default_colmap[0]; break; /* default */
5212 case COLORSBLACK: thisptr = &colmap[32]; break; /* black */
5213 case COLORSWHITE: thisptr = &colmap[33]; break; /* white */
5214 }
5215 if (thisptr == 0) continue;
5216 }
5217 red[i] = thisptr->red; green[i] = thisptr->green;
5218 blue[i] = thisptr->blue;
5219 }
5220
5221 /* also set the grid color appropriately if it doesn't have its own bitplane */
5222 if (el_maplength < 256)
5223 {
5224 switch (style)
5225 {
5226 case COLORSDEFAULT: us_gbox.col = BLACK; break; /* black */
5227 case COLORSBLACK: us_gbox.col = WHITE; break; /* white */
5228 case COLORSWHITE: us_gbox.col = BLACK; break; /* black */
5229 }
5230 }
5231 }
5232
5233 /* set the color map */
5234 if (broadcast)
5235 startobjectchange((INTBIG)us_tool, VTOOL);
5236 if (!broadcast) nextchangequiet();
5237 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)red,
5238 VINTEGER|VISARRAY|(256<<VLENGTHSH));
5239 if (!broadcast) nextchangequiet();
5240 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)green,
5241 VINTEGER|VISARRAY|(256<<VLENGTHSH));
5242 if (!broadcast) nextchangequiet();
5243 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)blue,
5244 VINTEGER|VISARRAY|(256<<VLENGTHSH));
5245 if (broadcast)
5246 endobjectchange((INTBIG)us_tool, VTOOL);
5247 }
5248
5249 /*
5250 * routine to load entry "entry" of the global color map entries with the value
5251 * (red, green, blue), letter "letter". Handles highlight and grid layers
5252 * right if "spread" is true.
5253 */
us_setcolorentry(INTBIG entry1,INTBIG red,INTBIG green,INTBIG blue,INTBIG letter,BOOLEAN spread)5254 void us_setcolorentry(INTBIG entry1, INTBIG red, INTBIG green, INTBIG blue, INTBIG letter,
5255 BOOLEAN spread)
5256 {
5257 REGISTER INTBIG j;
5258 Q_UNUSED( letter );
5259
5260 startobjectchange((INTBIG)us_tool, VTOOL);
5261 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, entry1, red);
5262 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, entry1, green);
5263 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, entry1, blue);
5264
5265 /* place in other entries if special */
5266 if ((entry1&LAYERH) == LAYERH && spread)
5267 {
5268 /* set all highlight colors */
5269 for(j=0; j<256; j++) if ((j&LAYERH) == LAYERH)
5270 {
5271 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, j, red);
5272 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, j, green);
5273 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, j, blue);
5274 }
5275 } else if ((entry1&(LAYERG|LAYERH)) == LAYERG && spread)
5276 {
5277 /* set all grid colors */
5278 for(j=0; j<256; j++) if ((j&(LAYERG|LAYERH)) == LAYERG)
5279 {
5280 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, j, red);
5281 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, j, green);
5282 (void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, j, blue);
5283 }
5284 }
5285 endobjectchange((INTBIG)us_tool, VTOOL);
5286 }
5287
5288 /*
5289 * routine to convert a red/green/blue color in (ir,ig,ib) to a hue/saturation/
5290 * intensity color in (h,s,i)
5291 */
us_rgbtohsv(INTBIG ir,INTBIG ig,INTBIG ib,float * h,float * s,float * i)5292 void us_rgbtohsv(INTBIG ir, INTBIG ig, INTBIG ib, float *h, float *s, float *i)
5293 {
5294 float x, r, g, b, rdot, gdot, bdot;
5295
5296 r = ir / 255.0f;
5297 g = ig / 255.0f;
5298 b = ib / 255.0f;
5299
5300 /* "i" is maximum of "r", "g", and "b" */
5301 if (r > g) *i = r; else *i = g;
5302 if (b > *i) *i = b;
5303
5304 /* "x" is minimum of "r", "g", and "b" */
5305 if (r < g) x = r; else x = g;
5306 if (b < x) x = b;
5307
5308 /* "saturation" is (i-x)/i */
5309 if (*i == 0.0) *s = 0.0; else *s = (*i - x) / *i;
5310
5311 if (*s == 0.0) *h = 0.0; else
5312 {
5313 rdot = (*i - r) / (*i - x);
5314 gdot = (*i - g) / (*i - x);
5315 bdot = (*i - b) / (*i - x);
5316 if (b == x && r == *i) *h = (1.0f - gdot) / 6.0f; else
5317 if (b == x && g == *i) *h = (1.0f + rdot) / 6.0f; else
5318 if (r == x && g == *i) *h = (3.0f - bdot) / 6.0f; else
5319 if (r == x && b == *i) *h = (3.0f + gdot) / 6.0f; else
5320 if (g == x && b == *i) *h = (5.0f - rdot) / 6.0f; else
5321 if (g == x && r == *i) *h = (5.0f + bdot) / 6.0f; else
5322 ttyputmsg(_("Cannot convert (%ld,%ld,%ld), for x=%g i=%g s=%g"), ir, ig, ib, x, *i, *s);
5323 }
5324 }
5325
5326 /*
5327 * routine to convert a hue/saturation/intensity color in (h,s,v) to a red/
5328 * green/blue color in (r,g,b)
5329 */
us_hsvtorgb(float h,float s,float v,INTBIG * r,INTBIG * g,INTBIG * b)5330 void us_hsvtorgb(float h, float s, float v, INTBIG *r, INTBIG *g, INTBIG *b)
5331 {
5332 REGISTER INTBIG i;
5333 REGISTER float f, m, n, k;
5334
5335 h = h * 6.0f;
5336 i = (INTBIG)h;
5337 f = h - (float)i;
5338 m = v * (1.0f - s);
5339 n = v * (1.0f - s * f);
5340 k = v * (1.0f - s * (1.0f - f));
5341 switch (i)
5342 {
5343 case 0:
5344 *r = (INTBIG)(v*255.0); *g = (INTBIG)(k*255.0); *b = (INTBIG)(m*255.0);
5345 break;
5346 case 1:
5347 *r = (INTBIG)(n*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(m*255.0);
5348 break;
5349 case 2:
5350 *r = (INTBIG)(m*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(k*255.0);
5351 break;
5352 case 3:
5353 *r = (INTBIG)(m*255.0); *g = (INTBIG)(n*255.0); *b = (INTBIG)(v*255.0);
5354 break;
5355 case 4:
5356 *r = (INTBIG)(k*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(v*255.0);
5357 break;
5358 case 5:
5359 *r = (INTBIG)(v*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(n*255.0);
5360 break;
5361 }
5362 if (*r < 0 || *r > 255 || *g < 0 || *g > 255 || *b < 0 || *b > 255)
5363 ttyputmsg(x_("(%g,%g,%g) -> (%ld,%ld,%ld) (i=%ld)"),h, s, v, *r, *g, *b, i);
5364 }
5365
5366 /*
5367 * Routine to return an array of integers that describes the print colors for technology "tech".
5368 * The array has 5 entries for each layer in the technology. The first 3 are the red/green/blue
5369 * color. The 4th entry is the opacity and the 5th entry is the foreground factor.
5370 *
5371 * Opacity indicates how much a layer should obscure lower levels. It is
5372 * a fractional integer (where 1.0 is WHOLE).
5373 * Set it to WHOLE if the layer should be opaque, or a smaller fraction if lower
5374 * levels should partially show through.
5375 *
5376 * Foreground should be 1 if the layer should show up beneath partially
5377 * transparent layers. It is set to 0 for layers like wells and selects
5378 * that should not show through.
5379 *
5380 * The R, G, and B coordinates are on a scale of 0 to 255 from dark to light.
5381 * White layers (R=G=B=255) will not be visible.
5382 */
us_getprintcolors(TECHNOLOGY * tech)5383 INTBIG *us_getprintcolors(TECHNOLOGY *tech)
5384 {
5385 REGISTER VARIABLE *var, *varred, *vargreen, *varblue;
5386 REGISTER INTBIG i, fun, col, tot;
5387 float opacity;
5388
5389 /* make sure the array is there */
5390 if (us_printcolordata != 0) efree((CHAR *)us_printcolordata);
5391 us_printcolordata = (INTBIG *)emalloc(tech->layercount*5*SIZEOFINTBIG, io_tool->cluster);
5392 if (us_printcolordata == 0) return(0);
5393
5394 /* presume no print colors and create them from the display colors */
5395 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
5396 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
5397 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
5398 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return(0);
5399 for(i=0; i<tech->layercount; i++)
5400 {
5401 fun = layerfunction(tech, i);
5402 if ((fun&LFPSEUDO) != 0) continue;
5403 col = tech->layers[i]->col;
5404 us_printcolordata[i*5] = ((INTBIG *)varred->addr)[col];
5405 us_printcolordata[i*5+1] = ((INTBIG *)vargreen->addr)[col];
5406 us_printcolordata[i*5+2] = ((INTBIG *)varblue->addr)[col];
5407 opacity = 1.0f;
5408 switch (fun&LFTYPE)
5409 {
5410 case LFMETAL12: opacity *= 0.9f;
5411 case LFMETAL11: opacity *= 0.9f;
5412 case LFMETAL10: opacity *= 0.9f;
5413 case LFMETAL9: opacity *= 0.9f;
5414 case LFMETAL8: opacity *= 0.9f;
5415 case LFMETAL7: opacity *= 0.9f;
5416 case LFMETAL6: opacity *= 0.9f;
5417 case LFMETAL5: opacity *= 0.9f;
5418 case LFMETAL4: opacity *= 0.9f;
5419 case LFMETAL3: opacity *= 0.9f;
5420 case LFMETAL2: opacity *= 0.9f;
5421 case LFMETAL1: opacity *= 0.9f;
5422 }
5423 us_printcolordata[i*5+3] = (INTBIG)(opacity*WHOLE);
5424 if ((fun&LFTYPE) == LFIMPLANT || (fun&LFTYPE) == LFSUBSTRATE ||
5425 (fun&LFTYPE) == LFWELL) us_printcolordata[i*5+4] = 0; else
5426 us_printcolordata[i*5+4] = 1;
5427 }
5428
5429 /* if there are print colors, use them */
5430 var = getval((INTBIG)tech, VTECHNOLOGY, VINTEGER|VISARRAY, x_("USER_print_colors"));
5431 if (var != NOVARIABLE)
5432 {
5433 tot = getlength(var);
5434 if (tot > tech->layercount*5) tot = tech->layercount*5;
5435 for(i=0; i<tot; i++) us_printcolordata[i] = ((INTBIG *)var->addr)[i];
5436 }
5437 return(us_printcolordata);
5438 }
5439
5440 /******************** MISCELLANEOUS ********************/
5441
5442 /*
5443 * Routine to determine the offset of the "length" and "width" attributes on
5444 * node "ni" given that it uses a text descriptor of "descript".
5445 */
us_getlenwidoffset(NODEINST * ni,UINTBIG * descript,INTBIG * xoff,INTBIG * yoff)5446 void us_getlenwidoffset(NODEINST *ni, UINTBIG *descript, INTBIG *xoff, INTBIG *yoff)
5447 {
5448 REGISTER INTBIG i;
5449
5450 *xoff = *yoff = 0;
5451 i = TXTGETQLAMBDA(TDGETSIZE(descript));
5452 if (i > 4) i /= 2; else i = 2;
5453 switch (ni->rotation)
5454 {
5455 case 0:
5456 if (ni->transpose == 0) *yoff = i; else
5457 *xoff = -i;
5458 break;
5459 case 900:
5460 if (ni->transpose == 0) *xoff = i; else
5461 *yoff = i;
5462 break;
5463 case 1800:
5464 if (ni->transpose == 0) *yoff = -i; else
5465 *xoff = i;
5466 break;
5467 case 2700:
5468 if (ni->transpose == 0) *xoff = -i; else
5469 *yoff = -i;
5470 break;
5471 }
5472 }
5473
5474 /*
5475 * Routine to return the placement angle to use for node "np".
5476 */
us_getplacementangle(NODEPROTO * np)5477 INTBIG us_getplacementangle(NODEPROTO *np)
5478 {
5479 REGISTER VARIABLE *var;
5480
5481 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle_key);
5482 if (var != NOVARIABLE) return(var->addr);
5483 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_placement_angle_key);
5484 if (var != NOVARIABLE) return(var->addr);
5485 return(0);
5486 }
5487
5488 /*
5489 * Routine to adjust the coordinates (cx,cy) to account for the fact that they are from primitive
5490 * "prim" and in cell "cell". If this is not a primitive, or if the technology of the primitive
5491 * matches the technology of the cell, then do nothing. Otherwise, adjust the size of the coordinates
5492 * so that the technology/lambda of the primitive is adjusted to that of the cell.
5493 */
us_adjustfornodeincell(NODEPROTO * prim,NODEPROTO * cell,INTBIG * cx,INTBIG * cy)5494 void us_adjustfornodeincell(NODEPROTO *prim, NODEPROTO *cell, INTBIG *cx, INTBIG *cy)
5495 {
5496 REGISTER LIBRARY *lib;
5497 REGISTER INTBIG celllambda, primlambda;
5498
5499 if (prim->primindex == 0) return;
5500 if (cell == NONODEPROTO) return;
5501 if (prim->tech == cell->tech) return;
5502 if (cell->tech == gen_tech) return;
5503
5504 lib = cell->lib;
5505 celllambda = lib->lambda[cell->tech->techindex],
5506 primlambda = lib->lambda[prim->tech->techindex],
5507 *cx = muldiv(*cx, celllambda, primlambda);
5508 *cy = muldiv(*cy, celllambda, primlambda);
5509 }
5510
5511 /*
5512 * Routine to get the "displayed" location of node "ni" and return it in
5513 * (xpos, ypos).
5514 */
us_getnodedisplayposition(NODEINST * ni,INTBIG * xpos,INTBIG * ypos)5515 void us_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos)
5516 {
5517 REGISTER NODEPROTO *np;
5518 INTBIG cox, coy, plx, ply, phx, phy;
5519 REGISTER INTBIG dx, dy;
5520 REGISTER VARIABLE *var;
5521 XARRAY trans;
5522
5523 np = ni->proto;
5524 if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
5525 {
5526 corneroffset(ni, np, ni->rotation, ni->transpose, &cox, &coy, FALSE);
5527 *xpos = ni->lowx+cox;
5528 *ypos = ni->lowy+coy;
5529 } else
5530 {
5531 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
5532 if (var != NOVARIABLE)
5533 {
5534 dx = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
5535 (np->lowx+np->highx)/2;
5536 dy = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
5537 (np->lowy+np->highy)/2;
5538 makerot(ni, trans);
5539 xform(dx, dy, &cox, &coy, trans);
5540 *xpos = cox;
5541 *ypos = coy;
5542 } else
5543 {
5544 nodesizeoffset(ni, &plx, &ply, &phx, &phy);
5545 makerot(ni, trans);
5546 dx = (ni->lowx+plx+ni->highx-phx)/2;
5547 dy = (ni->lowy+ply+ni->highy-phy)/2;
5548 xform(dx, dy, xpos, ypos, trans);
5549 }
5550 }
5551 }
5552
5553 /*
5554 * routine to put cell center (x, y) on cell "np".
5555 */
us_setnodeprotocenter(INTBIG x,INTBIG y,NODEPROTO * np)5556 void us_setnodeprotocenter(INTBIG x, INTBIG y, NODEPROTO *np)
5557 {
5558 INTBIG position[2];
5559
5560 position[0] = x; position[1] = y;
5561 nextchangequiet();
5562 (void)setvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key,
5563 (INTBIG)position, VINTEGER|VISARRAY|(2<<VLENGTHSH));
5564 }
5565
5566 /*
5567 * routine to remove cell center from cell "np".
5568 */
us_delnodeprotocenter(NODEPROTO * np)5569 void us_delnodeprotocenter(NODEPROTO *np)
5570 {
5571 nextchangequiet();
5572 (void)delvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key);
5573 }
5574
5575 /*
5576 * Routine called when any of the "essential bounds" nodes are created, destroyed, or moved
5577 * in cell "cell".
5578 */
us_setessentialbounds(NODEPROTO * cell)5579 void us_setessentialbounds(NODEPROTO *cell)
5580 {
5581 REGISTER NODEINST *ni;
5582 REGISTER INTBIG lx, hx, ly, hy, x, y, essentialcount;
5583 REGISTER VARIABLE *var;
5584 INTBIG bounds[4];
5585
5586 essentialcount = 0;
5587 lx = hx = ly = hy = 0;
5588 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5589 {
5590 if (ni->proto != gen_essentialprim) continue;
5591 x = (ni->lowx + ni->highx) / 2;
5592 y = (ni->lowy + ni->highy) / 2;
5593 if (essentialcount == 0)
5594 {
5595 lx = hx = x;
5596 ly = hy = y;
5597 } else
5598 {
5599 if (x < lx) lx = x;
5600 if (x > hx) hx = x;
5601 if (y < ly) ly = y;
5602 if (y > hy) hy = y;
5603 }
5604 essentialcount++;
5605 }
5606 if (essentialcount > 2)
5607 {
5608 /* make sure they are all on the bounds */
5609 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5610 {
5611 if (ni->proto != gen_essentialprim) continue;
5612 x = (ni->lowx + ni->highx) / 2;
5613 y = (ni->lowy + ni->highy) / 2;
5614 if ((x == lx || x == hx) && (y == ly || y == hy)) continue;
5615 ttyputerr(_("Warning: Essential bounds markers inconsistent in cell %s"),
5616 describenodeproto(cell));
5617 break;
5618 }
5619 }
5620
5621 /* set the essential bounds */
5622 if (essentialcount <= 1)
5623 {
5624 /* delete the bounds */
5625 var = getvalkey((INTBIG)cell, VNODEPROTO, VINTEGER|VISARRAY, el_essential_bounds_key);
5626 if (var != NOVARIABLE)
5627 {
5628 nextchangequiet();
5629 delvalkey((INTBIG)cell, VNODEPROTO, el_essential_bounds_key);
5630 }
5631 } else
5632 {
5633 bounds[0] = lx; bounds[1] = hx;
5634 bounds[2] = ly; bounds[3] = hy;
5635 nextchangequiet();
5636 setvalkey((INTBIG)cell, VNODEPROTO, el_essential_bounds_key, (INTBIG)bounds,
5637 VINTEGER|VISARRAY|(4<<VLENGTHSH));
5638 }
5639 }
5640
us_getlowleft(NODEINST * ni,INTBIG * x,INTBIG * y)5641 void us_getlowleft(NODEINST *ni, INTBIG *x, INTBIG *y)
5642 {
5643 INTBIG lx, ly, hx, hy;
5644 XARRAY trans;
5645 static POLYGON *poly = NOPOLYGON;
5646
5647 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
5648
5649 nodesizeoffset(ni, &lx, &ly, &hx, &hy);
5650 maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, poly);
5651 if (ni->rotation != 0 || ni->transpose != 0)
5652 {
5653 makerot(ni, trans);
5654 xformpoly(poly, trans);
5655 }
5656 getbbox(poly, x, &hx, y, &hy);
5657 }
5658
5659 /*
5660 * routine to modify the text descriptor in the highlighted object "high"
5661 */
us_modifytextdescript(HIGHLIGHT * high,UINTBIG * descript)5662 void us_modifytextdescript(HIGHLIGHT *high, UINTBIG *descript)
5663 {
5664 REGISTER VARIABLE *var;
5665
5666 if (high->fromvar != NOVARIABLE)
5667 {
5668 var = high->fromvar;
5669 if (high->fromvarnoeval != NOVARIABLE) var = high->fromvarnoeval;
5670 if (TDDIFF(descript, var->textdescript))
5671 {
5672 if (high->fromport != NOPORTPROTO)
5673 {
5674 modifydescript((INTBIG)high->fromport, VPORTPROTO, var, descript);
5675 } else if (high->fromgeom == NOGEOM)
5676 {
5677 modifydescript((INTBIG)high->cell, VNODEPROTO, var, descript);
5678 } else
5679 {
5680 modifydescript((INTBIG)high->fromgeom->entryaddr.blind,
5681 high->fromgeom->entryisnode ? VNODEINST : VARCINST, var, descript);
5682 }
5683 }
5684 return;
5685 }
5686 if (high->fromport != NOPORTPROTO)
5687 {
5688 (void)setind((INTBIG)high->fromport, VPORTPROTO, x_("textdescript"), 0, descript[0]);
5689 (void)setind((INTBIG)high->fromport, VPORTPROTO, x_("textdescript"), 1, descript[1]);
5690 return;
5691 }
5692 if (high->fromgeom->entryisnode)
5693 {
5694 (void)setind((INTBIG)high->fromgeom->entryaddr.ni, VNODEINST,
5695 x_("textdescript"), 0, descript[0]);
5696 (void)setind((INTBIG)high->fromgeom->entryaddr.ni, VNODEINST,
5697 x_("textdescript"), 1, descript[1]);
5698 return;
5699 }
5700 }
5701
5702 /*
5703 * Routine to adjust the popup menu stored on the user interface object to correspond
5704 * to changes made to entry "pindex" of memory-structure popup "pm".
5705 */
us_adjustpopupmenu(POPUPMENU * pm,INTBIG pindex)5706 void us_adjustpopupmenu(POPUPMENU *pm, INTBIG pindex)
5707 {
5708 CHAR **lines, *popupname;
5709 CHAR *pt;
5710 VARIABLE *var;
5711 COMMANDBINDING commandbinding;
5712 REGISTER void *infstr;
5713
5714 infstr = initinfstr();
5715 addstringtoinfstr(infstr, x_("USER_binding_popup_"));
5716 addstringtoinfstr(infstr, pm->name);
5717 popupname = returninfstr(infstr);
5718 var = getval((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, popupname);
5719 if (var != NOVARIABLE)
5720 {
5721 lines = (CHAR **)var->addr;
5722 us_parsebinding(lines[pindex+1], &commandbinding);
5723 infstr = initinfstr();
5724 for(pt = lines[pindex+1]; *pt != 0; pt++)
5725 {
5726 if (estrncmp(pt, x_("message=\""), 9) == 0)
5727 {
5728 addstringtoinfstr(infstr, x_("message=\""));
5729 pt += 9;
5730 while (*pt != 0 && *pt != '"') pt++;
5731 addstringtoinfstr(infstr, pm->list[pindex].attribute);
5732 }
5733 addtoinfstr(infstr, *pt);
5734 }
5735 nextchangequiet();
5736 (void)setind((INTBIG)us_tool, VTOOL, popupname, pindex+1, (INTBIG)returninfstr(infstr));
5737 us_freebindingparse(&commandbinding);
5738 }
5739 }
5740
5741 /*
5742 * Routine to set the 9 entries of an XARRAY on a C object using change control.
5743 * This must be done as individual index changes because "setval()" cannot handle
5744 * arrays on fixed objects (objects in the C structures). The array is attribute
5745 * "name" on object "addr" of type "type". It is filled from "array".
5746 */
us_setxarray(INTBIG addr,INTBIG type,CHAR * name,XARRAY array)5747 void us_setxarray(INTBIG addr, INTBIG type, CHAR *name, XARRAY array)
5748 {
5749 REGISTER INTBIG i, x, y;
5750
5751 i = 0;
5752 for(y=0; y<3; y++)
5753 {
5754 for(x=0; x<3; x++)
5755 {
5756 (void)setind(addr, type, name, i, array[y][x]);
5757 i++;
5758 }
5759 }
5760 }
5761
5762 /*
5763 * Routine to return true if "name" is legal for objects of type "type".
5764 */
us_validname(CHAR * name,INTBIG type)5765 BOOLEAN us_validname(CHAR *name, INTBIG type)
5766 {
5767 REGISTER CHAR *pt;
5768
5769 for(pt = name; *pt != 0; pt++)
5770 {
5771 if (*pt == ' ' || *pt == '\t')
5772 {
5773 ttyputerr(_("Name cannot have embedded spaces"));
5774 return(FALSE);
5775 }
5776 if (*pt < ' ' || *pt >= 0177)
5777 {
5778 ttyputerr(_("Name has unprintable characters"));
5779 return(FALSE);
5780 }
5781 if (type == VNODEPROTO)
5782 {
5783 if (*pt == ':' || *pt == ';' || *pt == '{')
5784 {
5785 ttyputerr(_("Name cannot have '%c' in it"), *pt);
5786 return(FALSE);
5787 }
5788 }
5789 if (type == VARCPROTO || type == VTECHNOLOGY || type == VLIBRARY)
5790 {
5791 if (*pt == ':')
5792 {
5793 ttyputerr(_("Name cannot have '%c' in it"), *pt);
5794 return(FALSE);
5795 }
5796 }
5797 }
5798 return(TRUE);
5799 }
5800
5801 /*
5802 * Helper routine to determine the proper "address" field to use from variable "var".
5803 * Normally, it is simply "var->addr", but if it is a string with the "++" or "--"
5804 * sequence in it, then it auto-increments/decrements a numeric value, and so the
5805 * "++"/"--" are removed, and the original variable (which resides on "addr"/"type")
5806 * is modified.
5807 */
us_inheritaddress(INTBIG addr,INTBIG type,VARIABLE * var)5808 INTBIG us_inheritaddress(INTBIG addr, INTBIG type, VARIABLE *var)
5809 {
5810 REGISTER CHAR *str;
5811 CHAR line[30];
5812 REGISTER INTBIG i, j, len, incrpoint, retval, curval;
5813 REGISTER void *infstr;
5814
5815 /* if it isn't a string, just return its address */
5816 if ((var->type&(VCODE1|VCODE1)) == 0 && (var->type & VTYPE) != VSTRING) return(var->addr);
5817 if ((var->type & VISARRAY) != 0) return(var->addr);
5818
5819 str = (CHAR *)var->addr;
5820 len = estrlen(str);
5821 for(i=0; i<len; i++)
5822 {
5823 if (str[i] == '+' && str[i+1] == '+') break;
5824 if (str[i] == '-' && str[i+1] == '-') break;
5825 }
5826 if (i >= len) return(var->addr);
5827
5828 /* construct the proper inherited string and increment the variable */
5829 incrpoint = 0;
5830 infstr = initinfstr();
5831 for(i=0; i<len; i++)
5832 {
5833 if (str[i] == '+' && str[i+1] == '+')
5834 {
5835 incrpoint = i;
5836 i++;
5837 continue;
5838 }
5839 if (str[i] == '-' && str[i+1] == '-')
5840 {
5841 incrpoint = i;
5842 i++;
5843 continue;
5844 }
5845 addtoinfstr(infstr, str[i]);
5846 }
5847
5848 /* get the new value */
5849 retval = (INTBIG)returninfstr(infstr);
5850
5851 /* increment the variable */
5852 for(i = incrpoint-1; i>0; i--)
5853 if (!isdigit(str[i])) break;
5854 i++;
5855 str[incrpoint] = 0;
5856 curval = myatoi(&str[i]);
5857 str[incrpoint] = str[incrpoint+1];
5858 if (str[incrpoint] == '+') curval++; else curval--;
5859 infstr = initinfstr();
5860 for(j=0; j<i; j++)
5861 addtoinfstr(infstr, str[j]);
5862 esnprintf(line, 30, x_("%ld"), curval);
5863 addstringtoinfstr(infstr, line);
5864 addstringtoinfstr(infstr, &str[incrpoint]);
5865 (void)setval(addr, type, makename(var->key), (INTBIG)returninfstr(infstr), var->type);
5866
5867 return(retval);
5868 }
5869
5870 /*
5871 * Routine to update the location of parameters on node "ni".
5872 * Returns TRUE if adjustments were made.
5873 */
us_adjustparameterlocations(NODEINST * ni)5874 BOOLEAN us_adjustparameterlocations(NODEINST *ni)
5875 {
5876 REGISTER INTBIG i, xo, yo;
5877 REGISTER UINTBIG pos, size, face, rot, it, bo, un;
5878 REGISTER BOOLEAN changed;
5879 REGISTER VARIABLE *npvar, *nivar, *iconvar;
5880 REGISTER NODEPROTO *np, *cnp;
5881 REGISTER NODEINST *icon;
5882
5883 /* get the location from the example icon */
5884 np = ni->proto;
5885 cnp = contentsview(np);
5886 if (cnp == NONODEPROTO) return(FALSE);
5887
5888 /* look for an example of the icon in the contents */
5889 for(icon = cnp->firstnodeinst; icon != NONODEINST; icon = icon->nextnodeinst)
5890 if (icon->proto == np) break;
5891 if (icon == NONODEINST) return(FALSE);
5892
5893 /* now adjust the positions to match the icon */
5894 changed = FALSE;
5895 for(i=0; i<cnp->numvar; i++)
5896 {
5897 /* find a parameter */
5898 npvar = &cnp->firstvar[i];
5899 if (TDGETINHERIT(npvar->textdescript) == 0) continue;
5900
5901 /* find the parameter on this instance */
5902 nivar = getvalkeynoeval((INTBIG)ni, VNODEINST, -1, npvar->key);
5903 if (nivar == NOVARIABLE) continue;
5904
5905 /* see what the icon's position is */
5906 iconvar = getvalkeynoeval((INTBIG)icon, VNODEINST, -1, npvar->key);
5907 if (iconvar == NOVARIABLE) continue;
5908
5909 /* see if the offsets are the same */
5910 xo = TDGETXOFF(iconvar->textdescript);
5911 yo = TDGETYOFF(iconvar->textdescript);
5912 pos = TDGETPOS(iconvar->textdescript);
5913 size = TDGETSIZE(iconvar->textdescript);
5914 face = TDGETFACE(iconvar->textdescript);
5915 rot = TDGETROTATION(iconvar->textdescript);
5916 it = TDGETITALIC(iconvar->textdescript);
5917 bo = TDGETBOLD(iconvar->textdescript);
5918 un = TDGETUNDERLINE(iconvar->textdescript);
5919 if (xo == TDGETXOFF(nivar->textdescript) && yo == TDGETYOFF(nivar->textdescript) &&
5920 pos == TDGETPOS(nivar->textdescript) && size == TDGETSIZE(nivar->textdescript) &&
5921 face == TDGETFACE(nivar->textdescript) && rot == TDGETROTATION(nivar->textdescript) &&
5922 it == TDGETITALIC(nivar->textdescript) && bo == TDGETBOLD(nivar->textdescript) &&
5923 un == TDGETUNDERLINE(nivar->textdescript)) continue;
5924 if (!changed)
5925 startobjectchange((INTBIG)ni, VNODEINST);
5926 TDSETOFF(nivar->textdescript, xo, yo);
5927 TDSETPOS(nivar->textdescript, pos);
5928 TDSETSIZE(nivar->textdescript, size);
5929 TDSETFACE(nivar->textdescript, face);
5930 TDSETROTATION(nivar->textdescript, rot);
5931 TDSETITALIC(nivar->textdescript, it);
5932 TDSETBOLD(nivar->textdescript, bo);
5933 TDSETUNDERLINE(nivar->textdescript, un);
5934 changed = TRUE;
5935 }
5936 if (changed) endobjectchange((INTBIG)ni, VNODEINST);
5937 return(changed);
5938 }
5939
5940 /*
5941 * Routine to inherit all prototype attributes down to instance "ni".
5942 */
us_inheritattributes(NODEINST * ni)5943 void us_inheritattributes(NODEINST *ni)
5944 {
5945 REGISTER NODEPROTO *np, *cnp;
5946 REGISTER NODEINST *icon;
5947 REGISTER INTBIG i, j;
5948 REGISTER VARIABLE *var, *ovar;
5949 REGISTER BOOLEAN found, first;
5950 REGISTER PORTPROTO *pp, *cpp;
5951
5952 /* ignore primitives */
5953 np = ni->proto;
5954 if (np->primindex != 0) return;
5955
5956 /* first inherit directly from this node's prototype */
5957 for(i=0; i<np->numvar; i++)
5958 {
5959 var = &np->firstvar[i];
5960 if (TDGETINHERIT(var->textdescript) == 0) continue;
5961 us_inheritcellattribute(var, ni, np, NONODEINST);
5962 }
5963
5964 /* inherit directly from each port's prototype */
5965 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5966 us_inheritexportattributes(pp, ni, np);
5967
5968 /* if this node is an icon, also inherit from the contents prototype */
5969 cnp = contentsview(np);
5970 if (cnp != NONODEPROTO)
5971 {
5972 /* look for an example of the icon in the contents */
5973 for(icon = cnp->firstnodeinst; icon != NONODEINST; icon = icon->nextnodeinst)
5974 if (icon->proto == np) break;
5975
5976 for(i=0; i<cnp->numvar; i++)
5977 {
5978 var = &cnp->firstvar[i];
5979 if (TDGETINHERIT(var->textdescript) == 0) continue;
5980 us_inheritcellattribute(var, ni, cnp, icon);
5981 }
5982 for(cpp = cnp->firstportproto; cpp != NOPORTPROTO; cpp = cpp->nextportproto)
5983 us_inheritexportattributes(cpp, ni, cnp);
5984 }
5985
5986 /* now delete parameters that are not in the prototype */
5987 cnp = contentsview(np);
5988 if (cnp == NONODEPROTO) cnp = np;
5989 found = TRUE;
5990 first = TRUE;
5991 while (found)
5992 {
5993 found = FALSE;
5994 for(i=0; i<ni->numvar; i++)
5995 {
5996 var = &ni->firstvar[i];
5997 if (TDGETISPARAM(var->textdescript) == 0) continue;
5998 for(j=0; j<cnp->numvar; j++)
5999 {
6000 ovar = &cnp->firstvar[j];
6001 if (TDGETISPARAM(ovar->textdescript) == 0) continue;
6002 if (ovar->key == var->key) break;
6003 }
6004 if (j >= cnp->numvar)
6005 {
6006 if (first) startobjectchange((INTBIG)ni, VNODEINST);
6007 first = FALSE;
6008 delvalkey((INTBIG)ni, VNODEINST, var->key);
6009 found = TRUE;
6010 break;
6011 }
6012 }
6013 }
6014 if (!first) endobjectchange((INTBIG)ni, VNODEINST);
6015 }
6016
6017 /*
6018 * Routine to add all inheritable export variables from export "pp" on cell "np"
6019 * to instance "ni".
6020 */
us_inheritexportattributes(PORTPROTO * pp,NODEINST * ni,NODEPROTO * np)6021 void us_inheritexportattributes(PORTPROTO *pp, NODEINST *ni, NODEPROTO *np)
6022 {
6023 REGISTER INTSML saverot, savetrn;
6024 REGISTER INTBIG i, dx, dy, lambda, style=0;
6025 INTBIG x, y;
6026 UINTBIG descript[TEXTDESCRIPTSIZE];
6027 REGISTER VARIABLE *var, *newvar;
6028 REGISTER CHAR *pt, *attrname;
6029 XARRAY trans;
6030 REGISTER void *infstr;
6031 Q_UNUSED( np );
6032
6033 for(i=0; i<pp->numvar; i++)
6034 {
6035 var = &pp->firstvar[i];
6036 if (TDGETINHERIT(var->textdescript) == 0) continue;
6037 infstr = initinfstr();
6038 addstringtoinfstr(infstr, x_("ATTRP_"));
6039 addstringtoinfstr(infstr, pp->protoname);
6040 addstringtoinfstr(infstr, x_("_"));
6041 pt = makename(var->key);
6042 addstringtoinfstr(infstr, &pt[5]);
6043 attrname = returninfstr(infstr);
6044
6045 /* see if the attribute is already there */
6046 newvar = getval((INTBIG)ni, VNODEINST, -1, attrname);
6047 if (newvar != NOVARIABLE) continue;
6048
6049 /* set the attribute */
6050 startobjectchange((INTBIG)ni, VNODEINST);
6051 newvar = setval((INTBIG)ni, VNODEINST, attrname,
6052 us_inheritaddress((INTBIG)pp, VPORTPROTO, var), var->type);
6053 if (newvar != NOVARIABLE)
6054 {
6055 lambda = lambdaofnode(ni);
6056 TDCOPY(descript, var->textdescript);
6057 dx = TDGETXOFF(descript);
6058 dx = dx * lambda / 4;
6059 dy = TDGETYOFF(descript);
6060 dy = dy * lambda / 4;
6061
6062 saverot = pp->subnodeinst->rotation;
6063 savetrn = pp->subnodeinst->transpose;
6064 pp->subnodeinst->rotation = pp->subnodeinst->transpose = 0;
6065 portposition(pp->subnodeinst, pp->subportproto, &x, &y);
6066 pp->subnodeinst->rotation = saverot;
6067 pp->subnodeinst->transpose = savetrn;
6068 x += dx; y += dy;
6069 makerot(pp->subnodeinst, trans);
6070 xform(x, y, &x, &y, trans);
6071 maketrans(ni, trans);
6072 xform(x, y, &x, &y, trans);
6073 makerot(ni, trans);
6074 xform(x, y, &x, &y, trans);
6075 x = x - (ni->lowx + ni->highx) / 2;
6076 y = y - (ni->lowy + ni->highy) / 2;
6077 switch (TDGETPOS(descript))
6078 {
6079 case VTPOSCENT: style = TEXTCENT; break;
6080 case VTPOSBOXED: style = TEXTBOX; break;
6081 case VTPOSUP: style = TEXTBOT; break;
6082 case VTPOSDOWN: style = TEXTTOP; break;
6083 case VTPOSLEFT: style = TEXTRIGHT; break;
6084 case VTPOSRIGHT: style = TEXTLEFT; break;
6085 case VTPOSUPLEFT: style = TEXTBOTRIGHT; break;
6086 case VTPOSUPRIGHT: style = TEXTBOTLEFT; break;
6087 case VTPOSDOWNLEFT: style = TEXTTOPRIGHT; break;
6088 case VTPOSDOWNRIGHT: style = TEXTTOPLEFT; break;
6089 }
6090 makerot(pp->subnodeinst, trans);
6091 style = rotatelabel(style, TDGETROTATION(descript), trans);
6092 switch (style)
6093 {
6094 case TEXTCENT: TDSETPOS(descript, VTPOSCENT); break;
6095 case TEXTBOX: TDSETPOS(descript, VTPOSBOXED); break;
6096 case TEXTBOT: TDSETPOS(descript, VTPOSUP); break;
6097 case TEXTTOP: TDSETPOS(descript, VTPOSDOWN); break;
6098 case TEXTRIGHT: TDSETPOS(descript, VTPOSLEFT); break;
6099 case TEXTLEFT: TDSETPOS(descript, VTPOSRIGHT); break;
6100 case TEXTBOTRIGHT: TDSETPOS(descript, VTPOSUPLEFT); break;
6101 case TEXTBOTLEFT: TDSETPOS(descript, VTPOSUPRIGHT); break;
6102 case TEXTTOPRIGHT: TDSETPOS(descript, VTPOSDOWNLEFT); break;
6103 case TEXTTOPLEFT: TDSETPOS(descript, VTPOSDOWNRIGHT); break;
6104 }
6105 x = x * 4 / lambda;
6106 y = y * 4 / lambda;
6107 TDSETOFF(descript, x, y);
6108 TDSETINHERIT(descript, 0);
6109 TDCOPY(newvar->textdescript, descript);
6110 }
6111 endobjectchange((INTBIG)ni, VNODEINST);
6112 }
6113 }
6114
6115 /*
6116 * Routine to add inheritable variable "var" from cell "np" to instance "ni".
6117 * If "icon" is not NONODEINST, use the position of the variable from it.
6118 */
us_inheritcellattribute(VARIABLE * var,NODEINST * ni,NODEPROTO * np,NODEINST * icon)6119 void us_inheritcellattribute(VARIABLE *var, NODEINST *ni, NODEPROTO *np, NODEINST *icon)
6120 {
6121 REGISTER VARIABLE *newvar, *ivar, *posvar;
6122 REGISTER INTBIG xc, yc, lambda, i, newtype;
6123
6124 /* see if the attribute is already there */
6125 newvar = getvalkey((INTBIG)ni, VNODEINST, -1, var->key);
6126 if (newvar != NOVARIABLE)
6127 {
6128 /* make sure visibility is OK */
6129 if (TDGETINTERIOR(var->textdescript) == 0)
6130 {
6131 /* parameter should be visible: make it so */
6132 if ((newvar->type&VDISPLAY) == 0)
6133 {
6134 startobjectchange((INTBIG)ni, VNODEINST);
6135 newvar->type |= VDISPLAY;
6136 endobjectchange((INTBIG)ni, VNODEINST);
6137 }
6138 } else
6139 {
6140 /* parameter not normally visible: make it invisible if it has the default value */
6141 if ((newvar->type&VDISPLAY) != 0)
6142 {
6143 if (estrcmp(describevariable(var, -1, -1), describevariable(newvar, -1, -1)) == 0)
6144 {
6145 startobjectchange((INTBIG)ni, VNODEINST);
6146 newvar->type &= ~VDISPLAY;
6147 endobjectchange((INTBIG)ni, VNODEINST);
6148 }
6149 }
6150 }
6151 return;
6152 }
6153
6154 /* determine offset of the attribute on the instance */
6155 posvar = var;
6156 if (icon != NONODEINST)
6157 {
6158 ivar = NOVARIABLE;
6159 for(i=0; i<icon->numvar; i++)
6160 {
6161 ivar = &icon->firstvar[i];
6162 if (ivar->key == var->key) break;
6163 }
6164 if (i < icon->numvar) posvar = ivar;
6165 }
6166
6167 lambda = np->lib->lambda[np->tech->techindex];
6168 xc = TDGETXOFF(posvar->textdescript) * lambda / 4;
6169 if (posvar == var) xc -= (np->lowx + np->highx) / 2;
6170 yc = TDGETYOFF(posvar->textdescript) * lambda / 4;
6171 if (posvar == var) yc -= (np->lowy + np->highy) / 2;
6172 lambda = lambdaofnode(ni);
6173 xc = xc * 4 / lambda;
6174 yc = yc * 4 / lambda;
6175
6176 /* set the attribute */
6177 startobjectchange((INTBIG)ni, VNODEINST);
6178 newtype = (var->type & ~(VDISPLAY|VTYPE|VCODE1|VCODE2)) |
6179 (posvar->type & (VDISPLAY|VTYPE|VCODE1|VCODE2));
6180 if (TDGETINTERIOR(var->textdescript) != 0) newtype &= ~VDISPLAY;
6181 newvar = setvalkey((INTBIG)ni, VNODEINST, var->key,
6182 us_inheritaddress((INTBIG)np, VNODEPROTO, posvar), newtype);
6183 if (newvar != NOVARIABLE)
6184 {
6185 defaulttextsize(3, newvar->textdescript);
6186 TDCOPY(newvar->textdescript, posvar->textdescript);
6187 TDSETINHERIT(newvar->textdescript, 0);
6188 TDSETOFF(newvar->textdescript, xc, yc);
6189 if (TDGETISPARAM(var->textdescript) != 0)
6190 {
6191 TDSETINTERIOR(newvar->textdescript, 0);
6192 i = TDGETDISPPART(newvar->textdescript);
6193 if (i == VTDISPLAYNAMEVALINH || i == VTDISPLAYNAMEVALINHALL)
6194 TDSETDISPPART(newvar->textdescript, VTDISPLAYNAMEVALUE);
6195 }
6196 }
6197 endobjectchange((INTBIG)ni, VNODEINST);
6198 }
6199
6200 /*
6201 * Routine to add a parameter attribute to node "ni". The variable key is "key",
6202 * the new value is "addr", and the type is "type".
6203 */
us_addparameter(NODEINST * ni,INTBIG key,INTBIG addr,INTBIG type,UINTBIG * descript)6204 void us_addparameter(NODEINST *ni, INTBIG key, INTBIG addr, INTBIG type, UINTBIG *descript)
6205 {
6206 REGISTER VARIABLE *var;
6207 UINTBIG textdescript[TEXTDESCRIPTSIZE];
6208
6209 us_findexistingparameter(ni, key, textdescript);
6210 startobjectchange((INTBIG)ni, VNODEINST);
6211 var = setvalkey((INTBIG)ni, VNODEINST, key, addr, type|VDISPLAY);
6212 if (var != NOVARIABLE)
6213 {
6214 TDCOPY(var->textdescript, textdescript);
6215 TDSETISPARAM(var->textdescript, VTISPARAMETER);
6216 TDSETINTERIOR(var->textdescript, 0);
6217 TDSETDISPPART(var->textdescript, VTDISPLAYNAMEVALUE);
6218 if (descript != 0) TDSETUNITS(var->textdescript, TDGETUNITS(descript));
6219 }
6220 endobjectchange((INTBIG)ni, VNODEINST);
6221 }
6222
6223 /*
6224 * Routine to find the formal parameter that corresponds to the actual parameter
6225 * "var" on node "ni". Returns NOVARIABLE if not a parameter or cannot be found.
6226 */
us_findparametersource(VARIABLE * var,NODEINST * ni)6227 VARIABLE *us_findparametersource(VARIABLE *var, NODEINST *ni)
6228 {
6229 REGISTER NODEPROTO *np, *cnp;
6230 REGISTER INTBIG k;
6231 REGISTER VARIABLE *nvar;
6232
6233 /* find this parameter in the cell */
6234 np = ni->proto;
6235 cnp = contentsview(np);
6236 if (cnp != NONODEPROTO) np = cnp;
6237 for(k=0; k<np->numvar; k++)
6238 {
6239 nvar = &np->firstvar[k];
6240 if (namesame(makename(var->key), makename(nvar->key)) == 0) return(nvar);
6241 }
6242 return(NOVARIABLE);
6243 }
6244
6245 /*
6246 * Routine to determine the location of parameter "key" on node "ni".
6247 * Returns the variable
6248 * The parameter offset is stored in (xoff, yoff).
6249 */
us_findexistingparameter(NODEINST * ni,INTBIG key,UINTBIG * textdescript)6250 void us_findexistingparameter(NODEINST *ni, INTBIG key, UINTBIG *textdescript)
6251 {
6252 REGISTER NODEINST *icon;
6253 REGISTER NODEPROTO *np, *cnp;
6254 REGISTER INTBIG i, numvar, count, xsum, yval, lowy, highy, xoff, yoff;
6255 REGISTER VARIABLE *firstvar, *var;
6256
6257 /* special case if this is a parameter */
6258 np = ni->proto;
6259 cnp = contentsview(np);
6260 if (cnp != NONODEPROTO)
6261 {
6262 /* look for an example of the icon in the contents */
6263 for(icon = cnp->firstnodeinst; icon != NONODEINST; icon = icon->nextnodeinst)
6264 if (icon->proto == np) break;
6265 if (icon != NONODEINST)
6266 {
6267 var = NOVARIABLE;
6268 for(i=0; i<icon->numvar; i++)
6269 {
6270 var = &icon->firstvar[i];
6271 if (var->key == key) break;
6272 }
6273 if (i < icon->numvar)
6274 {
6275 TDCOPY(textdescript, var->textdescript);
6276 return;
6277 }
6278 }
6279 }
6280
6281 numvar = ni->numvar;
6282 firstvar = ni->firstvar;
6283 count = xsum = 0;
6284 lowy = highy = 0;
6285 for(i=0; i<numvar; i++)
6286 {
6287 var = &firstvar[i];
6288 if (TDGETISPARAM(var->textdescript) == 0) continue;
6289 xsum += TDGETXOFF(var->textdescript);
6290 yval = TDGETYOFF(var->textdescript);
6291 if (count == 0) lowy = highy = yval; else
6292 {
6293 if (yval < lowy) lowy = yval;
6294 if (yval > highy) highy = yval;
6295 }
6296 count++;
6297 }
6298 defaulttextsize(3, textdescript);
6299 if (count == 0) xoff = yoff = 0; else
6300 {
6301 xoff = xsum / count;
6302 if (count == 1) yoff = lowy - 4; else
6303 yoff = lowy - (highy - lowy) / (count-1);
6304 }
6305 TDSETOFF(textdescript, xoff, yoff);
6306 }
6307
6308 /*
6309 * Routine to determine the location of a new parameter in cell "np".
6310 * The parameter offset is stored in (xoff, yoff).
6311 */
us_getnewparameterpos(NODEPROTO * np,INTBIG * xoff,INTBIG * yoff)6312 void us_getnewparameterpos(NODEPROTO *np, INTBIG *xoff, INTBIG *yoff)
6313 {
6314 REGISTER INTBIG i, numvar, count, xsum, yval, lowy, highy;
6315 REGISTER VARIABLE *firstvar, *var;
6316
6317 numvar = np->numvar;
6318 firstvar = np->firstvar;
6319 count = xsum = 0;
6320 lowy = highy = 0;
6321 for(i=0; i<numvar; i++)
6322 {
6323 var = &firstvar[i];
6324 if (TDGETISPARAM(var->textdescript) == 0) continue;
6325 xsum += TDGETXOFF(var->textdescript);
6326 yval = TDGETYOFF(var->textdescript);
6327 if (count == 0) lowy = highy = yval; else
6328 {
6329 if (yval < lowy) lowy = yval;
6330 if (yval > highy) highy = yval;
6331 }
6332 count++;
6333 }
6334 if (count == 0) *xoff = *yoff = 0; else
6335 {
6336 *xoff = xsum / count;
6337 if (count == 1) *yoff = lowy - 4; else
6338 *yoff = lowy - (highy - lowy) / (count-1);
6339 }
6340 }
6341
6342 static INTBIG us_coveragepolyscrunched;
6343 static INTBIG us_coveragejobsize;
6344 static INTBIG *us_coveragelayers;
6345 static INTBIG us_coveragelayercount;
6346 static TECHNOLOGY *us_coveragetech;
6347 static void *us_coveragedialog;
6348 static float *us_coveragearea;
6349
6350 void us_gathercoveragegeometry(NODEPROTO *np, XARRAY trans, void **merge);
6351 void us_getcoveragegeometry(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
6352
6353 /*
6354 * Routine to compute the percentage of coverage for the polysilicon and metal layers.
6355 */
us_showlayercoverage(NODEPROTO * cell)6356 void us_showlayercoverage(NODEPROTO *cell)
6357 {
6358 REGISTER LIBRARY *lib;
6359 REGISTER NODEPROTO *np;
6360 REGISTER VARIABLE *var;
6361 REGISTER INTBIG i, fun, lambda, percentcoverage;
6362 REGISTER float totalarea, coverageratio;
6363 REGISTER void **submerge, **polymerge;
6364
6365 /* initialize for analysis */
6366 lambda = lambdaofcell(cell);
6367 us_coveragetech = cell->tech;
6368
6369 /* determine which layers are being collected */
6370 us_coveragelayercount = 0;
6371 for(i=0; i<us_coveragetech->layercount; i++)
6372 {
6373 fun = layerfunction(us_coveragetech, i);
6374 if ((fun&LFPSEUDO) != 0) continue;
6375 if (!layerismetal(fun) && !layerispoly(fun)) continue;
6376 us_coveragelayercount++;
6377 }
6378 if (us_coveragelayercount == 0)
6379 {
6380 ttyputerr(_("No metal or polysilicon layers in this technology"));
6381 return;
6382 }
6383 us_coveragelayers = (INTBIG *)emalloc(us_coveragelayercount * SIZEOFINTBIG, us_tool->cluster);
6384 if (us_coveragelayers == 0) return;
6385 us_coveragelayercount = 0;
6386 for(i=0; i<us_coveragetech->layercount; i++)
6387 {
6388 fun = layerfunction(us_coveragetech, i);
6389 if ((fun&LFPSEUDO) != 0) continue;
6390 if (!layerismetal(fun) && !layerispoly(fun)) continue;
6391 us_coveragelayers[us_coveragelayercount++] = i;
6392 }
6393
6394 /* show the progress dialog */
6395 us_coveragedialog = DiaInitProgress(_("Merging geometry..."), 0);
6396 if (us_coveragedialog == 0)
6397 {
6398 termerrorlogging(TRUE);
6399 return;
6400 }
6401 DiaSetProgress(us_coveragedialog, 0, 1);
6402
6403 /* reset merging information */
6404 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
6405 {
6406 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
6407 {
6408 np->temp1 = 0;
6409
6410 /* if this cell has parameters, force its polygons to be examined for every instance */
6411 for(i=0; i<np->numvar; i++)
6412 {
6413 var = &np->firstvar[i];
6414 if (TDGETISPARAM(var->textdescript) != 0) break;
6415 }
6416 if (i < np->numvar) np->temp1 = -1;
6417 }
6418 }
6419
6420 /* run through the work and count the number of polygons */
6421 us_coveragepolyscrunched = 0;
6422 us_gathercoveragegeometry(cell, el_matid, 0);
6423 us_coveragejobsize = us_coveragepolyscrunched;
6424
6425 /* now gather all of the geometry into the polygon merging system */
6426 polymerge = (void **)emalloc(us_coveragelayercount * (sizeof (void *)), us_tool->cluster);
6427 if (polymerge == 0) return;
6428 for(i=0; i<us_coveragelayercount; i++)
6429 polymerge[i] = mergenew(us_tool->cluster);
6430 us_coveragepolyscrunched = 0;
6431 us_gathercoveragegeometry(cell, el_matid, polymerge);
6432
6433 /* extract the information */
6434 us_coveragearea = (float *)emalloc(us_coveragelayercount * (sizeof (float)), us_tool->cluster);
6435 if (us_coveragearea == 0) return;
6436 for(i=0; i<us_coveragelayercount; i++)
6437 {
6438 us_coveragearea[i] = 0.0;
6439 mergeextract(polymerge[i], us_getcoveragegeometry);
6440 }
6441
6442 /* show the results */
6443 totalarea = (float)(cell->highx - cell->lowx);
6444 totalarea *= (float)(cell->highy - cell->lowy);
6445 ttyputmsg(x_("Cell is %g square lambda"), totalarea/(float)lambda/(float)lambda);
6446 for(i=0; i<us_coveragelayercount; i++)
6447 {
6448 if (us_coveragearea[i] == 0.0) continue;
6449 if (totalarea == 0.0) coverageratio = 0.0; else
6450 coverageratio = us_coveragearea[i] / totalarea;
6451 percentcoverage = (INTBIG)(coverageratio * 100.0 + 0.5);
6452
6453 ttyputmsg(x_("Layer %s covers %g square lambda (%ld%%)"),
6454 layername(us_coveragetech, us_coveragelayers[i]),
6455 us_coveragearea[i]/(float)lambda/(float)lambda, percentcoverage);
6456 }
6457
6458 /* delete merge information */
6459 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
6460 {
6461 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
6462 {
6463 if (np->temp1 == 0 || np->temp1 == -1) continue;
6464 submerge = (void **)np->temp1;
6465 for(i=0; i<us_coveragelayercount; i++)
6466 mergedelete(submerge[i]);
6467 efree((CHAR *)submerge);
6468 }
6469 }
6470 for(i=0; i<us_coveragelayercount; i++)
6471 mergedelete(polymerge[i]);
6472 efree((CHAR *)polymerge);
6473
6474 /* clean up */
6475 efree((CHAR *)us_coveragelayers);
6476 DiaDoneProgress(us_coveragedialog);
6477 }
6478
6479 /*
6480 * Recursive helper routine to gather all well areas in cell "np"
6481 * (transformed by "trans"). If "merge" is nonzero, merge geometry into it.
6482 * If "gathernet" is true, follow networks, looking for special primitives and nets.
6483 */
us_gathercoveragegeometry(NODEPROTO * np,XARRAY trans,void ** merge)6484 void us_gathercoveragegeometry(NODEPROTO *np, XARRAY trans, void **merge)
6485 {
6486 REGISTER NODEINST *ni;
6487 REGISTER NODEPROTO *subnp;
6488 REGISTER ARCINST *ai;
6489 REGISTER GEOM *geom;
6490 REGISTER INTBIG i, j, tot, updatepct, sea;
6491 REGISTER void **submerge;
6492 static INTBIG checkstop = 0;
6493 XARRAY localrot, localtran, final, subrot;
6494 static POLYGON *poly = NOPOLYGON;
6495
6496 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
6497
6498 /* do a spatial search so that polygon merging grows sensibly */
6499 updatepct = 0;
6500 sea = initsearch(np->lowx, np->highx, np->lowy, np->highy, np);
6501 for(;;)
6502 {
6503 geom = nextobject(sea);
6504 if (geom == NOGEOM) break;
6505 checkstop++;
6506 if ((checkstop%10) == 0)
6507 {
6508 if (stopping(STOPREASONERC)) { termsearch(sea); return; }
6509 }
6510 if (!geom->entryisnode)
6511 {
6512 ai = geom->entryaddr.ai;
6513 tot = arcpolys(ai, NOWINDOWPART);
6514 us_coveragepolyscrunched += tot;
6515 if (merge != 0)
6516 {
6517 if (us_coveragejobsize > 0)
6518 {
6519 if (updatepct++ > 25)
6520 {
6521 DiaSetProgress(us_coveragedialog, us_coveragepolyscrunched, us_coveragejobsize);
6522 updatepct = 0;
6523 }
6524 }
6525 for(i=0; i<tot; i++)
6526 {
6527 shapearcpoly(ai, i, poly);
6528 if (poly->tech != us_coveragetech) continue;
6529 for(j=0; j<us_coveragelayercount; j++)
6530 {
6531 if (poly->layer == us_coveragelayers[j])
6532 {
6533 xformpoly(poly, trans);
6534 mergeaddpolygon(merge[j], poly->layer, poly->tech, poly);
6535 }
6536 }
6537 }
6538 }
6539 continue;
6540 }
6541
6542 ni = geom->entryaddr.ni;
6543 subnp = ni->proto;
6544 makerot(ni, localrot);
6545 transmult(localrot, trans, final);
6546 if (subnp->primindex == 0)
6547 {
6548 maketrans(ni, localtran);
6549 transmult(localtran, final, subrot);
6550
6551 if (merge != 0)
6552 {
6553 if (subnp->temp1 == -1)
6554 {
6555 /* parameterized cell: examine the contents recursively */
6556 us_gathercoveragegeometry(subnp, subrot, merge);
6557 } else
6558 {
6559 submerge = (void **)subnp->temp1;
6560 if (submerge == 0)
6561 {
6562 /* gather the subcell's merged information */
6563 submerge = (void **)emalloc(us_coveragelayercount * (sizeof (void *)),
6564 us_tool->cluster);
6565 if (submerge == 0) return;
6566 for(i=0; i<us_coveragelayercount; i++)
6567 submerge[i] = mergenew(us_tool->cluster);
6568 us_gathercoveragegeometry(subnp, el_matid, submerge);
6569 subnp->temp1 = (INTBIG)submerge;
6570 }
6571
6572 for(i=0; i<us_coveragelayercount; i++)
6573 mergeaddmerge(merge[i], submerge[i], subrot);
6574 }
6575 }
6576 } else
6577 {
6578 tot = nodepolys(ni, 0, NOWINDOWPART);
6579 us_coveragepolyscrunched += tot;
6580 if (merge != 0)
6581 {
6582 if (us_coveragejobsize > 0)
6583 {
6584 if (updatepct++ > 25)
6585 {
6586 DiaSetProgress(us_coveragedialog, us_coveragepolyscrunched, us_coveragejobsize);
6587 updatepct = 0;
6588 }
6589 }
6590 for(i=0; i<tot; i++)
6591 {
6592 shapenodepoly(ni, i, poly);
6593 if (poly->tech != us_coveragetech) continue;
6594 for(j=0; j<us_coveragelayercount; j++)
6595 {
6596 if (poly->layer == us_coveragelayers[j])
6597 {
6598 xformpoly(poly, final);
6599 mergeaddpolygon(merge[j], poly->layer, poly->tech, poly);
6600 }
6601 }
6602 }
6603 }
6604 }
6605 }
6606 }
6607
6608 /*
6609 * Coroutine of the polygon merging package that is given a merged polygon with
6610 * "count" points in (x,y) with area "area".
6611 */
us_getcoveragegeometry(INTBIG layer,TECHNOLOGY * tech,INTBIG * x,INTBIG * y,INTBIG count)6612 void us_getcoveragegeometry(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
6613 {
6614 REGISTER INTBIG i;
6615 Q_UNUSED( tech );
6616
6617 for(i=0; i<us_coveragelayercount; i++)
6618 {
6619 if (layer != us_coveragelayers[i]) continue;
6620 us_coveragearea[i] += areapoints(count, x, y);
6621 break;
6622 }
6623 }
6624