~ubuntu-branches/ubuntu/utopic/electric/utopic-proposed

« back to all changes in this revision

Viewing changes to src/usr/usrmisc.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2008-07-23 02:09:53 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080723020953-1gmnv7q2wpsdbnop
Tags: 8.07-0ubuntu1
* New Upstream version. Please check changelog for details. (LP: #242720)
* debian/control
  - Add build dependencies *-jdk, cdbs and bsh.
  - Remove build dependency dpatch. We will be using CDBS simple patchsys.
  - Refreshed runtime dependencies to default-jre | java2-runtime and bsh.
  - Added home page field.
  - Standard version 3.8.0.
  - Modify Maintainer value to match the DebianMaintainerField
    specification.
  - Changed email address for original maintainer to indicate who has
    refreshed the packaging.
* debian/rules
  - Revamped to use cdbs.
  - Added get-orig-source target.
* debian/patches
  - 00list, 02_sensible-browser.dpatch, 01_errors-numbers.dpatch,
    03_manpage.dpatch - Deleted, not relevant anymore.
  - 01_fix_build_xml.patch - Patch to fix the build.xml.
* debian/ant.properties
  - File to set various compilation properties.
* debian/electric.1
  - Remove the entry that causes lintian warning.
* debian/electric.desktop
  - Change as suggested by desktop-file-validate.
* debian/electric.docs
  - Updated as per changes in file names.
* debian/electric.svg
  - Name changed from electric_icon.svg.
* debian/install
  - Added appropriate locations for jar file, desktop file and wrapper shell
    script.
* debian/README.source
  - Added to comply with standards version 3.8.0.
* debian/TODO.Debian
  - Name changed form TODO.
* debain/wrapper/electric
  - Wrapper shell script to launch the application.
* debian/manpages
  - Added for installation of manpage.
* debian/watch
  - Updated to match jar files instead of older tar.gz files.
* debian/dirs
  - Removed, not needed anymore.
* debian/{electric.doc-base, electric.examples, substvars}
  - Removed, not relevant anymore.
* debian/*.debhelper
  - Removed auto generated files. Not relevant anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Electric(tm) VLSI Design System
3
 
 *
4
 
 * File: usrmisc.c
5
 
 * User interface tool: miscellaneous control
6
 
 * Written by: Steven M. Rubin, Static Free Software
7
 
 *
8
 
 * Copyright (c) 2000 Static Free Software.
9
 
 *
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.
14
 
 *
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.
19
 
 *
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.
24
 
 *
25
 
 * Static Free Software
26
 
 * 4119 Alpine Road
27
 
 * Portola Valley, California 94028
28
 
 * info@staticfreesoft.com
29
 
 */
30
 
 
31
 
#include "global.h"
32
 
#include "egraphics.h"
33
 
#include "efunction.h"
34
 
#include "usr.h"
35
 
#include "usreditemacs.h"
36
 
#include "usreditpac.h"
37
 
#include "usrtrack.h"
38
 
#include "tecgen.h"
39
 
#include "tecart.h"
40
 
#include "sim.h"
41
 
#include <math.h>
42
 
 
43
 
#define ALLTEXTWIDTH    70              /* width of side menu when it is all text */
44
 
 
45
 
/******************** INITIALIZATION ********************/
46
 
 
47
 
#define INITIALMENUX    18      /* default height of component menu */
48
 
#define INITIALMENUY    2       /* default width of component menu */
49
 
 
50
 
/*
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.
59
 
 */
60
 
typedef struct
61
 
{
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 */
68
 
} INITBUTTONS;
69
 
 
70
 
static INITBUTTONS us_initialbutton[] =
71
 
{
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},
76
 
 
77
 
        /* on four-button puck, add one more basic command */
78
 
        {{"GREEN","",""},          "o", "find",    2, {"another",       "port"},       FALSE},
79
 
 
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 */
85
 
};
86
 
 
87
 
/*
88
 
 * default keyboard state: the table below shows the set of commands
89
 
 * that will be bound to the keyboard keys.
90
 
 */
91
 
typedef struct
92
 
{
93
 
        char  *key;
94
 
        char  *command;
95
 
        INTBIG count;
96
 
        char  *args[2];
97
 
} INITKEYS;
98
 
 
99
 
static INITKEYS us_initialkeyboard[] =
100
 
{
101
 
#if 0
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",    ""}},
145
 
#endif
146
 
        {"-",    "telltool",  1, {"user",           ""}},
147
 
        {NULL, NULL, 0, {NULL, NULL}} /* 0 */
148
 
};
149
 
 
150
 
/*
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
155
 
 */
156
 
#define NOUBCHANGE ((UBCHANGE *)-1)
157
 
#define UBKILLFM     1          /* remove facet_message variable */
158
 
#define UBNEWFC      2          /* add facet-center */
159
 
 
160
 
typedef struct Iubchange
161
 
{
162
 
        INTBIG     change;              /* type of change */
163
 
        void      *object;              /* object that is being changed */
164
 
        struct Iubchange *nextubchange;
165
 
} UBCHANGE;
166
 
static UBCHANGE *us_ubchangefree = NOUBCHANGE;
167
 
static UBCHANGE *us_ubchanges = NOUBCHANGE;
168
 
 
169
 
static NODEPROTO *us_layouttextprim;
170
 
 
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);
187
 
 
188
 
/*
189
 
 * Routine to free all memory associated with this module.
190
 
 */
191
 
void us_freemiscmemory(void)
192
 
{
193
 
}
194
 
 
195
 
/*
196
 
 * initialization routine to bind keys and buttons to functions
197
 
 * returns true upon error
198
 
 */
199
 
BOOLEAN us_initialbinding(void)
200
 
{
201
 
        REGISTER INTBIG i, k, menusave, menux, menuy;
202
 
        INTBIG j;
203
 
        char si[50], sj[20], *par[MAXPARS+7];
204
 
        REGISTER char **temp;
205
 
 
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);
210
 
        temp[0] = "a/";
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));
218
 
        efree((char *)temp);
219
 
 
220
 
        /* bind the keys */
221
 
        for(i=0; us_initialkeyboard[i].key != 0; i++)
222
 
        {
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);
229
 
        }
230
 
 
231
 
        /* bind the mouse commands that fit on the mouse */
232
 
        for(i=0; i<buttoncount(); i++)
233
 
        {
234
 
                (void)strcpy(si, buttonname(i, &j));
235
 
                for(j=0; us_initialbutton[j].but[0] != 0; j++)
236
 
                        if (!us_initialbutton[j].used)
237
 
                {
238
 
                        for(k=0; k<3; k++)
239
 
                                if (namesame(si, us_initialbutton[j].but[k]) == 0)
240
 
                        {
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;
247
 
                                break;
248
 
                        }
249
 
                }
250
 
        }
251
 
 
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)
255
 
        {
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);
261
 
        }
262
 
 
263
 
        /* bind the component menu entries to all "getproto" */
264
 
        if (us_menupos <= 1)
265
 
        {
266
 
                menux = INITIALMENUX;
267
 
                menuy = INITIALMENUY;
268
 
        } else
269
 
        {
270
 
                menux = INITIALMENUY;
271
 
                menuy = INITIALMENUX;
272
 
        }
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++)
276
 
        {
277
 
                par[0] = "set";   par[1] = "menu";
278
 
                (void)sprintf(si, "%ld", i%INITIALMENUX);
279
 
                (void)sprintf(sj, "%ld", i/INITIALMENUX);
280
 
                if (us_menupos <= 1)
281
 
                {
282
 
                        par[2] = sj;  par[3] = si;
283
 
                } else
284
 
                {
285
 
                        par[2] = si;  par[3] = sj;
286
 
                }
287
 
                par[4] = "getproto";
288
 
                us_bind(5, par);
289
 
        }
290
 
 
291
 
        /* now fill in the "getproto" commands properly */
292
 
        us_setmenunodearcs();
293
 
 
294
 
        if (menusave != 0) us_tool->toolstate |= MENUON; else
295
 
                us_tool->toolstate &= ~MENUON;
296
 
        return(FALSE);
297
 
}
298
 
 
299
 
/*
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.
305
 
 */
306
 
void us_figuretechopaque(TECHNOLOGY *tech)
307
 
{
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;
314
 
 
315
 
        /* get polygon */
316
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
317
 
 
318
 
        for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
319
 
        {
320
 
                if ((np->userbits&NHASOPA) != 0) continue;
321
 
                np->userbits &= ~NHASOPA;
322
 
                node = dummynode();
323
 
                node->proto = np;
324
 
                node->lowx = np->lowx;   node->highx = np->highx;
325
 
                node->lowy = np->lowy;   node->highy = np->highy;
326
 
                j = nodepolys(node, 0, NOWINDOWPART);
327
 
                for(k=0; k<j; k++)
328
 
                {
329
 
                        shapenodepoly(node, k, poly);
330
 
                        if (poly->desc->bits == LAYERN) continue;
331
 
                        if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
332
 
                        {
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);
336
 
                                continue;
337
 
                        }
338
 
 
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;
343
 
                }
344
 
        }
345
 
        for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
346
 
        {
347
 
                ap->userbits &= ~AHASOPA;
348
 
                arc = dummyarc();
349
 
                arc->proto = ap;
350
 
                arc->userbits = ISDIRECTIONAL;
351
 
                j = arcpolys(arc, NOWINDOWPART);
352
 
                for(k=0; k<j; k++)
353
 
                {
354
 
                        shapearcpoly(arc, k, poly);
355
 
                        if (poly->desc->bits == LAYERN) continue;
356
 
                        if ((poly->desc->bits & ~(LAYERT1|LAYERT2|LAYERT3|LAYERT4|LAYERT5)) == 0)
357
 
                        {
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);
361
 
                                continue;
362
 
                        }
363
 
 
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;
368
 
                }
369
 
        }
370
 
}
371
 
 
372
 
/*
373
 
 * Routine to recompute the "NINVISIBLE" and "AINVISIBLE" bits on node and arc protos
374
 
 * according to whether or not all layers are invisible.
375
 
 */
376
 
void us_figuretechselectability(void)
377
 
{
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;
385
 
 
386
 
        /* get polygon */
387
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
388
 
 
389
 
        for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
390
 
        {
391
 
                for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
392
 
                {
393
 
                        np->userbits &= ~NINVISIBLE;
394
 
                        node = dummynode();
395
 
                        node->proto = np;
396
 
                        node->lowx = np->lowx;   node->highx = np->highx;
397
 
                        node->lowy = np->lowy;   node->highy = np->highy;
398
 
                        j = nodepolys(node, 0, NOWINDOWPART);
399
 
                        for(k=0; k<j; k++)
400
 
                        {
401
 
                                shapenodepoly(node, k, poly);
402
 
                                if (poly->desc->bits == LAYERN) continue;
403
 
                                if ((poly->desc->colstyle&INVISIBLE) == 0) break;
404
 
                        }
405
 
                        if (k >= j) np->userbits |= NINVISIBLE;
406
 
                }
407
 
                for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
408
 
                {
409
 
                        ap->userbits &= ~AINVISIBLE;
410
 
                        arc = dummyarc();
411
 
                        arc->proto = ap;
412
 
                        j = arcpolys(arc, NOWINDOWPART);
413
 
                        for(k=0; k<j; k++)
414
 
                        {
415
 
                                shapearcpoly(arc, k, poly);
416
 
                                if (poly->desc->bits == LAYERN) continue;
417
 
                                if ((poly->desc->colstyle&INVISIBLE) == 0) break;
418
 
                        }
419
 
                        if (k >= j) ap->userbits |= AINVISIBLE;
420
 
                }
421
 
        }
422
 
}
423
 
 
424
 
/*
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.
427
 
 */
428
 
void us_windowfit(WINDOWFRAME *whichframe, BOOLEAN placemenu, INTBIG scaletofit)
429
 
{
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;
439
 
 
440
 
        for(frame = el_firstwindowframe; frame != NOWINDOWFRAME; frame = frame->nextwindowframe)
441
 
        {
442
 
                if (whichframe != NOWINDOWFRAME && whichframe != frame) continue;
443
 
                getwindowframesize(frame, &swid, &shei);
444
 
                lowy = 0;   highy = shei - 1 - us_menubarsize;
445
 
 
446
 
                /* presume that there is no menu */
447
 
                drawlx = 0;      drawhx = swid-1;
448
 
                drawly = lowy;   drawhy = highy;
449
 
 
450
 
                /* if there is a menu, figure it out */
451
 
                if ((us_tool->toolstate&MENUON) != 0)
452
 
                {
453
 
                        /* see if the menu is all text */
454
 
                        alltext = 0;
455
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
456
 
                        if (var != NOVARIABLE)
457
 
                        {
458
 
                                total = us_menux*us_menuy;
459
 
                                for(i=0; i<total; i++)
460
 
                                {
461
 
                                        us_parsebinding(((char **)var->addr)[i], &commandbinding);
462
 
                                        if (*commandbinding.command == 0 || commandbinding.nodeglyph != NONODEPROTO ||
463
 
                                                commandbinding.arcglyph != NOARCPROTO)
464
 
                                        {
465
 
                                                us_freebindingparse(&commandbinding);
466
 
                                                break;
467
 
                                        }
468
 
                                        us_freebindingparse(&commandbinding);
469
 
                                }
470
 
                                if (i >= total) alltext = 1;
471
 
                        }
472
 
                        getpaletteparameters(&mwid, &mhei, &pwid);
473
 
                        if (us_menuframe == NOWINDOWFRAME)
474
 
                        {
475
 
                                /* menus come out of the only editor window */
476
 
                                switch (us_menupos)
477
 
                                {
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;
483
 
                                                us_menuhy = highy;
484
 
                                                drawlx = 0;      drawhx = swid-1;
485
 
                                                drawly = lowy;   drawhy = us_menuly-1;
486
 
                                                break;
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;
491
 
                                                us_menuly = lowy;
492
 
                                                us_menuhy = lowy + us_menuysz * us_menuy;
493
 
                                                drawlx = 0;             drawhx = swid-1;
494
 
                                                drawly = us_menuhy+1;   drawhy = highy;
495
 
                                                break;
496
 
                                        case 2:         /* menu on left */
497
 
                                                us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
498
 
 
499
 
                                                /* if the menu is all text, allow nonsquare menus */
500
 
                                                if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
501
 
 
502
 
                                                us_menulx = 0;
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;
508
 
                                                break;
509
 
                                        case 3:         /* menu on right */
510
 
                                                us_menuxsz = us_menuysz = (highy-lowy) / us_menuy;
511
 
 
512
 
                                                /* if the menu is all text, allow nonsquare menus */
513
 
                                                if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
514
 
 
515
 
                                                us_menulx = swid - us_menuxsz * us_menux;
516
 
                                                us_menuhx = swid-1;
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;
521
 
                                                break;
522
 
                                }
523
 
                        } else
524
 
                        {
525
 
                                /* floating menu window */
526
 
                                if (frame == us_menuframe && placemenu)
527
 
                                {
528
 
                                        getpaletteparameters(&mwid, &mhei, &pwid);
529
 
                                        switch (us_menupos)
530
 
                                        {
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;
536
 
                                                        us_menulx = 0;
537
 
                                                        us_menuhx = us_menux * us_menuxsz;
538
 
                                                        us_menuly = 0;
539
 
                                                        us_menuhy = us_menuy * us_menuysz;
540
 
                                                        mleft = 0;
541
 
                                                        if (us_menupos == 0)
542
 
                                                        {
543
 
                                                                /* menu on the top */
544
 
                                                                mtop = 1;
545
 
                                                        } else
546
 
                                                        {
547
 
                                                                /* menu on the bottom */
548
 
                                                                mtop = mhei - us_menuysz*us_menuy - 3;
549
 
                                                        }
550
 
                                                        break;
551
 
 
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;
558
 
 
559
 
                                                        /* if the menu is all text, allow nonsquare menus */
560
 
                                                        if (alltext != 0) us_menuxsz = ALLTEXTWIDTH / us_menux;
561
 
 
562
 
                                                        /* compute menu parameters */
563
 
                                                        us_menuly = 0;
564
 
                                                        us_menuhy = us_menuy * us_menuysz;
565
 
                                                        us_menulx = 0;
566
 
                                                        us_menuhx = us_menux * us_menuxsz;
567
 
                                                        mtop = 0;
568
 
                                                        if (us_menupos == 2)
569
 
                                                        {
570
 
                                                                /* menu on the left */
571
 
                                                                mleft = 0;
572
 
                                                        } else
573
 
                                                        {
574
 
                                                                /* menu on the right */
575
 
                                                                mleft = mwid - us_menuxsz * us_menux - 2;
576
 
                                                        }
577
 
                                                        break;
578
 
                                        }
579
 
                                        sizewindowframe(us_menuframe, us_menuhx-us_menulx, us_menuhy-us_menuly);
580
 
                                        movewindowframe(us_menuframe, mleft, mtop);
581
 
                                }
582
 
                        }
583
 
                }
584
 
 
585
 
                /* now fit the windows in the remaining space */
586
 
                for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
587
 
                {
588
 
                        /* this window must be on the right frame */
589
 
                        if (w->frame != frame) continue;
590
 
 
591
 
                        /* entire window is handled simply */
592
 
                        if (strcmp(w->location, "entire") == 0)
593
 
                        {
594
 
                                ulx = drawlx;              uhx = drawhx;
595
 
                                uly = drawly;              uhy = drawhy;
596
 
                        } else if (strncmp(w->location, "top", 3) == 0)
597
 
                        {
598
 
                                ulx = drawlx;              uhx = drawhx;
599
 
                                uly = (drawhy-drawly)*(100-w->vratio)/100;
600
 
                                uhy = drawhy;
601
 
                        } else if (strncmp(w->location, "bot", 3) == 0)
602
 
                        {
603
 
                                ulx = drawlx;              uhx = drawhx;
604
 
                                uly = drawly;              uhy = (drawhy-drawly)*w->vratio/100;
605
 
                        } else if (strcmp(w->location, "left") == 0)
606
 
                        {
607
 
                                ulx = drawlx;              uhx = (drawhx-drawlx)*w->hratio/100;
608
 
                                uly = drawly;              uhy = drawhy;
609
 
                        } else if (strcmp(w->location, "right") == 0)
610
 
                        {
611
 
                                ulx = (drawhx-drawlx)*(100-w->hratio)/100;
612
 
                                uhx = drawhx;
613
 
                                uly = drawly;              uhy = drawhy;
614
 
                        }
615
 
 
616
 
                        /* subdivide for fractions of half windows */
617
 
                        i = 3;
618
 
                        while (w->location[i] == '-')
619
 
                        {
620
 
                                switch (w->location[i+1])
621
 
                                {
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;
626
 
                                }
627
 
                                i += 2;
628
 
                        }
629
 
                        if (strcmp(w->location, "entire") != 0)
630
 
                        {
631
 
                                ulx++;   uhx--;   uly++;   uhy--;
632
 
                        }
633
 
 
634
 
                        /* make sure window has some size */
635
 
                        if (ulx >= uhx) uhx = ulx + 1;
636
 
                        if (uly >= uhy) uhy = uly + 1;
637
 
 
638
 
                        /* make room for border if simulating */
639
 
                        if ((w->state&WINDOWSIMULATING) != 0)
640
 
                        {
641
 
                                ulx += SIMULATINGBORDERSIZE;   uhx -= SIMULATINGBORDERSIZE;
642
 
                                uly += SIMULATINGBORDERSIZE;   uhy -= SIMULATINGBORDERSIZE;
643
 
                        }
644
 
 
645
 
                        /* make room for sliders if a display window */
646
 
                        if ((w->state&WINDOWTYPE) == DISPWINDOW)
647
 
                        {
648
 
                                uhx -= DISPLAYSLIDERSIZE;
649
 
                                uly += DISPLAYSLIDERSIZE;
650
 
                        }
651
 
                        if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
652
 
                        {
653
 
                                ulx += DISPLAYSLIDERSIZE;
654
 
                                uly += DISPLAYSLIDERSIZE;
655
 
                        }
656
 
 
657
 
                        /* update if the extent changed */
658
 
                        if (w->uselx != ulx || w->usehx != uhx ||
659
 
                                w->usely != uly || w->usehy != uhy)
660
 
                        {
661
 
                                /* set the window extent */
662
 
                                w->uselx = ulx;      w->usehx = uhx;
663
 
                                w->usely = uly;      w->usehy = uhy;
664
 
 
665
 
                                /* now adjust the database extents of the window */
666
 
                                slx = w->screenlx;   shx = w->screenhx;
667
 
                                sly = w->screenly;   shy = w->screenhy;
668
 
                                if (scaletofit > 0)
669
 
                                {
670
 
                                        us_squarescreen(w, NOWINDOWPART, FALSE, &slx, &shx, &sly, &shy, 0);
671
 
                                } else if (scaletofit < 0)
672
 
                                {
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);
677
 
                                        slx -= offx / 2;
678
 
                                        shx = slx + newwid;
679
 
                                        sly -= offy / 2;
680
 
                                        shy = sly + newhei;
681
 
                                }
682
 
                                w->screenlx = slx;   w->screenhx = shx;
683
 
                                w->screenly = sly;   w->screenhy = shy;
684
 
                                computewindowscale(w);
685
 
                        }
686
 
                }
687
 
        }
688
 
}
689
 
 
690
 
/*
691
 
 * routine to adjust the actual drawing area of window "win" to account for
692
 
 * the appearance or disappearance of the red simulation border
693
 
 */
