1 /* selCreate.c -
2 *
3 * This file provides routines to make selections by copying
4 * things into a special cell named "__SELECT__".
5 *
6 * *********************************************************************
7 * * Copyright (C) 1985, 1990 Regents of the University of California. *
8 * * Permission to use, copy, modify, and distribute this *
9 * * software and its documentation for any purpose and without *
10 * * fee is hereby granted, provided that the above copyright *
11 * * notice appear in all copies. The University of California *
12 * * makes no representations about the suitability of this *
13 * * software for any purpose. It is provided "as is" without *
14 * * express or implied warranty. Export of this software outside *
15 * * of the United States of America may require an export license. *
16 * *********************************************************************
17 */
18
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/select/selCreate.c,v 1.10 2010/06/24 12:37:56 tim Exp $";
21 #endif /* not lint */
22
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "utils/magic.h"
27 #include "utils/malloc.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/undo.h"
35 #include "commands/commands.h"
36 #include "select/selInt.h"
37 #include "select/select.h"
38 #include "drc/drc.h"
39 #include "utils/main.h"
40 #include "utils/signals.h"
41
42 /* Two cells worth of information are kept around by the selection
43 * module. SelectDef and SelectUse are for the cells whose contents
44 * are the current selection. Select2Def and Select2Use provide a
45 * temporary working space for procedures that manipulate the selection.
46 * for example, Select2Def is used to hold nets or regions while they
47 * are being extracted by SelectRegion or SelectNet. Once completely
48 * extracted, information is copied to SelectDef. Changes to
49 * SelectDef are undo-able and redo-able (so that the undo package
50 * can deal with selection changes), but changes to Select2Def are
51 * not undo-able (undoing is always disabled when the cell is modified).
52 */
53
54 global CellDef *SelectDef, *Select2Def;
55 global CellUse *SelectUse, *Select2Use;
56
57 /* The CellDef below points to the definition FROM which the selection
58 * is extracted. This is the root definition of a window. Everything
59 * in the selection must have come from the same place, so we clear the
60 * selection whenever the user tries to select from a new hierarchy.
61 */
62
63 CellDef *SelectRootDef = NULL;
64
65 /* The CellUse below is the last use selected by SelectUse. It is
66 * kept around to support the "replace" feature of SelectUse.
67 *
68 * Procedures which deselect a cell must reset this to null if they
69 * happen to deselect this usage. (Danger Will Robinson)
70 */
71
72 global CellUse *selectLastUse = NULL;
73
74
75 /*
76 * ----------------------------------------------------------------------------
77 *
78 * SelectInit --
79 *
80 * This procedure initializes the selection code by creating
81 * the selection cells.
82 *
83 * Results:
84 * None.
85 *
86 * Side effects:
87 * The select cells are created if they don't already exist.
88 * Selection undo-ing is also initialized.
89 *
90 * ----------------------------------------------------------------------------
91 */
92
93 void
SelectInit()94 SelectInit()
95 {
96 static bool initialized = FALSE;
97
98 if (initialized) return;
99 else initialized = TRUE;
100
101 /* Create the working cells used internally to this module to
102 * hold selected information. Don't allow any of this to be
103 * undone, or else it could invalidate all the pointers we
104 * keep around to the cells.
105 */
106
107 UndoDisable();
108 SelectDef = DBCellLookDef("__SELECT__");
109 if (SelectDef == (CellDef *) NULL)
110 {
111 SelectDef = DBCellNewDef("__SELECT__");
112 ASSERT(SelectDef != (CellDef *) NULL, "SelectInit");
113 DBCellSetAvail(SelectDef);
114 SelectDef->cd_flags |= CDINTERNAL;
115 TTMaskZero(&SelectDef->cd_types);
116 }
117 SelectUse = DBCellNewUse(SelectDef, (char *) NULL);
118 DBSetTrans(SelectUse, &GeoIdentityTransform);
119 SelectUse->cu_expandMask = CU_DESCEND_SPECIAL; /* This is always expanded. */
120 SelectUse->cu_flags = 0; /* never locked down */
121
122 Select2Def = DBCellLookDef("__SELECT2__");
123 if (Select2Def == (CellDef *) NULL)
124 {
125 Select2Def = DBCellNewDef("__SELECT2__");
126 ASSERT(Select2Def != (CellDef *) NULL, "SelectInit");
127 DBCellSetAvail(Select2Def);
128 Select2Def->cd_flags |= CDINTERNAL;
129 }
130 Select2Use = DBCellNewUse(Select2Def, (char *) NULL);
131 DBSetTrans(Select2Use, &GeoIdentityTransform);
132 Select2Use->cu_expandMask = CU_DESCEND_SPECIAL; /* This is always expanded. */
133 Select2Use->cu_flags = 0; /* never locked down */
134 UndoEnable();
135
136 SelUndoInit();
137 }
138
139 /*
140 * ----------------------------------------------------------------------------
141 *
142 * SelectClear --
143 *
144 * This procedure clears the current selection.
145 *
146 * Results:
147 * None.
148 *
149 * Side effects:
150 * All information is removed from the select cell, and selection
151 * information is also taken off the screen.
152 *
153 * ----------------------------------------------------------------------------
154 */
155
156 /* The variables below are used to record information about subcells that
157 * must be cleared from the select cell.
158 */
159
160 #define MAXUSES 30
161 static CellUse *(selDeleteUses[MAXUSES]);
162 static int selNDelete;
163
164 void
SelectClear()165 SelectClear()
166 {
167 SearchContext scx;
168 Rect r, expand;
169 extern int selClearFunc(); /* Forward declaration. */
170
171 if (SelectRootDef == NULL) return;
172
173 scx.scx_area = SelectDef->cd_bbox;
174 expand = scx.scx_area;
175
176 /* Special handling when the cell is flagged as a net selection */
177
178 if (SelectUse->cu_flags & CU_SELECT_NET)
179 {
180 SelNetRememberForUndo((CellDef *)NULL, (Point *)NULL,
181 TT_SPACE, FALSE, FALSE);
182 SelectUse->cu_flags = 0;
183 DBCellClearDef(SelectDef);
184 }
185 else
186 {
187 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
188 SelectUse->cu_flags = 0;
189
190 /* Erase all the paint from the select cell. */
191 DBEraseMask(SelectDef, &TiPlaneRect, &DBAllButSpaceBits);
192
193 /* For the line below to work, paint tables need to be set up correctly! */
194 /* DBErase(SelectDef, &TiPlaneRect, TT_SPACE); */
195
196 /* Erase all of the labels from the select cell. */
197
198 (void) DBEraseLabel(SelectDef, &TiPlaneRect, &DBAllTypeBits, &expand);
199
200 /* Erase all of the subcells from the select cell. This is a bit tricky,
201 * because we can't erase the subcells while searching for them (it will
202 * cause problems for the database). The code below first grabs up a
203 * few subcells, then deletes them, then grabs up a few more, then deletes
204 * them, and so on until done.
205 */
206
207 scx.scx_use = SelectUse;
208 scx.scx_trans = GeoIdentityTransform;
209 while (TRUE)
210 {
211 int i;
212
213 selNDelete = 0;
214 (void) DBCellSrArea(&scx, selClearFunc, (ClientData) NULL);
215 for (i = 0; i < selNDelete; i += 1)
216 {
217 DBUnLinkCell(selDeleteUses[i], SelectDef);
218 DBDeleteCell(selDeleteUses[i]);
219 (void) DBCellDeleteUse(selDeleteUses[i]);
220 }
221 if (selNDelete < MAXUSES) break;
222 }
223 selectLastUse = NULL;
224
225 SelRememberForUndo(FALSE, SelectRootDef, &scx.scx_area);
226 }
227
228 TTMaskZero(&SelectDef->cd_types);
229
230 /* Reset the transform, if we have been moving the selection around */
231 GeoTransRect(&SelectUse->cu_transform, &expand, &r);
232 SelectUse->cu_transform = GeoIdentityTransform;
233
234 /* Erase the selection from the screen. */
235 DBWHLRedraw(SelectRootDef, &r, TRUE);
236
237 DBReComputeBbox(SelectDef);
238 DBWAreaChanged(SelectDef, &expand, DBW_ALLWINDOWS,
239 (TileTypeBitMask *) NULL);
240 }
241
242 /* Search function to help clear subcells from the selection. It just
243 * records information about several subcells (up to MAXUSES).
244 */
245
246 int
selClearFunc(scx)247 selClearFunc(scx)
248 SearchContext *scx; /* Describes a cell that was found. */
249 {
250 selDeleteUses[selNDelete] = scx->scx_use;
251 selNDelete += 1;
252 if (selNDelete == MAXUSES) return 1;
253 else return 2;
254 }
255
256 /*
257 * ----------------------------------------------------------------------------
258 *
259 * selIntersectPaintFunc2 ---
260 *
261 * ----------------------------------------------------------------------------
262 */
263
264 int
selIntersectPaintFunc2(tile,rect)265 selIntersectPaintFunc2(tile, rect)
266 Tile *tile; /* The tile to copy paint from. */
267 Rect *rect; /* Area to clip to */
268 {
269 Rect r;
270
271 TiToRect(tile, &r);
272 GEOCLIP(&r, rect); /* Clip out the intersection area */
273 DBPaint(SelectDef, &r, TiGetTypeExact(tile)); /* Paint back into SelectDef */
274 return 0; /* Keep the search going. */
275 }
276
277 /*
278 * ----------------------------------------------------------------------------
279 *
280 * selIntersectPaintFunc --
281 *
282 * Erase paint of types in rMask from the area of the tile.
283 *
284 * ----------------------------------------------------------------------------
285 */
286
287 int
selIntersectPaintFunc(tile)288 selIntersectPaintFunc(tile)
289 Tile *tile; /* The tile to copy paint from. */
290 {
291 TileTypeBitMask tMask;
292 Rect r;
293 int pNum;
294
295 TiToRect(tile, &r);
296
297 for (pNum = 0; pNum < DBNumPlanes; pNum++)
298 {
299 DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r,
300 &DBAllButSpaceAndDRCBits, selIntersectPaintFunc2,
301 (ClientData)&r);
302 }
303 return 0; /* Keep the search going. */
304 }
305
306 /*
307 * ----------------------------------------------------------------------------
308 *
309 * SelectIntersect --
310 *
311 * This procedure selects all information that falls in a given area
312 * and contains the intersection of all the supplied types.
313 *
314 * Results:
315 * None.
316 *
317 * Side effects:
318 * The indicated information is added to the select cell, and
319 * outlined on the screen. Only information of particular
320 * types, and in expanded cells (according to xMask) is
321 * selected.
322 *
323 * ----------------------------------------------------------------------------
324 */
325
326 void
SelectIntersect(scx,type,xMask,negate)327 SelectIntersect(scx, type, xMask, negate)
328 SearchContext *scx; /* Describes the area in which material
329 * is to be selected. The resulting
330 * coordinates should map to the coordinates
331 * of EditRootDef. The cell use should be
332 * the root of a window.
333 */
334 TileType type; /* Indicates which layer to intersect with
335 * the current selection.
336 */
337 int xMask; /* Indicates window (or windows) where cells
338 * must be expanded for their contents to be
339 * considered. 0 means treat everything as
340 * expanded.
341 */
342 bool negate; /* If true, search on NOT(type) */
343 {
344 TileTypeBitMask tMask, rMask;
345 TileType s, t;
346 int plane;
347 SearchContext scx2;
348
349 /* The source definition may not change */
350 if (SelectRootDef != scx->scx_use->cu_def) return;
351
352 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
353
354 /* Copy SelectDef contents (paint only) into Select2Def */
355 DBCellClearDef(Select2Def);
356 scx2.scx_use = SelectUse;
357 scx2.scx_area = SelectUse->cu_bbox;
358 GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx2.scx_trans);
359 DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK,
360 Select2Use);
361
362 /* Clear the original selection */
363 DBCellClearDef(SelectDef);
364
365 /* Select all paint of type "type" and copy into SelectDef */
366 TTMaskSetOnlyType(&tMask, type);
367
368 plane = DBPlane(type);
369 (void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse);
370
371 /* Scan Select2Def for all geometry inside the area of "type", and */
372 /* copy back to SelectDef as "type" */
373
374 if (negate)
375 {
376 TTMaskCom(&tMask);
377 TTMaskAndMask(&tMask, &DBPlaneTypes[plane]);
378 }
379 DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane],
380 &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL);
381
382 if (negate) TTMaskSetOnlyType(&tMask, type); /* Restore original mask */
383
384 DBEraseMask(SelectDef, &TiPlaneRect, &tMask);
385
386 /* Display the new selection. */
387
388 SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area);
389 DBReComputeBbox(SelectDef);
390 DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE);
391 DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
392 &DBAllButSpaceBits);
393 }
394
395 /*
396 * ----------------------------------------------------------------------------
397 *
398 * SelectArea --
399 *
400 * This procedure selects all information of given types that
401 * falls in a given area.
402 *
403 * Results:
404 * None.
405 *
406 * Side effects:
407 * The indicated information is added to the select cell, and
408 * outlined on the screen. Only information of particular
409 * types, and in expanded cells (according to xMask) is
410 * selected.
411 *
412 * ----------------------------------------------------------------------------
413 */
414
415 void
SelectArea(scx,types,xMask,globmatch)416 SelectArea(scx, types, xMask, globmatch)
417 SearchContext *scx; /* Describes the area in which material
418 * is to be selected. The resulting
419 * coordinates should map to the coordinates
420 * of EditRootDef. The cell use should be
421 * the root of a window.
422 */
423 TileTypeBitMask *types; /* Indicates which layers to select. Can
424 * include L_CELL and L_LABELS to select
425 * labels and unexpanded subcells. If L_LABELS
426 * is specified then all labels touching the
427 * area are selected. If L_LABELS isn't
428 * specified, then only labels attached to
429 * selected material are selected.
430 */
431 int xMask; /* Indicates window (or windows) where cells
432 * must be expanded for their contents to be
433 * considered. 0 means treat everything as
434 * expanded.
435 */
436 char *globmatch; /* If non-NULL, and if L_LABELS is among the
437 * selection types, then do glob-style matching
438 * of any labels against this string.
439 */
440 {
441 Rect labelArea, cellArea;
442
443 /* If the source definition is changing, clear the old selection. */
444
445 if (SelectRootDef != scx->scx_use->cu_def)
446 {
447 if (SelectRootDef != NULL)
448 SelectClear();
449 SelectRootDef = scx->scx_use->cu_def;
450 SelSetDisplay(SelectUse, SelectRootDef);
451 }
452
453 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
454
455 /* Select paint. */
456
457 (void) DBCellCopyAllPaint(scx, types, xMask, SelectUse);
458
459 SelectDef->cd_types = *types; /* Remember what types were requested */
460
461 /* Select labels. */
462
463 if (TTMaskHasType(types, L_LABEL))
464 {
465 if (globmatch != NULL)
466 DBCellCopyGlobLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea,
467 globmatch);
468 else
469 DBCellCopyAllLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea);
470 }
471 else (void) DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
472
473 /* Select unexpanded cell uses. */
474
475 if (TTMaskHasType(types, L_CELL))
476 (void) DBCellCopyAllCells(scx, xMask, SelectUse, &cellArea);
477 else
478 {
479 cellArea.r_xbot = 0;
480 cellArea.r_xtop = -1;
481 }
482
483 /* Display the new selection. */
484
485 (void) GeoIncludeAll(&scx->scx_area, &labelArea);
486 (void) GeoIncludeAll(&cellArea, &labelArea);
487 SelRememberForUndo(FALSE, SelectRootDef, &labelArea);
488 DBReComputeBbox(SelectDef);
489 DBWHLRedraw(SelectRootDef, &labelArea, TRUE);
490 DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
491 &DBAllButSpaceBits);
492 }
493
494
495 /*
496 * ----------------------------------------------------------------------------
497 *
498 * selFindChunk --
499 *
500 * This is a recursive procedure to find the largest chunk of
501 * material in a particular area. It locates a rectangular
502 * area of given materials whose minimum dimension is as
503 * large as possible, and whose maximum dimension is also as
504 * large as possible (but minimum dimension is more important).
505 * Furthermore, the chunk must lie within a particular area and
506 * must contain a given area.
507 *
508 * Results:
509 * None.
510 *
511 * Side effects:
512 * None.
513 *
514 * ----------------------------------------------------------------------------
515 */
516
517 #define MAX_RECURSION_LEVEL 22
518
519 void
selFindChunk(plane,wrongTypes,searchArea,containedArea,bestMin,bestMax,bestChunk,level)520 selFindChunk(plane, wrongTypes, searchArea, containedArea, bestMin,
521 bestMax, bestChunk, level)
522 Plane *plane; /* Plane on which to hunt for chunk. */
523 TileTypeBitMask *wrongTypes; /* Types that are not allowed to be
524 * part of the chunk.
525 */
526 Rect *searchArea; /* Largest allowable size for the
527 * chunk. Note: don't overestimate
528 * this or the procedure will take a
529 * long time! (it processes every
530 * tile in this area).
531 */
532 Rect *containedArea; /* The chunk returned must contain
533 * this entire area.
534 */
535 int *bestMin; /* Largest minimum dimension seen so
536 * far: skip any chunks that can't
537 * match this. Updated by this
538 * procedure.
539 */
540 int *bestMax; /* Largest maximum dimension seen
541 * so far.
542 */
543 Rect *bestChunk; /* Filled in with largest chunk seen
544 * so far, if we find one better than
545 * bestMin and bestMax.
546 */
547 int level; /* Recursion level (to avoid worst-
548 * case scenarios)
549 */
550 {
551 Rect smaller;
552 int min, max;
553 extern int selChunkFunc();
554 Rect wrong;
555
556 if (level == MAX_RECURSION_LEVEL) return;
557
558 /* If the search area is already smaller than the chunk to beat,
559 * there's no point in even examining this chunk.
560 */
561
562 min = searchArea->r_xtop - searchArea->r_xbot;
563 max = searchArea->r_ytop - searchArea->r_ybot;
564 if (min > max)
565 {
566 int tmp;
567 tmp = min; min = max; max = tmp;
568 }
569
570 if (min < *bestMin) return;
571 if ((min == *bestMin) && (max <= *bestMax)) return;
572
573 /* At each stage, search the area that's left for material of the
574 * wrong type.
575 */
576
577 if (DBSrPaintArea((Tile *) NULL, plane, searchArea, wrongTypes,
578 selChunkFunc, (ClientData) &wrong) == 0)
579 {
580 /* The area contains nothing but material of the right type,
581 * so it is now the "chunk to beat".
582 */
583
584 *bestMin = min;
585 *bestMax = max;
586 *bestChunk = *searchArea;
587 return;
588 }
589
590 if (SigInterruptPending)
591 return;
592
593 /* At this point the current search area contains some material of
594 * the wrong type. We have to reduce the search area to exclude this
595 * material. There are two ways that this can be done while still
596 * producing areas that contain containedArea. Try both of those,
597 * and repeat the whole thing recursively on the smaller areas.
598 */
599
600 /* First, try reducing the x-range. */
601
602 smaller = *searchArea;
603 if (wrong.r_xbot >= containedArea->r_xtop)
604 smaller.r_xtop = wrong.r_xbot;
605 else if (wrong.r_xtop <= containedArea->r_xbot)
606 smaller.r_xbot = wrong.r_xtop;
607 else goto tryY; /* Bad material overlaps containedArea in x. */
608 selFindChunk(plane, wrongTypes, &smaller, containedArea,
609 bestMin, bestMax, bestChunk, level + 1);
610
611
612 /* Also try reducing the y-range to see if that works better. */
613
614 tryY: smaller = *searchArea;
615 if (wrong.r_ybot >= containedArea->r_ytop)
616 smaller.r_ytop = wrong.r_ybot;
617 else if (wrong.r_ytop <= containedArea->r_ybot)
618 smaller.r_ybot = wrong.r_ytop;
619 else return; /* Bad material overlaps containedArea in y. */
620 selFindChunk(plane, wrongTypes, &smaller, containedArea,
621 bestMin, bestMax, bestChunk, level + 1);
622 }
623
624 /* Search function to find split tiles in the area of interest.
625 */
626
627 int
selSplitFunc(tile,cxp)628 selSplitFunc(tile, cxp)
629 Tile *tile;
630 TreeContext *cxp;
631 {
632 SearchContext *scx = cxp->tc_scx;
633 Rect *area = (Rect *) cxp->tc_filter->tf_arg;
634 Rect locarea;
635
636 if (IsSplit(tile))
637 {
638 TiToRect(tile, &locarea);
639 GeoTransRect(&scx->scx_trans, &locarea, area);
640 return 1;
641 }
642 return 0;
643 }
644
645 /* This procedure is called for each tile of the wrong type in an
646 * area that is supposed to contain only tiles of other types. It
647 * just returns the area of the wrong material and aborts the search.
648 */
649
650 int
selChunkFunc(tile,wrong)651 selChunkFunc(tile, wrong)
652 Tile *tile; /* The offending tile. */
653 Rect *wrong; /* Place to store the tile's area. */
654 {
655 TiToRect(tile, wrong);
656 return 1; /* Abort the search. */
657 }
658
659
660 /*
661 * ----------------------------------------------------------------------------
662 *
663 * SelectChunk --
664 *
665 * This procedure selects a single rectangular chunk of
666 * homogeneous material.
667 *
668 * Results:
669 * None.
670 *
671 * Side effects:
672 * More material is added to the select cell and displayed
673 * on the screen. This procedure finds the largest rectangular
674 * chunk of material "type" that contains the area given in
675 * in scx. The material need not all be in one cell, but it
676 * must all be in cells that are expanded according to "xMask".
677 * If pArea is given, the rectangle it points to is filled in
678 * with the area of the chunk that was selected.
679 *
680 * ----------------------------------------------------------------------------
681 */
682
683 void
SelectChunk(scx,type,xMask,pArea,less)684 SelectChunk(scx, type, xMask, pArea, less)
685 SearchContext *scx; /* Area to tree-search for material. The
686 * transform must map to root coordinates
687 * of the edit cell.
688 */
689 TileType type; /* The type of material to be considered. */
690 int xMask; /* Indicates window (or windows) where cells
691 * must be expanded for their contents to be
692 * considered. 0 means treat everything as
693 * expanded.
694 */
695 Rect *pArea; /* If non-NULL, gets filled in with the area
696 * of the selection.
697 */
698 bool less;
699 {
700 #define INITIALSIZE 10
701 SearchContext newscx;
702 TileTypeBitMask wrongTypes, typeMask;
703 TileType ttype;
704 Rect bestChunk;
705 int bestMin, bestMax, width, height;
706 extern int selSplitFunc(); /* Forward reference. */
707
708 /* If the source definition is changing, clear the old selection. */
709
710 if (SelectRootDef != scx->scx_use->cu_def)
711 {
712 if (SelectRootDef != NULL)
713 SelectClear();
714 SelectRootDef = scx->scx_use->cu_def;
715 SelSetDisplay(SelectUse, SelectRootDef);
716 }
717
718 /* The chunk is computed iteratively. First extract a small
719 * region (defined by INITIALSIZE) into Select2Def. Then find
720 * the largest chunk in the region. If the chunk touches a
721 * side of the region, then extract a larger region and try
722 * again. Keep making the region larger and larger until we
723 * eventually find a region that completely contains the chunk
724 * with space left over around the edges.
725 */
726
727 UndoDisable();
728 TTMaskSetOnlyType(&typeMask, type);
729
730 /* Stacked types containing "type" need to be added to the mask */
731 if (DBIsContact(type)) DBMaskAddStacking(&typeMask);
732
733 TTMaskCom2(&wrongTypes, &typeMask);
734
735 newscx = *scx;
736
737 /* If the tile under the area of interest is a split tile, */
738 /* then we use that tile as the chunk. This routine should */
739 /* work like the while() loop underneath, looking for the */
740 /* largest split tile, but this is a minor enhancement. */
741 /* *However*, if it is done, the functions */
742 /* DBCellCopyManhattanPaint()/dbCopyManhattanPaint() should */
743 /* be reconsidered. */
744
745 if (DBTreeSrTiles(&newscx, &typeMask, 0, selSplitFunc,
746 (ClientData)&bestChunk) != 0)
747 {
748 goto chunkdone;
749 }
750
751 bestMin = bestMax = 0;
752 bestChunk = GeoNullRect;
753
754 GEO_EXPAND(&newscx.scx_area, INITIALSIZE, &newscx.scx_area);
755 while (TRUE)
756 {
757 /* Extract a bunch of junk. */
758
759 DBCellClearDef(Select2Def);
760 DBCellCopyManhattanPaint(&newscx, &typeMask, xMask, Select2Use);
761
762 /* Now find the best chunk in the area. */
763
764 selFindChunk(Select2Def->cd_planes[DBPlane(type)],
765 &wrongTypes, &newscx.scx_area, &scx->scx_area,
766 &bestMin, &bestMax, &bestChunk, 0);
767 if (GEO_RECTNULL(&bestChunk))
768 {
769 /* No chunk was found, so return. */
770
771 UndoEnable();
772 if (pArea != NULL) *pArea = bestChunk;
773 return;
774 }
775
776 /* If the chunk is completely inside the area we yanked, then we're
777 * done.
778 */
779
780 if (GEO_SURROUND_STRONG(&newscx.scx_area, &bestChunk)) break;
781
782 /* The chunk extends to the edge of the area. Any place that the
783 * chunk touches an edge, move that edge out by a factor of two.
784 * Any place it doesn't touch, move the edge in to be just one
785 * unit out from the chunk.
786 */
787
788 width = newscx.scx_area.r_xtop - newscx.scx_area.r_xbot;
789 height = newscx.scx_area.r_ytop - newscx.scx_area.r_ybot;
790
791 if (bestChunk.r_xbot == newscx.scx_area.r_xbot)
792 newscx.scx_area.r_xbot -= width;
793 else newscx.scx_area.r_xbot = bestChunk.r_xbot - 1;
794 if (bestChunk.r_ybot == newscx.scx_area.r_ybot)
795 newscx.scx_area.r_ybot -= height;
796 else newscx.scx_area.r_ybot= bestChunk.r_ybot - 1;
797 if (bestChunk.r_xtop == newscx.scx_area.r_xtop)
798 newscx.scx_area.r_xtop += width;
799 else newscx.scx_area.r_xtop = bestChunk.r_xtop + 1;
800 if (bestChunk.r_ytop == newscx.scx_area.r_ytop)
801 newscx.scx_area.r_ytop += height;
802 else newscx.scx_area.r_ytop = bestChunk.r_ytop + 1;
803 }
804
805 chunkdone:
806
807 /* Flag the cell as a chunk selection so we can treat */
808 /* the contents differently when doing a move op. */
809
810 SelectUse->cu_flags |= CU_SELECT_CHUNK;
811 UndoEnable();
812
813 if (less)
814 {
815 SelRemoveArea(&bestChunk, &typeMask, NULL);
816 }
817 else
818 {
819 newscx.scx_area = bestChunk;
820
821 /* Remove any stacked contact types for SelectArea */
822 if (DBIsContact(type))
823 TTMaskSetOnlyType(&typeMask, type);
824
825 SelectArea(&newscx, &typeMask, xMask, NULL);
826 }
827
828 if (pArea != NULL) *pArea = bestChunk;
829 }
830
831 /*
832 * ----------------------------------------------------------------------------
833 *
834 * SelectRegion --
835 *
836 * Select an entire region of material, no matter what its
837 * shape.
838 *
839 * Results:
840 * None.
841 *
842 * Side effects:
843 * This procedure traces out the region consisting entirely
844 * of type "type", and selects all that material. The search
845 * starts from "type" material under scx and continues outward
846 * to get all material in all cells connected to the area under
847 * scx by material of type "type". If pArea is specified, then
848 * the rectangle that it points to is filled in with the bounding
849 * box of the region that was selected.
850 *
851 * ----------------------------------------------------------------------------
852 */
853
854 void
SelectRegion(scx,type,xMask,pArea,less)855 SelectRegion(scx, type, xMask, pArea, less)
856 SearchContext *scx; /* Area to tree-search for material. The
857 * transform must map to EditRoot coordinates.
858 */
859 TileType type; /* The type of material to be considered. */
860 int xMask; /* Indicates window (or windows) where cells
861 * must be expanded for their contents to be
862 * considered. 0 means treat everything as
863 * expanded.
864 */
865 Rect *pArea; /* If non-NULL, points to rectangle to be
866 * filled in with region's bounding box.
867 */
868 bool less;
869 {
870 TileTypeBitMask connections[TT_MAXTYPES];
871 int i;
872 SearchContext scx2;
873
874 /* If the source definition is changing, clear the old selection. */
875
876 if (SelectRootDef != scx->scx_use->cu_def)
877 {
878 if (SelectRootDef != NULL)
879 SelectClear();
880 SelectRootDef = scx->scx_use->cu_def;
881 SelSetDisplay(SelectUse, SelectRootDef);
882 }
883
884 /* Set up a connection table that allows only a particular type
885 * of material to be considered in the region.
886 */
887
888 for (i=0; i<DBNumTypes; i+=1)
889 TTMaskZero(&connections[i]);
890 TTMaskSetType(&connections[type], type);
891
892 /* Clear out the temporary selection cell and yank all of the
893 * connected paint into it.
894 */
895
896 UndoDisable();
897 DBCellClearDef(Select2Def);
898 DBTreeCopyConnect(scx, &connections[type], xMask, connections,
899 &TiPlaneRect, SelectDoLabels, Select2Use);
900 UndoEnable();
901
902 /* Now transfer what we found into the main selection cell. Pick
903 * up all the labels that correspond to the selected material.
904 */
905
906 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
907 if (less)
908 {
909 (void) SelRemoveSel2();
910 }
911 else
912 {
913 scx2.scx_use = Select2Use;
914 scx2.scx_area = Select2Def->cd_bbox;
915 scx2.scx_trans = GeoIdentityTransform;
916 DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits,
917 0, SelectUse);
918 DBCellCopyAllLabels(&scx2, &DBAllTypeBits, CU_DESCEND_SPECIAL, SelectUse,
919 (Rect *) NULL);
920 }
921
922 /* Display the new selection. */
923
924 SelRememberForUndo(FALSE, SelectRootDef, &Select2Def->cd_bbox);
925
926 DBReComputeBbox(SelectDef);
927 DBComputeUseBbox(SelectUse);
928
929 DBWHLRedraw(SelectRootDef, &Select2Def->cd_extended, TRUE);
930 DBWAreaChanged(SelectDef, &Select2Def->cd_extended, DBW_ALLWINDOWS,
931 &DBAllButSpaceBits);
932
933 if (pArea != NULL) *pArea = Select2Def->cd_extended;
934 }
935
936 /*
937 * ----------------------------------------------------------------------------
938 *
939 * SelectNet --
940 *
941 * This procedure selects an entire electrically-connected net.
942 *
943 * Results:
944 * None.
945 *
946 * Side effects:
947 * Starting from material of type "type" under scx, this procedure
948 * finds and highlights all material in all expanded cells that
949 * is electrically-connected to the starting material through a
950 * chain of expanded cells. If pArea is specified, then the
951 * rectangle that it points to is filled in with the bounding box
952 * of the net that was selected.
953 *
954 * ----------------------------------------------------------------------------
955 */
956
957 void
SelectNet(scx,type,xMask,pArea,less)958 SelectNet(scx, type, xMask, pArea, less)
959 SearchContext *scx; /* Area to tree-search for material. The
960 * transform must map to EditRoot coordinates.
961 */
962 TileType type; /* The type of material to be considered. */
963 int xMask; /* Indicates window (or windows) where cells
964 * must be expanded for their contents to be
965 * considered. 0 means treat everything as
966 * expanded.
967 */
968 Rect *pArea; /* If non-NULL, points to rectangle to be
969 * filled in with net's bounding box.
970 */
971 bool less; /* Whether to remove material from the
972 * selection using SelDeleteSel2
973 */
974 {
975 TileTypeBitMask mask;
976 SearchContext scx2;
977 Point savePoint = scx->scx_area.r_ll;
978
979 /* If the source definition is changing, clear the old selection. */
980
981 if (SelectRootDef != scx->scx_use->cu_def)
982 {
983 if (SelectRootDef != NULL)
984 SelectClear();
985 SelectRootDef = scx->scx_use->cu_def;
986 SelSetDisplay(SelectUse, SelectRootDef);
987 }
988
989 TTMaskZero(&mask);
990
991 // Make sure that SelectNet() matches connection-compatible
992 // types with the type passed to the routine.
993
994 // TTMaskSetType(&mask, type);
995 TTMaskSetMask(&mask, &DBConnectTbl[type]);
996
997 UndoDisable();
998 DBCellClearDef(Select2Def);
999 DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
1000 &TiPlaneRect, SelectDoLabels, Select2Use);
1001 UndoEnable();
1002
1003 /* Network undo method added by Nishit and Tim, July 8-10, 2004 */
1004 SelNetRememberForUndo(SelectRootDef, &savePoint, type, less, TRUE);
1005
1006 /* Now transfer what we found into the main selection cell. Pick
1007 * up all the labels that correspond to the selected material.
1008 */
1009
1010 UndoDisable();
1011 if (less)
1012 {
1013 (void) SelRemoveSel2();
1014 }
1015 else
1016 {
1017 scx2.scx_use = Select2Use;
1018 scx2.scx_area = Select2Def->cd_bbox;
1019 scx2.scx_trans = GeoIdentityTransform;
1020 DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits,
1021 0, SelectUse);
1022 DBCellCopyAllLabels(&scx2, &DBAllTypeBits, CU_DESCEND_SPECIAL, SelectUse,
1023 (Rect *) NULL);
1024 }
1025
1026 /* Set the cell use flags to mark this as a net selection, */
1027 /* so we can treat it differently when it comes time to */
1028 /* unselect it. */
1029
1030 SelectUse->cu_flags |= CU_SELECT_NET;
1031 UndoEnable();
1032
1033 DBReComputeBbox(SelectDef);
1034 DBComputeUseBbox(SelectUse);
1035
1036 DBWHLRedraw(SelectRootDef, &Select2Def->cd_extended, TRUE);
1037 DBWAreaChanged(SelectDef, &Select2Def->cd_extended, DBW_ALLWINDOWS,
1038 &DBAllButSpaceBits);
1039
1040 if (pArea != NULL) *pArea = Select2Def->cd_extended;
1041 }
1042
1043 /*
1044 * ----------------------------------------------------------------------------
1045 *
1046 * SelectCell --
1047 *
1048 * Select a subcell by making a copy of it in the __SELECT__ cell.
1049 *
1050 * Results:
1051 * None.
1052 *
1053 * Side effects:
1054 * The given use is copied into the selection. If replace is TRUE,
1055 * then the last subcell to be selected via this procedure is
1056 * deselected.
1057 *
1058 * ----------------------------------------------------------------------------
1059 */
1060
1061 void
SelectCell(use,rootDef,trans,replace)1062 SelectCell(use, rootDef, trans, replace)
1063 CellUse *use; /* Cell use to be selected. */
1064 CellDef *rootDef; /* Root definition of window in which selection
1065 * is being made.
1066 */
1067 Transform *trans; /* Transform from the coordinates of use's
1068 * definition to the coordinates of rootDef.
1069 */
1070 bool replace; /* TRUE means deselect the last cell selected
1071 * by this procedure, if it's still selected.
1072 */
1073 {
1074 CellUse *newUse;
1075
1076 /* If the source definition is changing, clear the old selection. */
1077
1078 if (SelectRootDef != rootDef)
1079 {
1080 if (SelectRootDef != NULL)
1081 SelectClear();
1082 SelectRootDef = rootDef;
1083 SelSetDisplay(SelectUse, SelectRootDef);
1084 }
1085
1086 /* Deselect the last cell selected, if requested. */
1087
1088 if (replace && (selectLastUse != NULL))
1089 {
1090 Rect area;
1091
1092 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1093 area = selectLastUse->cu_bbox;
1094 DBUnLinkCell(selectLastUse, SelectDef);
1095 DBDeleteCell(selectLastUse);
1096 (void) DBCellDeleteUse(selectLastUse);
1097 SelRememberForUndo(FALSE, SelectRootDef, &area);
1098 DBWHLRedraw(SelectRootDef, &area, TRUE);
1099 selectLastUse = (CellUse *)NULL;
1100 }
1101
1102 /* When creating a new use, try to re-use the id from the old
1103 * one. Only create a new one if the old id can't be used.
1104 */
1105
1106 newUse = DBCellNewUse(use->cu_def, (char *) use->cu_id);
1107 if (!DBLinkCell(newUse, SelectDef))
1108 {
1109 freeMagic((char *) newUse->cu_id);
1110 newUse->cu_id = NULL;
1111 (void) DBLinkCell(newUse, SelectDef);
1112 }
1113
1114 DBSetArray(use, newUse);
1115 DBSetTrans(newUse, trans);
1116 newUse->cu_expandMask = use->cu_expandMask;
1117 newUse->cu_flags = use->cu_flags;
1118
1119 /* If this cell is already selected, there's nothing more to do.
1120 * Since we didn't change the selection here, be sure NOT to remember
1121 * it for future deselection!
1122 */
1123
1124 if (DBCellFindDup(newUse, SelectDef) != NULL)
1125 {
1126 DBUnLinkCell(newUse, SelectDef);
1127 (void) DBCellDeleteUse(newUse);
1128 selectLastUse = (CellUse *) NULL;
1129 return;
1130 }
1131
1132 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1133 DBPlaceCell(newUse, SelectDef);
1134 selectLastUse = newUse;
1135
1136 SelRememberForUndo(FALSE, SelectRootDef, &newUse->cu_bbox);
1137 DBReComputeBbox(SelectDef);
1138 DBWHLRedraw(SelectRootDef, &newUse->cu_bbox, TRUE);
1139 DBWAreaChanged(SelectDef, &newUse->cu_bbox, DBW_ALLWINDOWS,
1140 &DBAllButSpaceBits);
1141 }
1142
1143 /*
1144 * ----------------------------------------------------------------------------
1145 *
1146 * SelectAndCopy1 --
1147 *
1148 * This procedure takes the contents of SelectDef, and makes a
1149 * copy of them in the edit cell. Unlike SelectAndCopy2, the
1150 * original selection is unchanged, and SelectDef is not cleared.
1151 * This allows the implementation of "drag and drop" selections.
1152 *
1153 * Results:
1154 * None.
1155 *
1156 * Side effects:
1157 * The selection is augmented with what's in Select2Def. The caller
1158 * should normally have cleared the selection before calling us.
1159 * The edit cell is modified to include everything that was in
1160 * Select2Def.
1161 *
1162 * ----------------------------------------------------------------------------
1163 */
1164
1165 void
SelectAndCopy1()1166 SelectAndCopy1()
1167 {
1168 SearchContext scx;
1169 Rect editArea;
1170 TileTypeBitMask mask;
1171
1172 /* Just copy the information in Select2Def twice, once into the
1173 * edit cell and once into the main selection cell.
1174 */
1175
1176 scx.scx_use = SelectUse;
1177 scx.scx_area = SelectUse->cu_bbox;
1178 GeoTransTrans(&SelectUse->cu_transform, &RootToEditTransform, &scx.scx_trans);
1179 TTMaskAndMask3(&mask, &DBAllButSpaceAndDRCBits, &DBActiveLayerBits);
1180 (void) DBCellCopyAllPaint(&scx, &mask, CU_DESCEND_SPECIAL, EditCellUse);
1181 (void) DBCellCopyAllLabels(&scx, &DBActiveLayerBits, CU_DESCEND_SPECIAL,
1182 EditCellUse, (Rect *) NULL);
1183 (void) DBCellCopyAllCells(&scx, CU_DESCEND_SPECIAL, EditCellUse, (Rect *) NULL);
1184 GeoTransRect(&scx.scx_trans, &scx.scx_area, &editArea);
1185 DBAdjustLabels(EditCellUse->cu_def, &editArea);
1186 DBWAreaChanged(EditCellUse->cu_def, &editArea, DBW_ALLWINDOWS,
1187 (TileTypeBitMask *) NULL);
1188 DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editArea);
1189 DBReComputeBbox(EditCellUse->cu_def);
1190 }
1191
1192 /*
1193 * ----------------------------------------------------------------------------
1194 *
1195 * SelectAndCopy2 --
1196 *
1197 * This procedure is intended for use only within the selection
1198 * module. It takes what's in Select2Def, makes a copy of it in the
1199 * edit cell, and makes the copy the selection. It's used, for
1200 * example, by the transformation and copying routines.
1201 *
1202 * Results:
1203 * None.
1204 *
1205 * Side effects:
1206 * The selection is augmented with what's in Select2Def. The caller
1207 * should normally have cleared the selection before calling us.
1208 * The edit cell is modified to include everything that was in
1209 * Select2Def.
1210 *
1211 * ----------------------------------------------------------------------------
1212 */
1213
1214 void
SelectAndCopy2(newSourceDef)1215 SelectAndCopy2(newSourceDef)
1216 CellDef *newSourceDef; /* The new selection is to be
1217 * associated with this cell in the
1218 * user's layout.
1219 */
1220 {
1221 SearchContext scx;
1222 Rect editArea, labelArea, expanded;
1223 int plane;
1224 int (*savedPaintPlane)();
1225 extern int selACPaintFunc(); /* Forward reference. */
1226 extern int selACCellFunc();
1227
1228 /* Just copy the information in Select2Def twice, once into the
1229 * edit cell and once into the main selection cell.
1230 */
1231
1232 scx.scx_use = Select2Use;
1233 scx.scx_area = Select2Use->cu_bbox;
1234 scx.scx_trans = RootToEditTransform;
1235 savedPaintPlane = DBNewPaintPlane(DBPaintPlaneActive);
1236 (void) DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_SPECIAL,
1237 EditCellUse);
1238 DBNewPaintPlane(savedPaintPlane);
1239 (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL, EditCellUse,
1240 (Rect *) NULL);
1241 (void) DBCellCopyAllCells(&scx, CU_DESCEND_SPECIAL, EditCellUse, (Rect *) NULL);
1242 GeoTransRect(&scx.scx_trans, &scx.scx_area, &editArea);
1243
1244 DBAdjustLabels(EditCellUse->cu_def, &editArea);
1245 DBWAreaChanged(EditCellUse->cu_def, &editArea, DBW_ALLWINDOWS,
1246 (TileTypeBitMask *) NULL);
1247 DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editArea);
1248 DBReComputeBbox(EditCellUse->cu_def);
1249
1250 SelectRootDef = newSourceDef;
1251 SelSetDisplay(SelectUse, SelectRootDef);
1252
1253 SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1254 scx.scx_trans = GeoIdentityTransform;
1255
1256 /* In copying stuff into SelectUse, we have to be careful. The problem
1257 * is that the stuff now in the edit cell may have switched layers.
1258 * (for example, Select2Def might have diff, which got painted
1259 * over poly in the edit cell to form transistor). As a result, we
1260 * use Select2Def to figure out what areas of what planes to put into
1261 * SelectUse, but use the actual tile types from the edit cell.
1262 */
1263
1264 for (plane = PL_SELECTBASE; plane < DBNumPlanes; plane++)
1265 {
1266 (void) DBSrPaintArea((Tile *) NULL, Select2Def->cd_planes[plane],
1267 &TiPlaneRect, &DBAllButSpaceAndDRCBits, selACPaintFunc,
1268 (ClientData) plane);
1269 DBMergeNMTiles(Select2Def->cd_planes[plane], &TiPlaneRect,
1270 (PaintUndoInfo *)NULL);
1271 }
1272
1273 (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL,
1274 SelectUse, NULL);
1275
1276 /* We also have to be careful about copying subcells into the
1277 * main selection cell. It might not have been possible to copy
1278 * a subcell into the edit cell (above), because the copying
1279 * would have formed a circularity. In that case, we need to
1280 * drop that subcell from the new selection. The code below just
1281 * copies those that are still in the edit cell.
1282 */
1283
1284 (void) SelEnumCells(TRUE, (bool *) NULL, &scx, selACCellFunc,
1285 (ClientData) NULL);
1286
1287 DBReComputeBbox(SelectDef);
1288 DBComputeUseBbox(SelectUse);
1289
1290 /* A little hack here: don't do explicit redisplay of the selection,
1291 * or record a very large redisplay area for undo-ing. It's not
1292 * necessary since the layout redisplay also redisplays the highlights.
1293 * If we do it too, then we're just double-displaying and wasting
1294 * time. (note: must record something for undo-ing in order to get
1295 * SelectRootDef set right... just don't pass a redisplay area).
1296 */
1297
1298 SelRememberForUndo(FALSE, SelectRootDef, (Rect *) NULL);
1299 DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
1300 (TileTypeBitMask *) NULL);
1301 }
1302
1303 /* Structure to hold information about an edit area, which may be
1304 * a triangular region.
1305 */
1306 typedef struct {
1307 Rect *editClip;
1308 TileType ttype;
1309 } acparg;
1310
1311 /* Utility function: for each tile, copy information over its area from
1312 * the given edit cell plane to SelectDef. Always return 0 to keep the
1313 * search alive.
1314 */
1315
1316 int
selACPaintFunc(tile,plane)1317 selACPaintFunc(tile, plane)
1318 Tile *tile; /* Tile in Select2Def. */
1319 int plane; /* Index of plane this tile came from. */
1320 {
1321 Rect area, editArea;
1322 acparg selACarg;
1323 int selACPaintFunc2(); /* Forward reference. */
1324
1325 TiToRect(tile, &area);
1326 /* we want editClip in root coordinates. . . */
1327 selACarg.editClip = &area;
1328 GeoTransRect(&RootToEditTransform, &area, &editArea);
1329
1330 selACarg.ttype = TiGetTypeExact(tile);
1331
1332 if (IsSplit(tile))
1333 {
1334 DBSrPaintNMArea((Tile *) NULL, EditCellUse->cu_def->cd_planes[plane],
1335 selACarg.ttype, &editArea, &DBAllButSpaceAndDRCBits,
1336 selACPaintFunc2, (ClientData) &selACarg);
1337 }
1338 else
1339 (void) DBSrPaintArea((Tile *) NULL, EditCellUse->cu_def->cd_planes[plane],
1340 &editArea, &DBAllButSpaceAndDRCBits, selACPaintFunc2,
1341 (ClientData) &selACarg);
1342 return 0;
1343 }
1344
1345 /* Second-level paint function: just paint the overlap between
1346 * tile and editClip into SelectDef.
1347 *
1348 * This function is like dbCopyAllPaint() but differs just enough
1349 * that a separate function is required. However, much of the code
1350 * could be shared between the two functions if it were properly
1351 * broken out into subroutines.
1352 */
1353
1354 int
selACPaintFunc2(tile,selACarg)1355 selACPaintFunc2(tile, selACarg)
1356 Tile *tile; /* Tile in edit cell. */
1357 acparg *selACarg; /* Contains edit-cell area to clip to
1358 * before painting into selection.
1359 */
1360 {
1361 Rect *editClip = selACarg->editClip;
1362 Rect area, selArea;
1363 TileType type = TiGetTypeExact(tile);
1364 TileTypeBitMask tmask, *rmask;
1365 TileType ttype, rtype;
1366 TileType dinfo = selACarg->ttype & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE);
1367
1368 TiToRect(tile, &area);
1369 GeoTransRect(&EditToRootTransform, &area, &selArea);
1370
1371 if ((dinfo & TT_DIAGONAL) || (type & TT_DIAGONAL))
1372 {
1373 /* If the select area is triangular, then we need to */
1374 /* clip in a more complicated manner. */
1375 /* Likewise if the edit cell tile is triangular and */
1376 /* the select area not. */
1377
1378 Point points[5];
1379 Rect rrect, orect;
1380 int np, i, j;
1381
1382 ttype = (selACarg->ttype & TT_SIDE) ? ((selACarg->ttype & TT_RIGHTMASK) >> 14) :
1383 selACarg->ttype & TT_LEFTMASK;
1384
1385 if (type & TT_DIAGONAL)
1386 rtype = (type & TT_SIDE) ? SplitRightType(tile) :
1387 SplitLeftType(tile);
1388 else
1389 rtype = type;
1390
1391 if (rtype >= DBNumUserLayers)
1392 {
1393 rmask = DBResidueMask(rtype);
1394 if (TTMaskHasType(rmask, ttype))
1395 rtype = ttype;
1396 }
1397
1398 TTMaskSetOnlyType(&tmask, rtype);
1399
1400 type = (dinfo & TT_SIDE) ? (rtype << 14) : rtype;
1401 type |= dinfo;
1402
1403 if (dinfo & TT_DIAGONAL)
1404 GrClipTriangle(editClip, &selArea, TRUE, dinfo, points, &np);
1405 else
1406 GrClipTriangle(&selArea, editClip, TRUE, type, points, &np);
1407
1408 if (np == 0)
1409 return 0;
1410 if (np >= 3)
1411 {
1412 for (i = 0; i < np; i++)
1413 {
1414 j = (i + 1) % np;
1415 if (points[i].p_x != points[j].p_x && points[i].p_y !=
1416 points[j].p_y)
1417 {
1418 /* Break out the triangle */
1419 rrect.r_xbot = points[i].p_x;
1420 rrect.r_xtop = points[j].p_x;
1421 rrect.r_ybot = points[i].p_y;
1422 rrect.r_ytop = points[j].p_y;
1423 GeoCanonicalRect(&rrect, &selArea);
1424 break;
1425 }
1426 }
1427 if (i == np) /* Exactly one Manhattan rectangle */
1428 {
1429 rrect.r_xbot = points[0].p_x;
1430 rrect.r_xtop = points[2].p_x;
1431 rrect.r_ybot = points[0].p_y;
1432 rrect.r_ytop = points[2].p_y;
1433 GeoCanonicalRect(&rrect, &selArea);
1434 type = rtype;
1435 }
1436 else if (np >= 4) /* Process extra rectangles in the area */
1437 {
1438 /* "orect" is the bounding box of the polygon returned */
1439 /* by ClipTriangle. */
1440
1441 orect.r_xtop = orect.r_xbot = points[0].p_x;
1442 orect.r_ytop = orect.r_ybot = points[0].p_y;
1443 for (i = 0; i < np; i++)
1444 GeoIncludePoint(&points[i], &orect);
1445
1446 /* Rectangle to left or right */
1447 rrect.r_ybot = orect.r_ybot;
1448 rrect.r_ytop = orect.r_ytop;
1449 if (selArea.r_xbot > orect.r_xbot)
1450 {
1451 rrect.r_xbot = orect.r_xbot;
1452 rrect.r_xtop = selArea.r_xbot;
1453 }
1454 else if (selArea.r_xtop < orect.r_xtop)
1455 {
1456 rrect.r_xtop = orect.r_xtop;
1457 rrect.r_xbot = selArea.r_xtop;
1458 }
1459 else
1460 goto topbottom;
1461
1462 DBPaintValid(SelectDef, &rrect, &tmask, 0);
1463 topbottom:
1464 /* Rectangle to top or bottom */
1465 rrect.r_xbot = selArea.r_xbot;
1466 rrect.r_xtop = selArea.r_xtop;
1467 if (selArea.r_ybot > orect.r_ybot)
1468 {
1469 rrect.r_ybot = orect.r_ybot;
1470 rrect.r_ytop = selArea.r_ybot;
1471 }
1472 else if (selArea.r_ytop < orect.r_ytop)
1473 {
1474 rrect.r_ytop = orect.r_ytop;
1475 rrect.r_ybot = selArea.r_ytop;
1476 }
1477 else
1478 goto splitdone;
1479
1480 DBPaintValid(SelectDef, &rrect, &tmask, 0);
1481 }
1482 }
1483 }
1484 else
1485 {
1486 ttype = selACarg->ttype;
1487
1488 if (type & TT_DIAGONAL)
1489 rtype = (type & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
1490 else
1491 rtype = type;
1492
1493 if (rtype >= DBNumUserLayers)
1494 {
1495 rmask = DBResidueMask(rtype);
1496 if (TTMaskHasType(rmask, ttype))
1497 rtype = ttype;
1498 }
1499 TTMaskSetOnlyType(&tmask, rtype);
1500 }
1501 GeoClip(&selArea, editClip); /* editClip already in root coords */
1502
1503 splitdone:
1504 DBPaintValid(SelectDef, &selArea, &tmask, type);
1505 return 0;
1506 }
1507
1508 /* Cell search function: invoked for each subcell in Select2Def that's
1509 * also in the edit cell. Make a copy of the cell in SelectDef.
1510 */
1511
1512 int
selACCellFunc(selUse,realUse)1513 selACCellFunc(selUse, realUse)
1514 CellUse *selUse; /* Use to be copied into SelectDef. This
1515 * is the instance inside Select2Def.
1516 */
1517 CellUse *realUse; /* The cellUse (in the edit cell) corresponding
1518 * to selUse. We need this in order to use its
1519 * instance id and expand mask in the selection.
1520 */
1521 {
1522 CellUse *newUse;
1523
1524 newUse = DBCellNewUse(selUse->cu_def, realUse->cu_id);
1525 if (!DBLinkCell(newUse, SelectDef))
1526 {
1527 freeMagic((char *) newUse->cu_id);
1528 newUse->cu_id = NULL;
1529 (void) DBLinkCell(newUse, SelectDef);
1530 }
1531 newUse->cu_expandMask = realUse->cu_expandMask;
1532 newUse->cu_flags = realUse->cu_flags;
1533 DBSetArray(selUse, newUse);
1534 DBSetTrans(newUse, &selUse->cu_transform);
1535 DBPlaceCell(newUse, SelectDef);
1536 return 0;
1537 }
1538
1539