1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrtrack.c
6  * User interface tool: cursor tracking routines
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 /*
33  * the code in this module makes me quiver with trepidation whenever it
34  * breaks ... smr
35  */
36 #include "global.h"
37 #include "egraphics.h"
38 #include "usr.h"
39 #include "usrtrack.h"
40 #include "efunction.h"
41 #include "tecart.h"
42 #include "tecgen.h"
43 #include "sim.h"
44 
45 #define MAXTRACE 400
46 #define MINSLIDEDELAY 60			/* ticks between shifts of window when dragging to edge */
47 static INTBIG us_tracelist;
48 static INTBIG us_tracedata[MAXTRACE];
49 static GRAPHICS us_highl = {LAYERH, 0, SOLIDC, SOLIDC,
50 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
51 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
52 
53 static INTBIG us_dragx, us_dragy, us_dragox, us_dragoy, us_dragoffx,
54 	us_dragoffy, us_lastcurx, us_lastcury, us_dragpoint,
55 	us_dragnodetotal, us_cantdrag, us_draglowval, us_draghighval, us_measureshown,
56 	us_firstmeasurex, us_firstmeasurey, us_dragshown, us_dragangle, us_dragstate,
57 	us_dragfport, us_dragextra, us_dragnobox, us_dragstayonhigh, us_dragstill,
58 	us_dragcorner, us_dragspecial;
59 static BOOLEAN     us_dragjoinfactor;
60 static BOOLEAN     us_multidragshowinvpin, us_multidragshowoffset;
61 static INTBIG      us_multidragmostzeros;
62 static UINTBIG     us_dragdescript[TEXTDESCRIPTSIZE];
63 static INTBIG      us_arrowamount;				/* for slider tracking */
64 static INTBIG      us_arrowlx, us_arrowhx, us_arrowly, us_arrowhy;
65 static WINDOWPART *us_dragwindow;
66 static POLYGON    *us_dragpoly = NOPOLYGON;
67 static NODEPROTO  *us_dragnodeproto;
68 static PORTPROTO  *us_dragportproto, *us_dragfromport;
69 static NODEINST   *us_dragnodeinst, **us_dragnodelist;
70 static ARCINST    *us_dragarcinst;
71 static GEOM       *us_dragobject, **us_dragobjectlist;
72 static GEOM       *us_dragfromgeom;
73 static INTBIG      us_dragaddr, us_dragtype;
74 static INTBIG      us_dragstartx, us_dragstarty;
75 static INTBIG      us_dragwirepathcount;
76 static INTBIG      us_dragwirepath[8];
77 static HIGHLIGHT   us_draghigh;
78 static CHAR        us_dragmessage[100];
79 static UINTBIG     us_beforepantime = 0;
80 static INTBIG      us_initthumbcoord;
81 static WINDOWPART  us_trackww;
82 static INTBIG      us_dragtextcount;
83 static CHAR      **us_dragtexts;
84 static void      (*us_trackingcallback)(INTBIG);
85 
86 /* prototypes for local routines */
87 static void us_finddoibegin(BOOLEAN);
88 static void us_multidragdraw(INTBIG, INTBIG, INTBIG);
89 static void us_invertstretch(void);
90 static void us_wanttoinvert(INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, WINDOWPART *w);
91 static void us_drawdistance(void);
92 static void us_panatscreenedge(INTBIG *x, INTBIG *y);
93 static void us_wanttoinvert(INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, WINDOWPART *w);
94 
95 /************************* NODE TRACE *************************/
96 
97 /* initialization routine when reading a cursor trace */
us_tracebegin(void)98 void us_tracebegin(void)
99 {
100 	us_tracelist = 0;
101 	us_highl.col = HIGHLIT;
102 }
103 
104 /* cursor advance routine when reading a cursor trace */
us_tracedown(INTBIG x,INTBIG y)105 BOOLEAN us_tracedown(INTBIG x, INTBIG y)
106 {
107 	INTBIG fx, fy, tx, ty;
108 
109 	if (us_tracelist >= MAXTRACE) return(TRUE);
110 	if (us_tracelist != 0)
111 	{
112 		fx = us_tracedata[us_tracelist-2];
113 		fy = us_tracedata[us_tracelist-1];
114 		tx = x;   ty = y;
115 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
116 		{
117 			xform(fx, fy, &fx, &fy, el_curwindowpart->outofcell);
118 			xform(tx, ty, &tx, &ty, el_curwindowpart->outofcell);
119 		}
120 		screendrawline(el_curwindowpart, fx, fy, tx, ty, &us_highl, 0);
121 	}
122 	us_tracedata[us_tracelist++] = x;
123 	us_tracedata[us_tracelist++] = y;
124 	return(FALSE);
125 }
126 
127 /* termination routine when reading a cursor trace */
us_traceup(void)128 void us_traceup(void)
129 {
130 	REGISTER INTBIG i;
131 	INTBIG fx, fy, tx, ty;
132 
133 	if (us_tracelist == 0)
134 	{
135 		(void)setval((INTBIG)us_tool, VTOOL, us_commandvarname('T'), (INTBIG)x_("nothing"),
136 			VSTRING|VDONTSAVE);
137 		return;
138 	}
139 	(void)setval((INTBIG)us_tool, VTOOL, us_commandvarname('T'), (INTBIG)us_tracedata,
140 		(INTBIG)(VINTEGER|VISARRAY|(us_tracelist<<VLENGTHSH)|VDONTSAVE));
141 	us_highl.col = 0;
142 	for(i=2; i<us_tracelist; i += 2)
143 	{
144 		fx = us_tracedata[us_tracelist-2];
145 		fy = us_tracedata[us_tracelist-1];
146 		tx = us_tracedata[us_tracelist];
147 		ty = us_tracedata[us_tracelist+1];
148 		if ((el_curwindowpart->state&INPLACEEDIT) != 0)
149 		{
150 			xform(fx, fy, &fx, &fy, el_curwindowpart->outofcell);
151 			xform(tx, ty, &tx, &ty, el_curwindowpart->outofcell);
152 		}
153 		screendrawline(el_curwindowpart, us_tracedata[i-2], us_tracedata[i-1],
154 			us_tracedata[i], us_tracedata[i+1], &us_highl, 0);
155 	}
156 }
157 
158 /* preinitialization routine when creating or moving a point on a node */
us_pointinit(NODEINST * node,INTBIG point)159 void us_pointinit(NODEINST *node, INTBIG point)
160 {
161 	us_dragnodeinst = node;
162 	us_dragpoint = point;
163 }
164 
165 /* initialization routine when creating or moving a point on a node */
us_pointbegin(void)166 void us_pointbegin(void)
167 {
168 	/* initialize polygon */
169 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
170 	us_dragpoly->desc = &us_highl;
171 
172 	us_dragshown = 0;
173 	(void)getxy(&us_dragx, &us_dragy);
174 	us_dragwindow = el_curwindowpart;
175 }
176 
177 /* initialization routine when finding and moving a point on a node */
us_findpointbegin(void)178 void us_findpointbegin(void)
179 {
180 	REGISTER VARIABLE *highvar;
181 	HIGHLIGHT newhigh;
182 
183 	/* initialize polygon */
184 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
185 	us_dragpoly->desc = &us_highl;
186 
187 	us_dragshown = 0;
188 	if (getxy(&us_dragx, &us_dragy)) return;
189 	gridalign(&us_dragx, &us_dragy, 1, el_curlib->curnodeproto);
190 	us_setcursorpos(NOWINDOWFRAME, us_dragx, us_dragy);
191 	us_dragwindow = el_curwindowpart;
192 
193 	/* select the current point on the node */
194 	highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
195 	if (highvar == NOVARIABLE) return;
196 	(void)us_makehighlight(((CHAR **)highvar->addr)[0], &newhigh);
197 	newhigh.fromport = NOPORTPROTO;
198 	newhigh.cell = getcurcell();
199 	us_setfind(&newhigh, 1, 0, 0, 0);
200 
201 	/* get the point to be moved */
202 	highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
203 	if (highvar == NOVARIABLE) return;
204 	(void)us_makehighlight(((CHAR **)highvar->addr)[0], &newhigh);
205 	us_dragpoint = newhigh.frompoint;
206 }
207 
208 /* cursor advance routine when creating a point on a node */
us_addpdown(INTBIG x,INTBIG y)209 BOOLEAN us_addpdown(INTBIG x, INTBIG y)
210 {
211 	REGISTER INTBIG p, size;
212 	REGISTER INTBIG cx, cy;
213 	XARRAY trans;
214 	REGISTER VARIABLE *var;
215 
216 	/* pan the screen if the edge was hit */
217 	us_panatscreenedge(&x, &y);
218 
219 	/* grid align the cursor value */
220 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
221 	{
222 		(void)us_setxy(us_lastcurx, us_lastcury);
223 		return(FALSE);
224 	}
225 	(void)getxy(&us_lastcurx, &us_lastcury);
226 	gridalign(&us_lastcurx, &us_lastcury, 1, el_curlib->curnodeproto);
227 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
228 
229 	/* if the lines are already being shown, erase them */
230 	if (us_dragshown != 0)
231 	{
232 		/* if it didn't actually move, go no further */
233 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
234 
235 		/* undraw the box */
236 		us_highl.col = 0;
237 		us_showpoly(us_dragpoly, us_dragwindow);
238 	}
239 
240 	makerot(us_dragnodeinst, trans);
241 	var = gettrace(us_dragnodeinst);
242 	if (var == NOVARIABLE)
243 	{
244 		us_dragpoly->xv[0] = us_lastcurx;
245 		us_dragpoly->yv[0] = us_lastcury;
246 		us_dragpoly->count = 1;
247 		us_dragpoly->style = CROSS;
248 	} else
249 	{
250 		size = getlength(var) / 2;
251 		cx = (us_dragnodeinst->lowx + us_dragnodeinst->highx) / 2;
252 		cy = (us_dragnodeinst->lowy + us_dragnodeinst->highy) / 2;
253 		p = 0;
254 		if (us_dragpoint > 0 && us_dragpoint <= size)
255 		{
256 			xform(((INTBIG *)var->addr)[(us_dragpoint-1)*2] + cx,
257 				((INTBIG *)var->addr)[(us_dragpoint-1)*2+1] + cy,
258 					&us_dragpoly->xv[p], &us_dragpoly->yv[p], trans);
259 			p++;
260 		}
261 		us_dragpoly->xv[p] = us_lastcurx;
262 		us_dragpoly->yv[p] = us_lastcury;
263 		p++;
264 		if (us_dragpoint < size)
265 		{
266 			xform(((INTBIG *)var->addr)[us_dragpoint*2] + cx,
267 				((INTBIG *)var->addr)[us_dragpoint*2+1] + cy,
268 					&us_dragpoly->xv[p], &us_dragpoly->yv[p], trans);
269 			p++;
270 		}
271 		us_dragpoly->count = p;
272 		us_dragpoly->style = OPENED;
273 	}
274 
275 	us_dragx = us_lastcurx;
276 	us_dragy = us_lastcury;
277 
278 	/* draw the new box */
279 	us_highl.col = HIGHLIT;
280 	us_showpoly(us_dragpoly, us_dragwindow);
281 	us_dragshown = 1;
282 	return(FALSE);
283 }
284 
285 /* cursor advance routine when moving a point on a node */
us_movepdown(INTBIG x,INTBIG y)286 BOOLEAN us_movepdown(INTBIG x, INTBIG y)
287 {
288 	REGISTER INTBIG p, size;
289 	REGISTER INTBIG cx, cy;
290 	XARRAY trans;
291 	REGISTER VARIABLE *var;
292 
293 	/* pan the screen if the edge was hit */
294 	us_panatscreenedge(&x, &y);
295 
296 	/* grid align the cursor value */
297 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
298 	{
299 		(void)us_setxy(us_lastcurx, us_lastcury);
300 		return(FALSE);
301 	}
302 	(void)getxy(&us_lastcurx, &us_lastcury);
303 	gridalign(&us_lastcurx, &us_lastcury, 1, el_curlib->curnodeproto);
304 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
305 
306 	/* if the lines are already being shown, erase them */
307 	if (us_dragshown != 0)
308 	{
309 		/* if it didn't actually move, go no further */
310 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
311 
312 		/* undraw the box */
313 		us_highl.col = 0;
314 		us_showpoly(us_dragpoly, us_dragwindow);
315 	}
316 
317 	makerot(us_dragnodeinst, trans);
318 	var = gettrace(us_dragnodeinst);
319 	if (var == NOVARIABLE) return(FALSE);
320 
321 	size = getlength(var) / 2;
322 	cx = (us_dragnodeinst->lowx + us_dragnodeinst->highx) / 2;
323 	cy = (us_dragnodeinst->lowy + us_dragnodeinst->highy) / 2;
324 	p = 0;
325 	if (us_dragpoint > 1)
326 	{
327 		xform(((INTBIG *)var->addr)[(us_dragpoint-2)*2] + cx,
328 			((INTBIG *)var->addr)[(us_dragpoint-2)*2+1] + cy,
329 				&us_dragpoly->xv[p], &us_dragpoly->yv[p], trans);
330 		p++;
331 	}
332 	us_dragpoly->xv[p] = us_lastcurx;
333 	us_dragpoly->yv[p] = us_lastcury;
334 	p++;
335 	if (us_dragpoint < size)
336 	{
337 		xform(((INTBIG *)var->addr)[us_dragpoint*2] + cx,
338 			((INTBIG *)var->addr)[us_dragpoint*2+1] + cy,
339 				&us_dragpoly->xv[p], &us_dragpoly->yv[p], trans);
340 		p++;
341 	}
342 	us_dragpoly->count = p;
343 	us_dragpoly->style = OPENED;
344 
345 	us_dragx = us_lastcurx;
346 	us_dragy = us_lastcury;
347 
348 	/* draw the new box */
349 	us_highl.col = HIGHLIT;
350 	us_showpoly(us_dragpoly, us_dragwindow);
351 	us_dragshown = 1;
352 	return(FALSE);
353 }
354 
355 /************************* ARC CURVATURE *************************/
356 
357 /* initialization routine when changing an arc's curvature */
us_arccurveinit(ARCINST * ai)358 void us_arccurveinit(ARCINST *ai)
359 {
360 	us_dragarcinst = ai;
361 	us_dragwindow = el_curwindowpart;
362 }
363 
364 /*
365  * Routine for changing the curvature of an arc so that it pass through (x,y)
366  */
us_arccurvedown(INTBIG x,INTBIG y)367 BOOLEAN us_arccurvedown(INTBIG x, INTBIG y)
368 {
369 	INTBIG xcur, ycur, r;
370 
371 	/* grid align the cursor value */
372 	if (us_dragwindow != el_curwindowpart) return(FALSE);
373 	if (us_setxy(x, y)) return(FALSE);
374 	(void)getxy(&xcur, &ycur);
375 
376 	/* get radius that lets arc curve through this point */
377 	r = us_curvearcthroughpoint(us_dragarcinst, xcur, ycur);
378 
379 	startobjectchange((INTBIG)us_dragarcinst, VARCINST);
380 	(void)setvalkey((INTBIG)us_dragarcinst, VARCINST, el_arc_radius_key, r, VINTEGER);
381 	(void)modifyarcinst(us_dragarcinst, 0, 0, 0, 0, 0);
382 	endobjectchange((INTBIG)us_dragarcinst, VARCINST);
383 	us_endchanges(NOWINDOWPART);
384 	return(FALSE);
385 }
386 
387 /*
388  * Routine for changing the curvature of an arc so that it curves around (x,y)
389  * (that coordinate is the center)
390  */
us_arccenterdown(INTBIG x,INTBIG y)391 BOOLEAN us_arccenterdown(INTBIG x, INTBIG y)
392 {
393 	INTBIG xcur, ycur;
394 	REGISTER INTBIG r;
395 
396 	/* grid align the cursor value */
397 	if (us_dragwindow != el_curwindowpart) return(FALSE);
398 	if (us_setxy(x, y)) return(FALSE);
399 	(void)getxy(&xcur, &ycur);
400 
401 	/* get radius that lets arc curve about this point */
402 	r = us_curvearcaboutpoint(us_dragarcinst, xcur, ycur);
403 
404 	startobjectchange((INTBIG)us_dragarcinst, VARCINST);
405 	(void)setvalkey((INTBIG)us_dragarcinst, VARCINST, el_arc_radius_key, r, VINTEGER);
406 	(void)modifyarcinst(us_dragarcinst, 0, 0, 0, 0, 0);
407 	endobjectchange((INTBIG)us_dragarcinst, VARCINST);
408 	us_endchanges(NOWINDOWPART);
409 	return(FALSE);
410 }
411 
412 /************************* TEXT GRAB-POINT *************************/
413 
414 /* preinitialization routine when positioning text's grab point */
us_textgrabinit(UINTBIG * olddescript,INTBIG xw,INTBIG yw,INTBIG xc,INTBIG yc,GEOM * geom)415 void us_textgrabinit(UINTBIG *olddescript, INTBIG xw, INTBIG yw, INTBIG xc, INTBIG yc,
416 	GEOM *geom)
417 {
418 	/* save text extent information */
419 	TDCOPY(us_dragdescript, olddescript);
420 	us_dragx = xc;          us_dragy = yc;
421 	us_dragox = xw;         us_dragoy = yw;
422 	us_dragobject = geom;
423 }
424 
425 /* initialization routine when positioning text's grab-point */
us_textgrabbegin(void)426 void us_textgrabbegin(void)
427 {
428 	/* initialize polygon */
429 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
430 	us_dragpoly->desc = &us_highl;
431 
432 	us_dragshown = 0;
433 	us_dragwindow = el_curwindowpart;
434 }
435 
436 /* cursor advance routine when positioning text's grab-point */
us_textgrabdown(INTBIG x,INTBIG y)437 BOOLEAN us_textgrabdown(INTBIG x, INTBIG y)
438 {
439 	UINTBIG descript[TEXTDESCRIPTSIZE];
440 	REGISTER INTBIG style;
441 	REGISTER NODEINST *ni;
442 	XARRAY trans;
443 
444 	/* get the cursor value */
445 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
446 	{
447 		(void)us_setxy(us_lastcurx, us_lastcury);
448 		return(FALSE);
449 	}
450 	(void)getxy(&us_lastcurx, &us_lastcury);
451 
452 	/* if the box is already being shown, erase it */
453 	if (us_dragshown != 0)
454 	{
455 		/* undraw the box */
456 		us_highl.col = 0;
457 		us_showpoly(us_dragpoly, us_dragwindow);
458 	}
459 
460 	/* convert the cursor position into a text descriptor */
461 	TDCOPY(descript, us_dragdescript);
462 	us_figuregrabpoint(descript, us_lastcurx, us_lastcury,
463 		us_dragx, us_dragy, us_dragox, us_dragoy);
464 	us_rotatedescriptI(us_dragobject, descript);
465 
466 	/* convert the text descriptor into a GRAPHICS style */
467 	switch (TDGETPOS(descript))
468 	{
469 		case VTPOSCENT:      style = TEXTCENT;      break;
470 		case VTPOSBOXED:     style = TEXTBOX;       break;
471 		case VTPOSUP:        style = TEXTBOT;       break;
472 		case VTPOSDOWN:      style = TEXTTOP;       break;
473 		case VTPOSLEFT:      style = TEXTRIGHT;     break;
474 		case VTPOSRIGHT:     style = TEXTLEFT;      break;
475 		case VTPOSUPLEFT:    style = TEXTBOTRIGHT;  break;
476 		case VTPOSUPRIGHT:   style = TEXTBOTLEFT;   break;
477 		case VTPOSDOWNLEFT:  style = TEXTTOPRIGHT;  break;
478 		case VTPOSDOWNRIGHT: style = TEXTTOPLEFT;   break;
479 	}
480 	if (us_dragobject->entryisnode)
481 	{
482 		ni = us_dragobject->entryaddr.ni;
483 		makeangle(ni->rotation, ni->transpose, trans);
484 		style = rotatelabel(style, TDGETROTATION(descript), trans);
485 	}
486 
487 	/* convert the text descriptor into a POLYGON */
488 	us_buildtexthighpoly(us_dragobject->lowx, us_dragobject->highx,
489 		us_dragobject->lowy, us_dragobject->highy, us_dragx, us_dragy, us_dragox, us_dragoy,
490 			style, us_dragpoly);
491 
492 	/* draw the new box */
493 	us_highl.col = HIGHLIT;
494 	us_showpoly(us_dragpoly, us_dragwindow);
495 	us_dragshown = 1;
496 	return(FALSE);
497 }
498 
499 /************************* ROTATE *************************/
500 
501 /* preinitialization routine when rotating a node */
us_rotateinit(NODEINST * node)502 void us_rotateinit(NODEINST *node)
503 {
504 	us_dragnodeinst = node;
505 }
506 
507 /* initialization routine when rotating a node */
us_rotatebegin(void)508 void us_rotatebegin(void)
509 {
510 	/* initialize polygon */
511 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
512 	us_dragpoly->desc = &us_highl;
513 
514 	(void)getxy(&us_dragx, &us_dragy);
515 	us_dragshown = 0;
516 	us_dragwindow = el_curwindowpart;
517 	us_dragangle = figureangle((us_dragnodeinst->lowx+us_dragnodeinst->highx)/2,
518 		(us_dragnodeinst->lowy+us_dragnodeinst->highy)/2, us_dragx, us_dragy);
519 }
520 
521 /* cursor advance routine when rotating the current node */
us_rotatedown(INTBIG x,INTBIG y)522 BOOLEAN us_rotatedown(INTBIG x, INTBIG y)
523 {
524 	REGISTER INTBIG lx, hx, ly, hy;
525 	REGISTER INTBIG newangle;
526 	REGISTER INTSML saver, savet;
527 	XARRAY trans;
528 	INTBIG xl, yl, xh, yh;
529 
530 	/* grid align the cursor value */
531 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
532 	{
533 		(void)us_setxy(us_lastcurx, us_lastcury);
534 		return(FALSE);
535 	}
536 	(void)getxy(&us_lastcurx, &us_lastcury);
537 
538 	/* if the box is already being shown, erase it */
539 	if (us_dragshown != 0)
540 	{
541 		/* undraw the box */
542 		us_highl.col = 0;
543 		us_showpoly(us_dragpoly, us_dragwindow);
544 	}
545 
546 	/* compute new angle from node center to cursor */
547 	newangle = figureangle((us_dragnodeinst->lowx+us_dragnodeinst->highx)/2,
548 		(us_dragnodeinst->lowy+us_dragnodeinst->highy)/2, us_lastcurx, us_lastcury);
549 
550 	/* compute highlighted box about node */
551 	nodesizeoffset(us_dragnodeinst, &xl, &yl, &xh, &yh);
552 	lx = us_dragnodeinst->lowx+xl;   hx = us_dragnodeinst->highx-xh;
553 	ly = us_dragnodeinst->lowy+yl;   hy = us_dragnodeinst->highy-yh;
554 	makerot(us_dragnodeinst, trans);
555 	maketruerectpoly(lx, hx, ly, hy, us_dragpoly);
556 	us_dragpoly->style = CLOSEDRECT;
557 	xformpoly(us_dragpoly, trans);
558 
559 	/* rotate this box according to the cursor */
560 	saver = us_dragnodeinst->rotation;
561 	savet = us_dragnodeinst->transpose;
562 	us_dragnodeinst->transpose = 0;
563 	us_dragnodeinst->rotation = (INTSML)(newangle-us_dragangle);
564 	while (us_dragnodeinst->rotation < 0) us_dragnodeinst->rotation += 3600;
565 	while (us_dragnodeinst->rotation > 3600) us_dragnodeinst->rotation -= 3600;
566 	makerot(us_dragnodeinst, trans);
567 	xformpoly(us_dragpoly, trans);
568 	us_dragnodeinst->rotation = saver;
569 	us_dragnodeinst->transpose = savet;
570 
571 	/* draw the new box */
572 	us_highl.col = HIGHLIT;
573 	us_showpoly(us_dragpoly, us_dragwindow);
574 	us_dragshown = 1;
575 	return(FALSE);
576 }
577 
578 /************************* SIZE *************************/
579 
580 /* preinitialization routine when changing the size of a node */
us_sizeinit(NODEINST * node)581 void us_sizeinit(NODEINST *node)
582 {
583 	/* initialize polygon */
584 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
585 	us_dragpoly->desc = &us_highl;
586 	us_dragnodeinst = node;
587 	us_dragshown = 0;
588 	us_dragwindow = el_curwindowpart;
589 	us_dragcorner = -1;
590 }
591 
us_sizeterm(void)592 INTBIG us_sizeterm(void)
593 {
594 	return(us_dragcorner);
595 }
596 
597 /* preinitialization routine when changing the size of an arc */
us_sizeainit(ARCINST * arc)598 void us_sizeainit(ARCINST *arc)
599 {
600 	us_dragarcinst = arc;
601 }
602 
603 /* initialization routine when changing the size of an arc */
us_sizeabegin(void)604 void us_sizeabegin(void)
605 {
606 	/* initialize polygon */
607 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
608 	us_dragpoly->desc = &us_highl;
609 
610 	us_dragshown = 0;
611 	us_dragwindow = el_curwindowpart;
612 }
613 
614 /* cursor advance routine when stretching the current arc */
us_sizeadown(INTBIG x,INTBIG y)615 BOOLEAN us_sizeadown(INTBIG x, INTBIG y)
616 {
617 	REGISTER INTBIG wid;
618 
619 	/* pan the screen if the edge was hit */
620 	us_panatscreenedge(&x, &y);
621 
622 	/* grid align the cursor value */
623 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
624 	{
625 		(void)us_setxy(us_lastcurx, us_lastcury);
626 		return(FALSE);
627 	}
628 	(void)getxy(&us_lastcurx, &us_lastcury);
629 	gridalign(&us_lastcurx, &us_lastcury, 2, el_curlib->curnodeproto);
630 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
631 
632 	/* if the box is already being shown, erase it */
633 	if (us_dragshown != 0)
634 	{
635 		/* if it didn't actually move, go no further */
636 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
637 
638 		/* undraw the box */
639 		us_highl.col = 0;
640 		us_showpoly(us_dragpoly, us_dragwindow);
641 	}
642 
643 	/* compute new size of the arcinst */
644 	if (us_dragarcinst->end[0].xpos == us_dragarcinst->end[1].xpos)
645 		wid = abs(us_lastcurx - us_dragarcinst->end[0].xpos) * 2; else
646 			wid = abs(us_lastcury - us_dragarcinst->end[0].ypos) * 2;
647 	makearcpoly(us_dragarcinst->length, wid, us_dragarcinst, us_dragpoly, CLOSED);
648 	us_dragx = us_lastcurx;
649 	us_dragy = us_lastcury;
650 
651 	/* draw the new box */
652 	us_highl.col = HIGHLIT;
653 	us_showpoly(us_dragpoly, us_dragwindow);
654 	us_dragshown = 1;
655 	return(FALSE);
656 }
657 
658 /* cursor advance routine when stretching the current node about far corner */
us_sizedown(INTBIG x,INTBIG y)659 BOOLEAN us_sizedown(INTBIG x, INTBIG y)
660 {
661 	REGISTER INTBIG lx, hx, ly, hy, otherx, othery, dist, bestdist;
662 	INTBIG xl, xh, yl, yh, rx, ry;
663 	REGISTER INTBIG corner, bits;
664 	XARRAY trans;
665 
666 	/* pan the screen if the edge was hit */
667 	us_panatscreenedge(&x, &y);
668 
669 	/* grid align the cursor value */
670 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
671 	{
672 		(void)us_setxy(us_lastcurx, us_lastcury);
673 		return(FALSE);
674 	}
675 	(void)getxy(&us_lastcurx, &us_lastcury);
676 	gridalign(&us_lastcurx, &us_lastcury, 1, el_curlib->curnodeproto);
677 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
678 
679 	/* if the box is already being shown, erase it */
680 	if (us_dragshown != 0)
681 	{
682 		/* if it didn't actually move, go no further */
683 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
684 
685 		/* undraw the box */
686 		us_highl.col = 0;
687 		us_showpoly(us_dragpoly, us_dragwindow);
688 	}
689 
690 	nodesizeoffset(us_dragnodeinst, &xl, &yl, &xh, &yh);
691 	lx = us_dragnodeinst->lowx+xl;   hx = us_dragnodeinst->highx-xh;
692 	ly = us_dragnodeinst->lowy+yl;   hy = us_dragnodeinst->highy-yh;
693 	makerot(us_dragnodeinst, trans);
694 
695 	/* determine which corner is fixed by finding farthest from cursor */
696 	corner = us_dragcorner;
697 	if (corner < 0)
698 	{
699 		xform(lx, ly, &rx, &ry, trans);
700 		bestdist = abs(rx - us_lastcurx) + abs(ry - us_lastcury);
701 		corner = 1;	/* lower-left */
702 		xform(hx, ly, &rx, &ry, trans);
703 		dist = abs(rx - us_lastcurx) + abs(ry - us_lastcury);
704 		if (dist < bestdist)
705 		{
706 			bestdist = dist;   corner = 2;	/* lower-right */
707 		}
708 		xform(lx, hy, &rx, &ry, trans);
709 		dist = abs(rx - us_lastcurx) + abs(ry - us_lastcury);
710 		if (dist < bestdist)
711 		{
712 			bestdist = dist;   corner = 3;	/* upper-left */
713 		}
714 		xform(hx, hy, &rx, &ry, trans);
715 		dist = abs(rx - us_lastcurx) + abs(ry - us_lastcury);
716 		if (dist < bestdist) corner = 4;	/* upper-right */
717 		if (us_dragcorner < 0) us_dragcorner = corner;
718 	}
719 
720 	bits = getbuckybits();
721 	switch (corner)
722 	{
723 		case 1:		/* lower-left */
724 			otherx = hx;   othery = hy;
725 			if ((bits&CONTROLDOWN) != 0)
726 			{
727 				xform(lx, ly, &rx, &ry, trans);
728 				if (abs(rx-us_lastcurx) < abs(ry-us_lastcury)) us_lastcurx = rx; else
729 					us_lastcury = ry;
730 			}
731 			break;
732 		case 2:		/* lower-right */
733 			otherx = lx;   othery = hy;
734 			if ((bits&CONTROLDOWN) != 0)
735 			{
736 				xform(hx, ly, &rx, &ry, trans);
737 				if (abs(rx-us_lastcurx) < abs(ry-us_lastcury)) us_lastcurx = rx; else
738 					us_lastcury = ry;
739 			}
740 			break;
741 		case 3:		/* upper-left */
742 			otherx = hx;   othery = ly;
743 			if ((bits&CONTROLDOWN) != 0)
744 			{
745 				xform(lx, hy, &rx, &ry, trans);
746 				if (abs(rx-us_lastcurx) < abs(ry-us_lastcury)) us_lastcurx = rx; else
747 					us_lastcury = ry;
748 			}
749 			break;
750 		case 4:		/* upper-right */
751 			otherx = lx;   othery = ly;
752 			if ((bits&CONTROLDOWN) != 0)
753 			{
754 				xform(hx, hy, &rx, &ry, trans);
755 				if (abs(rx-us_lastcurx) < abs(ry-us_lastcury)) us_lastcurx = rx; else
756 					us_lastcury = ry;
757 			}
758 			break;
759 	}
760 	xform(otherx, othery, &rx, &ry, trans);
761 	maketruerectpoly(mini(rx, us_lastcurx), maxi(rx, us_lastcurx),
762 		mini(ry, us_lastcury), maxi(ry, us_lastcury), us_dragpoly);
763 	us_dragpoly->style = CLOSEDRECT;
764 	us_dragx = us_lastcurx;
765 	us_dragy = us_lastcury;
766 
767 	/* draw the new box */
768 	us_highl.col = HIGHLIT;
769 	us_showpoly(us_dragpoly, us_dragwindow);
770 	us_dragshown = 1;
771 	return(FALSE);
772 }
773 
774 /* cursor advance routine when stretching the current node about center */
us_sizecdown(INTBIG x,INTBIG y)775 BOOLEAN us_sizecdown(INTBIG x, INTBIG y)
776 {
777 	REGISTER INTBIG dx, dy, cx, cy;
778 
779 	/* pan the screen if the edge was hit */
780 	us_panatscreenedge(&x, &y);
781 
782 	/* grid align the cursor value */
783 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
784 	{
785 		(void)us_setxy(us_lastcurx, us_lastcury);
786 		return(FALSE);
787 	}
788 	(void)getxy(&us_lastcurx, &us_lastcury);
789 	gridalign(&us_lastcurx, &us_lastcury, 2, el_curlib->curnodeproto);
790 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
791 
792 	/* if the box is already being shown, erase it */
793 	if (us_dragshown != 0)
794 	{
795 		/* if it didn't actually move, go no further */
796 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
797 
798 		/* undraw the box */
799 		us_highl.col = 0;
800 		us_showpoly(us_dragpoly, us_dragwindow);
801 	}
802 
803 	/* compute new size of the nodeinst */
804 	cx = (us_dragnodeinst->lowx+us_dragnodeinst->highx) / 2;
805 	cy = (us_dragnodeinst->lowy+us_dragnodeinst->highy) / 2;
806 	dx = abs(cx - us_lastcurx);
807 	dy = abs(cy - us_lastcury);
808 
809 	maketruerectpoly(cx-dx, cx+dx, cy-dy, cy+dy, us_dragpoly);
810 	us_dragpoly->style = CLOSEDRECT;
811 	us_dragx = us_lastcurx;
812 	us_dragy = us_lastcury;
813 
814 	/* draw the new box */
815 	us_highl.col = HIGHLIT;
816 	us_showpoly(us_dragpoly, us_dragwindow);
817 	us_dragshown = 1;
818 	return(FALSE);
819 }
820 
821 /************************* FIND AREA *************************/
822 
823 /* pre-initialization routine when doing "find area-XXXX" */
us_findinit(INTBIG sizex,INTBIG sizey)824 void us_findinit(INTBIG sizex, INTBIG sizey)
825 {
826 	us_dragox = sizex;
827 	us_dragoy = sizey;
828 }
829 
830 /* initialization routine when doing "find area-move" */
us_findmbegin(void)831 void us_findmbegin(void)
832 {
833 	INTBIG xcur, ycur;
834 
835 	/* initialize polygon */
836 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
837 	us_dragpoly->desc = &us_highl;
838 
839 	us_dragshown = 0;
840 	(void)getxy(&xcur, &ycur);
841 	maketruerectpoly(xcur, xcur+us_dragox, ycur, ycur+us_dragoy, us_dragpoly);
842 	us_dragpoly->style = CLOSEDRECT;
843 	us_dragx = xcur;   us_dragy = ycur;
844 	us_dragwindow = el_curwindowpart;
845 }
846 
847 /* initialization routine when doing "find area-size" */
us_findsbegin(void)848 void us_findsbegin(void)
849 {
850 	INTBIG xcur, ycur;
851 
852 	/* initialize polygon */
853 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
854 	us_dragpoly->desc = &us_highl;
855 
856 	us_dragshown = 0;
857 	(void)getxy(&xcur, &ycur);
858 	maketruerectpoly(us_dragox, xcur, us_dragoy, ycur, us_dragpoly);
859 	us_dragpoly->style = CLOSEDRECT;
860 	us_dragx = xcur;   us_dragy = ycur;
861 	us_dragwindow = el_curwindowpart;
862 }
863 
864 /* initialization routine when doing "find area-define" */
us_finddbegin(void)865 void us_finddbegin(void)
866 {
867 	INTBIG xcur, ycur;
868 
869 	/* initialize polygon */
870 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
871 	us_dragpoly->desc = &us_highl;
872 
873 	us_dragshown = 0;
874 	(void)getxy(&xcur, &ycur);
875 	us_setcursorpos(NOWINDOWFRAME, xcur, ycur);
876 	us_dragox = xcur;
877 	us_dragoy = ycur;
878 	maketruerectpoly(us_dragox, xcur, us_dragoy, ycur, us_dragpoly);
879 	us_dragpoly->style = CLOSEDRECT;
880 	us_dragx = xcur;   us_dragy = ycur;
881 	us_dragwindow = el_curwindowpart;
882 }
883 
884 /* posttermination routine when doing "find area-define" */
us_finddterm(INTBIG * x,INTBIG * y)885 void us_finddterm(INTBIG *x, INTBIG *y)
886 {
887 	*x = us_dragox;
888 	*y = us_dragoy;
889 }
890 
891 /************************* FIND INTERACTIVE *************************/
892 
us_findiinit(INTBIG findport,INTBIG extrainfo,INTBIG findangle,INTBIG stayonhighlighted,INTBIG findstill,INTBIG findnobox,INTBIG findspecial)893 void us_findiinit(INTBIG findport, INTBIG extrainfo, INTBIG findangle, INTBIG stayonhighlighted,
894 	INTBIG findstill, INTBIG findnobox, INTBIG findspecial)
895 {
896 	us_dragfport = findport;
897 	us_dragextra = (extrainfo != 0 ? 1 : 0);
898 	us_dragangle = findangle;
899 	us_dragstill = findstill;
900 	us_dragnobox = findnobox;
901 	us_dragspecial = findspecial;
902 	us_dragpoint = -1;
903 	us_dragstayonhigh = stayonhighlighted;
904 }
905 
us_findcibegin(void)906 void us_findcibegin(void)
907 {
908 	us_finddoibegin(TRUE);
909 }
910 
us_findibegin(void)911 void us_findibegin(void)
912 {
913 	us_finddoibegin(FALSE);
914 }
915 
916 static UINTBIG us_initialtime, us_motiondelayafterselection;
917 
us_finddoibegin(BOOLEAN complement)918 void us_finddoibegin(BOOLEAN complement)
919 {
920 	REGISTER VARIABLE *highvar;
921 	REGISTER NODEINST *ni;
922 	REGISTER PORTPROTO *pp;
923 	REGISTER VARIABLE *var;
924 	REGISTER INTBIG len, another;
925 	HIGHLIGHT newhigh, oldhigh;
926 	INTBIG i;
927 	INTBIG xcur, ycur, dist, bestdist;
928 
929 	/* remember initial time of this action */
930 	us_initialtime = ticktime();
931 	var = getvalkey((INTBIG)us_tool, VTOOL, VFRACT, us_motiondelaykey);
932 	if (var == NOVARIABLE) us_motiondelayafterselection = 30; else
933 		us_motiondelayafterselection = var->addr * 30 / WHOLE;
934 
935 	/* initialize polygon */
936 	(void)needstaticpolygon(&us_dragpoly, 4, us_tool->cluster);
937 	us_dragpoly->desc = &us_highl;
938 	us_dragstate = -1;
939 	us_dragshown = 0;
940 	us_dragtextcount = 0;
941 	us_dragwindow = el_curwindowpart;
942 
943 	/* get cursor coordinates */
944 	if (getxy(&xcur, &ycur)) return;
945 	us_dragx = xcur;   us_dragy = ycur;
946 	us_dragox = us_dragx;   us_dragoy = us_dragy;
947 	us_dragnodeproto = getcurcell();
948 
949 	/* see what is highlighted */
950 	highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
951 	if (highvar != NOVARIABLE)
952 	{
953 		len = getlength(highvar);
954 		(void)us_makehighlight(((CHAR **)highvar->addr)[0], &newhigh);
955 	} else
956 	{
957 		len = 0;
958 		newhigh.status = 0;
959 		newhigh.fromgeom = NOGEOM;
960 		newhigh.fromport = NOPORTPROTO;
961 		newhigh.fromvar = NOVARIABLE;
962 		newhigh.fromvarnoeval = NOVARIABLE;
963 		newhigh.frompoint = 0;
964 	}
965 
966 	/* see what is under the cursor */
967 	if (us_dragstayonhigh != 0 && highvar != NOVARIABLE)
968 	{
969 		/* see if the cursor is over something highlighted */
970 		for(i=0; i<len; i++)
971 		{
972 			(void)us_makehighlight(((CHAR **)highvar->addr)[i], &oldhigh);
973 			if (us_cursoroverhigh(&oldhigh, xcur, ycur, el_curwindowpart)) break;
974 		}
975 		if (i < len)
976 		{
977 			/* re-find the closest port when one node is selected */
978 			(void)us_makehighlight(((CHAR **)highvar->addr)[i], &newhigh);
979 			if (len == 1 && (newhigh.status&HIGHFROM) != 0 &&
980 				newhigh.fromgeom->entryisnode)
981 			{
982 				ni = newhigh.fromgeom->entryaddr.ni;
983 				newhigh.fromport = NOPORTPROTO;
984 				for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
985 				{
986 					shapeportpoly(ni, pp, us_dragpoly, FALSE);
987 					us_dragpoly->desc = &us_highl;
988 
989 					/* get distance of desired point to polygon */
990 					dist = polydistance(us_dragpoly, xcur, ycur);
991 					if (dist < 0)
992 					{
993 						newhigh.fromport = pp;
994 						break;
995 					}
996 					if (newhigh.fromport == NOPORTPROTO) bestdist = dist;
997 					if (dist > bestdist) continue;
998 					bestdist = dist;   newhigh.fromport = pp;
999 				}
1000 			}
1001 		} else
1002 		{
1003 			/* control NOT held, nothing under cursor */
1004 			us_findobject(xcur, ycur, el_curwindowpart, &newhigh, 0, 0, us_dragfport, 1, us_dragspecial);
1005 		}
1006 	} else
1007 	{
1008 		another = 0;
1009 		if (complement)
1010 		{
1011 			/* control-shift held or nothing highlighted and shift held */
1012 			if (len > 0)
1013 			{
1014 				for(i=0; i<len; i++)
1015 				{
1016 					(void)us_makehighlight(((CHAR **)highvar->addr)[i], &newhigh);
1017 					if (us_cursoroverhigh(&newhigh, xcur, ycur, el_curwindowpart)) break;
1018 				}
1019 				if (i < len)
1020 				{
1021 					/* remove current highlight, find another */
1022 					another = 1;
1023 					us_delhighlight(&newhigh);
1024 					highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1025 					if (highvar == NOVARIABLE) len = 0; else
1026 						len = getlength(highvar);
1027 				}
1028 				us_findobject(xcur, ycur, el_curwindowpart, &newhigh, 0, another, us_dragfport,
1029 					1, us_dragspecial);
1030 			}
1031 		} else
1032 		{
1033 			/* control held or nothing highlighted */
1034 			us_findobject(xcur, ycur, el_curwindowpart, &newhigh, 0, another, us_dragfport,
1035 				1, us_dragspecial);
1036 		}
1037 	}
1038 	if (newhigh.status == 0)
1039 	{
1040 		/* nothing under cursor: select an area */
1041 		if (complement) us_dragstate = 2; else us_dragstate = 1;
1042 		maketruerectpoly(us_dragx, us_dragx, us_dragy, us_dragy, us_dragpoly);
1043 		us_dragpoly->style = CLOSEDRECT;
1044 		return;
1045 	}
1046 
1047 	/* grid the cursor coordinates when over something */
1048 	gridalign(&us_dragx, &us_dragy, 1, us_dragnodeproto);
1049 	us_setcursorpos(NOWINDOWFRAME, us_dragx, us_dragy);
1050 	us_dragox = us_dragx;   us_dragoy = us_dragy;
1051 
1052 	/* clear port info if not requested or multiple highlights */
1053 	if (us_dragfport == 0) newhigh.fromport = NOPORTPROTO;
1054 
1055 	/* do not show invisible pins (text on them is shown separately) */
1056 	us_multidragshowinvpin = FALSE;
1057 
1058 	/* see if object under cursor is already highlighted */
1059 	for(i=0; i<len; i++)
1060 	{
1061 		if (us_makehighlight(((CHAR **)highvar->addr)[i], &oldhigh)) continue;
1062 		if (oldhigh.cell != newhigh.cell) continue;
1063 		if ((oldhigh.status&HIGHTYPE) != (newhigh.status&HIGHTYPE)) continue;
1064 		if (oldhigh.fromgeom != newhigh.fromgeom) continue;
1065 		if ((oldhigh.status&HIGHTYPE) == HIGHTEXT)
1066 		{
1067 			if (oldhigh.fromvar != newhigh.fromvar) continue;
1068 			if (oldhigh.fromport != NOPORTPROTO && newhigh.fromport != NOPORTPROTO &&
1069 				oldhigh.fromport != newhigh.fromport) continue;
1070 		}
1071 		break;
1072 	}
1073 
1074 	/* is this a normal command or SHIFTed? */
1075 	if (!complement)
1076 	{
1077 		/* normal find/move */
1078 		newhigh.cell = getcurcell();
1079 		if (i >= len || us_dragpoint >= 0)
1080 		{
1081 			/* object is not highlighted: select only it and move */
1082 			us_setfind(&newhigh, (us_dragpoint < 0 ? 0 : 1),
1083 				(us_dragextra != 0 ? HIGHEXTRA : 0), 0, us_dragnobox);
1084 		} else
1085 		{
1086 			/* object is already highlighted: rehighlight and move */
1087 			us_delhighlight(&newhigh);
1088 			us_addhighlight(&newhigh);
1089 		}
1090 	} else
1091 	{
1092 		/* SHIFT held: find/move */
1093 		if (i >= len)
1094 		{
1095 			/* object not highlighted: add it and move */
1096 			newhigh.cell = getcurcell();
1097 			us_setfind(&newhigh, 0, (us_dragextra != 0 ? HIGHEXTRA : 0), 1, us_dragnobox);
1098 		} else
1099 		{
1100 			/* object highlighted: unhighlight it and quit */
1101 			us_delhighlight(&newhigh);
1102 			return;
1103 		}
1104 	}
1105 
1106 	/* can only drag if in "Mac" mode */
1107 	us_cantdrag = 1;
1108 	if (us_dragstayonhigh == 0) return;
1109 
1110 	/* do no motion if stillness requested */
1111 	if (us_dragstill != 0 || (us_dragnodeproto->userbits&NPLOCKED) != 0)
1112 	{
1113 		us_dragstate = -1;
1114 		return;
1115 	}
1116 
1117 	/* get the objects to be moved */
1118 	highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1119 	if (highvar == NOVARIABLE) return;
1120 
1121 	/* get the selected nodes, arcs, and text (mark nodes with nonzero "temp1") */
1122 	us_dragobjectlist = us_gethighlighted(WANTNODEINST | WANTARCINST,
1123 		&us_dragtextcount, &us_dragtexts);
1124 
1125 	/* stop if nothing selected */
1126 	if (us_dragobjectlist[0] == NOGEOM && us_dragtextcount == 0) return;
1127 	us_cantdrag = 0;
1128 
1129 	/* stop if from different cells */
1130 	for(i=0; us_dragobjectlist[i] != NOGEOM; i++)
1131 		if (us_dragnodeproto != geomparent(us_dragobjectlist[i])) return;
1132 
1133 	/* count the number of nodes */
1134 	us_dragnodetotal = 0;
1135 	for(ni = us_dragnodeproto->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1136 		if (ni->temp1 != 0) us_dragnodetotal++;
1137 
1138 	/* build a list that includes all nodes touching selected arcs */
1139 	if (us_dragnodetotal != 0)
1140 	{
1141 		us_dragnodelist = (NODEINST **)emalloc((us_dragnodetotal * (sizeof (NODEINST *))),
1142 			el_tempcluster);
1143 		if (us_dragnodelist == 0) return;
1144 		for(i=0, ni = us_dragnodeproto->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1145 		{
1146 			if (ni->temp1 != 0)
1147 				us_dragnodelist[i++] = ni;
1148 		}
1149 	}
1150 
1151 	/* save and turn off all highlighting */
1152 	us_pushhighlight();
1153 	us_clearhighlightcount();
1154 
1155 	/* setup for moving */
1156 	us_multidragbegin();
1157 	us_multidragshowoffset = TRUE;
1158 	us_dragstate = 0;
1159 }
1160 
us_findidown(INTBIG x,INTBIG y)1161 BOOLEAN us_findidown(INTBIG x, INTBIG y)
1162 {
1163 	REGISTER UINTBIG now;
1164 	BOOLEAN ret;
1165 
1166 	/* make the drag */
1167 	ret = TRUE;
1168 	switch (us_dragstate)
1169 	{
1170 		case 0:
1171 			/* pan the screen if the edge was hit */
1172 			us_panatscreenedge(&x, &y);
1173 			now = eventtime();
1174 			if (now < us_initialtime + us_motiondelayafterselection) ret = 0; else
1175 				ret = us_multidragdown(x, y);
1176 			break;
1177 		case 1:
1178 		case 2:
1179 			ret = us_stretchdown(x, y);
1180 			break;
1181 	}
1182 	return(ret);
1183 }
1184 
us_findiup(void)1185 void us_findiup(void)
1186 {
1187 	INTBIG xcur, ycur;
1188 	CHAR **list;
1189 	REGISTER INTBIG i, len, k, slx, shx, sly, shy, bits, angle, total;
1190 	REGISTER NODEINST *ni;
1191 	REGISTER ARCINST *ai;
1192 	REGISTER BOOLEAN domove;
1193 	REGISTER UINTBIG now;
1194 	HIGHLIGHT newhigh, oldhigh;
1195 	REGISTER VARIABLE *highvar;
1196 	static POLYGON *poly = NOPOLYGON;
1197 
1198 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1199 	if (us_dragstate == 0)
1200 	{
1201 		us_multidragup();
1202 		now = ticktime();
1203 		if (now >= us_initialtime + us_motiondelayafterselection &&
1204 			us_cantdrag == 0 && el_pleasestop == 0)
1205 		{
1206 			if (getxy(&xcur, &ycur)) return;
1207 			gridalign(&xcur, &ycur, 1, us_dragnodeproto);
1208 			us_setcursorpos(NOWINDOWFRAME, xcur, ycur);
1209 			bits = getbuckybits();
1210 			if ((bits&CONTROLDOWN) != 0) angle = us_dragangle; else angle = 0;
1211 			us_getslide(angle, us_dragox, us_dragoy, xcur, ycur, &us_dragx, &us_dragy);
1212 			if (us_dragx != us_dragox || us_dragy != us_dragoy)
1213 			{
1214 				/* eliminate locked nodes */
1215 				domove = TRUE;
1216 				for(i=0; i<us_dragnodetotal; i++)
1217 				{
1218 					ni = us_dragnodelist[i];
1219 					if (us_cantedit(ni->parent, ni, TRUE)) { domove = FALSE;   break; }
1220 				}
1221 
1222 				/* also check for locked nodes at the end of selected arcs */
1223 				if (domove)
1224 				{
1225 					for(i=0; us_dragobjectlist[i] != NOGEOM; i++)
1226 					{
1227 						if (!us_dragobjectlist[i]->entryisnode)
1228 						{
1229 							ai = us_dragobjectlist[i]->entryaddr.ai;
1230 							if (us_cantedit(us_dragnodeproto, ai->end[0].nodeinst, TRUE) ||
1231 								us_cantedit(us_dragnodeproto, ai->end[1].nodeinst, TRUE))
1232 							{
1233 								domove = FALSE;
1234 								break;
1235 							}
1236 						}
1237 					}
1238 				}
1239 
1240 				/* do the move */
1241 				if (domove)
1242 				{
1243 					us_manymove(us_dragobjectlist, us_dragnodelist, us_dragnodetotal,
1244 						us_dragx-us_dragox, us_dragy-us_dragoy);
1245 					us_moveselectedtext(us_dragtextcount, us_dragtexts,
1246 						us_dragobjectlist, us_dragx - us_dragox, us_dragy - us_dragoy);
1247 				}
1248 			}
1249 		}
1250 		if (us_dragnodetotal > 0) efree((CHAR *)us_dragnodelist);
1251 		us_pophighlight(TRUE);
1252 	} else if (us_dragstate == 1)
1253 	{
1254 		/* get area of drag */
1255 		us_invertdragup();
1256 		slx = mini(us_dragox, us_dragx);   shx = maxi(us_dragox, us_dragx);
1257 		sly = mini(us_dragoy, us_dragy);   shy = maxi(us_dragoy, us_dragy);
1258 		us_clearhighlightcount();
1259 
1260 		total = us_selectarea(us_dragnodeproto, slx, shx, sly, shy, us_dragspecial,
1261 			us_dragfport, us_dragnobox, &list);
1262 		if (total > 0)
1263 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_highlightedkey, (INTBIG)list,
1264 				VSTRING|VISARRAY|(total<<VLENGTHSH)|VDONTSAVE);
1265 	} else if (us_dragstate == 2)
1266 	{
1267 		/* special case when complementing highlight */
1268 		us_invertdragup();
1269 		slx = mini(us_dragox, us_dragx);   shx = maxi(us_dragox, us_dragx);
1270 		sly = mini(us_dragoy, us_dragy);   shy = maxi(us_dragoy, us_dragy);
1271 		highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1272 		if (highvar != NOVARIABLE) len = getlength(highvar); else len = 0;
1273 
1274 		total = us_selectarea(us_dragnodeproto, slx, shx, sly, shy, us_dragspecial,
1275 			us_dragfport, us_dragnobox, &list);
1276 
1277 		for(i=0; i<total; i++)
1278 		{
1279 			if (us_makehighlight(list[i], &newhigh)) continue;
1280 
1281 			/* see if this object is already highlighted */
1282 			for(k=0; k<len; k++)
1283 			{
1284 				if (us_makehighlight(((CHAR **)highvar->addr)[k], &oldhigh)) continue;
1285 				if (oldhigh.cell != newhigh.cell) continue;
1286 				if ((oldhigh.status&HIGHTYPE) != (newhigh.status&HIGHTYPE)) continue;
1287 				if ((oldhigh.status&HIGHTYPE) == HIGHFROM)
1288 				{
1289 					if (oldhigh.fromgeom != newhigh.fromgeom) continue;
1290 				} else if ((oldhigh.status&HIGHTYPE) == HIGHTEXT)
1291 				{
1292 					if (oldhigh.fromvar != newhigh.fromvar) continue;
1293 					if (oldhigh.fromvar == NOVARIABLE)
1294 					{
1295 						if (oldhigh.fromgeom != newhigh.fromgeom) continue;
1296 						if (oldhigh.fromport != newhigh.fromport) continue;
1297 					}
1298 				}
1299 				break;
1300 			}
1301 			if (k < len) us_delhighlight(&newhigh); else
1302 				us_addhighlight(&newhigh);
1303 
1304 			/* recache what is highlighted */
1305 			highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1306 			if (highvar != NOVARIABLE) len = getlength(highvar); else len = 0;
1307 		}
1308 	}
1309 }
1310 
1311 /*
1312  * Routine to determine whether geometry object "geom" is inside the area
1313  * (slx <= X <= shx, sly <= Y <= shy).  Returns true if so.
1314  */
us_geominrect(GEOM * geom,INTBIG slx,INTBIG shx,INTBIG sly,INTBIG shy)1315 BOOLEAN us_geominrect(GEOM *geom, INTBIG slx, INTBIG shx, INTBIG sly, INTBIG shy)
1316 {
1317 	REGISTER NODEINST *ni;
1318 	REGISTER ARCINST *ai;
1319 	INTBIG plx, ply, phx, phy;
1320 	REGISTER INTBIG wid, lx, hx, ly, hy;
1321 	XARRAY trans;
1322 	static POLYGON *poly = NOPOLYGON;
1323 
1324 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1325 	if (geom->entryisnode)
1326 	{
1327 		/* handle nodes */
1328 		ni = geom->entryaddr.ni;
1329 		makerot(ni, trans);
1330 
1331 		/* get the true bounds of the node */
1332 		nodesizeoffset(ni, &plx, &ply, &phx, &phy);
1333 		lx = ni->lowx+plx;   hx = ni->highx-phx;
1334 		ly = ni->lowy+ply;   hy = ni->highy-phy;
1335 		maketruerectpoly(lx, hx, ly, hy, poly);
1336 		poly->style = FILLEDRECT;
1337 
1338 		/* transform to account for node orientation */
1339 		xformpoly(poly, trans);
1340 
1341 		/* see if it is in the selected area */
1342 		if ((us_useroptions&MUSTENCLOSEALL) != 0)
1343 		{
1344 			getbbox(poly, &plx, &phx, &ply, &phy);
1345 			if (plx < slx || phx > shx || ply < sly || phy > shy)
1346 				return(FALSE);
1347 		} else
1348 		{
1349 			if (!polyinrect(poly, slx, shx, sly, shy)) return(FALSE);
1350 		}
1351 		return(TRUE);
1352 	}
1353 
1354 	/* handle arcs */
1355 	ai = geom->entryaddr.ai;
1356 	wid = ai->width - arcwidthoffset(ai);
1357 	if (wid == 0) wid = lambdaofarc(ai);
1358 	if (curvedarcoutline(ai, poly, FILLED, wid))
1359 		makearcpoly(ai->length, wid, ai, poly, FILLED);
1360 	if ((us_useroptions&MUSTENCLOSEALL) != 0)
1361 	{
1362 		getbbox(poly, &plx, &phx, &ply, &phy);
1363 		if (plx < slx || phx > shx || ply < sly || phy > shy)
1364 			return(FALSE);
1365 	} else
1366 	{
1367 		if (!polyinrect(poly, slx, shx, sly, shy)) return(FALSE);
1368 	}
1369 	return(TRUE);
1370 }
1371 
1372 /************************* CREATE INSERT/BREAKPOINT *************************/
1373 
1374 /* pre-initialization routine when inserting type "np" in arc "ai" */
us_createinsinit(ARCINST * ai,NODEPROTO * np)1375 void us_createinsinit(ARCINST *ai, NODEPROTO *np)
1376 {
1377 	us_dragarcinst = ai;
1378 	us_dragnodeproto = np;
1379 }
1380 
1381 /* initialization routine when inserting a breakpoint */
us_createinsbegin(void)1382 void us_createinsbegin(void)
1383 {
1384 	XARRAY trans;
1385 	INTBIG cx, cy, lx, ly, hx, hy, xcur, ycur, pxs, pys;
1386 	BOOLEAN centeredprimitives;
1387 	REGISTER NODEINST *ni;
1388 	NODEINST node;
1389 
1390 	/* initialize polygon */
1391 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
1392 	us_dragpoly->desc = &us_highl;
1393 
1394 	(void)getxy(&xcur, &ycur);
1395 
1396 	us_dragshown = 0;
1397 	ni = &node;   initdummynode(ni);
1398 	ni->proto = us_dragnodeproto;
1399 	ni->rotation = 0;
1400 	ni->transpose = 0;
1401 	defaultnodesize(us_dragnodeproto, &pxs, &pys);
1402 	ni->lowx = xcur;   ni->highx = xcur + pxs;
1403 	ni->lowy = ycur;   ni->highy = ycur + pys;
1404 	makerot(ni, trans);
1405 	nodeprotosizeoffset(us_dragnodeproto, &lx, &ly, &hx, &hy, el_curwindowpart->curnodeproto);
1406 	maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, us_dragpoly);
1407 	us_dragpoly->style = CLOSEDRECT;
1408 	xformpoly(us_dragpoly, trans);
1409 	if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
1410 		centeredprimitives = FALSE;
1411 	corneroffset(NONODEINST, us_dragnodeproto, 0, 0, &cx, &cy,
1412 		centeredprimitives);
1413 	us_dragoffx = cx;
1414 	us_dragoffy = cy;
1415 	us_dragx = xcur;   us_dragy = ycur;
1416 	us_dragwindow = el_curwindowpart;
1417 	us_dragobject = NOGEOM;
1418 	us_dragportproto = NOPORTPROTO;
1419 }
1420 
1421 /* cursor advance routine when creating inside an arc */
us_createinsdown(INTBIG x,INTBIG y)1422 BOOLEAN us_createinsdown(INTBIG x, INTBIG y)
1423 {
1424 	REGISTER INTBIG i;
1425 	INTBIG dx, dy, pxs, pys;
1426 
1427 	/* grid align the cursor value */
1428 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
1429 	{
1430 		(void)us_setxy(us_lastcurx, us_lastcury);
1431 		return(FALSE);
1432 	}
1433 	(void)getxy(&us_lastcurx, &us_lastcury);
1434 	gridalign(&us_lastcurx, &us_lastcury, 1, el_curlib->curnodeproto);
1435 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
1436 
1437 	/* find closest point along arc */
1438 	dx = us_lastcurx;   dy = us_lastcury;
1439 	(void)closestpointtosegment(us_dragarcinst->end[0].xpos, us_dragarcinst->end[0].ypos,
1440 		us_dragarcinst->end[1].xpos, us_dragarcinst->end[1].ypos, &dx, &dy);
1441 	defaultnodesize(us_dragnodeproto, &pxs, &pys);
1442 	dx -= pxs/2;
1443 	dy -= pys/2;
1444 
1445 	/* if the box is already being shown, erase it */
1446 	if (us_dragshown != 0)
1447 	{
1448 		/* if it didn't actually move, go no further */
1449 		if (us_dragx == dx && us_dragy == dy) return(FALSE);
1450 
1451 		/* undraw the box */
1452 		us_highl.col = 0;
1453 		us_showpoly(us_dragpoly, us_dragwindow);
1454 	}
1455 
1456 	/* advance the box */
1457 	for(i = 0; i < us_dragpoly->count; i++)
1458 	{
1459 		us_dragpoly->xv[i] += dx - us_dragx;
1460 		us_dragpoly->yv[i] += dy - us_dragy;
1461 	}
1462 	us_dragx = dx;
1463 	us_dragy = dy;
1464 
1465 	/* draw the new box */
1466 	us_highl.col = HIGHLIT;
1467 	us_showpoly(us_dragpoly, us_dragwindow);
1468 	us_dragshown = 1;
1469 	return(FALSE);
1470 }
1471 
1472 /************************* CREATE NODE *************************/
1473 
1474 /* pre-initialization routine when creating an object */
us_createinit(INTBIG cornerx,INTBIG cornery,NODEPROTO * np,INTBIG angle,BOOLEAN join,GEOM * fromgeom,PORTPROTO * fromport)1475 void us_createinit(INTBIG cornerx, INTBIG cornery, NODEPROTO *np, INTBIG angle,
1476 	BOOLEAN join, GEOM *fromgeom, PORTPROTO *fromport)
1477 {
1478 	us_dragox = cornerx;
1479 	us_dragoy = cornery;
1480 	us_dragnodeproto = np;
1481 	us_dragangle = angle;
1482 	us_dragjoinfactor = join;
1483 	us_dragfromgeom = fromgeom;
1484 	us_dragfromport = fromport;
1485 }
1486 
1487 /* initialization routine when creating an object */
us_createbegin(void)1488 void us_createbegin(void)
1489 {
1490 	XARRAY trans;
1491 	INTBIG cx, cy, lx, ly, hx, hy, xcur, ycur, pxs, pys;
1492 	REGISTER NODEINST *ni;
1493 	NODEINST node;
1494 	BOOLEAN centeredprimitives;
1495 	REGISTER WINDOWFRAME *curframe;
1496 
1497 	/* initialize polygon */
1498 	(void)needstaticpolygon(&us_dragpoly, 4, us_tool->cluster);
1499 	us_dragpoly->desc = &us_highl;
1500 
1501 	(void)getxy(&xcur, &ycur);
1502 	curframe = getwindowframe(TRUE);
1503 	if ((us_tool->toolstate&MENUON) != 0)
1504 	{
1505 		if (curframe == us_menuframe ||
1506 			(us_menuframe == NOWINDOWFRAME && ycur >= us_menuly && ycur <= us_menuhy &&
1507 				xcur >= us_menulx && xcur <= us_menuhx))
1508 		{
1509 			el_pleasestop = 1;
1510 		}
1511 	}
1512 
1513 	us_dragshown = 0;
1514 	ni = &node;   initdummynode(ni);
1515 	ni->proto = us_dragnodeproto;
1516 	ni->rotation = (INTSML)(us_dragangle%3600);
1517 	ni->transpose = (INTSML)(us_dragangle/3600);
1518 	defaultnodesize(us_dragnodeproto, &pxs, &pys);
1519 	if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
1520 		centeredprimitives = FALSE;
1521 	corneroffset(NONODEINST, us_dragnodeproto, us_dragangle%3600,
1522 		us_dragangle/3600, &cx, &cy, centeredprimitives);
1523 
1524 	/* adjust size if technologies differ */
1525 	us_adjustfornodeincell(us_dragnodeproto, el_curwindowpart->curnodeproto, &cx, &cy);
1526 	us_adjustfornodeincell(us_dragnodeproto, el_curwindowpart->curnodeproto, &pxs, &pys);
1527 	ni->lowx = xcur;   ni->highx = xcur + pxs;
1528 	ni->lowy = ycur;   ni->highy = ycur + pys;
1529 	makerot(ni, trans);
1530 	nodeprotosizeoffset(us_dragnodeproto, &lx, &ly, &hx, &hy, el_curwindowpart->curnodeproto);
1531 	maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, us_dragpoly);
1532 	us_dragpoly->style = CLOSEDRECT;
1533 	xformpoly(us_dragpoly, trans);
1534 	us_dragx = xcur + cx;   us_dragy = ycur + cy;
1535 	us_dragwindow = el_curwindowpart;
1536 	us_dragwirepathcount = 0;
1537 }
1538 
1539 /* initialization routine when creating along an angle */
us_createabegin(void)1540 void us_createabegin(void)
1541 {
1542 	XARRAY trans;
1543 	INTBIG cx, cy, lx, ly, hx, hy, xcur, ycur, pxs, pys;
1544 	REGISTER NODEINST *ni;
1545 	NODEINST node;
1546 	REGISTER BOOLEAN centeredprimitives;
1547 
1548 	/* initialize polygon */
1549 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
1550 	us_dragpoly->desc = &us_highl;
1551 
1552 	(void)getxy(&xcur, &ycur);
1553 
1554 	/* determine starting coordinate */
1555 	if ((us_dragfromport->userbits&PORTISOLATED) != 0)
1556 	{
1557 		/* use prefered location on isolated ports */
1558 		us_dragpoly->xv[0] = xcur;   us_dragpoly->yv[0] = ycur;   us_dragpoly->count = 1;
1559 		shapeportpoly(us_dragfromgeom->entryaddr.ni, us_dragfromport, us_dragpoly, TRUE);
1560 		us_dragstartx = xcur;   us_dragstarty = ycur;
1561 		closestpoint(us_dragpoly, &us_dragstartx, &us_dragstarty);
1562 	} else
1563 	{
1564 		us_portposition(us_dragfromgeom->entryaddr.ni, us_dragfromport,
1565 			&us_dragstartx, &us_dragstarty);
1566 	}
1567 
1568 	us_dragshown = 0;
1569 	ni = &node;   initdummynode(ni);
1570 	ni->proto = us_dragnodeproto;
1571 	ni->rotation = 0;
1572 	ni->transpose = 0;
1573 	defaultnodesize(us_dragnodeproto, &pxs, &pys);
1574 	if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
1575 		centeredprimitives = FALSE;
1576 	corneroffset(NONODEINST, us_dragnodeproto, 0, 0, &cx, &cy, centeredprimitives);
1577 
1578 	/* adjust size if technologies differ */
1579 	us_adjustfornodeincell(us_dragnodeproto, us_dragwindow->curnodeproto, &cx, &cy);
1580 	us_adjustfornodeincell(us_dragnodeproto, us_dragwindow->curnodeproto, &pxs, &pys);
1581 
1582 	ni->lowx = xcur;   ni->highx = xcur + pxs;
1583 	ni->lowy = ycur;   ni->highy = ycur + pys;
1584 	makerot(ni, trans);
1585 	nodeprotosizeoffset(us_dragnodeproto, &lx, &ly, &hx, &hy, el_curwindowpart->curnodeproto);
1586 	maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, us_dragpoly);
1587 	us_dragpoly->style = CLOSEDRECT;
1588 	xformpoly(us_dragpoly, trans);
1589 
1590 	us_dragoffx = cx;
1591 	us_dragoffy = cy;
1592 	us_dragx = xcur;   us_dragy = ycur;
1593 	us_dragwindow = el_curwindowpart;
1594 	us_dragobject = NOGEOM;
1595 	us_dragportproto = NOPORTPROTO;
1596 }
1597 
1598 /* cursor advance routine when creating along an angle */
us_createadown(INTBIG x,INTBIG y)1599 BOOLEAN us_createadown(INTBIG x, INTBIG y)
1600 {
1601 	REGISTER INTBIG dx, dy, dist, bestdist, count, samepath, alignment;
1602 	REGISTER INTBIG i;
1603 	INTBIG pxs, pys, unalx, unaly, fakecoords[8];
1604 	REGISTER PORTPROTO *pp, *foundpp;
1605 	REGISTER NODEINST *ni, *fakefromnode, *faketonode;
1606 	ARCINST *ai1, *ai2, *ai3;
1607 	NODEINST *con1, *con2;
1608 	GEOM *fakefromgeom, *faketogeom;
1609 	PORTPROTO *fakefromport, *faketoport;
1610 	REGISTER GEOM *foundgeom;
1611 	static POLYGON *poly = NOPOLYGON;
1612 
1613 	/* get the polygon */
1614 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1615 
1616 	/* pan the screen if the edge was hit */
1617 	us_panatscreenedge(&x, &y);
1618 
1619 	/* grid align the cursor value */
1620 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
1621 	{
1622 		(void)us_setxy(us_lastcurx, us_lastcury);
1623 		return(FALSE);
1624 	}
1625 	(void)getxy(&us_lastcurx, &us_lastcury);
1626 	unalx = us_lastcurx;   unaly = us_lastcury;
1627 	gridalign(&us_lastcurx, &us_lastcury, 1, us_dragwindow->curnodeproto);
1628 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
1629 
1630 	us_getslide(us_dragangle, us_dragox, us_dragoy, us_lastcurx, us_lastcury, &pxs, &pys);
1631 	dx = pxs - us_dragoffx;
1632 	dy = pys - us_dragoffy;
1633 
1634 	/* find the object under the cursor */
1635 	foundpp = NOPORTPROTO;
1636 	foundgeom = NOGEOM;
1637 	if (us_dragjoinfactor)
1638 	{
1639 		defaultnodesize(us_dragnodeproto, &pxs, &pys);
1640 		us_adjustfornodeincell(us_dragnodeproto, us_dragwindow->curnodeproto, &pxs, &pys);
1641 		alignment = muldiv(us_alignment_ratio, el_curlib->lambda[el_curtech->techindex], WHOLE);
1642 		foundgeom = us_getclosest(us_lastcurx-us_dragoffx+pxs/2, us_lastcury-us_dragoffy+pys/2,
1643 			alignment/2, us_dragwindow->curnodeproto);
1644 
1645 		/* determine closest port if a node was found */
1646 		if (foundgeom != NOGEOM && foundgeom->entryisnode)
1647 		{
1648 			/* find the closest port if this is a nodeinst and no port hit directly */
1649 			ni = foundgeom->entryaddr.ni;
1650 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1651 			{
1652 				shapeportpoly(ni, pp, poly, FALSE);
1653 
1654 				/* get distance of desired point to polygon */
1655 				dist = polydistance(poly, unalx, unaly);
1656 				if (dist < 0)
1657 				{
1658 					foundpp = pp;
1659 					break;
1660 				}
1661 				if (foundpp == NOPORTPROTO) bestdist = dist;
1662 				if (dist > bestdist) continue;
1663 				bestdist = dist;   foundpp = pp;
1664 			}
1665 		}
1666 	}
1667 
1668 	/* determine what is being connected */
1669 	count = 0;
1670 	fakefromgeom = us_dragfromgeom;   fakefromport = us_dragfromport;
1671 	faketogeom = foundgeom;           faketoport = foundpp;
1672 	if (fakefromgeom == NOGEOM) fakefromnode = NONODEINST; else
1673 		fakefromnode = us_getnodeonarcinst(&fakefromgeom, &fakefromport, faketogeom,
1674 			faketoport, pxs, pys, 1);
1675 	if (faketogeom == NOGEOM) faketonode = NONODEINST; else
1676 		faketonode = us_getnodeonarcinst(&faketogeom, &faketoport, fakefromgeom,
1677 			fakefromport, pxs, pys, 1);
1678 	if (fakefromnode != NONODEINST && faketonode != NONODEINST)
1679 	{
1680 		if (!us_figuredrawpath(us_dragfromgeom, us_dragfromport,
1681 			foundgeom, foundpp, &unalx, &unaly))
1682 		{
1683 			ai1 = us_makeconnection(fakefromnode, fakefromport,
1684 				gen_universalarc, faketonode, faketoport, gen_universalarc,
1685 				gen_univpinprim, unalx, unaly, &ai2, &ai3, &con1, &con2,
1686 				us_dragangle, FALSE, fakecoords, TRUE);
1687 			if (ai1 != NOARCINST) count = 4;
1688 			if (ai2 != NOARCINST) count = 6;
1689 			if (ai3 != NOARCINST) count = 8;
1690 		}
1691 	}
1692 	if (count == 0)
1693 	{
1694 		/* should draw a line from the node to the new pin */
1695 		if (us_dragfromgeom != NOGEOM && us_dragfromgeom->entryisnode)
1696 		{
1697 			fakecoords[0] = us_dragstartx;
1698 			fakecoords[1] = us_dragstarty;
1699 			fakecoords[2] = dx + us_dragoffx;
1700 			fakecoords[3] = dy + us_dragoffy;
1701 			count = 4;
1702 		}
1703 	}
1704 
1705 	/* see if the connection path is the same as before */
1706 	samepath = 0;
1707 	if (count == us_dragwirepathcount)
1708 	{
1709 		for(i=0; i<count; i++) if (fakecoords[i] != us_dragwirepath[i]) break;
1710 		if (i >= count) samepath = 1;
1711 	}
1712 
1713 	/* remove previous highlighting */
1714 	if (us_dragobject != NOGEOM)
1715 	{
1716 		if (us_dragshown != 0)
1717 		{
1718 			/* undraw the box */
1719 			us_highl.col = 0;
1720 			us_showpoly(us_dragpoly, us_dragwindow);
1721 			us_dragshown = 0;
1722 		}
1723 		if (us_dragobject == foundgeom && us_dragportproto == foundpp && samepath != 0) return(FALSE);
1724 		us_highlighteverywhere(us_dragobject, us_dragportproto, 0, FALSE, ALLOFF, FALSE);
1725 	} else
1726 	{
1727 		if (us_dragshown != 0)
1728 		{
1729 			/* if it didn't actually move, go no further */
1730 			if (us_dragx == dx && us_dragy == dy && samepath != 0 &&
1731 				us_dragobject == foundgeom) return(FALSE);
1732 
1733 			/* undraw the box */
1734 			us_highl.col = 0;
1735 			us_showpoly(us_dragpoly, us_dragwindow);
1736 			us_dragshown = 0;
1737 		}
1738 	}
1739 
1740 	/* undraw the previous wire path */
1741 	if (us_dragwirepathcount > 0)
1742 	{
1743 		poly->style = OPENED;
1744 		poly->count = us_dragwirepathcount/2;
1745 		for(i=0; i<poly->count; i++)
1746 		{
1747 			poly->xv[i] = us_dragwirepath[i*2];
1748 			poly->yv[i] = us_dragwirepath[i*2+1];
1749 		}
1750 		poly->desc = &us_highl;
1751 		us_highl.col = 0;
1752 		us_showpoly(poly, us_dragwindow);
1753 	}
1754 
1755 	/* advance the box */
1756 	for(i = 0; i < us_dragpoly->count; i++)
1757 	{
1758 		us_dragpoly->xv[i] += dx - us_dragx;
1759 		us_dragpoly->yv[i] += dy - us_dragy;
1760 	}
1761 	us_dragx = dx;
1762 	us_dragy = dy;
1763 
1764 	/* include any wiring path */
1765 	for(i=0; i<count; i++)
1766 		us_dragwirepath[i] = fakecoords[i];
1767 	us_dragwirepathcount = count;
1768 
1769 	/* set highlighted destination object */
1770 	us_dragobject = foundgeom;
1771 	us_dragportproto = foundpp;
1772 
1773 	/* draw the previous wire path */
1774 	if (us_dragwirepathcount > 0)
1775 	{
1776 		poly->style = OPENED;
1777 		poly->count = us_dragwirepathcount/2;
1778 		for(i=0; i<poly->count; i++)
1779 		{
1780 			poly->xv[i] = us_dragwirepath[i*2];
1781 			poly->yv[i] = us_dragwirepath[i*2+1];
1782 		}
1783 		poly->desc = &us_highl;
1784 		us_highl.col = HIGHLIT;
1785 		us_showpoly(poly, us_dragwindow);
1786 	}
1787 
1788 	/* draw the new highlight */
1789 	if (us_dragobject != NOGEOM)
1790 	{
1791 		us_highlighteverywhere(us_dragobject, us_dragportproto, 0, FALSE, HIGHLIT, FALSE);
1792 	} else
1793 	{
1794 		us_highl.col = HIGHLIT;
1795 		us_showpoly(us_dragpoly, us_dragwindow);
1796 		us_dragshown = 1;
1797 	}
1798 	return(FALSE);
1799 }
1800 
us_createajoinedobject(GEOM ** thegeom,PORTPROTO ** theport)1801 void us_createajoinedobject(GEOM **thegeom, PORTPROTO **theport)
1802 {
1803 	*theport = us_dragportproto;
1804 	*thegeom = us_dragobject;
1805 }
1806 
1807 /* termination routine when creating along an angle */
us_createaup(void)1808 void us_createaup(void)
1809 {
1810 	REGISTER INTBIG i;
1811 
1812 	if (us_dragshown != 0)
1813 	{
1814 		/* undraw the box */
1815 		us_highl.col = 0;
1816 		us_showpoly(us_dragpoly, us_dragwindow);
1817 	}
1818 	if (us_dragobject != NOGEOM)
1819 		us_highlighteverywhere(us_dragobject, us_dragportproto, 0, FALSE, ALLOFF, FALSE);
1820 
1821 	/* undraw the previous wire path */
1822 	if (us_dragwirepathcount > 0)
1823 	{
1824 		us_dragpoly->style = OPENED;
1825 		us_dragpoly->count = us_dragwirepathcount/2;
1826 		for(i=0; i<us_dragpoly->count; i++)
1827 		{
1828 			us_dragpoly->xv[i] = us_dragwirepath[i*2];
1829 			us_dragpoly->yv[i] = us_dragwirepath[i*2+1];
1830 		}
1831 		us_highl.col = 0;
1832 		us_showpoly(us_dragpoly, us_dragwindow);
1833 	}
1834 }
1835 
1836 /************************* DUPLICATE and multiple MOVE *************************/
1837 
1838 /* preinitialization routine when duplicating objects */
us_multidraginit(INTBIG xc,INTBIG yc,GEOM ** geomlist,NODEINST ** nodelist,INTBIG total,INTBIG angle,BOOLEAN showoffset)1839 void us_multidraginit(INTBIG xc, INTBIG yc, GEOM **geomlist, NODEINST **nodelist,
1840 	INTBIG total, INTBIG angle, BOOLEAN showoffset)
1841 {
1842 	us_multidragshowoffset = showoffset;
1843 	us_dragox = xc;
1844 	us_dragoy = yc;
1845 	us_dragobjectlist = geomlist;
1846 	us_dragnodelist = nodelist;
1847 	us_dragnodetotal = total;
1848 	us_dragangle = angle;
1849 	us_dragextra = 0;
1850 	us_cantdrag = 0;
1851 
1852 	/* show invisible pins */
1853 	us_multidragshowinvpin = TRUE;
1854 }
1855 
1856 static INTBIG us_multidragoffx, us_multidragoffy;
1857 
1858 /* initialization routine when duplicating objects */
us_multidragbegin(void)1859 void us_multidragbegin(void)
1860 {
1861 	REGISTER INTBIG i;
1862 	REGISTER PORTARCINST *pi;
1863 	REGISTER ARCINST *ai;
1864 
1865 	/* initialize polygon */
1866 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
1867 	us_dragpoly->desc = &us_highl;
1868 
1869 	(void)getxy(&us_dragx, &us_dragy);
1870 	gridalign(&us_dragx, &us_dragy, 1, el_curlib->curnodeproto);
1871 	us_setcursorpos(NOWINDOWFRAME, us_dragx, us_dragy);
1872 	us_dragwindow = el_curwindowpart;
1873 
1874 	/* preprocess all arcs that stretch to moved nodes if in verbose mode */
1875 	if (us_dragextra != 0)
1876 	{
1877 		/* reset clock (temp2) and clear display nature bits (temp1) on arcs */
1878 		for(i=0; i<us_dragnodetotal; i++)
1879 			for(pi = us_dragnodelist[i]->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1880 		{
1881 			ai = pi->conarcinst;
1882 			ai->temp1 = ai->temp2 = 0;
1883 		}
1884 
1885 		/* mark number of ends that move on each arc */
1886 		for(i=0; i<us_dragnodetotal; i++)
1887 			for(pi = us_dragnodelist[i]->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1888 				pi->conarcinst->temp1++;
1889 
1890 		/* do not move arcs that are already in move list */
1891 		for(i=0; us_dragobjectlist[i] != NOGEOM; i++)
1892 		{
1893 			if (us_dragobjectlist[i]->entryisnode) continue;
1894 			ai = us_dragobjectlist[i]->entryaddr.ai;
1895 			ai->temp1 = 0;
1896 		}
1897 	}
1898 
1899 	us_multidragmostzeros = -1;
1900 	us_multidragoffx = us_dragx-us_dragox;
1901 	us_multidragoffy = us_dragy-us_dragoy;
1902 	us_multidragdraw(HIGHLIT, us_multidragoffx, us_multidragoffy);
1903 	us_dragshown = 1;
1904 }
1905 
1906 /* cursor advance routine when duplicating objects */
us_multidragdown(INTBIG x,INTBIG y)1907 BOOLEAN us_multidragdown(INTBIG x, INTBIG y)
1908 {
1909 	INTBIG nx, ny, bits, angle;
1910 
1911 	/* pan the screen if the edge was hit */
1912 	us_panatscreenedge(&x, &y);
1913 
1914 	/* grid align the cursor value */
1915 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
1916 	{
1917 		(void)us_setxy(us_lastcurx, us_lastcury);
1918 		return(FALSE);
1919 	}
1920 	(void)getxy(&us_lastcurx, &us_lastcury);
1921 	gridalign(&us_lastcurx, &us_lastcury, 1, el_curlib->curnodeproto);
1922 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
1923 	bits = getbuckybits();
1924 	if ((bits&CONTROLDOWN) != 0) angle = us_dragangle; else angle = 0;
1925 	us_getslide(angle, us_dragox, us_dragoy, us_lastcurx, us_lastcury, &nx, &ny);
1926 	us_lastcurx = nx;   us_lastcury = ny;
1927 
1928 	/* warn if moving and can't */
1929 	if (us_cantdrag != 0)
1930 	{
1931 		if (us_dragx != us_lastcurx || us_dragy != us_lastcury)
1932 		{
1933 			if (us_cantdrag == 1)
1934 				us_abortcommand(_("Sorry, changes are currently disallowed"));
1935 			us_cantdrag++;
1936 			return(FALSE);
1937 		}
1938 	}
1939 
1940 	/* if the highlighting is already being shown, erase it */
1941 	if (us_dragshown != 0)
1942 	{
1943 		/* if it didn't actually move, go no further */
1944 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
1945 
1946 		/* undraw highlighting */
1947 		us_multidragdraw(0, us_multidragoffx, us_multidragoffy);
1948 	}
1949 
1950 	us_dragx = us_lastcurx;
1951 	us_dragy = us_lastcury;
1952 	us_multidragoffx = us_dragx-us_dragox;
1953 	us_multidragoffy = us_dragy-us_dragoy;
1954 	us_multidragdraw(HIGHLIT, us_multidragoffx, us_multidragoffy);
1955 	us_dragshown = 1;
1956 	return(FALSE);
1957 }
1958 
us_multidragup(void)1959 void us_multidragup(void)
1960 {
1961 	if (us_dragshown != 0)
1962 		us_multidragdraw(0, us_multidragoffx, us_multidragoffy);
1963 }
1964 
us_multidragdraw(INTBIG col,INTBIG dx,INTBIG dy)1965 void us_multidragdraw(INTBIG col, INTBIG dx, INTBIG dy)
1966 {
1967 	REGISTER INTBIG i, thisend, portcount, endfixed, wid, xzeros, yzeros, savestate;
1968 	INTBIG lx, ly, hx, hy, xc, yc, xw, yw, j;
1969 	CHAR coords[100], xcoord[50], ycoord[50], *pt;
1970 	XARRAY trans;
1971 	REGISTER BOOLEAN moveotherx, moveothery;
1972 	REGISTER NODEINST *ni;
1973 	REGISTER ARCINST *ai;
1974 	REGISTER PORTARCINST *pi;
1975 	REGISTER PORTPROTO *pp;
1976 	REGISTER TECHNOLOGY *tech;
1977 
1978 	us_highl.col = col;
1979 	if (us_dragextra != 0) us_dragextra++;
1980 	for(i=0; us_dragobjectlist[i] != NOGEOM; i++)
1981 	{
1982 		if (!us_dragobjectlist[i]->entryisnode) continue;
1983 		ni = us_dragobjectlist[i]->entryaddr.ni;
1984 
1985 		/* if node is an invisible pin with text, ignore the pin */
1986 		if (ni->proto == gen_invispinprim)
1987 		{
1988 			for(j=0; j<ni->numvar; j++)
1989 				if ((ni->firstvar[j].type&VDISPLAY) != 0) break;
1990 			if (j < ni->numvar)
1991 			{
1992 				if (us_multidragshowinvpin)
1993 				{
1994 					makerot(ni, trans);
1995 					xform((ni->lowx+ni->highx)/2, (ni->lowy+ni->highy)/2,
1996 						&us_dragpoly->xv[0], &us_dragpoly->yv[0], trans);
1997 					us_dragpoly->xv[0] += dx;
1998 					us_dragpoly->yv[0] += dy;
1999 					us_dragpoly->count = 1;
2000 					us_dragpoly->style = CROSS;
2001 					us_showpoly(us_dragpoly, us_dragwindow);
2002 				}
2003 				continue;
2004 			}
2005 		}
2006 
2007 		makerot(ni, trans);
2008 		nodesizeoffset(ni, &lx, &ly, &hx, &hy);
2009 		maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, us_dragpoly);
2010 		us_dragpoly->style = CLOSEDRECT;
2011 		xformpoly(us_dragpoly, trans);
2012 		for(j=0; j<us_dragpoly->count; j++)
2013 		{
2014 			us_dragpoly->xv[j] += dx;
2015 			us_dragpoly->yv[j] += dy;
2016 		}
2017 		us_showpoly(us_dragpoly, us_dragwindow);
2018 
2019 		/* draw more if in verbose mode */
2020 		if (us_dragextra != 0)
2021 		{
2022 			/* if only 1 node selected, show its ports */
2023 			if (us_dragnodetotal == 1)
2024 			{
2025 				portcount = 0;
2026 				for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2027 				{
2028 					/* compute the port bounds */
2029 					shapeportpoly(ni, pp, us_dragpoly, FALSE);
2030 
2031 					/* see if the polygon is a single point */
2032 					for(j=1; j<us_dragpoly->count; j++)
2033 						if (us_dragpoly->xv[j] != us_dragpoly->xv[j-1] ||
2034 							us_dragpoly->yv[j] != us_dragpoly->yv[j-1]) break;
2035 					if (j < us_dragpoly->count)
2036 					{
2037 						/* not a single point, draw its outline */
2038 						switch (us_dragpoly->style)
2039 						{
2040 							case FILLEDRECT: us_dragpoly->style = CLOSEDRECT;  break;
2041 							case FILLED:     us_dragpoly->style = CLOSED;      break;
2042 							case DISC:       us_dragpoly->style = CIRCLE;      break;
2043 							case OPENEDT1:
2044 							case OPENEDT2:
2045 							case OPENEDT3:
2046 							case OPENEDO1:   us_dragpoly->style = OPENED;      break;
2047 						}
2048 					} else
2049 					{
2050 						/* single point port: make it a cross */
2051 						us_dragpoly->count = 1;
2052 						us_dragpoly->style = CROSS;
2053 					}
2054 					for(j=0; j<us_dragpoly->count; j++)
2055 					{
2056 						us_dragpoly->xv[j] += dx;
2057 						us_dragpoly->yv[j] += dy;
2058 					}
2059 
2060 					/* draw the port */
2061 					us_showpoly(us_dragpoly, us_dragwindow);
2062 
2063 					/* stop if interrupted */
2064 					portcount++;
2065 					if ((portcount%20) == 0)
2066 					{
2067 						if (stopping(STOPREASONDISPLAY)) break;
2068 					}
2069 				}
2070 			}
2071 
2072 			/* rubber-band arcs to this node */
2073 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2074 			{
2075 				ai = pi->conarcinst;
2076 
2077 				/* ignore if not drawing this arc or already drawn */
2078 				if (ai->temp1 == 0 || ai->temp2 == us_dragextra) continue;
2079 				ai->temp2 = us_dragextra;
2080 
2081 				/* get original endpoint of arc */
2082 				us_dragpoly->xv[0] = ai->end[0].xpos;
2083 				us_dragpoly->yv[0] = ai->end[0].ypos;
2084 				us_dragpoly->xv[1] = ai->end[1].xpos;
2085 				us_dragpoly->yv[1] = ai->end[1].ypos;
2086 				us_dragpoly->count = 2;
2087 				us_dragpoly->style = OPENED;
2088 
2089 				/* offset this end by amount node moves */
2090 				if (ai->end[0].portarcinst == pi) thisend = 0; else thisend = 1;
2091 				us_dragpoly->xv[thisend] += dx;
2092 				us_dragpoly->yv[thisend] += dy;
2093 
2094 				/* offset other end if both connect to moved nodes or arc rigid */
2095 				endfixed = 0;
2096 				if (ai->temp1 >= 2 || (ai->userbits&FIXED) != 0) endfixed = 1;
2097 
2098 				moveotherx = moveothery = FALSE;
2099 				if (endfixed != 0)
2100 				{
2101 					 moveotherx = moveothery = TRUE;
2102 				} else if ((ai->userbits&FIXANG) != 0)
2103 				{
2104 					if (ai->end[0].xpos != ai->end[1].xpos && ai->end[0].ypos != ai->end[1].ypos)
2105 					{
2106 						moveotherx = moveothery = TRUE;
2107 					} else
2108 					{
2109 						if (ai->end[0].xpos == ai->end[1].xpos) moveotherx = TRUE;
2110 						if (ai->end[0].ypos == ai->end[1].ypos) moveothery = TRUE;
2111 					}
2112 				}
2113 				if (moveotherx) us_dragpoly->xv[1-thisend] += dx;
2114 				if (moveothery) us_dragpoly->yv[1-thisend] += dy;
2115 
2116 				/* draw line */
2117 				us_showpoly(us_dragpoly, us_dragwindow);
2118 			}
2119 		}
2120 	}
2121 
2122 	for(i=0; us_dragobjectlist[i] != NOGEOM; i++)
2123 	{
2124 		if (us_dragobjectlist[i]->entryisnode) continue;
2125 		ai = us_dragobjectlist[i]->entryaddr.ai;
2126 		wid = ai->width - arcwidthoffset(ai);
2127 		makearcpoly(ai->length, wid, ai, us_dragpoly, CLOSED);
2128 		for(j=0; j<us_dragpoly->count; j++)
2129 		{
2130 			us_dragpoly->xv[j] += dx;
2131 			us_dragpoly->yv[j] += dy;
2132 		}
2133 		us_showpoly(us_dragpoly, us_dragwindow);
2134 	}
2135 
2136 	/* update selected text, too */
2137 	for(i=0; i<us_dragtextcount; i++)
2138 	{
2139 		(void)us_makehighlight(us_dragtexts[i], &us_draghigh);
2140 		if ((us_draghigh.status&HIGHTYPE) != HIGHTEXT) continue;
2141 
2142 		/* get object and extent */
2143 		us_gethighaddrtype(&us_draghigh, &us_dragaddr, &us_dragtype);
2144 		tech = us_getobjectinfo(us_dragaddr, us_dragtype, &lx, &hx, &ly, &hy);
2145 
2146 		/* determine number of lines of text and text size */
2147 		us_gethightextsize(&us_draghigh, &xw, &yw, el_curwindowpart);
2148 		us_gethightextcenter(&us_draghigh, &xc, &yc, &j);
2149 		us_dragpoly->style = j;
2150 
2151 #if 0		/* clip range of text descriptor */
2152 		lambda = el_curlib->lambda[tech->techindex];
2153 		xcur = (us_lastcurx - us_dragx) * 4 / lambda;
2154 		us_lastcurx = us_lastcurx - us_dragx + us_dragoffx;
2155 		if (xcur > 1023)
2156 			us_lastcurx = 1023 * lambda / 4 + us_dragoffx; else
2157 				if (xcur < -1023)
2158 					us_lastcurx = -1023 * lambda / 4 + us_dragoffx;
2159 		ycur = (us_lastcury - us_dragy) * 4 / lambda;
2160 		us_lastcury = us_lastcury - us_dragy + us_dragoffy;
2161 		if (ycur > 1023)
2162 			us_lastcury = 1023 * lambda / 4 + us_dragoffy; else
2163 				if (ycur < -1023)
2164 					us_lastcury = -1023 * lambda / 4 + us_dragoffy;
2165 #endif
2166 
2167 		/* draw the descriptor */
2168 		us_buildtexthighpoly(lx, hx, ly, hy, xc+dx, yc+dy,
2169 			xw, yw, us_dragpoly->style, us_dragpoly);
2170 
2171 		/* draw the new box */
2172 		us_showpoly(us_dragpoly, us_dragwindow);
2173 	}
2174 
2175 	/* show the distance moved */
2176 	if (us_multidragshowoffset)
2177 	{
2178 		estrcpy(xcoord, latoa(dx, 0));
2179 		for(pt = xcoord; *pt != 0; pt++) if (*pt == '.') break;
2180 		if (*pt == 0) xzeros = -1; else xzeros = estrlen(pt) - 1;
2181 		estrcpy(ycoord, latoa(dy, 0));
2182 		for(pt = ycoord; *pt != 0; pt++) if (*pt == '.') break;
2183 		if (*pt == 0) yzeros = -1; else yzeros = estrlen(pt) - 1;
2184 		if (xzeros > us_multidragmostzeros) us_multidragmostzeros = xzeros;
2185 		if (yzeros > us_multidragmostzeros) us_multidragmostzeros = yzeros;
2186 		if (xzeros < us_multidragmostzeros)
2187 		{
2188 			if (xzeros < 0) { estrcat(xcoord, x_(".")); xzeros++; }
2189 			for(i=xzeros; i<us_multidragmostzeros; i++) estrcat(xcoord, x_("0"));
2190 		}
2191 		if (yzeros < us_multidragmostzeros)
2192 		{
2193 			if (yzeros < 0) { estrcat(ycoord, x_(".")); yzeros++; }
2194 			for(i=yzeros; i<us_multidragmostzeros; i++) estrcat(ycoord, x_("0"));
2195 		}
2196 
2197 		esnprintf(coords, 100, x_("(%s,%s)"), xcoord, ycoord);
2198 		TDCLEAR(us_dragpoly->textdescript);
2199 		TDSETSIZE(us_dragpoly->textdescript, TXTSETPOINTS(20));
2200 		us_dragpoly->style = TEXTCENT;
2201 		us_dragpoly->count = 1;
2202 		us_dragpoly->xv[0] = (us_dragwindow->screenlx + us_dragwindow->screenhx) / 2;
2203 		us_dragpoly->yv[0] = (us_dragwindow->screenly + us_dragwindow->screenhy) / 2;
2204 		us_dragpoly->string = coords;
2205 		savestate = us_dragwindow->state;
2206 		us_dragwindow->state &= ~INPLACEEDIT;
2207 		us_showpoly(us_dragpoly, us_dragwindow);
2208 		us_dragwindow->state = savestate;
2209 	}
2210 }
2211 
2212 /************************* DISTANCE TRACKING *************************/
2213 
us_distanceinit(void)2214 void us_distanceinit(void)
2215 {
2216 	us_measureshown = 0;
2217 	us_dragwindow = el_curwindowpart;
2218 }
2219 
us_distancedown(INTBIG x,INTBIG y)2220 BOOLEAN us_distancedown(INTBIG x, INTBIG y)
2221 {
2222 	REGISTER INTBIG dist, lastshown;
2223 
2224 	/* initialize polygon */
2225 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
2226 	us_dragpoly->desc = &us_highl;
2227 
2228 	/* pan the screen if the edge was hit */
2229 	lastshown = us_measureshown;
2230 	us_panatscreenedge(&x, &y);
2231 	if (lastshown != us_measureshown)
2232 	{
2233 		us_highl.col = HIGHLIT;
2234 		us_drawdistance();
2235 		us_measureshown = 1;
2236 	}
2237 
2238 	/* grid align the cursor value */
2239 	if (us_setxy(x, y)) return(FALSE);
2240 	if ((us_dragwindow->state&WINDOWTYPE) != DISPWINDOW ||
2241 		us_dragwindow->curnodeproto == NONODEPROTO) return(FALSE);
2242 	us_dragnodeproto = us_dragwindow->curnodeproto;
2243 	(void)getxy(&us_dragx, &us_dragy);
2244 	gridalign(&us_dragx, &us_dragy, 1, us_dragnodeproto);
2245 	us_setcursorpos(NOWINDOWFRAME, us_dragx, us_dragy);
2246 
2247 	if (us_measureshown == 0)
2248 	{
2249 		us_firstmeasurex = us_dragx;   us_firstmeasurey = us_dragy;
2250 	} else
2251 	{
2252 		/* if it didn't actually move, go no further */
2253 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
2254 
2255 		/* undraw the distance */
2256 		us_highl.col = 0;
2257 		us_drawdistance();
2258 	}
2259 
2260 	/* remember this measured distance */
2261 	us_lastmeasurex = us_dragx - us_firstmeasurex;
2262 	us_lastmeasurey = us_dragy - us_firstmeasurey;
2263 	us_validmesaure = TRUE;
2264 
2265 	/* draw crosses at the end */
2266 	us_highl.col = HIGHLIT;
2267 	us_lastcurx = us_dragx;   us_lastcury = us_dragy;
2268 	TDCLEAR(us_dragpoly->textdescript);
2269 	TDSETSIZE(us_dragpoly->textdescript, TXTSETPOINTS(12));
2270 	us_dragpoly->tech = el_curtech;
2271 	dist = computedistance(us_firstmeasurex, us_firstmeasurey, us_dragx, us_dragy);
2272 	(void)estrcpy(us_dragmessage, _("Distance: "));
2273 	(void)estrcat(us_dragmessage, latoa(dist, 0));
2274 	(void)estrcat(us_dragmessage, x_(" (dX="));
2275 	(void)estrcat(us_dragmessage, latoa(us_dragx - us_firstmeasurex, 0));
2276 	(void)estrcat(us_dragmessage, x_(" dY="));
2277 	(void)estrcat(us_dragmessage, latoa(us_dragy - us_firstmeasurey, 0));
2278 	(void)estrcat(us_dragmessage, x_(")"));
2279 	us_dragpoly->string = us_dragmessage;
2280 	us_drawdistance();
2281 	us_measureshown = 1;
2282 	return(FALSE);
2283 }
2284 
us_drawdistance(void)2285 void us_drawdistance(void)
2286 {
2287 	REGISTER WINDOWPART *w;
2288 	INTBIG fx, fy, tx, ty;
2289 
2290 	us_dragpoly->count = 1;
2291 	us_dragpoly->style = TEXTBOTLEFT;
2292 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2293 	{
2294 		if (w->curnodeproto != us_dragnodeproto) continue;
2295 		fx = us_firstmeasurex;   fy = us_firstmeasurey;
2296 		tx = us_lastcurx;        ty = us_lastcury;
2297 		if (clipline(&fx, &fy, &tx, &ty, w->screenlx, w->screenhx,
2298 			w->screenly, w->screenhy)) continue;
2299 		us_dragpoly->xv[0] = (fx+tx) / 2;
2300 		us_dragpoly->yv[0] = (fy+ty) / 2;
2301 		us_showpoly(us_dragpoly, w);
2302 	}
2303 
2304 	/* draw the line */
2305 	us_dragpoly->xv[0] = us_firstmeasurex;  us_dragpoly->yv[0] = us_firstmeasurey;
2306 	us_dragpoly->xv[1] = us_lastcurx;       us_dragpoly->yv[1] = us_lastcury;
2307 	us_dragpoly->count = 2;
2308 	us_dragpoly->style = OPENED;
2309 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2310 		if (w->curnodeproto == us_dragnodeproto)
2311 			us_showpoly(us_dragpoly, w);
2312 
2313 	/* draw crosses at the end */
2314 	us_dragpoly->xv[0] = us_firstmeasurex;     us_dragpoly->yv[0] = us_firstmeasurey;
2315 	us_dragpoly->count = 1;
2316 	us_dragpoly->style = CROSS;
2317 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2318 		if (w->curnodeproto == us_dragnodeproto)
2319 			us_showpoly(us_dragpoly, w);
2320 	us_dragpoly->xv[0] = us_lastcurx;   us_dragpoly->yv[0] = us_lastcury;
2321 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2322 		if (w->curnodeproto == us_dragnodeproto)
2323 			us_showpoly(us_dragpoly, w);
2324 }
2325 
us_distanceup(void)2326 void us_distanceup(void)
2327 {
2328 	if (us_measureshown != 0)
2329 	{
2330 		/* leave the results in the messages window */
2331 		ttyputmsg(x_("%s"), us_dragpoly->string);
2332 	}
2333 }
2334 
2335 /************************* SLIDER THUMB TRACKING *************************/
2336 
2337 /*
2338  * initialization method for tracking the horizontal thumb.  The cursor X coordinate
2339  * is "x" and the window is "w".  The horizontal slider's top side is "hy" and it
2340  * runs horizontally from "lx" to "hx" (including arrows).  The routine "callback"
2341  * is invoked with the difference each time.
2342  */
us_hthumbbegin(INTBIG x,WINDOWPART * w,INTBIG hy,INTBIG lx,INTBIG hx,void (* callback)(INTBIG))2343 void us_hthumbbegin(INTBIG x, WINDOWPART *w, INTBIG hy, INTBIG lx, INTBIG hx,
2344 	void (*callback)(INTBIG))
2345 {
2346 	/* initialize polygon */
2347 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
2348 	us_dragpoly->desc = &us_highl;
2349 
2350 	us_dragshown = 0;
2351 	us_dragwindow = w;
2352 	us_initthumbcoord = x;
2353 	us_trackingcallback = callback;
2354 
2355 	us_trackww.screenlx = us_trackww.uselx = lx;
2356 	us_trackww.screenhx = us_trackww.usehx = hx;
2357 	us_trackww.screenly = us_trackww.usely = hy-DISPLAYSLIDERSIZE;
2358 	us_trackww.screenhy = us_trackww.usehy = hy;
2359 	us_trackww.frame = w->frame;
2360 	us_trackww.state = DISPWINDOW;
2361 	computewindowscale(&us_trackww);
2362 }
2363 
2364 /* tracking method for the horizontal thumb */
us_hthumbdown(INTBIG x,INTBIG y)2365 BOOLEAN us_hthumbdown(INTBIG x, INTBIG y)
2366 {
2367 	REGISTER INTBIG dx;
2368 
2369 	if (us_dragshown != 0)
2370 	{
2371 		/* if it didn't actually move, go no further */
2372 		if (x == us_lastcurx) return(FALSE);
2373 
2374 		/* undraw the outline */
2375 		us_highl.col = 0;
2376 		us_dragpoly->xv[0] = us_dragwindow->thumblx + (us_lastcurx-us_initthumbcoord)+1;
2377 		us_dragpoly->yv[0] = us_trackww.usehy-3;
2378 		us_dragpoly->xv[1] = us_dragwindow->thumbhx + (us_lastcurx-us_initthumbcoord)-1;
2379 		us_dragpoly->yv[1] = us_trackww.usehy-DISPLAYSLIDERSIZE+1;
2380 		us_dragpoly->count = 2;
2381 		us_dragpoly->style = FILLEDRECT;
2382 		us_showpoly(us_dragpoly, &us_trackww);
2383 	}
2384 
2385 	/* draw the outline */
2386 	us_highl.col = HIGHLIT;
2387 	if (us_dragwindow->thumblx + (x-us_initthumbcoord) <= us_trackww.uselx+DISPLAYSLIDERSIZE)
2388 		 x = us_trackww.uselx+DISPLAYSLIDERSIZE+1 - us_dragwindow->thumblx + us_initthumbcoord;
2389 	if (us_dragwindow->thumbhx + (x-us_initthumbcoord) >= us_trackww.usehx-DISPLAYSLIDERSIZE)
2390 		 x = us_trackww.usehx-DISPLAYSLIDERSIZE-1 - us_dragwindow->thumbhx + us_initthumbcoord;
2391 	us_dragpoly->xv[0] = us_dragwindow->thumblx + (x-us_initthumbcoord)+1;
2392 	us_dragpoly->yv[0] = us_trackww.usehy-3;
2393 	us_dragpoly->xv[1] = us_dragwindow->thumbhx + (x-us_initthumbcoord)-1;
2394 	us_dragpoly->yv[1] = us_trackww.usehy-DISPLAYSLIDERSIZE+1;
2395 	us_dragpoly->count = 2;
2396 	us_dragpoly->style = FILLEDRECT;
2397 	us_showpoly(us_dragpoly, &us_trackww);
2398 
2399 	us_dragshown = 1;
2400 	us_lastcurx = x;
2401 
2402 	if (us_trackingcallback != 0)
2403 	{
2404 		dx = us_lastcurx-us_initthumbcoord;
2405 		us_initthumbcoord = us_lastcurx;
2406 		(*us_trackingcallback)(dx);
2407 	}
2408 	return(FALSE);
2409 }
2410 
us_hthumbtrackingcallback(INTBIG delta)2411 void us_hthumbtrackingcallback(INTBIG delta)
2412 {
2413 	REGISTER NODEPROTO *np;
2414 	REGISTER INTBIG cellsizex, screensizex, thumbareax, dsx;
2415 
2416 	np = us_dragwindow->curnodeproto;
2417 	if (np == NONODEPROTO) return;
2418 	cellsizex = np->highx - np->lowx;
2419 	screensizex = us_dragwindow->screenhx - us_dragwindow->screenlx;
2420 	thumbareax = (us_dragwindow->usehx - us_dragwindow->uselx - DISPLAYSLIDERSIZE*2-4) / 2;
2421 	if (cellsizex <= screensizex)
2422 	{
2423 		dsx = delta * (us_dragwindow->screenhx-us_dragwindow->screenlx) / thumbareax;
2424 	} else
2425 	{
2426 		dsx = delta * (np->highx-np->lowx) / thumbareax;
2427 	}
2428 	us_slideleft(dsx);
2429 	us_endbatch();
2430 }
2431 
2432 /* completion method for tracking the horozintal thumb in a regular edit window */
us_hthumbdone(void)2433 void us_hthumbdone(void)
2434 {
2435 	if (us_dragshown != 0)
2436 	{
2437 		/* undraw the outline */
2438 		us_highl.col = 0;
2439 		us_dragpoly->xv[0] = us_dragwindow->thumblx + (us_lastcurx-us_initthumbcoord)+1;
2440 		us_dragpoly->yv[0] = us_trackww.usehy-3;
2441 		us_dragpoly->xv[1] = us_dragwindow->thumbhx + (us_lastcurx-us_initthumbcoord)-1;
2442 		us_dragpoly->yv[1] = us_trackww.usehy-DISPLAYSLIDERSIZE+1;
2443 		us_dragpoly->count = 2;
2444 		us_dragpoly->style = FILLEDRECT;
2445 		us_showpoly(us_dragpoly, &us_trackww);
2446 	}
2447 }
2448 
2449 /*
2450  * initialization method for tracking the vertical thumb.  The cursor Y coordinate
2451  * is "y" and the window is "w".  The vertical slider's left side is "hx" and it
2452  * runs vertically from "ly" to "hy" (including arrows).  The total number of
2453  * lines of text is "totallines" and the slider is on the left side if "onleft"
2454  * is nonzero.
2455  */
us_vthumbbegin(INTBIG y,WINDOWPART * w,INTBIG hx,INTBIG ly,INTBIG hy,BOOLEAN onleft,void (* callback)(INTBIG))2456 void us_vthumbbegin(INTBIG y, WINDOWPART *w, INTBIG hx, INTBIG ly, INTBIG hy,
2457 	BOOLEAN onleft, void (*callback)(INTBIG))
2458 {
2459 	/* initialize polygon */
2460 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
2461 	us_dragpoly->desc = &us_highl;
2462 
2463 	us_dragshown = 0;
2464 	us_dragwindow = w;
2465 	us_initthumbcoord = y;
2466 	us_dragpoint = -1;
2467 	us_trackingcallback = callback;
2468 
2469 	if (onleft != 0)
2470 	{
2471 		/* slider is on the left (simulation window) */
2472 		us_trackww.screenlx = us_trackww.uselx = hx;
2473 		us_trackww.screenhx = us_trackww.usehx = w->usehx;
2474 		us_dragoffx = hx-2;
2475 	} else
2476 	{
2477 		/* slider is on the right (edit, text edit, and explorer window) */
2478 		us_trackww.screenlx = us_trackww.uselx = w->uselx;
2479 		us_trackww.screenhx = us_trackww.usehx = hx+DISPLAYSLIDERSIZE;
2480 		us_dragoffx = hx;
2481 	}
2482 	us_trackww.screenly = ly;
2483 	us_trackww.usely = ly;
2484 	us_trackww.screenhy = hy;
2485 	us_trackww.usehy = hy;
2486 	us_trackww.frame = w->frame;
2487 	us_trackww.state = DISPWINDOW;
2488 	computewindowscale(&us_trackww);
2489 }
2490 
2491 /* tracking method for the vertical thumb */
us_vthumbdown(INTBIG x,INTBIG y)2492 BOOLEAN us_vthumbdown(INTBIG x, INTBIG y)
2493 {
2494 	REGISTER INTBIG dy;
2495 
2496 	if (us_dragshown != 0)
2497 	{
2498 		/* if it didn't actually move, go no further */
2499 		if (y == us_lastcury) return(FALSE);
2500 
2501 		/* undraw the outline */
2502 		us_highl.col = 0;
2503 		us_dragpoly->xv[0] = us_dragoffx+3;
2504 		us_dragpoly->yv[0] = us_dragwindow->thumbly + (us_lastcury-us_initthumbcoord)+1;
2505 		us_dragpoly->yv[1] = us_dragwindow->thumbhy + (us_lastcury-us_initthumbcoord)-1;
2506 		us_dragpoly->xv[1] = us_dragoffx+DISPLAYSLIDERSIZE-1;
2507 		us_dragpoly->count = 2;
2508 		us_dragpoly->style = FILLEDRECT;
2509 		us_showpoly(us_dragpoly, &us_trackww);
2510 	}
2511 
2512 	/* draw the outline */
2513 	us_highl.col = HIGHLIT;
2514 	if (us_dragwindow->thumbly + (y-us_initthumbcoord) <= us_trackww.usely+DISPLAYSLIDERSIZE)
2515 		 y = us_trackww.usely+DISPLAYSLIDERSIZE+1 - us_dragwindow->thumbly + us_initthumbcoord;
2516 	if (us_dragwindow->thumbhy + (y-us_initthumbcoord) >= us_trackww.usehy-DISPLAYSLIDERSIZE)
2517 		 y = us_trackww.usehy-DISPLAYSLIDERSIZE-1 - us_dragwindow->thumbhy + us_initthumbcoord;
2518 	us_dragpoly->xv[0] = us_dragoffx+3;
2519 	us_dragpoly->yv[0] = us_dragwindow->thumbly + (y-us_initthumbcoord)+1;
2520 	us_dragpoly->yv[1] = us_dragwindow->thumbhy + (y-us_initthumbcoord)-1;
2521 	us_dragpoly->xv[1] = us_dragoffx+DISPLAYSLIDERSIZE-1;
2522 	us_dragpoly->count = 2;
2523 	us_dragpoly->style = FILLEDRECT;
2524 	us_showpoly(us_dragpoly, &us_trackww);
2525 
2526 	us_dragshown = 1;
2527 	us_lastcury = y;
2528 
2529 	if (us_trackingcallback != 0)
2530 	{
2531 		dy = us_lastcury-us_initthumbcoord;
2532 		us_initthumbcoord = us_lastcury;
2533 		(*us_trackingcallback)(dy);
2534 	}
2535 	return(FALSE);
2536 }
2537 
us_vthumbtrackingcallback(INTBIG delta)2538 void us_vthumbtrackingcallback(INTBIG delta)
2539 {
2540 	REGISTER NODEPROTO *np;
2541 	REGISTER INTBIG cellsizey, screensizey, thumbareay, dsy;
2542 
2543 	/* adjust the screen */
2544 	np = us_dragwindow->curnodeproto;
2545 	if (np == NONODEPROTO) return;
2546 	cellsizey = np->highy - np->lowy;
2547 	screensizey = us_dragwindow->screenhy - us_dragwindow->screenly;
2548 	thumbareay = (us_dragwindow->usehy - us_dragwindow->usely - DISPLAYSLIDERSIZE*2-4) / 2;
2549 	if (cellsizey <= screensizey)
2550 	{
2551 		dsy = delta * (us_dragwindow->screenhy-us_dragwindow->screenly) / thumbareay;
2552 	} else
2553 	{
2554 		dsy = delta * (np->highy-np->lowy) / thumbareay;
2555 	}
2556 	us_slideup(-dsy);
2557 	us_endbatch();
2558 }
2559 
2560 /* completion method for tracking the vertical thumb in regular edit window */
us_vthumbdone(void)2561 void us_vthumbdone(void)
2562 {
2563 	if (us_dragshown != 0)
2564 	{
2565 		/* undraw the outline */
2566 		us_highl.col = 0;
2567 		us_dragpoly->xv[0] = us_dragoffx+3;
2568 		us_dragpoly->yv[0] = us_dragwindow->thumbly + (us_lastcury-us_initthumbcoord)+1;
2569 		us_dragpoly->yv[1] = us_dragwindow->thumbhy + (us_lastcury-us_initthumbcoord)-1;
2570 		us_dragpoly->xv[1] = us_dragoffx+DISPLAYSLIDERSIZE-1;
2571 		us_dragpoly->count = 2;
2572 		us_dragpoly->style = FILLEDRECT;
2573 		us_showpoly(us_dragpoly, &us_trackww);
2574 	}
2575 }
2576 
2577 /* initialization method for tracking the arrows on sliders */
us_arrowclickbegin(WINDOWPART * w,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG amount)2578 void us_arrowclickbegin(WINDOWPART *w, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, INTBIG amount)
2579 {
2580 	us_dragwindow = w;
2581 	us_arrowlx = lx;
2582 	us_arrowhx = hx;
2583 	us_arrowly = ly;
2584 	us_arrowhy = hy;
2585 	us_arrowamount = amount;
2586 }
2587 
us_varrowdown(INTBIG x,INTBIG y)2588 BOOLEAN us_varrowdown(INTBIG x, INTBIG y)
2589 {
2590 	if (x < us_arrowlx || x > us_arrowhx) return(FALSE);
2591 	if (y < us_arrowly || y > us_arrowhy) return(FALSE);
2592 	if (y >= us_dragwindow->thumbly && y <= us_dragwindow->thumbhy) return(FALSE);
2593 	us_slideup(us_arrowamount);
2594 	us_endbatch();
2595 	return(FALSE);
2596 }
2597 
us_harrowdown(INTBIG x,INTBIG y)2598 BOOLEAN us_harrowdown(INTBIG x, INTBIG y)
2599 {
2600 	if (x < us_arrowlx || x > us_arrowhx) return(FALSE);
2601 	if (y < us_arrowly || y > us_arrowhy) return(FALSE);
2602 	if (x >= us_dragwindow->thumblx && x <= us_dragwindow->thumbhx) return(FALSE);
2603 	us_slideleft(us_arrowamount);
2604 	us_endbatch();
2605 	return(FALSE);
2606 }
2607 
2608 /************************* WINDOW PARTITION DIVIDER TRACKING *************************/
2609 
us_vpartdividerbegin(INTBIG x,INTBIG ly,INTBIG hy,WINDOWFRAME * wf)2610 void us_vpartdividerbegin(INTBIG x, INTBIG ly, INTBIG hy, WINDOWFRAME *wf)
2611 {
2612 	/* initialize polygon */
2613 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
2614 	us_dragpoly->desc = &us_highl;
2615 
2616 	us_dragshown = 0;
2617 	us_initthumbcoord = x;
2618 	us_draglowval = ly;
2619 	us_draghighval = hy;
2620 
2621 	us_trackww.screenlx = us_trackww.uselx = 0;
2622 	us_trackww.screenhx = us_trackww.usehx = wf->swid;
2623 	us_trackww.screenly = us_trackww.usely = 0;
2624 	us_trackww.screenhy = us_trackww.usehy = wf->shei;
2625 	us_trackww.frame = wf;
2626 	us_trackww.state = DISPWINDOW;
2627 	computewindowscale(&us_trackww);
2628 }
2629 
us_vpartdividerdown(INTBIG x,INTBIG y)2630 BOOLEAN us_vpartdividerdown(INTBIG x, INTBIG y)
2631 {
2632 	if (us_dragshown != 0)
2633 	{
2634 		/* if it didn't actually move, go no further */
2635 		if (x == us_lastcurx) return(FALSE);
2636 
2637 		/* undraw the line */
2638 		us_highl.col = 0;
2639 		us_dragpoly->xv[0] = us_lastcurx;
2640 		us_dragpoly->yv[0] = us_draglowval;
2641 		us_dragpoly->xv[1] = us_lastcurx;
2642 		us_dragpoly->yv[1] = us_draghighval;
2643 		us_dragpoly->count = 2;
2644 		us_dragpoly->style = VECTORS;
2645 		us_showpoly(us_dragpoly, &us_trackww);
2646 	}
2647 
2648 	us_lastcurx = x;
2649 	if (us_lastcurx >= us_trackww.usehx) us_lastcurx = us_trackww.usehx-1;
2650 	if (us_lastcurx < us_trackww.uselx) us_lastcurx = us_trackww.uselx;
2651 
2652 	/* draw the outline */
2653 	us_highl.col = HIGHLIT;
2654 	us_dragpoly->xv[0] = us_lastcurx;
2655 	us_dragpoly->yv[0] = us_draglowval;
2656 	us_dragpoly->xv[1] = us_lastcurx;
2657 	us_dragpoly->yv[1] = us_draghighval;
2658 	us_dragpoly->count = 2;
2659 	us_dragpoly->style = VECTORS;
2660 	us_showpoly(us_dragpoly, &us_trackww);
2661 
2662 	us_dragshown = 1;
2663 	return(FALSE);
2664 }
2665 
us_vpartdividerdone(void)2666 void us_vpartdividerdone(void)
2667 {
2668 	INTBIG lx, hx, ly, hy;
2669 	REGISTER WINDOWPART *w;
2670 
2671 	if (us_dragshown != 0)
2672 	{
2673 		/* undraw the outline */
2674 		us_highl.col = 0;
2675 		us_dragpoly->xv[0] = us_lastcurx;
2676 		us_dragpoly->yv[0] = us_draglowval;
2677 		us_dragpoly->xv[1] = us_lastcurx;
2678 		us_dragpoly->yv[1] = us_draghighval;
2679 		us_dragpoly->count = 2;
2680 		us_dragpoly->style = VECTORS;
2681 		us_showpoly(us_dragpoly, &us_trackww);
2682 
2683 		/* adjust the screen */
2684 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2685 		{
2686 			if (w->frame != us_trackww.frame) continue;
2687 			if (estrcmp(w->location, x_("entire")) == 0) continue;
2688 
2689 			us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
2690 			lx--;   hx++;
2691 			ly--;   hy++;
2692 			if (us_initthumbcoord >= lx-2 && us_initthumbcoord <= lx+2)
2693 			{
2694 				w->hratio = ((hx - us_lastcurx) * w->hratio + (hx - lx)/2) / (hx - lx);
2695 				if (w->hratio > 95)
2696 				{
2697 					el_curwindowpart = w;
2698 					us_killcurrentwindow(FALSE);
2699 					return;
2700 				}
2701 				if (w->hratio < 5)
2702 				{
2703 					el_curwindowpart = w;
2704 					us_killcurrentwindow(TRUE);
2705 					return;
2706 				}
2707 			}
2708 			if (us_initthumbcoord >= hx-2 && us_initthumbcoord <= hx+2)
2709 			{
2710 				w->hratio = ((us_lastcurx - lx) * w->hratio + (hx - lx)/2) / (hx - lx);
2711 				if (w->hratio > 95)
2712 				{
2713 					el_curwindowpart = w;
2714 					us_killcurrentwindow(FALSE);
2715 					return;
2716 				}
2717 				if (w->hratio < 5)
2718 				{
2719 					el_curwindowpart = w;
2720 					us_killcurrentwindow(TRUE);
2721 					return;
2722 				}
2723 			}
2724 		}
2725 
2726 		/* remember the explorer percentage */
2727 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2728 		{
2729 			if ((w->state&WINDOWTYPE) != EXPLORERWINDOW) continue;
2730 			us_explorerratio = w->hratio;
2731 		}
2732 		us_beginchanges();
2733 		us_drawmenu(1, us_trackww.frame);
2734 		us_endchanges(NOWINDOWPART);
2735 		us_state |= HIGHLIGHTSET;
2736 		us_showallhighlight();
2737 	}
2738 }
2739 
us_hpartdividerbegin(INTBIG y,INTBIG lx,INTBIG hx,WINDOWFRAME * wf)2740 void us_hpartdividerbegin(INTBIG y, INTBIG lx, INTBIG hx, WINDOWFRAME *wf)
2741 {
2742 	/* initialize polygon */
2743 	if (us_dragpoly == NOPOLYGON) us_dragpoly = allocpolygon(4, us_tool->cluster);
2744 	us_dragpoly->desc = &us_highl;
2745 
2746 	us_dragshown = 0;
2747 	us_initthumbcoord = y;
2748 	us_draglowval = lx;
2749 	us_draghighval = hx;
2750 
2751 	us_trackww.screenlx = us_trackww.uselx = 0;
2752 	us_trackww.screenhx = us_trackww.usehx = wf->swid;
2753 	us_trackww.screenly = us_trackww.usely = 0;
2754 	us_trackww.screenhy = us_trackww.usehy = wf->shei;
2755 	us_trackww.frame = wf;
2756 	us_trackww.state = DISPWINDOW;
2757 	computewindowscale(&us_trackww);
2758 }
2759 
us_hpartdividerdown(INTBIG x,INTBIG y)2760 BOOLEAN us_hpartdividerdown(INTBIG x, INTBIG y)
2761 {
2762 	if (us_dragshown != 0)
2763 	{
2764 		/* if it didn't actually move, go no further */
2765 		if (y == us_lastcury) return(FALSE);
2766 
2767 		/* undraw the line */
2768 		us_highl.col = 0;
2769 		us_dragpoly->xv[0] = us_draglowval;
2770 		us_dragpoly->yv[0] = us_lastcury;
2771 		us_dragpoly->xv[1] = us_draghighval;
2772 		us_dragpoly->yv[1] = us_lastcury;
2773 		us_dragpoly->count = 2;
2774 		us_dragpoly->style = VECTORS;
2775 		us_showpoly(us_dragpoly, &us_trackww);
2776 	}
2777 
2778 	us_lastcury = y;
2779 	if (us_lastcury >= us_trackww.usehy) us_lastcury = us_trackww.usehy-1;
2780 	if (us_lastcury < us_trackww.usely) us_lastcury = us_trackww.usely;
2781 
2782 	/* draw the outline */
2783 	us_highl.col = HIGHLIT;
2784 	us_dragpoly->xv[0] = us_draglowval;
2785 	us_dragpoly->yv[0] = us_lastcury;
2786 	us_dragpoly->xv[1] = us_draghighval;
2787 	us_dragpoly->yv[1] = us_lastcury;
2788 	us_dragpoly->count = 2;
2789 	us_dragpoly->style = VECTORS;
2790 	us_showpoly(us_dragpoly, &us_trackww);
2791 
2792 	us_dragshown = 1;
2793 	return(FALSE);
2794 }
2795 
us_hpartdividerdone(void)2796 void us_hpartdividerdone(void)
2797 {
2798 	INTBIG lx, hx, ly, hy;
2799 	REGISTER WINDOWPART *w;
2800 
2801 	if (us_dragshown != 0)
2802 	{
2803 		/* undraw the outline */
2804 		us_highl.col = 0;
2805 		us_dragpoly->xv[0] = us_draglowval;
2806 		us_dragpoly->yv[0] = us_lastcury;
2807 		us_dragpoly->xv[1] = us_draghighval;
2808 		us_dragpoly->yv[1] = us_lastcury;
2809 		us_dragpoly->count = 2;
2810 		us_dragpoly->style = VECTORS;
2811 		us_showpoly(us_dragpoly, &us_trackww);
2812 
2813 		/* adjust the screen */
2814 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2815 		{
2816 			if (w->frame != us_trackww.frame) continue;
2817 			if (estrcmp(w->location, x_("entire")) == 0) continue;
2818 
2819 			us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
2820 			lx--;   hx++;
2821 			ly--;   hy++;
2822 			if (us_initthumbcoord >= ly-2 && us_initthumbcoord <= ly+2)
2823 			{
2824 				w->vratio = ((hy - us_lastcury) * w->vratio + (hy - ly)/2) / (hy - ly);
2825 				if (w->vratio > 95)
2826 				{
2827 					el_curwindowpart = w;
2828 					us_killcurrentwindow(FALSE);
2829 					return;
2830 				}
2831 				if (w->vratio < 5)
2832 				{
2833 					el_curwindowpart = w;
2834 					us_killcurrentwindow(TRUE);
2835 					return;
2836 				}
2837 			}
2838 			if (us_initthumbcoord >= hy-2 && us_initthumbcoord <= hy+2)
2839 			{
2840 				w->vratio = ((us_lastcury - ly) * w->vratio + (hy - ly)/2) / (hy - ly);
2841 				if (w->vratio > 95)
2842 				{
2843 					el_curwindowpart = w;
2844 					us_killcurrentwindow(FALSE);
2845 					return;
2846 				}
2847 				if (w->vratio < 5)
2848 				{
2849 					el_curwindowpart = w;
2850 					us_killcurrentwindow(TRUE);
2851 					return;
2852 				}
2853 			}
2854 		}
2855 		us_beginchanges();
2856 		us_drawmenu(1, us_trackww.frame);
2857 		us_endchanges(NOWINDOWPART);
2858 		us_state |= HIGHLIGHTSET;
2859 		us_showallhighlight();
2860 	}
2861 }
2862 
2863 /************************* MISCELLANEOUS *************************/
2864 
2865 /* cursor advance routine when stretching the highlight object */
us_stretchdown(INTBIG x,INTBIG y)2866 BOOLEAN us_stretchdown(INTBIG x, INTBIG y)
2867 {
2868 	/* pan the screen if the edge was hit */
2869 	us_panatscreenedge(&x, &y);
2870 
2871 	/* grid align the cursor value */
2872 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
2873 	{
2874 		(void)us_setxy(us_lastcurx, us_lastcury);
2875 		return(FALSE);
2876 	}
2877 	(void)getxy(&us_lastcurx, &us_lastcury);
2878 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
2879 
2880 	/* if the box is already being shown, erase it */
2881 	if (us_dragshown != 0)
2882 	{
2883 		/* if it didn't actually move, go no further */
2884 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
2885 
2886 		/* undraw the box */
2887 		us_invertstretch();
2888 	}
2889 
2890 	/* advance the box */
2891 	us_dragx = us_lastcurx;
2892 	us_dragy = us_lastcury;
2893 
2894 	/* draw the new box */
2895 	us_invertstretch();
2896 	us_dragshown = 1;
2897 	return(FALSE);
2898 }
2899 
us_invertstretch(void)2900 void us_invertstretch(void)
2901 {
2902 	us_wanttoinvert(us_dragox, us_dragoy, us_dragox, us_dragy,  us_dragwindow);
2903 	us_wanttoinvert(us_dragox, us_dragy,  us_dragx,  us_dragy,  us_dragwindow);
2904 	us_wanttoinvert(us_dragx,  us_dragy,  us_dragx,  us_dragoy, us_dragwindow);
2905 	us_wanttoinvert(us_dragx,  us_dragoy, us_dragox, us_dragoy, us_dragwindow);
2906 }
2907 
2908 /*
2909  * routine to clip and possibly draw a line from (fx,fy) to (tx,ty) in
2910  * window "w" with description "desc", texture "texture"
2911  */
us_wanttoinvert(INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,WINDOWPART * w)2912 void us_wanttoinvert(INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, WINDOWPART *w)
2913 {
2914 	if ((w->state&INPLACEEDIT) != 0)
2915 	{
2916 		xform(fx, fy, &fx, &fy, w->outofcell);
2917 		xform(tx, ty, &tx, &ty, w->outofcell);
2918 	}
2919 	fx = applyxscale(w, fx-w->screenlx) + w->uselx;
2920 	fy = applyyscale(w, fy-w->screenly) + w->usely;
2921 	tx = applyxscale(w, tx-w->screenlx) + w->uselx;
2922 	ty = applyyscale(w, ty-w->screenly) + w->usely;
2923 	if (clipline(&fx, &fy, &tx, &ty, w->uselx, w->usehx, w->usely, w->usehy)) return;
2924 	screeninvertline(w, fx, fy, tx, ty);
2925 }
2926 
2927 /* cursor advance routine when creating or moving an object */
us_dragdown(INTBIG x,INTBIG y)2928 BOOLEAN us_dragdown(INTBIG x, INTBIG y)
2929 {
2930 	REGISTER INTBIG i;
2931 
2932 	if (el_pleasestop != 0) return(TRUE);
2933 
2934 	/* pan the screen if the edge was hit */
2935 	us_panatscreenedge(&x, &y);
2936 
2937 	/* grid align the cursor value */
2938 	if (us_setxy(x, y) || us_dragwindow != el_curwindowpart)
2939 	{
2940 		(void)us_setxy(us_lastcurx, us_lastcury);
2941 		return(FALSE);
2942 	}
2943 	(void)getxy(&us_lastcurx, &us_lastcury);
2944 	gridalign(&us_lastcurx, &us_lastcury, 1, us_dragwindow->curnodeproto);
2945 	us_setcursorpos(NOWINDOWFRAME, us_lastcurx, us_lastcury);
2946 
2947 	/* if the box is already being shown, erase it */
2948 	if (us_dragshown != 0)
2949 	{
2950 		/* if it didn't actually move, go no further */
2951 		if (us_dragx == us_lastcurx && us_dragy == us_lastcury) return(FALSE);
2952 
2953 		/* undraw the box */
2954 		us_highl.col = 0;
2955 		us_showpoly(us_dragpoly, us_dragwindow);
2956 	}
2957 
2958 	/* advance the box */
2959 	for(i = 0; i < us_dragpoly->count; i++)
2960 	{
2961 		us_dragpoly->xv[i] += us_lastcurx - us_dragx;
2962 		us_dragpoly->yv[i] += us_lastcury - us_dragy;
2963 	}
2964 	us_dragx = us_lastcurx;
2965 	us_dragy = us_lastcury;
2966 
2967 	/* draw the new box */
2968 	us_highl.col = HIGHLIT;
2969 	us_showpoly(us_dragpoly, us_dragwindow);
2970 	us_dragshown = 1;
2971 	return(FALSE);
2972 }
2973 
2974 /* termination routine when stretching an area */
us_invertdragup(void)2975 void us_invertdragup(void)
2976 {
2977 	if (us_dragshown != 0) us_invertstretch();
2978 }
2979 
2980 /* termination routine when creating or moving an object */
us_dragup(void)2981 void us_dragup(void)
2982 {
2983 	if (us_dragshown != 0)
2984 	{
2985 		/* undraw the box */
2986 		us_highl.col = 0;
2987 		us_showpoly(us_dragpoly, us_dragwindow);
2988 	}
2989 }
2990 
2991 /*
2992  * Routine to pan the screen if the cursor at (x,y) hits the edge of window "us_dragwindow".
2993  * Adjusts the coordinates to be on the screen.
2994  */
us_panatscreenedge(INTBIG * x,INTBIG * y)2995 void us_panatscreenedge(INTBIG *x, INTBIG *y)
2996 {
2997 	REGISTER UINTBIG now;
2998 	REGISTER BOOLEAN didpan;
2999 
3000 	/* pan screen if drag went over edge */
3001 	didpan = FALSE;
3002 	if (*x >= us_dragwindow->usehx)
3003 	{
3004 		*x = us_dragwindow->usehx;
3005 		now = ticktime();
3006 		if (now - us_beforepantime >= MINSLIDEDELAY)
3007 		{
3008 			us_beforepantime = now;
3009 			us_slideleft((us_dragwindow->screenhx - us_dragwindow->screenlx) / 10);
3010 			didpan = TRUE;
3011 		}
3012 	}
3013 	if (*x <= us_dragwindow->uselx)
3014 	{
3015 		*x = us_dragwindow->uselx;
3016 		now = ticktime();
3017 		if (now - us_beforepantime >= MINSLIDEDELAY)
3018 		{
3019 			us_beforepantime = now;
3020 			us_slideleft(-(us_dragwindow->screenhx - us_dragwindow->screenlx) / 10);
3021 			didpan = TRUE;
3022 		}
3023 	}
3024 	if (*y >= us_dragwindow->usehy)
3025 	{
3026 		*y = us_dragwindow->usehy;
3027 		now = ticktime();
3028 		if (now - us_beforepantime >= MINSLIDEDELAY)
3029 		{
3030 			us_beforepantime = now;
3031 			us_slideup(-(us_dragwindow->screenhy - us_dragwindow->screenly) / 10);
3032 			didpan = TRUE;
3033 		}
3034 	}
3035 	if (*y <= us_dragwindow->usely)
3036 	{
3037 		*y = us_dragwindow->usely;
3038 		now = ticktime();
3039 		if (now - us_beforepantime >= MINSLIDEDELAY)
3040 		{
3041 			us_beforepantime = now;
3042 			us_slideup((us_dragwindow->screenhy - us_dragwindow->screenly) / 10);
3043 			didpan = TRUE;
3044 		}
3045 	}
3046 	if (didpan)
3047 	{
3048 		us_endchanges(NOWINDOWPART);
3049 		us_dragshown = 0;
3050 	}
3051 }
3052 
us_nullup(INTBIG x,INTBIG y)3053 BOOLEAN us_nullup(INTBIG x, INTBIG y)  { return(FALSE); }
3054 
us_nullvoid(void)3055 void us_nullvoid(void) {}
3056 
us_nullchar(INTBIG x,INTBIG y,INTSML ch)3057 BOOLEAN us_nullchar(INTBIG x, INTBIG y, INTSML ch) { return(FALSE); }
3058 
3059 /*
3060  * routine to ignore all cursor motion while the button is up
3061  */
us_ignoreup(INTBIG x,INTBIG y)3062 BOOLEAN us_ignoreup(INTBIG x, INTBIG y)
3063 {
3064 	gridalign(&x, &y, 1, el_curlib->curnodeproto);
3065 	us_setcursorpos(NOWINDOWFRAME, x, y);
3066 	return(FALSE);
3067 }
3068 
3069 /*
3070  * routine to cause termination of tracking when a key is typed
3071  */
us_stoponchar(INTBIG x,INTBIG y,INTSML chr)3072 BOOLEAN us_stoponchar(INTBIG x, INTBIG y, INTSML chr)
3073 {
3074 	if (chr == 'a' || chr == 'A')
3075 	{
3076 		el_pleasestop = 1;
3077 		(void)stopping(STOPREASONTRACK);
3078 	}
3079 	return(TRUE);
3080 }
3081 
3082 /*
3083  * routine to cause termination of tracking and pop stacked highlighting
3084  * when a key is typed
3085  */
us_stopandpoponchar(INTBIG x,INTBIG y,INTSML chr)3086 BOOLEAN us_stopandpoponchar(INTBIG x, INTBIG y, INTSML chr)
3087 {
3088 	if (chr == 'a' || chr == 'A')
3089 	{
3090 		el_pleasestop = 1;
3091 		(void)stopping(STOPREASONTRACK);
3092 		us_pophighlight(FALSE);
3093 	}
3094 	return(TRUE);
3095 }
3096