Logo Search packages:      
Sourcecode: xcircuit version File versions

selection.c

/*-------------------------------------------------------------------------*/
/* selection.c --- xcircuit routines handling element selection etc.       */
/* Copyright (c) 2002  Tim Edwards, Johns Hopkins University               */
/*-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------*/
/*      written by Tim Edwards, 8/13/93                              */
/*-------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#ifdef TCL_WRAPPER 
#include <tk.h>
#else
#include "Xw/Xw.h"
#endif

/*-------------------------------------------------------------------------*/
/* Local includes                                        */
/*-------------------------------------------------------------------------*/

#include "xcircuit.h"
#include "colordefs.h"

/*----------------------------------------------------------------------*/
/* Function prototype declarations                                      */
/*----------------------------------------------------------------------*/
#include "prototypes.h"

/*-------------------------------------------------------------------------*/
/* Global Variable definitions                                       */
/*-------------------------------------------------------------------------*/

extern short eventmode; /* keep track of the mode the screen is in */
extern Display    *dpy;   /* Works well to make this globally accessible */
extern int *appcolors;
extern Cursor     appcursors[NUM_CURSORS];
extern Clientdata areastruct;
extern char _STR[150];
extern short attachto;
extern short textpos, textend;

/*----------------------------------------------------------------------*/
/* Change filter to determine what types can be selected          */
/*----------------------------------------------------------------------*/

void selectfilter(xcWidget w, pointertype value, caddr_t calldata)
{
   short bitwise = (short)value;
   Boolean bval = (areastruct.filter & bitwise) ? True : False;

   if (bval)
      areastruct.filter &= ~bitwise;
   else
      areastruct.filter |= bitwise;

#ifndef TCL_WRAPPER
   toggle(w, &bval, calldata);
#endif
}

/*----------------------------------------------------------------------------*/
/* Look at select stack to see if there are any selects; call select, if not. */
/*----------------------------------------------------------------------------*/

Boolean checkselect(short value)
{
   short *check;
 
   value &= areastruct.filter;      /* apply the selection filter */

   if (areastruct.selects == 0) objectselect(value);
   if (areastruct.selects == 0) return False;
   for (check = areastruct.selectlist; check < areastruct.selectlist +
      areastruct.selects; check++)
      if (SELECTTYPE(check) & value) break;
   if (check == areastruct.selectlist + areastruct.selects) return False;
   else return True;
}

/*-----------------------------------------------------------*/
/* Select list numbering revision for routine objectdelete() */
/*-----------------------------------------------------------*/

void reviseselect(short *selectobj)
{
   short *chkselect;

   for (chkselect = selectobj + 1; chkselect < areastruct.selectlist
        + areastruct.selects; chkselect++)
      if (*chkselect > *selectobj) (*chkselect)--;

   for (chkselect = areastruct.selectlast; chkselect < areastruct.selectlast
        + areastruct.lastselects; chkselect++)
      if (*chkselect > *selectobj) (*chkselect)--;
}

/*----------------------*/
/* Draw a selected item */
/*----------------------*/

void geneasydraw(short instance, short mode, objectptr curobj, objinstptr curinst)
{
   genericptr elementptr = *(curobj->plist + instance);

   switch ((*(curobj->plist + instance))->type) {
      case ARC:
         UDrawArc((arcptr)elementptr);
       break;
      case POLYGON:
         UDrawPolygon((polyptr)elementptr);
       break;
      case SPLINE:
       UDrawSpline((splineptr)elementptr);
       break;
      case PATH:
       UDrawPath((pathptr)elementptr);
       break;
      case LABEL:
         UDrawString((labelptr)elementptr, mode, curinst);
       break;
      case OBJECT:
         UDrawObject((objinstptr)elementptr, SINGLE, mode, NULL);
         break;
   }
}

/*-------------------------------------------------*/
/* Draw a selected item, including selection color */
/*-------------------------------------------------*/

