Logo Search packages:      
Sourcecode: xcircuit version File versions

schema.c

/*-------------------------------------------------------------------------*/
/* schema.c --- xcircuit routines specific to the schematic capture system */
/* Copyright (c) 2002  Tim Edwards, Johns Hopkins University               */
/*-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------*/
/*      written by Tim Edwards, 10/13/97                             */
/*-------------------------------------------------------------------------*/

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

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

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

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

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

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

/*------------------------------------------------------------------------*/
/* External Variable definitions                                          */
/*------------------------------------------------------------------------*/

#ifdef TCL_WRAPPER
extern Tcl_Interp *xcinterp;
#endif

extern Globaldata xobjs;
extern Clientdata areastruct;
extern short        eventmode;
extern int    *appcolors;
extern xcWidget     menuwidgets[];
extern xcWidget     netbutton;
extern char   _STR[150];
extern char   _STR2[250];

/*-------------------------------------------------------------------------*/
#ifdef SCHEMA

extern xcWidget wsymb, wschema;

/*--------------------------------------------------------*/
/* Menu calls (procedure wrappers)                */
/*--------------------------------------------------------*/

void callgennet(xcWidget w, pointertype mode, caddr_t calldata)
{
   switch(mode) {
     case 0:
        gennet("spice", "spc");
      break;
     case 1:
        gennet("sim", "sim");
      break;
     case 2:
        gennet("pcb", "pcbnet");
      break;
     case 3:
        gennet("flatspice", "fspc");
      break;
     case 4:
      gennet("idxpcb", "");   /* Auto-numbering:  no output generated */
      break;
   }
}

/*--------------------------------------------------------------*/
/* Enable schematic capture (set schemon and realize widgets)     */
/* If mode == 1, do a redraw (e.g., not called during a file      */
/* load)                                        */
/*--------------------------------------------------------------*/

void doxschema(xcWidget w, pointertype mode, caddr_t calldata)
{
   Arg wargs[1];

   if (areastruct.schemon) {
      areastruct.schemon = False;
#ifndef TCL_WRAPPER
      XtUnmanageChild(wschema);
      XtUnmanageChild(wsymb);
      XtUnmanageChild(netbutton);

      XtSetArg(wargs[0], XtNlabel, "Enable XSchema");
      XtSetValues(OptionsEnableXSchemaButton, wargs, 1);
#endif
   }
   else {
      areastruct.schemon = True;
#ifndef TCL_WRAPPER
      XtManageChild(wschema);
      XtManageChild(wsymb);
      XtManageChild(netbutton);

      XtSetArg(wargs[0], XtNlabel, "Disable XSchema");
      XtSetValues(OptionsEnableXSchemaButton, wargs, 1);
#endif
   }

   /* Redraw the screen, since this action may effect the presence of   */
   /* pins and schematic informational labels.                    */

   if (mode) drawarea(NULL, NULL, NULL);
}

/*------------------------------------------------------------------------*/
/* Ensure that a page name is unique (required for schematic association) */
/*------------------------------------------------------------------------*/

int checkpagename(objectptr thispageobj)
{
   int p, thispage;
   char *objname = thispageobj->name;
   Boolean changed;
   Boolean update = False;
   char *clnptr = NULL;
   int n;

   /* Check for ":n" suffix and prepare for possible update */
   clnptr = strrchr(thispageobj->name, ':');
   if (clnptr != NULL)
      if (sscanf(clnptr + 1, "%d", &n) != 1)
       clnptr = NULL;

   /* Find the page number of this page object */
   for (p = 0; p < xobjs.pages; p++) {
      if (xobjs.pagelist[p]->pageinst != NULL) {
       if (xobjs.pagelist[p]->pageinst->thisobject == thispageobj) {
          thispage = p;
          break;
       }
      }
   }
   if (p == xobjs.pages) {
      Fprintf(stderr, "Error:  Object is not a page object!\n");
      return 0;
   }

   /* Look for any other pages with the same name */
   do {
      changed = False;
      for (p = 0; p < xobjs.pages; p++) {
       if (p == thispage) continue;
         if (xobjs.pagelist[p]->pageinst != NULL) {
          if (!strcmp(xobjs.pagelist[p]->pageinst->thisobject->name,
                  thispageobj->name)) {
             /* append ":2" to name or update suffix to ensure uniqueness */
             if (clnptr == NULL)
              sprintf(thispageobj->name, "%s:2", thispageobj->name);
             else
              sprintf(clnptr + 1, "%d", n + 1);
             changed = True;
             update = True;
             break;
          }
       }
      }
   } while (changed);
   if (update) {
      renamepage(thispage);
      return -1;
   }
   return 0;
}