694
 
void us_setwindowsimulation(WINDOWPART *win, BOOLEAN on)
695
 
{
696
 
        if (on)
697
 
        {
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;
702
 
        } else
703
 
        {
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;
708
 
        }
709
 
}
710
 
 
711
 
/*
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.
716
 
 */
717
 
void us_splitwindownames(char *w, char *hwind1, char *hwind2, char *vwind1, char *vwind2)
718
 
{
719
 
        REGISTER INTBIG i;
720
 
 
721
 
        if (strcmp(w, "entire") == 0)
722
 
        {
723
 
                (void)strcpy(hwind1, "top");   (void)strcpy(hwind2, "bottom");
724
 
                (void)strcpy(vwind1, "left");  (void)strcpy(vwind2, "right");
725
 
                return;
726
 
        }
727
 
        if (strcmp(w, "top") == 0)
728
 
        {
729
 
                (void)strcpy(hwind1, "top-l"); (void)strcpy(hwind2, "top-r");
730
 
                (void)strcpy(vwind1, "");      (void)strcpy(vwind2, "");
731
 
                return;
732
 
        }
733
 
        if (strcmp(w, "bottom") == 0)
734
 
        {
735
 
                (void)strcpy(hwind1, "bot-l"); (void)strcpy(hwind2, "bot-r");
736
 
                (void)strcpy(vwind1, "");      (void)strcpy(vwind2, "");
737
 
                return;
738
 
        }
739
 
        if (strcmp(w, "left") == 0)
740
 
        {
741
 
                (void)strcpy(vwind1, "top-l"); (void)strcpy(vwind2, "bot-l");
742
 
                (void)strcpy(hwind1, "");      (void)strcpy(hwind2, "");
743
 
                return;
744
 
        }
745
 
        if (strcmp(w, "right") == 0)
746
 
        {
747
 
                (void)strcpy(vwind1, "top-r"); (void)strcpy(vwind2, "bot-r");
748
 
                (void)strcpy(hwind1, "");      (void)strcpy(hwind2, "");
749
 
                return;
750
 
        }
751
 
        (void)strcpy(hwind1, w);   (void)strcpy(hwind2, w);
752
 
        (void)strcpy(vwind1, w);   (void)strcpy(vwind2, w);
753
 
        i = w[strlen(w)-1];
754
 
        if (i == 'l' || i == 'r')
755
 
        {
756
 
                (void)strcat(vwind1, "-t");  (void)strcat(vwind2, "-b");
757
 
                (void)strcpy(hwind1, "");    (void)strcpy(hwind2, "");
758
 
        } else
759
 
        {
760
 
                (void)strcat(hwind1, "-l");  (void)strcat(hwind2, "-r");
761
 
                (void)strcpy(vwind1, "");    (void)strcpy(vwind2, "");
762
 
        }
763
 
}
764
 
 
765
 
/*
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.
771
 
 */
772
 
WINDOWPART *us_wantnewwindow(INTBIG orientation)
773
 
{
774
 
        REGISTER WINDOWPART *w;
775
 
        WINDOWFRAME *wf;
776
 
 
777
 
        if (graphicshas(CANUSEFRAMES) && orientation == 0)
778
 
        {
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)
784
 
                {
785
 
                        us_abortcommand(_("Cannot create new window"));
786
 
                        return(NOWINDOWPART);
787
 
                }
788
 
                w->frame = wf;
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);
796
 
 
797
 
                /* now draw everything */
798
 
                us_drawmenu(0, wf);
799
 
                return(w);
800
 
        }
801
 
 
802
 
        if (us_needwindow()) return(NOWINDOWPART);
803
 
        w = us_splitcurrentwindow(orientation, FALSE, 0);
804
 
        return(w);
805
 
}
806
 
 
807
 
/*
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).
814
 
 */
815
 
WINDOWPART *us_splitcurrentwindow(INTBIG splitkey, BOOLEAN fillboth, WINDOWPART **other)
816
 
{
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;
824
 
 
825
 
        /* figure out new name of windows */
826
 
        if (other != 0) *other = NOWINDOWPART;
827
 
        horizsplit = 1;
828
 
        us_splitwindownames(el_curwindowpart->location, wind1, wind2, vwind1, vwind2);
829
 
 
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;
833
 
 
834
 
        /* special case when splitting just one window: which way to split */
835
 
        if (strcmp(el_curwindowpart->location, "entire") == 0)
836
 
        {
837
 
                /* see if a "horizontal" or "vertical" parameter was given */
838
 
                if (splitkey == 2)
839
 
                {
840
 
                        /* vertical window specified explicitly */
841
 
                        win1 = vwind1;   win2 = vwind2;
842
 
                        horizsplit = 0;
843
 
                } else if (splitkey == 0)
844
 
                {
845
 
                        /* make a guess about window splitting */
846
 
                        switch (el_curwindowpart->state&WINDOWTYPE)
847
 
                        {
848
 
                                case EXPLORERWINDOW:
849
 
                                        win1 = vwind1;   win2 = vwind2;
850
 
                                        horizsplit = 0;
851
 
                                        break;
852
 
                                default:
853
 
                                        np = el_curwindowpart->curnodeproto;
854
 
                                        if (np != NONODEPROTO)
855
 
                                        {
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))
863
 
                                                {
864
 
                                                        /* vertical window makes more sense */
865
 
                                                        win1 = vwind1;   win2 = vwind2;
866
 
                                                        horizsplit = 0;
867
 
                                                }
868
 
                                        }
869
 
                                        break;
870
 
                        }
871
 
                }
872
 
        } else
873
 
        {
874
 
                l = strlen(wind1) - 1;
875
 
                if (wind1[l] == 'l' || wind1[l] == 'r') horizsplit = 0;
876
 
        }
877
 
 
878
 
        /* turn off object and window highlighting */
879
 
        us_pushhighlight();
880
 
        us_clearhighlightcount();
881
 
        w = el_curwindowpart;
882
 
        copywindowpart(&windowsave, el_curwindowpart);
883
 
 
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)
891
 
        {
892
 
                ttyputnomemory();
893
 
                return(NOWINDOWPART);
894
 
        }
895
 
 
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;
899
 
 
900
 
        /* if splitting an editor window, move the editor structure */
901
 
        if ((w->state&WINDOWTYPE) == TEXTWINDOW || (w->state&WINDOWTYPE) == POPTEXTWINDOW)
902
 
        {
903
 
                (void)setval((INTBIG)w3, VWINDOWPART, "editor", (INTBIG)w->editor, VADDRESS);
904
 
                (void)setval((INTBIG)w, VWINDOWPART, "editor", -1, VADDRESS);
905
 
        }
906
 
 
907
 
        /* free the current window */
908
 
        killwindowpart(w);
909
 
 
910
 
        /* zap the returned window if both are not to be filled */
911
 
        retwin = w2;
912
 
        if (other != 0) *other = w3;
913
 
        if ((windowsave.state&WINDOWTYPE) != DISPWINDOW) fillboth = FALSE;
914
 
        if (!fillboth)
915
 
        {
916
 
                retwin->state = (retwin->state & ~(WINDOWTYPE|GRIDON|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;
924
 
        }
925
 
 
926
 
        /* set the window extents */
927
 
        us_windowfit(w2->frame, FALSE, 1);
928
 
 
929
 
        /* use former window for scaling */
930
 
        w = &windowsave;
931
 
 
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);
935
 
 
936
 
        endobjectchange((INTBIG)us_tool, VTOOL);
937
 
        (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w2,
938
 
                VWINDOWPART|VDONTSAVE);
939
 
 
940
 
        /* restore all highlighting */
941
 
        us_pophighlight(FALSE);
942
 
        return(retwin);
943
 
}
944
 
 
945
 
/*
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.
948
 
 */
949
 
void us_killcurrentwindow(BOOLEAN thisw)
950
 
{
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;
956
 
 
957
 
        w1 = el_curwindowpart;
958
 
 
959
 
        /* if this is the only partition, see if the window frame can be deleted */
960
 
        if (strcmp(w1->location, "entire") == 0)
961
 
        {
962
 
                if (!graphicshas(CANHAVENOWINDOWS))
963
 
                {
964
 
                        /* disallow deletion if this is the last window */
965
 
                        windows = 0;
966
 
                        for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
967
 
                                if (wf->floating == 0) windows++;
968
 
                        if (windows <= 1)
969
 
                        {
970
 
                                ttyputerr(_("Sorry, cannot delete the last window"));
971
 
                                return;
972
 
                        }
973
 
                }
974
 
                if (graphicshas(CANUSEFRAMES))
975
 
                {
976
 
                        /* save highlighting and turn it off */
977
 
                        us_pushhighlight();
978
 
                        us_clearhighlightcount();
979
 
 
980
 
                        /* kill the window */
981
 
                        startobjectchange((INTBIG)us_tool, VTOOL);
982
 
                        us_killwindowpickanother(w1);
983
 
                        endobjectchange((INTBIG)us_tool, VTOOL);
984
 
 
985
 
                        /* restore highlighting */
986
 
                        us_pophighlight(FALSE);
987
 
                        return;
988
 
                }
989
 
        }
990
 
 
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
995
 
        {
996
 
                (void)strcpy(windcomb, w1->location);
997
 
                windcomb[strlen(windcomb)-2] = 0;
998
 
                if (strcmp(windcomb, "bot") == 0) (void)strcpy(windcomb, "bottom");
999
 
        }
1000
 
 
1001
 
        /* see what divisions this higher window typically makes */
1002
 
        us_splitwindownames(windcomb, wind1, wind2, vwind1, vwind2);
1003
 
 
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);
1010
 
 
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;
1014
 
 
1015
 
        /* if the other window can't be found, try one more hack */
1016
 
        if (w2 == NOWINDOWPART)
1017
 
        {
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)
1021
 
                {
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;
1029
 
                }
1030
 
        }
1031
 
        if (w2 == NOWINDOWPART)
1032
 
        {
1033
 
                us_abortcommand(_("Cannot kill the current window"));
1034
 
                return;
1035
 
        }
1036
 
 
1037
 
        /* if the other window is to be killed, swap them */
1038
 
        if (!thisw)
1039
 
        {
1040
 
                w = w1;   w1 = w2;   w2 = w;
1041
 
        }
1042
 
 
1043
 
        /* turn off highlighting */
1044
 
        us_pushhighlight();
1045
 
        us_clearhighlightcount();
1046
 
 
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;
1053
 
 
1054
 
        /* save information from the old window */
1055
 
        copywindowpart(&windowsave, w2);
1056
 
 
1057
 
        /* if merging an editor window, move the editor structure */
1058
 
        if ((w2->state&WINDOWTYPE) == TEXTWINDOW || (w2->state&WINDOWTYPE) == POPTEXTWINDOW)
1059
 
        {
1060
 
                (void)setval((INTBIG)wnew, VWINDOWPART, "editor", (INTBIG)w2->editor, VADDRESS);
1061
 
                (void)setval((INTBIG)w2, VWINDOWPART, "editor", -1, VADDRESS);
1062
 
        }
1063
 
 
1064
 
        /* remove old windows */
1065
 
        killwindowpart(w1);
1066
 
        killwindowpart(w2);
1067
 
 
1068
 
        /* set window extents */
1069
 
        us_windowfit(wnew->frame, FALSE, 1);
1070
 
 
1071
 
        /* use former window for scaling */
1072
 
        w = &windowsave;
1073
 
 
1074
 
        /* window might have got bigger: see if grid can be drawn */
1075
 
        if ((wnew->state&GRIDTOOSMALL) != 0) us_gridset(wnew, GRIDON);
1076
 
 
1077
 
        (void)setval((INTBIG)el_curlib, VLIBRARY, "curnodeproto", (INTBIG)wnew->curnodeproto,
1078
 
                VNODEPROTO);
1079
 
        endobjectchange((INTBIG)us_tool, VTOOL);
1080
 
        (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)wnew,
1081
 
                VWINDOWPART|VDONTSAVE);
1082
 
 
1083
 
        /* restore highlighting */
1084
 
        us_pophighlight(FALSE);
1085
 
}
1086
 
 
1087
 
/*
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
1091
 
 */
1092
 
BOOLEAN us_windowcansplit(WINDOWPART *w1, WINDOWPART *w2, WINDOWPART *w3)
1093
 
{
1094
 
        REGISTER INTBIG new2l, new2h;
1095
 
 
1096
 
        if (w2->usehx-w2->uselx == w3->usehx-w3->uselx &&
1097
 
                w2->screenhx-w2->screenlx == w3->screenhx-w3->screenlx)
1098
 
        {
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)
1102
 
                                return(TRUE);
1103
 
 
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);
1110
 
        }
1111
 
        if (w2->usehy-w2->usely == w3->usehy-w3->usely &&
1112
 
                w2->screenhy-w2->screenly == w3->screenhy-w3->screenly)
1113
 
        {
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)
1117
 
                                return(TRUE);
1118
 
 
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);
1125
 
        }
1126
 
        return(FALSE);
1127
 
}
1128
 
 
1129
 
/*
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
1133
 
 */
1134
 
void us_ensurewindow(NODEPROTO *np)
1135
 
{
1136
 
        REGISTER WINDOWPART *w;
1137
 
        char *par[1];
1138
 
 
1139
 
        /* if nothing specified, quit */
1140
 
        if (np == NONODEPROTO) return;
1141
 
 
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;
1145
 
 
1146
 
        /* if the facet is not in a window, put it there */
1147
 
        if (w == NOWINDOWPART)
1148
 
        {
1149
 
                par[0] = describenodeproto(np);
1150
 
                us_editfacet(1, par);
1151
 
                us_endchanges(NOWINDOWPART);
1152
 
        }
1153
 
}
1154
 
 
1155
 
/*
1156
 
 * Routine to kill window "w" and set the current window to some other.
1157
 
 */
1158
 
void us_killwindowpickanother(WINDOWPART *w)
1159
 
{
1160
 
        REGISTER NODEPROTO *np;
1161
 
 
1162
 
        killwindowpart(w);
1163
 
 
1164
 
        if (w != el_curwindowpart) return;
1165
 
 
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);
1171
 
}
1172
 
 
1173
 
/*
1174
 
 * routine to adjust the coordinate values in (x, y) from screen space to
1175
 
 * the space of window "w"
1176
 
 */
1177
 
void us_scaletowindow(INTBIG *x, INTBIG *y, WINDOWPART *w)
1178
 
{
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;
1181
 
}
1182
 
 
1183
 
/******************** TEXT EDITING ********************/
1184
 
 
1185
 
EDITORTABLE us_editortable[] =
1186
 
{
1187
 
        /* the point-and-click editor */
1188
 
        {"Point-and-click",
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},
1196
 
 
1197
 
        /* the EMACS-like editor */
1198
 
        {"EMACS-like",
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},
1206
 
 
1207
 
        {NULL,
1208
 
        NULL, NULL, NULL, NULL,
1209
 
        NULL, NULL, NULL, NULL,
1210
 
        NULL, NULL,
1211
 
        NULL, NULL,
1212
 
        NULL, NULL, NULL,
1213
 
        NULL, NULL, NULL}
1214
 
};
1215
 
 
1216
 
/*
1217
 
 * dispatch routine to describe this editor
1218
 
 */
1219
 
void us_describeeditor(char **name)
1220
 
{
1221
 
        *name = us_editortable[us_currenteditor].editorname;
1222
 
}
1223
 
 
1224
 
/*
1225
 
 * dispatch routine for creating a new editor
1226
 
 */
1227
 
WINDOWPART *us_makeeditor(WINDOWPART *oriwin, char *header, INTBIG *chars, INTBIG *lines)
1228
 
{
1229
 
        return((*us_editortable[us_currenteditor].makeeditor)(oriwin,header,chars,lines));
1230
 
}
1231
 
 
1232
 
/*
1233
 
 * dispatch routine to return the total number of valid lines in the edit buffer
1234
 
 */
1235
 
INTBIG us_totallines(WINDOWPART *win)
1236
 
{
1237
 
        return((*us_editortable[us_currenteditor].totallines)(win));
1238
 
}
1239
 
 
1240
 
/*
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
1243
 
 */
1244
 
char *us_getline(WINDOWPART *win, INTBIG lindex)
1245
 
{
1246
 
        return((*us_editortable[us_currenteditor].getline)(win, lindex));
1247
 
}
1248
 
 
1249
 
/*
1250
 
 * dispatch routine to add line "str" to the text facet to become line "lindex"
1251
 
 */
1252
 
void us_addline(WINDOWPART *win, INTBIG lindex, char *str)
1253
 
{
1254
 
        (*us_editortable[us_currenteditor].addline)(win, lindex, str);
1255
 
}
1256
 
 
1257
 
/*
1258
 
 * dispatch routine to replace the line number "lindex" with the string "str".
1259
 
 */
1260
 
void us_replaceline(WINDOWPART *win, INTBIG lindex, char *str)
1261
 
{
1262
 
        (*us_editortable[us_currenteditor].replaceline)(win, lindex, str);
1263
 
}
1264
 
 
1265
 
/*
1266
 
 * dispatch routine to delete line number "lindex"
1267
 
 */
1268
 
void us_deleteline(WINDOWPART *win, INTBIG lindex)
1269
 
{
1270
 
        (*us_editortable[us_currenteditor].deleteline)(win, lindex);
1271
 
}
1272
 
 
1273
 
/*
1274
 
 * dispatch routine to highlight lines "lindex" to "hindex" in the text window
1275
 
 */
1276
 
void us_highlightline(WINDOWPART *win, INTBIG lindex, INTBIG hindex)
1277
 
{
1278
 
        (*us_editortable[us_currenteditor].highlightline)(win, lindex, hindex);
1279
 
}
1280
 
 
1281
 
/*
1282
 
 * dispatch routine to stop the graphic display of changes (for batching)
1283
 
 */
1284
 
void us_suspendgraphics(WINDOWPART *win)
1285
 
{
1286
 
        (*us_editortable[us_currenteditor].suspendgraphics)(win);
1287
 
}
1288
 
 
1289
 
/*
1290
 
 * dispatch routine to restart the graphic display of changes and redisplay (for batching)
1291
 
 */
1292
 
void us_resumegraphics(WINDOWPART *win)
1293
 
{
1294
 
        (*us_editortable[us_currenteditor].resumegraphics)(win);
1295
 
}
1296
 
 
1297
 
/*
1298
 
 * dispatch routine to write the text file to "file"
1299
 
 */
1300
 
void us_writetextfile(WINDOWPART *win, char *file)
1301
 
{
1302
 
        (*us_editortable[us_currenteditor].writetextfile)(win, file);
1303
 
}
1304
 
 
1305
 
/*
1306
 
 * dispatch routine to read the text file "file"
1307
 
 */
1308
 
void us_readtextfile(WINDOWPART *win, char *file)
1309
 
{
1310
 
        (*us_editortable[us_currenteditor].readtextfile)(win, file);
1311
 
}
1312
 
 
1313
 
/*
1314
 
 * dispatch routine to get the next character
1315
 
 */
1316
 
void us_editorterm(WINDOWPART *w)
1317
 
{
1318
 
        (*us_editortable[us_currenteditor].editorterm)(w);
1319
 
}
1320
 
 
1321
 
/*
1322
 
 * dispatch routine to force changes from the editor in window "w"
1323
 
 */
1324
 
void us_shipchanges(WINDOWPART *w)
1325
 
{
1326
 
        (*us_editortable[us_currenteditor].shipchanges)(w);
1327
 
}
1328
 
 
1329
 
/*
1330
 
 * dispatch routine to get the next character
1331
 
 */
1332
 
BOOLEAN us_gotchar(WINDOWPART *w, INTSML i, INTBIG special)
1333
 
{
1334
 
        return((*us_editortable[us_currenteditor].gotchar)(w, i, special));
1335
 
}
1336
 
 
1337
 
/*
1338
 
 * dispatch routine to cut text
1339
 
 */
1340
 
void us_cuttext(WINDOWPART *w)
1341
 
{
1342
 
        (*us_editortable[us_currenteditor].cut)(w);
1343
 
}
1344
 
 
1345
 
/*
1346
 
 * dispatch routine to copy text
1347
 
 */
1348
 
void us_copytext(WINDOWPART *w)
1349
 
{
1350
 
        (*us_editortable[us_currenteditor].copy)(w);
1351
 
}
1352
 
 
1353
 
/*
1354
 
 * dispatch routine to paste text
1355
 
 */
1356
 
void us_pastetext(WINDOWPART *w)
1357
 
{
1358
 
        (*us_editortable[us_currenteditor].paste)(w);
1359
 
}
1360
 
 
1361
 
/*
1362
 
 * dispatch routine to undo text changes
1363
 
 */
1364
 
void us_undotext(WINDOWPART *w)
1365
 
{
1366
 
        (*us_editortable[us_currenteditor].undo)(w);
1367
 
}
1368
 
 
1369
 
/*
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:
1372
 
 *   1   search from top
1373
 
 *   2   replace all
1374
 
 *   4   case sensitive
1375
 
 *   8   search upwards
1376
 
 */
1377
 
void us_searchtext(WINDOWPART *w, char *str, char *replace, INTBIG bits)
1378
 
{
1379
 
        (*us_editortable[us_currenteditor].search)(w, str, replace, bits);
1380
 
}
1381
 
 
1382
 
/*
1383
 
 * dispatch routine to pan the text window by (dx, dy)
1384
 
 */
1385
 
