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