/* DBWelement.c - * * * This file provides a standard set of procedures for Magic * commands to use to handle drawing of various elements on * top of the layout. Elements can be lines, rectangles, * and text (and hopefully will be expanded to include polygons * and arcs). These operate very similarly to feedback regions, * in that they are persistant until destroyed, and do not * interact with the layout in any way. * * Copyright (C) 2003 Open Circuit Design, Inc., for MultiGiG, Ltd. */ #include #include #include #include "tcltk/tclmagic.h" #include "utils/magic.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 "utils/styles.h" #include "utils/malloc.h" #include "utils/signals.h" /* C99 compat */ #include "textio/textio.h" /* Types of elements */ #define ELEMENT_RECT 0 #define ELEMENT_LINE 1 #define ELEMENT_TEXT 2 /* Linked list definition for styles */ typedef struct _style *styleptr; typedef struct _style { int style; styleptr next; } stylestruct; /* Each element is stored in a record that looks like this: */ typedef struct _element { int type; /* Type of element (see list above) */ unsigned char flags; /* Special flags (depends on element type) */ CellDef *rootDef; /* Root definition of windows in which to * display this element. */ stylestruct *stylelist; /* Linked list of display styles with which * to paint this element. There must be at * least one style, so first one is hardwired. */ Rect area; /* The area of a rectangle element, * or the two points of a line element, * or the area box of a text element. */ char *text; /* The text of a text element, or NULL. */ } DBWElement; /* The following stuff describes all the feedback information we know * about. The feedback is stored in a big array that grows whenever * necessary. */ HashTable elementTable; /* Hash table holding elements info */ static CellDef *dbwelemRootDef; /* To pass root cell definition from * dbwelemGetTransform back up to * DBWElementAdd. */ /* * ---------------------------------------------------------------------------- * * AppendString --- * * Support function for DBWPrintElements(). Allocates memory for and * adds string "newstr" to the string pointed to by "oldstr". If * "postfix" is non-NULL, this is also appended to "oldstr". * * Results: * None. * * Side effects: * Memory reallocation of *oldstr. * * ---------------------------------------------------------------------------- */ void AppendString(oldstr, newstr, postfix) char **oldstr; const char *newstr; const char *postfix; { char *tmpstr; int olen = 0; int nlen = strlen(newstr); int plen = 0; if (*oldstr != NULL) olen = strlen(*oldstr); if (postfix != NULL) plen = strlen(postfix); tmpstr = (char *)mallocMagic(olen + nlen + plen + 1); if (*oldstr == NULL) strcpy(tmpstr, newstr); else { strcpy(tmpstr, *oldstr); strcat(tmpstr, newstr); freeMagic(*oldstr); } if (postfix != NULL) strcat(tmpstr, postfix); *oldstr = tmpstr; } /* * ---------------------------------------------------------------------------- * * AppendFlag -- * * Support function for DBWPrintElements to assist in generating * the string of comma-separated flags for each element printed * to the output. * * Results: * None. * * Side Effects: * Space is allocated and text added to "rstr". The pointer to * boolean "flagset" is set to TRUE, indicating that at least one * flag has been written to the output. * * ---------------------------------------------------------------------------- */ void AppendFlag( char **rstr, bool *flagset, const char *fname) { AppendString(rstr, *flagset ? "," : " ", fname); *flagset = TRUE; } /* * ---------------------------------------------------------------------------- * * DBWPrintElements -- * * Generate a string containing the names of all elements which are * defined in CellDef "cellDef" and have flags matching "flagmask". * Format is appropriate for writing output to a .mag file. * * Results: * An allocated string, or NULL if no elements were found. * * Side Effects: * Memory is allocated for the string and must be freed by the calling * procedure. * ---------------------------------------------------------------------------- */ char * DBWPrintElements(cellDef, flagmask, reducer) CellDef *cellDef; unsigned char flagmask; int reducer; { DBWElement *elem; HashSearch hs; HashEntry *he; char *rstr = NULL; /* allocated return string */ char istr[10]; styleptr sptr; bool flagset; /* These must match the order of text sizes in graphics/graphics.h */ static char *textSizes[] = {"small", "medium", "large", "xlarge", "default", NULL}; /* These must match the order of element type definitions above! */ char *etypes[] = {"rectangle", "line", "text"}; HashStartSearch(&hs); while ((he = HashNext(&elementTable, &hs))) { if ((elem = (DBWElement *)HashGetValue(he))) { if ((elem->rootDef == cellDef) && (elem->flags & flagmask)) { /* print element type */ AppendString(&rstr, etypes[elem->type], " "); /* print element name */ AppendString(&rstr, (char *)he->h_key.h_name, " "); /* print dstyle(s) */ for (sptr = elem->stylelist; sptr != NULL; sptr = sptr->next) AppendString(&rstr, GrStyleTable[sptr->style].longname, ((sptr->next == NULL) ? " " : ",")); /* print start point */ sprintf(istr, "%d", elem->area.r_xbot / reducer); AppendString(&rstr, istr, " "); sprintf(istr, "%d", elem->area.r_ybot / reducer); AppendString(&rstr, istr, " "); switch (elem->type) { case ELEMENT_RECT: /* end point */ sprintf(istr, "%d", elem->area.r_xtop / reducer); AppendString(&rstr, istr, " "); sprintf(istr, "%d", elem->area.r_ytop / reducer); AppendString(&rstr, istr, "\n"); /* no flags to write. Only applicable flag is */ /* temporary/persistent, and temporary elements */ /* don't get written to the file. */ break; case ELEMENT_LINE: /* end point */ sprintf(istr, "%d", elem->area.r_xtop / reducer); AppendString(&rstr, istr, " "); sprintf(istr, "%d", elem->area.r_ytop / reducer); AppendString(&rstr, istr, NULL); /* any non-default flags? */ flagset = FALSE; if (elem->flags & DBW_ELEMENT_LINE_HALFX) AppendFlag(&rstr, &flagset, "halfx"); if (elem->flags & DBW_ELEMENT_LINE_HALFY) AppendFlag(&rstr, &flagset, "halfy"); if (elem->flags & DBW_ELEMENT_LINE_ARROWL) AppendFlag(&rstr, &flagset, "arrowleft"); if (elem->flags & DBW_ELEMENT_LINE_ARROWR) AppendFlag(&rstr, &flagset, "arrowright"); AppendString(&rstr, "\n", NULL); break; case ELEMENT_TEXT: /* label text */ AppendString(&rstr, "\"", NULL); AppendString(&rstr, elem->text, NULL); AppendString(&rstr, "\"", NULL); /* any non-default flags? */ flagset = FALSE; if (((elem->flags & DBW_ELEMENT_TEXT_POS) >> 4) != GEO_CENTER) AppendFlag(&rstr, &flagset, GeoPosToName((elem->flags & DBW_ELEMENT_TEXT_POS) >> 4)); if (((elem->flags & DBW_ELEMENT_TEXT_SIZE) >> 1) != GR_TEXT_MEDIUM) AppendFlag(&rstr, &flagset, textSizes[(elem->flags & DBW_ELEMENT_TEXT_SIZE) >> 1]); AppendString(&rstr, "\n", NULL); break; } } } } return rstr; } /* * ---------------------------------------------------------------------------- * * DBWScaleElements -- * * Scale each element by the given integer numerator and denominator * * Results: * None. * * Side Effects: * Element values are modified. * ---------------------------------------------------------------------------- */ void DBWScaleElements(n, d) int n, d; { DBWElement *elem; HashSearch hs; HashEntry *he; extern bool DBScalePoint(); /* Forward declaration */ HashStartSearch(&hs); while ((he = HashNext(&elementTable, &hs))) { if ((elem = (DBWElement *)HashGetValue(he))) { /* scale area rectangle */ DBScalePoint(&elem->area.r_ll, n, d); DBScalePoint(&elem->area.r_ur, n, d); } } } /* * ---------------------------------------------------------------------------- * * DBWElementRedraw -- * * This procedure is called by the highlight manager to redisplay * feedback highlights. The window is locked before entry. * * Results: * None. * * Side effects: * Any feedback information that overlaps a non-space tile in * plane is redrawn. * * Tricky stuff: * Redisplay is numerically difficult, particularly when feedbacks * have a large internal scale factor: the tendency is to get * integer overflow and get everything goofed up. Be careful * when making changes to the code below. * * ---------------------------------------------------------------------------- */ void DBWElementRedraw(window, plane) MagWindow *window; /* Window in which to redraw. */ Plane *plane; /* Non-space tiles on this plane mark what * needs to be redrawn. */ { int curStyle, newStyle; styleptr stylePtr; CellDef *windowRoot; Rect screenArea; DBWElement *elem; HashSearch hs; HashEntry *entry; Point p; windowRoot = ((CellUse *) (window->w_surfaceID))->cu_def; curStyle = -1; HashStartSearch(&hs); while ((entry = HashNext(&elementTable, &hs)) != NULL) { elem = (DBWElement *) HashGetValue(entry); if (!elem) continue; else if (elem->rootDef != windowRoot) continue; /* Transform the feedback area to screen coords. This is * very similar to the code in WindSurfaceToScreen, except * that there's additional scaling involved. */ WindSurfaceToScreenNoClip(window, &elem->area, &screenArea); /* Deal with half-point-offset flags for the line element */ if ((elem->type == ELEMENT_LINE) && (elem->flags & (DBW_ELEMENT_LINE_HALFX | DBW_ELEMENT_LINE_HALFY))) { static Rect unitArea = {{0, 0}, {1, 1}}; Rect transArea; int offx, offy; WindSurfaceToScreenNoClip(window, &unitArea, &transArea); offx = (transArea.r_xtop - transArea.r_xbot) >> 1; offy = (transArea.r_ytop - transArea.r_ybot) >> 1; if (elem->flags & DBW_ELEMENT_LINE_HALFX) { screenArea.r_xbot += offx; screenArea.r_xtop += offx; } if (elem->flags & DBW_ELEMENT_LINE_HALFY) { screenArea.r_ybot += offy; screenArea.r_ytop += offy; } } if ((screenArea.r_xbot <= screenArea.r_xtop) && (screenArea.r_ybot <= screenArea.r_ytop)) { for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next) { newStyle = stylePtr->style; if (newStyle != curStyle) { curStyle = newStyle; GrSetStuff(curStyle); } switch (elem->type) { case ELEMENT_RECT: GrFastBox(&screenArea); break; case ELEMENT_TEXT: p.p_x = screenArea.r_xbot; p.p_y = screenArea.r_ybot; GrPutText(elem->text, curStyle, &p, ((elem->flags & DBW_ELEMENT_TEXT_POS) >> 4), ((elem->flags & DBW_ELEMENT_TEXT_SIZE) >> 1), FALSE, &(window->w_screenArea), (Rect *)NULL); break; case ELEMENT_LINE: GrClipLine(screenArea.r_xbot, screenArea.r_ybot, screenArea.r_xtop, screenArea.r_ytop); /* Draw arrowheads on endpoints, if flags are set */ if (elem->flags & (DBW_ELEMENT_LINE_ARROWL | DBW_ELEMENT_LINE_ARROWR)) { static Rect unitArea = {{0, 0}, {1, 1}}; Rect transArea; Point polyp[4]; double theta, r; int i, offx, offy; WindSurfaceToScreenNoClip(window, &unitArea, &transArea); offx = (transArea.r_xtop - transArea.r_xbot) >> 1; offy = (transArea.r_ytop - transArea.r_ybot) >> 1; WindSurfaceToScreenNoClip(window, &elem->area, &screenArea); if (elem->flags & DBW_ELEMENT_LINE_HALFX) { screenArea.r_xbot += offx; screenArea.r_xtop += offx; } if (elem->flags & DBW_ELEMENT_LINE_HALFY) { screenArea.r_ybot += offy; screenArea.r_ytop += offy; } theta = atan2((double)(screenArea.r_ytop - screenArea.r_ybot), (double) (screenArea.r_xtop - screenArea.r_xbot)); r = (double)(transArea.r_xtop - transArea.r_xbot); if (elem->flags & DBW_ELEMENT_LINE_ARROWL) { for (i = 0; i < 4; i++) { polyp[i].p_x = screenArea.r_xbot; polyp[i].p_y = screenArea.r_ybot; } polyp[1].p_x += (int)(r * cos(theta + 0.2)); polyp[1].p_y += (int)(r * sin(theta + 0.2)); polyp[2].p_x += (int)(r * 0.9 * cos(theta)); polyp[2].p_y += (int)(r * 0.9 * sin(theta)); polyp[3].p_x += (int)(r * cos(theta - 0.2)); polyp[3].p_y += (int)(r * sin(theta - 0.2)); GrFillPolygon(polyp, 4); } if (elem->flags & DBW_ELEMENT_LINE_ARROWR) { for (i = 0; i < 4; i++) { polyp[i].p_x = screenArea.r_xtop; polyp[i].p_y = screenArea.r_ytop; } polyp[1].p_x -= (int)(r * cos(theta + 0.2)); polyp[1].p_y -= (int)(r * sin(theta + 0.2)); polyp[2].p_x -= (int)(r * 0.9 * cos(theta)); polyp[2].p_y -= (int)(r * 0.9 * sin(theta)); polyp[3].p_x -= (int)(r * cos(theta - 0.2)); polyp[3].p_y -= (int)(r * sin(theta - 0.2)); GrFillPolygon(polyp, 4); } } break; } } } } } /* * ---------------------------------------------------------------------------- * * DBWElementUndraw -- * * Paint the element in style ERASE_ALL to erase it. * * ---------------------------------------------------------------------------- */ void dbwElementUndraw(mw, elem) MagWindow *mw; DBWElement *elem; /* The element to erase */ { CellDef *windowRoot; Rect screenArea, textArea; if (mw == NULL) return; /* No window; can't undraw */ windowRoot = ((CellUse *) (mw->w_surfaceID))->cu_def; GrLock(mw, TRUE); /* Deal with half-point-offset flags for the line element */ /* by enlarging the area by 1 unit. */ if ((elem->type == ELEMENT_LINE) && (elem->flags & (DBW_ELEMENT_LINE_HALFX | DBW_ELEMENT_LINE_HALFY))) { Rect newArea = elem->area; if (elem->flags & DBW_ELEMENT_LINE_HALFX) newArea.r_xtop++; if (elem->flags & DBW_ELEMENT_LINE_HALFY) newArea.r_ytop++; WindSurfaceToScreen(mw, &newArea, &screenArea); } else WindSurfaceToScreen(mw, &elem->area, &screenArea); /* For text, determine the size of the text and expand the */ /* screenArea rectangle accordingly. */ if (elem->type == ELEMENT_TEXT) { int tpos = (elem->flags & DBW_ELEMENT_TEXT_POS) >> 4; int tsize = (elem->flags & DBW_ELEMENT_TEXT_SIZE) >> 1; GrLabelSize(elem->text, tpos, tsize, &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; } if ((screenArea.r_xbot <= screenArea.r_xtop) && (screenArea.r_ybot <= screenArea.r_ytop)) { GrSetStuff(STYLE_ERASEALL); GrFastBox(&screenArea); WindAreaChanged(mw, &screenArea); } GrUnlock(mw, TRUE); } /* * ---------------------------------------------------------------------------- * * DBWElementDelete -- * * This procedure deletes an element. * * Results: * None. * * Side effects: * An element is found in the hash table by name, and if it exists, * it is deleted. * * ---------------------------------------------------------------------------- */ void DBWElementDelete(MagWindow *w, char *name) { DBWElement *elem; CellDef *currentRoot; HashEntry *entry; styleptr stylePtr; entry = HashFind(&elementTable, name); if (entry == NULL) return; elem = (DBWElement *)HashGetValue(entry); if (elem == NULL) return; dbwElementUndraw(w, elem); /* mark element's cell as having been modified */ if (elem->flags & DBW_ELEMENT_PERSISTENT) elem->rootDef->cd_flags |= CDMODIFIED; for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next) { freeMagic(stylePtr); } if (elem->type == ELEMENT_TEXT) freeMagic(elem->text); HashSetValue(entry, NULL); freeMagic(elem); /* Area of elem->area is set to be updated by dbwElementUndraw(). */ /* Can't do WindUpdate(), though, until the hash table entry is */ /* removed, or DBWdisplay will try to draw it again. */ WindUpdate(); } /* * Initialize the Element hash table. */ void dbwElementInit() { HashInit(&elementTable, 10, HT_STRINGKEYS); DBWHLAddClient(DBWElementRedraw); } /* * ---------------------------------------------------------------------------- * * DBWElementNames -- * * Go through the hash table and print the names of all elements * * ---------------------------------------------------------------------------- */ void DBWElementNames() { DBWElement *elem; HashSearch hs; HashEntry *he; #ifndef MAGIC_WRAPPER TxPrintf("Known elements:"); #endif HashStartSearch(&hs); while ((he = HashNext(&elementTable, &hs))) { if ((elem = (DBWElement *)HashGetValue(he))) { #ifdef MAGIC_WRAPPER Tcl_AppendElement(magicinterp, he->h_key.h_name); #else TxPrintf(" %s", he->h_key.h_name); #endif } } #ifndef MAGIC_WRAPPER TxPrintf("/n"); #endif } /* * ---------------------------------------------------------------------------- * * DBWElementInbox -- * * Find the element that is nearest the box. * * ---------------------------------------------------------------------------- */ void DBWElementInbox(area) Rect *area; { DBWElement *elem; HashSearch hs; HashEntry *he; int sqdist; #ifndef MAGIC_WRAPPER TxPrintf("Element(s) inside box: "); #endif HashStartSearch(&hs); while ((he = HashNext(&elementTable, &hs))) { if ((elem = (DBWElement *)HashGetValue(he))) { if (GEO_SURROUND(area, &elem->area)) { #ifdef MAGIC_WRAPPER Tcl_AppendElement(magicinterp, he->h_key.h_name); #else TxPrintf(" %s", he->h_key.h_name); #endif } } } #ifndef MAGIC_WRAPPER TxPrintf("/n"); #endif } /* * ---------------------------------------------------------------------------- * * DBWElementAdd* -- * * Adds a new element to the element hash table. * * Results: * None, except * DBWElementAdd(): returns Pointer to a DBWElement structure. * * Side effects: * CellDef's ancestors are searched until its first root definition * is found, and the coordinates of area are transformed into the * root. Then the area is added to the element structure. * This stuff will be displayed on the screen at the end of the * current command. * ---------------------------------------------------------------------------- */ /* Set up everything is generic to all element types */ DBWElement * DBWElementAdd(w, name, area, cellDef, style) MagWindow *w; char *name; /* Name of this element for the hash table */ Rect *area; /* The area of the element */ CellDef *cellDef; /* The cellDef in whose coordinates area * is given. */ int style; /* An initial display style to use */ { Transform transform; DBWElement *elem; HashEntry *entry; extern int dbwelemGetTransform(); /* Forward declaration. */ /* Find a transform from this cell to the root, and use it to * transform the area. If the root isn't an ancestor, just * return. */ if (!DBSrRoots(cellDef, &GeoIdentityTransform, dbwelemGetTransform, (ClientData) &transform)) if (w != NULL) return NULL; /* SigInterruptPending screws up DBSrRoots */ if (SigInterruptPending) return NULL; /* If there is already an entry by this name, delete it */ DBWElementDelete(w, name); entry = HashFind(&elementTable, name); elem = (DBWElement *)mallocMagic(sizeof(DBWElement)); HashSetValue(entry, elem); GeoCanonicalRect(area, &elem->area); elem->stylelist = (styleptr)mallocMagic(sizeof(stylestruct)); elem->stylelist->style = style; elem->stylelist->next = NULL; /* For .mag file loads, w will be NULL and cellDef will be */ /* the root. */ if (w == NULL) elem->rootDef = cellDef; else elem->rootDef = dbwelemRootDef; elem->text = NULL; elem->flags = 0; return elem; } void DBWElementAddRect(w, name, area, cellDef, style) MagWindow *w; char *name; /* Name of this element for the hash table */ Rect *area; /* The area to be highlighted. */ CellDef *cellDef; /* The cellDef in whose coordinates area * is given. */ int style; /* An initial display style to use */ { DBWElement *elem; elem = DBWElementAdd(w, name, area, cellDef, style); if (elem == NULL) return; elem->type = ELEMENT_RECT; } void DBWElementAddLine(w, name, area, cellDef, style) MagWindow *w; char *name; /* Name of this element for the hash table */ Rect *area; /* The area to be highlighted. */ CellDef *cellDef; /* The cellDef in whose coordinates area * is given. */ int style; /* An initial display style to use */ { DBWElement *elem; elem = DBWElementAdd(w, name, area, cellDef, style); if (elem == NULL) return; elem->type = ELEMENT_LINE; } void DBWElementAddText(w, name, x, y, text, cellDef, style) MagWindow *w; char *name; /* Name of this element for the hash table */ int x, y; /* Point of origin (x, y coordinates) */ char *text; /* The text of the label */ CellDef *cellDef; /* The cellDef in whose coordinates area * is given. */ int style; /* An initial display style to use */ { DBWElement *elem; Rect area; area.r_xbot = x; area.r_xtop = x; area.r_ybot = y; area.r_ytop = y; elem = DBWElementAdd(w, name, &area, cellDef, style); if (elem == NULL) return; elem->type = ELEMENT_TEXT; elem->text = StrDup((char **)NULL, text); elem->flags |= (GEO_CENTER << 4); /* default centered */ elem->flags |= (GR_TEXT_MEDIUM << 1); /* default medium size */ } /* This utility procedure is invoked by DBSrRoots. Save the root definition * in dbwRootDef, save the transform in the argument, and abort the search. * Make sure that the root we pick is actually displayed in a window * someplace (there could be root cells that are no longer displayed * anywhere). */ int dbwelemGetTransform(use, transform, cdarg) CellUse *use; /* A root use that is an ancestor * of cellDef in DBWElementAdd. */ Transform *transform; /* Transform up from cellDef to use. */ Transform *cdarg; /* Place to store transform from * cellDef to its root def. */ { extern int dbwElementAlways1(); if (use->cu_def->cd_flags & CDINTERNAL) return 0; if (!WindSearch((ClientData) DBWclientID, (ClientData) use, (Rect *) NULL, dbwElementAlways1, (ClientData) NULL)) return 0; if (SigInterruptPending) return 0; dbwelemRootDef = use->cu_def; *cdarg = *transform; return 1; } int dbwElementAlways1() { return 1; } /* * ---------------------------------------------------------------------------- * * DBWElementText -- * * Configures text of a text element * * Results: * None. * * Side effects: * Text element's text string is reallocated, or string is printed. * If altered, the element is erased and redrawn. * * ---------------------------------------------------------------------------- */ void DBWElementText(MagWindow *w, char *ename, char *text) { DBWElement *elem; HashEntry *entry; entry = HashFind(&elementTable, ename); if (entry == NULL) { TxError("No such element %s\n", ename); return; } elem = (DBWElement *)HashGetValue(entry); if (elem == NULL) return; if (elem->type != ELEMENT_TEXT) { TxError("Element %s is not a text element\n", ename); return; } if (text == NULL) /* get text */ { #ifdef MAGIC_WRAPPER Tcl_SetResult(magicinterp, elem->text, NULL); #else TxPrintf("%s\n", elem->text); #endif } else /* replace text */ { dbwElementUndraw(w, elem); freeMagic(elem->text); elem->text = StrDup((char **)NULL, text); } } /* * ---------------------------------------------------------------------------- * * DBWElementParseFlags -- * * Configures flags of any element * * Results: * None. * * Side effects: * Element's flags are set. * If altered, the element is erased and redrawn. * * ---------------------------------------------------------------------------- */ void DBWElementParseFlags(MagWindow *w, char *ename, char *flagstr) { DBWElement *elem; HashEntry *entry; int flidx, newflags; static const char * const lineOffset[] = {"halfx", "halfy", "exactx", "exacty", "arrowleft", "arrowbottom", "arrowright", "arrowtop", "plainleft", "plainbottom", "plainright", "plaintop", NULL}; static const char * const textSizes[] = {"small", "medium", "large", "xlarge", "default", NULL}; static const char * const genFlags[] = {"persistent", "temporary", NULL}; entry = HashFind(&elementTable, ename); if (entry == NULL) { TxError("No such element %s\n", ename); return; } elem = (DBWElement *)HashGetValue(entry); if (elem == NULL) return; newflags = elem->flags; /* Return list of known flags */ if (flagstr == NULL) { #ifdef MAGIC_WRAPPER Tcl_AppendElement(magicinterp, "(flags)"); #else TxPrintf("%s\n", "(flags)"); #endif } else { /* Parse string for known flags */ flidx = Lookup(flagstr, genFlags); switch (flidx) { case 0: newflags |= DBW_ELEMENT_PERSISTENT; break; case 1: newflags &= ~DBW_ELEMENT_PERSISTENT; break; default: switch (elem->type) { case ELEMENT_TEXT: flidx = Lookup(flagstr, textSizes); if (flidx >= 0) { newflags &= ~DBW_ELEMENT_TEXT_SIZE; newflags |= (flidx << 1) & DBW_ELEMENT_TEXT_SIZE; } else { flidx = GeoNameToPos(flagstr, FALSE, FALSE); if (flidx >= 0) { newflags &= ~DBW_ELEMENT_TEXT_POS; newflags |= (flidx << 4) & DBW_ELEMENT_TEXT_POS; } else TxError("No such text element flag \"%s\"\n", flagstr); } break; case ELEMENT_LINE: flidx = Lookup(flagstr, lineOffset); switch(flidx) { case 0: newflags |= DBW_ELEMENT_LINE_HALFX; break; case 1: newflags |= DBW_ELEMENT_LINE_HALFY; break; case 2: newflags &= ~(DBW_ELEMENT_LINE_HALFX); break; case 3: newflags &= ~(DBW_ELEMENT_LINE_HALFY); break; case 4: case 5: newflags |= DBW_ELEMENT_LINE_ARROWL; break; case 6: case 7: newflags |= DBW_ELEMENT_LINE_ARROWR; break; case 8: case 9: newflags &= ~(DBW_ELEMENT_LINE_ARROWL); break; case 10: case 11: newflags &= ~(DBW_ELEMENT_LINE_ARROWR); break; default: TxError("No such line element flag \"%s\"\n", flagstr); break; } break; case ELEMENT_RECT: TxError("No such rect element flag \"%s\"\n", flagstr); break; } break; } if (newflags != elem->flags) { dbwElementUndraw(w, elem); /* Mark element's cell as having been modified either if */ /* it is persistent or if its persistence has changed. */ if (elem->flags & DBW_ELEMENT_PERSISTENT || newflags & DBW_ELEMENT_PERSISTENT) elem->rootDef->cd_flags |= CDMODIFIED; elem->flags = newflags; } } } /* * ---------------------------------------------------------------------------- * * DBWElementStyle -- * * Configures style of any element * * Results: * None. * * Side effects: * Element's style list is reallocated, or printed. * If altered, the element is erased and redrawn. * * ---------------------------------------------------------------------------- */ void DBWElementStyle(MagWindow *w, char *ename, int style, bool add) { DBWElement *elem; HashEntry *entry; styleptr sptr, newstyle; entry = HashFind(&elementTable, ename); if (entry == NULL) { TxError("No such element %s\n", ename); return; } elem = (DBWElement *)HashGetValue(entry); if (elem == NULL) return; if (style== -1) /* get style(s) */ { #ifdef MAGIC_WRAPPER for (sptr = elem->stylelist; sptr != NULL; sptr = sptr->next) { Tcl_AppendElement(magicinterp, GrStyleTable[sptr->style].longname); } #else for (sptr = elem->stylelist; sptr != NULL; sptr = sptr->next) { TxPrintf("%s ", GrStyleTable[sptr->style].longname); } TxPrintf("\n"); #endif } else { dbwElementUndraw(w, elem); if (add == TRUE) { /* add style */ for (sptr = elem->stylelist; sptr != NULL && sptr->next != NULL; sptr = sptr->next); newstyle = (styleptr)mallocMagic(sizeof(stylestruct)); newstyle->style = style; newstyle->next = NULL; if (sptr == NULL) elem->stylelist = newstyle; else sptr->next = newstyle; } else { /* find style in list */ for (sptr = elem->stylelist; sptr != NULL; sptr = sptr->next) { if (sptr->next != NULL) if (sptr->next->style == style) break; } /* delete style (if it is in the list) */ if ((sptr == NULL) && (elem->stylelist != NULL) && (elem->stylelist->style == style)) { dbwElementUndraw(w, elem); freeMagic(elem->stylelist); elem->stylelist = elem->stylelist->next; if (elem->stylelist == NULL) TxPrintf("Warning: Element %s has no styles!\n", ename); } else if (sptr == NULL) { TxError("Style %d is not in the style list for element %s\n", style, ename); } else if (sptr->next != NULL) { dbwElementUndraw(w, elem); freeMagic(sptr->next); sptr->next = sptr->next->next; } } /* mark element's cell as having been modified */ if (elem->flags & DBW_ELEMENT_PERSISTENT) elem->rootDef->cd_flags |= CDMODIFIED; } } /* * ---------------------------------------------------------------------------- * * DBWElementPos -- * * Configures position of a rect or line element * * Results: * None. * * Side effects: * Rect or line element's rect structure is altered, or else the * position is printed. If altered, the element is erased and redrawn. * * ---------------------------------------------------------------------------- */ void DBWElementPos(MagWindow *w, char *ename, Rect *crect) { DBWElement *elem; HashEntry *entry; Rect prect; char ptemp[22]; entry = HashFind(&elementTable, ename); if (entry == NULL) { TxError("No such element %s\n", ename); return; } elem = (DBWElement *)HashGetValue(entry); if (elem == NULL) return; if (crect == NULL) /* Get position */ { #ifdef MAGIC_WRAPPER snprintf(ptemp, 20, "%d", elem->area.r_xbot); Tcl_AppendElement(magicinterp, ptemp); snprintf(ptemp, 20, "%d", elem->area.r_ybot); Tcl_AppendElement(magicinterp, ptemp); if (elem->type == ELEMENT_RECT || elem->type == ELEMENT_LINE) { snprintf(ptemp, 20, "%d", elem->area.r_xtop); Tcl_AppendElement(magicinterp, ptemp); snprintf(ptemp, 20, "%d", elem->area.r_ytop); Tcl_AppendElement(magicinterp, ptemp); } #else TxPrintf("(%d, %d)", elem->area.r_xbot, elem->area.r_ybot); if (elem->type == ELEMENT_RECT || elem->type == ELEMENT_LINE) TxPrintf(" to (%d, %d)", elem->area.r_xtop, elem->area.r_ytop); TxPrintf("\n"); #endif } else /* Change position */ { dbwElementUndraw(w, elem); elem->area = *crect; /* mark element's cell as having been modified */ if (elem->flags & DBW_ELEMENT_PERSISTENT) elem->rootDef->cd_flags |= CDMODIFIED; } } /* * ---------------------------------------------------------------------------- * * DBWElementClearDef -- * * Removes all elements associated with the given CellDef. * * Results: * None. * * Side effects: * Elements are removed from the element hash. * * ---------------------------------------------------------------------------- */ void DBWElementClearDef(cellDef) CellDef *cellDef; { DBWElement *elem; HashEntry *entry; styleptr stylePtr; HashSearch hs; HashStartSearch(&hs); while ((entry = HashNext(&elementTable, &hs)) != NULL) { elem = (DBWElement *) HashGetValue(entry); if (!elem) continue; if (elem->rootDef != cellDef) continue; for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next) freeMagic(stylePtr); if (elem->type == ELEMENT_TEXT) freeMagic(elem->text); HashSetValue(entry, NULL); freeMagic(elem); } }