/*--------------------------------------*/
/* Find connectivity of a selection */
/*--------------------------------------*/

void startconnect(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   if (areastruct.selects > 0)
      connectivity(button, clientdata, calldata);
   else if (eventmode == NORMAL_MODE) {
      Wprintf("Click button1 on wire to see connectivity.");
      eventmode = CONNECT_MODE;
   }
}

/*----------------------------------------------------------------------*/
/* connectivity():  Find electrical connections into a node.            */
/* (does recursive search on object heirarchy)                    */
/* Returns net number found (0 if no network found, -1 if error)  */
/*----------------------------------------------------------------------*/

int connectivity(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   short *gsel;
   genericptr ggen;
   int depth, netid = -1;
   pushlistptr seltop, nextptr;
   objectptr nettop, thisobj;
   char *snew;
   stringpart *ppin;

   /* erase any existing highlighted network */
   highlightnet(topobject, areastruct.topinstance, -1, 0);

   seltop = (pushlistptr)malloc(sizeof(pushlist));
   seltop->thisinst = areastruct.topinstance;
   seltop->next = NULL;

   /* pick the first selection that looks like a valid network part */

   if (areastruct.selects > 0) {
      for (gsel = areastruct.selectlist; gsel < areastruct.selectlist +
            areastruct.selects; gsel++) {
       ggen = *(topobject->plist + *gsel);
         if (SELECTTYPE(gsel) == LABEL) {
          labelptr glab = SELTOLABEL(gsel);
          if (glab->pin == LOCAL || glab->pin == GLOBAL) break;
         }
       else if (SELECTTYPE(gsel) == POLYGON) {
          polyptr gpoly = SELTOPOLY(gsel);
          if (!nonnetwork(gpoly)) break;
       }
      }
      if (gsel == areastruct.selectlist + areastruct.selects) {
       Wprintf("Selected element is not part of a valid network.");
      }
   }
   else
      ggen = recurselect(POLYGON | LABEL, &seltop);

   /* Determine the netid and the topmost object in which that    */
   /* net appears.  Then build the transformation matrix down     */
   /* to that object.  highlightnet() should end by popping the */
   /* entire matrix stack.                            */

   if (ggen != NULL) {
      if (checkvalid(topobject) == -1) {
         destroynets();
         createnets();
      }
      if ((netid = is_resolved(&ggen, seltop, &nettop)) != 0) {
         /* Fprintf(stdout, "Net ID is %d in object %s\n", netid, nettop->name); */
         depth = pushnetwork(seltop, nettop);
         /* Fprintf(stdout, ">> Pushed network %d levels deep\n", depth); */
         nextptr = seltop;
         while (nextptr->thisinst->thisobject != nettop)
          nextptr = nextptr->next;

       nextptr->thisinst->thisobject->highlight.netid = netid;
       nextptr->thisinst->thisobject->highlight.thisinst = nextptr->thisinst;
          
         highlightnet(nettop, nextptr->thisinst, netid, 1);

         /* pop the matrix stack */
         while (depth-- > 0) 
          UPopCTM();

       /* print the net name to the message window */

       ppin = nettopin(netid, nettop, NULL);
         snew = textprint(ppin, areastruct.topinstance);

       sprintf(_STR, "Network is \"%s\" in %s", snew, nettop->name);
       Wprintf(_STR);

#ifdef TCL_WRAPPER
       Tcl_SetObjResult(xcinterp, Tcl_NewStringObj(snew, strlen(snew)));
#endif
         free(snew);
      }
      else
       Wprintf("Selected element is not part of a valid network.");
   }
   else { 
      Wprintf("No networks found near the cursor position");
      netid = 0;
   }

   /* free up linked list */

   while (seltop != NULL) {
      nextptr = seltop->next;
      free(seltop);
      seltop = nextptr;
   }
   return netid;
}

