1
2 /* SimDBstuff.c -
3 *
4 * This file contains routines that extract electrically connected
5 * regions of a layout for Magic. This extractor operates
6 * hierarchically, across cell boundaries (SimTreeCopyConnect), as
7 * well as within a single cell (SimSrConnect).
8 *
9 * This also contains routines corresponding to those in the DBWind
10 * module.
11 *
12 * *********************************************************************
13 * * Copyright (C) 1985, 1990 Regents of the University of California. *
14 * * Permission to use, copy, modify, and distribute this *
15 * * software and its documentation for any purpose and without *
16 * * fee is hereby granted, provided that the above copyright *
17 * * notice appear in all copies. The University of California *
18 * * makes no representations about the suitability of this *
19 * * software for any purpose. It is provided "as is" without *
20 * * express or implied warranty. Export of this software outside *
21 * * of the United States of America may require an export license. *
22 * *********************************************************************
23 * University of California
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "utils/magic.h"
30 #include "utils/geometry.h"
31 #include "utils/geofast.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "utils/stack.h"
35 #include "database/database.h"
36 #include "database/databaseInt.h"
37 #include "textio/textio.h"
38 #include "utils/signals.h"
39 #include "utils/malloc.h"
40 #include "extract/extractInt.h"
41 #include "sim/sim.h"
42 #include "windows/windows.h"
43 #include "dbwind/dbwind.h"
44 #include "commands/commands.h"
45 #include "textio/txcommands.h"
46 #include "utils/styles.h"
47 #include "graphics/graphics.h"
48
49 /* Forward declarations */
50
51 extern char *DBPrintUseId();
52 extern int dbcUnconnectFunc();
53 extern void SimInitScxStk();
54 extern void SimPopScx();
55 extern void SimMakePathname();
56
57 static char bestName[256];
58
59
60 /*
61 * ----------------------------------------------------------------------------
62 *
63 * SimConnectFunc
64 *
65 * This procedure is based upon the function dbcConnectFunc in the
66 * database module.
67 *
68 * This procedure is invoked by SimTreeSrTiles from SimTreeCopyConnect,
69 * whenever a tile is found that is connected to the current area
70 * being processed. If the tile overlaps the search area in a non-
71 * trivial way (i.e. more than a 1x1 square of overlap at a corner)
72 * then the area of the tile is added onto the list of things to check.
73 * The "non-trivial" overlap check is needed to prevent caddy-corner
74 * tiles from being considered as connected.
75 *
76 * Results:
77 * Returns 0 normally, 1 if an abort condition has been encountered.
78 *
79 * Side effects:
80 * Paints into the destination definition.
81 *
82 * ----------------------------------------------------------------------------
83 */
84
85 int
SimConnectFunc(tile,cx)86 SimConnectFunc(tile, cx)
87 Tile *tile; /* Tile found. */
88 TreeContext *cx; /* Describes context of search. The client
89 * data is a pointer to the list head of
90 * the conSrArg2's describing the areas
91 * left to check.
92 */
93 {
94 struct conSrArg2 *csa2;
95 Rect tileArea, *srArea, newarea;
96 SearchContext *scx = cx->tc_scx;
97 TileTypeBitMask notConnectMask, *connectMask;
98 TileType loctype, ctype;
99 TileType dinfo = 0;
100 int i, pNum;
101 static char nodeName[256];
102 CellDef *def;
103 TerminalPath *tpath = cx->tc_filter->tf_tpath;
104
105 TiToRect(tile, &tileArea);
106 srArea = &scx->scx_area;
107
108 if (((tileArea.r_xbot >= srArea->r_xtop-1) ||
109 (tileArea.r_xtop <= srArea->r_xbot+1)) &&
110 ((tileArea.r_ybot >= srArea->r_ytop-1) ||
111 (tileArea.r_ytop <= srArea->r_ybot+1)))
112 {
113 /* If the search area is only one unit wide or tall, then it's
114 * OK to have only a small overlap. This happens only when
115 * looking for an initial search tile.
116 */
117
118 if (((srArea->r_xtop-1) != srArea->r_xbot)
119 && ((srArea->r_ytop-1) != srArea->r_ybot)) return 0;
120 }
121 GeoTransRect(&scx->scx_trans, &tileArea, &newarea);
122
123 /* Clip the current area down to something that overlaps the
124 * area of interest.
125 */
126
127 csa2 = (struct conSrArg2 *)cx->tc_filter->tf_arg;
128 GeoClip(&newarea, csa2->csa2_bounds);
129 if (GEO_RECTNULL(&newarea)) return 0;
130
131 /* Stuff unique to the nodename search follows. */
132
133 if (tpath != (TerminalPath *)NULL)
134 {
135 /* Extract the node name */
136
137 char *n = tpath->tp_next;
138 char c = *n;
139
140 SigDisableInterrupts();
141 strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, tpath->tp_first));
142 SigEnableInterrupts();
143
144 *n = c;
145
146 /* save the "best" name for this node */
147
148 if (bestName[0] == '\0' || efPreferredName(nodeName, bestName))
149 strcpy(bestName, nodeName);
150 }
151
152 loctype = TiGetTypeExact(tile);
153
154 /* Resolve geometric transformations on diagonally-split tiles */
155
156 if (IsSplit(tile))
157 {
158 dinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
159 loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
160 }
161
162 /* See if the destination cell contains stuff over the whole
163 * current area (on its home plane) that is connected to it.
164 * If so, then there's no need to process the current area,
165 * since any processing that is needed was already done before.
166 */
167
168 pNum = DBPlane(loctype);
169 connectMask = &csa2->csa2_connect[loctype];
170
171 if (DBIsContact(loctype))
172 {
173 TileTypeBitMask *rMask = DBResidueMask(loctype);
174 TileTypeBitMask *cMask;
175
176 TTMaskSetOnlyType(¬ConnectMask, loctype);
177
178 /* Differenct contact types may share residues (6/18/04) */
179 for (ctype = TT_TECHDEPBASE; ctype < DBNumUserLayers; ctype++)
180 {
181 if (DBIsContact(ctype))
182 {
183 cMask = DBResidueMask(ctype);
184 if (TTMaskIntersect(rMask, cMask))
185 TTMaskSetType(¬ConnectMask, ctype);
186 }
187 }
188
189 /* The mask of contact types must include all stacked contacts */
190 for (ctype = DBNumUserLayers; ctype < DBNumTypes; ctype++)
191 {
192 cMask = DBResidueMask(ctype);
193 if TTMaskHasType(cMask, loctype)
194 TTMaskSetType(¬ConnectMask, ctype);
195 }
196
197 TTMaskCom(¬ConnectMask);
198 }
199 else
200 {
201 TTMaskCom2(¬ConnectMask, connectMask);
202 }
203
204 def = csa2->csa2_use->cu_def;
205 if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
206 dinfo, &newarea, ¬ConnectMask, dbcUnconnectFunc,
207 (ClientData) connectMask) == 0)
208 return 0;
209
210 /* Paint this tile into the destination cell. */
211
212 DBNMPaintPlane(def->cd_planes[pNum], dinfo, &newarea,
213 DBStdPaintTbl(loctype, pNum), (PaintUndoInfo *) NULL);
214
215 /* Since the whole area of this tile hasn't been recorded,
216 * we must process its area to find any other tiles that
217 * connect to it. Add each of them to the list of things
218 * to process. We have to expand the search area by 1 unit
219 * on all sides because SimTreeSrTiles only returns things
220 * that overlap the search area, and we want things that
221 * even just touch.
222 */
223
224 /* Only extend those sides bordering the diagonal tile */
225
226 if (dinfo & TT_DIAGONAL)
227 {
228 if (dinfo & TT_SIDE) /* right */
229 newarea.r_xtop += 1;
230 else /* left */
231 newarea.r_xbot -= 1;
232 if (((dinfo & TT_SIDE) >> 1)
233 == (dinfo & TT_DIRECTION)) /* top */
234 newarea.r_ytop += 1;
235 else /* bottom */
236 newarea.r_ybot -= 1;
237 }
238 else
239 {
240 newarea.r_xbot -= 1;
241 newarea.r_ybot -= 1;
242 newarea.r_xtop += 1;
243 newarea.r_ytop += 1;
244 }
245
246 /* Abort the name search if the name is in the abort name search table
247 * or if the name is global and the SimIgnoreGlobals flag is not set.
248 */
249
250 if (SimSawAbortString || SigInterruptPending)
251 return 1;
252 else if (SimIsGetnode && !SimIgnoreGlobals)
253 {
254 i = strlen(nodeName);
255 if (nodeName[i - 1] == '!')
256 return 1;
257 }
258
259 /* Check if any of the last 5 entries has the same type and */
260 /* area. If so, don't duplicate the existing entry. */
261 /* (NOTE: Connect masks are all from the same table, so */
262 /* they can be compared by address, no need for TTMaskEqual)*/
263
264 for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
265 if (connectMask == csa2->csa2_list[i].connectMask)
266 if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
267 return 0;
268
269 /* Register the area and connection mask as needing to be processed */
270
271 if (++csa2->csa2_top == CSA2_LIST_SIZE)
272 {
273 /* Reached list size limit---need to enlarge the list */
274 /* Double the size of the list every time we hit the limit */
275
276 conSrArea *newlist;
277
278 newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
279 StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
280 csa2->csa2_list = newlist;
281 csa2->csa2_top = 0;
282 }
283
284 csa2->csa2_list[csa2->csa2_top].area = newarea;
285 csa2->csa2_list[csa2->csa2_top].connectMask = connectMask;
286 csa2->csa2_list[csa2->csa2_top].dinfo = dinfo;
287 return 0;
288 }
289
290
291 /*
292 * ----------------------------------------------------------------------------
293 *
294 * SimTreeCopyConnect
295 *
296 * This procedure is very similar to DBTreeCopyConnect.
297 *
298 * This procedure copies connected information from a given cell
299 * hierarchy to a given (flat) cell. Starting from the tile underneath
300 * the given area, this procedure finds all paint in all cells
301 * that is connected to that information. All such paint is
302 * copied into the result cell. If there are several electrically
303 * distinct nets underneath the given area, one of them is picked
304 * at more-or-less random.
305 *
306 * Modified so the result cell is NOT first cleared of all paint. This
307 * allows multiple calls, to highlight incomplete routing nets.
308 *
309 * Results:
310 * None.
311 *
312 * Side effects:
313 * The contents of the result cell are modified.
314 *
315 * ----------------------------------------------------------------------------
316 */
317
318 #define MAXPATHNAME 256
319
320 void
SimTreeCopyConnect(scx,mask,xMask,connect,area,destUse,Node_Name)321 SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
322 SearchContext *scx; /* Describes starting area. The
323 * scx_use field gives the root of
324 * the hierarchy to search, and the
325 * scx_area field gives the starting
326 * area. An initial tile must overlap
327 * this area. The transform is from
328 * coords of scx_use to destUse.
329 */
330 TileTypeBitMask *mask; /* Tile types to start from in area. */
331 int xMask; /* Information must be expanded in all
332 * of the windows indicated by this
333 * mask. Use 0 to consider all info
334 * regardless of expansion.
335 */
336 TileTypeBitMask *connect; /* Points to table that defines what
337 * each tile type is considered to
338 * connect to. Use DBConnectTbl as
339 * a default.
340 */
341 Rect *area; /* The resulting information is
342 * clipped to this area. Pass
343 * TiPlaneRect to get everything.
344 */
345 CellUse *destUse; /* Result use in which to place
346 * anything connected to material of
347 * type mask in area of rootUse.
348 */
349 char *Node_Name; /* Name of node returned.
350 * NOTE: Don't call this "NodeName",
351 * because that conflicts with reserved
352 * words in some compilers.
353 */
354 {
355 TerminalPath tpath;
356 char pathName[MAXPATHNAME];
357 TileTypeBitMask *newmask;
358 struct conSrArg2 csa2;
359 TileType newtype;
360
361 csa2.csa2_use = destUse;
362 csa2.csa2_bounds = area;
363 csa2.csa2_connect = connect;
364
365 csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
366 csa2.csa2_top = -1;
367 csa2.csa2_lasttop = -1;
368
369 csa2.csa2_stack = StackNew(100);
370
371 tpath.tp_first = tpath.tp_next = pathName;
372 tpath.tp_last = pathName + MAXPATHNAME;
373
374 pathName[0] = '\0';
375 bestName[0] = '\0';
376
377 (void) SimTreeSrTiles(scx, mask, xMask, &tpath, SimConnectFunc,
378 (ClientData) &csa2);
379 while (csa2.csa2_top >= 0)
380 {
381 newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
382 scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
383 newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
384 if (csa2.csa2_top == 0)
385 {
386 if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
387 {
388 freeMagic(csa2.csa2_list);
389 csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
390 csa2.csa2_top = CSA2_LIST_SIZE - 1;
391 }
392 else
393 csa2.csa2_top--;
394 }
395 else
396 csa2.csa2_top--;
397
398 csa2.csa2_lasttop = csa2.csa2_top;
399
400 if (newtype & TT_DIAGONAL)
401 SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath,
402 SimConnectFunc, (ClientData) &csa2);
403 else
404 SimTreeSrTiles(scx, newmask, xMask, &tpath, SimConnectFunc,
405 (ClientData) &csa2);
406 }
407 freeMagic((char *)csa2.csa2_list);
408 StackFree(csa2.csa2_stack);
409
410 /* Recompute the bounding box of the destination and record
411 * its area for redisplay.
412 */
413
414 strcpy(Node_Name, bestName);
415 DBReComputeBbox(destUse->cu_def);
416 }
417
418 /*
419 * ----------------------------------------------------------------------------
420 *
421 * efPreferredName --
422 *
423 * This is the same function used in the ext2sim module. We need this
424 * function for the rsim interface to Magic.
425 *
426 * Determine which of two names is more preferred. The most preferred
427 * name is a global name. Given two non-global names, the one with the
428 * fewest pathname components is the most preferred. If the two names
429 * have equally many pathname components, we choose the shortest.
430 *
431 * Results:
432 * TRUE if 'name1' is preferable to 'name2', FALSE if not.
433 *
434 * Side effects:
435 * None.
436 *
437 * ----------------------------------------------------------------------------
438 */
439
440 bool
efPreferredName(name1,name2)441 efPreferredName(name1, name2)
442 char *name1, *name2;
443 {
444 int nslashes1, nslashes2;
445 char *np1, *np2;
446
447 if( name1[0] == '@' && name1[1] == '=' )
448 return( TRUE );
449 else if( name2[0] == '@' && name2[1] == '=' )
450 return( FALSE );
451
452 for (nslashes1 = 0, np1 = name1; *np1; ) {
453 if (*np1++ == '/')
454 nslashes1++;
455 }
456
457 for (nslashes2 = 0, np2 = name2; *np2; ) {
458 if (*np2++ == '/')
459 nslashes2++;
460 }
461
462 --np1;
463 --np2;
464
465 if (!SimIgnoreGlobals)
466 {
467 /* both are global names */
468 if ((*np1 == '!') && (*np2 == '!')) {
469 /* check # of pathname components */
470 if (nslashes1 < nslashes2) return (TRUE);
471 if (nslashes1 > nslashes2) return (FALSE);
472
473 /* same # of pathname components; check length */
474 if (np1 - name1 < np2 - name2) return (TRUE);
475 if (np1 - name1 > np2 - name2) return (FALSE);
476
477 /* same # of pathname components; same length; use lex order */
478 if (strcmp(name1, name2) > 0)
479 return(TRUE);
480 else
481 return(FALSE);
482 }
483 if (*np1 == '!') return(TRUE);
484 if (*np2 == '!') return(FALSE);
485 }
486
487 /* neither name is global */
488 /* chose label over generated name */
489 if (*np1 != '#' && *np2 == '#') return (TRUE);
490 if (*np1 == '#' && *np2 != '#') return (FALSE);
491
492 /* either both are labels or generated names */
493 /* check pathname components */
494 if (nslashes1 < nslashes2) return (TRUE);
495 if (nslashes1 > nslashes2) return (FALSE);
496
497 /* same # of pathname components; check length */
498 if (np1 - name1 < np2 - name2) return (TRUE);
499 if (np1 - name1 > np2 - name2) return (FALSE);
500
501 /* same # of pathname components; same length; use lex ordering */
502 if (strcmp(name1, name2) > 0)
503 return(TRUE);
504 else
505 return(FALSE);
506 }
507
508
509
510 /*
511 * ----------------------------------------------------------------------------
512 *
513 * SimSrConnect
514 *
515 * This is similar to the procedure DBSrConnect, except that the
516 * marks on each tile in the cell are not erased.
517 *
518 * Search through a cell to find all paint that is electrically
519 * connected to things in a given starting area.
520 *
521 * Results:
522 * 0 is returned if the search finished normally. 1 is returned
523 * if the search was aborted.
524 *
525 * Side effects:
526 * The search starts from one (random) non-space tile in "startArea"
527 * that matches the types in the mask parameter. For every paint
528 * tile that is electrically connected to the initial tile and that
529 * intersects the rectangle "bounds", func is called. Func should
530 * have the following form:
531 *
532 * int
533 * func(tile, clientData)
534 * Tile *tile;
535 * ClientData clientData;
536 * {
537 * }
538 *
539 * The clientData passed to func is the same one that was passed
540 * to us. Func returns 0 under normal conditions; if it returns
541 * 1 then the search is aborted.
542 *
543 * *** WARNING ***
544 *
545 * Func should not modify any paint during the search, since this
546 * will mess up pointers kept by these procedures and likely cause
547 * a core-dump.
548 *
549 * ----------------------------------------------------------------------------
550 */
551
552 int
SimSrConnect(def,startArea,mask,connect,bounds,func,clientData)553 SimSrConnect(def, startArea, mask, connect, bounds, func, clientData)
554 CellDef *def; /* Cell definition in which to carry out
555 * the connectivity search. Only paint
556 * in this definition is considered.
557 */
558 Rect *startArea; /* Area to search for an initial tile. Only
559 * tiles OVERLAPPING the area are considered.
560 * This area should have positive x and y
561 * dimensions.
562 */
563 TileTypeBitMask *mask; /* Only tiles of one of these types are used
564 * as initial tiles.
565 */
566 TileTypeBitMask *connect; /* Pointer to a table indicating what tile
567 * types connect to what other tile types.
568 * Each entry gives a mask of types that
569 * connect to tiles of a given type.
570 */
571 Rect *bounds; /* Area, in coords of scx->scx_use->cu_def,
572 * that limits the search: only tiles
573 * overalapping this area will be returned.
574 * Use TiPlaneRect to search everywhere.
575 */
576 int (*func)(); /* Function to apply at each connected tile. */
577 ClientData clientData; /* Client data for above function. */
578
579 {
580 struct conSrArg csa;
581 int startPlane, result;
582 Tile *startTile; /* Starting tile for search. */
583 extern int dbSrConnectFunc(); /* Forward declaration. */
584 extern int dbSrConnectStartFunc();
585
586 result = 0;
587 csa.csa_def = def;
588 csa.csa_bounds = *bounds;
589
590 /* Find a starting tile (if there are many tiles underneath the
591 * starting area, pick any one). The search function just saves
592 * the tile address and returns.
593 */
594
595 startTile = NULL;
596 for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
597 {
598 if (DBSrPaintArea((Tile *) NULL,
599 def->cd_planes[startPlane], startArea, mask,
600 dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
601 }
602 if (startTile == NULL) return 0;
603
604 /* Pass 1. During this pass the client function gets called. */
605
606 csa.csa_clientFunc = func;
607 csa.csa_clientData = clientData;
608 csa.csa_clear = FALSE;
609 csa.csa_connect = connect;
610 csa.csa_pNum = startPlane;
611 if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
612
613 return result;
614 }
615
616
617 /*
618 *-----------------------------------------------------------------------------
619 *
620 * SimTreeSrTiles
621 *
622 * Similar to the procedure DBTreeSrTiles, although having a terminal
623 * path similar to procedure DBTreeSrLabels.
624 *
625 * Recursively search downward from the supplied CellUse for
626 * all visible paint tiles matching the supplied type mask.
627 *
628 * The procedure should be of the following form:
629 * int
630 * func(tile, cxp)
631 * Tile *tile;
632 * TreeContext *cxp;
633 * {
634 * }
635 *
636 * The SearchContext is stored in cxp->tc_scx, the user's arg is stored
637 * in cxp->tc_filter->tf_arg, and the terminal path is stored in
638 * cxp->tc_filter->tf_tpath.
639 *
640 * In the above, the scx transform is the net transform from the coordinates
641 * of tile to "world" coordinates (or whatever coordinates the initial
642 * transform supplied to SimTreeSrTiles was a transform to). Func returns
643 * 0 under normal conditions. If 1 is returned, it is a request to
644 * abort the search.
645 *
646 * *** WARNING ***
647 *
648 * The client procedure should not modify any of the paint planes in
649 * the cells visited by SimTreeSrTiles, because we use DBSrPaintArea
650 * as our paint-tile enumeration function.
651 *
652 * Results:
653 * 0 is returned if the search finished normally. 1 is returned
654 * if the search was aborted.
655 *
656 * Side effects:
657 * Whatever side effects are brought about by applying the
658 * procedure supplied.
659 *
660 *-----------------------------------------------------------------------------
661 */
662
663 int
SimTreeSrTiles(scx,mask,xMask,tpath,func,cdarg)664 SimTreeSrTiles(scx, mask, xMask, tpath, func, cdarg)
665 SearchContext *scx; /* Pointer to search context specifying
666 * a cell use to search, an area in the
667 * coordinates of the cell's def, and a
668 * transform back to "root" coordinates.
669 */
670 TileTypeBitMask *mask; /* Only tiles with a type for which
671 * a bit in this mask is on are processed.
672 */
673 int xMask; /* All subcells are visited recursively
674 * until we encounter uses whose flags,
675 * when anded with xMask, are not
676 * equal to xMask.
677 */
678 TerminalPath *tpath; /* Pointer to a structure describing a
679 * partially filled-in terminal pathname.
680 * Add new components as encountered.
681 */
682 int (*func)(); /* Function to apply at each qualifying tile */
683 ClientData cdarg; /* Client data for above function */
684 {
685 int SimCellTileSrFunc();
686 TreeFilter filter;
687
688 filter.tf_func = func;
689 filter.tf_arg = cdarg;
690 filter.tf_mask = mask;
691 filter.tf_xmask = xMask;
692 filter.tf_planes = DBTechTypesToPlanes(mask);
693 filter.tf_tpath = tpath;
694 filter.tf_dinfo = 0;
695
696 return SimCellTileSrFunc(scx, &filter);
697 }
698
699 /*
700 * SimTreeSrNMTiles ---
701 * This is a variant of the above in which the search is over
702 * a non-Manhattan triangular area.
703 */
704
705 int
SimTreeSrNMTiles(scx,dinfo,mask,xMask,tpath,func,cdarg)706 SimTreeSrNMTiles(scx, dinfo, mask, xMask, tpath, func, cdarg)
707 SearchContext *scx; /* Pointer to search context specifying
708 * a cell use to search, an area in the
709 * coordinates of the cell's def, and a
710 * transform back to "root" coordinates.
711 */
712 TileType dinfo; /* Type containing information about the
713 * triangular area to search.
714 */
715 TileTypeBitMask *mask; /* Only tiles with a type for which
716 * a bit in this mask is on are processed.
717 */
718 int xMask; /* All subcells are visited recursively
719 * until we encounter uses whose flags,
720 * when anded with xMask, are not
721 * equal to xMask.
722 */
723 TerminalPath *tpath; /* Pointer to a structure describing a
724 * partially filled-in terminal pathname.
725 * Add new components as encountered.
726 */
727 int (*func)(); /* Function to apply at each qualifying tile */
728 ClientData cdarg; /* Client data for above function */
729 {
730 int SimCellTileSrFunc();
731 TreeFilter filter;
732
733 filter.tf_func = func;
734 filter.tf_arg = cdarg;
735 filter.tf_mask = mask;
736 filter.tf_xmask = xMask;
737 filter.tf_dinfo = dinfo;
738 filter.tf_planes = DBTechTypesToPlanes(mask);
739 filter.tf_tpath = tpath;
740
741 return SimCellTileSrFunc(scx, &filter);
742 }
743
744 /*
745 * Filter procedure applied to subcells by SimTreeSrTiles().
746 */
747
748 int
SimCellTileSrFunc(scx,fp)749 SimCellTileSrFunc(scx, fp)
750 SearchContext *scx;
751 TreeFilter *fp;
752 {
753 TreeContext context;
754 TerminalPath *tp;
755 CellDef *def = scx->scx_use->cu_def;
756 int pNum, result;
757 char *tnext;
758
759 ASSERT(def != (CellDef *) NULL, "SimCellTileSrFunc");
760 if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
761 return 0;
762 if ((def->cd_flags & CDAVAILABLE) == 0)
763 {
764 bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
765 if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
766 }
767
768 context.tc_scx = scx;
769 context.tc_filter = fp;
770
771 /* Create the path prefix */
772 /* Don't prepend the "Topmost cell" ID of the top-level cell. */
773
774 if ((fp->tf_tpath != (TerminalPath *)NULL)
775 && (scx->scx_use->cu_parent != NULL))
776 {
777 tp = fp->tf_tpath;
778 tnext = tp->tp_next;
779 tp->tp_next = DBPrintUseId(scx, tp->tp_next, tp->tp_last -
780 tp->tp_next, FALSE);
781 if (tp->tp_next < tp->tp_last)
782 {
783 *(tp->tp_next++) = '/';
784 *(tp->tp_next) = '\0';
785 }
786 }
787
788 /*
789 * Apply the function first to any of the tiles in the planes
790 * for this CellUse's CellDef that match the mask.
791 */
792
793 result = 0;
794 for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
795 if (PlaneMaskHasPlane(fp->tf_planes, pNum))
796 {
797 if (fp->tf_dinfo & TT_DIAGONAL)
798 {
799 TileType dinfo = DBTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
800 if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
801 dinfo, &scx->scx_area, fp->tf_mask,
802 fp->tf_func, (ClientData) &context))
803 {
804 result = 1;
805 goto cleanup;
806 }
807 }
808 else
809 if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
810 &scx->scx_area, fp->tf_mask,
811 fp->tf_func, (ClientData) &context))
812 {
813 result = 1;
814 goto cleanup;
815 }
816 }
817
818 /*
819 * Now apply ourselves recursively to each of the CellUses
820 * in our tile plane.
821 */
822
823 if (DBCellSrArea(scx, SimCellTileSrFunc, (ClientData) fp))
824 result = 1;
825
826 cleanup:
827 /* Remove the trailing pathname component from the TerminalPath */
828 if ((fp->tf_tpath != (TerminalPath *)NULL)
829 && (scx->scx_use->cu_parent != NULL))
830 {
831 fp->tf_tpath->tp_next = tnext;
832 *tnext = '\0';
833 }
834 return (result);
835 }
836
837
838 /*
839 * ----------------------------------------------------------------------------
840 *
841 * SimPutLabel --
842 *
843 * Same as DBPutLabel, except this does not set the cell modified flag.
844 *
845 * Place a rectangular label in the database, in a particular cell.
846 *
847 * It is the responsibility of higher-level routines to insure that
848 * the material to which the label is being attached really exists at
849 * this point in the cell, and that TT_SPACE is used if there is
850 * no single material covering the label's entire area. The routine
851 * DBAdjustLabels is useful for this.
852 *
853 * Results:
854 * The return value is the actual alignment position used for
855 * the label. This may be different from align, if align is
856 * defaulted.
857 *
858 * Side effects:
859 * Updates the label list in the CellDef to contain the label.
860 *
861 * ----------------------------------------------------------------------------
862 */
863
864 int
SimPutLabel(cellDef,rect,align,text,type)865 SimPutLabel(cellDef, rect, align, text, type)
866 CellDef *cellDef; /* Cell in which label is placed */
867 Rect *rect; /* Location of label; see above for description */
868 int align; /* Orientation/alignment of text. If this is < 0,
869 * an orientation will be picked to keep the text
870 * inside the cell boundary.
871 */
872 char *text; /* Pointer to actual text of label */
873 TileType type; /* Type of tile to be labeled */
874 {
875 Label *lab;
876 int len, x1, x2, y1, y2, tmp, labx, laby;
877
878 len = strlen(text) + sizeof (Label) - sizeof lab->lab_text + 1;
879 lab = (Label *) mallocMagic((unsigned) len);
880 strcpy(lab->lab_text, text);
881
882 /* Pick a nice alignment if the caller didn't give one. If the
883 * label is more than BORDER units from an edge of the cell,
884 * use GEO_NORTH. Otherwise, put the label on the opposite side
885 * from the boundary, so it won't stick out past the edge of
886 * the cell boundary.
887 */
888
889 #define BORDER 5
890 if (align < 0)
891 {
892 tmp = (cellDef->cd_bbox.r_xtop - cellDef->cd_bbox.r_xbot)/3;
893 if (tmp > BORDER) tmp = BORDER;
894 x1 = cellDef->cd_bbox.r_xbot + tmp;
895 x2 = cellDef->cd_bbox.r_xtop - tmp;
896 tmp = (cellDef->cd_bbox.r_ytop - cellDef->cd_bbox.r_ybot)/3;
897 if (tmp > BORDER) tmp = BORDER;
898 y1 = cellDef->cd_bbox.r_ybot + tmp;
899 y2 = cellDef->cd_bbox.r_ytop - tmp;
900 labx = (rect->r_xtop + rect->r_xbot)/2;
901 laby = (rect->r_ytop + rect->r_ybot)/2;
902
903 if (labx <= x1)
904 {
905 if (laby <= y1) align = GEO_NORTHEAST;
906 else if (laby >= y2) align = GEO_SOUTHEAST;
907 else align = GEO_EAST;
908 }
909 else if (labx >= x2)
910 {
911 if (laby <= y1) align = GEO_NORTHWEST;
912 else if (laby >= y2) align = GEO_SOUTHWEST;
913 else align = GEO_WEST;
914 }
915 else
916 {
917 if (laby <= y1) align = GEO_NORTH;
918 else if (laby >= y2) align = GEO_SOUTH;
919 else align = GEO_NORTH;
920 }
921 }
922
923 lab->lab_just = align;
924 lab->lab_type = type;
925 lab->lab_rect = *rect;
926 lab->lab_next = NULL;
927 lab->lab_flags = 0;
928 if (cellDef->cd_labels == NULL)
929 cellDef->cd_labels = lab;
930 else
931 {
932 ASSERT(cellDef->cd_lastLabel->lab_next == NULL, "SimPutLabel");
933 cellDef->cd_lastLabel->lab_next = lab;
934 }
935 cellDef->cd_lastLabel = lab;
936
937 DBUndoPutLabel(cellDef, lab);
938 return align;
939 }
940
941
942 #ifdef RSIM_MODULE
943
944 /*
945 * ----------------------------------------------------------------------------
946 *
947 * SimRsimHandler
948 *
949 * This procedure is the button handler for the rsim tool.
950 *
951 * Results:
952 * None.
953 *
954 * Side effects:
955 * Left button: used to move the whole box by the lower-left corner.
956 * Right button: used to re-size the box by its upper-right corner.
957 * If one of the left or right buttons is pushed, then the
958 * other is pushed, the corner is switched to the nearest
959 * one to the cursor. This corner is remembered for use
960 * in box positioning/sizing when both buttons have gone up.
961 * Middle button: used to display the rsim node values of whatever
962 * paint is selected.
963 *
964 * ----------------------------------------------------------------------------
965 */
966
967 void
SimRsimHandler(w,cmd)968 SimRsimHandler(w, cmd)
969 MagWindow *w; /* Window containing cursor. */
970 TxCommand *cmd; /* Describes what happened. */
971 {
972
973 static int buttonCorner = TOOL_ILG;
974 int button = cmd->tx_button;
975
976 if (button == TX_MIDDLE_BUTTON)
977 {
978 if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
979 SimRsimMouse(w);
980 return;
981 }
982
983 if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
984 {
985 if ((WindNewButtons & (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
986 == (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
987 {
988 /* Both buttons are now down. In this case, the FIRST
989 * button pressed determines whether we move or size,
990 * and the second button is just used as a signal to pick
991 * the closest corner.
992 */
993
994 buttonCorner = ToolGetCorner(&cmd->tx_p);
995 if (button == TX_LEFT_BUTTON) button = TX_RIGHT_BUTTON;
996 else button = TX_LEFT_BUTTON;
997 }
998 else if (button == TX_LEFT_BUTTON) buttonCorner = TOOL_BL;
999 else buttonCorner = TOOL_TR;
1000 dbwButtonSetCursor(button, buttonCorner);
1001 }
1002 else
1003 {
1004 /* A button has just come up. If both buttons are down and one
1005 * is released, we just change the cursor to reflect the current
1006 * corner and the remaining button (i.e. move or size box).
1007 */
1008
1009 if (WindNewButtons != 0)
1010 {
1011 if (button == TX_LEFT_BUTTON)
1012 dbwButtonSetCursor(TX_RIGHT_BUTTON, buttonCorner);
1013 else dbwButtonSetCursor(TX_LEFT_BUTTON, buttonCorner);
1014 return;
1015 }
1016
1017 /* The last button has been released. Reset the cursor to normal
1018 * form and then move or size the box.
1019 */
1020
1021 GrSetCursor(STYLE_CURS_RSIM);
1022 switch (button)
1023 {
1024 case TX_LEFT_BUTTON:
1025 ToolMoveBox(buttonCorner, &cmd->tx_p, TRUE, (CellDef *) NULL);
1026 break;
1027 case TX_RIGHT_BUTTON:
1028 ToolMoveCorner(buttonCorner, &cmd->tx_p, TRUE,
1029 (CellDef *) NULL);
1030 }
1031 }
1032 }
1033
1034 #endif
1035