Added a screen resolution check in preparation for handling retinal
[xcircuit.git] / schema.c
blobfcd14fb8ead8cf5b21783c184c8e7adc3818fe95
1 /*-------------------------------------------------------------------------*/
2 /* schema.c --- xcircuit routines specific to the schematic capture system */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 /*-------------------------------------------------------------------------*/
7 /* written by Tim Edwards, 10/13/97 */
8 /*-------------------------------------------------------------------------*/
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #ifndef XC_WIN32
15 #include <X11/Intrinsic.h>
16 #include <X11/StringDefs.h>
17 #endif
19 #ifdef TCL_WRAPPER
20 #include <tk.h>
21 #else
22 #ifndef XC_WIN32
23 #include "Xw/Xw.h"
24 #include "Xw/MenuBtn.h"
25 #endif
26 #endif
28 /*-------------------------------------------------------------------------*/
29 /* Local includes */
30 /*-------------------------------------------------------------------------*/
32 #include "xcircuit.h"
33 #include "colordefs.h"
34 #include "menudep.h"
36 /*----------------------------------------------------------------------*/
37 /* Function prototype declarations */
38 /*----------------------------------------------------------------------*/
39 #include "prototypes.h"
41 /*------------------------------------------------------------------------*/
42 /* External Variable definitions */
43 /*------------------------------------------------------------------------*/
45 #ifdef TCL_WRAPPER
46 extern Tcl_Interp *xcinterp;
47 #endif
49 extern Globaldata xobjs;
50 extern XCWindowData *areawin;
51 extern xcWidget menuwidgets[];
52 extern xcWidget netbutton;
53 extern char _STR[150];
54 extern char _STR2[250];
55 extern colorindex *colorlist;
57 /*-------------------------------------------------------------------------*/
59 extern xcWidget wsymb, wschema;
61 /*--------------------------------------------------------*/
62 /* Menu calls (procedure wrappers) */
63 /*--------------------------------------------------------*/
65 void callwritenet(xcWidget w, pointertype mode, caddr_t calldata)
67 switch(mode) {
68 case 0:
69 writenet(topobject, "spice", "spc");
70 break;
71 case 1:
72 writenet(topobject, "flatsim", "sim");
73 break;
74 case 2:
75 writenet(topobject, "pcb", "pcbnet");
76 break;
77 case 3:
78 writenet(topobject, "flatspice", "fspc");
79 break;
80 case 4:
81 /* Auto-numbering: no output generated */
82 writenet(topobject, "indexpcb", "");
83 break;
87 /*----------------------------------------------------------------------*/
88 /* Find the page object and instance with the indicated name. */
89 /*----------------------------------------------------------------------*/
91 objectptr NameToPageObject(char *objname, objinstptr *ret_inst, int *ret_page)
93 int i;
95 for (i = 0; i < xobjs.pages; i++) {
96 if (xobjs.pagelist[i]->pageinst == NULL) continue;
97 if (!strcmp(objname, xobjs.pagelist[i]->pageinst->thisobject->name)) {
98 if (ret_inst) *ret_inst = xobjs.pagelist[i]->pageinst;
99 if (ret_page) *ret_page = i;
100 return xobjs.pagelist[i]->pageinst->thisobject;
103 return NULL;
106 /*--------------------------------------------------------------*/
107 /* Get the canonical name of an object (the part without the */
108 /* technology prefix, if any). */
109 /*--------------------------------------------------------------*/
111 char *GetCanonicalName(char *fullname)
113 char *canonname = strstr(fullname, "::");
114 if (canonname == NULL) return fullname;
115 return canonname + 2;
118 /*----------------------------------------------------------------------*/
119 /* Find the object with the indicated name. */
120 /* */
121 /* WARNING: If no library technology is given, XCircuit will return */
122 /* the first object with the name "objname". If there are multiple */
123 /* objects of the same name in different technologies, then the one */
124 /* returned may not be the one expected! */
125 /*----------------------------------------------------------------------*/
127 objectptr NameToObject(char *objname, objinstptr *ret_inst, Boolean dopages)
129 int i;
130 liblistptr spec;
131 Boolean notech = FALSE;
132 char *techptr;
134 if (strstr(objname, "::") == NULL) notech = TRUE;
136 for (i = 0; i < xobjs.numlibs; i++) {
137 for (spec = xobjs.userlibs[i].instlist; spec != NULL; spec = spec->next) {
138 techptr = spec->thisinst->thisobject->name;
139 if (notech)
140 techptr = GetCanonicalName(spec->thisinst->thisobject->name);
141 if (!strcmp(objname, techptr)) {
142 if (ret_inst) *ret_inst = spec->thisinst;
143 return spec->thisinst->thisobject;
148 if (dopages)
149 return NameToPageObject(objname, ret_inst, NULL);
150 else
151 return NULL;
154 /*------------------------------------------------------------------------*/
155 /* Ensure that a page name is unique (required for schematic association) */
156 /*------------------------------------------------------------------------*/
158 int checkpagename(objectptr thispageobj)
160 int p, thispage;
161 /* char *objname = thispageobj->name; (jdk) */
162 Boolean changed;
163 Boolean update = False;
164 char *clnptr = NULL;
165 int n;
167 /* Check for ":n" suffix and prepare for possible update */
168 clnptr = strrchr(thispageobj->name, ':');
169 if (clnptr != NULL)
170 if (sscanf(clnptr + 1, "%d", &n) != 1)
171 clnptr = NULL;
173 /* Find the page number of this page object */
174 for (p = 0; p < xobjs.pages; p++) {
175 if (xobjs.pagelist[p]->pageinst != NULL) {
176 if (xobjs.pagelist[p]->pageinst->thisobject == thispageobj) {
177 thispage = p;
178 break;
182 if (p == xobjs.pages) {
183 Fprintf(stderr, "Error: Object is not a page object!\n");
184 return 0;
187 /* Look for any other pages with the same name */
188 do {
189 changed = False;
190 for (p = 0; p < xobjs.pages; p++) {
191 if (p == thispage) continue;
192 if (xobjs.pagelist[p]->pageinst != NULL) {
193 if (!filecmp(xobjs.pagelist[p]->pageinst->thisobject->name,
194 thispageobj->name)) {
195 /* append ":2" to name or update suffix to ensure uniqueness */
196 if (clnptr == NULL)
197 sprintf(thispageobj->name, "%s:2", thispageobj->name);
198 else
199 sprintf(clnptr + 1, "%d", n + 1);
200 changed = True;
201 update = True;
202 break;
206 } while (changed);
207 if (update) {
208 renamepage(thispage);
209 return -1;
211 return 0;
214 /*--------------------------------------*/
215 /* Find connectivity of a selection */
216 /*--------------------------------------*/
218 void startconnect(xcWidget button, caddr_t clientdata, caddr_t calldata)
220 if (areawin->selects > 0)
221 connectivity(button, clientdata, calldata);
224 /*----------------------------------------------------------------------*/
225 /* connectivity(): Find electrical connections into a node. */
226 /* (does recursive search on object heirarchy) */
227 /*----------------------------------------------------------------------*/
229 void connectivity(xcWidget button, caddr_t clientdata, caddr_t calldata)
231 short *gsel = NULL;
232 selection *rselect = NULL, *nextselect;
233 genericptr ggen = NULL;
234 Genericlist *netlist = NULL;
235 int depth, lbus, netid, subnetid;
236 buslist *sbus;
237 pushlistptr seltop, nextptr;
238 objectptr nettop, pschem; /* thisobj, (jdk) */
239 char *snew;
240 stringpart *ppin;
242 /* erase any existing highlighted network */
243 highlightnetlist(topobject, areawin->topinstance, 0);
245 seltop = (pushlistptr)malloc(sizeof(pushlist));
246 seltop->thisinst = areawin->topinstance;
247 seltop->next = NULL;
249 /* pick the first selection that looks like a valid network part */
251 if (areawin->selects > 0) {
252 for (gsel = areawin->selectlist; gsel < areawin->selectlist +
253 areawin->selects; gsel++) {
254 ggen = *(topobject->plist + *gsel);
255 if (SELECTTYPE(gsel) == LABEL) {
256 labelptr glab = SELTOLABEL(gsel);
257 if (glab->pin == LOCAL || glab->pin == GLOBAL) break;
259 else if (SELECTTYPE(gsel) == POLYGON) {
260 polyptr gpoly = SELTOPOLY(gsel);
261 if (!nonnetwork(gpoly)) break;
265 if ((areawin->selects == 0) || (gsel == areawin->selectlist
266 + areawin->selects)) {
267 rselect = recurselect(POLYGON | LABEL | OBJINST, MODE_CONNECT, &seltop);
268 /* Should look at the top scorer, when scoring has been implemented */
269 if (rselect && (rselect->selects > 0)) {
270 for (nextselect = rselect; (nextselect->next != NULL) &&
271 (nextselect->selects > 0); nextselect = nextselect->next);
272 ggen = *(nextselect->thisinst->thisobject->plist + *(nextselect->selectlist));
273 while (rselect != NULL) {
274 nextselect = rselect->next;
275 free(rselect->selectlist);
276 free(rselect);
277 rselect = nextselect;
282 /* Determine the net and the topmost object in which that */
283 /* net appears. Then build the transformation matrix down */
284 /* to that object. highlightnet() should end by popping the */
285 /* entire matrix stack. */
287 if (ggen != NULL) {
288 if (checkvalid(topobject) == -1) {
289 destroynets(topobject);
290 createnets(areawin->topinstance, FALSE);
292 if ((netlist = is_resolved(&ggen, seltop, &nettop)) != NULL) {
293 depth = pushnetwork(seltop, nettop);
294 /* Fprintf(stdout, ">> Pushed network %d levels deep\n", depth); */
295 nextptr = seltop;
296 while (nextptr->thisinst->thisobject != nettop)
297 nextptr = nextptr->next;
299 nextptr->thisinst->thisobject->highlight.netlist = netlist;
300 nextptr->thisinst->thisobject->highlight.thisinst = nextptr->thisinst;
301 highlightnetlist(nettop, nextptr->thisinst, 1);
303 /* pop the matrix stack */
304 while (depth-- > 0)
305 UPopCTM();
307 /* get the primary schematic */
308 pschem = (nettop->schemtype == SECONDARY) ? nettop->symschem : nettop;
310 /* print the net name to the message window */
312 if (netlist->subnets == 0) {
313 ppin = nettopin(netlist->net.id, pschem, NULL);
314 snew = textprint(ppin, areawin->topinstance);
315 sprintf(_STR2, "Network is \"%s\" in %s", snew, nettop->name);
316 free(snew);
318 else {
319 char *sptr;
320 sprintf(_STR2, "Network(s): ");
321 sptr = _STR2 + strlen(_STR2);
322 for (lbus = 0; lbus < netlist->subnets; lbus++) {
323 sbus = netlist->net.list + lbus;
324 netid = sbus->netid;
325 subnetid = sbus->subnetid;
326 ppin = nettopin(netid, pschem, NULL);
327 snew = textprintsubnet(ppin, areawin->topinstance, subnetid);
328 sprintf(sptr, "%s ", snew);
329 sptr += strlen(snew) + 1;
330 free(snew);
332 sprintf(sptr, "in %s", nettop->name);
334 Wprintf("%s", _STR2);
336 #ifdef TCL_WRAPPER
337 Tcl_SetObjResult(xcinterp, Tcl_NewStringObj(snew, strlen(snew)));
338 #endif
340 else
341 Wprintf("Selected element is not part of a valid network.");
343 else {
344 Wprintf("No networks found near the cursor position");
345 netid = 0;
348 /* free up linked list */
350 while (seltop != NULL) {
351 nextptr = seltop->next;
352 free(seltop);
353 seltop = nextptr;
357 /*--------------------------------------------------------------*/
358 /* Set object type to FUNDAMENTAL if it contains one or more */
359 /* info labels and is not associated with a schematic/symbol. */
360 /* */
361 /* Return TRUE if the object has electrically relevant */
362 /* networks, FALSE if not. */
363 /*--------------------------------------------------------------*/
365 Boolean setobjecttype(objectptr cschem)
367 genericptr *cgen;
368 labelptr clab;
370 /* If networks are specifically prohibited. . . */
371 if (cschem->schemtype == NONETWORK) return False;
373 /* Apply only to schematic objects */
375 if ((cschem->schemtype != PRIMARY) && (cschem->schemtype != SECONDARY)) {
376 if (cschem->schemtype == FUNDAMENTAL)
377 cschem->schemtype = SYMBOL;
378 if (cschem->symschem == NULL) {
379 for (cgen = cschem->plist; cgen < cschem->plist + cschem->parts; cgen++) {
380 if (IS_LABEL(*cgen)) {
381 clab = TOLABEL(cgen);
382 if (clab->pin == INFO) {
383 cschem->schemtype = FUNDAMENTAL;
384 break;
391 if ((cschem->symschem != NULL) && (cschem->schemtype == SYMBOL))
392 return False;
393 else if ((cschem->schemtype == TRIVIAL) || (cschem->schemtype == FUNDAMENTAL))
394 return False;
396 return True;
399 /*------------------------------------------------------*/
400 /* Pin conversion subroutine for dopintype() */
401 /*------------------------------------------------------*/
403 void pinconvert(labelptr thislab, pointertype mode)
405 thislab->pin = mode;
406 switch (mode) {
407 case NORMAL:
408 thislab->color = DEFAULTCOLOR; /* nominally black */
409 break;
410 case GLOBAL:
411 thislab->color = GLOBALPINCOLOR; /* orange */
412 break;
413 case LOCAL:
414 thislab->color = LOCALPINCOLOR; /* red */
415 break;
416 case INFO:
417 thislab->color = INFOLABELCOLOR; /* green */
418 break;
422 /*---------------------------------------------------------*/
423 /* Change a label's type to NORMAL, GLOBAL, INFO, or LOCAL */
424 /*---------------------------------------------------------*/
426 void dopintype(xcWidget w, pointertype mode, caddr_t calldata)
428 short *gsel;
429 char typestr[40];
430 short savetype = -1;
432 if (areawin->selects == 0) {
433 Wprintf("Must first select a label to change type");
434 return;
437 strcpy(typestr, "Changed label to ");
438 switch(mode) {
439 case NORMAL:
440 strcat(typestr, "normal label");
441 break;
442 case GLOBAL:
443 strcat(typestr, "global pin");
444 break;
445 case LOCAL:
446 strcat(typestr, "local pin");
447 break;
448 case INFO:
449 strcat(typestr, "info-label");
450 break;
453 for (gsel = areawin->selectlist; gsel < areawin->selectlist +
454 areawin->selects; gsel++)
455 if (SELECTTYPE(gsel) == LABEL) {
456 labelptr glab = SELTOLABEL(gsel);
457 savetype = glab->pin;
458 pinconvert(glab, mode);
459 setobjecttype(topobject);
462 if (savetype >= 0) {
463 unselect_all();
464 drawarea(NULL, NULL, NULL);
465 Wprintf("%s", typestr);
467 else {
468 Wprintf("No labels selected.");
472 /*----------------------------------------------------------*/
473 /* Set colors on the symbol/schematic buttons appropriately */
474 /*----------------------------------------------------------*/
476 #ifdef TCL_WRAPPER
478 void setsymschem()
480 XcInternalTagCall(xcinterp, 1, "schematic");
483 #else
485 void setsymschem()
487 Arg aargs[2], bargs[2];
489 /* Set menu items appropriately for this object */
491 if (topobject->symschem != NULL) {
492 if (topobject->schemtype == PRIMARY || topobject->schemtype == SECONDARY) {
493 XtSetArg(aargs[0], XtNlabel, "Go To Symbol");
494 XtSetArg(bargs[0], XtNlabel, "Disassociate Symbol");
496 else {
497 XtSetArg(aargs[0], XtNlabel, "Go To Schematic");
498 XtSetArg(bargs[0], XtNlabel, "Disassociate Schematic");
501 else {
502 if (topobject->schemtype == PRIMARY || topobject->schemtype == SECONDARY) {
503 XtSetArg(aargs[0], XtNlabel, "Make Matching Symbol");
504 XtSetArg(bargs[0], XtNlabel, "Associate with Symbol");
506 else {
507 XtSetArg(aargs[0], XtNlabel, "Make Matching Schematic");
508 XtSetArg(bargs[0], XtNlabel, "Associate with Schematic");
511 XtSetValues(NetlistMakeMatchingSymbolButton, aargs, 1);
512 XtSetValues(NetlistAssociatewithSymbolButton, bargs, 1);
514 /* Set colors on the symbol and schematic buttons */
516 if (topobject->schemtype == PRIMARY || topobject->schemtype == SECONDARY) {
517 if (topobject->symschem == NULL) {
518 XtSetArg(aargs[0], XtNbackground, colorlist[OFFBUTTONCOLOR].color.pixel);
519 XtSetArg(aargs[1], XtNforeground, colorlist[OFFBUTTONCOLOR].color.pixel);
521 else {
522 XtSetArg(aargs[0], XtNbackground, colorlist[BACKGROUND].color.pixel);
523 XtSetArg(aargs[1], XtNforeground, colorlist[FOREGROUND].color.pixel);
526 XtSetArg(bargs[1], XtNforeground, colorlist[FOREGROUND].color.pixel);
527 XtSetArg(bargs[0], XtNbackground, colorlist[SNAPCOLOR].color.pixel);
529 else {
530 if (topobject->symschem != NULL) {
531 XtSetArg(bargs[0], XtNbackground, colorlist[BACKGROUND].color.pixel);
532 XtSetArg(bargs[1], XtNforeground, colorlist[FOREGROUND].color.pixel);
534 else {
535 XtSetArg(bargs[0], XtNbackground, colorlist[OFFBUTTONCOLOR].color.pixel);
536 XtSetArg(bargs[1], XtNforeground, colorlist[OFFBUTTONCOLOR].color.pixel);
539 XtSetArg(aargs[1], XtNforeground, colorlist[FOREGROUND].color.pixel);
540 if (topobject->schemtype == FUNDAMENTAL)
541 XtSetArg(aargs[0], XtNbackground, colorlist[AUXCOLOR].color.pixel);
542 else if (topobject->schemtype == TRIVIAL || topobject->symschem != NULL)
543 XtSetArg(aargs[0], XtNbackground, colorlist[SNAPCOLOR].color.pixel);
544 else {
545 XtSetArg(aargs[0], XtNbackground, colorlist[OFFBUTTONCOLOR].color.pixel);
546 XtSetArg(aargs[1], XtNforeground, colorlist[OFFBUTTONCOLOR].color.pixel);
547 XtSetArg(bargs[0], XtNbackground, colorlist[BBOXCOLOR].color.pixel);
548 XtSetArg(bargs[1], XtNforeground, colorlist[FOREGROUND].color.pixel);
552 XtSetValues(wsymb, aargs, 2);
553 XtSetValues(wschema, bargs, 2);
556 #endif
558 /*--------------------------------------------------------*/
559 /* Find the page number for an object */
560 /*--------------------------------------------------------*/
562 int findpageobj(objectptr pobj)
564 int tpage;
566 for (tpage = 0; tpage < xobjs.pages; tpage++)
567 if (xobjs.pagelist[tpage]->pageinst != NULL)
568 if (xobjs.pagelist[tpage]->pageinst->thisobject == pobj)
569 return tpage;
571 return -1;
574 /*------------------------------------------------------*/
575 /* Enumerate all of the pages which are subschematics */
576 /* of "toppage" and return the result in the list */
577 /* passed as a pointer. The list is assumed to be */
578 /* already allocated, and equal to the total number of */
579 /* pages (xobjs.pages). */
580 /* */
581 /* Avoid possible recursion problems by limiting the */
582 /* number of recursion levels. Presumably no circuit */
583 /* would have more than several hundred hierarchical */
584 /* levels. */
585 /* */
586 /* If "dolinks" is TRUE, ennumerate and follow pages */
587 /* that are descendents of the top level when the */
588 /* calling symbol instance has a "link" parameter and */
589 /* that parameter points to the same filename as the */
590 /* page. This indicates a multiple-file project; the */
591 /* pages keep separate records of changes, and are */
592 /* saved independently, and loaded through the link */
593 /* dependency method. */
594 /*------------------------------------------------------*/
596 int findsubschems(int toppage, objectptr cschem, int level, short *pagelist,
597 Boolean dolinks)
599 genericptr *cgen;
601 if (level == HIERARCHY_LIMIT) return -1; /* sanity check */
603 for (cgen = cschem->plist; cgen < cschem->plist + cschem->parts; cgen++) {
604 if (IS_OBJINST(*cgen)) {
605 objinstptr cinst = TOOBJINST(cgen);
606 objectptr cobj = cinst->thisobject;
608 if (cobj->symschem != NULL) {
609 int pageno = findpageobj(cobj->symschem);
611 if ((pageno >= 0) && (pageno < xobjs.pages)) {
613 /* Look for a "link" parameter */
614 if (dolinks == FALSE) {
615 oparamptr ops;
616 ops = find_param(cinst, "link");
617 if ((ops != NULL) && (ops->type == XC_STRING)) {
618 char *filename = textprint(ops->parameter.string, cinst);
619 if (!strcmp(filename, "%n") || !strcmp(filename, "%N") ||
620 !strcmp(filename, xobjs.pagelist[pageno]->filename)) {
621 free(filename);
622 continue;
624 free(filename);
628 /* Add this page to the list */
629 pagelist[pageno]++;
632 /* A symbol on its own schematic page is allowed for clarity */
633 /* of the schematic, but this cannot be a functional part of */
634 /* the schematic circuit! */
636 if (cobj->symschem != cschem) {
637 if (findsubschems(toppage, cobj->symschem,
638 level + 1, pagelist, dolinks) == -1)
639 return -1;
642 else if (cobj->schemtype != FUNDAMENTAL && cobj->schemtype != TRIVIAL) {
643 /* Check symbols acting as their own schematics */
644 if (findsubschems(toppage, cobj, level + 1, pagelist, dolinks) == -1)
645 return -1;
649 return 0;
652 /*------------------------------------------------------*/
653 /* Recursively find all sub-circuits associated with */
654 /* the top-level circuit. For each schematic that does */
655 /* not have a valid filename, set the filename equal to */
656 /* the filename of the "toppage" schematic. */
657 /*------------------------------------------------------*/
659 void collectsubschems(int toppage)
661 int loctop;
662 objectptr cschem;
663 short *pagelist, pageno;
664 Pagedata *curpage;
666 loctop = toppage;
667 curpage = xobjs.pagelist[loctop];
668 if (curpage->pageinst == NULL) return;
669 cschem = curpage->pageinst->thisobject;
670 if (cschem->schemtype == SECONDARY) {
671 cschem = cschem->symschem;
672 loctop = is_page(cschem);
673 if (loctop < 0) return;
674 curpage = xobjs.pagelist[loctop];
677 pagelist = (short *)malloc(xobjs.pages * sizeof(short));
679 for (pageno = 0; pageno < xobjs.pages; pageno++)
680 pagelist[pageno] = 0;
682 findsubschems(loctop, cschem, 0, pagelist, FALSE);
684 for (pageno = 0; pageno < xobjs.pages; pageno++) {
685 if (pageno == loctop) continue;
686 if (pagelist[pageno] > 0) {
687 if (xobjs.pagelist[pageno]->filename != NULL)
688 free(xobjs.pagelist[pageno]->filename);
689 xobjs.pagelist[pageno]->filename =
690 strdup(xobjs.pagelist[loctop]->filename);
693 free((char *)pagelist);
696 /*------------------------------------------------------*/
697 /* compare_qualified(str1, str2) --- */
698 /* */
699 /* String comparison for technology-qualified */
700 /* names. str2" must be a fully-qualified name. */
701 /* "str1" may be qualified or unqualified. If */
702 /* unqualified, compare_qualified will return TRUE */
703 /* for any "str2" that matches the name part of */
704 /* the technology::name format. */
705 /* */
706 /* Return value: TRUE if match, FALSE if not. */
707 /*------------------------------------------------------*/
709 Boolean compare_qualified(char *str1, char *str2)
711 char *sptr1, *sptr2;
712 Boolean qual1, qual2;
714 sptr2 = strstr(str2, "::");
715 qual2 = (sptr2 == NULL) ? FALSE : TRUE;
717 if (!qual2) return (!strcmp(str1, str2));
719 sptr1 = strstr(str1, "::");
720 qual1 = (sptr1 == NULL) ? FALSE : TRUE;
722 if (qual1) return (!strcmp(str1, str2));
724 sptr2 += 2;
725 return (!strcmp(str1, sptr2));
728 /*-------------------------------------------------------*/
729 /* Check if top-level page is the same name as a library */
730 /* object; if so, connect it. */
731 /* Note that it is not an error not to find the matching */
732 /* symbol/schematic. "is_schematic" and "is_symbol" */
733 /* comments in the .ps file are complementary, so the */
734 /* first one encountered will always fail, and the other */
735 /* will succeed. */
736 /*-------------------------------------------------------*/
738 int checkschem(objectptr thisobj, char *cname)
740 objectptr *tlib;
741 short i, j;
743 if (thisobj->symschem != NULL) return 0;
745 for (i = 0; i < xobjs.numlibs; i++) {
746 for (j = 0; j < xobjs.userlibs[i].number; j++) {
747 tlib = xobjs.userlibs[i].library + j;
749 if (compare_qualified(cname, (*tlib)->name)) {
750 thisobj->symschem = (*tlib);
751 thisobj->schemtype = PRIMARY;
752 (*tlib)->symschem = thisobj;
753 (*tlib)->schemtype = SYMBOL;
754 return 1;
758 return 0;
761 /*--------------------------------------------------------*/
762 /* Complement to the above routine: If a library object */
763 /* name is the same as a top-level page, connect them. */
764 /*--------------------------------------------------------*/
766 int checksym(objectptr symobj, char *cname)
768 short cpage;
769 objectptr checkpage;
771 if (symobj->symschem != NULL) return 0;
773 for (cpage = 0; cpage < xobjs.pages; cpage++) {
774 if (xobjs.pagelist[cpage]->pageinst != NULL) {
775 checkpage = xobjs.pagelist[cpage]->pageinst->thisobject;
776 if (compare_qualified(cname, checkpage->name)) {
777 symobj->symschem = checkpage;
778 symobj->schemtype = SYMBOL;
779 checkpage->symschem = symobj;
780 checkpage->schemtype = PRIMARY;
781 return 1;
785 return 0;
788 /*----------------------------------------------------------------------*/
789 /* Find location of corresponding pin in symbol/schematic and change it */
790 /* to the text of the indicated label. */
791 /* */
792 /* Return the number of other pins changed. zero indicates that no */
793 /* corresponding pins were found, and therefore nothing was changed. */
794 /*----------------------------------------------------------------------*/
796 int changeotherpins(labelptr newlabel, stringpart *oldstring)
798 objectptr other = topobject->symschem;
799 genericptr *tgen;
800 labelptr tlab;
801 int rval = 0;
803 if (other == NULL) return rval;
805 for (tgen = other->plist; tgen < other->plist + other->parts; tgen++) {
806 if (IS_LABEL(*tgen)) {
807 tlab = TOLABEL(tgen);
808 if (tlab->pin != LOCAL) continue;
809 if (!stringcomp(tlab->string, oldstring)) {
810 if (newlabel != NULL) {
811 free(tlab->string);
812 tlab->string = stringcopy(newlabel->string);
813 rval++;
818 return rval;
821 /*----------------------------------------------------------------------*/
822 /* Xt wrapper for swapschem() */
823 /*----------------------------------------------------------------------*/
825 void xlib_swapschem(xcWidget w, pointertype mode, caddr_t calldata)
827 swapschem((int)mode, -1, NULL);
830 /*----------------------------------------------------------------------*/
831 /* Swap object schematic and symbol pages. */
832 /* allow_create = 0 disallows creation of a new schematic or symbol; */
833 /* i.e., if there is no corresponding schematic/symbol, nothing */
834 /* happens. */
835 /*----------------------------------------------------------------------*/
837 void swapschem(int allow_create, int libnum, char *fullname)
839 objectptr savepage = topobject;
840 labelptr *pinlab;
841 genericptr *plab;
842 Boolean lflag;
843 pushlistptr stacktop;
844 short loclibnum = libnum;
845 char *canonname;
847 if (libnum == -1) loclibnum = USERLIB - LIBRARY;
849 /* Create symbol or schematic, if allowed by allow_create */
851 if ((topobject->symschem == NULL) && (allow_create != 0)
852 && (topobject->schemtype != SECONDARY)) {
854 if (topobject->schemtype != PRIMARY) {
855 int tpage;
857 /* create a new page for the new schematic */
859 for (tpage = 0; tpage < xobjs.pages; tpage++)
860 if (xobjs.pagelist[tpage]->pageinst == NULL) break;
862 /* Push the current instance onto the push stack */
863 /* Change the page without destroying the pushlist */
865 push_stack(&areawin->stack, areawin->topinstance, NULL);
866 stacktop = areawin->stack;
867 areawin->stack = NULL;
868 changepage(tpage);
869 areawin->stack = stacktop;
871 else {
872 objectptr *newobject;
874 /* create a new library object for the new symbol */
876 xobjs.userlibs[loclibnum].library = (objectptr *)
877 realloc(xobjs.userlibs[loclibnum].library,
878 ++xobjs.userlibs[loclibnum].number * sizeof(objectptr));
879 newobject = xobjs.userlibs[loclibnum].library
880 + xobjs.userlibs[loclibnum].number - 1;
881 *newobject = (objectptr) malloc(sizeof(object));
882 initmem(*newobject);
883 (*newobject)->schemtype = SYMBOL;
884 (*newobject)->hidden = False;
886 incr_changes(*newobject);
888 if (eventmode == MOVE_MODE || eventmode == COPY_MODE)
889 standard_element_delete(ERASE);
890 else
891 unselect_all();
893 /* Generate a library instance for this object and set the */
894 /* top instance to point to it. */
896 topobject->viewscale = areawin->vscale;
897 topobject->pcorner = areawin->pcorner;
898 push_stack(&areawin->stack, areawin->topinstance, NULL);
899 areawin->topinstance = addtoinstlist(loclibnum, *newobject, FALSE);
901 /* Generate the default bounding box for a size-zero object */
902 calcbbox(areawin->topinstance);
905 /* set links between the two objects */
907 savepage->symschem = topobject;
908 topobject->symschem = savepage;
910 /* Make the name of the new object equal to that of the old, */
911 /* except that symbols get the full name while schematics */
912 /* get the canonical name (without the technology prefix) */
914 if (fullname == NULL)
915 canonname = GetCanonicalName(savepage->name);
916 else {
917 canonname = strstr(fullname, "::");
918 if ((canonname == NULL) || (topobject->schemtype != PRIMARY))
919 canonname = fullname;
920 else
921 canonname += 2;
923 strcpy(topobject->name, canonname);
924 checkname(topobject);
926 /* copy all pin labels into the new object */
928 for (plab = savepage->plist; plab < savepage->plist + savepage->parts;
929 plab++) {
930 if (IS_LABEL(*plab)) {
931 genericptr *tgen;
932 labelptr tlab, lpin = (labelptr)*plab;
934 if (lpin->pin == LOCAL) {
936 /* Only make one copy of each pin name */
938 lflag = False;
939 for (tgen = topobject->plist; tgen <
940 topobject->plist + topobject->parts; tgen++) {
941 if (IS_LABEL(*tgen)) {
942 tlab = TOLABEL(tgen);
943 if (!stringcomp(tlab->string, lpin->string)) lflag = True;
946 if (lflag == True) continue;
948 NEW_LABEL(pinlab, topobject);
949 (*pinlab)->pin = lpin->pin;
950 (*pinlab)->color = lpin->color;
951 (*pinlab)->rotation = 0.0;
952 (*pinlab)->scale = 1.0;
953 (*pinlab)->anchor = areawin->anchor;
954 (*pinlab)->position.x = 0;
955 (*pinlab)->position.y = topobject->parts * (TEXTHEIGHT + 10);
956 (*pinlab)->passed = NULL;
957 (*pinlab)->cycle = NULL;
958 u2u_snap(&((*pinlab)->position));
959 (*pinlab)->string = stringcopy(lpin->string);
960 incr_changes(topobject);
964 calcbbox(areawin->topinstance);
966 /* Recreate the user library with the new symbol */
967 if (savepage->schemtype != SYMBOL) composelib(loclibnum + LIBRARY);
969 else if (topobject->symschem != NULL) {
971 /* If symschem matches the last entry on the push stack, then we */
972 /* pop; otherwise, we push. */
974 if (areawin->stack && areawin->stack->thisinst->thisobject
975 == topobject->symschem) {
976 topobject->viewscale = areawin->vscale;
977 topobject->pcorner = areawin->pcorner;
978 areawin->topinstance = areawin->stack->thisinst;
979 pop_stack(&areawin->stack);
981 else {
982 int p;
983 objinstptr syminst = NULL;
984 liblistptr symlist;
986 /* If symschem is a schematic, find the appropriate page */
988 for (p = 0; p < xobjs.pages; p++) {
989 syminst = xobjs.pagelist[p]->pageinst;
990 if (syminst != NULL)
991 if (syminst->thisobject == topobject->symschem)
992 break;
994 if (p == xobjs.pages) {
996 /* If symschem is a symbol, and it wasn't on the push stack, */
997 /* get the library default symbol and go there. */
999 for (p = 0; p < xobjs.numlibs; p++) {
1000 for (symlist = xobjs.userlibs[p].instlist; symlist != NULL;
1001 symlist = symlist->next) {
1002 syminst = symlist->thisinst;
1003 if (syminst->thisobject == topobject->symschem &&
1004 symlist->virtual == FALSE)
1005 break;
1007 if (symlist != NULL) break;
1009 if (p == xobjs.numlibs) {
1010 Fprintf(stderr, "swapschem(): BAD SYMSCHEM\n");
1011 return;
1015 if (eventmode == MOVE_MODE || eventmode == COPY_MODE)
1016 delete_for_xfer(NORMAL, areawin->selectlist, areawin->selects);
1018 topobject->viewscale = areawin->vscale;
1019 topobject->pcorner = areawin->pcorner;
1020 push_stack(&areawin->stack, areawin->topinstance, NULL);
1021 areawin->topinstance = syminst;
1025 /* If there was no action, then there is nothing more to do. */
1027 if (topobject == savepage) return;
1029 setpage(TRUE);
1030 transferselects();
1031 refresh(NULL, NULL, NULL);
1032 setsymschem();
1035 #ifndef TCL_WRAPPER
1037 /*----------------------------------------------------------------------*/
1038 /* Wrapper for swapschem() when generating a new symbol. */
1039 /*----------------------------------------------------------------------*/
1041 void makesymbol(xcWidget w, caddr_t calldata)
1043 /* copy name from popup prompt buffer and check */
1045 swapschem(1, -1, _STR2);
1048 /*----------------------------------------------------------------------*/
1049 /* Check name before doing a swap: If name begins with "Page", prompt */
1050 /* for the object name, as you would when doing selectsave(). */
1051 /*----------------------------------------------------------------------*/
1053 void dobeforeswap(xcWidget w, caddr_t clientdata, caddr_t calldata)
1055 buttonsave *popdata = (buttonsave *)malloc(sizeof(buttonsave));
1057 /* Check for requirement to change the name before creating the symbol */
1059 if ((topobject->symschem == NULL) && (topobject->schemtype == PRIMARY)
1060 && (strstr(topobject->name, "Page ") != NULL)) {
1062 /* Get a name for the new object */
1064 eventmode = NORMAL_MODE;
1065 popdata->dataptr = NULL;
1066 popdata->button = NULL; /* indicates that no button is assc'd w/ the popup */
1067 popupprompt(w, "Enter name for new object:", "\0", makesymbol, popdata, NULL);
1069 else
1070 swapschem(1, -1, NULL);
1073 #endif /* !TCL_WRAPPER */
1075 /*------------------------------------------*/
1076 /* Disassociate a symbol from its schematic */
1077 /*------------------------------------------*/
1079 void schemdisassoc()
1081 if (eventmode != NORMAL) {
1082 Wprintf("Cannot disassociate schematics in this mode");
1084 else {
1085 topobject->symschem->symschem = NULL;
1086 topobject->symschem = NULL;
1087 setsymschem();
1088 Wprintf("Schematic and symbol are now unlinked.");
1092 /*--------------------------------------------------------------*/
1093 /* Schematic<-->symbol association. Determine whether action */
1094 /* acts on a symbol or a schematic from context. */
1095 /* mode == 0 associate only. */
1096 /* mode == 1 determine action (associate or disassociate) from */
1097 /* context (toggle) */
1098 /*--------------------------------------------------------------*/
1100 void startschemassoc(xcWidget w, pointertype mode, caddr_t calldata)
1102 if ((topobject->symschem != NULL) && (mode == 1))
1103 schemdisassoc();
1104 else if ((topobject->symschem != NULL) && (mode == 0)) {
1105 Wprintf("Refusing to undo current association.");
1107 else if (topobject->schemtype == SECONDARY) {
1108 Wprintf("Cannot attach symbol to a secondary schematic page.");
1110 else {
1111 eventmode = ASSOC_MODE;
1112 if (topobject->schemtype == PRIMARY) {
1113 /* Find a symbol to associate */
1114 startcatalog(w, LIBLIB, NULL);
1115 Wprintf("Select library page, then symbol to associate.");
1117 else {
1118 /* Find a schematic (page) to associate */
1119 startcatalog(w, PAGELIB, NULL);
1120 Wprintf("Select schematic page to associate.");
1125 /*--------------------------------------------------------------*/
1126 /* Callback procedures on the schematic/symbol buttons. */
1127 /*--------------------------------------------------------------*/
1129 Boolean schemassoc(objectptr schemobj, objectptr symbolobj)
1131 if (schemobj->symschem != NULL || symbolobj->symschem != NULL) {
1132 Wprintf("Both objects must be disassociated first.");
1133 #if TCL_WRAPPER
1134 Tcl_SetResult(xcinterp, "Both objects must be disassociated first.", NULL);
1135 #endif
1136 return False;
1138 else {
1139 schemobj->symschem = symbolobj;
1140 symbolobj->symschem = schemobj;
1141 if (symbolobj->schemtype == TRIVIAL)
1142 symbolobj->schemtype = SYMBOL;
1144 /* Schematic takes the name of its associated symbol, by default */
1145 /* Don't copy any technology prefix. */
1146 strcpy(schemobj->name, GetCanonicalName(symbolobj->name));
1148 /* Ensure that schematic (page) name is unique */
1149 while (checkpagename(schemobj) < 0);
1150 setsymschem(); /* Set buttons and menu items appropriately */
1152 return True;
1155 /*-------------------------------------------------------------------------*/