2017-04-25 14:41:48 +02:00
|
|
|
/* 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.
|
2020-05-23 23:13:14 +02:00
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* Copyright (C) 2003 Open Circuit Design, Inc., for MultiGiG, Ltd.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#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"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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;
|
|
|
|
|
char *newstr;
|
|
|
|
|
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, 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 *
|
2020-05-12 18:03:38 +02:00
|
|
|
DBWPrintElements(cellDef, flagmask, reducer)
|
2017-04-25 14:41:48 +02:00
|
|
|
CellDef *cellDef;
|
|
|
|
|
unsigned char flagmask;
|
2020-05-12 18:03:38 +02:00
|
|
|
int reducer;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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",
|
2020-05-23 23:13:14 +02:00
|
|
|
"default", NULL};
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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))
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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 */
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_xbot / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
AppendString(&rstr, istr, " ");
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_ybot / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
AppendString(&rstr, istr, " ");
|
|
|
|
|
switch (elem->type)
|
|
|
|
|
{
|
|
|
|
|
case ELEMENT_RECT:
|
|
|
|
|
/* end point */
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_xtop / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
AppendString(&rstr, istr, " ");
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_ytop / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
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 */
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_xtop / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
AppendString(&rstr, istr, " ");
|
2020-05-12 18:03:38 +02:00
|
|
|
sprintf(istr, "%d", elem->area.r_ytop / reducer);
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 18:03:38 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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(stdout, "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(stdout, " %s", he->h_key.h_name);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef MAGIC_WRAPPER
|
|
|
|
|
TxPrintf(stdout, "/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(stdout, "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(stdout, " %s", he->h_key.h_name);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef MAGIC_WRAPPER
|
|
|
|
|
TxPrintf(stdout, "/n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!DBSrRoots(cellDef, &GeoIdentityTransform,
|
|
|
|
|
dbwelemGetTransform, (ClientData) &transform))
|
|
|
|
|
if (w != NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* SigInterruptPending screws up DBSrRoots */
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
return NULL;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
2020-05-23 23:13:14 +02:00
|
|
|
if (entry == NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
TxError("No such element %s\n", ename);
|
|
|
|
|
return;
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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 char *lineOffset[] = {"halfx", "halfy", "exactx", "exacty",
|
|
|
|
|
"arrowleft", "arrowbottom", "arrowright", "arrowtop",
|
|
|
|
|
"plainleft", "plainbottom", "plainright", "plaintop", NULL};
|
|
|
|
|
static char *textSizes[] = {"small", "medium", "large", "xlarge",
|
2020-05-23 23:13:14 +02:00
|
|
|
"default", NULL};
|
|
|
|
|
static char *genFlags[] = {"persistent", "temporary", NULL};
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
entry = HashFind(&elementTable, ename);
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("No such element %s\n", ename);
|
|
|
|
|
return;
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-16 02:49:51 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|