void us_pantext(WINDOWPART *w, INTBIG dx, INTBIG dy)
1386
 
{
1387
 
        (*us_editortable[us_currenteditor].pan)(w, dx, dy);
1388
 
}
1389
 
 
1390
 
/*
1391
 
 * support routine to allocate a new editor from the pool (if any) or memory
1392
 
 * routine returns NOEDITOR upon error
1393
 
 */
1394
 
EDITOR *us_alloceditor(void)
1395
 
{
1396
 
        REGISTER EDITOR *e;
1397
 
 
1398
 
        e = (EDITOR *)emalloc((sizeof (EDITOR)), us_tool->cluster);
1399
 
        if (e == 0) return(NOEDITOR);
1400
 
        e->state = 0;
1401
 
        e->nexteditor = NOEDITOR;
1402
 
        e->editobjvar = NOVARIABLE;
1403
 
        return(e);
1404
 
}
1405
 
 
1406
 
/*
1407
 
 * support routine to return editor "e" to the pool of free editors
1408
 
 */
1409
 
void us_freeeditor(EDITOR *e)
1410
 
{
1411
 
        if (e == 0 || e == NOEDITOR) return;
1412
 
        efree(e->header);
1413
 
        (*us_editortable[us_currenteditor].terminate)(e);
1414
 
        efree((char *)e);
1415
 
}
1416
 
 
1417
 
/******************** SPECIAL WINDOW HANDLERS ********************/
1418
 
 
1419
 
/*
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
1425
 
 */
1426
 
void us_varchanges(WINDOWPART *w, INTBIG nature, char *oldline, char *newline, INTBIG changed)
1427
 
{
1428
 
        REGISTER INTBIG j, l, save;
1429
 
        REGISTER BOOLEAN res;
1430
 
        REGISTER INTBIG newval, i, len;
1431
 
        REGISTER char **newlist, *pt;
1432
 
        float newfloat;
1433
 
        REGISTER EDITOR *ed;
1434
 
 
1435
 
        ed = w->editor;
1436
 
        if (ed->editobjvar == NOVARIABLE) return;
1437
 
        if ((ed->editobjvar->type&VCANTSET) != 0)
1438
 
        {
1439
 
                ttyputerr(M_("This variable cannot be changed"));
1440
 
                ed->editobjvar = NOVARIABLE;
1441
 
                return;
1442
 
        }
1443
 
        len = getlength(ed->editobjvar);
1444
 
 
1445
 
        /* when replacing the entire text, reduce to individual calls */
1446
 
        if (nature == REPLACEALLTEXT)
1447
 
        {
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);
1453
 
                return;
1454
 
        }
1455
 
 
1456
 
        if (nature == DELETETEXTLINE && len == 1)
1457
 
        {
1458
 
                /* delete of last entry: instead, replace it with a null */
1459
 
                newline = "";
1460
 
                nature = REPLACETEXTLINE;
1461
 
        } else if (nature == REPLACETEXTLINE && changed >= len)
1462
 
        {
1463
 
                /* change of line beyond end: instead make an insert */
1464
 
                nature = INSERTTEXTLINE;
1465
 
        }
1466
 
 
1467
 
        /* disallow deletions and insertions if the number of lines is fixed */
1468
 
        if (nature == DELETETEXTLINE || nature == INSERTTEXTLINE)
1469
 
        {
1470
 
                if ((ed->state&LINESFIXED) != 0) return;
1471
 
        }
1472
 
 
1473
 
        /* get the value */
1474
 
        if (nature == REPLACETEXTLINE || nature == INSERTTEXTLINE)
1475
 
        {
1476
 
                pt = newline;
1477
 
                while (*pt == ' ' || *pt == '\t') pt++;
1478
 
                switch (ed->editobjvar->type&VTYPE)
1479
 
                {
1480
 
                        case VINTEGER:
1481
 
                        case VSHORT:
1482
 
                        case VADDRESS:
1483
 
                                newval = myatoi(pt);
1484
 
                                break;
1485
 
                        case VFRACT:
1486
 
                                newval = atofr(pt);
1487
 
                                break;
1488
 
                        case VFLOAT:
1489
 
                        case VDOUBLE:
1490
 
                                newfloat = (float)atof(pt);
1491
 
                                newval = castint(newfloat);
1492
 
                                break;
1493
 
                        case VSTRING:
1494
 
                                j = l = strlen(newline);
1495
 
                                if (strcmp(&newline[l-3], " */") == 0)
1496
 
                                {
1497
 
                                        for(j = l-5; j >= 0; j--)
1498
 
                                                if (strncmp(&newline[j], "/* ", 3) == 0) break;
1499
 
                                        while (j > 0 && newline[j-1] == ' ') j--;
1500
 
                                        if (j < 0) j = l;
1501
 
                                }
1502
 
                                save = newline[j];
1503
 
                                newline[j] = 0;
1504
 
                                newval = (INTBIG)newline;
1505
 
                                break;
1506
 
                        default:
1507
 
                                ttyputmsg(_("Cannot update this type of variable (0%o)"), ed->editobjvar->type);
1508
 
                                break;
1509
 
                }
1510
 
        }
1511
 
 
1512
 
        /* make the change */
1513
 
        res = TRUE;
1514
 
        switch (nature)
1515
 
        {
1516
 
                case REPLACETEXTLINE:
1517
 
                        if (changed < 0 || changed >= len) return;
1518
 
                        res = setind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1519
 
                        break;
1520
 
                case DELETETEXTLINE:
1521
 
                        if (changed < 0 || changed >= len) return;
1522
 
                        res = delind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed);
1523
 
                        break;
1524
 
                case INSERTTEXTLINE:
1525
 
                        if (changed <= 0 || changed > len) return;
1526
 
                        res = insind((INTBIG)ed->editobjaddr, ed->editobjtype, ed->editobjqual, changed, newval);
1527
 
 
1528
 
                        /* why is this next line necessary? */
1529
 
                        ed->editobjvar = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
1530
 
                        break;
1531
 
        }
1532
 
 
1533
 
        /* clean-up string if one was passed */
1534
 
        if ((nature == REPLACETEXTLINE || nature == INSERTTEXTLINE) &&
1535
 
                (ed->editobjvar->type&VTYPE) == VSTRING) newline[j] = (char)save;
1536
 
 
1537
 
        if (res)
1538
 
        {
1539
 
                ttyputerr(_("Error changing variable: ignoring further changes"));
1540
 
                ed->editobjvar = NOVARIABLE;
1541
 
        }
1542
 
}
1543
 
 
1544
 
/*
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
1550
 
 */
1551
 
void us_textfacetchanges(WINDOWPART *w, INTBIG nature, char *oldline, char *newline, INTBIG changed)
1552
 
{
1553
 
        REGISTER INTBIG len;
1554
 
        REGISTER BOOLEAN res;
1555
 
        REGISTER EDITOR *ed;
1556
 
 
1557
 
        ed = w->editor;
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);
1562
 
 
1563
 
        if (nature == DELETETEXTLINE && len == 1)
1564
 
        {
1565
 
                /* delete of last line: instead, replace it with a blank */
1566
 
                newline = "";
1567
 
                nature = REPLACETEXTLINE;
1568
 
        } else if (nature == REPLACETEXTLINE && changed >= len)
1569
 
        {
1570
 
                if (changed >= len)
1571
 
                {
1572
 
                        /* change of line one beyond end: instead make an insert */
1573
 
                        nature = INSERTTEXTLINE;
1574
 
                }
1575
 
        }
1576
 
 
1577
 
        res = TRUE;
1578
 
        switch (nature)
1579
 
        {
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);
1584
 
                        break;
1585
 
                case DELETETEXTLINE:
1586
 
                        if (changed < 0 || changed >= len) return;
1587
 
                        res = delindkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1588
 
                                changed);
1589
 
                        break;
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);
1594
 
                        break;
1595
 
                case REPLACEALLTEXT:
1596
 
                        if (setvalkey((INTBIG)ed->editobjaddr, VNODEPROTO, el_facet_message_key,
1597
 
                                (INTBIG)newline, VSTRING | VISARRAY | (changed << VLENGTHSH)) != NOVARIABLE)
1598
 
                                        res = FALSE;
1599
 
                        break;
1600
 
        }
1601
 
 
1602
 
        if (res)
1603
 
        {
1604
 
                ttyputerr(_("Error changing variable: ignoring further changes"));
1605
 
                ed->editobjvar = NOVARIABLE;
1606
 
        }
1607
 
}
1608
 
 
1609
 
/*
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
1613
 
 */
1614
 
BOOLEAN us_facetedithandler(WINDOWPART *w, INTSML ch, INTBIG special)
1615
 
{
1616
 
        char *newpar[2], *str;
1617
 
        REGISTER INTBIG i;
1618
 
        REGISTER BOOLEAN meta;
1619
 
        REGISTER EDITOR *ed;
1620
 
        extern INTBIG us_lastemacschar;
1621
 
 
1622
 
        /* the EMACS text editor must be running */
1623
 
        us_describeeditor(&str);
1624
 
        if (namesame(str, "emacs") != 0) return(us_gotchar(w, ch, special));
1625
 
 
1626
 
        /* see if the meta key is held down (serious black magic) */
1627
 
        meta = FALSE;
1628
 
        if ((special&ACCELERATORDOWN) != 0) meta = TRUE;
1629
 
        if ((us_lastemacschar&2) != 0) meta = TRUE;
1630
 
 
1631
 
        /* pass character on to the editor if not M(=) */
1632
 
        if (!meta || ch != '=') return(us_gotchar(w, ch, special));
1633
 
 
1634
 
        /* M(=) typed: parse current line to edit named facet */
1635
 
        ed = w->editor;
1636
 
        (void)allocstring(&str, us_getline(w, ed->curline), el_tempcluster);
1637
 
 
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;
1641
 
 
1642
 
        if (str[0] == 0) ttyputerr(_("No facet specified on this line")); else
1643
 
        {
1644
 
                /* issue the "editfacet" command */
1645
 
                newpar[0] = "editfacet";
1646
 
                newpar[1] = str;
1647
 
                telltool(us_tool, 2, newpar);
1648
 
                setactivity(_("Facet Selection"));
1649
 
        }
1650
 
 
1651
 
        /* clean up */
1652
 
        efree(str);
1653
 
        return(FALSE);
1654
 
}
1655
 
 
1656
 
/******************** COMMAND SUPPORT ********************/
1657
 
 
1658
 
BOOLEAN us_demandxy(INTBIG *x, INTBIG *y)
1659
 
{
1660
 
        BOOLEAN ret;
1661
 
 
1662
 
        ret = getxy(x, y);
1663
 
        if (ret) ttyputmsg(_("Cursor must be in an editing window"));
1664
 
        return(ret);
1665
 
}
1666
 
 
1667
 
static INTBIG us_curx, us_cury;
1668
 
 
1669
 
/*
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.
1674
 
 */
1675
 
BOOLEAN getxy(INTBIG *x, INTBIG *y)
1676
 
{
1677
 
        INTBIG gx, gy;
1678
 
        REGISTER BOOLEAN ret;
1679
 
 
1680
 
        if ((us_state&GOTXY) == 0)
1681
 
        {
1682
 
                readtablet(&gx, &gy);
1683
 
                ret = us_setxy(gx, gy);
1684
 
        } else ret = FALSE;
1685
 
        *x = us_curx;
1686
 
        *y = us_cury;
1687
 
        return(ret);
1688
 
}
1689
 
 
1690
 
/*
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.
1697
 
 */
1698
 
BOOLEAN us_setxy(INTBIG x, INTBIG y)
1699
 
{
1700
 
        REGISTER WINDOWPART *w;
1701
 
        REGISTER WINDOWFRAME *wf;
1702
 
 
1703
 
        us_curx = x;   us_cury = y;
1704
 
 
1705
 
        /* figure out which window it is in */
1706
 
        wf = getwindowframe(TRUE);
1707
 
        for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1708
 
        {
1709
 
                if (w->frame != wf) continue;
1710
 
                if (x >= w->uselx && x <= w->usehx && y >= w->usely && y <= w->usehy)
1711
 
                {
1712
 
                        /* make this window the current one */
1713
 
                        if (w != el_curwindowpart)
1714
 
                        {
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);
1719
 
                        }
1720
 
                        us_scaletowindow(&us_curx, &us_cury, w);
1721
 
                        xform(us_curx, us_cury, &us_curx, &us_cury, w->intofacet);
1722
 
                        us_state |= GOTXY;
1723
 
                        return(FALSE);
1724
 
                }
1725
 
        }
1726
 
        return(TRUE);
1727
 
}
1728
 
 
1729
 
/*
1730
 
 * routine to force the parameters "xcur" and "ycur" to align to the
1731
 
 * nearest "alignment" units
1732
 
 */
1733
 
void gridalign(INTBIG *xcur, INTBIG *ycur, INTBIG alignmentdivisor)
1734
 
{
1735
 
        INTBIG otheralign;
1736
 
        REGISTER INTBIG val, alignment;
1737
 
 
1738
 
        alignment = muldiv(us_alignment_ratio, el_curlib->lambda[el_curtech->techindex], WHOLE) /
1739
 
                alignmentdivisor;
1740
 
        val = us_alignvalue(*xcur, alignment, &otheralign);
1741
 
        if (abs(*xcur-val) < abs(*xcur-otheralign)) *xcur = val; else
1742
 
                *xcur = otheralign;
1743
 
        val = us_alignvalue(*ycur, alignment, &otheralign);
1744
 
        if (abs(*ycur-val) < abs(*ycur-otheralign)) *ycur = val; else
1745
 
                *ycur = otheralign;
1746
 
}
1747
 
 
1748
 
/*
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".
1752
 
 */
1753
 
INTBIG us_alignvalue(INTBIG value, INTBIG alignment, INTBIG *otheralign)
1754
 
{
1755
 
        REGISTER INTBIG i, v1, v2;
1756
 
        REGISTER INTBIG sign;
1757
 
 
1758
 
        /* determine the sign of the value */
1759
 
        if (value < 0) { sign = -1; value = -value; } else sign = 1;
1760
 
 
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;
1766
 
 
1767
 
        /* make sure "v1" is the closest aligned value */
1768
 
        if (abs(v1-value) > abs(v2-value)) { i = v1;   v1 = v2;   v2 = i; }
1769
 
 
1770
 
        *otheralign = v2;
1771
 
        return(v1);
1772
 
}
1773
 
 
1774
 
/* routine to ensure that a current window exists */
1775
 
BOOLEAN us_needwindow(void)
1776
 
{
1777
 
        if (el_curwindowpart != NOWINDOWPART) return(FALSE);
1778
 
        us_abortcommand(_("No current window"));
1779
 
        return(TRUE);
1780
 
}
1781
 
 
1782
 
/* routine to ensure that a facet exists in the current window */
1783
 
NODEPROTO *us_needfacet(void)
1784
 
{
1785
 
        REGISTER NODEPROTO *np;
1786
 
 
1787
 
        np = getcurfacet();
1788
 
        if (np != NONODEPROTO) return(np);
1789
 
        if (el_curwindowpart == NOWINDOWPART)
1790
 
        {
1791
 
                us_abortcommand(_("No current window (select one with Facets/Edit Facet)"));
1792
 
        } else
1793
 
        {
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')"));
1797
 
        }
1798
 
        return(NONODEPROTO);
1799
 
}
1800
 
 
1801
 
/*
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.
1805
 
 */
1806
 
BOOLEAN us_cantedit(NODEPROTO *facet, NODEPROTO *item, BOOLEAN giveerror)
1807
 
{
1808
 
        REGISTER INTBIG count;
1809
 
        extern COMCOMP us_noyesalwaysp;
1810
 
        char *pars[5];
1811
 
 
1812
 
        /* if a prototype is specified, check it */
1813
 
        if (item != NONODEPROTO)
1814
 
        {
1815
 
                if (item->primindex != 0)
1816
 
                {
1817
 
                        /* see if a primitive is locked */
1818
 
                        if ((item->userbits&LOCKEDPRIM) != 0 &&
1819
 
                                (us_useroptions&NOPRIMCHANGES) != 0)
1820
 
                        {
1821
 
                                if (!giveerror) return(TRUE);
1822
 
                                (void)initinfstr();
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);
1830
 
                        }
1831
 
                } else
1832
 
                {
1833
 
                        /* see if this type of facet is locked */
1834
 
                        if ((facet->userbits&NILOCKED) != 0)
1835
 
                        {
1836
 
                                if (!giveerror) return(TRUE);
1837
 
                                (void)initinfstr();
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);
1845
 
                        }
1846
 
                }
1847
 
        }
1848
 
 
1849
 
        /* check for general changes to the facet */
1850
 
        if ((facet->userbits&NLOCKED) != 0)
1851
 
        {
1852
 
                if (!giveerror) return(TRUE);
1853
 
                (void)initinfstr();
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);
1860
 
        }
1861
 
        return(FALSE);
1862
 
}
1863
 
 
1864
 
/*
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).
1870
 
 */
1871
 
void us_getslide(INTBIG angle, INTBIG tx, INTBIG ty, INTBIG nx, INTBIG ny, INTBIG *fx,
1872
 
        INTBIG *fy)
1873
 
{
1874
 
        REGISTER INTBIG ang;
1875
 
        INTBIG ix, iy;
1876
 
 
1877
 
        /* if angle is unconstrained, use the exact cursor position */
1878
 
        if (angle <= 0)
1879
 
        {
1880
 
                *fx = nx;   *fy = ny;
1881
 
                return;
1882
 
        }
1883
 
 
1884
 
        /* check all permissable angles */
1885
 
        for(ang = 0; ang < 3600; ang += angle)
1886
 
        {
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);
1889
 
 
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;
1892
 
                *fx = ix;   *fy = iy;
1893
 
        }
1894
 
}
1895
 
 
1896
 
/*
1897
 
 * routine to convert command interpreter letter "letter" to the full
1898
 
 * variable name on the user tool object
1899
 
 */
1900
 
char *us_commandvarname(INTSML letter)
1901
 
{
1902
 
        static char varname[20];
1903
 
 
1904
 
        if (isupper(letter))
1905
 
        {
1906
 
                (void)strcpy(varname, "USER_local_capX");
1907
 
                varname[14] = tolower(letter);
1908
 
        } else
1909
 
        {
1910
 
                (void)strcpy(varname, "USER_local_X");
1911
 
                varname[11] = (char)letter;
1912
 
        }
1913
 
        return(varname);
1914
 
}
1915
 
 
1916
 
/*
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.
1925
 
 */
1926
 
BOOLEAN us_getvar(char *str, INTBIG *objaddr, INTBIG *objtype, char **varname,
1927
 
        BOOLEAN *comvar, INTBIG *aindex)
1928
 
{
1929
 
        REGISTER INTBIG i;
1930
 
        static char fullvarname[50];
1931
 
 
1932
 
        /* see if an array index is specified */
1933
 
        *aindex = -1;
1934
 
        i = strlen(str);
1935
 
        if (str[i-1] == ']') for(i--; i >= 0; i--) if (str[i] == '[')
1936
 
        {
1937
 
                *aindex = myatoi(&str[i+1]);
1938
 
                break;
1939
 
        }
1940
 
 
1941
 
        /* see if this is a command interpreter variable */
1942
 
        *comvar = FALSE;
1943
 
        if (str[1] == 0 || str[1] == '[')
1944
 
        {
1945
 
                if (str[0] >= 'a' && str[0] <= 'z') *comvar = TRUE;
1946
 
                if (str[0] >= 'A' && str[0] <= 'Z') *comvar = TRUE;
1947
 
        }
1948
 
 
1949
 
        /* replace the actual name for command interpreter variables */
1950
 
        if (*comvar)
1951
 
        {
1952
 
                (void)sprintf(fullvarname, "tool:user.%s", us_commandvarname(str[0]));
1953
 
                str = fullvarname;
1954
 
        }
1955
 
 
1956
 
        /* pick apart the variable path */
1957
 
        return(us_evaluatevariable(str, objaddr, objtype, varname));
1958
 
}
1959
 
 
1960
 
/******************** QUICK-KEY BINDING ********************/
1961
 
 
1962
 
/*
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".
1967
 
 */
1968
 
INTBIG us_findboundkey(INTSML key, INTBIG special, char **binding)
1969
 
{
1970
 
        REGISTER INTBIG i, len;
1971
 
        INTSML boundkey;
1972
 
        INTBIG boundspecial;
1973
 
        REGISTER VARIABLE *var;
1974
 
        REGISTER char *thisbinding, *pt;
1975
 
 
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++)
1980
 
        {
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;
1985
 
        }
1986
 
        if (i >= len) return(-1);
1987
 
        *binding = pt;
1988
 
        return(i);
1989
 
}
1990
 
 
1991
 
/*
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.
1994
 
 */
1995
 
void us_setkeybinding(char *binding, INTSML key, INTBIG special, BOOLEAN quietly)
1996
 
{
1997
 
        char *pt, *justone[1], **bigger, *str;
1998
 
        REGISTER INTBIG i, j, len, inserted;
1999
 
        INTSML boundkey;
2000
 
        INTBIG boundspecial;
2001
 
        REGISTER VARIABLE *var;
2002
 
 
2003
 
        if ((special&ACCELERATORDOWN) != 0) key = toupper(key);
2004
 
        i = us_findboundkey(key, special, &pt);
2005
 
        if (i >= 0)
2006
 
        {
2007
 
                if (quietly) nextchangequiet();
2008
 
                (void)setindkey((INTBIG)us_tool, VTOOL, us_binding_keys_key, i, (INTBIG)binding);
2009
 
                return;
2010
 
        }
2011
 
 
2012
 
        var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
2013
 
        if (var == NOVARIABLE)
2014
 
        {
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));
2019
 
        } else