void gendrawselected(short *newselect, objectptr curobj, objinstptr curinst)
{
   XSetFunction(dpy, areastruct.gc, GXcopy);
   XSetForeground(dpy, areastruct.gc, BACKGROUND);
   geneasydraw(*newselect, DOFORALL, curobj, curinst);
   indicateparams(*(curobj->plist + *newselect));

   XSetFunction(dpy, areastruct.gc, GXxor);
   XSetForeground(dpy, areastruct.gc, SELECTCOLOR ^ BACKGROUND);
   geneasydraw(*newselect, DOFORALL, curobj, curinst);

/* XSetForeground(dpy, areastruct.gc, PARAMCOLOR ^ BACKGROUND); */
   XSetForeground(dpy, areastruct.gc, AUXCOLOR ^ BACKGROUND);
   indicateparams(*(curobj->plist + *newselect));
}

/*---------------------------------------------------*/
/* Allocate or reallocate memory for a new selection */
/*---------------------------------------------------*/

short *allocselect()
{
   short *newselect;

   if (areastruct.selects == 0)
      areastruct.selectlist = (short *) malloc(sizeof(short));
   else
      areastruct.selectlist = (short *) realloc(areastruct.selectlist,
       (areastruct.selects + 1) * sizeof(short));

   newselect = areastruct.selectlist + areastruct.selects;
   areastruct.selects++;

   return newselect;
}

/*-------------------------------------------------*/
/* Set Options menu according to 1st selection     */
/*-------------------------------------------------*/

void setoptionmenu()
{
   short      *mselect;
   labelptr   mlabel;

   if (areastruct.selects == 0) {
      setallstylemarks(areastruct.style);
      setcolormark(areastruct.color);
      setdefaultfontmarks();
      setparammarks(NULL);
      return;
   }

   for (mselect = areastruct.selectlist; mselect < areastruct.selectlist +
      areastruct.selects; mselect++) {
      setcolormark(SELTOCOLOR(mselect));
      setparammarks(SELTOGENERIC(mselect));
      switch(SELECTTYPE(mselect)) {
       case ARC:
          setallstylemarks(SELTOARC(mselect)->style);
          return;
       case POLYGON:
          setallstylemarks(SELTOPOLY(mselect)->style);
          return;
       case SPLINE:
            setallstylemarks(SELTOSPLINE(mselect)->style);
          return;
       case PATH:
            setallstylemarks(SELTOPATH(mselect)->style);
          return;
       case LABEL:
          mlabel = SELTOLABEL(mselect);
          setfontmarks(mlabel->string->data.font, mlabel->justify);
          return;
      }
   }
}

/*-------------------------------------*/
/* Test of point being inside of a box */
/*-------------------------------------*/

int test_insideness(int tx, int ty, XPoint *boxpoints)
{
   int i, stval = 0; 
   XPoint *pt1, *pt2;
   int stdir;   

   for (i = 0; i < 4; i++) {
      pt1 = boxpoints + i;
      pt2 = boxpoints + ((i + 1) % 4);
      stdir = (pt2->x - pt1->x) * (ty - pt1->y)
            - (pt2->y - pt1->y) * (tx - pt1->x);
      stval += sign(stdir);
   }
   return (abs(stval) == 4) ? 1 : 0;
}

/*--------------------------------------------*/
/* Search for selection among path components */
/*--------------------------------------------*/