/*--------------------------------------------------------------*/
/* Set object type to FUNDAMENTAL if it contains one or more      */
/* info labels and is not associated with a schematic/symbol.     */
/*                                              */
/* Return TRUE if the object has electrically relevant            */
/* networks, FALSE if not.                            */
/*--------------------------------------------------------------*/

Boolean setobjecttype(objectptr cschem)
{
   genericptr *cgen;
   labelptr clab;

   /* Apply only to schematic objects */

   if (cschem->schemtype != SCHEMATIC) {
      if (cschem->schemtype == FUNDAMENTAL)
       cschem->schemtype = SYMBOL;
      if (cschem->symschem == NULL) {
         for (cgen = cschem->plist; cgen < cschem->plist + cschem->parts; cgen++) {
            if ((*cgen)->type == LABEL) {
               clab = TOLABEL(cgen);
             if (clab->pin == INFO) {
                cschem->schemtype = FUNDAMENTAL;
                break;
             }
          }
         }
      }
   }

   if ((cschem->symschem != NULL) && (cschem->schemtype == SYMBOL))
      return False;
   else if ((cschem->schemtype == TRIVIAL) || (cschem->schemtype == FUNDAMENTAL))
      return False;

   return True;
}

/*------------------------------------------------------*/
/* Pin conversion subroutine for dopintype()          */
/*------------------------------------------------------*/

void pinconvert(labelptr thislab, pointertype mode)
{
   thislab->pin = mode;
   switch (mode) {
      case NORMAL:
       thislab->color = DEFAULTCOLOR;           /* nominally black */
       break;
      case GLOBAL:
       thislab->color = GLOBALPINCOLOR;   /* orange */
         break;
      case LOCAL:
       thislab->color = LOCALPINCOLOR;    /* red */
         break;
      case INFO:
       thislab->color = INFOLABELCOLOR;   /* green */
         break;
   }
}

/*---------------------------------------------------------*/
/* Change a label's type to NORMAL, GLOBAL, INFO, or LOCAL */
/*---------------------------------------------------------*/

void dopintype(xcWidget w, pointertype mode, caddr_t calldata)
{
   short *gsel;
   char typestr[40];
   short savetype = -1;

   if (areastruct.selects == 0) {
      Wprintf("Must first select a label to change type");
      return;
   }

   strcpy(typestr, "Changed label to ");
   switch(mode) {
      case NORMAL:
       strcat(typestr, "normal label");
         break;
      case GLOBAL:
       strcat(typestr, "global pin");
         break;
      case LOCAL:
       strcat(typestr, "local pin");
         break;
      case INFO:
       strcat(typestr, "info-label");
         break;
   }

   for (gsel = areastruct.selectlist; gsel < areastruct.selectlist +
            areastruct.selects; gsel++)
      if (SELECTTYPE(gsel) == LABEL) {
       labelptr glab = SELTOLABEL(gsel);
       savetype = glab->pin;
       pinconvert(glab, mode);
       setobjecttype(topobject);
      }

   if (savetype >= 0) {
      objectdeselect();
      drawarea(NULL, NULL, NULL);
      Wprintf(typestr);
   }
   else {
      Wprintf("No labels selected.");
   }
}

/*----------------------------------------------------------*/
/* Set colors on the symbol/schematic buttons appropriately */
/*----------------------------------------------------------*/

#ifdef TCL_WRAPPER

void setsymschem()
{
   /* This is temporary (hopefully). . . Call the Tcl function    */
   /* "setsymschem" which had better be defined by the wrapper.   */

   Tcl_SavedResult state;

   Tcl_SaveResult(xcinterp, &state);
   Tcl_Eval(xcinterp, "xcircuit::setsymschem");
   Tcl_RestoreResult(xcinterp, &state);
}

#else