2020
 
        {
2021
 
                len = getlength(var);
2022
 
                bigger = (char **)emalloc((len+1) * (sizeof (char *)), el_tempcluster);
2023
 
                if (bigger == 0) return;
2024
 
                j = 0;
2025
 
                inserted = 0;
2026
 
                for(i=0; i<len; i++)
2027
 
                {
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;
2032
 
                        if (inserted == 0)
2033
 
                        {
2034
 
                                if (boundspecial > special || (boundspecial == special && boundkey > key))
2035
 
                                {
2036
 
                                        (void)allocstring(&bigger[j++], binding, el_tempcluster);
2037
 
                                        inserted = 1;
2038
 
                                }
2039
 
                        }
2040
 
                        (void)allocstring(&bigger[j++], pt, el_tempcluster);
2041
 
                }
2042
 
                if (inserted == 0)
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);
2049
 
        }
2050
 
}
2051
 
 
2052
 
/*
2053
 
 * Routine to describe key "boundkey"/"boundspecial".  Formats it according to
2054
 
 * "readable":
2055
 
 *  -1 for end of menu ("/A")
2056
 
 *   0 for beginning of menu storage ("A/")
2057
 
 *   1 for display ("Ctrl-A")
2058
 
 */
2059
 
char *us_describeboundkey(INTSML boundkey, INTBIG boundspecial, INTBIG readable)
2060
 
{
2061
 
        char *acceleratorstring, *acceleratorprefix, *shiftprefix, *accprefix;
2062
 
 
2063
 
        getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2064
 
        if (readable > 0)
2065
 
        {
2066
 
                accprefix = acceleratorprefix;
2067
 
                shiftprefix = "S-";
2068
 
        } else
2069
 
        {
2070
 
                accprefix = "m-";
2071
 
                shiftprefix = "S";
2072
 
        }
2073
 
        (void)initinfstr();
2074
 
        if ((boundspecial&SPECIALKEYDOWN) != 0)
2075
 
        {
2076
 
                if (readable < 0) (void)addtoinfstr('/');
2077
 
                switch ((boundspecial&SPECIALKEY)>>SPECIALKEYSH)
2078
 
                {
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");
2097
 
                                break;
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");
2104
 
                                break;
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");
2111
 
                                break;
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");
2118
 
                                break;
2119
 
                }
2120
 
                if (readable == 0) (void)addtoinfstr('/');
2121
 
        } else
2122
 
        {
2123
 
                if ((boundspecial&ACCELERATORDOWN) != 0)
2124
 
                {
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('/');
2130
 
                } else
2131
 
                {
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('\\');
2137
 
                }
2138
 
        }
2139
 
        return(returninfstr());
2140
 
}
2141
 
 
2142
 
/*
2143
 
 * Returns true if the keys "key1"/"special1" is the same as "key2"/"special2"
2144
 
 */
2145
 
BOOLEAN us_samekey(INTSML key1, INTBIG special1, INTSML key2, INTBIG special2)
2146
 
{
2147
 
        if (special1 != special2) return(FALSE);
2148
 
        if ((special1&SPECIALKEYDOWN) == 0)
2149
 
        {
2150
 
                if ((special1&ACCELERATORDOWN) != 0)
2151
 
                {
2152
 
                        key1 = toupper(key1);
2153
 
                        key2 = toupper(key2);
2154
 
                }
2155
 
                if (key1 != key2) return(FALSE);
2156
 
        }
2157
 
        return(TRUE);
2158
 
}
2159
 
 
2160
 
/*
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.
2165
 
 */
2166
 
char *us_getboundkey(char *origbinding, INTSML *boundkey, INTBIG *boundspecial)
2167
 
{
2168
 
        REGISTER char *pt, save, *word;
2169
 
        REGISTER INTBIG offset, len;
2170
 
        char binding[200], *acceleratorstring, *acceleratorprefix;
2171
 
 
2172
 
        strcpy(binding, origbinding);
2173
 
        *boundspecial = 0;
2174
 
        if (binding[0] != 0 && binding[1] == 0)
2175
 
        {
2176
 
                *boundkey = binding[0];
2177
 
                return("");
2178
 
        }
2179
 
        if (*binding == '/' || *binding == '\\')
2180
 
        {
2181
 
                pt = binding;
2182
 
                save = *pt;
2183
 
                word = binding + 1;
2184
 
        } else
2185
 
        {
2186
 
                for(pt = binding; *pt != 0; pt++)
2187
 
                        if (*pt == '/' || *pt == '\\') break;
2188
 
                save = *pt;
2189
 
                *pt = 0;
2190
 
                word = binding;
2191
 
        }
2192
 
 
2193
 
        getacceleratorstrings(&acceleratorstring, &acceleratorprefix);
2194
 
        len = strlen(acceleratorprefix);
2195
 
        if (namesamen(word, acceleratorprefix, len) == 0)
2196
 
        {
2197
 
                word += len;
2198
 
                *boundspecial |= ACCELERATORDOWN;
2199
 
        } else if (word[0] == 'm' && word[1] == '-')
2200
 
        {
2201
 
                word += 2;
2202
 
                *boundspecial |= ACCELERATORDOWN;
2203
 
        }
2204
 
 
2205
 
        /* handle single keystrokes */
2206
 
        if (word[1] == 0)
2207
 
        {
2208
 
                *boundkey = word[0];
2209
 
                if (save == '/') *boundspecial |= ACCELERATORDOWN;
2210
 
        } else
2211
 
        {
2212
 
                /* look for special names */
2213
 
                if (word[0] == '^')
2214
 
                {
2215
 
                        if (word[1] == '^')
2216
 
                        {
2217
 
                                *boundkey = '^';
2218
 
                        } else if (isdigit(word[1]) != 0)
2219
 
                        {
2220
 
                                *boundkey = (INTSML)myatoi(&word[1]);
2221
 
                        } else
2222
 
                        {
2223
 
                                *boundkey = toupper(word[1]) - 0100;
2224
 
                        }
2225
 
                } else
2226
 
                {
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);
2248
 
                }
2249
 
        }
2250
 
        *pt++ = save;
2251
 
        offset = pt - binding;
2252
 
        return(origbinding+offset);     
2253
 
}
2254
 
 
2255
 
/*
2256
 
 * Routine to adjust the quick keys according to the variable "var".
2257
 
 */
2258
 
void us_adjustquickkeys(VARIABLE *var, BOOLEAN warnofchanges)
2259
 
{
2260
 
        REGISTER INTBIG len, i, j, clen, elen;
2261
 
        INTSML key;
2262
 
        INTBIG special;
2263
 
        REGISTER char *keybinding, *menuname, *menucommand, *pt, **quickkeylist,
2264
 
                *expected;
2265
 
        REGISTER POPUPMENU *pm;
2266
 
        REGISTER POPUPMENUITEM *mi;
2267
 
 
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);
2273
 
 
2274
 
        /* next scan the list of quick keys and make sure they are attached to menus */
2275
 
        for(i=0; i<len; i++)
2276
 
        {
2277
 
                keybinding = quickkeylist[i];
2278
 
                menuname = us_getboundkey(keybinding, &key, &special);
2279
 
                for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
2280
 
                if (*pt == 0) continue;
2281
 
                *pt = 0;
2282
 
                pm = us_getpopupmenu(menuname);
2283
 
                *pt = '/';
2284
 
                if (pm == NOPOPUPMENU) continue;
2285
 
                menucommand = pt + 1;
2286
 
                for(j=0; j<pm->total; j++)
2287
 
                {
2288
 
                        mi = &pm->list[j];
2289
 
                        if (namesame(us_removeampersand(mi->attribute), menucommand) == 0) break;
2290
 
                }
2291
 
                if (j >= pm->total) continue;
2292
 
 
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;
2300
 
 
2301
 
                /* not there: see if there is another key bound */
2302
 
                (void)initinfstr();
2303
 
                for(pt = mi->attribute; *pt != 0; pt++)
2304
 
                {
2305
 
                        if (*pt == '/' || *pt == '\\' || *pt == '<') break;
2306
 
                        (void)addtoinfstr(*pt);
2307
 
                }
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);
2315
 
 
2316
 
                /* make it the Meta key */
2317
 
                (void)initinfstr();
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);
2323
 
 
2324
 
                if (warnofchanges)
2325
 
                {
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));
2330
 
                }
2331
 
        }
2332
 
}
2333
 
 
2334
 
/*
2335
 
 * Helper routine for "us_quickkeydlog" to recursively examine menu "pm" and
2336
 
 * load the quick keys tables.
2337
 
 */
2338
 
void us_scanquickkeys(POPUPMENU *pm, char **quickkeylist, INTBIG quickkeycount, BOOLEAN *warnofchanges)
2339
 
{
2340
 
        REGISTER INTBIG j, i, checked, len;
2341
 
        INTBIG special;
2342
 
        REGISTER POPUPMENUITEM *mi;
2343
 
        REGISTER USERCOM *uc;
2344
 
        REGISTER POPUPMENU *thispm;
2345
 
        char *pt, menuline[200], menukey[50];
2346
 
        REGISTER char *mname, *menuname;
2347
 
        INTSML key;
2348
 
 
2349
 
        for(i=0; i<pm->total; i++)
2350
 
        {
2351
 
                mi = &pm->list[i];
2352
 
                uc = mi->response;
2353
 
                if (uc->menu != NOPOPUPMENU)
2354
 
                {
2355
 
                        us_scanquickkeys(uc->menu, quickkeylist, quickkeycount, warnofchanges);
2356
 
                        continue;
2357
 
                }
2358
 
                if (uc->active < 0 && *mi->attribute == 0) continue;
2359
 
 
2360
 
                /* see if this item has a quick key */
2361
 
                strcpy(menuline, mi->attribute);
2362
 
                j = strlen(menuline) - 1;
2363
 
                checked = 0;
2364
 
                if (menuline[j] == '<')
2365
 
                {
2366
 
                        menuline[j] = 0;
2367
 
                        checked = 1;
2368
 
                }
2369
 
                for(mname = menuline; *mname != 0; mname++)
2370
 
                        if (*mname == '/' || *mname == '\\') break;
2371
 
                if (*mname == 0) continue;
2372
 
                strcpy(menukey, &mname[1]);
2373
 
                mname[1] = 0;
2374
 
                strcat(menukey, mname);
2375
 
                len = strlen(menukey);
2376
 
 
2377
 
                /* item has a quick key: see if it is in the list */
2378
 
                for(j=0; j<quickkeycount; j++)
2379
 
                {
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;
2384
 
                        *pt = 0;
2385
 
                        thispm = us_getpopupmenu(menuname);
2386
 
                        *pt = '/';
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;
2390
 
                }
2391
 
                if (j < quickkeycount) continue;
2392
 
 
2393
 
                /* remove the Meta key */
2394
 
                (void)us_getboundkey(menukey, &key, &special);
2395
 
                us_setkeybinding("", key, special, TRUE);
2396
 
 
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;
2400
 
                if (*mname != 0)
2401
 
                {
2402
 
                        if (checked != 0) *mname++ = '<';
2403
 
                        *mname = 0;
2404
 
                }
2405
 
                nativemenurename(pm, i);
2406
 
                us_adjustpopupmenu(pm, i);
2407
 
                if (*warnofchanges)
2408
 
                {
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));
2415
 
                }
2416
 
        }
2417
 
}
2418
 
 
2419
 
/*
2420
 
 * Helper routine to remove special characters from menu item "name".
2421
 
 */
2422
 
char *us_removeampersand(char *name)
2423
 
{
2424
 
        REGISTER char *pt;
2425
 
        REGISTER INTBIG len;
2426
 
 
2427
 
        len = strlen(name);
2428
 
        if (name[len-1] == '<' && name[0] == '>') name++;
2429
 
        (void)initinfstr();
2430
 
        for(pt = name; *pt != 0; pt++)
2431
 
        {
2432
 
                if (*pt == '/' || *pt == '\\') break;
2433
 
                if (*pt == '<' || *pt == '&') continue;
2434
 
                (void)addtoinfstr(*pt);
2435
 
        }
2436
 
        return(returninfstr());
2437
 
}
2438
 
 
2439
 
/*
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!
2444
 
 */
2445
 
BOOLEAN us_islasteval(INTSML key, INTBIG special)
2446
 
{
2447
 
        REGISTER INTBIG i, j, keytotal, foundanother;
2448
 
        REGISTER BOOLEAN retval;
2449
 
        INTBIG boundspecial;
2450
 
        INTSML boundkey;
2451
 
        REGISTER VARIABLE *var;
2452
 
        char *pt;
2453
 
        COMMANDBINDING commandbindingthis, commandbindingother;
2454
 
 
2455
 
        /* get the command on this key */
2456
 
        retval = FALSE;
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)
2463
 
        {
2464
 
                /* see if it is "telltool user" */
2465
 
                if (namesame(commandbindingthis.command, "telltool user") == 0)
2466
 
                {
2467
 
                        /* this is "telltool user"...check all other keys for this command */
2468
 
                        keytotal = getlength(var);
2469
 
                        foundanother = 0;
2470
 
                        for(j=0; j<keytotal; j++)
2471
 
                        {
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;
2479
 
                        }
2480
 
                        if (foundanother == 0) retval = TRUE;
2481
 
                }
2482
 
        }
2483
 
        us_freebindingparse(&commandbindingthis);
2484
 
        return(retval);
2485
 
}
2486
 
 
2487
 
/*
2488
 
 * routine to set the trace information in the "size" coordinate pairs in
2489
 
 * "newlist" onto the node "ni".
2490
 
 */
2491
 
void us_settrace(NODEINST *ni, INTBIG *newlist, INTBIG size)
2492
 
{
2493
 
        REGISTER INTBIG lx, hx, ly, hy, x, y, i;
2494
 
        INTBIG lxo, hxo, lyo, hyo;
2495
 
 
2496
 
        /* get the extent of the data */
2497
 
        lx = hx = newlist[0];   ly = hy = newlist[1];
2498
 
        for(i=1; i<size; i++)
2499
 
        {
2500
 
                x = newlist[i*2];
2501
 
                y = newlist[i*2+1];
2502
 
                lx = mini(lx, x);   hx = maxi(hx, x);
2503
 
                ly = mini(ly, y);   hy = maxi(hy, y);
2504
 
        }
2505
 
 
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++)
2509
 
        {
2510
 
                newlist[i*2] = newlist[i*2] - x;
2511
 
                newlist[i*2+1] = newlist[i*2+1] - y;
2512
 
        }
2513
 
 
2514
 
        /* adjust size for node size offset */
2515
 
        nodesizeoffset(ni, &lxo, &lyo, &hxo, &hyo);
2516
 
        lx -= lxo;   hx += hxo;
2517
 
        ly -= lyo;   hy += hyo;
2518
 
 
2519
 
        /* erase the node instance */
2520
 
        startobjectchange((INTBIG)ni, VNODEINST);
2521
 
 
2522
 
        /* change the trace data */
2523
 
        (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
2524
 
                VINTEGER|VISARRAY|((size*2)<<VLENGTHSH));
2525
 
 
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);
2531
 
 
2532
 
        /* redisplay */
2533
 
        endobjectchange((INTBIG)ni, VNODEINST);
2534
 
 
2535
 
        /* restore original data */
2536
 
        for(i=0; i<size; i++)
2537
 
        {
2538
 
                newlist[i*2] = newlist[i*2] + x;
2539
 
                newlist[i*2+1] = newlist[i*2+1] + y;
2540
 
        }
2541
 
}
2542
 
 
2543
 
/*
2544
 
 * routine to scale the trace information on node "ni" given that it will change
2545
 
 * in size to "nlx"->"nhx" and "nly"->"nhy".
2546
 
 */
2547
 
void us_scaletraceinfo(NODEINST *ni, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy)
2548
 
{
2549
 
        REGISTER VARIABLE *var;
2550
 
        REGISTER INTBIG *newlist, oldx, oldy, denx, deny, len, i;
2551
 
 
2552
 
        /* stop now if no trace information */
2553
 
        var = gettrace(ni);
2554
 
        if (var == NOVARIABLE) return;
2555
 
 
2556
 
        /* get new array for new trace */
2557
 
        len = getlength(var);
2558
 
        newlist = (INTBIG *)emalloc(len * SIZEOFINTBIG, el_tempcluster);
2559
 
        if (newlist == 0) return;
2560
 
 
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)
2567
 
        {
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;
2573
 
        }
2574
 
 
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);
2579
 
}
2580
 
 
2581
 
/*
2582
 
 * Routine to fillet the two highlighted objects
2583
 
 */
2584
 
void us_dofillet(void)
2585
 
{
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;
2595
 
        XARRAY trans;
2596
 
 
2597
 
        /* must be exactly two nodes selected */
2598
 
        var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2599
 
        if (var == NOVARIABLE)
2600
 
        {
2601
 
                us_abortcommand(_("Must select two nodes before filleting"));
2602
 
                return;
2603
 
        }
2604
 
        if (getlength(var) != 2)
2605
 
        {
2606
 
                us_abortcommand(_("Must select two nodes before filleting"));
2607
 
                return;
2608
 
        }
2609
 
 
2610
 
        if (us_makehighlight(((char **)var->addr)[0], &thishigh) ||
2611
 
                us_makehighlight(((char **)var->addr)[1], &otherhigh)) return;
2612
 
 
2613
 
        /* get the two objects */
2614
 
        if ((thishigh.status&HIGHTYPE) != HIGHFROM || (otherhigh.status&HIGHTYPE) != HIGHFROM)
2615
 
        {
2616
 
                us_abortcommand(_("Must select two nodes before filleting"));
2617
 
                return;
2618
 
        }
2619
 
 
2620
 
        if (!thishigh.fromgeom->entryisnode || !otherhigh.fromgeom->entryisnode)
2621
 
        {
2622
 
                us_abortcommand(_("Must select two nodes before filleting"));
2623
 
                return;
2624
 
        }
2625
 
 
2626
 
        /* get description of first node */
2627
 
        ni1 = thishigh.fromgeom->entryaddr.ni;
2628
 
        if (ni1->proto == art_circleprim || ni1->proto == art_thickcircleprim)
2629
 
        {
2630
 
                getarcdegrees(ni1, &startoffset, &endangle);
2631
 
                if (startoffset == 0.0 && endangle == 0.0)
2632
 
                {
2633
 
                        us_abortcommand(_("Must select arcs, not circles before filleting"));
2634
 
                        return;
2635
 
                }
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]);
2642
 
                arc1 = 1;
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)
2646
 
        {
2647
 
                var = gettrace(ni1);
2648
 
                if (var == NOVARIABLE)
2649
 
                {
2650
 
                        us_abortcommand(_("Must select nodes with outline information before filleting"));
2651
 
                        return;
2652
 
                }
2653
 
 
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);
2664
 
                arc1 = 0;
2665
 
        } else
2666
 
        {
2667
 
                us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni1));
2668
 
                return;
2669
 
        }
2670
 
 
2671
 
        /* get description of second node */
2672
 
        ni2 = otherhigh.fromgeom->entryaddr.ni;
2673
 
        if (ni2->proto == art_circleprim || ni2->proto == art_thickcircleprim)
2674
 
        {
2675
 
                getarcdegrees(ni2, &startoffset, &endangle);
2676
 
                if (startoffset == 0.0 && endangle == 0.0)
2677
 
                {
2678
 
                        us_abortcommand(_("Must select arcs, not circles before filleting"));
2679
 
                        return;
2680
 
                }
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]);
2687
 
                arc2 = 1;
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)
2691
 
        {
2692
 
                var = gettrace(ni2);
2693
 
                if (var == NOVARIABLE)
2694
 
                {
2695
 
                        us_abortcommand(_("Must select nodes with outline information before filleting"));
2696
 
                        return;
2697
 
                }
2698
 
 
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);
2709
 
                arc2 = 0;
2710
 
        } else
2711
 
        {
2712
 
                us_abortcommand(_("Node %s cannot be filleted"), describenodeinst(ni2));
2713
 
                return;
2714
 
        }
2715
 
 
2716
 
        /* handle different types of filleting */
2717
 
        if (arc1 != 0 && arc2 != 0)
2718
 
        {
2719
 
                /* cannot handle arc-to-arc filleting */
2720
 
                us_abortcommand(_("Cannot fillet two curves"));
2721
 
        } else if (arc1 == 0 && arc2 == 0)
2722
 
        {
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]))
2726
 
                {
2727
 
                        line1xs = &newlist1[0];
2728
 
                        line1ys = &newlist1[1];
2729
 
                        line1xe = &newlist1[2];
2730
 
                        line1ye = &newlist1[3];
2731
 
                } else
2732
 
                {
2733
 
                        line1xs = &newlist1[size1*2-2];
2734
 
                        line1ys = &newlist1[size1*2-1];
2735
 
                        line1xe = &newlist1[size1*2-4];
2736
 
                        line1ye = &newlist1[size1*2-3];
2737
 
                }
2738
 
                if (computedistance(*line1xs,*line1ys, newlist2[0],newlist2[1]) <
2739
 
                        computedistance(*line1xs,*line1ys, newlist2[size2*2-2],newlist2[size2*2-1]))
