From dde7144966ca6313e6a6283f38c0fcbad5893fa2 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Wed, 26 Mar 2025 14:45:46 -0400 Subject: [PATCH] Modified the behavior of SelectCopy() so that it surveys cell instance names in both the selection and in the root edit CellDef, and then wipes duplicate names from the selection and regenerates unique IDs. This avoids the unexpected behavior displayed by magic in which a "copy" function renames the *original* instance and gives the original name to the copied instance. This is not only unexpected, but causes an error in which "undo" after multiple copies fails to remove earlier copies because the name change was not recorded, and the instance can no longer be found by name. --- VERSION | 2 +- database/DBcellname.c | 44 ++++++++++++++++++++++++++++++++++++++++++ database/database.h.in | 1 + select/selOps.c | 11 ++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 19969575..6bdf1944 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.522 +8.3.523 diff --git a/database/DBcellname.c b/database/DBcellname.c index 9bac905f..5e0fa7f9 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -2380,6 +2380,50 @@ DBGenerateUniqueIds(def, warn) HashKill(&dbUniqueNameTable); } +/* + * ---------------------------------------------------------------------------- + * + * DBSelectionUniqueIds -- + * + * This is similar to DBGenerateUniqueIds(), but the purpose is to make + * sure that cell IDs in the selection do not collide with IDs in the + * definition. This is done before copying from Select2Def back to the + * root edit CellDef. Otherwise, any copied cell takes the name of the + * original, and the original gets renamed, which is unexpected behavior. + * Called only from SelectCopy(). + * + * Results: + * None. + * + * Side effects: + * May modify the use-id's of the cells in the cell plane of 'selDef'. + * + * ---------------------------------------------------------------------------- + */ + +void +DBSelectionUniqueIds(selDef, rootDef) + CellDef *selDef; /* Should be Select2Def */ + CellDef *rootDef; /* Should be EditRootDef */ +{ + int dbFindNamesFunc(); + int dbGenerateUniqueIdsFunc(); + + dbWarnUniqueIds = FALSE; + HashInit(&dbUniqueDefTable, 32, 1); /* Indexed by (CellDef *) */ + HashInit(&dbUniqueNameTable, 32, 0); /* Indexed by use-id */ + + /* Build up tables of names */ + DBCellEnum(rootDef, dbFindNamesFunc, (ClientData) rootDef); + DBCellEnum(selDef, dbFindNamesFunc, (ClientData) selDef); + + /* Assign unique use-ids to all cells in the selection */ + DBCellEnum(selDef, dbGenerateUniqueIdsFunc, (ClientData) selDef); + + HashKill(&dbUniqueDefTable); + HashKill(&dbUniqueNameTable); +} + /* * ---------------------------------------------------------------------------- * diff --git a/database/database.h.in b/database/database.h.in index c5f9f964..220a5ae1 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -983,6 +983,7 @@ extern int DBScaleCell(); extern TileType DBTechNameTypes(); extern void DBTreeFindUse(); extern void DBGenerateUniqueIds(); +extern void DBSelectionUniqueIds(); extern TileType DBInvTransformDiagonal(); extern bool DBIsSubcircuit(); extern int DBSrPaintNMArea(); diff --git a/select/selOps.c b/select/selOps.c index c9785d01..73fc9915 100644 --- a/select/selOps.c +++ b/select/selOps.c @@ -311,9 +311,18 @@ SelectCopy(transform) (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_NO_LOCK, Select2Use, (Rect *) NULL); (void) DBCellCopyAllCells(&scx, CU_DESCEND_NO_LOCK, Select2Use, (Rect *) NULL); + + /* The selection now has the same instance names as the cell def. If + * copies are made, then there will be name conflicts, and the original + * instance may be the one renamed. The sensible thing to do is to make + * sure that all conflicts are resolved within the select CellDef before + * the copy is made. + */ + DBSelectionUniqueIds(Select2Def, EditRootDef); + DBReComputeBbox(Select2Def); UndoEnable(); - + SelectClear(); SelectAndCopy2(EditRootDef); }