void setsymschem()
{
   Arg aargs[2], bargs[2];

   /* Set menu items appropriately for this object */

   if (topobject->symschem != NULL) {
      if (topobject->schemtype == SCHEMATIC) {
         XtSetArg(aargs[0], XtNlabel, "Go To Symbol");
         XtSetArg(bargs[0], XtNlabel, "Disassociate Symbol");
      }
      else {
         XtSetArg(aargs[0], XtNlabel, "Go To Schematic");
         XtSetArg(bargs[0], XtNlabel, "Disassociate Schematic");
      }
   }
   else {
      if (topobject->schemtype == SCHEMATIC) {
         XtSetArg(aargs[0], XtNlabel, "Make Matching Symbol");
         XtSetArg(bargs[0], XtNlabel, "Associate with Symbol");
      }
      else {
         XtSetArg(aargs[0], XtNlabel, "Make Matching Schematic");
         XtSetArg(bargs[0], XtNlabel, "Associate with Schematic");
      }
   }
   XtSetValues(NetlistMakeMatchingSymbolButton, aargs, 1);
   XtSetValues(NetlistAssociatewithSymbolButton, bargs, 1);

   /* Set colors on the symbol and schematic buttons */

   if (topobject->schemtype == SCHEMATIC) {
      if (topobject->symschem == NULL) {
         XtSetArg(aargs[0], XtNbackground, OFFBUTTONCOLOR);
       XtSetArg(aargs[1], XtNforeground, OFFBUTTONCOLOR);
      }
      else {
         XtSetArg(aargs[0], XtNbackground, BACKGROUND);
       XtSetArg(aargs[1], XtNforeground, FOREGROUND);
      }

      XtSetArg(bargs[1], XtNforeground, FOREGROUND);
      XtSetArg(bargs[0], XtNbackground, SNAPCOLOR);
   }
   else {
      if (topobject->symschem != NULL) {
         XtSetArg(bargs[0], XtNbackground, BACKGROUND);
       XtSetArg(bargs[1], XtNforeground, FOREGROUND);
      }
      else {
         XtSetArg(bargs[0], XtNbackground, OFFBUTTONCOLOR);
       XtSetArg(bargs[1], XtNforeground, OFFBUTTONCOLOR);
      }

      XtSetArg(aargs[1], XtNforeground, FOREGROUND);
      if (topobject->schemtype == FUNDAMENTAL)
         XtSetArg(aargs[0], XtNbackground, AUXCOLOR);
      else if (topobject->schemtype == TRIVIAL || topobject->symschem != NULL)
         XtSetArg(aargs[0], XtNbackground, SNAPCOLOR);
      else {
         XtSetArg(aargs[0], XtNbackground, OFFBUTTONCOLOR);
       XtSetArg(aargs[1], XtNforeground, OFFBUTTONCOLOR);
         XtSetArg(bargs[0], XtNbackground, BBOXCOLOR);
         XtSetArg(bargs[1], XtNforeground, FOREGROUND);
      }
   }

   XtSetValues(wsymb, aargs, 2);
   XtSetValues(wschema, bargs, 2);
}

#endif

/*--------------------------------------------------------*/
/* Find the page number for an object                   */
/*--------------------------------------------------------*/

int findpageobj(objectptr pobj)
{
   int tpage;

   for (tpage = 0; tpage < xobjs.pages; tpage++)
      if (xobjs.pagelist[tpage]->pageinst != NULL)
         if (xobjs.pagelist[tpage]->pageinst->thisobject == pobj)
          return tpage;

   return -1;
}

/*------------------------------------------------------*/
/* Enumerate all of the pages which are subschematics   */
/* of "toppage" and return the result in the list     */
/* passed as a pointer.  The list is assumed to be    */
/* already allocated, and equal to the total number of      */
/* pages (xobjs.pages).                         */
/*                                        */
/* Avoid possible recursion problems by limiting the  */
/* number of recursion levels.  Presumably no circuit */
/* would have more than several hundred hierarchical  */
/* levels.                                */
/*------------------------------------------------------*/

