From ca99d0b76a82bc19a8b3213020ce3c135a28456e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 4 May 2024 21:12:55 -0400 Subject: [PATCH] Altered the behavior of handling labels when a layer under a label is erased. In cases where magic would previously unattach the label from the material and attach it to "space", now magic will instead adjust the size of the label to stay entirely on the material. That avoids a common error of losing label or port connections when the material is trimmed back. Thanks to Philipp Guhring for suggesting this implementation (github issue #305). --- database/DBlabel.c | 97 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 9 deletions(-) diff --git a/database/DBlabel.c b/database/DBlabel.c index c57d6805..eb8001fc 100644 --- a/database/DBlabel.c +++ b/database/DBlabel.c @@ -561,6 +561,41 @@ DBReOrientLabel(cellDef, area, newPos) } } +/* + * ---------------------------------------------------------------------------- + * + * dbGetLabelArea --- + * + * Callback function used by DBAdjustLabels. Find all material under a label + * that is *not* the label type, and return the + * + * Note: This clips in a regular order, and does not consider what is the + * largest rectangular area outside the area that has been clipped out. + * + * ---------------------------------------------------------------------------- + */ + +int +dbGetLabelArea(tile, area) + Tile *tile; /* Tile found. */ + Rect *area; /* Area to be modified. */ +{ + Rect r; + + TiToRect(tile, &r); + + if (r.r_xbot > area->r_xbot) + area->r_xtop = r.r_xbot; + else if (r.r_xtop < area->r_xtop) + area->r_xbot = r.r_xtop; + else if (r.r_ybot > area->r_ybot) + area->r_ytop = r.r_ybot; + else if (r.r_ytop < area->r_ytop) + area->r_ybot = r.r_ytop; + + return 0; +} + /* * ---------------------------------------------------------------------------- * @@ -590,7 +625,7 @@ DBAdjustLabels(def, area) { Label *lab; TileType newType; - bool modified = FALSE; + bool modified = FALSE, adjusted = FALSE; /* First, find each label that crosses the area we're * interested in. @@ -602,16 +637,60 @@ DBAdjustLabels(def, area) newType = DBPickLabelLayer(def, lab, FALSE); if (newType == lab->lab_type) continue; if (lab->lab_flags & LABEL_STICKY) continue; - if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0)) + + /* New behavior (5/2024) (idea from Philipp Guhring)---If the new + * type is space, then instead of immediately casting the label off + * of its material, find the amount of the label that is still + * covered by the material. If the material covers more than half + * the label area, then adjust the label area to match the material. + */ + + adjusted = FALSE; + if (newType == TT_SPACE) { - TxPrintf("Moving label \"%s\" from %s to %s in cell %s.\n", - lab->lab_text, DBTypeLongName(lab->lab_type), - DBTypeLongName(newType), def->cd_name); + Rect r; + TileTypeBitMask lmask; + + TTMaskSetOnlyType(&lmask, lab->lab_type); + /* To do: Add compatible types (contact, residue) */ + TTMaskCom(&lmask); + + r = lab->lab_rect; + DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)], + &lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r); + + if (!GEO_RECTNULL(&r)) + { + if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0)) + { + TxPrintf("Adjusting size of label \"%s\" in cell %s.\n", + lab->lab_text, def->cd_name); + } + + DBUndoEraseLabel(def, lab); + DBWLabelChanged(def, lab, DBW_ALLWINDOWS); + lab->lab_rect = r; + DBFontLabelSetBBox(lab); + DBUndoPutLabel(def, lab); + DBWLabelChanged(def, lab, DBW_ALLWINDOWS); + modified = TRUE; + adjusted = TRUE; + } + } + + if (!adjusted) + { + if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0)) + { + TxPrintf("Moving label \"%s\" from %s to %s in cell %s.\n", + lab->lab_text, DBTypeLongName(lab->lab_type), + DBTypeLongName(newType), def->cd_name); + } + DBUndoEraseLabel(def, lab); + lab->lab_type = newType; + DBUndoPutLabel(def, lab); + modified = TRUE; } - DBUndoEraseLabel(def, lab); - lab->lab_type = newType; - DBUndoPutLabel(def, lab); - modified = TRUE; } if (modified) DBCellSetModified(def, TRUE);