/*
 * Electric(tm) VLSI Design System
 *
 * File: usrdiacom.c
 * Special command dialogs
 * Written by: Steven M. Rubin, Static Free Software
 *
 * Copyright (c) 2000 Static Free Software.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 *
 * Static Free Software
 * 4119 Alpine Road
 * Portola Valley, California 94028
 * info@staticfreesoft.com
 */

#include "global.h"
#include "egraphics.h"
#include "usr.h"
#include "usrdiacom.h"
#include "usrtrack.h"
#include "efunction.h"
#include "tecart.h"
#include "tecschem.h"
#include "tecgen.h"
#include "usredtec.h"
#include "eio.h"
#include "edialogs.h"
#include "conlay.h"
#include "tecmocmossub.h"
#include <math.h>

struct butlist
{
	INTBIG value;  INTBIG button;
};

/* Progress (extended) */
DIALOGITEM us_eprogressdialogitems[] =
{
/*  1 */ {0, {56,8,73,230}, PROGRESS, ""},
/*  2 */ {0, {32,8,48,230}, MESSAGE, N_("Reading file...")},
/*  3 */ {0, {8,8,24,230}, MESSAGE, ""}
};
DIALOG us_eprogressdialog = {{50,75,135,314}, 0, 0, 3, us_eprogressdialogitems};

/* Progress (simple) */
DIALOGITEM us_progressdialogitems[] =
{
/*  1 */ {0, {32,8,49,230}, PROGRESS, ""},
/*  2 */ {0, {8,8,24,230}, MESSAGE, N_("Reading file...")}
};
DIALOG us_progressdialog = {{50,75,112,314}, 0, 0, 2, us_progressdialogitems};

/* icons for text and port dialogs */
unsigned char us_icon200[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 040, 0, 0200, 0200, 060, 0, 0200, 0203, 0370, 0, 0200,
	0200, 060, 0, 0200, 0200, 040, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 010, 0, 0200, 0200, 010, 0, 0200,
	0200, 010, 0, 0200, 0200, 010, 0, 0200, 0200, 076, 0, 0200, 0200, 034, 0, 0200,
	0200, 010, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0
};
unsigned char us_icon201[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 010, 0, 0200, 0200, 034, 0, 0200,
	0200, 076, 0, 0200, 0200, 010, 0, 0200, 0200, 010, 0, 0200, 0200, 010, 0, 0200,
	0200, 010, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 010, 0200, 0200, 0, 014, 0200, 0200, 0, 0376, 0200,
	0200, 0, 014, 0200, 0200, 0, 010, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0
};
unsigned char us_icon202[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0210, 0, 0, 0200, 0230, 0, 0, 0200, 0277, 0200, 0, 0200,
	0230, 0, 0, 0200, 0210, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0100, 0200,
	0200, 0, 040, 0200, 0200, 0, 022, 0200, 0200, 0, 016, 0200, 0200, 0, 016, 0200,
	0200, 0, 036, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0
};
unsigned char us_icon203[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0201, 0, 0, 0200,
	0202, 0, 0, 0200, 0244, 0, 0, 0200, 0270, 0, 0, 0200, 0270, 0, 0, 0200,
	0274, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 0, 036, 0200, 0200, 0, 016, 0200,
	0200, 0, 016, 0200, 0200, 0, 022, 0200, 0200, 0, 040, 0200, 0200, 0, 0100, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0
};
unsigned char us_icon204[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0274, 0, 0, 0200, 0270, 0, 0, 0200,
	0270, 0, 0, 0200, 0244, 0, 0, 0200, 0202, 0, 0, 0200, 0201, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0200, 010, 0, 0200, 0200, 034, 0, 0200,
	0200, 076, 0, 0200, 0210, 010, 010, 0200, 0230, 010, 014, 0200, 0277, 0200, 0376, 0200,
	0230, 010, 014, 0200, 0210, 010, 010, 0200, 0200, 076, 0, 0200, 0200, 034, 0, 0200,
	0200, 010, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0
};
unsigned char us_icon205[] =
{
	0377, 0377, 0377, 0200, 0200, 0, 0, 0200, 0274, 0, 0, 0200, 0270, 0, 0, 0200,
	0270, 0, 0, 0200, 0244, 0, 0, 0200, 0202, 0, 0, 0200, 0201, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200, 0200, 0, 0, 0200,
	0200, 0, 0, 0200, 0200, 0, 0, 0200, 0377, 0377, 0377, 0200, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static char      *us_lastplacetextmessage = 0;
static NODEPROTO *us_oldfacetprotos;
       INTBIG     us_showoldversions;
       INTBIG     us_showcellibraryfacets;
static LIBRARY   *us_curlib;

/* prototypes for local routines */
INTSML us_oldfacettopoffacets(char**);
char *us_oldfacetnextfacets(void);

/*
 * Routine to free all memory associated with this module.
 */
void us_freediacommemory(void)
{
	if (us_lastplacetextmessage != 0) efree((char *)us_lastplacetextmessage);
}

/*
 * Routines for listing all facets in library "us_curlib".  If "us_showoldversions" is nonzero,
 * show old versions.  If "us_showcellibraryfacets" is nonzero, show facets that are part of cell libraries.
 */
INTSML us_oldfacettopoffacets(char **c)
{
	us_oldfacetprotos = us_curlib->firstnodeproto;
	return(1);
}

char *us_oldfacetnextfacets(void)
{
	REGISTER NODEPROTO *thisnp;
	REGISTER LIBRARY *savelibrary;
	REGISTER char *ret;

	while (us_oldfacetprotos != NONODEPROTO)
	{
		thisnp = us_oldfacetprotos;
		us_oldfacetprotos = us_oldfacetprotos->nextnodeproto;
		if (us_showoldversions == 0 && thisnp->newestversion != thisnp) continue;
		if (us_showcellibraryfacets == 0 && (thisnp->userbits&INCELLLIBRARY) != 0)
			continue;
		savelibrary = el_curlib;
		el_curlib = us_curlib;
		ret = describenodeproto(thisnp);
		el_curlib = savelibrary;
		return(ret);
	}
	return(0);
}

/****************************** 3D DEPTH DIALOG ******************************/

/* 3D Depth */
DIALOGITEM us_3ddepthdialogitems[] =
{
/*  1 */ {0, {520,52,544,132}, BUTTON, N_("OK")},
/*  2 */ {0, {484,52,508,132}, BUTTON, N_("Cancel")},
/*  3 */ {0, {32,8,404,168}, SCROLL, ""},
/*  4 */ {0, {32,176,544,380}, USERDRAWN, ""},
/*  5 */ {0, {412,8,428,88}, MESSAGE, N_("Thickness:")},
/*  6 */ {0, {412,96,428,168}, EDITTEXT, "0"},
/*  7 */ {0, {8,8,24,324}, MESSAGE, ""},
/*  8 */ {0, {460,8,476,160}, CHECK, N_("Use Perspective")},
/*  9 */ {0, {436,8,452,88}, MESSAGE, N_("Height:")},
/* 10 */ {0, {436,96,452,168}, MESSAGE, "0"}
};
DIALOG us_3ddepthdialog = {{75,75,628,464}, N_("3D Options"), 0, 10, us_3ddepthdialogitems};

/*
 * special case for the "3D depth" dialog
 * List of layers        = 3 (scroll)
 * Layer heights diagram = 4 (user item)
 * Thickness             = 6 (edit text)
 * Technology name       = 7 (message)
 * Use perspective       = 8 (check)
 * Height               = 10 (message)
 */
RECTAREA  us_3dheightrect;
INTBIG    us_3dcurlayer;
INTBIG   *us_3dheight;
INTBIG   *us_3dthickness;
INTBIG   *us_3dlayerindex;
INTBIG    us_3dlayercount;
INTBIG    us_3dlowheight, us_3dhighheight;
INTBIG    us_3dchanged;

void us_redraw3ddepth(RECTAREA *bigr);
INTSML us_3ddepthstroke(INTBIG ox, INTBIG oy);

INTSML us_3ddepthdlog(void)
{
	INTBIG itemHit;
	INTSML x, y;
	char line[20];
	REGISTER WINDOWPART *w;
	REGISTER INTBIG i, j, funct, functp, thickness, height;

	/* cache the heights and thicknesses */
	us_3dheight = (INTBIG *)emalloc(el_curtech->layercount * SIZEOFINTBIG, el_tempcluster);
	if (us_3dheight == 0) return(0);
	us_3dthickness = (INTBIG *)emalloc(el_curtech->layercount * SIZEOFINTBIG, el_tempcluster);
	if (us_3dthickness == 0) return(0);
	us_3dlayerindex = (INTBIG *)emalloc(el_curtech->layercount * SIZEOFINTBIG, el_tempcluster);
	if (us_3dlayerindex == 0) return(0);
	for(i=0; i<el_curtech->layercount; i++)
	{
		if (get3dfactors(el_curtech, i, &us_3dheight[i], &us_3dthickness[i]) != 0)
		{
			us_3dheight[i] = 0;
			us_3dthickness[i] = 0;
		}
	}

	/* determine which layers are useful */
	us_3dlayercount = 0;
	for(i=0; i<el_curtech->layercount; i++)
	{
		funct = layerfunction(el_curtech, (INTSML)i);
		if ((funct&LFPSEUDO) != 0) continue;
		us_3dlayerindex[us_3dlayercount++] = i;
	}

	/* display the 3D options dialog box */
	if (DiaInitDialog(&us_3ddepthdialog) != 0) return(0);
	(void)initinfstr();
	(void)addstringtoinfstr(_("Layer heights for technology "));
	(void)addstringtoinfstr(el_curtech->techname);
	DiaSetText(7, returninfstr());
	if ((us_useroptions&NO3DPERSPECTIVE) == 0) DiaSetControl(8, 1);

	/* setup list of layer names */
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	for(i=0; i<us_3dlayercount; i++)
		DiaStuffLine(3, layername(el_curtech, (INTSML)us_3dlayerindex[i]));
	DiaSelectLine(3, 0);
	us_3dcurlayer = us_3dlayerindex[0];
	sprintf(line, "%ld", us_3dthickness[us_3dcurlayer]);   DiaSetText(6, line);
	sprintf(line, "%ld", us_3dheight[us_3dcurlayer]);   DiaSetText(10, line);

	/* setup layer height area */
	DiaItemRect(4, &us_3dheightrect);
	DiaRedispRoutine(4, us_redraw3ddepth);
	for(i=0; i<el_curtech->layercount; i++)
	{
		height = us_3dheight[i] * 2;
		thickness = us_3dthickness[i] * 2;
		if (i == 0)
		{
			us_3dlowheight = height - thickness/2;
			us_3dhighheight = height + thickness/2;
		} else
		{
			if (height - thickness/2 < us_3dlowheight) us_3dlowheight = height - thickness/2;
			if (height + thickness/2 > us_3dhighheight) us_3dhighheight = height + thickness/2;
		}
	}
	us_3dlowheight -= 4;
	us_3dhighheight += 4;
	us_redraw3ddepth(&us_3dheightrect);

	/* loop until done */
	us_3dchanged = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK) break;
		if (itemHit == 3)
		{
			j = DiaGetCurLine(3);
			us_3dcurlayer = us_3dlayerindex[j];
			sprintf(line, "%ld", us_3dthickness[us_3dcurlayer]);   DiaSetText(6, line);
			sprintf(line, "%ld", us_3dheight[us_3dcurlayer]);   DiaSetText(10, line);
			us_redraw3ddepth(&us_3dheightrect);
			continue;
		}
		if (itemHit == 6)
		{
			j = DiaGetCurLine(3);
			us_3dcurlayer = us_3dlayerindex[j];
			i = atoi(DiaGetText(6));
			if (i == us_3dthickness[us_3dcurlayer]) continue;
			us_3dchanged++;
			us_3dthickness[us_3dcurlayer] = i;
			us_redraw3ddepth(&us_3dheightrect);
			continue;
		}
		if (itemHit == 4)
		{
			DiaGetMouse(&x, &y);
			height = ((us_3dheightrect.bottom - y) * (us_3dhighheight - us_3dlowheight) +
				(us_3dheightrect.bottom - us_3dheightrect.top)/2) /
				(us_3dheightrect.bottom - us_3dheightrect.top) + us_3dlowheight;
			if (us_3dheight[us_3dcurlayer] * 2 != height)
			{
				for(i=0; i<us_3dlayercount; i++)
					if (us_3dheight[us_3dlayerindex[i]] == height / 2) break;
				if (i >= us_3dlayercount) continue;
				us_3dcurlayer = us_3dlayerindex[i];
				DiaSelectLine(3, i);
				sprintf(line, "%ld", us_3dthickness[us_3dcurlayer]);   DiaSetText(6, line);
				sprintf(line, "%ld", us_3dheight[us_3dcurlayer]);   DiaSetText(10, line);
			}
			us_redraw3ddepth(&us_3dheightrect);
			trackcursor(0, us_nullup, us_nullvoid, us_3ddepthstroke,
				us_nullchar, us_nullvoid, TRACKNORMAL);
			continue;
		}
		if (itemHit == 8)
		{
			DiaSetControl(itemHit, 1 - DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* copy regular layers to pseudo-layers */
		for(i=0; i<el_curtech->layercount; i++)
		{
			functp = layerfunction(el_curtech, (INTSML)i);
			if ((functp&LFPSEUDO) == 0) continue;

			/* pseudo layer found: look for real one */
			for(j=0; j<el_curtech->layercount; j++)
			{
				funct = layerfunction(el_curtech, (INTSML)j);
				if ((funct&LFPSEUDO) != 0) continue;
				if ((functp & ~LFPSEUDO) == funct)
				{
					us_3dheight[i] = us_3dheight[j];
					us_3dthickness[i] = us_3dthickness[j];
					break;
				}
			}
		}
		set3dheight(el_curtech, us_3dheight);
		set3dthickness(el_curtech, us_3dthickness);
		j = us_useroptions;
		if (DiaGetControl(8) == 0) j |= NO3DPERSPECTIVE; else j &= ~NO3DPERSPECTIVE;
		if (j != us_useroptions)
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags, j, VINTEGER);
	}
	DiaDoneDialog();
	efree((char *)us_3dheight);
	efree((char *)us_3dthickness);
	if (itemHit != CANCEL)
	{
		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
		{
			if ((w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
			if (w->redisphandler != 0) (*w->redisphandler)(w);
		}
	}
	return(0);
}

void us_redraw3ddepth(RECTAREA *bigr)
{
	REGISTER INTBIG i, height, thickness, ypos1, ypos2, ypos, layer;
	INTBIG wid, hei;
	char *pt;

	DiaFrameRect(4, bigr);
	for(i=0; i<us_3dlayercount; i++)
	{
		layer = us_3dlayerindex[i];
		height = us_3dheight[layer] * 2;
		thickness = us_3dthickness[layer] * 2;
		ypos = bigr->bottom - (height - us_3dlowheight) *
			(bigr->bottom - bigr->top) / (us_3dhighheight - us_3dlowheight);
		if (layer == us_3dcurlayer)
		{
			DiaDrawLine(4, bigr->left, ypos, bigr->left+8, ypos, DLMODEON);
			DiaDrawLine(4, bigr->left+4, ypos-4, bigr->left+4, ypos+4, DLMODEON);
			DiaDrawLine(4, bigr->left, ypos-4, bigr->left+8, ypos+4, DLMODEON);
			DiaDrawLine(4, bigr->left+8, ypos-4, bigr->left, ypos+4, DLMODEON);
		}
		if (thickness == 0)
		{
			DiaDrawLine(4, bigr->left+10, ypos, bigr->left+70, ypos, DLMODEON);
		} else
		{
			ypos1 = bigr->bottom - (height - thickness/2 - us_3dlowheight) *
				(bigr->bottom - bigr->top) / (us_3dhighheight - us_3dlowheight) - 2;
			ypos2 = bigr->bottom - (height + thickness/2 - us_3dlowheight) *
				(bigr->bottom - bigr->top) / (us_3dhighheight - us_3dlowheight) + 2;
			DiaDrawLine(4, bigr->left+10, ypos1, bigr->left+40, ypos1, DLMODEON);
			DiaDrawLine(4, bigr->left+40, ypos1, bigr->left+50, ypos, DLMODEON);
			DiaDrawLine(4, bigr->left+40, ypos2, bigr->left+50, ypos, DLMODEON);
			DiaDrawLine(4, bigr->left+10, ypos2, bigr->left+40, ypos2, DLMODEON);
			DiaDrawLine(4, bigr->left+50, ypos, bigr->left+70, ypos, DLMODEON);
		}
		pt = layername(el_curtech, (INTSML)layer);
		DiaGetTextInfo(pt, &wid, &hei);
		DiaPutText(4, pt, bigr->left+70, ypos - hei/2);
	}
}

INTSML us_3ddepthstroke(INTBIG ox, INTBIG oy)
{
	INTSML x, y;
	REGISTER INTBIG height;
	char line[20];

	DiaGetMouse(&x, &y);
	height = ((us_3dheightrect.bottom - y) * (us_3dhighheight - us_3dlowheight) +
		(us_3dheightrect.bottom - us_3dheightrect.top)/2) /
		(us_3dheightrect.bottom - us_3dheightrect.top) + us_3dlowheight;
	if (us_3dheight[us_3dcurlayer] == height / 2) return(0);
	us_3dchanged++;
	us_3dheight[us_3dcurlayer] = height / 2;
	sprintf(line, "%ld", us_3dheight[us_3dcurlayer]);   DiaSetText(10, line);
	us_redraw3ddepth(&us_3dheightrect);
	return(0);
}

/****************************** ABOUT ELECTRIC DIALOG ******************************/

/*
 * the list of contributors to Electric (not including Steven M. Rubin)
 */
typedef struct
{
	char *name;
	char *help;
} HELPERS;
HELPERS us_castofthousands[] =
{
	"Philip Attfield",			N_("Box merging, facet date checking"),
	"Ron Bolton",				N_("Mathematical help"),
	"Mark Brinsmead",			N_("Mathematical help"),
	"Stefano Concina",			N_("Polygon clipping"),
	"Jonathan Gainsley",		N_("User testing"),
	"Peter Gallant",			N_("ALS simulator"),
	"R. Brian Gardiner",		N_("Electric lifeline"),
	"T. J. Goodman",			N_("Texsim simulator"),
	"D. Guptill",			    N_("X-window help"),
	"Robert Hon",				N_("CIF input parser"),
	"Sundaravarathan Iyengar",	N_("nMOS PLA generator"),
	"Allan Jost",				N_("VHDL compiler help, X-window help"),
	"Wallace Kroeker",			N_("Digital filter technology, CMOS PLA generator"),
	"Andrew Kostiuk",			N_("VHDL compiler, Silicon Compiler"),
	"Oliver Laumann",			N_("ELK Lisp"),
	"Glen Lawson",				N_("Maze routing, GDS input, EDIF I/O"),
	"David Lewis",				N_("Flat DRC checking"),
	"Erwin Liu",				N_("Schematic and Round CMOS technology help"),
	"Dick Lyon",				N_("MOSIS and Round CMOS technology help"),
	"John Mohammed",			N_("Mathematical help"),
	"Mark Moraes",				N_("Hierarchical DRC, X-window help"),
	"Sid Penstone",				N_("SPICE output, SILOS output, GDS output, Box merging, technologies"),
	"J. P. Polonovski",			N_("Memory allocation help"),
	"Kevin Ryan",			    N_("X-window help"),
	"Nora Ryan",				N_("Compaction, technology conversion"),
	"Brent Serbin",				N_("ALS simulator"),
	"Ken Stevens",				N_("Network flattening help"),
	"Lyndon Swab",				N_("HPGL output, SPICE output help, technologies"),
	"Brian W. Thomson",			N_("Mimic stitcher, RSIM interface"),
	"Burnie West",				N_("Bipolar technology, EDIF output help, NCC help"),
	"Telle Whitney",			N_("River router"),
	"Rob Winstanley",			N_("CIF input, RNL interface"),
	"Russell Wright",			N_("SDF input, miscellaneous help"),
	"David J. Yurach",			N_("VHDL help"),
	0, 0
};

char *us_gnucopying[] =
{
	"TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION",
	"",
	"0. This License applies to any program or other work which contains a notice placed by",
	"the copyright holder saying it may be distributed under the terms of this General",
	"Public License. The 'Program', below, refers to any such program or work, and a",
	"'work based on the Program' means either the Program or any derivative work under",
	"copyright law: that is to say, a work containing the Program or a portion of it,",
	"either verbatim or with modifications and/or translated into another language.",
	"(Hereinafter, translation is included without limitation in the term 'modification'.)",
	"Each licensee is addressed as 'you'.",
	"",
	"Activities other than copying, distribution and modification are not covered by this",
	"License; they are outside its scope. The act of running the Program is not restricted,",
	"and the output from the Program is covered only if its contents constitute a work based",
	"on the Program (independent of having been made by running the Program). Whether that",
	"is true depends on what the Program does.",
	"",
	"1. You may copy and distribute verbatim copies of the Program's source code as you",
	"receive it, in any medium, provided that you conspicuously and appropriately publish",
	"on each copy an appropriate copyright notice and disclaimer of warranty; keep intact",
	"all the notices that refer to this License and to the absence of any warranty; and",
	"give any other recipients of the Program a copy of this License along with the Program.",
	"",
	"You may charge a fee for the physical act of transferring a copy, and you may at your",
	"option offer warranty protection in exchange for a fee.",
	"",
	"2. You may modify your copy or copies of the Program or any portion of it, thus forming",
	"a work based on the Program, and copy and distribute such modifications or work under",
	"the terms of Section 1 above, provided that you also meet all of these conditions:",
	"",
	"*	a) You must cause the modified files to carry prominent notices stating that you",
	"	changed the files and the date of any change.",
	"",
	"*	b) You must cause any work that you distribute or publish, that in whole or",
	"	in part contains or is derived from the Program or any part thereof, to be licensed",
	"	as a whole at no charge to all third parties under the terms of this License.",
	"",
	"*	c) If the modified program normally reads commands interactively when run, you",
	"	must cause it, when started running for such interactive use in the most ordinary",
	"	way, to print or display an announcement including an appropriate copyright notice",
	"	and a notice that there is no warranty (or else, saying that you provide a warranty)",
	"	and that users may redistribute the program under these conditions, and telling the",
	"	user how to view a copy of this License. (Exception: if the Program itself is",
	"	interactive but does not normally print such an announcement, your work based on the",
	"	Program is not required to print an announcement.)",
	"",
	"These requirements apply to the modified work as a whole. If identifiable sections",
	"of that work are not derived from the Program, and can be reasonably considered independent",
	"and separate works in themselves, then this License, and its terms, do not apply to those",
	"sections when you distribute them as separate works. But when you distribute the same",
	"sections as part of a whole which is a work based on the Program, the distribution of",
	"the whole must be on the terms of this License, whose permissions for other licensees",
	"extend to the entire whole, and thus to each and every part regardless of who wrote it.",
	"",
	"Thus, it is not the intent of this section to claim rights or contest your rights to",
	"work written entirely by you; rather, the intent is to exercise the right to control",
	"the distribution of derivative or collective works based on the Program.",
	"",
	"In addition, mere aggregation of another work not based on the Program with the Program",
	"(or with a work based on the Program) on a volume of a storage or distribution medium",
	"does not bring the other work under the scope of this License.",
	"",
	"3. You may copy and distribute the Program (or a work based on it, under Section 2)",
	"in object code or executable form under the terms of Sections 1 and 2 above provided",
	"that you also do one of the following:",
	"",
	"*	a) Accompany it with the complete corresponding machine-readable source code,",
	"which must be distributed under the terms of Sections 1 and 2 above on a medium",
	"customarily used for software interchange; or,",
	"",
	"*	b) Accompany it with a written offer, valid for at least three years, to give",
	"any third party, for a charge no more than your cost of physically performing source",
	"distribution, a complete machine-readable copy of the corresponding source code,",
	"to be distributed under the terms of Sections 1 and 2 above on a medium customarily",
	"used for software interchange; or,",
	"",
	"*	c) Accompany it with the information you received as to the offer to distribute",
	"corresponding source code. (This alternative is allowed only for noncommercial",
	"distribution and only if you received the program in object code or executable",
	"form with such an offer, in accord with Subsection b above.)",
	"",
	"The source code for a work means the preferred form of the work for making",
	"modifications to it. For an executable work, complete source code means all",
	"the source code for all modules it contains, plus any associated interface",
	"definition files, plus the scripts used to control compilation and installation",
	"of the executable. However, as a special exception, the source code distributed",
	"need not include anything that is normally distributed (in either source or binary",
	"form) with the major components (compiler, kernel, and so on) of the operating",
	"system on which the executable runs, unless that component itself accompanies the executable.",
	"",
	"If distribution of executable or object code is made by offering access to copy",
	"from a designated place, then offering equivalent access to copy the source code",
	"from the same place counts as distribution of the source code, even though third",
	"parties are not compelled to copy the source along with the object code.",
	"",
	"4. You may not copy, modify, sublicense, or distribute the Program except as",
	"expressly provided under this License. Any attempt otherwise to copy, modify,",
	"sublicense or distribute the Program is void, and will automatically terminate your",
	"rights under this License. However, parties who have received copies, or rights,",
	"from you under this License will not have their licenses terminated so long as",
	"such parties remain in full compliance.",
	"",
	"5. You are not required to accept this License, since you have not signed it.",
	"However, nothing else grants you permission to modify or distribute the Program or",
	"its derivative works. These actions are prohibited by law if you do not accept this",
	"License. Therefore, by modifying or distributing the Program (or any work based on",
	"the Program), you indicate your acceptance of this License to do so, and all its",
	"terms and conditions for copying, distributing or modifying the Program or works based on it.",
	"",
	"6. Each time you redistribute the Program (or any work based on the Program),",
	"the recipient automatically receives a license from the original licensor to copy,",
	"distribute or modify the Program subject to these terms and conditions. You may not",
	"impose any further restrictions on the recipients' exercise of the rights granted",
	"herein. You are not responsible for enforcing compliance by third parties to this License.",
	"",
	"7. If, as a consequence of a court judgment or allegation of patent infringement",
	"or for any other reason (not limited to patent issues), conditions are imposed",
	"on you (whether by court order, agreement or otherwise) that contradict the conditions",
	"of this License, they do not excuse you from the conditions of this License. If you",
	"cannot distribute so as to satisfy simultaneously your obligations under this",
	"License and any other pertinent obligations, then as a consequence you may not",
	"distribute the Program at all. For example, if a patent license would not permit",
	"royalty-free redistribution of the Program by all those who receive copies directly",
	"or indirectly through you, then the only way you could satisfy both it and this",
	"License would be to refrain entirely from distribution of the Program.",
	"",
	"If any portion of this section is held invalid or unenforceable under any",
	"particular circumstance, the balance of the section is intended to apply and",
	"the section as a whole is intended to apply in other circumstances.",
	"",
	"It is not the purpose of this section to induce you to infringe any patents",
	"or other property right claims or to contest validity of any such claims; this",
	"section has the sole purpose of protecting the integrity of the free software",
	"distribution system, which is implemented by public license practices. Many",
	"people have made generous contributions to the wide range of software distributed",
	"through that system in reliance on consistent application of that system; it is",
	"up to the author/donor to decide if he or she is willing to distribute software",
	"through any other system and a licensee cannot impose that choice.",
	"",
	"This section is intended to make thoroughly clear what is believed to be a",
	"consequence of the rest of this License.",
	"",
	"8. If the distribution and/or use of the Program is restricted in certain",
	"countries either by patents or by copyrighted interfaces, the original copyright",
	"holder who places the Program under this License may add an explicit geographical",
	"distribution limitation excluding those countries, so that distribution is permitted",
	"only in or among countries not thus excluded. In such case, this License incorporates",
	"the limitation as if written in the body of this License.",
	"",
	"9. The Free Software Foundation may publish revised and/or new versions of the",
	"General Public License from time to time. Such new versions will be similar in",
	"spirit to the present version, but may differ in detail to address new problems",
	"or concerns.",
	"",
	"Each version is given a distinguishing version number. If the Program specifies",
	"a version number of this License which applies to it and 'any later version',",
	"you have the option of following the terms and conditions either of that version",
	"or of any later version published by the Free Software Foundation. If the Program",
	"does not specify a version number of this License, you may choose any version ever",
	"published by the Free Software Foundation.",
	"",
	"10. If you wish to incorporate parts of the Program into other free programs",
	"whose distribution conditions are different, write to the author to ask for",
	"permission. For software which is copyrighted by the Free Software Foundation,",
	"write to the Free Software Foundation; we sometimes make exceptions for this.",
	"Our decision will be guided by the two goals of preserving the free status of",
	"all derivatives of our free software and of promoting the sharing and reuse of",
	"software generally.",
	0
};

char *us_gnuwarranty[] =
{
	"NO WARRANTY",
	"",
	"11. Because the program is licensed free of charge, there is no warranty for the",
	"program, to the extent permitted by applicable law. Except when otherwise stated",
	"in writing the copyright holders and/or other parties provide the program 'as is'",
	"without warranty of any kind, either expressed or implied, including, but not",
	"limited to, the implied warranties of merchantability and fitness for a particular",
	"purpose. The entire risk as to the quality and performance of the program is with you.",
	"Should the program prove defective, you assume the cost of all necessary servicing,",
	"repair or correction. ",
	"",
	"12. In no event unless required by applicable law or agreed to in writing will any",
	"copyright holder, or any other party who may modify and/or redistribute the program",
	"as permitted above, be liable to you for damages, including any general, special,",
	"incidental or consequential damages arising out of the use or inability to use the",
	"program (including but not limited to loss of data or data being rendered inaccurate",
	"or losses sustained by you or third parties or a failure of the program to operate",
	"with any other programs), even if such holder or other party has been advised of",
	"the possibility of such damages. ",
	0
};

/* icons for the "About Electric" dialog */
unsigned char us_icon130[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 03, 0377, 0377, 0, 07, 0377, 0377, 0, 014, 0, 0, 0, 030, 0, 0,
	0, 060, 0, 0, 0, 0140, 0, 0, 0, 0300, 0, 0, 01, 0200, 0, 0,
	03, 0, 0, 0, 03, 0, 0, 0, 06, 0, 0, 0, 06, 0, 0, 0,
	014, 03, 0374, 0, 014, 03, 0374, 0, 030, 03, 0374, 0, 030, 03, 0374, 0,
	060, 03, 0374, 0, 060, 03, 0374, 0, 0140, 03, 0374, 0, 0140, 03, 0374, 0,
	0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0,
	0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0
};
unsigned char us_icon129[] =
{
	0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 03, 0374, 0,
	0300, 03, 0374, 0, 0300, 03, 0374, 0, 0300, 0, 0, 0, 0300, 0, 0, 0,
	0140, 0, 0, 03, 0140, 0, 0, 07, 060, 0, 0, 017, 060, 0, 0, 037,
	030, 0, 0, 077, 030, 0, 0, 077, 014, 0, 0, 077, 014, 0, 0, 077,
	06, 0, 0, 077, 06, 0, 0, 077, 03, 0, 0, 077, 03, 0, 0, 077,
	01, 0200, 0, 0, 0, 0300, 0, 0, 0, 0140, 0, 0, 0, 060, 0, 0,
	0, 030, 0, 0, 0, 014, 0, 0, 0, 07, 0377, 0377, 0, 03, 0377, 0377,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon131[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0377, 0377, 0300, 0, 0377, 0377, 0340, 0, 0, 0, 060, 0, 0, 0, 030, 0,
	0, 0, 014, 0, 0, 0, 06, 0, 0, 0, 03, 0, 0, 0, 01, 0200,
	0, 0, 0, 0300, 0, 0, 0, 0300, 0, 0, 0, 0140, 0, 0, 0, 0140,
	0, 077, 0300, 060, 0, 077, 0300, 060, 0, 077, 0300, 030, 0, 077, 0300, 030,
	0, 077, 0300, 014, 0, 077, 0300, 014, 0, 077, 0300, 06, 0, 077, 0300, 06,
	0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03,
	0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03
};
unsigned char us_icon132[] =
{
	0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03, 0, 077, 0300, 03,
	0, 0, 0, 03, 0, 0, 0, 03, 0, 0, 0, 03, 0, 0, 0, 03,
	0300, 0, 0, 06, 0340, 0, 0, 06, 0360, 0, 0, 014, 0370, 0, 0, 014,
	0374, 0, 0, 030, 0374, 0, 0, 030, 0374, 0, 0, 060, 0374, 0, 0, 060,
	0374, 0, 0, 0140, 0374, 0, 0, 0140, 0374, 0, 0, 0300, 0374, 0, 0, 0300,
	0, 0, 01, 0200, 0, 0, 03, 0, 0, 0, 06, 0, 0, 0, 014, 0,
	0, 0, 030, 0, 0, 0, 060, 0, 0377, 0377, 0340, 0, 0377, 0377, 0300, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* About Electric */
DIALOGITEM us_aboutgnudialogitems[] =
{
 /*  1 */ {0, {16,320,40,400}, BUTTON, N_("Continue")},
 /*  2 */ {0, {308,12,324,356}, MESSAGE, N_("Electric comes with ABSOLUTELY NO WARRANTY")},
 /*  3 */ {0, {284,12,300,489}, MESSAGE, N_("Copyright (c) 2000 Static Free Software (www.staticfreesoft.com)")},
 /*  4 */ {0, {56,8,72,221}, MESSAGE, N_("Written by Steven M. Rubin")},
 /*  5 */ {0, {8,8,24,295}, MESSAGE, N_("The Electric(tm) Design System")},
 /*  6 */ {0, {32,8,48,246}, MESSAGE, N_("Version XXXX")},
 /*  7 */ {0, {4,420,36,452}, ICON|INACTIVE, (char *)us_icon130},
 /*  8 */ {0, {36,420,68,452}, ICON|INACTIVE, (char *)us_icon129},
 /*  9 */ {0, {4,452,36,484}, ICON|INACTIVE, (char *)us_icon131},
 /* 10 */ {0, {36,452,68,484}, ICON|INACTIVE, (char *)us_icon132},
 /* 11 */ {0, {100,8,273,487}, SCROLL, ""},
 /* 12 */ {0, {76,160,94,348}, BUTTON, N_("And a Cast of Thousands")},
 /* 13 */ {0, {332,12,348,330}, MESSAGE, N_("This is free software, and you are welcome to")},
 /* 14 */ {0, {308,358,326,487}, BUTTON, N_("Warranty details")},
 /* 15 */ {0, {344,358,362,487}, BUTTON, N_("Copying details")},
 /* 16 */ {0, {352,12,368,309}, MESSAGE, N_("redistribute it under certain conditions")}
};
DIALOG us_aboutgnudialog = {{50,75,427,573}, 0, 0, 16, us_aboutgnudialogitems};

/*
 * special case for the "About Electric" dialog
 * version number        = 6 (message)
 * authors               = 12 (button)
 * restrictions (nonGNU) = 13 (button)
 * warranty (GNU)        = 14 (button)
 * copying (GNU)         = 15 (button)
 */
INTSML us_aboutdlog(void)
{
	char line[256], date[30];
	INTBIG itemHit, i, castlisted;

	/* show the "about" dialog */
#ifdef EPROGRAMNAME
	sprintf(line, _("About %s"), EPROGRAMNAME);
	us_aboutgnudialog.movable = line;
#else
	us_aboutgnudialog.movable = _("About Electric");
#endif
	if (DiaInitDialog(&us_aboutgnudialog) != 0) return(0);
	DiaInitTextDialog(11, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT|SCSMALLFONT|SCHORIZBAR);

	/* show the version and copyright information */
	(void)strcpy(line, _("Version "));
	(void)strcat(line, el_version);
	(void)strcat(line, ", ");
	(void)strcat(line, __DATE__);
	DiaSetText(6, line);
	strcpy(date, timetostring(getcurrenttime()));
	date[24] = 0;
	(void)sprintf(line, _("Copyright (c) %s Static Free Software (www.staticfreesoft.com)"), &date[20]);
	DiaSetText(3, line);

	castlisted = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK) break;
		if (itemHit == 11)
		{
			if (castlisted == 0) continue;
			i = DiaGetCurLine(11);
			(void)initinfstr();
			(void)formatinfstr("%s did %s", us_castofthousands[i].name, _(us_castofthousands[i].help));
			DiaSetScrollLine(11, i, returninfstr());
			continue;
		}
		if (itemHit == 12)
		{
			DiaLoadTextDialog(11, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(i=0; us_castofthousands[i].name != 0; i++) DiaStuffLine(11, us_castofthousands[i].name);
			DiaSelectLine(11, -1);
			castlisted = 1;
			continue;
		}
		if (itemHit == 14)
		{
			DiaLoadTextDialog(11, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(i=0; us_gnuwarranty[i] != 0; i++) DiaStuffLine(11, us_gnuwarranty[i]);
			DiaSelectLine(11, -1);
			castlisted = 0;
			continue;
		}
		if (itemHit == 15)
		{
			DiaLoadTextDialog(11, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(i=0; us_gnucopying[i] != 0; i++) DiaStuffLine(11, us_gnucopying[i]);
			DiaSelectLine(11, -1);
			castlisted = 0;
			continue;
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** ALIGNMENT OPTIONS DIALOG ******************************/

/* Alignment Options */
DIALOGITEM us_alignmentdialogitems[] =
{
/*  1 */ {0, {68,340,92,404}, BUTTON, N_("OK")},
/*  2 */ {0, {68,32,92,96}, BUTTON, N_("Cancel")},
/*  3 */ {0, {8,8,24,205}, MESSAGE, N_("Alignment of cursor to grid:")},
/*  4 */ {0, {40,8,56,205}, MESSAGE, N_("Alignment of edges to grid:")},
/*  5 */ {0, {8,208,24,280}, EDITTEXT, ""},
/*  6 */ {0, {40,208,56,280}, EDITTEXT, ""},
/*  7 */ {0, {16,284,32,426}, MESSAGE, N_("Values of zero will")},
/*  8 */ {0, {32,284,48,428}, MESSAGE, N_("cause no alignment.")}
};
DIALOG us_alignmentdialog = {{50,75,154,512}, N_("Alignment Options"), 0, 8, us_alignmentdialogitems};

/*
 * special case for the "alignment options" dialog
 * Grid alignment     = 5 (edit text)
 * Edge alignment     = 6 (edit text)
 */
INTSML us_alignmentdlog(void)
{
	INTBIG itemHit;
	INTBIG retval1;

	if (us_needwindow()) return(0);

	/* display the alignment settings dialog box */
	if (DiaInitDialog(&us_alignmentdialog) != 0) return(0);
	DiaSetText(5, latoa(us_alignment));
	DiaSetText(6, latoa(us_edgealignment));

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}

	if (itemHit != CANCEL)
	{
		/* see if alignment changed */
		retval1 = atola(DiaGetText(5));
		if (retval1 != us_alignment)
			(void)setvalkey((INTBIG)us_aid, VAID, us_alignment_obj, retval1, VINTEGER);
		retval1 = atola(DiaGetText(6));
		if (retval1 != us_edgealignment)
			(void)setvalkey((INTBIG)us_aid, VAID, us_alignment_edge, retval1, VINTEGER);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** ARC CREATION OPTIONS DIALOG ******************************/

/* New arc options */
DIALOGITEM us_defarcdialogitems[] =
{
/*  1 */ {0, {192,312,216,384}, BUTTON, N_("OK")},
/*  2 */ {0, {192,72,216,144}, BUTTON, N_("Cancel")},
/*  3 */ {0, {15,150,31,430}, POPUP, ""},
/*  4 */ {0, {15,15,31,145}, RADIO, N_("Defaults for arc:")},
/*  5 */ {0, {40,15,56,175}, RADIO, N_("Defaults for all arcs")},
/*  6 */ {0, {160,368,176,423}, BUTTON, N_("Set pin")},
/*  7 */ {0, {80,16,96,73}, CHECK, N_("Rigid")},
/*  8 */ {0, {80,112,96,214}, CHECK, N_("Fixed-angle")},
/*  9 */ {0, {80,224,96,299}, CHECK, N_("Slidable")},
/* 10 */ {0, {104,16,120,95}, CHECK, N_("Negated")},
/* 11 */ {0, {104,112,120,205}, CHECK, N_("Directional")},
/* 12 */ {0, {104,224,120,344}, CHECK, N_("Ends extended")},
/* 13 */ {0, {40,260,60,428}, BUTTON, N_("Reset to initial defaults")},
/* 14 */ {0, {136,72,152,160}, EDITTEXT, ""},
/* 15 */ {0, {136,16,152,64}, MESSAGE, N_("Width:")},
/* 16 */ {0, {136,184,152,232}, MESSAGE, N_("Angle:")},
/* 17 */ {0, {136,240,152,304}, EDITTEXT, ""},
/* 18 */ {0, {160,16,176,47}, MESSAGE, N_("Pin:")},
/* 19 */ {0, {160,48,176,358}, MESSAGE, ""}
};
DIALOG us_defarcdialog = {{50,75,278,514}, N_("New Arc Options"), 0, 19, us_defarcdialogitems};

static ARCPROTO *us_thisap;
static NODEPROTO *us_posprims;

void us_defarcload(ARCPROTO*, NODEPROTO**, INTBIG);
INTSML us_topofpins(char**);
char *us_nextpins(void);

/*
 * special case for the "defarc" dialog
 * defaults for specific type = 4 (radio)
 * defaults for all types     = 5 (radio)
 * specific arc               = 3 (message)
 * reset to initial state     = 13 (button)
 * rigid                      = 7 (check)
 * fixed-angle                = 8 (check)
 * slidable                   = 9 (check)
 * negated                    = 10 (check)
 * directional                = 11 (check)
 * ends extended              = 12 (check)
 * width                      = 14 (edit text)
 * width title                = 15 (message)
 * angle title                = 16 (message)
 * angle                      = 17 (edit text)
 * default pin title          = 18 (message)
 * default pin                = 19 (message)
 * set pin                    = 6 (button)
 */
INTSML us_defarcdlog(void)
{
	INTBIG itemHit;
	REGISTER INTBIG allstyle, i, j, origallstyle, bits;
	REGISTER VARIABLE *var;
	char **arcnames;
	REGISTER ARCPROTO *ap, **arcs;
	REGISTER NODEPROTO **pins, *np;
	extern DIALOG us_listdialog;

	/* display the default arc dialog box */
	if (DiaInitDialog(&us_defarcdialog) != 0) return(0);

	/* remember all state */
	var = getvalkey((INTBIG)us_aid, VAID, VINTEGER, us_arcstyle);
	if (var != NOVARIABLE) allstyle = var->addr; else
		allstyle = WANTFIXANG;
	origallstyle = allstyle;
	for(i=0, ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto) i++;
	pins = (NODEPROTO **)emalloc(i * (sizeof (NODEPROTO *)), el_tempcluster);
	arcs = (ARCPROTO **)emalloc(i * (sizeof (ARCPROTO *)), el_tempcluster);
	arcnames = (char **)emalloc(i * (sizeof (char *)), el_tempcluster);
	if (pins == 0 || arcs == 0 || arcnames == 0) return(0);
	for(i=0, ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto, i++)
	{
		var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstyle);
		if (var != NOVARIABLE) ap->temp1 = var->addr; else
			ap->temp1 = ap->userbits;
		ap->temp2 = defaultarcwidth(ap);
		pins[i] = getpinproto(ap);
		arcs[i] = ap;
		arcnames[i] = ap->protoname;
	}

	/* initially load for first arc in technology */
	us_thisap = us_curarcproto;
	us_defarcload(us_thisap, pins, allstyle);
	DiaSetControl(4, 1);
	DiaSetPopup(3, i, arcnames);
	efree((char *)arcnames);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 7 || itemHit == 8 || itemHit == 9 ||
			itemHit == 10 || itemHit == 11 || itemHit == 12)
		{
			j = DiaGetControl(itemHit);
			DiaSetControl(itemHit, 1-j);
			if (DiaGetControl(4) == 0) i = allstyle; else
				i = us_thisap->temp1;
			switch (itemHit)
			{
				case 7:
					if (j == 0) i |= WANTFIX; else i &= ~WANTFIX;
					break;
				case 8:
					if (j == 0) i |= WANTFIXANG; else i &= ~WANTFIXANG;
					break;
				case 9:
					if (j != 0) i |= WANTCANTSLIDE; else i &= ~WANTCANTSLIDE;
					break;
				case 10:
					if (j == 0) i |= WANTNEGATED; else i &= ~WANTNEGATED;
					break;
				case 11:
					if (j == 0) i |= WANTDIRECTIONAL; else i &= ~WANTDIRECTIONAL;
					break;
				case 12:
					if (j != 0) i |= WANTNOEXTEND; else i &= ~WANTNOEXTEND;
					break;
			}
			if (DiaGetControl(4) == 0) allstyle = i; else
				us_thisap->temp1 = i;
			continue;
		}
		if (itemHit == 4)
		{
			us_defarcload(us_thisap, pins, allstyle);
			DiaSetControl(4, 1);
			DiaSetControl(5, 0);
			continue;
		}
		if (itemHit == 5)
		{
			us_defarcload(NOARCPROTO, pins, allstyle);
			DiaSetControl(4, 0);
			DiaSetControl(5, 1);
			continue;
		}
		if (itemHit == 13)
		{
			allstyle = WANTFIXANG;
			DiaSetControl(7, 0);
			DiaSetControl(8, 1);
			DiaSetControl(9, 1);
			DiaSetControl(10, 0);
			DiaSetControl(11, 0);
			DiaSetControl(12, 1);
			continue;
		}
		if (itemHit == 3)
		{
			i = DiaGetPopupEntry(3);
			us_thisap = arcs[i];
			us_defarcload(us_thisap, pins, allstyle);
			continue;
		}
		if (itemHit == 14)
		{
			if (DiaGetControl(4) == 0) continue;
			us_thisap->temp2 = atola(DiaGetText(14));
			continue;
		}
		if (itemHit == 17)
		{
			if (DiaGetControl(4) == 0) continue;
			us_thisap->temp1 = (us_thisap->temp1 & ~AANGLEINC) | ((atoi(DiaGetText(17))%360) << AANGLEINCSH);
			continue;
		}
		if (itemHit == 6)
		{
			if (DiaGetControl(4) == 0) continue;

			if (DiaInitDialog(&us_listdialog) != 0) continue;
			DiaInitTextDialog(3, us_topofpins, us_nextpins, DiaNullDlogDone,
				0, SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT);
			DiaSetText(4, _("Select a node to use as a pin"));

			for(;;)
			{
				itemHit = DiaNextHit();
				if (itemHit == OK || itemHit == CANCEL) break;
			}
			np = getnodeproto(DiaGetScrollLine(3, DiaGetCurLine(3)));
			DiaDoneDialog();
			if (itemHit == CANCEL) continue;

			for(i=0, ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto, i++)
				if (us_thisap == ap) break;
			if (ap != NOARCPROTO) pins[i] = np;
			DiaSetText(19, describenodeproto(np));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		for(i=0, ap = el_curtech->firstarcproto; ap != NOARCPROTO;
			ap = ap->nextarcproto, i++)
		{
			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstyle);
			if (var != NOVARIABLE) bits = var->addr; else
				bits = ap->userbits;
			if (ap->temp1 != bits)
			{
				if ((ap->temp1 & AANGLEINC) != (bits & AANGLEINC))
					(void)setval((INTBIG)ap, VARCPROTO, "userbits", ap->temp1, VINTEGER);
				if ((ap->temp1 & ~AANGLEINC) != (bits & ~AANGLEINC))
					(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstyle, ap->temp1, VINTEGER);
			}
			if (ap->temp2 != defaultarcwidth(ap))
				(void)setvalkey((INTBIG)ap, VARCPROTO, el_arc_default_width,
					arcprotowidthoffset(ap) + ap->temp2, VINTEGER);
			np = getpinproto(ap);
			if (np != pins[i])
				(void)setval((INTBIG)ap, VARCPROTO, "ARC_Default_Pin", (INTBIG)pins[i], VNODEPROTO);
		}
		if (allstyle != origallstyle)
			(void)setvalkey((INTBIG)us_aid, VAID, us_arcstyle, allstyle, VINTEGER);
	}
	DiaDoneDialog();
	efree((char *)pins);
	efree((char *)arcs);
	return(0);
}

INTSML us_topofpins(char **c)
{
	us_posprims = el_curtech->firstnodeproto;
	return(1);
}

char *us_nextpins(void)
{
	REGISTER char *nextname;
	REGISTER INTBIG i;
	REGISTER PORTPROTO *pp;

	for( ; us_posprims != NONODEPROTO; us_posprims = us_posprims->nextnodeproto)
	{
		/* test this pin for validity */
		pp = us_posprims->firstportproto;
		for(i=0; pp->connects[i] != NOARCPROTO; i++)
			if (pp->connects[i] == us_thisap) break;
		if (pp->connects[i] == NOARCPROTO) continue;
		nextname = us_posprims->primname;
		us_posprims = us_posprims->nextnodeproto;
		return(nextname);
	}
	return(0);
}

/*
 * Helper routine for arc options
 */
void us_defarcload(ARCPROTO *ap, NODEPROTO **pins, INTBIG allstyle)
{
	REGISTER NODEPROTO *np;
	REGISTER ARCPROTO *oap;
	REGISTER INTBIG i;
	REGISTER INTBIG style;
	char line[20];

	if (ap == NOARCPROTO)
	{
		style = allstyle;
		DiaDimItem(3);
		DiaUnDimItem(13);
		DiaDimItem(15);
		DiaSetText(14, "");
		DiaNoEditControl(14);
		DiaDimItem(16);
		DiaSetText(17, "");
		DiaNoEditControl(17);
		DiaDimItem(18);
		DiaSetText(19, "");
		DiaDimItem(6);
	} else
	{
		style = ap->temp1;
		DiaUnDimItem(3);
		DiaDimItem(13);
		DiaUnDimItem(15);
		DiaSetText(-14, latoa(defaultarcwidth(ap) - arcprotowidthoffset(ap)));
		DiaEditControl(14);
		DiaUnDimItem(16);
		(void)sprintf(line, "%ld", (ap->userbits&AANGLEINC) >> AANGLEINCSH);
		DiaSetText(17, line);
		DiaEditControl(17);
		DiaUnDimItem(18);
		np = NONODEPROTO;
		for(i=0, oap = el_curtech->firstarcproto; oap != NOARCPROTO; oap = oap->nextarcproto, i++)
			if (ap == oap) np = pins[i];
		DiaSetText(19, describenodeproto(np));
		DiaUnDimItem(6);
	}
	DiaSetControl(7, (style&WANTFIX) != 0 ? 1 : 0);
	DiaSetControl(8, (style&WANTFIXANG) != 0 ? 1 : 0);
	DiaSetControl(9, (style&WANTCANTSLIDE) == 0 ? 1 : 0);
	DiaSetControl(10, (style&WANTNEGATED) != 0 ? 1 : 0);
	DiaSetControl(11, (style&WANTDIRECTIONAL) != 0 ? 1 : 0);
	DiaSetControl(12, (style&WANTNOEXTEND) == 0 ? 1 : 0);
}

/****************************** ARC SIZE DIALOG ******************************/

/* Arc Size */
DIALOGITEM us_arcsizedialogitems[] =
{
/*  1 */ {0, {36,96,60,176}, BUTTON, N_("OK")},
/*  2 */ {0, {36,4,60,84}, BUTTON, N_("Cancel")},
/*  3 */ {0, {8,4,24,84}, MESSAGE|INACTIVE, N_("Width")},
/*  4 */ {0, {8,92,24,172}, EDITTEXT, ""}
};
DIALOG us_arcsizedialog = {{75,75,144,260}, N_("Set Arc Size"), 0, 4, us_arcsizedialogitems};

/*
 * special case for the "arc size" dialog
 * width = 4 (edit text)
 */
INTSML us_arcsizedlog(char *paramstart[])
{
	INTBIG itemHit;
	INTSML ret;
	static char w[20];

	/* display the node size dialog box */
	if (DiaInitDialog(&us_arcsizedialog) != 0) return(0);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}

	ret = 0;
	if (itemHit != CANCEL)
	{
		strcpy(w, DiaGetText(4));
		paramstart[0] = w;
		ret = 1;
	}
	DiaDoneDialog();
	return(ret);
}

/****************************** ARRAY DIALOG ******************************/

/* Array */
DIALOGITEM us_arraydialogitems[] =
{
 /*  1 */ {0, {220,360,244,424}, BUTTON, N_("OK")},
 /*  2 */ {0, {220,264,244,328}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {16,160,32,205}, EDITTEXT, "1"},
 /*  4 */ {0, {72,160,88,205}, EDITTEXT, "1"},
 /*  5 */ {0, {136,160,152,235}, EDITTEXT, "0"},
 /*  6 */ {0, {164,160,180,235}, EDITTEXT, "0"},
 /*  7 */ {0, {224,4,240,182}, CHECK, N_("Generate array indices")},
 /*  8 */ {0, {4,216,20,393}, CHECK, N_("Flip alternate columns")},
 /*  9 */ {0, {60,216,76,376}, CHECK, N_("Flip alternate rows")},
 /* 10 */ {0, {16,36,32,151}, MESSAGE, N_("X repeat factor:")},
 /* 11 */ {0, {72,36,88,151}, MESSAGE, N_("Y repeat factor:")},
 /* 12 */ {0, {136,4,152,154}, MESSAGE, N_("X edge overlap:")},
 /* 13 */ {0, {164,4,180,154}, MESSAGE, N_("Y centerline distance:")},
 /* 14 */ {0, {116,244,132,480}, RADIO, N_("Space by edge overlap")},
 /* 15 */ {0, {140,244,156,480}, RADIO, N_("Space by centerline distance")},
 /* 16 */ {0, {28,216,44,425}, CHECK, N_("Stagger alternate columns")},
 /* 17 */ {0, {84,216,100,400}, CHECK, N_("Stagger alternate rows")},
 /* 18 */ {0, {164,244,180,480}, RADIO, N_("Space by characteristic spacing")},
 /* 19 */ {0, {188,244,204,480}, RADIO, N_("Space by last measured distance")},
 /* 20 */ {0, {200,4,216,182}, CHECK, N_("Linear diagonal array")}
};
DIALOG us_arraydialog = {{50,75,303,564}, N_("Array Current Objects"), 0, 20, us_arraydialogitems};

/*
 * special case for the "array" dialog
 * X repeat factor        = 3 (edit text)
 * Y repeat factor        = 4 (edit text)
 * X spacing              = 5 (edit text)
 * Y spacing              = 6 (edit text)
 * Flip in X              = 8 (check)
 * Flip in Y              = 9 (check)
 * Add names              = 7 (check)
 * X spacing label        = 12 (message)
 * Y spacing label        = 13 (message)
 * Space by edge          = 14 (radio)
 * Space by center        = 15 (radio)
 * Stagger in X           = 16 (check)
 * Stagger in Y           = 17 (check)
 * Space by char. spacing = 18 (radio)
 * Space by measured dist = 19 (radio)
 * Linear diagonal array  = 20 (check)
 */
INTSML us_arraydlog(char *paramstart[])
{
	REGISTER INTBIG itemHit, first, xcentdist, ycentdist, xsize, ysize, lx, hx, ly, hy, i,
		chardistx, chardisty, curspacing, measdistx, measdisty, x, y, havechar,
		thischarx, thischary, swap, xyrev;
	INTBIG xoverlap, yoverlap;
	static INTBIG lastXrepeat = 1, lastYrepeat = 1;
	static INTBIG lastXdist = 0, lastYdist = 0;
	static INTBIG lastspacing = 14;
	REGISTER VARIABLE *var;
	char line[40];
	REGISTER NODEINST *ni;
	REGISTER ARCINST *ai;
	REGISTER GEOM **list, *geom;
	REGISTER NODEPROTO *np;

	/* get the objects to be arrayed */
	list = us_gethighlighted(OBJNODEINST|OBJARCINST);
	if (list[0] == NOGEOM)
	{
		us_abortcommand(_("Must select circuitry before arraying it"));
		return(0);
	}
	np = geomparent(list[0]);

	/* display the array dialog box */
	if (DiaInitDialog(&us_arraydialog) != 0) return(0);
	sprintf(line, "%ld", lastXrepeat);   DiaSetText(3, line);
	sprintf(line, "%ld", lastYrepeat);   DiaSetText(4, line);

	/* see if a facet was selected which has a characteristic distance */
	havechar = 0;
	for(i=0; list[i] != NOGEOM; i++)
	{
		if (list[i]->entrytype != OBJNODEINST) continue;
		ni = list[i]->entryaddr.ni;
		if (ni->proto->primindex != 0) continue;
		var = getval((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, "FACET_characteristic_spacing");
		if (var == NOVARIABLE) continue;
		thischarx = ((INTBIG *)var->addr)[0];
		thischary = ((INTBIG *)var->addr)[1];
		xyrev = 0;
		if (ni->transpose == 0)
		{
			if (ni->rotation == 900 || ni->rotation == 2700) xyrev = 1;
		} else
		{
			if (ni->rotation == 0 || ni->rotation == 1800) xyrev = 1;
		}
		if (xyrev != 0)
		{
			swap = thischarx;   thischarx = thischary;   thischary = swap;
		}

		if (havechar != 0)
		{
			if (chardistx != thischarx || chardisty != thischary)
			{
				havechar = 0;
				break;
			}
		}
		chardistx = thischarx;
		chardisty = thischary;
		havechar = 1;
	}
	if (havechar == 0)
	{
		DiaDimItem(18);
		if (lastspacing == 18)
		{
			lastspacing = 14;
			lastXdist = lastYdist = 0;
		}
	} else if (lastspacing == 18)
	{
		lastXdist = chardistx;
		lastYdist = chardisty;
	}

	/* see if there was a measured distance */
	if (us_validmesaure != 0)
	{
		measdistx = abs(us_lastmeasurex);
		measdisty = abs(us_lastmeasurey);
		if (lastspacing == 19)
		{
			lastXdist = measdistx;
			lastYdist = measdisty;
		}
	} else
	{
		DiaDimItem(19);
		if (lastspacing == 19)
		{
			lastspacing = 14;
			lastXdist = lastYdist = 0;
		}
	}

	DiaSetText(5, latoa(lastXdist));
	DiaSetText(6, latoa(lastYdist));
	curspacing = lastspacing;
	DiaSetControl(curspacing, 1);
	if (curspacing == 14)
	{
		DiaSetText(12, _("X edge overlap:"));
		DiaSetText(13, _("Y edge overlap:"));
	} else
	{
		DiaSetText(12, _("X centerline distance:"));
		DiaSetText(13, _("Y centerline distance:"));
	}

	/* mark the list of nodes and arcs in the facet that will be arrayed */
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
		ni->temp1 = 0;
	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
		ai->temp1 = 0;
	for(i=0; list[i] != NOGEOM; i++)
	{
		geom = list[i];
		if (geom->entrytype == OBJNODEINST)
		{
			ni = geom->entryaddr.ni;
			ni->temp1 = 1;
		} else
		{
			ai = geom->entryaddr.ai;
			ai->temp1 = 1;
			ai->end[0].nodeinst->temp1 = ai->end[1].nodeinst->temp1 = 1;
		}
	}

	/* determine spacing between arrayed objects */
	first = 1;
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		if (ni->temp1 == 0) continue;
		if (first != 0)
		{
			lx = ni->geom->lowx;   hx = ni->geom->highx;
			ly = ni->geom->lowy;   hy = ni->geom->highy;
			first = 0;
		} else
		{
			if (ni->geom->lowx < lx) lx = ni->geom->lowx;
			if (ni->geom->highx > hx) hx = ni->geom->highx;
			if (ni->geom->lowy < ly) ly = ni->geom->lowy;
			if (ni->geom->highy > hy) hy = ni->geom->highy;
		}
	}
	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
	{
		if (ai->temp1 == 0) continue;
		if (first != 0)
		{
			lx = ai->geom->lowx;   hx = ai->geom->highx;
			ly = ai->geom->lowy;   hy = ai->geom->highy;
			first = 0;
		} else
		{
			if (ai->geom->lowx < lx) lx = ai->geom->lowx;
			if (ai->geom->highx > hx) hx = ai->geom->highx;
			if (ai->geom->lowy < ly) ly = ai->geom->lowy;
			if (ai->geom->highy > hy) hy = ai->geom->highy;
		}
	}
	xsize = xcentdist = hx - lx;
	ysize = ycentdist = hy - ly;
	xoverlap = yoverlap = 0;

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(3) && DiaValidEntry(4) && DiaValidEntry(5) &&
			DiaValidEntry(6)) break;
		if (itemHit == 7 || itemHit == 8 || itemHit == 9 || itemHit == 16 ||
			itemHit == 17 || itemHit == 20)
				DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
		if (itemHit == 14 || itemHit == 15 || itemHit == 18 || itemHit == 19)
		{
			DiaSetControl(14, 0);
			DiaSetControl(15, 0);
			DiaSetControl(18, 0);
			DiaSetControl(19, 0);
			DiaSetControl(itemHit, 1);
			x = atola(DiaGetText(5));   y = atola(DiaGetText(6));
			switch (curspacing)
			{
				case 14: xoverlap = x;    yoverlap = y;    break;
				case 15: xcentdist = x;   ycentdist = y;   break;
			}
			curspacing = itemHit;
			if (curspacing == 14)
			{
				DiaSetText(12, _("X edge overlap:"));
				DiaSetText(13, _("Y edge overlap:"));
			} else
			{
				DiaSetText(12, _("X centerline distance:"));
				DiaSetText(13, _("Y centerline distance:"));
			}
			switch (curspacing)
			{
				case 14: x = xoverlap;    y = yoverlap;    break;
				case 15: x = xcentdist;   y = ycentdist;   break;
				case 18: x = chardistx;   y = chardisty;   break;
				case 19: x = measdistx;   y = measdisty;   break;
			}
			DiaSetText(5, latoa(x));
			DiaSetText(6, latoa(y));
			continue;
		}
	}
	lastXrepeat = atoi(DiaGetText(3));
	lastYrepeat = atoi(DiaGetText(4));
	lastXdist = atola(DiaGetText(5));
	lastYdist = atola(DiaGetText(6));
	lastspacing = curspacing;

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		(void)initinfstr();
		(void)addstringtoinfstr(DiaGetText(3));
		if (DiaGetControl(8) != 0) (void)addtoinfstr('f');
		if (DiaGetControl(16) != 0) (void)addtoinfstr('s');
		(void)addtoinfstr(' ');
		(void)addstringtoinfstr(DiaGetText(4));
		if (DiaGetControl(9) != 0) (void)addtoinfstr('f');
		if (DiaGetControl(17) != 0) (void)addtoinfstr('s');
		(void)addtoinfstr(' ');
		xoverlap = atola(DiaGetText(5));
		yoverlap = atola(DiaGetText(6));
		if (DiaGetControl(14) == 0)
		{
			xoverlap = xsize - xoverlap;
			yoverlap = ysize - yoverlap;
		}
		(void)addstringtoinfstr(latoa(xoverlap));
		(void)addtoinfstr(' ');
		(void)addstringtoinfstr(latoa(yoverlap));
		if (DiaGetControl(7) == 0) (void)addstringtoinfstr(" no-names");
		if (DiaGetControl(20) != 0) (void)addstringtoinfstr(" diagonal");
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(1);
}

/****************************** ARTWORK AND COLOR DIALOGS ******************************/

/* Layer Patterns */
unsigned char us_icon300[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0210, 0210, 0210, 0210, 0104, 0104, 021, 021, 042, 042, 042, 042, 021, 021, 0104, 0104,
	0210, 0210, 0210, 0210, 0104, 0104, 021, 021, 042, 042, 042, 042, 021, 021, 0104, 0104,
	0210, 0210, 0210, 0210, 0104, 0104, 021, 021, 042, 042, 042, 042, 021, 021, 0104, 0104,
	0210, 0210, 0210, 0210, 0104, 0104, 021, 021, 042, 042, 042, 042, 021, 021, 0104, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon301[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0314, 0314, 0377, 0377, 0314, 0314, 0, 0, 063, 063, 0377, 0377, 063, 063, 0, 0,
	0314, 0314, 0377, 0377, 0314, 0314, 0, 0, 063, 063, 0377, 0377, 063, 063, 0, 0,
	0314, 0314, 0377, 0377, 0314, 0314, 0, 0, 063, 063, 0377, 0377, 063, 063, 0, 0,
	0314, 0314, 0377, 0377, 0314, 0314, 0, 0, 063, 063, 0377, 0377, 063, 063, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon302[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0125, 0125, 0140, 0140, 0125, 0125, 0220, 0220, 0125, 0125, 0220, 0220, 0125, 0125, 0140, 0140,
	0125, 0125, 06, 06, 0125, 0125, 011, 011, 0125, 0125, 011, 011, 0125, 0125, 06, 06,
	0125, 0125, 0140, 0140, 0125, 0125, 0220, 0220, 0125, 0125, 0220, 0220, 0125, 0125, 0140, 0140,
	0125, 0125, 06, 06, 0125, 0125, 011, 011, 0125, 0125, 011, 011, 0, 0, 06, 06,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon303[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	042, 042, 0104, 0104, 0, 0, 021, 021, 0210, 0210, 0104, 0104, 0, 0, 021, 021,
	042, 042, 0104, 0104, 0, 0, 021, 021, 0210, 0210, 0104, 0104, 0, 0, 021, 021,
	042, 042, 0104, 0104, 0, 0, 021, 021, 0210, 0210, 0104, 0104, 0, 0, 021, 021,
	042, 042, 0104, 0104, 0, 0, 021, 021, 0210, 0210, 0104, 0104, 0, 0, 021, 021,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon304[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	020, 020, 04, 04, 040, 040, 02, 02, 0100, 0100, 01, 01, 0200, 0200, 0200, 0200,
	01, 01, 0100, 0100, 02, 02, 040, 040, 04, 04, 020, 020, 010, 010, 010, 010,
	020, 020, 04, 04, 040, 040, 02, 02, 0100, 0100, 01, 01, 0200, 0200, 0200, 0200,
	01, 01, 0100, 0100, 02, 02, 040, 040, 04, 04, 020, 020, 010, 010, 010, 010,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon305[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0100, 0100, 020, 0, 0200, 0200, 0, 040, 01, 01, 0100, 0, 02, 02, 0, 0200,
	01, 01, 0, 01, 0200, 0200, 02, 0, 0100, 0100, 0, 04, 040, 040, 010, 0,
	0100, 0100, 0, 020, 0200, 0200, 040, 0, 01, 01, 0, 0100, 02, 02, 0200, 0,
	01, 01, 01, 0, 0200, 0200, 0, 02, 0100, 0100, 04, 0, 040, 040, 0, 010,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon306[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	010, 0, 0, 0, 0, 04, 03, 03, 02, 0, 0204, 0204, 0, 01, 03, 03,
	0, 0200, 0, 0, 0100, 0, 060, 060, 0, 040, 0110, 0110, 020, 0, 060, 060,
	0, 010, 0, 0, 04, 0, 03, 03, 0, 02, 0204, 0204, 01, 0, 03, 03,
	0200, 0, 0, 0, 0, 0100, 060, 060, 040, 0, 0110, 0110, 0, 020, 060, 060,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon307[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	034, 034, 0, 0, 076, 076, 0314, 0314, 066, 066, 0, 0, 076, 076, 0314, 0314,
	034, 034, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	034, 034, 0, 0, 076, 076, 0314, 0314, 066, 066, 0, 0, 076, 076, 0314, 0314,
	034, 034, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon308[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 042, 042, 021, 021, 0210, 0210, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 042, 042, 021, 021, 0210, 0210, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 042, 042, 021, 021, 0210, 0210, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 042, 042, 021, 021, 0210, 0210, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon309[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 042, 042, 042, 042, 0104, 0104, 0125, 0125, 0210, 0210, 042, 042,
	0, 0, 0, 0, 042, 042, 042, 042, 0104, 0104, 0125, 0125, 0210, 0210, 042, 042,
	0, 0, 0, 0, 042, 042, 042, 042, 0104, 0104, 0125, 0125, 0210, 0210, 042, 042,
	0, 0, 0, 0, 042, 042, 042, 042, 0104, 0104, 0125, 0125, 0210, 0210, 042, 042,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char us_icon310[] =
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377,
	0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377,
	0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377,
	0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377, 0, 0, 0377, 0377,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

UINTSML us_predefpats[] =
{
	0x8888,  /* X   X   X   X    */
	0x4444,  /*  X   X   X   X   */
	0x2222,  /*   X   X   X   X  */
	0x1111,  /*    X   X   X   X */
	0x8888,  /* X   X   X   X    */
	0x4444,  /*  X   X   X   X   */
	0x2222,  /*   X   X   X   X  */
	0x1111,  /*    X   X   X   X */

	0x8888,  /* X   X   X   X    */
	0x1111,  /*    X   X   X   X */
	0x2222,  /*   X   X   X   X  */
	0x4444,  /*  X   X   X   X   */
	0x8888,  /* X   X   X   X    */
	0x1111,  /*    X   X   X   X */
	0x2222,  /*   X   X   X   X  */
	0x4444,  /*  X   X   X   X   */

	0xCCCC,  /* XX  XX  XX  XX   */
	0xCCCC,  /* XX  XX  XX  XX   */
	0x3333,  /*   XX  XX  XX  XX */
	0x3333,  /*   XX  XX  XX  XX */
	0xCCCC,  /* XX  XX  XX  XX   */
	0xCCCC,  /* XX  XX  XX  XX   */
	0x3333,  /*   XX  XX  XX  XX */
	0x3333,  /*   XX  XX  XX  XX */

	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0x0000,  /*                  */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0x0000,  /*                  */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0x0000,  /*                  */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0x0000,  /*                  */

	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */
	0xAAAA,  /* X X X X X X X X  */

	0x6060,  /*  XX      XX      */
	0x9090,  /* X  X    X  X     */
	0x9090,  /* X  X    X  X     */
	0x6060,  /*  XX      XX      */
	0x0606,  /*      XX      XX  */
	0x0909,  /*     X  X    X  X */
	0x0909,  /*     X  X    X  X */
	0x0606,  /*      XX      XX  */

	0x2222,  /*   X   X   X   X  */
	0x0000,  /*                  */
	0x8888,  /* X   X   X   X    */
	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x0000,  /*                  */
	0x8888,  /* X   X   X   X    */
	0x0000,  /*                  */

	0x4444,  /*  X   X   X   X   */
	0x1111,  /*    X   X   X   X */
	0x4444,  /*  X   X   X   X   */
	0x1111,  /*    X   X   X   X */
	0x4444,  /*  X   X   X   X   */
	0x1111,  /*    X   X   X   X */
	0x4444,  /*  X   X   X   X   */
	0x1111,  /*    X   X   X   X */

	0x1010,  /*    X       X     */
	0x2020,  /*   X       X      */
	0x4040,  /*  X       X       */
	0x8080,  /* X       X        */
	0x0101,  /*        X       X */
	0x0202,  /*       X       X  */
	0x0404,  /*      X       X   */
	0x0808,  /*     X       X    */

	0x0808,  /*     X       X    */
	0x0404,  /*      X       X   */
	0x0202,  /*       X       X  */
	0x0101,  /*        X       X */
	0x8080,  /* X       X        */
	0x4040,  /*  X       X       */
	0x2020,  /*   X       X      */
	0x1010,  /*    X       X     */

	0x4040,  /*  X       X       */
	0x8080,  /* X       X        */
	0x0101,  /*        X       X */
	0x0202,  /*       X       X  */
	0x0101,  /*        X       X */
	0x8080,  /* X       X        */
	0x4040,  /*  X       X       */
	0x2020,  /*   X       X      */

	0x1000,  /*    X             */
	0x0020,  /*           X      */
	0x4000,  /*  X               */
	0x0080,  /*         X        */
	0x0001,  /*                X */
	0x0200,  /*       X          */
	0x0004,  /*              X   */
	0x0800,  /*     X            */

	0x0800,  /*     X            */
	0x0004,  /*              X   */
	0x0200,  /*       X          */
	0x0001,  /*                X */
	0x0080,  /*         X        */
	0x4000,  /*  X               */
	0x0020,  /*           X      */
	0x1000,  /*    X             */

	0x0000,  /*                  */
	0x0303,  /*       XX      XX */
	0x4848,  /*  X  X    X  X    */
	0x0303,  /*       XX      XX */
	0x0000,  /*                  */
	0x3030,  /*   XX      XX     */
	0x8484,  /* X    X  X    X   */
	0x3030,  /*   XX      XX     */

	0x1C1C,  /*    XXX     XXX   */
	0x3E3E,  /*   XXXXX   XXXXX  */
	0x3636,  /*   XX XX   XX XX  */
	0x3E3E,  /*   XXXXX   XXXXX  */
	0x1C1C,  /*    XXX     XXX   */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */

	0x0000,  /*                  */
	0xCCCC,  /* XX  XX  XX  XX   */
	0x0000,  /*                  */
	0xCCCC,  /* XX  XX  XX  XX   */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */

	0x0000,  /*                  */
	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x8888,  /* X   X   X   X    */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x8888,  /* X   X   X   X    */

	0x0000,  /*                  */
	0x0000,  /*                  */
	0x1111,  /*    X   X   X   X */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x1111,  /*    X   X   X   X */
	0x0000,  /*                  */

	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x4444,  /*  X   X   X   X   */
	0x8888,  /* X   X   X   X    */
	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x4444,  /*  X   X   X   X   */
	0x8888,  /* X   X   X   X    */

	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x5555,  /*  X X X X X X X X */
	0x2222,  /*   X   X   X   X  */
	0x0000,  /*                  */
	0x2222,  /*   X   X   X   X  */
	0x5555,  /*  X X X X X X X X */
	0x2222,  /*   X   X   X   X  */

	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */
	0x0000,  /*                  */

	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF,  /* XXXXXXXXXXXXXXXX */
	0xFFFF   /* XXXXXXXXXXXXXXXX */
};

/* Artwork Color/Layer */
DIALOGITEM us_artworkdialogitems[] =
{
/*  1 */ {0, {168,340,192,404}, BUTTON, N_("OK")},
/*  2 */ {0, {168,244,192,308}, BUTTON, N_("Cancel")},
/*  3 */ {0, {120,292,136,419}, RADIO, N_("Outlined Pattern")},
/*  4 */ {0, {32,16,160,272}, USERDRAWN, ""},
/*  5 */ {0, {56,292,72,388}, RADIO, N_("Solid color")},
/*  6 */ {0, {168,24,184,77}, MESSAGE, N_("Color:")},
/*  7 */ {0, {88,292,104,388}, RADIO, N_("Use Pattern")},
/*  8 */ {0, {0,16,32,48}, ICON, (char *)us_icon300},
/*  9 */ {0, {0,48,32,80}, ICON, (char *)us_icon301},
/* 10 */ {0, {0,80,32,112}, ICON, (char *)us_icon302},
/* 11 */ {0, {0,112,32,144}, ICON, (char *)us_icon303},
/* 12 */ {0, {0,144,32,176}, ICON, (char *)us_icon304},
/* 13 */ {0, {0,176,32,208}, ICON, (char *)us_icon305},
/* 14 */ {0, {0,208,32,240}, ICON, (char *)us_icon306},
/* 15 */ {0, {0,240,32,272}, ICON, (char *)us_icon307},
/* 16 */ {0, {0,272,32,304}, ICON, (char *)us_icon308},
/* 17 */ {0, {0,304,32,336}, ICON, (char *)us_icon309},
/* 18 */ {0, {0,336,32,368}, ICON, (char *)us_icon310},
/* 19 */ {0, {168,80,184,214}, POPUP, ""}
};
DIALOG us_artworkdialog = {{50,75,253,503}, N_("Set Look of Highlighted"), 0, 19, us_artworkdialogitems};

DIALOGITEM us_patterndialogitems[] =
{
/*  1 */ {0, {176,296,200,360}, BUTTON, N_("OK")},
/*  2 */ {0, {136,296,160,360}, BUTTON, N_("Cancel")},
/*  3 */ {0, {4,8,20,184}, MESSAGE, N_("Stipple Pattern for Layer:")},
/*  4 */ {0, {84,16,212,272}, USERDRAWN, ""},
/*  5 */ {0, {4,184,20,368}, POPUP, ""},
/*  6 */ {0, {64,184,80,336}, CHECK, N_("Outline Pattern")},
/*  7 */ {0, {64,8,80,160}, CHECK, N_("Use Stipple Pattern")},
/*  8 */ {0, {28,8,60,40}, ICON, (char *)us_icon300},
/*  9 */ {0, {28,40,60,72}, ICON, (char *)us_icon301},
/* 10 */ {0, {28,72,60,104}, ICON, (char *)us_icon302},
/* 11 */ {0, {28,104,60,136}, ICON, (char *)us_icon303},
/* 12 */ {0, {28,136,60,168}, ICON, (char *)us_icon304},
/* 13 */ {0, {28,168,60,200}, ICON, (char *)us_icon305},
/* 14 */ {0, {28,200,60,232}, ICON, (char *)us_icon306},
/* 15 */ {0, {28,232,60,264}, ICON, (char *)us_icon307},
/* 16 */ {0, {28,264,60,296}, ICON, (char *)us_icon308},
/* 17 */ {0, {28,296,60,328}, ICON, (char *)us_icon309},
/* 18 */ {0, {28,328,60,360}, ICON, (char *)us_icon310}
};
DIALOG us_patterndialog = {{50,75,271,453}, N_("Layer Pattern Options"), 0, 18, us_patterndialogitems};

/*
 * special case for the "artwork primitive color&pattern" dialog
 * Pattern squares = 4 (user item)
 * Color           = 19 (popup)
 * Solid           = 5 (radio)
 * Use Pattern     = 7 (radio)
 * Outline pattern = 3 (radio)
 * Predefined pats = 8-18
 */
static RECTAREA us_strokerect;
static INTBIG us_origpattern[8];
static INTBIG us_strokeup;
static INTBIG us_patternchanged;

void us_redrawpattern(RECTAREA*);
INTSML us_patternstroke(INTBIG, INTBIG);

void us_redrawpattern(RECTAREA *bigr)
{
	INTBIG j, k, bits;
	RECTAREA r;

	for(j=0; j<8; j++)
	{
		bits = us_origpattern[j] & 0xFFFF;
		for(k=0; k<16; k++)
		{
			r.left = us_strokerect.left + k*16;   r.right = r.left + 17;
			r.top = us_strokerect.top + j*16;     r.bottom = r.top + 17;
			if ((bits & (1<<(15-k))) != 0) DiaDrawRect(4, &r, 0, 0, 0); else
				DiaFrameRect(4, &r);
		}
	}
}

INTSML us_patternstroke(INTBIG ox, INTBIG oy)
{
	INTSML x, y;
	REGISTER INTBIG j, k, bits;
	RECTAREA r;

	DiaGetMouse(&x, &y);
	j = (y - us_strokerect.top) / 16;  if (j < 0) j = 0;  if (j > 7) j = 7;
	k = (x - us_strokerect.left) / 16;  if (k < 0) k = 0;  if (k > 15) k = 15;
	r.left = us_strokerect.left + k*16;   r.right = r.left + 17;
	r.top = us_strokerect.top + j*16;     r.bottom = r.top + 17;
	bits = us_origpattern[j] & 0xFFFF;
	if (us_strokeup == 0)
	{
		DiaFrameRect(4, &r);
		bits &= ~(1<<(15-k));
	} else
	{
		DiaDrawRect(4, &r, 0, 0, 0);
		bits |= 1<<(15-k);
	}
	us_origpattern[j] = bits;
	us_patternchanged++;
	return(0);
}

INTSML us_artlookdlog(void)
{
	RECTAREA r;
	INTBIG addr, type, itemHit;
	UINTSML spattern[8];
	REGISTER NODEINST *ni;
	REGISTER ARCINST *ai;
	REGISTER VARIABLE *colorvar, *patternvar;
	INTBIG i, j, k, bits, err;
	INTSML x, y;
	HIGHLIGHT *high;
	char *newlang[25];
	static char *colornames[25] = {N_("Overlappable 1"), N_("Overlappable 2"), N_("Overlappable 3"),
		N_("Overlappable 4"), N_("Overlappable 5"), N_("White"), N_("Black"), N_("Gray"),
		N_("Light Gray"), N_("Dark Gray"), N_("Red"), N_("Light Red"), N_("Dark Red"), N_("Green"),
		N_("Light Green"), N_("Dark Green"), N_("Blue"), N_("Light Blue"), N_("Dark Blue"),
		N_("Cyan"), N_("Magenta"), N_("Yellow"), N_("Orange"), N_("Purple"), N_("Brown")};
	static INTSML valuelist[25] =
	{
		COLORT1,		/* overlappable 1 */
		COLORT2,		/* overlappable 2 */
		COLORT3,		/* overlappable 3 */
		COLORT4,		/* overlappable 4 */
		COLORT5,		/* overlappable 5 */
		WHITE,			/* white */
		BLACK,			/* black */
		GRAY,			/* gray */
		LGRAY,			/* light gray */
		DGRAY,			/* dark gray */
		RED,			/* red */
		LRED,			/* light red */
		DRED,			/* dark red */
		GREEN,			/* green */
		LGREEN,			/* light green */
		DGREEN,			/* dark green */
		BLUE,			/* blue */
		LBLUE,			/* light blue */
		DBLUE,			/* dark blue */
		CYAN,			/* cyan */
		MAGENTA,		/* magenta */
		YELLOW,			/* yellow */
		ORANGE,			/* orange */
		PURPLE,			/* purple */
		BROWN			/* brown */
	};

	/* make sure there is an artwork primitive highlighted */
	high = us_getonehighlight();
	if (high == NOHIGHLIGHT) return(0);
	err = 0;
	if ((high->status&HIGHTYPE) != HIGHFROM) err = 1; else
	{
		if (high->fromgeom->entrytype == OBJNODEINST)
		{
			ni = high->fromgeom->entryaddr.ni;
			if (ni->proto->primindex == 0 || ni->proto->tech != art_tech) err = 1;
			addr = (INTBIG)ni;
			type = VNODEINST;
		} else
		{
			ai = high->fromgeom->entryaddr.ai;
			if (ai->proto->tech != art_tech) err = 1;
			addr = (INTBIG)ai;
			type = VARCINST;
		}
	}
	if (err != 0)
	{
		us_abortcommand(_("First find a single node or arc in the Artwork technology"));
		return(0);
	}

	/* display the artwork dialog box */
	if (DiaInitDialog(&us_artworkdialog) != 0) return(0);
	for(i=0; i<25; i++) newlang[i] = _(colornames[i]);   DiaSetPopup(19, 25, newlang);
	DiaItemRect(4, &us_strokerect);
	DiaRedispRoutine(4, us_redrawpattern);
	DiaFrameRect(4, &us_strokerect);

	/* set existing conditions */
	colorvar = getvalkey(addr, type, VINTEGER, art_colorkey);
	if (colorvar != NOVARIABLE)
	{
		for(i=0; i<25; i++) if (valuelist[i] == colorvar->addr)
		{
			DiaSetPopupEntry(19, i);
			break;
		}
	}
	for(i=0; i<8; i++) us_origpattern[i] = 0;
	patternvar = getvalkey(addr, type, -1, art_patternkey);
	if (patternvar != NOVARIABLE && getlength(patternvar) == 8)
	{
		if ((patternvar->type&VTYPE) == VINTEGER)
		{
			for(i=0; i<8; i++) us_origpattern[i] = ((UINTBIG *)patternvar->addr)[i];
			DiaSetControl(7, 1);
		} else if ((patternvar->type&VTYPE) == VSHORT)
		{
			for(i=0; i<8; i++) us_origpattern[i] = ((UINTSML *)patternvar->addr)[i];
			DiaSetControl(3, 1);
		}
	} else DiaSetControl(5, 1);
	us_redrawpattern(&us_strokerect);

	/* loop until done */
	us_patternchanged = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 4)
		{
			DiaGetMouse(&x, &y);
			j = (y - us_strokerect.top) / 16;  if (j < 0) j = 0;  if (j > 7) j = 7;
			k = (x - us_strokerect.left) / 16;  if (k < 0) k = 0;  if (k > 15) k = 15;
			bits = us_origpattern[j] & 0xFFFF;
			if ((bits & (1<<(15-k))) != 0) us_strokeup = 0; else us_strokeup = 1;
			trackcursor(0, us_nullup, us_nullvoid, us_patternstroke, us_nullchar,
				us_nullvoid, TRACKNORMAL);
			continue;
		}
		if (itemHit == 5 || itemHit == 7 || itemHit == 3)
		{
			DiaSetControl(5, 0);
			DiaSetControl(7, 0);
			DiaSetControl(3, 0);
			DiaSetControl(itemHit, 1);
			us_patternchanged++;
			continue;
		}
		if (itemHit >= 8 && itemHit <= 18)
		{
			DiaGetMouse(&x, &y);
			DiaItemRect(itemHit, &r);
			j = (r.top+r.bottom)/2;
			if (y < j-8 || y > j+8) continue;
			i = (itemHit-8) * 2;
			if (x > (r.left+r.right)/2) i++;
			i *= 8;
			for(j=0; j<8; j++) us_origpattern[j] = us_predefpats[i++] & 0xFFFF;
			us_redrawpattern(&us_strokerect);
			us_patternchanged++;
			continue;
		}
		if (itemHit == 19)
		{
			us_patternchanged++;
			continue;
		}
	}

	if (itemHit != CANCEL && us_patternchanged != 0)
	{
		/* prepare for change */
		us_pushhighlight();
		us_clearhighlightcount();
		startobjectchange(addr, type);

		/* make the change */
		if (DiaGetControl(5) != 0)
		{
			if (patternvar != NOVARIABLE) (void)delvalkey(addr, type, art_patternkey);
		} else if (DiaGetControl(7) != 0)
		{
			(void)setvalkey(addr, type, art_patternkey, (INTBIG)us_origpattern,
				VINTEGER|VISARRAY|(8<<VLENGTHSH));
		} else
		{
			for(i=0; i<8; i++) spattern[i] = (UINTSML)us_origpattern[i];
			(void)setvalkey(addr, type, art_patternkey, (INTBIG)spattern, VSHORT|VISARRAY|(8<<VLENGTHSH));
		}
		i = DiaGetPopupEntry(19);
		if (valuelist[i] == 014)
		{
			/* black is the default */
			if (colorvar != NOVARIABLE) (void)delvalkey(addr, type, art_colorkey);
		} else (void)setvalkey(addr, type, art_colorkey, valuelist[i], VINTEGER);

		/* complete change */
		endobjectchange(addr, type);
		(void)us_pophighlight(0);
	}
	DiaDoneDialog();
	return(0);
}

/*
 * special case for the "layer pattern" dialog
 * Pattern squares = 4 (user item) (***MUST NOT CHANGE***)
 * Name of layer   = 5 (popup)
 * Outline pattern = 6 (check)
 * Use pattern     = 7 (check)
 * Predefined pats = 8-18 (icon)
 */
INTSML us_patterndlog(void)
{
	INTBIG itemHit, curlayer, i, j, k, newpat[9];
	INTSML *origbits, *orignature, *origchanged, x, y, bits;
	RECTAREA r;
	REGISTER VARIABLE *var;
	REGISTER char **layernames;

	/* get memory to save state */
	origbits = (INTSML *)emalloc(el_curtech->layercount * 8 * SIZEOFINTSML, us_aid->cluster);
	if (origbits == 0) return(0);
	orignature = (INTSML *)emalloc(el_curtech->layercount * SIZEOFINTSML, us_aid->cluster);
	if (orignature == 0) return(0);
	origchanged = (INTSML *)emalloc(el_curtech->layercount * SIZEOFINTSML, us_aid->cluster);
	if (origchanged == 0) return(0);
	for(i=0; i<el_curtech->layercount; i++)
	{
		orignature[i] = (el_curtech->layers[i])->colstyle;
		origchanged[i] = 0;
		for(j=0; j<8; j++) origbits[i*8+j] = (el_curtech->layers[i])->raster[j];

		/* see if there is an override */
		(void)initinfstr();
		(void)addstringtoinfstr("TECH_layer_pattern_");
		(void)addstringtoinfstr(layername(el_curtech, (INTSML)i));
		var = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER|VISARRAY, returninfstr());
		if (var != NOVARIABLE)
		{
			orignature[i] = (INTSML)(((INTBIG *)var->addr)[8]);
			for(j=0; j<8; j++) origbits[i*8+j] = (INTSML)(((INTBIG *)var->addr)[j]);
		}
	}
	curlayer = 0;

	/* display the pattern dialog box */
	if (DiaInitDialog(&us_patterndialog) != 0)
	{
		efree((char *)origbits);
		efree((char *)orignature);
		efree((char *)origchanged);
		return(0);
	}
	DiaItemRect(4, &us_strokerect);
	DiaRedispRoutine(4, us_redrawpattern);
	DiaFrameRect(4, &us_strokerect);

	/* setup list of layer names */
	layernames = (char **)emalloc(el_curtech->layercount * (sizeof (char *)), el_tempcluster);
	for(i=0; i<el_curtech->layercount; i++)
		allocstring(&layernames[i], layername(el_curtech, (INTSML)i), el_tempcluster);
	DiaSetPopup(5, el_curtech->layercount, layernames);
	for(i=0; i<el_curtech->layercount; i++)
		efree(layernames[i]);
	efree((char *)layernames);

	/* setup initial layer: number 0 */
	curlayer = 0;
	DiaSetPopupEntry(5, curlayer);
	if ((orignature[curlayer]&NATURE) == PATTERNED)
	{
		DiaUnDimItem(6);
		DiaSetControl(7, 1);
		if ((orignature[curlayer]&OUTLINEPAT) != 0) DiaSetControl(6, 1);
	} else DiaDimItem(6);
	for(j=0; j<8; j++) us_origpattern[j] = origbits[curlayer*8+j] & 0xFFFF;
	us_redrawpattern(&us_strokerect);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK) break;
		if (itemHit == 7)
		{
			/* the "Use Stipple" box */
			if (DiaGetControl(7) == 0)
			{
				DiaSetControl(7, 1);
				DiaUnDimItem(6);
				orignature[curlayer] = (orignature[curlayer] & ~NATURE) | PATTERNED;
			} else
			{
				DiaSetControl(7, 0);
				DiaSetControl(6, 0);
				DiaDimItem(6);
				orignature[curlayer] = (orignature[curlayer] & ~NATURE) | SOLIDC;
			}
			origchanged[curlayer] = 1;
			continue;
		}
		if (itemHit == 6)
		{
			/* the "Outline Pattern" box */
			if (DiaGetControl(6) == 0)
			{
				DiaSetControl(6, 1);
				orignature[curlayer] |= OUTLINEPAT;
			} else
			{
				DiaSetControl(6, 0);
				orignature[curlayer] &= ~OUTLINEPAT;
			}
			origchanged[curlayer] = 1;
			continue;
		}
		if (itemHit == 5)
		{
			/* the layer popup */
			curlayer = DiaGetPopupEntry(5);
			DiaSetControl(7, 0);
			DiaUnDimItem(6);
			DiaSetControl(6, 0);
			if ((orignature[curlayer]&NATURE) == PATTERNED)
			{
				DiaSetControl(7, 1);
				if ((orignature[curlayer]&OUTLINEPAT) != 0) DiaSetControl(6, 1);
			} else DiaDimItem(6);
			for(j=0; j<8; j++) us_origpattern[j] = origbits[curlayer*8+j] & 0xFFFF;
			us_redrawpattern(&us_strokerect);
			continue;
		}
		if (itemHit == 4)
		{
			DiaGetMouse(&x, &y);
			j = (y - us_strokerect.top) / 16;  if (j < 0) j = 0;  if (j > 7) j = 7;
			k = (x - us_strokerect.left) / 16;  if (k < 0) k = 0;  if (k > 15) k = 15;
			bits = origbits[curlayer*8+j] & 0xFFFF;
			if ((bits & (1<<(15-k))) != 0) us_strokeup = 0; else us_strokeup = 1;
			trackcursor(0, us_nullup, us_nullvoid, us_patternstroke,
				us_nullchar, us_nullvoid, TRACKNORMAL);
			for(j=0; j<8; j++) origbits[curlayer*8+j] = (UINTSML)us_origpattern[j];
			origchanged[curlayer] = 1;
			continue;
		}
		if (itemHit >= 8 && itemHit <= 18)
		{
			DiaGetMouse(&x, &y);
			DiaItemRect(itemHit, &r);
			j = (r.top+r.bottom)/2;
			if (y < j-8 || y > j+8) continue;
			i = (itemHit-8) * 2;
			if (x > (r.left+r.right)/2) i++;
			i *= 8;
			for(j=0; j<8; j++)
			{
				bits = us_predefpats[i++] & 0xFFFF;
				origbits[curlayer*8+j] = bits;
				us_origpattern[j] = bits;
			}
			us_redrawpattern(&us_strokerect);
			origchanged[curlayer] = 1;
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		for(i=0; i<el_curtech->layercount; i++)
		{
			if (origchanged[i] == 0) continue;
			(el_curtech->layers[i])->colstyle = orignature[i];
			for(j=0; j<8; j++) (el_curtech->layers[i])->raster[j] = origbits[i*8+j];

			/* save a shadow variable for this layer pattern */
			for(j=0; j<8; j++) newpat[j] = origbits[i*8+j];
			newpat[8] = orignature[i];
			(void)initinfstr();
			(void)addstringtoinfstr("TECH_layer_pattern_");
			(void)addstringtoinfstr(layername(el_curtech, (INTSML)i));
			(void)setval((INTBIG)el_curtech, VTECHNOLOGY, returninfstr(),
				(INTBIG)newpat, VINTEGER|VISARRAY|(9<<VLENGTHSH));
		}
	}
	efree((char *)origbits);
	efree((char *)orignature);
	efree((char *)origchanged);
	DiaDoneDialog();
	return(0);
}

/****************************** ATTRIBUTE DIALOG ******************************/

/* Attributes */
DIALOGITEM us_attrdialogitems[] =
{
 /*  1 */ {0, {320,280,344,360}, BUTTON, N_("Done")},
 /*  2 */ {0, {136,216,152,312}, MESSAGE, N_("Attribute name:")},
 /*  3 */ {0, {8,8,24,300}, RADIO, N_("Facet")},
 /*  4 */ {0, {32,8,48,300}, RADIO, N_("Node")},
 /*  5 */ {0, {56,8,72,300}, RADIO, N_("Facet port")},
 /*  6 */ {0, {80,8,96,300}, RADIO, N_("Node port")},
 /*  7 */ {0, {104,8,120,300}, RADIO, N_("Arc")},
 /*  8 */ {0, {136,8,324,208}, SCROLL, ""},
 /*  9 */ {0, {136,316,152,444}, EDITTEXT, ""},
 /* 10 */ {0, {160,276,176,444}, EDITTEXT, ""},
 /* 11 */ {0, {216,216,232,348}, CHECK, N_("Instances inherit")},
 /* 12 */ {0, {160,216,176,272}, MESSAGE, N_("Value")},
 /* 13 */ {0, {112,492,128,576}, BUTTON, N_("Make Array")},
 /* 14 */ {0, {328,136,344,252}, BUTTON, N_("Delete Attribute")},
 /* 15 */ {0, {328,8,344,124}, BUTTON, N_("Create Attribute")},
 /* 16 */ {0, {136,452,152,512}, BUTTON, N_("Rename")},
 /* 17 */ {0, {160,452,176,512}, BUTTON, N_("Change")},
 /* 18 */ {0, {244,216,260,348}, MESSAGE, N_("X offset:")},
 /* 19 */ {0, {264,216,280,348}, MESSAGE, N_("Y offset:")},
 /* 20 */ {0, {184,388,216,420}, ICON, (char *)us_icon200},
 /* 21 */ {0, {216,388,248,420}, ICON, (char *)us_icon201},
 /* 22 */ {0, {248,388,280,420}, ICON, (char *)us_icon202},
 /* 23 */ {0, {280,388,312,420}, ICON, (char *)us_icon203},
 /* 24 */ {0, {312,388,344,420}, ICON, (char *)us_icon205},
 /* 25 */ {0, {184,424,200,536}, RADIO, N_("Center")},
 /* 26 */ {0, {200,424,216,536}, RADIO, N_("Bottom")},
 /* 27 */ {0, {216,424,232,536}, RADIO, N_("Top")},
 /* 28 */ {0, {232,424,248,536}, RADIO, N_("Right")},
 /* 29 */ {0, {248,424,264,536}, RADIO, N_("Left")},
 /* 30 */ {0, {264,424,280,536}, RADIO, N_("Lower right")},
 /* 31 */ {0, {280,424,296,536}, RADIO, N_("Lower left")},
 /* 32 */ {0, {296,424,312,536}, RADIO, N_("Upper right")},
 /* 33 */ {0, {312,424,328,536}, RADIO, N_("Upper left")},
 /* 34 */ {0, {8,304,128,484}, SCROLL, ""},
 /* 35 */ {0, {288,280,312,360}, BUTTON, N_("More...")},
 /* 36 */ {0, {12,492,28,564}, MESSAGE, N_("Array:")},
 /* 37 */ {0, {32,492,48,576}, BUTTON, N_("Add")},
 /* 38 */ {0, {52,492,68,576}, BUTTON, N_("Remove")},
 /* 39 */ {0, {72,492,88,576}, BUTTON, N_("Add All")},
 /* 40 */ {0, {92,492,108,576}, BUTTON, N_("Remove All")},
 /* 41 */ {0, {188,216,204,272}, MESSAGE, N_("Show:")},
 /* 42 */ {0, {188,276,204,380}, POPUP, ""}
};
DIALOG us_attrdialog = {{75,75,428,660}, N_("Attributes"), 0, 42, us_attrdialogitems};

VARIABLE *us_attrfindvarname(INTBIG curcontrol, INTBIG numvar, VARIABLE *firstvar);
void us_attrgetfactors(INTBIG curcontrol, INTBIG addr, INTBIG *numvar, VARIABLE **firstvar);
void us_attrloadchoices(INTBIG numvar, VARIABLE *firstvar, INTBIG curcontrol);
char *us_attrmakevarname(INTBIG curcontrol, PORTPROTO *pp, char *name);
char *us_attrgenportvalue(INTBIG curcontrol, INTBIG addr, INTBIG type, char *attrname, NODEPROTO *np, char *oldvalue);
void us_attrsetportposition(VARIABLE *var, PORTPROTO *pp);
void us_attrloadportlist(INTBIG curcontrol);
void us_attrselectattributeline(INTBIG curcontrol, INTBIG which, INTBIG numvar, VARIABLE *firstvar);
INTBIG us_attrtextposition(INTBIG olddescript);

/*
 * special case for the "attributes" dialog
 * Current facet               = 3 (radio)
 * Current node inst           = 4 (radio)
 * Current portproto           = 5 (radio)
 * Current portinst            = 6 (radio)
 * Current network             = 7 (radio)
 * Attribute list              = 8 (scroll)
 * Attribute name              = 9 (edit test)
 * Attribute value             = 10 (edit test)
 * Instances inherit           = 11 (check)
 * Array Port attribute        = 13 (button)
 * Delete attribute            = 14 (button)
 * Create attribute            = 15 (button)
 * Rename attribute            = 16 (button)
 * Change attribute value      = 17 (button)
 * Attribute X offset          = 18 (stat text)
 * Attribute Y offset          = 19 (stat text)
 * Icon: cent/bot              = 20 (icon)
 * Icon: top/right             = 21 (icon)
 * Icon: left/lower-left       = 22 (icon)
 * Icon: lower-left/upper-right= 23 (icon)
 * Icon: upper-left            = 24 (icon)
 * Attribute: centered         = 25 (radio)
 * Attribute: bottom           = 26 (radio)
 * Attribute: top              = 27 (radio)
 * Attribute: right            = 28 (radio)
 * Attribute: left             = 29 (radio)
 * Attribute: lower-right      = 30 (radio)
 * Attribute: lower-left       = 31 (radio)
 * Attribute: upper-right      = 32 (radio)
 * Attribute: upper-left       = 33 (radio)
 * Port list                   = 34 (scroll)
 * More                        = 35 (button)
 * Add port to array           = 37 (button)      
 * Remove port from array      = 38 (button)      
 * Add all ports to array      = 39 (button)      
 * Remove all ports from array = 40 (button)      
 * What to show                = 42 (popup)
 */
static NODEPROTO *us_attrnodeprotoaddr;
static NODEINST *us_attrnodeinstaddr;
static ARCINST *us_attrarcinstaddr;
static PORTPROTO *us_attrportprotoaddr, *us_attrexportprotoaddr;

INTSML us_attributesdlog(void)
{
	REGISTER INTBIG itemHit, i, which, value, curcontrol, addr, type, newtype, descript;
	INTBIG numvar;
	INTSML x, y;
	RECTAREA r;
	REGISTER PORTPROTO *pp;
	REGISTER PORTEXPINST *pe;
	REGISTER VARIABLE *var, *newvar;
	VARIABLE *firstvar;
	char *oldvalue, *newvarname, *attrname, *newlang[4];
	REGISTER char *pt, *newvalue;
	HIGHLIGHT high;
	static char *whattodisplay[] = {N_("Nothing"), N_("Value"), N_("Name"),
		N_("Name&Value")};

	/* display the attributes dialog box */
	us_attrnodeprotoaddr = us_needfacet();
	if (us_attrnodeprotoaddr == NONODEPROTO) return(0);
	if (DiaInitDialog(&us_attrdialog) != 0) return(0);
	DiaInitTextDialog(8, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE|SCREPORT);
	DiaInitTextDialog(34, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE|SCREPORT|SCDOUBLEQUIT);
	for(i=0; i<4; i++) newlang[i] = _(whattodisplay[i]);   DiaSetPopup(42, 4, newlang);

	/* determine what attributes can be set */
	us_attrnodeinstaddr = NONODEINST;
	us_attrexportprotoaddr = us_attrnodeprotoaddr->firstportproto;
	us_attrportprotoaddr = NOPORTPROTO;
	us_attrarcinstaddr = NOARCINST;
	var = getvalkey((INTBIG)us_aid, VAID, VSTRING|VISARRAY, us_highlighted);
	if (var != NOVARIABLE)
	{
		if (getlength(var) == 1)
		{
			if (us_makehighlight(((char **)var->addr)[0], &high) == 0)
			{
				if ((high.status&HIGHTYPE) == HIGHFROM)
				{
					if (high.fromgeom->entrytype == OBJARCINST)
					{
						us_attrarcinstaddr = high.fromgeom->entryaddr.ai;
					} else
					{
						us_attrnodeinstaddr = high.fromgeom->entryaddr.ni;
						if (high.fromport != NOPORTPROTO)
						{
							for(pe = us_attrnodeinstaddr->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
								if (pe->proto == high.fromport) break;
							if (pe != NOPORTEXPINST) us_attrexportprotoaddr = high.fromport;
							if (us_attrnodeinstaddr->proto->primindex == 0) us_attrportprotoaddr = high.fromport;
						}
					}
				} else if ((high.status&HIGHTYPE) == HIGHTEXT)
				{
					if (high.fromport != NOPORTPROTO)
					{
						us_attrexportprotoaddr = high.fromport;
					}
				}
			}
		}
	}

	/* load the button names */
	(void)initinfstr();
	(void)formatinfstr(_("Facet (%s)"), describenodeproto(us_attrnodeprotoaddr));
	DiaSetText(3, returninfstr());
	if (us_attrnodeinstaddr != NONODEINST)
	{
		(void)initinfstr();
		(void)formatinfstr(_("Node (%s)"), describenodeinst(us_attrnodeinstaddr));
		DiaSetText(4, returninfstr());
	} else DiaDimItem(4);
	if (us_attrexportprotoaddr != NOPORTPROTO)
	{
		(void)initinfstr();
		(void)formatinfstr(_("Facet Export (%s)"), us_attrexportprotoaddr->protoname);
		DiaSetText(5, returninfstr());
	} else DiaDimItem(5);
	if (us_attrportprotoaddr != NOPORTPROTO)
	{
		(void)initinfstr();
		(void)formatinfstr(_("Node Port (%s)"), us_attrportprotoaddr->protoname);
		DiaSetText(6, returninfstr());
	} else DiaDimItem(6);
	if (us_attrarcinstaddr != NOARCINST)
	{
		(void)initinfstr();
		(void)formatinfstr(_("Network (%s)"), describearcinst(us_attrarcinstaddr));
		DiaSetText(7, returninfstr());
	} else DiaDimItem(7);

	/* figure out the initial control */
	if (us_attrarcinstaddr != NOARCINST) curcontrol = 7; else
	{
		if (us_attrexportprotoaddr != NOPORTPROTO) curcontrol = 5; else
		{
			if (us_attrportprotoaddr != NOPORTPROTO) curcontrol = 6; else
			{
				if (us_attrnodeinstaddr != NONODEINST) curcontrol = 4; else
					curcontrol = 3;
			}
		}
	}
	DiaSetControl(curcontrol, 1);
	switch (curcontrol)
	{
		case 3: addr = (INTBIG)us_attrnodeprotoaddr;    type = VNODEPROTO;   break;
		case 4: addr = (INTBIG)us_attrnodeinstaddr;     type = VNODEINST;    break;
		case 5: addr = (INTBIG)us_attrexportprotoaddr;  type = VPORTPROTO;   break;
		case 6: addr = (INTBIG)us_attrnodeinstaddr;     type = VNODEINST;    break;
		case 7: addr = (INTBIG)us_attrarcinstaddr;      type = VARCINST;     break;
	}
	if (curcontrol == 3 || curcontrol == 5) DiaUnDimItem(11); else
	{
		DiaSetControl(11, 0);
		DiaDimItem(11);
	}
	us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
	us_attrloadchoices(numvar, firstvar, curcontrol);
	us_attrloadportlist(curcontrol);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == 35) break;
		if (itemHit >= 3 && itemHit <= 7)
		{
			/* selected different object */
			for(i=3; i<=7; i++) DiaSetControl(i, 0);
			curcontrol = itemHit;
			DiaSetControl(curcontrol, 1);
			switch (curcontrol)
			{
				case 3: addr = (INTBIG)us_attrnodeprotoaddr;    type = VNODEPROTO;   break;
				case 4: addr = (INTBIG)us_attrnodeinstaddr;     type = VNODEINST;    break;
				case 5: addr = (INTBIG)us_attrexportprotoaddr;  type = VPORTPROTO;   break;
				case 6: addr = (INTBIG)us_attrnodeinstaddr;     type = VNODEINST;    break;
				case 7: addr = (INTBIG)us_attrarcinstaddr;      type = VARCINST;     break;
			}
			DiaSetText(9, "");
			if (curcontrol == 3 || curcontrol == 5) DiaUnDimItem(11); else
			{
				DiaSetControl(11, 0);
				DiaDimItem(11);
			}
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);
			us_attrloadportlist(curcontrol);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 8)
		{
			/* selected attribute name in scroll area */
			i = DiaGetCurLine(8);
			us_attrselectattributeline(curcontrol, i, numvar, firstvar);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 34)
		{
			/* selected port name */
			i = DiaGetCurLine(8);
			if (i < 0) attrname = 0; else
				(void)allocstring(&attrname, DiaGetScrollLine(8, i), el_tempcluster);
			which = DiaGetCurLine(34);
			pt = DiaGetScrollLine(34, which);
			if (*pt == '>') DiaDefaultButton(38); else DiaDefaultButton(37);
			if (curcontrol == 5)
			{
				for(i=0, pp = us_attrnodeprotoaddr->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
					if (which == i) break;
				if (pp == NOPORTPROTO) continue;
				us_attrexportprotoaddr = pp;
				(void)initinfstr();
				(void)formatinfstr(_("Facet Export (%s)"), us_attrexportprotoaddr->protoname);
				DiaSetText(5, returninfstr());
				addr = (INTBIG)us_attrexportprotoaddr;
			} else
			{
				for(i=0, pp = us_attrnodeinstaddr->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
					if (which == i) break;
				if (pp == NOPORTPROTO) continue;
				us_attrportprotoaddr = pp;
				(void)initinfstr();
				(void)formatinfstr(_("Node Port (%s)"), us_attrportprotoaddr->protoname);
				DiaSetText(6, returninfstr());
			}
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);

			/* see if former attribute name is in the new list */
			if (attrname != 0)
			{
				for(i=0; ; i++)
				{
					pt = DiaGetScrollLine(8, i);
					if (*pt == 0) break;
					if (namesame(pt, attrname) == 0)
					{
						DiaSelectLine(8, i);
						us_attrselectattributeline(curcontrol, i, numvar, firstvar);
						break;
					}
				}
				efree(attrname);
			}
			continue;
		}
		if (itemHit >= 20 && itemHit <= 24)
		{
			/* icon clicks: convert to buttons */
			DiaGetMouse(&x, &y);
			DiaItemRect(itemHit, &r);
			i = (itemHit-20) * 2;
			if (y > (r.top+r.bottom)/2) i++;
			itemHit = i + 25;
		}
		if (itemHit >= 25 && itemHit <= 33)
		{
			/* change text position */
			for(i=25; i<=33; i++) DiaSetControl(i, 0);
			DiaSetControl(itemHit, 1);
			if (DiaGetCurLine(8) < 0) continue;
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			if (curcontrol != 5) startobjectchange(addr, type); else
				startobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			if (curcontrol == 3) us_undrawfacetvariable(var, us_attrnodeprotoaddr);
			descript = us_attrtextposition(var->textdescript);
			modifydescript(addr, type, var, descript);
			if (curcontrol == 3) us_drawfacetvariable(var, us_attrnodeprotoaddr);
			if (curcontrol != 5) endobjectchange(addr, type); else
				endobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			us_endbatch();
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 42)
		{
			/* selected "what to show" */
			if (DiaGetCurLine(8) < 0) continue;
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			if (curcontrol != 5) startobjectchange(addr, type); else
				startobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			if (curcontrol == 3) us_undrawfacetvariable(var, us_attrnodeprotoaddr);
			if (DiaGetPopupEntry(42) == 0) var->type &= ~VDISPLAY; else
			{
				var->type |= VDISPLAY;
				descript = us_attrtextposition(var->textdescript);
				modifydescript(addr, type, var, descript);
			}
			if (curcontrol == 3) us_drawfacetvariable(var, us_attrnodeprotoaddr);
			if (curcontrol != 5) endobjectchange(addr, type); else
				endobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			us_endbatch();
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 11)
		{
			/* checked "instances inherit" */
			value = 1 - DiaGetControl(11);
			DiaSetControl(11, value);
			if (DiaGetCurLine(8) < 0) continue;
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			descript = var->textdescript;
			if (value == 0) descript &= ~VTINHERIT; else
				descript |= VTINHERIT;
			startobjectchange(addr, type);
			modifydescript(addr, type, var, descript);
			endobjectchange(addr, type);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 17)
		{
			/* change attribute value */
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			if (curcontrol != 5) startobjectchange(addr, type); else
				startobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			if (curcontrol == 3) us_undrawfacetvariable(var, us_attrnodeprotoaddr);
			pt = DiaGetText(10);
			setvalkey(addr, type, var->key, (INTBIG)pt, var->type);
			if (curcontrol == 3) us_drawfacetvariable(var, us_attrnodeprotoaddr);
			if (curcontrol != 5) endobjectchange(addr, type); else
				endobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			us_endbatch();
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 16)
		{
			/* rename attribute */
			pt = DiaGetText(9);
			while (*pt == ' ' || *pt == '\t') pt++;
			if (*pt == 0)
			{
				us_givemessagedialog(_("No attribute name given"));
				continue;
			}
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			newvarname = us_attrmakevarname(curcontrol, us_attrportprotoaddr, pt);
			pt = DiaGetText(10);
			newtype = var->type;
			descript = var->textdescript;
			startobjectchange(addr, type);
			if (curcontrol == 3) us_undrawfacetvariable(var, us_attrnodeprotoaddr);
			delvalkey(addr, type, var->key);
			newvar = setval(addr, type, newvarname, (INTBIG)pt, newtype);
			if (curcontrol == 6) newvar->textdescript = descript;
			if (curcontrol == 3) us_drawfacetvariable(newvar, us_attrnodeprotoaddr);
			endobjectchange(addr, type);
			us_endbatch();
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 14)
		{
			/* delete attribute */
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			if (curcontrol != 5) startobjectchange(addr, type); else
				startobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			if (curcontrol == 3) us_drawfacetvariable(var, us_attrnodeprotoaddr);
			delvalkey(addr, type, var->key);
			if (curcontrol != 5) endobjectchange(addr, type); else
				endobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			us_endbatch();
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 15)
		{
			/* new attribute */
			pt = DiaGetText(9);
			while (*pt == ' ' || *pt == '\t') pt++;
			if (*pt == 0)
			{
				us_givemessagedialog(_("No attribute name given"));
				continue;
			}
			newvarname = us_attrmakevarname(curcontrol, us_attrportprotoaddr, pt);
			pt = DiaGetText(10);
			newtype = VSTRING;
			if (DiaGetPopupEntry(42) != 0) newtype |= VDISPLAY;
			startobjectchange(addr, type);
			newvar = setval(addr, type, newvarname, (INTBIG)pt, newtype);
			if (newvar == NOVARIABLE) continue;
			if (curcontrol == 6)
			{
				/* add in offset to the port */
				us_attrsetportposition(newvar, us_attrportprotoaddr);
			}
			newvar->textdescript = us_attrtextposition(newvar->textdescript);
			if (curcontrol == 3) us_drawfacetvariable(newvar, us_attrnodeprotoaddr);
			if (curcontrol != 5) endobjectchange(addr, type); else
				endobjectchange((INTBIG)us_attrexportprotoaddr->subnodeinst, VNODEINST);				
			us_endbatch();
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 37)
		{
			/* Add port to array */
			i = DiaGetCurLine(34);
			if (i < 0) continue;
			pt = DiaGetScrollLine(34, i);
			if (pt[0] == '>' && pt[1] == ' ') continue;
			(void)initinfstr();
			(void)addstringtoinfstr("> ");
			(void)addstringtoinfstr(pt);
			DiaSetScrollLine(34, i, returninfstr());
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 38)
		{
			/* Remove port from array */
			i = DiaGetCurLine(34);
			if (i < 0) continue;
			pt = DiaGetScrollLine(34, i);
			if (pt[0] != '>' || pt[1] != ' ') continue;
			DiaSetScrollLine(34, i, &pt[2]);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 39)
		{
			/* Add all ports to array */
			which = DiaGetCurLine(34);
			for(i=0; ; i++)
			{
				pt = DiaGetScrollLine(34, i);
				if (*pt == 0) break;
				if (pt[0] == '>' && pt[1] == ' ') continue;
				(void)initinfstr();
				(void)addstringtoinfstr("> ");
				(void)addstringtoinfstr(pt);
				DiaSetScrollLine(34, i, returninfstr());
			}
			DiaSelectLine(34, which);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 40)
		{
			/* Remove all ports from array */
			which = DiaGetCurLine(34);
			for(i=0; ; i++)
			{
				pt = DiaGetScrollLine(34, i);
				if (*pt == 0) break;
				if (pt[0] != '>' || pt[1] != ' ') continue;
				DiaSetScrollLine(34, i, &pt[2]);
			}
			DiaSelectLine(34, which);
			DiaDefaultButton(1);
			continue;
		}
		if (itemHit == 13)
		{
			/* array port attribute */
			var = us_attrfindvarname(curcontrol, numvar, firstvar);
			if (var == NOVARIABLE) continue;
			allocstring(&attrname, DiaGetScrollLine(8, DiaGetCurLine(8)), el_tempcluster);
			allocstring(&oldvalue, (char *)var->addr, el_tempcluster);
			newtype = var->type;
			if (curcontrol == 6)
			{
				/* array node port attributes */
				startobjectchange(addr, type);
				for(i=0, pp = us_attrnodeinstaddr->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
				{
					pt = DiaGetScrollLine(34, i);
					if (pt[0] != '>' || pt[1] != ' ') continue;
					(void)allocstring(&newvarname, us_attrmakevarname(curcontrol, pp, attrname), el_tempcluster);
					newvar = getval(addr, type, -1, newvarname);
					if (newvar == NOVARIABLE)
					{
						newvalue = us_attrgenportvalue(curcontrol, addr, type, attrname, us_attrnodeinstaddr->proto, oldvalue);
						newvar = setval(addr, type, newvarname, (INTBIG)newvalue, newtype);
						if (newvar != NOVARIABLE)
						{
							us_attrsetportposition(newvar, pp);
							newvar->textdescript = us_attrtextposition(newvar->textdescript);
						}
					}
					efree(newvarname);
				}
				endobjectchange(addr, type);
			} else
			{
				/* array facet port attributes */
				(void)allocstring(&newvarname, us_attrmakevarname(curcontrol, pp, attrname), el_tempcluster);
				for(i=0, pp = us_attrnodeprotoaddr->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
				{
					pt = DiaGetScrollLine(34, i);
					if (pt[0] != '>' || pt[1] != ' ') continue;
					newvar = getval((INTBIG)pp, VPORTPROTO, -1, newvarname);
					if (newvar == NOVARIABLE)
					{
						startobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
						newvalue = us_attrgenportvalue(curcontrol, addr, type, attrname, us_attrnodeprotoaddr, oldvalue);
						newvar = setval((INTBIG)pp, VPORTPROTO, newvarname, (INTBIG)newvalue, newtype);
						if (newvar != NOVARIABLE)
						{
							newvar->textdescript = us_attrtextposition(newvar->textdescript);
						}
						endobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
					}
				}
				efree(newvarname);
			}
			us_endbatch();
			efree(oldvalue);
			efree(attrname);
			us_attrgetfactors(curcontrol, addr, &numvar, &firstvar);
			us_attrloadchoices(numvar, firstvar, curcontrol);
			DiaDefaultButton(1);
			continue;
		}
	}
	DiaDoneDialog();
	if (itemHit == 35)
	{
		/* "More" button: fire up "variables" dialog */
		(void)us_variablesdlog();
	}
	return(0);
}

/* helper routine to modify the text descriptor from the dialog controls */
INTBIG us_attrtextposition(INTBIG descript)
{
	INTBIG value;

	descript &= ~(VTPOSITION|VTDISPLAYPART|VTINHERIT);
	if (DiaGetControl(25) != 0) descript |= VTPOSCENT;
	if (DiaGetControl(26) != 0) descript |= VTPOSUP;
	if (DiaGetControl(27) != 0) descript |= VTPOSDOWN;
	if (DiaGetControl(28) != 0) descript |= VTPOSLEFT;
	if (DiaGetControl(29) != 0) descript |= VTPOSRIGHT;
	if (DiaGetControl(30) != 0) descript |= VTPOSUPLEFT;
	if (DiaGetControl(31) != 0) descript |= VTPOSUPRIGHT;
	if (DiaGetControl(32) != 0) descript |= VTPOSDOWNLEFT;
	if (DiaGetControl(33) != 0) descript |= VTPOSDOWNRIGHT;
	value = DiaGetPopupEntry(42);
	switch (value)
	{
		case 1: descript |= VTDISPLAYVALUE;       break;
		case 2: descript |= VTDISPLAYNAME;        break;
		case 3: descript |= VTDISPLAYNAMEVALUE;   break;
	}
	if (DiaGetControl(11) != 0) descript |= VTINHERIT;
	return(descript);
}

void us_attrselectattributeline(INTBIG curcontrol, INTBIG which, INTBIG numvar, VARIABLE *firstvar)
{
	REGISTER VARIABLE *var;
	REGISTER INTBIG x, y, i, lambda;

	if (which < 0) return;
	var = us_attrfindvarname(curcontrol, numvar, firstvar);
	if (var == NOVARIABLE) return;
	DiaSetText(9, DiaGetScrollLine(8, which));
	if ((var->type&VTYPE) == VSTRING) DiaSetText(10, (char *)var->addr); else
		DiaSetText(10, describevariable(var, -1, 0));
	if ((var->type&VDISPLAY) == 0) DiaSetPopupEntry(42, 0); else
	{
		switch (var->textdescript&VTDISPLAYPART)
		{
			case VTDISPLAYVALUE:     DiaSetPopupEntry(42, 1);   break;
			case VTDISPLAYNAME:      DiaSetPopupEntry(42, 2);   break;
			case VTDISPLAYNAMEVALUE: DiaSetPopupEntry(42, 3);   break;
		}
	}
	if ((var->textdescript&VTINHERIT) != 0) DiaSetControl(11, 1); else
		DiaSetControl(11, 0);
	if (curcontrol != 6)
	{
		switch (curcontrol)
		{
			case 3:
				lambda = el_curlib->lambda[us_attrnodeprotoaddr->tech->techindex];
				break;
			case 4:
				lambda = figurelambda(us_attrnodeinstaddr->geom);
				break;
			case 5:
				lambda = el_curlib->lambda[us_attrexportprotoaddr->parent->tech->techindex];
				break;
			case 7:
				lambda = figurelambda(us_attrarcinstaddr->geom);
				break;
		}
		x = (var->textdescript&VTXOFF) >> VTXOFFSH;
		if ((var->textdescript&VTXOFFNEG) != 0) x = -x;
		x = x * lambda / 4;
		y = (var->textdescript&VTYOFF) >> VTYOFFSH;
		if ((var->textdescript&VTYOFFNEG) != 0) y = -y;
		y = y * lambda / 4;
		(void)initinfstr();
		(void)addstringtoinfstr(_("X offset: "));
		(void)addstringtoinfstr(latoa(x));
		DiaSetText(18, returninfstr());
		(void)initinfstr();
		(void)addstringtoinfstr(_("Y offset: "));
		(void)addstringtoinfstr(latoa(y));
		DiaSetText(19, returninfstr());
	}
	for(i=25; i<=33; i++) DiaSetControl(i, 0);
	switch (var->textdescript&VTPOSITION)
	{
		case VTPOSCENT:      DiaSetControl(25, 1);   break;
		case VTPOSUP:        DiaSetControl(26, 1);   break;
		case VTPOSDOWN:      DiaSetControl(27, 1);   break;
		case VTPOSLEFT:      DiaSetControl(28, 1);   break;
		case VTPOSRIGHT:     DiaSetControl(29, 1);   break;
		case VTPOSUPLEFT:    DiaSetControl(30, 1);   break;
		case VTPOSUPRIGHT:   DiaSetControl(31, 1);   break;
		case VTPOSDOWNLEFT:  DiaSetControl(32, 1);   break;
		case VTPOSDOWNRIGHT: DiaSetControl(33, 1);   break;
	}
}

void us_attrsetportposition(VARIABLE *var, PORTPROTO *pp)
{
	INTBIG x, y;
	REGISTER INTBIG lambda, descript;

	portposition(us_attrnodeinstaddr, pp, &x, &y);
	x -= (us_attrnodeinstaddr->lowx + us_attrnodeinstaddr->highx) / 2;
	y -= (us_attrnodeinstaddr->lowy + us_attrnodeinstaddr->highy) / 2;
	lambda = figurelambda(us_attrnodeinstaddr->geom);
	x = x * 4 / lambda;
	y = y * 4 / lambda;
	descript = var->textdescript & ~(VTXOFF|VTXOFFNEG|VTYOFF|VTYOFFNEG);
	if (x < 0) { descript |= VTXOFFNEG;   x = -x; }
	if (y < 0) { descript |= VTYOFFNEG;   y = -y; }
	descript |= x << VTXOFFSH;
	descript |= y << VTYOFFSH;
	var->textdescript = descript;
}

char *us_attrgenportvalue(INTBIG curcontrol, INTBIG addr, INTBIG type, char *attrname, NODEPROTO *np, char *oldvalue)
{
	REGISTER PORTPROTO *pp;
	REGISTER char *pt, *start, save, *varname;
	REGISTER VARIABLE *var;
	char line[30], *testvalue;
	REGISTER INTBIG value, i;

	/* see if there are numbers here */
	for(pt = oldvalue; *pt != 0; pt++)
		if (isdigit(*pt) != 0) break;
	if (*pt == 0) return(oldvalue);

	/* get the number and the text around it */
	start = pt;
	while (isdigit(*pt) != 0) pt++;
	value = atoi(start);

	/* loop through higher numbers looking for unused value */
	for(i = value+1; i<value+5000; i++)
	{
		(void)initinfstr();
		save = *start;   *start = 0;
		(void)addstringtoinfstr(oldvalue);
		*start = save;
		sprintf(line, "%ld", i);
		(void)addstringtoinfstr(line);
		(void)addstringtoinfstr(pt);
		allocstring(&testvalue, returninfstr(), el_tempcluster);

		/* see if the value is used */
		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
		{
			varname = us_attrmakevarname(curcontrol, pp, attrname);
			if (curcontrol == 6)
			{
				var = getval(addr, type, VSTRING, varname);
			} else
			{
				var = getval((INTBIG)pp, VPORTPROTO, VSTRING, varname);
			}
			if (var == NOVARIABLE) continue;
			if (namesame((char *)var->addr, testvalue) == 0) break;
		}
		if (pp == NOPORTPROTO)
		{
			(void)initinfstr();
			(void)addstringtoinfstr(testvalue);
			efree(testvalue);
			return(returninfstr());
		} else
		{
			efree(testvalue);
		}
	}
	return(oldvalue);
}

char *us_attrmakevarname(INTBIG curcontrol, PORTPROTO *pp, char *name)
{
	(void)initinfstr();
	if (curcontrol == 6)
	{
		(void)addstringtoinfstr("ATTRP_");
		(void)addstringtoinfstr(pp->protoname);
		(void)addstringtoinfstr("_");
	} else
	{
		(void)addstringtoinfstr("ATTR_");
	}
	(void)addstringtoinfstr(name);
	return(returninfstr());
}

void us_attrloadchoices(INTBIG numvar, VARIABLE *firstvar, INTBIG curcontrol)
{
	REGISTER VARIABLE *var;
	REGISTER INTBIG i, protolen, found;
	REGISTER char *varname;

	if (curcontrol == 6) protolen = strlen(us_attrportprotoaddr->protoname);
	DiaLoadTextDialog(8, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
	found = 0;
	for(i=0; i<numvar; i++)
	{
		var = &firstvar[i];
		varname = makename(var->key);
		if (curcontrol == 6)
		{
			if (namesamen(varname, "ATTRP_", 6) == 0)
			{
				if (namesamen(&varname[6], us_attrportprotoaddr->protoname, protolen) == 0)
				{
					if (varname[6+protolen] == '_')
					{
						DiaStuffLine(8, &varname[7+protolen]);
						found++;
					}
				}
			}
		} else
		{
			if (namesamen(varname, "ATTR_", 5) == 0)
			{
				DiaStuffLine(8, &varname[5]);
				found++;
			}
		}
	}
	if (found == 0)
	{
		DiaSelectLine(8, -1);
		DiaSetText(18, "");
		DiaSetText(19, "");
		DiaSetText(10, "");
		DiaSetText(9, "");
	} else
	{
		DiaSelectLine(8, 0);
		us_attrselectattributeline(curcontrol, 0, numvar, firstvar);
	}
}

void us_attrloadportlist(INTBIG curcontrol)
{
	REGISTER INTBIG i, which;
	REGISTER PORTPROTO *pp;

	DiaLoadTextDialog(34, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
	if (curcontrol == 5 || curcontrol == 6)
	{
		/* port selected: show all ports */
		if (curcontrol == 5)
		{
			for(i=0, pp = us_attrnodeprotoaddr->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
			{
				if (pp == us_attrexportprotoaddr) which = i;
				(void)initinfstr();
				(void)addstringtoinfstr("> ");
				(void)addstringtoinfstr(pp->protoname);
				DiaStuffLine(34, returninfstr());
			}
			DiaSelectLine(34, which);
		} else
		{
			for(i=0, pp = us_attrnodeinstaddr->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, i++)
			{
				if (pp == us_attrportprotoaddr) which = i;
				(void)initinfstr();
				(void)addstringtoinfstr("> ");
				(void)addstringtoinfstr(pp->protoname);
				DiaStuffLine(34, returninfstr());
			}
			DiaSelectLine(34, which);
		}
		DiaUnDimItem(13);
		DiaUnDimItem(36);
		DiaUnDimItem(37);
		DiaUnDimItem(38);
		DiaUnDimItem(39);
		DiaUnDimItem(40);
	} else
	{
		DiaDimItem(13);
		DiaDimItem(36);
		DiaDimItem(37);
		DiaDimItem(38);
		DiaDimItem(39);
		DiaDimItem(40);
	}
}

void us_attrgetfactors(INTBIG curcontrol, INTBIG addr, INTBIG *numvar, VARIABLE **firstvar)
{
	REGISTER NODEPROTO *np;
	REGISTER NODEINST *ni;
	REGISTER PORTPROTO *pp;
	REGISTER ARCINST *ai;

	switch (curcontrol)
	{
		case 3:
			np = (NODEPROTO *)addr;
			*numvar = np->numvar;
			*firstvar = np->firstvar;
			break;
		case 4:
		case 6:
			ni = (NODEINST *)addr;
			*numvar = ni->numvar;
			*firstvar = ni->firstvar;
			break;
		case 5:
			pp = (PORTPROTO *)addr;
			*numvar = pp->numvar;
			*firstvar = pp->firstvar;
			break;
		case 7:
			ai = (ARCINST *)addr;
			*numvar = ai->numvar;
			*firstvar = ai->firstvar;
			break;
	}
}

VARIABLE *us_attrfindvarname(INTBIG curcontrol, INTBIG numvar, VARIABLE *firstvar)
{
	REGISTER INTBIG i, len;
	REGISTER char *pt, *varname;
	REGISTER VARIABLE *var;

	i = DiaGetCurLine(8);
	if (i < 0)
	{
		us_givemessagedialog(_("Select an attribute name first"));
		return(NOVARIABLE);
	}
	pt = DiaGetScrollLine(8, i);
	for(i=0; i<numvar; i++)
	{
		var = &firstvar[i];
		varname = makename(var->key);
		if (curcontrol == 6)
		{
			if (namesamen(varname, "ATTRP_", 6) != 0) continue;
			len = strlen(us_attrportprotoaddr->protoname);
			if (namesamen(&varname[6], us_attrportprotoaddr->protoname, len) != 0) continue;
			if (varname[6+len] != '_') continue;
			if (namesame(&varname[7+len], pt) == 0) return(var);
		} else
		{
			if (namesamen(varname, "ATTR_", 5) != 0) continue;
			if (namesame(&varname[5], pt) == 0) return(var);
		}
	}
	return(NOVARIABLE);
}

/****************************** CHANGE DIALOG ******************************/

/* Change */
DIALOGITEM us_changedialogitems[] =
{
 /*  1 */ {0, {168,340,192,412}, BUTTON, N_("OK")},
 /*  2 */ {0, {168,244,192,316}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,232,24,438}, RADIO, N_("Change this one only")},
 /*  4 */ {0, {64,232,80,438}, RADIO, N_("Change all in this facet")},
 /*  5 */ {0, {92,232,108,438}, RADIO, N_("Change all in this library")},
 /*  6 */ {0, {36,232,52,438}, RADIO, N_("Change all connected to this")},
 /*  7 */ {0, {8,8,168,223}, SCROLL, ""},
 /*  8 */ {0, {176,8,192,78}, MESSAGE, N_("Library:")},
 /*  9 */ {0, {176,80,192,218}, POPUP, ""},
 /* 10 */ {0, {132,232,148,438}, CHECK, N_("Ignore port names")}
};
DIALOG us_changedialog = {{50,75,251,522}, N_("Change Type of Highlight"), 0, 10, us_changedialogitems};

INTSML us_onproto(PORTPROTO*, ARCPROTO*);

/*
 * special case for the "change" dialog
 * Alternate list    = 7 (user item)
 * This only         = 3 (radio)
 * In facet          = 4 (radio)
 * Universally       = 5 (radio)
 * Connected         = 6 (radio)
 * Library label     = 8 (stat text)
 * Libraries         = 9 (popup)
 * Ignore port names = 10 (check)
 */
INTSML us_replacedlog(void)
{
	INTBIG i, itemHit, total, ac;
	HIGHLIGHT *high;
	REGISTER ARCPROTO *ap;
	REGISTER NODEPROTO *np;
	REGISTER ARCINST *ai;
	REGISTER PORTPROTO *pp1, *pp2;
	REGISTER LIBRARY *lib;
	REGISTER char **liblist;
	char *par[3];

	/* see what is highlighted */
	high = us_getonehighlight();
	if (high == NOHIGHLIGHT) return(0);
	if ((high->status&HIGHTYPE) != HIGHFROM)
	{
		ttyputerr("Must select a node or an arc to replace");
		return(0);
	}

	/* display the change dialog box */
	if (DiaInitDialog(&us_changedialog) != 0) return(0);
	DiaInitTextDialog(7, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT);
	liblist = 0;
	us_curlib = el_curlib;
	if (high->fromgeom->entrytype == OBJARCINST)
	{
		/* load arcs in current technology, arc's technology, and generic technology */
		ai = high->fromgeom->entryaddr.ai;
		pp1 = ai->end[0].portarcinst->proto;
		pp2 = ai->end[1].portarcinst->proto;
		for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
		{
			if (us_onproto(pp1, ap) == 0) continue;
			if (us_onproto(pp2, ap) == 0) continue;
			DiaStuffLine(7, ap->protoname);
		}
		if (el_curtech != gen_tech)
			for(ap = gen_tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
		{
			if (us_onproto(pp1, ap) == 0) continue;
			if (us_onproto(pp2, ap) == 0) continue;
			DiaStuffLine(7, describearcproto(ap));
		}
		if (ai->proto->tech != el_curtech && ai->proto->tech != gen_tech)
			for(ap = ai->proto->tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
		{
			if (us_onproto(pp1, ap) == 0) continue;
			if (us_onproto(pp2, ap) == 0) continue;
			DiaStuffLine(7, describearcproto(ap));
		}
		DiaSelectLine(7, 0);
		DiaDimItem(8);
		DiaDimItem(9);
		DiaDimItem(10);
	} else
	{
		if (high->fromgeom->entryaddr.ni->proto->primindex == 0)
		{
			/* facet: only list other facets as replacements */
			us_showoldversions = 1;
			us_showcellibraryfacets = 1;
			DiaLoadTextDialog(7, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
			(void)us_setscrolltocurrentfacet(7, 1, 0, 0);
			DiaUnDimItem(8);
			DiaUnDimItem(9);
			total = 0;
			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
				if ((lib->userbits&HIDDENLIBRARY) == 0) total++;
			liblist = (char **)emalloc(total * (sizeof (char *)), el_tempcluster);
			if (liblist == 0) return(0);
			total = 0;
			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
				if ((lib->userbits&HIDDENLIBRARY) == 0) liblist[total++] = lib->libname;
			DiaSetPopup(9, total, liblist);
		} else
		{
			/* primitive: list primitives in this and the generic technology */
			for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				DiaStuffLine(7, np->primname);
			if (el_curtech != gen_tech)
			{
				DiaStuffLine(7, "Generic:Universal-Pin");
				DiaStuffLine(7, "Generic:Invisible-Pin");
				DiaStuffLine(7, "Generic:Unrouted-Pin");
			}
			DiaSelectLine(7, 0);
			DiaDimItem(8);
			DiaDimItem(9);
		}
	}
	DiaSetControl(3, 1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit >= 3 && itemHit <= 6)
		{
			for(i=3; i<=6; i++) DiaSetControl(i, 0);
			DiaSetControl(itemHit, 1);
		}
		if (itemHit == 10)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			continue;
		}
		if (itemHit == 9)
		{
			i = DiaGetPopupEntry(9);
			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
				if (namesame(lib->libname, liblist[i]) == 0) break;
			if (lib == NOLIBRARY) continue;
			us_curlib = lib;
			DiaLoadTextDialog(7, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
			(void)us_setscrolltocurrentfacet(7, 1, 0, 0);
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		ac = 0;
		(void)initinfstr();
		if (us_curlib != el_curlib)
		{
			(void)addstringtoinfstr(us_curlib->libname);
			(void)addtoinfstr(':');
		}
		(void)addstringtoinfstr(DiaGetScrollLine(7, DiaGetCurLine(7)));
		par[ac++] = returninfstr();
		if (DiaGetControl(4) != 0) par[ac++] = "this-facet";
		if (DiaGetControl(5) != 0) par[ac++] = "universally";
		if (DiaGetControl(6) != 0) par[ac++] = "connected";
		if (DiaGetControl(10) != 0) par[ac++] = "ignore-port-names";
		us_replace((INTSML)ac, par);
	}
	if (liblist != 0) efree((char *)liblist);
	DiaDoneDialog();
	return(0);
}

/*
 * helper routine to determine whether arcproto "ap" can connect to portproto "pp".
 * returns nonzero if so
 */
INTSML us_onproto(PORTPROTO *pp, ARCPROTO *ap)
{
	REGISTER INTBIG i;

	for(i=0; pp->connects[i] != NOARCPROTO; i++)
		if (pp->connects[i] == ap) return(1);
	return(0);
}

/****************************** CHOICE DIALOGS ******************************/

/* No/Yes */
DIALOGITEM us_noyesdialogitems[] =
{
/*  1 */ {0, {80,132,104,204}, BUTTON, N_("No")},
/*  2 */ {0, {80,60,104,124}, BUTTON, N_("Yes")},
/*  3 */ {0, {8,8,72,256}, MESSAGE, ""}
};
DIALOG us_noyesdialog = {{50,75,163,341}, N_("Choice"), 0, 3, us_noyesdialogitems};

/* Yes/No */
DIALOGITEM us_yesnodialogitems[] =
{
/*  1 */ {0, {64,156,88,228}, BUTTON, N_("Yes")},
/*  2 */ {0, {64,68,88,140}, BUTTON, N_("No")},
/*  3 */ {0, {6,15,54,279}, MESSAGE, ""}
};
DIALOG us_yesnodialog = {{50,75,150,369}, N_("Choice"), 0, 3, us_yesnodialogitems};

/* Prompt: No/Yes/Always */
DIALOGITEM us_noyesalwaysdialogitems[] =
{
/*  1 */ {0, {64,168,88,248}, BUTTON, N_("No")},
/*  2 */ {0, {64,8,88,88}, BUTTON, N_("Yes")},
/*  3 */ {0, {124,88,148,168}, BUTTON, N_("Always")},
/*  4 */ {0, {8,8,56,248}, MESSAGE, N_("Allow this?")},
/*  5 */ {0, {100,8,116,248}, MESSAGE, N_("Click \"Always\" to disable the lock")}
};
DIALOG us_noyesalwaysdialog = {{75,75,232,332}, N_("Allow this change?"), 0, 5, us_noyesalwaysdialogitems};

/*
 * special case for "yes/no" options ("no" is default)
 * Message = 3 (message)
 * No = 1      (button)
 * Yes = 2     (button)
 */
INTSML us_noyesdlog(char *prompt, char *paramstart[])
{
	INTBIG itemHit;
	INTSML oldplease;

	/* display the no/yes dialog box */
	if (DiaInitDialog(&us_noyesdialog) != 0) return(0);

	/* load the message */
	DiaSetText(3, prompt);

	/* loop until done */
	oldplease = el_pleasestop;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == 1 || itemHit == 2) break;
	}
	el_pleasestop = oldplease;

	if (itemHit == 1) paramstart[0] = "no"; else
		paramstart[0] = "yes";
	DiaDoneDialog();
	return(1);
}

/*
 * special case for "yes/no" options ("yes" is default)
 * Message = 3 (message)
 * Yes = 1     (button)
 * No = 2      (button)
 */
INTSML us_yesnodlog(char *prompt, char *paramstart[])
{
	INTBIG itemHit;
	INTSML oldplease;

	/* display the yes/no dialog box */
	if (DiaInitDialog(&us_yesnodialog) != 0) return(0);

	/* load the message */
	DiaSetText(3, prompt);

	/* loop until done */
	oldplease = el_pleasestop;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == 1 || itemHit == 2) break;
	}
	el_pleasestop = oldplease;

	if (itemHit == 1) paramstart[0] = "yes"; else paramstart[0] = "no";
	DiaDoneDialog();
	return(1);
}

/*
 * special case for "no/yes/always" options ("no" is default)
 * Message = 4 (message)
 * No = 1      (button)
 * Yes = 2     (button)
 * Always = 3  (button)
 */
/*
 * Routine to prompt when a change has been disallowed.  Returns 0 to retain the lock;
 * 1 to allow the change, and -1 to permanently allow the change.
 */
INTSML us_noyesalwaysdlog(char *prompt, char *paramstart[])
{
	REGISTER INTBIG itemHit;

	if (DiaInitDialog(&us_noyesalwaysdialog) != 0) return(0);
	DiaSetText(4, prompt);
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == 1 || itemHit == 2 || itemHit == 3) break;
	}
	DiaDoneDialog();
	if (itemHit == 1) paramstart[0] = "no"; else
		if (itemHit == 2) paramstart[0] = "yes"; else
			paramstart[0] = "always";
	return(1);
}

/* Prompt: OK */
DIALOGITEM us_okmessagedialogitems[] =
{
/*  1 */ {0, {72,64,96,144}, BUTTON, N_("OK")},
/*  2 */ {0, {8,8,56,212}, MESSAGE, ""}
};
DIALOG us_okmessagedialog = {{75,75,180,296}, 0, 0, 2, us_okmessagedialogitems};

/*
 * special case for "OK prompt" options
 * Message = 2 (message)
 */
void us_givemessagedialog(char *message)
{
	INTBIG itemHit;

	/* display the message dialog box */
	if (DiaInitDialog(&us_okmessagedialog) != 0) return;
	DiaSetText(2, message);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK) break;
	}
	DiaDoneDialog();
}

/****************************** COLOR OPTIONS DIALOG ******************************/

#define	DEGTORAD    (EPI/180.0)
#define INTENSITYDIVISIONS 20
#define WHEELRADIUS        96
#define WHEELEDGE          (WHEELRADIUS + WHEELRADIUS/16)

/* Color Mixing */
DIALOGITEM us_colormixdialogitems[] =
{
 /*  1 */ {0, {212,400,236,468}, BUTTON, N_("OK")},
 /*  2 */ {0, {212,320,236,388}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {252,8,268,24}, USERDRAWN, ""},
 /*  4 */ {0, {252,36,268,472}, RADIO, N_("Entry")},
 /*  5 */ {0, {272,8,288,24}, USERDRAWN, ""},
 /*  6 */ {0, {272,36,288,472}, RADIO, N_("Entry")},
 /*  7 */ {0, {292,8,308,24}, USERDRAWN, ""},
 /*  8 */ {0, {292,36,308,472}, RADIO, N_("Entry")},
 /*  9 */ {0, {312,8,328,24}, USERDRAWN, ""},
 /* 10 */ {0, {312,36,328,472}, RADIO, N_("Entry")},
 /* 11 */ {0, {332,8,348,24}, USERDRAWN, ""},
 /* 12 */ {0, {332,36,348,472}, RADIO, N_("Entry")},
 /* 13 */ {0, {352,8,368,24}, USERDRAWN, ""},
 /* 14 */ {0, {352,36,368,472}, RADIO, N_("Entry")},
 /* 15 */ {0, {372,8,388,24}, USERDRAWN, ""},
 /* 16 */ {0, {372,36,388,472}, RADIO, N_("Entry")},
 /* 17 */ {0, {392,8,408,24}, USERDRAWN, ""},
 /* 18 */ {0, {392,36,408,472}, RADIO, N_("Entry")},
 /* 19 */ {0, {412,8,428,24}, USERDRAWN, ""},
 /* 20 */ {0, {412,36,428,472}, RADIO, N_("Entry")},
 /* 21 */ {0, {432,8,448,24}, USERDRAWN, ""},
 /* 22 */ {0, {432,36,448,472}, RADIO, N_("Entry")},
 /* 23 */ {0, {452,8,468,24}, USERDRAWN, ""},
 /* 24 */ {0, {452,36,468,472}, RADIO, N_("Entry")},
 /* 25 */ {0, {472,8,488,24}, USERDRAWN, ""},
 /* 26 */ {0, {472,36,488,472}, RADIO, N_("Entry")},
 /* 27 */ {0, {492,8,508,24}, USERDRAWN, ""},
 /* 28 */ {0, {492,36,508,472}, RADIO, N_("Entry")},
 /* 29 */ {0, {512,8,528,24}, USERDRAWN, ""},
 /* 30 */ {0, {512,36,528,472}, RADIO, N_("Entry")},
 /* 31 */ {0, {532,8,548,24}, USERDRAWN, ""},
 /* 32 */ {0, {532,36,548,472}, RADIO, N_("Entry")},
 /* 33 */ {0, {552,8,568,24}, USERDRAWN, ""},
 /* 34 */ {0, {552,36,568,472}, RADIO, N_("Entry")},
 /* 35 */ {0, {32,8,244,220}, USERDRAWN, ""},
 /* 36 */ {0, {32,228,244,308}, USERDRAWN, ""},
 /* 37 */ {0, {8,16,24,144}, MESSAGE, N_("Hue/Saturation:")},
 /* 38 */ {0, {8,228,24,308}, MESSAGE, N_("Intensity:")},
 /* 39 */ {0, {28,356,44,472}, RADIO, N_("Primaries")},
 /* 40 */ {0, {48,356,64,472}, RADIO, N_("Specials")},
 /* 41 */ {0, {68,356,84,472}, RADIO, N_("Layer 1")},
 /* 42 */ {0, {88,356,104,472}, RADIO, N_("Layer 2")},
 /* 43 */ {0, {108,356,124,472}, RADIO, N_("Layer 3")},
 /* 44 */ {0, {128,356,144,472}, RADIO, N_("Layer 4")},
 /* 45 */ {0, {148,356,164,472}, RADIO, N_("Layer 5")},
 /* 46 */ {0, {4,356,20,436}, MESSAGE, N_("Palettes:")},
 /* 47 */ {0, {176,312,200,472}, BUTTON, N_("Compute from Primaries")}
};
DIALOG us_colormixdialog = {{75,75,652,556}, N_("Color Mixing"), 0, 47, us_colormixdialogitems};

INTBIG us_colormixredmap[256], us_colormixgreenmap[256], us_colormixbluemap[256];
INTBIG us_colormixindex[16];
INTBIG us_colormixcurindex;
float us_colormixtheta, us_colormixr, us_colormixinten;
char *us_colormixnames[5];

void us_colormixreload(void);
char *us_colormixentryname(char *overlayernames[], INTBIG ind);
void us_colormixbuildindex(INTBIG layer1, INTBIG layer2, INTBIG layer3, INTBIG layer4, INTBIG layer5);
void us_colormixdrawpalette(RECTAREA *ra);
void us_colormixtogglemarker(void);
void us_colormixdrawsquare(INTBIG sindex);
void us_colormixmergecolor(INTBIG r1, INTBIG g1, INTBIG b1, INTBIG r2, INTBIG g2, INTBIG b2,
INTBIG *ro, INTBIG *go, INTBIG *bo);
void us_colormixsmoothcolors(void);

/*
 * special case for the "Color Mixing" dialog
 * Color patches for palettes  = 3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33 (user)
 * Buttons for color palette   = 4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34 (radio)
 * Hue/Saturation wheel        = 35 (user)
 * Intensity slider            = 36 (user)
 * Primaries palette selection = 39 (radio)
 * Specials palette selection  = 40 (radio)
 * Layer 1 palette selection   = 41 (radio)
 * Layer 2 palette selection   = 42 (radio)
 * Layer 3 palette selection   = 43 (radio)
 * Layer 4 palette selection   = 44 (radio)
 * Layer 5 palette selection   = 45 (radio)
 * Compute from primaries      = 47 (button)
 */
INTSML us_colormixdlog(char *overlayernames[])
{
	REGISTER INTBIG itemHit, i, colorchanged;
	INTSML x, y;
	INTBIG r, g, b;
	REGISTER INTBIG cx, cy;
	REGISTER VARIABLE *varred, *vargreen, *varblue;
	RECTAREA ra;

	varred = getvalkey((INTBIG)us_aid, VAID, VINTEGER|VISARRAY, us_colormap_red);
	vargreen = getvalkey((INTBIG)us_aid, VAID, VINTEGER|VISARRAY, us_colormap_green);
	varblue = getvalkey((INTBIG)us_aid, VAID, VINTEGER|VISARRAY, us_colormap_blue);
	if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return(0);
	for(i=0; i<256; i++)
	{
		us_colormixredmap[i] = ((INTBIG *)varred->addr)[i];
		us_colormixgreenmap[i] = ((INTBIG *)vargreen->addr)[i];
		us_colormixbluemap[i] = ((INTBIG *)varblue->addr)[i];
	}

	/* display the color mixing dialog box */
	us_colormixdialogitems[40].msg = overlayernames[0];
	us_colormixdialogitems[41].msg = overlayernames[1];
	us_colormixdialogitems[42].msg = overlayernames[2];
	us_colormixdialogitems[43].msg = overlayernames[3];
	us_colormixdialogitems[44].msg = overlayernames[4];
	if (DiaInitDialog(&us_colormixdialog) != 0) return(0);
	for(i=0; i<5; i++) us_colormixnames[i] = overlayernames[i];
	DiaSetControl(39, 1);
	DiaSetControl(4, 1);
	us_colormixdrawpalette(&ra);
	DiaRedispRoutine(35, us_colormixdrawpalette);

	/* loop until done */
	colorchanged = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit >= 3 && itemHit <= 34)
		{
			/* hit on one of the 16 colors */
			us_colormixtogglemarker();
			for(i=4; i<=34; i += 2) DiaSetControl(i, 0);
			i = (itemHit + 1) / 2 * 2;
			DiaSetControl(i, 1);
			us_colormixtogglemarker();
			continue;
		}
		if (itemHit >= 39 && itemHit <= 45)
		{
			/* hit on one of the 7 palette sets */
			us_colormixtogglemarker();
			for(i=39; i<=45; i++) DiaSetControl(i, 0);
			DiaSetControl(itemHit, 1);
			us_colormixreload();
			us_colormixtogglemarker();
			continue;
		}
		if (itemHit == 35)
		{
			/* hit in the hue/saturation wheel */
			DiaGetMouse(&x, &y);
			DiaItemRect(35, &ra);
			cx = (ra.left + ra.right) / 2;
			cy = (ra.top + ra.bottom) / 2;
			us_colormixtogglemarker();
			us_colormixtheta = (float)((figureangle(cx, cy, x, y) + 5) / 10);
			if (us_colormixtheta < 0.0) us_colormixtheta += 360.0;
			us_colormixr = (float)sqrt((float)((y-cy)*(y-cy) + (x-cx)*(x-cx)));
			if (us_colormixr > WHEELEDGE) us_colormixr = WHEELEDGE;
			us_hsvtorgb(us_colormixtheta / 360.0f, us_colormixr / WHEELEDGE, us_colormixinten, &r,
				&g, &b);
			if (r == us_colormixredmap[us_colormixindex[us_colormixcurindex]] &&
				g == us_colormixgreenmap[us_colormixindex[us_colormixcurindex]] &&
				b == us_colormixbluemap[us_colormixindex[us_colormixcurindex]]) continue;
			colorchanged++;
			us_colormixredmap[us_colormixindex[us_colormixcurindex]] = r;
			us_colormixgreenmap[us_colormixindex[us_colormixcurindex]] = g;
			us_colormixbluemap[us_colormixindex[us_colormixcurindex]] = b;
			us_colormixtogglemarker();
			us_colormixdrawsquare(us_colormixcurindex);
			continue;
		}
		if (itemHit == 36)
		{
			/* hit in the intensity slider */
			DiaGetMouse(&x, &y);
			DiaItemRect(36, &ra);
			cx = (ra.left + ra.right) / 2;
			cy = (ra.top + ra.bottom) / 2;
			us_colormixtogglemarker();
			us_colormixinten = (float)(ra.bottom - y) / (float)(ra.bottom - ra.top);
			us_hsvtorgb(us_colormixtheta / 360.0f, us_colormixr / WHEELEDGE, us_colormixinten, &r,
				&g, &b);
			if (r == us_colormixredmap[us_colormixindex[us_colormixcurindex]] &&
				g == us_colormixgreenmap[us_colormixindex[us_colormixcurindex]] &&
				b == us_colormixbluemap[us_colormixindex[us_colormixcurindex]]) continue;
			colorchanged++;
			us_colormixredmap[us_colormixindex[us_colormixcurindex]] = r;
			us_colormixgreenmap[us_colormixindex[us_colormixcurindex]] = g;
			us_colormixbluemap[us_colormixindex[us_colormixcurindex]] = b;
			us_colormixtogglemarker();
			us_colormixdrawsquare(us_colormixcurindex);
			continue;
		}
		if (itemHit == 47)
		{
			/* recompute colors based on layer depth of primaries */
			us_colormixsmoothcolors();
			us_colormixreload();
			us_colormixtogglemarker();
			colorchanged++;
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* load the color map with the new values */
		if (colorchanged != 0)
		{
			startobjectchange((INTBIG)us_aid, VAID);
			(void)setvalkey((INTBIG)us_aid, VAID, us_colormap_red, (INTBIG)us_colormixredmap,
				VINTEGER|VISARRAY|(256<<VLENGTHSH));
			(void)setvalkey((INTBIG)us_aid, VAID, us_colormap_green, (INTBIG)us_colormixgreenmap,
				VINTEGER|VISARRAY|(256<<VLENGTHSH));
			(void)setvalkey((INTBIG)us_aid, VAID, us_colormap_blue, (INTBIG)us_colormixbluemap,
				VINTEGER|VISARRAY|(256<<VLENGTHSH));
			endobjectchange((INTBIG)us_aid, VAID);
		}
	}
	DiaDoneDialog();
	return(0);
}

void us_colormixsmoothcolors(void)
{
	INTBIG funct[5], height[5], bit[5], red[5], green[5], blue[5], fun,
		r, g, b, gotcol, i, j;
	char *lname[5], *name;

	/* get information about the current transparent layers */
	for(i=0; i<5; i++) funct[i] = -1;
	for(i=0; i<el_curtech->layercount; i++)
	{
		fun = layerfunction(el_curtech, (INTSML)i);
		name = layername(el_curtech, (INTSML)i);
		if ((fun&LFTRANS1) != 0 && funct[0] < 0) { funct[0] = fun;  lname[0] = name; }
		if ((fun&LFTRANS2) != 0 && funct[1] < 0) { funct[1] = fun;  lname[1] = name; }
		if ((fun&LFTRANS3) != 0 && funct[2] < 0) { funct[2] = fun;  lname[2] = name; }
		if ((fun&LFTRANS4) != 0 && funct[3] < 0) { funct[3] = fun;  lname[3] = name; }
		if ((fun&LFTRANS5) != 0 && funct[4] < 0) { funct[4] = fun;  lname[4] = name; }
	}
	bit[0] = LAYERT1;
	bit[1] = LAYERT2;
	bit[2] = LAYERT3;
	bit[3] = LAYERT4;
	bit[4] = LAYERT5;
	for(i=0; i<5; i++)
		height[i] = layerfunctionheight(funct[i]);

	/* sort the layers by height */
	j = 0;
	while (j == 0)
	{
		j = 1;
		for(i=1; i<5; i++)
		{
			if (height[i] <= height[i-1]) continue;
			fun = height[i];  height[i] = height[i-1];  height[i-1] = fun;
			fun = funct[i];   funct[i] = funct[i-1];    funct[i-1] = fun;
			fun = bit[i];     bit[i] = bit[i-1];        bit[i-1] = fun;
			j = 0;
		}
	}
	for(i=0; i<5; i++)
	{
		red[i] = us_colormixredmap[bit[i]];
		green[i] = us_colormixgreenmap[bit[i]];
		blue[i] = us_colormixbluemap[bit[i]];
	}

	/* now reconstruct the colors */
	for(i=0; i<256; i++)
	{
		if ((i&(LAYERH|LAYEROE|LAYERG)) != 0) continue;
		gotcol = 0;
		for(j=0; j<5; j++)
		{
			if ((i&bit[j]) == 0) continue;
			if (gotcol == 0)
			{
				r = red[j];   g = green[j];   b = blue[j];
				gotcol = 1;
			} else
			{
				us_colormixmergecolor(r, g, b, red[j], green[j], blue[j], &r, &g, &b);
			}
		}
		if (gotcol != 0)
		{
			us_colormixredmap[i] = r;
			us_colormixgreenmap[i] = g;
			us_colormixbluemap[i] = b;
		}
	}

#if 0		/* code to generate color map code */
	{
		FILE *io;
		INTBIG k;

		io = fopen("bettercolors.txt", "w");
		if (io == 0) return;
		fprintf(io, "static TECH_COLORMAP %s_colmap[32] =\n", el_curtech->techname);
		fprintf(io, "{                  /*     %s %s %s %s %s */\n", lname[4],
			lname[3], lname[2], lname[1], lname[0]);
		j = 0;
		for(i=0; i<256; i++)
		{
			if ((i&(LAYERH|LAYEROE|LAYERG)) != 0) continue;
			fprintf(io, "\t{%3d,%3d,%3d}", us_colormixredmap[i],
				us_colormixgreenmap[i], us_colormixbluemap[i]);
			if (j != 31) fprintf(io, ","); else fprintf(io, " ");
			fprintf(io, " /* %2d: ", j);
			if ((i&LAYERT5) != 0) fprintf(io, "%s ", lname[4]); else
				for(k=0; k<=(INTBIG)strlen(lname[4]); k++) fprintf(io, " ");
			if ((i&LAYERT4) != 0) fprintf(io, "%s ", lname[3]); else
				for(k=0; k<=(INTBIG)strlen(lname[3]); k++) fprintf(io, " ");
			if ((i&LAYERT3) != 0) fprintf(io, "%s ", lname[2]); else
				for(k=0; k<=(INTBIG)strlen(lname[2]); k++) fprintf(io, " ");
			if ((i&LAYERT2) != 0) fprintf(io, "%s ", lname[1]); else
				for(k=0; k<=(INTBIG)strlen(lname[1]); k++) fprintf(io, " ");
			if ((i&LAYERT1) != 0) fprintf(io, "%s ", lname[0]); else
				for(k=0; k<=(INTBIG)strlen(lname[0]); k++) fprintf(io, " ");
			fprintf(io, "*/\n");
			j++;
		}
		fprintf(io, "};\n");
		fclose(io);
	}
#endif
}

void us_colormixmergecolor(INTBIG r1, INTBIG g1, INTBIG b1, INTBIG r2, INTBIG g2, INTBIG b2,
	INTBIG *ro, INTBIG *go, INTBIG *bo)
{
	float f1[3], f2[3], f3[3];

	f1[0] = r1 / 255.0f;
	f1[1] = g1 / 255.0f;
	f1[2] = b1 / 255.0f;
	vectornormalize3d(f1);
	vectormultiply3d(f1, 1.0f, f1);

	f2[0] = r2 / 255.0f;
	f2[1] = g2 / 255.0f;
	f2[2] = b2 / 255.0f;
	vectornormalize3d(f2);
	vectormultiply3d(f2, 0.5f, f2);

	vectoradd3d(f1, f2, f3);
	vectornormalize3d(f3);

	*ro = (INTBIG)(f3[0] * 255.0);
	*go = (INTBIG)(f3[1] * 255.0);
	*bo = (INTBIG)(f3[2] * 255.0);
}

/* Routine to draw the hue/saturation wheel and the intensity slider */
void us_colormixdrawpalette(RECTAREA *ra)
{
	REGISTER INTBIG theta, inc, rr, cx, cy, i, col, spacing;
	INTBIG r, g, b, x[4], y[4];
	RECTAREA rect, stripe;
	float intermed, intertwo;

	/* draw hue/saturation wheel */
	DiaItemRect(35, &rect);
	cx = (rect.left + rect.right) / 2;
	cy = (rect.top + rect.bottom) / 2;
	for(theta=0; theta<360; theta+=60)
	{
		for(inc=0; inc<60; inc+=20)
			for(rr = 0; rr < WHEELRADIUS/2; rr += WHEELRADIUS/8)
		{
			intermed = (float) theta + inc;
			intertwo = (float) rr + WHEELRADIUS/8;
			x[0] = (INTBIG)(((float)rr) * cos(intermed*DEGTORAD)) + cx;
			y[0] = (INTBIG)(((float)rr) * sin(intermed*DEGTORAD)) + cy;
			x[1] = (INTBIG)(intertwo * cos(intermed*DEGTORAD)) + cx;
			y[1] = (INTBIG)(intertwo * sin(intermed*DEGTORAD)) + cy;
			intermed += 21.0;
			x[2] = (INTBIG)(intertwo * cos(intermed*DEGTORAD)) + cx;
			y[2] = (INTBIG)(intertwo * sin(intermed*DEGTORAD)) + cy;
			x[3] = (INTBIG)(((float)rr) * cos(intermed*DEGTORAD)) + cx;
			y[3] = (INTBIG)(((float)rr) * sin(intermed*DEGTORAD)) + cy;
			us_hsvtorgb(((float)(theta+inc+10)) / 360.0f,
				((float)rr+WHEELRADIUS/16) / WHEELRADIUS, 1.0f, &r, &g, &b);
			DiaFillPoly(35, x, y, 4, r, g, b);
		}
		for(inc=0; inc<60; inc+=10)
			for(rr = WHEELRADIUS/8; rr < WHEELRADIUS; rr += WHEELRADIUS/8)
		{
			intermed = (float) theta + inc;
			intertwo = (float) rr + WHEELRADIUS/8;
			x[0] = (INTBIG)(((float)rr)* cos(intermed*DEGTORAD)) + cx;
			y[0] = (INTBIG)(((float)rr)* sin(intermed*DEGTORAD)) + cy;
			x[1] = (INTBIG)(intertwo * cos(intermed*DEGTORAD)) + cx;
			y[1] = (INTBIG)(intertwo * sin(intermed*DEGTORAD)) + cy;
			intermed += 12.0;
			x[2] = (INTBIG)(intertwo * cos(intermed*DEGTORAD)) + cx;
			y[2] = (INTBIG)(intertwo * sin(intermed*DEGTORAD)) + cy;
			x[3] = (INTBIG)(((float)rr) * cos(intermed*DEGTORAD)) + cx;
			y[3] = (INTBIG)(((float)rr) * sin(intermed*DEGTORAD)) + cy;
			us_hsvtorgb(((float)(theta+inc+5)) / 360.0f,
				((float)rr+WHEELRADIUS/16) / WHEELRADIUS, 1.0f, &r, &g, &b);
			DiaFillPoly(35, x, y, 4, r, g, b);
		}
	}

	/* draw the intensity slider */
	DiaItemRect(36, &rect);
	rect.left--;   rect.right++;
	rect.top--;    rect.bottom++;
	DiaFrameRect(36, &rect);
	rect.left++;   rect.right--;
	rect.top++;    rect.bottom--;
	spacing = (rect.bottom - rect.top) / INTENSITYDIVISIONS;
	for(i=0; i<INTENSITYDIVISIONS; i++)
	{
		stripe.left = rect.left;
		stripe.right = rect.right;
		stripe.top = (INTSML)(rect.bottom - (i+1)*spacing);
		stripe.bottom = (INTSML)(rect.bottom - i*spacing);
		col = i * 255 / INTENSITYDIVISIONS;
		DiaDrawRect(36, &stripe, col, col, col);
	}

	/* draw the current color marker */
	us_colormixtogglemarker();
	us_colormixreload();
}

/*
 * Routine to draw an "x" on the hue/saturation wheel and the intensity slider
 * to indicate the current color.
 */
void us_colormixtogglemarker(void)
{
	REGISTER INTBIG r, g, b, cx, cy, x, y;
	RECTAREA rect;

	/* get the current color */
	for(us_colormixcurindex=0; us_colormixcurindex<16; us_colormixcurindex++)
		if (DiaGetControl(us_colormixcurindex*2+4) != 0) break;
	r = us_colormixredmap[us_colormixindex[us_colormixcurindex]];
	g = us_colormixgreenmap[us_colormixindex[us_colormixcurindex]];
	b = us_colormixbluemap[us_colormixindex[us_colormixcurindex]];
	us_rgbtohsv((INTSML)r, (INTSML)g, (INTSML)b, &us_colormixtheta, &us_colormixr, &us_colormixinten);
	us_colormixtheta *= 360.0;
	us_colormixr *= WHEELEDGE;

	/* show the position in the hue/saturation area */
	DiaItemRect(35, &rect);
	cx = (rect.left + rect.right) / 2;
	cy = (rect.top + rect.bottom) / 2;
	x = (INTBIG)(us_colormixr * cos(us_colormixtheta * DEGTORAD)) + cx;
	y = (INTBIG)(us_colormixr * sin(us_colormixtheta * DEGTORAD)) + cy;
	DiaDrawLine(35, x-5, y-5, x+5, y+5, DLMODEINVERT);
	DiaDrawLine(35, x-5, y+5, x+5, y-5, DLMODEINVERT);

	/* show the position in the intensity area */
	DiaItemRect(36, &rect);
	cx = (rect.left + rect.right) / 2;
	y = rect.bottom - (INTBIG)(us_colormixinten * (float)(rect.bottom - rect.top));
	DiaDrawLine(36, cx-5, y-5, cx+5, y+5, DLMODEINVERT);
	DiaDrawLine(36, cx-5, y+5, cx+5, y-5, DLMODEINVERT);
}

/*
 * Routine to reload the 16 color entries according to the selected palette set.
 */
void us_colormixreload(void)
{
	INTBIG i;

	if (DiaGetControl(39) != 0)
	{
		us_colormixindex[0]  = ALLOFF;
		us_colormixindex[1]  = LAYERT1;
		us_colormixindex[2]  = LAYERT2;
		us_colormixindex[3]  = LAYERT3;
		us_colormixindex[4]  = LAYERT4;
		us_colormixindex[5]  = LAYERT5;
		us_colormixindex[6]  = LAYERT1 | LAYERT2;
		us_colormixindex[7]  = LAYERT1 | LAYERT3;
		us_colormixindex[8]  = LAYERT1 | LAYERT4;
		us_colormixindex[9]  = LAYERT1 | LAYERT5;
		us_colormixindex[10] = LAYERT2 | LAYERT3;
		us_colormixindex[11] = LAYERT2 | LAYERT4;
		us_colormixindex[12] = LAYERT2 | LAYERT5;
		us_colormixindex[13] = LAYERT3 | LAYERT4;
		us_colormixindex[14] = LAYERT3 | LAYERT5;
		us_colormixindex[15] = LAYERT4 | LAYERT5;
	}
	if (DiaGetControl(40) != 0)
	{
		us_colormixindex[0]  = ALLOFF;
		us_colormixindex[1]  = GRID;
		us_colormixindex[2]  = HIGHLIT;
		us_colormixindex[3]  = el_colfacettxt;
		us_colormixindex[4]  = el_colfacet;
		us_colormixindex[5]  = el_colwinbor;
		us_colormixindex[6]  = el_colhwinbor;
		us_colormixindex[7]  = el_colmenbor;
		us_colormixindex[8]  = el_colhmenbor;
		us_colormixindex[9]  = el_colmentxt;
		us_colormixindex[10] = el_colmengly;
		us_colormixindex[11] = el_colcursor;
		us_colormixindex[12] = 0354;
		us_colormixindex[13] = 0364;
		us_colormixindex[14] = 0374;
		us_colormixindex[15] = ALLOFF;
	}
	if (DiaGetControl(41) != 0)
		us_colormixbuildindex(LAYERT1, LAYERT2, LAYERT3, LAYERT4, LAYERT5);
	if (DiaGetControl(42) != 0)
		us_colormixbuildindex(LAYERT2, LAYERT1, LAYERT3, LAYERT4, LAYERT5);
	if (DiaGetControl(43) != 0)
		us_colormixbuildindex(LAYERT3, LAYERT1, LAYERT2, LAYERT4, LAYERT5);
	if (DiaGetControl(44) != 0)
		us_colormixbuildindex(LAYERT4, LAYERT1, LAYERT2, LAYERT3, LAYERT5);
	if (DiaGetControl(45) != 0)
		us_colormixbuildindex(LAYERT5, LAYERT1, LAYERT2, LAYERT3, LAYERT4);
	for(i=0; i<16; i++)
	{
		DiaSetText(i*2+4, us_colormixentryname(us_colormixnames, us_colormixindex[i]));
		us_colormixdrawsquare(i);
	}
}

/*
 * Routine to build the entries desired given the five layers "layer1-5".
 */
void us_colormixbuildindex(INTBIG layer1, INTBIG layer2, INTBIG layer3, INTBIG layer4, INTBIG layer5)
{
	us_colormixindex[0]  = layer1;
	us_colormixindex[1]  = layer1 | layer2;
	us_colormixindex[2]  = layer1 |          layer3;
	us_colormixindex[3]  = layer1 | layer2 | layer3;
	us_colormixindex[4]  = layer1 |                   layer4;
	us_colormixindex[5]  = layer1 | layer2 |          layer4;
	us_colormixindex[6]  = layer1 |          layer3 | layer4;
	us_colormixindex[7]  = layer1 | layer2 | layer3 | layer4;
	us_colormixindex[8]  = layer1 |                            layer5;
	us_colormixindex[9]  = layer1 | layer2 |                   layer5;
	us_colormixindex[10] = layer1 |          layer3 |          layer5;
	us_colormixindex[11] = layer1 | layer2 | layer3 |          layer5;
	us_colormixindex[12] = layer1 |                   layer4 | layer5;
	us_colormixindex[13] = layer1 | layer2 |          layer4 | layer5;
	us_colormixindex[14] = layer1 |          layer3 | layer4 | layer5;
	us_colormixindex[15] = layer1 | layer2 | layer3 | layer4 | layer5;
}

/*
 * Routine to redraw color square "sindex" from the current settings.
 */
void us_colormixdrawsquare(INTBIG sindex)
{
	RECTAREA r;

	DiaItemRect(sindex*2+3, &r);
	r.left--;   r.right++;
	r.top--;    r.bottom++;
	DiaFrameRect(sindex*2+3, &r);
	r.left++;   r.right--;
	r.top++;    r.bottom--;
	DiaDrawRect(sindex*2+3, &r, us_colormixredmap[us_colormixindex[sindex]],
		us_colormixgreenmap[us_colormixindex[sindex]], us_colormixbluemap[us_colormixindex[sindex]]);
}

/*
 * Routine to construct the name of color map entry "ind", given the transparent layer names in "overlayernames".
 */
char *us_colormixentryname(char *overlayernames[], INTBIG ind)
{
	INTBIG gotname;

	if (ind == ALLOFF) return(_("Background"));
	if (ind == GRID) return(_("Grid"));
	if (ind == HIGHLIT) return(_("Highlight"));
	if (ind == 0354) return(_("Extra 1"));
	if (ind == 0364) return(_("Extra 2"));
	if (ind == 0374) return(_("Extra 3"));
	if (ind == el_colfacettxt) return(_("Facet Name"));
	if (ind == el_colfacet) return(_("Facet Outline"));
	if (ind == el_colwinbor) return(_("Window Border"));
	if (ind == el_colhwinbor) return(_("Current Window Border"));
	if (ind == el_colmenbor) return(_("Component Menu Border"));
	if (ind == el_colhmenbor) return(_("Highlighted Component Menu Border"));
	if (ind == el_colmentxt) return(_("Text in Component Menu"));
	if (ind == el_colmengly) return(_("Glyphs in Component Menu"));
	if (ind == el_colcursor) return(_("Cursor"));
	(void)initinfstr();
	gotname = 0;
	if ((ind&LAYERT1) != 0)
	{
		if (gotname != 0) (void)addstringtoinfstr(", ");
		(void)addstringtoinfstr(overlayernames[0]);
		gotname = 1;
	}
	if ((ind&LAYERT2) != 0)
	{
		if (gotname != 0) (void)addstringtoinfstr(", ");
		(void)addstringtoinfstr(overlayernames[1]);
		gotname = 1;
	}
	if ((ind&LAYERT3) != 0)
	{
		if (gotname != 0) (void)addstringtoinfstr(", ");
		(void)addstringtoinfstr(overlayernames[2]);
		gotname = 1;
	}
	if ((ind&LAYERT4) != 0)
	{
		if (gotname != 0) (void)addstringtoinfstr(", ");
		(void)addstringtoinfstr(overlayernames[3]);
		gotname = 1;
	}
	if ((ind&LAYERT5) != 0)
	{
		if (gotname != 0) (void)addstringtoinfstr(", ");
		(void)addstringtoinfstr(overlayernames[4]);
	}
	return(returninfstr());
}

/****************************** COMPONENT MENU DIALOG ******************************/

/* Component Menu */
DIALOGITEM us_menuposdialogitems[] =
{
 /*  1 */ {0, {128,168,152,232}, BUTTON, N_("OK")},
 /*  2 */ {0, {88,168,112,232}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,200,48,248}, EDITTEXT, ""},
 /*  4 */ {0, {64,8,80,136}, RADIO, N_("Menu at Top")},
 /*  5 */ {0, {88,8,104,136}, RADIO, N_("Menu at Bottom")},
 /*  6 */ {0, {112,8,128,136}, RADIO, N_("Menu on Left")},
 /*  7 */ {0, {136,8,152,136}, RADIO, N_("Menu on Right")},
 /*  8 */ {0, {8,8,24,197}, MESSAGE, N_("Number of Entries Across:")},
 /*  9 */ {0, {32,8,48,197}, MESSAGE, N_("Number of Entries Down:")},
 /* 10 */ {0, {8,200,24,248}, EDITTEXT, ""},
 /* 11 */ {0, {160,8,176,100}, RADIO, N_("No Menu")}
};
DIALOG us_menuposdialog = {{50,75,235,334}, N_("Component Menu Configuration"), 0, 11, us_menuposdialogitems};

/*
 * special case for the "menu" dialog
 * Menus at top    = 4 (radio)
 * Menus at bottom = 5 (radio)
 * Menus at left   = 6 (radio)
 * Menus at right  = 7 (radio)
 * No menu         = 11 (radio)
 * Across label    = 8 (message)
 * Down label      = 9 (message)
 * Across          = 10 (edit text)
 * Down            = 3 (edit text)
 */
INTSML us_menudlog(char *paramstart[])
{
	INTBIG itemHit, large, smallf;
	char amt[10];

	/* display the array dialog box */
	if (DiaInitDialog(&us_menuposdialog) != 0) return(0);
	if ((us_aid->aidstate&MENUON) == 0)
	{
		DiaSetControl(11, 1);
		DiaNoEditControl(3);
		DiaNoEditControl(10);
		DiaDimItem(8);
		DiaDimItem(9);
	} else
	{
		switch (us_menupos)
		{
			case 0: DiaSetControl(4, 1);   break;
			case 1: DiaSetControl(5, 1);   break;
			case 2: DiaSetControl(6, 1);   break;
			case 3: DiaSetControl(7, 1);   break;
		}
		DiaEditControl(3);
		DiaEditControl(10);
		DiaUnDimItem(8);
		DiaUnDimItem(9);
	}
	if (us_menux < us_menuy) { large = us_menuy;   smallf = us_menux; } else
		{ large = us_menux;   smallf = us_menuy; }
	if (us_menupos <= 1)
	{
		(void)sprintf(amt, "%d", large);
		DiaSetText(10, amt);
		(void)sprintf(amt, "%d", smallf);
		DiaSetText(3, amt);
	} else
	{
		(void)sprintf(amt, "%d", smallf);
		DiaSetText(10, amt);
		(void)sprintf(amt, "%d", large);
		DiaSetText(3, amt);
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(10) && DiaValidEntry(3)) break;
		if (itemHit == 4 || itemHit == 5 || itemHit == 6 || itemHit == 7 || itemHit == 11)
		{
			DiaSetControl(4, 0);
			DiaSetControl(5, 0);
			DiaSetControl(6, 0);
			DiaSetControl(7, 0);
			DiaSetControl(11, 0);
			DiaSetControl(itemHit, 1);
			if (itemHit == 11)
			{
				DiaNoEditControl(3);
				DiaNoEditControl(10);
				DiaDimItem(8);
				DiaDimItem(9);
			} else
			{
				DiaEditControl(3);
				DiaEditControl(10);
				DiaUnDimItem(8);
				DiaUnDimItem(9);
			}
		}
	}

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		(void)initinfstr();
		if (DiaGetControl(11) != 0) (void)addstringtoinfstr("off"); else
		{
			if (DiaGetControl(4) != 0) (void)addstringtoinfstr("top");
			if (DiaGetControl(5) != 0) (void)addstringtoinfstr("bottom");
			if (DiaGetControl(6) != 0) (void)addstringtoinfstr("left");
			if (DiaGetControl(7) != 0) (void)addstringtoinfstr("right");
			(void)addstringtoinfstr(" size ");
			(void)addstringtoinfstr(DiaGetText(10));
			(void)addtoinfstr(' ');
			(void)addstringtoinfstr(DiaGetText(3));
		}
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(1);
}

/****************************** CREATE TO DIALOG ******************************/

/* Create To */
DIALOGITEM us_createtodialogitems[] =
{
 /*  1 */ {0, {64,96,88,160}, BUTTON, N_("OK")},
 /*  2 */ {0, {64,8,88,72}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,48,24,142}, EDITTEXT, ""},
 /*  4 */ {0, {8,20,24,42}, MESSAGE, N_("X:")},
 /*  5 */ {0, {32,48,48,142}, EDITTEXT, ""},
 /*  6 */ {0, {32,20,48,42}, MESSAGE, N_("Y:")}
};
DIALOG us_createtodialog = {{50,75,147,244}, N_("Create At Location"), 0, 6, us_createtodialogitems};

/*
 * special case for the "Create To" dialog
 * X coordinate     = 3 (edit text)
 * Y coordinate     = 5 (edit text)
 */
INTSML us_createtodlog(char *paramstart[])
{
	INTBIG itemHit;
	INTBIG x, y;

	/* determine default location (use snap point if there is one) */
	if (us_getonesnappoint(&x, &y) == 0) x = y = 0;

	/* get coordinates from dialog */
	if (DiaInitDialog(&us_createtodialog) != 0) return(0);
	DiaSetText(3, latoa(x));
	DiaSetText(5, latoa(y));
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
	}
	paramstart[0] = us_putintoinfstr(DiaGetText(3));
	paramstart[1] = us_putintoinfstr(DiaGetText(5));
	DiaDoneDialog();
	if (itemHit == CANCEL) return(0);
	return(2);
}

/****************************** CROSS-LIBRARY COPY DIALOG ******************************/

/* Copy between libraries */
DIALOGITEM us_copyfacetdialogitems[] =
{
 /*  1 */ {0, {340,168,364,240}, BUTTON, N_("Done")},
 /*  2 */ {0, {8,8,24,207}, POPUP, ""},
 /*  3 */ {0, {312,40,336,112}, BUTTON, N_("<< Copy")},
 /*  4 */ {0, {312,296,336,368}, BUTTON, N_("Copy >>")},
 /*  5 */ {0, {32,8,268,408}, SCROLL, ""},
 /*  6 */ {0, {8,209,24,408}, POPUP, ""},
 /*  7 */ {0, {272,8,288,191}, BUTTON, N_("Examine contents")},
 /*  8 */ {0, {292,8,304,407}, MESSAGE, ""},
 /*  9 */ {0, {272,224,288,407}, BUTTON, N_("Examine contents quietly")},
 /* 10 */ {0, {312,136,328,276}, CHECK, N_("Delete after copy")}
};
DIALOG us_copyfacetdialog = {{50,75,423,492}, N_("Cross-Library Copy"), 0, 10, us_copyfacetdialogitems};

INTBIG us_loadlibraryfacets(LIBRARY *lib, LIBRARY *otherlib, INTBIG examinecontents);
INTSML us_facetexists(NODEPROTO *facet);

/*
 * special case for the "copyfacet" dialog
 * First library            = 2 (popup)
 * << Copy                  = 3 (button)
 * Copy >>                  = 4 (button)
 * Facet list               = 5 (scroll list)
 * Other library            = 6 (popup)
 * Examine contents         = 7 (button)
 * contents footnote        = 8 (stat text)
 * Examine contents quietly = 9 (button)
 * Delete after copy        = 10 (check)
 */
INTSML us_copyfacetdlog(char *prompt)
{
	INTBIG itemHit, libcount, i, len, libindex, otherlibindex, examinecontents;
	char *lastfacetname, *param0, *param1, *newparam[5];
	REGISTER INTSML ac;
	REGISTER INTBIG charpos;
	REGISTER LIBRARY *lib, *otherlib, *olib;
	REGISTER char **liblist, *pt;
	REGISTER WINDOWPART *w;

	/* see how many libraries should be in the popups */
	libcount = 0;
	lib = el_curlib;   otherlib = NOLIBRARY;
	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
	{
		if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
		libcount++;
		if (olib != lib && otherlib == NOLIBRARY) otherlib = olib;
	}
	if (libcount < 2)
	{
		ttyputerr(_("There must be two libraries read in before copying between them"));
		return(0);
	}

	/* see if the initial library is specified */
	if (*prompt == '!')
	{
		olib = getlibrary(&prompt[1]);
		if (olib != NOLIBRARY && olib != lib)
			otherlib = olib;
	}

	/* load up list of libraries */
	liblist = (char **)emalloc(libcount * (sizeof (char *)), el_tempcluster);
	if (liblist == 0) return(0);
	for(olib = el_curlib, i=0; olib != NOLIBRARY; olib = olib->nextlibrary)
	{
		if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
		liblist[i] = olib->libname;
		if (olib == lib) libindex = i;
		if (olib == otherlib) otherlibindex = i;
		i++;
	}
	libcount = i;

	/* display the copyfacet dialog box */
	if (DiaInitDialog(&us_copyfacetdialog) != 0)
	{
		efree((char *)liblist);
		return(0);
	}
	DiaSetPopup(2, libcount, liblist);
	DiaSetPopupEntry(2, libindex);
	DiaSetPopup(6, libcount, liblist);
	DiaSetPopupEntry(6, otherlibindex);

	DiaInitTextDialog(5, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCREPORT|SCSELMOUSE|SCDOUBLEQUIT|SCSMALLFONT|SCFIXEDWIDTH|SCHORIZBAR);
	examinecontents = 0;
	charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK) break;
		if (itemHit == 10)
		{
			i = 1 - DiaGetControl(itemHit);
			DiaSetControl(itemHit, i);
			if (i == 0)
			{
				DiaSetText(3, _("<< Copy"));
				DiaSetText(4, _("Copy >>"));
			} else
			{
				DiaSetText(3, _("<< Move"));
				DiaSetText(4, _("Move >>"));
			}
			continue;
		}
		if (itemHit == 3)
		{
			/* copy into the current library ("<< Copy/Move") */
			i = DiaGetCurLine(5);
			if (i < 0) continue;
			pt = DiaGetScrollLine(5, i);
			if (pt[charpos] == 0) continue;
			allocstring(&lastfacetname, &pt[charpos], el_tempcluster);

			(void)initinfstr();
			(void)addstringtoinfstr(otherlib->libname);
			(void)addtoinfstr(':');
			(void)addstringtoinfstr(lastfacetname);
			allocstring(&param0, returninfstr(), el_tempcluster);
			ac = 0;
			newparam[ac++] = param0;

			(void)initinfstr();
			(void)addstringtoinfstr(lib->libname);
			(void)addtoinfstr(':');
			for(i=0; lastfacetname[i] != 0; i++)
			{
				if (lastfacetname[i] == '{' || lastfacetname[i] == ';') break;
				(void)addtoinfstr(lastfacetname[i]);
			}
			allocstring(&param1, returninfstr(), el_tempcluster);
			newparam[ac++] = param1;

			/* do the copy */
			if (DiaGetControl(10) != 0) newparam[ac++] = "move";
			us_copyfacet(ac, newparam);
			efree(param0);
			efree(param1);

			/* reload the dialog */
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);

			/* reselect the last selected line */
			len = strlen(lastfacetname);
			for(i=0; ; i++)
			{
				pt = DiaGetScrollLine(5, i);
				while (*pt == ' ') pt++;
				if (*pt == 0) break;
				if (strncmp(lastfacetname, pt, len) != 0) continue;
				DiaSelectLine(5, i);
				break;
			}
			efree(lastfacetname);
			continue;
		}
		if (itemHit == 4)
		{
			/* copy out of the current library ("Copy/Move >>") */
			i = DiaGetCurLine(5);
			if (i < 0) continue;
			pt = DiaGetScrollLine(5, i);
			if (*pt == 0) continue;
			(void)initinfstr();
			for(i=0; i<charpos-9; i++)
			{
				if (pt[i] == ' ') break;
				(void)addtoinfstr(pt[i]);
			}
			allocstring(&lastfacetname, returninfstr(), el_tempcluster);

			(void)initinfstr();
			(void)addstringtoinfstr(lib->libname);
			(void)addtoinfstr(':');
			(void)addstringtoinfstr(lastfacetname);
			allocstring(&param0, returninfstr(), el_tempcluster);
			ac = 0;
			newparam[ac++] = param0;

			(void)initinfstr();
			(void)addstringtoinfstr(otherlib->libname);
			(void)addtoinfstr(':');
			for(i=0; lastfacetname[i] != 0; i++)
			{
				if (lastfacetname[i] == '{' || lastfacetname[i] == ';') break;
				(void)addtoinfstr(lastfacetname[i]);
			}
			allocstring(&param1, returninfstr(), el_tempcluster);
			newparam[ac++] = param1;

			/* do the copy/move */
			if (DiaGetControl(10) != 0) newparam[ac++] = "move";
			us_copyfacet(ac, newparam);
			efree(param0);
			efree(param1);

			/* reload the dialog */
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);

			/* reselect the last selected line */
			len = strlen(lastfacetname);
			for(i=0; ; i++)
			{
				pt = DiaGetScrollLine(5, i);
				while (*pt == ' ') pt++;
				if (*pt == 0) break;
				if (strncmp(lastfacetname, pt, len) != 0) continue;
				DiaSelectLine(5, i);
				break;
			}
			efree(lastfacetname);
			continue;
		}
		if (itemHit == 2)
		{
			/* selected different left-hand library */
			i = DiaGetPopupEntry(2);
			olib = getlibrary(liblist[i]);
			if (olib == NOLIBRARY) continue;
			lib = olib;
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);
			continue;
		}
		if (itemHit == 6)
		{
			/* selected different right-hand library */
			i = DiaGetPopupEntry(6);
			olib = getlibrary(liblist[i]);
			if (olib == NOLIBRARY) continue;
			otherlib = olib;
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);
			continue;
		}
		if (itemHit == 7)
		{
			/* examine contents */
			examinecontents = 1;
			DiaDimItem(7);
			DiaDimItem(9);

			/* reload the dialog */
			i = DiaGetCurLine(5);
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);
			DiaSelectLine(5, i);
			continue;
		}
		if (itemHit == 9)
		{
			/* examine contents quietly */
			examinecontents = -1;
			DiaDimItem(7);
			DiaDimItem(9);

			/* reload the dialog */
			i = DiaGetCurLine(5);
			charpos = us_loadlibraryfacets(lib, otherlib, examinecontents);
			DiaSelectLine(5, i);
			continue;
		}
	}

	DiaDoneDialog();
	efree((char *)liblist);

	/* validate all windows */
	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
	{
		if (w->curnodeproto == NONODEPROTO) continue;
		if (us_facetexists(w->curnodeproto) != 0) continue;

		/* window no longer valid */
		us_clearwindow(w);
	}
	if (el_curlib->curnodeproto != NONODEPROTO)
	{
		if (us_facetexists(el_curlib->curnodeproto) == 0)
			(void)setval((INTBIG)el_curlib, VLIBRARY, "curnodeproto",
				(INTBIG)NONODEPROTO, VNODEPROTO);
	}

	/* update status display if necessary */
	if (us_curnodeproto != NONODEPROTO && us_curnodeproto->primindex == 0 &&
		us_facetexists(us_curnodeproto) == 0)
	{
		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO); else
			us_setnodeproto(el_curtech->firstnodeproto);
	}
	return(0);
}

/*
 * Routine to return nonzero if facet "facet" exists in a library somewhere.
 */
INTSML us_facetexists(NODEPROTO *facet)
{
	REGISTER LIBRARY *lib;
	REGISTER NODEPROTO *np;

	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
	{
		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			if (np == facet) return(1);
	}
	return(0);
}

/*
 * Routine to compare the two libraries "lib" and "otherlib" and list their facets in
 * the cross-library copy dialog.  If "examinecontents" is nonzero, compare facet
 * contents when their dates don't match (if negative, do so quietly).
 */
INTBIG us_loadlibraryfacets(LIBRARY *lib, LIBRARY *otherlib, INTBIG examinecontents)
{
	REGISTER NODEPROTO *np, **curnp, **othernp, *curf, *otherf;
	REGISTER INTBIG i, j, sorted, len, widest, curcount, othercount, curpos, otherpos, op;
	REGISTER char *pt, **curnames, **othernames;
	REGISTER LIBRARY *oldlib;

	if (examinecontents != 0) DiaSetText(8, _("Examining contents..."));
	DiaLoadTextDialog(5, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);

	/* gather a list of facet names in "lib" */
	curcount = 0;
	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		curcount++;
	if (curcount > 0)
	{
		curnames = (char **)emalloc(curcount * (sizeof (char *)), el_tempcluster);
		curnp = (NODEPROTO **)emalloc(curcount * (sizeof (NODEPROTO *)), el_tempcluster);
		oldlib = el_curlib;   el_curlib = lib;
		for(i=0, np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto, i++)
		{
			curnp[i] = np;
			(void)allocstring(&curnames[i], describenodeproto(np), el_tempcluster);
		}
		el_curlib = oldlib;
	}

	/* gather a list of facet names in "otherlib" */
	othercount = 0;
	for(np = otherlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		othercount++;
	if (othercount > 0)
	{
		othernames = (char **)emalloc(othercount * (sizeof (char *)), el_tempcluster);
		othernp = (NODEPROTO **)emalloc(othercount * (sizeof (NODEPROTO *)), el_tempcluster);
		oldlib = el_curlib;   el_curlib = otherlib;
		for(i=0, np = otherlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto, i++)
		{
			othernp[i] = np;
			(void)allocstring(&othernames[i], describenodeproto(np), el_tempcluster);
		}
		el_curlib = oldlib;
	}

	/* sort the list of names in the current library */
	sorted = 0;
	while (sorted == 0)
	{
		sorted = 1;
		for(i=1; i<curcount; i++)
		{
			j = namesame(curnames[i-1], curnames[i]);
			if (j < 0) continue;
			pt = curnames[i-1];   curnames[i-1] = curnames[i];   curnames[i] = pt;
			np = curnp[i-1];      curnp[i-1] = curnp[i];         curnp[i] = np;
			sorted = 0;
		}
	}

	/* sort the list of names in the other library */
	sorted = 0;
	while (sorted == 0)
	{
		sorted = 1;
		for(i=1; i<othercount; i++)
		{
			j = namesame(othernames[i-1], othernames[i]);
			if (j < 0) continue;
			pt = othernames[i-1];   othernames[i-1] = othernames[i];   othernames[i] = pt;
			np = othernp[i-1];      othernp[i-1] = othernp[i];         othernp[i] = np;
			sorted = 0;
		}
	}

	/* determine the widest facet name in the current library */
	widest = 0;
	for(i=0; i<curcount; i++)
	{
		len = strlen(curnames[i]);
		if (len > widest) widest = len;
	}
	widest += 9;

	/* put out the parallel list of facets in the two libraries */
	curpos = otherpos = 0;
	for(;;)
	{
		if (curpos >= curcount && otherpos >= othercount) break;
		if (curpos >= curcount) op = 2; else
			if (otherpos >= othercount) op = 1; else
		{
			curf = curnp[curpos];
			otherf = othernp[otherpos];
			j = namesame(curnames[curpos], othernames[otherpos]);
			if (j < 0) op = 1; else
				if (j > 0) op = 2; else
					op = 3;
		}

		(void)initinfstr();
		if (op == 1 || op == 3)
		{
			pt = curnames[curpos++];
			(void)addstringtoinfstr(pt);
		} else pt = "";

		if (op == 3)
		{
			for(i = strlen(pt); i<widest-9; i++) (void)addtoinfstr(' ');
			if (curf->revisiondate < otherf->revisiondate)
			{
				if (examinecontents != 0)
				{
					if (us_samecontents(curf, otherf, examinecontents) != 0)
						(void)addstringtoinfstr(_(" <-OLD   ")); else
							(void)addstringtoinfstr(_(" <-OLD*  "));
				} else (void)addstringtoinfstr(_(" <-OLD   "));
			} else if (curf->revisiondate > otherf->revisiondate)
			{
				if (examinecontents != 0)
				{
					if (us_samecontents(curf, otherf, examinecontents) != 0)
						(void)addstringtoinfstr(_("   OLD-> ")); else
							(void)addstringtoinfstr(_("  *OLD-> "));
				} else (void)addstringtoinfstr(_("   OLD-> "));
			} else
			{
				(void)addstringtoinfstr(_(" -EQUAL- "));
			}
		} else
		{
			for(i = strlen(pt); i<widest; i++) (void)addtoinfstr(' ');
		}

		if (op == 2 || op == 3)
		{
			pt = othernames[otherpos++];
			(void)addstringtoinfstr(pt);
		}
		DiaStuffLine(5, returninfstr());
	}
	DiaSelectLine(5, 0);

	/* clean up */
	for(i=0; i<curcount; i++) efree(curnames[i]);
	if (curcount > 0)
	{
		efree((char *)curnames);
		efree((char *)curnp);
	}
	for(i=0; i<othercount; i++) efree(othernames[i]);
	if (othercount > 0)
	{
		efree((char *)othernames);
		efree((char *)othernp);
	}
	if (examinecontents != 0) DiaSetText(8, _("* contents differ"));
	return(widest);
}

/****************************** FACET EDIT/CREATE DIALOGS ******************************/

/* Edit facet */
DIALOGITEM us_editfacetdialoglist[] =
{
 /*  1 */ {0, {292,208,316,272}, BUTTON, N_("OK")},
 /*  2 */ {0, {292,16,316,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,8,208,281}, SCROLL, ""},
 /*  4 */ {0, {216,8,232,153}, CHECK, N_("Show Old Versions")},
 /*  5 */ {0, {264,8,280,231}, CHECK, N_("Make New Window for Facet")},
 /*  6 */ {0, {292,104,316,187}, BUTTON, N_("New Facet")},
 /*  7 */ {0, {8,8,24,67}, MESSAGE, N_("Library:")},
 /*  8 */ {0, {8,72,24,280}, POPUP, ""},
 /*  9 */ {0, {240,8,256,231}, CHECK, N_("Show Facets from Cell-Library")}
};
DIALOG us_editfacetdialog = {{50,75,375,365}, N_("Edit Facet"), 0, 9, us_editfacetdialoglist};

/* New facet */
DIALOGITEM us_newfacetdialogitems[] =
{
 /*  1 */ {0, {56,304,80,368}, BUTTON, N_("OK")},
 /*  2 */ {0, {56,12,80,76}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,160,24,367}, EDITTEXT, ""},
 /*  4 */ {0, {8,8,24,157}, MESSAGE, N_("Name of new facet:")},
 /*  5 */ {0, {32,160,48,367}, POPUP, ""},
 /*  6 */ {0, {32,56,48,149}, MESSAGE, N_("Facet view:")},
 /*  7 */ {0, {60,84,78,297}, CHECK, N_("Make new window for facet")}
};
DIALOG us_newfacetdialog = {{350,75,445,455}, N_("New Facet Creation"), 0, 7, us_newfacetdialogitems};

/*
 * special case for the "edit facet" command
 * Facet list                = 3 (message)
 * Show old versions         = 4 (check)
 * Make new window for facet = 5 (check)
 * New facet                 = 6 (button)
 * Library name              = 8 (popup)
 * Show from cell-library    = 9 (check)
 *
 * special case for the "new facet" button
 * Facet name                = 3 (edit text)
 * View list                 = 5 (popup)
 * Make new window for facet = 7 (check)
 */
INTSML us_editfacetdlog(char *prompt)
{
	INTBIG itemHit;
	REGISTER INTBIG viewcount, librarycount, i, libindex, defaultindex;
	REGISTER NODEPROTO *np, *curfacet;
	char **viewlist, **librarylist, *pt, *ptr, *newpar[5];
	REGISTER VIEW *v;
	REGISTER LIBRARY *lib;
	static INTBIG makenewwindow = -1;
	static VIEW *lastview = NOVIEW;
	VIEW *thisview;

	/* see what the current view is (if any) */
	thisview = NOVIEW;
	if (el_curwindowpart != NOWINDOWPART)
	{
		if (el_curwindowpart->curnodeproto != NONODEPROTO)
			thisview = el_curwindowpart->curnodeproto->cellview;
	}
	if (thisview == NOVIEW) thisview = lastview;

	/* make a list of view names */
	for(viewcount=0, v=el_views; v!=NOVIEW; v=v->nextview) viewcount++;
	viewlist = (char **)emalloc(viewcount * (sizeof (char *)), el_tempcluster);
	if (viewlist == 0) return(0);
	viewlist[0] = "unknown";   i = 1;
	defaultindex = 0;
	for(v = el_views; v != NOVIEW; v = v->nextview)
	{
		if (namesame(v->viewname, "unknown") != 0)
		{
			if (v == thisview) defaultindex = i;
			viewlist[i++] = v->viewname;
		}
	}

	/* the general case: display the dialog box */
	us_curlib = el_curlib;
	for(pt = prompt; *pt != 0; pt++) if (*pt == '/') break;
	if (*pt == '/')
	{
		*pt++ = 0;
		us_curlib = getlibrary(prompt);
		if (us_curlib == NOLIBRARY) us_curlib = el_curlib;
		prompt = pt;
	}

	us_editfacetdialog.movable = prompt;
	if (us_curlib->firstnodeproto == NONODEPROTO)
	{
		us_editfacetdialoglist[0].type = BUTTON;
		us_editfacetdialoglist[5].type = DEFBUTTON;
	} else
	{
		us_editfacetdialoglist[0].type = DEFBUTTON;
		us_editfacetdialoglist[5].type = BUTTON;
	}
	if (DiaInitDialog(&us_editfacetdialog) != 0) return(0);

	/* make a list of library names */
	for(librarycount = 0, lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
		librarycount++;
	librarylist = (char **)emalloc(librarycount * (sizeof (char *)), el_tempcluster);
	if (librarylist == 0) return(0);
	i = 0;
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
	{
		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
		if (lib == us_curlib) libindex = i;
		librarylist[i++] = lib->libname;
	}
	DiaSetPopup(8, i, librarylist);
	DiaSetPopupEntry(8, libindex);

	/* show the facets */
	us_showoldversions = 1;
	us_showcellibraryfacets = 1;
	DiaInitTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone,
		0, SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT);

	/* find the current node and make it the default */
	np = us_setscrolltocurrentfacet(3, 0, 1, 0);

	/* see if there are any old versions */
	for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		if (np->newestversion != np) break;
	if (np == NONODEPROTO) DiaDimItem(4); else
	{
		DiaUnDimItem(4);
		DiaSetControl(4, us_showoldversions);
	}

	/* see if there are any cell-library facets */
	for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		if ((np->userbits&INCELLLIBRARY) != 0) break;
	if (np == NONODEPROTO) DiaDimItem(9); else
	{
		DiaUnDimItem(9);
		DiaSetControl(9, us_showcellibraryfacets);
	}

	/* if the current window has a facet in it and multiple windows are supported, offer new one */
	curfacet = getcurfacet();
	if (makenewwindow < 0)
	{
		makenewwindow = 0;
		if (curfacet != NONODEPROTO && graphicshas(CANUSEFRAMES)) makenewwindow = 1;
	}
	if (curfacet == NONODEPROTO) makenewwindow = 0;
	DiaSetControl(5, makenewwindow);

	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK)
		{
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			pt = DiaGetScrollLine(3, i);
			if (*pt == 0) continue;
			(void)initinfstr();
			if (us_curlib != el_curlib)
			{
				(void)addstringtoinfstr(us_curlib->libname);
				(void)addtoinfstr(':');
			}
			(void)addstringtoinfstr(pt);
			newpar[0] = returninfstr();
			break;
		}
		if (itemHit == 5)
		{
			DiaSetControl(5, 1 - DiaGetControl(5));
			continue;
		}
		if (itemHit == 8)
		{
			i = DiaGetPopupEntry(8);
			us_curlib = getlibrary(librarylist[i]);
			DiaLoadTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);

			/* see if there are any old versions */
			for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if (np->newestversion != np) break;
			if (np == NONODEPROTO) DiaDimItem(4); else
			{
				DiaUnDimItem(4);
				DiaSetControl(4, us_showoldversions);
			}

			/* see if there are any cell-library facets */
			for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if ((np->userbits&INCELLLIBRARY) != 0) break;
			if (np == NONODEPROTO) DiaDimItem(9); else
			{
				DiaUnDimItem(9);
				DiaSetControl(9, us_showcellibraryfacets);
			}
			continue;
		}
		if (itemHit == 4)
		{
			us_showoldversions = 1 - DiaGetControl(4);
			DiaSetControl(4, us_showoldversions);
			i = DiaGetCurLine(3);
			if (i >= 0) pt = DiaGetScrollLine(3, i); else pt = "";
			DiaLoadTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
			if (*pt != 0)
			{
				for(i=0; ; i++)
				{
					ptr = DiaGetScrollLine(3, i);
					if (*ptr == 0) break;
					if (strcmp(ptr, pt) != 0) continue;
					DiaSelectLine(3, i);
					break;
				}
			}
			continue;
		}
		if (itemHit == 9)
		{
			us_showcellibraryfacets = 1 - DiaGetControl(9);
			DiaSetControl(9, us_showcellibraryfacets);
			i = DiaGetCurLine(3);
			if (i >= 0) pt = DiaGetScrollLine(3, i); else pt = "";
			DiaLoadTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
			if (*pt != 0)
			{
				for(i=0; ; i++)
				{
					ptr = DiaGetScrollLine(3, i);
					if (*ptr == 0) break;
					if (strcmp(ptr, pt) != 0) continue;
					DiaSelectLine(3, i);
					break;
				}
			}
			continue;
		}
		if (itemHit == 6)
		{
			/* display the new facet dialog box */
			makenewwindow = DiaGetControl(5);
			if (DiaInitDialog(&us_newfacetdialog) != 0) continue;
			DiaSetPopup(5, viewcount, viewlist);
			DiaSetControl(7, makenewwindow);
			DiaSetPopupEntry(5, defaultindex);

			/* loop until done */
			for(;;)
			{
				itemHit = DiaNextHit();
				if (itemHit == CANCEL) break;
				if (itemHit == 7)
				{
					DiaSetControl(7, 1 - DiaGetControl(7));
					continue;
				}
				if (itemHit == OK && DiaValidEntry(3)) break;
			}

			newpar[0] = "";
			if (itemHit != CANCEL)
			{
				i = DiaGetPopupEntry(5);
				(void)initinfstr();
				if (us_curlib != el_curlib)
				{
					(void)addstringtoinfstr(us_curlib->libname);
					(void)addtoinfstr(':');
				}
				(void)addstringtoinfstr(DiaGetText(3));
				for(v = el_views; v != NOVIEW; v = v->nextview)
					if (namesame(viewlist[i], v->viewname) == 0)
				{
					if (*v->sviewname == 0) break;
					(void)addtoinfstr('{');
					(void)addstringtoinfstr(v->sviewname);
					(void)addtoinfstr('}');
					lastview = v;
					break;
				}
				newpar[0] = returninfstr();
			}
			makenewwindow = DiaGetControl(7);
			DiaDoneDialog();
			if (itemHit == CANCEL) continue;
			DiaSetControl(5, makenewwindow);
			break;
		}
	}
	makenewwindow = DiaGetControl(5);
	DiaDoneDialog();
	efree((char *)librarylist);
	efree((char *)viewlist);
	if (itemHit != CANCEL)
	{
		if (makenewwindow != 0)
		{
			newpar[1] = "new-window";
			us_editfacet(2, newpar);
		} else
		{
			us_editfacet(1, newpar);
		}
	}
	return(0);
}

/****************************** FACET LIST DIALOGS ******************************/

/* Facet List */
DIALOGITEM us_facetlistdialoglist[] =
{
 /*  1 */ {0, {308,208,332,272}, BUTTON, N_("OK")},
 /*  2 */ {0, {308,16,332,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {36,8,251,280}, SCROLL, ""},
 /*  4 */ {0, {256,8,274,153}, CHECK, N_("Show Old Versions")},
 /*  5 */ {0, {280,8,298,205}, CHECK, N_("Show Facets from Cell-Library")},
 /*  6 */ {0, {8,8,26,67}, MESSAGE, N_("Library:")},
 /*  7 */ {0, {8,72,26,280}, POPUP, ""}
};
DIALOG us_facetlistdialog = {{50,75,391,364}, N_("Facet List"), 0, 7, us_facetlistdialoglist};

/*
 * special case for the "Delete Facet", "New Facet Instance", "List Facet Usage", and
 * "plot simulation in facet window" command
 * Facet list               = 3 (message)
 * Show old versions        = 4 (check)
 * Show cell-library facets = 5 (check)
 */
INTSML us_facetlist(char *prompt, char *paramstart[], INTSML curinstance)
{
	REGISTER INTBIG itemHit, i, libindex, librarycount;
	REGISTER LIBRARY *lib;
	REGISTER char **librarylist;
	REGISTER NODEPROTO *np;

	/* display the dialog box */
	us_facetlistdialog.movable = prompt;
	if (DiaInitDialog(&us_facetlistdialog) != 0) return(0);
	us_showoldversions = 1;
	us_showcellibraryfacets = 1;
	us_curlib = el_curlib;
	DiaInitTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone,
		0, SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT);
	us_setscrolltocurrentfacet(3, curinstance, 0, 0);

	/* make a list of library names */
	for(librarycount = 0, lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
		librarycount++;
	librarylist = (char **)emalloc(librarycount * (sizeof (char *)), el_tempcluster);
	if (librarylist == 0) return(0);
	i = 0;
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
	{
		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
		if (lib == us_curlib) libindex = i;
		librarylist[i++] = lib->libname;
	}
	DiaSetPopup(7, i, librarylist);
	DiaSetPopupEntry(7, libindex);

	/* see if there are any old versions */
	for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		if (np->newestversion != np) break;
	if (np == NONODEPROTO) DiaDimItem(4); else
	{
		DiaUnDimItem(4);
		DiaSetControl(4, us_showoldversions);
	}

	/* see if there are any cell-library facets */
	for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		if ((np->userbits&INCELLLIBRARY) != 0) break;
	if (np == NONODEPROTO) DiaDimItem(5); else
	{
		DiaUnDimItem(5);
		DiaSetControl(5, us_showcellibraryfacets);
	}

	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 4)
		{
			us_showoldversions = 1 - DiaGetControl(4);
			DiaSetControl(4, us_showoldversions);
			DiaLoadTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
		}
		if (itemHit == 5)
		{
			us_showcellibraryfacets = 1 - DiaGetControl(5);
			DiaSetControl(5, us_showcellibraryfacets);
			DiaLoadTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone, 0);
		}
		if (itemHit == 7)
		{
			i = DiaGetPopupEntry(7);
			us_curlib = getlibrary(librarylist[i]);
			DiaInitTextDialog(3, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone,
				0, SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT);

			/* see if there are any old versions */
			for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if (np->newestversion != np) break;
			if (np == NONODEPROTO) DiaDimItem(4); else
			{
				DiaUnDimItem(4);
				DiaSetControl(4, us_showoldversions);
			}

			/* see if there are any cell-library facets */
			for(np = us_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if ((np->userbits&INCELLLIBRARY) != 0) break;
			if (np == NONODEPROTO) DiaDimItem(5); else
			{
				DiaUnDimItem(5);
				DiaSetControl(5, us_showcellibraryfacets);
			}
			continue;
		}
	}
	(void)initinfstr();
	if (us_curlib != el_curlib)
	{
		(void)addstringtoinfstr(us_curlib->libname);
		(void)addtoinfstr(':');
	}
	(void)addstringtoinfstr(DiaGetScrollLine(3, DiaGetCurLine(3)));
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == CANCEL) return(0);
	return(1);
}

/****************************** FACET OPTIONS DIALOG ******************************/

/* Facet options */
DIALOGITEM us_facetdialogitems[] =
{
 /*  1 */ {0, {288,496,312,560}, BUTTON, N_("OK")},
 /*  2 */ {0, {232,496,256,560}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {304,24,320,324}, CHECK, N_("Tiny facet instances hashed out")},
 /*  4 */ {0, {8,8,24,130}, MESSAGE, N_("For facet:")},
 /*  5 */ {0, {28,4,184,150}, SCROLL, ""},
 /*  6 */ {0, {232,24,248,324}, CHECK, N_("Disallow modification of facet instances")},
 /*  7 */ {0, {196,4,197,568}, DIVIDELINE, ""},
 /*  8 */ {0, {208,4,224,116}, MESSAGE, N_("For all facets:")},
 /*  9 */ {0, {28,156,44,480}, CHECK, N_("Disallow modification of anything in this facet")},
 /* 10 */ {0, {4,484,20,568}, MESSAGE, N_("Every facet:")},
 /* 11 */ {0, {52,156,68,480}, CHECK, N_("Disallow modification of instances in this facet")},
 /* 12 */ {0, {144,156,160,344}, MESSAGE|INACTIVE, N_("Characteristic X Spacing:")},
 /* 13 */ {0, {168,156,184,344}, MESSAGE|INACTIVE, N_("Characteristic Y Spacing:")},
 /* 14 */ {0, {144,348,160,424}, EDITTEXT, ""},
 /* 15 */ {0, {168,348,184,424}, EDITTEXT, ""},
 /* 16 */ {0, {76,156,92,344}, CHECK, N_("Part of a cell-library")},
 /* 17 */ {0, {76,484,92,520}, BUTTON, N_("Set")},
 /* 18 */ {0, {76,528,92,568}, BUTTON, N_("Clear")},
 /* 19 */ {0, {328,24,344,280}, MESSAGE|INACTIVE, N_("Hash facets when scale is more than:")},
 /* 20 */ {0, {328,284,344,344}, EDITTEXT, ""},
 /* 21 */ {0, {328,348,344,472}, MESSAGE|INACTIVE, N_("lambda per pixel")},
 /* 22 */ {0, {100,156,116,344}, RADIO, N_("Expand new instances")},
 /* 23 */ {0, {120,156,136,344}, RADIO, N_("Unexpand new instances")},
 /* 24 */ {0, {256,24,272,324}, CHECK, N_("Check facet dates during creation")},
 /* 25 */ {0, {28,528,44,568}, BUTTON, N_("Clear")},
 /* 26 */ {0, {28,484,44,520}, BUTTON, N_("Set")},
 /* 27 */ {0, {52,528,68,568}, BUTTON, N_("Clear")},
 /* 28 */ {0, {52,484,68,520}, BUTTON, N_("Set")},
 /* 29 */ {0, {280,24,296,324}, CHECK, N_("Switch technology to match current facet")}
};
DIALOG us_facetdialog = {{50,75,403,652}, N_("Facet Options"), 0, 29, us_facetdialogitems};

/*
 * special case for the "facet info" dialog
 * Tiny facets                           =  3 (check)
 * Facet names                           =  5 (scroll)
 * Allow all inst mod                    =  6 (check)
 * Allow all mod in facet                =  9 (check)
 * Allow inst mod in facet               = 11 (check)
 * X Characteristic spacing              = 14 (edit)
 * Y Characteristic spacing              = 15 (edit)
 * Part of cell library                  = 16 (check)
 * "Set all" for cell library            = 17 (button)
 * "Clear all" for cell library          = 18 (button)
 * Tiny lambda per pixel                 = 20 (edit)
 * Expand new instances                  = 22 (radio)
 * Unexpand new instances                = 23 (radio)
 * Check dates                           = 24 (check)
 * "Clear all" for facet modification    = 25 (button)
 * "Set all" for facet modification      = 26 (button)
 * "Clear all" for instance modification = 27 (button)
 * "Set all" for instance modification   = 28 (button)
 * Switch technology when facet changes  = 29 (check)
 */
INTSML us_facetdlog(void)
{
	INTBIG itemHit, i, lx, value;
	REGISTER NODEPROTO *thisfacet, *np;
	REGISTER VARIABLE *var;
	REGISTER char *pt;
	typedef struct
	{
		INTBIG newbits;
		INTBIG validcharacteristicspacing;
		INTBIG characteristicspacing[2];
	} FACETINFO;
	FACETINFO *fi;

	/* display the facet dialog box */
	if (DiaInitDialog(&us_facetdialog) != 0) return(0);
	us_showoldversions = 1;
	us_showcellibraryfacets = 1;
	us_curlib = el_curlib;
	DiaInitTextDialog(5, us_oldfacettopoffacets, us_oldfacetnextfacets, DiaNullDlogDone,
		0, SCSELMOUSE|SCSELKEY|SCREPORT);

	/* get the current facet, and set the scroll item to it */
	thisfacet = us_setscrolltocurrentfacet(5, 0, 1, 0);
	if (thisfacet != NONODEPROTO && thisfacet->cell->lib != el_curlib)
		thisfacet = NONODEPROTO;
	if (thisfacet == NONODEPROTO) thisfacet = el_curlib->firstnodeproto;

	/* save facet information */
	for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
	{
		fi = (FACETINFO *)emalloc(sizeof (FACETINFO), el_tempcluster);
		if (fi == 0) return(0);
		fi->newbits = np->userbits;
		var = getval((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, "FACET_characteristic_spacing");
		if (var == NOVARIABLE) fi->validcharacteristicspacing = 0; else
		{
			fi->characteristicspacing[0] = ((INTBIG *)var->addr)[0];
			fi->characteristicspacing[1] = ((INTBIG *)var->addr)[1];
			fi->validcharacteristicspacing = 1;
		}
		np->temp1 = (INTBIG)fi;
	}

	/* load defaults for primitives and facets */
	if (thisfacet != NONODEPROTO)
	{
		fi = (FACETINFO *)thisfacet->temp1;
		if ((fi->newbits&NLOCKED) != 0) DiaSetControl(9, 1); else
			DiaSetControl(9, 0);
		if ((fi->newbits&NILOCKED) != 0) DiaSetControl(11, 1); else
			DiaSetControl(11, 0);
		if ((fi->newbits&INCELLLIBRARY) != 0) DiaSetControl(16, 1); else
			DiaSetControl(16, 0);
		if ((fi->newbits&WANTNEXPAND) != 0) DiaSetControl(22, 1); else
			DiaSetControl(23, 1);
		if (fi->validcharacteristicspacing != 0)
		{
			DiaSetText(14, latoa(fi->characteristicspacing[0]));
			DiaSetText(15, latoa(fi->characteristicspacing[1]));
		}
	} else
	{
		DiaDimItem(5);
		DiaDimItem(9);
		DiaDimItem(11);
		DiaDimItem(14);
		DiaDimItem(15);
		DiaDimItem(16);
		DiaDimItem(17);
		DiaDimItem(18);
		DiaDimItem(22);
		DiaDimItem(23);
		DiaDimItem(25);
		DiaDimItem(26);
		DiaDimItem(27);
		DiaDimItem(28);
	}

	/* load defaults for all nodes */
	DiaSetControl(6, (us_useroptions&NOFACETCHANGES) != 0 ? 1 : 0);
	DiaSetControl(3, (us_useroptions&DRAWTINYFACETS) == 0 ? 1 : 0);
	DiaSetControl(24, (us_useroptions&CHECKDATE) != 0 ? 1 : 0);
	DiaSetControl(29, (us_useroptions&AUTOSWITCHTECHNOLOGY) != 0 ? 1 : 0);
	DiaSetText(20, frtoa(us_tinyratio));

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 5)
		{
			i = DiaGetCurLine(5);
			if (i < 0) continue;
			pt = DiaGetScrollLine(5, i);
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if (namesame(pt, describenodeproto(np)) == 0) break;
			thisfacet = np;
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			if ((fi->newbits&NLOCKED) != 0) DiaSetControl(9, 1); else
				DiaSetControl(9, 0);
			if ((fi->newbits&NILOCKED) != 0) DiaSetControl(11, 1); else
				DiaSetControl(11, 0);
			if ((fi->newbits&INCELLLIBRARY) != 0) DiaSetControl(16, 1); else
				DiaSetControl(16, 0);
			if ((fi->newbits&WANTNEXPAND) != 0)
			{
				DiaSetControl(22, 1);
				DiaSetControl(23, 0);
			} else
			{
				DiaSetControl(22, 0);
				DiaSetControl(23, 1);
			}
			if (fi->validcharacteristicspacing != 0)
			{
				DiaSetText(14, latoa(fi->characteristicspacing[0]));
				DiaSetText(15, latoa(fi->characteristicspacing[1]));
			} else
			{
				DiaSetText(14, "");
				DiaSetText(15, "");
			}
			continue;
		}
		if (itemHit == 9)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			value = 1 - DiaGetControl(9);
			DiaSetControl(9, value);
			if (value == 0) fi->newbits &= ~NLOCKED; else
				fi->newbits |= NLOCKED;
			continue;
		}
		if (itemHit == 11)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			value = 1 - DiaGetControl(11);
			DiaSetControl(11, value);
			if (value == 0) fi->newbits &= ~NILOCKED; else
				fi->newbits |= NILOCKED;
			continue;
		}
		if (itemHit == 16)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			value = 1 - DiaGetControl(16);
			DiaSetControl(16, value);
			if (value == 0) fi->newbits &= ~INCELLLIBRARY; else
				fi->newbits |= INCELLLIBRARY;
			continue;
		}
		if (itemHit == 22 || itemHit == 23)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			DiaSetControl(22, 0);
			DiaSetControl(23, 0);
			DiaSetControl(itemHit, 1);
			if (itemHit == 22) fi->newbits |= WANTNEXPAND; else
				fi->newbits &= ~WANTNEXPAND;
			continue;
		}
		if (itemHit == 17)
		{
			/* all facets part of cell library */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits |= INCELLLIBRARY;
			}
			DiaSetControl(16, 1);
			continue;
		}
		if (itemHit == 18)
		{
			/* all facets not part of cell library */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits &= ~INCELLLIBRARY;
			}
			DiaSetControl(16, 0);
			continue;
		}
		if (itemHit == 25)
		{
			/* allow modification for all facets */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits &= ~NLOCKED;
			}
			DiaSetControl(9, 0);
			continue;
		}
		if (itemHit == 26)
		{
			/* disallow modification for all facets */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits |= NLOCKED;
			}
			DiaSetControl(9, 1);
			continue;
		}
		if (itemHit == 27)
		{
			/* allow instance modification for all facets */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits &= ~NILOCKED;
			}
			DiaSetControl(11, 0);
			continue;
		}
		if (itemHit == 28)
		{
			/* disallow instance modification for all facets */
			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
			{
				fi = (FACETINFO *)np->temp1;
				fi->newbits |= NILOCKED;
			}
			DiaSetControl(11, 1);
			continue;
		}
		if (itemHit == 14)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			pt = DiaGetText(14);
			if (fi->validcharacteristicspacing == 0 && *pt == 0) continue;
			if (fi->validcharacteristicspacing == 0)
				fi->characteristicspacing[1] = 0;
			fi->validcharacteristicspacing = 1;
			fi->characteristicspacing[0] = atola(pt);
			continue;
		}
		if (itemHit == 15)
		{
			if (thisfacet == NONODEPROTO) continue;
			fi = (FACETINFO *)thisfacet->temp1;
			pt = DiaGetText(15);
			if (fi->validcharacteristicspacing == 0 && *pt == 0) continue;
			if (fi->validcharacteristicspacing == 0)
				fi->characteristicspacing[0] = 0;
			fi->validcharacteristicspacing = 1;
			fi->characteristicspacing[1] = atola(pt);
			continue;
		}
		if (itemHit == 6 || itemHit == 3 || itemHit == 24 || itemHit == 29)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* handle facet changes */
		for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		{
			fi = (FACETINFO *)np->temp1;
			if ((fi->newbits&(NLOCKED|NILOCKED|INCELLLIBRARY|WANTNEXPAND)) !=
				(INTBIG)(np->userbits&(NLOCKED|NILOCKED|INCELLLIBRARY|WANTNEXPAND)))
					(void)setval((INTBIG)np, VNODEPROTO, "userbits", fi->newbits, VINTEGER);
			if (fi->validcharacteristicspacing != 0)
				setval((INTBIG)np, VNODEPROTO, "FACET_characteristic_spacing",
					(INTBIG)fi->characteristicspacing, VINTEGER|VISARRAY|(2<<VLENGTHSH));
		}

		/* handle changes to all nodes */
		lx = us_useroptions;
		i = DiaGetControl(6);
		if (i != 0) lx |= NOFACETCHANGES; else lx &= ~NOFACETCHANGES;
		i = DiaGetControl(3);
		if (i == 0) lx |= DRAWTINYFACETS; else lx &= ~DRAWTINYFACETS;
		i = DiaGetControl(24);
		if (i != 0) lx |= CHECKDATE; else lx &= ~CHECKDATE;
		i = DiaGetControl(29);
		if (i != 0) lx |= AUTOSWITCHTECHNOLOGY; else lx &= ~AUTOSWITCHTECHNOLOGY;
		if (lx != us_useroptions)
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags, lx, VINTEGER);
		i = atofr(DiaGetText(20));
		if (i != us_tinyratio)
			(void)setvalkey((INTBIG)us_aid, VAID, us_tinylambdaperpixel, i, VFRACT);
	}
	DiaDoneDialog();
	for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		efree((char *)np->temp1);
	return(0);
}

/****************************** FRAME OPTIONS DIALOG ******************************/

/* Drawing Options */
DIALOGITEM us_drawingoptdialogitems[] =
{
 /*  1 */ {0, {172,244,196,308}, BUTTON, N_("OK")},
 /*  2 */ {0, {172,32,196,96}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {116,16,132,125}, MESSAGE, N_("Company Name:")},
 /*  4 */ {0, {116,128,132,328}, EDITTEXT, ""},
 /*  5 */ {0, {140,16,156,125}, MESSAGE, N_("Designer Name:")},
 /*  6 */ {0, {140,128,156,328}, EDITTEXT, ""},
 /*  7 */ {0, {44,8,60,105}, MESSAGE, N_("Frame size:")},
 /*  8 */ {0, {44,108,60,204}, POPUP, ""},
 /*  9 */ {0, {32,208,48,305}, RADIO, N_("Landscape")},
 /* 10 */ {0, {56,208,72,305}, RADIO, N_("Portrait")},
 /* 11 */ {0, {8,8,24,328}, MESSAGE, N_("For facet:")},
 /* 12 */ {0, {92,8,108,113}, MESSAGE, N_("For all facets:")},
 /* 13 */ {0, {80,8,81,328}, DIVIDELINE, ""}
};
DIALOG us_drawingoptdialog = {{50,75,255,412}, N_("Frame Options"), 0, 13, us_drawingoptdialogitems};

/*
 * special case for the "Drawing Options" dialog
 * Company Name      = 4 (edit text)
 * Designer Name     = 6 (edit text)
 * Frame size        = 8 (popup)
 * Landscape         = 9 (radio)
 * Portrait         = 10 (radio)
 * Facet name       = 11 (stat text)
 */
INTSML us_frameoptionsdlog(void)
{
	INTBIG itemHit, index, i;
	REGISTER VARIABLE *var;
	REGISTER NODEPROTO *np;
	REGISTER char *pt;
	char line[10], *newlang[6];
	static char *framenames[] = {N_("None"), N_("A-Size"), N_("B-Size"), N_("C-Size"),
		N_("D-Size"), N_("E-Size")};

	/* show the frame options dialog */
	if (DiaInitDialog(&us_drawingoptdialog) != 0) return(0);
	var = getval((INTBIG)us_aid, VAID, VSTRING, "USER_drawing_company_name");
	if (var != NOVARIABLE) DiaSetText(4, (char *)var->addr);
	var = getval((INTBIG)us_aid, VAID, VSTRING, "USER_drawing_designer_name");
	if (var != NOVARIABLE) DiaSetText(6, (char *)var->addr);
	np = getcurfacet();
	if (np != NONODEPROTO)
	{
		(void)initinfstr();
		(void)addstringtoinfstr(_("For facet: "));
		(void)addstringtoinfstr(describenodeproto(np));
		DiaSetText(11, returninfstr());
		for(i=0; i<6; i++) newlang[i] = _(framenames[i]);   DiaSetPopup(8, 6, newlang);
		index = 0;
		var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, el_schematic_page_size);
		if (var != NOVARIABLE)
		{
			pt = (char *)var->addr;
			if (*pt == 'a') index = 1; else
			if (*pt == 'b') index = 2; else
			if (*pt == 'c') index = 3; else
			if (*pt == 'd') index = 4; else
			if (*pt == 'e') index = 5; else index = 4;
			DiaSetPopupEntry(8, index);
			if (pt[1] == 'v') DiaSetControl(10, 1); else
				DiaSetControl(9, 1);
		}
	} else
	{
		DiaSetText(11, _("No facet in window"));
		DiaDimItem(9);
		DiaDimItem(10);
	}
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 8)
		{
			i = DiaGetPopupEntry(8);
			if (i == 0)
			{
				DiaSetControl(9, 0);
				DiaSetControl(10, 0);
			} else
			{
				if (DiaGetControl(9) == 0 && DiaGetControl(10) == 0)
					DiaSetControl(9, 1);
			}
		}
		if (itemHit == 9 || itemHit == 10)
		{
			DiaSetControl(9, 0);
			DiaSetControl(10, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
	}
	if (itemHit == OK)
	{
		if (np != NONODEPROTO)
		{
			index = DiaGetPopupEntry(8);
			var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, el_schematic_page_size);
			if (index == 0)
			{
				if (var != NOVARIABLE)
					(void)delvalkey((INTBIG)np, VNODEPROTO, el_schematic_page_size);
			} else
			{
				pt = line;
				switch (index)
				{
					case 1: *pt++ = 'a';   break;
					case 2: *pt++ = 'b';   break;
					case 3: *pt++ = 'c';   break;
					case 4: *pt++ = 'd';   break;
					case 5: *pt++ = 'e';   break;
				}
				if (DiaGetControl(10) != 0) *pt++ = 'v';
				if (var == NOVARIABLE || strcmp(line, (char *)var->addr) != 0)
					(void)setvalkey((INTBIG)np, VNODEPROTO, el_schematic_page_size,
						(INTBIG)line, VSTRING);
			}
		}

		pt = DiaGetText(4);
		while (*pt == ' ' || *pt == '\t') pt++;
		var = getval((INTBIG)us_aid, VAID, VSTRING, "USER_drawing_company_name");
		if (*pt == 0)
		{
			/* remove company information */
			if (var != NOVARIABLE) delval((INTBIG)us_aid, VAID, "USER_drawing_company_name");
		} else
		{
			if (var == NOVARIABLE || strcmp(pt, (char *)var->addr) != 0)
				(void)setval((INTBIG)us_aid, VAID, "USER_drawing_company_name", (INTBIG)pt, VSTRING);
		}

		pt = DiaGetText(6);
		while (*pt == ' ' || *pt == '\t') pt++;
		var = getval((INTBIG)us_aid, VAID, VSTRING, "USER_drawing_designer_name");
		if (*pt == 0)
		{
			/* remove designer information */
			if (var != NOVARIABLE) delval((INTBIG)us_aid, VAID, "USER_drawing_designer_name");
		} else
		{
			if (var == NOVARIABLE || strcmp(pt, (char *)var->addr) != 0)
				(void)setval((INTBIG)us_aid, VAID, "USER_drawing_designer_name", (INTBIG)pt, VSTRING);
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** GET INFO DIALOGS ******************************/

/* Multiple Object Info */
DIALOGITEM us_multigetinfodialogitems[] =
{
 /*  1 */ {0, {248,116,272,196}, BUTTON, N_("OK")},
 /*  2 */ {0, {248,8,272,88}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {20,4,236,304}, SCROLL, ""},
 /*  4 */ {0, {0,4,16,304}, MESSAGE, N_("0 Objects:")},
 /*  5 */ {0, {52,308,68,388}, MESSAGE, N_("X Position:")},
 /*  6 */ {0, {52,392,68,472}, EDITTEXT, ""},
 /*  7 */ {0, {80,308,96,388}, MESSAGE, N_("Y Position:")},
 /*  8 */ {0, {80,392,96,472}, EDITTEXT, ""},
 /*  9 */ {0, {108,308,124,388}, MESSAGE, N_("X Size:")},
 /* 10 */ {0, {108,392,124,472}, EDITTEXT, ""},
 /* 11 */ {0, {136,308,152,388}, MESSAGE, N_("Y Size:")},
 /* 12 */ {0, {136,392,152,472}, EDITTEXT, ""},
 /* 13 */ {0, {212,308,228,388}, MESSAGE, N_("Width:")},
 /* 14 */ {0, {212,392,228,472}, EDITTEXT, ""},
 /* 15 */ {0, {28,308,44,472}, MESSAGE, N_("For all selected nodes:")},
 /* 16 */ {0, {184,308,200,472}, MESSAGE, N_("For all selected arcs:")},
 /* 17 */ {0, {248,224,272,304}, BUTTON, N_("Info")}
};
DIALOG us_multigetinfodialog = {{75,75,356,556}, N_("Multiple Object Information"), 0, 17, us_multigetinfodialogitems};

/* Node info */
DIALOGITEM us_shownodedialogitems[] =
{
 /*  1 */ {0, {372,316,396,388}, BUTTON, N_("OK")},
 /*  2 */ {0, {372,12,396,84}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {236,8,364,392}, SCROLL, ""},
 /*  4 */ {0, {196,88,212,184}, RADIO, N_("Expanded")},
 /*  5 */ {0, {196,192,212,296}, RADIO, N_("Unexpanded")},
 /*  6 */ {0, {8,64,24,392}, MESSAGE, ""},
 /*  7 */ {0, {32,64,48,392}, EDITTEXT, ""},
 /*  8 */ {0, {76,80,92,174}, EDITTEXT, ""},
 /*  9 */ {0, {100,80,116,174}, EDITTEXT, ""},
 /* 10 */ {0, {124,80,140,128}, EDITTEXT, ""},
 /* 11 */ {0, {124,136,140,246}, CHECK, N_("Transposed")},
 /* 12 */ {0, {76,296,92,392}, EDITTEXT, ""},
 /* 13 */ {0, {100,296,116,392}, EDITTEXT, ""},
 /* 14 */ {0, {8,8,24,56}, MESSAGE, N_("Type:")},
 /* 15 */ {0, {32,8,48,56}, MESSAGE, N_("Name:")},
 /* 16 */ {0, {76,8,92,72}, MESSAGE, N_("X size:")},
 /* 17 */ {0, {100,8,116,72}, MESSAGE, N_("Y size:")},
 /* 18 */ {0, {124,8,140,72}, MESSAGE, N_("Rotation:")},
 /* 19 */ {0, {76,208,92,288}, MESSAGE, N_("X position:")},
 /* 20 */ {0, {100,208,116,288}, MESSAGE, N_("Y position:")},
 /* 21 */ {0, {220,8,236,76}, MESSAGE, N_("Ports:")},
 /* 22 */ {0, {172,160,188,392}, MESSAGE, ""},
 /* 23 */ {0, {148,8,164,160}, MESSAGE, ""},
 /* 24 */ {0, {148,160,164,392}, MESSAGE, ""},
 /* 25 */ {0, {172,8,188,160}, MESSAGE, ""},
 /* 26 */ {0, {372,112,396,184}, BUTTON, N_("See Arc")},
 /* 27 */ {0, {56,76,72,193}, MESSAGE, ""},
 /* 28 */ {0, {56,292,72,392}, MESSAGE, N_("Lower-left:")},
 /* 29 */ {0, {124,264,140,392}, CHECK, N_("Easy to Select")},
 /* 30 */ {0, {372,216,396,288}, BUTTON, N_("Attributes")}
};
DIALOG us_shownodedialog = {{50,75,455,484}, N_("Node Information"), 0, 30, us_shownodedialogitems};

/* Arc info */
DIALOGITEM us_showarcdialogitems[] =
{
 /*  1 */ {0, {148,336,172,408}, BUTTON, N_("OK")},
 /*  2 */ {0, {108,336,132,408}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {228,312,244,392}, CHECK, N_("Rigid")},
 /*  4 */ {0, {276,312,292,408}, CHECK, N_("Fixed-angle")},
 /*  5 */ {0, {8,88,24,393}, MESSAGE, ""},
 /*  6 */ {0, {32,88,48,393}, MESSAGE, ""},
 /*  7 */ {0, {56,88,72,393}, EDITTEXT, ""},
 /*  8 */ {0, {104,88,120,173}, MESSAGE, ""},
 /*  9 */ {0, {128,88,144,320}, MESSAGE, ""},
 /* 10 */ {0, {80,280,96,365}, MESSAGE, ""},
 /* 11 */ {0, {176,88,192,320}, MESSAGE, ""},
 /* 12 */ {0, {8,16,24,80}, MESSAGE, N_("Type:")},
 /* 13 */ {0, {32,16,48,80}, MESSAGE, N_("Network:")},
 /* 14 */ {0, {80,16,96,80}, MESSAGE, N_("Width:")},
 /* 15 */ {0, {104,16,120,80}, MESSAGE, N_("Angle:")},
 /* 16 */ {0, {128,16,144,80}, MESSAGE, N_("Head:")},
 /* 17 */ {0, {80,216,96,280}, MESSAGE, N_("Bus size:")},
 /* 18 */ {0, {176,16,192,80}, MESSAGE, N_("Tail:")},
 /* 19 */ {0, {300,312,316,408}, CHECK, N_("Slidable")},
 /* 20 */ {0, {252,16,268,112}, CHECK, N_("Negated")},
 /* 21 */ {0, {276,16,292,112}, CHECK, N_("Directional")},
 /* 22 */ {0, {300,16,316,120}, CHECK, N_("Ends extend")},
 /* 23 */ {0, {252,136,268,240}, CHECK, N_("Ignore head")},
 /* 24 */ {0, {276,136,292,232}, CHECK, N_("Ignore tail")},
 /* 25 */ {0, {300,136,316,304}, CHECK, N_("Reverse head and tail")},
 /* 26 */ {0, {252,328,268,424}, CHECK, N_("Temporary")},
 /* 27 */ {0, {80,88,96,173}, EDITTEXT, ""},
 /* 28 */ {0, {56,16,72,80}, MESSAGE, N_("Name:")},
 /* 29 */ {0, {228,16,244,240}, MESSAGE, ""},
 /* 30 */ {0, {152,40,168,80}, MESSAGE, N_("At:")},
 /* 31 */ {0, {152,88,168,223}, MESSAGE, ""},
 /* 32 */ {0, {152,232,168,272}, BUTTON, N_("See")},
 /* 33 */ {0, {200,40,216,80}, MESSAGE, N_("At:")},
 /* 34 */ {0, {200,88,216,223}, MESSAGE, ""},
 /* 35 */ {0, {200,232,216,272}, BUTTON, N_("See")},
 /* 36 */ {0, {152,280,168,320}, BUTTON, N_("Info")},
 /* 37 */ {0, {200,280,216,320}, BUTTON, N_("Info")},
 /* 38 */ {0, {104,200,120,320}, CHECK, N_("Easy to Select")},
 /* 39 */ {0, {188,336,212,408}, BUTTON, N_("Attributes")}
};
DIALOG us_showarcdialog = {{50,75,375,508}, N_("Arc Information"), 0, 39, us_showarcdialogitems};

/* Text info */
DIALOGITEM us_showtextdialogitems[] =
{
 /*  1 */ {0, {216,248,240,320}, BUTTON, N_("OK")},
 /*  2 */ {0, {216,160,240,232}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {144,8,160,64}, RADIO, N_("Left")},
 /*  4 */ {0, {40,16,56,332}, EDITTEXT, ""},
 /*  5 */ {0, {68,232,84,340}, POPUP, ""},
 /*  6 */ {0, {80,8,96,80}, RADIO, N_("Center")},
 /*  7 */ {0, {96,8,112,80}, RADIO, N_("Bottom")},
 /*  8 */ {0, {112,8,128,64}, RADIO, N_("Top")},
 /*  9 */ {0, {128,8,144,72}, RADIO, N_("Right")},
 /* 10 */ {0, {160,8,176,104}, RADIO, N_("Lower right")},
 /* 11 */ {0, {176,8,192,104}, RADIO, N_("Lower left")},
 /* 12 */ {0, {192,8,208,104}, RADIO, N_("Upper right")},
 /* 13 */ {0, {208,8,224,96}, RADIO, N_("Upper left")},
 /* 14 */ {0, {224,8,240,80}, RADIO, N_("Boxed")},
 /* 15 */ {0, {68,152,84,231}, MESSAGE, N_("Text size:")},
 /* 16 */ {0, {64,16,80,110}, MESSAGE, N_("Text corner:")},
 /* 17 */ {0, {96,224,112,304}, EDITTEXT, ""},
 /* 18 */ {0, {120,224,136,304}, EDITTEXT, ""},
 /* 19 */ {0, {96,152,112,217}, MESSAGE, N_("X offset:")},
 /* 20 */ {0, {120,152,136,217}, MESSAGE, N_("Y offset:")},
 /* 21 */ {0, {80,112,112,144}, ICON, (char *)us_icon200},
 /* 22 */ {0, {112,112,144,144}, ICON, (char *)us_icon201},
 /* 23 */ {0, {144,112,176,144}, ICON, (char *)us_icon202},
 /* 24 */ {0, {176,112,208,144}, ICON, (char *)us_icon203},
 /* 25 */ {0, {208,112,240,144}, ICON, (char *)us_icon204},
 /* 26 */ {0, {8,16,24,340}, MESSAGE, ""},
 /* 27 */ {0, {176,190,196,290}, BUTTON, N_("Edit Text")},
 /* 28 */ {0, {148,152,164,340}, CHECK, N_("Only visible inside facet")}
};
DIALOG us_showtextdialog = {{50,75,304,424}, N_("Information on Highlighted Text"), 0, 28, us_showtextdialogitems};

/* Port info */
DIALOGITEM us_portinfodialogitems[] =
{
 /*  1 */ {0, {188,336,212,408}, BUTTON, N_("OK")},
 /*  2 */ {0, {116,336,140,408}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {120,8,136,56}, RADIO, N_("Left")},
 /*  4 */ {0, {8,112,24,408}, EDITTEXT, ""},
 /*  5 */ {0, {72,232,88,354}, POPUP, ""},
 /*  6 */ {0, {56,8,72,88}, RADIO, N_("Center")},
 /*  7 */ {0, {72,8,88,80}, RADIO, N_("Bottom")},
 /*  8 */ {0, {88,8,104,56}, RADIO, N_("Top")},
 /*  9 */ {0, {104,8,120,64}, RADIO, N_("Right")},
 /* 10 */ {0, {136,8,152,104}, RADIO, N_("Lower right")},
 /* 11 */ {0, {152,8,168,96}, RADIO, N_("Lower left")},
 /* 12 */ {0, {168,8,184,104}, RADIO, N_("Upper right")},
 /* 13 */ {0, {184,8,200,96}, RADIO, N_("Upper left")},
 /* 14 */ {0, {72,160,88,231}, MESSAGE, N_("Text size:")},
 /* 15 */ {0, {152,336,176,408}, BUTTON, N_("Attributes")},
 /* 16 */ {0, {40,16,56,107}, MESSAGE, N_("Text corner:")},
 /* 17 */ {0, {104,232,120,312}, EDITTEXT, ""},
 /* 18 */ {0, {128,232,144,312}, EDITTEXT, ""},
 /* 19 */ {0, {104,160,120,225}, MESSAGE, N_("X offset:")},
 /* 20 */ {0, {128,160,144,225}, MESSAGE, N_("Y offset:")},
 /* 21 */ {0, {56,112,88,144}, ICON, (char *)us_icon200},
 /* 22 */ {0, {88,112,120,144}, ICON, (char *)us_icon201},
 /* 23 */ {0, {120,112,152,144}, ICON, (char *)us_icon202},
 /* 24 */ {0, {152,112,184,144}, ICON, (char *)us_icon203},
 /* 25 */ {0, {184,112,216,144}, ICON, (char *)us_icon205},
 /* 26 */ {0, {8,8,24,104}, MESSAGE, N_("Export name:")},
 /* 27 */ {0, {40,272,56,416}, POPUP, ""},
 /* 28 */ {0, {40,160,56,271}, MESSAGE, N_("Characteristics:")},
 /* 29 */ {0, {184,160,200,272}, CHECK, N_("Always drawn")},
 /* 30 */ {0, {160,160,176,252}, CHECK, N_("Body only")}
};
DIALOG us_portinfodialog = {{50,75,275,500}, N_("Export Information"), 0, 30, us_portinfodialogitems};

void us_getinfonode(NODEINST *ni, PORTPROTO *fromport);
void us_getinfoarc(ARCINST *ai);
void us_getinfotext(HIGHLIGHT *high, INTBIG canspecialize);
INTBIG us_dlogchatportproto(NODEINST*, PORTPROTO*, PORTPROTO*, INTBIG);
void us_updatenodeinfo(NODEINST*, VARIABLE*, char*, char*, char*);
void us_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos);
void us_getnodedisplaysize(NODEINST *ni, INTBIG *xsize, INTBIG *ysize);
void us_setnodefromdisplayinfo(NODEINST *ni, INTBIG xs, INTBIG ys, INTBIG xc, INTBIG yc,
	INTBIG r, INTBIG t, INTBIG positionchanged);

/*
 * special case for the "Multiple-object Get Info" dialog
 * list of objects       = 3 (scroll)
 * object count          = 4 (static text)
 * node X position       = 6 (edit text)
 * node Y position       = 8 (edit text)
 * node X size           = 10 (edit text)
 * node Y size           = 12 (edit text)
 * arc width             = 14 (edit text)
 * info                  = 17 (button)
 */
INTSML us_showdlog(INTSML canspecialize)
{
	HIGHLIGHT high, *manyhigh;
	char buf[200], *pt;
	REGISTER NODEINST *ni, *ni1, *ni2;
	REGISTER ARCINST *ai;
	REGISTER GEOM *geom, *got1, *got2;
	REGISTER INTSML nodeinfochanged, arcinfochanged, gotxpos, gotypos, gotxsize,
		gotysize, gotwidth, positionchanged;
	REGISTER INTBIG len, i, cx1, cy1, cx2, cy2, dx, dy, swap, distx, disty,
		nodistx, nodisty, width, value, xyrev;
	INTBIG cx, cy, lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2,
		xvalue, yvalue, xpos, ypos, xsize, ysize;
	XARRAY trans;
	REGISTER INTBIG itemHit, which, highlightchanged;
	REGISTER VARIABLE *var;

	/* see if anything is highlighted */
	var = getvalkey((INTBIG)us_aid, VAID, VSTRING|VISARRAY, us_highlighted);
	if (var == NOVARIABLE)
	{
		us_abortcommand(_("Nothing is highlighted"));
		return(0);
	}

	/* special dialog when only 1 highlighted object */
	len = getlength(var);
	if (len == 1)
	{
		/* get the one highlighted object */
		if (us_makehighlight(((char **)var->addr)[0], &high) != 0)
		{
			us_abortcommand(_("Highlight unintelligible"));
			return(0);
		}

		if ((high.status&HIGHTYPE) == HIGHTEXT)
		{
			us_getinfotext(&high, canspecialize);
			return(0);
		}
		if ((high.status&HIGHTYPE) == HIGHFROM)
		{
			if (high.fromgeom->entrytype == OBJARCINST)
			{
				/* arc getinfo */
				ai = (ARCINST *)high.fromgeom->entryaddr.ai;
				us_getinfoarc(ai);
				return(0);
			}
			ni = (NODEINST *)high.fromgeom->entryaddr.ni;
			us_getinfonode(ni, high.fromport);
			return(0);
		}
	}

	/* multiple objects highlighted: remember them all */
	manyhigh = (HIGHLIGHT *)emalloc(len * (sizeof (HIGHLIGHT)), el_tempcluster);
	if (manyhigh == 0) return(0);
	for(i=0; i<len; i++)
	{
		if (us_makehighlight(((char **)var->addr)[i], &manyhigh[i]) != 0)
		{
			us_abortcommand(_("Highlight unintelligible"));
			break;
		}
	}

	if (DiaInitDialog(&us_multigetinfodialog) != 0)
	{
		efree((char *)manyhigh);
		return(0);
	}
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCDOUBLEQUIT|SCREPORT);

	/* multiple objects selected: list them */
	sprintf(buf, "%ld %s:", len, makeplural(_("selection"), len));
	DiaSetText(4, buf);
	got1 = got2 = NOGEOM;
	gotxpos = gotypos = gotxsize = gotysize = gotwidth = 0;
	for(i=0; i<len; i++)
	{
		(void)initinfstr();
		switch (manyhigh[i].status&HIGHTYPE)
		{
			case HIGHFROM:
				geom = manyhigh[i].fromgeom;
				cx = (geom->lowx + geom->highx) / 2;
				cy = (geom->lowy + geom->highy) / 2;
				if (geom->entrytype == OBJNODEINST)
				{
					ni = (NODEINST *)geom->entryaddr.ni;
					(void)addstringtoinfstr(_("Node "));
					(void)addstringtoinfstr(describenodeinst(ni));
					var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center);
					if (var != NOVARIABLE)
					{
						dx = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
							(ni->proto->lowx+ni->proto->highx)/2;
						dy = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
							(ni->proto->lowy+ni->proto->highy)/2;
						makerot(ni, trans);
						xform(dx, dy, &cx, &cy, trans);
					}

					/* accumulate X and Y size */
					if (ni->proto->primindex != 0)
					{
						us_getnodedisplaysize(ni, &xvalue, &yvalue);
						if (gotxsize == 0)
						{
							xsize = xvalue;
							gotxsize = 1;
						} else if (gotxsize == 1)
						{
							if (xsize != xvalue) gotxsize = -1;
						}
						if (gotysize == 0)
						{
							ysize = yvalue;
							gotysize = 1;
						} else if (gotysize == 1)
						{
							if (ysize != yvalue) gotysize = -1;
						}
					}

					/* accumulate X and Y position */
					us_getnodedisplayposition(ni, &xvalue, &yvalue);
					if (gotxpos == 0)
					{
						xpos = xvalue;
						gotxpos = 1;
					} else if (gotxpos == 1)
					{
						if (xpos != xvalue) gotxpos = -1;
					}
					if (gotypos == 0)
					{
						ypos = yvalue;
						gotypos = 1;
					} else if (gotypos == 1)
					{
						if (ypos != yvalue) gotypos = -1;
					}
				} else
				{
					ai = (ARCINST *)geom->entryaddr.ai;
					(void)addstringtoinfstr(_("Arc "));
					(void)addstringtoinfstr(describearcinst(ai));
					value = ai->width - arcwidthoffset(ai);
					if (gotwidth == 0)
					{
						width = value;
						gotwidth = 1;
					} else if (gotwidth == 1)
					{
						if (width != value) gotwidth = -1;
					}
				}
				if (i == 0)
				{
					cx1 = cx;
					cy1 = cy;
					got1 = geom;
				} else if (i == 1)
				{
					cx2 = cx;
					cy2 = cy;
					got2 = geom;
				}
				break;
			case HIGHBBOX:
				(void)formatinfstr(_("Bounds: X from %s to %s, Y from %s to %s"), latoa(manyhigh[i].stalx),
					latoa(manyhigh[i].stahx), latoa(manyhigh[i].staly), latoa(manyhigh[i].stahy));
				break;
			case HIGHLINE:
				(void)formatinfstr(_("Line (%s, %s) to (%s, %s)"), latoa(manyhigh[i].stalx),
					latoa(manyhigh[i].staly), latoa(manyhigh[i].stahx), latoa(manyhigh[i].stahy));
				break;
			case HIGHTEXT:
				if (manyhigh[i].fromport != NOPORTPROTO)
				{
					(void)formatinfstr(_("Port "));
					(void)addstringtoinfstr(manyhigh[i].fromport->protoname);
					break;
				}
				if (manyhigh[i].fromvar != NOVARIABLE)
				{
					if (manyhigh[i].fromport != NOPORTPROTO)
					{
						(void)formatinfstr(_("Text on port %s"), manyhigh[i].fromport->protoname);
						break;
					}
					if (manyhigh[i].fromgeom == NOGEOM)
					{
						(void)formatinfstr(_("Text on facet %s"), describenodeproto(manyhigh[i].facet));
						break;
					}
					if (manyhigh[i].fromgeom->entrytype == OBJARCINST)
					{
						ai = (ARCINST *)manyhigh[i].fromgeom->entryaddr.ai;
						(void)formatinfstr(_("Text on arc %s"), describearcinst(ai));
						break;
					}
					ni = (NODEINST *)manyhigh[i].fromgeom->entryaddr.ni;
					(void)formatinfstr(_("Text on node %s"), describenodeinst(ni));
					break;
				}
				(void)addstringtoinfstr(_("Text object"));
				break;
		}
		DiaStuffLine(3, returninfstr());
	}

	/* if there are exactly two node/arc objects, show the distance between them */
	if (len == 2 && got1 != NOGEOM && got2 != NOGEOM)
	{
		DiaStuffLine(3, "----------------------------");
		(void)initinfstr();
		(void)formatinfstr(_("Distance between centers: X=%s Y=%s"), latoa(abs(cx1-cx2)), latoa(abs(cy1-cy2)));
		DiaStuffLine(3, returninfstr());
		if (got1->entrytype == OBJNODEINST && got1->entryaddr.ni->proto->primindex == 0 &&
			got2->entrytype == OBJNODEINST && got2->entryaddr.ni->proto->primindex == 0)
		{
			/* report edge distance between two facet instances */
			ni1 = got1->entryaddr.ni;
			lx1 = ni1->lowx;   hx1 = ni1->highx;
			ly1 = ni1->lowy;   hy1 = ni1->highy;
			makerot(ni1, trans);
			xform(lx1, ly1, &lx1, &ly1, trans);
			xform(hx1, hy1, &hx1, &hy1, trans);
			if (hx1 < lx1) { swap = lx1;   lx1 = hx1;   hx1 = swap; }
			if (hy1 < ly1) { swap = ly1;   ly1 = hy1;   hy1 = swap; }

			ni2 = got2->entryaddr.ni;
			lx2 = ni2->lowx;   hx2 = ni2->highx;
			ly2 = ni2->lowy;   hy2 = ni2->highy;
			makerot(ni2, trans);
			xform(lx2, ly2, &lx2, &ly2, trans);
			xform(hx2, hy2, &hx2, &hy2, trans);
			if (hx2 < lx2) { swap = lx2;   lx2 = hx2;   hx2 = swap; }
			if (hy2 < ly2) { swap = ly2;   ly2 = hy2;   hy2 = swap; }

			nodistx = nodisty = 0;
			if (lx1 > hx2) distx = lx1 - hx2; else
				if (lx2 > hx1) distx = lx2 - hx1; else
					nodistx = 1;
			if (ly1 > hy2) disty = ly1 - hy2; else
				if (ly2 > hy1) disty = ly2 - hy1; else
					nodisty = 1;
			if (nodistx != 0 && nodisty != 0) DiaStuffLine(3, _("Facets overlap")); else
			{
				(void)initinfstr();
				(void)addstringtoinfstr(_("Distance between edges:"));
				if (nodistx == 0)
				{
					(void)formatinfstr(_(" X=%s"), latoa(distx));
				}
				if (nodisty == 0)
				{
					(void)formatinfstr(_(" Y=%s"), latoa(disty));
				}
				DiaStuffLine(3, returninfstr());
			}
		}
	}
	DiaSelectLine(3, 0);

	if (gotxpos == 1) DiaSetText(6, latoa(xpos));
	if (gotypos == 1) DiaSetText(8, latoa(ypos));
	if (gotxsize == 1) DiaSetText(10, latoa(xsize));
	if (gotysize == 1) DiaSetText(12, latoa(ysize));
	if (gotwidth == 1) DiaSetText(14, latoa(width));

	/* loop dialog */
	highlightchanged = 0;
	nodeinfochanged = arcinfochanged = positionchanged = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL || itemHit == 17) break;
		if (itemHit == 3)
		{
			which = DiaGetCurLine(3);
			if (which >= len)
			{
				DiaDimItem(17);
				continue;
			}
			DiaUnDimItem(17);
			high = manyhigh[which];
			us_clearhighlightcount();
			(void)us_addhighlight(&high);
			us_showallhighlight();
			us_endchanges(NOWINDOWPART);
			highlightchanged = 1;
			continue;
		}
		if (itemHit == 6 || itemHit == 8 || itemHit == 10 || itemHit == 12)
		{
			nodeinfochanged = 1;
			if (itemHit == 6 || itemHit == 8) positionchanged = 1;
			continue;
		}
		if (itemHit == 14)
		{
			arcinfochanged = 1;
			continue;
		}
	}

	/* remember the selected item */
	which = DiaGetCurLine(3);

	/* if not switching to another get-info, restore highlighting */
	if (itemHit != 17 && highlightchanged != 0)
	{
		us_clearhighlightcount();
		for(i=0; i<len; i++)
			(void)us_addhighlight(&manyhigh[i]);
	}

	/* accept multiple changes */
	if (itemHit != CANCEL && (arcinfochanged != 0 || nodeinfochanged != 0))
	{
		us_pushhighlight();
		us_clearhighlightcount();
		for(i=0; i<len; i++)
		{
			high = manyhigh[i];
			if ((high.status&HIGHTYPE) != HIGHFROM) continue;
			if (high.fromgeom->entrytype == OBJARCINST)
			{
				if (arcinfochanged != 0)
				{
					ai = (ARCINST *)high.fromgeom->entryaddr.ai;
					value = atola(DiaGetText(14));
					if (value >= 0)
					{
						value = arcwidthoffset(ai) + value;
						if (value != ai->width)
						{
							startobjectchange((INTBIG)ai, VARCINST);
							(void)modifyarcinst(ai, value - ai->width, 0, 0, 0, 0);
							endobjectchange((INTBIG)ai, VARCINST);
						}
					}
				}
			} else
			{
				if (nodeinfochanged != 0)
				{
					ni = (NODEINST *)high.fromgeom->entryaddr.ni;
					us_getnodedisplaysize(ni, &xsize, &ysize);
					xyrev = 0;
					if (ni->transpose == 0)
					{
						if (ni->rotation == 900 || ni->rotation == 2700) xyrev = 1;
					} else
					{
						if (ni->rotation == 0 || ni->rotation == 1800) xyrev = 1;
					}
					us_getnodedisplayposition(ni, &xpos, &ypos);
					pt = DiaGetText(6);
					if (*pt != 0) xpos = atola(pt);
					pt = DiaGetText(8);
					if (*pt != 0) ypos = atola(pt);
					if (ni->proto->primindex != 0)
					{
						pt = DiaGetText(10);
						if (*pt != 0)
						{
							if (xyrev == 0) xsize = atola(pt); else
								ysize = atola(pt);
						}
						pt = DiaGetText(12);
						if (*pt != 0)
						{
							if (xyrev == 0) ysize = atola(pt); else
								xsize = atola(pt);
						}
					}
					us_setnodefromdisplayinfo(ni, xsize, ysize, xpos, ypos,
						ni->rotation, ni->transpose, positionchanged);
				}
			}
		}
		(void)us_pophighlight(1);
	}
	if (itemHit == 17) high = manyhigh[which];

	/* cleanup */
	DiaDoneDialog();
	efree((char *)manyhigh);

	/* if info requested for one of the objects, give it now */
	if (itemHit == 17)
	{
		if ((high.status&HIGHTYPE) == HIGHTEXT)
		{
			us_getinfotext(&high, canspecialize);
			return(0);
		}
		if ((high.status&HIGHTYPE) == HIGHFROM)
		{
			if (high.fromgeom->entrytype == OBJARCINST)
			{
				/* arc getinfo */
				ai = (ARCINST *)high.fromgeom->entryaddr.ai;
				us_getinfoarc(ai);
				return(0);
			}
			ni = (NODEINST *)high.fromgeom->entryaddr.ni;
			us_getinfonode(ni, high.fromport);
			return(0);
		}
	}
	return(0);
}

/*
 * special case for the "Text Get Info" dialog
 * text name             = 4 (edit text)
 * text size             = 5 (popup)
 * X offset              = 17 (edit text)
 * Y offset              = 18 (edit text)
 * center                = 6 (radio)
 * bottom                = 7 (radio)
 * top                   = 8 (radio)
 * right                 = 9 (radio)
 * left                  = 3 (radio)
 * lower right           = 10 (radio)
 * lower left            = 11 (radio)
 * upper right           = 12 (radio)
 * upper left            = 13 (radio)
 * boxed                 = 14 (radio)
 * title                 = 26 (message)
 * Only inside facet     = 28 (check)
 *
 * special case for the "Port Get Info" dialog
 * text name             = 4 (edit text)
 * text size             = 5 (popup)
 * X offset              = 17 (edit text)
 * Y offset              = 18 (edit text)
 * center                = 6 (radio)
 * bottom                = 7 (radio)
 * top                   = 8 (radio)
 * right                 = 9 (radio)
 * left                  = 3 (radio)
 * lower right           = 10 (radio)
 * lower left            = 11 (radio)
 * upper right           = 12 (radio)
 * upper left            = 13 (radio)
 * attributes            = 15 (button)
 * characteristics       = 27 (popup)
 * always drawn          = 29 (check)
 * body only             = 30 (check)
 */
void us_getinfotext(HIGHLIGHT *high, INTBIG canspecialize)
{
	INTBIG itemHit, j, haslw, trandessize, skipchrs, changed,
		posnotoffset, cantbox;
	INTSML x, y;
	char *str, *newstr, *pt, *formerstr, *paramstart[10], *newlang[15];
	RECTAREA itemRect;
	INTBIG descript, i, newval, newdescript, objtype, lambda,
		xcur, ycur, newbit, lindex, xc, yc, nlx, nhx, nly, nhy;
	REGISTER NODEINST *ni;
	REGISTER VARIABLE *var;
	REGISTER TECHNOLOGY *tech;
	REGISTER DIALOG *whichdialog;
	static char *sizenames[12] = {N_("4 Points"), N_("6 Points"), N_("8 Points"), N_("10 Points"), N_("12 Points"),
		N_("14 Points"), N_("16 Points"), N_("18 Points"), N_("20 Points"), N_("Small"), N_("Medium"), N_("Large")};
	static char *charnames[15] = {N_("Input"), N_("Output"), N_("Bidirectional"), N_("Power"), N_("Ground"),
		N_("Reference Output"), N_("Reference Input"), N_("Clock"), N_("Clock phase 1"), N_("Clock phase 2"),
		N_("Clock phase 3"), N_("Clock phase 4"), N_("Clock phase 5"), N_("Clock phase 6"), N_("Unknown")};
	static UINTBIG charlist[15] = {INPORT, OUTPORT, BIDIRPORT, PWRPORT, GNDPORT,
		REFOUTPORT, REFINPORT, CLKPORT, C1PORT, C2PORT, C3PORT, C4PORT, C5PORT, C6PORT};
	static INTBIG sizelist[12] = {TXT4P, TXT6P, TXT8P, TXT10P, TXT12P, TXT14P, TXT16P,
		TXT18P, TXT20P, TXTSMALL, TXTMEDIUM, TXTLARGE};
	static struct butlist poslist[10] =
	{
		{VTPOSCENT,       6},
		{VTPOSUP,         7},
		{VTPOSDOWN,       8},
		{VTPOSLEFT,       9},
		{VTPOSRIGHT,      3},
		{VTPOSUPLEFT,    10},
		{VTPOSUPRIGHT,   11},
		{VTPOSDOWNLEFT,  12},
		{VTPOSDOWNRIGHT, 13},
		{VTPOSBOXED,     14}
	};

	/* display text */
	formerstr = 0;
	skipchrs = 0;
	posnotoffset = 0;
	cantbox = 0;
	if (high->fromvar != NOVARIABLE)
	{
		if (high->fromgeom != NOGEOM)
		{
			if (high->fromgeom->entrytype == OBJNODEINST) objtype = VNODEINST; else
				objtype = VARCINST;
		}

		/* special case if known variables are selected */
		if (canspecialize != 0)
		{
			if (high->fromvar->key == sch_resistancekey)
			{
				i = us_resistancedlog(_("Resistor"), paramstart, (char *)high->fromvar->addr);
				if (i == 0) return;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_resistancekey,
					(INTBIG)paramstart[0], high->fromvar->type);
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)us_pophighlight(0);
				return;
			}
			if (high->fromvar->key == sch_capacitancekey)
			{
				str = (char *)high->fromvar->addr;
				while (*str == ' ') str++;
				if (*str == 'e' || *str == 'E') str++;
				i = us_capacitancedlog(paramstart, str);
				if (i == 0) return;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)initinfstr();
				for(pt = (char *)high->fromvar->addr; pt != str; pt++)
					(void)addtoinfstr(*pt);
				(void)addstringtoinfstr(paramstart[0]);
				(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_capacitancekey,
					(INTBIG)returninfstr(), high->fromvar->type);
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)us_pophighlight(0);
				return;
			}
			if (high->fromvar->key == sch_inductancekey)
			{
				i = us_inductancedlog(paramstart, (char *)high->fromvar->addr);
				if (i == 0) return;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_inductancekey,
					(INTBIG)paramstart[0], high->fromvar->type);
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)us_pophighlight(0);
				return;
			}
			if (high->fromvar->key == sch_sourcekey)
			{
				i = us_sourcedlog(paramstart, (char *)high->fromvar->addr);
				if (i == 0) return;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_sourcekey,
					(INTBIG)paramstart[0], high->fromvar->type);
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)us_pophighlight(0);
				return;
			}
			if (high->fromvar->key == sch_diodekey)
			{
				str = (char *)high->fromvar->addr;
				while (*str == ' ') str++;
				if (*str == 'z' || *str == 'Z') str++;
				i = us_areadlog(_("Diode"), paramstart, str);
				if (i == 0) return;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)initinfstr();
				for(pt = (char *)high->fromvar->addr; pt != str; pt++)
					(void)addtoinfstr(*pt);
				(void)addstringtoinfstr(paramstart[0]);
				(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_diodekey,
					(INTBIG)returninfstr(), high->fromvar->type);
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
				(void)us_pophighlight(0);
				return;
			}
			if (high->fromvar->key == sch_twoportkey)
			{
				str = (char *)high->fromvar->addr;
				while (*str == ' ') str++;
				if (*str == 'h' || *str == 'H')
				{
					str++;
					i = us_resistancedlog(_("CCVS"), paramstart, str);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(pt = (char *)high->fromvar->addr; pt != str; pt++)
						(void)addtoinfstr(*pt);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_twoportkey,
						(INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				} else if (*str == 'g' || *str == 'G')
				{
					str++;
					i = us_vccsdlog(paramstart, str);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(pt = (char *)high->fromvar->addr; pt != str; pt++)
						(void)addtoinfstr(*pt);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_twoportkey,
						(INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				} else if (*str == 'u' || *str == 'U')
				{
					str++;
					i = us_gaindlog(_("VCVS"), paramstart, str);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(pt = (char *)high->fromvar->addr; pt != str; pt++)
						(void)addtoinfstr(*pt);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_twoportkey,
						(INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				} else if (*str == 'f' || *str == 'F')
				{
					str++;
					i = us_gaindlog(_("CCCS"), paramstart, str);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(pt = (char *)high->fromvar->addr; pt != str; pt++)
						(void)addtoinfstr(*pt);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype, sch_twoportkey,
						(INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				}
			}
			if (high->fromvar->key == sch_transistortypekey)
			{
				str = (char *)high->fromvar->addr;
				haslw = trandessize = 0;
				if (namesamen(str, "nmos", 4) == 0)  { trandessize = 4;  haslw = 1;   } else
				if (namesamen(str, "dmos", 4) == 0)  { trandessize = 4;  haslw = 1;   } else
				if (namesamen(str, "pmos", 4) == 0)  { trandessize = 4;  haslw = 1;   } else
				if (namesamen(str, "npn", 3) == 0)   { trandessize = 3;  } else
				if (namesamen(str, "pnp", 3) == 0)   { trandessize = 3;  } else
				if (namesamen(str, "njfet", 5) == 0) { trandessize = 5;  } else
				if (namesamen(str, "pjfet", 5) == 0) { trandessize = 5;  } else
				if (namesamen(str, "dmes", 4) == 0)  { trandessize = 4;  } else
				if (namesamen(str, "emes", 4) == 0)  { trandessize = 4;  }
				if (haslw != 0)
				{
					i = us_widlendlog(paramstart, &str[trandessize]);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(i=0; i<trandessize; i++) (void)addtoinfstr(str[i]);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype,
						sch_transistortypekey, (INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				} else if (trandessize != 0)
				{
					i = us_areadlog(_("Transistor"), paramstart, &str[trandessize]);
					if (i == 0) return;
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)initinfstr();
					for(i=0; i<trandessize; i++) (void)addtoinfstr(str[i]);
					(void)addstringtoinfstr(paramstart[0]);
					(void)setvalkey((INTBIG)high->fromgeom->entryaddr.blind, objtype,
						sch_transistortypekey, (INTBIG)returninfstr(), high->fromvar->type);
					endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
					(void)us_pophighlight(0);
					return;
				}
			}

			/* if this is a displayable text variable, edit it in place */
			if ((high->fromvar->type&VDISPLAY) != 0 &&
				(high->fromvar->type&VTYPE) == VSTRING)
			{
				/* save and clear highlighting */
				us_pushhighlight();
				us_clearhighlightcount();

				/* edit the variable */
				if (high->fromport != NOPORTPROTO)
				{
					us_editvariabletext(high->fromvar, VPORTPROTO, (INTBIG)high->fromport,
						makename(high->fromvar->key));
				} else if (high->fromgeom == NOGEOM)
				{
					us_editvariabletext(high->fromvar, VNODEPROTO, (INTBIG)high->facet,
						makename(high->fromvar->key));
				} else
				{
					us_editvariabletext(high->fromvar, objtype, (INTBIG)high->fromgeom->entryaddr.blind,
						makename(high->fromvar->key));
				}

				/* restore highlighting */
				(void)us_pophighlight(0);
				return;
			}
		}

		/* display the text dialog box */
		whichdialog = &us_showtextdialog;
		if (DiaInitDialog(&us_showtextdialog) != 0) return;
		for(i=0; i<12; i++) newlang[i] = _(sizenames[i]);   DiaSetPopup(5, 12, newlang);
		DiaDimItem(27);

		(void)initinfstr();
		if (high->fromgeom == NOGEOM)
		{
			(void)formatinfstr(_("Text on facet '%s'"), describenodeproto(high->facet));
		} else if (high->fromport != NOPORTPROTO)
		{
			(void)formatinfstr(_("Text on port '%s'"), high->fromport->protoname);
		} else
		{
			if (high->fromgeom->entrytype == OBJNODEINST)
			{
				if (high->fromgeom->entryaddr.ni->proto == gen_invispinprim)
				{
					if (namesame(makename(high->fromvar->key), "VERILOG_code") == 0)
						(void)addstringtoinfstr(_("Verilog code")); else
					if (namesame(makename(high->fromvar->key), "VERILOG_declaration") == 0)
						(void)addstringtoinfstr(_("Verilog declaration")); else
							(void)addstringtoinfstr(_("Text on Message Node"));
					DiaSetText(19, _("X position:"));
					DiaSetText(20, _("Y position:"));
					posnotoffset = 1;
				} else
				{
					(void)formatinfstr(_("Text on node '%s'"),
						describenodeinst(high->fromgeom->entryaddr.ni));
				}
				boundobj(high->fromgeom, &nlx, &nhx, &nly, &nhy);
				if (nhx == nlx || nhy == nly)
				{
					cantbox = 1;
					DiaDimItem(14);
				}
			} else
			{
				(void)formatinfstr(_("Text on arc '%s'"),
					describearcinst(high->fromgeom->entryaddr.ai));
			}
		}
		DiaSetText(26, returninfstr());
		lindex = -1;
		DiaEditControl(4);
		if ((high->fromvar->type&VISARRAY) != 0)
		{
			if (getlength(high->fromvar) == 1) lindex = 0; else
			{
				DiaNoEditControl(4);
				DiaUnDimItem(27);
			}
		} else skipchrs = (high->fromvar->type&VLENGTH) >> VLENGTHSH;
		if ((high->fromvar->type&VDISPLAY) != 0 &&
			(high->fromvar->textdescript&VTDISPLAYPART) == VTDISPLAYNAMEVALUE &&
				(high->fromvar->type&VISARRAY) == 0)
		{
			str = (char *)high->fromvar->addr;
		} else
		{
			(void)allocstring(&formerstr, describevariable(high->fromvar, (INTSML)lindex, -1),
				el_tempcluster);
			str = formerstr;
		}
		descript = high->fromvar->textdescript;
		DiaSetText(-4, &str[skipchrs]);
	} else if (high->fromport != NOPORTPROTO)
	{
		/* display the port dialog box */
		whichdialog = &us_portinfodialog;
		if (DiaInitDialog(&us_portinfodialog) != 0) return;
		for(i=0; i<12; i++) newlang[i] = _(sizenames[i]);   DiaSetPopup(5, 12, newlang);
		for(i=0; i<15; i++) newlang[i] = _(charnames[i]);   DiaSetPopup(27, 15, newlang);

		str = high->fromport->protoname;
		descript = high->fromport->textdescript;
		objtype = VNODEINST;

		/* set the port characteristics button */
		for(i=0; i<15; i++)
			if (charlist[i] == (high->fromport->userbits&STATEBITS))
		{
			DiaSetPopupEntry(27, i);
			break;
		}
		if ((high->fromport->userbits&PORTDRAWN) != 0) DiaSetControl(29, 1);
		if ((high->fromport->userbits&BODYONLY) != 0) DiaSetControl(30, 1);
		DiaSetText(-4, str);
		DiaEditControl(4);
		cantbox = 1;
	} else if (high->fromgeom->entrytype == OBJNODEINST)
	{
		/* display the text dialog box */
		whichdialog = &us_showtextdialog;
		if (DiaInitDialog(&us_showtextdialog) != 0) return;
		for(i=0; i<12; i++) newlang[i] = _(sizenames[i]);   DiaSetPopup(5, 12, newlang);

		ni = high->fromgeom->entryaddr.ni;
		str = describenodeproto(ni->proto);
		descript = ni->textdescript;
		objtype = VNODEINST;
		DiaNoEditControl(4);
		DiaSetText(4, str);
		DiaSetText(26, _("Text information for facet name:"));
	} else return;

	/* if this is on a node and the node is rotated, modify grab-point */
	if (high->fromgeom != NOGEOM && high->fromgeom->entrytype == OBJNODEINST)
	{
		ni = high->fromgeom->entryaddr.ni;
		if (ni->rotation != 0 || ni->transpose != 0)
		{
			descript = us_rotatedescript(high->fromgeom, descript);
		}
	}

	/* set the orientation button */
	for(i=0; i<10; i++)
		if (poslist[i].value == (descript&VTPOSITION))
	{
		DiaSetControl(poslist[i].button, 1);
		break;
	}

	/* set the size button */
	for(i=0; i<12; i++)
		if (sizelist[i] == ((descript&VTSIZE) >> VTSIZESH))
	{
		DiaSetPopupEntry(5, i);
		break;
	}

	/* set the interior checkbox */
	if ((descript&VTINTERIOR) != 0) DiaSetControl(28, 1);

	/* set offsets */
	if (posnotoffset != 0)
	{
		ni = high->fromgeom->entryaddr.ni;
		DiaSetText(17, latoa((ni->lowx + ni->highx) / 2));
		DiaSetText(18, latoa((ni->lowy + ni->highy) / 2));
	} else
	{
		tech = us_hightech(high);
		lambda = el_curlib->lambda[tech->techindex];
		i = (descript&VTXOFF) >> VTXOFFSH;
		if ((descript&VTXOFFNEG) != 0) i = -i;
		DiaSetText(17, latoa(i * lambda / 4));
		j = (descript&VTYOFF) >> VTYOFFSH;
		if ((descript&VTYOFFNEG) != 0) j = -j;
		DiaSetText(18, latoa(j * lambda / 4));
	}

	/* loop until done */
	changed = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL ||
			(itemHit == 15 && whichdialog == &us_portinfodialog) ||
			(itemHit == 27 && whichdialog == &us_showtextdialog)) break;
		if (itemHit >= 21 && itemHit <= 25)
		{
			DiaItemRect(itemHit, &itemRect);
			DiaGetMouse(&x, &y);
			itemHit = (itemHit-21) * 2;
			if (y > (itemRect.top + itemRect.bottom) / 2) itemHit++;
			itemHit = poslist[itemHit].button;
			if (itemHit == 14 && cantbox != 0) continue;
		}
		for(i=0; i<10; i++) if (itemHit == poslist[i].button)
		{
			for(j=0; j<10; j++) DiaSetControl(poslist[j].button, 0);
			DiaSetControl(itemHit, 1);
			changed++;
			continue;
		}
		if (itemHit == 28 || itemHit == 29 || itemHit == 30)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			changed++;
		}
		if (itemHit == 5 || itemHit == 17 || itemHit == 18 ||
			(itemHit == 27 && whichdialog == &us_portinfodialog)) changed++;
	}

	if (itemHit != CANCEL)
	{
		/* get new port characteristics if applicable */
		if (whichdialog == &us_portinfodialog && changed != 0)
		{
			newbit = high->fromport->userbits;
			i = DiaGetPopupEntry(27);
			newbit = (newbit & ~STATEBITS) | charlist[i];
			if (DiaGetControl(29) == 0) newbit &= ~PORTDRAWN; else
				newbit |= PORTDRAWN;
			if (DiaGetControl(30) == 0) newbit &= ~BODYONLY; else
				newbit |= BODYONLY;
			if (newbit != (INTBIG)high->fromport->userbits)
			{
				setval((INTBIG)high->fromport, VPORTPROTO, "userbits",
					newbit, VINTEGER);
				changeallports(high->fromport);
			}
		}

		/* get the new descriptor */
		newdescript = descript;
		if (changed != 0)
		{
			xcur = atola(DiaGetText(17));
			ycur = atola(DiaGetText(18));
			if (posnotoffset != 0)
			{
				ni = high->fromgeom->entryaddr.ni;
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)ni, VNODEINST);
				xc = (ni->lowx + ni->highx) / 2;
				yc = (ni->lowy + ni->highy) / 2;
				modifynodeinst(ni, xcur-xc, ycur-yc, xcur-xc, ycur-yc, 0, 0);
				endobjectchange((INTBIG)ni, VNODEINST);
				(void)us_pophighlight(1);
			} else
			{
				newdescript = us_setdescriptoffset(newdescript, xcur*4/lambda, ycur*4/lambda);
			}
			j = DiaGetPopupEntry(5);
			newdescript = (newdescript & ~VTSIZE) | (sizelist[j] << VTSIZESH);
			for(j=0; j<10; j++)
				if (DiaGetControl(poslist[j].button) != 0) break;
			newdescript = (newdescript & ~VTPOSITION) | poslist[j].value;
			if (whichdialog == &us_showtextdialog)
			{
				if (DiaGetControl(28) != 0) newdescript |= VTINTERIOR; else
					newdescript &= ~VTINTERIOR;
			}

			/* if this is on a node and the node is rotated, modify grab-point */
			if (high->fromgeom != NOGEOM && high->fromgeom->entrytype == OBJNODEINST)
			{
				ni = high->fromgeom->entryaddr.ni;
				if (ni->rotation != 0 || ni->transpose != 0)
				{
					newdescript = us_rotatedescriptI(high->fromgeom, newdescript);
				}
			}
		}

		/* get the new name */
		newstr = DiaGetText(4);

		/* see if changes were made */
		if (newdescript != descript || strcmp(&str[skipchrs], newstr) != 0)
		{
			/* save highlighting */
			us_pushhighlight();
			us_clearhighlightcount();

			/* set the new descriptor */
			if (high->fromgeom == NOGEOM)
			{
				us_undrawfacetvariable(high->fromvar, high->facet);
			} else
			{
				startobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
			}

			/* handle changes */
			if (newdescript != descript) us_modifytextdescript(high, newdescript);
			if (strcmp(&str[skipchrs], newstr) != 0)
			{
				/* message field changed */
				var = high->fromvar;
				if (var != NOVARIABLE)
				{
					switch (var->type&VTYPE)
					{
						case VINTEGER:
						case VSHORT:
							newval = myatoi(newstr);
							break;
						case VSTRING:
							if (skipchrs == 0) newval = (INTBIG)newstr; else
							{
								(void)initinfstr();
								for(j=0; j<skipchrs; j++)
									if (str[j] != 0) (void)addtoinfstr(str[j]);
								(void)addstringtoinfstr(newstr);
								newval = (INTBIG)returninfstr();
							}
							break;
						case VFLOAT:
						case VDOUBLE:
							newval = castint((float)atof(newstr));
							break;
					}
					if ((var->type&VISARRAY) == 0)
					{
						if (high->fromport != NOPORTPROTO)
						{
							(void)setval((INTBIG)high->fromport, VPORTPROTO,
								makename(var->key), newval, var->type);
						} else if (high->fromgeom == NOGEOM)
						{
							(void)setval((INTBIG)high->facet, VNODEPROTO,
								makename(var->key), newval, var->type);
						} else
						{
							(void)setval((INTBIG)high->fromgeom->entryaddr.blind, objtype,
								makename(var->key), newval, var->type);
						}
					} else
					{
						(void)setind((INTBIG)high->fromgeom->entryaddr.blind, objtype,
							makename(var->key), 0, newval);
					}
				} else if (high->fromport != NOPORTPROTO)
				{
					us_renameport(high->fromport, newstr);
				}
			}

			/* redisplay the text */
			if (high->fromgeom == NOGEOM)
			{
				us_drawfacetvariable(high->fromvar, high->facet);
			} else
			{
				endobjectchange((INTBIG)high->fromgeom->entryaddr.blind, objtype);
			}

			/* restore highlighting */
			(void)us_pophighlight(1);
		}
	}
	DiaDoneDialog();
	if (high->fromvar != NOVARIABLE && itemHit == 27)
	{
		/* save and clear highlighting */
		us_pushhighlight();
		us_clearhighlightcount();

		/* edit the variable */
		us_editvariabletext(high->fromvar, objtype,
			(INTBIG)high->fromgeom->entryaddr.blind, makename(high->fromvar->key));

		/* restore highlighting */
		(void)us_pophighlight(0);
	}
	if (itemHit == 15 && whichdialog == &us_portinfodialog)
		(void)us_attributesdlog();
	if (formerstr != 0) efree(formerstr);
}

/*
 * special case for the "Arc Get Info" dialog
 * rigid                 = 3 (check)
 * fixed-angle           = 4 (check)
 * type                  = 5 (message)
 * network               = 6 (message)
 * name                  = 7 (edit text)
 * angle                 = 8 (message)
 * head node             = 9 (message)
 * bus size              = 10 (message)
 * tail node             = 11 (message)
 * slidable              = 19 (check)
 * negated               = 20 (check)
 * directional           = 21 (check)
 * ends extend           = 22 (check)
 * ignore head           = 23 (check)
 * ignore tail           = 24 (check)
 * reverse               = 25 (check)
 * temporarily           = 26 (check)
 * width                 = 27 (edit text)
 * constraints           = 29 (message)
 * head coordinate       = 31 (message)
 * see head              = 32 (button)
 * tail coordinate       = 34 (message)
 * see tail              = 35 (button)
 * head info             = 36 (button)
 * tail info             = 37 (button)
 * easy to select        = 38 (check)
 * attributes            = 39 (button)
 */
void us_getinfoarc(ARCINST *ai)
{
	INTBIG itemHit, rigstate, oldrigstate, changed;
	char ent[50], *str, *newstr;
	INTBIG i, wid, oldwid, end;
	REGISTER VARIABLE *var;
	HIGHLIGHT high;
	extern INTBIG cla_changeclock;	/* from layout constraints: "conlay.c" */

	if (DiaInitDialog(&us_showarcdialog) != 0) return;

	/* set prototype name */
	DiaSetText(5, ai->proto->protoname);

	/* load the network and arc names if any */
	var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name);
	if (var != NOVARIABLE)
	{
		str = (char *)var->addr;
		DiaSetText(-7, str);
	} else str = "";
	if (ai->network != NONETWORK)
		DiaSetText(6, describenetwork(ai->network)); else
			DiaSetText(6, _("*** NONE ***"));

	/* load the width */
	oldwid = ai->width - arcwidthoffset(ai);
	DiaSetText(27, latoa(oldwid));

	/* load the position */
	(void)sprintf(ent, "(%s,%s)", latoa(ai->end[1].xpos), latoa(ai->end[1].ypos));
	DiaSetText(31, ent);
	DiaSetText(9, describenodeinst(ai->end[1].nodeinst));
	(void)sprintf(ent, "(%s,%s)", latoa(ai->end[0].xpos), latoa(ai->end[0].ypos));
	DiaSetText(34, ent);
	DiaSetText(11, describenodeinst(ai->end[0].nodeinst));

	/* load angle */
	(void)sprintf(ent, " %ld", (ai->userbits&AANGLE) >> AANGLESH);
	DiaSetText(8, ent);

	/* load the selectability factor */
	if ((ai->userbits&HARDSELECTA) == 0) DiaSetControl(38, 1);

	/* load bus width if any */
	if (ai->network != NONETWORK && ai->network->signals > 1)
	{
		(void)sprintf(ent, " %d", ai->network->signals);
		DiaSetText(10, ent);
	} else DiaSetText(10, _("N/A"));

	/* set the constraint buttons */
	if (el_curconstraint == cla_constraint)
	{
		oldrigstate = 1;
		if (((ai->userbits&FIXED) == 0 || ai->changed == cla_changeclock+3) &&
			ai->changed != cla_changeclock+2)
		{
			if (ai->changed == cla_changeclock+3) oldrigstate = 3;
		} else
		{
			if (ai->changed == cla_changeclock+2) oldrigstate = 2; else
				oldrigstate = 0;
		}
		switch (oldrigstate)
		{
			case 0: DiaSetControl(3, 1);    break;
			case 1:                         break;
			case 2: DiaSetControl(3, 1);
			case 3: DiaSetControl(26, 1);   break;
		}
		if ((ai->userbits&FIXANG) != 0) DiaSetControl(4, 1);
		if ((ai->userbits&CANTSLIDE) == 0) DiaSetControl(19, 1);
	} else
	{
		DiaDimItem(3);
		DiaDimItem(4);
		DiaDimItem(19);
		DiaDimItem(26);
		newstr = (char *)(*(el_curconstraint->request))("describearc", (INTBIG)ai);
		if (*newstr != 0)
		{
			(void)initinfstr();
			(void)formatinfstr(_("Constraint: %s"), newstr);
			DiaSetText(29, returninfstr());
		}
	}
	if ((ai->userbits&ISNEGATED) != 0) DiaSetControl(20, 1);
	if ((ai->userbits&ISDIRECTIONAL) != 0) DiaSetControl(21, 1);
	if ((ai->userbits&NOEXTEND) == 0) DiaSetControl(22, 1);
	if ((ai->userbits&NOTEND1) != 0) DiaSetControl(23, 1);
	if ((ai->userbits&NOTEND0) != 0) DiaSetControl(24, 1);
	if ((ai->userbits&REVERSEEND) != 0) DiaSetControl(25, 1);

	/* if the arc can't be edited, disable all changes */
	if (us_canedit(ai->parent, NONODEPROTO, 0) != 0)
	{
		DiaDimItem(3);
		DiaDimItem(4);
		DiaDimItem(7);
		DiaDimItem(8);
		DiaDimItem(19);
		DiaDimItem(20);
		DiaDimItem(21);
		DiaDimItem(22);
		DiaDimItem(23);
		DiaDimItem(24);
		DiaDimItem(25);
		DiaDimItem(26);
		DiaDimItem(27);
		DiaDimItem(38);
	}

	/* loop until done */
	changed = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL || itemHit == 36 || itemHit == 37 ||
			itemHit == 39) break;
		if (itemHit == 3 || itemHit == 4 || itemHit == 19 || itemHit == 20 || itemHit == 21 ||
			itemHit == 22 || itemHit == 23 || itemHit == 24 || itemHit == 25 ||
			itemHit == 26 || itemHit == 38)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			changed++;
			continue;
		}
		if (itemHit == 7 || itemHit == 27)
		{
			changed++;
			continue;
		}
		if (itemHit == 32 || itemHit == 35)
		{
			/* highlight an end */
			if (itemHit == 32) end = 1; else end = 0;
			us_clearhighlightcount();
			high.status = HIGHFROM;
			high.facet = ai->parent;
			high.fromgeom = ai->end[end].nodeinst->geom;
			high.fromport = ai->end[end].portarcinst->proto;
			high.frompoint = 0;
			high.fromvar = NOVARIABLE;
			(void)us_addhighlight(&high);
			us_showallhighlight();
			us_endchanges(NOWINDOWPART);
			continue;
		}
	}

	if (itemHit != CANCEL && changed != 0)
	{
		us_pushhighlight();
		us_clearhighlightcount();
		startobjectchange((INTBIG)ai, VARCINST);
		wid = atola(DiaGetText(27));
		if (wid < 0) wid = oldwid;
		wid = arcwidthoffset(ai) + wid;
		startobjectchange((INTBIG)ai, VARCINST);
		if (DiaGetControl(3) == 0)
		{
			if (DiaGetControl(26) == 0) rigstate = 1; else
				rigstate = 3;
		} else
		{
			if (DiaGetControl(26) == 0) rigstate = 0; else
				rigstate = 2;
		}
		if (rigstate != oldrigstate) switch (rigstate)
		{
			case 0:
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPEREMOVETEMP,0);
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPERIGID,0);
				break;
			case 1:
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPEREMOVETEMP,0);
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPEUNRIGID,0);
				break;
			case 2:
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPETEMPRIGID,0);
				break;
			case 3:
				(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPETEMPUNRIGID,0);
				break;
		}
		i = DiaGetControl(4);
		if (i != 0 && (ai->userbits&FIXANG) == 0)
			(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPEFIXEDANGLE,0);
		if (i == 0 && (ai->userbits&FIXANG) != 0)
			(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPENOTFIXEDANGLE,0);
		i = DiaGetControl(19);
		if (i != 0 && (ai->userbits&CANTSLIDE) != 0)
			(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPESLIDABLE,0);
		if (i == 0 && (ai->userbits&CANTSLIDE) == 0)
			(void)(*el_curconstraint->setobject)((INTBIG)ai,VARCINST,CHANGETYPENOTSLIDABLE,0);
		i = DiaGetControl(20);
		if (i != 0 && (ai->userbits&ISNEGATED) == 0)
			(void)setval((INTBIG)ai, VARCINST,"userbits", ai->userbits | ISNEGATED, VINTEGER);
		if (i == 0 && (ai->userbits&ISNEGATED) != 0)
			(void)setval((INTBIG)ai, VARCINST,"userbits", ai->userbits & ~ISNEGATED, VINTEGER);
		i = DiaGetControl(21);
		if (i != 0 && (ai->userbits&ISDIRECTIONAL) == 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits | ISDIRECTIONAL, VINTEGER);
		if (i == 0 && (ai->userbits&ISDIRECTIONAL) != 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~ISDIRECTIONAL, VINTEGER);
		i = DiaGetControl(22);
		if (i != 0 && (ai->userbits&NOEXTEND) != 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~NOEXTEND, VINTEGER);
		if (i == 0 && (ai->userbits&NOEXTEND) == 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits | NOEXTEND, VINTEGER);
		i = DiaGetControl(23);
		if (i != 0 && (ai->userbits&NOTEND1) == 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits | NOTEND1, VINTEGER);
		if (i == 0 && (ai->userbits&NOTEND1) != 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~NOTEND1, VINTEGER);
		i = DiaGetControl(24);
		if (i != 0 && (ai->userbits&NOTEND0) == 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits | NOTEND0, VINTEGER);
		if (i == 0 && (ai->userbits&NOTEND0) != 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~NOTEND0, VINTEGER);
		i = DiaGetControl(25);
		if (i != 0 && (ai->userbits&REVERSEEND) == 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits | REVERSEEND, VINTEGER);
		if (i == 0 && (ai->userbits&REVERSEEND) != 0)
			(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~REVERSEEND, VINTEGER);
		if (DiaGetControl(38) != 0) ai->userbits &= ~HARDSELECTA; else
			ai->userbits |= HARDSELECTA;
		newstr = DiaGetText(7);
		while (*newstr == ' ') newstr++;
		if (strcmp(str, newstr) != 0)
		{
			if (*newstr == 0) us_setarcname(ai, (char *)0); else
				us_setarcname(ai, newstr);
		}
		(void)modifyarcinst(ai, wid - ai->width, 0, 0, 0, 0);
		endobjectchange((INTBIG)ai, VARCINST);
		(void)us_pophighlight(0);
	}
	DiaDoneDialog();
	if (itemHit == 36 || itemHit == 37)
	{
		if (itemHit == 36) end = 1; else end = 0;
		us_clearhighlightcount();
		high.status = HIGHFROM;
		high.facet = ai->parent;
		high.fromgeom = ai->end[end].nodeinst->geom;
		high.fromport = ai->end[end].portarcinst->proto;
		high.frompoint = 0;
		high.fromvar = NOVARIABLE;
		(void)us_addhighlight(&high);
		us_showallhighlight();
		us_endchanges(NOWINDOWPART);
		us_getinfonode(ai->end[end].nodeinst, ai->end[end].portarcinst->proto);
	}
	if (itemHit == 39)
		(void)us_attributesdlog();
}

void us_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos)
{
	REGISTER NODEPROTO *np;
	INTBIG cox, coy;
	REGISTER INTBIG dx, dy;
	REGISTER VARIABLE *var;
	XARRAY trans;

	np = ni->proto;
	if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
	{
		corneroffset(ni, np, ni->rotation, ni->transpose, &cox, &coy, 0);
		*xpos = ni->lowx+cox;
		*ypos = ni->lowy+coy;
	} else
	{
		var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center);
		if (var != NOVARIABLE)
		{
			dx = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
				(np->lowx+np->highx)/2;
			dy = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
				(np->lowy+np->highy)/2;
			makerot(ni, trans);
			xform(dx, dy, &cox, &coy, trans);
			*xpos = cox;
			*ypos = coy;
		} else
		{
			*xpos = (ni->lowx+ni->highx)/2;
			*ypos = (ni->lowy+ni->highy)/2;
		}
	}
}

void us_getnodedisplaysize(NODEINST *ni, INTBIG *xsize, INTBIG *ysize)
{
	REGISTER INTSML xyrev, serptrans;
	REGISTER INTBIG fun;
	INTBIG plx, ply, phx, phy;
	REGISTER VARIABLE *var;

	serptrans = 0;
	if (ni->proto->primindex != 0)
	{
		fun = (ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun == NPTRANMOS || fun == NPTRADMOS || fun == NPTRAPMOS)
		{
			var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER|VISARRAY, el_trace);
			if (var != NOVARIABLE) serptrans = 1;
		}
	}

	xyrev = 0;
	if (serptrans == 0)
	{
		if (ni->transpose == 0)
		{
			if (ni->rotation == 900 || ni->rotation == 2700) xyrev = 1;
		} else
		{
			if (ni->rotation == 0 || ni->rotation == 1800) xyrev = 1;
		}
	}
	nodesizeoffset(ni, &plx, &ply, &phx, &phy);
	if (xyrev == 0)
	{
		*xsize = ni->highx-ni->lowx-plx-phx;
		*ysize = ni->highy-ni->lowy-ply-phy;
	} else
	{
		*xsize = ni->highy-ni->lowy-ply-phy;
		*ysize = ni->highx-ni->lowx-plx-phx;
	}
}

void us_setnodefromdisplayinfo(NODEINST *ni, INTBIG xs, INTBIG ys, INTBIG xc, INTBIG yc,
	INTBIG r, INTBIG t, INTBIG positionchanged)
{
	INTBIG plx, ply, phx, phy, cox, coy;
	REGISTER INTBIG dx, dy, nlx, nhx, nly, nhy;
	REGISTER VARIABLE *var;
	XARRAY trans;

	nodesizeoffset(ni, &plx, &ply, &phx, &phy);
	corneroffset(ni, ni->proto, ni->rotation, ni->transpose, &cox, &coy, 0);
	if (positionchanged != 0 || r != ni->rotation || t != ni->transpose ||
		xs != ni->highx-ni->lowx-plx-phx || ys != ni->highy-ni->lowy-ply-phy)
	{
		startobjectchange((INTBIG)ni, VNODEINST);
		if (positionchanged == 0)
		{
			/* only size changed: adjust position appropriately */
			dx = (xs + plx + phx) - (ni->highx - ni->lowx);
			dy = (ys + ply + phy) - (ni->highy - ni->lowy);
			nlx = ni->lowx - dx/2;
			nhx = nlx + xs + plx + phx;
			nly = ni->lowy - dy/2;
			nhy = nly + ys + ply + phy;
			modifynodeinst(ni, nlx-ni->lowx, nly-ni->lowy, nhx-ni->highx,
				nhy-ni->highy, (INTSML)(r - ni->rotation), (INTSML)(t - ni->transpose));
		} else
		{
			/* position (and possibly size) changed: update from dialog */
			if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
			{
				dx = xc - ni->lowx - cox;   dy = yc - ni->lowy - coy;
				nlx = ni->lowx + dx;
				nhx = nlx + xs + plx + phx;
				nly = ni->lowy + dy;
				nhy = nly + ys + ply + phy;
			} else
			{
				var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center);
				if (var != NOVARIABLE)
				{
					dx = ((INTBIG *)var->addr)[0] + (ni->lowx+ni->highx)/2 -
						(ni->proto->lowx+ni->proto->highx)/2;
					dy = ((INTBIG *)var->addr)[1] + (ni->lowy+ni->highy)/2 -
						(ni->proto->lowy+ni->proto->highy)/2;
					makerot(ni, trans);
					xform(dx, dy, &cox, &coy, trans);
					xc -= cox - (ni->lowx+ni->highx)/2;
					yc -= coy - (ni->lowy+ni->highy)/2;
				}
				nlx = xc - xs/2 - plx;
				nhx = nlx + xs + plx + phx;
				nly = yc - ys/2 - ply;
				nhy = nly + ys + ply + phy;
			}
			modifynodeinst(ni, nlx-ni->lowx, nly-ni->lowy, nhx-ni->highx,
				nhy-ni->highy, (INTSML)(r - ni->rotation), (INTSML)(t - ni->transpose));
		}
		endobjectchange((INTBIG)ni, VNODEINST);
	}
}

/*
 * special case for the "Node Get Info" dialog
 * expanded              = 4 (radio)
 * unexpanded            = 5 (radio)
 * type                  = 6 (message)
 * name                  = 7 (edit text)
 * connection list       = 3 (user item)
 * X size                = 8 (edit text)
 * Y size                = 9 (edit text)
 * rotation              = 10 (edit text)
 * transposed            = 11 (check)
 * X position            = 12 (edit text)
 * X position            = 13 (edit text)
 * Special value value   = 22 (stat/edit text)
 * Special feature title = 23 (message)
 * Special feature value = 24 (message)
 * Special value title   = 25 (message)
 * See arc               = 26 (button)
 * Size information      = 27 (message)
 * Position information  = 28 (message)
 * Easy to Select        = 29 (check)
 * Attributes            = 30 (button)
 */
void us_getinfonode(NODEINST *ni, PORTPROTO *fromport)
{
	INTBIG itemHit, r, t, haslw, wantedit, wantpopup, holdsoutline,
		fun, changed, positionchanged, xyrev;
	char ent[50], *str, *newstr, *namestr, *extra, *newlang[25];
	double startoffset, endangle, newstart, newend;
	INTBIG descript, i, wid, len, xs, ys, xc, yc, xsize, ysize,
		serpwidth, lineno, highlineno, techedrel, xpos, ypos, plx, ply, phx, phy;
	HIGHLIGHT high;
	REGISTER NODEPROTO *np, *onp;
	REGISTER PORTPROTO *pp;
	REGISTER PORTARCINST *pi;
	REGISTER ARCINST *ai, *selectedai;
	REGISTER VARIABLE *var;
	static char *diodetype[2] = {N_("Regular"), N_("Zener")};
	static char *capacitortype[2] = {N_("Regular"), N_("Electrolytic")};
	static char *sourcetype[11] = {N_("Unknown"), N_("Voltage"), N_("Current"), N_("Metered Current"),
		N_("Transient"), N_("DC Analysis"), N_("AC Analysis"), N_("Nodeset"), N_("Extension"), N_("Bulk"), N_("Special")};
	static char *twoporttype[5] = {N_("VCCS"), N_("CCVS"), N_("VCVS"), N_("CCCS"), N_("Transmission")};
	static char *transistortype[9] = {N_("N-type MOS"), N_("Depletion MOS"), N_("P-type MOS"),
		N_("NPN Bipolar"), N_("PNP Bipolar"), N_("N-type JFET"), N_("P-type JFET"), N_("Depletion MESFET"),
		N_("Enhancement MESFET")};
	static char *colortype[25] = {N_("Overlappable-1"), N_("Overlappable-2"), N_("Overlappable-3"),
		N_("Overlappable-4"), N_("Overlappable-5"), N_("White"), N_("Black"), N_("Red"), N_("Blue"), N_("Green"),
		N_("Cyan"), N_("Magenta"), N_("Yellow"), N_("Gray"), N_("Orange"), N_("Purple"), N_("Brown"), N_("Light Gray"),
		N_("Dark Gray"), N_("Light Red"), N_("Dark Red"), N_("Light Green"), N_("Dark Green"), N_("Light Blue"),
		N_("Dark Blue")};

	/* node getinfo: determine what will be in the dialog box */
	np = ni->proto;
	wantedit = wantpopup = holdsoutline = 0;
	serpwidth = -1;
	var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER|VISARRAY, el_trace);
	if (var != NOVARIABLE) holdsoutline = 1;
	fun = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
	if (fun == NPTRANMOS || fun == NPTRADMOS || fun == NPTRAPMOS)
	{
		if (np->primindex != 0 && (np->userbits&HOLDSTRACE) != 0 && holdsoutline != 0)
		{
			serpwidth = 0;
			wantedit = 1;
		}
	}
	techedrel = us_tecedgetoption(ni);
	if (np == sch_resistorprim || np == sch_inductorprim ||
		np == sch_bboxprim || np == art_circleprim)
			wantedit = 1;
	if (np == sch_diodeprim || np == sch_capacitorprim || np == sch_sourceprim ||
		np == sch_twoportprim || np == sch_transistorprim ||
			(np->primindex != 0 && np->tech == art_tech && techedrel < 0))
				wantedit = wantpopup = 1;
	if (wantedit == 0) us_shownodedialogitems[22-1].type = MESSAGE; else
		us_shownodedialogitems[22-1].type = EDITTEXT;
	if (wantpopup == 0) us_shownodedialogitems[24-1].type = MESSAGE; else
		us_shownodedialogitems[24-1].type = POPUP;

	/* display the dialog box */
	if (DiaInitDialog(&us_shownodedialog) != 0) return;
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT|SCHORIZBAR);

	/* load the prototype name */
	DiaSetText(6, describenodeproto(np));

	/* load the node name if any */
	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name);
	if (var != NOVARIABLE)
	{
		namestr = (char *)var->addr;
		DiaSetText(-7, namestr);
	} else namestr = "";

	/* load the size */
	xyrev = 0;
	if ((fun == NPTRANMOS || fun == NPTRADMOS || fun == NPTRAPMOS) && serpwidth < 0)
	{
		DiaSetText(16, _("Width:"));
		DiaSetText(17, _("Length:"));
	} else
	{
		if (ni->transpose == 0)
		{
			if (ni->rotation == 900 || ni->rotation == 2700) xyrev = 1;
		} else
		{
			if (ni->rotation == 0 || ni->rotation == 1800) xyrev = 1;
		}
		if (xyrev != 0) DiaSetText(27, _("Transformed:")); else
		{
			if ((ni->rotation%900) != 0)
				DiaSetText(27, _("Untransformed:"));
		}
	}
	nodesizeoffset(ni, &plx, &ply, &phx, &phy);
	if (xyrev == 0)
	{
		xsize = ni->highx-ni->lowx-plx-phx;
		ysize = ni->highy-ni->lowy-ply-phy;
	} else
	{
		xsize = ni->highy-ni->lowy-ply-phy;
		ysize = ni->highx-ni->lowx-plx-phx;
	}
	DiaSetText(8, latoa(xsize));
	DiaSetText(9, latoa(ysize));

	/* set the expansion button */
	if (np->primindex == 0)
	{
		if ((ni->userbits&NEXPAND) != 0) i = 4; else i = 5;
		DiaSetControl(i, 1);
		DiaNoEditControl(8);
		DiaNoEditControl(9);
	} else
	{
		DiaDimItem(4);
		DiaDimItem(5);
		DiaEditControl(8);
		DiaEditControl(9);
	}

	/* no size controls if this is polygonally defined */
	if (holdsoutline != 0)
	{
		DiaDimItem(8);
		DiaDimItem(9);
	}

	/* load the position */
	if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
	{
		DiaSetText(28, _("Lower-left:"));
	} else
	{
		var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center);
		if (var != NOVARIABLE)
		{
			DiaSetText(28, _("Facet center:"));
		} else
		{
			DiaSetText(28, _("Center:"));
		}
	}
	us_getnodedisplayposition(ni, &xpos, &ypos);
	DiaSetText(12, latoa(xpos));
	DiaSetText(13, latoa(ypos));

	/* load rotation */
	DiaSetText(10, frtoa(ni->rotation*WHOLE/10));
	if (ni->transpose != 0) DiaSetControl(11, 1);

	/* load easy of selection */
	if ((ni->userbits&HARDSELECTN) == 0) DiaSetControl(29, 1);
	if (np->primindex == 0 && (us_useroptions&NOINSTANCESELECT) != 0)
		DiaDimItem(29);

	/* load special features, if any */
	if (serpwidth == 0)
	{
		transistorsize(ni, &len, &wid);
		if (len != -1 && wid != -1)
		{
			DiaSetText(23, _("Transistor Width:"));
			DiaSetText(24, latoa(wid));
			DiaSetText(25, _("Transistor Length:"));
			DiaSetText(22, latoa(len));
			serpwidth = len;
		}
	}
	if (np == sch_diodeprim)
	{
		DiaSetText(25, _("Diode size:"));
		DiaSetText(23, _("Diode type:"));
		for(i=0; i<2; i++) newlang[i] = _(diodetype[i]);   DiaSetPopup(24, 2, newlang);
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_diodekey);
		if (var != NOVARIABLE)
		{
			str = (char *)var->addr;
			while (*str == ' ') str++;
			if (*str == 'z' || *str == 'Z')
			{
				str++;
				DiaSetPopupEntry(24, 1);
			}
			DiaSetText(22, str);
		} else DiaSetText(22, "0");
	}
	if (np == sch_capacitorprim)
	{
		DiaSetText(25, _("Capacitance:"));
		DiaSetText(23, _("Capacitor type:"));
		for(i=0; i<2; i++) newlang[i] = _(capacitortype[i]);   DiaSetPopup(24, 2, newlang);
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_capacitancekey);
		if (var != NOVARIABLE)
		{
			str = (char *)var->addr;
			while (*str == ' ') str++;
			if (*str == 'e' || *str == 'E')
			{
				str++;
				DiaSetPopupEntry(24, 1);
			}
			DiaSetText(22, str);
		} else DiaSetText(22, "0");
	}
	if (np == sch_resistorprim)
	{
		DiaSetText(25, _("Resistance:"));
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_resistancekey);
		if (var != NOVARIABLE) DiaSetText(22, (char *)var->addr); else
			DiaSetText(22, "0");
	}
	if (np == sch_inductorprim)
	{
		DiaSetText(25, _("Inductance:"));
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_inductancekey);
		if (var != NOVARIABLE) DiaSetText(22, (char *)var->addr); else
			DiaSetText(22, "0");
	}
	if (np == sch_bboxprim)
	{
		DiaSetText(25, _("Function:"));
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_functionkey);
		if (var != NOVARIABLE) DiaSetText(22, (char *)var->addr); else
			DiaSetText(22, "");
	}
	if (np == sch_sourceprim)
	{
		DiaSetText(25, _("SPICE card:"));
		DiaSetText(23, _("Source type:"));
		for(i=0; i<11; i++) newlang[i] = _(sourcetype[i]);   DiaSetPopup(24, 11, newlang);
		switch (nodefunction(ni, &extra))
		{
			case NPSOURCE:   DiaSetPopupEntry(24, 0);   break;
			case NPSOURCEV:  DiaSetPopupEntry(24, 1);   break;
			case NPSOURCEC:  DiaSetPopupEntry(24, 2);   break;
			case NPSOURCECM: DiaSetPopupEntry(24, 3);   break;
			case NPSOURCET:  DiaSetPopupEntry(24, 4);   break;
			case NPSOURCEDC: DiaSetPopupEntry(24, 5);   break;
			case NPSOURCEAC: DiaSetPopupEntry(24, 6);   break;
			case NPSOURCEN:  DiaSetPopupEntry(24, 7);   break;
			case NPSOURCEX:  DiaSetPopupEntry(24, 8);   break;
			case NPSOURCEB:  DiaSetPopupEntry(24, 9);   break;
			case NPSOURCES:  DiaSetPopupEntry(24, 10);  break;
		}
		if (extra != 0) DiaSetText(22, extra);
	}
	if (np == sch_twoportprim)
	{
		DiaSetText(23, _("Two-port type:"));
		for(i=0; i<5; i++) newlang[i] = _(twoporttype[i]);   DiaSetPopup(24, 5, newlang);
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_twoportkey);
		if (var != NOVARIABLE)
		{
			str = (char *)var->addr;
			while (*str == ' ') str++;
			switch (*str)
			{
				case 'g': DiaSetPopupEntry(24, 0);   DiaSetText(25, _("Transconductance:"));   break;
				case 'h': DiaSetPopupEntry(24, 1);   DiaSetText(25, _("Transresistance:"));    break;
				case 'u': DiaSetPopupEntry(24, 2);   DiaSetText(25, _("Gain:"));               break;
				case 'f': DiaSetPopupEntry(24, 3);   DiaSetText(25, _("Gain:"));               break;
				case 'l': DiaSetPopupEntry(24, 4);   DiaSetText(25, _("Value:"));              break;
			}
			DiaSetText(22, &str[1]);
		} else
		{
			DiaSetPopupEntry(24, 5);
			DiaSetText(25, _("Value:"));
		}
	}
	if (np == sch_transistorprim)
	{
		DiaSetText(23, _("Transistor type:"));
		for(i=0; i<9; i++) newlang[i] = _(transistortype[i]);   DiaSetPopup(24, 9, newlang);
		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_transistortypekey);
		if (var != NOVARIABLE)
		{
			str = (char *)var->addr;
			haslw = 0;
			if (namesamen(str, "nmos", 4) == 0)  { str += 4;  haslw = 1;   DiaSetPopupEntry(24, 0); } else
			if (namesamen(str, "dmos", 4) == 0)  { str += 4;  haslw = 1;   DiaSetPopupEntry(24, 1); } else
			if (namesamen(str, "pmos", 4) == 0)  { str += 4;  haslw = 1;   DiaSetPopupEntry(24, 2); } else
			if (namesamen(str, "npn", 3) == 0)   { str += 3;  DiaSetPopupEntry(24, 3); } else
			if (namesamen(str, "pnp", 3) == 0)   { str += 3;  DiaSetPopupEntry(24, 4); } else
			if (namesamen(str, "njfet", 5) == 0) { str += 5;  DiaSetPopupEntry(24, 5); } else
			if (namesamen(str, "pjfet", 5) == 0) { str += 5;  DiaSetPopupEntry(24, 6); } else
			if (namesamen(str, "dmes", 4) == 0)  { str += 4;  DiaSetPopupEntry(24, 7); } else
			if (namesamen(str, "emes", 4) == 0)  { str += 4;  DiaSetPopupEntry(24, 8); }
			if (haslw != 0) DiaSetText(25, _("Width/Length:")); else
				DiaSetText(25, _("Area:"));
			DiaSetText(22, str);
		} else DiaSetText(25, _("Size:"));
	}
	if (techedrel >= 0)
	{
		DiaSetText(23, _("Tech. edit relevance:"));
		switch (techedrel)
		{
			case ARCFIXANG:
				DiaSetText(24, _("Arc fixed-angle factor"));
				break;
			case ARCFUNCTION:
				DiaSetText(24, _("Arc function"));
				break;
			case ARCINC:
				DiaSetText(24, _("Arc angle increment"));
				break;
			case ARCNOEXTEND:
				DiaSetText(24, _("Arc extension"));
				break;
			case ARCWIPESPINS:
				DiaSetText(24, _("Arc coverage"));
				break;
			case CENTEROBJ:
				DiaSetText(24, _("Grab point"));
				break;
			case LAYER3DHEIGHT:
				DiaSetText(24, _("3D height"));
				break;
			case LAYER3DTHICK:
				DiaSetText(24, _("3D thickness"));
				break;
			case LAYERCIF:
				DiaSetText(24, _("CIF name"));
				break;
			case LAYERCOLOR:
				DiaSetText(24, _("Color definition"));
				break;
			case LAYERDXF:
				DiaSetText(24, _("DXF name(s)"));
				break;
			case LAYERDRCMINWID:
				DiaSetText(24, _("DRC minimum width"));
				break;
			case LAYERFUNCTION:
				DiaSetText(24, _("Layer function"));
				break;
			case LAYERGDS:
				DiaSetText(24, _("GDS-II number"));
				break;
			case LAYERLETTERS:
				DiaSetText(24, _("Layer letters"));
				break;
			case LAYERPATTERN:
				DiaSetText(24, _("Layer stipple pattern"));
				break;
			case LAYERSTYLE:
				DiaSetText(24, _("Style definition"));
				break;
			case LAYERPATCH:
			case HIGHLIGHTOBJ:
				var = getval((INTBIG)ni, VNODEINST, VNODEPROTO, "EDTEC_layer");
				if (var == NOVARIABLE) DiaSetText(24, _("UNKNOWN LAYER")); else
				{
					onp = (NODEPROTO *)var->addr;
					if (onp == NONODEPROTO) DiaSetText(24, _("Highlight box")); else
					{
						(void)strcpy(ent, _("Layer "));
						(void)strcat(ent, &onp->cell->cellname[6]);
						DiaSetText(24, ent);
					}
				}
				break;
			case NODEFUNCTION:
				DiaSetText(24, _("Node function"));
				break;
			case NODELOCKABLE:
				DiaSetText(24, _("Node lockability"));
				break;
			case NODESERPENTINE:
				DiaSetText(24, _("Serpentine transistor"));
				break;
			case NODESQUARE:
				DiaSetText(24, _("Square node"));
				break;
			case NODEWIPES:
				DiaSetText(24, _("Disappearing pin"));
				break;
			case PORTOBJ:
				var = getval((INTBIG)ni, VNODEINST, VSTRING, "EDTEC_portname");
				if (var == NOVARIABLE) DiaSetText(24, _("Unnamed port")); else
				{
					(void)strcpy(ent, _("Port "));
					(void)strcat(ent, (char *)var->addr);
					DiaSetText(24, ent);
				}
				break;
			case TECHDESCRIPT:
				DiaSetText(24, _("Technology description"));
				break;
			case TECHLAMBDA:
				DiaSetText(24, _("Lambda value"));
				break;
		}
	} else if (np->primindex != 0 && np->tech == art_tech)
	{
		DiaSetText(23, _("Color:"));
		for(i=0; i<25; i++) newlang[i] = _(colortype[i]);   DiaSetPopup(24, 25, newlang);
		var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_colorkey);
		if (var == NOVARIABLE) i = 6; else
			switch (var->addr)
		{
			case LAYERT1: i = 0;   break;
			case LAYERT2: i = 1;   break;
			case LAYERT3: i = 2;   break;
			case LAYERT4: i = 3;   break;
			case LAYERT5: i = 4;   break;
			case WHITE:   i = 5;   break;
			case BLACK:   i = 6;   break;
			case RED:     i = 7;   break;
			case BLUE:    i = 8;   break;
			case GREEN:   i = 9;   break;
			case CYAN:    i = 10;  break;
			case MAGENTA: i = 11;  break;
			case YELLOW:  i = 12;  break;
			case GRAY:    i = 13;  break;
			case ORANGE:  i = 14;  break;
			case PURPLE:  i = 15;  break;
			case BROWN:   i = 16;  break;
			case LGRAY:   i = 17;  break;
			case DGRAY:   i = 18;  break;
			case LRED:    i = 19;  break;
			case DRED:    i = 20;  break;
			case LGREEN:  i = 21;  break;
			case DGREEN:  i = 22;  break;
			case LBLUE:   i = 23;  break;
			case DBLUE:   i = 24;  break;
		}
		DiaSetPopupEntry(24, i);
	}

	/* load the special-value entries if appropriate */
	if (np == art_circleprim)
	{
		getarcdegrees(ni, &startoffset, &endangle);
		if (startoffset != 0.0)
		{
			DiaSetText(25, _("Offset angle / Degrees of circle:"));
			sprintf(ent, "%g / %g", startoffset*180.0/EPI, endangle*180.0/EPI);
			DiaSetText(22, ent);
		} else
		{
			DiaSetText(25, _("Degrees of circle:"));
			if (endangle == 0.0) DiaSetText(22, "360"); else
			{
				sprintf(ent, "%g", endangle*180.0/EPI);
				DiaSetText(22, ent);
			}
		}
	}

	/* describe all ports */
	lineno = 0;
	highlineno = -1;
	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
	{
		if (pp == fromport) highlineno = lineno;
		lineno = us_dlogchatportproto(ni, pp, fromport, lineno);
	}
	DiaSelectLine(3, highlineno);

	/* if the node can't be edited, disable all changes */
	if (us_canedit(ni->parent, np, 0) != 0)
	{
		DiaDimItem(4);
		DiaDimItem(5);
		DiaDimItem(7);
		DiaDimItem(8);
		DiaDimItem(9);
		DiaDimItem(10);
		DiaDimItem(11);
		DiaDimItem(12);
		DiaDimItem(13);
		DiaDimItem(22);
		DiaDimItem(29);
	}

	/* loop until done */
	changed = positionchanged = 0;
	selectedai = NOARCINST;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL || itemHit == 26 || itemHit == 30) break;
		if (itemHit == 11 || itemHit == 29)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			changed++;
			continue;
		}
		if (itemHit == 4 || itemHit == 5)
		{
			DiaSetControl(4, 0);   DiaSetControl(5, 0);
			DiaSetControl(itemHit, 1);
			changed++;
			continue;
		}
		if (itemHit == 7 || itemHit == 8 || itemHit == 9 || itemHit == 10 ||
			itemHit == 22 || itemHit == 24)
				changed++;
		if (itemHit == 12 || itemHit == 13)
		{
			changed++;
			positionchanged++;
		}
		if (itemHit == 3)
		{
			lineno = DiaGetCurLine(3);
			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
			{
				ai = pi->conarcinst;
				if (ai->temp2 == lineno) break;
			}
			if (pi == NOPORTARCINST) continue;
			selectedai = ai;
			us_clearhighlightcount();
			high.status = HIGHFROM;
			high.facet = selectedai->parent;
			high.fromgeom = selectedai->geom;
			high.fromport = NOPORTPROTO;
			high.frompoint = 0;
			high.fromvar = NOVARIABLE;
			(void)us_addhighlight(&high);
			us_showallhighlight();
			us_endchanges(NOWINDOWPART);
			continue;
		}
	}

	if (itemHit != CANCEL && changed != 0)
	{
		/* see if size, rotation, or position changed */
		if (xyrev == 0)
		{
			xs = atola(DiaGetText(8));
			ys = atola(DiaGetText(9));
		} else
		{
			xs = atola(DiaGetText(9));
			ys = atola(DiaGetText(8));
		}
		xc = atola(DiaGetText(12));
		yc = atola(DiaGetText(13));
		r = atofr(DiaGetText(10))*10/WHOLE;
		t = (DiaGetControl(11) != 0 ? 1 : 0);
		us_pushhighlight();
		us_clearhighlightcount();
		us_setnodefromdisplayinfo(ni, xs, ys, xc, yc, r, t, positionchanged);
		(void)us_pophighlight(1);

		/* update transistor width if it changed */
		if (serpwidth >= 0)
		{
			newstr = DiaGetText(22);
			while (*newstr == ' ') newstr++;
			if (*newstr != 0 && atola(newstr) != serpwidth)
			{
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)ni, VNODEINST);
				(void)setvalkey((INTBIG)ni, VNODEINST, el_transistor_width, atofr(newstr), VFRACT);
				endobjectchange((INTBIG)ni, VNODEINST);
				(void)us_pophighlight(0);
			}
		}

		/* update diode area if it changed */
		if (np == sch_diodeprim)
		{
			(void)initinfstr();
			if (DiaGetPopupEntry(24) == 1) addtoinfstr('z');
			addstringtoinfstr(DiaGetText(22));
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_diodekey, (INTBIG)returninfstr(),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update capacitance if it changed */
		if (np == sch_capacitorprim)
		{
			(void)initinfstr();
			if (DiaGetPopupEntry(24) == 1) addtoinfstr('e');
			addstringtoinfstr(DiaGetText(22));
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_capacitancekey, (INTBIG)returninfstr(),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update resistance if it changed */
		if (np == sch_resistorprim)
		{
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_resistancekey, (INTBIG)DiaGetText(22),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update inductance if it changed */
		if (np == sch_inductorprim)
		{
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_inductancekey, (INTBIG)DiaGetText(22),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update black-box function if it changed */
		if (np == sch_bboxprim)
		{
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_functionkey, (INTBIG)DiaGetText(22),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update source information if it changed */
		if (np == sch_sourceprim)
		{
			(void)initinfstr();
			switch (DiaGetPopupEntry(24))
			{
				case 0:
				case 1:  addstringtoinfstr("v/");   break;
				case 2:  addstringtoinfstr("c/");   break;
				case 3:  addstringtoinfstr("cm/");  break;
				case 4:  addstringtoinfstr("t/");   break;
				case 5:  addstringtoinfstr("vd/");  break;
				case 6:  addstringtoinfstr("a/");   break;
				case 7:  addstringtoinfstr("n/");   break;
				case 8:  addstringtoinfstr("x/");   break;
				case 9:  addstringtoinfstr("b/");   break;
				case 10: addstringtoinfstr("s/");   break;
			}
			addstringtoinfstr(DiaGetText(22));
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_sourcekey, (INTBIG)returninfstr(),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update two-port information if it changed */
		if (np == sch_twoportprim)
		{
			(void)initinfstr();
			switch (DiaGetPopupEntry(24))
			{
				case 0: addtoinfstr('g');    break;
				case 1: addtoinfstr('h');    break;
				case 2: addtoinfstr('u');    break;
				case 3: addtoinfstr('f');    break;
				case 4: addtoinfstr('l');    break;
			}
			addstringtoinfstr(DiaGetText(22));
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_twoportkey, (INTBIG)returninfstr(),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update transistor size if it changed */
		if (np == sch_transistorprim)
		{
			(void)initinfstr();
			switch (DiaGetPopupEntry(24))
			{
				case 0: addstringtoinfstr("nmos");   break;
				case 1: addstringtoinfstr("dmos");   break;
				case 2: addstringtoinfstr("pmos");   break;
				case 3: addstringtoinfstr("npn");    break;
				case 4: addstringtoinfstr("pnp");    break;
				case 5: addstringtoinfstr("njfet");  break;
				case 6: addstringtoinfstr("pjfet");  break;
				case 7: addstringtoinfstr("dmes");   break;
				case 8: addstringtoinfstr("emes");   break;
			}
			addstringtoinfstr(DiaGetText(22));
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			(void)setvalkey((INTBIG)ni, VNODEINST, sch_transistortypekey, (INTBIG)returninfstr(),
				VSTRING|VDISPLAY);
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(1);
		}

		/* update color if it changed */
		if (np->primindex != 0 && np->tech == art_tech && techedrel < 0)
		{
			switch (DiaGetPopupEntry(24))
			{
				case 0:  i = LAYERT1;   break;
				case 1:  i = LAYERT2;   break;
				case 2:  i = LAYERT3;   break;
				case 3:  i = LAYERT4;   break;
				case 4:  i = LAYERT5;   break;
				case 5:  i = WHITE;     break;
				case 6:  i = BLACK;     break;
				case 7:  i = RED;       break;
				case 8:  i = BLUE;      break;
				case 9:  i = GREEN;     break;
				case 10: i = CYAN;      break;
				case 11: i = MAGENTA;   break;
				case 12: i = YELLOW;    break;
				case 13: i = GRAY;      break;
				case 14: i = ORANGE;    break;
				case 15: i = PURPLE;    break;
				case 16: i = BROWN;     break;
				case 17: i = LGRAY;     break;
				case 18: i = DGRAY;     break;
				case 19: i = LRED;      break;
				case 20: i = DRED;      break;
				case 21: i = LGREEN;    break;
				case 22: i = DGREEN;    break;
				case 23: i = LBLUE;     break;
				case 24: i = DBLUE;     break;
			}
			us_pushhighlight();
			us_clearhighlightcount();
			startobjectchange((INTBIG)ni, VNODEINST);
			if (i == BLACK)
			{
				var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_colorkey);
				if (var != NOVARIABLE)
					delvalkey((INTBIG)ni, VNODEINST, art_colorkey);
			} else
			{
				setvalkey((INTBIG)ni, VNODEINST, art_colorkey, i, VINTEGER);
			}
			endobjectchange((INTBIG)ni, VNODEINST);
			(void)us_pophighlight(0);
		}

		/* update ease of selection if changed */
		if (DiaGetControl(29) != 0) ni->userbits &= ~HARDSELECTN; else
			ni->userbits |= HARDSELECTN;

		/* update expansion bit if changed */
		if (np->primindex == 0)
		{
			i = ni->userbits;
			if (DiaGetControl(4) != 0) i |= NEXPAND; else
				i &= ~NEXPAND;
			if (i != (INTBIG)ni->userbits)
			{
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)ni, VNODEINST);
				ni->userbits = i;
				endobjectchange((INTBIG)ni, VNODEINST);
				(void)us_pophighlight(0);
			}
		}

		/* update name if it changed */
		newstr = DiaGetText(7);
		while (*newstr == ' ') newstr++;
		if (strcmp(newstr, namestr) != 0)
		{
			us_pushhighlight();
			us_clearhighlightcount();

			/* change the name of the nodeinst */
			startobjectchange((INTBIG)ni, VNODEINST);
			if (*newstr == 0)
				(void)delvalkey((INTBIG)ni, VNODEINST, el_node_name); else
			{
				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name);
				if (var != NOVARIABLE) descript = var->textdescript; else
					descript = defaulttextdescript(NOGEOM);
				var = setvalkey((INTBIG)ni, VNODEINST, el_node_name, (INTBIG)newstr, VSTRING|VDISPLAY);
				if (var != NOVARIABLE) var->textdescript = descript;

				/* shift text down if on a facet instance */
				if (var != NOVARIABLE && np->primindex == 0)
				{
					var->textdescript = us_setdescriptoffset(var->textdescript,
						0, (ni->highy-ni->lowy) / el_curlib->lambda[el_curtech->techindex]);
				}
			}
			endobjectchange((INTBIG)ni, VNODEINST);

			/* restore highlighting */
			(void)us_pophighlight(0);
		}

		/* update the circle degrees if it changed */
		if (np == art_circleprim)
		{
			str = DiaGetText(25);
			if (strcmp(str, _("Degrees of circle:")) == 0)
			{
				newend = atof(DiaGetText(22));
				if (newend == 360.0) newend = 0.0;
				newend = newend * EPI / 180.0;
				if (newend != endangle)
				{
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)ni, VNODEINST);
					setarcdegrees(ni, startoffset, newend);
					endobjectchange((INTBIG)ni, VNODEINST);
					(void)us_pophighlight(1);
				}
			} else
			{
				str = DiaGetText(22);
				while (*str == ' ' || *str == '\t') str++;
				newstart = atof(str);
				while (*str != 0 && *str != '/') str++;
				if (*str == 0)
				{
					newend = newstart;
					newstart = 0.0;
				} else
				{
					str++;
					while (*str == ' ' || *str == '\t') str++;
					newend = atof(str);
				}
				
				if (newend == 360.0) newend = newstart = 0.0;
				newend = newend * EPI / 180.0;
				newstart = newstart * EPI / 180.0;
				if (newend != endangle || newstart != startoffset)
				{
					us_pushhighlight();
					us_clearhighlightcount();
					startobjectchange((INTBIG)ni, VNODEINST);
					setarcdegrees(ni, newstart, newend);
					endobjectchange((INTBIG)ni, VNODEINST);
					(void)us_pophighlight(1);
				}
			}
		}
	}
	DiaDoneDialog();
	if (itemHit == 26 && selectedai != NOARCINST)
		us_getinfoarc(selectedai);
	if (itemHit == 30)
		(void)us_attributesdlog();
}

void us_updatenodeinfo(NODEINST *ni, VARIABLE *var, char *varname, char *wholemessage,
	char *variablepart)
{
	REGISTER char *newstr, *pt;

	newstr = DiaGetText(22);
	if (strcmp(newstr, variablepart) == 0) return;

	us_pushhighlight();
	us_clearhighlightcount();
	startobjectchange((INTBIG)ni, VNODEINST);
	(void)initinfstr();
	for(pt = wholemessage; pt < variablepart; pt++) (void)addtoinfstr(*pt);
	(void)addstringtoinfstr(newstr);
	(void)setval((INTBIG)ni, VNODEINST, varname, (INTBIG)returninfstr(), var->type);
	endobjectchange((INTBIG)ni, VNODEINST);
	(void)us_pophighlight(1);
}

/*
 * routine to display information about port prototype "pp" on nodeinst "ni".
 * If the port prototype's "temp1" is nonzero, this port has already been
 * mentioned and should not be done again.
 */
INTBIG us_dlogchatportproto(NODEINST *ni, PORTPROTO *pp, PORTPROTO *selected, INTBIG lineno)
{
	REGISTER PORTARCINST *pi;
	REGISTER PORTEXPINST *pe;
	REGISTER ARCINST *ai;
	REGISTER ARCPROTO *ap;
	REGISTER INTBIG i, count, moreinfo;
	REGISTER char *activity;
	char line[256];

	/* talk about the port prototype */
	(void)initinfstr();
	activity = us_describeportbits(pp);
	if (*activity != 0)
	{
		(void)formatinfstr(_("%s port %s connects to"), activity, pp->protoname);
	} else
	{
		(void)formatinfstr(_("Port %s connects to"), pp->protoname);
	}
	count = 0;
	for(i=0; pp->connects[i] != NOARCPROTO; i++)
	{
		ap = pp->connects[i];
		if ((ni->proto->primindex == 0 || ni->proto->tech != gen_tech) &&
			ap->tech == gen_tech) continue;
		if (count > 0) (void)addstringtoinfstr(",");
		(void)addstringtoinfstr(" ");
		(void)addstringtoinfstr(ap->protoname);
		count++;
	}
	moreinfo = 0;
	if (pp == selected) moreinfo = 1;
	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
		if (pi->proto == pp) moreinfo = 1;
	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
		if (pe->proto == pp) moreinfo = 1;
	if (moreinfo != 0) (void)addstringtoinfstr(":");
	DiaStuffLine(3, returninfstr());
	lineno++;

	/* mention if it is highlighted */
	if (pp == selected)
	{
		DiaStuffLine(3, _("  Highlighted port"));
		lineno++;
	}

	/* talk about any arcs on this prototype */
	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
	{
		if (pi->proto != pp) continue;
		ai = pi->conarcinst;
		if (ai->end[0].portarcinst == pi) i = 0; else i = 1;
		(void)sprintf(line, _("  Connected at (%s,%s) to %s arc"), latoa(ai->end[i].xpos),
			latoa(ai->end[i].ypos), describearcinst(ai));
		ai->temp2 = lineno;
		DiaStuffLine(3, line);
		lineno++;
	}

	/* talk about any exports of this prototype */
	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
		if (pe->proto == pp)
	{
		(void)initinfstr();
		(void)formatinfstr(_("  Available as %s export '%s'"), us_describeportbits(pe->exportproto),
			pe->exportproto->protoname);
		DiaStuffLine(3, returninfstr());
		lineno++;
	}
	return(lineno);
}

/****************************** GRID OPTIONS DIALOG ******************************/

/* Grid options */
DIALOGITEM us_griddialogitems[] =
{
 /*  1 */ {0, {116,384,140,448}, BUTTON, N_("OK")},
 /*  2 */ {0, {116,12,140,76}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,8,48,269}, MESSAGE, N_("Grid dot spacing (current window):")},
 /*  4 */ {0, {32,272,48,352}, EDITTEXT, ""},
 /*  5 */ {0, {8,272,24,366}, MESSAGE, N_("Horizontal:")},
 /*  6 */ {0, {32,372,48,452}, EDITTEXT, ""},
 /*  7 */ {0, {60,8,76,269}, MESSAGE, N_("Default grid spacing (new windows):")},
 /*  8 */ {0, {60,272,76,352}, EDITTEXT, ""},
 /*  9 */ {0, {8,372,24,466}, MESSAGE, N_("Vertical:")},
 /* 10 */ {0, {60,372,76,452}, EDITTEXT, ""},
 /* 11 */ {0, {88,8,104,269}, MESSAGE, N_("Distance between bold dots:")},
 /* 12 */ {0, {88,272,104,352}, EDITTEXT, ""},
 /* 13 */ {0, {120,132,136,329}, CHECK, N_("Align grid with circuitry")},
 /* 14 */ {0, {88,372,104,452}, EDITTEXT, ""}
};
DIALOG us_griddialog = {{50,75,199,550}, N_("Grid Options"), 0, 14, us_griddialogitems};

/*
 * special case for the "grid settings" dialog
 * Horizontal spacing           = 4 (edit text)
 * Vertical spacing             = 6 (edit text)
 * Default horizontal spacing   = 8 (edit text)
 * Default vertical spacing     = 10 (edit text)
 * Bold dot horizontal distance = 12 (edit text)
 * Bold dot vertical distance   = 14 (edit text)
 * Align with circuitry         = 13 (check)
 */
INTSML us_griddlog(void)
{
	REGISTER INTBIG itemHit, val, xspacing, yspacing, xboldspacing, yboldspacing,
		newgridx, newgridy, oldgridfloats;
	INTBIG defgrid[2];
	REGISTER VARIABLE *var;
	char buf[20];

	/* display the grid settings dialog box */
	if (DiaInitDialog(&us_griddialog) != 0) return(0);
	if (el_curwindowpart == NOWINDOWPART || el_curwindowpart->curnodeproto == NONODEPROTO)
	{
		DiaDimItem(4);
		DiaDimItem(6);
	} else
	{
		DiaSetText(-4, latoa(el_curwindowpart->gridx));
		DiaSetText(6, latoa(el_curwindowpart->gridy));
	}
	var = getval((INTBIG)us_aid, VAID, VFRACT|VISARRAY, "USER_default_grid");
	if (var == NOVARIABLE) xspacing = yspacing = WHOLE; else
	{
		xspacing = ((INTBIG *)var->addr)[0];
		yspacing = ((INTBIG *)var->addr)[1];
	}
	DiaSetText(8, frtoa(xspacing));
	DiaSetText(10, frtoa(yspacing));

	var = getvalkey((INTBIG)us_aid, VAID, -1, us_gridboldspacing);
	if (var == NOVARIABLE) xboldspacing = yboldspacing = 10; else
	{
		if ((var->type&VISARRAY) == 0)
			xboldspacing = yboldspacing = var->addr; else
		{
			xboldspacing = ((INTBIG *)var->addr)[0];
			yboldspacing = ((INTBIG *)var->addr)[1];
		}
	}
	sprintf(buf, "%ld", xboldspacing);   DiaSetText(12, buf);
	sprintf(buf, "%ld", yboldspacing);   DiaSetText(14, buf);

	oldgridfloats = 0;
	var = getvalkey((INTBIG)us_aid, VAID, VINTEGER, us_gridfloats);
	if (var != NOVARIABLE && var->addr != 0) oldgridfloats = 1;
	DiaSetControl(13, oldgridfloats);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 13)
		{
			DiaSetControl(itemHit, 1 - DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* change window-independent grid options */
		defgrid[0] = atofr(DiaGetText(8));
		defgrid[1] = atofr(DiaGetText(10));
		if (defgrid[0] != xspacing || defgrid[1] != yspacing)
			(void)setval((INTBIG)us_aid, VAID, "USER_default_grid",
				(INTBIG)defgrid, VFRACT|VISARRAY|(2<<VLENGTHSH));
		defgrid[0] = atoi(DiaGetText(12));
		defgrid[1] = atoi(DiaGetText(14));
		if (defgrid[0] != xboldspacing || defgrid[1] != yboldspacing)
			(void)setvalkey((INTBIG)us_aid, VAID, us_gridboldspacing,
				(INTBIG)defgrid, VINTEGER|VISARRAY|(2<<VLENGTHSH));
		val = DiaGetControl(13);
		if (val != oldgridfloats)
			(void)setvalkey((INTBIG)us_aid, VAID, us_gridfloats,
				(INTBIG)val, VINTEGER);

		/* see if grid changed in this facet */
		if (el_curwindowpart != NOWINDOWPART && el_curwindowpart->curnodeproto != NONODEPROTO)
		{
			newgridx = atola(DiaGetText(4));
			newgridy = atola(DiaGetText(6));
			if (newgridx != el_curwindowpart->gridx || newgridy != el_curwindowpart->gridy)
			{
				/* adjust grid in current window */
				us_pushhighlight();
				us_clearhighlightcount();
				startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);

				/* turn grid off if on */
				if ((el_curwindowpart->state&GRIDON) != 0)
					(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, "state",
						el_curwindowpart->state & ~GRIDON, VINTEGER);

				(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, "gridx", newgridx, VINTEGER);
				(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, "gridy", newgridy, VINTEGER);

				/* show new grid */
				us_gridset(el_curwindowpart, GRIDON);

				/* restore highlighting */
				endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
				(void)us_pophighlight(0);
			}
		}

	}
	DiaDoneDialog();
	return(0);
}

/****************************** HELP DIALOG ******************************/

/* Help */
DIALOGITEM us_helpdialogitems[] =
{
 /*  1 */ {0, {288,376,312,440}, BUTTON, N_("OK")},
 /*  2 */ {0, {8,32,24,91}, MESSAGE, N_("Topics:")},
 /*  3 */ {0, {8,192,280,636}, SCROLL, ""},
 /*  4 */ {0, {24,8,309,177}, SCROLL, ""}
};
DIALOG us_helpdialog = {{50,75,378,720}, N_("Help"), 0, 4, us_helpdialogitems};

/*
 * special case for the "help" dialog
 * topics       = 4 (user item)
 * help         = 3 (user item)
 */
INTSML us_helpdlog(char *prompt)
{
	char *filename, *line, buf[256], *platform, *pt;
	INTBIG itemHit, i;
	FILE *in;
	REGISTER VARIABLE *var;

	/* get the help file */
	(void)initinfstr();
	(void)addstringtoinfstr(el_libdir);
	(void)addstringtoinfstr(prompt);
	line = returninfstr();
	in = xopen(line, us_filetypehelp, "", &filename);
	if (in == NULL)
	{
		us_abortcommand(_("Cannot find help file: %s"), line);
		return(0);
	}

	/* show the "help" dialog */
	if (DiaInitDialog(&us_helpdialog) != 0)
	{
		xclose(in);
		return(0);
	}
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCHORIZBAR|SCSMALLFONT|SCFIXEDWIDTH);
	DiaInitTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCSELKEY|SCREPORT|SCSMALLFONT);

	/* determine the platform that is running */
	var = getval((INTBIG)us_aid, VAID, VSTRING, "USER_machine");
	if (var == NOVARIABLE) platform = ""; else
		platform = (char *)var->addr;

	/* load the topics list */
	for(;;)
	{
		if (xfgets(buf, 256, in) != 0) break;
		if (buf[0] != '!') continue;
		for(pt = buf; *pt != 0; pt++)
			if (*pt == '[') break;
		if (*pt == '[')
		{
			*pt++ = 0;
			if (namesamen(pt, platform, strlen(platform)) != 0) continue;
		}
		DiaStuffLine(4, &buf[1]);
	}
	DiaSelectLine(4, -1);

	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK) break;
		if (itemHit == 4)
		{
			line = DiaGetScrollLine(4, DiaGetCurLine(4));
			xseek(in, 0, 0);
			DiaLoadTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(;;)
			{
				if (xfgets(buf, 256, in) != 0) break;
				if (buf[0] != '!') continue;
				for(pt = buf; *pt != 0; pt++)
					if (*pt == '[') break;
				if (*pt == '[')
				{
					*pt++ = 0;
					if (namesamen(pt, platform, strlen(platform)) != 0) continue;
				}
				if (strcmp(&buf[1], line) == 0) break;
			}
			for(i=0; ; i++)
			{
				if (xfgets(buf, 256, in) != 0) break;
				if (buf[0] == '!') break;
				if (buf[0] == 0 && i == 0) continue;
				DiaStuffLine(3, buf);
			}
			DiaSelectLine(3, -1);
			continue;
		}
	}
	DiaDoneDialog();
	xclose(in);
	return(0);
}

/****************************** ICON STYLE DIALOG ******************************/

/* Icon Options */
DIALOGITEM us_iconoptdialogitems[] =
{
 /*  1 */ {0, {304,140,328,220}, BUTTON, N_("OK")},
 /*  2 */ {0, {304,12,328,92}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,8,24,88}, MESSAGE, N_("Inputs on:")},
 /*  4 */ {0, {8,92,24,192}, POPUP, ""},
 /*  5 */ {0, {32,8,48,88}, MESSAGE, N_("Outputs on:")},
 /*  6 */ {0, {32,92,48,192}, POPUP, ""},
 /*  7 */ {0, {56,8,72,88}, MESSAGE, N_("Bidir. on:")},
 /*  8 */ {0, {56,92,72,192}, POPUP, ""},
 /*  9 */ {0, {80,8,96,88}, MESSAGE, N_("Power on:")},
 /* 10 */ {0, {80,92,96,192}, POPUP, ""},
 /* 11 */ {0, {104,8,120,88}, MESSAGE, N_("Ground on:")},
 /* 12 */ {0, {104,92,120,192}, POPUP, ""},
 /* 13 */ {0, {128,8,144,88}, MESSAGE, N_("Clock on:")},
 /* 14 */ {0, {128,92,144,192}, POPUP, ""},
 /* 15 */ {0, {216,8,232,116}, CHECK, N_("Draw leads")},
 /* 16 */ {0, {160,8,176,128}, MESSAGE, N_("Export location:")},
 /* 17 */ {0, {160,128,176,228}, POPUP, ""},
 /* 18 */ {0, {184,8,200,128}, MESSAGE, N_("Export style:")},
 /* 19 */ {0, {184,128,200,228}, POPUP, ""},
 /* 20 */ {0, {240,8,256,116}, CHECK, N_("Draw body")},
 /* 21 */ {0, {272,8,288,152}, CHECK, N_("Place facet-center")}
};
DIALOG us_iconoptdialog = {{75,75,412,312}, N_("Icon Options"), 0, 21, us_iconoptdialogitems};

/*
 * special case for the "Icon Style" dialog
 * Input location      = 4 (popup)
 * Output location     = 6 (popup)
 * Bidir location      = 8 (popup)
 * Power location      = 10 (popup)
 * Ground location     = 12 (popup)
 * Clock location      = 14 (popup)
 * Draw leads          = 15 (check)
 * Port Location       = 17 (popup)
 * Port Style          = 19 (popup)
 * Draw body           = 20 (check)
 * Place facet-center  = 21 (check)
 */
INTSML us_iconstyledlog(void)
{
	INTBIG itemHit, style, origstyle, index, i;
	REGISTER VARIABLE *var;
	char *newlang[4];
	static char *location[] = {N_("Left side"), N_("Right side"), N_("Top side"), N_("Bottom side")};
	static char *portlocation[] = {N_("Body"), N_("Lead end"), N_("Lead middle")};
	static char *portstyle[] = {N_("Centered"), N_("Inward"), N_("Outward")};

	var = getval((INTBIG)us_aid, VAID, VINTEGER, "USER_icon_style");
	if (var != NOVARIABLE) style = var->addr; else style = ICONSTYLEEFAULT;
	origstyle = style;
	if (DiaInitDialog(&us_iconoptdialog) != 0) return(0);
	for(i=0; i<4; i++) newlang[i] = _(location[i]);   DiaSetPopup(4, 4, newlang);
	index = (style & ICONSTYLESIDEIN) >> ICONSTYLESIDEINSH;
	DiaSetPopupEntry(4, index);
	DiaSetPopup(6, 4, newlang);
	index = (style & ICONSTYLESIDEOUT) >> ICONSTYLESIDEOUTSH;
	DiaSetPopupEntry(6, index);
	DiaSetPopup(8, 4, newlang);
	index = (style & ICONSTYLESIDEBIDIR) >> ICONSTYLESIDEBIDIRSH;
	DiaSetPopupEntry(8, index);
	DiaSetPopup(10, 4, newlang);
	index = (style & ICONSTYLESIDEPOWER) >> ICONSTYLESIDEPOWERSH;
	DiaSetPopupEntry(10, index);
	DiaSetPopup(12, 4, newlang);
	index = (style & ICONSTYLESIDEGROUND) >> ICONSTYLESIDEGROUNDSH;
	DiaSetPopupEntry(12, index);
	DiaSetPopup(14, 4, newlang);
	index = (style & ICONSTYLESIDECLOCK) >> ICONSTYLESIDECLOCKSH;
	DiaSetPopupEntry(14, index);

	for(i=0; i<3; i++) newlang[i] = _(portlocation[i]);   DiaSetPopup(17, 3, newlang);
	index = (style & ICONSTYLEPORTLOC) >> ICONSTYLEPORTLOCSH;
	DiaSetPopupEntry(17, index);
	for(i=0; i<3; i++) newlang[i] = _(portstyle[i]);   DiaSetPopup(19, 3, newlang);
	index = (style & ICONSTYLEPORTSTYLE) >> ICONSTYLEPORTSTYLESH;
	DiaSetPopupEntry(19, index);

	if ((style&ICONSTYLEDRAWNOLEADS) == 0) DiaSetControl(15, 1);
	if ((style&ICONSTYLEDRAWNOBODY) == 0) DiaSetControl(20, 1);
	if ((us_useroptions&PUTFACETCENTERINICON) != 0) DiaSetControl(21, 1);

	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 15 || itemHit == 20 || itemHit == 21)
		{
			DiaSetControl(itemHit, 1 - DiaGetControl(itemHit));
			continue;
		}
	}
	if (itemHit == OK)
	{
		style = 0;
		index = DiaGetPopupEntry(4);
		style |= index << ICONSTYLESIDEINSH;
		index = DiaGetPopupEntry(6);
		style |= index << ICONSTYLESIDEOUTSH;
		index = DiaGetPopupEntry(8);
		style |= index << ICONSTYLESIDEBIDIRSH;
		index = DiaGetPopupEntry(10);
		style |= index << ICONSTYLESIDEPOWERSH;
		index = DiaGetPopupEntry(12);
		style |= index << ICONSTYLESIDEGROUNDSH;
		index = DiaGetPopupEntry(14);
		style |= index << ICONSTYLESIDECLOCKSH;

		index = DiaGetPopupEntry(17);
		style |= index << ICONSTYLEPORTLOCSH;
		index = DiaGetPopupEntry(19);
		style |= index << ICONSTYLEPORTSTYLESH;
		if (DiaGetControl(15) == 0) style |= ICONSTYLEDRAWNOLEADS;
		if (DiaGetControl(20) == 0) style |= ICONSTYLEDRAWNOBODY;
		if (style != origstyle)
			setval((INTBIG)us_aid, VAID, "USER_icon_style", style, VINTEGER);
		style = us_useroptions;
		if (DiaGetControl(21) != 0) style |= PUTFACETCENTERINICON; else
			style &= ~PUTFACETCENTERINICON;
		if (style != us_useroptions)
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags, style, VINTEGER);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** LAYER HIGHLIGHT DIALOG ******************************/

/* Layer Highlighting */
DIALOGITEM us_highlightlayerdialogitems[] =
{
 /*  1 */ {0, {108,184,132,248}, BUTTON, N_("Done")},
 /*  2 */ {0, {12,184,36,248}, BUTTON, N_("None")},
 /*  3 */ {0, {8,8,136,170}, SCROLL, ""}
};
DIALOG us_highlightlayerdialog = {{50,75,195,334}, N_("Layer to Highlight"), 0, 3, us_highlightlayerdialogitems};

/*
 * special case for the "highlight layer" command
 * No layer           = 2 (button)
 * Layer list         = 3 (scroll)
 */
INTSML us_highlayerlog(void)
{
	REGISTER INTBIG itemHit, i;
	REGISTER INTBIG funct;
	REGISTER char *la;
	char buf[2], *newpar[3];

	if (us_needwindow()) return(0);

	/* display the grid settings dialog box */
	if (DiaInitDialog(&us_highlightlayerdialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCREPORT|SCSELMOUSE);
	for(i=0; i<el_curtech->layercount; i++)
	{
		if (el_curtech->layers[i]->bits == LAYERO ||
			el_curtech->layers[i]->bits == LAYERN) continue;
		funct = layerfunction(el_curtech, (INTSML)i);
		if ((funct&LFPSEUDO) != 0) continue;
		DiaStuffLine(3, layername(el_curtech, (INTSML)i));
	}
	DiaSelectLine(3, -1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK) break;
		if (itemHit == 2)
		{
			DiaSelectLine(3, -1);
			newpar[0] = "default";
			us_color(1, newpar);
			continue;
		}
		if (itemHit == 3)
		{
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			la = DiaGetScrollLine(3, i);
			for(i=0; i<el_curtech->layercount; i++)
				if (strcmp(la, layername(el_curtech, (INTSML)i)) == 0) break;
			if (i >= el_curtech->layercount) continue;
			newpar[0] = "default";
			us_color(1, newpar);
			la = us_layerletters(el_curtech, (INTSML)i);
			buf[0] = *la;
			buf[1] = 0;
			newpar[0] = "highlight";
			newpar[1] = buf;
			us_color(2, newpar);
			continue;
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** LIBRARY PATH DIALOG ******************************/

/* Library paths */
DIALOGITEM us_librarypathdialogitems[] =
{
 /*  1 */ {0, {76,312,100,376}, BUTTON, N_("OK")},
 /*  2 */ {0, {76,32,100,96}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,16,24,220}, MESSAGE, N_("Location of library files:")},
 /*  4 */ {0, {32,8,64,400}, EDITTEXT, ""}
};
DIALOG us_librarypathdialog = {{50,75,159,485}, N_("Current Library Path"), 0, 4, us_librarypathdialogitems};

/*
 * special case for the "library paths" dialog
 * library file location = 4 (message)
 */
INTSML us_librarypathdlog(void)
{
	INTBIG itemHit;
	char *pt;

	/* display the library paths dialog box */
	if (DiaInitDialog(&us_librarypathdialog) != 0) return(0);
	DiaSetText(4, el_libdir);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(4)) break;
	}

	if (itemHit != CANCEL)
	{
		pt = DiaGetText(4);
		if (strcmp(pt, el_libdir) != 0) (void)reallocstring(&el_libdir, pt, db_cluster);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** LIBRARY SELECTION DIALOG ******************************/

/* Change Library */
DIALOGITEM us_chglibrarydialogitems[] =
{
 /*  1 */ {0, {164,208,188,288}, BUTTON, N_("OK")},
 /*  2 */ {0, {116,208,140,288}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {4,4,20,100}, MESSAGE, N_("Current Library:")},
 /*  4 */ {0, {4,104,20,288}, MESSAGE, ""},
 /*  5 */ {0, {52,4,196,196}, SCROLL, ""},
 /*  6 */ {0, {32,16,48,168}, MESSAGE|INACTIVE, N_("Switch to Library:")}
};
DIALOG us_chglibrarydialog = {{75,75,280,372}, N_("Set Current Library"), 0, 6, us_chglibrarydialogitems};

/*
 * special case for the "change current library" dialog
 * current library = 4 (message)
 * library list    = 5 (scroll)
 */
INTSML us_oldlibrarydlog(void)
{
	REGISTER INTBIG itemHit;
	REGISTER LIBRARY *lib;
	REGISTER char *pt;

	/* display the node size dialog box */
	if (DiaInitDialog(&us_chglibrarydialog) != 0) return(0);
	DiaSetText(4, el_curlib->libname);
	DiaInitTextDialog(5, topoflibs, nextlibs, DiaNullDlogDone, -1,
		SCSELMOUSE|SCDOUBLEQUIT);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}

	lib = el_curlib;
	if (itemHit != CANCEL)
	{
		pt = DiaGetScrollLine(5, DiaGetCurLine(5));
		lib = getlibrary(pt);
	}
	DiaDoneDialog();
	if (lib != NOLIBRARY && lib != el_curlib)
		us_switchtolibrary(lib);
	return(0);
}

/****************************** NODE: CREATE ANNULAR RING DIALOG ******************************/

/* Annular Ring */
DIALOGITEM us_annringdialogitems[] =
{
 /*  1 */ {0, {268,176,292,240}, BUTTON, N_("OK")},
 /*  2 */ {0, {268,20,292,84}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {164,12,180,160}, MESSAGE, N_("Inner Radius:")},
 /*  4 */ {0, {164,164,180,244}, EDITTEXT, ""},
 /*  5 */ {0, {188,12,204,160}, MESSAGE, N_("Outer Radius:")},
 /*  6 */ {0, {188,164,204,244}, EDITTEXT, ""},
 /*  7 */ {0, {212,12,228,160}, MESSAGE, N_("Number of segments:")},
 /*  8 */ {0, {212,164,228,244}, EDITTEXT, "32"},
 /*  9 */ {0, {236,12,252,160}, MESSAGE, N_("Number of degrees:")},
 /* 10 */ {0, {236,164,252,244}, EDITTEXT, "360"},
 /* 11 */ {0, {8,8,24,172}, MESSAGE, N_("Layer to use for ring:")},
 /* 12 */ {0, {28,8,156,244}, SCROLL, ""}
};
DIALOG us_annringdialog = {{75,75,376,330}, N_("Annulus Construction"), 0, 12, us_annringdialogitems};

/*
 * special case for the "Annular ring" dialog
 * inner radius       = 4 (edit text)
 * outer radius       = 6 (edit text)
 * number of segments = 8 (edit text)
 * number of degrees  = 10 (edit text)
 * layer to use       = 12 (scroll)
 */
INTSML us_annularringdlog(void)
{
	INTBIG itemHit, i;
	REGISTER INTBIG lx, hx, ly, hy, cx, cy, layers, fun;
	REGISTER NODEINST *ni;
	REGISTER NODEPROTO *layer, *parent, *prim;
	char inner[20], outer[20], segs[20], degrees[20], *pars[6];
	static POLYGON *poly = NOPOLYGON;
	HIGHLIGHT newhigh;

	parent = us_needfacet();
	if (parent == NONODEPROTO) return(0);

	/* get polygon */
	if (poly == NOPOLYGON) poly = allocstaticpolygon(4, us_aid->cluster);

	/* count all pure-layer nodes in the current technology */
	layers = 0;
	for(prim = el_curtech->firstnodeproto; prim != NONODEPROTO; prim = prim->nextnodeproto)
	{
		fun = (prim->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun == NPNODE) layers++;
	}
	if (layers <= 0)
	{
		us_abortcommand(_("This technology has no pure-layer nodes"));
		return(0);
	}

	/* display the window view dialog box */
	if (DiaInitDialog(&us_annringdialog) != 0) return(0);
	DiaInitTextDialog(12, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE);
	for(prim = el_curtech->firstnodeproto; prim != NONODEPROTO; prim = prim->nextnodeproto)
	{
		fun = (prim->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun != NPNODE) continue;
		DiaStuffLine(12, prim->primname);
	}
	DiaSelectLine(12, 0);
	DiaSetText(8, "32");
	DiaSetText(10, "360");

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}

	if (itemHit == OK)
	{
		/* figure out which pure-layer node to create */
		i = DiaGetCurLine(12);
		layer = getnodeproto(DiaGetScrollLine(12, i));
		if (layer == NONODEPROTO) { DiaDoneDialog();   return(0); }

		/* create the pure-layer node */
		cx = (el_curwindowpart->screenlx + el_curwindowpart->screenhx) / 2;
		cy = (el_curwindowpart->screenly + el_curwindowpart->screenhy) / 2;
		lx = cx - (layer->highx - layer->lowx) / 2;
		hx = lx + layer->highx - layer->lowx;
		ly = cy - (layer->highy - layer->lowy) / 2;
		hy = ly + layer->highy - layer->lowy;
		ni = newnodeinst(layer, lx, hx, ly, hy, 0, 0, parent);
		if (ni == NONODEINST) { DiaDoneDialog();   return(0); }
		endobjectchange((INTBIG)ni, VNODEINST);

		/* highlight the pure-layer node */
		us_clearhighlightcount();
		newhigh.status = HIGHFROM;
		newhigh.facet = parent;
		newhigh.fromgeom = ni->geom;
		newhigh.fromport = NOPORTPROTO;
		newhigh.frompoint = 0;
		(void)us_addhighlight(&newhigh);

		/* turn it into an annular ring */
		strcpy(inner, DiaGetText(4));
		strcpy(outer, DiaGetText(6));
		strcpy(segs, DiaGetText(8));
		strcpy(degrees, DiaGetText(10));
		pars[0] = "trace";
		pars[1] = "construct-annulus";
		pars[2] = inner;
		pars[3] = outer;
		pars[4] = segs;
		pars[5] = degrees;
		us_node(6, pars);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** NODE: CREATE LAYOUT TEXT DIALOG ******************************/

/* Node: Make Text Layout */
DIALOGITEM us_spelldialogitems[] =
{
 /*  1 */ {0, {124,172,148,252}, BUTTON, N_("OK")},
 /*  2 */ {0, {124,12,148,92}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,76,24,180}, POPUP, ""},
 /*  4 */ {0, {8,8,24,72}, MESSAGE, N_("Size:")},
 /*  5 */ {0, {92,8,108,72}, MESSAGE, N_("Message:")},
 /*  6 */ {0, {92,76,108,252}, EDITTEXT, ""},
 /*  7 */ {0, {64,76,80,252}, POPUP, ""},
 /*  8 */ {0, {64,8,80,72}, MESSAGE, N_("Layer:")},
 /*  9 */ {0, {36,76,52,124}, EDITTEXT, ""},
 /* 10 */ {0, {36,8,52,72}, MESSAGE, N_("Scale:")}
};
DIALOG us_spelldialog = {{75,75,232,336}, N_("Create Text Layout"), 0, 10, us_spelldialogitems};

/*
 * special case for the "Layout Text" dialog
 * Text size       = 3 (popup)
 * Layer           = 7 (popup)
 * Text to place   = 6 (edit text)
 * Scale           = 9 (edit text)
 */
INTSML us_placetextdlog(void)
{
	INTBIG itemHit, layers, fun, i;
	char **layernames, line[20], *newlang[12];
	static INTBIG lastprim = 0, lastfont = 4, lastscale = 1;
	REGISTER NODEPROTO *prim;
	static char *fontnames[9] = {N_("4 Points"), N_("6 Points"), N_("8 Points"), N_("10 Points"),
		N_("12 Points"), N_("14 Points"), N_("16 Points"), N_("18 Points"), N_("20 Points")};

	/* count all pure-layer nodes in the current technology */
	layers = 0;
	for(prim = el_curtech->firstnodeproto; prim != NONODEPROTO; prim = prim->nextnodeproto)
	{
		fun = (prim->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun == NPNODE) layers++;
	}
	if (layers <= 0)
	{
		us_abortcommand(_("This technology has no pure-layer nodes"));
		return(0);
	}

	/* display the text-layout dialog box */
	if (DiaInitDialog(&us_spelldialog) != 0) return(0);
	for(i=0; i<9; i++) newlang[i] = _(fontnames[i]);   DiaSetPopup(3, 9, newlang);
	DiaSetPopupEntry(3, lastfont);
	layernames = (char **)emalloc(layers * (sizeof (char *)), el_tempcluster);
	if (layernames == 0) return(0);
	layers = 0;
	for(prim = el_curtech->firstnodeproto; prim != NONODEPROTO; prim = prim->nextnodeproto)
	{
		fun = (prim->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun != NPNODE) continue;
		layernames[layers++] = prim->primname;
	}
	DiaSetPopup(7, layers, layernames);
	if (lastprim < layers) DiaSetPopupEntry(7, lastprim);
	sprintf(line, "%ld", lastscale);
	DiaSetText(9, line);
	if (us_lastplacetextmessage != 0)
		DiaSetText(-6, us_lastplacetextmessage);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}
	lastfont = DiaGetPopupEntry(3);
	lastprim = DiaGetPopupEntry(7);
	lastscale = atoi(DiaGetText(9));
	if (us_lastplacetextmessage != 0) efree((char *)us_lastplacetextmessage);
	(void)allocstring(&us_lastplacetextmessage, DiaGetText(6), us_aid->cluster);

	if (itemHit == OK)
	{
		us_layouttext(layernames[lastprim], fontnames[lastfont],
			lastscale, us_lastplacetextmessage);
	}
	DiaDoneDialog();
	efree((char *)layernames);
	return(0);
}

/****************************** NODE CREATION OPTIONS DIALOG ******************************/

/* New node options */
DIALOGITEM us_defnodedialogitems[] =
{
 /*  1 */ {0, {236,388,260,452}, BUTTON, N_("OK")},
 /*  2 */ {0, {196,388,220,452}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,208,48,318}, EDITTEXT, ""},
 /*  4 */ {0, {32,24,48,205}, MESSAGE, N_("X size of new primitives:")},
 /*  5 */ {0, {56,24,72,205}, MESSAGE, N_("Y size of new primitives:")},
 /*  6 */ {0, {56,208,72,318}, EDITTEXT, ""},
 /*  7 */ {0, {8,4,24,142}, MESSAGE, N_("For primitive:")},
 /*  8 */ {0, {8,144,24,354}, POPUP, ""},
 /*  9 */ {0, {168,24,184,230}, MESSAGE, N_("Rotation of new nodes:")},
 /* 10 */ {0, {168,240,184,293}, EDITTEXT, ""},
 /* 11 */ {0, {168,316,184,421}, CHECK, N_("Transposed")},
 /* 12 */ {0, {132,4,133,452}, DIVIDELINE, ""},
 /* 13 */ {0, {144,4,160,152}, MESSAGE, N_("For all nodes:")},
 /* 14 */ {0, {192,24,208,338}, CHECK, N_("Disallow modification of locked primitives")},
 /* 15 */ {0, {216,24,232,338}, CHECK, N_("Move after Duplicate")},
 /* 16 */ {0, {240,24,256,338}, CHECK, N_("Duplicate/Array/Extract copies exports")},
 /* 17 */ {0, {104,40,120,246}, MESSAGE, N_("Rotation of new nodes:")},
 /* 18 */ {0, {104,256,120,309}, EDITTEXT, ""},
 /* 19 */ {0, {104,332,120,437}, CHECK, N_("Transposed")},
 /* 20 */ {0, {84,24,100,225}, CHECK, N_("Override default orientation")}
};
DIALOG us_defnodedialog = {{50,75,319,536}, N_("New Node Options"), 0, 20, us_defnodedialogitems};

/*
 * special case for the "defnode" dialog
 * X size               = 3 (edit text)
 * Y size               = 6 (edit text)
 * Primitive name       = 8 (popup)
 * all Rotation         = 10 (edit text)
 * all Transposed       = 11 (check)
 * Allow prim mod       = 14 (check)
 * Move after dup       = 15 (check)
 * Dup copies ports     = 16 (check)
 * node Rotation        = 18 (edit text)
 * node Transposed      = 19 (check)
 * override orientation = 20 (check)
 */
typedef struct
{
	INTBIG xsize, ysize;
	INTBIG pangle;
} DEFPRIMINFO;

INTSML us_defnodedlog(void)
{
	INTBIG itemHit, i, j, pangle, thispangle, numprims, reloadprim, value;
	INTBIG plx, ply, phx, phy, lx, pxs, pys, nodesize[2];
	REGISTER NODEPROTO *thisprim, *np;
	REGISTER VARIABLE *var;
	REGISTER char **primnames;
	REGISTER DEFPRIMINFO *dpi;

	/* display the defnode dialog box */
	if (DiaInitDialog(&us_defnodedialog) != 0) return(0);

	/* construct lists of primitives */
	numprims = 0;
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		numprims++;
	primnames = (char **)emalloc(numprims * (sizeof (char *)), el_tempcluster);
	numprims = 0;
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		primnames[numprims++] = np->primname;
	DiaSetPopup(8, numprims, primnames);
	efree((char *)primnames);

	/* save existing state */
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
	{
		dpi = (DEFPRIMINFO *)emalloc(sizeof (DEFPRIMINFO), el_tempcluster);
		if (dpi == 0) return(0);
		np->temp1 = (INTBIG)dpi;
		defaultnodesize(np, &pxs, &pys);
		nodeprotosizeoffset(np, &plx, &ply, &phx, &phy);
		dpi->xsize = pxs - plx - phx;
		dpi->ysize = pys - ply - phy;
		var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle);
		if (var == NOVARIABLE) dpi->pangle = -1; else
			dpi->pangle = var->addr;
	}

	/* load defaults for primitives */
	thisprim = el_curtech->firstnodeproto;

	/* load defaults for all nodes */
	var = getvalkey((INTBIG)us_aid, VAID, VINTEGER, us_placement_angle);
	if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
	DiaSetText(-10, frtoa(pangle%3600*WHOLE/10));
	DiaSetControl(11, (pangle >= 3600 ? 1 : 0));
	DiaSetControl(14, (us_useroptions&NOPRIMCHANGES) != 0 ? 1 : 0);
	DiaSetControl(15, (us_useroptions&NOMOVEAFTERDUP) == 0 ? 1 : 0);
	DiaSetControl(16, (us_useroptions&DUPCOPIESPORTS) != 0 ? 1 : 0);

	/* loop until done */
	reloadprim = 1;
	for(;;)
	{
		if (reloadprim != 0)
		{
			reloadprim = 0;
			dpi = (DEFPRIMINFO *)thisprim->temp1;
			DiaSetPopupEntry(8, thisprim->primindex-1);
			DiaSetText(3, latoa(dpi->xsize));
			DiaSetText(6, latoa(dpi->ysize));
			if (dpi->pangle < 0)
			{
				DiaSetControl(20, 0);
				DiaSetText(18, "");
				DiaSetControl(19, 0);
				DiaDimItem(17);
				DiaDimItem(18);
				DiaDimItem(19);
			} else
			{
				DiaSetControl(20, 1);
				DiaUnDimItem(17);
				DiaUnDimItem(18);
				DiaUnDimItem(19);
				DiaSetText(18, frtoa(dpi->pangle%3600*WHOLE/10));
				DiaSetControl(19, (dpi->pangle >= 3600 ? 1 : 0));
			}
		}

		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 8)
		{
			i = DiaGetPopupEntry(8);
			for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
				if (np->primindex == i+1) break;
			thisprim = np;
			reloadprim = 1;
			continue;
		}
		if (itemHit == 3 || itemHit == 6)
		{
			dpi = (DEFPRIMINFO *)thisprim->temp1;
			dpi->xsize = atola(DiaGetText(3));
			dpi->ysize = atola(DiaGetText(6));
			continue;
		}
		if (itemHit == 18)
		{
			if (DiaGetControl(20) == 0) continue;
			dpi = (DEFPRIMINFO *)thisprim->temp1;
			dpi->pangle = atofr(DiaGetText(18)) * 10 / WHOLE;
			if (DiaGetControl(19) != 0) dpi->pangle += 3600;
			continue;
		}
		if (itemHit == 11 || itemHit == 14 || itemHit == 15 || itemHit == 16 ||
			itemHit == 19 || itemHit == 20)
		{
			value = 1 - DiaGetControl(itemHit);
			DiaSetControl(itemHit, value);
			if (itemHit == 20)
			{
				dpi = (DEFPRIMINFO *)thisprim->temp1;
				if (value != 0) dpi->pangle = 0; else
					dpi->pangle = -1;
				reloadprim = 1;
			}
			if (itemHit == 19)
			{
				if (DiaGetControl(20) == 0) continue;
				dpi = (DEFPRIMINFO *)thisprim->temp1;
				dpi->pangle = atofr(DiaGetText(18)) * 10 / WHOLE;
				if (DiaGetControl(19) != 0) dpi->pangle += 3600;
				reloadprim = 1;
			}
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* handle primitive size changes */
		for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		{
			dpi = (DEFPRIMINFO *)np->temp1;
			defaultnodesize(np, &pxs, &pys);
			nodeprotosizeoffset(np, &plx, &ply, &phx, &phy);
			if (dpi->xsize != pxs - plx - phx || dpi->ysize != pys - ply - phy)
			{
				nodesize[0] = dpi->xsize+plx+phx;
				nodesize[1] = dpi->ysize+ply+phy;
				(void)setvalkey((INTBIG)np, VNODEPROTO, el_node_default_size,
					(INTBIG)nodesize, VINTEGER|VISARRAY|(2<<VLENGTHSH));
			}
			var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle);
			if (var == NOVARIABLE) thispangle = -1; else
				thispangle = var->addr;
			if (thispangle != dpi->pangle)
			{
				if (dpi->pangle < 0)
				{
					delvalkey((INTBIG)np, VNODEPROTO, us_placement_angle);
				} else
				{
					setvalkey((INTBIG)np, VNODEPROTO, us_placement_angle,
						dpi->pangle, VINTEGER);
				}
			}
		}

		/* handle changes to all nodes */
		lx = us_useroptions;
		i = DiaGetControl(14);
		if (i != 0) lx |= NOPRIMCHANGES; else lx &= ~NOPRIMCHANGES;
		i = DiaGetControl(15);
		if (i == 0) lx |= NOMOVEAFTERDUP; else lx &= ~NOMOVEAFTERDUP;
		i = DiaGetControl(16);
		if (i != 0) lx |= DUPCOPIESPORTS; else lx &= ~DUPCOPIESPORTS;
		if (lx != us_useroptions)
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags, lx, VINTEGER);
		j = (atofr(DiaGetText(10))*10/WHOLE) % 3600;
		if (DiaGetControl(11) != 0) j += 3600;
		if (j != pangle)
			(void)setvalkey((INTBIG)us_aid, VAID, us_placement_angle, j, VINTEGER);
	}
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
		efree((char *)np->temp1);
	DiaDoneDialog();
	return(1);
}

/****************************** NODE INFORMATION DIALOGS ******************************/

/* Resistance */
DIALOGITEM us_resistancedialogitems[] =
{
 /*  1 */ {0, {40,192,64,256}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,16,64,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,24,24,118}, EDITTEXT, ""},
 /*  4 */ {0, {8,128,24,239}, POPUP, ""},
 /*  5 */ {0, {40,104,64,168}, BUTTON, N_("More...")}
};
DIALOG us_resistancedialog = {{50,75,124,345}, N_("Resistance"), 0, 5, us_resistancedialogitems};

/* Capacitance */
DIALOGITEM us_capacitancedialogitems[] =
{
 /*  1 */ {0, {40,176,64,240}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,16,64,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,16,24,110}, EDITTEXT, ""},
 /*  4 */ {0, {8,120,24,246}, POPUP, ""},
 /*  5 */ {0, {40,96,64,160}, BUTTON, N_("More...")}
};
DIALOG us_capacitancedialog = {{50,75,123,330}, N_("Capacitance"), 0, 5, us_capacitancedialogitems};

/* Inductance */
DIALOGITEM us_inductancedialogitems[] =
{
 /*  1 */ {0, {40,168,64,232}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,8,64,72}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,16,24,110}, EDITTEXT, ""},
 /*  4 */ {0, {8,120,24,237}, POPUP, ""},
 /*  5 */ {0, {40,88,64,152}, BUTTON, N_("More...")}
};
DIALOG us_inductancedialog = {{50,75,126,321}, N_("Inductance"), 0, 5, us_inductancedialogitems};

/* VCCS Transconductance */
DIALOGITEM us_vccsdialogitems[] =
{
 /*  1 */ {0, {40,176,64,240}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,16,64,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,16,24,110}, EDITTEXT, ""},
 /*  4 */ {0, {8,120,24,247}, POPUP, ""},
 /*  5 */ {0, {40,96,64,160}, BUTTON, N_("More...")}
};
DIALOG us_vccsdialog = {{50,75,125,331}, N_("VCCS Transconductance"), 0, 5, us_vccsdialogitems};

/* Area */
DIALOGITEM us_areadialogitems[] =
{
 /*  1 */ {0, {40,184,64,248}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,8,64,72}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,80,24,174}, EDITTEXT, ""},
 /*  4 */ {0, {40,96,64,160}, BUTTON, N_("More...")}
};
DIALOG us_areadialog = {{50,75,124,333}, N_("Area"), 0, 4, us_areadialogitems};

/* Width/Length */
DIALOGITEM us_widlendialogitems[] =
{
 /*  1 */ {0, {88,184,112,248}, BUTTON, N_("OK")},
 /*  2 */ {0, {88,8,112,72}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,108,24,202}, EDITTEXT, ""},
 /*  4 */ {0, {8,8,24,59}, MESSAGE, N_("Width:")},
 /*  5 */ {0, {32,108,48,202}, EDITTEXT, ""},
 /*  6 */ {0, {32,8,48,60}, MESSAGE, N_("Length:")},
 /*  7 */ {0, {56,108,72,202}, EDITTEXT, ""},
 /*  8 */ {0, {56,8,72,96}, MESSAGE, N_("SPICE name:")},
 /*  9 */ {0, {88,96,112,160}, BUTTON, N_("More")}
};
DIALOG us_widlendialog = {{50,75,171,332}, N_("Transistor Information"), 0, 9, us_widlendialogitems};

/* Gain */
DIALOGITEM us_gaindialogitems[] =
{
 /*  1 */ {0, {40,176,64,240}, BUTTON, N_("OK")},
 /*  2 */ {0, {40,16,64,80}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,88,24,213}, EDITTEXT, ""},
 /*  4 */ {0, {8,40,24,83}, MESSAGE, N_("Gain:")},
 /*  5 */ {0, {40,96,64,160}, BUTTON, N_("More...")}
};
DIALOG us_gaindialog = {{50,75,123,334}, N_("Gain"), 0, 5, us_gaindialogitems};

/* Source Information */
DIALOGITEM us_sourcedialogitems[] =
{
 /*  1 */ {0, {72,268,96,336}, BUTTON, N_("OK")},
 /*  2 */ {0, {72,20,96,88}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,112,24,264}, POPUP, ""},
 /*  4 */ {0, {36,8,52,100}, MESSAGE, N_("SPICE Card:")},
 /*  5 */ {0, {8,8,24,100}, MESSAGE, N_("Source type:")},
 /*  6 */ {0, {36,112,52,348}, EDITTEXT, ""},
 /*  7 */ {0, {72,144,96,212}, BUTTON, N_("More...")}
};
DIALOG us_sourcedialog = {{75,75,186,440}, N_("Source Information"), 0, 7, us_sourcedialogitems};

void us_movedialogtonode(DIALOG*, GEOM*);

/*
 * routine to move dialog "dia" to a place close to object "geom" in the current window
 */
void us_movedialogtonode(DIALOG *dia, GEOM *geom)
{
	REGISTER INTBIG x, y, wid, hei;
	INTSML swid, shei;

	if (geom == NOGEOM) return;
	if (el_curwindowpart == NOWINDOWPART) return;
	wid = dia->windowRect.right - dia->windowRect.left;
	hei = dia->windowRect.bottom - dia->windowRect.top;

	/* see which side the dialog goes on */
	x = applyxscale(el_curwindowpart, geom->highx-el_curwindowpart->screenlx) + el_curwindowpart->uselx;
	getwindowframesize(el_curwindowpart->frame, &swid, &shei);
	if (x + wid > swid)
	{
		/* attach on left side */
		x = applyxscale(el_curwindowpart, geom->lowx-el_curwindowpart->screenlx) + el_curwindowpart->uselx;
		dia->windowRect.left = (INTSML)(x - wid);   dia->windowRect.right = (INTSML)x;
	} else
	{
		/* attach on right side */
		dia->windowRect.left = (INTSML)x;   dia->windowRect.right = (INTSML)(x + wid);
	}

	y = applyyscale(el_curwindowpart, geom->highy-el_curwindowpart->screenly) + el_curwindowpart->usely;
	if (shei-y-hei <= 39)
	{
		/* attach on bottom side */
		y = applyyscale(el_curwindowpart, geom->lowy-el_curwindowpart->screenly) + el_curwindowpart->usely;
		dia->windowRect.bottom = (INTSML)(shei - y + hei);
		dia->windowRect.top = (INTSML)(shei - y);
	} else
	{
		/* attach on top side */
		dia->windowRect.bottom = (INTSML)(shei - y);
		dia->windowRect.top = (INTSML)(shei - y - hei);
	}
}

/*
 * special case for the "resistance" dialog
 * resistance value   = 3 (edit)
 * units              = 4 (popup)
 * More...            = 5 (button)
 */
INTSML us_resistancedlog(char *prompt, char *paramstart[], char *initial)
{
	INTBIG itemHit, i;
	char *newlang[4];
	static char *resnames[] = {N_("Ohms"), N_("Kilo-ohms"), N_("Mega-ohms"), N_("Giga-Ohms")};
	REGISTER HIGHLIGHT *high;
	char line[70];

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_resistancedialog, high->fromgeom);
	}

	/* display the resistance dialog box */
	if (namesame(prompt, "ccvs") == 0) (void)strcpy(line, _("CCVS transresistance")); else
		(void)sprintf(line, _("%s resistance"), prompt);
	us_resistancedialog.movable = line;
	if (initial != 0) us_resistancedialog.items = 5; else us_resistancedialog.items = 4;
	if (DiaInitDialog(&us_resistancedialog) != 0) return(0);
	for(i=0; i<4; i++) newlang[i] = _(resnames[i]);   DiaSetPopup(4, 4, newlang);
	if (initial == 0) DiaSetText(3, "100"); else
	{
		i = strlen(initial);
		if (i > 0 && namesame(&initial[i-1], "K") == 0)
		{
			DiaSetPopupEntry(4, 1);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'K';
		} else if (i > 2 && namesame(&initial[i-3], "MEG") == 0)
		{
			DiaSetPopupEntry(4, 2);
			initial[i-3] = 0;
			DiaSetText(3, initial);
			initial[i-3] = 'M';
		} else if (i > 0 && namesame(&initial[i-1], "G") == 0)
		{
			DiaSetPopupEntry(4, 3);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'G';
		} else DiaSetText(3, initial);
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 5) break;
	}

	(void)initinfstr();
	(void)addstringtoinfstr(DiaGetText(3));
	i = DiaGetPopupEntry(4);
	switch (i)
	{
		case 1: (void)addstringtoinfstr("K");     break;
		case 2: (void)addstringtoinfstr("MEG");   break;
		case 3: (void)addstringtoinfstr("G");     break;
	}
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 5) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "capacitance" dialog
 * capacitance value   = 3 (edit)
 * units               = 4 (popup)
 * More...             = 5 (button)
 */
INTSML us_capacitancedlog(char *paramstart[], char *initial)
{
	INTBIG itemHit, i;
	char *newlang[5];
	static char *capnames[] = {N_("Femto-farads"), N_("Pico-farads"), N_("Micro-farads"), N_("Milli-farads"),
		N_("Farads")};
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_capacitancedialog, high->fromgeom);
	}

	/* display the capacitance dialog box */
	if (initial != 0) us_capacitancedialog.items = 5; else us_capacitancedialog.items = 4;
	if (DiaInitDialog(&us_capacitancedialog) != 0) return(0);
	for(i=0; i<5; i++) newlang[i] = _(capnames[i]);   DiaSetPopup(4, 5, newlang);
	if (initial == 0)
	{
		DiaSetText(3, "100");
		DiaSetPopupEntry(4, 3);
	} else
	{
		i = strlen(initial);
		if (i > 0 && namesame(&initial[i-1], "F") == 0)
		{
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'F';
		} else if (i > 0 && namesame(&initial[i-1], "P") == 0)
		{
			DiaSetPopupEntry(4, 1);
			initial[i-3] = 0;
			DiaSetText(3, initial);
			initial[i-3] = 'P';
		} else if (i > 0 && namesame(&initial[i-1], "U") == 0)
		{
			DiaSetPopupEntry(4, 2);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'U';
		} else if (i > 0 && namesame(&initial[i-1], "M") == 0)
		{
			DiaSetPopupEntry(4, 3);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'M';
		} else
		{
			DiaSetPopupEntry(4, 4);
			DiaSetText(3, initial);
		}
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 5) break;
	}

	(void)initinfstr();
	(void)addstringtoinfstr(DiaGetText(3));
	i = DiaGetPopupEntry(4);
	switch (i)
	{
		case 0: (void)addstringtoinfstr("F");   break;
		case 1: (void)addstringtoinfstr("P");   break;
		case 2: (void)addstringtoinfstr("U");   break;
		case 3: (void)addstringtoinfstr("M");   break;
	}
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 5) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "inductance" dialog
 * inductance value   = 3 (edit)
 * units              = 4 (popup)
 * More...            = 5 (button)
 */
INTSML us_inductancedlog(char *paramstart[], char *initial)
{
	INTBIG itemHit, i;
	char *newlang[3];
	static char *indnames[] = {N_("Micro-henrys"), N_("Milli-henrys"), N_("Henrys")};
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_inductancedialog, high->fromgeom);
	}

	/* display the inductance dialog box */
	if (initial != 0) us_inductancedialog.items = 5; else us_inductancedialog.items = 4;
	if (DiaInitDialog(&us_inductancedialog) != 0) return(0);
	for(i=0; i<3; i++) newlang[i] = _(indnames[i]);   DiaSetPopup(4, 3, newlang);
	if (initial == 0)
	{
		DiaSetText(3, "100");
		DiaSetPopupEntry(4, 2);
	} else
	{
		i = strlen(initial);
		if (i > 0 && namesame(&initial[i-1], "U") == 0)
		{
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'U';
		} else if (i > 0 && namesame(&initial[i-1], "M") == 0)
		{
			DiaSetPopupEntry(4, 1);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'M';
		} else
		{
			DiaSetPopupEntry(4, 2);
			DiaSetText(3, initial);
		}
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 5) break;
	}

	(void)initinfstr();
	(void)addstringtoinfstr(DiaGetText(3));
	i = DiaGetPopupEntry(4);
	switch (i)
	{
		case 0: (void)addstringtoinfstr("U");   break;
		case 1: (void)addstringtoinfstr("M");   break;
	}
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 5) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "VCCS Transconductance" dialog
 * siemens value       = 3 (edit)
 * units               = 4 (popup)
 * More...             = 5 (button)
 */
INTSML us_vccsdlog(char *paramstart[], char *initial)
{
	INTBIG itemHit, i;
	char *newlang[3];
	static char *sienames[] = {N_("Micro-siemens"), N_("Milli-siemens"), N_("Siemens")};
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_vccsdialog, high->fromgeom);
	}

	/* display the siemens dialog box */
	if (initial != 0) us_vccsdialog.items = 5; else us_vccsdialog.items = 4;
	if (DiaInitDialog(&us_vccsdialog) != 0) return(0);
	for(i=0; i<3; i++) newlang[i] = _(sienames[i]);   DiaSetPopup(4, 3, newlang);
	if (initial == 0)
	{
		DiaSetText(3, "100");
		DiaSetPopupEntry(4, 2);
	} else
	{
		i = strlen(initial);
		if (i > 0 && namesame(&initial[i-1], "U") == 0)
		{
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'U';
		} else if (i > 0 && namesame(&initial[i-1], "M") == 0)
		{
			DiaSetPopupEntry(4, 1);
			initial[i-1] = 0;
			DiaSetText(3, initial);
			initial[i-1] = 'M';
		} else
		{
			DiaSetPopupEntry(4, 2);
			DiaSetText(3, initial);
		}
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 5) break;
	}

	(void)initinfstr();
	(void)addstringtoinfstr(DiaGetText(3));
	i = DiaGetPopupEntry(4);
	switch (i)
	{
		case 0: (void)addstringtoinfstr("U");   break;
		case 1: (void)addstringtoinfstr("M");   break;
	}
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 5) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "area" dialog
 * area value           = 3 (edit)
 * More...              = 4 (button)
 */
INTSML us_areadlog(char *prompt, char *paramstart[], char *initial)
{
	INTBIG itemHit;
	static char line[80];
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_areadialog, high->fromgeom);
	}

	/* display the area dialog box */
	(void)sprintf(line, _("%s area"), prompt);
	us_areadialog.movable = line;
	if (initial != 0) us_areadialog.items = 4; else us_areadialog.items = 3;
	if (DiaInitDialog(&us_areadialog) != 0) return(0);
	if (initial == 0) DiaSetText(3, "10"); else
		DiaSetText(3, initial);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 4) break;
	}

	strcpy(line, DiaGetText(3));
	paramstart[0] = line;
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 4) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "width/length" dialog
 * width value      = 3 (edit)
 * length value     = 5 (edit)
 * More...          = 9 (button)
 * SPICE name       = 7 (edit)
 */
INTSML us_widlendlog(char *paramstart[], char *initial)
{
	INTBIG itemHit;
	REGISTER char *pt, *ptex, *start;
	static char line[90];
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_widlendialog, high->fromgeom);
	}

	/* display the width/length dialog box */
	if (initial != 0) us_widlendialog.items = 9; else us_widlendialog.items = 8;
	if (DiaInitDialog(&us_widlendialog) != 0) return(0);
	if (initial == 0)
	{
		DiaSetText(3, "2");
		DiaSetText(5, "2");
		DiaSetText(7, "");
	} else
	{
		for(pt = initial; *pt != 0 && *pt != '/'; pt++) ;
		if (*pt == '/')
		{
			*pt = 0;
			DiaSetText(3, initial);
			*pt++ = '/';
			start = pt;
			for( ; *pt != 0 && *pt != '/'; pt++) ;
			if (*pt == '/')
			{
				*pt = 0;
				DiaSetText(5, start);
				*pt++ = '/';
				DiaSetText(7, pt);
			} else
			{
				DiaSetText(5, start);
				DiaSetText(7, "");
			}
		} else
		{
			DiaSetText(3, initial);
			DiaSetText(5, initial);
			DiaSetText(7, "");
		}
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 9) break;
	}

	strcpy(line, DiaGetText(3));
	pt = DiaGetText(5);
	while (*pt == ' ' || *pt == '\t') pt++;
	ptex = DiaGetText(7);
	while (*ptex == ' ' || *ptex == '\t') ptex++;

	if (*pt != 0 || *ptex != 0)
	{
		strcat(line, "/");
		strcat(line, pt);
	}
	if (*ptex != 0)
	{
		strcat(line, "/");
		strcat(line, ptex);
	}
	paramstart[0] = line;
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 9) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "gain" dialog
 * area value           = 3 (edit)
 * units                = 4 (popup)
 * More...              = 5 (button)
 */
INTSML us_gaindlog(char *prompt, char *paramstart[], char *initial)
{
	INTBIG itemHit;
	static char line[50];
	REGISTER HIGHLIGHT *high;

	/* if an initial value is given, search for highlighted node and move dialog to it */
	if (initial != 0)
	{
		high = us_getonehighlight();
		if (high != NOHIGHLIGHT) us_movedialogtonode(&us_gaindialog, high->fromgeom);
	}

	/* display the gain dialog box */
	(void)sprintf(line, _("%s gain"), prompt);
	us_gaindialog.movable = line;
	if (initial != 0) us_gaindialog.items = 5; else us_gaindialog.items = 4;
	if (DiaInitDialog(&us_gaindialog) != 0) return(0);
	if (initial == 0) DiaSetText(3, "10"); else DiaSetText(3, initial);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 5) break;
	}

	paramstart[0] = us_putintoinfstr(DiaGetText(3));
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 5) (void)us_showdlog(0);
	return(0);
}

/*
 * special case for the "source" dialog
 * source type          = 3 (popup)
 * SPICE card           = 6 (edit text)
 * More...              = 7 (button)
 */
INTSML us_sourcedlog(char *paramstart[], char *initial)
{
	INTBIG itemHit, sourcetype, i;
	char *extra, *newlang[11];
	REGISTER NODEINST *ni;
	enum {kSourceUnknown=0, kSourceVoltage, kSourceCurrent, kSourceCurrentMeter,
		kSourceTransient, kSourceDC, kSourceAC, kSourceNodeSet, kSourceExtension,
		kSourceBulk, kNodeSpecial};
	static char *sourcetypes[] = {N_("Unknown"), N_("Voltage Source"), N_("Current Source"),
		N_("Current Meter"), N_("Transient Analysis"), N_("DC Analysis"), N_("AC Analysis"),
		N_("Node Set"), N_("Extension"), N_("Bulk"), N_("Special")};

	/* if an initial value is given, search for highlighted node and move dialog to it */
	ni = (NODEINST *)us_getobject(OBJNODEINST, 1);
	if (ni == NONODEINST)
	{
		us_abortcommand(_("Select a source node first"));
		return(0);
	}
	if (initial != 0)
		us_movedialogtonode(&us_sourcedialog, ni->geom);

	/* display the gain dialog box */
	if (DiaInitDialog(&us_sourcedialog) != 0) return(0);

	switch (nodefunction(ni, &extra))
	{
		case NPSOURCE:   sourcetype = kSourceUnknown;        break;
		case NPSOURCEV:  sourcetype = kSourceVoltage;        break;
		case NPSOURCEC:  sourcetype = kSourceCurrent;        break;
		case NPSOURCECM: sourcetype = kSourceCurrentMeter;   break;
		case NPSOURCET:  sourcetype = kSourceTransient;      break;
		case NPSOURCEDC: sourcetype = kSourceDC;             break;
		case NPSOURCEAC: sourcetype = kSourceAC;             break;
		case NPSOURCEN:  sourcetype = kSourceNodeSet;        break;
		case NPSOURCEX:  sourcetype = kSourceExtension;      break;
		case NPSOURCEB:  sourcetype = kSourceBulk;           break;
		case NPSOURCES:  sourcetype = kNodeSpecial;          break;
	}

	if (initial != 0 && extra != 0) DiaSetText(-6, extra);
	for(i=0; i<11; i++) newlang[i] = _(sourcetypes[i]);   DiaSetPopup(3, 11, newlang);
	DiaSetPopupEntry(3, sourcetype);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK || itemHit == 7) break;
	}

	(void)initinfstr();
	switch (DiaGetPopupEntry(3))
	{
		case kSourceUnknown:
		case kSourceVoltage:      (void)addstringtoinfstr("v/");   break;
		case kSourceCurrent:      (void)addstringtoinfstr("c/");   break;
		case kSourceCurrentMeter: (void)addstringtoinfstr("cm/");  break;
		case kSourceTransient:    (void)addstringtoinfstr("t/");   break;
		case kSourceDC:           (void)addstringtoinfstr("vd/");  break;
		case kSourceAC:           (void)addstringtoinfstr("a/");   break;
		case kSourceNodeSet:      (void)addstringtoinfstr("n/");   break;
		case kSourceExtension:    (void)addstringtoinfstr("x/");   break;
		case kSourceBulk:         (void)addstringtoinfstr("b/");   break;
		case kNodeSpecial:        (void)addstringtoinfstr("s/");   break;
	}
	(void)addstringtoinfstr(DiaGetText(6));
	paramstart[0] = returninfstr();
	DiaDoneDialog();
	if (itemHit == OK) return(1);
	if (itemHit == 7) (void)us_showdlog(0);
	return(0);
}

/****************************** NODE SIZE DIALOG ******************************/

/* Node Size */
DIALOGITEM us_nodesizedialogitems[] =
{
 /*  1 */ {0, {104,132,128,212}, BUTTON, N_("OK")},
 /*  2 */ {0, {104,4,128,84}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,12,24,92}, MESSAGE|INACTIVE, N_("X Size:")},
 /*  4 */ {0, {36,12,52,92}, MESSAGE|INACTIVE, N_("Y Size:")},
 /*  5 */ {0, {8,100,24,200}, EDITTEXT, ""},
 /*  6 */ {0, {36,100,52,200}, EDITTEXT, ""},
 /*  7 */ {0, {64,4,96,212}, MESSAGE|INACTIVE, ""}
};
DIALOG us_nodesizedialog = {{75,75,212,297}, N_("Set Node Size"), 0, 7, us_nodesizedialogitems};

/*
 * special case for the "node size" dialog
 * X size        = 5 (edit text)
 * Y size        = 6 (edit text)
 * Extra message = 7 (message)
 */
INTSML us_nodesizedlog(char *paramstart[])
{
	INTBIG itemHit, allmanhattan;
	INTSML ret;
	REGISTER INTBIG i;
	static char x[20], y[20];
	REGISTER GEOM **list;
	REGISTER NODEINST *ni;

	/* display the node size dialog box */
	if (DiaInitDialog(&us_nodesizedialog) != 0) return(0);

	/* see if there are nonmanhattan nodes selected */
	allmanhattan = 1;
	list = us_gethighlighted(OBJNODEINST);
	for(i=0; list[i] != NOGEOM; i++)
	{
		ni = list[i]->entryaddr.ni;
		if ((ni->rotation % 900) != 0) allmanhattan = 0;
	}
	if (allmanhattan == 0)
	{
		DiaSetText(7, _("Nonmanhattan nodes selected: sizing in unrotated directions"));
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}

	ret = 0;
	if (itemHit != CANCEL)
	{
		strcpy(x, DiaGetText(5));
		strcpy(y, DiaGetText(6));
		paramstart[ret++] = x;
		paramstart[ret++] = y;
		if (allmanhattan != 0) paramstart[ret++] = "use-transformation";
	}
	DiaDoneDialog();
	return(ret);
}

/****************************** OPTION SAVING DIALOG ******************************/

/* Option Saving */
DIALOGITEM us_optionsavingdialogitems[] =
{
 /*  1 */ {0, {232,216,256,288}, BUTTON, N_("OK")},
 /*  2 */ {0, {232,12,256,84}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {4,8,20,291}, MESSAGE, N_("Marked options are saved with library.")},
 /*  4 */ {0, {44,8,220,298}, SCROLL, ""},
 /*  5 */ {0, {24,8,40,294}, MESSAGE, N_("Click an option to change its mark.")}
};
DIALOG us_optionsavingdialog = {{50,75,318,382}, N_("Option Saving"), 0, 5, us_optionsavingdialogitems};

/*
 * special case for the "Option Saving" dialog
 * List of options = 4 (scroll)
 */
/* this define should match the one in "dbvars.c" */
#define SAVEDBITWORDS 2

INTSML us_optionsavingdlog(void)
{
	INTBIG itemHit, i, err, len, opt;
	INTBIG bits[SAVEDBITWORDS], savebits[SAVEDBITWORDS], origbits[SAVEDBITWORDS];
	REGISTER VARIABLE *var;
	char *name, *msg;

	for(i=0; i<SAVEDBITWORDS; i++) savebits[i] = 0;
	var = getval((INTBIG)el_curlib, VLIBRARY, -1, "LIB_save_options");
	if (var != NOVARIABLE)
	{
		if ((var->type&VISARRAY) == 0)
		{
			savebits[0] = var->addr;
		} else
		{
			len = getlength(var);
			for(i=0; i<len; i++) savebits[i] = ((INTBIG *)var->addr)[i];
		}
	}
	for(i=0; i<SAVEDBITWORDS; i++) origbits[i] = savebits[i];

	/* display the visibility dialog box */
	if (DiaInitDialog(&us_optionsavingdialog) != 0) return(0);
	DiaInitTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	for(opt=0; ; opt++)
	{
		err = describeoptions(opt, &name, bits);
		if (err != 0) break;
		(void)initinfstr();
		for(i=0; i<SAVEDBITWORDS; i++) if ((savebits[i]&bits[i]) != 0) break;
		if (i < SAVEDBITWORDS) (void)addtoinfstr('>'); else
			(void)addtoinfstr(' ');
		(void)addtoinfstr(' ');
		(void)addstringtoinfstr(name);
		DiaStuffLine(4, returninfstr());
	}
	DiaSelectLine(4, -1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 4)
		{
			/* toggle layer visibility for this layer */
			i = DiaGetCurLine(4);
			msg = DiaGetScrollLine(4, i);
			if (*msg == ' ') *msg = '>'; else *msg = ' ';
			DiaSetScrollLine(4, i, msg);
			DiaSelectLine(4, -1);
			continue;
		}
	}

	if (itemHit == OK)
	{
		for(i=0; i<SAVEDBITWORDS; i++) savebits[i] = 0;
		for(opt=0; ; opt++)
		{
			err = describeoptions(opt, &name, bits);
			if (err != 0) break;
			msg = DiaGetScrollLine(4, opt);
			if (*msg == '>')
			{
				for(i=0; i<SAVEDBITWORDS; i++)
					savebits[i] |= bits[i];
			}
		}
		for(i=0; i<SAVEDBITWORDS; i++) if (origbits[i] != savebits[i]) break;
		if (i < SAVEDBITWORDS)
			(void)setval((INTBIG)el_curlib, VLIBRARY, "LIB_save_options",
				(INTBIG)savebits, VINTEGER|VISARRAY|(SAVEDBITWORDS<<VLENGTHSH));
	}
	DiaDoneDialog();
	return(0);
}

/****************************** OUTLINE INFO DIALOG ******************************/

/* Outline Info */
DIALOGITEM us_outlinedialogitems[] =
{
 /*  1 */ {0, {76,208,100,272}, BUTTON, N_("OK")},
 /*  2 */ {0, {20,208,44,272}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,8,168,192}, SCROLL, ""},
 /*  4 */ {0, {184,8,200,28}, MESSAGE, N_("X:")},
 /*  5 */ {0, {184,32,200,104}, EDITTEXT, ""},
 /*  6 */ {0, {216,8,232,28}, MESSAGE, N_("Y:")},
 /*  7 */ {0, {216,32,232,104}, EDITTEXT, ""},
 /*  8 */ {0, {208,160,232,272}, BUTTON, N_("Duplicate Point")},
 /*  9 */ {0, {176,160,200,272}, BUTTON, N_("Delete Point")},
 /* 10 */ {0, {132,208,156,272}, BUTTON, N_("Apply")}
};
DIALOG us_outlinedialog = {{50,75,291,356}, N_("Outline Information"), 0, 10, us_outlinedialogitems};

/* special case for the "outline" dialog
 * Points    = 3 (user item)
 * X         = 5 (edit text)
 * Y         = 7 (edit text)
 * duplicate = 8 (button)
 * delete    = 9 (button)
 * apply     = 10 (button)
 */
INTSML us_tracedlog(void)
{
	INTBIG itemHit, len, i, j, space, changed;
	INTBIG *pts, *newpts, x, y;
	char lne[256];
	HIGHLIGHT *high;
	REGISTER NODEINST *ni;
	REGISTER VARIABLE *var;

	/* make sure there is a highlighted node with outline information */
	high = us_getonehighlight();
	if (high == NOHIGHLIGHT) return(0);
	if ((high->status&HIGHTYPE) != HIGHFROM) return(0);
	if (high->fromgeom->entrytype != OBJNODEINST) return(0);
	ni = (NODEINST *)high->fromgeom->entryaddr.ni;
	if ((ni->proto->userbits&HOLDSTRACE) == 0) return(0);
	var = gettrace(ni);

	/* display the outline dialog box */
	if (DiaInitDialog(&us_outlinedialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);

	/* copy outline data and display it */
	if (var == NOVARIABLE) len = 0; else len = getlength(var) / 2;
	x = (ni->highx + ni->lowx) / 2;
	y = (ni->highy + ni->lowy) / 2;
	space = len+1;
	pts = (INTBIG *)emalloc(space * 2 * SIZEOFINTBIG, el_tempcluster);
	for(i=0; i<len; i++)
	{
		pts[i*2] = ((INTBIG *)var->addr)[i*2] + x;
		pts[i*2+1] = ((INTBIG *)var->addr)[i*2+1] + y;
		(void)sprintf(lne, "%d: (%s, %s)", i, latoa(pts[i*2]), latoa(pts[i*2+1]));
		DiaStuffLine(3, lne);
	}
	if (len == 0) DiaSelectLine(3, -1); else
	{
		DiaSelectLine(3, 0);
		DiaSetText(-5, latoa(pts[0]));
		DiaSetText(7, latoa(pts[1]));
	}

	/* loop until done */
	changed = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 3)
		{
			/* load this point */
			i = DiaGetCurLine(3);
			if (i < 0 || i >= len) continue;
			DiaSetText(5, latoa(pts[i*2]));
			DiaSetText(7, latoa(pts[i*2+1]));
			continue;
		}
		if (itemHit == 8)
		{
			/* duplicate point */
			changed++;
			if (len == 0)
			{
				pts[0] = pts[1] = 0;
				(void)sprintf(lne, "%d: (%s, %s)", 0, latoa(pts[0]), latoa(pts[1]));
				DiaSetScrollLine(3, 0, lne);
				len++;
				continue;
			}

			if (len >= space)
			{
				newpts = (INTBIG *)emalloc((len+1) * 2 * SIZEOFINTBIG, el_tempcluster);
				if (newpts == 0) continue;
				for(i=0; i<len; i++)
				{
					newpts[i*2] = pts[i*2];
					newpts[i*2+1] = pts[i*2+1];
				}
				efree((char *)pts);
				pts = newpts;
				space = len + 1;
			}
			i = DiaGetCurLine(3);
			for(j=len; j>i; j--)
			{
				pts[j*2] = pts[(j-1)*2];
				pts[j*2+1] = pts[(j-1)*2+1];
				(void)sprintf(lne, "%ld: (%s, %s)", j, latoa(pts[j*2]), latoa(pts[j*2+1]));
				DiaSetScrollLine(3, j, lne);
			}
			len++;
			continue;
		}
		if (itemHit == 9)
		{
			/* delete point */
			changed++;
			if (len <= 1) continue;
			i = DiaGetCurLine(3);
			for(j=i; j<len-1; j++)
			{
				pts[j*2] = pts[(j+1)*2];
				pts[j*2+1] = pts[(j+1)*2+1];
				(void)sprintf(lne, "%d: (%s, %s)", j, latoa(pts[j*2]), latoa(pts[j*2+1]));
				DiaSetScrollLine(3, j, lne);
			}
			DiaSetScrollLine(3, len-1, "");
			len--;
			if (i == len) DiaSelectLine(3, i-1);
			continue;
		}
		if (itemHit == 5 || itemHit == 7)
		{
			/* change to X or Y coordinates */
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			x = atola(DiaGetText(5));
			y = atola(DiaGetText(7));
			if (pts[i*2] == x && pts[i*2+1] == y) continue;
			changed++;
			pts[i*2] = x;   pts[i*2+1] = y;
			(void)sprintf(lne, "%d: (%s, %s)", i, latoa(pts[i*2]), latoa(pts[i*2+1]));
			DiaSetScrollLine(3, i, lne);
			continue;
		}
		if (itemHit == 10)
		{
			/* apply */
			us_pushhighlight();
			us_clearhighlightcount();
			us_settrace(ni, pts, (INTSML)len);
			(void)us_pophighlight(1);
			us_showallhighlight();
			us_endchanges(NOWINDOWPART);
			changed = 0;
			continue;
		}
	}

	if (itemHit != CANCEL && changed != 0)
	{
		us_pushhighlight();
		us_clearhighlightcount();
		us_settrace(ni, pts, (INTSML)len);
		(void)us_pophighlight(1);
	}
	DiaDoneDialog();
	efree((char *)pts);
	return(0);
}

/****************************** PORT CREATION DIALOG ******************************/

/* New port */
DIALOGITEM us_portdialogitems[] =
{
 /*  1 */ {0, {88,256,112,328}, BUTTON, N_("OK")},
 /*  2 */ {0, {88,32,112,104}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,176,48,340}, POPUP, ""},
 /*  4 */ {0, {8,116,24,340}, EDITTEXT, ""},
 /*  5 */ {0, {8,8,24,112}, MESSAGE, N_("Export name:")},
 /*  6 */ {0, {56,8,72,128}, CHECK, N_("Always drawn")},
 /*  7 */ {0, {32,8,48,175}, MESSAGE, N_("Export characteristics:")},
 /*  8 */ {0, {56,168,72,288}, CHECK, N_("Body only")}
};
DIALOG us_portdialog = {{50,75,171,424}, N_("Create Export on Highlighted"), 0, 8, us_portdialogitems};

/*
 * special case for the "port" dialog
 * Name             = 4 (edit text)
 * Characteristics  = 3 (popup)
 * Always drawn     = 6 (check)
 * Body only        = 8 (check)
 */
INTSML us_portdlog(char *paramstart[])
{
	INTBIG itemHit, i;
	static INTBIG lastchar = 0;
	char *newlang[15];
	struct portbut { INTBIG button;  char *name; };
	static char *charnames[15] = {N_("Unknown"), N_("Input"), N_("Output"), N_("Bidirectional"),
		N_("Power"), N_("Ground"), N_("Reference Output"), N_("Reference Input"), N_("Clock"),
		N_("Clock phase 1"), N_("Clock phase 2"), N_("Clock phase 3"), N_("Clock phase 4"),
		N_("Clock phase 5"), N_("Clock phase 6")};
	static char *intnames[15] = {"", " input", " output", " bidirectional",
		" power", " ground", " refout", " refin", " clock", " clock1",
		" clock2", " clock3", " clock4", " clock5", " clock6"};

	/* display the port dialog box */
	if (DiaInitDialog(&us_portdialog) != 0) return(0);
	DiaSetText(-4, "");
	for(i=0; i<15; i++) newlang[i] = _(charnames[i]);   DiaSetPopup(3, 15, newlang);
	DiaSetPopupEntry(3, lastchar);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(4)) break;
		if (itemHit == 6 || itemHit == 8)
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
	}

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		(void)initinfstr();
		(void)addstringtoinfstr(DiaGetText(4));
		lastchar = DiaGetPopupEntry(3);
		(void)addstringtoinfstr(intnames[lastchar]);
		if (DiaGetControl(6) != 0) (void)addstringtoinfstr(" always-drawn");
		if (DiaGetControl(8) != 0) (void)addstringtoinfstr(" body-only");
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(1);
}

/****************************** PORT DISPLAY DIALOG ******************************/

/* Port Display Options */
DIALOGITEM us_portdisplaydialogitems[] =
{
 /*  1 */ {0, {112,92,136,156}, BUTTON, N_("OK")},
 /*  2 */ {0, {112,8,136,72}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,8,24,155}, RADIO, N_("Full Export Names")},
 /*  4 */ {0, {32,8,48,155}, RADIO, N_("Short Export Names")},
 /*  5 */ {0, {56,8,72,155}, RADIO, N_("Exports as Crosses")},
 /*  6 */ {0, {80,8,96,155}, RADIO, N_("No Exports Shown")}
};
DIALOG us_portdisplaydialog = {{133,131,278,304}, N_("Export Display Options"), 0, 6, us_portdisplaydialogitems};

/*
 * special case for the "Port Display" dialog
 * Full Port Names     = 3 (button)
 * Short Port Names    = 4 (button)
 * Ports as Crosses    = 5 (button)
 * No Ports Shown      = 6 (button)
 */
INTSML us_portdisplaydlog(void)
{
	REGISTER INTBIG itemHit, newlabels, labels;
	WINDOWPART *w;

	/* display the port labels dialog */
	if (us_needwindow()) return(0);
	if (DiaInitDialog(&us_portdisplaydialog) != 0) return(0);
	labels = us_useroptions & PORTLABELS;
	switch (labels)
	{
		case PORTSFULL:  DiaSetControl(3, 1);   break;
		case PORTSSHORT: DiaSetControl(4, 1);   break;
		case PORTSCROSS: DiaSetControl(5, 1);   break;
		case PORTSOFF:   DiaSetControl(6, 1);   break;
	}
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 3 || itemHit == 4 || itemHit == 5 || itemHit == 6)
		{
			DiaSetControl(3, 0);
			DiaSetControl(4, 0);
			DiaSetControl(5, 0);
			DiaSetControl(6, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
	}
	if (DiaGetControl(3) != 0) newlabels = PORTSFULL; else
		if (DiaGetControl(4) != 0) newlabels = PORTSSHORT; else
			if (DiaGetControl(5) != 0) newlabels = PORTSCROSS; else
				newlabels = PORTSOFF;
	DiaDoneDialog();
	if (itemHit == OK)
	{
		if (labels != newlabels)
		{
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags,
				(us_useroptions & ~PORTLABELS) | newlabels, VINTEGER);
			us_pushhighlight();
			us_clearhighlightcount();
			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
			{
				startobjectchange((INTBIG)w, VWINDOWPART);
				if (w->redisphandler != 0) (*w->redisphandler)(w);
				endobjectchange((INTBIG)w, VWINDOWPART);
			}
			(void)us_pophighlight(0);
		}
	}
	return(0);
}

/****************************** PRINT OPTIONS DIALOG ******************************/

/* Printing Options */
DIALOGITEM us_printingoptdialogitems[] =
{
 /*  1 */ {0, {44,400,68,458}, BUTTON, N_("OK")},
 /*  2 */ {0, {8,400,32,458}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,8,48,204}, RADIO, N_("Plot only Highlighted Area")},
 /*  4 */ {0, {8,8,24,142}, RADIO, N_("Plot Entire Facet")},
 /*  5 */ {0, {88,104,104,220}, CHECK, N_("Encapsulated")},
 /*  6 */ {0, {8,228,24,383}, CHECK, N_("Plot Date In Corner")},
 /*  7 */ {0, {288,108,304,166}, RADIO, N_("HPGL")},
 /*  8 */ {0, {288,180,304,254}, RADIO, N_("HPGL/2")},
 /*  9 */ {0, {312,20,328,187}, RADIO, N_("HPGL/2 plot fills page")},
 /* 10 */ {0, {336,20,352,177}, RADIO, N_("HPGL/2 plot fixed at:")},
 /* 11 */ {0, {336,180,352,240}, EDITTEXT, ""},
 /* 12 */ {0, {336,244,352,406}, MESSAGE, N_("internal units per pixel")},
 /* 13 */ {0, {240,20,256,172}, CHECK, N_("Synchronize to file:")},
 /* 14 */ {0, {240,172,272,464}, MESSAGE, ""},
 /* 15 */ {0, {216,20,232,108}, MESSAGE, N_("EPS Scale:")},
 /* 16 */ {0, {216,124,232,164}, EDITTEXT, "2"},
 /* 17 */ {0, {192,8,208,80}, MESSAGE, N_("For facet:")},
 /* 18 */ {0, {192,80,208,464}, MESSAGE, ""},
 /* 19 */ {0, {280,8,281,464}, DIVIDELINE, ""},
 /* 20 */ {0, {88,8,104,96}, MESSAGE, N_("PostScript:")},
 /* 21 */ {0, {88,312,104,464}, POPUP, ""},
 /* 22 */ {0, {80,8,81,464}, DIVIDELINE, ""},
 /* 23 */ {0, {288,8,304,98}, MESSAGE, N_("HPGL Level:")},
 /* 24 */ {0, {112,20,128,78}, RADIO, N_("Printer")},
 /* 25 */ {0, {136,20,152,78}, RADIO, N_("Plotter")},
 /* 26 */ {0, {116,88,132,168}, MESSAGE, N_("Width (in):")},
 /* 27 */ {0, {116,172,132,212}, EDITTEXT, "2"},
 /* 28 */ {0, {140,88,156,168}, MESSAGE, N_("Width (in):")},
 /* 29 */ {0, {140,172,156,212}, EDITTEXT, "2"},
 /* 30 */ {0, {116,224,132,304}, MESSAGE, N_("Height (in):")},
 /* 31 */ {0, {116,308,132,348}, EDITTEXT, "2"},
 /* 32 */ {0, {164,20,180,240}, CHECK, N_("Rotate plot 90 degrees")},
 /* 33 */ {0, {164,244,180,324}, MESSAGE, N_("Margin (in):")},
 /* 34 */ {0, {164,328,180,368}, EDITTEXT, "2"},
 /* 35 */ {0, {88,228,104,304}, CHECK, N_("Flat")},
 /* 36 */ {0, {56,8,72,204}, RADIO, N_("Plot only Displayed Window")},
 /* 37 */ {0, {32,228,48,384}, MESSAGE, N_("Default printer:")},
 /* 38 */ {0, {56,228,72,384}, POPUP, ""}
};
DIALOG us_printingoptdialog = {{50,75,411,548}, N_("Printing Options"), 0, 38, us_printingoptdialogitems};

/*
 * special case for the "print options" dialog
 * plot entire facet       = 4 (radio)
 * focus on highlighted    = 3 (radio)
 * encapsulated postscript = 5 (check)
 * date in corner          = 6 (check)
 * HPGL                    = 7 (radio)
 * HPGL/2                  = 8 (radio)
 * HPGL/2 plot fills page  = 9 (radio)
 * HPGL/2 plot fixed at    = 10 (radio)
 * HPGL/2 plot scale       = 11 (edit text)
 * synchronize to file     = 13 (check)
 * EPS scale label         = 15 (message)
 * EPS scale               = 16 (edit text)
 * Facet                   = 18 (message)
 * Divider                 = 19 (message)
 * PostScript style        = 21 (popup)
 * Divider                 = 22 (message)
 * Printer                 = 24 (radio)
 * Plotter                 = 25 (radio)
 * Printer width           = 27 (edit text)
 * Plotter width           = 29 (edit text)
 * Printer height          = 31 (edit text)
 * Rotate output           = 32 (check)
 * Print margin            = 34 (edit text)
 * Flat PostScript         = 35 (check)
 * plot displayed window   = 36 (radio)
 * printer list label      = 37 (stat text)
 * printer list            = 38 (popup)
 */
INTSML us_plotoptionsdlog(void)
{
	INTSML oldplease;
	REGISTER INTBIG itemHit, scale, i, *curstate, wid, hei, margin, printercount, epsscale;
	INTBIG oldstate[NUMIOSTATEBITWORDS];
	REGISTER VARIABLE *var;
	REGISTER NODEPROTO *np;
	REGISTER char *pt;
	char buf[50], *subparams[3], *newlang[3], **printerlist, *defprinter;
	extern COMCOMP us_colorwritep;
	static char *postscripttype[3] = {N_("Black&White"), N_("Color"), N_("Color Stippled")};

	curstate = io_getstatebits();
	for(i=0; i<NUMIOSTATEBITWORDS; i++) oldstate[i] = curstate[i];

	/* display the print options dialog box */
	if (DiaInitDialog(&us_printingoptdialog) != 0) return(0);
	for(i=0; i<3; i++) newlang[i] = _(postscripttype[i]);   DiaSetPopup(21, 3, newlang);

	/* show printers and default */
	printerlist = eprinterlist();
	for(printercount=0; printerlist[printercount] != 0; printercount++) ;
	if (printercount == 0)
	{
		newlang[0] = _("<<Cannot set>>");
		DiaSetPopup(38, 1, newlang);
	} else
	{
		DiaSetPopup(38, printercount, printerlist);
		defprinter = 0;
		var = getval((INTBIG)io_aid, VAID, VSTRING, "IO_default_printer");
		if (var != NOVARIABLE) defprinter = (char *)var->addr; else
		{
			char *printer = egetenv("PRINTER");
			if (printer != 0 && *printer != 0) defprinter = printer;
		}
		if (defprinter != 0)
		{
			for(i=0; i<printercount; i++)
				if (namesame(defprinter, printerlist[i]) == 0) break;
			if (i < printercount) DiaSetPopupEntry(38, i);
		}
	}

	/* show state */
	if ((curstate[0]&PSCOLOR) == 0) DiaSetPopupEntry(21, 0); else
	{
		if ((curstate[0]&PSCOLORSTIP) != 0) DiaSetPopupEntry(21, 2); else
			DiaSetPopupEntry(21, 1);
	}
	if ((curstate[0]&PSHIERARCHICAL) == 0) DiaSetControl(35, 1);
	if ((curstate[0]&PLOTDATES) != 0) DiaSetControl(6, 1);
	if ((curstate[0]&PLOTFOCUS) == 0) DiaSetControl(4, 1); else
	{
		if ((curstate[0]&PLOTFOCUSDPY) != 0) DiaSetControl(36, 1); else
			DiaSetControl(3, 1);
	}		
	if ((curstate[0]&EPSPSCRIPT) != 0) DiaSetControl(5, 1);
	if ((curstate[0]&PSROTATE) != 0) DiaSetControl(32, 1);
	if ((curstate[0]&PSPLOTTER) != 0)
	{
		DiaSetControl(25, 1);
		DiaDimItem(26);
		DiaDimItem(27);
		DiaDimItem(30);
		DiaDimItem(31);
	} else
	{
		DiaSetControl(24, 1);
		DiaDimItem(28);
		DiaDimItem(29);
	}

	/* show PostScript page sizes */
	var = getval((INTBIG)io_aid, VAID, VFRACT, "IO_postscript_width");
	if (var == NOVARIABLE) wid = muldiv(DEFAULTPSWIDTH, WHOLE, 75); else
		wid = var->addr;
	DiaSetText(27, frtoa(wid));
	DiaSetText(29, frtoa(wid));
	var = getval((INTBIG)io_aid, VAID, VFRACT, "IO_postscript_height");
	if (var == NOVARIABLE) hei = muldiv(DEFAULTPSHEIGHT, WHOLE, 75); else
		hei = var->addr;
	DiaSetText(31, frtoa(hei));
	var = getval((INTBIG)io_aid, VAID, VFRACT, "IO_postscript_margin");
	if (var == NOVARIABLE) margin = muldiv(DEFAULTPSMARGIN, WHOLE, 75); else
		margin = var->addr;
	DiaSetText(34, frtoa(margin));

	np = el_curlib->curnodeproto;
	DiaDimItem(15);
	DiaDimItem(16);
	epsscale= 1;
	if (np == NONODEPROTO)
	{
		DiaDimItem(13);
		DiaDimItem(17);
	} else
	{
		DiaSetText(18, describenodeproto(np));
		DiaUnDimItem(17);
		if ((curstate[0]&EPSPSCRIPT) != 0)
		{
			DiaUnDimItem(15);
			DiaUnDimItem(16);
			var = getvalkey((INTBIG)np, VNODEPROTO, VFRACT, io_postscriptepsscale);
			if (var != NOVARIABLE)
			{
				epsscale = var->addr;
				DiaSetText(16, frtoa(epsscale));
			}
		}
		DiaUnDimItem(13);
		var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, io_postscriptfilename);
		if (var != NOVARIABLE)
		{
			DiaSetControl(13, 1);
			DiaSetText(14, (char *)var->addr);
		}
	}
	if ((curstate[0]&HPGL2) != 0)
	{
		DiaSetControl(8, 1);
		DiaUnDimItem(9);   DiaUnDimItem(10);   DiaUnDimItem(12);
		DiaEditControl(11);
		var = getval((INTBIG)io_aid, VAID, VINTEGER, "IO_hpgl2_scale");
		if (var == NOVARIABLE)
		{
			DiaSetControl(9, 1);
			DiaSetText(11, "20");
		} else
		{
			DiaSetControl(10, 1);
			(void)sprintf(buf, "%ld", var->addr);
			DiaSetText(11, buf);
		}
	} else
	{
		DiaSetControl(7, 1);
		DiaSetControl(9, 1);
		DiaSetText(11, "20");
		DiaDimItem(9);   DiaDimItem(10);   DiaDimItem(12);
		DiaNoEditControl(11);
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 5 || itemHit == 6 || itemHit == 13 || itemHit == 32 || itemHit == 35)
		{
			i = 1 - DiaGetControl(itemHit);
			DiaSetControl(itemHit, i);
			if (itemHit == 5)
			{
				if (i == 0)
				{
					DiaDimItem(15);
					DiaDimItem(16);
				} else
				{
					DiaUnDimItem(15);
					DiaUnDimItem(16);
				}
			}
			if (itemHit == 13)
			{
				if (i != 0)
				{
					/* select a file name to synchronize with this facet */
					oldplease = el_pleasestop;
					(void)initinfstr();
					(void)addstringtoinfstr("ps/");
					(void)addstringtoinfstr(_("PostScript File: "));
					i = ttygetparam(returninfstr(), &us_colorwritep, 1, subparams);
					el_pleasestop = oldplease;
					if (i != 0 && subparams[0][0] != 0)
					{
						DiaUnDimItem(14);
						DiaSetText(14, subparams[0]);
					} else
					{
						DiaSetControl(13, 0);
					}
				} else
				{
					DiaDimItem(14);
				}
			}
			continue;
		}
		if (itemHit == 3 || itemHit == 4 || itemHit == 36)
		{
			DiaSetControl(3, 0);
			DiaSetControl(4, 0);
			DiaSetControl(36, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 7)
		{
			DiaSetControl(7, 1);   DiaSetControl(8, 0);
			DiaDimItem(9);   DiaDimItem(10);   DiaDimItem(12);
			DiaNoEditControl(11);
			continue;
		}
		if (itemHit == 8)
		{
			DiaSetControl(7, 0);   DiaSetControl(8, 1);
			DiaUnDimItem(9);   DiaUnDimItem(10);   DiaUnDimItem(12);
			DiaEditControl(11);
			continue;
		}
		if (itemHit == 9 || itemHit == 10)
		{
			DiaSetControl(9, 0);
			DiaSetControl(10, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 24 || itemHit == 25)
		{
			DiaSetControl(24, 0);
			DiaSetControl(25, 0);
			DiaSetControl(itemHit, 1);
			if (itemHit == 25)
			{
				DiaUnDimItem(28);
				DiaUnDimItem(29);
				DiaDimItem(26);
				DiaDimItem(27);
				DiaDimItem(30);
				DiaDimItem(31);
			} else
			{
				DiaUnDimItem(26);
				DiaUnDimItem(27);
				DiaUnDimItem(30);
				DiaUnDimItem(31);
				DiaDimItem(28);
				DiaDimItem(29);
			}
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		i = DiaGetPopupEntry(38);
		var = getval((INTBIG)io_aid, VAID, VSTRING, "IO_default_printer");
		if (i < printercount)
		{
			if (var == NOVARIABLE || strcmp(printerlist[i], (char *)var->addr) != 0)
				(void)setval((INTBIG)io_aid, VAID, "IO_default_printer",
					(INTBIG)printerlist[i], VSTRING);
		}

		if (DiaGetControl(3) != 0) curstate[0] = (curstate[0] & ~PLOTFOCUSDPY) | PLOTFOCUS; else
		{
			if (DiaGetControl(4) != 0) curstate[0] &= ~(PLOTFOCUS|PLOTFOCUSDPY); else
				curstate[0] |= PLOTFOCUSDPY | PLOTFOCUS;
		}
		if (DiaGetControl(5) != 0) curstate[0] |= EPSPSCRIPT; else curstate[0] &= ~EPSPSCRIPT;
		if (DiaGetControl(32) != 0) curstate[0] |= PSROTATE; else curstate[0] &= ~PSROTATE;
		if (DiaGetControl(6) != 0) curstate[0] |= PLOTDATES; else curstate[0] &= ~PLOTDATES;
		if (DiaGetControl(8) != 0) curstate[0] |= HPGL2; else curstate[0] &= ~HPGL2;
		if (DiaGetControl(35) == 0) curstate[0] |= PSHIERARCHICAL; else curstate[0] &= ~PSHIERARCHICAL;
		switch (DiaGetPopupEntry(21))
		{
			case 0: curstate[0] &= ~PSCOLOR;                                break;
			case 1: curstate[0] = (curstate[0] & ~PSCOLORSTIP) | PSCOLOR;   break;
			case 2: curstate[0] |= PSCOLOR | PSCOLORSTIP;                   break;
		}
		for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != oldstate[i]) break;
		if (i < NUMIOSTATEBITWORDS) io_setstatebits(curstate);

		/* set PostScript page sizes */
		if (DiaGetControl(24) != 0)
		{
			/* printed */
			curstate[0] &= ~PSPLOTTER;
			i = atofr(DiaGetText(27));
			if (i != wid)
				(void)setval((INTBIG)io_aid, VAID, "IO_postscript_width", i, VFRACT);
			i = atofr(DiaGetText(31));
			if (i != hei)
				(void)setval((INTBIG)io_aid, VAID, "IO_postscript_height", i, VFRACT);
		} else
		{
			curstate[0] |= PSPLOTTER;
			i = atofr(DiaGetText(29));
			if (i != wid)
				(void)setval((INTBIG)io_aid, VAID, "IO_postscript_width", i, VFRACT);
		}
		i = atofr(DiaGetText(34));
		if (i != margin)
			(void)setval((INTBIG)io_aid, VAID, "IO_postscript_margin", i, VFRACT);

		if (np != NONODEPROTO)
		{
			var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, io_postscriptfilename);
			if (DiaGetControl(13) != 0)
			{
				/* add a synchronization file */
				pt = DiaGetText(14);
				if (var == NOVARIABLE || strcmp(pt, (char *)var->addr) != 0)
					(void)setvalkey((INTBIG)np, VNODEPROTO, io_postscriptfilename,
						(INTBIG)pt, VSTRING);
			} else
			{
				/* remove a synchronization file */
				if (var != NOVARIABLE)
					delvalkey((INTBIG)np, VNODEPROTO, io_postscriptfilename);
			}
			if (DiaGetControl(5) != 0)
			{
				i = atofr(DiaGetText(16));
				if (i != epsscale)
					(void)setvalkey((INTBIG)np, VNODEPROTO, io_postscriptepsscale,
						i, VFRACT);
			}
		}
		if ((curstate[0]&HPGL2) != 0)
		{
			var = getval((INTBIG)io_aid, VAID, VINTEGER, "IO_hpgl2_scale");
			if (DiaGetControl(9) != 0)
			{
				if (var != NOVARIABLE)
					(void)delval((INTBIG)io_aid, VAID, "IO_hpgl2_scale");
			} else
			{
				scale = myatoi(DiaGetText(11));
				if (scale <= 0) scale = 1;
				if (var == NOVARIABLE || scale != var->addr)
					(void)setval((INTBIG)io_aid, VAID, "IO_hpgl2_scale", scale, VINTEGER);
			}
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** PURE LAYER NODE DIALOG ******************************/

/* Edit: Pure Layer Node */
DIALOGITEM us_purelayerdialogitems[] =
{
 /*  1 */ {0, {204,116,228,196}, BUTTON, N_("OK")},
 /*  2 */ {0, {204,12,228,92}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {28,8,196,200}, SCROLL, ""},
 /*  4 */ {0, {4,12,20,100}, MESSAGE, N_("Technology:")},
 /*  5 */ {0, {4,100,20,200}, MESSAGE, ""}
};
DIALOG us_purelayerdialog = {{75,75,312,284}, N_("Make Pure Layer Node"), 0, 5, us_purelayerdialogitems};

/*
 * special case for the "pure layer node" dialog
 * list of nodes          = 3 (scroll)
 * technology             = 5 (message)
 */
INTSML us_purelayernodedlog(char *paramstart[])
{
	REGISTER INTBIG itemHit, fun;
	REGISTER INTSML ret;
	REGISTER NODEPROTO *np;

	if (us_needfacet() == NONODEPROTO) return(0);

	/* see if there are any pure layer nodes */
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
	{
		fun = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun == NPNODE) break;
	}
	if (np == NONODEPROTO)
	{
		ttyputerr(_("This technology has no pure-layer nodes"));
		return(0);
	}

	/* display the dialog box */
	if (DiaInitDialog(&us_purelayerdialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCDOUBLEQUIT);
	for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
	{
		fun = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
		if (fun != NPNODE) continue;
		DiaStuffLine(3, np->primname);
	}
	DiaSelectLine(3, 0);
	DiaSetText(5, el_curtech->techname);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
	}
	ret = 0;
	if (itemHit == OK)
	{
		ret = 1;
		(void)initinfstr();
		(void)addstringtoinfstr(DiaGetScrollLine(3, DiaGetCurLine(3)));
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(ret);
}

/****************************** QUICK KEY OPTIONS DIALOG ******************************/

/* Quick Keys */
DIALOGITEM us_quickkeydialogitems[] =
{
 /*  1 */ {0, {520,320,544,384}, BUTTON, N_("OK")},
 /*  2 */ {0, {520,12,544,76}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {24,4,168,168}, SCROLL, ""},
 /*  4 */ {0, {192,20,336,184}, SCROLL, ""},
 /*  5 */ {0, {4,4,20,68}, MESSAGE, N_("Menu:")},
 /*  6 */ {0, {172,20,188,136}, MESSAGE, N_("SubMenu/Item:")},
 /*  7 */ {0, {360,36,504,200}, SCROLL, ""},
 /*  8 */ {0, {340,36,356,140}, MESSAGE, N_("SubItem:")},
 /*  9 */ {0, {24,228,504,392}, SCROLL, ""},
 /* 10 */ {0, {4,228,20,328}, MESSAGE, N_("Quick Key:")},
 /* 11 */ {0, {256,192,280,220}, BUTTON, ">>"},
 /* 12 */ {0, {520,236,544,296}, BUTTON, N_("Remove")},
 /* 13 */ {0, {520,96,544,216}, BUTTON, N_("Factory Settings")}
};
DIALOG us_quickkeydialog = {{75,75,634,478}, N_("Quick Key Options"), 0, 13, us_quickkeydialogitems};

void us_setlastquickkeys(void);
void us_setmiddlequickkeys(void);
void us_loadquickkeys(POPUPMENU *pm);
char *us_makequickkey(INTBIG i);

/*
 * special case for the "Quick Keys" dialog
 * menu list          = 3 (scroll)
 * submenu/item list  = 4 (scroll)
 * subitem list       = 7 (scroll)
 * quick key list     = 9 (scroll)
 * ">>"               = 11 (button)
 * "<<"               = 12 (button)
 * "Factory settings" = 13 (button)
 */
#define MAXQUICKKEYS 50
unsigned char  us_quickkeyskey[MAXQUICKKEYS];
POPUPMENU     *us_quickkeysmenu[MAXQUICKKEYS];
INTBIG         us_quickkeysindex[MAXQUICKKEYS];
INTBIG         us_quickkeyscount;

INTSML us_quickkeydlog(void)
{
	INTBIG itemHit, i, j, k, which, whichmiddle, whichbottom, keychanged;
	char **quickkeylist;
	INTBIG quickkeycount;
	REGISTER char *pt, *menuname, *menucommand;
	REGISTER POPUPMENU *pm;
	REGISTER POPUPMENUITEM *mi;
	REGISTER USERCOM *uc;

	/* display the window view dialog box */
	if (DiaInitDialog(&us_quickkeydialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	DiaInitTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	DiaInitTextDialog(7, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	DiaInitTextDialog(9, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);

	/* make a list of quick keys */
	us_buildquickkeylist();
	for(i=0; i<us_quickkeyscount; i++)
		DiaStuffLine(9, us_makequickkey(i));
	DiaSelectLine(9, 0);

	/* load the list of menus */
	for(i=0; i<us_pulldownmenucount; i++)
		DiaStuffLine(3, us_removeampersand(us_pulldowns[i]->header));
	DiaSelectLine(3, 0);
	us_setmiddlequickkeys();

	/* loop until done */
	keychanged = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 3)
		{
			/* click in the top list (the pulldown menus) */
			us_setmiddlequickkeys();
			continue;
		}
		if (itemHit == 4)
		{
			/* click in the middle list (the submenus/items) */
			us_setlastquickkeys();
			continue;
		}
		if (itemHit == 7)
		{
			/* click in the lower list (the subitems) */
			which = DiaGetCurLine(3);
			whichmiddle = DiaGetCurLine(4);
			whichbottom = DiaGetCurLine(7);
			pm = us_pulldowns[which];
			mi = &pm->list[whichmiddle];
			uc = mi->response;
			pm = uc->menu;
			if (pm == NOPOPUPMENU) continue;
			for(j=0; j<us_quickkeyscount; j++)
				if (pm == us_quickkeysmenu[j] && whichbottom == us_quickkeysindex[j]) break;
			if (j < us_quickkeyscount) DiaSelectLine(9, j);
			continue;
		}
		if (itemHit == 11)
		{
			/* click in the ">>" button (add command to quick keys) */
			which = DiaGetCurLine(3);
			whichmiddle = DiaGetCurLine(4);
			whichbottom = DiaGetCurLine(7);
			pm = us_pulldowns[which];
			mi = &pm->list[whichmiddle];
			uc = mi->response;
			if (uc->menu != NOPOPUPMENU)
			{
				pm = uc->menu;
				whichmiddle = whichbottom;
			}
			which = DiaGetCurLine(9);
			us_quickkeysmenu[which] = pm;
			us_quickkeysindex[which] = whichmiddle;
			DiaSetScrollLine(9, which, us_makequickkey(which));
			keychanged++;
			continue;
		}
		if (itemHit == 12)
		{
			/* click in the "<<" button (remove command from quick key) */
			which = DiaGetCurLine(9);
			us_quickkeysmenu[which] = NOPOPUPMENU;
			DiaSetScrollLine(9, which, us_makequickkey(which));
			keychanged++;
			continue;
		}
		if (itemHit == 13)
		{
			/* click in the "Factory Settings" button */
			for(i=0; i<us_quickkeyscount; i++)
				us_quickkeysmenu[i] = NOPOPUPMENU;
			for(i=0; i<us_quickkeycount; i++)
			{
				pt = us_quickkeylist[i];
				for(j=0; j<us_quickkeyscount; j++)
					if (us_quickkeyskey[j] == *pt) break;
				if (j >= us_quickkeyscount) continue;
				menuname = &pt[2];
				for(pt = menuname; *pt != 0 && *pt != '/'; pt++) ;
				if (*pt == 0) continue;
				*pt = 0;
				pm = us_getpopupmenu(menuname);
				*pt = '/';
				menucommand = pt + 1;
				for(k=0; k<pm->total; k++)
				{
					mi = &pm->list[k];
					if (namesame(us_removeampersand(mi->attribute), menucommand) == 0) break;
				}
				if (k >= pm->total) continue;
				us_quickkeysmenu[j] = pm;
				us_quickkeysindex[j] = k;
			}
			DiaLoadTextDialog(9, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(i=0; i<us_quickkeyscount; i++)
				DiaStuffLine(9, us_makequickkey(i));
			DiaSelectLine(9, 0);
			keychanged++;
			continue;
		}
	}

	DiaDoneDialog();
	if (itemHit == OK && keychanged != 0)
	{
		us_getquickkeylist(&quickkeycount, &quickkeylist);
		(void)setvalkey((INTBIG)us_aid, VAID, us_quickkeys, (INTBIG)quickkeylist,
			VSTRING|VISARRAY|(quickkeycount<<VLENGTHSH));
		for(i=0; i<quickkeycount; i++)
			efree((char *)quickkeylist[i]);
		efree((char *)quickkeylist);
	}
	return(0);
}

/*
 * Helper routine for "us_quickkeydlog" to construct the string describing key "i".
 */
char *us_makequickkey(INTBIG i)
{
	REGISTER POPUPMENUITEM *mi;
	char line[10];

	(void)initinfstr();
	if (us_quickkeyskey[i] >= FUNCTIONF1 && us_quickkeyskey[i] <= FUNCTIONF12)
	{
		sprintf(line, "F%ld", us_quickkeyskey[i] - FUNCTIONF1 + 1);
		(void)addstringtoinfstr(line);
	} else
	{
		(void)addtoinfstr(us_quickkeyskey[i]);
	}
	if (us_quickkeysmenu[i] != NOPOPUPMENU)
	{
		mi = &us_quickkeysmenu[i]->list[us_quickkeysindex[i]];
		(void)addstringtoinfstr("   ");
		(void)addstringtoinfstr(us_removeampersand(mi->attribute));
	}
	return(returninfstr());
}

/*
 * Routine to scan all pulldown menus and build an internal list of quick keys.
 */
void us_buildquickkeylist(void)
{
	REGISTER INTBIG i;

	us_quickkeyscount = 0;
	for(i=0; i<26; i++)
		us_quickkeyskey[us_quickkeyscount++] = (char)('A' + i);
	for(i=0; i<10; i++)
		us_quickkeyskey[us_quickkeyscount++] = (char)('0' + i);
	for(i=0; i<12; i++)
		us_quickkeyskey[us_quickkeyscount++] = (char)(FUNCTIONF1 + i);
	for(i=0; i<us_quickkeyscount; i++) us_quickkeysmenu[i] = NOPOPUPMENU;
	for(i=0; i<us_pulldownmenucount; i++)
		us_loadquickkeys(us_pulldowns[i]);
}

/*
 * Routine to convert the internal list of quick keys to an array of bindings
 * in "quickkeylist" (that is "quickkeycount" long).
 */
void us_getquickkeylist(INTBIG *quickkeycount, char ***quickkeylist)
{
	REGISTER INTBIG count, i;
	REGISTER char **keylist;
	REGISTER POPUPMENUITEM *mi;

	count = 0;
	for(i=0; i<us_quickkeyscount; i++)
		if (us_quickkeysmenu[i] != NOPOPUPMENU) count++;
	keylist = (char **)emalloc(count * (sizeof (char *)), us_aid->cluster);
	if (keylist == 0)
	{
		*quickkeycount = 0;
		return;
	}
	count = 0;
	for(i=0; i<us_quickkeyscount; i++)
	{
		if (us_quickkeysmenu[i] == NOPOPUPMENU) continue;
		(void)initinfstr();
		(void)addtoinfstr(us_quickkeyskey[i]);
		(void)addtoinfstr('/');
		(void)addstringtoinfstr(us_quickkeysmenu[i]->name);
		(void)addtoinfstr('/');
		mi = &us_quickkeysmenu[i]->list[us_quickkeysindex[i]];
		(void)addstringtoinfstr(us_removeampersand(mi->attribute));
		(void)allocstring(&keylist[count], returninfstr(), us_aid->cluster);
		count++;
	}
	*quickkeycount = count;
	*quickkeylist = keylist;
}

/*
 * Helper routine for "us_quickkeydlog" to recursively examine menu "pm" and
 * load the quick keys tables.
 */
void us_loadquickkeys(POPUPMENU *pm)
{
	REGISTER INTBIG j, i, key;
	REGISTER POPUPMENUITEM *mi;
	REGISTER USERCOM *uc;
	REGISTER char *pt;

	for(i=0; i<pm->total; i++)
	{
		mi = &pm->list[i];
		uc = mi->response;
		if (uc->menu != NOPOPUPMENU)
		{
			us_loadquickkeys(uc->menu);
			continue;
		}
		if (uc->active < 0 && *mi->attribute == 0) continue;
		
		for(pt = mi->attribute; *pt != 0; pt++)
			if (*pt == '/') break;
		if (*pt == 0) continue;
		key = pt[1] & 0xFF;
		for(j=0; j<us_quickkeyscount; j++)
		{
			if (us_quickkeyskey[j] != key) continue;
			us_quickkeysmenu[j] = pm;
			us_quickkeysindex[j] = i;
		}
	}
}

/*
 * Helper routine for "us_quickkeydlog" to load the middle table (the
 * submenu/items) when the selected top table has changed.
 */
void us_setmiddlequickkeys(void)
{
	REGISTER INTBIG which, i;
	REGISTER POPUPMENU *pm;
	REGISTER POPUPMENUITEM *mi;
	REGISTER USERCOM *uc;

	DiaLoadTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
	which = DiaGetCurLine(3);
	pm = us_pulldowns[which];
	for(i=0; i<pm->total; i++)
	{
		mi = &pm->list[i];
		uc = mi->response;
		if (uc->active < 0 && *mi->attribute == 0)
		{
			DiaStuffLine(4, "---");
			continue;
		}
		DiaStuffLine(4, us_removeampersand(mi->attribute));
	}
	DiaSelectLine(4, 0);
	us_setlastquickkeys();
}

/*
 * Helper routine for "us_quickkeydlog" to load the bottom table (the
 * subitems) when the selected middle table has changed.
 */
void us_setlastquickkeys(void)
{
	REGISTER INTBIG which, whichmiddle, i, j;
	REGISTER POPUPMENU *pm;
	REGISTER POPUPMENUITEM *mi;
	REGISTER USERCOM *uc;

	DiaLoadTextDialog(7, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
	which = DiaGetCurLine(3);
	whichmiddle = DiaGetCurLine(4);
	pm = us_pulldowns[which];
	mi = &pm->list[whichmiddle];
	uc = mi->response;
	if (uc->menu != NOPOPUPMENU)
	{
		pm = uc->menu;
		for(i=0; i<pm->total; i++)
		{
			mi = &pm->list[i];
			uc = mi->response;
			if (uc->active < 0 && *mi->attribute == 0)
			{
				DiaStuffLine(7, "---");
				continue;
			}
			DiaStuffLine(7, us_removeampersand(mi->attribute));
		}
		DiaSelectLine(7, 0);
		mi = &pm->list[0];
		whichmiddle = 0;
	}

	for(j=0; j<us_quickkeyscount; j++)
		if (pm == us_quickkeysmenu[j] && whichmiddle == us_quickkeysindex[j]) break;
	if (j < us_quickkeyscount) DiaSelectLine(9, j);
}

/****************************** QUIT DIALOG ******************************/

/* Quit */
DIALOGITEM us_quitdialogitems[] =
{
 /*  1 */ {0, {101,16,125,80}, BUTTON, N_("Yes")},
 /*  2 */ {0, {136,136,160,192}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {136,16,160,80}, BUTTON, N_("No")},
 /*  4 */ {0, {8,16,90,208}, MESSAGE, ""}
};
DIALOG us_quitdialog = {{50,75,224,315}, 0, 0, 4, us_quitdialogitems};

/*
 * special case for the "quit" command
 * Message = 4 (message)
 * Yes     = 1 (button)
 * Cancel  = 2 (button)
 * No      = 3 (button)
 */
INTSML us_quitdlog(char *prompt, char *paramstart[])
{
	INTBIG itemHit, i, len;
	INTSML oldplease;

	/* display the quit dialog box */
	if (DiaInitDialog(&us_quitdialog) != 0) return(0);

	/* load the message */
	len = strlen(prompt);
	for(i=0; i<len; i++) if (strncmp(&prompt[i], _(" has changed.  "), 15) == 0) break;
	if (i >= len) DiaSetText(4, prompt); else
	{
		(void)initinfstr();
		prompt[i+15] = 0;
		(void)addstringtoinfstr(prompt);
		(void)addstringtoinfstr(_("Save?"));
		DiaSetText(4, returninfstr());
	}

	/* loop until done */
	oldplease = el_pleasestop;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == 1 || itemHit == 2 || itemHit == 3) break;
	}
	el_pleasestop = oldplease;

	switch (itemHit)
	{
		case 2:  paramstart[0] = "no";     break;
		case 3:  paramstart[0] = "yes";    break;
		default: paramstart[0] = "save";   break;
	}
	DiaDoneDialog();
	return(1);
}

/****************************** RENAME DIALOG ******************************/

/* Rename */
DIALOGITEM us_rendialogitems[] =
{
 /*  1 */ {0, {216,208,240,288}, BUTTON, N_("OK")},
 /*  2 */ {0, {216,44,240,124}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,132,168,336}, SCROLL, ""},
 /*  4 */ {0, {184,8,200,88}, MESSAGE, N_("New name:")},
 /*  5 */ {0, {184,96,200,336}, EDITTEXT, ""},
 /*  6 */ {0, {80,8,96,124}, RADIO, N_("Library")},
 /*  7 */ {0, {152,8,168,124}, RADIO, N_("Technology")},
 /*  8 */ {0, {104,8,120,124}, RADIO, N_("Primitive Node")},
 /*  9 */ {0, {128,8,144,124}, RADIO, N_("Arc")},
 /* 10 */ {0, {32,8,48,124}, RADIO, N_("Export")},
 /* 11 */ {0, {8,8,24,124}, RADIO, N_("Cell")},
 /* 12 */ {0, {56,8,72,124}, RADIO, N_("Network")}
};
DIALOG us_rendialog = {{75,75,324,420}, N_("Rename Object"), 0, 12, us_rendialogitems};

static LIBRARY *us_renamelib;
static TECHNOLOGY *us_renametech;
static NODEPROTO *us_renameprim;
static ARCPROTO *us_renamearc;
static PORTPROTO *us_renamediaport;
static CELL *us_renamecell;
static NETWORK *us_renamenet;

INTSML us_initrenamelist(char **c);
char *us_renamelistitem(void);

/*
 * special case for the "rename" dialog
 * list of old names = 3 (scroll)
 * new name          = 5 (edit text)
 * library           = 6 (radio)
 * technology        = 7 (radio)
 * prim node         = 8 (radio)
 * arc               = 9 (radio)
 * port              = 10 (radio)
 * cell              = 11 (radio)
 * network           = 12 (radio)
 */
INTSML us_renamedlog(void)
{
	REGISTER INTBIG itemHit, i;
	REGISTER NODEPROTO *np;
	char *par[3];

	/* display the node size dialog box */
	if (DiaInitDialog(&us_rendialog) != 0) return(0);
	np = getcurfacet();
	if (np == NONODEPROTO)
	{
		DiaDimItem(10);
		DiaDimItem(12);
	}
	if (el_curlib->firstcell != NOCELL) DiaSetControl(11, 1); else
		DiaSetControl(6, 1);
	DiaInitTextDialog(3, us_initrenamelist, us_renamelistitem, DiaNullDlogDone, 0,
		SCSELMOUSE);
	if (DiaGetControl(11) != 0)
		(void)us_setscrolltocurrentfacet(3, 1, 0, 1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK)
		{
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			if (DiaValidEntry(5) == 0) continue;
			break;
		}
		if (itemHit >= 6 && itemHit <= 12)
		{
			for(i=6; i<=12; i++) DiaSetControl(i, 0);
			DiaSetControl(itemHit, 1);
			DiaLoadTextDialog(3, us_initrenamelist, us_renamelistitem, DiaNullDlogDone, 0);
			if (DiaGetControl(11) != 0)
				(void)us_setscrolltocurrentfacet(3, 1, 0, 1);
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		if (DiaGetControl(6) != 0) par[2] = "l"; else
		if (DiaGetControl(7) != 0) par[2] = "t"; else
		if (DiaGetControl(8) != 0) par[2] = "p"; else
		if (DiaGetControl(9) != 0) par[2] = "a"; else
		if (DiaGetControl(10) != 0) par[2] = "r"; else
		if (DiaGetControl(11) != 0) par[2] = "c"; else
		if (DiaGetControl(12) != 0) par[2] = "n";
		i = DiaGetCurLine(3);
		par[0] = DiaGetScrollLine(3, i);
		par[1] = DiaGetText(5);
		us_rename(2, par);
	}
	DiaDoneDialog();
	return(0);
}

INTSML us_initrenamelist(char **c)
{
	REGISTER NODEPROTO *np;

	us_renamelib = el_curlib;
	us_renametech = el_technologies;
	us_renameprim = el_curtech->firstnodeproto;
	us_renamearc = el_curtech->firstarcproto;
	us_renamecell = el_curlib->firstcell;
	np = getcurfacet();
	if (np != NONODEPROTO)
	{
		us_renamediaport = np->firstportproto;
		us_renamenet = np->firstnetwork;
	}
	return(0);
}

char *us_renamelistitem(void)
{
	REGISTER LIBRARY *lib;
	REGISTER TECHNOLOGY *tech;
	REGISTER ARCPROTO *ap;
	REGISTER NODEPROTO *np;
	REGISTER CELL *cell;
	REGISTER NETWORK *net;
	REGISTER PORTPROTO *pp;

	if (DiaGetControl(6) != 0)
	{
		for(;;)
		{
			if (us_renamelib == NOLIBRARY) return(0);
			lib = us_renamelib;
			us_renamelib = us_renamelib->nextlibrary;
			if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
			return(lib->libname);
		}
	}
	if (DiaGetControl(7) != 0)
	{
		if (us_renametech == NOTECHNOLOGY) return(0);
		tech = us_renametech;
		us_renametech = us_renametech->nexttechnology;
		return(tech->techname);
	}
	if (DiaGetControl(8) != 0)
	{
		if (us_renameprim == NONODEPROTO) return(0);
		np = us_renameprim;
		us_renameprim = us_renameprim->nextnodeproto;
		return(np->primname);
	}
	if (DiaGetControl(9) != 0)
	{
		if (us_renamearc == NOARCPROTO) return(0);
		ap = us_renamearc;
		us_renamearc = us_renamearc->nextarcproto;
		return(ap->protoname);
	}
	if (DiaGetControl(10) != 0)
	{
		if (us_renamediaport == NOPORTPROTO) return(0);
		pp = us_renamediaport;
		us_renamediaport = us_renamediaport->nextportproto;
		return(pp->protoname);
	}
	if (DiaGetControl(11) != 0)
	{
		if (us_renamecell == NOCELL) return(0);
		cell = us_renamecell;
		us_renamecell = us_renamecell->nextcell;
		return(cell->cellname);
	}
	if (DiaGetControl(12) != 0)
	{
		for(;;)
		{
			if (us_renamenet == NONETWORK) return(0);
			net = us_renamenet;
			us_renamenet = us_renamenet->nextnetwork;
			if (net->namecount <= 0) continue;
			return(net->netname);
		}
	}
	return(0);
}

/****************************** SELECTION: OPTIONS DIALOG ******************************/

/* Selection Options */
DIALOGITEM us_seloptdialogitems[] =
{
 /*  1 */ {0, {108,172,132,252}, BUTTON, N_("OK")},
 /*  2 */ {0, {108,4,132,84}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,4,24,252}, CHECK, N_("Easy selection of facet instances")},
 /*  4 */ {0, {32,4,48,252}, CHECK, N_("Easy selection of annotation text")},
 /*  5 */ {0, {56,4,72,252}, CHECK, N_("Constrained dragging by default")},
 /*  6 */ {0, {80,4,96,252}, CHECK, N_("Center-based primitives")}
};
DIALOG us_seloptdialog = {{75,75,216,339}, N_("Selection Options"), 0, 6, us_seloptdialogitems};

/*
 * special case for the "selection options" dialog
 * easy selection of instances     = 3 (check)
 * easy selection of annotation    = 4 (check)
 * Constrained dragging by default = 5 (check)
 * Center-based primitives         = 6 (check)
 */
INTSML us_selectoptdlog(void)
{
	REGISTER INTBIG itemHit;
	REGISTER INTBIG options;

	/* display the dialog box */
	if (DiaInitDialog(&us_seloptdialog) != 0) return(0);
	if ((us_useroptions&NOINSTANCESELECT) == 0) DiaSetControl(3, 1);
	if ((us_useroptions&NOTEXTSELECT) == 0) DiaSetControl(4, 1);
	if ((us_useroptions&FLIPINTERACTIVECON) != 0) DiaSetControl(5, 1);
	if ((us_useroptions&CENTEREDPRIMITIVES) != 0) DiaSetControl(6, 1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit >= 3 && itemHit <= 6)
		{
			DiaSetControl(itemHit, 1 - DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		options = us_useroptions;
		if (DiaGetControl(3) != 0) options &= ~NOINSTANCESELECT; else
			options |= NOINSTANCESELECT;
		if (DiaGetControl(4) != 0) options &= ~NOTEXTSELECT; else
			options |= NOTEXTSELECT;
		if (DiaGetControl(5) == 0) options &= ~FLIPINTERACTIVECON; else
			options |= FLIPINTERACTIVECON;
		if (DiaGetControl(6) == 0) options &= ~CENTEREDPRIMITIVES; else
			options |= CENTEREDPRIMITIVES;
		if (options != us_useroptions)
			(void)setvalkey((INTBIG)us_aid, VAID, us_optionflags, options, VINTEGER);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** SELECTION: PORT/NODE/NET DIALOG ******************************/

/* Selection: Port/Net */
DIALOGITEM us_selnamedialogitems[] =
{
 /*  1 */ {0, {192,112,216,192}, BUTTON, N_("Select")},
 /*  2 */ {0, {192,8,216,88}, BUTTON, N_("Done")},
 /*  3 */ {0, {8,8,180,192}, SCROLL, ""}
};
DIALOG us_selnamedialog = {{75,75,300,276}, N_("Select Port"), 0, 3, us_selnamedialogitems};

INTSML     us_selportnodenet;
NETWORK   *us_selnet;
PORTPROTO *us_selport;
NODEINST  *us_selnode;

INTSML us_topofportnet(char **c);
char *us_nextportnet(void);

INTSML us_topofportnet(char **c)
{
	REGISTER NODEPROTO *np;

	np = us_needfacet();
	switch (us_selportnodenet)
	{
		case 0: us_selnet = np->firstnetwork;      break;
		case 1: us_selport = np->firstportproto;   break;
		case 2: us_selnode = np->firstnodeinst;    break;
	}
	return(1);
}

char *us_nextportnet(void)
{
	REGISTER char *retname;
	REGISTER NETWORK *retnet;
	REGISTER NODEINST *retnode;
	REGISTER VARIABLE *var;

	switch (us_selportnodenet)
	{
		case 0:		/* network */
			for(;;)
			{
				if (us_selnet == NONETWORK) return(0);
				retnet = us_selnet;
				us_selnet = us_selnet->nextnetwork;
				if (retnet->namecount != 0) break;
			}
			return(retnet->netname);
		case 1:		/* port */
			if (us_selport == NOPORTPROTO) break;
			retname = us_selport->protoname;
			us_selport = us_selport->nextportproto;
			return(retname);
		case 2:		/* node */
			for(;;)
			{
				if (us_selnode == NONODEINST) return(0);
				retnode = us_selnode;
				us_selnode = us_selnode->nextnodeinst;
				var = getvalkey((INTBIG)retnode, VNODEINST, VSTRING, el_node_name);
				if (var != NOVARIABLE) break;
			}
			return((char *)var->addr);
	}
	return(0);
}

/*
 * special case for the "selection port/net" dialog
 * "selport" is: 0=network, 1=port, 2=node
 * list of ports/nets     = 3 (scroll)
 */
INTSML us_selectportnodenetdlog(INTSML selportnodenet)
{
	REGISTER INTBIG itemHit, which;
	REGISTER NODEPROTO *np;
	REGISTER char *pt;
	char *par[3];

	np = us_needfacet();
	if (np == NONODEPROTO) return(0);

	/* display the dialog box */
	us_selportnodenet = selportnodenet;
	switch (selportnodenet)
	{
		case 0: us_selnamedialog.movable = _("Select Network");   break;
		case 1: us_selnamedialog.movable = _("Select Port");      break;
		case 2: us_selnamedialog.movable = _("Select Node");      break;
	}
	if (DiaInitDialog(&us_selnamedialog) != 0) return(0);
	DiaInitTextDialog(3, us_topofportnet, us_nextportnet, DiaNullDlogDone, 0,
		SCSELMOUSE|SCDOUBLEQUIT);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK)
		{
			which = DiaGetCurLine(3);
			if (which < 0) continue;
			pt = DiaGetScrollLine(3, which);
			switch (selportnodenet)
			{
				case 0:		/* find network */
					par[0] = "highlight";
					par[1] = pt;
					(void)tellaid(net_aid, 2, par);
					break;
				case 1:		/* find port */
					par[0] = "export";
					par[1] = pt;
					us_find(2, par);
					break;
				case 2:		/* find node */
					par[0] = "node";
					par[1] = pt;
					us_find(2, par);
					break;
			}
			us_showallhighlight();
			us_endchanges(NOWINDOWPART);
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** SPREAD DIALOG ******************************/

/* Spread */
DIALOGITEM us_spreaddialogitems[] =
{
 /*  1 */ {0, {96,128,120,200}, BUTTON, N_("OK")},
 /*  2 */ {0, {96,16,120,88}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {55,15,71,205}, EDITTEXT, ""},
 /*  4 */ {0, {20,230,36,380}, RADIO, N_("Spread up")},
 /*  5 */ {0, {45,230,61,380}, RADIO, N_("Spread down")},
 /*  6 */ {0, {70,230,86,380}, RADIO, N_("Spread left")},
 /*  7 */ {0, {95,230,111,380}, RADIO, N_("Spread right")},
 /*  8 */ {0, {25,15,41,180}, MESSAGE, N_("Distance to spread")}
};
DIALOG us_spreaddialog = {{50,75,188,464}, N_("Spread About Highlighted"), 0, 8, us_spreaddialogitems};

/*
 * special case for the "spread" dialog
 * Distance = 3 (edit text)
 * Up       = 4 (radio)
 * Down     = 5 (radio)
 * Left     = 6 (radio)
 * Right    = 7 (radio)
 */
INTSML us_spreaddlog(char *paramstart[])
{
	INTBIG itemHit, defdir;

	/* display the array dialog box */
	if (DiaInitDialog(&us_spreaddialog) != 0) return(0);

	/* "up" is the default direction, distance is 1 */
	DiaSetText(-3, "1");
	defdir = 4;
	DiaSetControl(defdir, 1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(3)) break;
		if (itemHit >= 4 && itemHit <= 7)
		{
			DiaSetControl(defdir, 0);
			defdir = itemHit;
			DiaSetControl(defdir, 1);
		}
	}

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		(void)initinfstr();
		switch (defdir)
		{
			case 4: (void)addstringtoinfstr("up ");      break;
			case 5: (void)addstringtoinfstr("down ");    break;
			case 6: (void)addstringtoinfstr("left ");    break;
			case 7: (void)addstringtoinfstr("right ");   break;
		}
		(void)addstringtoinfstr(DiaGetText(3));
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(1);
}

/****************************** TECHNOLOGY EDIT: CONVERT LIBRARY TO TECHNOLOGY ******************************/

/* Technology Edit: Convert Library */
DIALOGITEM us_tecedlibtotechdialogitems[] =
{
 /*  1 */ {0, {72,220,96,300}, BUTTON, N_("OK")},
 /*  2 */ {0, {72,12,96,92}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {40,80,56,212}, CHECK, N_("Also write C code")},
 /*  4 */ {0, {8,8,24,152}, MESSAGE, N_("New technology name:")},
 /*  5 */ {0, {8,156,24,300}, EDITTEXT, ""}
};
DIALOG us_tecedlibtotechdialog = {{75,75,180,384}, N_("Convert Library to Technology"), 0, 5, us_tecedlibtotechdialogitems};

/*
 * special case for the "convert library to technology" dialog
 * Write C code  = 3 (check)
 * New tech name = 5 (edit text)
 */
INTSML us_libtotechnologydlog(void)
{
	INTBIG itemHit;
	char *par[5];

	/* display the dependent library dialog box */
	if (DiaInitDialog(&us_tecedlibtotechdialog) != 0) return(0);
	DiaSetText(5, el_curlib->libname);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 3)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		par[0] = "edit";
		if (DiaGetControl(3) != 0) par[1] = "library-to-tech-and-C"; else
			par[1] = "library-to-tech";
		par[2] = DiaGetText(5);
		us_technology(3, par);
	}
	DiaDoneDialog();
	return(0);
}

/****************************** TECHNOLOGY EDIT: DEPENDENT LIBRARIES DIALOG ******************************/

/* Dependent Libraries */
DIALOGITEM us_dependentlibdialogitems[] =
{
 /*  1 */ {0, {208,368,232,432}, BUTTON, N_("OK")},
 /*  2 */ {0, {208,256,232,320}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,8,177,174}, SCROLL, ""},
 /*  4 */ {0, {8,8,24,153}, MESSAGE, N_("Dependent Libraries:")},
 /*  5 */ {0, {208,8,224,165}, MESSAGE, N_("Libraries are examined")},
 /*  6 */ {0, {40,192,64,256}, BUTTON, N_("Remove")},
 /*  7 */ {0, {88,192,112,256}, BUTTON, N_("<< Add")},
 /*  8 */ {0, {128,280,144,427}, MESSAGE, N_("Library (if not in list):")},
 /*  9 */ {0, {152,280,168,432}, EDITTEXT, ""},
 /* 10 */ {0, {8,272,24,361}, MESSAGE, N_("All Libraries:")},
 /* 11 */ {0, {224,8,240,123}, MESSAGE, N_("from bottom up")},
 /* 12 */ {0, {32,272,118,438}, SCROLL, ""},
 /* 13 */ {0, {184,8,200,67}, MESSAGE, N_("Current:")},
 /* 14 */ {0, {184,72,200,254}, MESSAGE, ""}
};
DIALOG us_dependentlibdialog = {{50,75,299,524}, N_("Dependent Library Selection"), 0, 14, us_dependentlibdialogitems};

void us_showliblist(char**, INTBIG);

/*
 * special case for the "dependent libraries" dialog
 * Dependent list = 3 (user item)
 * Library list   = 12 (user item)
 * Add lib        = 7 (button)
 * Remove lib     = 6 (button)
 * New name       = 9 (edit text)
 * Current lib    = 14 (message)
 */
INTSML us_dependentlibdlog(void)
{
	INTBIG itemHit, i, j, liblistlen;
	REGISTER VARIABLE *var;
	char **liblist, **newliblist, *pt;

	/* display the dependent library dialog box */
	if (DiaInitDialog(&us_dependentlibdialog) != 0) return(0);
	DiaSetText(14, el_curlib->libname);
	DiaInitTextDialog(12, topoflibs, nextlibs, DiaNullDlogDone, 0, SCSELMOUSE|SCSELKEY);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE|SCSELKEY);
	var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, "EDTEC_dependent_libraries");
	if (var == NOVARIABLE) liblistlen = 0; else
	{
		liblistlen = getlength(var);
		liblist = (char **)emalloc(liblistlen * (sizeof (char *)), el_tempcluster);
		if (liblist == 0) return(0);
		for(i=0; i<liblistlen; i++)
			(void)allocstring(&liblist[i], ((char **)var->addr)[i], el_tempcluster);
	}
	us_showliblist(liblist, liblistlen);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 6)
		{
			/* remove */
			i = DiaGetCurLine(3);
			if (i < 0 || i >= liblistlen) continue;
			efree(liblist[i]);
			for(j=i; j<liblistlen-1; j++) liblist[j] = liblist[j+1];
			liblistlen--;
			if (liblistlen == 0) efree((char *)liblist);
			us_showliblist(liblist, liblistlen);
			continue;
		}
		if (itemHit == 7)
		{
			/* add */
			pt = DiaGetText(9);
			while (*pt == ' ') pt++;
			if (*pt == 0) pt = DiaGetScrollLine(12, DiaGetCurLine(12));
			i = DiaGetCurLine(3);
			if (i < 0) i = 0;

			/* create a new list */
			newliblist = (char **)emalloc((liblistlen+1) * (sizeof (char *)), el_tempcluster);
			if (newliblist == 0) return(0);
			for(j=0; j<liblistlen; j++) newliblist[j] = liblist[j];
			if (liblistlen != 0) efree((char *)liblist);
			liblist = newliblist;

			for(j=liblistlen; j>i; j--) liblist[j] = liblist[j-1];
			liblistlen++;
			(void)allocstring(&liblist[i], pt, el_tempcluster);
			us_showliblist(liblist, liblistlen);
			DiaSetText(9, "");
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		if (liblistlen == 0)
		{
			if (var != NOVARIABLE)
				delval((INTBIG)el_curlib, VLIBRARY, "EDTEC_dependent_libraries");
		} else
		{
			(void)setval((INTBIG)el_curlib, VLIBRARY, "EDTEC_dependent_libraries",
				(INTBIG)liblist, VSTRING|VISARRAY|(liblistlen<<VLENGTHSH));
		}
	}
	for(i=0; i<liblistlen; i++) efree(liblist[i]);
	if (liblistlen != 0) efree((char *)liblist);
	DiaDoneDialog();
	return(0);
}

void us_showliblist(char **liblist, INTBIG liblistlen)
{
	REGISTER INTBIG i;

	DiaLoadTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
	if (liblistlen == 0)
	{
		DiaSelectLine(3, -1);
		return;
	}
	for(i=0; i<liblistlen; i++) DiaStuffLine(3, liblist[i]);
	DiaSelectLine(3, 0);
}

/****************************** TECHNOLOGY EDIT: VARIABLES DIALOG ******************************/

/* Technology Variables */
DIALOGITEM us_techvarsdialogitems[] =
{
 /*  1 */ {0, {208,472,232,536}, BUTTON, N_("OK")},
 /*  2 */ {0, {208,376,232,440}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {24,8,143,264}, SCROLL, ""},
 /*  4 */ {0, {176,16,192,55}, MESSAGE, N_("Type:")},
 /*  5 */ {0, {176,56,192,142}, MESSAGE, ""},
 /*  6 */ {0, {152,104,168,536}, MESSAGE, ""},
 /*  7 */ {0, {24,280,143,536}, SCROLL, ""},
 /*  8 */ {0, {8,16,24,240}, MESSAGE, N_("Current Variables on Technology:")},
 /*  9 */ {0, {8,288,24,419}, MESSAGE, N_("Possible Variables:")},
 /* 10 */ {0, {208,280,232,344}, BUTTON, N_("<< Copy")},
 /* 11 */ {0, {208,24,232,88}, BUTTON, N_("Remove")},
 /* 12 */ {0, {176,216,192,533}, EDITTEXT, ""},
 /* 13 */ {0, {208,136,232,237}, BUTTON, N_("Edit Strings")},
 /* 14 */ {0, {176,168,192,212}, MESSAGE, N_("Value:")},
 /* 15 */ {0, {152,16,168,98}, MESSAGE, N_("Description:")}
};
DIALOG us_techvarsdialog = {{50,75,293,622}, N_("Technology Variables"), 0, 15, us_techvarsdialogitems};

void us_setcurrenttechvar(TECHVAR*);

/*
 * special case for the "technology variables" dialog
 * Type          =  5 (message)
 * Description   =  6 (message)
 * Current vars  =  3 (user)
 * Known vars    =  7 (user)
 * Remove        = 11 (button)
 * Copy          = 10 (button)
 * Edit Strings  = 13 (button)
 * the Value     = 12 (edit text)
 */
INTSML us_techvarsdlog(void)
{
	char **varnames, *name, *cmd[5];
	INTBIG itemHit, i, j;
	REGISTER VARIABLE *var, *ovar;
	TECHVAR *newvars, *tvar, *ltvar, *t;

	/* show the "technology variables" dialog */
	if (DiaInitDialog(&us_techvarsdialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	DiaInitTextDialog(7, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);

	/* load the known variables list */
	for(i=0; us_knownvars[i].varname != 0; i++) DiaStuffLine(7, us_knownvars[i].varname);
	DiaSelectLine(7, -1);

	/* see what variables are already in the list */
	var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, "EDTEC_variable_list");
	newvars = NOTECHVAR;
	if (var != NOVARIABLE)
	{
		j = getlength(var);
		varnames = (char **)var->addr;
		for(i=0; i<j; i++)
		{
			ovar = getval((INTBIG)el_curlib, VLIBRARY, -1, varnames[i]);
			if (ovar == NOVARIABLE) continue;
			DiaStuffLine(3, varnames[i]);
			tvar = (TECHVAR *)emalloc(sizeof (TECHVAR), el_tempcluster);
			if (tvar == 0) break;
			(void)allocstring(&tvar->varname, varnames[i], el_tempcluster);
			tvar->nexttechvar = newvars;
			tvar->changed = 0;
			switch (ovar->type&(VTYPE|VISARRAY))
			{
				case VFLOAT:   tvar->fval = castfloat(ovar->addr);   break;
				case VINTEGER: tvar->ival = ovar->addr;              break;
				case VSTRING:
					(void)allocstring(&tvar->sval, (char *)ovar->addr, el_tempcluster);
					break;
			}
			tvar->vartype = ovar->type;
			newvars = tvar;
		}
	}
	DiaSelectLine(3, -1);

	/* set dialog allowances state */
	us_setcurrenttechvar(newvars);
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL || itemHit == 13) break;

		/* hit in one scroll area turns off highlight in the other */
		if (itemHit == 3)
		{
			DiaSelectLine(7, -1);
			us_setcurrenttechvar(newvars);
		}
		if (itemHit == 7)
		{
			DiaSelectLine(3, -1);
			us_setcurrenttechvar(newvars);
		}

		/* change to the value */
		if (itemHit == 12)
		{
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			name = DiaGetScrollLine(3, i);
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar)
				if (namesame(t->varname, name) == 0) break;
			if (t == NOTECHVAR) continue;
			switch (t->vartype&(VTYPE|VISARRAY))
			{
				case VINTEGER:
					t->ival = myatoi(DiaGetText(12));
					t->changed++;
					break;
				case VFLOAT:
					t->fval = (float)atof(DiaGetText(12));
					t->changed++;
					break;
				case VSTRING:
					(void)reallocstring(&t->sval, DiaGetText(12), el_tempcluster);
					t->changed++;
					break;
			}
			continue;
		}

		/* the "<< Copy" button */
		if (itemHit == 10)
		{
			i = DiaGetCurLine(7);
			if (i < 0) continue;
			name = DiaGetScrollLine(7, i);
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar)
				if (namesame(t->varname, name) == 0) break;
			if (t != NOTECHVAR) continue;

			tvar = (TECHVAR *)emalloc(sizeof (TECHVAR), el_tempcluster);
			if (tvar == 0) break;
			(void)allocstring(&tvar->varname, name, el_tempcluster);
			tvar->vartype = us_knownvars[i].vartype;
			tvar->ival = 0;
			tvar->fval = 0.0;
			if ((tvar->vartype&(VTYPE|VISARRAY)) == VSTRING)
				(void)allocstring(&tvar->sval, "", el_tempcluster);
			tvar->changed = 1;
			tvar->nexttechvar = newvars;
			newvars = tvar;
			DiaLoadTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar) DiaStuffLine(3, t->varname);
			DiaSelectLine(3, -1);
			us_setcurrenttechvar(newvars);
			continue;
		}

		/* the "Remove" button */
		if (itemHit == 11)
		{
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			name = DiaGetScrollLine(3, i);

			ltvar = NOTECHVAR;
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar)
			{
				if (namesame(t->varname, name) == 0) break;
				ltvar = t;
			}
			if (t == NOTECHVAR) continue;
			if (ltvar == NOTECHVAR) newvars = t->nexttechvar; else
				ltvar->nexttechvar = t->nexttechvar;
			if ((t->vartype&(VTYPE|VISARRAY)) == VSTRING) efree(t->sval);
			efree(t->varname);
			efree((char *)t);
			DiaLoadTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar) DiaStuffLine(3, t->varname);
			DiaSelectLine(3, -1);
			us_setcurrenttechvar(newvars);
			continue;
		}
	}
	if (itemHit == 13)
	{
		i = DiaGetCurLine(3);
		if (i < 0) itemHit = OK; else
			name = DiaGetScrollLine(3, i);
	}
	DiaDoneDialog();
	if (itemHit == OK || itemHit == 13)
	{
		j = 0;
		for(t = newvars; t != NOTECHVAR; t = t->nexttechvar) j++;
		if (j > 0)
		{
			varnames = (char **)emalloc(j * (sizeof (char *)), el_tempcluster);
			if (varnames == 0) return(0);
			j = 0;
			for(t = newvars; t != NOTECHVAR; t = t->nexttechvar)
			{
				(void)allocstring(&varnames[j], t->varname, el_tempcluster);
				j++;
				if (t->changed == 0) continue;
				switch (t->vartype&(VTYPE|VISARRAY))
				{
					case VINTEGER:
						(void)setval((INTBIG)el_curlib, VLIBRARY, t->varname, t->ival, VINTEGER);
						break;
					case VFLOAT:
						(void)setval((INTBIG)el_curlib, VLIBRARY, t->varname, castint(t->fval), VFLOAT);
						break;
					case VSTRING:
						(void)setval((INTBIG)el_curlib, VLIBRARY, t->varname, (INTBIG)t->sval, VSTRING);
						break;
					case VSTRING|VISARRAY:
						cmd[0] = "EMPTY";
						(void)setval((INTBIG)el_curlib, VLIBRARY, t->varname,
							(INTBIG)cmd, VSTRING|VISARRAY|(1<<VLENGTHSH));
						break;
				}
			}
			(void)setval((INTBIG)el_curlib, VLIBRARY, "EDTEC_variable_list",
				(INTBIG)varnames, VSTRING|VISARRAY|(j<<VLENGTHSH));
			for(i=0; i<j; i++) efree(varnames[i]);
			efree((char *)varnames);
		} else
		{
			if (getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, "EDTEC_variable_list") != NOVARIABLE)
				(void)delval((INTBIG)el_curlib, VLIBRARY, "EDTEC_variable_list");
		}
	}
	if (itemHit == 13)
	{
		cmd[0] = "textedit";
		(void)initinfstr();
		(void)addstringtoinfstr("lib:~.");
		(void)addstringtoinfstr(name);
		(void)allocstring(&cmd[1], returninfstr(), el_tempcluster);
		cmd[2] = "header";
		(void)initinfstr();
		(void)addstringtoinfstr(_("Editing technology variable: "));
		(void)addstringtoinfstr(name);
		(void)allocstring(&cmd[3], returninfstr(), el_tempcluster);
		us_var(4, cmd);
		efree(cmd[1]);
		efree(cmd[3]);
	}
	return(0);
}

void us_setcurrenttechvar(TECHVAR *newvars)
{
	TECHVAR *t;
	INTBIG i;
	char line[20], *name;

	DiaDimItem(13);      DiaSetText(12, "");   DiaNoEditControl(12);
	DiaDimItem(11);      DiaDimItem(10);
	DiaSetText(5, "");   DiaSetText(6, "");
	i = DiaGetCurLine(3);
	if (i >= 0)
	{
		DiaUnDimItem(11);
		name = DiaGetScrollLine(3, i);
		for(i=0; us_knownvars[i].varname != 0; i++)
			if (namesame(us_knownvars[i].varname, name) == 0) break;
		if (us_knownvars[i].varname != 0) DiaSetText(6, us_knownvars[i].description);
		for(t = newvars; t != NOTECHVAR; t = t->nexttechvar)
			if (namesame(t->varname, name) == 0) break;
		if (t != NOTECHVAR) switch (t->vartype&(VTYPE|VISARRAY))
		{
			case VINTEGER:
				DiaSetText(5, _("Integer"));
				DiaEditControl(12);
				(void)sprintf(line, "%ld", t->ival);
				DiaSetText(-12, line);
				break;
			case VFLOAT:
				DiaSetText(5, _("Real"));
				DiaEditControl(12);
				(void)sprintf(line, "%g", t->fval);
				DiaSetText(-12, line);
				break;
			case VSTRING:
				DiaSetText(5, _("String"));
				DiaEditControl(12);
				DiaSetText(-12, t->sval);
				break;
			case VSTRING|VISARRAY:
				DiaSetText(5, _("Strings"));
				DiaUnDimItem(13);
				break;
		}
	}

	i = DiaGetCurLine(7);
	if (i >= 0)
	{
		name = DiaGetScrollLine(7, i);
		for(i=0; us_knownvars[i].varname != 0; i++)
			if (namesame(us_knownvars[i].varname, name) == 0) break;
		if (us_knownvars[i].varname != 0)
		{
			DiaSetText(6, us_knownvars[i].description);
			switch (us_knownvars[i].vartype&(VTYPE|VISARRAY))
			{
				case VINTEGER:         DiaSetText(5, _("Integer"));   break;
				case VFLOAT:           DiaSetText(5, _("Real"));      break;
				case VSTRING:          DiaSetText(5, _("String"));    break;
				case VSTRING|VISARRAY: DiaSetText(5, _("Strings"));   break;
			}
		}
		DiaUnDimItem(10);
	}
}

/****************************** TECHNOLOGY SELECTION DIALOG ******************************/

/* Technologies */
DIALOGITEM us_techselectdialogitems[] =
{
 /*  1 */ {0, {96,216,120,280}, BUTTON, N_("OK")},
 /*  2 */ {0, {24,216,48,280}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,8,153,193}, SCROLL, ""},
 /*  4 */ {0, {160,8,192,292}, MESSAGE, ""}
};
DIALOG us_techselectdialog = {{50,75,251,376}, N_("Change Current Technology"), 0, 4, us_techselectdialogitems};

/*
 * the meaning of "us_techlist":
 *  0  list all technologies without modification
 *  1  list all technologies, splitting "schematics" into "digital" and "analog"
 *  2  list all technologies that can be edited
 *  3  list all technologies that can be deleted
 */
int us_techlist;
static TECHNOLOGY *us_postechcomcomp;

void us_stufftechdescript(void);
INTSML us_topoftechs(char**);
char *us_nexttechs(void);

INTSML us_topoftechs(char **c) { us_postechcomcomp = el_technologies; return(1); }

char *us_nexttechs(void)
{
	REGISTER char *retname;
	REGISTER TECHNOLOGY *tech;

	for(;;)
	{
		if (us_postechcomcomp == NOTECHNOLOGY)
		{
			us_postechcomcomp = 0;
			if (us_techlist == 1) return("schematic, analog");
		}
		if (us_postechcomcomp == 0) return(0);

		/* get the next technology in the list */
		tech = us_postechcomcomp;
		us_postechcomcomp = us_postechcomcomp->nexttechnology;

		/* adjust the name if requested */
		retname = tech->techname;
		if (tech == sch_tech && us_techlist == 1)
			retname = "schematic, digital";

		/* ignore if requested */
		if (us_techlist == 2 && (tech->userbits&NONSTANDARD) != 0) continue;
		if (us_techlist == 3 && tech == gen_tech) continue;

		/* accept */
		break;
	}
	return(retname);
}

void us_stufftechdescript(void)
{
	REGISTER TECHNOLOGY *t;
	REGISTER char *tech;

	tech = DiaGetScrollLine(3, DiaGetCurLine(3));
	if (namesamen(tech, "schematic", 9) == 0)
	{
		t = sch_tech;
		DiaSetText(4, t->techdescript);
		return;
	}

	for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
		if (strcmp(t->techname, tech) == 0) break;
	if (t == NOTECHNOLOGY) return;
	DiaSetText(4, t->techdescript);
}

/*
 * special case for the "select technology" dialog
 * Technology description = 5 (message)
 * Technology list        = 3 (user item)
 */
INTSML us_technologydlog(char *prompt, char *paramstart[])
{
	REGISTER INTBIG itemHit, i;
	REGISTER NODEPROTO *np;
	REGISTER char *defaulttech, *pt;

	/* display the new facet dialog box */
	us_techselectdialog.movable = prompt;

	/* the list of technologies depends on the nature of the operation */
	us_techlist = 0;
	defaulttech = "";
	if (namesame(prompt, _("Change current technology")) == 0)
	{
		us_techlist = 1;
		np = getcurfacet();
		if (np != NONODEPROTO)
			defaulttech = us_techname(np);
	} else if (namesame(prompt, _("Edit technology")) == 0) 
	{
		us_techlist = 2;
		defaulttech = el_curtech->techname;
	} else if (namesame(prompt, _("Document technology")) == 0)
	{
		us_techlist = 0;
		defaulttech = el_curtech->techname;
	} else if (namesame(prompt, _("Convert to new technology")) == 0) 
	{
		us_techlist = 0;
	} else if (namesame(prompt, _("Delete technology")) == 0)
	{
		us_techlist = 3;
	}

	if (DiaInitDialog(&us_techselectdialog) != 0) return(0);
	DiaInitTextDialog(3, us_topoftechs, us_nexttechs, DiaNullDlogDone, 0,
		SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT|SCREPORT);
	for(i=0; ; i++)
	{
		pt = DiaGetScrollLine(3, i);
		if (*pt == 0) break;
		if (strcmp(pt, defaulttech) == 0)
		{
			DiaSelectLine(3, i);
			break;
		}
	}
	us_stufftechdescript();

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL || itemHit == OK) break;
		if (itemHit == 3)
		{
			us_stufftechdescript();
			continue;
		}
	}

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		paramstart[0] = us_putintoinfstr(DiaGetScrollLine(3, DiaGetCurLine(3)));
	}
	DiaDoneDialog();
	return(1);
}

/****************************** TECHNOLOGY OPTIONS DIALOG ******************************/

/* Technology Options */
DIALOGITEM us_techsetdialogitems[] =
{
 /*  1 */ {0, {200,220,224,284}, BUTTON, N_("OK")},
 /*  2 */ {0, {200,32,224,96}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {32,20,48,156}, MESSAGE, N_("Metal layers:")},
 /*  4 */ {0, {32,164,48,300}, POPUP, ""},
 /*  5 */ {0, {56,20,72,156}, RADIO, N_("Full Geometry")},
 /*  6 */ {0, {56,164,72,300}, RADIO, N_("Stick Figures")},
 /*  7 */ {0, {88,8,104,112}, MESSAGE, N_("Artwork:")},
 /*  8 */ {0, {112,20,128,156}, CHECK, N_("Arrows filled")},
 /*  9 */ {0, {144,8,160,112}, MESSAGE, N_("Schematics:")},
 /* 10 */ {0, {168,20,184,180}, MESSAGE, N_("Negating Bubble Size")},
 /* 11 */ {0, {168,184,184,244}, EDITTEXT, ""},
 /* 12 */ {0, {8,8,24,192}, MESSAGE, N_("MOSIS CMOS Submicron:")},
 /* 13 */ {0, {136,8,137,300}, DIVIDELINE, ""},
 /* 14 */ {0, {80,8,81,300}, DIVIDELINE, ""}
};
DIALOG us_techsetdialog = {{75,75,308,384}, N_("Technology Options"), 0, 14, us_techsetdialogitems};

/*
 * special case for the "Technology Options" dialog
 * MOCMOSSUB metal layers   = 4 (popup)
 * MOCMOSSUB full-geometry  = 5 (radio)
 * MOCMOSSUB stick-figure   = 6 (radio)
 * ARTWORK filled arrow     = 8 (check)
 * SCHEMATICS invert bubble = 11 (edit text)
 */
INTSML us_techoptdlog(void)
{
	REGISTER INTBIG itemHit, which, i, mocmosbits, artbits,
		origmocmosbits, origartbits, schbubblesize, origschbubblesize;
	WINDOWPART *w;
	char *newlang[5];
	static char *metalcount[] = {N_("2 Layers"), N_("3 Layers"), N_("4 Layers"),
		N_("5 Layers"), N_("6 Layers")};
	char *par[2];

	/* display the options dialog box */
	if (DiaInitDialog(&us_techsetdialog) != 0) return(0);
	for(i=0; i<5; i++) newlang[i] = _(metalcount[i]);   DiaSetPopup(4, 5, newlang);
	origmocmosbits = mocmosbits = asktech(mocmossub_tech, "get-state");
	origartbits = artbits = asktech(art_tech, "get-state");
	origschbubblesize = schbubblesize = asktech(sch_tech, "get-bubble-size");
	switch (mocmosbits&MOCMOSSUBMETALS)
	{
		case MOCMOSSUB2METAL: DiaSetPopupEntry(4, 0);   break;
		case MOCMOSSUB3METAL: DiaSetPopupEntry(4, 1);   break;
		case MOCMOSSUB4METAL: DiaSetPopupEntry(4, 2);   break;
		case MOCMOSSUB5METAL: DiaSetPopupEntry(4, 3);   break;
		case MOCMOSSUB6METAL: DiaSetPopupEntry(4, 4);   break;
	}
	if ((mocmosbits&MOCMOSSUBSTICKFIGURE) != 0) DiaSetControl(6, 1); else
		DiaSetControl(5, 1);
	if ((artbits&ARTWORKFILLARROWHEADS) != 0) DiaSetControl(8, 1);
	DiaSetText(11, frtoa(schbubblesize));

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 5 || itemHit == 6)
		{
			DiaSetControl(5, 0);
			DiaSetControl(6, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 8)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit == OK)
	{
		which = DiaGetPopupEntry(4);
		mocmosbits &= ~MOCMOSSUBMETALS;
		switch (which)
		{
			case 0: mocmosbits |= MOCMOSSUB2METAL;   break;
			case 1: mocmosbits |= MOCMOSSUB3METAL;   break;
			case 2: mocmosbits |= MOCMOSSUB4METAL;   break;
			case 3: mocmosbits |= MOCMOSSUB5METAL;   break;
			case 4: mocmosbits |= MOCMOSSUB6METAL;   break;
		}
		if (DiaGetControl(6) != 0) mocmosbits |= MOCMOSSUBSTICKFIGURE; else
			mocmosbits &= ~MOCMOSSUBSTICKFIGURE;
		if (origmocmosbits != mocmosbits)
		{
			setval((INTBIG)mocmossub_tech, VTECHNOLOGY, "TECH_state", mocmosbits, VINTEGER);
			if ((origmocmosbits&MOCMOSSUBSTICKFIGURE) != (mocmosbits&MOCMOSSUBSTICKFIGURE))
				us_figuretechopaque(mocmossub_tech);
			if (el_curtech == mocmossub_tech)
			{
				par[0] = "size";
				par[1] = "auto";
				us_menu(2, par);
				us_setmenunodearcs();
			}
		}

		if (DiaGetControl(8) != 0) artbits |= ARTWORKFILLARROWHEADS; else
			artbits &= ~ARTWORKFILLARROWHEADS;
		if (artbits != origartbits)
		{
			setval((INTBIG)art_tech, VTECHNOLOGY, "TECH_state", artbits, VINTEGER);
			(void)asktech(art_tech, "set-state", artbits);
			if (el_curtech == art_tech)
				us_setmenunodearcs();
		}

		schbubblesize = atofr(DiaGetText(11));
		if (schbubblesize != origschbubblesize)
			(void)asktech(sch_tech, "set-bubble-size", schbubblesize);

		if ((origmocmosbits&MOCMOSSUBSTICKFIGURE) != (mocmosbits&MOCMOSSUBSTICKFIGURE) ||
			origartbits != artbits || origschbubblesize != schbubblesize)
		{
			us_pushhighlight();
			us_clearhighlightcount();
			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
				if (w->redisphandler != 0) (*w->redisphandler)(w);
			(void)us_pophighlight(0);
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** TEXT OPTIONS DIALOG ******************************/

/* Text options */
DIALOGITEM us_deftextdialogitems[] =
{
 /*  1 */ {0, {244,304,268,376}, BUTTON, N_("OK")},
 /*  2 */ {0, {244,216,268,288}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {112,32,128,88}, RADIO, N_("Left")},
 /*  4 */ {0, {8,80,24,196}, POPUP, ""},
 /*  5 */ {0, {48,32,64,104}, RADIO, N_("Center")},
 /*  6 */ {0, {64,32,80,104}, RADIO, N_("Bottom")},
 /*  7 */ {0, {80,32,96,88}, RADIO, N_("Top")},
 /*  8 */ {0, {96,32,112,96}, RADIO, N_("Right")},
 /*  9 */ {0, {128,32,144,128}, RADIO, N_("Lower right")},
 /* 10 */ {0, {144,32,160,128}, RADIO, N_("Lower left")},
 /* 11 */ {0, {160,32,176,128}, RADIO, N_("Upper right")},
 /* 12 */ {0, {176,32,192,120}, RADIO, N_("Upper left")},
 /* 13 */ {0, {192,32,208,104}, RADIO, N_("Boxed")},
 /* 14 */ {0, {8,8,24,79}, MESSAGE, N_("Text size:")},
 /* 15 */ {0, {32,8,48,103}, MESSAGE, N_("Text corner:")},
 /* 16 */ {0, {48,136,80,168}, ICON, (char *)us_icon200},
 /* 17 */ {0, {80,136,112,168}, ICON, (char *)us_icon201},
 /* 18 */ {0, {112,136,144,168}, ICON, (char *)us_icon202},
 /* 19 */ {0, {144,136,176,168}, ICON, (char *)us_icon203},
 /* 20 */ {0, {176,136,208,168}, ICON, (char *)us_icon204},
 /* 21 */ {0, {152,284,168,356}, RADIO, N_("Outside")},
 /* 22 */ {0, {64,200,80,272}, RADIO, N_("Off")},
 /* 23 */ {0, {32,180,48,376}, MESSAGE, N_("Smart Vertical Placement:")},
 /* 24 */ {0, {52,284,68,356}, RADIO, N_("Inside")},
 /* 25 */ {0, {76,284,92,356}, RADIO, N_("Outside")},
 /* 26 */ {0, {140,200,156,272}, RADIO, N_("Off")},
 /* 27 */ {0, {108,180,124,376}, MESSAGE, N_("Smart Horizontal Placement:")},
 /* 28 */ {0, {128,284,144,356}, RADIO, N_("Inside")},
 /* 29 */ {0, {188,180,204,376}, CHECK, N_("Only visible inside facet")},
 /* 30 */ {0, {220,100,236,224}, POPUP, ""},
 /* 31 */ {0, {220,8,236,99}, MESSAGE, N_("Text editor:")}
};
DIALOG us_deftextdialog = {{50,75,327,460}, N_("Text Options"), 0, 31, us_deftextdialogitems};

/*
 * special case for "text options" dialog
 * text size                = 4 (popup)
 * center                   = 5 (radio)
 * bottom                   = 6 (radio)
 * top                      = 7 (radio)
 * right                    = 8 (radio)
 * left                     = 3 (radio)
 * lower right              = 9 (radio)
 * lower left               = 10 (radio)
 * upper right              = 11 (radio)
 * upper left               = 12 (radio)
 * boxed                    = 13 (radio)
 * smart vertical off       = 22 (radio)
 * smart vertical inside    = 24 (radio)
 * smart vertical outside   = 25 (radio)
 * smart horizontal off     = 26 (radio)
 * smart horizontal inside  = 28 (radio)
 * smart horizontal outside = 21 (radio)
 * only inside facet        = 29 (check)
 * text editor              = 30 (popup)
 */
INTSML us_deftextdlog(char *prompt)
{
	INTBIG itemHit, i, j, ecount, cureditor;
	INTSML x, y;
	char *newlang[12];
	REGISTER VARIABLE *var;
	REGISTER WINDOWPART *w;
	REGISTER INTBIG grabpoint, textstyle, font, smarthstyle, smartvstyle;
	RECTAREA itemRect;
	static char *editorname[2] = {N_("Point-and-Click"), N_("EMACS")};
	static char *sizenames[12] = {N_("4 Points"), N_("6 Points"), N_("8 Points"), N_("10 Points"),
		N_("12 Points"), N_("14 Points"), N_("16 Points"), N_("18 Points"), N_("20 Points"),
		N_("Small"), N_("Medium"), N_("Large")};
	static INTBIG sizelist[12] = {TXT4P, TXT6P, TXT8P, TXT10P, TXT12P, TXT14P, TXT16P,
		TXT18P, TXT20P, TXTSMALL, TXTMEDIUM, TXTLARGE};
	static struct butlist poslist[10] =
	{
		{VTPOSCENT,       5},
		{VTPOSUP,         6},
		{VTPOSDOWN,       7},
		{VTPOSLEFT,       8},
		{VTPOSRIGHT,      3},
		{VTPOSUPLEFT,     9},
		{VTPOSUPRIGHT,   10},
		{VTPOSDOWNLEFT,  11},
		{VTPOSDOWNRIGHT, 12},
		{VTPOSBOXED,     13}
	};

	/* display the default text dialog box */
	if (DiaInitDialog(&us_deftextdialog) != 0) return(0);
	for(i=0; i<12; i++) newlang[i] = _(sizenames[i]);   DiaSetPopup(4, 12, newlang);

	/* load the editor choice popup */
	for(ecount=0; us_editortable[ecount].editorname != 0; ecount++)
		newlang[ecount] = us_editortable[ecount].editorname;
	DiaSetPopup(30, ecount, newlang);
	cureditor = 0;
	var = getvalkey((INTBIG)us_aid, VAID, VSTRING, us_text_editor);
	if (var != NOVARIABLE)
	{
		for(i=0; i<ecount; i++)
			if (namesame(newlang[i], (char *)var->addr) == 0) break;
		if (i < ecount) cureditor = i;
	}
	DiaSetPopupEntry(30, cureditor);

	/* make sure there are no text editors running */
	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
		if ((w->state&WINDOWTYPE) == TEXTWINDOW || (w->state&WINDOWTYPE) == POPTEXTWINDOW)
	{
		DiaDimItem(30);
		break;
	}

	/* set current defaults */
	var = getval((INTBIG)us_aid, VAID, VINTEGER, "USER_default_text_style");
	if (var == NOVARIABLE) textstyle = VTPOSCENT; else textstyle = var->addr;
	grabpoint = textstyle & VTPOSITION;
	for(i=0; i<10; i++) if (grabpoint == poslist[i].value)
	{
		DiaSetControl(poslist[i].button, 1);
		break;
	}
	if ((textstyle&VTINTERIOR) != 0) DiaSetControl(29, 1);

	var = getval((INTBIG)us_aid, VAID, VINTEGER, "USER_default_text_smart_style");
	if (var == NOVARIABLE)
	{
		smarthstyle = smartvstyle = 0;
	} else
	{
		smarthstyle = var->addr & 03;
		smartvstyle = (var->addr >> 2) & 03;
	}
	switch (smarthstyle)
	{
		case 1:  DiaSetControl(28, 1);  break;
		case 2:  DiaSetControl(21, 1);  break;
		default: DiaSetControl(26, 1);  break;
	}
	switch (smartvstyle)
	{
		case 1:  DiaSetControl(24, 1);  break;
		case 2:  DiaSetControl(25, 1);  break;
		default: DiaSetControl(22, 1);  break;
	}

	var = getval((INTBIG)us_aid, VAID, VINTEGER, "USER_default_text_size");
	if (var == NOVARIABLE) font = TXTSMALL; else font = var->addr;
	for(i=0; i<12; i++) if (font == sizelist[i])
	{
		DiaSetPopupEntry(4, i);
		break;
	}

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;

		if (itemHit >= 16 && itemHit <= 20)
		{
			DiaItemRect(itemHit, &itemRect);
			DiaGetMouse(&x, &y);
			itemHit = (itemHit-16) * 2;
			if (y > (itemRect.top + itemRect.bottom) / 2) itemHit++;
			itemHit = poslist[itemHit].button;
		}

		/* hits on the orientation buttons */
		for(i=0; i<10; i++) if (itemHit == poslist[i].button)
		{
			DiaSetControl(poslist[grabpoint].button, 0);
			grabpoint = i;
			DiaSetControl(poslist[i].button, 1);
			break;
		}

		if (itemHit == 22 || itemHit == 24 || itemHit == 25)
		{
			DiaSetControl(22, 0);
			DiaSetControl(24, 0);
			DiaSetControl(25, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 26 || itemHit == 28 || itemHit == 21)
		{
			DiaSetControl(26, 0);
			DiaSetControl(28, 0);
			DiaSetControl(21, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 29)
		{
			DiaSetControl(itemHit, 1 - DiaGetControl(itemHit));
			continue;
		}
	}

	if (itemHit == OK)
	{
		i = sizelist[DiaGetPopupEntry(4)];
		if (i != font)
			setval((INTBIG)us_aid, VAID, "USER_default_text_size", i, VINTEGER);
		if (DiaGetControl(29) != 0) grabpoint |= VTINTERIOR;
		if (grabpoint != textstyle)
			setval((INTBIG)us_aid, VAID, "USER_default_text_style", grabpoint, VINTEGER);
		if (DiaGetControl(26) != 0) i = 0; else
			if (DiaGetControl(28) != 0) i = 1; else
				if (DiaGetControl(21) != 0) i = 2;
		if (DiaGetControl(22) != 0) j = 0; else
			if (DiaGetControl(24) != 0) j = 1; else
				if (DiaGetControl(25) != 0) j = 2;
		if (smarthstyle != i || smartvstyle != j)
			setval((INTBIG)us_aid, VAID, "USER_default_text_smart_style",
				i | (j << 2), VINTEGER);
		i = DiaGetPopupEntry(30);
		if (i != cureditor)
		{
			setvalkey((INTBIG)us_aid, VAID, us_text_editor, (INTBIG)us_editortable[i].editorname,
				VSTRING);
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** UNITS DIALOG ******************************/

/* Units */
DIALOGITEM us_unitsdialogitems[] =
{
 /*  1 */ {0, {312,212,336,284}, BUTTON, N_("OK")},
 /*  2 */ {0, {276,212,300,284}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {216,212,232,288}, EDITTEXT, ""},
 /*  4 */ {0, {216,8,232,208}, MESSAGE, N_("Lambda size (internal units):")},
 /*  5 */ {0, {364,128,380,288}, POPUP, ""},
 /*  6 */ {0, {364,8,380,127}, MESSAGE, N_("Display Units:")},
 /*  7 */ {0, {388,128,404,288}, POPUP, ""},
 /*  8 */ {0, {388,8,404,127}, MESSAGE, N_("Internal Units:")},
 /*  9 */ {0, {52,8,208,288}, SCROLL, ""},
 /* 10 */ {0, {32,80,48,200}, MESSAGE, N_("Technologies:")},
 /* 11 */ {0, {8,152,24,288}, MESSAGE, ""},
 /* 12 */ {0, {8,8,24,152}, MESSAGE, N_("Current library:")},
 /* 13 */ {0, {328,24,344,176}, RADIO, N_("Change all libraries")},
 /* 14 */ {0, {304,24,320,176}, RADIO, N_("Change current library")},
 /* 15 */ {0, {352,8,353,288}, DIVIDELINE, ""},
 /* 16 */ {0, {240,212,256,288}, MESSAGE, ""},
 /* 17 */ {0, {280,24,296,176}, RADIO, N_("Change no libraries")},
 /* 18 */ {0, {256,8,272,176}, MESSAGE, N_("When changing lambda:")}
};
DIALOG us_unitsdialog = {{50,75,463,372}, N_("Change Units"), 0, 18, us_unitsdialogitems};

INTSML us_topoftechlambda(char **c);
char *us_nexttechlambda(void);

/*
 * special case for the "units" dialog
 * Lambda           = 3 (edit text)
 * Display units    = 5 (popup)
 * Internal units   = 7 (popup)
 * Technologies     = 9 (scroll)
 * Current lib      = 11 (stat text)
 * Change all libs  = 13 (radio)
 * Change this lib  = 14 (radio)
 * Micron value     = 16 (stat text)
 * Change no libs   = 17 (radio)
 */
INTSML us_lambdadlog(void)
{
	REGISTER INTBIG itemHit, i, count, newiunit, newdunit, oldiunit, olddunit,
		which, newlam, oldlam, *newlamarray;
	float lambdainmicrons;
	REGISTER WINDOWPART *w;
	char ent[30], *newlang[8], *pt, *line;
	REGISTER TECHNOLOGY **techarray, *tech, *curtech;
	static char *dispunitnames[8] = {N_("Lambda units"), N_("Inches"), N_("Centimeters"),
		N_("Millimeters"), N_("Mils"), N_("Microns"), N_("Centimicrons"), N_("Millimicrons")};
	static char *intunitnames[2] = {N_("Half-Millimicrons"), N_("Half-Decimicrons")};

	/* display the units dialog box */
	if (DiaInitDialog(&us_unitsdialog) != 0) return(0);
	DiaSetText(11, el_curlib->libname);
	DiaSetControl(13, 1);
	for(i=0; i<8; i++) newlang[i] = _(dispunitnames[i]);   DiaSetPopup(5, 8, newlang);
	olddunit = el_units&DISPLAYUNITS;
	switch (olddunit)
	{
		case DISPUNITLAMBDA: DiaSetPopupEntry(5, 0);   break;
		case DISPUNITINCH:   DiaSetPopupEntry(5, 1);   break;
		case DISPUNITCM:     DiaSetPopupEntry(5, 2);   break;
		case DISPUNITMM:     DiaSetPopupEntry(5, 3);   break;
		case DISPUNITMIL:    DiaSetPopupEntry(5, 4);   break;
		case DISPUNITMIC:    DiaSetPopupEntry(5, 5);   break;
		case DISPUNITCMIC:   DiaSetPopupEntry(5, 6);   break;
		case DISPUNITMMIC:   DiaSetPopupEntry(5, 7);   break;
	}
	for(i=0; i<2; i++) newlang[i] = _(intunitnames[i]);   DiaSetPopup(7, 2, newlang);
	oldiunit = el_units&INTERNALUNITS;
	switch (oldiunit)
	{
		case INTUNITHMMIC:   DiaSetPopupEntry(7, 0);   break;
		case INTUNITHDMIC:   DiaSetPopupEntry(7, 1);   break;
	}

	/* load the list of technologies */
	curtech = el_curtech;
	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
		tech->temp1 = el_curlib->lambda[tech->techindex];
	DiaInitTextDialog(9, us_topoftechlambda, us_nexttechlambda, DiaNullDlogDone, 0,
		SCSELMOUSE|SCREPORT);
	for(i=0; ; i++)
	{
		line = DiaGetScrollLine(9, i);
		if (*line == 0) break;
		for(pt = line; *pt != 0; pt++) if (*pt == ' ') break;
		*pt = 0;
		if (namesame(line, curtech->techname) == 0) break;
	}
	DiaSelectLine(9, i);

	/* set the current value of lambda */
	(void)sprintf(ent, "%ld", curtech->temp1);
	DiaSetText(-3, ent);
	lambdainmicrons = scaletodispunit(curtech->temp1, DISPUNITMIC);
	(void)sprintf(ent, "(%gu)", lambdainmicrons);
	DiaSetText(16, ent);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(3)) break;
		if (itemHit == 13 || itemHit == 14 || itemHit == 17)
		{
			DiaSetControl(13, 0);
			DiaSetControl(14, 0);
			DiaSetControl(17, 0);
			DiaSetControl(itemHit, 1);
			continue;
		}
		if (itemHit == 3)
		{
			curtech->temp1 = atoi(DiaGetText(3));
			lambdainmicrons = scaletodispunit(curtech->temp1, DISPUNITMIC);
			(void)sprintf(ent, "(%gu)", lambdainmicrons);
			DiaSetText(16, ent);
			which = DiaGetCurLine(9);
			(void)initinfstr();
			lambdainmicrons = scaletodispunit(curtech->temp1, DISPUNITMIC);
			(void)formatinfstr("%s (lambda=%ld, %gu)", curtech->techname, curtech->temp1,
				lambdainmicrons);
			DiaSetScrollLine(9, which, returninfstr());
			continue;
		}
		if (itemHit == 9)
		{
			which = DiaGetCurLine(9);
			line = DiaGetScrollLine(9, which);
			for(pt = line; *pt != 0; pt++) if (*pt == ' ') break;
			*pt = 0;
			for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
				if (namesame(line, tech->techname) == 0) break;
			*pt = ' ';
			if (tech == NOTECHNOLOGY) continue;
			curtech = tech;
			(void)sprintf(ent, "%ld", curtech->temp1);
			DiaSetText(-3, ent);
			lambdainmicrons = scaletodispunit(curtech->temp1, DISPUNITMIC);
			(void)sprintf(ent, "(%gu)", lambdainmicrons);
			continue;
		}
	}

	if (itemHit != CANCEL)
	{
		/* set display unit */
		i = DiaGetPopupEntry(5);
		switch (i)
		{
			case 0: newdunit = DISPUNITLAMBDA;   break;
			case 1: newdunit = DISPUNITINCH;     break;
			case 2: newdunit = DISPUNITCM;       break;
			case 3: newdunit = DISPUNITMM;       break;
			case 4: newdunit = DISPUNITMIL;      break;
			case 5: newdunit = DISPUNITMIC;      break;
			case 6: newdunit = DISPUNITCMIC;     break;
			case 7: newdunit = DISPUNITMMIC;     break;
		}
		if (newdunit != olddunit)
			setvalkey((INTBIG)us_aid, VAID, us_displayunits, newdunit, VINTEGER);

		/* see if internal unit was changed */
		i = DiaGetPopupEntry(7);
		switch (i)
		{
			case 0: newiunit = INTUNITHMMIC;   break;
			case 1: newiunit = INTUNITHDMIC;   break;
		}
		if (newiunit != oldiunit)
			changeinternalunits(NOLIBRARY, el_units, newiunit);

		/* see if lambda values changed */
		count = 0;
		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
			if (tech->temp1 != el_curlib->lambda[tech->techindex]) count++;
		if (count != 0)
		{
			techarray = (TECHNOLOGY **)emalloc(count * (sizeof (TECHNOLOGY *)), el_tempcluster);
			if (techarray == 0) return(0);
			newlamarray = (INTBIG *)emalloc(count * SIZEOFINTBIG, el_tempcluster);
			if (newlamarray == 0) return(0);
			count = 0;
			for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
			{
				if (tech->temp1 == el_curlib->lambda[tech->techindex]) continue;
				techarray[count] = tech;
				newlamarray[count] = tech->temp1;
				count++;
			}
			oldlam = el_curlib->lambda[el_curtech->techindex];
			newlam = el_curtech->temp1;

			if (DiaGetControl(13) != 0) i = 2; else
				if (DiaGetControl(14) != 0) i = 1; else
					i = 0;

			/* save highlighting */
			us_pushhighlight();
			us_clearhighlightcount();

			changelambda(count, techarray, newlamarray, el_curlib, i);
			us_setlambda(NOWINDOWFRAME);
			us_adjustlambda(oldlam, newlam);
			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
			{
				if (w->curnodeproto == NONODEPROTO) continue;
				if (w->curnodeproto->tech != el_curtech) continue;
				if (i == 2 || (i == 1 && w->curnodeproto->cell->lib == el_curlib))
				{
					w->screenlx = muldiv(w->screenlx, newlam, oldlam);
					w->screenhx = muldiv(w->screenhx, newlam, oldlam);
					w->screenly = muldiv(w->screenly, newlam, oldlam);
					w->screenhy = muldiv(w->screenhy, newlam, oldlam);
					computewindowscale(w);
				} else us_redisplay(w);
			}

			/* restore highlighting */
			(void)us_pophighlight(0);
			efree((char *)techarray);
			efree((char *)newlamarray);
		}
	}
	DiaDoneDialog();
	return(0);
}

TECHNOLOGY *us_curtechlambda;

INTSML us_topoftechlambda(char **c)
{
	us_curtechlambda = el_technologies;
	return(1);
}

char *us_nexttechlambda(void)
{
	float lambdainmicrons;

	if (us_curtechlambda == NOTECHNOLOGY) return(0);
	(void)initinfstr();
	lambdainmicrons = scaletodispunit(us_curtechlambda->temp1, DISPUNITMIC);
	(void)formatinfstr("%s (lambda=%ld, %gu)", us_curtechlambda->techname,
		us_curtechlambda->temp1, lambdainmicrons);
	us_curtechlambda = us_curtechlambda->nexttechnology;
	return(returninfstr());
}

/****************************** VARIABLES DIALOG ******************************/

/* Variables */
DIALOGITEM us_variabledialogitems[] =
{
 /*  1 */ {0, {408,344,432,400}, BUTTON, N_("OK")},
 /*  2 */ {0, {352,8,368,56}, MESSAGE, N_("Value:")},
 /*  3 */ {0, {336,8,337,408}, DIVIDELINE, ""},
 /*  4 */ {0, {24,8,40,64}, MESSAGE, N_("Object:")},
 /*  5 */ {0, {8,80,24,240}, RADIO, N_("Currently Highlighted")},
 /*  6 */ {0, {24,80,40,240}, RADIO, N_("Current Facet")},
 /*  7 */ {0, {40,80,56,240}, RADIO, N_("Current Cell")},
 /*  8 */ {0, {56,80,72,240}, RADIO, N_("Current Library")},
 /*  9 */ {0, {8,256,24,408}, RADIO, N_("Current Technology")},
 /* 10 */ {0, {24,256,40,408}, RADIO, N_("Current Aid")},
 /* 11 */ {0, {144,24,160,96}, MESSAGE, N_("Attribute:")},
 /* 12 */ {0, {160,8,304,184}, SCROLL, ""},
 /* 13 */ {0, {312,32,328,152}, CHECK, N_("New Attribute:")},
 /* 14 */ {0, {312,160,328,400}, EDITTEXT, ""},
 /* 15 */ {0, {216,192,232,251}, CHECK, N_("Array")},
 /* 16 */ {0, {240,200,256,248}, MESSAGE, N_("Index:")},
 /* 17 */ {0, {240,250,256,312}, EDITTEXT, ""},
 /* 18 */ {0, {408,192,432,296}, BUTTON, N_("Set Attribute")},
 /* 19 */ {0, {344,80,376,400}, EDITTEXT, ""},
 /* 20 */ {0, {408,24,432,144}, BUTTON, N_("Delete Attribute")},
 /* 21 */ {0, {168,192,184,288}, CHECK, N_("Displayable")},
 /* 22 */ {0, {192,192,208,288}, CHECK, N_("Temporary")},
 /* 23 */ {0, {276,224,300,361}, BUTTON, N_("Examine Attribute")},
 /* 24 */ {0, {112,40,128,80}, MESSAGE, N_("Type:")},
 /* 25 */ {0, {112,80,128,216}, MESSAGE, ""},
 /* 26 */ {0, {144,184,160,224}, MESSAGE, N_("Type:")},
 /* 27 */ {0, {144,224,160,383}, MESSAGE, ""},
 /* 28 */ {0, {136,8,137,408}, DIVIDELINE, ""},
 /* 29 */ {0, {80,80,112,408}, MESSAGE, ""},
 /* 30 */ {0, {80,32,96,80}, MESSAGE, N_("Name:")},
 /* 31 */ {0, {168,304,184,410}, POPUP, ""},
 /* 32 */ {0, {384,80,400,160}, MESSAGE, N_("Evaluation:")},
 /* 33 */ {0, {384,160,400,400}, MESSAGE, ""},
 /* 34 */ {0, {232,320,248,366}, BUTTON, N_("Next")},
 /* 35 */ {0, {248,320,264,366}, BUTTON, N_("Prev")},
 /* 36 */ {0, {40,256,56,408}, RADIO, N_("Current Window")},
 /* 37 */ {0, {56,256,72,408}, RADIO, N_("Current Constraint")}
};
DIALOG us_variabledialog = {{50,75,492,494}, N_("Variable Control"), 0, 37, us_variabledialogitems};

/* special case for the "variables" dialog
 * Currently highlighted object = 5 (radio)
 * Current facet                = 6 (radio)
 * Current cell                 = 7 (radio)
 * Current library              = 8 (radio)
 * Current technology           = 9 (radio)
 * Current aid                  = 10 (radio)
 * Object type                  = 25 (message)
 * Object name                  = 29 (message)
 * Object/Attribute Divider bar = 28 (message)
 * Attribute name list          = 12 (scroll)
 * Attribute type               = 27 (message)
 * Examine                      = 23 (button)
 * Displayable attribute        = 21 (check)
 * Temporary attribute          = 22 (check)
 * Array attribute              = 15 (check)
 * Array index                  = 17 (edit text)
 * New Attribute                = 13 (check)
 * New Attribute name           = 14 (edit text)
 * Attribute/Value Divider bar  = 3 (message)
 * Attribute value              = 19 (edit text)
 * Attribute language           = 31 (popup)
 * Set Attribute                = 18 (button)
 * OK                           = 1 (button)
 * Delete Attribute             = 20 (button)
 * CANCEL (not a button)        = 2 (returned by  us_modaldialog()
 */
INTBIG us_possearch, us_varaddr, us_curvaraddr;
INTBIG us_vartype, us_curvartype;
VARIABLE *us_variablesvar;

INTSML us_topofdlgvars(char**);
char *us_nextdlgvars(void);
void us_varestablish(INTBIG, INTBIG, char*);
void us_varidentify(void);

INTSML us_topofdlgvars(char **c)
{
	us_possearch = initobjlist(us_varaddr, us_vartype, 0);
	return(1);
}
char *us_nextdlgvars(void)
{
	VARIABLE *var;

	return(nextobjectlist(&var, us_possearch));
}

INTSML us_variablesdlog(void)
{
	INTBIG itemHit, i, j, which, len;
	REGISTER INTBIG search, newval, newtype, *newarray, oldlen, descript;
	char *varname, *name, *newstr, *pp, line[100], *newlang[4];
	HIGHLIGHT high;
	VARIABLE *var;
	NODEPROTO *curfacet;
	static char nullstr[] = "";
	static char *languages[] = {N_("Not Code"), N_("TCL"), N_("LISP"), N_("JAVA")};

	/* display the variables dialog box */
	if (DiaInitDialog(&us_variabledialog) != 0) return(0);
#if LANGTCL == 0
	languages[1] = N_("TCL (not available)");
#endif
#if LANGLISP == 0
	languages[2] = N_("LISP (not available)");
#endif
#if LANGJAVA == 0
	languages[3] = N_("JAVA (not available)");
#endif
	for(i=0; i<4; i++) newlang[i] = _(languages[i]);   DiaSetPopup(31, 4, newlang);
	DiaNoEditControl(14);
	DiaNoEditControl(17);

	/* presume the current facet or library */
	curfacet = getcurfacet();
	us_varaddr = (INTBIG)curfacet;
	us_vartype = VNODEPROTO;
	if (curfacet == NONODEPROTO)
	{
		/* no current facet: cannot select facet/cell */
		DiaDimItem(6);
		DiaDimItem(7);
		us_varaddr = (INTBIG)el_curlib;
		us_vartype = VLIBRARY;
	}

	/* see if a single object is highlighted */
	us_curvaraddr = 0;
	us_curvartype = VUNKNOWN;
	var = getvalkey((INTBIG)us_aid, VAID, VSTRING|VISARRAY, us_highlighted);
	if (var != NOVARIABLE)
	{
		if (getlength(var) == 1)
		{
			if (us_makehighlight(((char **)var->addr)[0], &high) == 0)
			{
				if ((high.status&HIGHTYPE) == HIGHFROM)
				{
					if (high.fromgeom->entrytype == OBJARCINST) us_vartype = VARCINST; else
						us_vartype = VNODEINST;
					us_curvaraddr = us_varaddr = (INTBIG)high.fromgeom->entryaddr.blind;
					us_curvartype = us_vartype;
				}
			}
		}
	}
	if (us_vartype == VNODEPROTO || us_vartype == VLIBRARY) DiaDimItem(5);

	/* initialize the attribute list */
	DiaInitTextDialog(12, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	us_varestablish(us_varaddr, us_vartype, "");

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == 1 || itemHit == 18 || itemHit == 20 || itemHit == 2) break;
		if (itemHit == 12)
		{
			/* select a new attribute name */
			us_varidentify();
			continue;
		}
		if (itemHit == 13)
		{
			/* want a new variable */
			DiaSetText(14, "");
			i = DiaGetControl(13);
			DiaSetControl(13, 1-i);
			if (i != 0) DiaNoEditControl(14); else DiaEditControl(14);
			DiaSetText(19, "");
			DiaSetText(-14, "");
			DiaUnDimItem(15);
			DiaUnDimItem(21);   DiaUnDimItem(22);
			DiaUnDimItem(31);
			DiaDimItem(23);
			DiaDimItem(20);
			DiaUnDimItem(18);
			continue;
		}
		if (itemHit == 23)
		{
			/* examine the variable */
			which = DiaGetCurLine(12);
			if (which < 0) continue;
			varname = DiaGetScrollLine(12, which);
			search = initobjlist(us_varaddr, us_vartype, 0);
			for(;;)
			{
				name = nextobjectlist(&var, search);
				if (name == 0) break;
				if (strcmp(name, varname) == 0)
				{
					if ((var->type&VISARRAY) != 0)
					{
						i = myatoi(DiaGetText(17));
						if (i < 0) i = 0;
						if (i > getlength(var)) i = getlength(var)-1;
						(void)sprintf(line, "%s[%d]", varname, i);
						us_varestablish(((INTBIG *)var->addr)[i], var->type&VTYPE, line);
					} else us_varestablish(var->addr, var->type&VTYPE, varname);
					break;
				}
			}
			continue;
		}
		if (itemHit == 17)
		{
			/* changing index */
			if (DiaGetControl(13) != 0) continue;
			i = myatoi(DiaGetText(17));
			if (i < 0) i = 0;
			len = getlength(us_variablesvar);
			if (i >= len) i = len-1;
			DiaSetText(19, describevariable(us_variablesvar, (INTSML)i, -1));
			continue;
		}
		if (itemHit == 34)
		{
			/* increment index */
			i = myatoi(DiaGetText(17)) + 1;
			if (DiaGetControl(13) == 0)
			{
				len = getlength(us_variablesvar);
				if (i >= len) i = len-1;
			}
			(void)sprintf(line, "%d", i);
			DiaSetText(17, line);
			if (DiaGetControl(13) == 0)
				DiaSetText(19, describevariable(us_variablesvar, (INTSML)i, -1));
			continue;
		}
		if (itemHit == 35)
		{
			/* decrement index */
			i = myatoi(DiaGetText(17)) - 1;
			if (i < 0) continue;
			(void)sprintf(line, "%d", i);
			DiaSetText(17, line);
			if (DiaGetControl(13) == 0)
				DiaSetText(19, describevariable(us_variablesvar, (INTSML)i, -1));
			continue;
		}
		if (itemHit == 5)
		{
			/* want current object */
			us_varestablish(us_curvaraddr, us_curvartype, "");
			continue;
		}
		if (itemHit == 6)
		{
			/* want current facet */
			us_varestablish((INTBIG)curfacet, VNODEPROTO, "");
			continue;
		}
		if (itemHit == 7)
		{
			/* want current cell */
			us_varestablish((INTBIG)curfacet->cell, VCELL, "");
			continue;
		}
		if (itemHit == 8)
		{
			/* want current library */
			us_varestablish((INTBIG)el_curlib, VLIBRARY, "");
			continue;
		}
		if (itemHit == 9)
		{
			/* want current technology */
			us_varestablish((INTBIG)el_curtech, VTECHNOLOGY, "");
			continue;
		}
		if (itemHit == 10)
		{
			/* want current aid */
			us_varestablish((INTBIG)us_aid, VAID, "");
			continue;
		}
		if (itemHit == 36)
		{
			/* want current window */
			us_varestablish((INTBIG)el_curwindowpart, VWINDOWPART, "");
			continue;
		}
		if (itemHit == 37)
		{
			/* want current constraint */
			us_varestablish((INTBIG)el_curconstraint, VCONSTRAINT, "");
			continue;
		}
		if (itemHit == 21)
		{
			/* displayable attribute */
			DiaSetControl(21, 1-DiaGetControl(21));
			continue;
		}
		if (itemHit == 22)
		{
			/* temporary attribute */
			DiaSetControl(22, 1-DiaGetControl(22));
			continue;
		}
		if (itemHit == 15)
		{
			/* array attribute */
			i = DiaGetControl(15);
			DiaSetControl(15, 1-i);
			if (i == 0)
			{
				DiaUnDimItem(16);   DiaUnDimItem(17);
				DiaUnDimItem(34);   DiaUnDimItem(35);
				DiaEditControl(17);
				DiaSetText(17, "0");
			} else
			{
				DiaDimItem(16);   DiaDimItem(17);
				DiaDimItem(34);   DiaDimItem(35);
				DiaNoEditControl(17);
				DiaSetText(17, "");
			}
			continue;
		}
	}

	/* handle attribute deletion */
	if (itemHit == 20)
	{
		startobjectchange(us_varaddr, us_vartype);
		delvalkey(us_varaddr, us_vartype, us_variablesvar->key);
		endobjectchange(us_varaddr, us_vartype);
	}

	/* handle attribute setting */
	if (itemHit == 18)
	{
		/* initialize object to be changed */
		startobjectchange(us_varaddr, us_vartype);
		if (DiaGetControl(5) != 0)
		{
			us_pushhighlight();
			us_clearhighlightcount();
		}

		/* get new attribute string */
		newstr = DiaGetText(19);

		/* determine type of attribute */
		if (DiaGetControl(13) != 0)
		{
			/* setting new attribute */
			varname = DiaGetText(14);
			if (isanumber(newstr) == 0) newtype = VSTRING; else
			{
				newtype = VINTEGER;
				for(pp = newstr; *pp != 0; pp++) if (*pp == '.')
				{
					newtype = VFLOAT;
					break;
				}
			}
			if (DiaGetControl(15) != 0) newtype |= VISARRAY;
		} else
		{
			/* modifying existing attribute */
			which = DiaGetCurLine(12);
			if (which >= 0) varname = DiaGetScrollLine(12, which); else
				varname = "";
			newtype = us_variablesvar->type;
		}
		if (DiaGetControl(21) != 0) newtype |= VDISPLAY; else newtype &= ~VDISPLAY;
		if (DiaGetControl(22) != 0) newtype |= VCANTSET; else newtype &= ~VCANTSET;
		newtype &= ~(VCODE1 | VCODE2);
		switch (DiaGetPopupEntry(31))
		{
			case 1: newtype |= VTCL;    break;
			case 2: newtype |= VLISP;   break;
			case 3: newtype |= VJAVA;   break;
		}

		/* get proper attribute value */
		newval = (INTBIG)newstr;
		if ((newtype&(VCODE1|VCODE2)) == 0)
		{
			switch (newtype&VTYPE)
			{
				case VINTEGER:
				case VADDRESS:
				case VSHORT:
					newval = myatoi(newstr);
					break;
				case VFRACT:
					newval = atofr(newstr);
					break;
				case VFLOAT:
				case VDOUBLE:
					newval = castint((float)atof(newstr));
					break;
			}
		}

		/* set the attribute if valid */
		if (*varname != 0)
		{
			/* see if it is an array attribute */
			if (DiaGetControl(15) != 0)
			{
				/* get the array index, examine former attribute */
				which = myatoi(DiaGetText(17));
				if (which < 0) which = 0;
				var = getval(us_varaddr, us_vartype, -1, varname);
				if (var == NOVARIABLE)
				{
					/* attribute did not exist: create the array */
					newarray = emalloc(((which+1) * SIZEOFINTBIG), el_tempcluster);
					if (newarray == 0) return(0);
					for(j=0; j<=which; j++) newarray[j] = newval;
					newtype |= VISARRAY | ((which+1)<<VLENGTHSH);
					var = setval(us_varaddr, us_vartype, varname, (INTBIG)newarray, newtype);
					if (var != NOVARIABLE) var->textdescript = defaulttextdescript(NOGEOM);
					efree((char *)newarray);
				} else if (getlength(var) <= which)
				{
					/* extend existing array attribute */
					oldlen = getlength(var);
					newarray = (INTBIG *)emalloc(((which+1) * SIZEOFINTBIG), el_tempcluster);
					if (newarray == 0) return(0);
					if ((newtype&VTYPE) == VSTRING)
					{
						for(j=0; j<oldlen; j++)
							(void)allocstring((char **)&newarray[j],
								(char *)((INTBIG *)var->addr)[j], el_tempcluster);
						for(j=oldlen; j<which; j++) newarray[j] = (INTBIG)nullstr;
					} else
					{
						for(j=0; j<oldlen; j++) newarray[j] = ((INTBIG *)var->addr)[j];
						for(j=oldlen; j<which; j++) newarray[j] = 0;
					}
					newarray[which] = newval;
					newtype = (newtype & ~VLENGTH) | ((which+1)<<VLENGTHSH);
					(void)setval(us_varaddr, us_vartype, varname, (INTBIG)newarray, newtype);
					if ((newtype&VTYPE) == VSTRING)
						for(j=0; j<oldlen; j++) efree((char *)newarray[j]);
					efree((char *)newarray);
				} else
				{
					/* set a single attribute entry */
					(void)setind(us_varaddr, us_vartype, varname, which, newval);
				}
			} else
			{
				/* setting non-array or code attribute */
				var = getval(us_varaddr, us_vartype, newtype, varname);
				if (var != NOVARIABLE) descript = var->textdescript; else
					descript = defaulttextdescript(NOGEOM);
				var = setval(us_varaddr, us_vartype, varname, newval, newtype);
				if (var != NOVARIABLE) var->textdescript = descript;
			}
		}

		/* finish the change */
		if (DiaGetControl(5) != 0) (void)us_pophighlight(1);
		endobjectchange(us_varaddr, us_vartype);
	}
	DiaDoneDialog();
	return(0);
}

void us_varestablish(INTBIG addr, INTBIG type, char *thisname)
{
	INTBIG i;

	/* determine which radio button to set */
	for(i=5; i<=10; i++) DiaSetControl(i, 0);
	DiaSetControl(36, 0);
	DiaSetControl(37, 0);
	if (us_curvaraddr != 0 && addr == us_curvaraddr && type == us_curvartype)
	{
		DiaSetControl(5, 1);
		DiaSetText(29, "~");
		thisname = "";
	} else if (getcurfacet() != NONODEPROTO && addr == (INTBIG)getcurfacet() && type == VNODEPROTO)
	{
		DiaSetControl(6, 1);
		DiaSetText(29, "facet:~");
		thisname = "";
	} else if (getcurfacet() != NONODEPROTO && addr == (INTBIG)getcurfacet()->cell && type == VCELL)
	{
		DiaSetControl(7, 1);
		DiaSetText(29, "cell:~");
		thisname = "";
	} else if (addr == (INTBIG)el_curlib && type == VLIBRARY)
	{
		DiaSetControl(8, 1);
		DiaSetText(29, "lib:~");
		thisname = "";
	} else if (addr == (INTBIG)el_curtech && type == VTECHNOLOGY)
	{
		DiaSetControl(9, 1);
		DiaSetText(29, "tech:~");
		thisname = "";
	} else if (addr == (INTBIG)us_aid && type == VAID)
	{
		DiaSetControl(10, 1);
		DiaSetText(29, "aid:~");
		thisname = "";
	} else if (addr == (INTBIG)el_curwindowpart && type == VWINDOWPART)
	{
		DiaSetControl(36, 1);
		DiaSetText(29, "window:~");
		thisname = "";
	} else if (addr == (INTBIG)el_curconstraint && type == VCONSTRAINT)
	{
		DiaSetControl(37, 1);
		DiaSetText(29, "constraint:~");
		thisname = "";
	}

	if (*thisname != 0)
	{
		(void)initinfstr();
		(void)addstringtoinfstr(DiaGetText(29));
		(void)addtoinfstr('.');
		(void)addstringtoinfstr(thisname);
		DiaSetText(29, returninfstr());
	}
	us_varaddr = addr;
	us_vartype = type;
	DiaSetText(25, us_variabletypename(type));
	DiaLoadTextDialog(12, us_topofdlgvars, us_nextdlgvars, DiaNullDlogDone, 0);
	us_varidentify();
}

void us_varidentify(void)
{
	INTBIG which, aindex, type;
	REGISTER INTBIG search, language;
	char *varname, *name;
	VARIABLE retvar;

	DiaSetControl(13, 0);
	DiaSetText(14, "");
	DiaNoEditControl(14);
	DiaDimItem(15);
	DiaDimItem(31);
	DiaDimItem(18);
	DiaDimItem(20);
	DiaDimItem(21);   DiaDimItem(22);
	DiaDimItem(23);
	DiaDimItem(16);   DiaDimItem(34);   DiaDimItem(35);
	which = DiaGetCurLine(12);
	if (which < 0) return;
	varname = DiaGetScrollLine(12, which);
	search = initobjlist(us_varaddr, us_vartype, 0);
	for(;;)
	{
		name = nextobjectlist(&us_variablesvar, search);
		if (name == 0) break;
		if (strcmp(name, varname) == 0) break;
	}
	if (name == 0) return;

	type = us_variablesvar->type&VTYPE;
	if ((us_variablesvar->type&VCREF) == 0)
	{
		DiaUnDimItem(20);   DiaUnDimItem(21);   DiaUnDimItem(22);
		DiaUnDimItem(31);
	}
	if ((us_variablesvar->type&VCANTSET) == 0) DiaUnDimItem(18);
	DiaSetText(27, us_variabletypename(type));
	if ((us_variablesvar->type&VDISPLAY) != 0) DiaSetControl(21, 1); else
		DiaSetControl(21, 0);
	if ((us_variablesvar->type&VDONTSAVE) != 0) DiaSetControl(22, 1); else
		DiaSetControl(22, 0);
	language = us_variablesvar->type & (VCODE1|VCODE2);
	switch (language)
	{
		case 0:     DiaSetPopupEntry(31, 0);   break;
		case VTCL:  DiaSetPopupEntry(31, 1);   break;
		case VLISP: DiaSetPopupEntry(31, 2);   break;
		case VJAVA: DiaSetPopupEntry(31, 3);   break;
	}
	if ((us_variablesvar->type&VISARRAY) != 0)
	{
		DiaSetControl(15, 1);
		DiaUnDimItem(16);   DiaUnDimItem(34);   DiaUnDimItem(35);
		DiaSetText(17, "0");
		DiaEditControl(17);
		aindex = 0;
	} else
	{
		DiaSetControl(15, 0);
		DiaSetText(17, "");
		DiaNoEditControl(17);
		aindex = -1;
	}
	DiaSetText(19, describevariable(us_variablesvar, (INTSML)aindex, -1));
	if (language != 0)
	{
		retvar.key = us_variablesvar->key;
		retvar.type = us_variablesvar->type & ~(VCODE1|VCODE2);
		retvar.textdescript = us_variablesvar->textdescript;
		if (doquerry((char *)us_variablesvar->addr, language, retvar.type, &retvar.addr) != 0)
			retvar.addr = 0;
		DiaSetText(33, describevariable(&retvar, (INTSML)aindex, -1));
		DiaSetText(32, _("Evaluation:"));
	} else
	{
		DiaSetText(33, "");
		DiaSetText(32, "");
	}
	if (type != VUNKNOWN && type != VINTEGER && type != VADDRESS && type != VCHAR &&
		type != VSTRING && type != VFLOAT && type != VDOUBLE && type != VFRACT && type != VSHORT)
			DiaUnDimItem(23);
}

/****************************** VIEW CREATION DIALOG ******************************/

/* New view */
DIALOGITEM us_newviewdialogitems[] =
{
 /*  1 */ {0, {64,232,88,304}, BUTTON, N_("OK")},
 /*  2 */ {0, {64,16,88,88}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {8,8,24,145}, MESSAGE, N_("New view name:")},
 /*  4 */ {0, {32,8,48,145}, MESSAGE, N_("View abbreviation:")},
 /*  5 */ {0, {8,148,24,304}, EDITTEXT, ""},
 /*  6 */ {0, {32,148,48,304}, EDITTEXT, ""},
 /*  7 */ {0, {68,104,84,213}, CHECK, N_("Textual View")}
};
DIALOG us_newviewdialog = {{50,75,154,391}, N_("New View"), 0, 7, us_newviewdialogitems};

/*
 * special case for the "new view" dialog
 * New view name     = 5 (edit text)
 * View abbreviation = 6 (edit text)
 * Textual view      = 7 (check)
 */
INTSML us_newviewdlog(char *paramstart[])
{
	INTBIG itemHit;

	/* display the port dialog box */
	if (DiaInitDialog(&us_newviewdialog) != 0) return(0);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == OK && DiaValidEntry(5) && DiaValidEntry(6)) break;
		if (itemHit == 7)
		{
			DiaSetControl(itemHit, 1-DiaGetControl(itemHit));
			continue;
		}
	}

	paramstart[0] = "";
	if (itemHit != CANCEL)
	{
		(void)initinfstr();
		(void)addstringtoinfstr(DiaGetText(5));
		(void)addtoinfstr(' ');
		(void)addstringtoinfstr(DiaGetText(6));
		if (DiaGetControl(7) != 0) (void)addstringtoinfstr(_(" text"));
		paramstart[0] = returninfstr();
	}
	DiaDoneDialog();
	return(1);
}

/****************************** VISIBLE LAYERS DIALOG ******************************/

/* Layer visibility */
DIALOGITEM us_visiblelaydialogitems[] =
{
 /*  1 */ {0, {168,328,192,400}, BUTTON, N_("OK")},
 /*  2 */ {0, {168,232,192,304}, BUTTON, N_("Cancel")},
 /*  3 */ {0, {48,224,64,412}, MESSAGE, N_("Marked layers are visible.")},
 /*  4 */ {0, {32,8,208,222}, SCROLL, ""},
 /*  5 */ {0, {32,224,48,412}, MESSAGE, N_("Click to change visibility.")},
 /*  6 */ {0, {88,232,112,404}, BUTTON, N_("Make all layers visible")},
 /*  7 */ {0, {120,232,144,404}, BUTTON, N_("Make all layers invisible")},
 /*  8 */ {0, {8,8,24,82}, MESSAGE, N_("Layer set:")},
 /*  9 */ {0, {8,88,24,222}, POPUP, ""}
};
DIALOG us_visiblelaydialog = {{50,75,267,496}, N_("Layer Visibility"), 0, 9, us_visiblelaydialogitems};

/* special case for the "visiblelayers" dialog
 * Layers             = 4 (user item)
 * Make all visible   = 6 (button)
 * Make all invisible = 7 (button)
 */
#define LAYERSELEC 0		/* Electric layers */
#define LAYERSDXF  1		/* DXF layers */
#define LAYERSGDS  2		/* GDS layers */

void us_vislayerloadset(void);

void us_vislayerloadset(void)
{
	REGISTER NODEINST *ni;
	REGISTER NODEPROTO *np;
	REGISTER VARIABLE *var, *cvar;
	REGISTER INTBIG i, layerset;
	REGISTER char *lname, *entry;
	char lbuff[100], lnum[20];

	DiaLoadTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);
	layerset = DiaGetPopupEntry(9);
	switch (layerset)
	{
		case LAYERSELEC:
			for(i=0; i<el_curtech->layercount; i++)
			{
				(void)initinfstr();
				if ((el_curtech->layers[i]->colstyle&INVISIBLE) != 0) (void)addtoinfstr(' '); else
					(void)addtoinfstr('>');
				(void)addtoinfstr(' ');
				(void)addstringtoinfstr(layername(el_curtech, (INTSML)i));
				DiaStuffLine(4, returninfstr());
			}
			break;
		case LAYERSDXF:
		case LAYERSGDS:
			np = getcurfacet();
			if (np == NONODEPROTO) break;
			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
			{
				if (layerset == LAYERSDXF)
				{
					var = getval((INTBIG)ni, VNODEINST, VSTRING, "IO_dxf_layer");
					if (var == NOVARIABLE) continue;
					lname = (char *)var->addr;
				} else
				{
					var = getval((INTBIG)ni, VNODEINST, VINTEGER, "IO_gds_layer");
					if (var == NOVARIABLE) continue;
					sprintf(lnum, "%ld", var->addr);
					lname = lnum;
				}
				for(i=0; ; i++)
				{
					entry = DiaGetScrollLine(4, i);
					if (*entry == 0) break;
					if (namesame(&entry[2], lname) == 0) break;
				}
				if (*entry == 0)
				{
					cvar = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_colorkey);
					if (cvar != NOVARIABLE && cvar->addr == 0)
						sprintf(lbuff, "  %s", lname); else
							sprintf(lbuff, "> %s", lname);
					DiaStuffLine(4, lbuff);
				}
			}
			break;
	}
	DiaSelectLine(4, -1);
}

INTSML us_visiblelayersdlog(char *prompt)
{
	INTBIG itemHit, i, changes, val, layerset;
	REGISTER NODEINST *ni;
	REGISTER NODEPROTO *np;
	REGISTER VARIABLE *var;
	WINDOWPART *w;
	char *msg, *entry, *layersets[3], lnum[20], *lname;

	if (us_needwindow()) return(0);

	/* display the visibility dialog box */
	if (DiaInitDialog(&us_visiblelaydialog) != 0) return(0);
	layersets[LAYERSELEC] = _("Electric layers");
	layersets[LAYERSDXF] = _("DXF layers");
	layersets[LAYERSGDS] = _("GDS layers");
	DiaSetPopup(9, 3, layersets);
	if (namesame(prompt, "DXF") == 0) DiaSetPopupEntry(9, LAYERSDXF); else
		if (namesame(prompt, "GDS") == 0) DiaSetPopupEntry(9, LAYERSGDS);
	DiaInitTextDialog(4, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
		SCSELMOUSE|SCREPORT);
	us_vislayerloadset();

	/* loop until done */
	changes = 0;
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == OK || itemHit == CANCEL) break;
		if (itemHit == 4)
		{
			/* toggle layer visibility for this layer */
			i = DiaGetCurLine(4);
			msg = DiaGetScrollLine(4, i);
			if (*msg == ' ') *msg = '>'; else *msg = ' ';
			DiaSetScrollLine(4, i, msg);
			DiaSelectLine(4, -1);
			changes++;
			continue;
		}
		if (itemHit == 6 || itemHit == 7)
		{
			/* set visibility for all layers */
			for(i=0; ; i++)
			{
				msg = DiaGetScrollLine(4, i);
				if (*msg == 0) break;
				if (itemHit == 6) *msg = '>'; else *msg = ' ';
				DiaSetScrollLine(4, i, msg);
			}
			changes++;
			continue;
		}
		if (itemHit == 9)
		{
			/* construct new layer set */
			us_vislayerloadset();
			changes = 0;
			continue;
		}
	}

	if (itemHit != CANCEL && changes != 0)
	{
		layerset = DiaGetPopupEntry(9);
		switch (layerset)
		{
			case LAYERSELEC:
				/* save highlighting */
				us_pushhighlight();

				/* start of change to all display windows */
				for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
					if ((w->state&WINDOWTYPE) == DISPWINDOW ||
						(w->state&WINDOWTYPE) == DISP3DWINDOW)
							startobjectchange((INTBIG)w, VWINDOWPART);

				/* change the layer visibility */
				for(i=0; i<el_curtech->layercount; i++)
				{
					msg = DiaGetScrollLine(4, i);
					val = el_curtech->layers[i]->colstyle;
					if ((val&INVISIBLE) == 0 && *msg == ' ')
					{
						(void)setval((INTBIG)el_curtech->layers[i], VGRAPHICS,
							"colstyle", val | INVISIBLE, VSHORT);
					} else if ((val&INVISIBLE) != 0 && *msg != ' ')
					{
						(void)setval((INTBIG)el_curtech->layers[i], VGRAPHICS,
							"colstyle", val & ~INVISIBLE, VSHORT);
					}
				}

				/* end of change to all display windows (redraws) */
				for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
					if ((w->state&WINDOWTYPE) == DISPWINDOW ||
						(w->state&WINDOWTYPE) == DISP3DWINDOW)
							endobjectchange((INTBIG)w, VWINDOWPART);

				/* restore highlighting */
				(void)us_pophighlight(0);
				break;
			case LAYERSDXF:
			case LAYERSGDS:
				np = getcurfacet();
				if (np == NONODEPROTO) break;
				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
				{
					if (layerset == LAYERSDXF)
					{
						var = getval((INTBIG)ni, VNODEINST, VSTRING, "IO_dxf_layer");
						if (var == NOVARIABLE) continue;
						lname = (char *)var->addr;
					} else
					{
						var = getval((INTBIG)ni, VNODEINST, VINTEGER, "IO_gds_layer");
						if (var == NOVARIABLE) continue;
						sprintf(lnum, "%ld", var->addr);
						lname = lnum;
					}
					for(i=0; ; i++)
					{
						entry = DiaGetScrollLine(4, i);
						if (*entry == 0) break;
						if (namesame(&entry[2], lname) == 0) break;
					}
					if (*entry != 0)
					{
						startobjectchange((INTBIG)ni, VNODEINST);
						if (entry[0] == '>')
						{
							/* make node visible */
							var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_colorkey);
							if (var != NOVARIABLE && var->addr == 0)
								delvalkey((INTBIG)ni, VNODEINST, art_colorkey);
						} else
						{
							/* make node invisible */
							setvalkey((INTBIG)ni, VNODEINST, art_colorkey, 0, VINTEGER);
						}
						endobjectchange((INTBIG)ni, VNODEINST);
					}
				}
				break;
		}
	}
	DiaDoneDialog();
	return(0);
}

/****************************** WINDOW VIEW DIALOG ******************************/

/* Window Views */
DIALOGITEM us_windowviewdialogitems[] =
{
 /*  1 */ {0, {256,56,280,166}, BUTTON, N_("Restore View")},
 /*  2 */ {0, {216,8,240,72}, BUTTON, N_("Done")},
 /*  3 */ {0, {32,8,208,234}, SCROLL, ""},
 /*  4 */ {0, {8,96,24,229}, EDITTEXT, ""},
 /*  5 */ {0, {216,120,240,230}, BUTTON, N_("Save This View")},
 /*  6 */ {0, {8,8,24,90}, MESSAGE, N_("View name:")}
};
DIALOG us_windowviewdialog = {{50,75,342,318}, N_("Window Views"), 0, 6, us_windowviewdialogitems};

/*
 * special case for the "Window View" dialog
 * restore view     = 1 (button)
 * save view        = 5 (button)
 * view list        = 3 (scroll)
 * new view name    = 4 (edit text)
 */
INTSML us_windowviewdlog(void)
{
	INTBIG itemHit, i;
	REGISTER VARIABLE *var;
	char *par[3], *pt;

	/* display the window view dialog box */
	if (DiaInitDialog(&us_windowviewdialog) != 0) return(0);
	DiaInitTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
		SCSELMOUSE | SCSELKEY | SCDOUBLEQUIT);
	for(i=0; i<us_aid->numvar; i++)
	{
		var = &us_aid->firstvar[i];
		pt = makename(var->key);
		if (namesamen(pt, "USER_windowview_", 16) == 0) DiaStuffLine(3, &pt[16]);
	}
	DiaSelectLine(3, -1);

	/* loop until done */
	for(;;)
	{
		itemHit = DiaNextHit();
		if (itemHit == CANCEL) break;
		if (itemHit == 1)
		{
			/* restore selected view */
			par[0] = "name";
			i = DiaGetCurLine(3);
			if (i < 0) continue;
			pt = DiaGetScrollLine(3, i);
			(void)allocstring(&par[1], pt, el_tempcluster);
			break;
		}

		if (itemHit == 5)
		{
			/* save selected view */
			if (DiaValidEntry(4) == 0) continue;
			par[0] = "save";
			par[1] = DiaGetText(4);
			us_window(2, par);
			DiaLoadTextDialog(3, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
			for(i=0; i<us_aid->numvar; i++)
			{
				var = &us_aid->firstvar[i];
				pt = makename(var->key);
				if (namesamen(pt, "USER_windowview_", 16) == 0) DiaStuffLine(3, &pt[16]);
			}
			DiaSelectLine(3, -1);
			continue;
		}
	}

	DiaDoneDialog();
	if (itemHit == 1)
	{
		us_window(2, par);
		efree(par[1]);
	}
	return(0);
}

/****************************** SUPPORT ******************************/

/*
 * Routine to set the correct line selection in scroll item "scrollitem".  This item
 * has a list of facet/cell names, and the current one should be selected.  If "curinstance"
 * is nonzero, consider the currently selected facet instance (if any).  If "forcecurlib"
 * is nonzero, strip off library names when matching.  If "justcells" is nonzero, only
 * consider cell names, not facet names.
 */
NODEPROTO *us_setscrolltocurrentfacet(INTBIG scrollitem, INTSML curinstance, INTSML forcecurlib,
	INTSML justcells)
{
	REGISTER NODEPROTO *np, *enp;
	REGISTER GEOM **list;
	REGISTER char *line, *curnode, *pt;
	REGISTER NODEINST *ni;
	REGISTER VARIABLE *var;
	REGISTER INTBIG i;
	REGISTER LIBRARY *savelib;

	/* find the current node and make it the default */
	np = getcurfacet();

	/* if there is an explorer window open, use it's selection */
	enp = us_currentexplorernode();
	if (enp != NONODEPROTO) np = enp;
	if (np != NONODEPROTO)
	{
		if (justcells != 0) curnode = np->cell->cellname; else
		{
			if (forcecurlib != 0)
			{
				savelib = el_curlib;
				el_curlib = us_curlib;
			}
			curnode = describenodeproto(np);
			if (forcecurlib != 0)
				el_curlib = savelib;
		}
		if (curinstance != 0)
		{
			list = us_gethighlighted(OBJNODEINST);
			if (list[0] != NOGEOM && list[1] == NOGEOM)
			{
				if (list[0]->entrytype == OBJNODEINST)
				{
					ni = list[0]->entryaddr.ni;
					if (ni->proto->primindex == 0)
					{
						if (justcells != 0) curnode = ni->proto->cell->cellname; else
							curnode = describenodeproto(ni->proto);
					}
				}
			}
		}
		if (namesame(np->cell->cellname, "facetstructure") == 0)
		{
			list = us_gethighlighted(OBJNODEINST);
			if (list[0] != NOGEOM && list[1] == NOGEOM)
			{
				if (list[0]->entrytype == OBJNODEINST)
				{
					ni = list[0]->entryaddr.ni;
					var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
					if (var != NOVARIABLE)
					{
						curnode = (char *)var->addr;
						if (justcells != 0)
						{
							(void)initinfstr();
							for(pt = curnode; *pt != 0; pt++)
							{
								if (*pt == ';' || *pt == '{') break;
								(void)addtoinfstr(*pt);
							}
							curnode = returninfstr();
						}
					}
				}
			}
		}
		for(i=0; ; i++)
		{
			line = DiaGetScrollLine(scrollitem, i);
			if (*line == 0) break;
			if (strcmp(line, curnode) == 0)
			{
				DiaSelectLine(scrollitem, i);
				break;
			}
		}
	}
	return(np);
}