int findsubschems(int toppage, objectptr cschem, int level, short *pagelist)
{
   genericptr *cgen;

   if (level == HIERARCHY_LIMIT) return -1;     /* sanity check */

   for (cgen = cschem->plist; cgen < cschem->plist + cschem->parts; cgen++) {
      if ((*cgen)->type == OBJECT) {
       objectptr cobj = TOOBJINST(cgen)->thisobject;

       if (cobj->symschem != NULL) {
          int pageno = findpageobj(cobj->symschem);
          if ((pageno >= 0) && (pageno < xobjs.pages))
            pagelist[pageno]++;

          /* A symbol on its own schematic page is allowed for clarity */
          /* of the schematic, but this cannot be a functional part of */
          /* the schematic circuit!                          */
          
          if (cobj->symschem != cschem) {
             if (findsubschems(toppage, cobj->symschem,
                        level + 1, pagelist) == -1)
              return -1;
          }
       }
       else if (cobj->schemtype != FUNDAMENTAL && cobj->schemtype != TRIVIAL) {
          /* Check symbols acting as their own schematics */
          if (findsubschems(toppage, cobj, level + 1, pagelist) == -1)
             return -1;
       }
      }
   }
   return 0;
}

/*-------------------------------------------------------*/
/* Recursively find all sub-circuits associated with the */
/* top-level circuit and set their filenames to be the       */
/* same.                                   */
/*-------------------------------------------------------*/

void collectsubschems(int toppage)
{
   int level = 0;
   objectptr cschem;
   short *pagelist, pageno;

   if (xobjs.pagelist[toppage]->pageinst == NULL) return;

   cschem = xobjs.pagelist[toppage]->pageinst->thisobject;

   pagelist = (short *)malloc(xobjs.pages * sizeof(short));

   for (pageno = 0; pageno < xobjs.pages; pageno++)
      pagelist[pageno] = 0;

   findsubschems(toppage, cschem, 0, pagelist);

   for (pageno = 0; pageno < xobjs.pages; pageno++) {
      if (pagelist[pageno] > 0) {
        if (xobjs.pagelist[pageno]->filename != NULL)
           free(xobjs.pagelist[pageno]->filename);
        xobjs.pagelist[pageno]->filename =
           strdup(xobjs.pagelist[toppage]->filename);
      }
   } 
   free((char *)pagelist);
}

/*--------------------------------------------------------*/
/* Copy label to corresponding schematic/symbol         */
/*--------------------------------------------------------*/

void copypinlabel(labelptr pinlab)
{
   labelptr *newlabel, tlabel;
   genericptr *tgen;
   objectptr schemobj = topobject->symschem;

   if (areastruct.schemon && schemobj != NULL && (pinlab->pin == LOCAL)) {

      /* If this pin already exists, don't copy it */

      for (tgen = schemobj->plist; tgen < schemobj->plist + schemobj->parts;
            tgen++) {
         if ((*tgen)->type == LABEL) {
          tlabel = TOLABEL(tgen);
          if (!stringcomp(tlabel->string, pinlab->string)) return;
         }
      }

      NEW_LABEL(newlabel, schemobj);
      (*newlabel)->pin = pinlab->pin;
      (*newlabel)->rotation = pinlab->rotation;
      (*newlabel)->justify = pinlab->justify;
      (*newlabel)->color = pinlab->color;
      (*newlabel)->scale = pinlab->scale;
      (*newlabel)->string = stringcopy(pinlab->string);
      (*newlabel)->num_params = 0;
      (*newlabel)->passed = NULL;

      /* place label just outside bounding box, then recompute bbox */

      (*newlabel)->position.x = schemobj->bbox.lowerleft.x + (schemobj->bbox.width >> 1);
      (*newlabel)->position.y = schemobj->bbox.lowerleft.y - TEXTHEIGHT
         * (*newlabel)->scale;
      schemobj->parts++;
      incr_changes(schemobj);
      schemobj->valid = False;
      singlebbox(ENDPART);
   }
}

/*-------------------------------------------------------*/
/* Check if top-level page is the same name as a library */
/* object; if so, connect it.                    */
/* Note that it is not an error not to find the matching */
/* symbol/schematic.  "is_schematic" and "is_symbol"   */
/* comments in the .ps file are complementary, so the  */
/* first one encountered will always fail, and the other */
/* will succeed.                           */
/*-------------------------------------------------------*/

