Logo Search packages:      
Sourcecode: magic version File versions  Download package

DBWelement.c

/* 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 <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"

/* Types of elements */

#define ELEMENT_RECT    0
#define ELEMENT_LINE    1
#define ELEMENT_TEXT    2

/* Linked list definition for styles */

typedef struct _style *styleptr;

00043 typedef struct _style
{
    int style;
    styleptr next;
} stylestruct;
    
/* Each element is stored in a record that looks like this: */

00051 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 *
DBWPrintElements(cellDef, flagmask)
    CellDef *cellDef;
    unsigned char flagmask;
{
    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);
            AppendString(&rstr, istr, " ");
            sprintf(istr, "%d", elem->area.r_ybot);
            AppendString(&rstr, istr, " ");
            switch (elem->type)
            {
                case ELEMENT_RECT:
                    /* end point */
                  sprintf(istr, "%d", elem->area.r_xtop);
                  AppendString(&rstr, istr, " ");
                  sprintf(istr, "%d", elem->area.r_ytop);
                  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);
                  AppendString(&rstr, istr, " ");
                  sprintf(istr, "%d", elem->area.r_ytop);
                  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;
}


/*
 * ----------------------------------------------------------------------------
 *
 * 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.
       */

      WindSurfaceToScreen(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, NULL);
                  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);
#ifdef NONMANHATTAN
                  /* 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);
                      }
                  }
#endif
                  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, NULL);
        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(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
}


/*
 * ----------------------------------------------------------------------------
 *
 * 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 char *lineOffset[] = {"halfx", "halfy", "exactx", "exacty",
            "arrowleft", "arrowbottom", "arrowright", "arrowtop",
            "plainleft", "plainbottom", "plainright", "plaintop", NULL};
    static char *textSizes[] = {"small", "medium", "large", "xlarge",
      "default", NULL}; 
    static char *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;
    }
}

Generated by  Doxygen 1.6.0   Back to index