2740
 
                {
2741
 
                        line2xs = &newlist2[0];
2742
 
                        line2ys = &newlist2[1];
2743
 
                        line2xe = &newlist2[2];
2744
 
                        line2ye = &newlist2[3];
2745
 
                } else
2746
 
                {
2747
 
                        line2xs = &newlist2[size2*2-2];
2748
 
                        line2ys = &newlist2[size2*2-1];
2749
 
                        line2xe = &newlist2[size2*2-4];
2750
 
                        line2ye = &newlist2[size2*2-3];
2751
 
                }
2752
 
 
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
2758
 
                {
2759
 
                        *line1xs = ix;   *line1ys = iy;
2760
 
                        *line2xs = ix;   *line2ys = iy;
2761
 
                        us_pushhighlight();
2762
 
                        us_clearhighlightcount();
2763
 
                        us_settrace(ni1, newlist1, size1);
2764
 
                        us_settrace(ni2, newlist2, size2);
2765
 
                        us_pophighlight(TRUE);
2766
 
                }
2767
 
        } else
2768
 
        {
2769
 
                /* handle arc-to-line filleting */
2770
 
                if (arc1 == 0)
2771
 
                {
2772
 
                        swaplist = newlist1;   newlist1 = newlist2;   newlist2 = swaplist;
2773
 
                        swapsize = size1;      size1 = size2;         size2 = swapsize;
2774
 
                        swapni = ni1;          ni1 = ni2;             ni2 = swapni;
2775
 
                }
2776
 
 
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]))
2780
 
                {
2781
 
                        line2xs = &newlist2[0];
2782
 
                        line2ys = &newlist2[1];
2783
 
                        line2xe = &newlist2[2];
2784
 
                        line2ye = &newlist2[3];
2785
 
                } else
2786
 
                {
2787
 
                        line2xs = &newlist2[size2*2-2];
2788
 
                        line2ys = &newlist2[size2*2-1];
2789
 
                        line2xe = &newlist2[size2*2-4];
2790
 
                        line2ye = &newlist2[size2*2-3];
2791
 
                }
2792
 
                icount = circlelineintersection(newlist1[0],newlist1[1], newlist1[2],newlist1[3],
2793
 
                        *line2xs, *line2ys, *line2xe, *line2ye, &ix1, &iy1, &ix2, &iy2, 0);
2794
 
                if (icount == 0)
2795
 
                {
2796
 
                        us_abortcommand(_("Line does not intersect arc: cannot fillet"));
2797
 
                } else
2798
 
                {
2799
 
                        if (icount == 2)
2800
 
                        {
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);
2805
 
                                if (!on1 && on2)
2806
 
                                {
2807
 
                                        icount = 1;
2808
 
                                        ix1 = ix2;   iy1 = iy2;
2809
 
                                } else if (on1 && !on2)
2810
 
                                {
2811
 
                                        icount = 1;
2812
 
                                }
2813
 
                        }
2814
 
                        if (icount == 2)
2815
 
                        {
2816
 
                                x = (*line2xs + *line2xe) / 2;
2817
 
                                y = (*line2ys + *line2ye) / 2;
2818
 
                                if (computedistance(ix1,iy1, x,y) > computedistance(ix2,iy2, x,y))
2819
 
                                {
2820
 
                                        ix1 = ix2;   iy1 = iy2;
2821
 
                                }
2822
 
                        }
2823
 
 
2824
 
                        /* make them fillet at (ix1,iy1) */
2825
 
                        us_pushhighlight();
2826
 
                        us_clearhighlightcount();
2827
 
 
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)
2831
 
                        {
2832
 
                                us_abortcommand(_("Domain error during fillet"));
2833
 
                                return;
2834
 
                        }
2835
 
                        srot = atan2(dy, dx);
2836
 
                        if (srot < 0.0) srot += EPI*2.0;
2837
 
 
2838
 
                        dx = (double)(newlist1[4]-newlist1[0]);   dy = (double)(newlist1[5]-newlist1[1]);
2839
 
                        if (dx == 0.0 && dy == 0.0)
2840
 
                        {
2841
 
                                us_abortcommand(_("Domain error during fillet"));
2842
 
                                return;
2843
 
                        }
2844
 
                        erot = atan2(dy, dx);
2845
 
                        if (erot < 0.0) erot += EPI*2.0;
2846
 
 
2847
 
                        dx = (double)(ix1-newlist1[0]);   dy = (double)(iy1-newlist1[1]);
2848
 
                        if (dx == 0.0 && dy == 0.0)
2849
 
                        {
2850
 
                                us_abortcommand(_("Domain error during fillet"));
2851
 
                                return;
2852
 
                        }
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
2857
 
                                        erot = newangle;
2858
 
                        erot -= srot;
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);
2866
 
 
2867
 
                        /* adjust the line (node ni2) */
2868
 
                        *line2xs = ix1;   *line2ys = iy1;
2869
 
                        us_settrace(ni2, newlist2, size2);
2870
 
 
2871
 
                        /* restore highlighting */
2872
 
                        us_pophighlight(TRUE);
2873
 
                }
2874
 
        }
2875
 
        efree((char *)newlist1);
2876
 
        efree((char *)newlist2);
2877
 
}
2878
 
 
2879
 
/*
2880
 
 * Houtine to convert the text in "msg" to bits on the display.
2881
 
 */
2882
 
void us_layouttext(char *layer, INTBIG tsize, INTBIG scale, INTBIG font, INTBIG italic,
2883
 
        INTBIG bold, INTBIG underline, INTBIG separation, char *msg)
2884
 
{
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;
2894
 
 
2895
 
        np = us_needfacet();
2896
 
        if (np == NONODEPROTO) return;
2897
 
 
2898
 
        /* convert the text to bits */
2899
 
        TDCLEAR(descript);
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);
2909
 
        if (err)
2910
 
        {
2911
 
                us_abortcommand(_("Sorry, this system cannot layout text"));
2912
 
                return;
2913
 
        }
2914
 
 
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)
2920
 
        {
2921
 
                us_abortcommand(_("Cannot find '%s' node"), layer);
2922
 
                return;
2923
 
        }
2924
 
 
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++)
2937
 
        {
2938
 
                cy = by - y * gridsize;
2939
 
                data = rowstart[y];
2940
 
                for(x=0; x<wid; x++)
2941
 
                {
2942
 
                        cx = bx + x * gridsize;
2943
 
                        if (*data != 0)
2944
 
                        {
2945
 
                                poly->xv[0] = cx;
2946
 
                                poly->yv[0] = cy;
2947
 
                                poly->xv[1] = cx + gridsize;
2948
 
                                poly->yv[1] = cy + gridsize;
2949
 
                                poly->style = FILLEDRECT;
2950
 
                                poly->count = 2;
2951
 
                                if (separation == 0) mergestorepolygon(0, el_curtech, poly); else
2952
 
                                {
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);
2958
 
                                }
2959
 
                        }
2960
 
                        data++;
2961
 
                }
2962
 
        }
2963
 
        if (separation == 0) mergedone(us_layouttextpolygon);
2964
 
}
2965
 
 
2966
 
/*
2967
 
 * Helper routine for "us_layouttext" to process a polygon and convert it to layout.
2968
 
 */
2969
 
void us_layouttextpolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
2970
 
{
2971
 
        REGISTER NODEPROTO *facet;
2972
 
        REGISTER NODEINST *ni;
2973
 
        REGISTER INTBIG lx, hx, ly, hy, cx, cy, *newlist;
2974
 
        REGISTER INTBIG i;
2975
 
        HIGHLIGHT high;
2976
 
 
2977
 
        facet = us_needfacet();
2978
 
        if (facet == NONODEPROTO) return;
2979
 
        lx = hx = x[0];
2980
 
        ly = hy = y[0];
2981
 
        for(i=1; i<count; i++)
2982
 
        {
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];
2987
 
        }
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++)
2993
 
        {
2994
 
                newlist[i*2] = x[i] - cx;
2995
 
                newlist[i*2+1] = y[i] - cy;
2996
 
        }
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;
3003
 
        high.frompoint = 0;
3004
 
        high.facet = facet;
3005
 
        us_addhighlight(&high);
3006
 
}
3007
 
 
3008
 
/*
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.
3011
 
 */
3012
 
BOOLEAN us_pointonexparc(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, INTBIG x, INTBIG y)
3013
 
{
3014
 
        REGISTER INTBIG as, ae, a;
3015
 
 
3016
 
        as = figureangle(cx, cy, sx, sy);
3017
 
        ae = figureangle(cx, cy, ex, ey);
3018
 
        a = figureangle(cx, cy, x, y);
3019
 
 
3020
 
        if (ae > as)
3021
 
        {
3022
 
                if (a >= as && a <= ae) return(TRUE);
3023
 
        } else
3024
 
        {
3025
 
                if (a >= as || a <= ae) return(TRUE);
3026
 
        }
3027
 
        return(FALSE);
3028
 
}
3029
 
 
3030
 
/*
3031
 
 * routine to recursively check sub-facet revision times
3032
 
 * P. Attfield
3033
 
 */
3034
 
void us_check_facet_date(NODEPROTO *np, UINTBIG rev_time)
3035
 
{
3036
 
        REGISTER NODEPROTO *np2;
3037
 
        REGISTER NODEINST *ni;
3038
 
 
3039
 
        for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3040
 
        {
3041
 
                np2 = ni->proto;
3042
 
                if (np2->primindex != 0) continue; /* ignore if primitive */
3043
 
 
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 */
3048
 
        }
3049
 
 
3050
 
        /* check this facet */
3051
 
        np->temp1++; /* flag that we have seen this one */
3052
 
        if (np->revisiondate <= rev_time) return;
3053
 
 
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"));
3057
 
}
3058
 
 
3059
 
/*
3060
 
 * routine to switch to library "lib"
3061
 
 */
3062
 
void us_switchtolibrary(LIBRARY *lib)
3063
 
{
3064
 
        char *newpar[2];
3065
 
        REGISTER INTBIG oldlam;
3066
 
        REGISTER WINDOWPART *w;
3067
 
 
3068
 
        /* select the new library */
3069
 
        us_clearhighlightcount();
3070
 
        oldlam = el_curlib->lambda[el_curtech->techindex];
3071
 
        selectlibrary(lib);
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)
3077
 
                us_setfacetname(w);
3078
 
 
3079
 
        /* if nothing displayed and new library has top facet, show it */
3080
 
        if (el_curwindowpart == NOWINDOWPART ||
3081
 
                el_curwindowpart->curnodeproto == NONODEPROTO)
3082
 
        {
3083
 
                if (el_curlib->curnodeproto != NONODEPROTO)
3084
 
                {
3085
 
                        newpar[0] = describenodeproto(el_curlib->curnodeproto);
3086
 
                        us_editfacet(1, newpar);
3087
 
                }
3088
 
        }
3089
 
 
3090
 
        /* redo the explorer window (if it is up) */
3091
 
        us_redoexplorerwindow();
3092
 
}
3093
 
 
3094
 
/*
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).
3098
 
 */
3099
 
void us_replacelibraryreferences(LIBRARY *oldlib, LIBRARY *newlib)
3100
 
{
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;
3107
 
 
3108
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
3109
 
        {
3110
 
                if (lib == oldlib || lib == newlib) continue;
3111
 
 
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)
3115
 
                {
3116
 
                        us_correctxlibref(&np->firstvar, &np->numvar, oldlib, newlib);
3117
 
                        for(ni = np->firstnodeinst; ni != NONODEINST; ni = nextni)
3118
 
                        {
3119
 
                                nextni = ni->nextnodeinst;
3120
 
 
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);
3128
 
 
3129
 
                                if (ni->proto->primindex != 0) continue;
3130
 
                                if (ni->proto->cell->lib == oldlib)
3131
 
                                {
3132
 
                                        /* find the equivalent name in the new library */
3133
 
                                        newnp = us_findfacetinotherlib(ni->proto, newlib);
3134
 
                                        if (newnp == NONODEPROTO)
3135
 
                                        {
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);
3139
 
                                                continue;
3140
 
                                        }
3141
 
                                        newni = replacenodeinst(ni, newnp, FALSE, TRUE);
3142
 
                                        if (newni == NONODEINST)
3143
 
                                        {
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);
3147
 
                                                continue;
3148
 
                                        }
3149
 
                                }
3150
 
                        }
3151
 
                        for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3152
 
                        {
3153
 
                                us_correctxlibref(&ai->firstvar, &ai->numvar, oldlib, newlib);
3154
 
                                us_correctxlibref(&ai->geom->firstvar, &ai->geom->numvar, oldlib, newlib);
3155
 
                        }
3156
 
                }
3157
 
        }
3158
 
}
3159
 
 
3160
 
/*
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".
3163
 
 */
3164
 
void us_correctxlibref(VARIABLE **firstvar, INTSML *numvar, LIBRARY *oldlib, LIBRARY *newlib)
3165
 
{
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;
3178
 
 
3179
 
        for(i=0; i < *numvar; i++)
3180
 
        {
3181
 
                var = &(*firstvar)[i];
3182
 
                if ((var->type&VISARRAY) != 0) continue;
3183
 
                checkfacet = 0;
3184
 
                switch (var->type&VTYPE)
3185
 
                {
3186
 
                        case VNODEINST:
3187
 
                                ni = (NODEINST *)var->addr;
3188
 
                                np = ni->parent;
3189
 
                                checkfacet = 1;
3190
 
                                break;
3191
 
                        case VNODEPROTO:
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;
3197
 
                                break;
3198
 
                        case VPORTARCINST:
3199
 
                                pi = (PORTARCINST *)var->addr;
3200
 
                                np = pi->conarcinst->parent;
3201
 
                                checkfacet = 1;
3202
 
                                break;
3203
 
                        case VPORTEXPINST:
3204
 
                                pe = (PORTEXPINST *)var->addr;
3205
 
                                np = pe->exportproto->parent;
3206
 
                                checkfacet = 1;
3207
 
                                break;
3208
 
                        case VPORTPROTO:
3209
 
                                pp = (PORTPROTO *)var->addr;
3210
 
                                np = pp->parent;
3211
 
                                checkfacet = 1;
3212
 
                                break;
3213
 
                        case VARCINST:
3214
 
                                ai = (ARCINST *)var->addr;
3215
 
                                np = ai->parent;
3216
 
                                checkfacet = 1;
3217
 
                                break;
3218
 
                        case VGEOM:
3219
 
                                geom = (GEOM *)var->addr;
3220
 
                                np = geomparent(geom);
3221
 
                                checkfacet = 1;
3222
 
                                break;
3223
 
                        case VLIBRARY:
3224
 
                                lib = (LIBRARY *)var->addr;
3225
 
                                if (lib != oldlib) break;
3226
 
                                var->addr = (INTBIG)newlib;
3227
 
                                break;
3228
 
                        case VNETWORK:
3229
 
                                net = (NETWORK *)var->addr;
3230
 
                                np = net->parent;
3231
 
                                checkfacet = 1;
3232
 
                                break;
3233
 
                        case VCELL:
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;
3239
 
                                break;
3240
 
                }
3241
 
                if (checkfacet != 0)
3242
 
                {
3243
 
                        if (np->primindex != 0) continue;
3244
 
                        if (np->cell->lib != oldlib) continue;
3245
 
 
3246
 
                        /* cannot correct the reference: delete the variable */
3247
 
                        for(j=i+1; j < *numvar; j++)
3248
 
                        {
3249
 
                                svar = &(*firstvar)[j];
3250
 
                                dvar = &(*firstvar)[j-1];
3251
 
                                *dvar = *svar;
3252
 
                        }
3253
 
                        (*numvar)--;
3254
 
                        i--;
3255
 
                }
3256
 
        }
3257
 
}
3258
 
 
3259
 
/*
3260
 
 * Helper routine to find the equivalent to facet "facet" in library "lib".
3261
 
 */
3262
 
NODEPROTO *us_findfacetinotherlib(NODEPROTO *facet, LIBRARY *lib)
3263
 
{
3264
 
        REGISTER NODEPROTO *newnp;
3265
 
 
3266
 
        for(newnp = lib->firstnodeproto; newnp != NONODEPROTO; newnp = newnp->nextnodeproto)
3267
 
        {
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;
3271
 
                break;
3272
 
        }
3273
 
        return(newnp);
3274
 
}
3275
 
 
3276
 
/******************** TEXT OBJECTS ********************/
3277
 
 
3278
 
/*
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.
3282
 
 */
3283
 
void us_figuregrabpoint(UINTBIG *descript, INTBIG xcur, INTBIG ycur, INTBIG xc,
3284
 
        INTBIG yc, INTBIG xw, INTBIG yw)
3285
 
{
3286
 
        if (xcur < xc - xw/2)
3287
 
        {
3288
 
                /* grab-point is on the bottom left */
3289
 
                if (ycur < yc - yw/2)
3290
 
                {
3291
 
                        TDSETPOS(descript, VTPOSUPRIGHT);
3292
 
                        return;
3293
 
                }
3294
 
 
3295
 
                /* grab-point is on the top left */
3296
 
                if (ycur > yc + yw/2)
3297
 
                {
3298
 
                        TDSETPOS(descript, VTPOSDOWNRIGHT);
3299
 
                        return;
3300
 
                }
3301
 
 
3302
 
                /* grab-point is on the left */
3303
 
                TDSETPOS(descript, VTPOSRIGHT);
3304
 
                return;
3305
 
        }
3306
 
 
3307
 
        if (xcur > xc + xw/2)
3308
 
        {
3309
 
                /* grab-point is on the bottom right */
3310
 
                if (ycur < yc - yw/2)
3311
 
                {
3312
 
                        TDSETPOS(descript, VTPOSUPLEFT);
3313
 
                        return;
3314
 
                }
3315
 
 
3316
 
                /* grab-point is on the top right */
3317
 
                if (ycur > yc + yw/2)
3318
 
                {
3319
 
                        TDSETPOS(descript, VTPOSDOWNLEFT);
3320
 
                        return;
3321
 
                }
3322
 
 
3323
 
                /* grab-point is on the right */
3324
 
                TDSETPOS(descript, VTPOSLEFT);
3325
 
                return;
3326
 
        }
3327
 
 
3328
 
        /* grab-point is on the bottom */
3329
 
        if (ycur < yc - yw/2)
3330
 
        {
3331
 
                TDSETPOS(descript, VTPOSUP);
3332
 
                return;
3333
 
        }
3334
 
 
3335
 
        /* grab-point is on the top */
3336
 
        if (ycur > yc + yw/2)
3337
 
        {
3338
 
                TDSETPOS(descript, VTPOSDOWN);
3339
 
                return;
3340
 
        }
3341
 
 
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 &&
3344
 
                xcur <= xc + xw/6)
3345
 
        {
3346
 
                TDSETPOS(descript, VTPOSBOXED);
3347
 
                return;
3348
 
        }
3349
 
 
3350
 
        /* grab-point is simply centered */
3351
 
        TDSETPOS(descript, VTPOSCENT);
3352
 
}
3353
 
 
3354
 
/*
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.
3359
 
 */
3360
 
void us_figurevariableplace(UINTBIG *formerdesc, INTBIG count, char *par[])
3361
 
{
3362
 
        INTBIG xval, yval;
3363
 
        REGISTER INTBIG grab;
3364
 
 
3365
 
        if (count >= 2)
3366
 
        {
3367
 
                xval = atofr(par[0]) * 4 / WHOLE;
3368
 
                yval = atofr(par[1]) * 4 / WHOLE;
3369
 
                us_setdescriptoffset(formerdesc, xval, yval);
3370
 
        }
3371
 
        if (count >= 3)
3372
 
        {
3373
 
                grab = us_gettextposition(par[2]);
3374
 
                TDSETPOS(formerdesc, grab);
3375
 
        }
3376
 
}
3377
 
 
3378
 
/*
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.
3381
 
 */
3382
 
void us_setdescriptoffset(UINTBIG *formerdesc, INTBIG xval, INTBIG yval)
3383
 
{
3384
 
        REGISTER INTBIG oldx, oldy;
3385
 
 
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"));
3391
 
 
3392
 
        TDSETOFF(formerdesc, xval, yval);
3393
 
}
3394
 
 
3395
 
/*
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.
3399
 
 */
3400
 
void us_rotatedescript(GEOM *geom, UINTBIG *descript)
3401
 
{
3402
 
        us_rotatedescriptArb(geom, descript, FALSE);
3403
 
}
3404
 
 
3405
 
/*
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.
3409
 
 */
3410
 
void us_rotatedescriptI(GEOM *geom, UINTBIG *descript)
3411
 
{
3412
 
        us_rotatedescriptArb(geom, descript, TRUE);
3413
 
}
3414
 
 
3415
 
/*
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.
3420
 
 */
3421
 
void us_rotatedescriptArb(GEOM *geom, UINTBIG *descript, BOOLEAN invert)
3422
 
{
3423
 
        REGISTER INTBIG style;
3424
 
        REGISTER NODEINST *ni;
3425
 
        XARRAY trans;
3426
 
 
3427
 
        /* arcs do not rotate */
3428
 
        if (!geom->entryisnode) return;
3429
 
 
3430
 
        switch (TDGETPOS(descript))
3431
 
        {
3432
 
                case VTPOSCENT:
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;
3442
 
        }
3443
 
        ni = geom->entryaddr.ni;
3444
 
        if (invert)
3445
 
        {
3446
 
                if (ni->transpose == 0) makeangle((3600 - ni->rotation)%3600, 0, trans); else
3447
 
                        makeangle(ni->rotation, ni->transpose, trans);
3448
 
        } else
3449
 
        {
3450
 
                makeangle(ni->rotation, ni->transpose, trans);
3451
 
        }
3452
 
        style = rotatelabel(style, TDGETROTATION(descript), trans);
3453
 
        switch (style)
3454
 
        {
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;
3463
 
        }
3464
 
}
3465
 
 
3466
 