Boolean pathselect(genericptr *curgen, short class)
{
   /*----------------------------------------------------------------------*/
   /* wirelim is the distance, in user-space units, at which an element is */
   /* considered for selection.                                      */
   /*                                                    */
   /* wirelim = A + B / (scale + C)                            */
   /*                                                    */
   /* where A = minimum possible distance (expands range at close scale)   */
   /*       C = minimum possible scale    (contract range at far scale)    */
   /*     B   makes wirelim approx. 25 at default scale of 0.5, which      */
   /*       is an empirical result.                            */
   /*----------------------------------------------------------------------*/

   float    wirelim = 2 + 11.5 / (*areastruct.vscale + 0.05);
   long           sqrwirelim = (int)(wirelim * wirelim);

   long           newdist;
   Boolean  selected = False;

   class &= areastruct.filter;      /* apply the selection filter */

   if ((*curgen)->type == (class & ARC)) {

      /* look among the arcs */

      fpointlist currentpt;
      XPoint nearpt[3];

      nearpt[2].x = nearpt[0].x = (short)(TOARC(curgen)->points[0].x);
      nearpt[2].y = nearpt[0].y = (short)(TOARC(curgen)->points[0].y);
      for (currentpt = TOARC(curgen)->points + 1; currentpt < TOARC(curgen)->points
              + TOARC(curgen)->number; currentpt++) {
       nearpt[1].x = nearpt[0].x;
       nearpt[1].y = nearpt[0].y;
       nearpt[0].x = (short)(currentpt->x);
       nearpt[0].y = (short)(currentpt->y);
       newdist = finddist(&nearpt[0], &nearpt[1], &areastruct.save);
         if (newdist <= sqrwirelim) break;
      }
      if ((!(TOARC(curgen)->style & UNCLOSED)) && (newdist > sqrwirelim))
       newdist = finddist(&nearpt[0], &nearpt[2], &areastruct.save);

      if (newdist <= sqrwirelim) selected = True;
   }

   else if ((*curgen)->type == (class & SPLINE)) {

      /* look among the splines --- look at polygon representation */

      fpointlist currentpt;
      XPoint nearpt[2];

      nearpt[0].x = (short)(TOSPLINE(curgen)->points[0].x);
      nearpt[0].y = (short)(TOSPLINE(curgen)->points[0].y);
      newdist = finddist(&(TOSPLINE(curgen)->ctrl[0]), &(nearpt[0]),
               &areastruct.save);
      if (newdist > sqrwirelim) {
         for (currentpt = TOSPLINE(curgen)->points; currentpt <
              TOSPLINE(curgen)->points + INTSEGS; currentpt++) {
          nearpt[1].x = nearpt[0].x;
          nearpt[1].y = nearpt[0].y;
          nearpt[0].x = (short)(currentpt->x);
          nearpt[0].y = (short)(currentpt->y);
          newdist = finddist(&nearpt[0], &nearpt[1], &areastruct.save);
            if (newdist <= sqrwirelim) break;
       }
       if (newdist > sqrwirelim) {
          newdist = finddist(&nearpt[0], &(TOSPLINE(curgen)->ctrl[3]),
                  &areastruct.save);
            if ((!(TOSPLINE(curgen)->style & UNCLOSED)) && (newdist > sqrwirelim))
             newdist = finddist(&(TOSPLINE(curgen)->ctrl[0]),
                 &(TOSPLINE(curgen)->ctrl[3]), &areastruct.save);
       }
      }

      if (newdist <= sqrwirelim) selected = True;
   }

   else if ((*curgen)->type == (class & POLYGON)) {

      /* finally, look among the polygons */

      pointlist currentpt;

      for (currentpt = TOPOLY(curgen)->points; currentpt < TOPOLY(curgen)
            ->points + TOPOLY(curgen)->number - 1; currentpt++) {
       newdist = finddist(currentpt, currentpt + 1, &areastruct.save);
       if (newdist <= sqrwirelim) break;
      }
      if ((!(TOPOLY(curgen)->style & UNCLOSED)) && (newdist > sqrwirelim))
       newdist = finddist(currentpt, TOPOLY(curgen)->points,
            &areastruct.save);

      if (newdist <= sqrwirelim) selected = True;
   }
   return selected;
}

/*--------------------------------------*/
/* Select one of the elements on-screen */
/*--------------------------------------*/

