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, ¤t, 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, ¤t, -1, astr);
1257 DBPutFontLabel(Select2Def, ¤t, 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