1 /*
2  * selOps.c --
3  *
4  * This file contains top-level procedures to manipulate the selection,
5  * e.g. to delete it, move it, etc.
6  *
7  *     *********************************************************************
8  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
9  *     * Permission to use, copy, modify, and distribute this              *
10  *     * software and its documentation for any purpose and without        *
11  *     * fee is hereby granted, provided that the above copyright          *
12  *     * notice appear in all copies.  The University of California        *
13  *     * makes no representations about the suitability of this            *
14  *     * software for any purpose.  It is provided "as is" without         *
15  *     * express or implied warranty.  Export of this software outside     *
16  *     * of the United States of America may require an export license.    *
17  *     *********************************************************************
18  */
19 
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/select/selOps.c,v 1.11 2010/08/22 21:58:26 tim Exp $";
22 #endif  /* not lint */
23 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "utils/magic.h"
28 #include "utils/geometry.h"
29 #include "tiles/tile.h"
30 #include "utils/hash.h"
31 #include "database/database.h"
32 #include "windows/windows.h"
33 #include "dbwind/dbwind.h"
34 #include "utils/main.h"
35 #include "select/select.h"
36 #include "select/selInt.h"
37 #include "textio/textio.h"
38 #include "utils/undo.h"
39 #include "plow/plow.h"
40 #include "utils/malloc.h"
41 #include "drc/drc.h"
42 
43 /* The following variables are shared between SelectStretch and the
44  * search functions that it causes to be invoked.
45  */
46 
47 static int selStretchX, selStretchY;	/* Stretch distances.  Only one should
48 					 * ever be non-zero.
49 					 */
50 static TileType selStretchType;		/* Type of material being stretched. */
51 unsigned char SelectDoLabels = SEL_DO_LABELS;	/* Whether or not to select subcell labels */
52 
53 typedef struct planeAndArea
54 {
55     int pa_plane;			/* Plane of interest */
56     Rect *pa_area;			/* Area affected */
57     TileTypeBitMask *pa_mask;		/* Mask used in plane search */
58 } planeAndArea;
59 
60 /* The following structure type is used to build up a list of areas
61  * to be painted.  It's used to save information while a search of
62  * the edit cell is in progress:  can't do the paints until the
63  * search has finished.
64  */
65 
66 typedef struct stretchArea
67 {
68     Rect sa_area;			/* Area to be painted. */
69     TileType sa_type;			/* Type of material to paint. */
70     struct stretchArea *sa_next;	/* Next element in list. */
71 } StretchArea;
72 
73 static StretchArea *selStretchList;	/* List of areas to paint. */
74 
75 /*
76  * ----------------------------------------------------------------------------
77  *
78  * SelectDelete --
79  *
80  * 	Delete everything in the edit cell that's selected.
81  *
82  * Results:
83  *	None.
84  *
85  * Side effects:
86  *	Stuff is removed from the edit cell.  If there's selected
87  *	stuff that isn't in the edit cell, the user is warned.
88  *
89  * ----------------------------------------------------------------------------
90  */
91 
92 void
SelectDelete(msg,do_clear)93 SelectDelete(msg, do_clear)
94     char *msg;		/* Some information to print in error messages.
95 			 * For example, if called as part of a move procedure,
96 			 * supply "moved".  This will appear in messages of
97 			 * the form "only edit cell information was moved".
98 			 */
99     bool do_clear;	/* If TRUE, clear the select def before returning. */
100 {
101     bool nonEdit;
102     Rect editArea;
103 
104     extern int selDelPaintFunc(), selDelCellFunc(), selDelLabelFunc();
105 
106     if (EditCellUse == NULL)
107     {
108 	TxError("The current cell is not editable.\n");
109 	return;
110     }
111     (void) SelEnumPaint(&DBAllButSpaceAndDRCBits, TRUE, &nonEdit,
112 	    selDelPaintFunc, (ClientData) NULL);
113     if (nonEdit)
114     {
115 	TxError("You selected paint outside the edit cell.  Only\n");
116 	TxError("    the paint in the edit cell was %s.\n", msg);
117     }
118     (void) SelEnumCells(TRUE, &nonEdit, (SearchContext *) NULL,
119 	    selDelCellFunc, (ClientData) NULL);
120     if (nonEdit)
121     {
122 	TxError("You selected one or more subcells that aren't children\n");
123 	TxError("    of the edit cell.  Only those in the edit cell were\n");
124 	TxError("    %s.\n", msg);
125     }
126     (void) SelEnumLabels(&DBAllTypeBits, TRUE, &nonEdit,
127 	    selDelLabelFunc, (ClientData) NULL);
128     if (nonEdit)
129     {
130 	TxError("You selected one or more labels that aren't in the\n");
131 	TxError("    edit cell.  Only the label(s) in the edit cell\n");
132 	TxError("    were %s.\n", msg);
133     }
134 
135     DBReComputeBbox(EditCellUse->cu_def);
136     GeoTransRect(&RootToEditTransform, &SelectDef->cd_extended, &editArea);
137     DBWAreaChanged(EditCellUse->cu_def, &editArea, DBW_ALLWINDOWS,
138 	(TileTypeBitMask *) NULL);
139     DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editArea);
140     if (do_clear) SelectClear();
141 }
142 
143 /* Search function to delete paint. */
144 
145 int
selDelPaintFunc(rect,type)146 selDelPaintFunc(rect, type)
147     Rect *rect;			/* Area of paint, in root coords. */
148     TileType type;		/* Type of paint to delete. */
149 {
150     Rect editRect;
151     TileTypeBitMask tmask;
152     TileType dinfo;
153 
154     /* Change diagonal side & direction according to the transform */
155 
156     if (type & TT_DIAGONAL)
157     {
158 	dinfo = DBTransformDiagonal(type, &RootToEditTransform);
159 	TTMaskSetOnlyType(&tmask, type & TT_LEFTMASK);
160     }
161     else
162     {
163 	dinfo = 0;
164 	TTMaskSetOnlyType(&tmask, type);
165     }
166 
167     GeoTransRect(&RootToEditTransform, rect, &editRect);
168 
169     DBEraseValid(EditCellUse->cu_def, &editRect, &tmask, dinfo);
170     return 0;
171 }
172 
173 /* Search function to delete subcell uses. */
174 
175     /* ARGSUSED */
176 int
selDelCellFunc(selUse,use)177 selDelCellFunc(selUse, use)
178     CellUse *selUse;		/* Not used. */
179     CellUse *use;		/* What to delete. */
180 {
181     if (use->cu_flags & CU_LOCKED) return 0;
182 
183     DBUnLinkCell(use, use->cu_parent);
184     DBDeleteCell(use);
185     (void) DBCellDeleteUse(use);
186     return 0;
187 }
188 
189 
190 /* Search function to delete labels.  Delete any label at the right
191  * place with the right name, regardless of layer attachment, because
192  * the selection can differ from the edit cell in this regard. */
193 
194 int
selDelLabelFunc(label)195 selDelLabelFunc(label)
196     Label *label;		/* Label to delete. */
197 {
198     DBEraseLabelsByContent(EditCellUse->cu_def, &label->lab_rect, -1,
199 		label->lab_text);
200     return 0;
201 }
202 
203 /*
204  * ----------------------------------------------------------------------------
205  *
206  * SelectCopy --
207  *
208  * 	This procedure makes a copy of the selection.
209  *
210  * Results:
211  *	None.
212  *
213  * Side effects:
214  *	The selection is copied, with the copy being transformed by
215  *	"transform" relative to the current selection.  The copy is
216  *	made the new selection.
217  *
218  * ----------------------------------------------------------------------------
219  */
220 
221 void
SelectCopy(transform)222 SelectCopy(transform)
223     Transform *transform;	/* How to displace the copy relative
224 				 * to the original.  This displacement
225 				 * is given in root coordinates.
226 				 */
227 {
228     SearchContext scx;
229 
230     /* Copy from SelectDef to Select2Def while transforming, then
231      * let SelectAndCopy2 do the rest of the work.  Don't record
232      * anything involving Select2Def for undo-ing.
233      */
234 
235     UndoDisable();
236     DBCellClearDef(Select2Def);
237     scx.scx_use = SelectUse;
238     scx.scx_area = SelectUse->cu_bbox;
239     GeoTransTrans(transform, &SelectUse->cu_transform, &scx.scx_trans);
240     (void) DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK,
241 		Select2Use);
242     (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_NO_LOCK, Select2Use,
243 		(Rect *) NULL);
244     (void) DBCellCopyAllCells(&scx, CU_DESCEND_NO_LOCK, Select2Use, (Rect *) NULL);
245     DBReComputeBbox(Select2Def);
246     UndoEnable();
247 
248     SelectClear();
249     SelectAndCopy2(EditRootDef);
250 }
251 
252 /*
253  * ----------------------------------------------------------------------------
254  *
255  * SelectFlat --
256  *
257  * 	This procedure copies the selection into Select2Def, flattening
258  *	it as it copies, then copies the result back into the selection
259  *	cell.
260  *
261  * Results:
262  *	None.
263  *
264  * Side effects:
265  *	The selection is flattened.  No changes are made in the edit cell.
266  *
267  * ----------------------------------------------------------------------------
268  */
269 
270 void
SelectFlat()271 SelectFlat()
272 {
273     SearchContext scx;
274 
275     /* Copy from SelectDef to Select2Def while transforming, then
276      * let SelectAndCopy2 do the rest of the work.  Don't record
277      * anything involving Select2Def for undo-ing.
278      */
279 
280     UndoDisable();
281     DBCellClearDef(Select2Def);
282     scx.scx_use = SelectUse;
283     scx.scx_area = SelectUse->cu_bbox;
284     GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx.scx_trans);
285     DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_ALL, Select2Use);
286     FlatCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_ALL, Select2Use);
287     DBReComputeBbox(Select2Def);
288     UndoEnable();
289 
290     /* Move everything from Select2 to Select */
291 
292     SelectClear();
293     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
294 
295     scx.scx_use = Select2Use;
296     scx.scx_area = Select2Use->cu_bbox;
297     GeoTransTrans(&GeoIdentityTransform, &Select2Use->cu_transform, &scx.scx_trans);
298 
299     DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_SPECIAL,
300 		SelectUse);
301     DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL, SelectUse,
302 		(Rect *)NULL);
303 
304     SelRememberForUndo(FALSE, SelectRootDef, &SelectUse->cu_bbox);
305 
306     /* Redisplay the select cell */
307     DBWHLRedraw(SelectRootDef, &SelectDef->cd_extended, TRUE);
308     DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
309 	&DBAllButSpaceBits);
310 
311 }
312 
313 /*
314  * ----------------------------------------------------------------------------
315  *
316  *  selShortFindPath --
317  *
318  *	Trace back through a path found by selShortFindNext from destination
319  *	to source, picking the lowest cost return path, and adding each tile
320  *	found to the linked list.
321  *
322  *	Algorithm notes (for this and selShortFindNext):  Note that by not
323  *	using one of the standard database search routines, TT_SIDE is NOT
324  *	set on any tile.  To find out what side we're looking at, we keep
325  *	a record of what direction we were traveling from the previous
326  *	tile.  Given this and the diagonal direction, we know the two
327  *	valid sides to search.
328  *
329  * ----------------------------------------------------------------------------
330  */
331 
332 int
selShortFindPath(tile,pnum,rlist,fdir)333 selShortFindPath(tile, pnum, rlist, fdir)
334    Tile *tile;
335    int pnum;
336    ExtRectList **rlist;
337    int fdir;
338 {
339     Tile *tp, *mintp;
340     // int mincost = (int)tile->ti_client;
341     int mincost = INT_MAX;
342     ExtRectList *newrrec;
343     int minp, p, mindir;
344     TileType ttype;
345 
346     newrrec = mallocMagic(sizeof(ExtRectList));
347 
348     if (IsSplit(tile))
349     {
350 	newrrec->r_type = TiGetTypeExact(tile) & ~TT_SIDE;
351 	switch(fdir)
352 	{
353 	    case GEO_NORTH:
354 		ttype = SplitBottomType(tile);
355 		if (!SplitDirection(tile)) newrrec->r_type |= TT_SIDE;
356 		break;
357 	    case GEO_SOUTH:
358 		ttype = SplitTopType(tile);
359 		if (SplitDirection(tile)) newrrec->r_type |= TT_SIDE;
360 		break;
361 	    case GEO_EAST:
362 		ttype = SplitLeftType(tile);
363 		break;
364 	    case GEO_WEST:
365 		ttype = SplitRightType(tile);
366 		newrrec->r_type |= TT_SIDE;
367 		break;
368 	    default:
369 		ttype = SplitRightType(tile);
370 		if (ttype == TT_SPACE)
371 		    ttype = SplitLeftType(tile);
372 		else
373 		    newrrec->r_type |= TT_SIDE;
374 		break;
375 	}
376     }
377     else
378     {
379 	ttype = TiGetTypeExact(tile);
380 	newrrec->r_type = ttype;
381     }
382 
383     /* Add this tile (area and type) to the linked list */
384 
385     TiToRect(tile, &newrrec->r_r);
386     newrrec->r_next = *rlist;
387     *rlist = newrrec;
388 
389     if ((int)tile->ti_client == 0) return 0;	/* We're done */
390     // if (mincost == 0) return 0;		/* We're done */
391     minp = pnum;
392 
393     /* Search top */
394     if (IsSplit(tile))
395     {
396 	if (fdir == GEO_NORTH) goto leftside;
397 	else if (SplitDirection(tile) && fdir == GEO_EAST) goto leftside;
398 	else if (!SplitDirection(tile) && fdir == GEO_WEST) goto leftside;
399     }
400 
401     for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
402     {
403 	if (tp->ti_client == (ClientData)CLIENTDEFAULT) continue;
404 	if ((int)tp->ti_client < mincost)
405 	{
406 	    mincost = (int)tp->ti_client;
407 	    mintp = tp;
408 	    mindir = GEO_NORTH;
409 	}
410     }
411 
412     /* Search left */
413 leftside:
414     if (IsSplit(tile))
415     {
416 	if (fdir == GEO_WEST) goto bottomside;
417 	else if (SplitDirection(tile) && fdir == GEO_SOUTH) goto bottomside;
418 	else if (!SplitDirection(tile) && fdir == GEO_NORTH) goto bottomside;
419     }
420 
421     for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
422     {
423 	if (tp->ti_client == (ClientData)CLIENTDEFAULT) continue;
424 	if ((int)tp->ti_client < mincost)
425 	{
426 	    mincost = (int)tp->ti_client;
427 	    mintp = tp;
428 	    mindir = GEO_WEST;
429 	}
430     }
431 
432     /* Search bottom */
433 bottomside:
434     if (IsSplit(tile))
435     {
436 	if (fdir == GEO_SOUTH) goto rightside;
437 	else if (SplitDirection(tile) && fdir == GEO_WEST) goto rightside;
438 	else if (!SplitDirection(tile) && fdir == GEO_EAST) goto rightside;
439     }
440 
441     for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
442     {
443 	if (tp->ti_client == (ClientData)CLIENTDEFAULT) continue;
444 	if ((int)tp->ti_client < mincost)
445 	{
446 	    mincost = (int)tp->ti_client;
447 	    mintp = tp;
448 	    mindir = GEO_SOUTH;
449 	}
450     }
451 
452     /* Search right */
453 rightside:
454     if (IsSplit(tile))
455     {
456 	if (fdir == GEO_EAST) goto donesides;
457 	else if (SplitDirection(tile) && fdir == GEO_NORTH) goto donesides;
458 	else if (!SplitDirection(tile) && fdir == GEO_SOUTH) goto donesides;
459     }
460 
461     for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
462     {
463 	if (tp->ti_client == (ClientData)CLIENTDEFAULT) continue;
464 	if ((int)tp->ti_client < mincost)
465 	{
466 	    mincost = (int)tp->ti_client;
467 	    mintp = tp;
468 	    mindir = GEO_EAST;
469 	}
470     }
471 
472     /* Search other connecting planes */
473 donesides:
474     if (DBIsContact(ttype))
475     {
476 	PlaneMask pmask;
477 
478 	pmask = DBConnPlanes[ttype];
479 	for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++)
480 	{
481 	    if (PlaneMaskHasPlane(pmask, p) && (p != pnum))
482 	    {
483 		tp = SelectDef->cd_planes[p]->pl_hint;
484 		GOTOPOINT(tp, &tile->ti_ll);
485 		if (tp->ti_client == (ClientData)CLIENTDEFAULT) continue;
486 		if ((int)tp->ti_client < mincost)
487 		{
488 		    mincost = (int)tp->ti_client;
489 		    mintp = tp;
490 		    minp = p;
491 		    mindir = GEO_CENTER;
492 		}
493 	    }
494 	}
495     }
496 
497     /* If mincost is still set to INT_MAX we have a real serious problem! */
498     if (mincost == INT_MAX) return 1;
499 
500     /* If no tile had lower cost than this one, then we have an error */
501     // if (mincost == (int)tile->ti_client) return 1;
502 
503     /* Stopgap measure:  Error should not happen, but it does!	*/
504     /* Remove client data of current tile and take minimum.	*/
505     if (mincost == (int)tile->ti_client) TiSetClient(tile, CLIENTDEFAULT);
506 
507     /* Now we have the minimum cost neighboring tile;  recursively search it */
508 
509     return selShortFindPath(mintp, minp, rlist, mindir);
510 }
511 
512 /*
513  * ----------------------------------------------------------------------------
514  *
515  * selShortFindNext --
516  *
517  *	Recursive function for finding shorts.  This routine makes strong
518  *	assumptions;  namely, that all non-space material in the cell being
519  *	searched belongs to the same net.  The cell searched is always
520  *	SelectDef.
521  *
522  * Results:
523  *	Return 0 to keep going;  return 1 to stop when the tile contains
524  *	the destination point.
525  *
526  * Side effects:
527  *	Each tile visited has its ClientData record set to the current
528  *	cost, in units equal to the steps from the source.
529  *
530  * ----------------------------------------------------------------------------
531  */
532 
533 int
selShortFindNext(tile,pnum,ldest,cost,best,fdir,mask)534 selShortFindNext(tile, pnum, ldest, cost, best, fdir, mask)
535     Tile *tile;
536     int pnum;
537     Label *ldest;
538     int cost, *best, fdir;
539     TileTypeBitMask *mask;
540 {
541     TileType ttype;
542     TileTypeBitMask *lmask;
543     Tile *tp;
544 
545     if (IsSplit(tile))
546     {
547 	switch(fdir)
548 	{
549 	    case GEO_NORTH:
550 		ttype = SplitBottomType(tile);
551 		break;
552 	    case GEO_SOUTH:
553 		ttype = SplitTopType(tile);
554 		break;
555 	    case GEO_EAST:
556 		ttype = SplitLeftType(tile);
557 		break;
558 	    case GEO_WEST:
559 		ttype = SplitRightType(tile);
560 		break;
561 	    default:
562 		ttype = SplitLeftType(tile);
563 		if (ttype == TT_SPACE) ttype = SplitRightType(tile);
564 		break;
565 	}
566     }
567     else
568 	ttype = TiGetTypeExact(tile);
569 
570     /* Ignore space tiles */
571     if (ttype == TT_SPACE) return 0;
572 
573     /* Ignore non-connecting tiles */
574     if (!TTMaskHasType(mask, ttype)) return 0;
575 
576     /* If this tile is unvisited, or has a lower cost, then return and	*/
577     /* keep going.  Otherwise, return 1 to stop the search this direction */
578 
579     if (tile->ti_client == (ClientData)CLIENTDEFAULT)
580 	TiSetClient(tile, cost);
581     else if ((int)tile->ti_client > cost)
582 	TiSetClient(tile, cost);
583     else
584 	return 0;
585 
586     /* If this tile contains the destination point, do not search further */
587 
588     if ((ttype == ldest->lab_type) && EnclosePoint(tile, &ldest->lab_rect.r_ll))
589     {
590 	if (*best >= cost) *best = (cost - 1);
591 	return 0;
592     }
593 
594     /* If we're more costly than the best known path to destination, do	*/
595     /* not search further.						*/
596 
597     if (cost >= *best) return 0;
598     lmask = &DBConnectTbl[ttype];
599 
600     /* Search top */
601     if (IsSplit(tile))
602     {
603 	if (fdir == GEO_NORTH) goto srchleft;
604 	else if (SplitDirection(tile) && fdir == GEO_EAST) goto srchleft;
605 	else if (!SplitDirection(tile) && fdir == GEO_WEST) goto srchleft;
606     }
607 
608     for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
609     {
610 	selShortFindNext(tp, pnum, ldest, cost + 1, best, GEO_NORTH, lmask);
611     }
612 
613     /* Search left */
614 srchleft:
615     if (IsSplit(tile))
616     {
617 	if (fdir == GEO_WEST) goto srchbot;
618 	else if (SplitDirection(tile) && fdir == GEO_SOUTH) goto srchbot;
619 	else if (!SplitDirection(tile) && fdir == GEO_NORTH) goto srchbot;
620     }
621 
622     for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
623     {
624 	selShortFindNext(tp, pnum, ldest, cost + 1, best, GEO_WEST, lmask);
625     }
626 
627     /* Search bottom */
628 srchbot:
629     if (IsSplit(tile))
630     {
631 	if (fdir == GEO_SOUTH) goto srchright;
632 	else if (SplitDirection(tile) && fdir == GEO_WEST) goto srchright;
633 	else if (!SplitDirection(tile) && fdir == GEO_EAST) goto srchright;
634     }
635 
636     for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
637     {
638 	selShortFindNext(tp, pnum, ldest, cost + 1, best, GEO_SOUTH, lmask);
639     }
640 
641     /* Search right */
642 srchright:
643     if (IsSplit(tile))
644     {
645 	if (fdir == GEO_EAST) goto donesrch;
646 	else if (SplitDirection(tile) && fdir == GEO_NORTH) goto donesrch;
647 	else if (!SplitDirection(tile) && fdir == GEO_SOUTH) goto donesrch;
648     }
649 
650     for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
651     {
652 	selShortFindNext(tp, pnum, ldest, cost + 1, best, GEO_EAST, lmask);
653     }
654 
655     /* Search other connecting planes */
656 donesrch:
657     if (DBIsContact(ttype))
658     {
659 	PlaneMask pmask;
660 	int p;
661 
662 	pmask = DBConnPlanes[ttype];
663 	for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++)
664 	{
665 	    if (PlaneMaskHasPlane(pmask, p) && (p != pnum))
666 	    {
667 		tp = SelectDef->cd_planes[p]->pl_hint;
668 		GOTOPOINT(tp, &tile->ti_ll);
669 		selShortFindNext(tp, p, ldest, cost + 1, best, GEO_CENTER, lmask);
670 	    }
671 	}
672     }
673     return 0;
674 }
675 
676 
677 /*
678  * ----------------------------------------------------------------------------
679  *
680  * SelectShort --
681  *
682  *	This procedure, given two labels, finds the location of those
683  *	labels in SelectDef.  One is marked as source, the other as
684  *	destination.  Then the SelectDef paint (which is assumed to be
685  *	a net selection that is all local to SelectDef) is recursively
686  *	searched for connecting material.  Each tile ClientData is
687  *	given a cost which is the number of steps from the source.
688  *	At the end, the minimum cost path is traced from the destination
689  * 	back to the source, and the path is saved as a linked list and
690  *	passed back to the calling procedure.
691  *
692  * Results:
693  *	A linked list of tiles representing the connecting path with the
694  *	fewest steps between source and destination.
695  *
696  * Side effects:
697  *	Tile database left with non-default ClientData.  It may be necessary
698  *	to re-run the search routine to return all tiles to the default
699  *	ClientData value.
700  * ----------------------------------------------------------------------------
701  */
702 
703 ExtRectList *
SelectShort(char * lab1,char * lab2)704 SelectShort(char *lab1, char *lab2)
705 {
706     Label *selLabel, *srclab = NULL, *destlab = NULL;
707     Tile *tile;
708     Plane *plane;
709     int pnum, best;
710     PlaneMask pmask;
711     ExtRectList *rlist;
712 
713     /* Step one: find the tiles containing the labels.  If not found,	*/
714     /* return NULL.							*/
715 
716     for (selLabel = SelectDef->cd_labels; selLabel != NULL; selLabel =
717 	selLabel->lab_next)
718     {
719 	if ((srclab == NULL) && Match(lab1, selLabel->lab_text))
720 	    srclab = selLabel;
721 
722 	if ((destlab == NULL) && Match(lab2, selLabel->lab_text))
723 	    destlab = selLabel;
724     }
725 
726     /* Was nothing selected?  Then run the equivalent of "goto lab1 ; select net */
727     if (srclab == NULL && destlab == NULL)
728     {
729 	CellUse *use;
730 	TileType ttype;
731 	Rect rect;
732 	SearchContext scx;
733 	MagWindow *window;
734 	DBWclientRec *crec;
735 	int windowMask;
736 
737 	window = ToolGetBoxWindow(&rect, &windowMask);
738 	if (!window) return NULL;
739 
740 	use = (CellUse *)window->w_surfaceID;
741 	ttype = CmdFindNetProc(lab1, use, &rect, FALSE);
742 	if (ttype == TT_SPACE) return NULL;
743 
744 	bzero(&scx, sizeof(SearchContext));
745 	scx.scx_use = use;
746 	scx.scx_trans = GeoIdentityTransform;
747 	scx.scx_area = rect;
748 	crec = (DBWclientRec *)window->w_clientData;
749 
750 	SelectNet(&scx, ttype, crec->dbw_bitmask, (Rect *)NULL, FALSE);
751 
752     	for (selLabel = SelectDef->cd_labels; selLabel != NULL; selLabel =
753 			selLabel->lab_next)
754     	{
755 	    if ((srclab == NULL) && Match(lab1, selLabel->lab_text))
756 	    	srclab = selLabel;
757 
758 	    if ((destlab == NULL) && Match(lab2, selLabel->lab_text))
759 	    	destlab = selLabel;
760     	}
761     }
762 
763     /* Must be able to find both labels */
764     if (srclab == NULL || destlab == NULL) return NULL;
765 
766     /* Must be able to find tiles associated with each label */
767 
768     pmask = DBTypePlaneMaskTbl[srclab->lab_type];
769     for (pnum = PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++)
770     {
771 	if (PlaneMaskHasPlane(pmask, pnum))
772 	{
773 	    plane = SelectDef->cd_planes[pnum];
774 	    tile = plane->pl_hint;
775 	    GOTOPOINT(tile, &srclab->lab_rect.r_ll)
776 	    if (TiGetType(tile) == srclab->lab_type) break;
777 	}
778     }
779     best = INT_MAX;
780     selShortFindNext(tile, pnum, &destlab->lab_rect.r_ll, 0, &best, GEO_CENTER,
781 		&DBConnectTbl[srclab->lab_type]);
782 
783     /* Now see if destination has been counted */
784 
785     pmask = DBTypePlaneMaskTbl[destlab->lab_type];
786     for (pnum = PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++)
787     {
788 	if (PlaneMaskHasPlane(pmask, pnum))
789 	{
790 	    plane = SelectDef->cd_planes[pnum];
791 	    tile = plane->pl_hint;
792 	    GOTOPOINT(tile, &destlab->lab_rect.r_ll)
793 	    if (TiGetType(tile) == destlab->lab_type) break;
794 	}
795     }
796 
797     if (tile->ti_client == (ClientData)CLIENTDEFAULT) return NULL;
798 
799     /* Now find the shortest path between source and destination */
800     rlist = NULL;
801     selShortFindPath(tile, pnum, &rlist, GEO_CENTER);
802 
803     return rlist;
804 }
805 
806 
807 /*
808  * ----------------------------------------------------------------------------
809  *
810  * selTransTo2 --
811  *
812  * 	This local procedure makes a transformed copy of the selection
813  *	in Select2Def, ignoring everything that's not in the edit cell.
814  *
815  * Results:
816  *	None.
817  *
818  * Side effects:
819  *	Select2Def gets modified to hold the transformed selection.
820  *	Error messages get printed if the selection contains any
821  *	non-edit material.
822  *
823  * ----------------------------------------------------------------------------
824  */
825 
826 void
selTransTo2(transform)827 selTransTo2(transform)
828     Transform *transform;	/* How to transform stuff before copying
829 				 * it to Select2Def.
830 				 */
831 {
832     int selTransPaintFunc();	/* Forward references. */
833     int selTransCellFunc();
834     int selTransLabelFunc();
835 
836     UndoDisable();
837     DBCellClearDef(Select2Def);
838     (void) SelEnumPaint(&DBAllButSpaceAndDRCBits, TRUE, (bool *) NULL,
839 	    selTransPaintFunc, (ClientData) transform);
840     (void) SelEnumCells(TRUE, (bool *) NULL, (SearchContext *) NULL,
841 	    selTransCellFunc, (ClientData) transform);
842     (void) SelEnumLabels(&DBAllTypeBits, TRUE, (bool *) NULL,
843 	    selTransLabelFunc, (ClientData) transform);
844     DBReComputeBbox(Select2Def);
845     UndoEnable();
846 }
847 
848 /* Search function to copy paint.  Always return 1 to keep the search alive. */
849 
850 int
selTransPaintFunc(rect,type,transform)851 selTransPaintFunc(rect, type, transform)
852     Rect *rect;			/* Area of paint. */
853     TileType type;		/* Type of paint. */
854     Transform *transform;	/* How to change coords before painting. */
855 {
856     Rect newarea;
857     TileType loctype;
858 
859     /* Change diagonal direction according to the transform */
860     if (type & TT_DIAGONAL)
861     {
862 	loctype = DBTransformDiagonal(type, transform);
863 	loctype |= (loctype & TT_SIDE) ? (type & TT_LEFTMASK) << 14 :
864 		(type & TT_LEFTMASK);
865     }
866     else
867 	loctype = type;
868 
869     GeoTransRect(transform, rect, &newarea);
870     DBPaint(Select2Def, &newarea, loctype);
871     return 0;
872 }
873 
874 /* Search function to copy subcells.  Always return 1 to keep the
875  * search alive.
876  */
877 
878     /* ARGSUSED */
879 int
selTransCellFunc(selUse,realUse,realTrans,transform)880 selTransCellFunc(selUse, realUse, realTrans, transform)
881     CellUse *selUse;		/* Use from selection. */
882     CellUse *realUse;		/* Corresponding use from layout (used to
883 				 * get id). */
884     Transform *realTrans;	/* Transform for realUse (ignored). */
885     Transform *transform;	/* How to change coords of selUse before
886 				 * copying.
887 				 */
888 {
889     CellUse  *newUse;
890     Transform newTrans;
891 
892     if (selUse->cu_flags & CU_LOCKED) return 0;
893 
894     newUse = DBCellNewUse(selUse->cu_def, (char *) realUse->cu_id);
895     if (!DBLinkCell(newUse, Select2Def))
896     {
897 	freeMagic((char *) newUse->cu_id);
898 	newUse->cu_id = NULL;
899 	(void) DBLinkCell(newUse, Select2Def);
900     }
901     GeoTransTrans(&selUse->cu_transform, transform, &newTrans);
902     DBSetArray(selUse, newUse);
903     DBSetTrans(newUse, &newTrans);
904     newUse->cu_expandMask = selUse->cu_expandMask;
905     newUse->cu_flags = selUse->cu_flags;
906     DBPlaceCell(newUse, Select2Def);
907 
908     return 0;
909 }
910 
911 /* Search function to copy labels.  Return 0 always to avoid
912  * aborting search.
913  */
914 
915     /* ARGSUSED */
916 int
selTransLabelFunc(label,cellUse,defTransform,transform)917 selTransLabelFunc(label, cellUse, defTransform, transform)
918     Label *label;		/* Label to copy.  This points to label
919 				 * in cellDef.
920 				 */
921     CellUse *cellUse;		/* (unused) */
922     Transform *defTransform;	/* Transform from cellDef to root. */
923     Transform *transform;	/* How to modify coords before copying to
924 				 * Select2Def.
925 				 */
926 {
927     Rect rootArea, finalArea;
928     int rootJust, finalJust;
929     Point rootOffset, finalOffset;
930     int rootRotate, finalRotate;
931 
932     GeoTransRect(defTransform, &label->lab_rect, &rootArea);
933     rootJust = GeoTransPos(defTransform, label->lab_just);
934     GeoTransPointDelta(defTransform, &label->lab_offset, &rootOffset);
935     rootRotate = GeoTransAngle(defTransform, label->lab_rotate);
936 
937     GeoTransRect(transform, &rootArea, &finalArea);
938     finalJust = GeoTransPos(transform, rootJust);
939     GeoTransPointDelta(transform, &rootOffset, &finalOffset);
940     finalRotate = GeoTransAngle(transform, rootRotate);
941 
942     (void) DBPutFontLabel(Select2Def, &finalArea, label->lab_font,
943 	    label->lab_size, finalRotate, &finalOffset, finalJust,
944 	    label->lab_text, label->lab_type, label->lab_flags,
945 	    label->lab_port);
946     return 0;
947 }
948 
949 /*
950  * ----------------------------------------------------------------------------
951  *
952  * SelectTransform --
953  *
954  * 	This procedure modifies the selection by transforming
955  *	it geometrically.
956  *
957  * Results:
958  *	None.
959  *
960  * Side effects:
961  *	The selection is modified and redisplayed.
962  *
963  * ----------------------------------------------------------------------------
964  */
965 
966 void
SelectTransform(transform)967 SelectTransform(transform)
968     Transform *transform;		/* How to displace the selection.
969 					 * The transform is in root (user-
970 					 * visible) coordinates.
971 					 */
972 {
973     if (EditCellUse == NULL)
974     {
975 	TxError("The current cell is not editable.\n");
976 	return;
977     }
978 
979     /* Copy from SelectDef to Select2Def, transforming along the way. */
980 
981     selTransTo2(transform);
982 
983     /* Now just delete the selection and recreate it from Select2Def,
984      * copying into the edit cell along the way.
985      */
986 
987     SelectDelete("modified", TRUE);
988     SelectAndCopy2(EditRootDef);
989 }
990 
991 /*
992  * ----------------------------------------------------------------------------
993  *
994  * SelectExpand --
995  *
996  * 	Expand all of the selected cells that are unexpanded, and
997  *	unexpand all of those that are expanded.
998  *
999  * Results:
1000  *	None.
1001  *
1002  * Side effects:
1003  *	The contents of the selected cells will become visible or
1004  *	invisible on the display in the indicated window(s).
1005  *
1006  * ----------------------------------------------------------------------------
1007  */
1008 
1009 void
SelectExpand(mask)1010 SelectExpand(mask)
1011     int mask;			/* Bits of this word indicate which
1012 				 * windows the selected cells will be
1013 				 * expanded in.
1014 				 */
1015 {
1016     extern int selExpandFunc();	/* Forward reference. */
1017 
1018     (void) SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL,
1019 	    selExpandFunc, (ClientData) mask);
1020 }
1021 
1022     /* ARGSUSED */
1023 int
selExpandFunc(selUse,use,transform,mask)1024 selExpandFunc(selUse, use, transform, mask)
1025     CellUse *selUse;		/* Use from selection. */
1026     CellUse *use;		/* Use to expand (in actual layout). */
1027     Transform *transform;	/* Not used. */
1028     int mask;			/* Windows in which to expand. */
1029 {
1030     /* Don't change expansion status of root cell:  screws up
1031      * DBWAreaChanged (need to always have at least top-level
1032      * cell be expanded).
1033      */
1034 
1035     if (use->cu_parent == NULL)
1036     {
1037 	TxError("Can't unexpand root cell of window.\n");
1038 	return 0;
1039     }
1040 
1041     /* Be sure to modify the expansion bit in the selection as well as
1042      * the one in the layout in order to keep them consistent.
1043      */
1044 
1045     if (DBDescendSubcell(use, mask))
1046     {
1047 	DBExpand(selUse, mask, FALSE);
1048 	DBExpand(use, mask, FALSE);
1049 	DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
1050 	    (TileTypeBitMask *) NULL);
1051     }
1052     else
1053     {
1054 	DBExpand(selUse, mask, TRUE);
1055 	DBExpand(use, mask, TRUE);
1056 	DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
1057     }
1058     return 0;
1059 }
1060 
1061 /*
1062  * ----------------------------------------------------------------------------
1063  *
1064  * SelectArray --
1065  *
1066  * 	Array everything in the selection.  Cells get turned into
1067  *	arrays, and paint and labels get replicated.
1068  *
1069  * Results:
1070  *	None.
1071  *
1072  * Side effects:
1073  *	The edit cell is modified in a big way.  It's also redisplayed.
1074  *
1075  * ----------------------------------------------------------------------------
1076  */
1077 
1078 void
SelectArray(arrayInfo)1079 SelectArray(arrayInfo)
1080     ArrayInfo *arrayInfo;	/* Describes desired shape of array, all in
1081 				 * root coordinates.
1082 				 */
1083 {
1084     extern int selArrayPFunc(), selArrayCFunc(), selArrayLFunc();
1085 
1086     /* The way arraying is done is similar to moving:  make an
1087      * arrayed copy of everything in Select2Def, then delete the
1088      * selection, then copy everything back from Select2Def and
1089      * select it.
1090      */
1091 
1092     UndoDisable();
1093     DBCellClearDef(Select2Def);
1094     (void) SelEnumPaint(&DBAllButSpaceAndDRCBits, TRUE, (bool *) NULL,
1095 	    selArrayPFunc, (ClientData) arrayInfo);
1096     (void) SelEnumCells(TRUE, (bool *) NULL, (SearchContext *) NULL,
1097 	    selArrayCFunc, (ClientData) arrayInfo);
1098     (void) SelEnumLabels(&DBAllTypeBits, TRUE, (bool *) NULL,
1099 	    selArrayLFunc, (ClientData) arrayInfo);
1100     DBReComputeBbox(Select2Def);
1101     UndoEnable();
1102 
1103     /* Now just delete the selection and recreate it from Select2Def,
1104      * copying into the edit cell along the way.
1105      */
1106 
1107     SelectDelete("arrayed", TRUE);
1108     SelectAndCopy2(EditRootDef);
1109 }
1110 
1111 /* Search function for paint.  Just make many copies of the paint
1112  * into Select2Def.  Always return 0 to keep the search alive.
1113  */
1114 
1115 int
selArrayPFunc(rect,type,arrayInfo)1116 selArrayPFunc(rect, type, arrayInfo)
1117     Rect *rect;			/* Rectangle to be arrayed. */
1118     TileType type;		/* Type of tile. */
1119     ArrayInfo *arrayInfo;	/* How to array. */
1120 {
1121     int y, nx, ny;
1122     Rect current;
1123 
1124     nx = arrayInfo->ar_xhi - arrayInfo->ar_xlo;
1125     if (nx < 0) nx = -nx;
1126     ny = arrayInfo->ar_yhi - arrayInfo->ar_ylo;
1127     if (ny < 0) ny = -ny;
1128 
1129     current = *rect;
1130     for ( ; nx >= 0; nx -= 1)
1131     {
1132 	current.r_ybot = rect->r_ybot;
1133 	current.r_ytop = rect->r_ytop;
1134 	for (y = ny; y >= 0; y -= 1)
1135 	{
1136 	    DBPaint(Select2Def, &current, type);
1137 	    current.r_ybot += arrayInfo->ar_ysep;
1138 	    current.r_ytop += arrayInfo->ar_ysep;
1139 	}
1140 	current.r_xbot += arrayInfo->ar_xsep;
1141 	current.r_xtop += arrayInfo->ar_xsep;
1142     }
1143     return 0;
1144 }
1145 
1146 /* Search function for cells.  Just make an arrayed copy of
1147  * each subcell found.
1148  */
1149 
1150     /* ARGSUSED */
1151 int
selArrayCFunc(selUse,use,transform,arrayInfo)1152 selArrayCFunc(selUse, use, transform, arrayInfo)
1153     CellUse *selUse;		/* Use from selection (not used). */
1154     CellUse *use;		/* Use to be copied and arrayed. */
1155     Transform *transform;	/* Transform from use->cu_def to root. */
1156     ArrayInfo *arrayInfo;	/* Array characteristics desired. */
1157 {
1158     CellUse *newUse;
1159     Transform tinv, newTrans;
1160     Rect tmp, oldBbox;
1161 
1162     /* When creating a new use, try to re-use the id from the old
1163      * one.  Only create a new one if the old id can't be used.
1164      */
1165 
1166     newUse = DBCellNewUse(use->cu_def, (char *) use->cu_id);
1167     if (!DBLinkCell(newUse, Select2Def))
1168     {
1169 	freeMagic((char *) newUse->cu_id);
1170 	newUse->cu_id = NULL;
1171 	(void) DBLinkCell(newUse, Select2Def);
1172     }
1173     newUse->cu_expandMask = use->cu_expandMask;
1174     newUse->cu_flags = use->cu_flags;
1175 
1176     DBSetTrans(newUse, transform);
1177     GeoInvertTrans(transform, &tinv);
1178     DBMakeArray(newUse, &tinv, arrayInfo->ar_xlo,
1179 	arrayInfo->ar_ylo, arrayInfo->ar_xhi, arrayInfo->ar_yhi,
1180 	arrayInfo->ar_xsep, arrayInfo->ar_ysep);
1181 
1182     /* Set the array's transform so that its lower-left corner is in
1183      * the same place that it used to be.
1184      */
1185 
1186     GeoInvertTrans(&use->cu_transform, &tinv);
1187     GeoTransRect(&tinv, &use->cu_bbox, &tmp);
1188     GeoTransRect(transform, &tmp, &oldBbox);
1189     GeoTranslateTrans(&newUse->cu_transform,
1190 	    oldBbox.r_xbot - newUse->cu_bbox.r_xbot,
1191 	    oldBbox.r_ybot - newUse->cu_bbox.r_ybot,
1192 	    &newTrans);
1193     DBSetTrans(newUse, &newTrans);
1194 
1195     if (DBCellFindDup(newUse, Select2Def) != NULL)
1196     {
1197 	DBUnLinkCell(newUse, Select2Def);
1198 	(void) DBCellDeleteUse(newUse);
1199     }
1200     else DBPlaceCell(newUse, Select2Def);
1201 
1202     return 0;
1203 }
1204 
1205 /* Search function for labels.  Similar to paint search function. */
1206 /* modified by harry eaton to increment numbers in array labels */
1207 
1208     /* ARGSUSED */
1209 int
selArrayLFunc(label,use,transform,arrayInfo)1210 selArrayLFunc(label, use, transform, arrayInfo)
1211     Label *label;		/* Label to be copied and replicated. */
1212     CellUse *use;		/* (unused) */
1213     Transform *transform;	/* Transform from coords of def to root. */
1214     ArrayInfo *arrayInfo;	/* How to replicate. */
1215 {
1216     int y, nx, ny, rootJust, rootRotate;
1217     Point rootOffset;
1218     Rect original, current;
1219     char *astr;
1220     int labx, laby, xi, yi, only1;	/* numeric parts of label */
1221 
1222     char *nmPutNums();			/* Forward reference */
1223 
1224     nx = arrayInfo->ar_xhi - arrayInfo->ar_xlo;
1225     if (nx < 0) nx = -nx;
1226     ny = arrayInfo->ar_yhi - arrayInfo->ar_ylo;
1227     if (ny < 0) ny = -ny;
1228 
1229     GeoTransRect(transform, &label->lab_rect, &original);
1230     rootJust = GeoTransPos(transform, label->lab_just);
1231     rootRotate = GeoTransAngle(transform, label->lab_rotate);
1232     GeoTransPointDelta(transform, &label->lab_offset, &rootOffset);
1233     current = original;
1234 
1235     /* get the existing numbers in the label */
1236     nmGetNums(label->lab_text, &labx, &laby);
1237 
1238     xi = yi = 0;
1239     if (nx > 0 && ny > 0)
1240 	only1 = 0;
1241     else
1242 	only1 = 1;
1243     for ( ; nx >= 0; nx -= 1)
1244     {
1245 	current.r_ybot = original.r_ybot;
1246 	current.r_ytop = original.r_ytop;
1247 	for (y = ny; y >= 0; y -= 1)
1248 	{
1249 	    /* Eliminate any duplicate labels.  Don't use type in comparing
1250 	     * for duplicates, because the selection's type could change
1251 	     * after it gets added to the edit cell.  Any label with
1252 	     * the same text and position is considered a duplicate.
1253 	     */
1254 	    yi = ny - y;
1255 	    astr = nmPutNums(label->lab_text, labx + xi, laby + yi);
1256 	    DBEraseLabelsByContent(Select2Def, &current, -1, astr);
1257 	    DBPutFontLabel(Select2Def, &current, label->lab_font,
1258 			label->lab_size, rootRotate, &rootOffset,
1259 			rootJust, astr, label->lab_type,
1260 			label->lab_flags, label->lab_port);
1261 	    current.r_ybot += arrayInfo->ar_ysep;
1262 	    current.r_ytop += arrayInfo->ar_ysep;
1263 	    xi += only1;
1264 	}
1265 	xi += (1 - only1);
1266 	current.r_xbot += arrayInfo->ar_xsep;
1267 	current.r_xtop += arrayInfo->ar_xsep;
1268     }
1269     return 0;
1270 }
1271 
1272 /*
1273  * ----------------------------------------------------------------------------
1274  *	SelectStretch --
1275  *
1276  * 	Move the selection a given amount in x (or y).  While moving,
1277  *	erase everything that the selection passes over, and stretch
1278  *	material behind the selection.
1279  *
1280  * Results:
1281  *	None.
1282  *
1283  * Side effects:
1284  *	The edit cell is modified.  The selection is also modified
1285  *	and redisplayed.
1286  * ----------------------------------------------------------------------------
1287  */
1288 
1289 void
SelectStretch(x,y)1290 SelectStretch(x, y)
1291     int x;			/* Amount to move in the x-direction. */
1292     int y;			/* Amount to move in the y-direction.  Must
1293 				 * be zero if x is non-zero.
1294 				 */
1295 {
1296     Transform transform;
1297     int plane;
1298     Rect modifiedArea, editModified;
1299     extern int selStretchEraseFunc(), selStretchFillFunc();
1300 				/* Forward declarations. */
1301 
1302     if ((x == 0) && (y == 0)) return;
1303 
1304     /* First of all, copy from SelectDef to Select2Def, moving the
1305      * selection along the way.
1306      */
1307 
1308     GeoTranslateTrans(&GeoIdentityTransform, x, y, &transform);
1309     selTransTo2(&transform);
1310 
1311     /* We're going to modify not just the old selection area or the new
1312      * one, but everything in-between too.  Remember this and tell the
1313      * displayer and DRC about it later.
1314      */
1315 
1316     modifiedArea = Select2Def->cd_extended;
1317     (void) GeoInclude(&SelectDef->cd_extended, &modifiedArea);
1318     GeoTransRect(&RootToEditTransform, &modifiedArea, &editModified);
1319 
1320     /* Delete the selection itself. */
1321 
1322     SelectDelete("stretched", TRUE);
1323 
1324     /* Next, delete all the material in front of each piece of paint in
1325      * the selection.
1326      */
1327 
1328     selStretchX = x;
1329     selStretchY = y;
1330     for (plane = PL_SELECTBASE; plane < DBNumPlanes; plane++)
1331     {
1332 	(void) DBSrPaintArea((Tile *) NULL, Select2Def->cd_planes[plane],
1333 		&TiPlaneRect, &DBAllButSpaceAndDRCBits, selStretchEraseFunc,
1334 		(ClientData) &plane);
1335     }
1336 
1337     /* To achieve the stretch affect, fill in material behind the selection
1338      * everywhere that it used to touch other material in the edit cell.
1339      * This code first builds up a list of areas to paint, then paints them
1340      * (can't paint as we go because the new paint interacts with the
1341      * computation of what to stretch).
1342      */
1343 
1344     selStretchList = NULL;
1345     for (plane = PL_SELECTBASE; plane < DBNumPlanes; plane++)
1346     {
1347 	(void) DBSrPaintArea((Tile *) NULL, Select2Def->cd_planes[plane],
1348 		&TiPlaneRect, &DBAllButSpaceAndDRCBits, selStretchFillFunc,
1349 		(ClientData) &plane);
1350     }
1351 
1352     /* Paint back the areas in the list. */
1353 
1354     while (selStretchList != NULL)
1355     {
1356 	TileTypeBitMask tmask;
1357 	TileType type = selStretchList->sa_type;
1358 
1359 	TileType tloc;
1360 	tloc = (type & TT_DIAGONAL) ?  ((type & TT_SIDE) ?
1361 		(type & TT_RIGHTMASK) >> 14 : (type & TT_LEFTMASK)) : type;
1362 	TTMaskSetOnlyType(&tmask, tloc);
1363 
1364 	DBPaintValid(EditCellUse->cu_def, &selStretchList->sa_area, &tmask, type);
1365 	freeMagic((char *) selStretchList);
1366 	selStretchList = selStretchList->sa_next;
1367     }
1368 
1369     /* Paint the new translated selection back into the edit cell,
1370      * select it again, and tell DRC and display about what we
1371      * changed.
1372      */
1373 
1374     SelectAndCopy2(EditRootDef);
1375     DBWAreaChanged(EditCellUse->cu_def, &editModified, DBW_ALLWINDOWS,
1376 	(TileTypeBitMask *) NULL);
1377     DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editModified);
1378 }
1379 
1380 /*
1381  * ----------------------------------------------------------------------------
1382  *	selStretchEraseFunc --
1383  *
1384  * 	Called by DBSrPaintArea during stretching for each tile in the
1385  *	new selection.  Erase the area that the tile swept out as it
1386  *	moved.
1387  *
1388  * Results:
1389  *	Always returns 0 to keep the search alive.
1390  *
1391  * Side effects:
1392  *	The edit cell is modified.
1393  * ----------------------------------------------------------------------------
1394  */
1395 
1396 int
selStretchEraseFunc(tile,plane)1397 selStretchEraseFunc(tile, plane)
1398     Tile *tile;			/* Tile being moved in a stretch operation. */
1399     int *plane;			/* Plane of tiles being searched */
1400 {
1401     Rect area, editArea;
1402     int planeNum;
1403     planeAndArea pa;
1404     TileType type, t;
1405     TileTypeBitMask tmpmask, mask, *residueMask;
1406     PaintUndoInfo ui;
1407     PaintResultType selStretchEraseTbl[NT];
1408     extern int selStretchEraseFunc2();
1409 
1410     if (IsSplit(tile))
1411 	type = (SplitSide(tile)) ? SplitRightType(tile) :
1412 			SplitLeftType(tile);
1413     else
1414 	type = TiGetType(tile);
1415 
1416     TiToRect(tile, &area);
1417 
1418     /* Compute the area that this tile swept out (the current area is
1419      * its location AFTER moving), and erase everything that was in
1420      * its path.
1421      */
1422 
1423     if (selStretchX > 0)
1424 	area.r_xbot -= selStretchX;
1425     else area.r_xtop -= selStretchX;
1426     if (selStretchY > 0)
1427 	area.r_ybot -= selStretchY;
1428     else area.r_ytop -= selStretchY;
1429 
1430     /* Translate into edit coords and erase all material on the
1431      * tile's plane.
1432      */
1433 
1434     GeoTransRect(&RootToEditTransform, &area, &editArea);
1435 
1436     /* We need to erase all types that interact with "type", *not* all	*/
1437     /* types on "plane", due to the way stacked contacts are handled.	*/
1438     /* Contacts on different planes may stretch across one another	*/
1439     /* without effect, if the types are stackable.  Likewise, layer	*/
1440     /* types may stretch across contacts for which they are a residue.	*/
1441 
1442     planeNum = *plane;
1443     mask = DBPlaneTypes[planeNum];
1444     if (DBIsContact(type))
1445     {
1446 	for (t = DBNumUserLayers; t < DBNumTypes; t++)
1447 	{
1448 	    if (t == type) continue;
1449 
1450 	    /* Exclude all contact types for which this type should "pass through" */
1451 
1452 	    if (TTMaskHasType(&mask, t))
1453 	    {
1454 		tmpmask = *DBResidueMask(t);
1455 		if (TTMaskHasType(&tmpmask, type))
1456 		{
1457 		    TTMaskClearType(&tmpmask, type);
1458 		    TTMaskClearMask(&mask, &tmpmask);
1459 		}
1460 	    }
1461 	}
1462     }
1463 
1464     /* For stacked type tiles do not erase common residue
1465      * type of both contacts from layout.
1466      */
1467 
1468     if (type >= DBNumUserLayers)
1469     {
1470         t = (DBPlaneToResidue(type, planeNum));
1471         TTMaskClearType(&mask, t);
1472     }
1473 
1474     TTMaskAndMask(&mask, &DBActiveLayerBits);
1475 
1476     /* Erase all tile types specified in the processed mask.
1477      * Erase contacts in mask first using DBErase.  This prevents
1478      * contacts from leaving partial images of themselves on other
1479      * planes.  Then, remove the non-contact layers on this plane
1480      * only, such that contacts are not disturbed.
1481      */
1482 
1483     TTMaskZero(&tmpmask);
1484 
1485     selStretchEraseTbl[TT_SPACE] = (PaintResultType)TT_SPACE;
1486     for (t = TT_SPACE + 1; t < DBNumUserLayers; t++)
1487     {
1488 	selStretchEraseTbl[t] = (PaintResultType)t;
1489 	if (TTMaskHasType(&mask, t))
1490 	{
1491 	    if (DBIsContact(t))
1492 	    {
1493 		if (t == type)
1494 		    DBErase(EditCellUse->cu_def, &editArea, t);
1495 		else
1496 		    TTMaskSetType(&tmpmask, t);
1497 	    }
1498 	    else
1499 		selStretchEraseTbl[t] = (PaintResultType)TT_SPACE;
1500 	}
1501     }
1502     for (; t < DBNumTypes; t++)
1503 	selStretchEraseTbl[t] = (PaintResultType)t;
1504 
1505     /* Remove conflicting contact types, where they exist */
1506 
1507     pa.pa_area = &editArea;
1508     pa.pa_plane = planeNum;
1509     pa.pa_mask = &tmpmask;
1510     DBSrPaintArea((Tile *)NULL, EditCellUse->cu_def->cd_planes[planeNum],
1511 		&editArea, &tmpmask, selStretchEraseFunc2, (ClientData)&pa);
1512 
1513     ui.pu_pNum = planeNum;
1514     ui.pu_def = EditCellUse->cu_def;
1515     DBPaintPlane(EditCellUse->cu_def->cd_planes[planeNum], &editArea,
1516 		selStretchEraseTbl, &ui);
1517 
1518     return 0;
1519 }
1520 
1521 int
selStretchEraseFunc2(tile,pa)1522 selStretchEraseFunc2(tile, pa)
1523     Tile *tile;
1524     planeAndArea *pa;
1525 {
1526     if (IsSplit(tile))
1527     {
1528 	if (TTMaskHasType(pa->pa_mask, TiGetLeftType(tile)))
1529 	    DBErase(EditCellUse->cu_def, pa->pa_area,
1530 			DBPlaneToResidue(TiGetLeftType(tile), pa->pa_plane));
1531 	if (TTMaskHasType(pa->pa_mask, TiGetRightType(tile)))
1532 	    DBErase(EditCellUse->cu_def, pa->pa_area,
1533 			DBPlaneToResidue(TiGetRightType(tile), pa->pa_plane));
1534     }
1535     else
1536 	DBErase(EditCellUse->cu_def, pa->pa_area,
1537 		DBPlaneToResidue(TiGetType(tile), pa->pa_plane));
1538     return 0;
1539 }
1540 
1541 /*
1542  * ----------------------------------------------------------------------------
1543  *	selStretchFillFunc --
1544  *
1545  * 	This function is invoked during stretching for each paint tile in
1546  *	the (new) selection.  It finds places in where the back-side of this
1547  *	tile borders space in the (new) selection, then looks for paint in
1548  *	the edit cell that borders the old location of the paint.  If the
1549  *	selection has been moved away from paint in the edit cell, additional
1550  *	material is filled in behind the selection.
1551  *
1552  * Results:
1553  *	Always returns 0 to keep the search alive.
1554  *
1555  * Side effects:
1556  *	Modifies the edit cell by painting material.
1557  * ----------------------------------------------------------------------------
1558  */
1559 
1560 int
selStretchFillFunc(tile,plane)1561 selStretchFillFunc(tile, plane)
1562     Tile *tile;			/* Tile in the old selection. */
1563     int *plane;			/* Plane of tile being searched */
1564 {
1565     Rect area;
1566     extern int selStretchFillFunc2();
1567 
1568     TiToRect(tile, &area);
1569 
1570     /* Check the material just behind this paint (in the sense of the
1571      * stretch direction) for space in the selection and non-space in
1572      * the edit cell.
1573      */
1574 
1575     if (selStretchX > 0)
1576     {
1577 	area.r_xtop = area.r_xbot;
1578 	area.r_xbot -= 1;
1579     }
1580     else if (selStretchX < 0)
1581     {
1582 	area.r_xbot = area.r_xtop;
1583 	area.r_xtop += 1;
1584     }
1585     else if (selStretchY > 0)
1586     {
1587 	area.r_ytop = area.r_ybot;
1588 	area.r_ybot -= 1;
1589     }
1590     else
1591     {
1592 	area.r_ybot = area.r_ytop;
1593 	area.r_ytop += 1;
1594     }
1595 
1596     if (IsSplit(tile))
1597     {
1598 	if (selStretchX > 0)
1599 	    selStretchType = SplitLeftType(tile);
1600 	else if (selStretchX < 0)
1601 	    selStretchType = SplitRightType(tile);
1602 	else if (selStretchY > 0)
1603 	    selStretchType = (SplitDirection(tile) ? SplitLeftType(tile) :
1604 			SplitRightType(tile));
1605 	else if (selStretchY < 0)
1606 	    selStretchType = (SplitDirection(tile) ? SplitRightType(tile) :
1607 			SplitLeftType(tile));
1608 	if (selStretchType == TT_SPACE) return 0;
1609     }
1610     else
1611 	selStretchType = TiGetType(tile);
1612 
1613     /* The search functions invoked indirectly by the following procedure
1614      * call build up a list of areas to paint.
1615      */
1616 
1617     (void) DBSrPaintArea((Tile *) NULL,
1618 	    Select2Def->cd_planes[*plane], &area,
1619 	    &DBSpaceBits, selStretchFillFunc2, (ClientData) &area);
1620 
1621     return 0;
1622 }
1623 
1624 /* Second-level filling search function:  find all of the edit material
1625  * that intersects areas where space borders a selected paint tile.
1626  */
1627 
1628 int
selStretchFillFunc2(tile,area)1629 selStretchFillFunc2(tile, area)
1630     Tile *tile;				/* Space tile that borders selected
1631 					 * paint.
1632 					 */
1633     Rect *area;				/* A one-unit wide strip along the
1634 					 * border (i.e. the area in which
1635 					 * we're interested in space).
1636 					 */
1637 {
1638     Rect spaceArea, editArea;
1639     int pNum;
1640 
1641     extern int selStretchFillFunc3();
1642 
1643     TiToRect(tile, &spaceArea);
1644 
1645     /* Find out which portion of this space tile borders the selected
1646      * tile, transform it back to coords of the old selection and then
1647      * to edit coords, and find all the edit material that borders the
1648      * selected tile in this area.
1649      */
1650 
1651     GeoClip(&spaceArea, area);
1652     spaceArea.r_xbot -= selStretchX;
1653     spaceArea.r_xtop -= selStretchX;
1654     spaceArea.r_ybot -= selStretchY;
1655     spaceArea.r_ytop -= selStretchY;
1656     GeoTransRect(&RootToEditTransform, &spaceArea, &editArea);
1657 
1658     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
1659     {
1660 	if (DBTypeOnPlane(selStretchType, pNum))
1661 	    (void) DBSrPaintArea((Tile *) NULL,
1662 			EditCellUse->cu_def->cd_planes[pNum],
1663 			&editArea, &DBActiveLayerBits, selStretchFillFunc3,
1664 			(ClientData) &spaceArea);
1665     }
1666     return 0;
1667 }
1668 
1669 /* OK, now we've found a piece of material in the edit cell that is
1670  * right next to a piece of selected material that's about to move
1671  * away from it.  Stretch one or the other to fill the gap.  Use the
1672  * material that's moving as the stretch material unless it's a fixed-size
1673  * material and the other stuff is stretchable.
1674  */
1675 
1676 int
selStretchFillFunc3(tile,area)1677 selStretchFillFunc3(tile, area)
1678     Tile *tile;			/* Tile of edit material that's about to
1679 				 * be left behind selection.
1680 				 */
1681     Rect *area;			/* The border area we're interested in,
1682 				 * in root coords.
1683 				 */
1684 {
1685     Rect editArea, rootArea;
1686     TileType type, stype;
1687     TileTypeBitMask *mask, *sMask, *tMask;
1688     StretchArea *sa;
1689 
1690     /* Compute the area to be painted. */
1691 
1692     TiToRect(tile, &editArea);
1693     GeoTransRect(&EditToRootTransform, &editArea, &rootArea);
1694     GeoClip(&rootArea, area);
1695     if (selStretchX > 0)
1696     {
1697 	rootArea.r_xbot = rootArea.r_xtop;
1698 	rootArea.r_xtop += selStretchX;
1699     }
1700     else if (selStretchX < 0)
1701     {
1702 	rootArea.r_xtop = rootArea.r_xbot;
1703 	rootArea.r_xbot += selStretchX;
1704     }
1705     else if (selStretchY > 0)
1706     {
1707 	rootArea.r_ybot = rootArea.r_ytop;
1708 	rootArea.r_ytop += selStretchY;
1709     }
1710     else
1711     {
1712 	rootArea.r_ytop = rootArea.r_ybot;
1713 	rootArea.r_ybot += selStretchY;
1714     }
1715     GeoTransRect(&RootToEditTransform, &rootArea, &editArea);
1716 
1717     /* Compute the material to be painted.  Be careful:  for contacts,
1718      * must use the master image.
1719      */
1720 
1721     if (IsSplit(tile))
1722     {
1723 	if (selStretchX > 0)
1724 	    type = SplitRightType(tile);
1725 	else if (selStretchX < 0)
1726 	    type = SplitLeftType(tile);
1727 	else if (selStretchY > 0)
1728 	    type = (SplitDirection(tile) ? SplitRightType(tile) :
1729 			SplitLeftType(tile));
1730 	else if (selStretchY < 0)
1731 	    type = (SplitDirection(tile) ? SplitLeftType(tile) :
1732 			SplitRightType(tile));
1733 	if (type == TT_SPACE) return 0;   /* nothing to stretch */
1734     }
1735     else
1736 	type = TiGetType(tile);
1737     sMask = DBResidueMask(selStretchType);
1738 
1739     /* If have type and stretch type are both contacts (fixed types)	*/
1740     /* and there exists a stacking contact type between them, then	*/
1741     /* we should be filling in the original type.			*/
1742 
1743     if (!DBIsContact(type) || !DBIsContact(selStretchType) ||
1744 		(((stype = DBTechFindStacking(type, selStretchType))
1745 		< DBNumUserLayers) && (stype >= TT_TECHDEPBASE)))
1746     {
1747 	/* If type is a residue of selStretchType then we always 	*/
1748 	/* fill with type.  Otherwise, we check the list of plow	*/
1749 	/* types to see what is and isn't fixed.			*/
1750 
1751 	if (!TTMaskHasType(sMask, type))
1752 	    if (TTMaskHasType(&PlowFixedTypes, type)
1753 			|| !TTMaskHasType(&PlowFixedTypes, selStretchType))
1754 		type = selStretchType;
1755     }
1756 
1757     /* Otherwise, if we have two fixed types, and they both border the	*/
1758     /* selection area (as opposed to overlapping), and they share a	*/
1759     /* residue, then the type to paint is the shared residue type.	*/
1760     /* We must ignore the case type == selStretchType (fixed by Nishit,	*/
1761     /* 6/29/04.								*/
1762 
1763     else if (DBIsContact(type) && DBIsContact(selStretchType)
1764 		&& (type != selStretchType))
1765     {
1766 	if (((selStretchX < 0) && (editArea.r_xtop == area->r_xbot)) ||
1767 	    ((selStretchX > 0) && (editArea.r_xbot == area->r_xtop)) ||
1768 	    ((selStretchY < 0) && (editArea.r_ytop == area->r_ybot)) ||
1769 	    ((selStretchY > 0) && (editArea.r_ybot == area->r_ytop)))
1770 	{
1771 	    TileTypeBitMask rmask;
1772 	    tMask = DBResidueMask(type);
1773 	    TTMaskAndMask3(&rmask, tMask, sMask);
1774 	    for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
1775 		if (TTMaskHasType(&rmask, type))
1776 		    break;
1777 
1778 	    if (type == DBNumUserLayers)
1779 		return 0;	/* Types do not share any residues */
1780 	}
1781     }
1782 
1783     /* Save around the area we just found. */
1784 
1785     sa = (StretchArea *) mallocMagic(sizeof(StretchArea));
1786     sa->sa_area = editArea;
1787     sa->sa_type = type;
1788     sa->sa_next = selStretchList;
1789     selStretchList = sa;
1790 
1791     return 0;
1792 }
1793 
1794 /*
1795  * ----------------------------------------------------------------------------
1796  *
1797  * SelectDump --
1798  *
1799  *      Copies an area of one cell into the edit cell, selecting the
1800  *	copy so that it can be manipulated later.
1801  *
1802  * Results:
1803  *      None.
1804  *
1805  * Side effects:
1806  *      The edit cell is modified.
1807  *
1808  * ----------------------------------------------------------------------------
1809  */
1810 
1811 void
SelectDump(scx)1812 SelectDump(scx)
1813     SearchContext *scx;			/* Describes the cell from which
1814 					 * material is to be copied, the
1815 					 * area to copy, and the transform
1816 					 * to root coordinates in the edit
1817 					 * cell's window.
1818 					 */
1819 {
1820     /* Copy from the source cell to Select2Def while transforming,
1821      * then let SelectandCopy2 do the rest of the work.  Don't
1822      * record any of the Select2Def changes for undo-ing.
1823      */
1824 
1825     UndoDisable();
1826     DBCellClearDef(Select2Def);
1827     (void) DBCellCopyAllPaint(scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_SPECIAL,
1828 		Select2Use);
1829     (void) DBCellCopyAllLabels(scx, &DBAllTypeBits, CU_DESCEND_SPECIAL, Select2Use,
1830 		(Rect *) NULL);
1831     (void) DBCellCopyAllCells(scx, CU_DESCEND_SPECIAL, Select2Use, (Rect *) NULL);
1832     DBReComputeBbox(Select2Def);
1833     UndoEnable();
1834 
1835     SelectClear();
1836     SelectAndCopy2(EditRootDef);
1837 }
1838