short *genobjectselect(short class, objectptr selobj, objinstptr selinst)
{
   short    *newselect, *foundtmp, *foundlist;

   genericptr     *curgen;
   XPoint   newboxpts[4];
   XEvent   event;
   XButtonEvent *buttonevent = (XButtonEvent *)(&event);
   Boolean  selected, unselect = False;
   short    found = 0;

   XDefineCursor(dpy, areastruct.areawin, QUESTION);

   /* Definition for unselecting an element */

   if (class < 0) {
      unselect = True;
      class = -class;
   }
   class &= areastruct.filter;      /* apply the selection filter */

   /* Loop through all elements found underneath the cursor */

   for (curgen = selobj->plist; curgen < selobj->plist + selobj->parts; curgen++) {

      /* when selection element to attach to, don't select the element */
      /* to be attached. . .                                 */

      if (attachto == 1 && eventmode != COPY2_MODE && eventmode !=
          PRESS_MODE && curgen == EDITPART) continue;

      selected = False;

      /* check for position inside the bounding box of one of the objects */

      if ((*curgen)->type == (class & OBJECT)) {

       objinstbbox(TOOBJINST(curgen), newboxpts);

         /* Look for an intersect of the boundingbox and pointer position. */
         /* This is a simple matter of rotating the pointer position with  */
         /*  respect to the origin of the bounding box segment, as if the  */
         /*  segment were rotated to 0 degrees.  The sign of the resulting */
         /*  point's y-position is the same for all bbox segments if the   */
         /*  pointer position is inside the bounding box.            */

       selected = test_insideness(areastruct.save.x, areastruct.save.y,
            newboxpts);
      }

      else if ((*curgen)->type == (class & LABEL)) {

         /* Look among the labels */

       labelptr curlab = TOLABEL(curgen);

#ifdef SCHEMA
       /* Don't select temporary labels from schematic capture system */
       if (curlab->string->type != FONT_NAME) continue;
#endif

       labelbbox(curlab, newboxpts, selinst);

         /* check for point inside bounding box, as for objects */

       selected = test_insideness(areastruct.save.x, areastruct.save.y,
            newboxpts);
       if (selected) textpos = textend = 0;
      }


      else if ((*curgen)->type == (class & PATH)) {

         /* Check among the paths */

       genericptr *pathp;

       /* Accept path if any subcomponent of the path is accepted */
       /* Record which part was selected in the "subeditpart" variable */

       for (pathp = TOPATH(curgen)->plist; pathp < TOPATH(curgen)->plist +
            TOPATH(curgen)->parts; pathp++)
          if (pathselect(pathp, SPLINE|ARC|POLYGON)) {
             selected = True;
             areastruct.editsubpart = (short)(pathp - TOPATH(curgen)->plist);
             break;
          }
      }

      /* Check among polygons, arcs, and curves */

      else selected = pathselect(curgen, class);

      /* check if this object has already been selected */

      for (newselect = areastruct.selectlist; newselect <
             areastruct.selectlist + areastruct.selects; newselect++) 
         if (*newselect == (short)(curgen - selobj->plist)) {
          if (!unselect) selected = False;
          break;
       }

      if (unselect && (newselect == areastruct.selectlist + areastruct.selects))
       selected = False;

      /* Add this object to the list of things found under the cursor */

      if (selected && (!unselect)) {

         if (found == 0)
            foundlist = (short *) malloc(sizeof(short));
         else
            foundlist = (short *) realloc(foundlist, (found + 1) * sizeof(short));

         newselect = foundlist + found;
         found++;
     
         if (selected) *newselect = (short)(curgen - selobj->plist);
      }

      /* mechanism for unselecting elements under the cursor */

      else if (selected) {
         short *desel;

         XSetFunction(dpy, areastruct.gc, GXcopy);
         XTopSetForeground(GSELTOCOLOR(selobj, newselect));
         geneasydraw(*newselect, DEFAULTCOLOR, selobj, selinst);
         areastruct.selects--;
         for (desel = newselect; desel < areastruct.selectlist +
              areastruct.selects; desel++)
          *desel = *(desel + 1);
         if (areastruct.selects == 0) free (areastruct.selectlist);
      }
      else newselect = NULL;

   } /* for-loop over all parts */

   /* Various options depending on how many things were found */

   switch (found) {
      case 0: 
       newselect = NULL;
       break;

      case 1: 
       newselect = allocselect();
       *newselect = *foundlist;
       free(foundlist);
       gendrawselected(newselect, selobj, selinst);
       break;

      default: {
       newselect = NULL;
       XSetFunction(dpy, areastruct.gc, GXcopy);
       for (foundtmp = foundlist; foundtmp < foundlist + found; foundtmp++) {
            XSetForeground(dpy, areastruct.gc, QUERYCOLOR);
            geneasydraw(*foundtmp, DOFORALL, selobj, selinst);
          sprintf(_STR, "Click to accept/reject: %d of %d",
            (int)(foundtmp - foundlist + 1), found);
          Wprintf(_STR);

          for(;;) {     /* This flushes the X event queue */
             XNextEvent(dpy, &event); 
             if (event.type != ButtonPress && event.type != ButtonRelease
                && event.type != MotionNotify && event.type != KeyPress)
                xcDispatchEvent(&event);
             else if (event.type == ButtonPress) break;
          }
          if (buttonevent->button == Button3) {
               XTopSetForeground(GSELTOCOLOR(selobj, foundtmp));
               geneasydraw(*foundtmp, DEFAULTCOLOR, selobj, selinst);
          }
          else {
             newselect = allocselect();
               *newselect = *foundtmp;
               XSetForeground(dpy, areastruct.gc, SELECTCOLOR);
               geneasydraw(*newselect, DOFORALL, selobj, selinst);
          }
         }
      }  break;
   }

   if (found > 1) {
      short *nselect;

      XDefineCursor(dpy, areastruct.areawin, CIRCLE);
      if (eventmode == PRESS_MODE)
       Wprintf("Click and hold button 1 to continue move.");
      else
       Wprintf("Selection complete");

      for(;;) {
       XNextEvent(dpy, &event); 
       if (event.type != ButtonPress && event.type != ButtonRelease &&
            event.type != MotionNotify && event.type != KeyPress)
          xcDispatchEvent(&event);
       else if ((event.type == ButtonPress) && (eventmode == PRESS_MODE))
          break;
       else if ((event.type == ButtonRelease) && (eventmode != PRESS_MODE))
          break;
      }
      free(foundlist);

      /* make it work right for smooth xor'ing */

      XSetFunction(dpy, areastruct.gc, GXcopy);
      XSetForeground(dpy, areastruct.gc, BACKGROUND);
      for (nselect = areastruct.selectlist; nselect < areastruct.selectlist
         + areastruct.selects; nselect++)
         geneasydraw(*nselect, DOFORALL, selobj, selinst);
      XSetFunction(dpy, areastruct.gc, GXxor);
      XSetForeground(dpy, areastruct.gc, SELECTCOLOR ^ BACKGROUND);
      for (nselect = areastruct.selectlist; nselect < areastruct.selectlist
         + areastruct.selects; nselect++)
         geneasydraw(*nselect, DOFORALL, selobj, selinst);
   }

   setoptionmenu();

   if (eventmode == DELETE_MODE)
      XDefineCursor(dpy, areastruct.areawin, SCISSORS);
   else
      XDefineCursor(dpy, areastruct.areawin, CROSS);

   /* snap the coordinates */

   u2u_snap(&areastruct.save);
   return newselect;
}

