2
* Electric(tm) VLSI Design System
5
* User interface tool: miscellaneous control
6
* Written by: Steven M. Rubin, Static Free Software
8
* Copyright (c) 2000 Static Free Software.
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* Static Free Software
27
* Portola Valley, California 94028
28
* info@staticfreesoft.com
32
#include "egraphics.h"
33
#include "efunction.h"
35
#include "usreditemacs.h"
36
#include "usreditpac.h"
43
#define ALLTEXTWIDTH 70 /* width of side menu when it is all text */
45
/******************** INITIALIZATION ********************/
47
#define INITIALMENUX 18 /* default height of component menu */
48
#define INITIALMENUY 2 /* default width of component menu */
51
* default tablet state: the table below shows the set of commands
52
* that will be bound to the tablet buttons. If there is a button
53
* with the name in "us_tablet[i].but[0]" or "us_tablet[i].but[1]"
54
* then that button will be bound to the command "us_tablet[i].com".
55
* If no tablet button exists for an entry "i", then the command
56
* there will be bound to the key "us_tablet[i].key". Thus, tablets
57
* with varying numbers of buttons can be handled by placing commands
58
* on the keys if they don't fit on the buttons.
62
char *but[3]; /* the button names for this command */
63
char *key; /* the key name for this command */
64
char *com; /* the actual command */
65
INTBIG count; /* number of parameters to the command */
66
char *args[2]; /* parameters to the command */
67
BOOLEAN used; /* set when the command is bound */
70
static INITBUTTONS us_initialbutton[] =
72
/* left/middle/right (white/yellow/blue) are basic commands */
73
{{"LEFT","WHITE","BUTTON"},"f", "find", 2, {"port", "extra-info"}, FALSE},
74
{{"RIGHT","YELLOW",""}, "m", "move", 0, {"", ""}, FALSE},
75
{{"MIDDLE","BLUE",""}, "n", "create", 0, {"", ""}, FALSE},
77
/* on four-button puck, add one more basic command */
78
{{"GREEN","",""}, "o", "find", 2, {"another", "port"}, FALSE},
80
/* on mice with shift-buttons, add in others still */
81
{{"SLEFT","",""}, "", "find", 1, {"more", ""}, FALSE},
82
{{"SRIGHT","",""}, "", "var", 2, {"textedit", "~"}, FALSE},
83
{{"SMIDDLE","",""}, "", "create", 1, {"join-angle", ""}, FALSE},
84
{{NULL, NULL, NULL}, NULL, NULL, 0, {NULL, NULL}, FALSE} /* 0 */
88
* default keyboard state: the table below shows the set of commands
89
* that will be bound to the keyboard keys.
99
static INITKEYS us_initialkeyboard[] =
102
{"a", "move", 1, {"left", ""}},
103
{"A", "move", 2, {"left", "8"}},
104
{"b", "size", 1, {"corner-fixed", ""}},
105
{"c", "window", 1, {"cursor-centered",""}},
106
{"d", "create", 1, {"join-angle", ""}},
107
{"e", "erase", 0, {"", ""}},
108
{"E", "erase", 1, {"pass-through", ""}},
109
{"g", "grid", 0, {"", ""}},
110
{"G", "text", 1, {"style", ""}},
111
{"i", "show", 2, {"object", "short"}},
112
{"I", "create", 1, {"insert", ""}},
113
{"k", "text", 2, {"size", "down"}},
114
{"K", "text", 2, {"size", "up"}},
115
{"l", "move", 1, {"angle", ""}},
116
{"p", "window", 1, {"peek", ""}},
117
{"s", "move", 1, {"right", ""}},
118
{"S", "move", 2, {"right", "8"}},
119
{"t", "duplicate", 0, {"", ""}},
120
{"T", "getproto", 1, {"this-proto", ""}},
121
{"u", "undo", 0, {"", ""}},
122
{"v", "window", 1, {"in-zoom", ""}},
123
{"V", "window", 1, {"out-zoom", ""}},
124
{"w", "move", 1, {"up", ""}},
125
{"W", "move", 2, {"up", "8"}},
126
{"x", "port", 1, {"export", ""}},
127
{"z", "move", 1, {"down", ""}},
128
{"Z", "move", 2, {"down", "8"}},
129
{" ", "getproto", 1, {"next-proto", ""}},
130
{"^^", "getproto", 1, {"prev-proto", ""}},
131
{"^014", "redraw", 0, {"", ""}},
132
{"^015", "echo", 1, {"Electric", ""}},
133
{"?", "show", 2, {"bindings", "short"}},
134
{"&", "iterate", 0, {"", ""}},
135
{"!", "system", 1, {"*", ""}},
136
{"=", "telltool", 2, {"network", "highlight"}},
137
{"[", "macbegin", 1, {"macro", ""}},
138
{"]", "macend", 0, {"", ""}},
139
{"%", "macro", 0, {"", ""}},
140
{",", "find", 1, {"area-move", ""}},
141
{".", "find", 1, {"area-size", ""}},
142
{"~", "arc", 2, {"not", "rigid"}},
143
{"|", "arc", 1, {"rigid", ""}},
144
{"+", "arc", 1, {"fixed-angle", ""}},
146
{"-", "telltool", 1, {"user", ""}},
147
{NULL, NULL, 0, {NULL, NULL}} /* 0 */
151
* When information, detected during broadcast, evokes a reaction that causes
152
* change, that change must be queued until the next slice. For example:
153
* deletion of the variable associated with a text window.
154
* These routines queue the changes and then execute them when requested
156
#define NOUBCHANGE ((UBCHANGE *)-1)
157
#define UBKILLFM 1 /* remove facet_message variable */
158
#define UBNEWFC 2 /* add facet-center */
160
typedef struct Iubchange
162
INTBIG change; /* type of change */
163
void *object; /* object that is being changed */
164
struct Iubchange *nextubchange;
166
static UBCHANGE *us_ubchangefree = NOUBCHANGE;
167
static UBCHANGE *us_ubchanges = NOUBCHANGE;
169
static NODEPROTO *us_layouttextprim;
171
/* prototypes for local routines */
172
static void us_splitwindownames(char*, char*, char*, char*, char*);
173
static BOOLEAN us_newubchange(INTBIG, void*);
174
static void us_freeubchange(UBCHANGE*);
175
static BOOLEAN us_pointonexparc(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, INTBIG x, INTBIG y);
176
static void us_rotatedescriptArb(GEOM *geom, UINTBIG *descript, BOOLEAN invert);
177
static void us_scanquickkeys(POPUPMENU *pm, char **quickkeylist, INTBIG quickkeycount, BOOLEAN *warnofchanges);
178
static void us_layouttextpolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
179
static INTBIG us_inheritaddress(INTBIG addr, INTBIG type, VARIABLE *var);
180
static NODEPROTO *us_findfacetinotherlib(NODEPROTO *facet, LIBRARY *lib);
181
static void us_correctxlibref(VARIABLE **firstvar, INTSML *numvar, LIBRARY *oldlib, LIBRARY *newlib);
182
static void us_adjustpopupmenu(POPUPMENU *pm, INTBIG pindex);
183
static void us_inheritexportattributes(PORTPROTO *pp, NODEINST *ni, NODEPROTO *np);
184
static void us_inheritfacetattribute(VARIABLE *var, NODEINST *ni, NODEPROTO *np, NODEINST *icon);
185
static void us_advancecircuittext(char *search, INTBIG bits);
186
static INTBIG us_stringinstring(char *string, char *search, INTBIG bits);
189
* Routine to free all memory associated with this module.
191
void us_freemiscmemory(void)
196
* initialization routine to bind keys and buttons to functions
197
* returns true upon error
199
BOOLEAN us_initialbinding(void)
201
REGISTER INTBIG i, k, menusave, menux, menuy;
203
char si[50], sj[20], *par[MAXPARS+7];
204
REGISTER char **temp;
206
/* make the variables with the bindings */
207
i = maxi(maxi(NUMKEYS, NUMBUTS), INITIALMENUX*INITIALMENUY);
208
temp = (char **)emalloc(i * (sizeof (char *)), el_tempcluster);
209
if (temp == 0) return(TRUE);
211
(void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)temp,
212
VSTRING|VISARRAY|VDONTSAVE|(1<<VLENGTHSH));
213
for(j=0; j<i; j++) temp[j] = "";
214
(void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_buttons_key, (INTBIG)temp,
215
VSTRING|VISARRAY|VDONTSAVE|(NUMBUTS<<VLENGTHSH));
216
(void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_menu_key, (INTBIG)temp,
217
VSTRING|VISARRAY|VDONTSAVE|((INITIALMENUX*INITIALMENUY)<<VLENGTHSH));
221
for(i=0; us_initialkeyboard[i].key != 0; i++)
223
par[0] = "set"; par[1] = "key";
224
par[2] = us_initialkeyboard[i].key;
225
par[3] = us_initialkeyboard[i].command;
226
for(j=0; j<us_initialkeyboard[i].count; j++)
227
par[j+4] = us_initialkeyboard[i].args[j];
228
us_bind(us_initialkeyboard[i].count+4, par);
231
/* bind the mouse commands that fit on the mouse */
232
for(i=0; i<buttoncount(); i++)
234
(void)strcpy(si, buttonname(i, &j));
235
for(j=0; us_initialbutton[j].but[0] != 0; j++)
236
if (!us_initialbutton[j].used)
239
if (namesame(si, us_initialbutton[j].but[k]) == 0)
241
par[0] = "set"; par[1] = "button"; par[2] = si;
242
par[3] = us_initialbutton[j].com;
243
for(k=0; k<us_initialbutton[j].count; k++)
244
par[k+4] = us_initialbutton[j].args[k];
245
us_bind(us_initialbutton[j].count+4, par);
246
us_initialbutton[j].used = TRUE;
252
/* now bind those mouse commands that can't fit on the mouse */
253
for(j=0; us_initialbutton[j].but[0] != 0; j++)
254
if (!us_initialbutton[j].used && *us_initialbutton[j].key != 0)
256
par[0] = "set"; par[1] = "key"; par[2] = us_initialbutton[j].key;
257
par[3] = us_initialbutton[j].com;
258
for(k=0; k<us_initialbutton[j].count; k++)
259
par[k+4] = us_initialbutton[j].args[k];
260
us_bind(us_initialbutton[j].count+4, par);
263
/* bind the component menu entries to all "getproto" */
266
menux = INITIALMENUX;
267
menuy = INITIALMENUY;
270
menux = INITIALMENUY;
271
menuy = INITIALMENUX;
273
us_setmenusize(menux, menuy, us_menupos, FALSE);
274
menusave = us_tool->toolstate&MENUON; us_tool->toolstate &= ~MENUON;
275
for(i=0; i<(INITIALMENUX*INITIALMENUY); i++)
277
par[0] = "set"; par[1] = "menu";
278
(void)sprintf(si, "%ld", i%INITIALMENUX);
279
(void)sprintf(sj, "%ld", i/INITIALMENUX);
282
par[2] = sj; par[3] = si;
285
par[2] = si; par[3] = sj;
291
/* now fill in the "getproto" commands properly */
292
us_setmenunodearcs();
294
if (menusave != 0) us_tool->toolstate |= MENUON; else
295
us_tool->toolstate &= ~MENUON;
300
* routine to determine for technology "tech" which node and arc prototypes
301
* have opaque layers and set the bits in the prototype->userbits.
302
* The rules for layer orderings are that the overlappable layers
303
* must come first followed by the opaque layers. The field that is
304
* set in the "userbits" is then the index of the first opaque layer.
306
void us_figuretechopaque(TECHNOLOGY *tech)
308
REGISTER INTBIG j, k;
309
REGISTER NODEPROTO *np;
310
REGISTER ARCPROTO *ap;
311
REGISTER NODEINST *node;
312
REGISTER ARCINST *arc;
313
static POLYGON *poly = NOPOLYGON;
316
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
318
for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
320
if ((np->userbits&NHASOPA) != 0) continue;
321
np->userbits &= ~NHASOPA;
324
node->lowx = np->lowx; node->highx = np->highx;
325
node->lowy = np->lowy; node->highy = np->highy;
326
j = nodepolys(node, 0, NOWINDOWPART);
329
shapenodepoly(node, k, poly);
330
if (poly->desc->bits == LAYERN) continue;
331
if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
333
/* overlappable layer found, make sure it is at start */
334
if ((np->userbits&NHASOPA) != 0)
335
ttyputerr(_("%s: node %s has layers out of order!"), tech->techname, np->primname);
339
/* opaque layer found, mark its index if it is the first */
340
if ((np->userbits&NHASOPA) == 0)
341
np->userbits = (np->userbits & ~NFIRSTOPA) | (k << NFIRSTOPASH);
342
np->userbits |= NHASOPA;
345
for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
347
ap->userbits &= ~AHASOPA;
350
arc->userbits = ISDIRECTIONAL;
351
j = arcpolys(arc, NOWINDOWPART);
354
shapearcpoly(arc, k, poly);
355
if (poly->desc->bits == LAYERN) continue;
356
if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
358
/* overlappable layer found, make sure it is at start */
359
if ((ap->userbits&AHASOPA) != 0)
360
ttyputerr(_("Arc %s:%s has layers out of order!"), tech->techname, ap->protoname);
364
/* opaque layer found, mark its index if it is the first */
365
if ((ap->userbits&AHASOPA) == 0)
366
ap->userbits = (ap->userbits & ~AFIRSTOPA) | (k << AFIRSTOPASH);
367
ap->userbits |= AHASOPA;
373
* Routine to recompute the "NINVISIBLE" and "AINVISIBLE" bits on node and arc protos
374
* according to whether or not all layers are invisible.
376
void us_figuretechselectability(void)
378
REGISTER INTBIG j, k;
379
REGISTER TECHNOLOGY *tech;
380
REGISTER NODEPROTO *np;
381
REGISTER ARCPROTO *ap;
382
REGISTER NODEINST *node;
383
REGISTER ARCINST *arc;
384
static POLYGON *poly = NOPOLYGON;
387
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
389
for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
391
for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
393
np->userbits &= ~NINVISIBLE;
396
node->lowx = np->lowx; node->highx = np->highx;
397
node->lowy = np->lowy; node->highy = np->highy;
398
j = nodepolys(node, 0, NOWINDOWPART);
401
shapenodepoly(node, k, poly);
402
if (poly->desc->bits == LAYERN) continue;
403
if ((poly->desc->colstyle&INVISIBLE) == 0) break;
405
if (k >= j) np->userbits |= NINVISIBLE;
407
for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
409
ap->userbits &= ~AINVISIBLE;
412
j = arcpolys(arc, NOWINDOWPART);
415
shapearcpoly(arc, k, poly);
416
if (poly->desc->bits == LAYERN) continue;
417
if ((poly->desc->colstyle&INVISIBLE) == 0) break;
419
if (k >= j) ap->userbits |= AINVISIBLE;
425
* routine to examine the current window structure and fit their sizes
426
* to the screen. If "placemenu" is nonzero, set the menu location too.
428
void us_windowfit(WINDOWFRAME *whichframe, BOOLEAN placemenu, INTBIG scaletofit)
430
REGISTER WINDOWPART *w;
431
REGISTER INTBIG lowy, highy, ulx, uhx, uly, uhy, drawlx, drawhx, drawly, drawhy,
432
mtop, mleft, alltext;
433
INTBIG swid, shei, mwid, mhei, pwid;
434
REGISTER INTBIG i, total, newwid, newhei, offx, offy;
435
INTBIG slx, shx, sly, shy;
436
REGISTER WINDOWFRAME *frame;
437
REGISTER VARIABLE *var;
438
COMMANDBINDING commandbinding;
440
for(frame = el_firstwindowframe; frame != NOWINDOWFRAME; frame = frame->nextwindowframe)
442
if (whichframe != NOWINDOWFRAME && whichframe != frame) continue;
443
getwindowframesize(frame, &swid, &shei);
444
lowy = 0; highy = shei - 1 - us_menubarsize;
446
/* presume that there is no menu */
447
drawlx = 0; drawhx = swid-1;
448
drawly = lowy; drawhy = highy;
450
/* if there is a menu, figure it out */
451
if ((us_tool->toolstate&MENUON) != 0)
453
/* see if the menu is all text */
455
var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
456
if (var != NOVARIABLE)
458
total = us_menux*us_menuy;
459
for(i=0; i<total; i++)
461
us_parsebinding(((char **)var->addr)[i], &commandbinding);
462
if (*commandbinding.command == 0 || commandbinding.nodeglyph != NONODEPROTO ||
463
commandbinding.arcglyph != NOARCPROTO)
465
us_freebindingparse(&commandbinding);
468
us_freebindingparse(&commandbinding);
470
if (i >= total) alltext = 1;
472
getpaletteparameters(&mwid, &mhei, &pwid);
473
if (us_menuframe == NOWINDOWFRAME)
475
/* menus come out of the only editor window */
478
case 0: /* menu at top */
479
us_menuxsz = us_menuysz = swid / us_menux;
480
us_menulx = (swid - us_menux*us_menuxsz)/2;
481
us_menuhx = swid - us_menulx;
482
us_menuly = highy - us_menuysz*us_menuy;
484
drawlx = 0; drawhx = swid-1;
485
drawly = lowy; drawhy = us_menuly-1;
487
case 1: /* menu at bottom */
488
us_menuxsz = us_menuysz = swid / us_menux;
489
us_menulx = (swid - us_menux*us_menuxsz)/2;
490
us_menuhx = swid - us_menulx;
492
us_menuhy = lowy + us_menuysz * us_menuy;
493
drawlx = 0; drawhx = swid-1;
494
drawly = us_menuhy+1; drawhy = highy;
496
case 2: /* menu on left */
497
us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
499
/* if the menu is all text, allow nonsquare menus */
500
if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
503
us_menuhx = us_menuxsz * us_menux;
504
us_menuly = ((highy-lowy) - us_menuy*us_menuysz)/2 + lowy;
505
us_menuhy = us_menuly + us_menuy*us_menuysz;
506
drawlx = us_menuhx+1; drawhx = swid-1;
507
drawly = lowy; drawhy = highy;
509
case 3: /* menu on right */
510
us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
512
/* if the menu is all text, allow nonsquare menus */
513
if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
515
us_menulx = swid - us_menuxsz * us_menux;
517
us_menuly = ((highy-lowy) - us_menuy*us_menuysz)/2 + lowy;
518
us_menuhy = us_menuly + us_menuy*us_menuysz;
519
drawlx = 0; drawhx = us_menulx-1;
520
drawly = lowy; drawhy = highy;
525
/* floating menu window */
526
if (frame == us_menuframe && placemenu)
528
getpaletteparameters(&mwid, &mhei, &pwid);
531
case 0: /* menu at top */
532
case 1: /* menu at bottom */
533
us_menuxsz = us_menuysz = mwid / us_menux;
534
if (us_menuysz * us_menuy > pwid)
535
us_menuxsz = us_menuysz = pwid / us_menuy;
537
us_menuhx = us_menux * us_menuxsz;
539
us_menuhy = us_menuy * us_menuysz;
543
/* menu on the top */
547
/* menu on the bottom */
548
mtop = mhei - us_menuysz*us_menuy - 3;
552
case 2: /* menu on left */
553
case 3: /* menu on right */
554
/* determine size of menu entries */
555
us_menuxsz = us_menuysz = mhei / us_menuy;
556
if (us_menuxsz * us_menux > pwid)
557
us_menuxsz = us_menuysz = pwid / us_menux;
559
/* if the menu is all text, allow nonsquare menus */
560
if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
562
/* compute menu parameters */
564
us_menuhy = us_menuy * us_menuysz;
566
us_menuhx = us_menux * us_menuxsz;
570
/* menu on the left */
574
/* menu on the right */
575
mleft = mwid - us_menuxsz * us_menux - 2;
579
sizewindowframe(us_menuframe, us_menuhx-us_menulx, us_menuhy-us_menuly);
580
movewindowframe(us_menuframe, mleft, mtop);
585
/* now fit the windows in the remaining space */
586
for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
588
/* this window must be on the right frame */
589
if (w->frame != frame) continue;
591
/* entire window is handled simply */
592
if (strcmp(w->location, "entire") == 0)
594
ulx = drawlx; uhx = drawhx;
595
uly = drawly; uhy = drawhy;
596
} else if (strncmp(w->location, "top", 3) == 0)
598
ulx = drawlx; uhx = drawhx;
599
uly = (drawhy-drawly)*(100-w->vratio)/100;
601
} else if (strncmp(w->location, "bot", 3) == 0)
603
ulx = drawlx; uhx = drawhx;
604
uly = drawly; uhy = (drawhy-drawly)*w->vratio/100;
605
} else if (strcmp(w->location, "left") == 0)
607
ulx = drawlx; uhx = (drawhx-drawlx)*w->hratio/100;
608
uly = drawly; uhy = drawhy;
609
} else if (strcmp(w->location, "right") == 0)
611
ulx = (drawhx-drawlx)*(100-w->hratio)/100;
613
uly = drawly; uhy = drawhy;
616
/* subdivide for fractions of half windows */
618
while (w->location[i] == '-')
620
switch (w->location[i+1])
622
case 'l': uhx = (uhx - ulx)*w->hratio/100; break;
623
case 'r': ulx = (uhx - ulx)*(100-w->hratio)/100; break;
624
case 't': uly = (uhy - uly)*(100-w->vratio)/100; break;
625
case 'b': uhy = (uhy - uly)*w->vratio/100; break;
629
if (strcmp(w->location, "entire") != 0)
631
ulx++; uhx--; uly++; uhy--;
634
/* make sure window has some size */
635
if (ulx >= uhx) uhx = ulx + 1;
636
if (uly >= uhy) uhy = uly + 1;
638
/* make room for border if simulating */
639
if ((w->state&WINDOWSIMULATING) != 0)
641
ulx += SIMULATINGBORDERSIZE; uhx -= SIMULATINGBORDERSIZE;
642
uly += SIMULATINGBORDERSIZE; uhy -= SIMULATINGBORDERSIZE;
645
/* make room for sliders if a display window */
646
if ((w->state&WINDOWTYPE) == DISPWINDOW)
648
uhx -= DISPLAYSLIDERSIZE;
649
uly += DISPLAYSLIDERSIZE;
651
if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
653
ulx += DISPLAYSLIDERSIZE;
654
uly += DISPLAYSLIDERSIZE;
657
/* update if the extent changed */
658
if (w->uselx != ulx || w->usehx != uhx ||
659
w->usely != uly || w->usehy != uhy)
661
/* set the window extent */
662
w->uselx = ulx; w->usehx = uhx;
663
w->usely = uly; w->usehy = uhy;
665
/* now adjust the database extents of the window */
666
slx = w->screenlx; shx = w->screenhx;
667
sly = w->screenly; shy = w->screenhy;
670
us_squarescreen(w, NOWINDOWPART, FALSE, &slx, &shx, &sly, ­, 0);
671
} else if (scaletofit < 0)
673
newwid = (INTBIG)(((float)(uhx - ulx)) / w->scalex + 0.5);
674
newhei = (INTBIG)(((float)(uhy - uly)) / w->scaley + 0.5);
675
offx = newwid - (shx - slx);
676
offy = newhei - (shy - sly);
682
w->screenlx = slx; w->screenhx = shx;
683
w->screenly = sly; w->screenhy = shy;
684
computewindowscale(w);
691
* routine to adjust the actual drawing area of window "win" to account for
692
* the appearance or disappearance of the red simulation border
694
void us_setwindowsimulation(WINDOWPART *win, BOOLEAN on)
698
/* simulation beginning: shrink window to make room for red border */
699
win->uselx += SIMULATINGBORDERSIZE; win->usehx -= SIMULATINGBORDERSIZE;
700
win->usely += SIMULATINGBORDERSIZE; win->usehy -= SIMULATINGBORDERSIZE;
701
win->state |= WINDOWSIMULATING;
704
/* simulation ending: expand window to remove red border */
705
win->uselx -= SIMULATINGBORDERSIZE; win->usehx += SIMULATINGBORDERSIZE;
706
win->usely -= SIMULATINGBORDERSIZE; win->usehy += SIMULATINGBORDERSIZE;
707
win->state &= ~WINDOWSIMULATING;
712
* routine to tell the names of the windows that result when the window
713
* with name "w" is split. The strings "hwind1" and "hwind2" are filled
714
* with the names if the window is split horizontally. The strings "vwind1"
715
* and "vwind2" are filled with the names if the window is split verticaly.
717
void us_splitwindownames(char *w, char *hwind1, char *hwind2, char *vwind1, char *vwind2)
721
if (strcmp(w, "entire") == 0)
723
(void)strcpy(hwind1, "top"); (void)strcpy(hwind2, "bottom");
724
(void)strcpy(vwind1, "left"); (void)strcpy(vwind2, "right");
727
if (strcmp(w, "top") == 0)
729
(void)strcpy(hwind1, "top-l"); (void)strcpy(hwind2, "top-r");
730
(void)strcpy(vwind1, ""); (void)strcpy(vwind2, "");
733
if (strcmp(w, "bottom") == 0)
735
(void)strcpy(hwind1, "bot-l"); (void)strcpy(hwind2, "bot-r");
736
(void)strcpy(vwind1, ""); (void)strcpy(vwind2, "");
739
if (strcmp(w, "left") == 0)
741
(void)strcpy(vwind1, "top-l"); (void)strcpy(vwind2, "bot-l");
742
(void)strcpy(hwind1, ""); (void)strcpy(hwind2, "");
745
if (strcmp(w, "right") == 0)
747
(void)strcpy(vwind1, "top-r"); (void)strcpy(vwind2, "bot-r");
748
(void)strcpy(hwind1, ""); (void)strcpy(hwind2, "");
751
(void)strcpy(hwind1, w); (void)strcpy(hwind2, w);
752
(void)strcpy(vwind1, w); (void)strcpy(vwind2, w);
754
if (i == 'l' || i == 'r')
756
(void)strcat(vwind1, "-t"); (void)strcat(vwind2, "-b");
757
(void)strcpy(hwind1, ""); (void)strcpy(hwind2, "");
760
(void)strcat(hwind1, "-l"); (void)strcat(hwind2, "-r");
761
(void)strcpy(vwind1, ""); (void)strcpy(vwind2, "");
766
* Routine to create a new window with whatever method is available on the
767
* current machine (new window in its own frame or just a split of the current
768
* window). If "orientation" is 1, make it a horizontal window; if 2,
769
* make it vertical. Otherwise use any configuration. Prints an error and
770
* returns NOWINDOWPART on failure.
772
WINDOWPART *us_wantnewwindow(INTBIG orientation)
774
REGISTER WINDOWPART *w;
777
if (graphicshas(CANUSEFRAMES) && orientation == 0)
779
/* create a default window space on this frame */
780
wf = newwindowframe(FALSE, 0);
781
if (wf == NOWINDOWFRAME) wf = getwindowframe(FALSE);
782
w = newwindowpart("entire", NOWINDOWPART);
783
if (w == NOWINDOWPART)
785
us_abortcommand(_("Cannot create new window"));
786
return(NOWINDOWPART);
789
w->buttonhandler = DEFAULTBUTTONHANDLER;
790
w->charhandler = DEFAULTCHARHANDLER;
791
w->changehandler = DEFAULTCHANGEHANDLER;
792
w->termhandler = DEFAULTTERMHANDLER;
793
w->redisphandler = DEFAULTREDISPHANDLER;
794
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
795
VWINDOWPART|VDONTSAVE);
797
/* now draw everything */
802
if (us_needwindow()) return(NOWINDOWPART);
803
w = us_splitcurrentwindow(orientation, FALSE, 0);
808
* routine to split the current window into two windows. If "splitkey" is zero,
809
* nature of split is unspecified. If "splitkey" is 1, split horizontally
810
* (only when splitting top window). If "splitkey" is 2, split vertically.
811
* If "fillboth" is true, fill both windows with the contents of the
812
* old one. Otherwise, leave the new current window empty. Returns the address
813
* of the new current window, and the other half in "other" (NOWINDOWPART on error).
815
WINDOWPART *us_splitcurrentwindow(INTBIG splitkey, BOOLEAN fillboth, WINDOWPART **other)
817
char wind1[40], wind2[40], vwind1[40], vwind2[40];
818
REGISTER char *win1, *win2;
819
WINDOWPART windowsave;
820
REGISTER WINDOWPART *w2, *w3, *w, *retwin;
821
REGISTER INTBIG curwx, curwy, horizsplit;
822
REGISTER INTBIG x, y, l;
823
REGISTER NODEPROTO *np;
825
/* figure out new name of windows */
826
if (other != 0) *other = NOWINDOWPART;
828
us_splitwindownames(el_curwindowpart->location, wind1, wind2, vwind1, vwind2);
830
/* use the horizontal window split unless there is none */
831
if (*wind1 == 0) win1 = vwind1; else win1 = wind1;
832
if (*wind2 == 0) win2 = vwind2; else win2 = wind2;
834
/* special case when splitting just one window: which way to split */
835
if (strcmp(el_curwindowpart->location, "entire") == 0)
837
/* see if a "horizontal" or "vertical" parameter was given */
840
/* vertical window specified explicitly */
841
win1 = vwind1; win2 = vwind2;
843
} else if (splitkey == 0)
845
/* make a guess about window splitting */
846
switch (el_curwindowpart->state&WINDOWTYPE)
849
win1 = vwind1; win2 = vwind2;
853
np = el_curwindowpart->curnodeproto;
854
if (np != NONODEPROTO)
856
curwx = el_curwindowpart->usehx - el_curwindowpart->uselx;
857
curwy = el_curwindowpart->usehy - el_curwindowpart->usely;
858
x = np->highx - np->lowx;
859
y = np->highy - np->lowy;
860
l = el_curlib->lambda[el_curtech->techindex];
861
if (muldiv(x, curwy/2, l) + muldiv(y, curwx, l) >=
862
muldiv(x, curwy, l) + muldiv(y, curwx/2, l))
864
/* vertical window makes more sense */
865
win1 = vwind1; win2 = vwind2;
874
l = strlen(wind1) - 1;
875
if (wind1[l] == 'l' || wind1[l] == 'r') horizsplit = 0;
878
/* turn off object and window highlighting */
880
us_clearhighlightcount();
881
w = el_curwindowpart;
882
copywindowpart(&windowsave, el_curwindowpart);
884
/* make two new windows in "w2" and "w3" to replace "el_curwindowpart" */
885
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)NOWINDOWPART,
886
VWINDOWPART|VDONTSAVE);
887
startobjectchange((INTBIG)us_tool, VTOOL);
888
w2 = newwindowpart(win1, w);
889
w3 = newwindowpart(win2, w);
890
if (w2 == NOWINDOWPART || w3 == NOWINDOWPART)
893
return(NOWINDOWPART);
896
/* make sure the split is even in the split direction */
897
if (horizsplit != 0) w2->vratio = w3->vratio = 50; else
898
w2->hratio = w3->hratio = 50;
900
/* if splitting an editor window, move the editor structure */
901
if ((w->state&WINDOWTYPE) == TEXTWINDOW || (w->state&WINDOWTYPE) == POPTEXTWINDOW)
903
(void)setval((INTBIG)w3, VWINDOWPART, "editor", (INTBIG)w->editor, VADDRESS);
904
(void)setval((INTBIG)w, VWINDOWPART, "editor", -1, VADDRESS);
907
/* free the current window */
910
/* zap the returned window if both are not to be filled */
912
if (other != 0) *other = w3;
913
if ((windowsave.state&WINDOWTYPE) != DISPWINDOW) fillboth = FALSE;
916
retwin->state = (retwin->state & ~(WINDOWTYPE|GRIDON|WINDOWSIMULATING)) | 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;
926
/* set the window extents */
927
us_windowfit(w2->frame, FALSE, 1);
929
/* use former window for scaling */
932
/* windows might have got bigger: see if grid can be drawn */
933
if ((w2->state&GRIDTOOSMALL) != 0) us_gridset(w2, GRIDON);
934
if ((w2->state&GRIDTOOSMALL) != 0) us_gridset(w3, GRIDON);
936
endobjectchange((INTBIG)us_tool, VTOOL);
937
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w2,
938
VWINDOWPART|VDONTSAVE);
940
/* restore all highlighting */
941
us_pophighlight(FALSE);
946
* routine to kill a window. Kills the current window if "thisw" is true.
947
* Kills the other window, making the current one larger, if "thisw" is false.
949
void us_killcurrentwindow(BOOLEAN thisw)
951
REGISTER WINDOWPART *w1, *w2, *wnew, *w;
952
WINDOWPART windowsave;
953
REGISTER INTBIG windows;
954
char windcomb[40], windother[40], wind1[40], wind2[40], vwind1[40], vwind2[40];
955
REGISTER WINDOWFRAME *wf;
957
w1 = el_curwindowpart;
959
/* if this is the only partition, see if the window frame can be deleted */
960
if (strcmp(w1->location, "entire") == 0)
962
if (!graphicshas(CANHAVENOWINDOWS))
964
/* disallow deletion if this is the last window */
966
for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
967
if (wf->floating == 0) windows++;
970
ttyputerr(_("Sorry, cannot delete the last window"));
974
if (graphicshas(CANUSEFRAMES))
976
/* save highlighting and turn it off */
978
us_clearhighlightcount();
980
/* kill the window */
981
startobjectchange((INTBIG)us_tool, VTOOL);
982
us_killwindowpickanother(w1);
983
endobjectchange((INTBIG)us_tool, VTOOL);
985
/* restore highlighting */
986
us_pophighlight(FALSE);
991
/* figure out which other window to merge this with */
992
if (strcmp(w1->location, "top") == 0 || strcmp(w1->location, "bottom") == 0 ||
993
strcmp(w1->location, "left") == 0 || strcmp(w1->location, "right") == 0)
994
(void)strcpy(windcomb, "entire"); else
996
(void)strcpy(windcomb, w1->location);
997
windcomb[strlen(windcomb)-2] = 0;
998
if (strcmp(windcomb, "bot") == 0) (void)strcpy(windcomb, "bottom");
1001
/* see what divisions this higher window typically makes */
1002
us_splitwindownames(windcomb, wind1, wind2, vwind1, vwind2);
1004
/* look for the other window of the typical split */
1005
(void)strcpy(windother, "");
1006
if (strcmp(wind2, w1->location) == 0) (void)strcpy(windother, wind1);
1007
if (strcmp(wind1, w1->location) == 0) (void)strcpy(windother, wind2);
1008
if (strcmp(vwind2, w1->location) == 0) (void)strcpy(windother, vwind1);
1009
if (strcmp(vwind1, w1->location) == 0) (void)strcpy(windother, vwind2);
1011
/* see if there is a window with that name */
1012
for(w2 = el_topwindowpart; w2 != NOWINDOWPART; w2 = w2->nextwindowpart)
1013
if (strcmp(w2->location, windother) == 0) break;
1015
/* if the other window can't be found, try one more hack */
1016
if (w2 == NOWINDOWPART)
1018
/* special case for quadrants that get split strangely */
1019
if ((strncmp(w1->location, "top-", 4) == 0 || strncmp(w1->location, "bot-", 4) == 0) &&
1020
strlen(w1->location) == 5)
1022
if (*w1->location == 't') (void)strcpy(windother, "bot-l"); else
1023
(void)strcpy(windother, "top-l");
1024
windother[4] = w1->location[4];
1025
if (windother[4] == 'l') (void)strcpy(windcomb, "left"); else
1026
(void)strcpy(windcomb, "right");
1027
for(w2 = el_topwindowpart; w2 != NOWINDOWPART; w2 = w2->nextwindowpart)
1028
if (strcmp(w2->location, windother) == 0) break;
1031
if (w2 == NOWINDOWPART)
1033
us_abortcommand(_("Cannot kill the current window"));
1037
/* if the other window is to be killed, swap them */
1040
w = w1; w1 = w2; w2 = w;
1043
/* turn off highlighting */
1045
us_clearhighlightcount();
1047
/* create a new window to cover both */
1048
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)NOWINDOWPART,
1049
VWINDOWPART|VDONTSAVE);
1050
startobjectchange((INTBIG)us_tool, VTOOL);
1051
wnew = newwindowpart(windcomb, w2);
1052
if (wnew == NOWINDOWPART) return;
1054
/* save information from the old window */
1055
copywindowpart(&windowsave, w2);
1057
/* if merging an editor window, move the editor structure */
1058
if ((w2->state&WINDOWTYPE) == TEXTWINDOW || (w2->state&WINDOWTYPE) == POPTEXTWINDOW)
1060
(void)setval((INTBIG)wnew, VWINDOWPART, "editor", (INTBIG)w2->editor, VADDRESS);
1061
(void)setval((INTBIG)w2, VWINDOWPART, "editor", -1, VADDRESS);
1064
/* remove old windows */
1068
/* set window extents */
1069
us_windowfit(wnew->frame, FALSE, 1);
1071
/* use former window for scaling */
1074
/* window might have got bigger: see if grid can be drawn */
1075
if ((wnew->state&GRIDTOOSMALL) != 0) us_gridset(wnew, GRIDON);
1077
(void)setval((INTBIG)el_curlib, VLIBRARY, "curnodeproto", (INTBIG)wnew->curnodeproto,
1079
endobjectchange((INTBIG)us_tool, VTOOL);
1080
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)wnew,
1081
VWINDOWPART|VDONTSAVE);
1083
/* restore highlighting */
1084
us_pophighlight(FALSE);
1088
* routine to determine whether the division of window "w1" into windows
1089
* "w2" and "w3" can be done with block transfer. This requires that
1090
* the windows have identical aspect ratios in one axis
1092
BOOLEAN us_windowcansplit(WINDOWPART *w1, WINDOWPART *w2, WINDOWPART *w3)
1094
REGISTER INTBIG new2l, new2h;
1096
if (w2->usehx-w2->uselx == w3->usehx-w3->uselx &&
1097
w2->screenhx-w2->screenlx == w3->screenhx-w3->screenlx)
1099
/* first see if it is an obvious split */
1100
if (w2->usehx-w2->uselx == w1->usehx-w1->uselx &&
1101
w2->screenhx-w2->screenlx == w1->screenhx-w1->screenlx)
1104
/* now see if it is a relative fit for changed window size */
1105
new2l = muldiv(((w1->usehx-w1->uselx) - (w2->usehx-w2->uselx))/2,
1106
w1->screenhx-w1->screenlx, w1->usehx-w1->uselx) + w1->screenlx;
1107
new2h = w2->screenlx + muldiv(w2->usehx-w2->uselx,
1108
w1->screenhx-w1->screenlx, w1->usehx-w1->uselx);
1109
if (new2l == w2->screenlx && new2h == w2->screenhx) return(TRUE);
1111
if (w2->usehy-w2->usely == w3->usehy-w3->usely &&
1112
w2->screenhy-w2->screenly == w3->screenhy-w3->screenly)
1114
/* first see if it is an obvious split */
1115
if (w2->usehy-w2->usely == w1->usehy-w1->usely &&
1116
w2->screenhy-w2->screenly == w1->screenhy-w1->screenly)
1119
/* now see if it is a relative fit for changed window size */
1120
new2l = muldiv(((w1->usehy-w1->usely) - (w2->usehy-w2->usely))/2,
1121
w1->screenhy-w1->screenly, w1->usehy-w1->usely) + w1->screenly;
1122
new2h = w2->screenly + muldiv(w2->usehy-w2->usely,
1123
w1->screenhy-w1->screenly, w1->usehy-w1->usely);
1124
if (new2l == w2->screenly && new2h == w2->screenhy) return(TRUE);
1130
* routine to ensure that the facet "np"
1131
* is displayed somewhere on the screen. If not, it
1132
* is displayed in the current window
1134
void us_ensurewindow(NODEPROTO *np)
1136
REGISTER WINDOWPART *w;
1139
/* if nothing specified, quit */
1140
if (np == NONODEPROTO) return;
1142
/* see if that facet is in a window */
1143
for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1144
if (w->curnodeproto == np) break;
1146
/* if the facet is not in a window, put it there */
1147
if (w == NOWINDOWPART)
1149
par[0] = describenodeproto(np);
1150
us_editfacet(1, par);
1151
us_endchanges(NOWINDOWPART);
1156
* Routine to kill window "w" and set the current window to some other.
1158
void us_killwindowpickanother(WINDOWPART *w)
1160
REGISTER NODEPROTO *np;
1164
if (w != el_curwindowpart) return;
1166
w = el_topwindowpart;
1167
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1168
VWINDOWPART|VDONTSAVE);
1169
if (w != NOWINDOWPART) np = w->curnodeproto; else np = NONODEPROTO;
1170
(void)setval((INTBIG)el_curlib, VLIBRARY, "curnodeproto", (INTBIG)np, VNODEPROTO);
1174
* routine to adjust the coordinate values in (x, y) from screen space to
1175
* the space of window "w"
1177
void us_scaletowindow(INTBIG *x, INTBIG *y, WINDOWPART *w)
1179
*x = muldiv(*x - w->uselx, w->screenhx - w->screenlx, w->usehx - w->uselx) + w->screenlx;
1180
*y = muldiv(*y - w->usely, w->screenhy - w->screenly, w->usehy - w->usely) + w->screenly;
1183
/******************** TEXT EDITING ********************/
1185
EDITORTABLE us_editortable[] =
1187
/* the point-and-click editor */
1189
us_editpacmakeeditor, us_editpacterminate, us_editpactotallines, us_editpacgetline,
1190
us_editpacaddline, us_editpacreplaceline, us_editpacdeleteline, us_editpachighlightline,
1191
us_editpacsuspendgraphics, us_editpacresumegraphics,
1192
us_editpacwritetextfile, us_editpacreadtextfile,
1193
us_editpaceditorterm, us_editpacshipchanges, us_editpacgotchar,
1194
us_editpaccut, us_editpaccopy, us_editpacpaste,
1195
us_editpacundo, us_editpacsearch, us_editpacpan},
1197
/* the EMACS-like editor */
1199
us_editemacsmakeeditor, us_editemacsterminate, us_editemacstotallines, us_editemacsgetline,
1200
us_editemacsaddline, us_editemacsreplaceline, us_editemacsdeleteline, us_editemacshighlightline,
1201
us_editemacssuspendgraphics, us_editemacsresumegraphics,
1202
us_editemacswritetextfile, us_editemacsreadtextfile,
1203
us_editemacseditorterm, us_editemacsshipchanges, us_editemacsgotchar,
1204
us_editemacscut, us_editemacscopy, us_editemacspaste,
1205
us_editemacsundo, us_editemacssearch, us_editemacspan},
1208
NULL, NULL, NULL, NULL,
1209
NULL, NULL, NULL, NULL,
1217
* dispatch routine to describe this editor
1219
void us_describeeditor(char **name)
1221
*name = us_editortable[us_currenteditor].editorname;
1225
* dispatch routine for creating a new editor
1227
WINDOWPART *us_makeeditor(WINDOWPART *oriwin, char *header, INTBIG *chars, INTBIG *lines)
1229
return((*us_editortable[us_currenteditor].makeeditor)(oriwin,header,chars,lines));
1233
* dispatch routine to return the total number of valid lines in the edit buffer
1235
INTBIG us_totallines(WINDOWPART *win)
1237
return((*us_editortable[us_currenteditor].totallines)(win));
1241
* dispatch routine to get the string on line "lindex" (0 based). A negative line
1242
* returns the current line. Returns -1 if the index is beyond the file limit
1244
char *us_getline(WINDOWPART *win, INTBIG lindex)
1246
return((*us_editortable[us_currenteditor].getline)(win, lindex));
1250
* dispatch routine to add line "str" to the text facet to become line "lindex"
1252
void us_addline(WINDOWPART *win, INTBIG lindex, char *str)
1254
(*us_editortable[us_currenteditor].addline)(win, lindex, str);
1258
* dispatch routine to replace the line number "lindex" with the string "str".
1260
void us_replaceline(WINDOWPART *win, INTBIG lindex, char *str)
1262
(*us_editortable[us_currenteditor].replaceline)(win, lindex, str);
1266
* dispatch routine to delete line number "lindex"
1268
void us_deleteline(WINDOWPART *win, INTBIG lindex)
1270
(*us_editortable[us_currenteditor].deleteline)(win, lindex);
1274
* dispatch routine to highlight lines "lindex" to "hindex" in the text window
1276
void us_highlightline(WINDOWPART *win, INTBIG lindex, INTBIG hindex)
1278
(*us_editortable[us_currenteditor].highlightline)(win, lindex, hindex);
1282
* dispatch routine to stop the graphic display of changes (for batching)
1284
void us_suspendgraphics(WINDOWPART *win)
1286
(*us_editortable[us_currenteditor].suspendgraphics)(win);
1290
* dispatch routine to restart the graphic display of changes and redisplay (for batching)
1292
void us_resumegraphics(WINDOWPART *win)
1294
(*us_editortable[us_currenteditor].resumegraphics)(win);
1298
* dispatch routine to write the text file to "file"
1300
void us_writetextfile(WINDOWPART *win, char *file)
1302
(*us_editortable[us_currenteditor].writetextfile)(win, file);
1306
* dispatch routine to read the text file "file"
1308
void us_readtextfile(WINDOWPART *win, char *file)
1310
(*us_editortable[us_currenteditor].readtextfile)(win, file);
1314
* dispatch routine to get the next character
1316
void us_editorterm(WINDOWPART *w)
1318
(*us_editortable[us_currenteditor].editorterm)(w);
1322
* dispatch routine to force changes from the editor in window "w"
1324
void us_shipchanges(WINDOWPART *w)
1326
(*us_editortable[us_currenteditor].shipchanges)(w);
1330
* dispatch routine to get the next character
1332
BOOLEAN us_gotchar(WINDOWPART *w, INTSML i, INTBIG special)
1334
return((*us_editortable[us_currenteditor].gotchar)(w, i, special));
1338
* dispatch routine to cut text
1340
void us_cuttext(WINDOWPART *w)
1342
(*us_editortable[us_currenteditor].cut)(w);
1346
* dispatch routine to copy text
1348
void us_copytext(WINDOWPART *w)
1350
(*us_editortable[us_currenteditor].copy)(w);
1354
* dispatch routine to paste text
1356
void us_pastetext(WINDOWPART *w)
1358
(*us_editortable[us_currenteditor].paste)(w);
1362
* dispatch routine to undo text changes
1364
void us_undotext(WINDOWPART *w)
1366
(*us_editortable[us_currenteditor].undo)(w);
1370
* dispatch routine to search and/or replace text. If "replace" is nonzero, this is
1371
* a replace. The meaning of "bits" is as follows:
1377
void us_searchtext(WINDOWPART *w, char *str, char *replace, INTBIG bits)
1379
(*us_editortable[us_currenteditor].search)(w, str, replace, bits);
1383
* dispatch routine to pan the text window by (dx, dy)
1385
void us_pantext(WINDOWPART *w, INTBIG dx, INTBIG dy)
1387
(*us_editortable[us_currenteditor].pan)(w, dx, dy);
1391
* support routine to allocate a new editor from the pool (if any) or memory
1392
* routine returns NOEDITOR upon error
1394
EDITOR *us_alloceditor(void)
1398
e = (EDITOR *)emalloc((sizeof (EDITOR)), us_tool->cluster);
1399
if (e == 0) return(NOEDITOR);
1401
e->nexteditor = NOEDITOR;
1402
e->editobjvar = NOVARIABLE;
1407
* support routine to return editor "e" to the pool of free editors
1409
void us_freeeditor(EDITOR *e)
1411
if (e == 0 || e == NOEDITOR) return;
1413
(*us_editortable[us_currenteditor].terminate)(e);
1417
/******************** SPECIAL WINDOW HANDLERS ********************/
1420
* routine to accept changes in an edit window examining a variable. If "nature" is:
1421
* REPLACETEXTLINE line "changed" goes from "oldline" to "newline"
1422
* DELETETEXTLINE line "changed deleted (was "oldline")
1423
* INSERTTEXTLINE line "newline" inserted before line "changed"
1424
* REPLACEALLTEXT "changed" lines "newline" replace all text
1426
void us_varchanges(WINDOWPART *w, INTBIG nature, char *oldline, char *newline, INTBIG changed)
1428
REGISTER INTBIG j, l, save;
1429
REGISTER BOOLEAN res;
1430
REGISTER INTBIG newval, i, len;
1431
REGISTER char **newlist, *pt;
1433
REGISTER EDITOR *ed;
1436
if (ed->editobjvar == NOVARIABLE) return;
1437
if ((ed->editobjvar->type&VCANTSET) != 0)
1439
ttyputerr(M_("This variable cannot be changed"));
1440
ed->editobjvar = NOVARIABLE;
1443
len = getlength(ed->editobjvar);
1445
/* when replacing the entire text, reduce to individual calls */
1446
if (nature == REPLACEALLTEXT)
1448
newlist = (char **)newline;
1449
for(i=0; i<changed; i++)
1450
us_varchanges(w, REPLACETEXTLINE, "", newlist[i], i);
1451
for(i=len-1; i>=changed; i--)
1452
us_varchanges(w, DELETETEXTLINE, "", "", i);
1456
if (nature == DELETETEXTLINE && len == 1)
1458
/* delete of last entry: instead, replace it with a null */
1460
nature = REPLACETEXTLINE;
1461
} else if (nature == REPLACETEXTLINE && changed >= len)
1463
/* change of line beyond end: instead make an insert */
1464
nature = INSERTTEXTLINE;
1467
/* disallow deletions and insertions if the number of lines is fixed */
1468
if (nature == DELETETEXTLINE || nature == INSERTTEXTLINE)
1470
if ((ed->state&LINESFIXED) != 0) return;
1474
if (nature == REPLACETEXTLINE || nature == INSERTTEXTLINE)
1477
while (*pt == ' ' || *pt == '\t') pt++;
1478
switch (ed->editobjvar->type&VTYPE)
1483
newval = myatoi(pt);
1490
newfloat = (float)atof(pt);
1491
newval = castint(newfloat);
1494
j = l = strlen(newline);
1495
if (strcmp(&newline[l-3], " */") == 0)
1497
for(j = l-5; j >= 0; j--)
1498
if (strncmp(&newline[j], "/* ", 3) == 0) break;
1499
while (j > 0 && newline[j-1] == ' ') j--;
1504
newval = (INTBIG)newline;
1507
ttyputmsg(_("Cannot update this type of variable (0%o)"), ed->editobjvar->type);
1512
/* make the change */
1516
case REPLACETEXTLINE:
1517
if (changed < 0 || changed >= len) return;
1518
res = setind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1520
case DELETETEXTLINE:
1521
if (changed < 0 || changed >= len) return;
1522
res = delind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed);
1524
case INSERTTEXTLINE:
1525
if (changed <= 0 || changed > len) return;
1526
res = insind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1528
/* why is this next line necessary? */
1529
ed->editobjvar = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
1533
/* clean-up string if one was passed */
1534
if ((nature == REPLACETEXTLINE || nature == INSERTTEXTLINE) &&
1535
(ed->editobjvar->type&VTYPE) == VSTRING) newline[j] = (char)save;
1539
ttyputerr(_("Error changing variable: ignoring further changes"));
1540
ed->editobjvar = NOVARIABLE;
1545
* routine to accept changes in an edit window examining a textual facet. If "nature" is:
1546
* REPLACETEXTLINE line "changed" goes from "oldline" to "newline"
1547
* DELETETEXTLINE line "changed" deleted (was "oldline")
1548
* INSERTTEXTLINE line "newline" inserted before line "changed"
1549
* REPLACEALLTEXT "changed" lines "newline" replace all text
1551
void us_textfacetchanges(WINDOWPART *w, INTBIG nature, char *oldline, char *newline, INTBIG changed)
1553
REGISTER INTBIG len;
1554
REGISTER BOOLEAN res;
1555
REGISTER EDITOR *ed;
1558
if (ed->editobjvar == NOVARIABLE) return;
1559
if ((ed->editobjvar->type&VTYPE) != VSTRING) return;
1560
if ((ed->editobjvar->type&VCANTSET) != 0) return;
1561
len = getlength(ed->editobjvar);
1563
if (nature == DELETETEXTLINE && len == 1)
1565
/* delete of last line: instead, replace it with a blank */
1567
nature = REPLACETEXTLINE;
1568
} else if (nature == REPLACETEXTLINE && changed >= len)
1572
/* change of line one beyond end: instead make an insert */
1573
nature = INSERTTEXTLINE;
1580
case REPLACETEXTLINE:
1581
if (changed < 0 || changed >= len) return;
1582
res = setindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1583
changed, (INTBIG)newline);
1585
case DELETETEXTLINE:
1586
if (changed < 0 || changed >= len) return;
1587
res = delindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1590
case INSERTTEXTLINE:
1591
if (changed <= 0 || changed > len) return;
1592
res = insindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1593
changed, (INTBIG)newline);
1595
case REPLACEALLTEXT:
1596
if (setvalkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1597
(INTBIG)newline, VSTRING | VISARRAY | (changed << VLENGTHSH)) != NOVARIABLE)
1604
ttyputerr(_("Error changing variable: ignoring further changes"));
1605
ed->editobjvar = NOVARIABLE;
1610
* private character handler for the text window. This routine normally
1611
* passes all commands to the editor's character handler. However, it
1612
* interprets M(=) which is for editing the facet on the current line
1614
BOOLEAN us_facetedithandler(WINDOWPART *w, INTSML ch, INTBIG special)
1616
char *newpar[2], *str;
1618
REGISTER BOOLEAN meta;
1619
REGISTER EDITOR *ed;
1620
extern INTBIG us_lastemacschar;
1622
/* the EMACS text editor must be running */
1623
us_describeeditor(&str);
1624
if (namesame(str, "emacs") != 0) return(us_gotchar(w, ch, special));
1626
/* see if the meta key is held down (serious black magic) */
1628
if ((special&ACCELERATORDOWN) != 0) meta = TRUE;
1629
if ((us_lastemacschar&2) != 0) meta = TRUE;
1631
/* pass character on to the editor if not M(=) */
1632
if (!meta || ch != '=') return(us_gotchar(w, ch, special));
1634
/* M(=) typed: parse current line to edit named facet */
1636
(void)allocstring(&str, us_getline(w, ed->curline), el_tempcluster);
1638
/* first drop everything past the first space character */
1639
for(i=0; str[i] != 0; i++) if (str[i] == ' ') break;
1640
if (str[i] != 0) str[i] = 0;
1642
if (str[0] == 0) ttyputerr(_("No facet specified on this line")); else
1644
/* issue the "editfacet" command */
1645
newpar[0] = "editfacet";
1647
telltool(us_tool, 2, newpar);
1648
setactivity(_("Facet Selection"));
1656
/******************** COMMAND SUPPORT ********************/
1658
BOOLEAN us_demandxy(INTBIG *x, INTBIG *y)
1663
if (ret) ttyputmsg(_("Cursor must be in an editing window"));
1667
static INTBIG us_curx, us_cury;
1670
* routine to get the co-ordinates of the cursor into the reference parameters
1671
* "x" and "y". If "GOTXY" is set in the global variable "us_state" then
1672
* this has already been done. The routine returns true if there is not a
1673
* valid cursor position.
1675
BOOLEAN getxy(INTBIG *x, INTBIG *y)
1678
REGISTER BOOLEAN ret;
1680
if ((us_state&GOTXY) == 0)
1682
readtablet(&gx, &gy);
1683
ret = us_setxy(gx, gy);
1691
* routine to take the values (realx, realy) from the tablet and store
1692
* them in the variables (us_curx, us_cury) which are in design-space
1693
* co-ordinates. "GOTXY" in the global variable "us_state" is set to indicate
1694
* that the co-ordinates are valid. The current window is set according
1695
* to the cursor position. The routine returns true if the position
1696
* is not in a window.
1698
BOOLEAN us_setxy(INTBIG x, INTBIG y)
1700
REGISTER WINDOWPART *w;
1701
REGISTER WINDOWFRAME *wf;
1703
us_curx = x; us_cury = y;
1705
/* figure out which window it is in */
1706
wf = getwindowframe(TRUE);
1707
for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1709
if (w->frame != wf) continue;
1710
if (x >= w->uselx && x <= w->usehx && y >= w->usely && y <= w->usehy)
1712
/* make this window the current one */
1713
if (w != el_curwindowpart)
1715
(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1716
VWINDOWPART|VDONTSAVE);
1717
(void)setval((INTBIG)el_curlib, VLIBRARY, "curnodeproto",
1718
(INTBIG)w->curnodeproto, VNODEPROTO);
1720
us_scaletowindow(&us_curx, &us_cury, w);
1721
xform(us_curx, us_cury, &us_curx, &us_cury, w->intofacet);
1730
* routine to force the parameters "xcur" and "ycur" to align to the
1731
* nearest "alignment" units
1733
void gridalign(INTBIG *xcur, INTBIG *ycur, INTBIG alignmentdivisor)
1736
REGISTER INTBIG val, alignment;
1738
alignment = muldiv(us_alignment_ratio, el_curlib->lambda[el_curtech->techindex], WHOLE) /
1740
val = us_alignvalue(*xcur, alignment, &otheralign);
1741
if (abs(*xcur-val) < abs(*xcur-otheralign)) *xcur = val; else
1743
val = us_alignvalue(*ycur, alignment, &otheralign);
1744
if (abs(*ycur-val) < abs(*ycur-otheralign)) *ycur = val; else
1749
* routine to return "value", aligned to the nearest "alignment" units.
1750
* The next closest alignment value (if "value" is not on the grid)
1751
* is returned in "otheralign".
1753
INTBIG us_alignvalue(INTBIG value, INTBIG alignment, INTBIG *otheralign)
1755
REGISTER INTBIG i, v1, v2;
1756
REGISTER INTBIG sign;
1758
/* determine the sign of the value */
1759
if (value < 0) { sign = -1; value = -value; } else sign = 1;
1761
/* compute the two aligned values */
1762
if (alignment == 0) v1 = value; else
1763
v1 = value / alignment * alignment;
1764
if (v1 == value) v2 = value; else v2 = v1 + alignment;
1765
v1 *= sign; v2 *= sign;
1767
/* make sure "v1" is the closest aligned value */
1768
if (abs(v1-value) > abs(v2-value)) { i = v1; v1 = v2; v2 = i; }
1774
/* routine to ensure that a current window exists */
1775
BOOLEAN us_needwindow(void)
1777
if (el_curwindowpart != NOWINDOWPART) return(FALSE);
1778
us_abortcommand(_("No current window"));
1782
/* routine to ensure that a facet exists in the current window */
1783
NODEPROTO *us_needfacet(void)
1785
REGISTER NODEPROTO *np;
1788
if (np != NONODEPROTO) return(np);
1789
if (el_curwindowpart == NOWINDOWPART)
1791
us_abortcommand(_("No current window (select one with Facets/Edit Facet)"));
1794
if ((us_tool->toolstate&NODETAILS) != 0)
1795
us_abortcommand(_("No facet in this window (select one with Facets/Edit Facet)")); else
1796
us_abortcommand(_("No facet in this window (select one with '-editfacet')"));
1798
return(NONODEPROTO);
1802
* Routine to ensure that nodes of type "item" can be modified in facet "facet".
1803
* If "item" is NONODEPROTO, check that facet "facet" can be modified at all.
1804
* Returns true if the edit cannot be done.
1806
BOOLEAN us_cantedit(NODEPROTO *facet, NODEPROTO *item, BOOLEAN giveerror)
1808
REGISTER INTBIG count;
1809
extern COMCOMP us_noyesalwaysp;
1812
/* if a prototype is specified, check it */
1813
if (item != NONODEPROTO)
1815
if (item->primindex != 0)
1817
/* see if a primitive is locked */
1818
if ((item->userbits&LOCKEDPRIM) != 0 &&
1819
(us_useroptions&NOPRIMCHANGES) != 0)
1821
if (!giveerror) return(TRUE);
1823
(void)formatinfstr(_("Changes to locked primitives (such as %s) are disallowed. Change anyway?"),
1824
describenodeproto(item));
1825
count = ttygetparam(returninfstr(), &us_noyesalwaysp, 5, pars);
1826
if (count <= 0 || namesamen(pars[0], "no", strlen(pars[0])) == 0) return(TRUE);
1827
if (namesamen(pars[0], "always", strlen(pars[0])) == 0)
1828
(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
1829
us_useroptions & ~NOPRIMCHANGES, VINTEGER);
1833
/* see if this type of facet is locked */
1834
if ((facet->userbits&NILOCKED) != 0)
1836
if (!giveerror) return(TRUE);
1838
(void)formatinfstr(_("Instances in facet %s are locked. Change anyway?"),
1839
describenodeproto(facet));
1840
count = ttygetparam(returninfstr(), &us_noyesalwaysp, 5, pars);
1841
if (count <= 0 || namesamen(pars[0], "no", strlen(pars[0])) == 0) return(TRUE);
1842
if (namesamen(pars[0], "always", strlen(pars[0])) == 0)
1843
setval((INTBIG)facet, VNODEPROTO, "userbits",
1844
facet->userbits & ~NILOCKED, VINTEGER);
1849
/* check for general changes to the facet */
1850
if ((facet->userbits&NLOCKED) != 0)
1852
if (!giveerror) return(TRUE);
1854
(void)formatinfstr(_("Changes to facet %s are locked. Change anyway?"),
1855
describenodeproto(facet));
1856
count = ttygetparam(returninfstr(), &us_noyesalwaysp, 5, pars);
1857
if (count <= 0 || namesamen(pars[0], "no", strlen(pars[0])) == 0) return(TRUE);
1858
if (namesamen(pars[0], "always", strlen(pars[0])) == 0)
1859
setval((INTBIG)facet, VNODEPROTO, "userbits", facet->userbits & ~NLOCKED, VINTEGER);
1865
* routine to determine the proper position of the cursor given that
1866
* it must adjust to the nearest "angle" tenth-degree radial coming out of
1867
* the point (tx,ty) and that it is currently at (nx, ny). The
1868
* adjusted point is placed into (fx, fy) and the proper radial starting
1869
* point in "poly" is placed in (tx, ty).
1871
void us_getslide(INTBIG angle, INTBIG tx, INTBIG ty, INTBIG nx, INTBIG ny, INTBIG *fx,
1874
REGISTER INTBIG ang;
1877
/* if angle is unconstrained, use the exact cursor position */
1884
/* check all permissable angles */
1885
for(ang = 0; ang < 3600; ang += angle)
1887
/* get close point to (nx,ny) on "ang" tenth-degree radial from (tx,ty) */
1888
(void)intersect(tx, ty, ang, nx, ny, (ang+900)%3600, &ix, &iy);
1890
/* accumulate the intersection closest to the cursor */
1891
if (ang != 0 && abs(*fx-nx) + abs(*fy-ny) < abs(ix-nx) + abs(iy-ny)) continue;
1897
* routine to convert command interpreter letter "letter" to the full
1898
* variable name on the user tool object
1900
char *us_commandvarname(INTSML letter)
1902
static char varname[20];
1904
if (isupper(letter))
1906
(void)strcpy(varname, "USER_local_capX");
1907
varname[14] = tolower(letter);
1910
(void)strcpy(varname, "USER_local_X");
1911
varname[11] = (char)letter;
1917
* routine to parse the variable path in "str" and return the object address
1918
* and type on which this variable resides along with the variable name.
1919
* The object address and type are placed in "objaddr" and "objtype";
1920
* the variable name is placed in "varname". "comvar" is set to true
1921
* if the variable is a command-interpreter variable (as opposed to a
1922
* database variable). If an array index specification is given (a "[]")
1923
* then the index value is returned in "aindex" (otherwise the value is set
1924
* to -1). The routine returns true if the variable path is invalid.
1926
BOOLEAN us_getvar(char *str, INTBIG *objaddr, INTBIG *objtype, char **varname,
1927
BOOLEAN *comvar, INTBIG *aindex)
1930
static char fullvarname[50];
1932
/* see if an array index is specified */
1935
if (str[i-1] == ']') for(i--; i >= 0; i--) if (str[i] == '[')
1937
*aindex = myatoi(&str[i+1]);
1941
/* see if this is a command interpreter variable */
1943
if (str[1] == 0 || str[1] == '[')
1945
if (str[0] >= 'a' && str[0] <= 'z') *comvar = TRUE;
1946
if (str[0] >= 'A' && str[0] <= 'Z') *comvar = TRUE;
1949
/* replace the actual name for command interpreter variables */
1952
(void)sprintf(fullvarname, "tool:user.%s", us_commandvarname(str[0]));
1956
/* pick apart the variable path */
1957
return(us_evaluatevariable(str, objaddr, objtype, varname));
1960
/******************** QUICK-KEY BINDING ********************/
1963
* Routine to find the entry in the key binding variable ("USER_binding_keys")
1964
* that corresponds to key "key", special code "special". Returns negative if
1965
* the key is not in the variable. If the key is found, the binding string
1966
* is returned in "binding".
1968
INTBIG us_findboundkey(INTSML key, INTBIG special, char **binding)
1970
REGISTER INTBIG i, len;
1972
INTBIG boundspecial;
1973
REGISTER VARIABLE *var;
1974
REGISTER char *thisbinding, *pt;
1976
var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
1977
if (var == NOVARIABLE) return(-1);
1978
len = getlength(var);
1979
for(i=0; i<len; i++)
1981
thisbinding = ((char **)var->addr)[i];
1982
pt = us_getboundkey(thisbinding, &boundkey, &boundspecial);
1983
if (pt == 0) continue;
1984
if (us_samekey(key, special, boundkey, boundspecial)) break;
1986
if (i >= len) return(-1);
1992
* Routine to set the binding of key "key", special code "special" to the string
1993
* "binding". If "quietly" is true, do this without change control.
1995
void us_setkeybinding(char *binding, INTSML key, INTBIG special, BOOLEAN quietly)
1997
char *pt, *justone[1], **bigger, *str;
1998
REGISTER INTBIG i, j, len, inserted;
2000
INTBIG boundspecial;
2001
REGISTER VARIABLE *var;
2003
if ((special&ACCELERATORDOWN) != 0) key = toupper(key);
2004
i = us_findboundkey(key, special, &pt);
2007
if (quietly) nextchangequiet();
2008
(void)setindkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, i, (INTBIG)binding);
2012
var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2013
if (var == NOVARIABLE)
2015
justone[0] = binding;
2016
if (quietly) nextchangequiet();
2017
(void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)justone,
2018
VSTRING|VDONTSAVE|VISARRAY|(1<<VLENGTHSH));
2021
len = getlength(var);
2022
bigger = (char **)emalloc((len+1) * (sizeof (char *)), el_tempcluster);
2023
if (bigger == 0) return;
2026
for(i=0; i<len; i++)
2028
pt = ((char **)var->addr)[i];
2029
str = us_getboundkey(pt, &boundkey, &boundspecial);
2030
if (str == 0) continue;
2031
if (namesame(str, "command=") == 0) continue;
2034
if (boundspecial > special || (boundspecial == special && boundkey > key))
2036
(void)allocstring(&bigger[j++], binding, el_tempcluster);
2040
(void)allocstring(&bigger[j++], pt, el_tempcluster);
2043
(void)allocstring(&bigger[j++], binding, el_tempcluster);
2044
if (quietly) nextchangequiet();
2045
(void)setvalkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, (INTBIG)bigger,
2046
VSTRING|VDONTSAVE|VISARRAY|(j<<VLENGTHSH));
2047
for(i=0; i<j; i++) efree((char *)bigger[i]);
2048
efree((char *)bigger);
2053
* Routine to describe key "boundkey"/"boundspecial". Formats it according to
2055
* -1 for end of menu ("/A")
2056
* 0 for beginning of menu storage ("A/")
2057
* 1 for display ("Ctrl-A")
2059
char *us_describeboundkey(INTSML boundkey, INTBIG boundspecial, INTBIG readable)
2061
char *acceleratorstring, *acceleratorprefix, *shiftprefix, *accprefix;
2063
getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2066
accprefix = acceleratorprefix;
2074
if ((boundspecial&SPECIALKEYDOWN) != 0)
2076
if (readable < 0) (void)addtoinfstr('/');
2077
switch ((boundspecial&SPECIALKEY)>>SPECIALKEYSH)
2079
case SPECIALKEYF1: (void)addstringtoinfstr("F1"); break;
2080
case SPECIALKEYF2: (void)addstringtoinfstr("F2"); break;
2081
case SPECIALKEYF3: (void)addstringtoinfstr("F3"); break;
2082
case SPECIALKEYF4: (void)addstringtoinfstr("F4"); break;
2083
case SPECIALKEYF5: (void)addstringtoinfstr("F5"); break;
2084
case SPECIALKEYF6: (void)addstringtoinfstr("F6"); break;
2085
case SPECIALKEYF7: (void)addstringtoinfstr("F7"); break;
2086
case SPECIALKEYF8: (void)addstringtoinfstr("F8"); break;
2087
case SPECIALKEYF9: (void)addstringtoinfstr("F9"); break;
2088
case SPECIALKEYF10: (void)addstringtoinfstr("F10"); break;
2089
case SPECIALKEYF11: (void)addstringtoinfstr("F11"); break;
2090
case SPECIALKEYF12: (void)addstringtoinfstr("F12"); break;
2091
case SPECIALKEYARROWL:
2092
if ((boundspecial&ACCELERATORDOWN) != 0)
2093
(void)addstringtoinfstr(accprefix);
2094
if ((boundspecial&SHIFTDOWN) != 0)
2095
(void)addstringtoinfstr(shiftprefix);
2096
(void)addstringtoinfstr("LEFT");
2098
case SPECIALKEYARROWR:
2099
if ((boundspecial&ACCELERATORDOWN) != 0)
2100
(void)addstringtoinfstr(accprefix);
2101
if ((boundspecial&SHIFTDOWN) != 0)
2102
(void)addstringtoinfstr(shiftprefix);
2103
(void)addstringtoinfstr("RIGHT");
2105
case SPECIALKEYARROWU:
2106
if ((boundspecial&ACCELERATORDOWN) != 0)
2107
(void)addstringtoinfstr(accprefix);
2108
if ((boundspecial&SHIFTDOWN) != 0)
2109
(void)addstringtoinfstr(shiftprefix);
2110
(void)addstringtoinfstr("UP");
2112
case SPECIALKEYARROWD:
2113
if ((boundspecial&ACCELERATORDOWN) != 0)
2114
(void)addstringtoinfstr(accprefix);
2115
if ((boundspecial&SHIFTDOWN) != 0)
2116
(void)addstringtoinfstr(shiftprefix);
2117
(void)addstringtoinfstr("DOWN");
2120
if (readable == 0) (void)addtoinfstr('/');
2123
if ((boundspecial&ACCELERATORDOWN) != 0)
2125
if (readable < 0) (void)addtoinfstr('/');
2126
if (readable > 0) (void)addstringtoinfstr(accprefix);
2127
if (boundkey > 0 && boundkey < 033) (void)formatinfstr("^%c", boundkey + 0100); else
2128
(void)addtoinfstr((char)boundkey);
2129
if (readable == 0) (void)addtoinfstr('/');
2132
if (readable < 0) (void)addtoinfstr('\\');
2133
if (boundkey > 0 && boundkey < 033) (void)formatinfstr("^%c", boundkey + 0100); else
2134
if (boundkey == 0177) (void)addstringtoinfstr("DEL"); else
2135
(void)addtoinfstr((char)boundkey);
2136
if (readable == 0) (void)addtoinfstr('\\');
2139
return(returninfstr());
2143
* Returns true if the keys "key1"/"special1" is the same as "key2"/"special2"
2145
BOOLEAN us_samekey(INTSML key1, INTBIG special1, INTSML key2, INTBIG special2)
2147
if (special1 != special2) return(FALSE);
2148
if ((special1&SPECIALKEYDOWN) == 0)
2150
if ((special1&ACCELERATORDOWN) != 0)
2152
key1 = toupper(key1);
2153
key2 = toupper(key2);
2155
if (key1 != key2) return(FALSE);
2161
* Routine to parse the key binding string in "origbinding" (an entry in "USER_binding_keys")
2162
* Extracts the key information from the start of the string and returns it in
2163
* "boundkey" and "boundspecial". Then returns the rest of the string.
2164
* Returns zero on error.
2166
char *us_getboundkey(char *origbinding, INTSML *boundkey, INTBIG *boundspecial)
2168
REGISTER char *pt, save, *word;
2169
REGISTER INTBIG offset, len;
2170
char binding[200], *acceleratorstring, *acceleratorprefix;
2172
strcpy(binding, origbinding);
2174
if (binding[0] != 0 && binding[1] == 0)
2176
*boundkey = binding[0];
2179
if (*binding == '/' || *binding == '\\')
2186
for(pt = binding; *pt != 0; pt++)
2187
if (*pt == '/' || *pt == '\\') break;
2193
getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2194
len = strlen(acceleratorprefix);
2195
if (namesamen(word, acceleratorprefix, len) == 0)
2198
*boundspecial |= ACCELERATORDOWN;
2199
} else if (word[0] == 'm' && word[1] == '-')
2202
*boundspecial |= ACCELERATORDOWN;
2205
/* handle single keystrokes */
2208
*boundkey = word[0];
2209
if (save == '/') *boundspecial |= ACCELERATORDOWN;
2212
/* look for special names */
2218
} else if (isdigit(word[1]) != 0)
2220
*boundkey = (INTSML)myatoi(&word[1]);
2223
*boundkey = toupper(word[1]) - 0100;
2227
if (namesame(word, "del") == 0) *boundkey = 0177; else
2228
if (namesame(word, "left") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH); else
2229
if (namesame(word, "sleft") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH)|SHIFTDOWN; else
2230
if (namesame(word, "right") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH); else
2231
if (namesame(word, "sright") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH)|SHIFTDOWN; else
2232
if (namesame(word, "up") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH); else
2233
if (namesame(word, "sup") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH)|SHIFTDOWN; else
2234
if (namesame(word, "down") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH); else
2235
if (namesame(word, "sdown") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH)|SHIFTDOWN; else
2236
if (namesame(word, "f1") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF1<<SPECIALKEYSH); else
2237
if (namesame(word, "f2") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF2<<SPECIALKEYSH); else
2238
if (namesame(word, "f3") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF3<<SPECIALKEYSH); else
2239
if (namesame(word, "f4") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF4<<SPECIALKEYSH); else
2240
if (namesame(word, "f5") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF5<<SPECIALKEYSH); else
2241
if (namesame(word, "f6") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF6<<SPECIALKEYSH); else
2242
if (namesame(word, "f7") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF7<<SPECIALKEYSH); else
2243
if (namesame(word, "f8") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF8<<SPECIALKEYSH); else
2244
if (namesame(word, "f9") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF9<<SPECIALKEYSH); else
2245
if (namesame(word, "f10") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF10<<SPECIALKEYSH); else
2246
if (namesame(word, "f11") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF11<<SPECIALKEYSH); else
2247
if (namesame(word, "f12") == 0) *boundspecial |= SPECIALKEYDOWN|(SPECIALKEYF12<<SPECIALKEYSH);
2251
offset = pt - binding;
2252
return(origbinding+offset);
2256
* Routine to adjust the quick keys according to the variable "var".
2258
void us_adjustquickkeys(VARIABLE *var, BOOLEAN warnofchanges)
2260
REGISTER INTBIG len, i, j, clen, elen;
2263
REGISTER char *keybinding, *menuname, *menucommand, *pt, **quickkeylist,
2265
REGISTER POPUPMENU *pm;
2266
REGISTER POPUPMENUITEM *mi;
2268
/* first scan all existing menus and make sure they are still in the quick key list */
2269
len = getlength(var);
2270
quickkeylist = (char **)var->addr;
2271
for(i=0; i<us_pulldownmenucount; i++)
2272
us_scanquickkeys(us_pulldowns[i], quickkeylist, len, &warnofchanges);
2274
/* next scan the list of quick keys and make sure they are attached to menus */
2275
for(i=0; i<len; i++)
2277
keybinding = quickkeylist[i];
2278
menuname = us_getboundkey(keybinding, &key, &special);
2279
for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
2280
if (*pt == 0) continue;
2282
pm = us_getpopupmenu(menuname);
2284
if (pm == NOPOPUPMENU) continue;
2285
menucommand = pt + 1;
2286
for(j=0; j<pm->total; j++)
2289
if (namesame(us_removeampersand(mi->attribute), menucommand) == 0) break;
2291
if (j >= pm->total) continue;
2293
/* see if this menu item has the quick key */
2294
expected = us_describeboundkey(key, special, -1);
2295
elen = strlen(expected);
2296
clen = strlen(mi->attribute);
2297
if (mi->attribute[clen-1] == '<') clen--;
2298
if (clen-elen > 0 &&
2299
namesamen(&mi->attribute[clen-elen], expected, elen) == 0) continue;
2301
/* not there: see if there is another key bound */
2303
for(pt = mi->attribute; *pt != 0; pt++)
2305
if (*pt == '/' || *pt == '\\' || *pt == '<') break;
2306
(void)addtoinfstr(*pt);
2308
(void)addstringtoinfstr(us_describeboundkey(key, special, -1));
2309
clen = strlen(mi->attribute) - 1;
2310
if (mi->attribute[clen] == '<') (void)addstringtoinfstr("<");
2311
pt = returninfstr();
2312
(void)reallocstring(&mi->attribute, pt, us_tool->cluster);
2313
nativemenurename(pm, j);
2314
us_adjustpopupmenu(pm, j);
2316
/* make it the Meta key */
2318
(void)addstringtoinfstr(us_describeboundkey(key, special, 0));
2319
(void)addstringtoinfstr("command=");
2320
(void)addstringtoinfstr(mi->response->comname);
2321
(void)us_appendargs(mi->response);
2322
us_setkeybinding(returninfstr(), key, special, TRUE);
2326
warnofchanges = FALSE;
2327
ttyputmsg(_("Warning: key bindings have been changed by this library"));
2328
ttyputmsg(_(" (for example, the '%s' key is now bound to '%s')"),
2329
us_describeboundkey(key, special, 1), us_removeampersand(mi->attribute));
2335
* Helper routine for "us_quickkeydlog" to recursively examine menu "pm" and
2336
* load the quick keys tables.
2338
void us_scanquickkeys(POPUPMENU *pm, char **quickkeylist, INTBIG quickkeycount, BOOLEAN *warnofchanges)
2340
REGISTER INTBIG j, i, checked, len;
2342
REGISTER POPUPMENUITEM *mi;
2343
REGISTER USERCOM *uc;
2344
REGISTER POPUPMENU *thispm;
2345
char *pt, menuline[200], menukey[50];
2346
REGISTER char *mname, *menuname;
2349
for(i=0; i<pm->total; i++)
2353
if (uc->menu != NOPOPUPMENU)
2355
us_scanquickkeys(uc->menu, quickkeylist, quickkeycount, warnofchanges);
2358
if (uc->active < 0 && *mi->attribute == 0) continue;
2360
/* see if this item has a quick key */
2361
strcpy(menuline, mi->attribute);
2362
j = strlen(menuline) - 1;
2364
if (menuline[j] == '<')
2369
for(mname = menuline; *mname != 0; mname++)
2370
if (*mname == '/' || *mname == '\\') break;
2371
if (*mname == 0) continue;
2372
strcpy(menukey, &mname[1]);
2374
strcat(menukey, mname);
2375
len = strlen(menukey);
2377
/* item has a quick key: see if it is in the list */
2378
for(j=0; j<quickkeycount; j++)
2380
if (strncmp(quickkeylist[j], menukey, len) != 0) continue;
2381
menuname = us_getboundkey(quickkeylist[j], &key, &special);
2382
for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
2383
if (*pt == 0) continue;
2385
thispm = us_getpopupmenu(menuname);
2387
if (thispm != pm) continue;
2388
if (strncmp(quickkeylist[j], menukey, len) != 0) continue;
2389
if (namesame(&pt[1], us_removeampersand(mi->attribute)) == 0) break;
2391
if (j < quickkeycount) continue;
2393
/* remove the Meta key */
2394
(void)us_getboundkey(menukey, &key, &special);
2395
us_setkeybinding("", key, special, TRUE);
2397
/* this menu entry is not in the quick key list: remove its quick key */
2398
for(mname = mi->attribute; *mname != 0; mname++)
2399
if (*mname == '/' || *mname == '\\') break;
2402
if (checked != 0) *mname++ = '<';
2405
nativemenurename(pm, i);
2406
us_adjustpopupmenu(pm, i);
2409
*warnofchanges = FALSE;
2410
ttyputmsg(_("Warning: key bindings have been changed by this library"));
2411
pt = us_removeampersand(mi->attribute);
2412
if (*pt == '>') pt++;
2413
ttyputmsg(_(" (for example, the '%s' command is no longer attached to key '%s')"),
2414
pt, us_describeboundkey(key, special, 1));
2420
* Helper routine to remove special characters from menu item "name".
2422
char *us_removeampersand(char *name)
2425
REGISTER INTBIG len;
2428
if (name[len-1] == '<' && name[0] == '>') name++;
2430
for(pt = name; *pt != 0; pt++)
2432
if (*pt == '/' || *pt == '\\') break;
2433
if (*pt == '<' || *pt == '&') continue;
2434
(void)addtoinfstr(*pt);
2436
return(returninfstr());
2440
* routine to determine whether the command bound to key "key" is the
2441
* last instance of the "telltool user" command that is bound to a key.
2442
* This is important to know because if the last "telltool user" is unbound,
2443
* there is no way to execute any long commands!
2445
BOOLEAN us_islasteval(INTSML key, INTBIG special)
2447
REGISTER INTBIG i, j, keytotal, foundanother;
2448
REGISTER BOOLEAN retval;
2449
INTBIG boundspecial;
2451
REGISTER VARIABLE *var;
2453
COMMANDBINDING commandbindingthis, commandbindingother;
2455
/* get the command on this key */
2457
var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2458
if (var == NOVARIABLE) return(FALSE);
2459
i = us_findboundkey(key, special, &pt);
2460
if (i < 0) return(FALSE);
2461
us_parsebinding(pt, &commandbindingthis);
2462
if (*commandbindingthis.command != 0)
2464
/* see if it is "telltool user" */
2465
if (namesame(commandbindingthis.command, "telltool user") == 0)
2467
/* this is "telltool user"...check all other keys for this command */
2468
keytotal = getlength(var);
2470
for(j=0; j<keytotal; j++)
2472
pt = us_getboundkey(((char **)var->addr)[j], &boundkey, &boundspecial);
2473
if (us_samekey(key, special, boundkey, boundspecial)) continue;
2474
us_parsebinding(pt, &commandbindingother);
2475
if (*commandbindingother.command != 0 &&
2476
namesame(commandbindingother.command, "telltool user") == 0) foundanother++;
2477
us_freebindingparse(&commandbindingother);
2478
if (foundanother != 0) break;
2480
if (foundanother == 0) retval = TRUE;
2483
us_freebindingparse(&commandbindingthis);
2488
* routine to set the trace information in the "size" coordinate pairs in
2489
* "newlist" onto the node "ni".
2491
void us_settrace(NODEINST *ni, INTBIG *newlist, INTBIG size)
2493
REGISTER INTBIG lx, hx, ly, hy, x, y, i;
2494
INTBIG lxo, hxo, lyo, hyo;
2496
/* get the extent of the data */
2497
lx = hx = newlist[0]; ly = hy = newlist[1];
2498
for(i=1; i<size; i++)
2502
lx = mini(lx, x); hx = maxi(hx, x);
2503
ly = mini(ly, y); hy = maxi(hy, y);
2506
/* make these co-ordinates relative to the center */
2507
x = (hx+lx) / 2; y = (hy+ly) / 2;
2508
for(i=0; i<size; i++)
2510
newlist[i*2] = newlist[i*2] - x;
2511
newlist[i*2+1] = newlist[i*2+1] - y;
2514
/* adjust size for node size offset */
2515
nodesizeoffset(ni, &lxo, &lyo, &hxo, &hyo);
2516
lx -= lxo; hx += hxo;
2517
ly -= lyo; hy += hyo;
2519
/* erase the node instance */
2520
startobjectchange((INTBIG)ni, VNODEINST);
2522
/* change the trace data */
2523
(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2524
VINTEGER|VISARRAY|((size*2)<<VLENGTHSH));
2526
/* scale the node (which redraws too) */
2527
if (ni->proto->primindex != 0 && (lx != ni->lowx || hx != ni->highx || ly != ni->lowy ||
2528
hy != ni->highy || ni->rotation != 0 || ni->transpose != 0))
2529
modifynodeinst(ni, lx-ni->lowx, ly-ni->lowy, hx-ni->highx, hy-ni->highy,
2530
-ni->rotation, ni->transpose);
2533
endobjectchange((INTBIG)ni, VNODEINST);
2535
/* restore original data */
2536
for(i=0; i<size; i++)
2538
newlist[i*2] = newlist[i*2] + x;
2539
newlist[i*2+1] = newlist[i*2+1] + y;
2544
* routine to scale the trace information on node "ni" given that it will change
2545
* in size to "nlx"->"nhx" and "nly"->"nhy".
2547
void us_scaletraceinfo(NODEINST *ni, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy)
2549
REGISTER VARIABLE *var;
2550
REGISTER INTBIG *newlist, oldx, oldy, denx, deny, len, i;
2552
/* stop now if no trace information */
2554
if (var == NOVARIABLE) return;
2556
/* get new array for new trace */
2557
len = getlength(var);
2558
newlist = (INTBIG *)emalloc(len * SIZEOFINTBIG, el_tempcluster);
2559
if (newlist == 0) return;
2561
/* copy the data and scale it */
2562
denx = ni->highx - ni->lowx;
2563
if (denx == 0) denx = nhx - nlx;
2564
deny = ni->highy - ni->lowy;
2565
if (deny == 0) deny = nhy - nly;
2566
for(i=0; i<len; i += 2)
2568
oldx = ((INTBIG *)var->addr)[i];
2569
oldy = ((INTBIG *)var->addr)[i+1];
2570
oldx = muldiv(oldx, nhx - nlx, denx);
2571
oldy = muldiv(oldy, nhy - nly, deny);
2572
newlist[i] = oldx; newlist[i+1] = oldy;
2575
/* store the new list */
2576
(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2577
VINTEGER|VISARRAY|(len<<VLENGTHSH));
2578
efree((char *)newlist);
2582
* Routine to fillet the two highlighted objects
2584
void us_dofillet(void)
2586
REGISTER VARIABLE *var;
2587
HIGHLIGHT thishigh, otherhigh;
2588
REGISTER NODEINST *ni1, *ni2, *swapni;
2589
double startoffset, endangle, srot, erot, newangle, dx, dy;
2590
INTBIG ix, iy, ix1, iy1, ix2, iy2;
2591
REGISTER BOOLEAN on1, on2;
2592
REGISTER INTBIG ang1, ang2, size1, size2, arc1, arc2, swapsize, icount, newrot;
2593
REGISTER INTBIG *newlist1, *newlist2, *line1xs, *line1ys, *line1xe, *line1ye,
2594
*line2xs, *line2ys, *line2xe, *line2ye, x, y, i, *swaplist;
2597
/* must be exactly two nodes selected */
2598
var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2599
if (var == NOVARIABLE)
2601
us_abortcommand(_("Must select two nodes before filleting"));
2604
if (getlength(var) != 2)
2606
us_abortcommand(_("Must select two nodes before filleting"));
2610
if (us_makehighlight(((char **)var->addr)[0], &thishigh) ||
2611
us_makehighlight(((char **)var->addr)[1], &otherhigh)) return;
2613
/* get the two objects */
2614
if ((thishigh.status&HIGHTYPE) != HIGHFROM || (otherhigh.status&HIGHTYPE) != HIGHFROM)
2616
us_abortcommand(_("Must select two nodes before filleting"));
2620
if (!thishigh.fromgeom->entryisnode || !otherhigh.fromgeom->entryisnode)
2622
us_abortcommand(_("Must select two nodes before filleting"));
2626
/* get description of first node */
2627
ni1 = thishigh.fromgeom->entryaddr.ni;
2628
if (ni1->proto == art_circleprim || ni1->proto == art_thickcircleprim)
2630
getarcdegrees(ni1, &startoffset, &endangle);
2631
if (startoffset == 0.0 && endangle == 0.0)
2633
us_abortcommand(_("Must select arcs, not circles before filleting"));
2636
newlist1 = emalloc((6*SIZEOFINTBIG), el_tempcluster);
2637
if (newlist1 == 0) return;
2638
newlist1[0] = (ni1->lowx + ni1->highx) / 2;
2639
newlist1[1] = (ni1->lowy + ni1->highy) / 2;
2640
getarcendpoints(ni1, startoffset, endangle, &newlist1[2], &newlist1[3],
2641
&newlist1[4], &newlist1[5]);
2643
} else if (ni1->proto == art_openedpolygonprim || ni1->proto == art_openeddottedpolygonprim ||
2644
ni1->proto == art_openeddashedpolygonprim || ni1->proto == art_openedthickerpolygonprim ||
2645
ni1->proto == art_closedpolygonprim)
2647
var = gettrace(ni1);
2648
if (var == NOVARIABLE)
2650
us_abortcommand(_("Must select nodes with outline information before filleting"));
2654
/* transform the traces */
2655
size1 = getlength(var) / 2;
2656
newlist1 = emalloc((size1*2*SIZEOFINTBIG), el_tempcluster);
2657
if (newlist1 == 0) return;
2658
makerot(ni1, trans);
2659
x = (ni1->highx + ni1->lowx) / 2;
2660
y = (ni1->highy + ni1->lowy) / 2;
2661
for(i=0; i<size1; i++)
2662
xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &newlist1[i*2],
2663
&newlist1[i*2+1], trans);
2667
us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni1));
2671
/* get description of second node */
2672
ni2 = otherhigh.fromgeom->entryaddr.ni;
2673
if (ni2->proto == art_circleprim || ni2->proto == art_thickcircleprim)
2675
getarcdegrees(ni2, &startoffset, &endangle);
2676
if (startoffset == 0.0 && endangle == 0.0)
2678
us_abortcommand(_("Must select arcs, not circles before filleting"));
2681
newlist2 = emalloc((6*SIZEOFINTBIG), el_tempcluster);
2682
if (newlist2 == 0) return;
2683
newlist2[0] = (ni2->lowx + ni2->highx) / 2;
2684
newlist2[1] = (ni2->lowy + ni2->highy) / 2;
2685
getarcendpoints(ni2, startoffset, endangle, &newlist2[2], &newlist2[3],
2686
&newlist2[4], &newlist2[5]);
2688
} else if (ni2->proto == art_openedpolygonprim || ni2->proto == art_openeddottedpolygonprim ||
2689
ni2->proto == art_openeddashedpolygonprim || ni2->proto == art_openedthickerpolygonprim ||
2690
ni2->proto == art_closedpolygonprim)
2692
var = gettrace(ni2);
2693
if (var == NOVARIABLE)
2695
us_abortcommand(_("Must select nodes with outline information before filleting"));
2699
/* transform the traces */
2700
size2 = getlength(var) / 2;
2701
newlist2 = emalloc((size2*2*SIZEOFINTBIG), el_tempcluster);
2702
if (newlist2 == 0) return;
2703
makerot(ni2, trans);
2704
x = (ni2->highx + ni2->lowx) / 2;
2705
y = (ni2->highy + ni2->lowy) / 2;
2706
for(i=0; i<size2; i++)
2707
xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &newlist2[i*2],
2708
&newlist2[i*2+1], trans);
2712
us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni2));
2716
/* handle different types of filleting */
2717
if (arc1 != 0 && arc2 != 0)
2719
/* cannot handle arc-to-arc filleting */
2720
us_abortcommand(_("Cannot fillet two curves"));
2721
} else if (arc1 == 0 && arc2 == 0)
2723
/* handle line-to-line filleting: find out which endpoints are closest */
2724
if (computedistance(x,y, newlist1[0],newlist1[1]) <
2725
computedistance(x,y, newlist1[size1*2-2],newlist1[size1*2-1]))
2727
line1xs = &newlist1[0];
2728
line1ys = &newlist1[1];
2729
line1xe = &newlist1[2];
2730
line1ye = &newlist1[3];
2733
line1xs = &newlist1[size1*2-2];
2734
line1ys = &newlist1[size1*2-1];
2735
line1xe = &newlist1[size1*2-4];
2736
line1ye = &newlist1[size1*2-3];
2738
if (computedistance(*line1xs,*line1ys, newlist2[0],newlist2[1]) <
2739
computedistance(*line1xs,*line1ys, newlist2[size2*2-2],newlist2[size2*2-1]))
2741
line2xs = &newlist2[0];
2742
line2ys = &newlist2[1];
2743
line2xe = &newlist2[2];
2744
line2ye = &newlist2[3];
2747
line2xs = &newlist2[size2*2-2];
2748
line2ys = &newlist2[size2*2-1];
2749
line2xe = &newlist2[size2*2-4];
2750
line2ye = &newlist2[size2*2-3];
2753
/* compute intersection point */
2754
ang1 = figureangle(*line1xs, *line1ys, *line1xe, *line1ye);
2755
ang2 = figureangle(*line2xs, *line2ys, *line2xe, *line2ye);
2756
if (intersect(*line1xs, *line1ys, ang1, *line2xs, *line2ys, ang2, &ix, &iy) != 0)
2757
us_abortcommand(_("Lines do not intersect")); else
2759
*line1xs = ix; *line1ys = iy;
2760
*line2xs = ix; *line2ys = iy;
2762
us_clearhighlightcount();
2763
us_settrace(ni1, newlist1, size1);
2764
us_settrace(ni2, newlist2, size2);
2765
us_pophighlight(TRUE);
2769
/* handle arc-to-line filleting */
2772
swaplist = newlist1; newlist1 = newlist2; newlist2 = swaplist;
2773
swapsize = size1; size1 = size2; size2 = swapsize;
2774
swapni = ni1; ni1 = ni2; ni2 = swapni;
2777
/* "newlist1" describes the arc, "newlist2" describes the line */
2778
if (computedistance(newlist1[0],newlist1[1], newlist2[0],newlist2[1]) <
2779
computedistance(newlist1[0],newlist1[1], newlist2[size2*2-2],newlist2[size2*2-1]))
2781
line2xs = &newlist2[0];
2782
line2ys = &newlist2[1];
2783
line2xe = &newlist2[2];
2784
line2ye = &newlist2[3];
2787
line2xs = &newlist2[size2*2-2];
2788
line2ys = &newlist2[size2*2-1];
2789
line2xe = &newlist2[size2*2-4];
2790
line2ye = &newlist2[size2*2-3];
2792
icount = circlelineintersection(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
2793
*line2xs, *line2ys, *line2xe, *line2ye, &ix1, &iy1, &ix2, &iy2, 0);
2796
us_abortcommand(_("Line does not intersect arc: cannot fillet"));
2801
on1 = us_pointonexparc(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
2802
newlist1[4],newlist1[5], ix1, iy1);
2803
on2 = us_pointonexparc(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
2804
newlist1[4],newlist1[5], ix2, iy2);
2808
ix1 = ix2; iy1 = iy2;
2809
} else if (on1 && !on2)
2816
x = (*line2xs + *line2xe) / 2;
2817
y = (*line2ys + *line2ye) / 2;
2818
if (computedistance(ix1,iy1, x,y) > computedistance(ix2,iy2, x,y))
2820
ix1 = ix2; iy1 = iy2;
2824
/* make them fillet at (ix1,iy1) */
2826
us_clearhighlightcount();
2828
/* adjust the arc (node ni1) */
2829
dx = (double)(newlist1[2]-newlist1[0]); dy = (double)(newlist1[3]-newlist1[1]);
2830
if (dx == 0.0 && dy == 0.0)
2832
us_abortcommand(_("Domain error during fillet"));
2835
srot = atan2(dy, dx);
2836
if (srot < 0.0) srot += EPI*2.0;
2838
dx = (double)(newlist1[4]-newlist1[0]); dy = (double)(newlist1[5]-newlist1[1]);
2839
if (dx == 0.0 && dy == 0.0)
2841
us_abortcommand(_("Domain error during fillet"));
2844
erot = atan2(dy, dx);
2845
if (erot < 0.0) erot += EPI*2.0;
2847
dx = (double)(ix1-newlist1[0]); dy = (double)(iy1-newlist1[1]);
2848
if (dx == 0.0 && dy == 0.0)
2850
us_abortcommand(_("Domain error during fillet"));
2853
newangle = atan2(dy, dx);
2854
if (newangle < 0.0) newangle += EPI*2.0;
2855
if (computedistance(ix1,iy1, newlist1[2],newlist1[3]) <
2856
computedistance(ix1,iy1, newlist1[4],newlist1[5])) srot = newangle; else
2859
if (erot < 0.0) erot += EPI*2.0;
2860
newrot = rounddouble(srot * 1800.0 / EPI);
2861
srot -= ((double)newrot) * EPI / 1800.0;
2862
startobjectchange((INTBIG)ni1, VNODEINST);
2863
modifynodeinst(ni1, 0, 0, 0, 0, newrot - ni1->rotation, 0);
2864
setarcdegrees(ni1, srot, erot);
2865
endobjectchange((INTBIG)ni1, VNODEINST);
2867
/* adjust the line (node ni2) */
2868
*line2xs = ix1; *line2ys = iy1;
2869
us_settrace(ni2, newlist2, size2);
2871
/* restore highlighting */
2872
us_pophighlight(TRUE);
2875
efree((char *)newlist1);
2876
efree((char *)newlist2);
2880
* Houtine to convert the text in "msg" to bits on the display.
2882
void us_layouttext(char *layer, INTBIG tsize, INTBIG scale, INTBIG font, INTBIG italic,
2883
INTBIG bold, INTBIG underline, INTBIG separation, char *msg)
2885
REGISTER NODEPROTO *np;
2886
REGISTER INTBIG x, y;
2887
REGISTER NODEINST *ni;
2888
REGISTER BOOLEAN err;
2889
REGISTER INTBIG cx, cy, lambda, gridsize;
2890
INTBIG wid, hei, bx, by;
2891
UINTBIG descript[TEXTDESCRIPTSIZE];
2892
char **rowstart, *data;
2893
static POLYGON *poly = NOPOLYGON;
2895
np = us_needfacet();
2896
if (np == NONODEPROTO) return;
2898
/* convert the text to bits */
2900
if (tsize < 4) tsize = 4;
2901
if (tsize > TXTMAXPOINTS) tsize = TXTMAXPOINTS;
2902
TDSETSIZE(descript, TXTSETPOINTS(tsize));
2903
TDSETFACE(descript, font);
2904
if (italic != 0) TDSETITALIC(descript, VTITALIC);
2905
if (bold != 0) TDSETBOLD(descript, VTBOLD);
2906
if (underline != 0) TDSETUNDERLINE(descript, VTUNDERLINE);
2907
screensettextinfo(el_curwindowpart, NOTECHNOLOGY, descript);
2908
err = gettextbits(el_curwindowpart, msg, &wid, &hei, &rowstart);
2911
us_abortcommand(_("Sorry, this system cannot layout text"));
2915
/* determine the primitive to use for the layout */
2916
for(us_layouttextprim = el_curtech->firstnodeproto; us_layouttextprim != NONODEPROTO;
2917
us_layouttextprim = us_layouttextprim->nextnodeproto)
2918
if (namesame(us_layouttextprim->primname, layer) == 0) break;
2919
if (us_layouttextprim == NONODEPROTO)
2921
us_abortcommand(_("Cannot find '%s' node"), layer);
2925
lambda = el_curlib->lambda[el_curtech->techindex];
2926
separation = separation * lambda / 2;
2927
gridsize = lambda * scale;
2928
bx = (el_curwindowpart->screenlx+el_curwindowpart->screenhx -
2929
wid * gridsize) / 2;
2930
by = (el_curwindowpart->screenly+el_curwindowpart->screenhy -
2931
hei * gridsize) / 2;
2932
gridalign(&bx, &by, 1);
2933
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
2934
us_clearhighlightcount();
2935
if (separation == 0) mergeinit();
2936
for(y=0; y<hei; y++)
2938
cy = by - y * gridsize;
2940
for(x=0; x<wid; x++)
2942
cx = bx + x * gridsize;
2947
poly->xv[1] = cx + gridsize;
2948
poly->yv[1] = cy + gridsize;
2949
poly->style = FILLEDRECT;
2951
if (separation == 0) mergestorepolygon(0, el_curtech, poly); else
2953
/* place the node now */
2954
ni = newnodeinst(us_layouttextprim, poly->xv[0]+separation,
2955
poly->xv[1]-separation, poly->yv[0]+separation,
2956
poly->yv[1]-separation, 0, 0, np);
2957
endobjectchange((INTBIG)ni, VNODEINST);
2963
if (separation == 0) mergedone(us_layouttextpolygon);
2967
* Helper routine for "us_layouttext" to process a polygon and convert it to layout.
2969
void us_layouttextpolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
2971
REGISTER NODEPROTO *facet;
2972
REGISTER NODEINST *ni;
2973
REGISTER INTBIG lx, hx, ly, hy, cx, cy, *newlist;
2977
facet = us_needfacet();
2978
if (facet == NONODEPROTO) return;
2981
for(i=1; i<count; i++)
2983
if (x[i] < lx) lx = x[i];
2984
if (x[i] > hx) hx = x[i];
2985
if (y[i] < ly) ly = y[i];
2986
if (y[i] > hy) hy = y[i];
2988
cx = (lx+hx) / 2; cy = (ly+hy) / 2;
2989
ni = newnodeinst(us_layouttextprim, lx, hx, ly, hy, 0, 0, facet);
2990
newlist = (INTBIG *)emalloc(count * 2 * SIZEOFINTBIG, el_tempcluster);
2991
if (newlist == 0) return;
2992
for(i=0; i<count; i++)
2994
newlist[i*2] = x[i] - cx;
2995
newlist[i*2+1] = y[i] - cy;
2997
(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2998
VINTEGER|VISARRAY|((count*2)<<VLENGTHSH));
2999
endobjectchange((INTBIG)ni, VNODEINST);
3000
high.status = HIGHFROM;
3001
high.fromgeom = ni->geom;
3002
high.fromport = NOPORTPROTO;
3005
us_addhighlight(&high);
3009
* Routine to determine whether the point (x,y) is on the arc centered at (cx,cy), starting
3010
* at (sx,sy), and ending at (ex,ey). Returns true if on the arc.
3012
BOOLEAN us_pointonexparc(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, INTBIG x, INTBIG y)
3014
REGISTER INTBIG as, ae, a;
3016
as = figureangle(cx, cy, sx, sy);
3017
ae = figureangle(cx, cy, ex, ey);
3018
a = figureangle(cx, cy, x, y);
3022
if (a >= as && a <= ae) return(TRUE);
3025
if (a >= as || a <= ae) return(TRUE);
3031
* routine to recursively check sub-facet revision times
3034
void us_check_facet_date(NODEPROTO *np, UINTBIG rev_time)
3036
REGISTER NODEPROTO *np2;
3037
REGISTER NODEINST *ni;
3039
for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3042
if (np2->primindex != 0) continue; /* ignore if primitive */
3044
/* ignore recursive references (showing icon in contents) */
3045
if (np2->cell == np->cell) continue;
3046
if (np2->temp1 != 0) continue; /* ignore if already seen */
3047
us_check_facet_date(np2, rev_time); /* recurse */
3050
/* check this facet */
3051
np->temp1++; /* flag that we have seen this one */
3052
if (np->revisiondate <= rev_time) return;
3054
/* possible error in hierarchy */
3055
ttyputerr(_("WARNING: sub-facet '%s' has been edited"), describenodeproto(np));
3056
ttyputmsg(_(" since the last revision to the current facet"));
3060
* routine to switch to library "lib"
3062
void us_switchtolibrary(LIBRARY *lib)
3065
REGISTER INTBIG oldlam;
3066
REGISTER WINDOWPART *w;
3068
/* select the new library */
3069
us_clearhighlightcount();
3070
oldlam = el_curlib->lambda[el_curtech->techindex];
3072
us_setlambda(NOWINDOWFRAME);
3073
if ((us_curnodeproto == NONODEPROTO || us_curnodeproto->primindex == 0) &&
3074
(us_state&NONPERSISTENTCURNODE) == 0)
3075
us_setnodeproto(el_curtech->firstnodeproto);
3076
for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3079
/* if nothing displayed and new library has top facet, show it */
3080
if (el_curwindowpart == NOWINDOWPART ||
3081
el_curwindowpart->curnodeproto == NONODEPROTO)
3083
if (el_curlib->curnodeproto != NONODEPROTO)
3085
newpar[0] = describenodeproto(el_curlib->curnodeproto);
3086
us_editfacet(1, newpar);
3090
/* redo the explorer window (if it is up) */
3091
us_redoexplorerwindow();
3095
* Routine to replace all cross-library references that point into
3096
* "oldlib" with equivalent ones that point to "newlib". This is called
3097
* when a library is re-read from disk ("oldlib" is the former one).
3099
void us_replacelibraryreferences(LIBRARY *oldlib, LIBRARY *newlib)
3101
REGISTER LIBRARY *lib;
3102
REGISTER NODEPROTO *np, *newnp;
3103
REGISTER NODEINST *ni, *nextni, *newni;
3104
REGISTER ARCINST *ai;
3105
REGISTER PORTARCINST *pi;
3106
REGISTER PORTEXPINST *pe;
3108
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
3110
if (lib == oldlib || lib == newlib) continue;
3112
/* look for cross-library references to "oldlib" */
3113
us_correctxlibref(&lib->firstvar, &lib->numvar, oldlib, newlib);
3114
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3116
us_correctxlibref(&np->firstvar, &np->numvar, oldlib, newlib);
3117
for(ni = np->firstnodeinst; ni != NONODEINST; ni = nextni)
3119
nextni = ni->nextnodeinst;
3121
/* correct variables */
3122
us_correctxlibref(&ni->firstvar, &ni->numvar, oldlib, newlib);
3123
us_correctxlibref(&ni->geom->firstvar, &ni->geom->numvar, oldlib, newlib);
3124
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3125
us_correctxlibref(&pi->firstvar, &pi->numvar, oldlib, newlib);
3126
for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
3127
us_correctxlibref(&pe->firstvar, &pe->numvar, oldlib, newlib);
3129
if (ni->proto->primindex != 0) continue;
3130
if (ni->proto->cell->lib == oldlib)
3132
/* find the equivalent name in the new library */
3133
newnp = us_findfacetinotherlib(ni->proto, newlib);
3134
if (newnp == NONODEPROTO)
3136
ttyputerr(_("Error: facet %s{%s};%ld no longer present in library %s"),
3137
ni->proto->cell->cellname, ni->proto->cellview->sviewname,
3138
ni->proto->version, newlib->libname);
3141
newni = replacenodeinst(ni, newnp, FALSE, TRUE);
3142
if (newni == NONODEINST)
3144
ttyputerr(_("Error: node %s{%s};%ld could not be replaced with equivalent in library %s"),
3145
ni->proto->cell->cellname, ni->proto->cellview->sviewname,
3146
ni->proto->version, newlib->libname);
3151
for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3153
us_correctxlibref(&ai->firstvar, &ai->numvar, oldlib, newlib);
3154
us_correctxlibref(&ai->geom->firstvar, &ai->geom->numvar, oldlib, newlib);
3161
* Helper routine to search "numvar" variables in "firstvar" and replace references
3162
* to anything in library "oldlib" to point to an equivalent in "newlib".
3164
void us_correctxlibref(VARIABLE **firstvar, INTSML *numvar, LIBRARY *oldlib, LIBRARY *newlib)
3166
REGISTER INTBIG i, j, checkfacet;
3167
REGISTER VARIABLE *var, *svar, *dvar;
3168
REGISTER NODEPROTO *np, *newnp;
3169
REGISTER NODEINST *ni;
3170
REGISTER ARCINST *ai;
3171
REGISTER PORTPROTO *pp;
3172
REGISTER PORTARCINST *pi;
3173
REGISTER PORTEXPINST *pe;
3174
REGISTER CELL *c, *nc;
3175
REGISTER LIBRARY *lib;
3176
REGISTER NETWORK *net;
3177
REGISTER GEOM *geom;
3179
for(i=0; i < *numvar; i++)
3181
var = &(*firstvar)[i];
3182
if ((var->type&VISARRAY) != 0) continue;
3184
switch (var->type&VTYPE)
3187
ni = (NODEINST *)var->addr;
3192
np = (NODEPROTO *)var->addr;
3193
if (np->primindex != 0) break;
3194
if (np->cell->lib != oldlib) break;
3195
newnp = us_findfacetinotherlib(np, newlib);
3196
var->addr = (INTBIG)newnp;
3199
pi = (PORTARCINST *)var->addr;
3200
np = pi->conarcinst->parent;
3204
pe = (PORTEXPINST *)var->addr;
3205
np = pe->exportproto->parent;
3209
pp = (PORTPROTO *)var->addr;
3214
ai = (ARCINST *)var->addr;
3219
geom = (GEOM *)var->addr;
3220
np = geomparent(geom);
3224
lib = (LIBRARY *)var->addr;
3225
if (lib != oldlib) break;
3226
var->addr = (INTBIG)newlib;
3229
net = (NETWORK *)var->addr;
3234
c = (CELL *)var->addr;
3235
if (c->lib != oldlib) break;
3236
for(nc = newlib->firstcell; nc != NOCELL; nc = nc->nextcell)
3237
if (namesame(c->cellname, nc->cellname) == 0) break;
3238
if (nc != NOCELL) var->addr = (INTBIG)nc;
3241
if (checkfacet != 0)
3243
if (np->primindex != 0) continue;
3244
if (np->cell->lib != oldlib) continue;
3246
/* cannot correct the reference: delete the variable */
3247
for(j=i+1; j < *numvar; j++)
3249
svar = &(*firstvar)[j];
3250
dvar = &(*firstvar)[j-1];
3260
* Helper routine to find the equivalent to facet "facet" in library "lib".
3262
NODEPROTO *us_findfacetinotherlib(NODEPROTO *facet, LIBRARY *lib)
3264
REGISTER NODEPROTO *newnp;
3266
for(newnp = lib->firstnodeproto; newnp != NONODEPROTO; newnp = newnp->nextnodeproto)
3268
if (namesame(facet->cell->cellname, newnp->cell->cellname) != 0) continue;
3269
if (facet->cellview != newnp->cellview) continue;
3270
if (facet->version != newnp->version) continue;
3276
/******************** TEXT OBJECTS ********************/
3279
* routine to recompute the text descriptor in "descript" to change the
3280
* grab-point according to the location of (xcur, ycur), given that the
3281
* text centers at (xc, yc) and is "xw" by "yw" in size.
3283
void us_figuregrabpoint(UINTBIG *descript, INTBIG xcur, INTBIG ycur, INTBIG xc,
3284
INTBIG yc, INTBIG xw, INTBIG yw)
3286
if (xcur < xc - xw/2)
3288
/* grab-point is on the bottom left */
3289
if (ycur < yc - yw/2)
3291
TDSETPOS(descript, VTPOSUPRIGHT);
3295
/* grab-point is on the top left */
3296
if (ycur > yc + yw/2)
3298
TDSETPOS(descript, VTPOSDOWNRIGHT);
3302
/* grab-point is on the left */
3303
TDSETPOS(descript, VTPOSRIGHT);
3307
if (xcur > xc + xw/2)
3309
/* grab-point is on the bottom right */
3310
if (ycur < yc - yw/2)
3312
TDSETPOS(descript, VTPOSUPLEFT);
3316
/* grab-point is on the top right */
3317
if (ycur > yc + yw/2)
3319
TDSETPOS(descript, VTPOSDOWNLEFT);
3323
/* grab-point is on the right */
3324
TDSETPOS(descript, VTPOSLEFT);
3328
/* grab-point is on the bottom */
3329
if (ycur < yc - yw/2)
3331
TDSETPOS(descript, VTPOSUP);
3335
/* grab-point is on the top */
3336
if (ycur > yc + yw/2)
3338
TDSETPOS(descript, VTPOSDOWN);
3342
/* grab-point is in the center: check for VERY center */
3343
if (ycur >= yc - yw/6 && ycur <= yc + yw/6 && xcur >= xc - xw/6 &&
3346
TDSETPOS(descript, VTPOSBOXED);
3350
/* grab-point is simply centered */
3351
TDSETPOS(descript, VTPOSCENT);
3355
* routine to return the new text descriptor field, given that the old is in
3356
* "formerdesc". The instructions for changing this variable are in "count"
3357
* and "par", where "count" where the first two values are the X and Y offset,
3358
* and the third value is the text position. Returns -1 on error.
3360
void us_figurevariableplace(UINTBIG *formerdesc, INTBIG count, char *par[])
3363
REGISTER INTBIG grab;
3367
xval = atofr(par[0]) * 4 / WHOLE;
3368
yval = atofr(par[1]) * 4 / WHOLE;
3369
us_setdescriptoffset(formerdesc, xval, yval);
3373
grab = us_gettextposition(par[2]);
3374
TDSETPOS(formerdesc, grab);
3379
* routine to change the X and Y offset factors in the text descriptor
3380
* "formerdesc" to "xval" and "yval". Returns the new text descriptor.
3382
void us_setdescriptoffset(UINTBIG *formerdesc, INTBIG xval, INTBIG yval)
3384
REGISTER INTBIG oldx, oldy;
3386
/* make sure the range is proper */
3387
oldx = xval; oldy = yval;
3388
propervaroffset(&xval, &yval);
3389
if (xval != oldx || yval != oldy)
3390
ttyputmsg(_("Text offset adjusted"));
3392
TDSETOFF(formerdesc, xval, yval);
3396
* routine to rotate the text descriptor in "descript" to account for
3397
* the rotation of the object on which it resides: "geom". The new
3398
* text descriptor is returned.
3400
void us_rotatedescript(GEOM *geom, UINTBIG *descript)
3402
us_rotatedescriptArb(geom, descript, FALSE);
3406
* routine to undo the rotation of the text descriptor in "descript" to account for
3407
* the rotation of the object on which it resides: "geom". The new
3408
* text descriptor is returned.
3410
void us_rotatedescriptI(GEOM *geom, UINTBIG *descript)
3412
us_rotatedescriptArb(geom, descript, TRUE);
3416
* routine to rotate the text descriptor in "descript" to account for
3417
* the rotation of the object on which it resides: "geom". Inverts the
3418
* sense of the rotation if "invert" is true. The new
3419
* text descriptor is returned.
3421
void us_rotatedescriptArb(GEOM *geom, UINTBIG *descript, BOOLEAN invert)
3423
REGISTER INTBIG style;
3424
REGISTER NODEINST *ni;
3427
/* arcs do not rotate */
3428
if (!geom->entryisnode) return;
3430
switch (TDGETPOS(descript))
3433
case VTPOSBOXED: return;
3434
case VTPOSUP: style = TEXTBOT; break;
3435
case VTPOSDOWN: style = TEXTTOP; break;
3436
case VTPOSLEFT: style = TEXTRIGHT; break;
3437
case VTPOSRIGHT: style = TEXTLEFT; break;
3438
case VTPOSUPLEFT: style = TEXTBOTRIGHT; break;
3439
case VTPOSUPRIGHT: style = TEXTBOTLEFT; break;
3440
case VTPOSDOWNLEFT: style = TEXTTOPRIGHT; break;
3441
case VTPOSDOWNRIGHT: style = TEXTTOPLEFT; break;
3443
ni = geom->entryaddr.ni;
3446
if (ni->transpose == 0) makeangle((3600 - ni->rotation)%3600, 0, trans); else
3447
makeangle(ni->rotation, ni->transpose, trans);
3450
makeangle(ni->rotation, ni->transpose, trans);
3452
style = rotatelabel(style, TDGETROTATION(descript), trans);
3455
case TEXTBOT: TDSETPOS(descript, VTPOSUP); break;
3456
case TEXTTOP: TDSETPOS(descript, VTPOSDOWN); break;
3457
case TEXTRIGHT: TDSETPOS(descript, VTPOSLEFT); break;
3458
case TEXTLEFT: TDSETPOS(descript, VTPOSRIGHT); break;
3459
case TEXTBOTRIGHT: TDSETPOS(descript, VTPOSUPLEFT); break;
3460
case TEXTBOTLEFT: TDSETPOS(descript, VTPOSUPRIGHT); break;
3461
case TEXTTOPRIGHT: TDSETPOS(descript, VTPOSDOWNLEFT); break;
3462
case TEXTTOPLEFT: TDSETPOS(descript, VTPOSDOWNRIGHT); break;
3467
* routine to adjust the displayable text on node "ni" to account for new
3468
* size/rotation factors in the node. This is only done for invisible pins
3469
* in the generic technology, where the displayable text must track the node.
3471
void us_adjustdisplayabletext(NODEINST *ni)
3474
REGISTER INTBIG halfx, halfy, lambda;
3475
UINTBIG descript[TEXTDESCRIPTSIZE];
3476
REGISTER VARIABLE *var;
3478
/* make sure this is the invisible pin */
3479
if (ni->proto != gen_invispinprim) return;
3481
/* search for displayable text */
3482
for(i=0; i<ni->numvar; i++)
3484
var = &ni->firstvar[i];
3485
if ((var->type&VDISPLAY) == 0) continue;
3487
/* compute the proper display offset */
3488
TDCOPY(descript, var->textdescript);
3489
lambda = lambdaofnode(ni);
3490
halfx = (ni->highx - ni->lowx) * 2 / lambda;
3491
halfy = (ni->highy - ni->lowy) * 2 / lambda;
3492
switch (TDGETPOS(descript))
3496
us_setdescriptoffset(descript, 0, 0);
3499
us_setdescriptoffset(descript, 0, -halfy);
3502
us_setdescriptoffset(descript, 0, halfy);
3505
us_setdescriptoffset(descript, halfx, 0);
3508
us_setdescriptoffset(descript, -halfx, 0);
3511
us_setdescriptoffset(descript, halfx, -halfy);
3514
us_setdescriptoffset(descript, -halfx, -halfy);
3517
us_setdescriptoffset(descript, halfx, halfy);
3519
case VTPOSDOWNRIGHT:
3520
us_setdescriptoffset(descript, -halfx, halfy);
3523
modifydescript((INTBIG)ni, VNODEINST, var, descript);
3528
* routine to parse the "grab-point" specification in "pp" and return the
3529
* code. Prints an error message on error.
3531
INTBIG us_gettextposition(char *pp)
3536
if (namesamen(pp, "centered", l) == 0 && l >= 1) return(VTPOSCENT);
3537
if (namesamen(pp, "boxed", l) == 0 && l >= 1) return(VTPOSBOXED);
3538
if (namesame(pp, "up") == 0) return(VTPOSUP);
3539
if (namesame(pp, "down") == 0) return(VTPOSDOWN);
3540
if (namesamen(pp, "left", l) == 0 && l >= 1) return(VTPOSLEFT);
3541
if (namesamen(pp, "right", l) == 0 && l >= 1) return(VTPOSRIGHT);
3542
if (namesamen(pp, "up-left", l) == 0 && l >= 4) return(VTPOSUPLEFT);
3543
if (namesamen(pp, "up-right", l) == 0 && l >= 4) return(VTPOSUPRIGHT);
3544
if (namesamen(pp, "down-left", l) == 0 && l >= 6) return(VTPOSDOWNLEFT);
3545
if (namesamen(pp, "down-right", l) == 0 && l >= 6) return(VTPOSDOWNRIGHT);
3546
us_abortcommand(_("Unrecognized grab-point: %s"), pp);
3551
* routine to parse the "text size" specification in "pp" and return the
3552
* code. Prints an error message and returns -1 on error.
3554
INTBIG us_gettextsize(char *pp, INTBIG old)
3556
REGISTER INTBIG i, l;
3559
if (tolower(pp[l-1]) == 'p')
3563
if (l > TXTMAXPOINTS) l = TXTMAXPOINTS;
3564
return(TXTSETPOINTS(l));
3566
if (tolower(pp[l-1]) == 'l')
3568
l = atofr(pp) * 4 / WHOLE;
3570
if (l > TXTMAXQLAMBDA) l = TXTMAXQLAMBDA;
3571
return(TXTSETQLAMBDA(l));
3573
if (namesamen(pp, "up", l) == 0 && l >= 1)
3575
i = TXTGETPOINTS(old);
3576
if (i > 0 && i < TXTMAXPOINTS) old = TXTSETPOINTS(i+1); else
3578
i = TXTGETQLAMBDA(old);
3579
if (i > 0 && i < TXTMAXQLAMBDA) old = TXTSETQLAMBDA(i+1);
3582
} else if (namesamen(pp, "down", l) == 0 && l >= 1)
3584
i = TXTGETPOINTS(old);
3585
if (i > 1) old = TXTSETPOINTS(i-1); else
3587
i = TXTGETQLAMBDA(old);
3588
if (i > 1) old = TXTSETQLAMBDA(i-1);
3592
us_abortcommand(_("Unrecognized text size: %s"), pp);
3596
static NODEINST *us_searchcircuittextni;
3597
static ARCINST *us_searchcircuittextai;
3598
static PORTPROTO *us_searchcircuittextpp;
3599
static INTBIG us_searchcircuittextvarnum; /* number of the variable on this text */
3600
static INTBIG us_searchcircuittextline; /* line number (in multiline text) */
3601
static INTBIG us_searchcircuittextstart; /* starting character position */
3602
static INTBIG us_searchcircuittextend; /* ending character position */
3603
static BOOLEAN us_searchcircuittextfound; /* true if text is selected */
3606
* Routine to initialize text searching in edit window "win".
3608
void us_initsearchcircuittext(WINDOWPART *win)
3610
REGISTER NODEPROTO *np;
3612
np = win->curnodeproto;
3613
if (np == NONODEPROTO) return;
3614
us_searchcircuittextni = np->firstnodeinst;
3615
us_searchcircuittextai = np->firstarcinst;
3616
us_searchcircuittextpp = np->firstportproto;
3617
us_searchcircuittextvarnum = 0;
3618
us_searchcircuittextfound = FALSE;
3621
void us_advancecircuittext(char *search, INTBIG bits)
3623
REGISTER NODEINST *ni;
3624
REGISTER ARCINST *ai;
3625
REGISTER PORTPROTO *pp;
3627
REGISTER INTBIG len;
3628
REGISTER VARIABLE *var;
3631
/* look for a node with this string */
3632
while (us_searchcircuittextni != NONODEINST)
3634
ni = us_searchcircuittextni;
3635
while (us_searchcircuittextvarnum < ni->numvar)
3637
var = &ni->firstvar[us_searchcircuittextvarnum];
3638
us_searchcircuittextvarnum++;
3639
if ((var->type&VDISPLAY) == 0) continue;
3640
if ((var->type&VTYPE) != VSTRING) continue;
3641
if ((var->type&VISARRAY) == 0)
3643
pt = (char *)var->addr;
3644
us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3645
if (us_searchcircuittextstart < 0) continue;
3646
us_searchcircuittextend = us_searchcircuittextstart + strlen(search);
3649
us_clearhighlightcount();
3650
newhigh.status = HIGHTEXT;
3651
newhigh.facet = ni->parent;
3652
newhigh.fromgeom = ni->geom;
3653
newhigh.fromport = NOPORTPROTO;
3654
newhigh.frompoint = 0;
3655
newhigh.fromvar = var;
3656
newhigh.fromvarnoeval = NOVARIABLE;
3657
us_addhighlight(&newhigh);
3658
us_showallhighlight();
3659
us_endchanges(NOWINDOWPART);
3660
us_searchcircuittextfound = TRUE;
3664
len = getlength(var);
3665
for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
3667
pt = ((char **)var->addr)[us_searchcircuittextline];
3668
us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3669
if (us_searchcircuittextstart < 0) continue;
3670
us_searchcircuittextend = us_searchcircuittextstart + strlen(search);
3673
us_clearhighlightcount();
3674
newhigh.status = HIGHTEXT;
3675
newhigh.facet = ni->parent;
3676
newhigh.fromgeom = ni->geom;
3677
newhigh.fromport = NOPORTPROTO;
3678
newhigh.frompoint = 0;
3679
newhigh.fromvar = var;
3680
newhigh.fromvarnoeval = NOVARIABLE;
3681
us_addhighlight(&newhigh);
3682
us_showallhighlight();
3683
us_endchanges(NOWINDOWPART);
3684
us_searchcircuittextfound = TRUE;
3689
us_searchcircuittextni = ni->nextnodeinst;
3690
us_searchcircuittextvarnum = 0;
3693
/* look for an arc with this string */
3694
while (us_searchcircuittextai != NOARCINST)
3696
ai = us_searchcircuittextai;
3697
while (us_searchcircuittextvarnum < ai->numvar)
3699
var = &ai->firstvar[us_searchcircuittextvarnum];
3700
us_searchcircuittextvarnum++;
3701
if ((var->type&VDISPLAY) == 0) continue;
3702
if ((var->type&VTYPE) != VSTRING) continue;
3703
if ((var->type&VISARRAY) == 0)
3705
pt = (char *)var->addr;
3706
us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3707
if (us_searchcircuittextstart < 0) continue;
3708
us_searchcircuittextend = us_searchcircuittextstart + strlen(search);
3711
us_clearhighlightcount();
3712
newhigh.status = HIGHTEXT;
3713
newhigh.facet = ai->parent;
3714
newhigh.fromgeom = ai->geom;
3715
newhigh.fromport = NOPORTPROTO;
3716
newhigh.frompoint = 0;
3717
newhigh.fromvar = var;
3718
newhigh.fromvarnoeval = NOVARIABLE;
3719
us_addhighlight(&newhigh);
3720
us_showallhighlight();
3721
us_endchanges(NOWINDOWPART);
3722
us_searchcircuittextfound = TRUE;
3726
len = getlength(var);
3727
for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
3729
pt = ((char **)var->addr)[us_searchcircuittextline];
3730
us_searchcircuittextstart = us_stringinstring(pt, search, bits);
3731
if (us_searchcircuittextstart < 0) continue;
3732
us_searchcircuittextend = us_searchcircuittextstart + strlen(search);
3735
us_clearhighlightcount();
3736
newhigh.status = HIGHTEXT;
3737
newhigh.facet = ai->parent;
3738
newhigh.fromgeom = ai->geom;
3739
newhigh.fromport = NOPORTPROTO;
3740
newhigh.frompoint = 0;
3741
newhigh.fromvar = var;
3742
newhigh.fromvarnoeval = NOVARIABLE;
3743
us_addhighlight(&newhigh);
3744
us_showallhighlight();
3745
us_endchanges(NOWINDOWPART);
3746
us_searchcircuittextfound = TRUE;
3751
us_searchcircuittextai = ai->nextarcinst;
3752
us_searchcircuittextvarnum = 0;
3755
/* look for an export with this string */
3756
while (us_searchcircuittextpp != NOPORTPROTO)
3758
pp = us_searchcircuittextpp;
3759
us_searchcircuittextpp = pp->nextportproto;
3760
us_searchcircuittextstart = us_stringinstring(pp->protoname, search, bits);
3761
if (us_searchcircuittextstart < 0) continue;
3762
us_searchcircuittextend = us_searchcircuittextstart + strlen(search);
3765
us_clearhighlightcount();
3766
newhigh.status = HIGHTEXT;
3767
newhigh.facet = pp->parent;
3768
newhigh.fromgeom = pp->subnodeinst->geom;
3769
newhigh.fromport = pp;
3770
newhigh.frompoint = 0;
3771
newhigh.fromvar = NOVARIABLE;
3772
newhigh.fromvarnoeval = NOVARIABLE;
3773
us_addhighlight(&newhigh);
3774
us_showallhighlight();
3775
us_endchanges(NOWINDOWPART);
3776
us_searchcircuittextfound = TRUE;
3779
us_searchcircuittextfound = FALSE;
3783
* Routine to look for the substring "search" inside of the larger string "string".
3784
* if "bits" has 4 in it, the search is case sensitive. Returns the character
3785
* position in "string" of where "search" is found (-1 if not found).
3787
INTBIG us_stringinstring(char *string, char *search, INTBIG bits)
3789
REGISTER INTBIG stringlen, searchlen, searchwid, i;
3791
stringlen = strlen(string);
3792
searchlen = strlen(search);
3793
searchwid = stringlen - searchlen;
3794
if (searchwid < 0) return(-1);
3797
for(i=0; i<=searchwid; i++)
3798
if (namesamen(&string[i], search, searchlen) == 0) return(i);
3801
for(i=0; i<=searchwid; i++)
3802
if (strncmp(&string[i], search, searchlen) == 0) return(i);
3808
* Routine to find the string "search" in the circuit in window "win". "bits" is:
3809
* 2 replace all with "replaceall"
3812
void us_searchcircuittext(WINDOWPART *win, char *search, char *replaceall, INTBIG bits)
3814
REGISTER NODEPROTO *np;
3817
np = win->curnodeproto;
3818
if (np == NONODEPROTO) return;
3825
/* advance to the next circuit text */
3826
us_advancecircuittext(search, bits);
3827
if (!us_searchcircuittextfound) break;
3828
us_replacecircuittext(win, replaceall);
3831
if (!found) ttybeep(1);
3834
us_advancecircuittext(search, bits);
3835
if (!us_searchcircuittextfound) ttybeep(1);
3839
* Routine to replace the text last selected with "us_searchcircuittext()" with
3840
* the string "replace".
3842
void us_replacecircuittext(WINDOWPART *win, char *replace)
3844
REGISTER HIGHLIGHT *high;
3845
REGISTER INTBIG i, len, addr, type;
3846
REGISTER VARIABLE *var;
3847
REGISTER NODEINST *ni;
3848
REGISTER PORTPROTO *pp;
3851
if (!us_searchcircuittextfound) return;
3852
high = us_getonehighlight();
3853
if (high->status != HIGHTEXT) return;
3854
if (high->fromgeom->entryisnode && high->fromvar == NOVARIABLE)
3857
ni = high->fromgeom->entryaddr.ni;
3858
pp = high->fromport;
3860
for(i=0; i<us_searchcircuittextstart; i++)
3861
(void)addtoinfstr(pp->protoname[i]);
3862
(void)addstringtoinfstr(replace);
3863
len = strlen(pp->protoname);
3864
for(i=us_searchcircuittextend; i<len; i++)
3865
(void)addtoinfstr(pp->protoname[i]);
3867
us_clearhighlightcount();
3868
us_renameport(pp, returninfstr());
3869
us_pophighlight(FALSE);
3870
us_endchanges(NOWINDOWPART);
3874
/* rename variable */
3875
var = high->fromvar;
3876
if (var == NOVARIABLE) return;
3877
addr = (INTBIG)high->fromgeom->entryaddr.blind;
3878
if (high->fromgeom->entryisnode) type = VNODEINST; else
3881
us_clearhighlightcount();
3882
startobjectchange(addr, type);
3883
if ((var->type&VISARRAY) != 0)
3885
pt = ((char **)var->addr)[us_searchcircuittextline];
3887
for(i=0; i<us_searchcircuittextstart; i++)
3888
(void)addtoinfstr(pt[i]);
3889
(void)addstringtoinfstr(replace);
3891
for(i=us_searchcircuittextend; i<len; i++)
3892
(void)addtoinfstr(pt[i]);
3893
(void)setindkey(addr, type, var->key, us_searchcircuittextline,
3894
(INTBIG)returninfstr());
3897
pt = (char *)var->addr;
3899
for(i=0; i<us_searchcircuittextstart; i++)
3900
(void)addtoinfstr(pt[i]);
3901
(void)addstringtoinfstr(replace);
3903
for(i=us_searchcircuittextend; i<len; i++)
3904
(void)addtoinfstr(pt[i]);
3905
(void)setvalkey(addr, type, var->key, (INTBIG)returninfstr(),
3908
endobjectchange(addr, type);
3909
us_pophighlight(FALSE);
3910
us_endchanges(NOWINDOWPART);
3913
/************************ IN-PLACE VARIABLE EDITING ************************/
3915
static INTBIG us_editvarstartline, us_editvarstartchar;
3916
static INTBIG us_editvarlabellen;
3917
static INTBIG us_editvarendline, us_editvarendchar;
3918
static INTBIG us_editvarclickline, us_editvarclickchar;
3919
static VARIABLE *us_editvariable;
3920
static INTBIG us_editvarlength;
3921
static INTBIG us_editvarlineheight;
3922
static INTBIG us_editvarobjtype;
3923
static INTBIG us_editvarobjaddr;
3924
static BOOLEAN us_editvariabledoubleclick;
3925
static char **us_editvarlines;
3926
static char *us_editvaroneline[1];
3927
static char *us_editvarvarname = 0;
3928
static TECHNOLOGY *us_editvartech;
3930
static void us_editvariabletexthighlight(void);
3931
static BOOLEAN us_editvariabletexteachdown(INTBIG x, INTBIG y);
3932
static BOOLEAN us_editvariabletextfindpos(INTBIG x, INTBIG y, INTBIG *line, INTBIG *chr);
3933
static void us_editvariableforcefullwords(INTBIG *startline, INTBIG *startchar, INTBIG *endline, INTBIG *endchar);
3934
static BOOLEAN us_editvariabletexthandlebutton(INTBIG x, INTBIG y, INTBIG but);
3935
static BOOLEAN us_editvariabletexthandlechar(INTSML chr, INTBIG special);
3936
static void us_editvariabletextreplacetext(char *replace);
3938
void us_editvariabletext(VARIABLE *var, INTBIG objtype, INTBIG objaddr, char *varname)
3941
UINTBIG textdescript[TEXTDESCRIPTSIZE];
3943
/* preserve information in globals */
3944
us_editvariable = var;
3945
us_editvarobjtype = objtype & VTYPE;
3946
us_editvarobjaddr = objaddr;
3947
if (us_editvarvarname == 0) (void)allocstring(&us_editvarvarname, varname, us_tool->cluster); else
3948
(void)reallocstring(&us_editvarvarname, varname, us_tool->cluster);
3949
us_editvarlabellen = 0;
3950
if ((us_editvariable->type&VISARRAY) == 0)
3952
us_editvarlength = 1;
3953
(void)allocstring(&us_editvaroneline[0], describedisplayedvariable(var, -1, -1), us_tool->cluster);
3954
if (TDGETDISPPART(var->textdescript) != VTDISPLAYVALUE)
3956
TDCOPY(textdescript, var->textdescript);
3957
TDSETDISPPART(var->textdescript, VTDISPLAYVALUE);
3958
us_editvarlabellen = strlen(us_editvaroneline[0]) - strlen(describedisplayedvariable(var, -1, -1));
3959
TDCOPY(var->textdescript, textdescript);
3961
us_editvarlines = us_editvaroneline;
3964
us_editvarlength = getlength(var);
3965
us_editvarlines = (char **)var->addr;
3970
us_editvartech = ((NODEINST *)objaddr)->parent->tech;
3973
us_editvartech = ((ARCINST *)objaddr)->parent->tech;
3976
us_editvartech = ((PORTPROTO *)objaddr)->subnodeinst->parent->tech;
3979
us_editvartech = ((NODEPROTO *)objaddr)->tech;
3983
/* flush graphics */
3984
us_endchanges(NOWINDOWPART);
3986
/* determine height of a line of text */
3987
screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
3988
screengettextsize(el_curwindowpart, "Xy", &tsx, &tsy);
3989
us_editvarlineheight = tsy;
3991
/* set highlighting to cover all text */
3992
us_editvarstartline = 0;
3993
us_editvarstartchar = us_editvarlabellen;
3994
us_editvarendline = us_editvarlength-1;
3995
us_editvarendchar = strlen(us_editvarlines[us_editvarendline]);
3996
us_editvariabletexthighlight();
3998
/* loop while editing text */
3999
modalloop(us_editvariabletexthandlechar, us_editvariabletexthandlebutton, IBEAMCURSOR);
4001
/* remove highlighting */
4002
us_editvariabletexthighlight();
4005
static BOOLEAN us_editvariabletexthandlebutton(INTBIG x, INTBIG y, INTBIG but)
4009
us_editvariabledoubleclick = doublebutton(but);
4010
if (!us_editvariabletextfindpos(x, y, &line, &chr)) return(TRUE);
4011
us_editvariabletexthighlight();
4012
if (line == 0 && chr < us_editvarlabellen) chr = us_editvarlabellen;
4013
if (shiftbutton(but))
4015
if (line < us_editvarstartline || (line == us_editvarstartline &&
4016
chr < us_editvarstartchar))
4018
us_editvarstartline = line;
4019
us_editvarstartchar = chr;
4020
} else if (line > us_editvarendline || (line == us_editvarendline &&
4021
chr > us_editvarendchar))
4023
us_editvarendline = line;
4024
us_editvarendchar = chr;
4028
us_editvarstartline = line;
4029
us_editvarstartchar = chr;
4030
us_editvarendline = line;
4031
us_editvarendchar = chr;
4033
us_editvarclickline = line;
4034
us_editvarclickchar = chr;
4035
if (us_editvariabledoubleclick)
4036
us_editvariableforcefullwords(&us_editvarstartline, &us_editvarstartchar,
4037
&us_editvarendline, &us_editvarendchar);
4038
us_editvariabletexthighlight();
4040
trackcursor(FALSE, us_ignoreup, us_nullvoid, us_editvariabletexteachdown, us_stoponchar,
4041
us_nullvoid, TRACKNORMAL);
4045
BOOLEAN us_editvariabletexthandlechar(INTSML chr, INTBIG special)
4047
char replace[2], *pt;
4048
REGISTER INTBIG startchar, endchar, i, j;
4050
if ((special&SPECIALKEYDOWN) != 0)
4052
switch ((special&SPECIALKEY)>>SPECIALKEYSH)
4054
case SPECIALKEYARROWL:
4055
us_editvariabletexthighlight();
4056
if (us_editvarstartline == us_editvarendline &&
4057
us_editvarstartchar == us_editvarendchar)
4059
if (us_editvarstartchar > 0)
4061
if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4062
us_editvarstartchar--;
4065
if (us_editvarstartline > 0)
4067
us_editvarstartline--;
4068
us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4072
us_editvarendline = us_editvarstartline;
4073
us_editvarendchar = us_editvarstartchar;
4074
us_editvariabletexthighlight();
4076
case SPECIALKEYARROWR:
4077
us_editvariabletexthighlight();
4078
if (us_editvarstartline == us_editvarendline &&
4079
us_editvarstartchar == us_editvarendchar)
4081
if (us_editvarendchar < (INTBIG)strlen(us_editvarlines[us_editvarendline]))
4082
us_editvarendchar++; else
4084
if (us_editvarendline < us_editvarlength-1)
4086
us_editvarendline++;
4087
us_editvarendchar = 0;
4091
us_editvarstartline = us_editvarendline;
4092
us_editvarstartchar = us_editvarendchar;
4093
us_editvariabletexthighlight();
4095
case SPECIALKEYARROWU:
4096
us_editvariabletexthighlight();
4097
if (us_editvarstartline > 0)
4099
us_editvarstartline--;
4100
if (us_editvarstartchar > (INTBIG)strlen(us_editvarlines[us_editvarstartline]))
4101
us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4103
us_editvarendline = us_editvarstartline;
4104
us_editvarendchar = us_editvarstartchar;
4105
us_editvariabletexthighlight();
4107
case SPECIALKEYARROWD:
4108
us_editvariabletexthighlight();
4109
if (us_editvarendline < us_editvarlength-1)
4111
us_editvarendline++;
4112
if (us_editvarendchar > (INTBIG)strlen(us_editvarlines[us_editvarendline]))
4113
us_editvarendchar = strlen(us_editvarlines[us_editvarendline]);
4115
us_editvarstartline = us_editvarendline;
4116
us_editvarstartchar = us_editvarendchar;
4117
us_editvariabletexthighlight();
4123
if ((special&ACCELERATORDOWN) != 0)
4125
if (chr == 'v' || chr == 'V')
4127
pt = getcutbuffer();
4128
us_editvariabletexthighlight();
4129
us_editvariabletextreplacetext(pt);
4130
if ((us_editvariable->type&VISARRAY) == 0)
4132
(void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4134
us_editvarlines = us_editvaroneline;
4137
us_editvarlength = getlength(us_editvariable);
4138
us_editvarlines = (char **)us_editvariable->addr;
4140
us_editvariabletexthighlight();
4144
/* handle copy/cut */
4145
if (chr == 'c' || chr == 'C' ||
4146
chr == 'x' || chr == 'X')
4149
for(i=us_editvarstartline; i<=us_editvarendline; i++)
4151
if (i > us_editvarstartline) (void)addtoinfstr('\n');
4153
endchar = strlen(us_editvarlines[i]);
4154
if (i == us_editvarstartline) startchar = us_editvarstartchar;
4155
if (i == us_editvarendline) endchar = us_editvarendchar;
4156
for(j=startchar; j<endchar; j++)
4157
(void)addtoinfstr(us_editvarlines[i][j]);
4159
setcutbuffer(returninfstr());
4160
if (chr == 'c' || chr == 'C') return(FALSE);
4165
/* delete what is selected and insert what was typed */
4166
if (chr == '\n' || chr == '\r')
4168
/* cannot insert second line if text is not an array */
4169
if ((us_editvariable->type&VISARRAY) == 0) return(TRUE);
4171
us_editvariabletexthighlight();
4172
if (chr == DELETEKEY || chr == BACKSPACEKEY)
4175
if (us_editvarstartline == us_editvarendline &&
4176
us_editvarstartchar == us_editvarendchar)
4178
if (us_editvarstartchar > 0)
4180
if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4181
us_editvarstartchar--;
4184
if (us_editvarstartline > 0)
4186
us_editvarstartline--;
4187
us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4192
replace[0] = (char)chr;
4194
us_editvariabletextreplacetext(replace);
4195
if ((us_editvariable->type&VISARRAY) == 0)
4197
(void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4199
us_editvarlines = us_editvaroneline;
4202
us_editvarlength = getlength(us_editvariable);
4203
us_editvarlines = (char **)us_editvariable->addr;
4205
us_editvariabletexthighlight();
4209
void us_editvariabletextreplacetext(char *replace)
4212
REGISTER INTBIG i, newline, newchar;
4214
REGISTER VARIABLE *var;
4215
INTBIG newtype, newvalue, count;
4217
stringarray = newstringarray(el_tempcluster);
4219
/* add all lines before the start of selection */
4221
for(i=0; i<us_editvarstartline; i++)
4223
if (i != 0) addtostringarray(stringarray, us_editvarlines[i]); else
4224
addtostringarray(stringarray, &us_editvarlines[i][us_editvarlabellen]);
4228
/* build the line with the selection start */
4229
if (newline == 0) newchar = us_editvarlabellen; else newchar = 0;
4231
for(i=newchar; i<us_editvarstartchar; i++)
4233
(void)addtoinfstr(us_editvarlines[us_editvarstartline][i]);
4237
/* now add the replacement text */
4238
for(i=0; i<(INTBIG)strlen(replace); i++)
4240
if (replace[i] == '\n' || replace[i] == '\r')
4242
addtostringarray(stringarray, returninfstr());
4248
(void)addtoinfstr(replace[i]);
4253
/* now add the line with the selection end */
4254
for(i=us_editvarendchar; i<(INTBIG)strlen(us_editvarlines[us_editvarendline]); i++)
4255
(void)addtoinfstr(us_editvarlines[us_editvarendline][i]);
4256
addtostringarray(stringarray, returninfstr());
4258
/* add all lines after the end of selection */
4259
for(i=us_editvarendline+1; i<us_editvarlength; i++)
4260
addtostringarray(stringarray, us_editvarlines[i]);
4262
/* get the new text and put it on the object */
4263
newtext = getstringarray(stringarray, &count);
4264
if (us_editvarobjtype != VPORTPROTO)
4265
startobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4266
startobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4267
if (us_editvarobjtype == VNODEPROTO)
4268
us_undrawfacetvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4269
if ((us_editvariable->type&VISARRAY) == 0)
4271
getsimpletype(newtext[0], &newtype, &newvalue);
4272
newtype = (us_editvariable->type & ~VTYPE) | newtype;
4273
var = setval(us_editvarobjaddr, us_editvarobjtype,
4274
us_editvarvarname, newvalue, newtype);
4277
newtype = (us_editvariable->type & ~VLENGTH) | (count << VLENGTHSH);
4278
var = setval(us_editvarobjaddr, us_editvarobjtype,
4279
us_editvarvarname, (INTBIG)newtext, newtype);
4281
if (var != NOVARIABLE) us_editvariable = var;
4282
if (us_editvarobjtype == VNODEPROTO)
4283
us_drawfacetvariable(us_editvariable, (NODEPROTO *)us_editvarobjaddr);
4284
if (us_editvarobjtype != VPORTPROTO)
4285
endobjectchange(us_editvarobjaddr, us_editvarobjtype); else
4286
endobjectchange((INTBIG)(((PORTPROTO *)us_editvarobjaddr)->subnodeinst), VNODEINST);
4287
us_endchanges(NOWINDOWPART);
4288
killstringarray(stringarray);
4290
/* set the new selection point */
4291
us_editvarstartline = us_editvarendline = newline;
4292
us_editvarstartchar = us_editvarendchar = newchar;
4295
BOOLEAN us_editvariabletexteachdown(INTBIG x, INTBIG y)
4297
INTBIG line, chr, startline, startchar, endline, endchar;
4299
if (!us_editvariabletextfindpos(x, y, &line, &chr)) return(FALSE);
4300
if (line == 0 && chr < us_editvarlabellen) chr = us_editvarlabellen;
4301
startline = us_editvarstartline;
4302
startchar = us_editvarstartchar;
4303
endline = us_editvarendline;
4304
endchar = us_editvarendchar;
4305
if (line > us_editvarclickline || (line == us_editvarclickline && chr > us_editvarclickchar))
4307
startline = us_editvarclickline;
4308
startchar = us_editvarclickchar;
4311
if (us_editvariabledoubleclick)
4312
us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4314
if (line < us_editvarclickline || (line == us_editvarclickline && chr < us_editvarclickchar))
4318
endline = us_editvarclickline;
4319
endchar = us_editvarclickchar;
4320
if (us_editvariabledoubleclick)
4321
us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4323
if (startline != us_editvarstartline || startchar != us_editvarstartchar ||
4324
endline != us_editvarendline || endchar != us_editvarendchar)
4326
us_editvariabletexthighlight();
4327
us_editvarstartline = startline;
4328
us_editvarstartchar = startchar;
4329
us_editvarendline = endline;
4330
us_editvarendchar = endchar;
4331
us_editvariabletexthighlight();
4336
void us_editvariableforcefullwords(INTBIG *startline, INTBIG *startchar, INTBIG *endline, INTBIG *endchar)
4341
pt = us_editvarlines[*startline];
4342
while (*startchar > 0 && isalnum(pt[*startchar - 1]))
4345
pt = us_editvarlines[*endline];
4347
while (*endchar < len && isalnum(pt[*endchar]))
4351
BOOLEAN us_editvariabletextfindpos(INTBIG xp, INTBIG yp, INTBIG *line, INTBIG *chr)
4353
REGISTER INTBIG i, j, screenlx, screenhx, screenly, screenhy;
4357
REGISTER INTBIG lasttsx, charwid;
4359
/* determine text size */
4360
screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4361
for(i = 0; i < us_editvarlength; i++)
4363
getdisparrayvarlinepos(us_editvarobjaddr, us_editvarobjtype, us_editvartech,
4364
el_curwindowpart, us_editvariable, i, &x, &y, TRUE);
4365
screenlx = applyxscale(el_curwindowpart, x - el_curwindowpart->screenlx) +
4366
el_curwindowpart->uselx;
4367
screenly = applyyscale(el_curwindowpart, y - el_curwindowpart->screenly) +
4368
el_curwindowpart->usely;
4369
screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4370
screenhx = screenlx + tsx;
4371
screenhy = screenly + us_editvarlineheight;
4372
if (yp < screenly || yp > screenhy) continue;
4373
if (xp < screenlx-us_editvarlineheight ||
4374
xp > screenhx+us_editvarlineheight) continue;
4377
for(j=1; j<=(INTBIG)strlen(us_editvarlines[i]); j++)
4379
save = us_editvarlines[i][j];
4380
us_editvarlines[i][j] = 0;
4381
screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4382
charwid = tsx - lasttsx;
4384
us_editvarlines[i][j] = save;
4385
if (xp < screenlx + tsx - charwid/2) break;
4393
void us_editvariabletexthighlight(void)
4395
REGISTER INTBIG i, j, startch;
4397
INTBIG x, y, screenlx, screenhx, screenly, screenhy;
4400
/* determine text size */
4401
screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4402
for(i = us_editvarstartline; i <= us_editvarendline; i++)
4404
getdisparrayvarlinepos(us_editvarobjaddr, us_editvarobjtype, us_editvartech,
4405
el_curwindowpart, us_editvariable, i, &x, &y, TRUE);
4406
screenlx = applyxscale(el_curwindowpart, x - el_curwindowpart->screenlx) +
4407
el_curwindowpart->uselx;
4408
screenly = applyyscale(el_curwindowpart, y - el_curwindowpart->screenly) +
4409
el_curwindowpart->usely;
4411
if (i == us_editvarstartline && us_editvarstartchar != 0)
4413
save = us_editvarlines[i][us_editvarstartchar];
4414
us_editvarlines[i][us_editvarstartchar] = 0;
4415
screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4417
us_editvarlines[i][us_editvarstartchar] = save;
4418
startch = us_editvarstartchar;
4420
if (i == us_editvarendline) j = us_editvarendchar; else
4421
j = strlen(us_editvarlines[i]);
4422
save = us_editvarlines[i][j];
4423
us_editvarlines[i][j] = 0;
4424
screengettextsize(el_curwindowpart, &us_editvarlines[i][startch], &tsx, &tsy);
4425
screenhx = screenlx + tsx;
4426
us_editvarlines[i][j] = save;
4427
screenhy = screenly + us_editvarlineheight;
4428
if (screenlx <= el_curwindowpart->uselx) screenlx = el_curwindowpart->uselx+1;
4429
if (screenhx > el_curwindowpart->usehx) screenhx = el_curwindowpart->usehx;
4430
if (screenly < el_curwindowpart->usely) screenly = el_curwindowpart->usely;
4431
if (screenhy > el_curwindowpart->usehy) screenhy = el_curwindowpart->usehy;
4432
if ((el_curwindowpart->state&INPLACEEDIT) != 0)
4433
xformbox(&screenlx, &screenhx, &screenly, &screenhy, el_curwindowpart->outoffacet);
4434
screeninvertbox(el_curwindowpart, screenlx-1, screenhx-1,
4435
screenly, screenhy-1);
4439
/******************** USER-BROADCAST CHANGES ********************/
4442
* routine to allocate a new ubchange from the pool (if any) or memory,
4443
* fill in the "facet", "change", "x", and "y" fields, and link it to the
4444
* global list. Returns true on error.
4446
BOOLEAN us_newubchange(INTBIG change, void *object)
4448
REGISTER UBCHANGE *d;
4450
if (us_ubchangefree == NOUBCHANGE)
4452
d = (UBCHANGE *)emalloc((sizeof (UBCHANGE)), us_tool->cluster);
4453
if (d == 0) return(TRUE);
4456
/* take ubchange from free list */
4457
d = us_ubchangefree;
4458
us_ubchangefree = (UBCHANGE *)d->nextubchange;
4462
d->nextubchange = us_ubchanges;
4468
* routine to return ubchange "d" to the pool of free ubchanges
4470
void us_freeubchange(UBCHANGE *d)
4472
d->nextubchange = us_ubchangefree;
4473
us_ubchangefree = d;
4477
* routine to remove all queued user broadcast changes to facet "np"
4478
* because it was deleted
4480
void us_removeubchange(NODEPROTO *np)
4482
REGISTER UBCHANGE *d, *lastd, *nextd;
4483
REGISTER NODEPROTO *thisnp;
4486
for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4488
nextd = d->nextubchange;
4489
if (d->change == UBNEWFC) thisnp = ((NODEINST *)d->object)->parent; else
4490
thisnp = (NODEPROTO *)d->object;
4493
if (lastd == NOUBCHANGE) us_ubchanges = nextd; else
4494
lastd->nextubchange = nextd;
4503
* routine to remove variable "FACET_message" from facet "np".
4505
void us_delfacetmessage(NODEPROTO *np)
4507
(void)us_newubchange(UBKILLFM, np);
4511
* routine to add a facet-center to facet "np"
4513
void us_addfacetcenter(NODEINST *ni)
4515
(void)us_newubchange(UBNEWFC, ni);
4519
* routine to implement all user broadcast changes queued during the last broadcast
4521
void us_doubchanges(void)
4523
REGISTER UBCHANGE *d, *nextd;
4524
REGISTER WINDOWPART *w;
4525
REGISTER NODEPROTO *np;
4526
REGISTER NODEINST *ni, *oni;
4527
REGISTER EDITOR *ed;
4528
REGISTER VARIABLE *var;
4530
for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4532
nextd = d->nextubchange;
4536
case UBKILLFM: /* remove facet_message */
4537
np = (NODEPROTO *)d->object;
4538
for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4540
if (w->curnodeproto != np) continue;
4541
if ((w->state&WINDOWTYPE) != TEXTWINDOW) continue;
4543
/* see if the window still has a valid variable */
4545
if (ed->editobjvar == NOVARIABLE) continue;
4546
var = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
4547
if (var == NOVARIABLE)
4549
(void)newwindowpart(w->location, w);
4554
case UBNEWFC: /* added facet-center */
4555
ni = (NODEINST *)d->object;
4557
for(oni = np->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
4559
if (oni == ni) continue;
4560
if (oni->proto == gen_facetcenterprim)
4562
ttyputerr(_("Can only be one facet-center in a facet: new one deleted"));
4563
us_clearhighlightcount();
4564
startobjectchange((INTBIG)ni, VNODEINST);
4565
(void)killnodeinst(ni);
4566
us_setnodeprotocenter(oni->lowx, oni->lowy, np);
4570
if (oni == NONODEINST)
4571
us_setnodeprotocenter(ni->lowx, ni->lowy, np);
4578
us_ubchanges = NOUBCHANGE;
4581
/******************** COLOR ********************/
4584
* setup the color map for the graphics of technology "tech". "style" is:
4585
* COLORSEXISTING continue existing colors
4586
* COLORSDEFAULT use default nonoverlappable colors
4587
* COLORSBLACK use black background colors
4588
* COLORSWHITE use white background colors
4589
* A set of overlappable colors is obtained from technology "tech", combined
4590
* with the appropriate nonoverlappable colors, and set into the proper
4591
* variables on the "user" tool (and subsequently displayed).
4592
* The 256 entries are organized thusly:
4593
* Bit 0 is for highlighting; bit 1 is an escape for
4594
* opaque colors, the next 5 bits are the overlappable colors (if the opaque
4595
* escape is off) or the opaque value (if the bit is set).
4596
* The last bit is for the grid, although it may not appear if there are 128 entries.
4597
* This routine uses the database variable "USER_color_map" on the
4600
void us_getcolormap(TECHNOLOGY *tech, INTBIG style, BOOLEAN broadcast)
4602
static TECH_COLORMAP colmap[38] =
4604
{255,255,255}, /* 4(0004) WHITE: white */
4605
{ 0, 0, 0}, /* 12(0014) BLACK: black */
4606
{255, 0, 0}, /* 20(0024) RED: red */
4607
{ 0, 0,255}, /* 28(0034) BLUE: blue */
4608
{ 0,255, 0}, /* 36(0044) GREEN: green */
4609
{ 0,255,255}, /* 44(0054) CYAN: cyan */
4610
{255, 0,255}, /* 52(0064) MAGENTA: magenta */
4611
{255,255, 0}, /* 60(0074) YELLOW: yellow */
4612
{ 0, 0, 0}, /* 68(0104) FACETTXT: facet and port names */
4613
{ 0, 0, 0}, /* 76(0114) FACETOUT: facet outline */
4614
{ 0, 0, 0}, /* 84(0124) WINBOR: window border color */
4615
{ 0,255, 0}, /* 92(0134) HWINBOR: highlighted window border color */
4616
{ 0, 0, 0}, /* 100(0144) MENBOR: menu border color */
4617
{255,255,255}, /* 108(0154) HMENBOR: highlighted menu border color */
4618
{ 0, 0, 0}, /* 116(0164) MENTXT: menu text color */
4619
{ 0, 0, 0}, /* 124(0174) MENGLY: menu glyph color */
4620
{ 0, 0, 0}, /* 132(0204) CURSOR: cursor color */
4621
{180,180,180}, /* 140(0214) GRAY: gray */
4622
{255,190, 6}, /* 148(0224) ORANGE: orange */
4623
{186, 0,255}, /* 156(0234) PURPLE: purple */
4624
{139, 99, 46}, /* 164(0244) BROWN: brown */
4625
{230,230,230}, /* 172(0254) LGRAY: light gray */
4626
{100,100,100}, /* 180(0264) DGRAY: dark gray */
4627
{255,150,150}, /* 188(0274) LRED: light red */
4628
{159, 80, 80}, /* 196(0304) DRED: dark red */
4629
{175,255,175}, /* 204(0314) LGREEN: light green */
4630
{ 89,159, 85}, /* 212(0324) DGREEN: dark green */
4631
{150,150,255}, /* 220(0334) LBLUE: light blue */
4632
{ 2, 15,159}, /* 228(0344) DBLUE: dark blue */
4633
{ 0, 0, 0}, /* 236(0354) unassigned */
4634
{ 0, 0, 0}, /* 244(0364) unassigned */
4635
{ 0, 0, 0}, /* 252(0374) unassigned */
4636
{ 0, 0, 0}, /* grid */
4637
{255,255,255}, /* highlight */
4638
{255, 0, 0}, /* black background highlight */
4639
{255, 0, 0}, /* white background highlight */
4640
{255,255,255}, /* black background cursor */
4641
{ 0, 0, 0} /* white background cursor */
4643
static TECH_COLORMAP default_colmap[32] =
4644
{ /* overlap4 overlap3 overlap2 overlap1 overlap0 */
4645
{200,200,200}, /* 0: */
4646
{ 0, 0,200}, /* 1: overlap0 */
4647
{220, 0,120}, /* 2: overlap1 */
4648
{ 80, 0,160}, /* 3: overlap1+overlap0 */
4649
{ 70,250, 70}, /* 4: overlap2 */
4650
{ 0,140,140}, /* 5: overlap2+ overlap0 */
4651
{180,130, 0}, /* 6: overlap2+overlap1 */
4652
{ 55, 70,140}, /* 7: overlap2+overlap1+overlap0 */
4653
{250,250, 0}, /* 8: overlap3 */
4654
{ 85,105,160}, /* 9: overlap3+ overlap0 */
4655
{190, 80,100}, /* 10: overlap3+ overlap1 */
4656
{ 70, 50,150}, /* 11: overlap3+ overlap1+overlap0 */
4657
{ 80,210, 0}, /* 12: overlap3+overlap2 */
4658
{ 50,105,130}, /* 13: overlap3+overlap2+ overlap0 */
4659
{170,110, 0}, /* 14: overlap3+overlap2+overlap1 */
4660
{ 60, 60,130}, /* 15: overlap3+overlap2+overlap1+overlap0 */
4661
{180,180,180}, /* 16: overlap4+ */
4662
{ 0, 0,180}, /* 17: overlap4+ overlap0 */
4663
{200, 0,100}, /* 18: overlap4+ overlap1 */
4664
{ 60, 0,140}, /* 19: overlap4+ overlap1+overlap0 */
4665
{ 50,230, 50}, /* 20: overlap4+ overlap2 */
4666
{ 0,120,120}, /* 21: overlap4+ overlap2+ overlap0 */
4667
{160,110, 0}, /* 22: overlap4+ overlap2+overlap1 */
4668
{ 35, 50,120}, /* 23: overlap4+ overlap2+overlap1+overlap0 */
4669
{230,230, 0}, /* 24: overlap4+overlap3 */
4670
{ 65, 85,140}, /* 25: overlap4+overlap3+ overlap0 */
4671
{170, 60, 80}, /* 26: overlap4+overlap3+ overlap1 */
4672
{ 50, 30,130}, /* 27: overlap4+overlap3+ overlap1+overlap0 */
4673
{ 60,190, 0}, /* 28: overlap4+overlap3+overlap2 */
4674
{ 30, 85,110}, /* 29: overlap4+overlap3+overlap2+ overlap0 */
4675
{150, 90, 0}, /* 30: overlap4+overlap3+overlap2+overlap1 */
4676
{ 40, 40,110}, /* 31: overlap4+overlap3+overlap2+overlap1+overlap0 */
4679
TECH_COLORMAP *mapptr, *thisptr;
4681
REGISTER VARIABLE *var, *rvar, *gvar, *bvar;
4682
static INTBIG USER_color_map_key = 0;
4683
INTBIG red[256], green[256], blue[256];
4684
extern GRAPHICS us_gbox;
4686
/* get the technology's color information */
4687
if (USER_color_map_key == 0) USER_color_map_key = makekey("USER_color_map");
4688
var = getvalkey((INTBIG)tech, VTECHNOLOGY, VCHAR|VISARRAY, USER_color_map_key);
4689
if (var != NOVARIABLE) mapptr = (TECH_COLORMAP *)var->addr; else mapptr = 0;
4691
/* get existing color information */
4692
rvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
4693
gvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
4694
bvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
4696
/* must have some colors */
4697
if (rvar == NOVARIABLE && gvar == NOVARIABLE && bvar == NOVARIABLE && var == NOVARIABLE)
4699
mapptr = default_colmap;
4702
if (style == COLORSEXISTING)
4704
/* not resetting, get the old color values */
4705
for(i=0; i<256; i++)
4707
red[i] = ((INTBIG *)rvar->addr)[i];
4708
green[i] = ((INTBIG *)gvar->addr)[i];
4709
blue[i] = ((INTBIG *)bvar->addr)[i];
4710
if ((i&(LAYERH|LAYERG|LAYEROE)) != 0) continue;
4711
if (mapptr == 0) continue;
4712
if (i == 0) continue;
4713
thisptr = &mapptr[i>>2];
4714
red[i] = thisptr->red; green[i] = thisptr->green;
4715
blue[i] = thisptr->blue;
4720
/* update simulation window colors */
4725
sim_window_displaycolor(OFF_STRENGTH, BLUE);
4726
sim_window_displaycolor(NODE_STRENGTH, GREEN);
4727
sim_window_displaycolor(GATE_STRENGTH, MAGENTA);
4728
sim_window_displaycolor(VDD_STRENGTH, BLACK);
4729
sim_window_displaycolor(LOGIC_LOW, BLUE);
4730
sim_window_displaycolor(LOGIC_HIGH, MAGENTA);
4731
sim_window_displaycolor(LOGIC_X, BLACK);
4734
sim_window_displaycolor(OFF_STRENGTH, GREEN);
4735
sim_window_displaycolor(NODE_STRENGTH, CYAN);
4736
sim_window_displaycolor(GATE_STRENGTH, MAGENTA);
4737
sim_window_displaycolor(VDD_STRENGTH, LRED);
4738
sim_window_displaycolor(LOGIC_LOW, GREEN);
4739
sim_window_displaycolor(LOGIC_HIGH, MAGENTA);
4740
sim_window_displaycolor(LOGIC_X, LRED);
4745
/* resetting: load entirely new color map */
4746
for(i=0; i<256; i++)
4748
if ((i&LAYERH) != 0)
4752
case COLORSDEFAULT: thisptr = &colmap[33]; break; /* white */
4753
case COLORSBLACK: thisptr = &colmap[34]; break; /* red */
4754
case COLORSWHITE: thisptr = &colmap[35]; break; /* red */
4756
} else if ((i&LAYERG) != 0)
4760
case COLORSDEFAULT: thisptr = &colmap[32]; break; /* black */
4761
case COLORSBLACK: thisptr = &colmap[33]; break; /* white */
4762
case COLORSWHITE: thisptr = &colmap[32]; break; /* black */
4764
} else if ((i&LAYEROE) != 0)
4766
thisptr = &colmap[i>>2];
4768
if (i == HMENBOR) switch (style)
4770
case COLORSBLACK: thisptr = &colmap[2]; break; /* red */
4771
case COLORSWHITE: thisptr = &colmap[2]; break; /* red */
4773
if (i == CURSOR) switch (style)
4775
case COLORSDEFAULT: thisptr = &colmap[16]; break; /* default */
4776
case COLORSBLACK: thisptr = &colmap[36]; break; /* white */
4777
case COLORSWHITE: thisptr = &colmap[37]; break; /* black */
4780
/* reverse black and white when using black background */
4781
if (style == COLORSBLACK)
4791
case BLACK: thisptr = &colmap[33]; break; /* white */
4792
case WHITE: thisptr = &colmap[37]; break; /* black */
4797
if (rvar != NOVARIABLE) red[i] = ((INTBIG *)rvar->addr)[i];
4798
if (gvar != NOVARIABLE) green[i] = ((INTBIG *)gvar->addr)[i];
4799
if (bvar != NOVARIABLE) blue[i] = ((INTBIG *)bvar->addr)[i];
4800
if (mapptr != 0) thisptr = &mapptr[i>>2]; else thisptr = 0;
4801
if (i == ALLOFF) switch (style)
4803
case COLORSDEFAULT: thisptr = &default_colmap[0]; break; /* default */
4804
case COLORSBLACK: thisptr = &colmap[32]; break; /* black */
4805
case COLORSWHITE: thisptr = &colmap[33]; break; /* white */
4807
if (thisptr == 0) continue;
4809
red[i] = thisptr->red; green[i] = thisptr->green;
4810
blue[i] = thisptr->blue;
4813
/* also set the grid color appropriately if it doesn't have its own bitplane */
4814
if (el_maplength < 256)
4818
case COLORSDEFAULT: us_gbox.col = BLACK; break; /* black */
4819
case COLORSBLACK: us_gbox.col = WHITE; break; /* white */
4820
case COLORSWHITE: us_gbox.col = BLACK; break; /* black */
4825
/* set the color map */
4827
startobjectchange((INTBIG)us_tool, VTOOL);
4828
if (!broadcast) nextchangequiet();
4829
(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)red,
4830
VINTEGER|VISARRAY|(256<<VLENGTHSH));
4831
if (!broadcast) nextchangequiet();
4832
(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)green,
4833
VINTEGER|VISARRAY|(256<<VLENGTHSH));
4834
if (!broadcast) nextchangequiet();
4835
(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)blue,
4836
VINTEGER|VISARRAY|(256<<VLENGTHSH));
4838
endobjectchange((INTBIG)us_tool, VTOOL);
4842
* routine to load entry "entry" of the global color map entries with the value
4843
* (red, green, blue), letter "letter". Handles highlight and grid layers
4844
* right if "spread" is true.
4846
void us_setcolorentry(INTBIG entry1, INTBIG red, INTBIG green, INTBIG blue, INTBIG letter,
4851
startobjectchange((INTBIG)us_tool, VTOOL);
4852
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, entry1, red);
4853
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, entry1, green);
4854
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, entry1, blue);
4856
/* place in other entries if special */
4857
if ((entry1&LAYERH) == LAYERH && spread)
4859
/* set all highlight colors */
4860
for(j=0; j<256; j++) if ((j&LAYERH) == LAYERH)
4862
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, j, red);
4863
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, j, green);
4864
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, j, blue);
4866
} else if ((entry1&(LAYERG|LAYERH)) == LAYERG && spread)
4868
/* set all grid colors */
4869
for(j=0; j<256; j++) if ((j&(LAYERG|LAYERH)) == LAYERG)
4871
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, j, red);
4872
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, j, green);
4873
(void)setindkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, j, blue);
4876
endobjectchange((INTBIG)us_tool, VTOOL);
4880
* routine to convert a red/green/blue color in (ir,ig,ib) to a hue/saturation/
4881
* intensity color in (h,s,i)
4883
void us_rgbtohsv(INTBIG ir, INTBIG ig, INTBIG ib, float *h, float *s, float *i)
4885
float x, r, g, b, rdot, gdot, bdot;
4891
/* "i" is maximum of "r", "g", and "b" */
4892
if (r > g) *i = r; else *i = g;
4895
/* "x" is minimum of "r", "g", and "b" */
4896
if (r < g) x = r; else x = g;
4899
/* "saturation" is (i-x)/i */
4900
if (*i == 0.0) *s = 0.0; else *s = (*i - x) / *i;
4902
if (*s == 0.0) *h = 0.0; else
4904
rdot = (*i - r) / (*i - x);
4905
gdot = (*i - g) / (*i - x);
4906
bdot = (*i - b) / (*i - x);
4907
if (b == x && r == *i) *h = (1.0f - gdot) / 6.0f; else
4908
if (b == x && g == *i) *h = (1.0f + rdot) / 6.0f; else
4909
if (r == x && g == *i) *h = (3.0f - bdot) / 6.0f; else
4910
if (r == x && b == *i) *h = (3.0f + gdot) / 6.0f; else
4911
if (g == x && b == *i) *h = (5.0f - rdot) / 6.0f; else
4912
if (g == x && r == *i) *h = (5.0f + bdot) / 6.0f; else
4913
ttyputmsg(_("Cannot convert (%ld,%ld,%ld), for x=%g i=%g s=%g"), ir, ig, ib, x, *i, *s);
4918
* routine to convert a hue/saturation/intensity color in (h,s,v) to a red/
4919
* green/blue color in (r,g,b)
4921
void us_hsvtorgb(float h, float s, float v, INTBIG *r, INTBIG *g, INTBIG *b)
4924
REGISTER float f, m, n, k;
4930
n = v * (1.0f - s * f);
4931
k = v * (1.0f - s * (1.0f - f));
4935
*r = (INTBIG)(v*255.0); *g = (INTBIG)(k*255.0); *b = (INTBIG)(m*255.0);
4938
*r = (INTBIG)(n*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(m*255.0);
4941
*r = (INTBIG)(m*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(k*255.0);
4944
*r = (INTBIG)(m*255.0); *g = (INTBIG)(n*255.0); *b = (INTBIG)(v*255.0);
4947
*r = (INTBIG)(k*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(v*255.0);
4950
*r = (INTBIG)(v*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(n*255.0);
4953
if (*r < 0 || *r > 255 || *g < 0 || *g > 255 || *b < 0 || *b > 255)
4954
ttyputmsg("(%g,%g,%g) -> (%ld,%ld,%ld) (i=%ld)",h, s, v, *r, *g, *b, i);
4957
/******************** MISCELLANEOUS ********************/
4960
* Routine to determine the offset of the "length" and "width" attributes on
4961
* node "ni" given that it uses a text descriptor of "descript".
4963
void us_getlenwidoffset(NODEINST *ni, UINTBIG *descript, INTBIG *xoff, INTBIG *yoff)
4968
i = TXTGETQLAMBDA(TDGETSIZE(descript));
4969
if (i > 4) i /= 2; else i = 2;
4970
switch (ni->rotation)
4973
if (ni->transpose == 0) *yoff = i; else
4977
if (ni->transpose == 0) *xoff = i; else
4981
if (ni->transpose == 0) *yoff = -i; else
4985
if (ni->transpose == 0) *xoff = -i; else
4992
* Routine to return the placement angle to use for node "np".
4994
INTBIG us_getplacementangle(NODEPROTO *np)
4996
REGISTER VARIABLE *var;
4998
var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle_key);
4999
if (var != NOVARIABLE) return(var->addr);
5000
var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_placement_angle_key);
5001
if (var != NOVARIABLE) return(var->addr);
5006
* Routine to get the "displayed" location of node "ni" and return it in
5009
void us_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos)
5011
REGISTER NODEPROTO *np;
5012
INTBIG cox, coy, plx, ply, phx, phy;
5013
REGISTER INTBIG dx, dy;
5014
REGISTER VARIABLE *var;
5018
if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
5020
corneroffset(ni, np, ni->rotation, ni->transpose, &cox, &coy, FALSE);
5021
*xpos = ni->lowx+cox;
5022
*ypos = ni->lowy+coy;
5025
var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
5026
if (var != NOVARIABLE)
5028
dx = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
5029
(np->lowx+np->highx)/2;
5030
dy = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
5031
(np->lowy+np->highy)/2;
5033
xform(dx, dy, &cox, &coy, trans);
5038
nodesizeoffset(ni, &plx, &ply, &phx, &phy);
5040
dx = (ni->lowx+plx+ni->highx-phx)/2;
5041
dy = (ni->lowy+ply+ni->highy-phy)/2;
5042
xform(dx, dy, xpos, ypos, trans);
5048
* routine to put facet center (x, y) on facet "np".
5050
void us_setnodeprotocenter(INTBIG x, INTBIG y, NODEPROTO *np)
5054
position[0] = x; position[1] = y;
5056
(void)setvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key,
5057
(INTBIG)position, VINTEGER|VISARRAY|(2<<VLENGTHSH));
5061
* routine to remove facet center from facet "np".
5063
void us_delnodeprotocenter(NODEPROTO *np)
5066
(void)delvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key);
5069
void us_getlowleft(NODEINST *ni, INTBIG *x, INTBIG *y)
5071
INTBIG lx, ly, hx, hy;
5073
static POLYGON *poly = NOPOLYGON;
5075
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
5077
nodesizeoffset(ni, &lx, &ly, &hx, &hy);
5078
maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, poly);
5079
if (ni->rotation != 0 || ni->transpose != 0)
5082
xformpoly(poly, trans);
5084
getbbox(poly, x, &hx, y, &hy);
5088
* routine to modify the text descriptor in the highlighted object "high"
5090
void us_modifytextdescript(HIGHLIGHT *high, UINTBIG *descript)
5092
REGISTER VARIABLE *var;
5094
if (high->fromvar != NOVARIABLE)
5096
var = high->fromvar;
5097
if (high->fromvarnoeval != NOVARIABLE) var = high->fromvarnoeval;
5098
if (TDDIFF(descript, var->textdescript))
5100
if (high->fromport != NOPORTPROTO)
5102
modifydescript((INTBIG)high->fromport, VPORTPROTO, high->fromvar, descript);
5103
} else if (high->fromgeom == NOGEOM)
5105
modifydescript((INTBIG)high->facet, VNODEPROTO, var, descript);
5108
modifydescript((INTBIG)high->fromgeom->entryaddr.blind,
5109
high->fromgeom->entryisnode ? VNODEINST : VARCINST, var, descript);
5114
if (high->fromport != NOPORTPROTO)
5116
(void)setind((INTBIG)high->fromport, VPORTPROTO, "textdescript", 0, descript[0]);
5117
(void)setind((INTBIG)high->fromport, VPORTPROTO, "textdescript", 1, descript[1]);
5120
if (high->fromgeom->entryisnode)
5122
(void)setind((INTBIG)high->fromgeom->entryaddr.ni, VNODEINST,
5123
"textdescript", 0, descript[0]);
5124
(void)setind((INTBIG)high->fromgeom->entryaddr.ni, VNODEINST,
5125
"textdescript", 1, descript[1]);
5131
* Routine to adjust the popup menu stored on the user interface object to correspond
5132
* to changes made to entry "pindex" of memory-structure popup "pm".
5134
void us_adjustpopupmenu(POPUPMENU *pm, INTBIG pindex)
5136
char **lines, *popupname;
5139
COMMANDBINDING commandbinding;
5142
(void)addstringtoinfstr("USER_binding_popup_");
5143
(void)addstringtoinfstr(pm->name);
5144
popupname = returninfstr();
5145
var = getval((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, popupname);
5146
if (var != NOVARIABLE)
5148
lines = (char **)var->addr;
5149
us_parsebinding(lines[pindex+1], &commandbinding);
5151
for(pt = lines[pindex+1]; *pt != 0; pt++)
5153
if (strncmp(pt, "message=\"", 9) == 0)
5155
(void)addstringtoinfstr("message=\"");
5157
while (*pt != 0 && *pt != '"') pt++;
5158
(void)addstringtoinfstr(pm->list[pindex].attribute);
5160
(void)addtoinfstr(*pt);
5163
(void)setind((INTBIG)us_tool, VTOOL, popupname, pindex+1, (INTBIG)returninfstr());
5164
us_freebindingparse(&commandbinding);
5169
* Routine to return true if "name" is legal for objects of type "type".
5171
BOOLEAN us_validname(char *name, INTBIG type)
5175
for(pt = name; *pt != 0; pt++)
5177
if (*pt == ' ' || *pt == '\t')
5179
ttyputerr(_("Name cannot have embedded spaces"));
5182
if (*pt < ' ' || *pt >= 0177)
5184
ttyputerr(_("Name has unprintable characters"));
5187
if (type == VNODEPROTO || type == VCELL)
5189
if (*pt == ':' || *pt == ';' || *pt == '{')
5191
ttyputerr(_("Name cannot have '%c' in it"), *pt);
5195
if (type == VARCPROTO || type == VTECHNOLOGY || type == VLIBRARY)
5199
ttyputerr(_("Name cannot have '%c' in it"), *pt);
5208
* Helper routine to determine the proper "address" field to use from variable "var".
5209
* Normally, it is simply "var->addr", but if it is a string with the "++" or "--"
5210
* sequence in it, then it auto-increments/decrements a numeric value, and so the
5211
* "++"/"--" are removed, and the original variable (which resides on "addr"/"type")
5214
INTBIG us_inheritaddress(INTBIG addr, INTBIG type, VARIABLE *var)
5218
REGISTER INTBIG i, j, len, incrpoint, retval, curval;
5220
/* if it isn't a string, just return its address */
5221
if ((var->type & VTYPE) != VSTRING) return(var->addr);
5222
if ((var->type & VISARRAY) != 0) return(var->addr);
5224
str = (char *)var->addr;
5226
for(i=0; i<len; i++)
5228
if (str[i] == '+' && str[i+1] == '+') break;
5229
if (str[i] == '-' && str[i+1] == '-') break;
5231
if (i >= len) return(var->addr);
5233
/* construct the proper inherited string and increment the variable */
5235
for(i=0; i<len; i++)
5237
if (str[i] == '+' && str[i+1] == '+')
5243
if (str[i] == '-' && str[i+1] == '-')
5249
(void)addtoinfstr(str[i]);
5252
/* get the new value */
5253
retval = (INTBIG)returninfstr();
5255
/* increment the variable */
5256
for(i = incrpoint-1; i>0; i--)
5257
if (!isdigit(str[i])) break;
5260
curval = myatoi(&str[i]);
5261
str[incrpoint] = str[incrpoint+1];
5262
if (str[incrpoint] == '+') curval++; else curval--;
5265
(void)addtoinfstr(str[j]);
5266
sprintf(line, "%ld", curval);
5267
(void)addstringtoinfstr(line);
5268
(void)addstringtoinfstr(&str[incrpoint]);
5269
(void)setval(addr, type, makename(var->key), (INTBIG)returninfstr(), var->type);
5275
* Routine to inherit all prototype attributes down to instance "ni".
5277
void us_inheritattributes(NODEINST *ni)
5279
REGISTER NODEPROTO *np, *cnp;
5280
REGISTER NODEINST *icon;
5282
REGISTER VARIABLE *var;
5283
REGISTER PORTPROTO *pp, *cpp;
5285
/* first inherit directly from this node's prototype */
5287
for(i=0; i<np->numvar; i++)
5289
var = &np->firstvar[i];
5290
if (TDGETINHERIT(var->textdescript) == 0) continue;
5291
us_inheritfacetattribute(var, ni, np, NONODEINST);
5294
/* inherit directly from each port's prototype */
5295
for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5296
us_inheritexportattributes(pp, ni, np);
5298
/* if this node is an icon, also inherit from the contents prototype */
5299
cnp = contentsview(np);
5300
if (cnp != NONODEPROTO)
5302
/* look for an example of the icon in the contents */
5303
for(icon = cnp->firstnodeinst; icon != NONODEINST; icon = icon->nextnodeinst)
5304
if (icon->proto == np) break;
5306
for(i=0; i<cnp->numvar; i++)
5308
var = &cnp->firstvar[i];
5309
if (TDGETINHERIT(var->textdescript) == 0) continue;
5310
us_inheritfacetattribute(var, ni, cnp, icon);
5312
for(cpp = cnp->firstportproto; cpp != NOPORTPROTO; cpp = cpp->nextportproto)
5313
us_inheritexportattributes(cpp, ni, cnp);
5318
* Routine to add all inheritable export variables from export "pp" on facet "np"
5321
void us_inheritexportattributes(PORTPROTO *pp, NODEINST *ni, NODEPROTO *np)
5323
REGISTER INTSML saverot, savetrn;
5324
REGISTER INTBIG i, dx, dy, lambda, style;
5326
UINTBIG descript[TEXTDESCRIPTSIZE];
5327
REGISTER VARIABLE *var, *newvar;
5328
REGISTER char *pt, *attrname;
5331
for(i=0; i<pp->numvar; i++)
5333
var = &pp->firstvar[i];
5334
if (TDGETINHERIT(var->textdescript) == 0) continue;
5336
(void)addstringtoinfstr("ATTRP_");
5337
(void)addstringtoinfstr(pp->protoname);
5338
(void)addstringtoinfstr("_");
5339
pt = makename(var->key);
5340
(void)addstringtoinfstr(&pt[5]);
5341
attrname = returninfstr();
5343
/* see if the attribute is already there */
5344
newvar = getval((INTBIG)ni, VNODEINST, -1, attrname);
5345
if (newvar != NOVARIABLE) continue;
5347
/* set the attribute */
5348
startobjectchange((INTBIG)ni, VNODEINST);
5349
newvar = setval((INTBIG)ni, VNODEINST, attrname,
5350
us_inheritaddress((INTBIG)pp, VPORTPROTO, var), var->type);
5351
if (newvar != NOVARIABLE)
5353
lambda = lambdaofnode(ni);
5354
TDCOPY(descript, var->textdescript);
5355
dx = TDGETXOFF(descript);
5356
dx = dx * lambda / 4;
5357
dy = TDGETYOFF(descript);
5358
dy = dy * lambda / 4;
5360
saverot = pp->subnodeinst->rotation;
5361
savetrn = pp->subnodeinst->transpose;
5362
pp->subnodeinst->rotation = pp->subnodeinst->transpose = 0;
5363
portposition(pp->subnodeinst, pp->subportproto, &x, &y);
5364
pp->subnodeinst->rotation = saverot;
5365
pp->subnodeinst->transpose = savetrn;
5367
makerot(pp->subnodeinst, trans);
5368
xform(x, y, &x, &y, trans);
5369
maketrans(ni, trans);
5370
xform(x, y, &x, &y, trans);
5372
xform(x, y, &x, &y, trans);
5373
x = x - (ni->lowx + ni->highx) / 2;
5374
y = y - (ni->lowy + ni->highy) / 2;
5375
switch (TDGETPOS(descript))
5377
case VTPOSCENT: style = TEXTCENT; break;
5378
case VTPOSBOXED: style = TEXTBOX; break;
5379
case VTPOSUP: style = TEXTBOT; break;
5380
case VTPOSDOWN: style = TEXTTOP; break;
5381
case VTPOSLEFT: style = TEXTRIGHT; break;
5382
case VTPOSRIGHT: style = TEXTLEFT; break;
5383
case VTPOSUPLEFT: style = TEXTBOTRIGHT; break;
5384
case VTPOSUPRIGHT: style = TEXTBOTLEFT; break;
5385
case VTPOSDOWNLEFT: style = TEXTTOPRIGHT; break;
5386
case VTPOSDOWNRIGHT: style = TEXTTOPLEFT; break;
5388
makerot(pp->subnodeinst, trans);
5389
style = rotatelabel(style, TDGETROTATION(descript), trans);
5392
case TEXTCENT: TDSETPOS(descript, VTPOSCENT); break;
5393
case TEXTBOX: TDSETPOS(descript, VTPOSBOXED); break;
5394
case TEXTBOT: TDSETPOS(descript, VTPOSUP); break;
5395
case TEXTTOP: TDSETPOS(descript, VTPOSDOWN); break;
5396
case TEXTRIGHT: TDSETPOS(descript, VTPOSLEFT); break;
5397
case TEXTLEFT: TDSETPOS(descript, VTPOSRIGHT); break;
5398
case TEXTBOTRIGHT: TDSETPOS(descript, VTPOSUPLEFT); break;
5399
case TEXTBOTLEFT: TDSETPOS(descript, VTPOSUPRIGHT); break;
5400
case TEXTTOPRIGHT: TDSETPOS(descript, VTPOSDOWNLEFT); break;
5401
case TEXTTOPLEFT: TDSETPOS(descript, VTPOSDOWNRIGHT); break;
5405
TDSETOFF(descript, x, y);
5406
TDSETINHERIT(descript, 0);
5407
TDCOPY(newvar->textdescript, descript);
5409
endobjectchange((INTBIG)ni, VNODEINST);
5414
* Routine to add inheritable variable "var" from facet "np" to instance "ni".
5415
* If "icon" is not NONODEINST, use the position of the variable from it.
5417
void us_inheritfacetattribute(VARIABLE *var, NODEINST *ni, NODEPROTO *np, NODEINST *icon)
5419
REGISTER VARIABLE *newvar, *ivar, *posvar;
5420
REGISTER INTBIG xc, yc, lambda, i;
5422
/* see if the attribute is already there */
5423
newvar = getvalkey((INTBIG)ni, VNODEINST, -1, var->key);
5424
if (newvar != NOVARIABLE) return;
5426
/* determine offset of the attribute on the instance */
5428
if (icon != NONODEINST)
5430
for(i=0; i<icon->numvar; i++)
5432
ivar = &icon->firstvar[i];
5433
if (ivar->key == var->key) break;
5435
if (i < icon->numvar) posvar = ivar;
5438
lambda = np->cell->lib->lambda[np->tech->techindex];
5439
xc = TDGETXOFF(posvar->textdescript) * lambda / 4;
5440
if (posvar == var) xc -= (np->lowx + np->highx) / 2;
5441
yc = TDGETYOFF(posvar->textdescript) * lambda / 4;
5442
if (posvar == var) yc -= (np->lowy + np->highy) / 2;
5443
lambda = lambdaofnode(ni);
5444
xc = xc * 4 / lambda;
5445
yc = yc * 4 / lambda;
5447
/* set the attribute */
5448
startobjectchange((INTBIG)ni, VNODEINST);
5449
newvar = setvalkey((INTBIG)ni, VNODEINST, var->key,
5450
us_inheritaddress((INTBIG)np, VNODEPROTO, var), var->type);
5451
if (newvar != NOVARIABLE)
5453
defaulttextsize(3, newvar->textdescript);
5454
TDCOPY(newvar->textdescript, posvar->textdescript);
5455
TDSETINHERIT(newvar->textdescript, 0);
5456
TDSETOFF(newvar->textdescript, xc, yc);
5457
if (TDGETISPARAM(var->textdescript) != 0)
5459
TDSETINTERIOR(newvar->textdescript, VTINTERIOR);
5460
TDSETDISPPART(newvar->textdescript, VTDISPLAYNAMEVALUE);
5463
endobjectchange((INTBIG)ni, VNODEINST);
5467
* Routine to add a parameter attribute to node "ni". The variable key is "key",
5468
* the new value is "addr", and the type is "type".
5470
void us_addparameter(NODEINST *ni, INTBIG key, INTBIG addr, INTBIG type, UINTBIG *descript)
5472
REGISTER VARIABLE *var;
5475
us_getnewparameterpos((INTBIG)ni, VNODEINST, &xoff, &yoff);
5476
startobjectchange((INTBIG)ni, VNODEINST);
5477
var = setvalkey((INTBIG)ni, VNODEINST, key, addr, type|VDISPLAY);
5478
if (var != NOVARIABLE)
5480
defaulttextsize(3, var->textdescript);
5481
TDSETISPARAM(var->textdescript, VTISPARAMETER);
5482
TDSETINTERIOR(var->textdescript, VTINTERIOR);
5483
TDSETDISPPART(var->textdescript, VTDISPLAYNAMEVALUE);
5484
TDSETOFF(var->textdescript, xoff, yoff);
5486
endobjectchange((INTBIG)ni, VNODEINST);
5490
* Routine to determine the location of a new parameter on object "addr" of type "type".
5491
* The parameter offset is stored in (xoff, yoff).
5493
void us_getnewparameterpos(INTBIG addr, INTBIG type, INTBIG *xoff, INTBIG *yoff)
5495
REGISTER NODEINST *ni;
5496
REGISTER NODEPROTO *np;
5497
REGISTER INTBIG i, numvar, count, xsum, yval, lowy, highy;
5498
REGISTER VARIABLE *firstvar, *var;
5503
ni = (NODEINST *)addr;
5504
numvar = ni->numvar;
5505
firstvar = ni->firstvar;
5508
np = (NODEPROTO *)addr;
5509
numvar = np->numvar;
5510
firstvar = np->firstvar;
5514
for(i=0; i<numvar; i++)
5517
if (TDGETISPARAM(var->textdescript) == 0) continue;
5518
xsum += TDGETXOFF(var->textdescript);
5519
yval = TDGETYOFF(var->textdescript);
5520
if (count == 0) lowy = highy = yval; else
5522
if (yval < lowy) lowy = yval;
5523
if (yval > highy) highy = yval;
5527
if (count == 0) *xoff = *yoff = 0; else
5529
*xoff = xsum / count;
5530
if (count == 1) *yoff = lowy - 4; else
5531
*yoff = lowy - (highy - lowy) / (count-1);