/*
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.
3470
 
 */
3471
 
void us_adjustdisplayabletext(NODEINST *ni)
3472
 
{
3473
 
        REGISTER INTBIG i;
3474
 
        REGISTER INTBIG halfx, halfy, lambda;
3475
 
        UINTBIG descript[TEXTDESCRIPTSIZE];
3476
 
        REGISTER VARIABLE *var;
3477
 
 
3478
 
        /* make sure this is the invisible pin */
3479
 
        if (ni->proto != gen_invispinprim) return;
3480
 
 
3481
 
        /* search for displayable text */
3482
 
        for(i=0; i<ni->numvar; i++)
3483
 
        {
3484
 
                var = &ni->firstvar[i];
3485
 
                if ((var->type&VDISPLAY) == 0) continue;
3486
 
 
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))
3493
 
                {
3494
 
                        case VTPOSCENT:
3495
 
                        case VTPOSBOXED:
3496
 
                                us_setdescriptoffset(descript, 0, 0);
3497
 
                                break;
3498
 
                        case VTPOSUP:
3499
 
                                us_setdescriptoffset(descript, 0, -halfy);
3500
 
                                break;
3501
 
                        case VTPOSDOWN:
3502
 
                                us_setdescriptoffset(descript, 0, halfy);
3503
 
                                break;
3504
 
                        case VTPOSLEFT:
3505
 
                                us_setdescriptoffset(descript, halfx, 0);
3506
 
                                break;
3507
 
                        case VTPOSRIGHT:
3508
 
                                us_setdescriptoffset(descript, -halfx, 0);
3509
 
                                break;
3510
 
                        case VTPOSUPLEFT:
3511
 
                                us_setdescriptoffset(descript, halfx, -halfy);
3512
 
                                break;
3513
 
                        case VTPOSUPRIGHT:
3514
 
                                us_setdescriptoffset(descript, -halfx, -halfy);
3515
 
                                break;
3516
 
                        case VTPOSDOWNLEFT:
3517
 
                                us_setdescriptoffset(descript, halfx, halfy);
3518
 
                                break;
3519
 
                        case VTPOSDOWNRIGHT:
3520
 
                                us_setdescriptoffset(descript, -halfx, halfy);
3521
 
                                break;
3522
 
                }
3523
 
                modifydescript((INTBIG)ni, VNODEINST, var, descript);
3524
 
        }
3525
 
}
3526
 
 
3527
 
/*
3528
 
 * routine to parse the "grab-point" specification in "pp" and return the
3529
 
 * code.  Prints an error message on error.
3530
 
 */
3531
 
INTBIG us_gettextposition(char *pp)
3532
 
{
3533
 
        REGISTER INTBIG l;
3534
 
 
3535
 
        l = strlen(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);
3547
 
        return(VTPOSCENT);
3548
 
}
3549
 
 
3550
 
/*
3551
 
 * routine to parse the "text size" specification in "pp" and return the
3552
 
 * code.  Prints an error message and returns -1 on error.
3553
 
 */
3554
 
INTBIG us_gettextsize(char *pp, INTBIG old)
3555
 
{
3556
 
        REGISTER INTBIG i, l;
3557
 
 
3558
 
        l = strlen(pp);
3559
 
        if (tolower(pp[l-1]) == 'p')
3560
 
        {
3561
 
                l = atoi(pp);
3562
 
                if (l <= 0) l = 8;
3563
 
                if (l > TXTMAXPOINTS) l = TXTMAXPOINTS;
3564
 
                return(TXTSETPOINTS(l));
3565
 
        }
3566
 
        if (tolower(pp[l-1]) == 'l')
3567
 
        {
3568
 
                l = atofr(pp) * 4 / WHOLE;
3569
 
                if (l <= 0) l = 4;
3570
 
                if (l > TXTMAXQLAMBDA) l = TXTMAXQLAMBDA;
3571
 
                return(TXTSETQLAMBDA(l));
3572
 
        }
3573
 
        if (namesamen(pp, "up", l) == 0 && l >= 1)
3574
 
        {
3575
 
                i = TXTGETPOINTS(old);
3576
 
                if (i > 0 && i < TXTMAXPOINTS) old = TXTSETPOINTS(i+1); else
3577
 
                {
3578
 
                        i = TXTGETQLAMBDA(old);
3579
 
                        if (i > 0 && i < TXTMAXQLAMBDA) old = TXTSETQLAMBDA(i+1);
3580
 
                }
3581
 
                return(old);
3582
 
        } else if (namesamen(pp, "down", l) == 0 && l >= 1)
3583
 
        {
3584
 
                i = TXTGETPOINTS(old);
3585
 
                if (i > 1) old = TXTSETPOINTS(i-1); else
3586
 
                {
3587
 
                        i = TXTGETQLAMBDA(old);
3588
 
                        if (i > 1) old = TXTSETQLAMBDA(i-1);
3589
 
                }
3590
 
                return(old);
3591
 
        }
3592
 
        us_abortcommand(_("Unrecognized text size: %s"), pp);
3593
 
        return(-1);
3594
 
}
3595
 
 
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 */
3604
 
 
3605
 
/*
3606
 
 * Routine to initialize text searching in edit window "win".
3607
 
 */
3608
 
void us_initsearchcircuittext(WINDOWPART *win)
3609
 
{
3610
 
        REGISTER NODEPROTO *np;
3611
 
 
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;
3619
 
}
3620
 
 
3621
 
void us_advancecircuittext(char *search, INTBIG bits)
3622
 
{
3623
 
        REGISTER NODEINST *ni;
3624
 
        REGISTER ARCINST *ai;
3625
 
        REGISTER PORTPROTO *pp;
3626
 
        REGISTER char *pt;
3627
 
        REGISTER INTBIG len;
3628
 
        REGISTER VARIABLE *var;
3629
 
        HIGHLIGHT newhigh;
3630
 
 
3631
 
        /* look for a node with this string */
3632
 
        while (us_searchcircuittextni != NONODEINST)
3633
 
        {
3634
 
                ni = us_searchcircuittextni;
3635
 
                while (us_searchcircuittextvarnum < ni->numvar)
3636
 
                {
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)
3642
 
                        {
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);
3647
 
 
3648
 
                                /* show the text */
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;
3661
 
                                return;
3662
 
                        } else
3663
 
                        {
3664
 
                                len = getlength(var);
3665
 
                                for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
3666
 
                                {
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);
3671
 
 
3672
 
                                        /* show the text */
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;
3685
 
                                        return;
3686
 
                                }
3687
 
                        }
3688
 
                }
3689
 
                us_searchcircuittextni = ni->nextnodeinst;
3690
 
                us_searchcircuittextvarnum = 0;
3691
 
        }
3692
 
 
3693
 
        /* look for an arc with this string */
3694
 
        while (us_searchcircuittextai != NOARCINST)
3695
 
        {
3696
 
                ai = us_searchcircuittextai;
3697
 
                while (us_searchcircuittextvarnum < ai->numvar)
3698
 
                {
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)
3704
 
                        {
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);
3709
 
 
3710
 
                                /* show the text */
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;
3723
 
                                return;
3724
 
                        } else
3725
 
                        {
3726
 
                                len = getlength(var);
3727
 
                                for(us_searchcircuittextline=0; us_searchcircuittextline<len; us_searchcircuittextline++)
3728
 
                                {
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);
3733
 
 
3734
 
                                        /* show the text */
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;
3747
 
                                        return;
3748
 
                                }
3749
 
                        }
3750
 
                }
3751
 
                us_searchcircuittextai = ai->nextarcinst;
3752
 
                us_searchcircuittextvarnum = 0;
3753
 
        }
3754
 
 
3755
 
        /* look for an export with this string */
3756
 
        while (us_searchcircuittextpp != NOPORTPROTO)
3757
 
        {
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);
3763
 
 
3764
 
                /* show the text */
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;
3777
 
                return;
3778
 
        }
3779
 
        us_searchcircuittextfound = FALSE;
3780
 
}
3781
 
 
3782
 
/*
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).
3786
 
 */
3787
 
INTBIG us_stringinstring(char *string, char *search, INTBIG bits)
3788
 
{
3789
 
        REGISTER INTBIG stringlen, searchlen, searchwid, i;
3790
 
 
3791
 
        stringlen = strlen(string);
3792
 
        searchlen = strlen(search);
3793
 
        searchwid = stringlen - searchlen;
3794
 
        if (searchwid < 0) return(-1);
3795
 
        if ((bits&4) == 0)
3796
 
        {
3797
 
                for(i=0; i<=searchwid; i++)
3798
 
                        if (namesamen(&string[i], search, searchlen) == 0) return(i);
3799
 
        } else
3800
 
        {
3801
 
                for(i=0; i<=searchwid; i++)
3802
 
                        if (strncmp(&string[i], search, searchlen) == 0) return(i);
3803
 
        }
3804
 
        return(-1);
3805
 
}
3806
 
 
3807
 
/*
3808
 
 * Routine to find the string "search" in the circuit in window "win".  "bits" is:
3809
 
 *  2  replace all with "replaceall"
3810
 
 *  4  case sensitive
3811
 
 */
3812
 
void us_searchcircuittext(WINDOWPART *win, char *search, char *replaceall, INTBIG bits)
3813
 
{
3814
 
        REGISTER NODEPROTO *np;
3815
 
        BOOLEAN found;
3816
 
 
3817
 
        np = win->curnodeproto;
3818
 
        if (np == NONODEPROTO) return;
3819
 
 
3820
 
        if ((bits&2) != 0)
3821
 
        {
3822
 
                found = FALSE;
3823
 
                for(;;)
3824
 
                {
3825
 
                        /* advance to the next circuit text */
3826
 
                        us_advancecircuittext(search, bits);
3827
 
                        if (!us_searchcircuittextfound) break;
3828
 
                        us_replacecircuittext(win, replaceall);
3829
 
                        found = TRUE;
3830
 
                }
3831
 
                if (!found) ttybeep(1);
3832
 
                return;
3833
 
        }
3834
 
        us_advancecircuittext(search, bits);
3835
 
        if (!us_searchcircuittextfound) ttybeep(1);
3836
 
}
3837
 
 
3838
 
/*
3839
 
 * Routine to replace the text last selected with "us_searchcircuittext()" with
3840
 
 * the string "replace".
3841
 
 */
3842
 
void us_replacecircuittext(WINDOWPART *win, char *replace)
3843
 
{
3844
 
        REGISTER HIGHLIGHT *high;
3845
 
        REGISTER INTBIG i, len, addr, type;
3846
 
        REGISTER VARIABLE *var;
3847
 
        REGISTER NODEINST *ni;
3848
 
        REGISTER PORTPROTO *pp;
3849
 
        REGISTER char *pt;
3850
 
 
3851
 
        if (!us_searchcircuittextfound) return;
3852
 
        high = us_getonehighlight();
3853
 
        if (high->status != HIGHTEXT) return;
3854
 
        if (high->fromgeom->entryisnode && high->fromvar == NOVARIABLE)
3855
 
        {
3856
 
                /* export text */
3857
 
                ni = high->fromgeom->entryaddr.ni;
3858
 
                pp = high->fromport;
3859
 
                (void)initinfstr();
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]);
3866
 
                us_pushhighlight();
3867
 
                us_clearhighlightcount();
3868
 
                us_renameport(pp, returninfstr());
3869
 
                us_pophighlight(FALSE);
3870
 
                us_endchanges(NOWINDOWPART);
3871
 
                return;
3872
 
        }
3873
 
 
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
3879
 
                type = VARCINST;
3880
 
        us_pushhighlight();
3881
 
        us_clearhighlightcount();
3882
 
        startobjectchange(addr, type);
3883
 
        if ((var->type&VISARRAY) != 0)
3884
 
        {
3885
 
                pt = ((char **)var->addr)[us_searchcircuittextline];
3886
 
                (void)initinfstr();
3887
 
                for(i=0; i<us_searchcircuittextstart; i++)
3888
 
                        (void)addtoinfstr(pt[i]);
3889
 
                (void)addstringtoinfstr(replace);
3890
 
                len = strlen(pt);
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());
3895
 
        } else
3896
 
        {
3897
 
                pt = (char *)var->addr;
3898
 
                (void)initinfstr();
3899
 
                for(i=0; i<us_searchcircuittextstart; i++)
3900
 
                        (void)addtoinfstr(pt[i]);
3901
 
                (void)addstringtoinfstr(replace);
3902
 
                len = strlen(pt);
3903
 
                for(i=us_searchcircuittextend; i<len; i++)
3904
 
                        (void)addtoinfstr(pt[i]);
3905
 
                (void)setvalkey(addr, type, var->key, (INTBIG)returninfstr(),
3906
 
                        var->type);
3907
 
        }
3908
 
        endobjectchange(addr, type);
3909
 
        us_pophighlight(FALSE);
3910
 
        us_endchanges(NOWINDOWPART);
3911
 
}
3912
 
 
3913
 
/************************ IN-PLACE VARIABLE EDITING ************************/
3914
 
 
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;
3929
 
 
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);
3937
 
 
3938
 
void us_editvariabletext(VARIABLE *var, INTBIG objtype, INTBIG objaddr, char *varname)
3939
 
{
3940
 
        INTBIG tsx, tsy;
3941
 
        UINTBIG textdescript[TEXTDESCRIPTSIZE];
3942
 
 
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)
3951
 
        {
3952
 
                us_editvarlength = 1;
3953
 
                (void)allocstring(&us_editvaroneline[0], describedisplayedvariable(var, -1, -1), us_tool->cluster);
3954
 
                if (TDGETDISPPART(var->textdescript) != VTDISPLAYVALUE)
3955
 
                {
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);
3960
 
                }
3961
 
                us_editvarlines = us_editvaroneline;
3962
 
        } else
3963
 
        {
3964
 
                us_editvarlength = getlength(var);
3965
 
                us_editvarlines = (char **)var->addr;
3966
 
        }
3967
 
        switch (objtype)
3968
 
        {
3969
 
                case VNODEINST:
3970
 
                        us_editvartech = ((NODEINST *)objaddr)->parent->tech;
3971
 
                        break;
3972
 
                case VARCINST:
3973
 
                        us_editvartech = ((ARCINST *)objaddr)->parent->tech;
3974
 
                        break;
3975
 
                case VPORTPROTO:
3976
 
                        us_editvartech = ((PORTPROTO *)objaddr)->subnodeinst->parent->tech;
3977
 
                        break;
3978
 
                case VNODEPROTO:
3979
 
                        us_editvartech = ((NODEPROTO *)objaddr)->tech;
3980
 
                        break;
3981
 
        }
3982
 
 
3983
 
        /* flush graphics */
3984
 
        us_endchanges(NOWINDOWPART);
3985
 
 
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;
3990
 
 
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();
3997
 
 
3998
 
        /* loop while editing text */
3999
 
        modalloop(us_editvariabletexthandlechar, us_editvariabletexthandlebutton, IBEAMCURSOR);
4000
 
 
4001
 
        /* remove highlighting */
4002
 
        us_editvariabletexthighlight();
4003
 
}
4004
 
 
4005
 
static BOOLEAN us_editvariabletexthandlebutton(INTBIG x, INTBIG y, INTBIG but)
4006
 
{
4007
 
        INTBIG line, chr;
4008
 
 
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))
4014
 
        {
4015
 
                if (line < us_editvarstartline || (line == us_editvarstartline &&
4016
 
                        chr < us_editvarstartchar))
4017
 
                {
4018
 
                        us_editvarstartline = line;
4019
 
                        us_editvarstartchar = chr;
4020
 
                } else if (line > us_editvarendline || (line == us_editvarendline &&
4021
 
                        chr > us_editvarendchar))
4022
 
                {
4023
 
                        us_editvarendline = line;
4024
 
                        us_editvarendchar = chr;
4025
 
                }
4026
 
        } else
4027
 
        {
4028
 
                us_editvarstartline = line;
4029
 
                us_editvarstartchar = chr;
4030
 
                us_editvarendline = line;
4031
 
                us_editvarendchar = chr;
4032
 
        }
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();
4039
 
 
4040
 
        trackcursor(FALSE, us_ignoreup, us_nullvoid, us_editvariabletexteachdown, us_stoponchar,
4041
 
                        us_nullvoid, TRACKNORMAL);
4042
 
        return(FALSE);
4043
 
}
4044
 
 
4045
 
BOOLEAN us_editvariabletexthandlechar(INTSML chr, INTBIG special)
4046
 
{
4047
 
        char replace[2], *pt;
4048
 
        REGISTER INTBIG startchar, endchar, i, j;
4049
 
 
4050
 
        if ((special&SPECIALKEYDOWN) != 0)
4051
 
        {
4052
 
                switch ((special&SPECIALKEY)>>SPECIALKEYSH)
4053
 
                {
4054
 
                        case SPECIALKEYARROWL:
4055
 
                                us_editvariabletexthighlight();
4056
 
                                if (us_editvarstartline == us_editvarendline &&
4057
 
                                        us_editvarstartchar == us_editvarendchar)
4058
 
                                {
4059
 
                                        if (us_editvarstartchar > 0)
4060
 
                                        {
4061
 
                                                if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4062
 
                                                        us_editvarstartchar--;
4063
 
                                        } else
4064
 
                                        {
4065
 
                                                if (us_editvarstartline > 0)
4066
 
                                                {
4067
 
                                                        us_editvarstartline--;
4068
 
                                                        us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4069
 
                                                }
4070
 
                                        }
4071
 
                                }
4072
 
                                us_editvarendline = us_editvarstartline;
4073
 
                                us_editvarendchar = us_editvarstartchar;
4074
 
                                us_editvariabletexthighlight();
4075
 
                                return(FALSE);
4076
 
                        case SPECIALKEYARROWR:
4077
 
                                us_editvariabletexthighlight();
4078
 
                                if (us_editvarstartline == us_editvarendline &&
4079
 
                                        us_editvarstartchar == us_editvarendchar)
4080
 
                                {
4081
 
                                        if (us_editvarendchar < (INTBIG)strlen(us_editvarlines[us_editvarendline]))
4082
 
                                                us_editvarendchar++; else
4083
 
                                        {
4084
 
                                                if (us_editvarendline < us_editvarlength-1)
4085
 
                                                {
4086
 
                                                        us_editvarendline++;
4087
 
                                                        us_editvarendchar = 0;
4088
 
                                                }
4089
 
                                        }
4090
 
                                }
4091
 
                                us_editvarstartline = us_editvarendline;
4092
 
                                us_editvarstartchar = us_editvarendchar;
4093
 
                                us_editvariabletexthighlight();
4094
 
                                return(FALSE);
4095
 
                        case SPECIALKEYARROWU:
4096
 
                                us_editvariabletexthighlight();
4097
 
                                if (us_editvarstartline > 0)
4098
 
                                {
4099
 
                                        us_editvarstartline--;
4100
 
                                        if (us_editvarstartchar > (INTBIG)strlen(us_editvarlines[us_editvarstartline]))
4101
 
                                                us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4102
 
                                }
4103
 
                                us_editvarendline = us_editvarstartline;
4104
 
                                us_editvarendchar = us_editvarstartchar;
4105
 
                                us_editvariabletexthighlight();
4106
 
                                return(FALSE);
4107
 
                        case SPECIALKEYARROWD:
4108
 
                                us_editvariabletexthighlight();
4109
 
                                if (us_editvarendline < us_editvarlength-1)
4110
 
                                {
4111
 
                                        us_editvarendline++;
4112
 
                                        if (us_editvarendchar > (INTBIG)strlen(us_editvarlines[us_editvarendline]))
4113
 
                                                us_editvarendchar = strlen(us_editvarlines[us_editvarendline]);
4114
 
                                }
4115
 
                                us_editvarstartline = us_editvarendline;
4116
 
                                us_editvarstartchar = us_editvarendchar;
4117
 
                                us_editvariabletexthighlight();
4118
 
                                return(FALSE);
4119
 
                }
4120
 
        }
4121
 
 
4122
 
        /* handle paste */
4123
 
        if ((special&ACCELERATORDOWN) != 0)
4124
 
        {
4125
 
                if (chr == 'v' || chr == 'V')
4126
 
                {
4127
 
                        pt = getcutbuffer();
4128
 
                        us_editvariabletexthighlight();
4129
 
                        us_editvariabletextreplacetext(pt);
4130
 
                        if ((us_editvariable->type&VISARRAY) == 0)
4131
 
                        {
4132
 
                                (void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4133
 
                                        us_tool->cluster);
4134
 
                                us_editvarlines = us_editvaroneline;
4135
 
                        } else
4136
 
                        {
4137
 
                                us_editvarlength = getlength(us_editvariable);
4138
 
                                us_editvarlines = (char **)us_editvariable->addr;
4139
 
                        }
4140
 
                        us_editvariabletexthighlight();
4141
 
                        return(FALSE);
4142
 
                }
4143
 
 
4144
 
                /* handle copy/cut */
4145
 
                if (chr == 'c' || chr == 'C' ||
4146
 
                        chr == 'x' || chr == 'X')
4147
 
                {
4148
 
                        (void)initinfstr();
4149
 
                        for(i=us_editvarstartline; i<=us_editvarendline; i++)
4150
 
                        {
4151
 
                                if (i > us_editvarstartline) (void)addtoinfstr('\n');
4152
 
                                startchar = 0;
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]);
4158
 
                        }
4159
 
                        setcutbuffer(returninfstr());
4160
 
                        if (chr == 'c' || chr == 'C') return(FALSE);
4161
 
                        chr = 0;
4162
 
                }