/*----------------------------------------------------------------*/
/* select arc, curve, and polygon objects from a defined box area */
/*----------------------------------------------------------------*/

Boolean areaelement(genericptr *curgen)
{
   Boolean selected;
   pointlist    currentpt;

   switch((*curgen)->type) {

      case(ARC):
         /* check center of arcs */

               selected = (TOARC(curgen)->position.x < areastruct.save.x) &&
            (TOARC(curgen)->position.x > areastruct.origin.x) &&
            (TOARC(curgen)->position.y < areastruct.save.y) &&
            (TOARC(curgen)->position.y > areastruct.origin.y);
         break;

      case(POLYGON):
         /* check each point of the polygons */

         selected = False;
           for (currentpt = TOPOLY(curgen)->points; currentpt <
            TOPOLY(curgen)->points + TOPOLY(curgen)->number; currentpt++) {
              if ((currentpt->x < areastruct.save.x) && (currentpt->x >
                 areastruct.origin.x) && (currentpt->y < areastruct.save.y) &&
                 (currentpt->y > areastruct.origin.y)) {
               selected = True;
             break;
            }
           }
         break;

      case(SPLINE):
         /* check each control point of the spline */
      
           selected = ((TOSPLINE(curgen)->ctrl[0].x < areastruct.save.x) && 
            (TOSPLINE(curgen)->ctrl[0].x > areastruct.origin.x) &&
            (TOSPLINE(curgen)->ctrl[0].y < areastruct.save.y) &&
            (TOSPLINE(curgen)->ctrl[0].y > areastruct.origin.y))
            || ((TOSPLINE(curgen)->ctrl[3].x < areastruct.save.x) &&
            (TOSPLINE(curgen)->ctrl[3].x > areastruct.origin.x) &&
            (TOSPLINE(curgen)->ctrl[3].y < areastruct.save.y) &&
            (TOSPLINE(curgen)->ctrl[3].y > areastruct.origin.y));
         break;
   }
   return selected;
}