int checkschem(objectptr thisobj, char *cname)
{
   objectptr *tlib;
   short i, j;

   if (areastruct.schemon == False || thisobj->symschem != NULL) return 0;

   for (i = 0; i < xobjs.numlibs; i++) {
      for (j = 0; j < xobjs.userlibs[i].number; j++) {
       tlib = xobjs.userlibs[i].library + j;

         if (!strcmp(cname, (*tlib)->name)) {
          thisobj->symschem = (*tlib);
          thisobj->schemtype = SCHEMATIC;
          (*tlib)->symschem = thisobj;
          (*tlib)->schemtype = SYMBOL;
          return 1;
       }
      }
   }
   return 0;
}

/*--------------------------------------------------------*/
/* Complement to the above routine:  If a library object  */
/* name is the same as a top-level page, connect them.        */
/*--------------------------------------------------------*/

int checksym(objectptr symobj, char *cname)
{
   short cpage;
   objectptr checkpage;

   if (areastruct.schemon == False || symobj->symschem != NULL) return 0;

   for (cpage = 0; cpage < xobjs.pages; cpage++) {
      if (xobjs.pagelist[cpage]->pageinst != NULL) {
         checkpage = xobjs.pagelist[cpage]->pageinst->thisobject;
         if (!strcmp(checkpage->name, cname)) {
          symobj->symschem = checkpage;
          symobj->schemtype = SYMBOL;
          checkpage->symschem = symobj;
          checkpage->schemtype = SCHEMATIC;
          return 1;
       }
      }
   }
   return 0;
}

/*----------------------------------------------------------------------*/
/* Find location of corresponding pin in symbol/schematic and change it */
/* to the text of the indicated label.  If "newlabel" is NULL, then     */
/* change the other label from pin to normal text.                */
/*----------------------------------------------------------------------*/

void changeotherpins(labelptr newlabel, stringpart *oldstring)
{
   objectptr other = topobject->symschem;
   genericptr *tgen;
   labelptr tlab;

   if (other == NULL) return;

   for (tgen = other->plist; tgen < other->plist + other->parts; tgen++) {
      if ((*tgen)->type == LABEL) {
       tlab = TOLABEL(tgen);
       if (!stringcomp(tlab->string, oldstring)) {
          if (newlabel != NULL) {
             free(tlab->string);
             tlab->string = stringcopy(newlabel->string);
          }
          else
             tlab->pin = NORMAL;
       }
      }
   }
}

/*----------------------------------------------------------------------*/
/* Swap object schematic and symbol pages.                        */
/*  mode = 0 disallows creation of a new schematic or symbol; i.e., if  */
/*  there is no corresponding schematic/symbol, nothing happens.  */
/*----------------------------------------------------------------------*/

