magic/dbwind/DBWdisplay.c

1803 lines
50 KiB
C
Raw Normal View History

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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
{
2025-01-06 17:12:11 +01:00
(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)
{
2025-01-06 17:12:11 +01:00
(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;
}