4163
 
        }
4164
 
 
4165
 
        /* delete what is selected and insert what was typed */
4166
 
        if (chr == '\n' || chr == '\r')
4167
 
        {
4168
 
                /* cannot insert second line if text is not an array */
4169
 
                if ((us_editvariable->type&VISARRAY) == 0) return(TRUE);
4170
 
        }
4171
 
        us_editvariabletexthighlight();
4172
 
        if (chr == DELETEKEY || chr == BACKSPACEKEY)
4173
 
        {
4174
 
                chr = 0;
4175
 
                if (us_editvarstartline == us_editvarendline &&
4176
 
                        us_editvarstartchar == us_editvarendchar)
4177
 
                {
4178
 
                        if (us_editvarstartchar > 0)
4179
 
                        {
4180
 
                                if (us_editvarstartline != 0 || us_editvarstartchar > us_editvarlabellen)
4181
 
                                        us_editvarstartchar--;
4182
 
                        } else
4183
 
                        {
4184
 
                                if (us_editvarstartline > 0)
4185
 
                                {
4186
 
                                        us_editvarstartline--;
4187
 
                                        us_editvarstartchar = strlen(us_editvarlines[us_editvarstartline]);
4188
 
                                }
4189
 
                        }
4190
 
                }
4191
 
        }
4192
 
        replace[0] = (char)chr;
4193
 
        replace[1] = 0;
4194
 
        us_editvariabletextreplacetext(replace);
4195
 
        if ((us_editvariable->type&VISARRAY) == 0)
4196
 
        {
4197
 
                (void)reallocstring(&us_editvaroneline[0], describedisplayedvariable(us_editvariable, -1, -1),
4198
 
                        us_tool->cluster);
4199
 
                us_editvarlines = us_editvaroneline;
4200
 
        } else
4201
 
        {
4202
 
                us_editvarlength = getlength(us_editvariable);
4203
 
                us_editvarlines = (char **)us_editvariable->addr;
4204
 
        }
4205
 
        us_editvariabletexthighlight();
4206
 
        return(FALSE);
4207
 
}
4208
 
 
4209
 
void us_editvariabletextreplacetext(char *replace)
4210
 
{
4211
 
        void *stringarray;
4212
 
        REGISTER INTBIG i, newline, newchar;
4213
 
        char **newtext;
4214
 
        REGISTER VARIABLE *var;
4215
 
        INTBIG newtype, newvalue, count;
4216
 
 
4217
 
        stringarray = newstringarray(el_tempcluster);
4218
 
 
4219
 
        /* add all lines before the start of selection */
4220
 
        newline = 0;
4221
 
        for(i=0; i<us_editvarstartline; i++)
4222
 
        {
4223
 
                if (i != 0) addtostringarray(stringarray, us_editvarlines[i]); else
4224
 
                        addtostringarray(stringarray, &us_editvarlines[i][us_editvarlabellen]);                 
4225
 
                newline++;
4226
 
        }
4227
 
 
4228
 
        /* build the line with the selection start */
4229
 
        if (newline == 0) newchar = us_editvarlabellen; else newchar = 0;
4230
 
        (void)initinfstr();
4231
 
        for(i=newchar; i<us_editvarstartchar; i++)
4232
 
        {
4233
 
                (void)addtoinfstr(us_editvarlines[us_editvarstartline][i]);
4234
 
                newchar++;
4235
 
        }
4236
 
 
4237
 
        /* now add the replacement text */
4238
 
        for(i=0; i<(INTBIG)strlen(replace); i++)
4239
 
        {
4240
 
                if (replace[i] == '\n' || replace[i] == '\r')
4241
 
                {
4242
 
                        addtostringarray(stringarray, returninfstr());
4243
 
                        (void)initinfstr();
4244
 
                        newline++;
4245
 
                        newchar = 0;
4246
 
                } else
4247
 
                {
4248
 
                        (void)addtoinfstr(replace[i]);
4249
 
                        newchar++;
4250
 
                }
4251
 
        }
4252
 
 
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());
4257
 
 
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]);
4261
 
 
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)
4270
 
        {
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);
4275
 
        } else
4276
 
        {
4277
 
                newtype = (us_editvariable->type & ~VLENGTH) | (count << VLENGTHSH);
4278
 
                var = setval(us_editvarobjaddr, us_editvarobjtype,
4279
 
                        us_editvarvarname, (INTBIG)newtext, newtype);
4280
 
        }
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);
4289
 
 
4290
 
        /* set the new selection point */
4291
 
        us_editvarstartline = us_editvarendline = newline;
4292
 
        us_editvarstartchar = us_editvarendchar = newchar;
4293
 
}
4294
 
 
4295
 
BOOLEAN us_editvariabletexteachdown(INTBIG x, INTBIG y)
4296
 
{
4297
 
        INTBIG line, chr, startline, startchar, endline, endchar;
4298
 
 
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))
4306
 
        {
4307
 
                startline = us_editvarclickline;
4308
 
                startchar = us_editvarclickchar;
4309
 
                endline = line;
4310
 
                endchar = chr;
4311
 
                if (us_editvariabledoubleclick)
4312
 
                        us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4313
 
        }
4314
 
        if (line < us_editvarclickline || (line == us_editvarclickline && chr < us_editvarclickchar))
4315
 
        {
4316
 
                startline = line;
4317
 
                startchar = chr;
4318
 
                endline = us_editvarclickline;
4319
 
                endchar = us_editvarclickchar;
4320
 
                if (us_editvariabledoubleclick)
4321
 
                        us_editvariableforcefullwords(&startline, &startchar, &endline, &endchar);
4322
 
        }
4323
 
        if (startline != us_editvarstartline || startchar != us_editvarstartchar ||
4324
 
                endline != us_editvarendline || endchar != us_editvarendchar)
4325
 
        {
4326
 
                us_editvariabletexthighlight();
4327
 
                us_editvarstartline = startline;
4328
 
                us_editvarstartchar = startchar;
4329
 
                us_editvarendline = endline;
4330
 
                us_editvarendchar = endchar;
4331
 
                us_editvariabletexthighlight();
4332
 
        }
4333
 
        return(FALSE);
4334
 
}
4335
 
 
4336
 
void us_editvariableforcefullwords(INTBIG *startline, INTBIG *startchar, INTBIG *endline, INTBIG *endchar)
4337
 
{
4338
 
        char *pt;
4339
 
        INTBIG len;
4340
 
 
4341
 
        pt = us_editvarlines[*startline];
4342
 
        while (*startchar > 0 && isalnum(pt[*startchar - 1]))
4343
 
                (*startchar)--;
4344
 
 
4345
 
        pt = us_editvarlines[*endline];
4346
 
        len = strlen(pt);
4347
 
        while (*endchar < len && isalnum(pt[*endchar]))
4348
 
                (*endchar)++;
4349
 
}
4350
 
 
4351
 
BOOLEAN us_editvariabletextfindpos(INTBIG xp, INTBIG yp, INTBIG *line, INTBIG *chr)
4352
 
{
4353
 
        REGISTER INTBIG i, j, screenlx, screenhx, screenly, screenhy;
4354
 
        char save;
4355
 
        INTBIG x, y;
4356
 
        INTBIG tsx, tsy;
4357
 
        REGISTER INTBIG lasttsx, charwid;
4358
 
 
4359
 
        /* determine text size */
4360
 
        screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4361
 
        for(i = 0; i < us_editvarlength; i++)
4362
 
        {
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;
4375
 
                *line = i;
4376
 
                lasttsx = 0;
4377
 
                for(j=1; j<=(INTBIG)strlen(us_editvarlines[i]); j++)
4378
 
                {
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;
4383
 
                        lasttsx = tsx;
4384
 
                        us_editvarlines[i][j] = save;
4385
 
                        if (xp < screenlx + tsx - charwid/2) break;
4386
 
                }
4387
 
                *chr = j-1;
4388
 
                return(TRUE);
4389
 
        }
4390
 
        return(FALSE);
4391
 
}
4392
 
 
4393
 
void us_editvariabletexthighlight(void)
4394
 
{
4395
 
        REGISTER INTBIG i, j, startch;
4396
 
        char save;
4397
 
        INTBIG x, y, screenlx, screenhx, screenly, screenhy;
4398
 
        INTBIG tsx, tsy;
4399
 
 
4400
 
        /* determine text size */
4401
 
        screensettextinfo(el_curwindowpart, us_editvartech, us_editvariable->textdescript);
4402
 
        for(i = us_editvarstartline; i <= us_editvarendline; i++)
4403
 
        {
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;
4410
 
                startch = 0;
4411
 
                if (i == us_editvarstartline && us_editvarstartchar != 0)
4412
 
                {
4413
 
                        save = us_editvarlines[i][us_editvarstartchar];
4414
 
                        us_editvarlines[i][us_editvarstartchar] = 0;
4415
 
                        screengettextsize(el_curwindowpart, us_editvarlines[i], &tsx, &tsy);
4416
 
                        screenlx += tsx;
4417
 
                        us_editvarlines[i][us_editvarstartchar] = save;
4418
 
                        startch = us_editvarstartchar;
4419
 
                }
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);
4436
 
        }
4437
 
}
4438
 
 
4439
 
/******************** USER-BROADCAST CHANGES ********************/
4440
 
 
4441
 
/*
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.
4445
 
 */
4446
 
BOOLEAN us_newubchange(INTBIG change, void *object)
4447
 
{
4448
 
        REGISTER UBCHANGE *d;
4449
 
 
4450
 
        if (us_ubchangefree == NOUBCHANGE)
4451
 
        {
4452
 
                d = (UBCHANGE *)emalloc((sizeof (UBCHANGE)), us_tool->cluster);
4453
 
                if (d == 0) return(TRUE);
4454
 
        } else
4455
 
        {
4456
 
                /* take ubchange from free list */
4457
 
                d = us_ubchangefree;
4458
 
                us_ubchangefree = (UBCHANGE *)d->nextubchange;
4459
 
        }
4460
 
        d->object = object;
4461
 
        d->change = change;
4462
 
        d->nextubchange = us_ubchanges;
4463
 
        us_ubchanges = d;
4464
 
        return(FALSE);
4465
 
}
4466
 
 
4467
 
/*
4468
 
 * routine to return ubchange "d" to the pool of free ubchanges
4469
 
 */
4470
 
void us_freeubchange(UBCHANGE *d)
4471
 
{
4472
 
        d->nextubchange = us_ubchangefree;
4473
 
        us_ubchangefree = d;
4474
 
}
4475
 
 
4476
 
/*
4477
 
 * routine to remove all queued user broadcast changes to facet "np"
4478
 
 * because it was deleted
4479
 
 */
4480
 
void us_removeubchange(NODEPROTO *np)
4481
 
{
4482
 
        REGISTER UBCHANGE *d, *lastd, *nextd;
4483
 
        REGISTER NODEPROTO *thisnp;
4484
 
 
4485
 
        lastd = NOUBCHANGE;
4486
 
        for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4487
 
        {
4488
 
                nextd = d->nextubchange;
4489
 
                if (d->change == UBNEWFC) thisnp = ((NODEINST *)d->object)->parent; else
4490
 
                        thisnp = (NODEPROTO *)d->object;
4491
 
                if (thisnp == np)
4492
 
                {
4493
 
                        if (lastd == NOUBCHANGE) us_ubchanges = nextd; else
4494
 
                                lastd->nextubchange = nextd;
4495
 
                        us_freeubchange(d);
4496
 
                        continue;
4497
 
                }
4498
 
                lastd = d;
4499
 
        }
4500
 
}
4501
 
 
4502
 
/*
4503
 
 * routine to remove variable "FACET_message" from facet "np".
4504
 
 */
4505
 
void us_delfacetmessage(NODEPROTO *np)
4506
 
{
4507
 
        (void)us_newubchange(UBKILLFM, np);
4508
 
}
4509
 
 
4510
 
/*
4511
 
 * routine to add a facet-center to facet "np"
4512
 
 */
4513
 
void us_addfacetcenter(NODEINST *ni)
4514
 
{
4515
 
        (void)us_newubchange(UBNEWFC, ni);
4516
 
}
4517
 
 
4518
 
/*
4519
 
 * routine to implement all user broadcast changes queued during the last broadcast
4520
 
 */
4521
 
void us_doubchanges(void)
4522
 
{
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;
4529
 
 
4530
 
        for(d = us_ubchanges; d != NOUBCHANGE; d = nextd)
4531
 
        {
4532
 
                nextd = d->nextubchange;
4533
 
 
4534
 
                switch (d->change)
4535
 
                {
4536
 
                        case UBKILLFM:  /* remove facet_message */
4537
 
                                np = (NODEPROTO *)d->object;
4538
 
                                for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4539
 
                                {
4540
 
                                        if (w->curnodeproto != np) continue;
4541
 
                                        if ((w->state&WINDOWTYPE) != TEXTWINDOW) continue;
4542
 
 
4543
 
                                        /* see if the window still has a valid variable */
4544
 
                                        ed = w->editor;
4545
 
                                        if (ed->editobjvar == NOVARIABLE) continue;
4546
 
                                        var = getval((INTBIG)ed->editobjaddr, ed->editobjtype, -1, ed->editobjqual);
4547
 
                                        if (var == NOVARIABLE)
4548
 
                                        {
4549
 
                                                (void)newwindowpart(w->location, w);
4550
 
                                                killwindowpart(w);
4551
 
                                        }
4552
 
                                }
4553
 
                                break;
4554
 
                        case UBNEWFC:   /* added facet-center */
4555
 
                                ni = (NODEINST *)d->object;
4556
 
                                np = ni->parent;
4557
 
                                for(oni = np->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
4558
 
                                {
4559
 
                                        if (oni == ni) continue;
4560
 
                                        if (oni->proto == gen_facetcenterprim)
4561
 
                                        {
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);
4567
 
                                                break;
4568
 
                                        }
4569
 
                                }
4570
 
                                if (oni == NONODEINST)
4571
 
                                        us_setnodeprotocenter(ni->lowx, ni->lowy, np);
4572
 
                                break;
4573
 
                }
4574
 
 
4575
 
                /* cleanup */
4576
 
                us_freeubchange(d);
4577
 
        }
4578
 
        us_ubchanges = NOUBCHANGE;
4579
 
}
4580
 
 
4581
 
/******************** COLOR ********************/
4582
 
 
4583
 
/*
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
4598
 
 * technologies.
4599
 
 */
4600
 
void us_getcolormap(TECHNOLOGY *tech, INTBIG style, BOOLEAN broadcast)
4601
 
{
4602
 
        static TECH_COLORMAP colmap[38] =
4603
 
        {
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         */
4642
 
        };
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 */
4677
 
        };
4678
 
 
4679
 
        TECH_COLORMAP *mapptr, *thisptr;
4680
 
        REGISTER INTBIG i;
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;
4685
 
 
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;
4690
 
 
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);
4695
 
 
4696
 
        /* must have some colors */
4697
 
        if (rvar == NOVARIABLE && gvar == NOVARIABLE && bvar == NOVARIABLE && var == NOVARIABLE)
4698
 
        {
4699
 
                mapptr = default_colmap;
4700
 
        }
4701
 
 
4702
 
        if (style == COLORSEXISTING)
4703
 
        {
4704
 
                /* not resetting, get the old color values */
4705
 
                for(i=0; i<256; i++)
4706
 
                {
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;
4716
 
                }
4717
 
        } else
4718
 
        {
4719
 
#if SIMTOOL
4720
 
                /* update simulation window colors */
4721
 
                switch (style)
4722
 
                {
4723
 
                        case COLORSWHITE:
4724
 
                        case COLORSDEFAULT:
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);
4732
 
                                break;
4733
 
                        case COLORSBLACK:
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);
4741
 
                                break;
4742
 
                }
4743
 
#endif
4744
 
 
4745
 
                /* resetting: load entirely new color map */
4746
 
                for(i=0; i<256; i++)
4747
 
                {
4748
 
                        if ((i&LAYERH) != 0)
4749
 
                        {
4750
 
                                switch (style)
4751
 
                                {
4752
 
                                        case COLORSDEFAULT: thisptr = &colmap[33];   break;     /* white */
4753
 
                                        case COLORSBLACK:   thisptr = &colmap[34];   break;     /* red */
4754
 
                                        case COLORSWHITE:   thisptr = &colmap[35];   break;     /* red */
4755
 
                                }
4756
 
                        } else if ((i&LAYERG) != 0)
4757
 
                        {
4758
 
                                switch (style)
4759
 
                                {
4760
 
                                        case COLORSDEFAULT: thisptr = &colmap[32];   break;     /* black */
4761
 
                                        case COLORSBLACK:   thisptr = &colmap[33];   break;     /* white */
4762
 
                                        case COLORSWHITE:   thisptr = &colmap[32];   break;     /* black */
4763
 
                                }
4764
 
                        } else if ((i&LAYEROE) != 0)
4765
 
                        {
4766
 
                                thisptr = &colmap[i>>2];
4767
 
 
4768
 
                                if (i == HMENBOR) switch (style)
4769
 
                                {
4770
 
                                        case COLORSBLACK: thisptr = &colmap[2];   break;        /* red */
4771
 
                                        case COLORSWHITE: thisptr = &colmap[2];   break;        /* red */
4772
 
                                }
4773
 
                                if (i == CURSOR) switch (style)
4774
 
                                {
4775
 
                                        case COLORSDEFAULT: thisptr = &colmap[16];   break;     /* default */
4776
 
                                        case COLORSBLACK:   thisptr = &colmap[36];   break;     /* white */
4777
 
                                        case COLORSWHITE:   thisptr = &colmap[37];   break;     /* black */
4778
 
                                }
4779
 
 
4780
 
                                /* reverse black and white when using black background */
4781
 
                                if (style == COLORSBLACK)
4782
 
                                {
4783
 
                                        switch (i)
4784
 
                                        {
4785
 
                                                case FACETTXT:
4786
 
                                                case FACETOUT:
4787
 
                                                case WINBOR:
4788
 
                                                case MENBOR:
4789
 
                                                case MENTXT:
4790
 
                                                case MENGLY:
4791
 
                                                case BLACK:    thisptr = &colmap[33];   break;          /* white */
4792
 
                                                case WHITE:    thisptr = &colmap[37];   break;          /* black */
4793
 
                                        }
4794
 
                                }
4795
 
                        } else
4796
 
                        {
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)
4802
 
                                {
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 */
4806
 
                                }
4807
 
                                if (thisptr == 0) continue;
4808
 
                        }
4809
 
                        red[i]  = thisptr->red;   green[i]   = thisptr->green;
4810
 
                        blue[i] = thisptr->blue;
4811
 
                }
4812
 
 
4813
 
                /* also set the grid color appropriately if it doesn't have its own bitplane */
4814
 
                if (el_maplength < 256)
4815
 
                {
4816
 
                        switch (style)
4817
 
                        {
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 */
4821
 
                        }
4822
 
                }
4823
 
        }
4824
 
 
4825
 
        /* set the color map */
4826
 
        if (broadcast)
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));
4837
 
        if (broadcast)
4838
 
                endobjectchange((INTBIG)us_tool, VTOOL);
4839
 
}
4840
 
 
4841
 
/*
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.
4845
 
 */
4846
 
void us_setcolorentry(INTBIG entry1, INTBIG red, INTBIG green, INTBIG blue, INTBIG letter,
4847
 
        BOOLEAN spread)
4848
 
{
4849
 
        REGISTER INTBIG j;
4850
 
 
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);
4855
 
 
4856
 
        /* place in other entries if special */
4857
 
        if ((entry1&LAYERH) == LAYERH && spread)
4858
 
        {
4859
 
                /* set all highlight colors */
4860
 
                for(j=0; j<256; j++) if ((j&LAYERH) == LAYERH)
4861
 
                {
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);
4865
 
                }
4866
 
        } else if ((entry1&(LAYERG|LAYERH)) == LAYERG && spread)
4867
 
        {
4868
 
                /* set all grid colors */
4869
 
                for(j=0; j<256; j++) if ((j&(LAYERG|LAYERH)) == LAYERG)
4870
 
                {
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);
4874
 
                }
4875
 
        }
4876
 
        endobjectchange((INTBIG)us_tool, VTOOL);
4877
 
}
4878
 
 
4879
 
/*
4880
 
 * routine to convert a red/green/blue color in (ir,ig,ib) to a hue/saturation/
4881
 
 * intensity color in (h,s,i)
4882
 
 */
4883
 
void us_rgbtohsv(INTBIG ir, INTBIG ig, INTBIG ib, float *h, float *s, float *i)
4884
 