/*--------------------------------------------*/
/* select all objects from a defined box area */
/*--------------------------------------------*/

void selectarea()
{
   short    *newselect;
   genericptr   *curgen, *pathgen;
   Boolean  selected;
   stringpart     *strptr;
   int            locpos;

   /* put points of area bounding box into proper order */

   if (areastruct.origin.y > areastruct.save.y) {
      short tmp;
      tmp = areastruct.origin.y;
      areastruct.origin.y = areastruct.save.y;
      areastruct.save.y = tmp;
   }
   if (areastruct.origin.x > areastruct.save.x) {
      short tmp;
      tmp = areastruct.origin.x;
      areastruct.origin.x = areastruct.save.x;
      areastruct.save.x = tmp;
   }

   textpos = textend = 0;
   for (curgen = topobject->plist; curgen < topobject->plist
      + topobject->parts; curgen++) {

      /* apply the selection filter */
      if (!((*curgen)->type & areastruct.filter)) continue;

      switch((*curgen)->type) {
      case(OBJECT):
           /* check for instance of object inside area box */
           selected = (TOOBJINST(curgen)->position.x < areastruct.save.x) &&
            (TOOBJINST(curgen)->position.x > areastruct.origin.x) &&
            (TOOBJINST(curgen)->position.y < areastruct.save.y) &&
            (TOOBJINST(curgen)->position.y > areastruct.origin.y);
         break;

        case(LABEL): {
         XPoint bboxpts[4], newboxpts[4], adj;
         labelptr slab = TOLABEL(curgen);
         short j, state, isect, tmpl1, tmpl2;
         TextExtents tmpext;

         selected = False;

#ifdef SCHEMA
         /* Ignore temporary labels created by the netlist generator */
         if (slab->string->type != FONT_NAME) break;
#endif

         /* create a 4-point polygon out of the select box information */
         bboxpts[0].x = bboxpts[3].x = areastruct.origin.x;
         bboxpts[0].y = bboxpts[1].y = areastruct.origin.y;
         bboxpts[1].x = bboxpts[2].x = areastruct.save.x;
         bboxpts[2].y = bboxpts[3].y = areastruct.save.y;

         /* translate select box into the coordinate system of the label */
         InvTransformPoints(bboxpts, newboxpts, 4, slab->position,
              slab->scale, slab->rotation);

#ifdef SCHEMA
         if (slab->pin) {
            if (!areastruct.schemon) continue;
            for (j = 0; j < 4; j++) 
             pinadjust(slab->justify, &(newboxpts[j].x),
                  &(newboxpts[j].y), -1);
         }
#endif
         tmpext = ULength(slab->string, areastruct.topinstance, 0.0, 0, NULL);
         adj.x = (slab->justify & NOTLEFT ? (slab->justify & RIGHT ? 
                  tmpext.width : tmpext.width >> 1) : 0);
         adj.y = (slab->justify & NOTBOTTOM ? (slab->justify & TOP ? 
                  tmpext.ascent : (tmpext.ascent + tmpext.base) >> 1)
                  : tmpext.base);
         
         /* Label selection:  For each character in the label string, */
         /* do an insideness test with the select box.            */

         state = tmpl2 = 0;
         for (j = 0; j < stringlength(slab->string, True, areastruct.topinstance); j++) {
            strptr = findstringpart(j, &locpos, slab->string, areastruct.topinstance);
            if (locpos < 0) continue;       /* only look at printable characters */
            if (strptr->type == RETURN) tmpl2 = 0;
            tmpl1 = tmpl2;
            tmpext = ULength(slab->string, areastruct.topinstance, 0.0, j + 1, NULL);
            tmpl2 = tmpext.width;
            isect = test_insideness(((tmpl1 + tmpl2) >> 1) - adj.x,
                  (tmpext.base + (BASELINE >> 1)) - adj.y, newboxpts);

            /* tiny state machine */
            if (state == 0) {
             if (isect) {
                state = 1;
                selected = True;
                textend = j;
                if ((textend > 1) && strptr->type != TEXT_STRING)
                   textend--;
             }
            }
            else {
             if (!isect) {
                textpos = j;
                state = 2;
                break;
             }
            }
         }
         if (state == 1) textpos = j;   /* selection goes to end of string */
         } break;
         
      case(PATH):
         /* check position point of each subpart of the path */

         selected = False;
         for (pathgen = TOPATH(curgen)->plist; pathgen < TOPATH(curgen)->plist
              + TOPATH(curgen)->parts; pathgen++) {
            if (areaelement(pathgen)) selected = True;
         }
         break;

      default:
         selected = areaelement(curgen);
         break;
      }

      /* check if this part has already been selected */

      if (selected)
         for (newselect = areastruct.selectlist; newselect <
              areastruct.selectlist + areastruct.selects; newselect++)
            if (*newselect == (short)(curgen - topobject->plist))
                  selected = False;

      /* add to list of selections */

      if (selected) {
         newselect = allocselect();
         *newselect = (short)(curgen - topobject->plist);
      }
   }
   setoptionmenu();

   /* if none or > 1 label has been selected, cancel any textpos placement */

   if (!checkselect(LABEL) || areastruct.selects != 1 ||
      (areastruct.selects == 1 && SELECTTYPE(areastruct.selectlist) != LABEL)) {
      textpos = textend = 0;
   }

   /* Drawing of selected objects will take place when drawarea() is */
   /* executed after the button release.                   */
}

