1 /*
2  * DBWdisplay.c --
3  *
4  * This file contains code for redisplaying layout on the display.
5  * It saves up information about what is to be redisplayed, then
6  * does all of the redisplay at a convenient time.
7  *
8  *     *********************************************************************
9  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
10  *     * Permission to use, copy, modify, and distribute this              *
11  *     * software and its documentation for any purpose and without        *
12  *     * fee is hereby granted, provided that the above copyright          *
13  *     * notice appear in all copies.  The University of California        *
14  *     * makes no representations about the suitability of this            *
15  *     * software for any purpose.  It is provided "as is" without         *
16  *     * express or implied warranty.  Export of this software outside     *
17  *     * of the United States of America may require an export license.    *
18  *     *********************************************************************
19  */
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWdisplay.c,v 1.5 2008/12/11 04:20:05 tim Exp $";
23 #endif  /* not lint */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "utils/magic.h"
30 #include "utils/malloc.h"
31 #include "utils/geometry.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "database/database.h"
35 #include "windows/windows.h"
36 #include "graphics/graphics.h"
37 #include "dbwind/dbwind.h"
38 #include "utils/utils.h"
39 #include "dbwind/dbwtech.h"
40 #include "utils/styles.h"
41 #include "utils/main.h"
42 #include "utils/tech.h"
43 #include "utils/signals.h"
44 
45 /* The following variable is exported to the rest of the world.
46  * It is read from the "styletype" line of the technology file,
47  * and defines the class of display styles file expected for
48  * this technology.  It defaults as below;  almost all technologies
49  * can use the default.
50  */
51 
52 char *DBWStyleType = "std";
53 
54 /* a round-up sort of integer division */
55 #define	ceilDiv(n,d)	( ((n) < 0)  ? -( ((-(n))+(d)-1) / d)  \
56 	: ((n)+(d)-1) / d )
57 
58 static bool debugit = FALSE;
59 
60 /* The following statics are just for convenience in talking between
61  * the top-level redisplay routine and the lower-level redisplay
62  * routines invoked during the recursive search.
63  */
64 
65 static MagWindow *dbwWindow;	/* Current window being redisplayed. */
66 static bool disWasPale;		/* TRUE if last rect was displayed pale */
67 static Rect rootClip;		/* Clip area for root area that is being
68 				 * redisplayed.
69 				 */
70 static Rect windClip;		/* Clip area for entire window. */
71 static int disStyle;		/* Display style. */
72 static Rect dbwWatchArea;	/* Area used to clip tiles being "watched" so
73 				 * that infinities don't cause arithmetic
74 				 * overflow.  In coords of cell being watched.
75 				 */
76 static Transform dbwWatchTrans;	/* Transform to root coords for watch tiles. */
77 static int dbwWatchDemo;	/* TRUE means use "demo" style for watch
78 				 * tile display.
79 				 */
80 static int  dbwSeeTypes;	/* TRUE means use tile type instead of
81 				   pointer value for watch display.
82 				*/
83 static Rect dbwMinBBox;		/* If bounding boxes aren't at least this
84 				 * large, don't bother displaying name and
85 				 * id.  The ur point of the box gives the
86 				 * minimum allowed dimensions.
87 				 */
88 static int dbwLabelSize;	/* Size to use for label drawing. */
89 static Rect *dbwExpandAmounts;	/* Box to accumulate total sizes of labels.
90 				 * Always refers to crec->dbw_expandAmounts
91 				 * in window being redrawn.
92 				 */
93 
94 /* The stuff below is shared between the top-level and action
95  * routines for redisplay.  It is used to identify the edit cell
96  * so it can be displayed differently.
97  */
98 
99 static CellDef *editDef;
100 static Transform editTrans;	/* Contains transform from edit cell to
101 				 * screen coordinates.  If edit cell isn't
102 				 * in this window, editDef is NULL.
103 				 */
104 static bool dbwAllSame;		/* Means don't display the edit cell
105 				 * differently after all.
106 				 */
107 
108 static bool dbwIsLocked;	/* Is window already locked */
109 static MagWindow *dbwLockW;	/* Window to lock */
110 static bool dbwNeedStyle;	/* Do we need to set the display style? */
111 
112 int DBWNumStyles = 0;		/* Number of styles usable in layer
113 				 * definitions.  This is also the amount
114 				 * to add to a style index to get its
115 				 * "pale" (non-edit-cell) version
116 				 */
117 
118 int RtrMetalWidth = 2;		/* These officially belong to the router */
119 int RtrPolyWidth = 2;		/* but they have been usurped for other	 */
120 int RtrContactWidth = 2;	/* purposes in DBWdisplay and in the plot
121 				 * module.
122 				 */
123 
124 extern char *MainMonType;	/* from main/main.c */
125 
126 /* Search functions, all of which are used before definition: */
127 
128 extern int dbwTileFunc(), dbwWatchFunc(), dbwLabelFunc();
129 extern int dbwPaintFunc(), dbwBBoxFunc();
130 extern int dbwWindowFunc(), dbwChangedFunc();
131 
132 
133 /*
134  * ----------------------------------------------------------------------------
135  * DBWredisplay --
136  *
137  * 	This procedure does the dirty of redisplaying information
138  *	on the graphics screen.  When it is done the given area of the
139  *	window will be correctly displayed, including the grid, any
140  *	watched tile planes, and tools.
141  *
142  *	This procedure locks windows as it goes.
143  *
144  * Results:
145  *	None.
146  *
147  * Side effects:
148  *	Stuff is drawn on the display in the given area.
149  * ----------------------------------------------------------------------------
150  */
151 
152 void
DBWredisplay(w,rootArea,clipArea)153 DBWredisplay(w, rootArea, clipArea)
154     MagWindow *w;			/* Window some of whose contents are to be
155 				 * redisplayed.
156 				 */
157     Rect *rootArea;		/* The area that must be redisplayed, in
158 				 * root cell coordinates.
159 				 */
160     Rect *clipArea;		/* The screen area that we should clip to
161 				 */
162 {
163     int i;
164     TileTypeBitMask *mask;
165     SearchContext scontext;
166     Rect largerArea, labelArea, screenArea;
167     int bitMask, lambdasPerPixel, pixelsPerLambda;
168     DBWclientRec *crec;
169     CellDef *cellDef;
170     TileTypeBitMask layers, rmask;
171 
172     /*
173     TxPrintf("Root area (%d, %d) (%d, %d) redisplay.\n",
174 	    rootArea->r_xbot, rootArea->r_ybot,
175 	    rootArea->r_xtop, rootArea->r_ytop);
176     */
177 
178 #ifdef MAGIC_WRAPPER
179     /* Honor the display suspend state */
180     if (GrDisplayStatus == DISPLAY_SUSPEND) return;
181 #endif
182 
183     GrLock(w, TRUE);
184 
185     /* Round up the redisplay area by 1 pixel on all sides.  This
186      * is needed because DBSrPaintArea won't return tiles that touch
187      * the area without overlapping it.  Without the round-up, there
188      * will be occasional (in fact, frequent), one-pixel wide slivers.
189      */
190 
191     largerArea = *rootArea;
192     largerArea.r_xbot -= 1;
193     largerArea.r_ybot -= 1;
194     largerArea.r_xtop += 1;
195     largerArea.r_ytop += 1;
196 
197     crec = ((DBWclientRec *) w->w_clientData);
198     cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
199 
200     pixelsPerLambda = w->w_scale / SUBPIXEL;
201     lambdasPerPixel = (SUBPIXEL / w->w_scale) + 1;
202 
203     if ((crec->dbw_origin.p_x != w->w_origin.p_x)
204 	|| (crec->dbw_origin.p_y != w->w_origin.p_y)
205 	|| (crec->dbw_scale != w->w_scale)
206 	|| (crec->dbw_surfaceArea.r_xbot != w->w_surfaceArea.r_xbot)
207 	|| (crec->dbw_surfaceArea.r_ybot != w->w_surfaceArea.r_ybot)
208 	|| (crec->dbw_surfaceArea.r_xtop != w->w_surfaceArea.r_xtop)
209 	|| (crec->dbw_surfaceArea.r_ytop != w->w_surfaceArea.r_ytop))
210     {
211 	/* The window has changed size or position or scale,
212 	 * so update measurements on label size in this window.
213 	 * Also, pick a size for labels based on the scale in
214 	 * half the window:  the idea is to make the labels about
215 	 * half the height of typical wires.
216 	 */
217 	int halfWireWidth;
218 	Rect text;
219 
220 	halfWireWidth = MAX(RtrMetalWidth, RtrPolyWidth);
221 	halfWireWidth = (halfWireWidth * w->w_scale) >> (SUBPIXELBITS + 1);
222 	for (i = GR_TEXT_XLARGE; i >= GR_TEXT_SMALL; i--)
223 	{
224 	    GrLabelSize("B", GEO_CENTER, i, &text);
225 	    if (halfWireWidth > (text.r_ytop - text.r_ybot)) break;
226 	}
227 	if (i < GR_TEXT_SMALL) i = GR_TEXT_SMALL;
228 	if ((3 * halfWireWidth) <= (text.r_ytop - text.r_ybot))
229 	    crec->dbw_labelSize = -lambdasPerPixel;
230 	else crec->dbw_labelSize = i;
231 
232 	crec->dbw_expandAmounts.r_xbot = 0;
233 	crec->dbw_expandAmounts.r_ybot = 0;
234 	crec->dbw_expandAmounts.r_xtop = 0;
235 	crec->dbw_expandAmounts.r_ytop = 0;
236 
237 	crec->dbw_origin = w->w_origin;
238 	crec->dbw_scale = w->w_scale;
239 	crec->dbw_surfaceArea = w->w_surfaceArea;
240     }
241 
242     /* Labels can stick out a long way from the point they are
243      * anchored to.  In the code that draws labels we record the
244      * size (in pixels) of the largest label in the window.  Here
245      * we use that information to increase the size of the search
246      * area for labels enough to be sure we'll see any label that
247      * falls partially or completely in the area we're redisplaying.
248      * Note:  we have to also include the size of the label cross
249      * in the area to be redisplayed.
250      */
251 
252     labelArea = largerArea;
253     (void) GeoInclude(&GrCrossRect, &crec->dbw_expandAmounts);
254     if (pixelsPerLambda > 0)
255     {
256 	labelArea.r_xtop -=
257 		ceilDiv(crec->dbw_expandAmounts.r_xbot, pixelsPerLambda);
258 	labelArea.r_ytop -=
259 		ceilDiv(crec->dbw_expandAmounts.r_ybot, pixelsPerLambda);
260 	labelArea.r_xbot -=
261 		ceilDiv(crec->dbw_expandAmounts.r_xtop, pixelsPerLambda);
262 	labelArea.r_ybot -=
263 		ceilDiv(crec->dbw_expandAmounts.r_ytop, pixelsPerLambda);
264     }
265     else
266     {
267 	labelArea.r_xtop -= crec->dbw_expandAmounts.r_xbot * lambdasPerPixel;
268 	labelArea.r_ytop -= crec->dbw_expandAmounts.r_ybot * lambdasPerPixel;
269 	labelArea.r_xbot -= crec->dbw_expandAmounts.r_xtop * lambdasPerPixel;
270 	labelArea.r_ybot -= crec->dbw_expandAmounts.r_ytop * lambdasPerPixel;
271     }
272 
273     /**
274     TxPrintf("Need to expand area by (%d %d) (%d %d) pixels.\n",
275 	crec->dbw_expandAmounts.r_xbot,
276 	crec->dbw_expandAmounts.r_ybot,
277 	crec->dbw_expandAmounts.r_xtop,
278 	crec->dbw_expandAmounts.r_ytop);
279     **/
280 
281     /* Set the clipping rectangle to contain only the area being displayed. */
282 
283     dbwWindow = w;
284     windClip = w->w_screenArea;
285     WindSurfaceToScreen(w, rootArea, &rootClip);
286     GrClipTo(&rootClip);
287 
288     scontext.scx_area = largerArea;
289     scontext.scx_use = ((CellUse *)w->w_surfaceID);
290     scontext.scx_x = scontext.scx_y = -1;
291     scontext.scx_trans = GeoIdentityTransform;
292     bitMask = crec->dbw_bitmask;
293 
294     /* See if this window contains the edit cell.  If so, remember
295      * information about the edit cell so we can identify it during
296      * the action routines.
297      */
298 
299     if (cellDef == EditRootDef)
300     {
301         editDef = EditCellUse->cu_def;
302 	editTrans = EditToRootTransform;
303     }
304     else editDef = NULL;
305     if (crec->dbw_flags & DBW_ALLSAME) dbwAllSame = TRUE;
306     else dbwAllSame = FALSE;
307 
308     /* Empty the area of all previous info. */
309 
310     GrClipBox(&rootClip, STYLE_ERASEALL);
311 
312     /* Go through all of the tile display styles.  For each
313      * style, if there are tiles that include that style, then
314      * find and display all the tiles.
315      *
316      * We use the fast version of GrClipBox in the filter
317      * function, GrFastBox.  To use it requires that we set
318      * the style before the call, which we do inside of
319      * dbwPaintFunc() on the first box displayed for each
320      * style.
321      *
322      * Unlock the window before the following loop to avoid
323      * holding the lock too long.
324      */
325     GrUnlock(w);
326     dbwLockW = w;
327     dbwIsLocked = FALSE;
328     for (i = 0; i < DBWNumStyles; i++)
329     {
330 	mask = DBWStyleToTypes(i);
331 	TTMaskAndMask3(&layers, mask, &crec->dbw_visibleLayers);
332 	if (!TTMaskIsZero(&layers))
333 	{
334 	    TileType t, s;
335 	    TileTypeBitMask *rMask;
336 
337 	    /* For each contact type, if the contact is not visible,	*/
338 	    /* display any of its residue layers that are visible.	*/
339 
340 	    for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
341 		if (DBIsContact(t))
342 		    if (!TTMaskHasType(&layers, t))
343 		    {
344 			rMask = DBResidueMask(t);
345 			if (TTMaskIntersect(rMask, &layers))
346 			    TTMaskSetType(&layers, t);
347 		    }
348 
349 	    /* Treat any stacking type in the mask like the	*/
350 	    /* residue type whose home plane is the same as	*/
351 	    /* the home plane of the stacking type.		*/
352 
353 	    for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++)
354 		if (TTMaskHasType(&layers, t))
355 		    for (s = DBNumUserLayers; s < DBNumTypes; s++)
356 		    {
357 			rMask = DBResidueMask(s);
358 			if (TTMaskHasType(&layers, s) &&
359 				TTMaskHasType(rMask, t))
360 			    if (DBPlane(s) != DBPlane(t))
361 				TTMaskClearType(&layers, s);
362 		    }
363 
364 	    /*
365 	     * To avoid holding a lock for too long, we don't set it
366 	     * until we actually see something to display, and we
367 	     * clear it immediately after we've displayed a style
368 	     * that had something in it.
369 	     */
370 	    disStyle = i + TECHBEGINSTYLES;
371 	    disWasPale = FALSE;		/* Using normal solid style */
372 	    dbwNeedStyle = TRUE;	/* Haven't set style yet */
373 	    if (DBTreeSrUniqueTiles(&scontext, &layers, bitMask,
374 		    dbwPaintFunc, (ClientData) NULL))
375 	    {
376 		/* We were interrupted.  If we deal with backing store,	*/
377 		/* it must be invalidated.				*/
378 		if (GrFreeBackingStorePtr != NULL)
379 		    (*GrFreeBackingStorePtr)(w);
380 	    }
381 
382 	    if (dbwIsLocked)
383 	    {
384 		GrUnlock(w);
385 		dbwIsLocked = FALSE;
386 	    }
387 	}
388     }
389 
390     GrLock(w, TRUE);
391     GrClipTo(&rootClip);
392 
393     /* Now, find any labels that are visible and display them.
394      * Label text is only displayed for certain ranges of magnification:
395      * If a window is too zoomed-out, then text redisplay takes too
396      * long and just clutters up the screen anyway.  For displaying
397      * labels, we set the clip area to the whole screen (otherwise
398      * new labels will be clipped to just the paint area).  This only
399      * works because (a) graphics clips down to the window's actual
400      * displayed area anyway, and (b) labels are opaque layers on top
401      * of everything else (otherwise there might be color mixing
402      * problems).
403      */
404 
405     if (crec->dbw_flags & DBW_SEELABELS)
406     {
407 	scontext.scx_area = labelArea;
408 
409 	/* make sure that we are searching an area, not just a point */
410 	scontext.scx_area.r_xtop = MAX(scontext.scx_area.r_xtop,
411 		scontext.scx_area.r_xbot + 1);
412 	scontext.scx_area.r_ytop = MAX(scontext.scx_area.r_ytop,
413 		scontext.scx_area.r_ybot + 1);
414 	dbwLabelSize = crec->dbw_labelSize;
415 	dbwExpandAmounts = &crec->dbw_expandAmounts;
416 	GrClipTo(&GrScreenRect);
417 
418         /* Set style information beforehand */
419         GrSetStuff(STYLE_LABEL);
420 	(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
421 		(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
422 		dbwLabelFunc, (ClientData) NULL);
423 	GrClipTo(&rootClip);
424     }
425 
426     /* Next, display the bounding boxes that are visible.  Before doing
427      * this, calculate the area occupied by the text "BBB".  A cell won't
428      * get its id or name displayed unless its bbox is at least this
429      * large.
430      */
431 
432     if (crec->dbw_flags & DBW_SEECELLS)
433     {
434 	GrLabelSize("BBB", GEO_CENTER, GR_TEXT_SMALL, &dbwMinBBox);
435 	dbwMinBBox.r_xtop -= dbwMinBBox.r_xbot;
436 	dbwMinBBox.r_ytop -= dbwMinBBox.r_ybot;
437 
438 	/* Redisplay cell names as if the whole window were visible.
439 	 * This must be done since we slide the names around to fit
440 	 * into the clip area.  Set the style beforehand for speed.
441 	 */
442 
443 	GrClipTo(&GrScreenRect); /* Will be cut down to window size by
444 				  * the graphics module.
445 				  */
446 	scontext.scx_area = largerArea;
447 	GrSetStuff(STYLE_BBOX);
448 	(void) DBTreeSrCells(&scontext, bitMask, dbwBBoxFunc, (ClientData)NULL);
449 	GrClipTo(&rootClip);
450     }
451 
452     /* Now redisplay the grid.  This code is a bit tricky because
453      * it makes sure that the origin ends up on a grid line.
454      */
455 
456     if (crec->dbw_flags & DBW_GRID)
457     {
458 	int width, height;
459 	Rect gridRect;
460 
461 	/* Compute a grid template rectangle, in screen coordinates, that
462 	 * is near the lower-left corner of the window.
463 	 */
464 
465 	gridRect.r_ll = w->w_origin;
466 	width = crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot;
467 	height = crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot;
468 	gridRect.r_xbot -= w->w_scale *
469 		((w->w_surfaceArea.r_xbot - crec->dbw_gridRect.r_xbot) % width);
470 	gridRect.r_ybot -= w->w_scale *
471 		((w->w_surfaceArea.r_ybot - crec->dbw_gridRect.r_ybot) % height);
472 	gridRect.r_xtop = gridRect.r_xbot + w->w_scale*width;
473 	gridRect.r_ytop = gridRect.r_ybot + w->w_scale*height;
474 	GrClipBox(&gridRect, STYLE_GRID);
475 
476 	/* Redisplay a little square around the origin for the edit cell
477 	 * (if the edit cell is in this window).  Make the origin 4 pixels
478 	 * across, but don't display it unless this is less than two lambda
479 	 * units.  That way, we always know how much to redisplay (in lambda
480 	 * units), when the edit cell changes.
481 	 */
482 
483 	if (editDef != NULL)
484 	{
485 	    Rect r, r2;
486 	    r.r_xbot = r.r_ybot = -1;
487 	    r.r_xtop = r.r_ytop = 1;
488 	    WindSurfaceToScreen(w, &r, &r2);
489 	    if ((r2.r_xtop - r2.r_xbot) >= 4)
490 	    {
491 		GeoTransRect(&EditToRootTransform, &GeoNullRect, &r2);
492 		WindSurfaceToScreen(w, &r2, &r);
493 		r.r_xbot -= 2;
494 		r.r_xtop += 2;
495 		r.r_ybot -= 2;
496 		r.r_ytop += 2;
497 		GrClipBox(&r, STYLE_ORIGIN);
498 	    }
499 	}
500     }
501 
502     /* If there is a tile plane being "watched", redisplay
503      * its structure.
504      */
505 
506     if (crec->dbw_watchPlane >= 0)
507     {
508 	Transform toCell;
509 
510 	GeoInvertTrans(&crec->dbw_watchTrans, &toCell);
511 	GeoTransRect(&toCell, &w->w_surfaceArea, &dbwWatchArea);
512 	dbwWatchArea.r_xbot -= lambdasPerPixel;
513 	dbwWatchArea.r_xtop += lambdasPerPixel;
514 	dbwWatchArea.r_ybot -= lambdasPerPixel;
515 	dbwWatchArea.r_ytop += lambdasPerPixel;
516 	dbwWatchTrans = crec->dbw_watchTrans;
517         dbwWatchDemo = ((crec->dbw_flags & DBW_WATCHDEMO) != 0);
518 	dbwSeeTypes = ((crec->dbw_flags & DBW_SEETYPES) != 0);
519 	(void) DBSrPaintArea((Tile *) NULL,
520 	    crec->dbw_watchDef->cd_planes[crec->dbw_watchPlane],
521 	    &dbwWatchArea, &DBAllTypeBits, dbwTileFunc, (ClientData) NULL);
522     }
523 
524     /* Record information so that the highlight manager will redisplay
525      * highlights over the area we just redisplayed.
526      */
527 
528     DBPaintPlane(crec->dbw_hlRedraw, &labelArea,
529 	    DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
530 	    (PaintUndoInfo *) NULL);
531 
532     /* display a debugging box which shows which area should be redrawn */
533     if (debugit)
534     {
535 	WindSurfaceToScreen(w, &largerArea, &screenArea);
536 	(void) GrClipBox(&screenArea, STYLE_LABEL);
537     }
538 
539 #ifdef	notdef
540     /* finally, display the plowing debugging information */
541     cmdPlowDisplayEdges(w, rootArea, clipArea);
542 #endif	/* notdef */
543 
544     GrUnlock(w);
545 
546     /* Create backing store of this area for quick refresh of highlight */
547     /* areas.								*/
548 
549     if (GrPutBackingStorePtr != NULL)
550 	(*GrPutBackingStorePtr)(w, &rootClip);
551 }
552 
553 /*
554  * ----------------------------------------------------------------------------
555  *
556  * dbwPaintFunc --
557  *
558  * 	Invoked by database searching routines during redisplay to
559  *	draw a tile on the screen.
560  *
561  * Results:
562  *	Always returns 0 to keep the search from aborting.
563  *
564  * Side effects:
565  *	Clips and draws a paint tile.
566  *
567  * ----------------------------------------------------------------------------
568  */
569 
570 int
dbwPaintFunc(tile,cxp)571 dbwPaintFunc(tile, cxp)
572     Tile *tile;	/* Tile to be redisplayed. */
573     TreeContext *cxp;		/* From DBTreeSrTiles */
574 {
575     SearchContext *scx = cxp->tc_scx;
576 			/* Contains pointer to use containing def
577 			 * in which tile appears, and transform to
578 			 * screen coordinates.
579 			 */
580 
581 #ifdef MAGIC_WRAPPER
582     /* This allows the display to be interrupted when running Tcl/Tk.	*/
583     /* Because graphics are not handled by a separate process, the	*/
584     /* drawing routine itself is responsible for periodically checking	*/
585     /* the graphics event queue to see if something is pending.		*/
586 
587     if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
588     {
589 	GrDisplayStatus = DISPLAY_IN_PROGRESS;
590 	if (GrEventPendingPtr)
591 	{
592 	    if ((*GrEventPendingPtr)())
593 		sigOnInterrupt(0);
594 	    else
595 		SigSetTimer(0);
596 	}
597     }
598 #endif
599 
600     /* Ignore DRC error tiles in anything but the top-level window */
601     if (scx->scx_use != (CellUse *)dbwWindow->w_surfaceID)
602     {
603 	TileType ttype = TiGetType(tile);
604 	if (ttype == TT_ERROR_P || ttype == TT_ERROR_S || ttype == TT_ERROR_PS)
605 	    return 0;
606     }
607 
608     if (!dbwIsLocked)
609     {
610 	GrLock(dbwLockW, TRUE);
611 	GrClipTo(&rootClip);
612 	dbwIsLocked = TRUE;
613     }
614     if (dbwNeedStyle)
615     {
616 	GrSetStuff(disStyle);
617 	dbwNeedStyle = FALSE;
618     }
619 
620     /* If this isn't the edit cell, add 64 to the display style
621      * to be used.
622      */
623 
624     if (!dbwAllSame && ((editDef != scx->scx_use->cu_def)
625 	|| (scx->scx_trans.t_a != editTrans.t_a)
626 	|| (scx->scx_trans.t_b != editTrans.t_b)
627 	|| (scx->scx_trans.t_c != editTrans.t_c)
628 	|| (scx->scx_trans.t_d != editTrans.t_d)
629 	|| (scx->scx_trans.t_e != editTrans.t_e)
630 	|| (scx->scx_trans.t_f != editTrans.t_f)))
631     {
632 	if (!disWasPale)
633 	{
634 	    GrSetStuff(disStyle + DBWNumStyles);
635 	    disWasPale = TRUE;
636 	}
637     }
638     else
639     {
640 	if (disWasPale)
641 	{
642 	    GrSetStuff(disStyle);
643 	    disWasPale = FALSE;
644 	}
645     }
646 
647     /* Note:  GrFastBox() has been replaced here with GrBox(). 	*/
648     /* This checks for non-square outlines before deciding	*/
649     /* whether to render the outline with a fast rectangle-	*/
650     /* drawing routine or to render it segment by segment.	*/
651 
652     GrBox(dbwWindow, &scx->scx_trans, tile);
653     return 0;
654 }
655 
656 
657 /*
658  * ----------------------------------------------------------------------------
659  *
660  * DBWDrawLabel --
661  *
662  * 	This procedure does all the work of actually drawing labels
663  * 	on the screen.  It is invoked by label redisplay code and also
664  *	by the selection redisplay code.
665  *
666  * Results:
667  *	None.
668  *
669  * Side effects:
670  *	The label given by text, rect, and pos is drawn on the screen
671  *	in style "style" and size "labelSize".  The caller must have set
672  *	up all of the clipping information for the window in which the
673  *	label is to be drawn.  This procedure updates sizeBox to be
674  *	large enough to hold the total pixel area occupied by the label
675  *	(assuming it were drawn at (0,0)).
676  *
677  * ----------------------------------------------------------------------------
678  */
679 
680 void
DBWDrawLabel(label,rect,pos,style,labelSize,sizeBox)681 DBWDrawLabel(label, rect, pos, style, labelSize, sizeBox)
682     Label *label;		/* Text to be displayed. */
683     Rect *rect;			/* labrect, clipped to the visible window
684 				 */
685     int pos;			/* Position of text relative to rect (e.g.
686 				 * GEO_NORTH) in screen coordinates.
687 				 */
688     int style;                 /* Style to use for redisplay; if -1 then
689                                 * this has already been set by the caller
690                                 * and we shouldn't call GrSetStuff.
691                                 */
692 
693     int labelSize;		/* Size to use for drawing labels.  If < 0 then
694 				 * no text is drawn:  only the box.
695 				 */
696     Rect *sizeBox;		/* Expanded if necessary to include the
697 				 * screen area of the text for this label.
698 				 */
699 {
700     Point p;
701     Rect location;
702     char *text = label->lab_text;
703     int result;
704 
705     if (style >= 0) GrSetStuff(style);
706     GrDrawFastBox(rect, labelSize);
707     if (labelSize < 0) return;
708 
709     switch (pos)
710     {
711 	case GEO_CENTER:
712 	    p.p_x = (rect->r_xbot + rect->r_xtop)/2;
713 	    p.p_y = (rect->r_ybot + rect->r_ytop)/2;
714 	    break;
715 	case GEO_NORTH:
716 	    p.p_x = (rect->r_xbot + rect->r_xtop)/2;
717 	    p.p_y = rect->r_ytop;
718 	    break;
719 	case GEO_NORTHEAST:
720 	    p = rect->r_ur;
721 	    break;
722 	case GEO_EAST:
723 	    p.p_x = rect->r_xtop;
724 	    p.p_y = (rect->r_ybot + rect->r_ytop)/2;
725 	    break;
726 	case GEO_SOUTHEAST:
727 	    p.p_x = rect->r_xtop;
728 	    p.p_y = rect->r_ybot;
729 	    break;
730 	case GEO_SOUTH:
731 	    p.p_x = (rect->r_xbot + rect->r_xtop)/2;
732 	    p.p_y = rect->r_ybot;
733 	    break;
734 	case GEO_SOUTHWEST:
735 	    p = rect->r_ll;
736 	    break;
737 	case GEO_WEST:
738 	    p.p_x = rect->r_xbot;
739 	    p.p_y = (rect->r_ybot + rect->r_ytop)/2;
740 	    break;
741 	case GEO_NORTHWEST:
742 	    p.p_x = rect->r_xbot;
743 	    p.p_y = rect->r_ytop;
744 	    break;
745     }
746     if (GrPutText(text, style, &p, pos, labelSize, FALSE,
747 			&GrScreenRect, &location))
748     {
749 	sizeBox->r_xbot = MIN(sizeBox->r_xbot, location.r_xbot - p.p_x);
750 	sizeBox->r_ybot = MIN(sizeBox->r_ybot, location.r_ybot - p.p_y);
751 	sizeBox->r_xtop = MAX(sizeBox->r_xtop, location.r_xtop - p.p_x);
752 	sizeBox->r_ytop = MAX(sizeBox->r_ytop, location.r_ytop - p.p_y);
753     }
754 }
755 
756 /*
757  * ----------------------------------------------------------------------------
758  *
759  * DBWDrawFontLabel --
760  *
761  *	This procedure is like DBWDrawLabel but handles rendered font
762  *	labels.  It is invoked by the label redisplay code in dbwind
763  *	and select.  Unlike DBWDrawLabel, it does all the layout-to-screen
764  *	transformations itself.
765  *
766  * Results:
767  *	None.
768  *
769  * Side effects:
770  *	The label given by text, rect, and pos is drawn on the screen
771  *	in style "style" and size "labelSize".  The caller must have set
772  *	up all of the clipping information for the window in which the
773  *	label is to be drawn.  This procedure updates sizeBox to be
774  *	large enough to hold the total pixel area occupied by the label
775  *	(assuming it were drawn at (0,0)).
776  *
777  * ----------------------------------------------------------------------------
778  */
779 
780 void
DBWDrawFontLabel(label,window,trans,style)781 DBWDrawFontLabel(label, window, trans, style)
782     Label *label;
783     MagWindow *window;
784     Transform *trans;
785     int style;		/* If -1, style is already set */
786 {
787     Point *p, newcorner, scrncorners[4], labOrigin;
788     Rect rootArea, labrect;
789     int i, rotate, minv, scaledLambdasPerPixel;
790     dlong tmp, dval, scale;
791     double rads;
792 
793     GeoTransRect(trans, &label->lab_rect, &rootArea);
794     WindSurfaceToScreen(window, &rootArea, &labrect);
795     labOrigin.p_x = (rootArea.r_xbot + rootArea.r_xtop) << 2;
796     labOrigin.p_y = (rootArea.r_ybot + rootArea.r_ytop) << 2;
797 
798     /* This bit of code sets the scale for the "cross" associated with	*/
799     /* a label as a logarithmic function of the window scale.  This is	*/
800     /* completely subjective, but seems to produce a decent result.	*/
801 
802     scaledLambdasPerPixel = 0;
803     i = (SUBPIXEL / window->w_scale);
804     while (i != 0)
805     {
806 	i >>= 1;
807 	scaledLambdasPerPixel++;
808     }
809 
810     if (style >= 0) GrSetStuff(style);
811     GrDrawFastBox(&labrect, -scaledLambdasPerPixel);
812 
813     for (i = 0; i < 4; i++)
814     {
815 	GeoTransPointDelta(trans, &label->lab_corners[i], &newcorner);
816 
817 	/* Effectively, WindPointToScreen(), but with an	*/
818 	/* extra scalefactor of 8, including computing the 	*/
819 	/* (unclipped) origin from the center of rootArea.	*/
820 
821 	tmp = labOrigin.p_x + newcorner.p_x;
822 	tmp -= (dlong)window->w_surfaceArea.r_xbot << 3;
823 	dval = ((dlong)window->w_origin.p_x << 3) + (dlong)(tmp * window->w_scale);
824 	scrncorners[i].p_x = (int)(dval >> (SUBPIXELBITS + 3));
825 
826 	tmp = labOrigin.p_y + newcorner.p_y;
827 	tmp -= (dlong)window->w_surfaceArea.r_ybot << 3;
828 	dval = ((dlong)window->w_origin.p_y << 3) + (dlong)(tmp * window->w_scale);
829 	scrncorners[i].p_y = (int)(dval >> (SUBPIXELBITS + 3));
830     }
831 
832     /* Ensure that the label is always drawn with text upright.	*/
833     /* Compute rotation from the transformed baseline angle.	*/
834     /* (The "2" is a slop factor to account for round-off error	*/
835     /* in the computation of scrncorners.)			*/
836 
837     rotate = GeoTransAngle(trans, label->lab_rotate);
838     if ((rotate >= 0 && rotate < 90) || (rotate >= 180 && rotate < 270))
839     {
840 	/* Startpoint is the bottommost point.   Due to roundoff error,	*/
841 	/* we need to watch closely when the angle is close to a	*/
842 	/* multiple of 90 degrees.					*/
843 
844 	minv = scrncorners[0].p_y;
845 	p = &scrncorners[0];
846 	for (i = 1; i < 4; i++)
847 	{
848 	    if ((scrncorners[i].p_y - 2) < minv)
849 	    {
850 		if ((scrncorners[i].p_y + 2) > minv)
851 		{
852 		    if (((rotate < 5) || (rotate >= 180 && rotate < 185)) &&
853 				(scrncorners[i].p_x > p->p_x))
854 			continue;
855 		    if (((rotate > 85 && rotate < 90) || (rotate > 265)) &&
856 				(scrncorners[i].p_x < p->p_x))
857 			continue;
858 		}
859 		minv = scrncorners[i].p_y;
860 		p = &scrncorners[i];
861 	    }
862 	}
863     }
864     else
865     {
866 	/* startpoint is the leftmost point */
867 	minv = scrncorners[0].p_x;
868 	p = &scrncorners[0];
869 	for (i = 1; i < 4; i++)
870 	{
871 	    if ((scrncorners[i].p_x - 2) < minv)
872 	    {
873 		if ((scrncorners[i].p_x + 2) > minv)
874 		{
875 		    if (((rotate < 95) || (rotate >= 270 && rotate < 275)) &&
876 				(scrncorners[i].p_y < p->p_y))
877 			continue;
878 		    if (((rotate > 175 && rotate < 180) || (rotate > 355)) &&
879 				(scrncorners[i].p_y > p->p_y))
880 			continue;
881 		}
882 		minv = scrncorners[i].p_x;
883 		p = &scrncorners[i];
884 	    }
885 	}
886     }
887     if (rotate >= 90 && rotate < 270)
888     {
889 	rotate += 180;
890 	if (rotate >= 360) rotate -= 360;
891     }
892 
893     scale = ((dlong)window->w_scale * (dlong)label->lab_size) >> (SUBPIXELBITS + 3);
894 
895     if (scale > 0)
896     {
897 	GrFontText(label->lab_text, style, p, label->lab_font,
898 			(int)scale, rotate, &GrScreenRect);
899     }
900 }
901 
902 
903 /*
904  * ----------------------------------------------------------------------------
905  *
906  * dbwLabelFunc --
907  *
908  * 	Called by database searching routines during redisplay.  It
909  *	displays a label on the screen.
910  *
911  * Results:
912  *	Always returns 0 to keep the search from aborting.
913  *
914  * Side effects:
915  *	The label is clipped and drawn on the screen.
916  *
917  * ----------------------------------------------------------------------------
918  */
919 
920 int
dbwLabelFunc(scx,label,tpath)921 dbwLabelFunc(scx, label, tpath)
922     SearchContext *scx;		/* Contains pointer to use containing def in
923 				 * which label appears, and transform to
924 				 * screen coordinates.
925 				 */
926     Label *label;		/* Label to be displayed. */
927     TerminalPath *tpath;	/* Contains pointer to full pathname of label */
928 {
929     Rect labRect, tmp;
930     int screenPos, screenRot, newStyle;
931 
932     if (!dbwAllSame && ((editDef != scx->scx_use->cu_def)
933 	|| (scx->scx_trans.t_a != editTrans.t_a)
934 	|| (scx->scx_trans.t_b != editTrans.t_b)
935 	|| (scx->scx_trans.t_c != editTrans.t_c)
936 	|| (scx->scx_trans.t_d != editTrans.t_d)
937 	|| (scx->scx_trans.t_e != editTrans.t_e)
938 	|| (scx->scx_trans.t_f != editTrans.t_f)))
939 	disWasPale = TRUE;
940     else
941 	disWasPale = FALSE;
942 
943     if (label->lab_flags & PORT_DIR_MASK)
944 	newStyle = (disWasPale) ? STYLE_PORT_PALE : STYLE_PORT;
945     else
946 	newStyle = (disWasPale) ? STYLE_LABEL_PALE : STYLE_LABEL;
947 
948     if (newStyle != disStyle)
949     {
950 	disStyle = newStyle;
951         GrSetStuff(newStyle);
952     }
953 
954     if (label->lab_font < 0)
955     {
956 	screenPos = GeoTransPos(&scx->scx_trans, label->lab_just);
957 	GeoTransRect(&scx->scx_trans, &label->lab_rect, &tmp);
958 	WindSurfaceToScreen(dbwWindow, &tmp, &labRect);
959 	if (!GEO_TOUCH(&labRect, &dbwWindow->w_screenArea)) return 0;
960 	DBWDrawLabel(label, &labRect, screenPos, -1, dbwLabelSize, dbwExpandAmounts);
961     }
962     else
963     {
964 	DBWDrawFontLabel(label, dbwWindow, &scx->scx_trans, -1);
965     }
966 
967     if (label->lab_flags & PORT_DIR_MASK)
968     {
969 	if (label->lab_font >= 0)	// If not done already. . .
970 	{
971 	    screenPos = GeoTransPos(&scx->scx_trans, label->lab_just);
972 	    GeoTransRect(&scx->scx_trans, &label->lab_rect, &tmp);
973 	}
974 	WindSurfaceToScreenNoClip(dbwWindow, &tmp, &labRect);
975 
976 	/* Temporarily set the style for port connection lines */
977         GrSetStuff(STYLE_PORT_CONNECT);
978 	if (label->lab_flags & PORT_DIR_NORTH)
979 	    GrClipLine(labRect.r_xbot, labRect.r_ytop,
980 			labRect.r_xtop, labRect.r_ytop);
981 	if (label->lab_flags & PORT_DIR_SOUTH)
982 	    GrClipLine(labRect.r_xbot, labRect.r_ybot,
983 			labRect.r_xtop, labRect.r_ybot);
984 	if (label->lab_flags & PORT_DIR_EAST)
985 	    GrClipLine(labRect.r_xtop, labRect.r_ybot,
986 			labRect.r_xtop, labRect.r_ytop);
987 	if (label->lab_flags & PORT_DIR_WEST)
988 	    GrClipLine(labRect.r_xbot, labRect.r_ybot,
989 			labRect.r_xbot, labRect.r_ytop);
990         GrSetStuff(disStyle);
991     }
992     return 0;
993 }
994 
995 /*
996  * ----------------------------------------------------------------------------
997  *
998  * dbwBBoxFunc --
999  *
1000  * 	Called by database searching routines during redisplay.
1001  *      The caller should have already set the style information.
1002  *
1003  * Results:
1004  *	Always returns 0 to keep the search from aborting.
1005  *
1006  * Side effects:
1007  *	The bounding box of the cell is clipped and drawn on the screen,
1008  *	along with the name and id of the celluse.  The bounding box
1009  *	area is returned in the pointer argument "sizeBox".
1010  *
1011  * ----------------------------------------------------------------------------
1012  */
1013 
1014 int
dbwBBoxFunc(scx)1015 dbwBBoxFunc(scx)
1016     SearchContext *scx;	 /* Describes context of cell. */
1017 {
1018     Rect r, r2;
1019     char idName[100];
1020     Point p;
1021     CellUse *cellUse;
1022 
1023     cellUse = scx->scx_use;
1024     GeoTransRect(&scx->scx_trans, &cellUse->cu_def->cd_bbox, &r2);
1025     WindSurfaceToScreen(dbwWindow, &r2, &r);
1026     GrFastBox(&r);
1027 
1028     /* Don't futz around with text if the bbox is tiny. */
1029 
1030     if (((r.r_xtop-r.r_xbot) < dbwMinBBox.r_xtop)
1031 	|| ((r.r_ytop-r.r_ybot) < dbwMinBBox.r_ytop)) return 0;
1032 
1033     p.p_x = (r.r_xbot + r.r_xtop)/2;
1034     p.p_y = (r.r_ybot + 2*r.r_ytop)/3;
1035     GeoClip(&r, &windClip);
1036 
1037     GrPutText(cellUse->cu_def->cd_name, -1, &p,
1038 		GEO_CENTER, GR_TEXT_LARGE, TRUE, &r, (Rect *) NULL);
1039 
1040     (void) DBPrintUseId(scx, idName, 100, TRUE);
1041     p.p_y = (2*r.r_ybot + r.r_ytop)/3;
1042     GrPutText(idName, -1, &p, GEO_CENTER,
1043         GR_TEXT_LARGE, TRUE, &r, (Rect *)NULL);
1044     return 0;
1045 }
1046 
1047 /*
1048  * ----------------------------------------------------------------------------
1049  *
1050  * dbwTileFunc --
1051  *
1052  * 	Called by the database search routines, from DBWredisplay
1053  *	during redisplay.
1054  *
1055  * Results:
1056  *	Always returns 0 to keep the search from aborting.
1057  *
1058  * Side effects:
1059  *	Displays a tile's bounding box and corner stitches.
1060  *
1061  * ----------------------------------------------------------------------------
1062  */
1063 
1064 int
dbwTileFunc(tile)1065 dbwTileFunc(tile)
1066     Tile *tile;				/* A tile to be redisplayed. */
1067 {
1068     Rect r, r2;
1069     int xoffset, yoffset;
1070     Point p;
1071     Point pLL, pUR;
1072     Tile *stitch;
1073     char string[20];
1074     int i, pos;
1075 
1076     TiToRect(tile, &r2);
1077 
1078     /* Some of the tiles have "infinite sizes", which we have to clip
1079      * in order to avoid numerical problems.
1080      */
1081 
1082     GeoClip(&r2, &dbwWatchArea);
1083     pLL = r2.r_ll;
1084     pUR = r2.r_ur;
1085     GeoTransRect(&dbwWatchTrans, &r2, &r);
1086     WindSurfaceToScreen(dbwWindow, &r, &r2);
1087 
1088     /* Draw the tile, then put up text for the tile's address and
1089      * stitches.
1090      */
1091 
1092     (void) GrClipBox(&r2, STYLE_DRAWTILE);
1093     GeoTransPoint(&dbwWatchTrans, &pLL, &p);
1094     WindPointToScreen(dbwWindow, &p, &pLL);
1095     GeoTransPoint(&dbwWatchTrans, &pUR, &p);
1096     WindPointToScreen(dbwWindow, &p, &pUR);
1097     GeoClipPoint(&pLL, &rootClip);
1098     GeoClipPoint(&pUR, &rootClip);
1099 
1100 
1101     if (dbwSeeTypes)
1102     {
1103     	 (void) sprintf(string, "%s",DBTypeShortName(TiGetType(tile)));
1104     }
1105     else
1106     {
1107 	(void) sprintf(string, "%p", tile);
1108     }
1109 
1110     GeoClip(&r2, &rootClip);
1111     p.p_x = (r2.r_xbot + r2.r_xtop)/2;
1112     p.p_y = (r2.r_ybot + r2.r_ytop)/2;
1113     if (!dbwWatchDemo || dbwSeeTypes)
1114 	GrPutText(string, STYLE_DRAWTILE, &p, GEO_CENTER,
1115 	    GR_TEXT_LARGE, FALSE, &r2, (Rect *) NULL);
1116 
1117 #define	XYOFFSET	12
1118 
1119     for (i=0;  i<4;  i++)
1120     {
1121 	xoffset = 0;
1122 	yoffset = 0;
1123 	switch (i)
1124 	{
1125 	    case 0:
1126 		stitch = BL(tile);
1127 		p = pLL;
1128 		yoffset = XYOFFSET;
1129 		pos = GEO_NORTHEAST;
1130 		break;
1131 	    case 1:
1132 		stitch = LB(tile);
1133 		p = pLL;
1134 		xoffset = XYOFFSET;
1135 		pos = GEO_NORTHEAST;
1136 		break;
1137 	    case 2:
1138 		stitch = RT(tile);
1139 		p = pUR;
1140 		xoffset = -XYOFFSET;
1141 		pos = GEO_SOUTHWEST;
1142 		break;
1143 	    case 3:
1144 		stitch = TR(tile);
1145 		p = pUR;
1146 		yoffset = -XYOFFSET;
1147 		pos = GEO_SOUTHWEST;
1148 		break;
1149 	}
1150 
1151 	pos = GeoTransPos(&dbwWatchTrans, pos);
1152 
1153 	if (dbwWatchTrans.t_a == 0)
1154 	{
1155 	    /* a rotation by 90 or 270 */
1156 	    int temp;
1157 	    temp = xoffset;
1158 	    xoffset = yoffset;
1159 	    yoffset = temp;
1160 	}
1161 
1162 	if ( (dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0) )
1163 	{
1164 	    /* mirror in x */
1165 	    xoffset = -xoffset;
1166 	}
1167 
1168 	if ( (dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0) )
1169 	{
1170 	    /* mirror in y */
1171 	    yoffset = -yoffset;
1172 	}
1173 
1174 	p.p_x += xoffset;
1175 	p.p_y += yoffset;
1176 	if (dbwWatchDemo)
1177 	{
1178 	    Rect stick, head, head2;
1179 	    stick.r_ll = p;
1180 	    stick.r_ur = p;
1181 #define TAIL	5
1182 #define HEAD	9
1183 	    switch (i)
1184 	    {
1185 		case 0:
1186 		    stick.r_xbot -= HEAD;
1187 		    stick.r_xtop += TAIL;
1188 		    head = stick;
1189 		    head.r_xbot++;
1190 		    head.r_xtop = head.r_xbot;
1191 		    head.r_ytop++;
1192 		    head.r_ybot--;
1193 		    head2 = head;
1194 		    head2.r_xbot++;
1195 		    head2.r_xtop++;
1196 		    head2.r_ytop++;
1197 		    head2.r_ybot--;
1198 		    break;
1199 		case 1:
1200 		    stick.r_ybot -= HEAD;
1201 		    stick.r_ytop += TAIL;
1202 		    head = stick;
1203 		    head.r_ybot++;
1204 		    head.r_ytop = head.r_ybot;
1205 		    head.r_xtop++;
1206 		    head.r_xbot--;
1207 		    head2 = head;
1208 		    head2.r_xbot--;
1209 		    head2.r_xtop++;
1210 		    head2.r_ytop++;
1211 		    head2.r_ybot++;
1212 		    break;
1213 		case 2:
1214 		    stick.r_ybot -= TAIL;
1215 		    stick.r_ytop += HEAD;
1216 		    head = stick;
1217 		    head.r_ytop--;
1218 		    head.r_ybot = head.r_ytop;
1219 		    head.r_xtop++;
1220 		    head.r_xbot--;
1221 		    head2 = head;
1222 		    head2.r_xbot--;
1223 		    head2.r_xtop++;
1224 		    head2.r_ytop--;
1225 		    head2.r_ybot--;
1226 		    break;
1227 		case 3:
1228 		    stick.r_xbot -= TAIL;
1229 		    stick.r_xtop += HEAD;
1230 		    head = stick;
1231 		    head.r_xtop--;
1232 		    head.r_xbot = head.r_xtop;
1233 		    head.r_ytop++;
1234 		    head.r_ybot--;
1235 		    head2 = head;
1236 		    head2.r_xbot--;
1237 		    head2.r_xtop--;
1238 		    head2.r_ytop++;
1239 		    head2.r_ybot--;
1240 		    break;
1241 	    }
1242 	    GrClipBox(&stick, STYLE_LABEL);
1243 	    GrClipBox(&head, STYLE_LABEL);
1244 	    GrClipBox(&head2, STYLE_LABEL);
1245 	}
1246 	else if (!dbwSeeTypes)
1247 	{
1248 	    (void) sprintf(string, "%p", stitch);
1249 	    GrPutText(string, STYLE_DRAWTILE, &p, pos,
1250 		GR_TEXT_SMALL, FALSE, &r2, (Rect *) NULL);
1251 	}
1252     }
1253     return 0;
1254 }
1255 
1256 
1257 /*
1258  * ----------------------------------------------------------------------------
1259  *	DBWAreaChanged --
1260  *
1261  * 	Invoked to remind us that a certain piece of a certain cell
1262  *	has been modified and must eventually be redisplayed.
1263  *
1264  * Results:
1265  *	None.
1266  *
1267  * Side effects:
1268  *	Information is remembered, so that when WindUpdate is called
1269  *	the area will be redisplayed in every window where it appears.
1270  *
1271  * ----------------------------------------------------------------------------
1272  */
1273 
1274 static TileTypeBitMask *dbwLayersChanged;
1275 				/* DBWAreaChanged's "layers" parameter. */
1276 
1277 void
DBWAreaChanged(cellDef,defArea,expandMask,layers)1278 DBWAreaChanged(cellDef, defArea, expandMask, layers)
1279     CellDef *cellDef;		/* The cell definition that was modified. */
1280     Rect *defArea;		/* The area of the definition that changed. */
1281     int expandMask;		/* We're only interested these windows.
1282 				 * Use DBW_ALLWINDOWS for all windows.
1283 				 */
1284     TileTypeBitMask *layers;	/* Indicates which layers were modified.  If
1285 				 * NULL, it means that labels were deleted
1286 				 * from defArea in addition to paint.  We'll
1287 				 * have to redisplay a larger area in order
1288 				 * to fully erase labels that used to stick
1289 				 * out from defArea.  NULL is used when
1290 				 * subcells are unexpanded or moved for
1291 				 * example.  NULL is the most inclusive option
1292 				 * (does everything that &DBAllButSpaceBits
1293 				 * does and more), and should be used whenever
1294 				 * you're not sure what to do.  Note:  it's
1295 				 * normally better to use DBWLabelChanged when
1296 				 * individual labels are modified;  the NULL
1297 				 * option is for when large numbers of labels
1298 				 * have potentially been modified.
1299 				 */
1300 {
1301     Rect newArea;		/* Corresponding area in parent. */
1302     int newMask;		/* Windows we're interested in in parent. */
1303     int x, y, xlo, ylo;		/* Array indices. */
1304     int xhi, yhi;
1305     Rect tmp;
1306     CellUse *use;
1307 
1308     if ((defArea->r_xbot == defArea->r_xtop)
1309 	|| (defArea->r_ybot == defArea->r_ytop)) return;
1310 
1311     /**
1312     TxPrintf("Cell %s, area (%d, %d) (%d, %d) changed, mask %d.\n",
1313 	    cellDef->cd_name,  defArea->r_xbot, defArea->r_ybot,
1314 	    defArea->r_xtop, defArea->r_ytop, expandMask);
1315     **/
1316 
1317     /* Don't permit signals to interrupt us here. */
1318 
1319     SigDisableInterrupts();
1320 
1321     /* First, translate the area back up through the hierarchy to
1322      * cells that are roots of windows.
1323      */
1324 
1325     for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse)
1326     {
1327 	/* We're only interested in a use if it's expanded in one of
1328 	 * the windows of expandMask.  Our new expand mask is the
1329 	 * AND of the old one and the windows in which this use is
1330 	 * expanded.
1331 	 */
1332 
1333 	newMask = expandMask & use->cu_expandMask;
1334 	if (newMask == 0) continue;
1335 
1336 	/* If this use has no parents, it might be the root of a window.
1337 	 * If so, log the area in the window.
1338 	 */
1339 
1340 	if (use->cu_parent == NULL)
1341 	{
1342 	    dbwLayersChanged = layers;
1343 	    (void) WindSearch((ClientData) DBWclientID, (ClientData) use,
1344 		defArea, dbwChangedFunc, (ClientData) defArea);
1345 	    continue;
1346 	}
1347 
1348 	/* This use isn't a root use.  If it isn't an array use, just
1349 	 * translate the area back into the coordinates of the parent
1350 	 * and invoke ourselves recursively.
1351 	 */
1352 
1353 	if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
1354 	{
1355 	    GeoTransRect(&use->cu_transform, defArea, &newArea);
1356 	    DBWAreaChanged(use->cu_parent, &newArea, newMask, layers);
1357 	    continue;
1358 	}
1359 
1360 	/* This is an array.  If the area to be redisplayed is a
1361 	 * substantial fraction of the total area of the array,
1362 	 * just redisplay the whole array.  Otherwise redisplay
1363 	 * the individual elements.
1364 	 */
1365 
1366 	if ((2*(defArea->r_xtop - defArea->r_xbot) >
1367 	    (cellDef->cd_bbox.r_xtop - cellDef->cd_bbox.r_xbot))
1368 	    || (2*(defArea->r_ytop - defArea->r_ybot) >
1369 	    (cellDef->cd_bbox.r_ytop - cellDef->cd_bbox.r_ybot)))
1370 	{
1371 	    DBComputeArrayArea(defArea, use, use->cu_xlo,
1372 		use->cu_ylo, &newArea);
1373 	    DBComputeArrayArea(defArea, use, use->cu_xhi,
1374 		use->cu_yhi, &tmp);
1375 	    (void) GeoInclude(&newArea, &tmp);
1376 	    GeoTransRect(&use->cu_transform, &tmp, &newArea);
1377 	    DBWAreaChanged(use->cu_parent, &newArea, newMask, layers);
1378 	}
1379 	else
1380 	{
1381 	    if (use->cu_xlo > use->cu_xhi)
1382 	    {
1383 		xlo = use->cu_xhi; xhi = use->cu_xlo;
1384 	    }
1385 	    else
1386 	    {
1387 		xlo = use->cu_xlo; xhi = use->cu_xhi;
1388 	    }
1389 	    if (use->cu_ylo > use->cu_yhi)
1390 	    {
1391 		ylo = use->cu_yhi; yhi = use->cu_ylo;
1392 	    }
1393 	    else
1394 	    {
1395 		ylo = use->cu_ylo; yhi = use->cu_yhi;
1396 	    }
1397 	    for (y = ylo ; y <= yhi; y++)
1398 		for (x = xlo; x <= xhi; x++)
1399 		{
1400 		    DBComputeArrayArea(defArea, use, x, y, &tmp);
1401 		    GeoTransRect(&use->cu_transform, &tmp, &newArea);
1402 		    DBWAreaChanged(use->cu_parent, &newArea, newMask, layers);
1403 		}
1404 	}
1405     }
1406     SigEnableInterrupts();
1407 }
1408 
1409 
1410 /*
1411  * ----------------------------------------------------------------------------
1412  *
1413  * dbwChangedFunc --
1414  *
1415  * 	This function is invoked by WindSearch under control of
1416  *	DBWAreaChanged.  It notifies the window manager to redisplay
1417  *	an area of a window.
1418  *
1419  * Results:
1420  *	Always returns 0 to keep the search alive.
1421  *
1422  * Side effects:
1423  *	An area to be redisplayed is recorded.
1424  *
1425  * ----------------------------------------------------------------------------
1426  */
1427 
1428 int
dbwChangedFunc(w,area)1429 dbwChangedFunc(w, area)
1430     MagWindow *w;			/* Window in which to record area. */
1431     Rect *area;			/* (Client data) Area to be redisplayed, in
1432 				 * coordinates of the root definition.
1433 				 */
1434 {
1435     Rect screenArea;
1436     TileTypeBitMask tmp;
1437     DBWclientRec *crec = (DBWclientRec *) w->w_clientData;
1438 
1439     /* If none of the layers being redisplayed is visible in this
1440      * window, then there's no need to do anything.
1441      */
1442 
1443     if (dbwLayersChanged != NULL)
1444     {
1445 	TTMaskAndMask3(&tmp, dbwLayersChanged, &crec->dbw_visibleLayers);
1446 	if (TTMaskIsZero(&tmp)) return 0;
1447     }
1448 
1449     /* Compute screen area to redisplay, in pixels. */
1450 
1451     WindSurfaceToScreen(w, area, &screenArea);
1452     GeoClip(&screenArea, &w->w_screenArea);
1453 
1454     /* If labels are being redisplayed, expand the redisplay area
1455      * to account for labels that are rooted in the given area but
1456      * stick out past it.
1457      */
1458 
1459     if (dbwLayersChanged == NULL)
1460     {
1461 	screenArea.r_xbot += crec->dbw_expandAmounts.r_xbot;
1462 	screenArea.r_ybot += crec->dbw_expandAmounts.r_ybot;
1463 	screenArea.r_xtop += crec->dbw_expandAmounts.r_xtop;
1464 	screenArea.r_ytop += crec->dbw_expandAmounts.r_ytop;
1465     }
1466     else if (GrPixelCorrect == 0)
1467     {
1468 	/* Correct for OpenGL coordinate system */
1469 	screenArea.r_xbot--;
1470 	screenArea.r_ybot--;
1471 	screenArea.r_xtop++;
1472 	screenArea.r_ytop++;
1473     }
1474 
1475     /* If watching is enabled for this window, so sorry but the whole
1476      * thing will have to be redisplayed (even a small change could have
1477      * affected many many tiles.
1478      */
1479 
1480     if (crec->dbw_watchPlane >= 0) WindAreaChanged(w, (Rect *) NULL);
1481     else WindAreaChanged(w, &screenArea);
1482     return 0;
1483 }
1484 
1485 /*
1486  * ----------------------------------------------------------------------------
1487  *
1488  * DBWLabelChanged --
1489  *
1490  * 	This procedure is invoked when a label has been created or
1491  *	deleted.  It figures out which areas to redisplay in order
1492  *	to make sure that the label is completely redrawn.
1493  *
1494  * Results:
1495  *	None.
1496  *
1497  * Side effects:
1498  *	The list of areas to be redisplayed is modified.
1499  *
1500  * ----------------------------------------------------------------------------
1501  */
1502 
1503 
1504 /* The following stuff is shared by the procedures below. */
1505 
1506 extern int dbwLabelChangedFunc();  /* Function to call for each label. */
1507 
1508 void
DBWLabelChanged(cellDef,lab,mask)1509 DBWLabelChanged(cellDef, lab, mask)
1510     CellDef *cellDef;		/* Cell definition containing label. */
1511     Label *lab;			/* The label structure */
1512     int mask;			/* Mask of windows where changes should be
1513 				 * reflected (DBW_ALLWINDOWS selects all
1514 				 * windows, and is usually the right value.)
1515 				 */
1516 {
1517     CellUse *use;
1518     Rect saveArea, tmp;
1519     int newMask, savePos;
1520     int x, y, xlo, ylo, xhi, yhi;
1521 
1522     /* This procedure is basically the same as DBWAreaChanged, so
1523      * see that procedure for documentation on how this all works.
1524      */
1525 
1526     saveArea = lab->lab_rect;
1527     savePos = lab->lab_just;
1528 
1529     SigDisableInterrupts();
1530     for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse)
1531     {
1532 	newMask = mask & use->cu_expandMask;
1533 	if (newMask == 0) continue;
1534 
1535 	if (use->cu_parent == NULL)
1536 	{
1537 	    /* Got the root use for a window.  Find the relevant windows
1538 	     * and do the rest of the processing on a per-window basis.
1539 	     */
1540 
1541 	    (void) WindSearch((ClientData) DBWclientID, (ClientData) use,
1542 		(Rect *) NULL, dbwLabelChangedFunc, (ClientData) lab);
1543 	    continue;
1544 	}
1545 
1546 	if (use->cu_xlo > use->cu_xhi)
1547 	{
1548 	    xlo = use->cu_xhi;
1549 	    xhi = use->cu_xlo;
1550 	}
1551 	else
1552 	{
1553 	    xlo = use->cu_xlo;
1554 	    xhi = use->cu_xhi;
1555 	}
1556 	if (use->cu_ylo > use->cu_yhi)
1557 	{
1558 	    ylo = use->cu_yhi;
1559 	    yhi = use->cu_ylo;
1560 	}
1561 	else
1562 	{
1563 	    ylo = use->cu_ylo;
1564 	    yhi = use->cu_yhi;
1565 	}
1566 	for (y = ylo; y <= yhi; y++)
1567 	    for (x = xlo; x <= xhi; x++)
1568 	    {
1569 		DBComputeArrayArea(&lab->lab_rect, use, x, y, &tmp);
1570 		GeoTransRect(&use->cu_transform, &tmp, &lab->lab_rect);
1571 		lab->lab_just = GeoTransPos(&use->cu_transform, lab->lab_just);
1572 		DBWLabelChanged(use->cu_parent, lab, newMask);
1573 	    }
1574     }
1575     lab->lab_rect = saveArea;
1576     lab->lab_just = savePos;
1577 
1578     SigEnableInterrupts();
1579 }
1580 
1581 int
dbwLabelChangedFunc(w,lab)1582 dbwLabelChangedFunc(w, lab)
1583     MagWindow *w;		/* Window in which label is displayed. */
1584     Label *lab;			/* Label being changed.	*/
1585 {
1586     Rect screenArea, textArea;
1587     int size;
1588 
1589     if (lab->lab_font < 0)
1590     {
1591 	WindSurfaceToScreen(w, &lab->lab_rect, &screenArea);
1592 	size = ((DBWclientRec *) w->w_clientData)->dbw_labelSize;
1593 	if (size < GR_TEXT_SMALL)
1594 	    textArea = GrCrossRect;
1595 	else
1596 	{
1597 	    GrLabelSize(lab->lab_text, lab->lab_just, size, &textArea);
1598 	    (void) GeoInclude(&GrCrossRect, &textArea);
1599 	}
1600 	screenArea.r_xbot += textArea.r_xbot;
1601 	screenArea.r_ybot += textArea.r_ybot;
1602 	screenArea.r_xtop += textArea.r_xtop;
1603 	screenArea.r_ytop += textArea.r_ytop;
1604     }
1605     else
1606     {
1607 	WindSurfaceToScreen(w, &lab->lab_bbox, &screenArea);
1608     }
1609     WindAreaChanged(w, &screenArea);
1610     return 0;
1611 }
1612 
1613 /*
1614  * Technology initialization for the display module.
1615  */
1616 
1617 global TileTypeBitMask	*DBWStyleToTypesTbl = NULL;
1618 
1619 /*
1620  * ----------------------------------------------------------------------------
1621  * DBWTechInitStyles --
1622  *
1623  * Initialize the display module's technology dependent variables.
1624  *
1625  * Results:
1626  *	None.
1627  *
1628  * Side effects:
1629  *	Clears the display module's technology dependent information.
1630  * ----------------------------------------------------------------------------
1631  */
1632 
1633 void
DBWTechInitStyles()1634 DBWTechInitStyles()
1635 {
1636     int i;
1637 
1638     if (DBWNumStyles == 0)
1639     {
1640 	TxError("Error:  Attempting to define tech styles before reading "
1641 		"dstyle file!\n");
1642 	return;
1643     }
1644     if (DBWStyleToTypesTbl != NULL)
1645 	freeMagic(DBWStyleToTypesTbl);
1646 
1647     DBWStyleToTypesTbl = (TileTypeBitMask *)mallocMagic(DBWNumStyles *
1648 		sizeof(TileTypeBitMask));
1649 
1650     for (i = 0; i < DBWNumStyles; i++)
1651 	TTMaskZero(DBWStyleToTypesTbl + i);
1652 }
1653 
1654 
1655 /*
1656  * ----------------------------------------------------------------------------
1657  *
1658  * DBWTechParseStyle --
1659  *
1660  *	Turn a style entry (either a style number or name) into an index
1661  *	into the styles array.
1662  *
1663  * Results:  Index into the DBW styles table, or -1 if no style found.
1664  *
1665  * Side Effects:  None.
1666  *
1667  * ----------------------------------------------------------------------------
1668  */
1669 
1670 int
DBWTechParseStyle(stylestr)1671 DBWTechParseStyle(stylestr)
1672     char *stylestr;
1673 {
1674     int sidx, style;
1675 
1676     if (StrIsInt(stylestr))
1677     {
1678 	style = atoi(stylestr);
1679 	for (sidx = 0; sidx < DBWNumStyles; sidx++)
1680 	    if (GrStyleTable[sidx + TECHBEGINSTYLES].idx == style)
1681 		break;
1682     }
1683     else {
1684 	for (sidx = 0; sidx < DBWNumStyles; sidx++)
1685 	    if (!strcmp(GrStyleTable[sidx + TECHBEGINSTYLES].longname,
1686 			stylestr))
1687 		break;
1688     }
1689     if (sidx >= DBWNumStyles)
1690 	return -1;
1691     else
1692 	return sidx;
1693 }
1694 
1695 /*
1696  * ----------------------------------------------------------------------------
1697  * DBWTechAddStyle --
1698  *
1699  * Add a new entry to the style tables.
1700  *
1701  * Results:
1702  *	TRUE if successful, FALSE on error.
1703  *
1704  * Side effects:
1705  *	Updates the display module's technology variables.
1706  * ----------------------------------------------------------------------------
1707  */
1708 
1709 bool
DBWTechAddStyle(sectionName,argc,argv)1710 DBWTechAddStyle(sectionName, argc, argv)
1711     char *sectionName;
1712     int argc;
1713     char *argv[];
1714 {
1715     TileType t, r;
1716     TileTypeBitMask *rMask;
1717     int i, sidx;
1718     static char styleType[50];
1719     char *pathptr;
1720 
1721     if (argc < 2)
1722     {
1723 	TechError("Badly formed line in \"style\" section\n");
1724     }
1725     else if (strcmp(argv[0], "styletype") == 0)
1726     {
1727 	(void) strncpy(styleType, argv[1], 49);
1728 	styleType[49] = 0;
1729 	DBWStyleType = styleType;
1730 
1731 	/* Optional 3rd and higher arguments are pathnames */
1732 
1733 	for (i = 2; i <= argc; i++)
1734 	{
1735 	    if (i == argc)
1736 		pathptr = SysLibPath;
1737 	    else
1738 		pathptr = argv[i];
1739 
1740 	    /* Learning the style type precipitates immediate reading	*/
1741 	    /* of the color map and style files.			*/
1742 
1743 	    if (GrReadCMap(DBWStyleType, (char *)NULL, MainMonType, ".", pathptr))
1744 		break;
1745 	}
1746 	if (i > argc) return FALSE;
1747 
1748 	if (GrLoadStyles(DBWStyleType, ".", pathptr) != 0)
1749 	    return FALSE;
1750 
1751 	DBWTechInitStyles();
1752 
1753 	if (!GrLoadCursors(".", pathptr))
1754 	    return FALSE;
1755 
1756 	GrSetCursor(0);
1757     }
1758     else
1759     {
1760 	if ((t = DBTechNoisyNameType(argv[0])) < 0) return (FALSE);
1761 
1762 	/* Allow space-separated list of styles for each type */
1763 
1764 	for (i = 1; i < argc; i++)
1765 	{
1766 	    sidx = DBWTechParseStyle(argv[i]);
1767 	    if (sidx < 0)
1768 		TechError("Invalid style \"%s\" for tile type %s\n", argv[i], argv[0]);
1769 	    else
1770 	    {
1771 		TTMaskSetType(&DBWStyleToTypesTbl[sidx], t);
1772 
1773 		/* If type t is a contact, then any stacked contact type which	*/
1774 		/* has t as a residue, and for which the home plane of the	*/
1775 		/* stacked contact is also the home plane of t, should be added	*/
1776 		/* to the list of types to be painted with this style.		*/
1777 
1778 		if (DBIsContact(t) && (t < DBNumUserLayers))
1779 		    for (r = DBNumUserLayers; r < DBNumTypes; r++)
1780 		    {
1781 			rMask = DBResidueMask(r);
1782 			if (TTMaskHasType(rMask, t) && (DBPlane(r) == DBPlane(t)))
1783 			    TTMaskSetType(&DBWStyleToTypesTbl[sidx], r);
1784 		    }
1785 	    }
1786 	}
1787     }
1788     return TRUE;
1789 }
1790