/* * DBWdisplay.c -- * * This file contains code for redisplaying layout on the display. * It saves up information about what is to be redisplayed, then * does all of the redisplay at a convenient time. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWdisplay.c,v 1.5 2008/12/11 04:20:05 tim Exp $"; #endif /* not lint */ #include #include #include #include "utils/magic.h" #include "utils/malloc.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "windows/windows.h" #include "graphics/graphics.h" #include "dbwind/dbwind.h" #include "utils/utils.h" #include "dbwind/dbwtech.h" #include "utils/styles.h" #include "utils/main.h" #include "utils/tech.h" #include "utils/signals.h" /* C99 compat */ #include "textio/textio.h" /* The following variable is exported to the rest of the world. * It is read from the "styletype" line of the technology file, * and defines the class of display styles file expected for * this technology. It defaults as below; almost all technologies * can use the default. */ char *DBWStyleType = "std"; /* a round-up sort of integer division */ #define ceilDiv(n,d) ( ((n) < 0) ? -( ((-(n))+(d)-1) / d) \ : ((n)+(d)-1) / d ) static bool debugit = FALSE; /* The following statics are just for convenience in talking between * the top-level redisplay routine and the lower-level redisplay * routines invoked during the recursive search. */ static MagWindow *dbwWindow; /* Current window being redisplayed. */ static bool disWasPale; /* TRUE if last rect was displayed pale */ static Rect rootClip; /* Clip area for root area that is being * redisplayed. */ static Rect windClip; /* Clip area for entire window. */ static int disStyle; /* Display style. */ static Rect dbwWatchArea; /* Area used to clip tiles being "watched" so * that infinities don't cause arithmetic * overflow. In coords of cell being watched. */ static Transform dbwWatchTrans; /* Transform to root coords for watch tiles. */ static int dbwWatchDemo; /* TRUE means use "demo" style for watch * tile display. */ static int dbwSeeTypes; /* TRUE means use tile type instead of pointer value for watch display. */ static Rect dbwMinBBox; /* If bounding boxes aren't at least this * large, don't bother displaying name and * id. The ur point of the box gives the * minimum allowed dimensions. */ static int dbwLabelSize; /* Size to use for label drawing. */ static Rect *dbwExpandAmounts; /* Box to accumulate total sizes of labels. * Always refers to crec->dbw_expandAmounts * in window being redrawn. */ /* The stuff below is shared between the top-level and action * routines for redisplay. It is used to identify the edit cell * so it can be displayed differently. */ static CellDef *editDef; static Transform editTrans; /* Contains transform from edit cell to * screen coordinates. If edit cell isn't * in this window, editDef is NULL. */ static bool dbwAllSame; /* Means don't display the edit cell * differently after all. */ static bool dbwIsLocked; /* Is window already locked */ static MagWindow *dbwLockW; /* Window to lock */ static bool dbwNeedStyle; /* Do we need to set the display style? */ int DBWNumStyles = 0; /* Number of styles usable in layer * definitions. This is also the amount * to add to a style index to get its * "pale" (non-edit-cell) version */ int RtrMetalWidth = 2; /* These officially belong to the router */ int RtrPolyWidth = 2; /* but they have been usurped for other */ int RtrContactWidth = 2; /* purposes in DBWdisplay and in the plot * module. */ extern char *MainMonType; /* from main/main.c */ /* Search functions, all of which are used before definition: */ extern int dbwTileFunc(), dbwWatchFunc(), dbwLabelFunc(); extern int dbwPaintFunc(), dbwBBoxFunc(); extern int dbwWindowFunc(), dbwChangedFunc(); /* * ---------------------------------------------------------------------------- * DBWredisplay -- * * This procedure does the dirty of redisplaying information * on the graphics screen. When it is done the given area of the * window will be correctly displayed, including the grid, any * watched tile planes, and tools. * * This procedure locks windows as it goes. * * Results: * None. * * Side effects: * Stuff is drawn on the display in the given area. * ---------------------------------------------------------------------------- */ void DBWredisplay(w, rootArea, clipArea) MagWindow *w; /* Window some of whose contents are to be * redisplayed. */ Rect *rootArea; /* The area that must be redisplayed, in * root cell coordinates. */ Rect *clipArea; /* The screen area that we should clip to */ { int i; TileTypeBitMask *mask; SearchContext scontext; Rect largerArea, labelArea, screenArea; int bitMask, lambdasPerPixel, pixelsPerLambda; DBWclientRec *crec; CellDef *cellDef; TileTypeBitMask layers, rmask; /* TxPrintf("Root area (%d, %d) (%d, %d) redisplay.\n", rootArea->r_xbot, rootArea->r_ybot, rootArea->r_xtop, rootArea->r_ytop); */ #ifdef MAGIC_WRAPPER /* Honor the display suspend state */ if (GrDisplayStatus == DISPLAY_SUSPEND) return; #endif GrLock(w, TRUE); /* Round up the redisplay area by 1 pixel on all sides. This * is needed because DBSrPaintArea won't return tiles that touch * the area without overlapping it. Without the round-up, there * will be occasional (in fact, frequent), one-pixel wide slivers. */ largerArea = *rootArea; largerArea.r_xbot -= 1; largerArea.r_ybot -= 1; largerArea.r_xtop += 1; largerArea.r_ytop += 1; crec = ((DBWclientRec *) w->w_clientData); cellDef = ((CellUse *)w->w_surfaceID)->cu_def; pixelsPerLambda = w->w_scale / SUBPIXEL; lambdasPerPixel = (SUBPIXEL / w->w_scale) + 1; if ((crec->dbw_origin.p_x != w->w_origin.p_x) || (crec->dbw_origin.p_y != w->w_origin.p_y) || (crec->dbw_scale != w->w_scale) || (crec->dbw_surfaceArea.r_xbot != w->w_surfaceArea.r_xbot) || (crec->dbw_surfaceArea.r_ybot != w->w_surfaceArea.r_ybot) || (crec->dbw_surfaceArea.r_xtop != w->w_surfaceArea.r_xtop) || (crec->dbw_surfaceArea.r_ytop != w->w_surfaceArea.r_ytop)) { /* The window has changed size or position or scale, * so update measurements on label size in this window. * Also, pick a size for labels based on the scale in * half the window: the idea is to make the labels about * half the height of typical wires. */ int halfWireWidth; Rect text; halfWireWidth = MAX(RtrMetalWidth, RtrPolyWidth); halfWireWidth = (halfWireWidth * w->w_scale) >> (SUBPIXELBITS + 1); for (i = GR_TEXT_XLARGE; i >= GR_TEXT_SMALL; i--) { GrLabelSize("B", GEO_CENTER, i, &text); if (halfWireWidth > (text.r_ytop - text.r_ybot)) break; } if (i < GR_TEXT_SMALL) i = GR_TEXT_SMALL; if ((3 * halfWireWidth) <= (text.r_ytop - text.r_ybot)) crec->dbw_labelSize = -lambdasPerPixel; else crec->dbw_labelSize = i; crec->dbw_expandAmounts.r_xbot = 0; crec->dbw_expandAmounts.r_ybot = 0; crec->dbw_expandAmounts.r_xtop = 0; crec->dbw_expandAmounts.r_ytop = 0; crec->dbw_origin = w->w_origin; crec->dbw_scale = w->w_scale; crec->dbw_surfaceArea = w->w_surfaceArea; } /* Labels can stick out a long way from the point they are * anchored to. In the code that draws labels we record the * size (in pixels) of the largest label in the window. Here * we use that information to increase the size of the search * area for labels enough to be sure we'll see any label that * falls partially or completely in the area we're redisplaying. * Note: we have to also include the size of the label cross * in the area to be redisplayed. */ labelArea = largerArea; (void) GeoInclude(&GrCrossRect, &crec->dbw_expandAmounts); if (pixelsPerLambda > 0) { labelArea.r_xtop -= ceilDiv(crec->dbw_expandAmounts.r_xbot, pixelsPerLambda); labelArea.r_ytop -= ceilDiv(crec->dbw_expandAmounts.r_ybot, pixelsPerLambda); labelArea.r_xbot -= ceilDiv(crec->dbw_expandAmounts.r_xtop, pixelsPerLambda); labelArea.r_ybot -= ceilDiv(crec->dbw_expandAmounts.r_ytop, pixelsPerLambda); } else { labelArea.r_xtop -= crec->dbw_expandAmounts.r_xbot * lambdasPerPixel; labelArea.r_ytop -= crec->dbw_expandAmounts.r_ybot * lambdasPerPixel; labelArea.r_xbot -= crec->dbw_expandAmounts.r_xtop * lambdasPerPixel; labelArea.r_ybot -= crec->dbw_expandAmounts.r_ytop * lambdasPerPixel; } /** TxPrintf("Need to expand area by (%d %d) (%d %d) pixels.\n", crec->dbw_expandAmounts.r_xbot, crec->dbw_expandAmounts.r_ybot, crec->dbw_expandAmounts.r_xtop, crec->dbw_expandAmounts.r_ytop); **/ /* Set the clipping rectangle to contain only the area being displayed. */ dbwWindow = w; windClip = w->w_screenArea; WindSurfaceToScreen(w, rootArea, &rootClip); GrClipTo(&rootClip); scontext.scx_area = largerArea; scontext.scx_use = ((CellUse *)w->w_surfaceID); scontext.scx_x = scontext.scx_y = -1; scontext.scx_trans = GeoIdentityTransform; bitMask = crec->dbw_bitmask; /* See if this window contains the edit cell. If so, remember * information about the edit cell so we can identify it during * the action routines. */ if (cellDef == EditRootDef) { editDef = EditCellUse->cu_def; editTrans = EditToRootTransform; } else editDef = NULL; if (crec->dbw_flags & DBW_ALLSAME) dbwAllSame = TRUE; else dbwAllSame = FALSE; /* Empty the area of all previous info. */ GrClipBox(&rootClip, STYLE_ERASEALL); /* Go through all of the tile display styles. For each * style, if there are tiles that include that style, then * find and display all the tiles. * * We use the fast version of GrClipBox in the filter * function, GrFastBox. To use it requires that we set * the style before the call, which we do inside of * dbwPaintFunc() on the first box displayed for each * style. * * Unlock the window before the following loop to avoid * holding the lock too long. */ GrUnlock(w); dbwLockW = w; dbwIsLocked = FALSE; for (i = 0; i < DBWNumStyles; i++) { mask = DBWStyleToTypes(i); TTMaskAndMask3(&layers, mask, &crec->dbw_visibleLayers); if (!TTMaskIsZero(&layers)) { TileType t, s; TileTypeBitMask *rMask; /* For each contact type, if the contact is not visible, */ /* display any of its residue layers that are visible. */ for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (DBIsContact(t)) if (!TTMaskHasType(&layers, t)) { rMask = DBResidueMask(t); if (TTMaskIntersect(rMask, &layers)) TTMaskSetType(&layers, t); } /* Treat any stacking type in the mask like the */ /* residue type whose home plane is the same as */ /* the home plane of the stacking type. */ for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++) if (TTMaskHasType(&layers, t)) for (s = DBNumUserLayers; s < DBNumTypes; s++) { rMask = DBResidueMask(s); if (TTMaskHasType(&layers, s) && TTMaskHasType(rMask, t)) if (DBPlane(s) != DBPlane(t)) TTMaskClearType(&layers, s); } /* * To avoid holding a lock for too long, we don't set it * until we actually see something to display, and we * clear it immediately after we've displayed a style * that had something in it. */ disStyle = i + TECHBEGINSTYLES; disWasPale = FALSE; /* Using normal solid style */ dbwNeedStyle = TRUE; /* Haven't set style yet */ if (DBTreeSrUniqueTiles(&scontext, &layers, bitMask, dbwPaintFunc, (ClientData) NULL)) { /* We were interrupted. If we deal with backing store, */ /* it must be invalidated. */ if (GrFreeBackingStorePtr != NULL) (*GrFreeBackingStorePtr)(w); } if (dbwIsLocked) { GrUnlock(w); dbwIsLocked = FALSE; } } } GrLock(w, TRUE); GrClipTo(&rootClip); /* Now, find any labels that are visible and display them. * Label text is only displayed for certain ranges of magnification: * If a window is too zoomed-out, then text redisplay takes too * long and just clutters up the screen anyway. For displaying * labels, we set the clip area to the whole screen (otherwise * new labels will be clipped to just the paint area). This only * works because (a) graphics clips down to the window's actual * displayed area anyway, and (b) labels are opaque layers on top * of everything else (otherwise there might be color mixing * problems). */ if (crec->dbw_flags & DBW_SEELABELS) { scontext.scx_area = labelArea; /* make sure that we are searching an area, not just a point */ scontext.scx_area.r_xtop = MAX(scontext.scx_area.r_xtop, scontext.scx_area.r_xbot + 1); scontext.scx_area.r_ytop = MAX(scontext.scx_area.r_ytop, scontext.scx_area.r_ybot + 1); dbwLabelSize = crec->dbw_labelSize; dbwExpandAmounts = &crec->dbw_expandAmounts; GrClipTo(&GrScreenRect); /* Set style information beforehand */ GrSetStuff(STYLE_LABEL); (void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask, (TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH, dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers)); GrClipTo(&rootClip); } /* Next, display the bounding boxes that are visible. Before doing * this, calculate the area occupied by the text "BBB". A cell won't * get its id or name displayed unless its bbox is at least this * large. */ if (crec->dbw_flags & DBW_SEECELLS) { GrLabelSize("BBB", GEO_CENTER, GR_TEXT_SMALL, &dbwMinBBox); dbwMinBBox.r_xtop -= dbwMinBBox.r_xbot; dbwMinBBox.r_ytop -= dbwMinBBox.r_ybot; /* Redisplay cell names as if the whole window were visible. * This must be done since we slide the names around to fit * into the clip area. Set the style beforehand for speed. */ GrClipTo(&GrScreenRect); /* Will be cut down to window size by * the graphics module. */ scontext.scx_area = largerArea; GrSetStuff(STYLE_BBOX); (void) DBTreeSrCells(&scontext, bitMask, dbwBBoxFunc, (ClientData)NULL); GrClipTo(&rootClip); } /* Now redisplay the grid. This code is a bit tricky because * it makes sure that the origin ends up on a grid line. */ if (crec->dbw_flags & DBW_GRID) { int width, height; Rect gridRect; /* Compute a grid template rectangle, in screen coordinates, that * is near the lower-left corner of the window. */ gridRect.r_ll = w->w_origin; width = crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot; height = crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot; gridRect.r_xbot -= w->w_scale * ((w->w_surfaceArea.r_xbot - crec->dbw_gridRect.r_xbot) % width); gridRect.r_ybot -= w->w_scale * ((w->w_surfaceArea.r_ybot - crec->dbw_gridRect.r_ybot) % height); gridRect.r_xtop = gridRect.r_xbot + w->w_scale*width; gridRect.r_ytop = gridRect.r_ybot + w->w_scale*height; GrClipBox(&gridRect, STYLE_GRID); /* Redisplay a little square around the origin for the edit cell * (if the edit cell is in this window). Make the origin 4 pixels * across, but don't display it unless this is less than two lambda * units. That way, we always know how much to redisplay (in lambda * units), when the edit cell changes. */ if (editDef != NULL) { Rect r, r2; r.r_xbot = r.r_ybot = -1; r.r_xtop = r.r_ytop = 1; WindSurfaceToScreen(w, &r, &r2); if ((r2.r_xtop - r2.r_xbot) >= 4) { GeoTransRect(&EditToRootTransform, &GeoNullRect, &r2); WindSurfaceToScreen(w, &r2, &r); r.r_xbot -= 2; r.r_xtop += 2; r.r_ybot -= 2; r.r_ytop += 2; GrClipBox(&r, STYLE_ORIGIN); } } } /* If there is a tile plane being "watched", redisplay * its structure. */ if (crec->dbw_watchPlane >= 0) { Transform toCell; GeoInvertTrans(&crec->dbw_watchTrans, &toCell); GeoTransRect(&toCell, &w->w_surfaceArea, &dbwWatchArea); dbwWatchArea.r_xbot -= lambdasPerPixel; dbwWatchArea.r_xtop += lambdasPerPixel; dbwWatchArea.r_ybot -= lambdasPerPixel; dbwWatchArea.r_ytop += lambdasPerPixel; dbwWatchTrans = crec->dbw_watchTrans; dbwWatchDemo = ((crec->dbw_flags & DBW_WATCHDEMO) != 0); dbwSeeTypes = ((crec->dbw_flags & DBW_SEETYPES) != 0); (void) DBSrPaintArea((Tile *) NULL, crec->dbw_watchDef->cd_planes[crec->dbw_watchPlane], &dbwWatchArea, &DBAllTypeBits, dbwTileFunc, (ClientData) NULL); } /* Record information so that the highlight manager will redisplay * highlights over the area we just redisplayed. */ DBPaintPlane(crec->dbw_hlRedraw, &labelArea, DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR), (PaintUndoInfo *) NULL); /* display a debugging box which shows which area should be redrawn */ if (debugit) { WindSurfaceToScreen(w, &largerArea, &screenArea); (void) GrClipBox(&screenArea, STYLE_LABEL); } #ifdef notdef /* finally, display the plowing debugging information */ cmdPlowDisplayEdges(w, rootArea, clipArea); #endif /* notdef */ GrUnlock(w); /* Create backing store of this area for quick refresh of highlight */ /* areas. */ if (GrPutBackingStorePtr != NULL) (*GrPutBackingStorePtr)(w, &rootClip); } /* * ---------------------------------------------------------------------------- * * dbwPaintFunc -- * * Invoked by database searching routines during redisplay to * draw a tile on the screen. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * Clips and draws a paint tile. * * ---------------------------------------------------------------------------- */ int dbwPaintFunc(tile, cxp) Tile *tile; /* Tile to be redisplayed. */ TreeContext *cxp; /* From DBTreeSrTiles */ { SearchContext *scx = cxp->tc_scx; /* Contains pointer to use containing def * in which tile appears, and transform to * screen coordinates. */ #ifdef MAGIC_WRAPPER /* This allows the display to be interrupted when running Tcl/Tk. */ /* Because graphics are not handled by a separate process, the */ /* drawing routine itself is responsible for periodically checking */ /* the graphics event queue to see if something is pending. */ if (GrDisplayStatus == DISPLAY_BREAK_PENDING) { GrDisplayStatus = DISPLAY_IN_PROGRESS; if (GrEventPendingPtr) { if ((*GrEventPendingPtr)()) sigOnInterrupt(0); else SigSetTimer(0); } } #endif /* Ignore DRC error tiles in anything but the top-level window */ if (scx->scx_use != (CellUse *)dbwWindow->w_surfaceID) { TileType ttype = TiGetType(tile); if (ttype == TT_ERROR_P || ttype == TT_ERROR_S || ttype == TT_ERROR_PS) return 0; } if (!dbwIsLocked) { GrLock(dbwLockW, TRUE); GrClipTo(&rootClip); dbwIsLocked = TRUE; } if (dbwNeedStyle) { GrSetStuff(disStyle); dbwNeedStyle = FALSE; } /* If this isn't the edit cell, add 64 to the display style * to be used. */ if (!dbwAllSame && ((editDef != scx->scx_use->cu_def) || (scx->scx_trans.t_a != editTrans.t_a) || (scx->scx_trans.t_b != editTrans.t_b) || (scx->scx_trans.t_c != editTrans.t_c) || (scx->scx_trans.t_d != editTrans.t_d) || (scx->scx_trans.t_e != editTrans.t_e) || (scx->scx_trans.t_f != editTrans.t_f))) { if (!disWasPale) { GrSetStuff(disStyle + DBWNumStyles); disWasPale = TRUE; } } else { if (disWasPale) { GrSetStuff(disStyle); disWasPale = FALSE; } } /* Note: GrFastBox() has been replaced here with GrBox(). */ /* This checks for non-square outlines before deciding */ /* whether to render the outline with a fast rectangle- */ /* drawing routine or to render it segment by segment. */ GrBox(dbwWindow, &scx->scx_trans, tile); return 0; } /* * ---------------------------------------------------------------------------- * * DBWDrawLabel -- * * This procedure does all the work of actually drawing labels * on the screen. It is invoked by label redisplay code and also * by the selection redisplay code. * * Results: * None. * * Side effects: * The label given by text, rect, and pos is drawn on the screen * in style "style" and size "labelSize". The caller must have set * up all of the clipping information for the window in which the * label is to be drawn. This procedure updates sizeBox to be * large enough to hold the total pixel area occupied by the label * (assuming it were drawn at (0,0)). * * ---------------------------------------------------------------------------- */ void DBWDrawLabel(label, rect, pos, style, labelSize, sizeBox) Label *label; /* Text to be displayed. */ Rect *rect; /* labrect, clipped to the visible window */ int pos; /* Position of text relative to rect (e.g. * GEO_NORTH) in screen coordinates. */ int style; /* Style to use for redisplay; if -1 then * this has already been set by the caller * and we shouldn't call GrSetStuff. */ int labelSize; /* Size to use for drawing labels. If < 0 then * no text is drawn: only the box. */ Rect *sizeBox; /* Expanded if necessary to include the * screen area of the text for this label. */ { Point p; Rect location; char *text = label->lab_text; int result; if (style >= 0) GrSetStuff(style); GrDrawFastBox(rect, labelSize); if (labelSize < 0) return; switch (pos) { case GEO_CENTER: p.p_x = (rect->r_xbot + rect->r_xtop)/2; p.p_y = (rect->r_ybot + rect->r_ytop)/2; break; case GEO_NORTH: p.p_x = (rect->r_xbot + rect->r_xtop)/2; p.p_y = rect->r_ytop; break; case GEO_NORTHEAST: p = rect->r_ur; break; case GEO_EAST: p.p_x = rect->r_xtop; p.p_y = (rect->r_ybot + rect->r_ytop)/2; break; case GEO_SOUTHEAST: p.p_x = rect->r_xtop; p.p_y = rect->r_ybot; break; case GEO_SOUTH: p.p_x = (rect->r_xbot + rect->r_xtop)/2; p.p_y = rect->r_ybot; break; case GEO_SOUTHWEST: p = rect->r_ll; break; case GEO_WEST: p.p_x = rect->r_xbot; p.p_y = (rect->r_ybot + rect->r_ytop)/2; break; case GEO_NORTHWEST: p.p_x = rect->r_xbot; p.p_y = rect->r_ytop; break; } if (GrPutText(text, style, &p, pos, labelSize, FALSE, &GrScreenRect, &location)) { sizeBox->r_xbot = MIN(sizeBox->r_xbot, location.r_xbot - p.p_x); sizeBox->r_ybot = MIN(sizeBox->r_ybot, location.r_ybot - p.p_y); sizeBox->r_xtop = MAX(sizeBox->r_xtop, location.r_xtop - p.p_x); sizeBox->r_ytop = MAX(sizeBox->r_ytop, location.r_ytop - p.p_y); } } /* * ---------------------------------------------------------------------------- * * DBWDrawFontLabel -- * * This procedure is like DBWDrawLabel but handles rendered font * labels. It is invoked by the label redisplay code in dbwind * and select. Unlike DBWDrawLabel, it does all the layout-to-screen * transformations itself. * * Results: * None. * * Side effects: * The label given by text, rect, and pos is drawn on the screen * in style "style" and size "labelSize". The caller must have set * up all of the clipping information for the window in which the * label is to be drawn. This procedure updates sizeBox to be * large enough to hold the total pixel area occupied by the label * (assuming it were drawn at (0,0)). * * ---------------------------------------------------------------------------- */ void DBWDrawFontLabel(label, window, trans, style) Label *label; MagWindow *window; Transform *trans; int style; /* If -1, style is already set */ { Point *p, newcorner, scrncorners[4], labOrigin; Rect rootArea, labrect; int i, rotate, minv, scaledLambdasPerPixel; dlong tmp, dval, scale; double rads; GeoTransRect(trans, &label->lab_rect, &rootArea); WindSurfaceToScreen(window, &rootArea, &labrect); labOrigin.p_x = (rootArea.r_xbot + rootArea.r_xtop) << 2; labOrigin.p_y = (rootArea.r_ybot + rootArea.r_ytop) << 2; /* This bit of code sets the scale for the "cross" associated with */ /* a label as a logarithmic function of the window scale. This is */ /* completely subjective, but seems to produce a decent result. */ scaledLambdasPerPixel = 0; i = (SUBPIXEL / window->w_scale); while (i != 0) { i >>= 1; scaledLambdasPerPixel++; } if (style >= 0) GrSetStuff(style); GrDrawFastBox(&labrect, -scaledLambdasPerPixel); for (i = 0; i < 4; i++) { GeoTransPointDelta(trans, &label->lab_corners[i], &newcorner); /* Effectively, WindPointToScreen(), but with an */ /* extra scalefactor of 8, including computing the */ /* (unclipped) origin from the center of rootArea. */ tmp = labOrigin.p_x + newcorner.p_x; tmp -= (dlong)window->w_surfaceArea.r_xbot << 3; dval = ((dlong)window->w_origin.p_x << 3) + (dlong)(tmp * window->w_scale); scrncorners[i].p_x = (int)(dval >> (SUBPIXELBITS + 3)); tmp = labOrigin.p_y + newcorner.p_y; tmp -= (dlong)window->w_surfaceArea.r_ybot << 3; dval = ((dlong)window->w_origin.p_y << 3) + (dlong)(tmp * window->w_scale); scrncorners[i].p_y = (int)(dval >> (SUBPIXELBITS + 3)); } /* Ensure that the label is always drawn with text upright. */ /* Compute rotation from the transformed baseline angle. */ /* (The "2" is a slop factor to account for round-off error */ /* in the computation of scrncorners.) */ rotate = GeoTransAngle(trans, label->lab_rotate); if ((rotate >= 0 && rotate < 90) || (rotate >= 180 && rotate < 270)) { /* Startpoint is the bottommost point. Due to roundoff error, */ /* we need to watch closely when the angle is close to a */ /* multiple of 90 degrees. */ minv = scrncorners[0].p_y; p = &scrncorners[0]; for (i = 1; i < 4; i++) { if ((scrncorners[i].p_y - 2) < minv) { if ((scrncorners[i].p_y + 2) > minv) { if (((rotate < 5) || (rotate >= 180 && rotate < 185)) && (scrncorners[i].p_x > p->p_x)) continue; if (((rotate > 85 && rotate < 90) || (rotate > 265)) && (scrncorners[i].p_x < p->p_x)) continue; } minv = scrncorners[i].p_y; p = &scrncorners[i]; } } } else { /* startpoint is the leftmost point */ minv = scrncorners[0].p_x; p = &scrncorners[0]; for (i = 1; i < 4; i++) { if ((scrncorners[i].p_x - 2) < minv) { if ((scrncorners[i].p_x + 2) > minv) { if (((rotate < 95) || (rotate >= 270 && rotate < 275)) && (scrncorners[i].p_y < p->p_y)) continue; if (((rotate > 175 && rotate < 180) || (rotate > 355)) && (scrncorners[i].p_y > p->p_y)) continue; } minv = scrncorners[i].p_x; p = &scrncorners[i]; } } } if (rotate >= 90 && rotate < 270) { rotate += 180; if (rotate >= 360) rotate -= 360; } scale = ((dlong)window->w_scale * (dlong)label->lab_size) >> (SUBPIXELBITS + 3); if (scale > 0) { GrFontText(label->lab_text, style, p, label->lab_font, (int)scale, rotate, &GrScreenRect); } } /* * ---------------------------------------------------------------------------- * * dbwLabelFunc -- * * Called by database searching routines during redisplay. It * displays a label on the screen. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * The label is clipped and drawn on the screen. * * ---------------------------------------------------------------------------- */ int dbwLabelFunc(scx, label, tpath, clientData) SearchContext *scx; /* Contains pointer to use containing def in * which label appears, and transform to * screen coordinates. */ Label *label; /* Label to be displayed. */ TerminalPath *tpath; /* Contains pointer to full pathname of label */ ClientData clientData; /* Used for mask for dbw_visibleLayers */ { Rect labRect, tmp; int screenPos, screenRot, newStyle; TileTypeBitMask *vmask; vmask = (TileTypeBitMask *)clientData; /* Do not draw the label if the layer to which it is attached is * not being drawn. */ if (!TTMaskHasType(vmask, label->lab_type)) return 0; if (!dbwAllSame && ((editDef != scx->scx_use->cu_def) || (scx->scx_trans.t_a != editTrans.t_a) || (scx->scx_trans.t_b != editTrans.t_b) || (scx->scx_trans.t_c != editTrans.t_c) || (scx->scx_trans.t_d != editTrans.t_d) || (scx->scx_trans.t_e != editTrans.t_e) || (scx->scx_trans.t_f != editTrans.t_f))) disWasPale = TRUE; else disWasPale = FALSE; if (label->lab_flags & PORT_DIR_MASK) newStyle = (disWasPale) ? STYLE_PORT_PALE : STYLE_PORT; else newStyle = (disWasPale) ? STYLE_LABEL_PALE : STYLE_LABEL; if (newStyle != disStyle) { disStyle = newStyle; GrSetStuff(newStyle); } if (label->lab_font < 0) { screenPos = GeoTransPos(&scx->scx_trans, label->lab_just); GeoTransRect(&scx->scx_trans, &label->lab_rect, &tmp); WindSurfaceToScreen(dbwWindow, &tmp, &labRect); if (!GEO_TOUCH(&labRect, &dbwWindow->w_screenArea)) return 0; DBWDrawLabel(label, &labRect, screenPos, -1, dbwLabelSize, dbwExpandAmounts); } else { DBWDrawFontLabel(label, dbwWindow, &scx->scx_trans, -1); } if (label->lab_flags & PORT_DIR_MASK) { if (label->lab_font >= 0) // If not done already. . . { screenPos = GeoTransPos(&scx->scx_trans, label->lab_just); GeoTransRect(&scx->scx_trans, &label->lab_rect, &tmp); } WindSurfaceToScreenNoClip(dbwWindow, &tmp, &labRect); /* Temporarily set the style for port connection lines */ GrSetStuff(STYLE_PORT_CONNECT); if (label->lab_flags & PORT_DIR_NORTH) GrClipLine(labRect.r_xbot, labRect.r_ytop, labRect.r_xtop, labRect.r_ytop); if (label->lab_flags & PORT_DIR_SOUTH) GrClipLine(labRect.r_xbot, labRect.r_ybot, labRect.r_xtop, labRect.r_ybot); if (label->lab_flags & PORT_DIR_EAST) GrClipLine(labRect.r_xtop, labRect.r_ybot, labRect.r_xtop, labRect.r_ytop); if (label->lab_flags & PORT_DIR_WEST) GrClipLine(labRect.r_xbot, labRect.r_ybot, labRect.r_xbot, labRect.r_ytop); GrSetStuff(disStyle); } return 0; } /* * ---------------------------------------------------------------------------- * * dbwBBoxFunc -- * * Called by database searching routines during redisplay. * The caller should have already set the style information. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * The bounding box of the cell is clipped and drawn on the screen, * along with the name and id of the celluse. The bounding box * area is returned in the pointer argument "sizeBox". * * ---------------------------------------------------------------------------- */ int dbwBBoxFunc(scx) SearchContext *scx; /* Describes context of cell. */ { Rect r, r2; char idName[100]; Point p; CellUse *cellUse; cellUse = scx->scx_use; GeoTransRect(&scx->scx_trans, &cellUse->cu_def->cd_bbox, &r2); WindSurfaceToScreen(dbwWindow, &r2, &r); GrFastBox(&r); /* Don't futz around with text if the bbox is tiny. */ if (((r.r_xtop-r.r_xbot) < dbwMinBBox.r_xtop) || ((r.r_ytop-r.r_ybot) < dbwMinBBox.r_ytop)) return 0; p.p_x = (r.r_xbot + r.r_xtop)/2; p.p_y = (r.r_ybot + 2*r.r_ytop)/3; GeoClip(&r, &windClip); GrPutText(cellUse->cu_def->cd_name, -1, &p, GEO_CENTER, GR_TEXT_LARGE, TRUE, &r, (Rect *) NULL); (void) DBPrintUseId(scx, idName, 100, TRUE); p.p_y = (2*r.r_ybot + r.r_ytop)/3; GrPutText(idName, -1, &p, GEO_CENTER, GR_TEXT_LARGE, TRUE, &r, (Rect *)NULL); return 0; } /* * ---------------------------------------------------------------------------- * * dbwTileFunc -- * * Called by the database search routines, from DBWredisplay * during redisplay. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * Displays a tile's bounding box and corner stitches. * * ---------------------------------------------------------------------------- */ int dbwTileFunc(tile) Tile *tile; /* A tile to be redisplayed. */ { Rect r, r2; int xoffset, yoffset; Point p; Point pLL, pUR; Tile *stitch; char string[20]; int i, pos; TiToRect(tile, &r2); /* Some of the tiles have "infinite sizes", which we have to clip * in order to avoid numerical problems. */ GeoClip(&r2, &dbwWatchArea); pLL = r2.r_ll; pUR = r2.r_ur; GeoTransRect(&dbwWatchTrans, &r2, &r); WindSurfaceToScreen(dbwWindow, &r, &r2); /* Draw the tile, then put up text for the tile's address and * stitches. */ (void) GrClipBox(&r2, STYLE_DRAWTILE); GeoTransPoint(&dbwWatchTrans, &pLL, &p); WindPointToScreen(dbwWindow, &p, &pLL); GeoTransPoint(&dbwWatchTrans, &pUR, &p); WindPointToScreen(dbwWindow, &p, &pUR); GeoClipPoint(&pLL, &rootClip); GeoClipPoint(&pUR, &rootClip); if (dbwSeeTypes) { (void) sprintf(string, "%s",DBTypeShortName(TiGetType(tile))); } else { (void) sprintf(string, "%p", (void *) tile); } GeoClip(&r2, &rootClip); p.p_x = (r2.r_xbot + r2.r_xtop)/2; p.p_y = (r2.r_ybot + r2.r_ytop)/2; if (!dbwWatchDemo || dbwSeeTypes) GrPutText(string, STYLE_DRAWTILE, &p, GEO_CENTER, GR_TEXT_LARGE, FALSE, &r2, (Rect *) NULL); #define XYOFFSET 12 for (i=0; i<4; i++) { xoffset = 0; yoffset = 0; switch (i) { case 0: stitch = BL(tile); p = pLL; yoffset = XYOFFSET; pos = GEO_NORTHEAST; break; case 1: stitch = LB(tile); p = pLL; xoffset = XYOFFSET; pos = GEO_NORTHEAST; break; case 2: stitch = RT(tile); p = pUR; xoffset = -XYOFFSET; pos = GEO_SOUTHWEST; break; case 3: stitch = TR(tile); p = pUR; yoffset = -XYOFFSET; pos = GEO_SOUTHWEST; break; } pos = GeoTransPos(&dbwWatchTrans, pos); if (dbwWatchTrans.t_a == 0) { /* a rotation by 90 or 270 */ int temp; temp = xoffset; xoffset = yoffset; yoffset = temp; } if ( (dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0) ) { /* mirror in x */ xoffset = -xoffset; } if ( (dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0) ) { /* mirror in y */ yoffset = -yoffset; } p.p_x += xoffset; p.p_y += yoffset; if (dbwWatchDemo) { Rect stick, head, head2; stick.r_ll = p; stick.r_ur = p; #define TAIL 5 #define HEAD 9 switch (i) { case 0: stick.r_xbot -= HEAD; stick.r_xtop += TAIL; head = stick; head.r_xbot++; head.r_xtop = head.r_xbot; head.r_ytop++; head.r_ybot--; head2 = head; head2.r_xbot++; head2.r_xtop++; head2.r_ytop++; head2.r_ybot--; break; case 1: stick.r_ybot -= HEAD; stick.r_ytop += TAIL; head = stick; head.r_ybot++; head.r_ytop = head.r_ybot; head.r_xtop++; head.r_xbot--; head2 = head; head2.r_xbot--; head2.r_xtop++; head2.r_ytop++; head2.r_ybot++; break; case 2: stick.r_ybot -= TAIL; stick.r_ytop += HEAD; head = stick; head.r_ytop--; head.r_ybot = head.r_ytop; head.r_xtop++; head.r_xbot--; head2 = head; head2.r_xbot--; head2.r_xtop++; head2.r_ytop--; head2.r_ybot--; break; case 3: stick.r_xbot -= TAIL; stick.r_xtop += HEAD; head = stick; head.r_xtop--; head.r_xbot = head.r_xtop; head.r_ytop++; head.r_ybot--; head2 = head; head2.r_xbot--; head2.r_xtop--; head2.r_ytop++; head2.r_ybot--; break; } GrClipBox(&stick, STYLE_LABEL); GrClipBox(&head, STYLE_LABEL); GrClipBox(&head2, STYLE_LABEL); } else if (!dbwSeeTypes) { (void) sprintf(string, "%p", (void *) stitch); GrPutText(string, STYLE_DRAWTILE, &p, pos, GR_TEXT_SMALL, FALSE, &r2, (Rect *) NULL); } } return 0; } /* * ---------------------------------------------------------------------------- * DBWAreaChanged -- * * Invoked to remind us that a certain piece of a certain cell * has been modified and must eventually be redisplayed. * * Results: * None. * * Side effects: * Information is remembered, so that when WindUpdate is called * the area will be redisplayed in every window where it appears. * * ---------------------------------------------------------------------------- */ static TileTypeBitMask *dbwLayersChanged; /* DBWAreaChanged's "layers" parameter. */ void DBWAreaChanged(cellDef, defArea, expandMask, layers) CellDef *cellDef; /* The cell definition that was modified. */ Rect *defArea; /* The area of the definition that changed. */ int expandMask; /* We're only interested these windows. * Use DBW_ALLWINDOWS for all windows. */ TileTypeBitMask *layers; /* Indicates which layers were modified. If * NULL, it means that labels were deleted * from defArea in addition to paint. We'll * have to redisplay a larger area in order * to fully erase labels that used to stick * out from defArea. NULL is used when * subcells are unexpanded or moved for * example. NULL is the most inclusive option * (does everything that &DBAllButSpaceBits * does and more), and should be used whenever * you're not sure what to do. Note: it's * normally better to use DBWLabelChanged when * individual labels are modified; the NULL * option is for when large numbers of labels * have potentially been modified. */ { Rect newArea; /* Corresponding area in parent. */ int newMask; /* Windows we're interested in in parent. */ int x, y, xlo, ylo; /* Array indices. */ int xhi, yhi; Rect tmp; CellUse *use; if ((defArea->r_xbot == defArea->r_xtop) || (defArea->r_ybot == defArea->r_ytop)) return; /** TxPrintf("Cell %s, area (%d, %d) (%d, %d) changed, mask %d.\n", cellDef->cd_name, defArea->r_xbot, defArea->r_ybot, defArea->r_xtop, defArea->r_ytop, expandMask); **/ /* Don't permit signals to interrupt us here. */ SigDisableInterrupts(); /* First, translate the area back up through the hierarchy to * cells that are roots of windows. */ for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse) { /* We're only interested in a use if it's expanded in one of * the windows of expandMask. Our new expand mask is the * AND of the old one and the windows in which this use is * expanded. */ newMask = expandMask & use->cu_expandMask; if (newMask == 0) continue; /* If this use has no parents, it might be the root of a window. * If so, log the area in the window. */ if (use->cu_parent == NULL) { dbwLayersChanged = layers; (void) WindSearch((ClientData) DBWclientID, (ClientData) use, defArea, dbwChangedFunc, (ClientData) defArea); continue; } /* This use isn't a root use. If it isn't an array use, just * translate the area back into the coordinates of the parent * and invoke ourselves recursively. */ if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi)) { GeoTransRect(&use->cu_transform, defArea, &newArea); DBWAreaChanged(use->cu_parent, &newArea, newMask, layers); continue; } /* This is an array. If the area to be redisplayed is a * substantial fraction of the total area of the array, * just redisplay the whole array. Otherwise redisplay * the individual elements. */ if ((2*(defArea->r_xtop - defArea->r_xbot) > (cellDef->cd_bbox.r_xtop - cellDef->cd_bbox.r_xbot)) || (2*(defArea->r_ytop - defArea->r_ybot) > (cellDef->cd_bbox.r_ytop - cellDef->cd_bbox.r_ybot))) { DBComputeArrayArea(defArea, use, use->cu_xlo, use->cu_ylo, &newArea); DBComputeArrayArea(defArea, use, use->cu_xhi, use->cu_yhi, &tmp); (void) GeoInclude(&newArea, &tmp); GeoTransRect(&use->cu_transform, &tmp, &newArea); DBWAreaChanged(use->cu_parent, &newArea, newMask, layers); } else { if (use->cu_xlo > use->cu_xhi) { xlo = use->cu_xhi; xhi = use->cu_xlo; } else { xlo = use->cu_xlo; xhi = use->cu_xhi; } if (use->cu_ylo > use->cu_yhi) { ylo = use->cu_yhi; yhi = use->cu_ylo; } else { ylo = use->cu_ylo; yhi = use->cu_yhi; } for (y = ylo ; y <= yhi; y++) for (x = xlo; x <= xhi; x++) { DBComputeArrayArea(defArea, use, x, y, &tmp); GeoTransRect(&use->cu_transform, &tmp, &newArea); DBWAreaChanged(use->cu_parent, &newArea, newMask, layers); } } } SigEnableInterrupts(); } /* * ---------------------------------------------------------------------------- * * dbwChangedFunc -- * * This function is invoked by WindSearch under control of * DBWAreaChanged. It notifies the window manager to redisplay * an area of a window. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * An area to be redisplayed is recorded. * * ---------------------------------------------------------------------------- */ int dbwChangedFunc(w, area) MagWindow *w; /* Window in which to record area. */ Rect *area; /* (Client data) Area to be redisplayed, in * coordinates of the root definition. */ { Rect screenArea; TileTypeBitMask tmp; DBWclientRec *crec = (DBWclientRec *) w->w_clientData; /* If none of the layers being redisplayed is visible in this * window, then there's no need to do anything. */ if (dbwLayersChanged != NULL) { TTMaskAndMask3(&tmp, dbwLayersChanged, &crec->dbw_visibleLayers); if (TTMaskIsZero(&tmp)) return 0; } /* Compute screen area to redisplay, in pixels. */ WindSurfaceToScreen(w, area, &screenArea); GeoClip(&screenArea, &w->w_screenArea); /* If labels are being redisplayed, expand the redisplay area * to account for labels that are rooted in the given area but * stick out past it. */ if (dbwLayersChanged == NULL) { screenArea.r_xbot += crec->dbw_expandAmounts.r_xbot; screenArea.r_ybot += crec->dbw_expandAmounts.r_ybot; screenArea.r_xtop += crec->dbw_expandAmounts.r_xtop; screenArea.r_ytop += crec->dbw_expandAmounts.r_ytop; } else if (GrPixelCorrect == 0) { /* Correct for OpenGL coordinate system */ screenArea.r_xbot--; screenArea.r_ybot--; screenArea.r_xtop++; screenArea.r_ytop++; } /* If watching is enabled for this window, so sorry but the whole * thing will have to be redisplayed (even a small change could have * affected many many tiles. */ if (crec->dbw_watchPlane >= 0) WindAreaChanged(w, (Rect *) NULL); else WindAreaChanged(w, &screenArea); return 0; } /* * ---------------------------------------------------------------------------- * * DBWLabelChanged -- * * This procedure is invoked when a label has been created or * deleted. It figures out which areas to redisplay in order * to make sure that the label is completely redrawn. * * Results: * None. * * Side effects: * The list of areas to be redisplayed is modified. * * ---------------------------------------------------------------------------- */ /* The following stuff is shared by the procedures below. */ extern int dbwLabelChangedFunc(); /* Function to call for each label. */ void DBWLabelChanged(cellDef, lab, mask) CellDef *cellDef; /* Cell definition containing label. */ Label *lab; /* The label structure */ int mask; /* Mask of windows where changes should be * reflected (DBW_ALLWINDOWS selects all * windows, and is usually the right value.) */ { CellUse *use; Rect saveArea, tmp; int newMask, savePos; int x, y, xlo, ylo, xhi, yhi; /* This procedure is basically the same as DBWAreaChanged, so * see that procedure for documentation on how this all works. */ saveArea = lab->lab_rect; savePos = lab->lab_just; SigDisableInterrupts(); for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse) { newMask = mask & use->cu_expandMask; if (newMask == 0) continue; if (use->cu_parent == NULL) { /* Got the root use for a window. Find the relevant windows * and do the rest of the processing on a per-window basis. */ (void) WindSearch((ClientData) DBWclientID, (ClientData) use, (Rect *) NULL, dbwLabelChangedFunc, (ClientData) lab); continue; } if (use->cu_xlo > use->cu_xhi) { xlo = use->cu_xhi; xhi = use->cu_xlo; } else { xlo = use->cu_xlo; xhi = use->cu_xhi; } if (use->cu_ylo > use->cu_yhi) { ylo = use->cu_yhi; yhi = use->cu_ylo; } else { ylo = use->cu_ylo; yhi = use->cu_yhi; } for (y = ylo; y <= yhi; y++) for (x = xlo; x <= xhi; x++) { DBComputeArrayArea(&lab->lab_rect, use, x, y, &tmp); GeoTransRect(&use->cu_transform, &tmp, &lab->lab_rect); lab->lab_just = GeoTransPos(&use->cu_transform, lab->lab_just); DBWLabelChanged(use->cu_parent, lab, newMask); } } lab->lab_rect = saveArea; lab->lab_just = savePos; SigEnableInterrupts(); } int dbwLabelChangedFunc(w, lab) MagWindow *w; /* Window in which label is displayed. */ Label *lab; /* Label being changed. */ { Rect screenArea, textArea; int size; if (lab->lab_font < 0) { WindSurfaceToScreen(w, &lab->lab_rect, &screenArea); size = ((DBWclientRec *) w->w_clientData)->dbw_labelSize; if (size < GR_TEXT_SMALL) textArea = GrCrossRect; else { GrLabelSize(lab->lab_text, lab->lab_just, size, &textArea); (void) GeoInclude(&GrCrossRect, &textArea); } screenArea.r_xbot += textArea.r_xbot; screenArea.r_ybot += textArea.r_ybot; screenArea.r_xtop += textArea.r_xtop; screenArea.r_ytop += textArea.r_ytop; } else { WindSurfaceToScreen(w, &lab->lab_bbox, &screenArea); } WindAreaChanged(w, &screenArea); return 0; } /* * Technology initialization for the display module. */ global TileTypeBitMask *DBWStyleToTypesTbl = NULL; /* * ---------------------------------------------------------------------------- * DBWTechInitStyles -- * * Initialize the display module's technology dependent variables. * * Results: * None. * * Side effects: * Clears the display module's technology dependent information. * ---------------------------------------------------------------------------- */ void DBWTechInitStyles() { int i; if (DBWNumStyles == 0) { TxError("Error: Attempting to define tech styles before reading " "dstyle file!\n"); return; } if (DBWStyleToTypesTbl != NULL) freeMagic(DBWStyleToTypesTbl); DBWStyleToTypesTbl = (TileTypeBitMask *)mallocMagic(DBWNumStyles * sizeof(TileTypeBitMask)); for (i = 0; i < DBWNumStyles; i++) TTMaskZero(DBWStyleToTypesTbl + i); } /* * ---------------------------------------------------------------------------- * * DBWTechParseStyle -- * * Turn a style entry (either a style number or name) into an index * into the styles array. * * Results: Index into the DBW styles table, or -1 if no style found. * * Side Effects: None. * * ---------------------------------------------------------------------------- */ int DBWTechParseStyle(stylestr) char *stylestr; { int sidx, style; if (StrIsInt(stylestr)) { style = atoi(stylestr); for (sidx = 0; sidx < DBWNumStyles; sidx++) if (GrStyleTable[sidx + TECHBEGINSTYLES].idx == style) break; } else { for (sidx = 0; sidx < DBWNumStyles; sidx++) if (!strcmp(GrStyleTable[sidx + TECHBEGINSTYLES].longname, stylestr)) break; } if (sidx >= DBWNumStyles) return -1; else return sidx; } /* * ---------------------------------------------------------------------------- * DBWTechAddStyle -- * * Add a new entry to the style tables. * * Results: * TRUE if successful, FALSE on error. * * Side effects: * Updates the display module's technology variables. * ---------------------------------------------------------------------------- */ bool DBWTechAddStyle(sectionName, argc, argv) char *sectionName; int argc; char *argv[]; { TileType t, r; TileTypeBitMask *rMask; int i, sidx; static char styleType[50]; char *pathptr; if (argc < 2) { TechError("Badly formed line in \"style\" section\n"); } else if (strcmp(argv[0], "styletype") == 0) { (void) strncpy(styleType, argv[1], 49); styleType[49] = 0; DBWStyleType = styleType; /* Optional 3rd and higher arguments are pathnames */ for (i = 2; i <= argc; i++) { if (i == argc) pathptr = SysLibPath; else pathptr = argv[i]; /* Learning the style type precipitates immediate reading */ /* of the color map and style files. */ if (GrReadCMap(DBWStyleType, (char *)NULL, MainMonType, ".", pathptr)) break; } if (i > argc) return FALSE; if (GrLoadStyles(DBWStyleType, ".", pathptr) != 0) return FALSE; DBWTechInitStyles(); if (!GrLoadCursors(".", pathptr)) return FALSE; GrSetCursor(0); } else { if ((t = DBTechNoisyNameType(argv[0])) < 0) return (FALSE); /* Allow space-separated list of styles for each type */ for (i = 1; i < argc; i++) { sidx = DBWTechParseStyle(argv[i]); if (sidx < 0) TechError("Invalid style \"%s\" for tile type %s\n", argv[i], argv[0]); else { TTMaskSetType(&DBWStyleToTypesTbl[sidx], t); /* If type t is a contact, then any stacked contact type which */ /* has t as a residue, and for which the home plane of the */ /* stacked contact is also the home plane of t, should be added */ /* to the list of types to be painted with this style. */ if (DBIsContact(t) && (t < DBNumUserLayers)) for (r = DBNumUserLayers; r < DBNumTypes; r++) { rMask = DBResidueMask(r); if (TTMaskHasType(rMask, t) && (DBPlane(r) == DBPlane(t))) TTMaskSetType(&DBWStyleToTypesTbl[sidx], r); } } } } return TRUE; }