/*------------------------*/
/* start deselection mode */
/*------------------------*/

void startdesel(xcWidget w, caddr_t clientdata, caddr_t calldata)
{
   if (eventmode == NORMAL_MODE) {
      if (areastruct.selects == 0)
       Wprintf("Nothing to deselect!");
      else if (areastruct.selects == 1)
       objectdeselect();
      else {
         eventmode = DESEL_MODE;
         Wprintf("Click on element to deselect");
      }
   }
}

/*---------------------------------------------------------*/
/* Redraw all the selected objects in their normal colors. */
/*---------------------------------------------------------*/

void drawselects(objectptr thisobj, objinstptr thisinst)
{
   short *lastselect;

   if (areastruct.selects == 0) return;

   /* reset the graphics state */

   XSetFunction(dpy, areastruct.gc, GXcopy);

   for (lastselect = areastruct.selectlist; lastselect < areastruct.selectlist 
      + areastruct.selects; lastselect++) {
      XTopSetForeground(SELTOCOLOR(lastselect)); 
      geneasydraw(*lastselect, SELTOCOLOR(lastselect), thisobj, thisinst);
   }
}

/*--------------------------------------------------------------*/
/* Free memory from the previous selection list, copy the   */
/* current selection list to the previous selection list, and     */
/* zero out the current selection list.                     */
/* Normally one would use clearselects();  use freeselects()      */
/* only if the menu/toolbars are going to be updated later in     */
/* the call.                                          */
/*--------------------------------------------------------------*/

void freeselects()
{
   if (areastruct.selects > 0) {
      if (areastruct.lastselects > 0)
         free(areastruct.selectlast);
      areastruct.selectlast = areastruct.selectlist;
      areastruct.lastselects = areastruct.selects;
      areastruct.selects = 0;
   }
}

/*--------------------------------------------------------------*/
/* Free memory from the selection list and set menu/toolbar */
/* items back to default values.                      */
/*--------------------------------------------------------------*/

void clearselects()
{
   if (areastruct.selects > 0) {
      freeselects();
      setallstylemarks(areastruct.style);
      setcolormark(areastruct.color);
      setdefaultfontmarks();
   }
}

/*--------------------------------------------------------------*/
/* Free memory from both the current and previous selection */
/* lists, because a page change has invalidated both.       */
/*--------------------------------------------------------------*/

void destroyselects()
{
   if (areastruct.selects > 0) free(areastruct.selectlist);
   if (areastruct.lastselects > 0) free(areastruct.selectlast);
   areastruct.selects = 0;
   areastruct.lastselects = 0;
 
   setallstylemarks(areastruct.style);
   setcolormark(areastruct.color);
   setdefaultfontmarks();
}

/*--------------------------------------------------------------*/
/* Unselect all the selected objects and free memory from the     */
/* selection list.                                    */
/*--------------------------------------------------------------*/

void objectdeselect()
{
   drawselects(topobject, areastruct.topinstance);
   clearselects();
}