void swapschem(xcWidget w, pointertype mode, caddr_t calldata)
{
   objectptr savepage = topobject;
   labelptr  *pinlab;
   genericptr *plab;
   Boolean lflag;
   pushlistptr stacktop;

   if (areastruct.schemon == False) return;

   if (eventmode == PRESS_MODE || eventmode == COPY2_MODE)
      objectdelete(NORMAL);

   /* Create symbol or schematic, if allowed by mode */

   if ((topobject->symschem == NULL) && (mode != 0)) {
      if (topobject->schemtype != SCHEMATIC) {
       int tpage;

       /* create a new page for the new schematic */

       for (tpage = 0; tpage < xobjs.pages; tpage++)
          if (xobjs.pagelist[tpage]->pageinst == NULL) break;

       /* Push the current instance onto the push stack */
       /* Change the page without destroying the pushlist */

       push_stack(&areastruct.stack, areastruct.topinstance);
       stacktop = areastruct.stack;
       areastruct.stack = NULL;
         changepage(tpage);
       areastruct.stack = stacktop;
      }
      else {
       objectptr *newobject;
       short libnum = USERLIB - LIBRARY;

       /* create a new library object for the new symbol */

       xobjs.userlibs[libnum].library = (objectptr *)
            realloc(xobjs.userlibs[libnum].library,
            ++xobjs.userlibs[libnum].number * sizeof(objectptr));
       newobject = xobjs.userlibs[libnum].library
            + xobjs.userlibs[libnum].number - 1;
         *newobject = (objectptr) malloc(sizeof(object));
       initmem(*newobject);
       (*newobject)->schemtype = SYMBOL;
       (*newobject)->hidden = False;
       (*newobject)->devname = NULL;

       incr_changes(*newobject);

       /* Generate a library instance for this object and set the */
       /* top instance to point to it.                    */

       push_stack(&areastruct.stack, areastruct.topinstance);
       areastruct.topinstance = addtoinstlist(libnum, *newobject, FALSE);

       /* Generate the default bounding box for a size-zero object */
       calcbbox(areastruct.topinstance);
      }

      /* set links between the two objects */

      savepage->symschem = topobject;
      topobject->symschem = savepage;

      /* make the name of the new object equal to that of the old */

      strcpy(topobject->name, savepage->name);

      /* copy all pin labels into the new object */

      for (plab = savepage->plist; plab < savepage->plist + savepage->parts;
            plab++) {
       if ((*plab)->type == LABEL) {
          genericptr *tgen;
          labelptr tlab, lpin = (labelptr)*plab;

          if (lpin->pin == LOCAL) {

                   /* Only make one copy of each pin name */

             lflag = False;
               for (tgen = topobject->plist; tgen <
                  topobject->plist + topobject->parts; tgen++) {
              if ((*tgen)->type == LABEL) {
                 tlab = TOLABEL(tgen);
                   if (!stringcomp(tlab->string, lpin->string)) lflag = True;
              }
                   }
             if (lflag == True) continue;

             NEW_LABEL(pinlab, topobject);
             (*pinlab)->pin = lpin->pin;
             (*pinlab)->color = lpin->color;
             (*pinlab)->rotation = 0;
             (*pinlab)->scale = 1.0;
             (*pinlab)->justify = areastruct.justify; 
             (*pinlab)->position.x = 0;
             (*pinlab)->position.y = topobject->parts * (TEXTHEIGHT + 10);
             (*pinlab)->num_params = 0;
             (*pinlab)->passed = NULL;
             u2u_snap(&((*pinlab)->position));
             (*pinlab)->string = stringcopy(lpin->string);
             topobject->parts++;
             incr_changes(topobject);
          }
         }
      }
      calcbbox(areastruct.topinstance);

      /* Recreate the user library with the new symbol */
      if (savepage->schemtype != SYMBOL) composelib(USERLIB);
   }
   else if (topobject->symschem != NULL) {

      /* If symschem matches the last entry on the push stack, then we  */
      /* pop; otherwise, we push.                           */

      if (areastruct.stack && areastruct.stack->thisinst->thisobject == topobject->symschem) {
       areastruct.topinstance = areastruct.stack->thisinst;
       pop_stack(&areastruct.stack);
      }
      else {
       int p;
       objinstptr syminst = NULL;
       liblistptr symlist;

       /* If symschem is a schematic, find the appropriate page */

       for (p = 0; p < xobjs.pages; p++) {
          syminst = xobjs.pagelist[p]->pageinst;
          if (syminst != NULL)
             if (syminst->thisobject == topobject->symschem)
              break;
       }
       if (p == xobjs.pages) {

          /* If symschem is a symbol, and it wasn't on the push stack, */
          /* get the library default symbol and go there.          */

          for (p = 0; p < xobjs.numlibs; p++) {
             for (symlist = xobjs.userlibs[p].instlist; symlist != NULL;
                  symlist = symlist->next) {
                syminst = symlist->thisinst;
                if (syminst->thisobject == topobject->symschem &&
                  symlist->virtual == FALSE)
                 break;
             }
             if (symlist != NULL) break;
          }
          if (p == xobjs.numlibs) {
             Fprintf(stderr, "swapschem(): BAD SYMSCHEM\n");
             return;
          }
         }
             
       push_stack(&areastruct.stack, areastruct.topinstance);
       areastruct.topinstance = syminst;
      }
   }

   /* If there was no action, then there is nothing more to do. */

   if (topobject == savepage) return;

   setpage(TRUE);
   transferselects();
   refresh(NULL, NULL, NULL);
   setsymschem();
}

