1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrcomtz.c
6  * User interface tool: command handler for W through Z
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "egraphics.h"
34 #include "usr.h"
35 #include "usrtrack.h"
36 #include "efunction.h"
37 
38 static struct
39 {
40 	CHAR         *keyword;
41 	short         unique;
42 	STATUSFIELD **fieldaddr;
43 } us_statusfields[] =
44 {
45 	{x_("align"),      2,  &us_statusalign},
46 	{x_("angle"),      2,  &us_statusangle},
47 	{x_("arc"),        2,  &us_statusarc},
48 	{x_("cell"),       1,  &us_statuscell},
49 	{x_("grid"),       1,  &us_statusgridsize},
50 	{x_("lambda"),     1,  &us_statuslambda},
51 	{x_("numselected"),2,  &us_statusselectcount},
52 	{x_("node"),       2,  &us_statusnode},
53 	{x_("package"),    3,  &us_statuspackage},
54 	{x_("part"),       3,  &us_statuspart},
55 	{x_("project"),    2,  &us_statusproject},
56 	{x_("root"),       1,  &us_statusroot},
57 	{x_("selection"),  2,  &us_statusselection},
58 	{x_("size"),       2,  &us_statuscellsize},
59 	{x_("technology"), 1,  &us_statustechnology},
60 	{x_("x"),          1,  &us_statusxpos},
61 	{x_("y"),          1,  &us_statusypos},
62 	{0,0,0}
63 };
64 
us_window(INTBIG count,CHAR * par[])65 void us_window(INTBIG count, CHAR *par[])
66 {
67 	REGISTER WINDOWPART *w, *oldw, *nextw, *neww;
68 	REGISTER INTBIG i, dist, curwx, curwy, size, x, y, diffx, diffy, lambda, needwx, needwy;
69 	REGISTER INTBIG l, nogood, splitkey, lineno, startper, endper;
70 	INTBIG lx, hx, ly, hy, xcur, ycur, windowView[8];
71 	UINTBIG descript[TEXTDESCRIPTSIZE];
72 	static POLYGON *poly = NOPOLYGON;
73 	REGISTER STATUSFIELD *sf, **whichstatus;
74 	CHAR *newpar[4], *fieldname;
75 	WINDOWFRAME *wf;
76 #if SIMTOOL
77 	extern TOOL *sim_tool;
78 #endif
79 	REGISTER CHAR *pp, *win;
80 	REGISTER VARIABLE *var;
81 	REGISTER NODEPROTO *np;
82 	REGISTER NODEINST *ni;
83 	extern GRAPHICS us_arbit;
84 	extern COMCOMP us_windowp, us_windowup, us_windowmp;
85 	REGISTER void *infstr;
86 	extern GRAPHICS us_hbox;
87 
88 	/* get polygon */
89 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
90 
91 	if (count == 0)
92 	{
93 		count = ttygetparam(M_("Window configuration: "), &us_windowp, MAXPARS, par);
94 		if (count == 0)
95 		{
96 			us_abortedmsg();
97 			return;
98 		}
99 	}
100 	l = estrlen(pp = par[0]);
101 
102 	if (namesamen(pp, x_("adjust"), l) == 0 && l >= 2)
103 	{
104 		if (count == 1)
105 		{
106 			ttyputusage(x_("window adjust STYLE"));
107 			return;
108 		}
109 		l = estrlen(pp = par[1]);
110 		if (namesamen(pp, x_("horizontal-tile"), l) == 0)
111 		{
112 			adjustwindowframe(0);
113 			return;
114 		}
115 		if (namesamen(pp, x_("vertical-tile"), l) == 0)
116 		{
117 			adjustwindowframe(1);
118 			return;
119 		}
120 		if (namesamen(pp, x_("cascade"), l) == 0)
121 		{
122 			adjustwindowframe(2);
123 			return;
124 		}
125 		ttyputusage(x_("window adjust (horizontal-tile | vertical-tile | cascade)"));
126 		return;
127 	}
128 
129 	if (namesamen(pp, x_("all-displayed"), l) == 0 && l >= 2)
130 	{
131 		if (us_needwindow()) return;
132 
133 #if SIMTOOL
134 		/* special case for waveform window */
135 		if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
136 		{
137 			newpar[0] = x_("window");
138 			newpar[1] = x_("zoom");
139 			newpar[2] = x_("all-displayed");
140 			telltool(sim_tool, 3, newpar);
141 			return;
142 		}
143 #endif
144 
145 		/* fill a 3D window */
146 		if ((el_curwindowpart->state&WINDOWTYPE) == DISP3DWINDOW)
147 		{
148 			us_3dfillview(el_curwindowpart);
149 			return;
150 		}
151 
152 		/* use direct methods on nonstandard windows */
153 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
154 		{
155 			if (el_curwindowpart->redisphandler != 0)
156 				(*el_curwindowpart->redisphandler)(el_curwindowpart);
157 			return;
158 		}
159 
160 		np = us_needcell();
161 		if (np == NONODEPROTO) return;
162 
163 		/* save and erase highlighting */
164 		us_pushhighlight();
165 		us_clearhighlightcount();
166 
167 		/* make the cell fill the window */
168 		us_fullview(np, &lx, &hx, &ly, &hy);
169 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
170 			xformbox(&lx, &hx, &ly, &hy, el_curwindowpart->outofcell);
171 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
172 
173 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
174 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
175 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
176 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
177 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
178 		us_gridset(el_curwindowpart, el_curwindowpart->state);
179 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
180 
181 		/* restore highlighting */
182 		us_pophighlight(FALSE);
183 		return;
184 	}
185 
186 	if (namesamen(pp, x_("center-highlight"), l) == 0 && l >= 2)
187 	{
188 		if (us_needwindow()) return;
189 
190 		np = us_getareabounds(&lx, &hx, &ly, &hy);
191 		if (np == NONODEPROTO)
192 		{
193 			us_abortcommand(_("Outline an area"));
194 			return;
195 		}
196 
197 		if (el_curwindowpart->curnodeproto == np) w = el_curwindowpart; else
198 		{
199 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
200 				if (w->curnodeproto == np && (w->state&WINDOWTYPE) == DISPWINDOW)
201 					break;
202 			if (w == NOWINDOWPART)
203 			{
204 				us_abortcommand(_("Cannot find an editing window with highlighted objects"));
205 				return;
206 			}
207 		}
208 
209 		/* cannot manipulate a nonstandard window */
210 		if ((w->state&WINDOWTYPE) != DISPWINDOW)
211 		{
212 			us_abortcommand(_("Can only pan circuit editing windows"));
213 			return;
214 		}
215 
216 		/* pre-compute current window size */
217 		curwx = w->screenhx - w->screenlx;
218 		curwy = w->screenhy - w->screenly;
219 
220 		/* center about this area without re-scaling */
221 		x = (hx + lx) / 2;     y = (hy + ly) / 2;
222 		lx = x - curwx/2;      ly = y - curwy/2;
223 		hx = lx + curwx;       hy = ly + curwy;
224 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
225 			xformbox(&lx, &hx, &ly, &hy, el_curwindowpart->outofcell);
226 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 1);
227 
228 		/* save and erase highlighting */
229 		us_pushhighlight();
230 		us_clearhighlightcount();
231 
232 		startobjectchange((INTBIG)w, VWINDOWPART);
233 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
234 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
235 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenly"), ly, VINTEGER);
236 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
237 		us_gridset(w, el_curwindowpart->state);
238 		endobjectchange((INTBIG)w, VWINDOWPART);
239 
240 		/* restore highlighting */
241 		us_pophighlight(FALSE);
242 		return;
243 	}
244 
245 	if (namesamen(pp, x_("cursor-centered"), l) == 0 && l >= 2)
246 	{
247 #if SIMTOOL
248 		if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
249 		{
250 			if (us_needwindow()) return;
251 			newpar[0] = x_("window");
252 			newpar[1] = x_("cursor");
253 			newpar[2] = x_("center");
254 			telltool(sim_tool, 3, newpar);
255 			return;
256 		}
257 #endif
258 
259 		np = us_needcell();
260 		if (np == NONODEPROTO) return;
261 
262 		/* cannot manipulate a nonstandard window */
263 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
264 		{
265 			us_abortcommand(_("Can only pan circuit editing windows"));
266 			return;
267 		}
268 
269 		if (us_demandxy(&xcur, &ycur)) return;
270 
271 		/* pre-compute current window size */
272 		curwx = el_curwindowpart->screenhx - el_curwindowpart->screenlx;
273 		curwy = el_curwindowpart->screenhy - el_curwindowpart->screenly;
274 		lx = xcur - curwx/2;   ly = ycur - curwy/2;
275 		hx = lx + curwx;       hy = ly + curwy;
276 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
277 			xformbox(&lx, &hx, &ly, &hy, el_curwindowpart->outofcell);
278 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 1);
279 
280 		/* save and erase highlighting */
281 		us_pushhighlight();
282 		us_clearhighlightcount();
283 
284 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
285 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
286 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
287 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
288 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
289 		us_gridset(el_curwindowpart, el_curwindowpart->state);
290 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
291 
292 		/* restore highlighting */
293 		us_pophighlight(FALSE);
294 		return;
295 	}
296 
297 	/* handle deletion of separate windows */
298 	if (namesamen(pp, x_("delete"), l) == 0 && l >= 2)
299 	{
300 		/* close the messages window if in front and can be closed */
301 		if (closefrontmostmessages()) return;
302 
303 		/* delete split if there are no multiple window frames */
304 		if (!graphicshas(CANUSEFRAMES))
305 		{
306 			if (us_needwindow()) return;
307 			us_killcurrentwindow(TRUE);
308 			return;
309 		}
310 
311 		/* disallow if this is the last window and it must remain */
312 		if (!graphicshas(CANHAVENOWINDOWS))
313 		{
314 			/* disallow deletion if this is the last window */
315 			i = 0;
316 			for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
317 				if (wf->floating == 0) i++;
318 			if (i <= 1)
319 			{
320 				ttyputerr(_("Sorry, cannot delete the last window"));
321 				return;
322 			}
323 		}
324 
325 		/* get the current frame */
326 		wf = getwindowframe(FALSE);
327 		if (wf == NOWINDOWFRAME)
328 		{
329 			us_abortcommand(_("No current window to delete"));
330 			return;
331 		}
332 
333 		/* save highlighting and turn it off */
334 		us_pushhighlight();
335 		us_clearhighlightcount();
336 
337 		startobjectchange((INTBIG)us_tool, VTOOL);
338 
339 		/* kill all editor windows on this frame */
340 		neww = NOWINDOWPART;
341 		for(w = el_topwindowpart; w != NOWINDOWPART; w = nextw)
342 		{
343 			nextw = w->nextwindowpart;
344 			if (w->frame != wf)
345 			{
346 				neww = w;
347 				continue;
348 			}
349 
350 			/* kill this window */
351 			killwindowpart(w);
352 		}
353 		endobjectchange((INTBIG)us_tool, VTOOL);
354 
355 		/* if (neww == NOWINDOWPART) */
356 		el_curwindowpart = NOWINDOWPART;
357 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)neww, VWINDOWPART|VDONTSAVE);
358 		if (neww != NOWINDOWPART) np = neww->curnodeproto; else np = NONODEPROTO;
359 		(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
360 
361 		/* restore highlighting */
362 		us_pophighlight(FALSE);
363 		return;
364 	}
365 
366 	if (namesamen(pp, x_("down"), l) == 0 && l >= 2)
367 	{
368 		if (us_needwindow()) return;
369 		if (count < 2) pp = x_("0.5"); else pp = par[1];
370 		switch (el_curwindowpart->state&WINDOWTYPE)
371 		{
372 			case DISPWINDOW:
373 				if (us_needcell() == NONODEPROTO) return;
374 				if (pp[estrlen(pp)-1] == 'l') dist = atola(pp, 0); else
375 					dist = muldiv(atofr(pp), (el_curwindowpart->screenhy - el_curwindowpart->screenly), WHOLE);
376 				us_slideup(-dist);
377 				return;
378 			case DISP3DWINDOW:
379 				us_3dpanview(el_curwindowpart, 0, -1);
380 				return;
381 			case TEXTWINDOW:
382 				us_pantext(el_curwindowpart, 0, -1);
383 				return;
384 #if SIMTOOL
385 			case WAVEFORMWINDOW:
386 				newpar[0] = x_("window");
387 				newpar[1] = x_("move");
388 				newpar[2] = x_("down");
389 				telltool(sim_tool, 3, newpar);
390 				return;
391 #endif
392 			case EXPLORERWINDOW:
393 				us_explorevpan(el_curwindowpart, -1);
394 				return;
395 		}
396 		us_abortcommand(_("Cannot pan this kind of windows"));
397 		return;
398 	}
399 
400 	if (namesamen(pp, x_("dragging"), l) == 0 && l >= 3)
401 	{
402 		if (count >= 2)
403 		{
404 			pp = par[1];
405 			if (namesame(pp, x_("on")) == 0)
406 				(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | INTERACTIVE, VINTEGER);
407 			else if (namesamen(pp, x_("of"), 2) == 0)
408 				(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~INTERACTIVE, VINTEGER);
409 			else
410 			{
411 				ttyputusage(x_("window dragging on|off"));
412 				return;
413 			}
414 		}
415 		if ((us_tool->toolstate&INTERACTIVE) == 0)
416 			ttyputverbose(M_("Cursor-based commands will act immediately")); else
417 				ttyputverbose(M_("Cursor-based commands will drag their objects"));
418 		return;
419 	}
420 
421 	if (namesamen(pp, x_("explore"), l) == 0)
422 	{
423 		/* see if this frame already has an explorer */
424 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
425 		{
426 			if (w->frame != el_curwindowpart->frame) continue;
427 			if ((w->state&WINDOWTYPE) == EXPLORERWINDOW) break;
428 		}
429 		if (w != NOWINDOWPART)
430 		{
431 			/* the explorer is up, delete it */
432 			el_curwindowpart = w;
433 			us_killcurrentwindow(TRUE);
434 			return;
435 		}
436 
437 		/* make an explorer window */
438 		w = el_curwindowpart;
439 		if (w == NOWINDOWPART)
440 		{
441 			w = us_wantnewwindow(0);
442 			if (w == NOWINDOWPART)
443 			{
444 				us_abortcommand(_("Cannot create new window frame"));
445 				return;
446 			}
447 		}
448 		if (estrcmp(w->location, x_("entire")) == 0)
449 		{
450 			w = us_splitcurrentwindow(2, FALSE, 0, us_explorerratio);
451 			if (w == NOWINDOWPART) return;
452 		}
453 
454 		/* find the other window */
455 		for(oldw = el_topwindowpart; oldw != NOWINDOWPART; oldw = oldw->nextwindowpart)
456 			if (oldw != w && oldw->frame == w->frame) break;
457 
458 		/* turn this window into an Explorer */
459 		us_createexplorerstruct(w);
460 
461 		if (oldw != NOWINDOWPART)
462 		{
463 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)oldw,
464 				VWINDOWPART|VDONTSAVE);
465 			us_setcellname(oldw);
466 		}
467 		return;
468 	}
469 
470 	if (namesamen(pp, x_("grid-zoom"), l) == 0 && l >= 1)
471 	{
472 		if (us_needwindow()) return;
473 
474 		/* cannot zoom a nonstandard window */
475 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
476 		{
477 			us_abortcommand(_("Can only grid-zoom circuit editing windows"));
478 			return;
479 		}
480 
481 		np = us_needcell();
482 		if (np == NONODEPROTO) return;
483 		lambda = lambdaofcell(np);
484 		x = muldiv(el_curwindowpart->gridx, lambda, WHOLE);
485 		y = muldiv(el_curwindowpart->gridy, lambda, WHOLE);
486 		curwx = el_curwindowpart->screenhx-el_curwindowpart->screenlx;
487 		curwy = el_curwindowpart->screenhy-el_curwindowpart->screenly;
488 		needwx = muldiv(x, el_curwindowpart->usehx-el_curwindowpart->uselx, 5);
489 		needwy = muldiv(y, el_curwindowpart->usehy-el_curwindowpart->usely, 5);
490 
491 		lx = el_curwindowpart->screenlx;   hx = el_curwindowpart->screenhx;
492 		ly = el_curwindowpart->screenly;   hy = el_curwindowpart->screenhy;
493 		lx = (hx+lx-needwx)/2;   hx = lx + needwx;
494 		ly = (hy+ly-needwy)/2;   hy = ly + needwy;
495 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 1);
496 
497 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
498 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
499 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
500 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
501 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
502 		us_gridset(el_curwindowpart, el_curwindowpart->state|GRIDON);
503 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
504 
505 		/* redisplay */
506 		us_endchanges(NOWINDOWPART);
507 		us_state |= HIGHLIGHTSET;
508 		us_showallhighlight();
509 		return;
510 	}
511 
512 	if (namesamen(pp, x_("highlight-displayed"), l) == 0 && l >= 3)
513 	{
514 		if (us_needwindow()) return;
515 
516 #if SIMTOOL
517 		/* special case for waveform window */
518 		if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
519 		{
520 			newpar[0] = x_("window");
521 			newpar[1] = x_("zoom");
522 			newpar[2] = x_("cursor");
523 			telltool(sim_tool, 3, newpar);
524 			return;
525 		}
526 #endif
527 
528 		np = us_getareabounds(&lx, &hx, &ly, &hy);
529 		if (np == NONODEPROTO)
530 		{
531 			us_abortcommand(_("Outline an area"));
532 			return;
533 		}
534 
535 		if (el_curwindowpart->curnodeproto == np) w = el_curwindowpart; else
536 		{
537 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
538 				if (w->curnodeproto == np && (w->state&WINDOWTYPE) == DISPWINDOW)
539 					break;
540 			if (w == NOWINDOWPART)
541 			{
542 				us_abortcommand(_("Cannot find an editing window with highlighted objects"));
543 				return;
544 			}
545 		}
546 
547 		/* cannot manipulate a nonstandard window */
548 		if ((w->state&WINDOWTYPE) != DISPWINDOW)
549 		{
550 			us_abortcommand(_("Can only adjust circuit editing windows"));
551 			return;
552 		}
553 
554 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
555 			xformbox(&lx, &hx, &ly, &hy, el_curwindowpart->outofcell);
556 		if (lx == hx && ly == hy)
557 		{
558 			lambda = lambdaofcell(np);
559 			lx -= lambda;
560 			hx += lambda;
561 			ly -= lambda;
562 			hy += lambda;
563 		}
564 
565 		/* save and erase highlighting */
566 		us_pushhighlight();
567 		us_clearhighlightcount();
568 
569 		/* make sure the new window has square pixels */
570 		us_squarescreen(w, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
571 
572 		startobjectchange((INTBIG)w, VWINDOWPART);
573 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
574 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
575 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenly"), ly, VINTEGER);
576 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
577 		us_gridset(w, el_curwindowpart->state);
578 		endobjectchange((INTBIG)w, VWINDOWPART);
579 
580 		/* restore highlighting */
581 		us_pophighlight(FALSE);
582 		return;
583 	}
584 
585 	if (namesamen(pp, x_("in-zoom"), l) == 0 && l >= 1)
586 	{
587 		if (us_needwindow()) return;
588 
589 #if SIMTOOL
590 		/* special case for waveform window */
591 		if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
592 		{
593 			newpar[0] = x_("window");
594 			newpar[1] = x_("zoom");
595 			newpar[2] = x_("in");
596 			telltool(sim_tool, 3, newpar);
597 			return;
598 		}
599 #endif
600 
601 		/* zoom a 3D window */
602 		if ((el_curwindowpart->state&WINDOWTYPE) == DISP3DWINDOW)
603 		{
604 			us_3dzoomview(el_curwindowpart, 0.75f);
605 			return;
606 		}
607 
608 		/* cannot zoom a nonstandard window */
609 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
610 		{
611 			us_abortcommand(_("Can only zoom circuit editing windows"));
612 			return;
613 		}
614 
615 		np = us_needcell();
616 		if (np == NONODEPROTO) return;
617 		lambda = lambdaofcell(np);
618 		if (count >= 2) dist = atola(par[1], 0); else
619 			dist = 2 * lambda;
620 		if (dist == 0)
621 		{
622 			us_abortcommand(_("Must zoom by a nonzero amount"));
623 			return;
624 		}
625 
626 		diffx = muldiv(el_curwindowpart->screenhx - el_curwindowpart->screenlx,
627 			lambda, dist);
628 		diffy = muldiv(el_curwindowpart->screenhy - el_curwindowpart->screenly,
629 			lambda, dist);
630 		lx = el_curwindowpart->screenlx;   hx = el_curwindowpart->screenhx;
631 		ly = el_curwindowpart->screenly;   hy = el_curwindowpart->screenhy;
632 		lx = (hx+lx-diffx)/2;   hx = lx + diffx;
633 		ly = (hy+ly-diffy)/2;   hy = ly + diffy;
634 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 1);
635 
636 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
637 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
638 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
639 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
640 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
641 		us_gridset(el_curwindowpart, el_curwindowpart->state);
642 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
643 
644 		/* restore highlighting */
645 		us_endchanges(NOWINDOWPART);
646 		us_state |= HIGHLIGHTSET;
647 		us_showallhighlight();
648 		return;
649 	}
650 
651 	/* handle killing of the other window specially */
652 	if (namesamen(pp, x_("join"), l) == 0 && l >= 1)
653 	{
654 		if (us_needwindow()) return;
655 		us_killcurrentwindow(FALSE);
656 		return;
657 	}
658 
659 	/* handle killing of this window specially */
660 	if (namesamen(pp, x_("kill"), l) == 0 && l >= 1)
661 	{
662 		if (us_needwindow()) return;
663 		us_killcurrentwindow(TRUE);
664 		return;
665 	}
666 
667 	if (namesamen(pp, x_("left"), l) == 0 && l >= 1)
668 	{
669 		if (us_needwindow()) return;
670 		if (count < 2) pp = x_("0.5"); else pp = par[1];
671 		switch (el_curwindowpart->state&WINDOWTYPE)
672 		{
673 			case DISPWINDOW:
674 				if (us_needcell() == NONODEPROTO) return;
675 				if (pp[estrlen(pp)-1] == 'l') dist = atola(pp, 0); else
676 					dist = muldiv(atofr(pp), (el_curwindowpart->screenhx - el_curwindowpart->screenlx), WHOLE);
677 				us_slideleft(dist);
678 				return;
679 			case DISP3DWINDOW:
680 				us_3dpanview(el_curwindowpart, 1, 0);
681 				return;
682 			case TEXTWINDOW:
683 				us_pantext(el_curwindowpart, 1, 0);
684 				return;
685 #if SIMTOOL
686 			case WAVEFORMWINDOW:
687 				newpar[0] = x_("window");
688 				newpar[1] = x_("move");
689 				newpar[2] = x_("left");
690 				telltool(sim_tool, 3, newpar);
691 				return;
692 #endif
693 		}
694 		us_abortcommand(_("Cannot pan this kind of windows"));
695 		return;
696 	}
697 
698 	if (namesamen(pp, x_("match"), l) == 0 && l >= 3)
699 	{
700 		/* count the number of windows */
701 		for(i = 0, w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart) i++;
702 		if (i <= 1)
703 		{
704 			us_abortcommand(_("Must be multiple windows to match them"));
705 			return;
706 		}
707 
708 		/* if there are two windows, the other to match is obvious */
709 		if (i == 2)
710 		{
711 			if (el_curwindowpart == el_topwindowpart) w = el_topwindowpart->nextwindowpart; else
712 				w = el_topwindowpart;
713 		} else
714 		{
715 			if (count < 2)
716 			{
717 				count = ttygetparam(_("Other window to match: "), &us_windowmp, MAXPARS-1, &par[1]) + 1;
718 				if (count == 1)
719 				{
720 					us_abortedmsg();
721 					return;
722 				}
723 			}
724 			win = par[1];
725 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
726 			{
727 				infstr = initinfstr();
728 				addstringtoinfstr(infstr, describenodeproto(w->curnodeproto));
729 				addtoinfstr(infstr, '(');
730 				addstringtoinfstr(infstr, w->location);
731 				addtoinfstr(infstr, ')');
732 				if (namesame(win, returninfstr(infstr)) == 0) break;
733 			}
734 			if (w == NOWINDOWPART)
735 			{
736 				us_abortcommand(_("No window named '%s'"), win);
737 				return;
738 			}
739 		}
740 
741 		if (w == el_curwindowpart)
742 		{
743 			us_abortcommand(_("Choose a window other than the current one to match"));
744 			return;
745 		}
746 
747 		/* cannot match if they are editing the same thing */
748 		if ((w->state&WINDOWTYPE) != (el_curwindowpart->state&WINDOWTYPE))
749 		{
750 			us_abortcommand(_("Can only match windows that edit the same thing"));
751 			return;
752 		}
753 
754 		/* cannot match if they are not normal display windows */
755 		if ((w->state&WINDOWTYPE) != DISPWINDOW)
756 		{
757 			us_abortcommand(_("Can only match normal editing windows"));
758 			return;
759 		}
760 
761 		/* save and erase highlighting */
762 		us_pushhighlight();
763 		us_clearhighlightcount();
764 
765 		/* make window "el_curwindowpart" match the scale of "w" */
766 		diffx = muldiv(w->screenhx - w->screenlx, el_curwindowpart->usehx -
767 			el_curwindowpart->uselx, w->usehx - w->uselx);
768 		diffx = diffx - (el_curwindowpart->screenhx - el_curwindowpart->screenlx);
769 		diffy = muldiv(w->screenhy - w->screenly, el_curwindowpart->usehy -
770 			el_curwindowpart->usely, w->usehy - w->usely);
771 		diffy = diffy - (el_curwindowpart->screenhy - el_curwindowpart->screenly);
772 
773 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
774 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"),
775 			el_curwindowpart->screenlx - diffx/2, VINTEGER);
776 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"),
777 			el_curwindowpart->screenhx + diffx/2, VINTEGER);
778 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"),
779 			el_curwindowpart->screenly - diffy/2, VINTEGER);
780 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"),
781 			el_curwindowpart->screenhy + diffy/2, VINTEGER);
782 		us_gridset(el_curwindowpart, el_curwindowpart->state);
783 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
784 
785 		/* restore highlighting */
786 		us_pophighlight(FALSE);
787 		return;
788 	}
789 
790 	if (namesamen(pp, x_("measure"), l) == 0 && l >= 2)
791 	{
792 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW &&
793 			(el_curwindowpart->state&WINDOWTYPE) != WAVEFORMWINDOW)
794 		{
795 			us_abortcommand(_("Can only measure distance in an edit and waveform windows"));
796 			return;
797 		}
798 		if (el_curwindowpart->curnodeproto == NONODEPROTO)
799 		{
800 			us_abortcommand(_("No cell in this window to measure"));
801 			return;
802 		}
803 		if ((us_state&MEASURINGDISTANCE) != 0)
804 		{
805 			us_state &= ~(MEASURINGDISTANCE | MEASURINGDISTANCEINI);
806 			ttyputmsg(_("Exiting distance measurement mode"));
807 		} else
808 		{
809 			us_clearhighlightcount();
810 			us_state |= MEASURINGDISTANCE | MEASURINGDISTANCEINI;
811 			ttyputmsg(_("Entering distance measurement mode"));
812 		}
813 		return;
814 	}
815 
816 	if (namesamen(pp, x_("move-display"), l) == 0 && l >= 2)
817 	{
818 		if (us_needwindow()) return;
819 #ifdef USEQT
820 		movedisplay();
821 #else
822 		ttyputmsg(_("(Display move works only on Qt"));
823 #endif
824 		return;
825 	}
826 
827 	if (namesamen(pp, x_("name"), l) == 0 && l >= 2)
828 	{
829 		if (us_needwindow()) return;
830 		if (count <= 1)
831 		{
832 			ttyputusage(x_("window name VIEWNAME"));
833 			return;
834 		}
835 		infstr = initinfstr();
836 		addstringtoinfstr(infstr, x_("USER_windowview_"));
837 		addstringtoinfstr(infstr, par[1]);
838 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, returninfstr(infstr));
839 		if (var == NOVARIABLE)
840 		{
841 			us_abortcommand(_("Cannot find saved window view '%s'"), par[1]);
842 			return;
843 		}
844 
845 		lx = ((INTBIG *)var->addr)[0];
846 		hx = ((INTBIG *)var->addr)[1];
847 		ly = ((INTBIG *)var->addr)[2];
848 		hy = ((INTBIG *)var->addr)[3];
849 
850 		/* if the window extent changed, make sure the pixels are square */
851 		if (((INTBIG *)var->addr)[5] - ((INTBIG *)var->addr)[4] != el_curwindowpart->usehx - el_curwindowpart->uselx ||
852 			((INTBIG *)var->addr)[7] - ((INTBIG *)var->addr)[6] != el_curwindowpart->usehy - el_curwindowpart->usely)
853 		{
854 			us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
855 		}
856 
857 		/* save and erase highlighting */
858 		us_pushhighlight();
859 		us_clearhighlightcount();
860 
861 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
862 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
863 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
864 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
865 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
866 		us_gridset(el_curwindowpart, el_curwindowpart->state);
867 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
868 
869 		/* restore highlighting */
870 		us_pophighlight(FALSE);
871 		return;
872 	}
873 
874 	/* handle creating of separate windows */
875 	if (namesamen(pp, x_("new"), l) == 0 && l >= 2)
876 	{
877 		/* create a new frame */
878 		w = us_wantnewwindow(0);
879 		if (w == NOWINDOWPART)
880 		{
881 			us_abortcommand(_("Cannot create new window frame"));
882 			return;
883 		}
884 		return;
885 	}
886 
887 	if (namesamen(pp, x_("normal-cursor"), l) == 0 && l >= 2)
888 	{
889 		if (count < 2)
890 		{
891 			ttyputusage(x_("window normal-cursor CURSORNAME"));
892 			return;
893 		}
894 		l = estrlen(pp = par[1]);
895 		if (namesamen(pp, x_("standard"), l) == 0) setnormalcursor(NORMALCURSOR); else
896 			if (namesamen(pp, x_("pen"), l) == 0) setnormalcursor(PENCURSOR); else
897 				if (namesamen(pp, x_("tee"), l) == 0) setnormalcursor(TECHCURSOR); else
898 					ttyputbadusage(x_("window cursor"));
899 		return;
900 	}
901 
902 	if (namesamen(pp, x_("out-zoom"), l) == 0 && l >= 4)
903 	{
904 		if (us_needwindow()) return;
905 
906 #if SIMTOOL
907 		/* special case for waveform window */
908 		if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
909 		{
910 			newpar[0] = x_("window");
911 			newpar[1] = x_("zoom");
912 			newpar[2] = x_("out");
913 			telltool(sim_tool, 3, newpar);
914 			return;
915 		}
916 #endif
917 
918 		/* zoom a 3D window */
919 		if ((el_curwindowpart->state&WINDOWTYPE) == DISP3DWINDOW)
920 		{
921 			us_3dzoomview(el_curwindowpart, 1.5f);
922 			return;
923 		}
924 
925 		/* cannot zoom a nonstandard window */
926 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
927 		{
928 			us_abortcommand(_("Can only zoom circuit editing windows"));
929 			return;
930 		}
931 
932 		np = us_needcell();
933 		if (np == NONODEPROTO) return;
934 		lambda = lambdaofcell(np);
935 		if (count >= 2) dist = atola(par[1], 0); else
936 			dist = 2 * lambda;
937 		if (dist == 0)
938 		{
939 			us_abortcommand(_("Must zoom by a nonzero amount"));
940 			return;
941 		}
942 
943 		lx = el_curwindowpart->screenlx;   hx = el_curwindowpart->screenhx;
944 		ly = el_curwindowpart->screenly;   hy = el_curwindowpart->screenhy;
945 		i = muldiv(el_curwindowpart->screenhx - el_curwindowpart->screenlx, dist, lambda);
946 		lx = (lx+hx-i)/2;   hx = lx + i;
947 		i = muldiv(el_curwindowpart->screenhy - el_curwindowpart->screenly, dist, lambda);
948 		ly = (ly+hy-i)/2;   hy = ly + i;
949 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 1);
950 
951 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
952 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
953 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
954 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
955 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
956 		us_gridset(el_curwindowpart, el_curwindowpart->state);
957 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
958 
959 		/* restore highlighting */
960 		us_endchanges(NOWINDOWPART);
961 		us_state |= HIGHLIGHTSET;
962 		us_showallhighlight();
963 		return;
964 	}
965 
966 	if (namesamen(pp, x_("outline-edit-toggle"), l) == 0 && l >= 4)
967 	{
968 		/* in outline edit mode:
969 		 * cursor is a pen
970 		 * "Erase" deletes selected point
971 		 * "Rotate" rotates about point
972 		 * "Mirror" mirrors about point
973 		 * "Get Info" gives polygon info
974 		 * left arrow goes to previous point
975 		 * right arrow goes to next point
976 		 * selection button selects a point
977 		 * creation button creates a point
978 		 */
979 		if (us_needwindow()) return;
980 
981 		/* find the rotate menu entry */
982 		if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) == 0)
983 		{
984 			/* enter outline-edit mode: must have a current node */
985 			ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
986 			if (ni == NONODEINST) return;
987 			if ((ni->proto->userbits&HOLDSTRACE) == 0)
988 			{
989 				us_abortcommand(_("Sorry, %s nodes cannot hold outline information"),
990 					describenodeproto(ni->proto));
991 				return;
992 			}
993 			us_pushhighlight();
994 			us_clearhighlightcount();
995 			startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
996 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("state"),
997 				el_curwindowpart->state | WINDOWOUTLINEEDMODE, VINTEGER);
998 			endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
999 			us_pophighlight(FALSE);
1000 
1001 			TDCLEAR(descript);
1002 			TDSETSIZE(descript, TXTSETPOINTS(18));
1003 			us_hbox.col = HIGHLIT;
1004 			us_writetext(el_curwindowpart->uselx, el_curwindowpart->usehx,
1005 				el_curwindowpart->usehy-30, el_curwindowpart->usehy, &us_hbox, _("OUTLINE EDIT MODE:"),
1006 					descript, el_curwindowpart, NOTECHNOLOGY);
1007 			infstr = initinfstr();
1008 			var = getval((INTBIG)us_tool, VTOOL, VSTRING, "USER_local_capf");
1009 			if (var != NOVARIABLE) formatinfstr(infstr, _("Use %s to select/move point; "), (CHAR *)var->addr);
1010 			var = getval((INTBIG)us_tool, VTOOL, VSTRING, "USER_local_capg");
1011 			if (var != NOVARIABLE) formatinfstr(infstr, _(" Use %s to create point; "), (CHAR *)var->addr);
1012 			us_writetext(el_curwindowpart->uselx, el_curwindowpart->usehx,
1013 				el_curwindowpart->usehy-60, el_curwindowpart->usehy-30, &us_hbox, returninfstr(infstr),
1014 					descript, el_curwindowpart, NOTECHNOLOGY);
1015 		} else
1016 		{
1017 			/* leave outline edit mode */
1018 			us_pushhighlight();
1019 			us_clearhighlightcount();
1020 			startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1021 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("state"),
1022 				el_curwindowpart->state & ~WINDOWOUTLINEEDMODE, VINTEGER);
1023 			endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1024 			us_pophighlight(FALSE);
1025 		}
1026 		noundoallowed();
1027 		return;
1028 	}
1029 
1030 	if (namesamen(pp, x_("overlappable-display"), l) == 0 && l >= 5)
1031 	{
1032 		if (count >= 2)
1033 		{
1034 			pp = par[1];
1035 			l = estrlen(pp);
1036 			if (namesamen(pp, x_("on"), l) == 0)
1037 			{
1038 				us_state &= ~NONOVERLAPPABLEDISPLAY;
1039 			} else if (namesamen(pp, x_("off"), l) == 0)
1040 			{
1041 				us_state |= NONOVERLAPPABLEDISPLAY;
1042 			} else
1043 			{
1044 				ttyputusage(x_("window overlappable-display [on|off]"));
1045 				return;
1046 			}
1047 		}
1048 		if ((us_state&NONOVERLAPPABLEDISPLAY) != 0)
1049 			ttyputverbose(M_("Transparent layers will not be handled")); else
1050 				ttyputverbose(M_("Transparent layers will be drawn properly"));
1051 		return;
1052 	}
1053 
1054 	if (namesamen(pp, x_("overview"), l) == 0 && l >= 5)
1055 	{
1056 		ttyputerr(_("Cannot make an overview window yet"));
1057 		return;
1058 	}
1059 
1060 	if (namesamen(pp, x_("peek"), l) == 0 && l >= 2)
1061 	{
1062 		np = us_getareabounds(&lx, &hx, &ly, &hy);
1063 		if (np == NONODEPROTO)
1064 		{
1065 			us_abortcommand(_("Enclose an area to be peeked"));
1066 			return;
1067 		}
1068 
1069 		if (el_curwindowpart->curnodeproto == np) w = el_curwindowpart; else
1070 		{
1071 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1072 				if (w->curnodeproto == np && (w->state&WINDOWTYPE) == DISPWINDOW)
1073 					break;
1074 			if (w == NOWINDOWPART)
1075 			{
1076 				us_abortcommand(_("Cannot find an editing window with highlighted objects"));
1077 				return;
1078 			}
1079 		}
1080 
1081 		/* clip this bounding box to the window extent */
1082 		lx = maxi(lx, w->screenlx);
1083 		hx = mini(hx, w->screenhx);
1084 		ly = maxi(ly, w->screenly);
1085 		hy = mini(hy, w->screenhy);
1086 
1087 		/* save and erase highlighting */
1088 		us_pushhighlight();
1089 		us_clearhighlightcount();
1090 
1091 		/* un-draw the peek area */
1092 		maketruerectpoly(lx, hx, ly, hy, poly);
1093 		poly->desc = &us_arbit;
1094 		us_arbit.col = 0;
1095 		us_arbit.bits = LAYERO;
1096 		poly->style = FILLEDRECT;
1097 		us_showpoly(poly, w);
1098 
1099 		/* get new window to describe sub-area */
1100 		w = us_subwindow(lx, hx, ly, hy, w);
1101 
1102 		/* do the peek operation */
1103 		us_dopeek(lx, hx, ly, hy, np, w);
1104 
1105 		/* restore highlighting */
1106 		us_pophighlight(FALSE);
1107 		return;
1108 	}
1109 
1110 	if (namesamen(pp, x_("right"), l) == 0 && l >= 1)
1111 	{
1112 		if (us_needwindow()) return;
1113 		if (count < 2) pp = x_("0.5"); else pp = par[1];
1114 		switch (el_curwindowpart->state&WINDOWTYPE)
1115 		{
1116 			case DISPWINDOW:
1117 				if (us_needcell() == NONODEPROTO) return;
1118 				if (pp[estrlen(pp)-1] == 'l') dist = atola(pp, 0); else
1119 					dist = muldiv(atofr(pp), (el_curwindowpart->screenhx - el_curwindowpart->screenlx), WHOLE);
1120 				us_slideleft(-dist);
1121 				return;
1122 			case DISP3DWINDOW:
1123 				us_3dpanview(el_curwindowpart, -1, 0);
1124 				return;
1125 			case TEXTWINDOW:
1126 				us_pantext(el_curwindowpart, -1, 0);
1127 				return;
1128 #if SIMTOOL
1129 			case WAVEFORMWINDOW:
1130 				newpar[0] = x_("window");
1131 				newpar[1] = x_("move");
1132 				newpar[2] = x_("right");
1133 				telltool(sim_tool, 3, newpar);
1134 				return;
1135 #endif
1136 		}
1137 		us_abortcommand(_("Cannot pan this kind of windows"));
1138 		return;
1139 	}
1140 
1141 	if (namesamen(pp, x_("save"), l) == 0 && l >= 2)
1142 	{
1143 		if (us_needwindow()) return;
1144 		if (count <= 1)
1145 		{
1146 			ttyputusage(x_("window save VIEWNAME"));
1147 			return;
1148 		}
1149 		windowView[0] = el_curwindowpart->screenlx;
1150 		windowView[1] = el_curwindowpart->screenhx;
1151 		windowView[2] = el_curwindowpart->screenly;
1152 		windowView[3] = el_curwindowpart->screenhy;
1153 		windowView[4] = el_curwindowpart->uselx;
1154 		windowView[5] = el_curwindowpart->usehx;
1155 		windowView[6] = el_curwindowpart->usely;
1156 		windowView[7] = el_curwindowpart->usehy;
1157 		infstr = initinfstr();
1158 		addstringtoinfstr(infstr, x_("USER_windowview_"));
1159 		addstringtoinfstr(infstr, par[1]);
1160 		(void)setval((INTBIG)us_tool, VTOOL, returninfstr(infstr), (INTBIG)windowView,
1161 			VINTEGER|VISARRAY|(8<<VLENGTHSH)|VDONTSAVE);
1162 		ttyputverbose(M_("Window view %s saved"), par[1]);
1163 		return;
1164 	}
1165 
1166 	if (namesamen(pp, x_("split"), l) == 0 && l >= 2)
1167 	{
1168 		if (us_needwindow()) return;
1169 		splitkey = 0;
1170 		if (count > 1)
1171 		{
1172 			l = estrlen(pp = par[1]);
1173 			if (namesamen(pp, x_("horizontal"), l) == 0 && l >= 1) splitkey = 1; else
1174 				if (namesamen(pp, x_("vertical"), l) == 0 && l >= 1) splitkey = 2; else
1175 			{
1176 				ttyputusage(x_("window split horizontal|vertical"));
1177 				return;
1178 			}
1179 		}
1180 
1181 		/* split the window */
1182 		(void)us_splitcurrentwindow(splitkey, TRUE, 0, 50);
1183 		return;
1184 	}
1185 
1186 	if (namesamen(pp, x_("status-bar"), l) == 0 && l >= 2)
1187 	{
1188 		if (count < 2)
1189 		{
1190 			/* report all status bar locations */
1191 			for(i=0; us_statusfields[i].fieldaddr != 0; i++)
1192 			{
1193 				sf = *us_statusfields[i].fieldaddr;
1194 				if (sf == 0) continue;
1195 				if (sf->line == 0)
1196 					ttyputmsg(M_("Window title has %s"), us_statusfields[i].fieldaddr); else
1197 						ttyputmsg(M_("Line %ld from %3ld%% to %3ld%% is %s"), sf->line, sf->startper,
1198 							sf->endper, us_statusfields[i].fieldaddr);
1199 			}
1200 			return;
1201 		}
1202 
1203 		if (namesamen(par[1], x_("current-node"), estrlen(par[1])) == 0)
1204 		{
1205 			if (count < 3)
1206 			{
1207 				if ((us_state&NONPERSISTENTCURNODE) != 0)
1208 					ttyputmsg(M_("Current node displayed temporarily")); else
1209 						ttyputmsg(M_("Current node display is persistent"));
1210 				return;
1211 			}
1212 			l = estrlen(pp = par[2]);
1213 			if (namesamen(pp, x_("persistent"), l) == 0)
1214 			{
1215 				us_state &= ~NONPERSISTENTCURNODE;
1216 				ttyputverbose(M_("Current node display is persistent"));
1217 				return;
1218 			}
1219 			if (namesamen(pp, x_("temporary"), l) == 0)
1220 			{
1221 				us_state |= NONPERSISTENTCURNODE;
1222 				ttyputverbose(M_("Current node displayed temporarily"));
1223 				return;
1224 			}
1225 			ttyputusage(x_("window status-bar current-node [persistent|temporary]"));
1226 			return;
1227 		}
1228 
1229 		if (count < 3)
1230 		{
1231 			ttyputusage(x_("window status-bar COMMAND FIELD..."));
1232 			return;
1233 		}
1234 
1235 		/* determine area being controlled */
1236 		l = estrlen(pp = par[2]);
1237 		for(i=0; us_statusfields[i].keyword != 0; i++)
1238 			if (namesamen(pp, us_statusfields[i].keyword, l) == 0 &&
1239 				l >= us_statusfields[i].unique)
1240 		{
1241 			whichstatus = us_statusfields[i].fieldaddr;
1242 			break;
1243 		}
1244 		if (us_statusfields[i].keyword == 0)
1245 		{
1246 			us_abortcommand(_("Unknown status-bar location: %s"), pp);
1247 			return;
1248 		}
1249 
1250 		/* get option */
1251 		l = estrlen(pp = par[1]);
1252 		if (namesamen(pp, x_("delete"), l) == 0)
1253 		{
1254 			if (*whichstatus != 0) ttyfreestatusfield(*whichstatus);
1255 			*whichstatus = 0;
1256 			us_redostatus(NOWINDOWFRAME);
1257 			return;
1258 		}
1259 		if (namesamen(pp, x_("add"), l) == 0)
1260 		{
1261 			if (count < 6)
1262 			{
1263 				ttyputusage(x_("window status-bar add FIELD LINE STARTPER ENDPER [TITLE]"));
1264 				return;
1265 			}
1266 			lineno = eatoi(par[3]);
1267 			if (lineno < 0 || lineno > ttynumstatuslines())
1268 			{
1269 				us_abortcommand(_("Line number must range from 0 to %ld"), ttynumstatuslines());
1270 				return;
1271 			}
1272 			startper = eatoi(par[4]);
1273 			if (startper < 0 || startper > 100)
1274 			{
1275 				us_abortcommand(_("Starting percentage must range from 0 to 100"));
1276 				return;
1277 			}
1278 			endper = eatoi(par[5]);
1279 			if (endper <= startper || endper > 100)
1280 			{
1281 				us_abortcommand(_("Ending percentage must range from %ld to 100"), startper+1);
1282 				return;
1283 			}
1284 			if (count == 7) fieldname = par[6]; else fieldname = x_("");
1285 			if (*whichstatus != 0) ttyfreestatusfield(*whichstatus);
1286 			*whichstatus = ttydeclarestatusfield(lineno, startper, endper, fieldname);
1287 			us_redostatus(NOWINDOWFRAME);
1288 			return;
1289 		}
1290 		ttyputusage(x_("window status-bar [add | delete]"));
1291 		return;
1292 	}
1293 
1294 	if (namesamen(pp, x_("tiny-cells"), l) == 0 && l >= 2)
1295 	{
1296 		if (us_needwindow()) return;
1297 		if (count >= 2)
1298 		{
1299 			l = estrlen(pp = par[1]);
1300 			if (namesamen(pp, x_("draw"), l) == 0)
1301 			{
1302 				startobjectchange((INTBIG)us_tool, VTOOL);
1303 				(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
1304 					us_useroptions | DRAWTINYCELLS, VINTEGER);
1305 				if (count >= 3)
1306 				{
1307 					i = atofr(par[2]);
1308 					(void)setvalkey((INTBIG)us_tool, VTOOL, us_tinylambdaperpixelkey,
1309 						i, VFRACT);
1310 				}
1311 				endobjectchange((INTBIG)us_tool, VTOOL);
1312 			} else if (namesamen(pp, x_("hash-out"), l) == 0)
1313 			{
1314 				startobjectchange((INTBIG)us_tool, VTOOL);
1315 				(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
1316 					us_useroptions & ~DRAWTINYCELLS, VINTEGER);
1317 				endobjectchange((INTBIG)us_tool, VTOOL);
1318 			} else
1319 			{
1320 				ttyputusage(x_("window tiny-cells draw|(hash-out [LAMBDAPERPIXEL])"));
1321 				return;
1322 			}
1323 		}
1324 		if ((us_useroptions&DRAWTINYCELLS) != 0)
1325 		{
1326 			ttyputverbose(M_("Tiny cells will be drawn"));
1327 		} else
1328 		{
1329 			ttyputverbose(M_("Tiny cells will be hashed-out after %s lambda per pixel"),
1330 				frtoa(us_tinyratio));
1331 		}
1332 		return;
1333 	}
1334 
1335 	if (namesamen(pp, x_("trace-displayed"), l) == 0 && l >= 2)
1336 	{
1337 		np = us_needcell();
1338 		if (np == NONODEPROTO) return;
1339 
1340 		/* cannot manipulate a nonstandard window */
1341 		if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
1342 		{
1343 			us_abortcommand(_("Can only adjust circuit editing windows"));
1344 			return;
1345 		}
1346 
1347 		/* pre-compute current window size */
1348 		curwx = el_curwindowpart->screenhx - el_curwindowpart->screenlx;
1349 		curwy = el_curwindowpart->screenhy - el_curwindowpart->screenly;
1350 
1351 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_commandvarname('T'));
1352 		if (var == NOVARIABLE)
1353 		{
1354 			us_abortcommand(_("Issue an outline before zooming into that area"));
1355 			return;
1356 		}
1357 		size = getlength(var) / 2;
1358 		nogood = 0;
1359 		for(i=0; i<size; i++)
1360 		{
1361 			x = ((INTBIG *)var->addr)[i*2];
1362 			y = ((INTBIG *)var->addr)[i*2+1];
1363 			if (us_setxy(x, y)) nogood++;
1364 			(void)getxy(&xcur, &ycur);
1365 			if (i == 0)
1366 			{
1367 				lx = hx = xcur;   ly = hy = ycur;
1368 			} else
1369 			{
1370 				lx = mini(lx, xcur);   hx = maxi(hx, xcur);
1371 				ly = mini(ly, ycur);   hy = maxi(hy, ycur);
1372 			}
1373 		}
1374 		if (nogood != 0)
1375 		{
1376 			us_abortcommand(_("Outline not inside window"));
1377 			return;
1378 		}
1379 
1380 		/* save and erase highlighting */
1381 		us_pushhighlight();
1382 		us_clearhighlightcount();
1383 
1384 		/* set the new window size */
1385 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
1386 
1387 		startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1388 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
1389 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
1390 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
1391 		(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
1392 		us_gridset(el_curwindowpart, el_curwindowpart->state);
1393 		endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1394 
1395 		/* restore highlighting */
1396 		us_pophighlight(FALSE);
1397 		return;
1398 	}
1399 
1400 	if (namesamen(pp, x_("up"), l) == 0 && l >= 2)
1401 	{
1402 		if (us_needwindow()) return;
1403 		if (count < 2) pp = x_("0.5"); else pp = par[1];
1404 		switch (el_curwindowpart->state&WINDOWTYPE)
1405 		{
1406 			case DISPWINDOW:
1407 				if (us_needcell() == NONODEPROTO) return;
1408 				if (pp[estrlen(pp)-1] == 'l') dist = atola(pp, 0); else
1409 					dist = muldiv(atofr(pp), (el_curwindowpart->screenhy - el_curwindowpart->screenly), WHOLE);
1410 				us_slideup(dist);
1411 				return;
1412 			case DISP3DWINDOW:
1413 				us_3dpanview(el_curwindowpart, 0, 1);
1414 				return;
1415 			case TEXTWINDOW:
1416 				us_pantext(el_curwindowpart, 0, 1);
1417 				return;
1418 #if SIMTOOL
1419 			case WAVEFORMWINDOW:
1420 				newpar[0] = x_("window");
1421 				newpar[1] = x_("move");
1422 				newpar[2] = x_("up");
1423 				telltool(sim_tool, 3, newpar);
1424 				return;
1425 #endif
1426 			case EXPLORERWINDOW:
1427 				us_explorevpan(el_curwindowpart, 1);
1428 				return;
1429 		}
1430 		us_abortcommand(_("Cannot pan this kind of windows"));
1431 		return;
1432 	}
1433 
1434 	if (namesamen(pp, x_("use"), l) == 0 && l >= 2)
1435 	{
1436 		if (count <= 1)
1437 		{
1438 			count = ttygetparam(M_("Window to use: "), &us_windowup, MAXPARS-1, &par[1]) + 1;
1439 			if (count == 1)
1440 			{
1441 				us_abortedmsg();
1442 				return;
1443 			}
1444 		}
1445 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1446 		{
1447 			infstr = initinfstr();
1448 			addstringtoinfstr(infstr, describenodeproto(w->curnodeproto));
1449 			addtoinfstr(infstr, '(');
1450 			addstringtoinfstr(infstr, w->location);
1451 			addtoinfstr(infstr, ')');
1452 			if (namesame(par[1], returninfstr(infstr)) == 0) break;
1453 		}
1454 		if (w == NOWINDOWPART)
1455 		{
1456 			us_abortcommand(_("No window named '%s'"), par[1]);
1457 			return;
1458 		}
1459 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w, VWINDOWPART|VDONTSAVE);
1460 		(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)w->curnodeproto, VNODEPROTO);
1461 		return;
1462 	}
1463 
1464 	if (namesamen(pp, x_("zoom-scale"), l) == 0 && l >= 1)
1465 	{
1466 		if (count >= 2)
1467 		{
1468 			l = estrlen(pp = par[1]);
1469 			if (namesamen(pp, x_("integral"), l) == 0 && l >= 1)
1470 				(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | INTEGRAL, VINTEGER);
1471 			else if (namesamen(pp, x_("nonintegral"), l) == 0 && l >= 1)
1472 				(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~INTEGRAL, VINTEGER);
1473 			else
1474 			{
1475 				ttyputusage(x_("window zoom-scale integral|nonintegral"));
1476 				return;
1477 			}
1478 		}
1479 		if ((us_tool->toolstate&INTEGRAL) == 0)
1480 			ttyputverbose(M_("Window scaling will be continuous")); else
1481 				ttyputverbose(M_("Window scaling will force integral pixel alignment"));
1482 		return;
1483 	}
1484 
1485 	if (namesamen(pp, x_("1-window"), l) == 0 && l >= 1)
1486 	{
1487 		if (us_needwindow()) return;
1488 
1489 		if (estrcmp(el_curwindowpart->location, x_("entire")) == 0)
1490 		{
1491 			ttyputmsg(_("Already displaying only one window"));
1492 			return;
1493 		}
1494 
1495 		/* remember the current window */
1496 		oldw = el_curwindowpart;
1497 
1498 		/* turn off highlighting */
1499 		us_pushhighlight();
1500 		us_clearhighlightcount();
1501 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)NOWINDOWPART,
1502 			VWINDOWPART|VDONTSAVE);
1503 
1504 		startobjectchange((INTBIG)us_tool, VTOOL);
1505 
1506 		/* create a new window */
1507 		neww = newwindowpart(x_("entire"), oldw);
1508 		if (neww == NOWINDOWPART)
1509 		{
1510 			ttyputnomemory();
1511 			return;
1512 		}
1513 
1514 		/* if reducing to an editor window, move the editor structure */
1515 		if ((oldw->state&WINDOWTYPE) == TEXTWINDOW ||
1516 			(oldw->state&WINDOWTYPE) == POPTEXTWINDOW)
1517 		{
1518 			(void)setval((INTBIG)neww, VWINDOWPART, x_("editor"), (INTBIG)oldw->editor, VADDRESS);
1519 			(void)setval((INTBIG)oldw, VWINDOWPART, x_("editor"), -1, VADDRESS);
1520 		}
1521 
1522 		/* now delete all other windows */
1523 		for(w = el_topwindowpart; w != NOWINDOWPART; w = nextw)
1524 		{
1525 			nextw = w->nextwindowpart;
1526 			if (w->frame != neww->frame) continue;
1527 			if (w != neww) killwindowpart(w);
1528 		}
1529 
1530 		/* set the window extents */
1531 		us_windowfit(NOWINDOWFRAME, FALSE, 1);
1532 		endobjectchange((INTBIG)us_tool, VTOOL);
1533 
1534 		/* restore highlighting */
1535 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)neww,
1536 			VWINDOWPART|VDONTSAVE);
1537 		us_pophighlight(FALSE);
1538 		return;
1539 	}
1540 
1541 	if (namesamen(pp, x_("3-dimensional"), l) == 0 && l >= 1)
1542 	{
1543 		if (us_needwindow()) return;
1544 		w = el_curwindowpart;
1545 		if (count < 2)
1546 		{
1547 			ttyputusage(x_("window 3-dimensional OPTION"));
1548 			return;
1549 		}
1550 
1551 		l = estrlen(pp = par[1]);
1552 		if (namesamen(pp, x_("begin"), l) == 0 && l >= 1)
1553 		{
1554 			if ((w->state&WINDOWTYPE) == DISP3DWINDOW)
1555 			{
1556 				ttyputmsg(_("Window already shown in 3 dimensions"));
1557 				return;
1558 			}
1559 			if ((w->state&WINDOWTYPE) != DISPWINDOW)
1560 			{
1561 				us_abortcommand(_("Cannot view this window in 3 dimensions"));
1562 				return;
1563 			}
1564 			np = us_needcell();
1565 			if (np == NONODEPROTO) return;
1566 
1567 			us_3dsetupviewing(w);
1568 
1569 			/* clear highlighting */
1570 			us_clearhighlightcount();
1571 
1572 			/* make the cell fill the window */
1573 			us_fullview(np, &lx, &hx, &ly, &hy);
1574 			us_squarescreen(w, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
1575 
1576 			/* set the window extents */
1577 			startobjectchange((INTBIG)w, VWINDOWPART);
1578 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
1579 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
1580 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), ly, VINTEGER);
1581 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
1582 			(void)setval((INTBIG)w, VWINDOWPART, x_("buttonhandler"), (INTBIG)us_3dbuttonhandler,
1583 				VADDRESS);
1584 			(void)setval((INTBIG)w, VWINDOWPART, x_("state"), (w->state & ~WINDOWTYPE) | DISP3DWINDOW,
1585 				VINTEGER);
1586 			endobjectchange((INTBIG)w, VWINDOWPART);
1587 			return;
1588 		}
1589 
1590 		if (namesamen(pp, x_("end"), l) == 0 && l >= 1)
1591 		{
1592 			if ((w->state&WINDOWTYPE) == DISPWINDOW)
1593 			{
1594 				ttyputmsg(_("Window already shown in 2 dimensions"));
1595 				return;
1596 			}
1597 			if ((w->state&WINDOWTYPE) != DISP3DWINDOW)
1598 			{
1599 				us_abortcommand(_("Cannot view this window in 2 dimensions"));
1600 				return;
1601 			}
1602 
1603 			/* set the window extents */
1604 			lx = w->screenlx;   hx = w->screenhx;
1605 			ly = w->screenly;   hy = w->screenhy;
1606 			us_squarescreen(w, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
1607 			startobjectchange((INTBIG)w, VWINDOWPART);
1608 			(void)setval((INTBIG)w, VWINDOWPART, x_("state"), (w->state & ~WINDOWTYPE) | DISPWINDOW,
1609 				VINTEGER);
1610 			(void)setval((INTBIG)w, VWINDOWPART, x_("buttonhandler"), (INTBIG)DEFAULTBUTTONHANDLER,
1611 				VADDRESS);
1612 			(void)setval((INTBIG)w, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
1613 			(void)setval((INTBIG)w, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
1614 			(void)setval((INTBIG)w, VWINDOWPART, x_("screenly"), ly, VINTEGER);
1615 			(void)setval((INTBIG)w, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
1616 			us_gridset(w, el_curwindowpart->state);
1617 			endobjectchange((INTBIG)w, VWINDOWPART);
1618 			return;
1619 		}
1620 		if (namesamen(pp, x_("rotate"), l) == 0 && l >= 1)
1621 		{
1622 			us_3dsetinteraction(0);
1623 			return;
1624 		}
1625 		if (namesamen(pp, x_("zoom"), l) == 0 && l >= 1)
1626 		{
1627 			us_3dsetinteraction(1);
1628 			return;
1629 		}
1630 		if (namesamen(pp, x_("pan"), l) == 0 && l >= 1)
1631 		{
1632 			us_3dsetinteraction(2);
1633 			return;
1634 		}
1635 		if (namesamen(pp, x_("twist"), l) == 0 && l >= 1)
1636 		{
1637 			us_3dsetinteraction(3);
1638 			return;
1639 		}
1640 	}
1641 
1642 	ttyputbadusage(x_("window"));
1643 }
1644 
us_yanknode(INTBIG count,CHAR * par[])1645 void us_yanknode(INTBIG count, CHAR *par[])
1646 {
1647 	REGISTER BOOLEAN found;
1648 	REGISTER INTBIG total;
1649 	REGISTER NODEINST *topno;
1650 	REGISTER NODEPROTO *np;
1651 	REGISTER GEOM **list;
1652 
1653 	list = us_gethighlighted(WANTNODEINST, 0, 0);
1654 	if (list[0] == NOGEOM)
1655 	{
1656 		us_abortcommand(_("Must highlight cell(s) to be yanked"));
1657 		return;
1658 	}
1659 
1660 	np = geomparent(list[0]);
1661 	found = FALSE;
1662 	for(total=0; list[total] != NOGEOM; total++)
1663 	{
1664 		topno = list[total]->entryaddr.ni;
1665 		if (topno->proto->primindex != 0) continue;
1666 
1667 		/* disallow yanking if lock is on */
1668 		if (us_cantedit(np, topno, TRUE)) return;
1669 
1670 		/* turn off highlighting for the first cell */
1671 		if (!found) us_clearhighlightcount();
1672 
1673 		/* yank this cell */
1674 		us_yankonenode(topno);
1675 		found = TRUE;
1676 	}
1677 
1678 	if (!found) us_abortcommand(_("Can only yank cells"));
1679 }
1680