/*----------------------------------------------------------------------*/
/* Select the nearest polygon, searching the hierarchy if necessary.    */
/* Return an pushlist pointer to a linked list containing the           */
/* hierarchy of objects, with the topmost pushlist also containing a    */
/* pointer to the polygon found.                            */
/* Allocates memory for the returned linked list which must be freed by */
/* the calling routine.                                     */
/*----------------------------------------------------------------------*/

genericptr recurselect(short class, pushlistptr *seltop)
{
   genericptr rgen = NULL;
   short *selectobj;
   objectptr selobj;
   objinstptr selinst;
   XPoint savesave, tmppt;

   if (*seltop == NULL) {
      Fprintf(stderr, "Error: recurselect called with NULL pushlist pointer\n");
      return NULL;
   }

   selinst = (*seltop)->thisinst;
   selobj = selinst->thisobject;

   if ((selectobj = genobjectselect(class, selobj, selinst)) != NULL) {
      rgen = *(selobj->plist + (*selectobj));
      /* Fprintf(stdout, "%s found in object %s\n", (rgen->type == LABEL) ?
                  "label" : "polygon", selobj->name); */
      drawselects(selobj, selinst);
      clearselects();
   }
   else if ((selectobj = genobjectselect(OBJECT, selobj, selinst)) != NULL) {
      pushlistptr selnew = (pushlistptr)malloc(sizeof(pushlist));

      selinst = TOOBJINST(selobj->plist + (*selectobj));    
      drawselects(selobj, selinst);
      clearselects();

      /* Link hierarchy information to the pushlist linked list */
      selnew->thisinst = selinst;
      selnew->next = NULL;
      (*seltop)->next = selnew;
       
      /* Translate areastruct.save into object's own coordinate system */
      savesave.x = areastruct.save.x;
      savesave.y = areastruct.save.y;
      InvTransformPoints(&areastruct.save, &tmppt, 1, selinst->position,
            selinst->scale, selinst->rotation);
      areastruct.save.x = tmppt.x;
      areastruct.save.y = tmppt.y;
      /* Fprintf(stdout, "objinst %s found in object %s; searching recursively\n",
            selinst->thisobject->name, selobj->name); */
      /* Fprintf(stdout, "cursor position originally (%d, %d); "
            "in new object is (%d, %d)\n",
            savesave.x, savesave.y,
            areastruct.save.x, areastruct.save.y); */
      UPushCTM();
      UPreMultCTM(DCTM, selinst->position, selinst->scale, selinst->rotation);
      rgen = recurselect(class, &selnew);
      UPopCTM();
      areastruct.save.x = savesave.x;
      areastruct.save.y = savesave.y;
   }
   /* else
      Fprintf(stdout, "nothing found in object %s\n", selobj->name); */

   return rgen;
}

/*----------------------------------*/
/* Start drawing a select area box. */
/*----------------------------------*/

#ifdef TCL_WRAPPER

xcTimeOutProc startselect(caddr_t clientdata)
{
   if (eventmode != PENDING_MODE) return;
   eventmode = SELAREA_MODE;
   areastruct.origin.x = areastruct.save.x;
   areastruct.origin.y = areastruct.save.y;
   UDrawBox(areastruct.origin, areastruct.save);

   Tk_CreateEventHandler(areastruct.area, ButtonMotionMask,
            (Tk_EventProc *)xctk_drag, NULL);
}

#else

xcTimeOutProc startselect(caddr_t clientdata, xcIntervalId *id)

{
   if (eventmode != PENDING_MODE) return;
   eventmode = SELAREA_MODE;
   areastruct.origin.x = areastruct.save.x;
   areastruct.origin.y = areastruct.save.y;
   UDrawBox(areastruct.origin, areastruct.save);
}

#endif

/*-------------------------*/
/* Track a select area box */
/*-------------------------*/

void trackselarea()
{
   XPoint newpos;
   u_int  nullui;

   newpos = UGetCursorPos();
   if (newpos.x == areastruct.save.x && newpos.y == areastruct.save.y) return;

   UDrawBox(areastruct.origin, areastruct.save);
   UDrawBox(areastruct.origin, newpos);

   areastruct.save.x = newpos.x;
   areastruct.save.y = newpos.y;
}

/*-------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index