{
4885
 
        float x, r, g, b, rdot, gdot, bdot;
4886
 
 
4887
 
        r = ir / 255.0f;
4888
 
        g = ig / 255.0f;
4889
 
        b = ib / 255.0f;
4890
 
 
4891
 
        /* "i" is maximum of "r", "g", and "b" */
4892
 
        if (r > g) *i = r; else *i = g;
4893
 
        if (b > *i) *i = b;
4894
 
 
4895
 
        /* "x" is minimum of "r", "g", and "b" */
4896
 
        if (r < g) x = r; else x = g;
4897
 
        if (b < x) x = b;
4898
 
 
4899
 
        /* "saturation" is (i-x)/i */
4900
 
        if (*i == 0.0) *s = 0.0; else *s = (*i - x) / *i;
4901
 
 
4902
 
        if (*s == 0.0) *h = 0.0; else
4903
 
        {
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);
4914
 
        }
4915
 
}
4916
 
 
4917
 
/*
4918
 
 * routine to convert a hue/saturation/intensity color in (h,s,v) to a red/
4919
 
 * green/blue color in (r,g,b)
4920
 
 */
4921
 
void us_hsvtorgb(float h, float s, float v, INTBIG *r, INTBIG *g, INTBIG *b)
4922
 
{
4923
 
        REGISTER INTBIG i;
4924
 
        REGISTER float f, m, n, k;
4925
 
 
4926
 
        h = h * 6.0f;
4927
 
        i = (INTBIG)h;
4928
 
        f = h - (float)i;
4929
 
        m = v * (1.0f - s);
4930
 
        n = v * (1.0f - s * f);
4931
 
        k = v * (1.0f - s * (1.0f - f));
4932
 
        switch (i)
4933
 
        {
4934
 
                case 0:
4935
 
                        *r = (INTBIG)(v*255.0); *g = (INTBIG)(k*255.0); *b = (INTBIG)(m*255.0);
4936
 
                        break;
4937
 
                case 1:
4938
 
                        *r = (INTBIG)(n*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(m*255.0);
4939
 
                        break;
4940
 
                case 2:
4941
 
                        *r = (INTBIG)(m*255.0); *g = (INTBIG)(v*255.0); *b = (INTBIG)(k*255.0);
4942
 
                        break;
4943
 
                case 3:
4944
 
                        *r = (INTBIG)(m*255.0); *g = (INTBIG)(n*255.0); *b = (INTBIG)(v*255.0);
4945
 
                        break;
4946
 
                case 4:
4947
 
                        *r = (INTBIG)(k*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(v*255.0);
4948
 
                        break;
4949
 
                case 5:
4950
 
                        *r = (INTBIG)(v*255.0); *g = (INTBIG)(m*255.0); *b = (INTBIG)(n*255.0);
4951
 
                        break;
4952
 
        }
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);
4955
 
}
4956
 
 
4957
 
/******************** MISCELLANEOUS ********************/
4958
 
 
4959
 
/*
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".
4962
 
 */
4963
 
void us_getlenwidoffset(NODEINST *ni, UINTBIG *descript, INTBIG *xoff, INTBIG *yoff)
4964
 
{
4965
 
        REGISTER INTBIG i;
4966
 
 
4967
 
        *xoff = *yoff = 0;
4968
 
        i = TXTGETQLAMBDA(TDGETSIZE(descript));
4969
 
        if (i > 4) i /= 2; else i = 2;
4970
 
        switch (ni->rotation)
4971
 
        {
4972
 
                case 0:
4973
 
                        if (ni->transpose == 0) *yoff = i; else
4974
 
                                *xoff = -i;
4975
 
                        break;
4976
 
                case 900:
4977
 
                        if (ni->transpose == 0) *xoff = i; else
4978
 
                                *yoff = i;
4979
 
                        break;
4980
 
                case 1800:
4981
 
                        if (ni->transpose == 0) *yoff = -i; else
4982
 
                                *xoff = i;
4983
 
                        break;
4984
 
                case 2700:
4985
 
                        if (ni->transpose == 0) *xoff = -i; else
4986
 
                                *yoff = -i;
4987
 
                        break;
4988
 
        }
4989
 
}
4990
 
 
4991
 
/*
4992
 
 * Routine to return the placement angle to use for node "np".
4993
 
 */
4994
 
INTBIG us_getplacementangle(NODEPROTO *np)
4995
 
{
4996
 
        REGISTER VARIABLE *var;
4997
 
 
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);
5002
 
        return(0);
5003
 
}
5004
 
 
5005
 
/*
5006
 
 * Routine to get the "displayed" location of node "ni" and return it in
5007
 
 * (xpos, ypos).
5008
 
 */
5009
 
void us_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos)
5010
 
{
5011
 
        REGISTER NODEPROTO *np;
5012
 
        INTBIG cox, coy, plx, ply, phx, phy;
5013
 
        REGISTER INTBIG dx, dy;
5014
 
        REGISTER VARIABLE *var;
5015
 
        XARRAY trans;
5016
 
 
5017
 
        np = ni->proto;
5018
 
        if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
5019
 
        {
5020
 
                corneroffset(ni, np, ni->rotation, ni->transpose, &cox, &coy, FALSE);
5021
 
                *xpos = ni->lowx+cox;
5022
 
                *ypos = ni->lowy+coy;
5023
 
        } else
5024
 
        {
5025
 
                var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
5026
 
                if (var != NOVARIABLE)
5027
 
                {
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;
5032
 
                        makerot(ni, trans);
5033
 
                        xform(dx, dy, &cox, &coy, trans);
5034
 
                        *xpos = cox;
5035
 
                        *ypos = coy;
5036
 
                } else
5037
 
                {
5038
 
                        nodesizeoffset(ni, &plx, &ply, &phx, &phy);
5039
 
                        makerot(ni, trans);
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);
5043
 
                }
5044
 
        }
5045
 
}
5046
 
 
5047
 
/*
5048
 
 * routine to put facet center (x, y) on facet "np".
5049
 
 */
5050
 
void us_setnodeprotocenter(INTBIG x, INTBIG y, NODEPROTO *np)
5051
 
{
5052
 
        INTBIG position[2];
5053
 
 
5054
 
        position[0] = x;   position[1] = y;
5055
 
        nextchangequiet();
5056
 
        (void)setvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key,
5057
 
                (INTBIG)position, VINTEGER|VISARRAY|(2<<VLENGTHSH));
5058
 
}
5059
 
 
5060
 
/*
5061
 
 * routine to remove facet center from facet "np".
5062
 
 */
5063
 
void us_delnodeprotocenter(NODEPROTO *np)
5064
 
{
5065
 
        nextchangequiet();
5066
 
        (void)delvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key);
5067
 
}
5068
 
 
5069
 
void us_getlowleft(NODEINST *ni, INTBIG *x, INTBIG *y)
5070
 
{
5071
 
        INTBIG lx, ly, hx, hy;
5072
 
        XARRAY trans;
5073
 
        static POLYGON *poly = NOPOLYGON;
5074
 
 
5075
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_tool->cluster);
5076
 
 
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)
5080
 
        {
5081
 
                makerot(ni, trans);
5082
 
                xformpoly(poly, trans);
5083
 
        }
5084
 
        getbbox(poly, x, &hx, y, &hy);
5085
 
}
5086
 
 
5087
 
/*
5088
 
 * routine to modify the text descriptor in the highlighted object "high"
5089
 
 */
5090
 
void us_modifytextdescript(HIGHLIGHT *high, UINTBIG *descript)
5091
 
{
5092
 
        REGISTER VARIABLE *var;
5093
 
 
5094
 
        if (high->fromvar != NOVARIABLE)
5095
 
        {
5096
 
                var = high->fromvar;
5097
 
                if (high->fromvarnoeval != NOVARIABLE) var = high->fromvarnoeval;
5098
 
                if (TDDIFF(descript, var->textdescript))
5099
 
                {
5100
 
                        if (high->fromport != NOPORTPROTO)
5101
 
                        {
5102
 
                                modifydescript((INTBIG)high->fromport, VPORTPROTO, high->fromvar, descript);
5103
 
                        } else if (high->fromgeom == NOGEOM)
5104
 
                        {
5105
 
                                modifydescript((INTBIG)high->facet, VNODEPROTO, var, descript);
5106
 
                        } else
5107
 
                        {
5108
 
                                modifydescript((INTBIG)high->fromgeom->entryaddr.blind,
5109
 
                                        high->fromgeom->entryisnode ? VNODEINST : VARCINST, var, descript);
5110
 
                        }
5111
 
                }
5112
 
                return;
5113
 
        }
5114
 
        if (high->fromport != NOPORTPROTO)
5115
 
        {
5116
 
                (void)setind((INTBIG)high->fromport, VPORTPROTO, "textdescript", 0, descript[0]);
5117
 
                (void)setind((INTBIG)high->fromport, VPORTPROTO, "textdescript", 1, descript[1]);
5118
 
                return;
5119
 
        }
5120
 
        if (high->fromgeom->entryisnode)
5121
 
        {
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]);
5126
 
                return;
5127
 
        }
5128
 
}
5129
 
 
5130
 
/*
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".
5133
 
 */
5134
 
void us_adjustpopupmenu(POPUPMENU *pm, INTBIG pindex)
5135
 
{
5136
 
        char **lines, *popupname;
5137
 
        char *pt;
5138
 
        VARIABLE *var;
5139
 
        COMMANDBINDING commandbinding;
5140
 
 
5141
 
        (void)initinfstr();
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)
5147
 
        {
5148
 
                lines = (char **)var->addr;
5149
 
                us_parsebinding(lines[pindex+1], &commandbinding);
5150
 
                (void)initinfstr();
5151
 
                for(pt = lines[pindex+1]; *pt != 0; pt++)
5152
 
                {
5153
 
                        if (strncmp(pt, "message=\"", 9) == 0)
5154
 
                        {
5155
 
                                (void)addstringtoinfstr("message=\"");
5156
 
                                pt += 9;
5157
 
                                while (*pt != 0 && *pt != '"') pt++;
5158
 
                                (void)addstringtoinfstr(pm->list[pindex].attribute);
5159
 
                        }
5160
 
                        (void)addtoinfstr(*pt);
5161
 
                }
5162
 
                nextchangequiet();
5163
 
                (void)setind((INTBIG)us_tool, VTOOL, popupname, pindex+1, (INTBIG)returninfstr());
5164
 
                us_freebindingparse(&commandbinding);
5165
 
        }
5166
 
}
5167
 
 
5168
 
/*
5169
 
 * Routine to return true if "name" is legal for objects of type "type".
5170
 
 */
5171
 
BOOLEAN us_validname(char *name, INTBIG type)
5172
 
{
5173
 
        REGISTER char *pt;
5174
 
 
5175
 
        for(pt = name; *pt != 0; pt++)
5176
 
        {
5177
 
                if (*pt == ' ' || *pt == '\t')
5178
 
                {
5179
 
                        ttyputerr(_("Name cannot have embedded spaces"));
5180
 
                        return(FALSE);
5181
 
                }
5182
 
                if (*pt < ' ' || *pt >= 0177)
5183
 
                {
5184
 
                        ttyputerr(_("Name has unprintable characters"));
5185
 
                        return(FALSE);
5186
 
                }
5187
 
                if (type == VNODEPROTO || type == VCELL)
5188
 
                {
5189
 
                        if (*pt == ':' || *pt == ';' || *pt == '{')
5190
 
                        {
5191
 
                                ttyputerr(_("Name cannot have '%c' in it"), *pt);
5192
 
                                return(FALSE);
5193
 
                        }
5194
 
                }
5195
 
                if (type == VARCPROTO || type == VTECHNOLOGY || type == VLIBRARY)
5196
 
                {
5197
 
                        if (*pt == ':')
5198
 
                        {
5199
 
                                ttyputerr(_("Name cannot have '%c' in it"), *pt);
5200
 
                                return(FALSE);
5201
 
                        }
5202
 
                }
5203
 
        }
5204
 
        return(TRUE);
5205
 
}
5206
 
 
5207
 
/*
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")
5212
 
 * is modified.
5213
 
 */
5214
 
INTBIG us_inheritaddress(INTBIG addr, INTBIG type, VARIABLE *var)
5215
 
{
5216
 
        REGISTER char *str;
5217
 
        char line[30];
5218
 
        REGISTER INTBIG i, j, len, incrpoint, retval, curval;
5219
 
 
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);
5223
 
 
5224
 
        str = (char *)var->addr;
5225
 
        len = strlen(str);
5226
 
        for(i=0; i<len; i++)
5227
 
        {
5228
 
                if (str[i] == '+' && str[i+1] == '+') break;
5229
 
                if (str[i] == '-' && str[i+1] == '-') break;
5230
 
        }
5231
 
        if (i >= len) return(var->addr);
5232
 
 
5233
 
        /* construct the proper inherited string and increment the variable */
5234
 
        (void)initinfstr();
5235
 
        for(i=0; i<len; i++)
5236
 
        {
5237
 
                if (str[i] == '+' && str[i+1] == '+')
5238
 
                {
5239
 
                        incrpoint = i;
5240
 
                        i++;
5241
 
                        continue;
5242
 
                }
5243
 
                if (str[i] == '-' && str[i+1] == '-')
5244
 
                {
5245
 
                        incrpoint = i;
5246
 
                        i++;
5247
 
                        continue;
5248
 
                }
5249
 
                (void)addtoinfstr(str[i]);
5250
 
        }
5251
 
 
5252
 
        /* get the new value */
5253
 
        retval = (INTBIG)returninfstr();
5254
 
 
5255
 
        /* increment the variable */
5256
 
        for(i = incrpoint-1; i>0; i--)
5257
 
                if (!isdigit(str[i])) break;
5258
 
        i++;
5259
 
        str[incrpoint] = 0;
5260
 
        curval = myatoi(&str[i]);
5261
 
        str[incrpoint] = str[incrpoint+1];
5262
 
        if (str[incrpoint] == '+') curval++; else curval--;
5263
 
        (void)initinfstr();
5264
 
        for(j=0; j<i; j++)
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); 
5270
 
 
5271
 
        return(retval);
5272
 
}
5273
 
 
5274
 
/*
5275
 
 * Routine to inherit all prototype attributes down to instance "ni".
5276
 
 */
5277
 
void us_inheritattributes(NODEINST *ni)
5278
 
{
5279
 
        REGISTER NODEPROTO *np, *cnp;
5280
 
        REGISTER NODEINST *icon;
5281
 
        REGISTER INTBIG i;
5282
 
        REGISTER VARIABLE *var;
5283
 
        REGISTER PORTPROTO *pp, *cpp;
5284
 
 
5285
 
        /* first inherit directly from this node's prototype */
5286
 
        np = ni->proto;
5287
 
        for(i=0; i<np->numvar; i++)
5288
 
        {
5289
 
                var = &np->firstvar[i];
5290
 
                if (TDGETINHERIT(var->textdescript) == 0) continue;
5291
 
                us_inheritfacetattribute(var, ni, np, NONODEINST);
5292
 
        }
5293
 
 
5294
 
        /* inherit directly from each port's prototype */
5295
 
        for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5296
 
                us_inheritexportattributes(pp, ni, np);
5297
 
 
5298
 
        /* if this node is an icon, also inherit from the contents prototype */
5299
 
        cnp = contentsview(np);
5300
 
        if (cnp != NONODEPROTO)
5301
 
        {
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;
5305
 
 
5306
 
                for(i=0; i<cnp->numvar; i++)
5307
 
                {
5308
 
                        var = &cnp->firstvar[i];
5309
 
                        if (TDGETINHERIT(var->textdescript) == 0) continue;
5310
 
                        us_inheritfacetattribute(var, ni, cnp, icon);
5311
 
                }
5312
 
                for(cpp = cnp->firstportproto; cpp != NOPORTPROTO; cpp = cpp->nextportproto)
5313
 
                        us_inheritexportattributes(cpp, ni, cnp);
5314
 
        }
5315
 
}
5316
 
 
5317
 
/*
5318
 
 * Routine to add all inheritable export variables from export "pp" on facet "np"
5319
 
 * to instance "ni".
5320
 
 */
5321
 
void us_inheritexportattributes(PORTPROTO *pp, NODEINST *ni, NODEPROTO *np)
5322
 
{
5323
 
        REGISTER INTSML saverot, savetrn;
5324
 
        REGISTER INTBIG i, dx, dy, lambda, style;
5325
 
        INTBIG x, y;
5326
 
        UINTBIG descript[TEXTDESCRIPTSIZE];
5327
 
        REGISTER VARIABLE *var, *newvar;
5328
 
        REGISTER char *pt, *attrname;
5329
 
        XARRAY trans;
5330
 
 
5331
 
        for(i=0; i<pp->numvar; i++)
5332
 
        {
5333
 
                var = &pp->firstvar[i];
5334
 
                if (TDGETINHERIT(var->textdescript) == 0) continue;
5335
 
                (void)initinfstr();
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();
5342
 
 
5343
 
                /* see if the attribute is already there */
5344
 
                newvar = getval((INTBIG)ni, VNODEINST, -1, attrname);
5345
 
                if (newvar != NOVARIABLE) continue;
5346
 
 
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)
5352
 
                {
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;
5359
 
 
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;
5366
 
                        x += dx;   y += dy;
5367
 
                        makerot(pp->subnodeinst, trans);
5368
 
                        xform(x, y, &x, &y, trans);
5369
 
                        maketrans(ni, trans);
5370
 
                        xform(x, y, &x, &y, trans);
5371
 
                        makerot(ni, 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))
5376
 
                        {
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;
5387
 
                        }
5388
 
                        makerot(pp->subnodeinst, trans);
5389
 
                        style = rotatelabel(style, TDGETROTATION(descript), trans);
5390
 
                        switch (style)
5391
 
                        {
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;
5402
 
                        }
5403
 
                        x = x * 4 / lambda;
5404
 
                        y = y * 4 / lambda;
5405
 
                        TDSETOFF(descript, x, y);
5406
 
                        TDSETINHERIT(descript, 0);
5407
 
                        TDCOPY(newvar->textdescript, descript);
5408
 
                }
5409
 
                endobjectchange((INTBIG)ni, VNODEINST);
5410
 
        }
5411
 
}
5412
 
 
5413
 
/*
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.
5416
 
 */
5417
 
void us_inheritfacetattribute(VARIABLE *var, NODEINST *ni, NODEPROTO *np, NODEINST *icon)
5418
 
{
5419
 
        REGISTER VARIABLE *newvar, *ivar, *posvar;
5420
 
        REGISTER INTBIG xc, yc, lambda, i;
5421
 
 
5422
 
        /* see if the attribute is already there */
5423
 
        newvar = getvalkey((INTBIG)ni, VNODEINST, -1, var->key);
5424
 
        if (newvar != NOVARIABLE) return;
5425
 
 
5426
 
        /* determine offset of the attribute on the instance */
5427
 
        posvar = var;
5428
 
        if (icon != NONODEINST)
5429
 
        {
5430
 
                for(i=0; i<icon->numvar; i++)
5431
 
                {
5432
 
                        ivar = &icon->firstvar[i];
5433
 
                        if (ivar->key == var->key) break;
5434
 
                }
5435
 
                if (i < icon->numvar) posvar = ivar;
5436
 
        }
5437
 
 
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;
5446
 
 
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)
5452
 
        {
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)
5458
 
                {
5459
 
                        TDSETINTERIOR(newvar->textdescript, VTINTERIOR);
5460
 
                        TDSETDISPPART(newvar->textdescript, VTDISPLAYNAMEVALUE);
5461
 
                }
5462
 
        }
5463
 
        endobjectchange((INTBIG)ni, VNODEINST);
5464
 
}
5465
 
 
5466
 
/*
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".
5469
 
 */
5470
 
void us_addparameter(NODEINST *ni, INTBIG key, INTBIG addr, INTBIG type, UINTBIG *descript)
5471
 
{
5472
 
        REGISTER VARIABLE *var;
5473
 
        INTBIG xoff, yoff;
5474
 
 
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)
5479
 
        {
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);
5485
 
        }
5486
 
        endobjectchange((INTBIG)ni, VNODEINST);
5487
 
}
5488
 
 
5489
 
/*
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).
5492
 
 */
5493
 
void us_getnewparameterpos(INTBIG addr, INTBIG type, INTBIG *xoff, INTBIG *yoff)
5494
 
{
5495
 
        REGISTER NODEINST *ni;
5496
 
        REGISTER NODEPROTO *np;
5497
 
        REGISTER INTBIG i, numvar, count, xsum, yval, lowy, highy;
5498
 
        REGISTER VARIABLE *firstvar, *var;
5499
 
 
5500
 
        switch (type)
5501
 
        {
5502
 
                case VNODEINST:
5503
 
                        ni = (NODEINST *)addr;
5504
 
                        numvar = ni->numvar;
5505
 
                        firstvar = ni->firstvar;
5506
 
                        break;
5507
 
                case VNODEPROTO:
5508
 
                        np = (NODEPROTO *)addr;
5509
 
                        numvar = np->numvar;
5510
 
                        firstvar = np->firstvar;
5511
 
                        break;
5512
 
        }
5513
 
        count = xsum = 0;
5514
 
        for(i=0; i<numvar; i++)
5515
 
        {
5516
 
                var = &firstvar[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
5521
 
                {
5522
 
                        if (yval < lowy) lowy = yval;
5523
 
                        if (yval > highy) highy = yval;
5524
 
                }
5525
 
                count++;
5526
 
        }
5527
 
        if (count == 0) *xoff = *yoff = 0; else
5528
 
        {
5529
 
                *xoff = xsum / count;
5530
 
                if (count == 1) *yoff = lowy - 4; else
5531
 
                        *yoff = lowy - (highy - lowy) / (count-1);
5532
 
        }
5533
 
}