/*----------------------------------------------------------------------*/
/* Wrapper for swapschem() when generating a new symbol.          */
/*----------------------------------------------------------------------*/

void makesymbol(xcWidget w, caddr_t calldata)
{
   /* copy name from popup prompt buffer and check */

   strcpy(topobject->name, _STR2);
   checkname(topobject);
   swapschem(w, (pointertype)1, calldata);
}

/*----------------------------------------------------------------------*/
/* Check name before doing a swap:  If name begins with "Page", prompt  */
/* for the object name, as you would when doing selectsave().           */ 
/*----------------------------------------------------------------------*/

void dobeforeswap(xcWidget w, caddr_t clientdata, caddr_t calldata)
{
   buttonsave *popdata = (buttonsave *)malloc(sizeof(buttonsave));

   /* Check if this function is valid */

   if (areastruct.schemon == False) return;

   /* Check for requirement to change the name before creating the symbol */

   if ((topobject->symschem == NULL) && (topobject->schemtype == SCHEMATIC)
            && (strstr(topobject->name, "Page ") != NULL)) {

      /* Get a name for the new object */

      eventmode = NORMAL_MODE;
      popdata->dataptr = NULL;
      popdata->button = NULL; /* indicates that no button is assc'd w/ the popup */
      popupprompt(w, "Enter name for new object:", "\0", makesymbol, popdata, NULL);
   }
   else
      swapschem(w, (pointertype)1, calldata);
}

/*------------------------------------------*/
/* Disassociate a symbol from its schematic */
/*------------------------------------------*/

void schemdisassoc()
{
   if (eventmode != NORMAL) {
      Wprintf("Cannot disassociate schematics in this mode");
   }
   else {
      topobject->symschem->symschem = NULL;
      topobject->symschem = NULL;
      setsymschem();
      Wprintf("Schematic and symbol are now unlinked.");
   }
}

/*--------------------------------------------------------------*/
/* Schematic<-->symbol association.  Determine whether action     */
/* acts on a symbol or a schematic from context.            */
/* mode == 0 associate only.                          */
/* mode == 1 determine action (associate or disassociate) from    */
/* context (toggle)                                   */
/*--------------------------------------------------------------*/

void startschemassoc(xcWidget w, pointertype mode, caddr_t calldata)
{
   if ((topobject->symschem != NULL) && (mode == 1))
      schemdisassoc();
   else if ((topobject->symschem != NULL) && (mode == 0)) {
      Wprintf("Refusing to undo current association.");
   }
   else {
      eventmode = ASSOC_MODE;
      if (topobject->schemtype == SCHEMATIC) {
       /* Find a symbol to associate */
       startcatalog(w, LIBLIB, NULL);
       Wprintf("Click on library page, then symbol to associate.");
      }
      else {
       /* Find a schematic (page) to associate */
       startcatalog(w, PAGELIB, NULL);
       Wprintf("Click on schematic page to associate.");
      }
   }
}

/*--------------------------------------------------------------*/
/* Callback procedures on the schematic/symbol buttons.           */
/*--------------------------------------------------------------*/

Boolean schemassoc(objectptr schemobj, objectptr symbolobj)
{
   if (eventmode != ASSOC_MODE) {
      Wprintf("Cannot make (dis)association in this mode");
#if TCL_WRAPPER
      Tcl_SetResult(xcinterp, "Cannot make association in this mode.", NULL);
#endif
      return False;
   }
   else if (schemobj->symschem != NULL || symbolobj->symschem != NULL) {
      Wprintf("Both objects must be disassociated first.");
#if TCL_WRAPPER
      Tcl_SetResult(xcinterp, "Both objects must be disassociated first.", NULL);
#endif
      return False;
   }
   else {
      schemobj->symschem = symbolobj;
      symbolobj->symschem = schemobj;
      if (symbolobj->schemtype == TRIVIAL)
       symbolobj->schemtype = SYMBOL;

      /* Schematic takes the name of its associated symbol, by default */
      strcpy(schemobj->name, symbolobj->name);

      /* Ensure that schematic (page) name is unique */
      while (checkpagename(schemobj) < 0);
      setsymschem();    /* Set buttons and menu items appropriately */
   }
   return True;
}

#endif
/*-------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index