1 /*-------------------------------------------------------------------------*/
2 /* libraries.c --- xcircuit routines for the builtin and user libraries */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 /*-------------------------------------------------------------------------*/
7 /* written by Tim Edwards, 8/13/93 */
8 /*-------------------------------------------------------------------------*/
15 #include <X11/Intrinsic.h>
16 #include <X11/StringDefs.h>
28 /*-------------------------------------------------------------------------*/
30 /*-------------------------------------------------------------------------*/
32 #include "colordefs.h"
35 /*----------------------------------------------------------------------*/
36 /* Function prototype declarations */
37 /*----------------------------------------------------------------------*/
38 #include "prototypes.h"
40 /*-------------------------------------------------------------------------*/
41 /* Global Variable definitions */
42 /*-------------------------------------------------------------------------*/
44 extern Display
*dpy
; /* Works well to make this globally accessible */
45 extern Cursor appcursors
[NUM_CURSORS
];
46 extern Globaldata xobjs
;
47 extern XCWindowData
*areawin
;
48 extern char _STR
[150];
49 extern short fontcount
;
50 extern fontinfo
*fonts
;
51 extern Boolean was_preselected
;
52 extern int number_colors
;
53 extern colorindex
*colorlist
;
55 /*---------------------------------------------------------*/
56 /* Find the Helvetica font for use in labeling the objects */
57 /*---------------------------------------------------------*/
63 if (fontcount
== 0) loadfontfile("Helvetica");
65 for (fval
= 0; fval
< fontcount
; fval
++)
66 if (!strcmp(fonts
[fval
].psname
, "Helvetica"))
69 /* If not there, use the first Helvetica font */
71 if (fval
== fontcount
) {
72 for (fval
= 0; fval
< fontcount
; fval
++)
73 if (!strcmp(fonts
[fval
].family
, "Helvetica"))
77 /* If still not there, use the first non-Symbol font */
78 /* If this doesn't work, then the libraries are probably misplaced. . .*/
80 if (fval
== fontcount
) {
81 for (fval
= 0; fval
< fontcount
; fval
++)
82 if (strcmp(fonts
[fval
].family
, "Symbol"))
89 /*-------------------------------------------*/
90 /* Return to drawing window from the library */
91 /*-------------------------------------------*/
95 /* Pop the object being edited from the push stack. */
97 popobject(NULL
, (pointertype
)1, NULL
);
100 /*------------------------------------------------------*/
101 /* Find page number from cursor position */
102 /* Mode = 0: Look for exact corresponding page number */
103 /* and return -1 if out-of-bounds */
104 /* Mode = 1: Look for position between pages, return */
105 /* page number of page to the right. */
106 /*------------------------------------------------------*/
108 int pageposition(short libmode
, int x
, int y
, int mode
)
110 int xin
, yin
, bpage
, pages
;
111 int gxsize
, gysize
, xdel
, ydel
;
113 pages
= (libmode
== PAGELIB
) ? xobjs
.pages
: xobjs
.numlibs
;
114 computespacing(libmode
, &gxsize
, &gysize
, &xdel
, &ydel
);
115 window_to_user(x
, y
, &areawin
->save
);
117 if (mode
== 0) { /* On-page */
118 if (areawin
->save
.x
>= 0 && areawin
->save
.y
<= 0) {
119 xin
= areawin
->save
.x
/ xdel
;
120 yin
= areawin
->save
.y
/ ydel
;
121 if (xin
< gxsize
&& yin
> -gysize
) {
122 bpage
= (xin
% gxsize
) - (yin
* gxsize
);
129 else { /* Between-pages */
130 xin
= (areawin
->save
.x
+ (xdel
>> 1)) / xdel
;
131 if (xin
> gxsize
) xin
= gxsize
;
132 if (xin
< 0) xin
= 0;
133 yin
= areawin
->save
.y
/ ydel
;
134 if (yin
> 0) yin
= 0;
135 if (yin
< -gysize
) yin
= -gysize
;
136 bpage
= (xin
% (gxsize
+ 1)) + 1 - (yin
* gxsize
);
137 if (bpage
> pages
+ 1) bpage
= pages
+ 1;
142 /*------------------------------------------------------*/
143 /* Find the number of other pages linked to the */
144 /* indicated page (having the same filename, and */
145 /* ignoring empty pages). result is the total number */
146 /* of pages in the output file. */
147 /*------------------------------------------------------*/
149 short pagelinks(int page
)
154 for (i
= 0; i
< xobjs
.pages
; i
++)
155 if (xobjs
.pagelist
[i
]->pageinst
!= NULL
)
156 if (xobjs
.pagelist
[i
]->pageinst
->thisobject
->parts
> 0)
157 if ((i
== page
) || (xobjs
.pagelist
[i
]->filename
&&
158 xobjs
.pagelist
[page
]->filename
&&
159 (!filecmp(xobjs
.pagelist
[i
]->filename
,
160 xobjs
.pagelist
[page
]->filename
))))
166 /*------------------------------------------------------*/
167 /* This is an expanded version of pagelinks() (above), */
168 /* to deal with the separate issues of independent top- */
169 /* level schematics and subcircuits. For the indicated */
170 /* page, return a list of pages depending on the mode: */
172 /* mode = INDEPENDENT: independent top-level pages */
173 /* mode = DEPENDENT: dependent pages (subcircuits) */
174 /* mode = PAGE_DEPEND: subcircuits of the current page, */
175 /* mode = LINKED_PAGES: subcircuits of the current */
176 /* page, including parameter links */
177 /* mode = TOTAL_PAGES: independent pages + subcircuits */
178 /* mode = ALL_PAGES: all pages in xcircuit */
180 /* The list is the size of the number of pages, and */
181 /* entries corresponding to the requested mode are set */
182 /* nonzero (the actual number indicates the number of */
183 /* references to the page, which may or may not be */
184 /* useful to know). */
186 /* It is the responsibility of the calling routine to */
187 /* free the memory allocated for the returned list. */
188 /*------------------------------------------------------*/
190 short *pagetotals(int page
, short mode
)
193 short *counts
, *icount
;
195 if (xobjs
.pagelist
[page
]->pageinst
== NULL
) return NULL
;
197 counts
= (short *)malloc(xobjs
.pages
* sizeof(short));
198 icount
= (short *)malloc(xobjs
.pages
* sizeof(short));
199 for (i
= 0; i
< xobjs
.pages
; i
++) {
204 /* Find all the subcircuits of this page */
206 if (mode
!= ALL_PAGES
)
207 findsubschems(page
, xobjs
.pagelist
[page
]->pageinst
->thisobject
,
208 0, counts
, (mode
== LINKED_PAGES
) ? TRUE
: FALSE
);
210 /* Check independent entries (top-level pages which are not */
211 /* subcircuits of another page, but have the same filename */
212 /* as the page we started from). Set the counts entry to -1 */
213 /* to mark each independent page. */
215 if (mode
!= PAGE_DEPEND
)
216 for (i
= 0; i
< xobjs
.pages
; i
++)
217 if (xobjs
.pagelist
[i
]->pageinst
!= NULL
)
218 if (xobjs
.pagelist
[i
]->pageinst
->thisobject
->parts
> 0)
220 if (mode
== ALL_PAGES
)
224 if ((i
== page
) || (xobjs
.pagelist
[i
]->filename
225 && xobjs
.pagelist
[page
]->filename
226 && (!filecmp(xobjs
.pagelist
[i
]->filename
,
227 xobjs
.pagelist
[page
]->filename
))))
228 if ((mode
== INDEPENDENT
) || (*(counts
+ i
) == 0))
233 /* Check other dependent entries (top-level pages which are */
234 /* subcircuits of any independent page). */
236 if ((mode
== DEPENDENT
) || (mode
== TOTAL_PAGES
) || (mode
== LINKED_PAGES
))
238 for (i
= 0; i
< xobjs
.pages
; i
++)
239 if ((i
!= page
) && (*(icount
+ i
) > 0))
240 findsubschems(i
, xobjs
.pagelist
[i
]->pageinst
->thisobject
,
241 0, counts
, (mode
== LINKED_PAGES
) ? TRUE
: FALSE
);
244 if (mode
== INDEPENDENT
)
246 free((char *)counts
);
251 if ((mode
== TOTAL_PAGES
) || (mode
== LINKED_PAGES
)) {
252 /* merge dependent and independent */
253 for (i
= 0; i
< xobjs
.pages
; i
++)
254 if (*(icount
+ i
) > 0)
257 free((char *)icount
);
262 /*---------------------------------------------------------*/
263 /* Test whether a library instance is a "virtual" instance */
264 /*---------------------------------------------------------*/
266 Boolean
is_virtual(objinstptr thisinst
) {
270 libno
= libfindobject(thisinst
->thisobject
, NULL
);
272 for (ilist
= xobjs
.userlibs
[libno
].instlist
; ilist
!= NULL
; ilist
= ilist
->next
)
273 if ((ilist
->thisinst
== thisinst
) && (ilist
->virtual == TRUE
))
279 /*------------------------------------------------------*/
280 /* Test whether an object is a page, and return the */
281 /* page number if it is. Otherwise, return -1. */
282 /*------------------------------------------------------*/
284 int is_page(objectptr thisobj
)
288 for (i
= 0; i
< xobjs
.pages
; i
++)
289 if (xobjs
.pagelist
[i
]->pageinst
!= NULL
)
290 if (xobjs
.pagelist
[i
]->pageinst
->thisobject
== thisobj
) return i
;
295 /*------------------------------------------------------*/
296 /* Test whether an object is a library, and return the */
297 /* library number if it is. Otherwise, return -1. */
298 /*------------------------------------------------------*/
300 int is_library(objectptr thisobj
)
304 for (i
= 0; i
< xobjs
.numlibs
; i
++)
305 if (xobjs
.libtop
[i
+ LIBRARY
]->thisobject
== thisobj
) return i
;
310 /*------------------------------------------------------*/
311 /* Check for library name (string). Because XCircuit */
312 /* generates the text "Library: <filename>" for */
313 /* library names, we also check against <filename> */
314 /* only in these names (this library name syntax is */
315 /* deprecated, but the check is retained for backwards */
316 /* compatibility). */
318 /* If no library matches the given name, return -1. */
319 /*------------------------------------------------------*/
321 int NameToLibrary(char *libname
)
326 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
327 slib
= xobjs
.libtop
[i
+ LIBRARY
]->thisobject
->name
;
328 if (!strcmp(libname
, slib
)) {
331 else if (!strncmp(slib
, "Library: ", 9)) {
332 if (!strcmp(libname
, slib
+ 9)) {
340 /*------------------------------------------------------*/
341 /* Move an object and all of its virtual instances from */
342 /* one library to another. */
343 /*------------------------------------------------------*/
345 int libmoveobject(objectptr thisobject
, int libtarget
)
348 liblistptr spec
, slast
, srch
;
350 libsource
= libfindobject(thisobject
, &j
);
352 if (libsource
== libtarget
) return libsource
; /* nothing to do */
353 if (libsource
< 0) return libsource
; /* object not in the library */
355 /* Move the object from library "libsource" to library "libtarget" */
357 xobjs
.userlibs
[libtarget
].library
= (objectptr
*)
358 realloc(xobjs
.userlibs
[libtarget
].library
,
359 (xobjs
.userlibs
[libtarget
].number
+ 1) * sizeof(objectptr
));
361 *(xobjs
.userlibs
[libtarget
].library
+ xobjs
.userlibs
[libtarget
].number
) = thisobject
;
362 xobjs
.userlibs
[libtarget
].number
++;
364 for (; j
< xobjs
.userlibs
[libsource
].number
; j
++)
365 *(xobjs
.userlibs
[libsource
].library
+ j
) =
366 *(xobjs
.userlibs
[libsource
].library
+ j
+ 1);
367 xobjs
.userlibs
[libsource
].number
--;
369 /* Move all instances from library "libsource" to library "libtarget" */
372 for (spec
= xobjs
.userlibs
[libsource
].instlist
; spec
!= NULL
;) {
373 if (spec
->thisinst
->thisobject
== thisobject
) {
375 /* Add to end of spec list in target */
376 srch
= xobjs
.userlibs
[libtarget
].instlist
;
378 xobjs
.userlibs
[libtarget
].instlist
= spec
;
380 for (; srch
->next
!= NULL
; srch
= srch
->next
);
381 spec
->next
= srch
->next
;
386 slast
->next
= spec
->next
;
390 xobjs
.userlibs
[libsource
].instlist
= spec
->next
;
391 spec
= xobjs
.userlibs
[libsource
].instlist
;
403 /*------------------------------------------------------*/
404 /* Determine which library contains the specified */
405 /* object. If found, return the library number, or */
406 /* else return -1 if the object was not found in any */
407 /* library. If "partidx" is non-null, fill with the */
408 /* integer offset of the object from the beginning of */
410 /*------------------------------------------------------*/
412 int libfindobject(objectptr thisobject
, int *partidx
)
417 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
418 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
419 libobj
= *(xobjs
.userlibs
[i
].library
+ j
);
420 if (libobj
== thisobject
) {
421 if (partidx
!= NULL
) *partidx
= j
;
429 /*------------------------------------------------------*/
430 /* ButtonPress handler during page catalog viewing mode */
431 /*------------------------------------------------------*/
433 void pagecat_op(int op
, int x
, int y
)
438 for (mode
= 0; mode
< LIBRARY
; mode
++) {
439 if (areawin
->topinstance
== xobjs
.libtop
[mode
]) break;
441 if (mode
== LIBRARY
) return; /* Something went wrong if this happens */
443 if (op
!= XCF_Cancel
) {
444 if ((bpage
= pageposition(mode
, x
, y
, 0)) >= 0) {
446 if (eventmode
== ASSOC_MODE
) {
447 if (mode
== PAGELIB
) {
448 /* using changepage() allows use of new page for schematic */
450 /* associate the new schematic */
451 schemassoc(topobject
, areawin
->stack
->thisinst
->thisobject
);
452 /* pop back to calling (symbol) page */
454 eventmode
= NORMAL_MODE
;
457 areawin
->lastlibrary
= bpage
;
458 startcatalog(NULL
, (pointertype
)(LIBRARY
+ bpage
), NULL
);
462 else if (op
== XCF_Select
) {
463 if (mode
== PAGELIB
) /* No such method for LIBLIB is defined. */
464 select_add_element(OBJINST
);
466 else if ((op
== XCF_Library_Pop
) || (op
== XCF_Finish
)) {
468 /* like catreturn(), but don't actually go to the popped page */
470 eventmode
= NORMAL_MODE
;
471 if (mode
== PAGELIB
) {
475 startcatalog(NULL
, (pointertype
)(LIBRARY
+ bpage
), NULL
);
482 eventmode
= NORMAL_MODE
;
487 /*------------------------------------------------------------------------------*/
488 /* Subroutine to find the correct scale and position of the object instance */
489 /* representing an entire page in the page directory. */
490 /*------------------------------------------------------------------------------*/
492 void pageinstpos(short mode
, short tpage
, objinstptr drawinst
, int gxsize
,
493 int gysize
, int xdel
, int ydel
)
495 objectptr libobj
= drawinst
->thisobject
;
496 float scalex
, scaley
;
498 drawinst
->position
.x
= (tpage
% gxsize
) * xdel
;
499 drawinst
->position
.y
= -(tpage
/ gxsize
+ 1) * ydel
;
501 /* center the object on its page bounding box */
503 if (drawinst
->bbox
.width
== 0 || drawinst
->bbox
.height
== 0) {
504 drawinst
->scale
= 0.45 * libobj
->viewscale
;
505 drawinst
->position
.x
+= 0.05 * xdel
- libobj
->pcorner
.x
* drawinst
->scale
;
506 drawinst
->position
.y
+= 0.05 * ydel
- libobj
->pcorner
.y
* drawinst
->scale
;
509 scalex
= (0.9 * xdel
) / drawinst
->bbox
.width
;
510 scaley
= (0.9 * ydel
) / drawinst
->bbox
.height
;
511 if (scalex
> scaley
) {
512 drawinst
->scale
= scaley
;
513 drawinst
->position
.x
-= (drawinst
->bbox
.lowerleft
.x
* scaley
);
514 drawinst
->position
.x
+= (xdel
- (drawinst
->bbox
.width
* scaley
)) / 2;
515 drawinst
->position
.y
+= 0.05 * ydel
- drawinst
->bbox
.lowerleft
.y
519 drawinst
->scale
= scalex
;
520 drawinst
->position
.y
-= (drawinst
->bbox
.lowerleft
.y
* scalex
);
521 drawinst
->position
.y
+= (ydel
- (drawinst
->bbox
.height
* scalex
)) / 2;
522 drawinst
->position
.x
+= 0.05 * xdel
- drawinst
->bbox
.lowerleft
.x
528 /*--------------------------------------------------------------*/
529 /* Make a new instance for inserting into the page directory */
530 /*--------------------------------------------------------------*/
532 objinstptr
newpageinst(objectptr pageobj
)
534 objinstptr newinst
= (objinstptr
) malloc(sizeof(objinst
));
535 instancedefaults(newinst
, pageobj
, 0, 0);
536 newinst
->type
= OBJINST
;
537 newinst
->color
= DEFAULTCOLOR
;
538 newinst
->style
= NORMAL
; /* Do not scale linewidth with page scale */
542 /*-----------------------------------------------------------*/
543 /* Find spacing of objects for pages in the page directories */
544 /*-----------------------------------------------------------*/
546 void computespacing(short mode
, int *gxsize
, int *gysize
, int *xdel
, int *ydel
)
548 int pages
= (mode
== PAGELIB
) ? xobjs
.pages
: xobjs
.numlibs
;
550 *gxsize
= (int)sqrt((double)pages
) + 1;
551 *gysize
= 1 + pages
/ (*gxsize
);
553 /* 0.5 is the default vscale; g#size is the number of pages per line */
555 *xdel
= areawin
->width
/ (0.5 * (*gxsize
));
556 *ydel
= areawin
->height
/ (0.5 * (*gysize
));
559 /*-------------------------------------------------------------------*/
560 /* Draw the catalog of page ordering or the library master directory */
561 /*-------------------------------------------------------------------*/
563 void composepagelib(short mode
)
567 objectptr libobj
, directory
= xobjs
.libtop
[mode
]->thisobject
;
573 int margin
, xdel
, ydel
, gxsize
, gysize
;
574 int pages
= (mode
== PAGELIB
) ? xobjs
.pages
: xobjs
.numlibs
;
575 short fval
= findhelvetica();
577 /* Like the normal libraries, instances come from a special list, so */
578 /* they should not be destroyed, but will be null'd out and retrieved */
581 for (pgen
= directory
->plist
; pgen
< directory
->plist
+ directory
->parts
; pgen
++)
582 if (IS_OBJINST(*pgen
)) *pgen
= NULL
;
584 reset(directory
, NORMAL
);
586 /* generate the list of object instances */
588 directory
->plist
= (genericptr
*)malloc(sizeof(genericptr
));
589 directory
->parts
= 0;
591 computespacing(mode
, &gxsize
, &gysize
, &xdel
, &ydel
);
592 margin
= xdel
/ 40; /* margin between pages */
594 for (i
= 0; i
< pages
; i
++) {
595 drawinst
= (mode
== PAGELIB
) ? xobjs
.pagelist
[i
]->pageinst
:
596 xobjs
.libtop
[i
+ LIBRARY
];
597 if (drawinst
!= NULL
) {
598 libobj
= drawinst
->thisobject
;
600 /* This is a stop-gap measure. . . should be recalculating the bounds of */
601 /* the instance on every action, not just before arranging the library. */
602 drawinst
->bbox
.lowerleft
.x
= libobj
->bbox
.lowerleft
.x
;
603 drawinst
->bbox
.lowerleft
.y
= libobj
->bbox
.lowerleft
.y
;
604 drawinst
->bbox
.width
= libobj
->bbox
.width
;
605 drawinst
->bbox
.height
= libobj
->bbox
.height
;
606 /* End stop-gap measure */
608 PLIST_INCR(directory
);
609 *(directory
->plist
+ directory
->parts
) = (genericptr
)drawinst
;
611 pageinstpos(mode
, i
, drawinst
, gxsize
, gysize
, xdel
, ydel
);
614 /* separate pages (including empty ones) with bounding boxes */
616 NEW_POLY(drawbox
, directory
);
617 (*drawbox
)->color
= LOCALPINCOLOR
; /* default red */
618 (*drawbox
)->style
= NORMAL
; /* CLOSED */
619 (*drawbox
)->width
= 1.0;
620 (*drawbox
)->number
= 4;
621 (*drawbox
)->points
= (pointlist
) malloc(4 * sizeof(XPoint
));
622 (*drawbox
)->passed
= NULL
;
623 (*drawbox
)->cycle
= NULL
;
624 pointptr
= (*drawbox
)->points
;
625 pointptr
->x
= (i
% gxsize
) * xdel
+ margin
;
626 pointptr
->y
= -(i
/ gxsize
) * ydel
- margin
;
627 pointptr
= (*drawbox
)->points
+ 1;
628 pointptr
->x
= ((i
% gxsize
) + 1) * xdel
- margin
;
629 pointptr
->y
= -(i
/ gxsize
) * ydel
- margin
;
630 pointptr
= (*drawbox
)->points
+ 2;
631 pointptr
->x
= ((i
% gxsize
) + 1) * xdel
- margin
;
632 pointptr
->y
= -((i
/ gxsize
) + 1) * ydel
+ margin
;
633 pointptr
= (*drawbox
)->points
+ 3;
634 pointptr
->x
= (i
% gxsize
) * xdel
+ margin
;
635 pointptr
->y
= -((i
/ gxsize
) + 1) * ydel
+ margin
;
637 /* each page gets its name printed at the bottom */
639 if (drawinst
!= NULL
) {
640 NEW_LABEL(pagelabel
, directory
);
641 labeldefaults(*pagelabel
, False
, (pointptr
->x
+ (pointptr
-1)->x
) / 2,
643 (*pagelabel
)->color
= DEFAULTCOLOR
;
644 (*pagelabel
)->scale
= 0.75;
645 (*pagelabel
)->string
->data
.font
= fval
;
646 (*pagelabel
)->passed
= NULL
;
647 strptr
= makesegment(&((*pagelabel
)->string
), NULL
);
648 strptr
->type
= TEXT_STRING
;
649 strptr
->data
.string
= (char *) malloc(1 + strlen(libobj
->name
));
650 strcpy(strptr
->data
.string
, libobj
->name
);
651 (*pagelabel
)->anchor
= TOP
| NOTBOTTOM
| NOTLEFT
;
655 /* calculate a bounding box for this display */
656 /* and center it in its window */
658 calcbbox(xobjs
.libtop
[mode
]);
659 centerview(xobjs
.libtop
[mode
]);
662 /*------------------------------------------------------------*/
663 /* Update the page or library directory based on new bounding */
664 /* box information for the page or library passed in "tpage". */
665 /*------------------------------------------------------------*/
667 void updatepagelib(short mode
, short tpage
)
669 objectptr compobj
, libinst
= xobjs
.libtop
[mode
]->thisobject
;
672 int i
, xdel
, ydel
, gxsize
, gysize
, lpage
;
674 /* lpage is the number of the page as found on the directory page */
675 lpage
= (mode
== PAGELIB
) ? tpage
: tpage
- LIBRARY
;
676 compobj
= (mode
== PAGELIB
) ? xobjs
.pagelist
[tpage
]->pageinst
->thisobject
677 : xobjs
.libtop
[tpage
]->thisobject
;
679 computespacing(mode
, &gxsize
, &gysize
, &xdel
, &ydel
);
681 for (i
= 0; i
< libinst
->parts
; i
++) {
682 gelem
= libinst
->plist
+ i
;
683 if (IS_OBJINST(*gelem
)) {
684 pinst
= TOOBJINST(gelem
);
685 if (pinst
->thisobject
== compobj
) {
686 /* recalculate scale and position of the object instance */
687 pageinstpos(mode
, lpage
, pinst
, gxsize
, gysize
, xdel
, ydel
);
693 /* if there is no instance for this page, then recompose the whole library */
695 if (i
== libinst
->parts
) composelib(mode
);
698 /*----------------------*/
699 /* Rearrange pages */
700 /*----------------------*/
702 void pagecatmove(int x
, int y
)
706 Pagedata
*ipage
, **testpage
, **tpage2
;
708 if (areawin
->selects
== 0) return;
709 else if (areawin
->selects
> 2) {
710 Wprintf("Select maximum of two objects.");
714 /* Get the page corresponding to the first selected object */
716 exchobj
= SELTOOBJINST(areawin
->selectlist
);
717 for (testpage
= xobjs
.pagelist
; testpage
< xobjs
.pagelist
+ xobjs
.pages
; testpage
++)
718 if (*testpage
!= NULL
&& (*testpage
)->pageinst
== exchobj
)
721 /* If two objects are selected, then exchange their order */
723 if (areawin
->selects
== 2) {
724 exchobj
= SELTOOBJINST(areawin
->selectlist
+ 1);
725 for (tpage2
= xobjs
.pagelist
; tpage2
< xobjs
.pagelist
+ xobjs
.pages
; tpage2
++)
726 if (*tpage2
!= NULL
&& (*tpage2
)->pageinst
== exchobj
)
734 /* If one object selected; find place to put from cursor position */
736 else if ((bpage
= pageposition(PAGELIB
, x
, y
, 1)) >= 0) {
740 /* Find page number of the original page */
742 epage
= (int)(testpage
- xobjs
.pagelist
);
743 eptr
= *(xobjs
.pagelist
+ epage
);
745 /* move page (epage) to position between current pages */
746 /* (bpage - 2) and (bpage - 1) by shifting pointers. */
748 if ((bpage
- 1) < epage
) {
749 for (k
= epage
- 1; k
>= bpage
- 1; k
--) {
750 *(xobjs
.pagelist
+ k
+ 1) = *(xobjs
.pagelist
+ k
);
753 *(xobjs
.pagelist
+ bpage
- 1) = eptr
;
754 renamepage(bpage
- 1);
756 else if ((bpage
- 2) > epage
) {
757 for (k
= epage
+ 1; k
<= bpage
- 2; k
++) {
758 *(xobjs
.pagelist
+ k
- 1) = *(xobjs
.pagelist
+ k
);
761 *(xobjs
.pagelist
+ bpage
- 2) = eptr
;
762 renamepage(bpage
- 2);
768 drawarea(NULL
, NULL
, NULL
);
771 /*-----------------------------------------*/
772 /* Draw the catalog of predefined elements */
773 /*-----------------------------------------*/
775 void composelib(short mode
)
780 objectptr libobj
, libpage
= xobjs
.libtop
[mode
]->thisobject
;
782 int xpos
= 0, ypos
= areawin
->height
<< 1;
783 int nypos
= 220, nxpos
;
785 short llx
, lly
, urx
, ury
, width
, height
, xcenter
;
787 int totalarea
, targetwidth
;
788 double scale
, savescale
;
792 /* Also make composelib() a wrapper for composepagelib() */
793 if ((mode
> FONTLIB
) && (mode
< LIBRARY
)) {
794 composepagelib(mode
);
798 /* The instances on the library page come from the library's */
799 /* "instlist". So that we don't destroy the actual instance when we */
800 /* call reset(), we find the pointer to the instance and NULL it. */
802 for (pgen
= libpage
->plist
; pgen
< libpage
->plist
+ libpage
->parts
; pgen
++)
803 if (IS_OBJINST(*pgen
)) *pgen
= NULL
;
805 /* Before resetting, save the position and scale. We will restore */
806 /* them at the end. */
808 savepos
= libpage
->pcorner
;
809 savescale
= libpage
->viewscale
;
810 reset(libpage
, NORMAL
);
812 /* Return if library defines no objects or virtual instances */
814 if (xobjs
.userlibs
[mode
- LIBRARY
].instlist
== NULL
) return;
816 /* Find the Helvetica font for use in labeling the objects */
818 fval
= findhelvetica();
820 /* Attempt to produce a library with the same aspect ratio as the */
821 /* drawing window. This is only approximate, and does not take */
822 /* into account factors such as the length of the name string. */
825 for (spec
= xobjs
.userlibs
[mode
- LIBRARY
].instlist
; spec
!= NULL
;
827 libobj
= spec
->thisinst
->thisobject
;
829 /* "Hidden" objects are not drawn */
830 if (libobj
->hidden
== True
) continue;
832 drawinst
= spec
->thisinst
;
833 drawinst
->position
.x
= 0;
834 drawinst
->position
.y
= 0;
836 /* Get the bounding box of the instance in the page's coordinate system */
837 calcinstbbox((genericptr
*)(&drawinst
), &llx
, &lly
, &urx
, &ury
);
840 width
+= 30; /* space padding */
841 height
+= 30; /* height padding */
842 if (width
< 200) width
= 200; /* minimum box width */
843 if (height
< 220) height
= 220; /* minimum box height */
844 totalarea
+= (width
* height
);
847 scale
= (double)totalarea
/ (double)(areawin
->width
* areawin
->height
);
848 targetwidth
= (int)(sqrt(scale
) * (double)areawin
->width
);
850 /* generate the list of object instances and their labels */
852 savemode
= eventmode
;
853 eventmode
= CATALOG_MODE
;
854 for (spec
= xobjs
.userlibs
[mode
- LIBRARY
].instlist
; spec
!= NULL
;
856 libobj
= spec
->thisinst
->thisobject
;
858 /* "Hidden" objects are not drawn */
859 if (libobj
->hidden
== True
) continue;
861 drawinst
= spec
->thisinst
;
862 drawinst
->position
.x
= 0;
863 drawinst
->position
.y
= 0;
865 /* Generate the part; unlike the usual NEW_OBJINST, the */
866 /* instance record isn't allocated. */
869 *(libpage
->plist
+ libpage
->parts
) = (genericptr
)drawinst
;
872 /* Get the bounding box of the instance in the page's coordinate system */
873 calcinstbbox((genericptr
*)(&drawinst
), &llx
, &lly
, &urx
, &ury
);
874 xcenter
= (llx
+ urx
) >> 1;
878 /* Add an ad-hoc spacing rule of 30 for padding space between objects */
881 /* Prepare the object name and determine its width. Adjust width */
882 /* needed for object on the library page if necessary. */
884 if (fval
< fontcount
) {
888 NEW_LABEL(drawname
, libpage
);
889 labeldefaults(*drawname
, False
, 0, 0);
890 (*drawname
)->color
= (spec
->virtual) ?
891 OFFBUTTONCOLOR
: DEFAULTCOLOR
;
892 (*drawname
)->scale
= 0.75;
893 (*drawname
)->string
->data
.font
= fval
;
894 strptr
= makesegment(&((*drawname
)->string
), NULL
);
895 strptr
->type
= TEXT_STRING
;
897 strptr
->data
.string
= strdup(libobj
->name
);
898 (*drawname
)->anchor
= TOP
| NOTBOTTOM
| NOTLEFT
;
900 /* If the label is longer than the object width, then */
901 /* adjust positions accordingly. Note that as an ad- */
902 /* hoc spacing rule, a padding of 30 is put between */
903 /* objects; this padding is reduced to 5 */
905 tmpext
= ULength(*drawname
, drawinst
, NULL
);
907 /* Ad-hoc spacing rule is 5 for labels */
910 if (tmpext
.width
> width
)
911 width
= tmpext
.width
;
914 /* Minimum allowed width is 200 */
915 if (width
< 200) width
= 200;
917 /* Determine the area needed on the page to draw the object */
919 nxpos
= xpos
+ width
;
920 if ((nxpos
> targetwidth
) && (xpos
> 0)) {
927 if (height
> (nypos
- 50)) nypos
= height
+ 50;
929 drawinst
->position
.x
= xpos
+ (width
>> 1) - xcenter
;
930 drawinst
->position
.y
= ypos
- (height
+ lly
);
931 if (height
<= 170) drawinst
->position
.y
-= ((170 - height
) >> 1);
932 drawinst
->color
= DEFAULTCOLOR
;
934 if (fval
< fontcount
) {
935 (*drawname
)->position
.x
= xpos
+ (width
>> 1);
938 (*drawname
)->position
.y
= drawinst
->position
.y
+ lly
- 10;
940 (*drawname
)->position
.y
= ypos
- 180;
945 eventmode
= savemode
;
947 /* Compute the bounding box of the library page */
948 calcbbox(xobjs
.libtop
[mode
]);
950 /* Update the library directory */
951 updatepagelib(LIBLIB
, mode
);
953 /* Restore original view position */
954 libpage
->pcorner
= savepos
;
955 libpage
->viewscale
= savescale
;
958 /*----------------------------------------------------------------*/
959 /* Find any dependencies on an object. */
960 /* Return values: 0 = no dependency, 1 = dependency on page, */
961 /* 2 = dependency in another library object. */
962 /* Object/Page with dependency (if any) returned in "compobjp". */
963 /*----------------------------------------------------------------*/
965 short finddepend(objinstptr libobj
, objectptr
**compobjp
)
971 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
972 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
973 compobj
= xobjs
.userlibs
[i
].library
+ j
;
976 for (testobj
= (*compobj
)->plist
; testobj
< (*compobj
)->plist
977 + (*compobj
)->parts
; testobj
++) {
978 if (IS_OBJINST(*testobj
)) {
979 if (TOOBJINST(testobj
)->thisobject
== libobj
->thisobject
) return 2;
985 /* also look in the xobjs.pagelist */
987 for (page
= 0; page
< xobjs
.pages
; page
++) {
988 if (xobjs
.pagelist
[page
]->pageinst
== NULL
) continue;
989 compobj
= &(xobjs
.pagelist
[page
]->pageinst
->thisobject
);
991 for (testobj
= (*compobj
)->plist
; testobj
< (*compobj
)->plist
992 + (*compobj
)->parts
; testobj
++) {
993 if (IS_OBJINST(*testobj
)) {
994 if (TOOBJINST(testobj
)->thisobject
== libobj
->thisobject
) return 1;
1001 /*--------------------------------------------------------------*/
1002 /* Virtual copy: Make a separate copy of an object on the same */
1003 /* library page as the original, representing an instance of */
1004 /* the object with different parameters. The object must have */
1005 /* parameters for this to make sense, so check for parameters */
1006 /* before allowing the virtual copy. */
1007 /*--------------------------------------------------------------*/
1009 void catvirtualcopy()
1011 short i
, *newselect
;
1012 objinstptr libobj
, libinst
;
1014 if (areawin
->selects
== 0) return;
1015 else if ((i
= is_library(topobject
)) < 0) return;
1017 /* Check for existance of parameters in the object for each */
1018 /* selected instance */
1020 for (newselect
= areawin
->selectlist
; newselect
< areawin
->selectlist
1021 + areawin
->selects
; newselect
++) {
1022 libobj
= SELTOOBJINST(newselect
);
1023 libinst
= addtoinstlist(i
, libobj
->thisobject
, TRUE
);
1024 instcopy(libinst
, libobj
);
1025 tech_mark_changed(GetObjectTechnology(libobj
->thisobject
));
1029 composelib(LIBRARY
+ i
);
1030 drawarea(NULL
, NULL
, NULL
);
1033 /*----------------------------------------------------------------*/
1034 /* "Hide" an object (must have a dependency or else it disappears)*/
1035 /*----------------------------------------------------------------*/
1044 if (areawin
->selects
== 0) return;
1046 /* Can only hide objects which are instances in other objects; */
1047 /* Otherwise, object would be "lost". */
1049 for (newselect
= areawin
->selectlist
; newselect
< areawin
->selectlist
1050 + areawin
->selects
; newselect
++) {
1051 libobj
= SELTOOBJINST(newselect
);
1053 if (finddepend(libobj
, &compobj
) == 0) {
1054 Wprintf("Cannot hide: no dependencies");
1056 else { /* All's clear to hide. */
1057 libobj
->thisobject
->hidden
= True
;
1063 if ((i
= is_library(topobject
)) >= 0) composelib(LIBRARY
+ i
);
1065 drawarea(NULL
, NULL
, NULL
);
1068 /*----------------------------------------------------------------*/
1069 /* Delete an object from the library if there are no dependencies */
1070 /*----------------------------------------------------------------*/
1074 short *newselect
, *libpobjs
;
1076 /* genericptr *testobj, *tobj; (jdk) */
1078 liblistptr ilist
, llist
;
1079 objectptr
*libpage
, *compobj
, *tlib
, *slib
;
1081 if (areawin
->selects
== 0) return;
1083 if ((i
= is_library(topobject
)) >= 0) {
1084 libpage
= xobjs
.userlibs
[i
].library
;
1085 libpobjs
= &xobjs
.userlibs
[i
].number
;
1088 return; /* To-do: Should have a mechanism here for deleting pages! */
1090 for (newselect
= areawin
->selectlist
; newselect
< areawin
->selectlist
1091 + areawin
->selects
; newselect
++) {
1092 libobj
= SELTOOBJINST(newselect
);
1094 /* If this is just a "virtual copy", simply remove it from the list */
1097 for (ilist
= xobjs
.userlibs
[i
].instlist
; ilist
!= NULL
;
1098 llist
= ilist
, ilist
= ilist
->next
) {
1099 if ((ilist
->thisinst
== libobj
) && (ilist
->virtual == TRUE
)) {
1101 xobjs
.userlibs
[i
].instlist
= ilist
->next
;
1103 llist
->next
= ilist
->next
;
1107 if (ilist
!= NULL
) {
1112 /* Cannot delete an object if another object uses an instance of it, */
1113 /* or if the object is used on a page. */
1115 if (finddepend(libobj
, &compobj
)) {
1116 Wprintf("Cannot delete: dependency in \"%s\"", (*compobj
)->name
);
1118 else { /* All's clear to delete. */
1120 /* Clear the undo stack so that any references to this object */
1121 /* won't screw up the database (this could be kinder & gentler */
1122 /* by first checking if there are any references to the object */
1123 /* in the undo stack. . . */
1127 /* Next, remove the object from the library page. */
1129 for (tlib
= libpage
; tlib
< libpage
+ *libpobjs
; tlib
++)
1130 if ((*tlib
) == libobj
->thisobject
) {
1131 for (slib
= tlib
; slib
< libpage
+ *libpobjs
- 1; slib
++)
1132 (*slib
) = (*(slib
+ 1));
1137 /* Next, remove all instances of the object on the library page. */
1140 for (ilist
= xobjs
.userlibs
[i
].instlist
; ilist
!= NULL
;
1141 llist
= ilist
, ilist
= ilist
->next
) {
1142 if (ilist
->thisinst
->thisobject
== libobj
->thisobject
) {
1143 if (llist
== NULL
) {
1144 xobjs
.userlibs
[i
].instlist
= ilist
->next
;
1146 if (!(ilist
= xobjs
.userlibs
[i
].instlist
)) break;
1149 llist
->next
= ilist
->next
;
1151 if (!(ilist
= llist
)) break;
1156 /* Finally, delete the object (permanent---no undoing this!) */
1157 tech_mark_changed(GetObjectTechnology(libobj
->thisobject
));
1158 reset(libobj
->thisobject
, DESTROY
);
1164 if ((i
= is_library(topobject
)) >= 0) {
1165 composelib(LIBRARY
+ i
);
1168 drawarea(NULL
, NULL
, NULL
);
1171 /*------------------------------------------------------*/
1172 /* Linked list rearrangement routines */
1173 /*------------------------------------------------------*/
1175 void linkedlistswap(liblistptr
*spec
, int o1
, int o2
)
1177 liblistptr s1
, s1m
, s2
, s2m
, stmp
;
1180 if (o1
== o2
) return;
1184 for (j
= 0; j
< o1
; j
++) {
1191 for (j
= 0; j
< o2
; j
++) {
1207 s1
->next
= s2
->next
;
1211 /*------------------------------------------------------*/
1213 void linkedlistinsertafter(liblistptr
*spec
, int o1
, int o2
)
1215 liblistptr s1
, s1m
, s2
; /* , s2m, stmp; (jdk) */
1218 if ((o1
== o2
) || (o1
== (o2
+ 1))) return;
1222 for (j
= 0; j
< o1
; j
++) {
1228 for (j
= 0; j
< o2
; j
++)
1232 s1m
->next
= s1
->next
;
1236 if (o2
== -1) { /* move s1 to front */
1241 s1
->next
= s2
->next
;
1246 /*------------------------------------------------------*/
1247 /* Set the "changed" flag in a library if any object */
1248 /* in that library has changed. */
1250 /* If "technology" is NULL, check all objects, */
1251 /* otherwise only check objects with a matching */
1253 /*------------------------------------------------------*/
1255 void tech_set_changes(TechPtr refns
)
1261 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
1262 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
1263 thisobj
= *(xobjs
.userlibs
[i
].library
+ j
);
1264 if (getchanges(thisobj
) > 0) {
1265 ns
= GetObjectTechnology(thisobj
);
1266 if ((refns
== NULL
) || (refns
== ns
))
1267 ns
->flags
|= TECH_CHANGED
;
1273 /*------------------------------------------------------*/
1274 /* Mark a technology as having been modified. */
1275 /*------------------------------------------------------*/
1277 void tech_mark_changed(TechPtr ns
)
1279 if (ns
!= NULL
) ns
->flags
|= TECH_CHANGED
;
1282 /*------------------------------------------------------*/
1283 /* Rearrange objects in the library */
1284 /*------------------------------------------------------*/
1286 void catmove(int x
, int y
)
1288 int i
, j
, k
, s1
, s2
, ocentx
, ocenty
, rangey
, l
; /* rangex, (jdk) */
1290 objinstptr exchobj
, lobj
;
1292 /* make catmove() a wrapper for pagecatmove() */
1294 if ((i
= is_library(topobject
)) < 0) {
1299 if (areawin
->selects
== 0) return;
1301 /* Add selected object or objects at the cursor position */
1303 window_to_user(x
, y
, &areawin
->save
);
1306 for (j
= 0, spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
;
1307 spec
= spec
->next
, j
++) {
1308 lobj
= spec
->thisinst
;
1309 for (k
= 0; k
< areawin
->selects
; k
++) {
1310 exchobj
= SELTOOBJINST(areawin
->selectlist
+ k
);
1311 if (lobj
== exchobj
) break;
1313 if (k
< areawin
->selects
) continue; /* ignore items being moved */
1315 ocentx
= lobj
->position
.x
+ lobj
->bbox
.lowerleft
.x
1316 + (lobj
->bbox
.width
>> 1);
1317 ocenty
= lobj
->position
.y
+ lobj
->bbox
.lowerleft
.y
1318 + (lobj
->bbox
.height
>> 1);
1319 rangey
= (lobj
->bbox
.height
> 200) ?
1320 (lobj
->bbox
.height
>> 1) : 100;
1322 if ((areawin
->save
.y
< ocenty
+ rangey
) && (areawin
->save
.y
1323 > ocenty
- rangey
)) {
1325 if (areawin
->save
.x
< ocentx
) break;
1329 if ((s2
== -1) && (spec
== NULL
)) {
1330 if (areawin
->save
.y
<
1331 xobjs
.libtop
[i
+ LIBRARY
]->thisobject
->bbox
.lowerleft
.y
)
1333 else if (areawin
->save
.y
<=
1334 xobjs
.libtop
[i
+ LIBRARY
]->thisobject
->bbox
.lowerleft
.y
+
1335 xobjs
.libtop
[i
+ LIBRARY
]->thisobject
->bbox
.height
) {
1337 Wprintf("Could not find appropriate place to insert object");
1342 /* Find object number s2 (because s2 value may change during insertion) */
1344 for (k
= 0, spec
= xobjs
.userlibs
[i
].instlist
; k
< s2
; spec
= spec
->next
, k
++);
1345 lobj
= spec
->thisinst
;
1349 /* Move items; insert them after item s2 in order selected */
1352 for (k
= 0; k
< areawin
->selects
; k
++) {
1354 /* Find number of lobj (may have changed) */
1359 for (s2
= 0, spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
;
1360 spec
= spec
->next
, s2
++)
1361 if (spec
->thisinst
== lobj
)
1365 exchobj
= SELTOOBJINST(areawin
->selectlist
+ k
);
1366 for (s1
= 0, spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
;
1367 spec
= spec
->next
, s1
++)
1368 if (spec
->thisinst
== exchobj
)
1372 /* Object came from another library */
1373 if ((l
= libmoveobject(exchobj
->thisobject
, i
)) >= 0) j
= l
;
1376 linkedlistinsertafter(&(xobjs
.userlibs
[i
].instlist
), s1
, s2
);
1381 composelib(LIBRARY
+ i
);
1383 composelib(LIBRARY
+ j
);
1384 centerview(xobjs
.libtop
[LIBRARY
+ j
]);
1387 drawarea(NULL
, NULL
, NULL
);
1390 /*------------------------------------------------------*/
1391 /* Make a duplicate of an object, put in the User */
1392 /* Library or the current library (if we're in one). */
1394 /* Updated 2/8/2014 for use with technology namespaces: */
1395 /* it is most likely that the copied object is to be */
1396 /* modified but kept in the same namespace. So, when */
1397 /* renaming the object, prepend "_" to the object name */
1398 /* instead of the namespace prefix. */
1399 /*------------------------------------------------------*/
1404 objectptr
*newobj
, *curlib
, oldobj
;
1406 oparamptr ops
, newops
;
1410 libnum
= is_library(topobject
);
1411 if (libnum
< 0) libnum
= USERLIB
- LIBRARY
; /* default */
1413 for (newselect
= areawin
->selectlist
; newselect
< areawin
->selectlist
1414 + areawin
->selects
; newselect
++) {
1416 libobj
= SELTOOBJINST(newselect
);
1417 oldobj
= libobj
->thisobject
;
1419 /* generate new entry in user library */
1421 curlib
= (objectptr
*) realloc(xobjs
.userlibs
[libnum
].library
,
1422 (xobjs
.userlibs
[libnum
].number
+ 1) * sizeof(objectptr
));
1423 xobjs
.userlibs
[libnum
].library
= curlib
;
1424 newobj
= xobjs
.userlibs
[libnum
].library
+ xobjs
.userlibs
[libnum
].number
;
1425 *newobj
= (objectptr
) malloc(sizeof(object
));
1426 xobjs
.userlibs
[libnum
].number
++;
1428 /* give the new object a unique name */
1430 cptr
= strstr(oldobj
->name
, "::");
1432 sprintf((*newobj
)->name
, "_%s", oldobj
->name
);
1434 strcpy((*newobj
)->name
, oldobj
->name
);
1435 sprintf((*newobj
)->name
+ (cptr
- oldobj
->name
) + 2, "_%s", cptr
+ 2);
1439 /* copy other object properties */
1441 (*newobj
)->bbox
.width
= oldobj
->bbox
.width
;
1442 (*newobj
)->bbox
.height
= oldobj
->bbox
.height
;
1443 (*newobj
)->bbox
.lowerleft
.x
= oldobj
->bbox
.lowerleft
.x
;
1444 (*newobj
)->bbox
.lowerleft
.y
= oldobj
->bbox
.lowerleft
.y
;
1445 (*newobj
)->pcorner
.x
= oldobj
->pcorner
.x
;
1446 (*newobj
)->pcorner
.y
= oldobj
->pcorner
.y
;
1447 (*newobj
)->viewscale
= oldobj
->viewscale
;
1448 /* don't attach the same schematic. . . */
1449 (*newobj
)->symschem
= NULL
;
1450 /* don't copy highlights */
1451 (*newobj
)->highlight
.netlist
= NULL
;
1452 (*newobj
)->highlight
.thisinst
= NULL
;
1454 /* Copy the parameter structure */
1455 (*newobj
)->params
= NULL
;
1456 for (ops
= oldobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
1457 newops
= (oparamptr
)malloc(sizeof(oparam
));
1458 newops
->next
= (*newobj
)->params
;
1459 newops
->key
= strdup(ops
->key
);
1460 (*newobj
)->params
= newops
;
1461 newops
->type
= ops
->type
;
1462 newops
->which
= ops
->which
;
1463 switch (ops
->type
) {
1465 newops
->parameter
.ivalue
= ops
->parameter
.ivalue
;
1468 newops
->parameter
.fvalue
= ops
->parameter
.fvalue
;
1471 newops
->parameter
.string
= stringcopy(ops
->parameter
.string
);
1474 newops
->parameter
.expr
= strdup(ops
->parameter
.expr
);
1479 (*newobj
)->schemtype
= oldobj
->schemtype
;
1480 (*newobj
)->netnames
= NULL
;
1481 (*newobj
)->ports
= NULL
;
1482 (*newobj
)->calls
= NULL
;
1483 (*newobj
)->polygons
= NULL
;
1484 (*newobj
)->labels
= NULL
;
1485 (*newobj
)->valid
= False
;
1486 (*newobj
)->traversed
= False
;
1487 (*newobj
)->hidden
= False
;
1489 /* copy over all the elements of the original object */
1491 (*newobj
)->parts
= 0;
1492 (*newobj
)->plist
= (genericptr
*)malloc(sizeof(genericptr
));
1494 for (i
= 0; i
< oldobj
->parts
; i
++) {
1495 switch(ELEMENTTYPE(*(oldobj
->plist
+ i
))) {
1497 register pathptr
*npath
, cpath
= TOPATH(oldobj
->plist
+ i
);
1499 NEW_PATH(npath
, (*newobj
));
1500 pathcopy(*npath
, cpath
);
1504 register arcptr
*narc
, carc
= TOARC(oldobj
->plist
+ i
);
1506 NEW_ARC(narc
, (*newobj
));
1507 arccopy(*narc
, carc
);
1511 register polyptr
*npoly
, cpoly
= TOPOLY(oldobj
->plist
+ i
);
1513 NEW_POLY(npoly
, (*newobj
));
1514 polycopy(*npoly
, cpoly
);
1518 register splineptr
*nspl
, cspl
= TOSPLINE(oldobj
->plist
+ i
);
1520 NEW_SPLINE(nspl
, (*newobj
));
1521 splinecopy(*nspl
, cspl
);
1525 register labelptr
*nlabel
, clabel
= TOLABEL(oldobj
->plist
+ i
);
1527 NEW_LABEL(nlabel
, (*newobj
));
1528 labelcopy(*nlabel
, clabel
);
1532 register objinstptr
*ninst
, cinst
= TOOBJINST(oldobj
->plist
+ i
);
1534 NEW_OBJINST(ninst
, (*newobj
));
1535 instcopy(*ninst
, cinst
);
1541 /* make instance for library and measure its bounding box */
1542 addtoinstlist(USERLIB
- LIBRARY
, *newobj
, FALSE
);
1544 composelib(USERLIB
);
1547 if (areawin
->topinstance
== xobjs
.libtop
[USERLIB
])
1548 drawarea(NULL
, NULL
, NULL
);
1549 else startcatalog(NULL
, (pointertype
)USERLIB
, NULL
);
1550 zoomview(NULL
, NULL
, NULL
);
1553 /*--------------------------------------------------------*/
1554 /* ButtonPress handler during normal catalog viewing mode */
1555 /*--------------------------------------------------------*/
1557 void catalog_op(int op
, int x
, int y
)
1560 objinstptr
*newobject
, *libobj
;
1561 objectptr libpage
= topobject
;
1562 short ocentx
, ocenty
, rangex
, rangey
, xdiff
, ydiff
, flag
= 0;
1565 /* Make catalog_op() a wrapper for pagecat_op() */
1567 if (is_library(topobject
) < 0) {
1568 pagecat_op(op
, x
, y
);
1572 /* If XCF_Cancel was invoked, return without a selection. */
1574 if (op
== XCF_Cancel
) {
1575 eventmode
= NORMAL_MODE
;
1580 window_to_user(x
, y
, &areawin
->save
);
1582 for (libobj
= (objinstptr
*)topobject
->plist
; libobj
<
1583 (objinstptr
*)topobject
->plist
+ topobject
->parts
; libobj
++) {
1584 if (IS_OBJINST(*libobj
)) {
1586 ocentx
= (*libobj
)->position
.x
+ (*libobj
)->bbox
.lowerleft
.x
1587 + ((*libobj
)->bbox
.width
>> 1);
1588 ocenty
= (*libobj
)->position
.y
+ (*libobj
)->bbox
.lowerleft
.y
1589 + ((*libobj
)->bbox
.height
>> 1);
1591 rangex
= ((*libobj
)->bbox
.width
> 200) ?
1592 ((*libobj
)->bbox
.width
>> 1) : 100;
1593 rangey
= ((*libobj
)->bbox
.height
> 200) ?
1594 ((*libobj
)->bbox
.height
>> 1) : 100;
1596 if (areawin
->save
.x
> ocentx
- rangex
&& areawin
->save
.x
<
1597 ocentx
+ rangex
&& areawin
->save
.y
< ocenty
+ rangey
1598 && areawin
->save
.y
> ocenty
- rangey
) {
1600 /* setup to move object around and draw the selected object */
1602 if (eventmode
== ASSOC_MODE
) {
1604 /* revert to old page */
1605 topobject
->viewscale
= areawin
->vscale
;
1606 topobject
->pcorner
= areawin
->pcorner
;
1607 areawin
->topinstance
= (areawin
->stack
== NULL
) ?
1608 xobjs
.pagelist
[areawin
->page
]->pageinst
1609 : areawin
->stack
->thisinst
;
1610 /* associate the new object */
1611 schemassoc(topobject
, (*libobj
)->thisobject
);
1614 eventmode
= NORMAL_MODE
;
1616 else if ((op
== XCF_Library_Pop
) || (op
== XCF_Library_Copy
)) {
1619 /* revert to old page */
1621 topobject
->viewscale
= areawin
->vscale
;
1622 topobject
->pcorner
= areawin
->pcorner
;
1623 areawin
->topinstance
= (areawin
->stack
== NULL
) ?
1624 xobjs
.pagelist
[areawin
->page
]->pageinst
1625 : areawin
->stack
->thisinst
;
1627 /* retrieve drawing window state and set position of object to
1628 be correct in reference to that window */
1630 snap(x
, y
, &oldpos
);
1632 saveselects
= areawin
->selects
;
1633 areawin
->selects
= 0;
1635 areawin
->selects
= saveselects
;
1637 snap(x
, y
, &areawin
->save
);
1638 xdiff
= areawin
->save
.x
- oldpos
.x
;
1639 ydiff
= areawin
->save
.y
- oldpos
.y
;
1641 /* collect all of the selected items */
1643 for (newselect
= areawin
->selectlist
; newselect
<
1644 areawin
->selectlist
+ areawin
->selects
; newselect
++) {
1645 NEW_OBJINST(newobject
, topobject
);
1646 instcopy(*newobject
, TOOBJINST(libpage
->plist
+ *newselect
));
1647 /* color should be recast as current color */
1648 (*newobject
)->color
= areawin
->color
;
1649 /* position modified by (xdiff, ydiff) */
1650 (*newobject
)->position
.x
+= xdiff
;
1651 (*newobject
)->position
.y
+= ydiff
;
1653 u2u_snap(&((*newobject
)->position
));
1654 *newselect
= (short)(newobject
- (objinstptr
*)topobject
->plist
);
1655 if ((*newobject
)->thisobject
== (*libobj
)->thisobject
)
1659 /* add final object to the list of object instances */
1662 NEW_OBJINST(newobject
, topobject
);
1663 instcopy(*newobject
, *libobj
);
1664 (*newobject
)->color
= areawin
->color
;
1665 (*newobject
)->position
.x
= areawin
->save
.x
;
1666 (*newobject
)->position
.y
= areawin
->save
.y
;
1668 /* add this object to the list of selected items */
1670 newselect
= allocselect();
1671 *newselect
= (short)(newobject
- (objinstptr
*)topobject
->plist
);
1674 if (op
== XCF_Library_Copy
) {
1676 /* Key "c" pressed for "copy" (default binding) */
1678 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
1679 eventmode
= COPY_MODE
;
1681 xcAddEventHandler(areawin
->area
, PointerMotionMask
|
1682 ButtonMotionMask
, False
,
1683 (xcEventHandler
)xlib_drag
, NULL
);
1687 eventmode
= MOVE_MODE
;
1688 was_preselected
= FALSE
;
1689 register_for_undo(XCF_Library_Pop
, UNDO_MORE
, areawin
->topinstance
,
1690 areawin
->selectlist
, areawin
->selects
);
1693 /* fprintf(stderr, "Creating event handler for xctk_drag: "); */
1694 /* printeventmode(); */
1695 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
1696 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
1701 /* Select the closest element and stay in the catalog. */
1702 /* Could just do "select_element" here, but would not cover */
1703 /* the entire area in the directory surrounding the object. */
1705 else if (op
== XCF_Select
) {
1706 short newinst
= (short)(libobj
- (objinstptr
*)topobject
->plist
);
1707 /* (ignore this object if it is already in the list of selects) */
1708 for (newselect
= areawin
->selectlist
; newselect
<
1709 areawin
->selectlist
+ areawin
->selects
; newselect
++)
1710 if (*newselect
== newinst
) break;
1711 if (newselect
== areawin
->selectlist
+ areawin
->selects
) {
1712 newselect
= allocselect();
1713 *newselect
= newinst
;
1714 XcTopSetForeground(SELECTCOLOR
);
1715 UDrawObject(*libobj
, SINGLE
, SELECTCOLOR
,
1716 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
1726 /*------------------------------*/
1727 /* Switch to the next catalog */
1728 /*------------------------------*/
1734 if ((i
= is_library(topobject
)) < 0) {
1735 if (areawin
->lastlibrary
>= xobjs
.numlibs
) areawin
->lastlibrary
= 0;
1736 j
= areawin
->lastlibrary
;
1737 eventmode
= CATALOG_MODE
;
1740 j
= (i
+ 1) % xobjs
.numlibs
;
1742 Wprintf("This is the only library.");
1745 areawin
->lastlibrary
= j
;
1748 if (eventmode
== CATMOVE_MODE
)
1749 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
1751 startcatalog(NULL
, (pointertype
)(j
+ LIBRARY
), NULL
);
1754 /*--------------------------------------*/
1755 /* Begin catalog viewing mode */
1756 /*--------------------------------------*/
1758 void startcatalog(xcWidget w
, pointertype libmod
, caddr_t nulldata
)
1760 if (xobjs
.libtop
== NULL
) return; /* No libraries defined */
1762 if ((xobjs
.libtop
[libmod
]->thisobject
== NULL
) ||
1763 (areawin
->topinstance
== xobjs
.libtop
[libmod
])) return;
1765 if (libmod
== FONTLIB
) {
1766 XDefineCursor (dpy
, areawin
->window
, DEFAULTCURSOR
);
1767 if (eventmode
== TEXT_MODE
)
1768 eventmode
= FONTCAT_MODE
;
1770 eventmode
= EFONTCAT_MODE
;
1772 else if (eventmode
== ASSOC_MODE
) {
1773 XDefineCursor (dpy
, areawin
->window
, DEFAULTCURSOR
);
1775 else if (libmod
== PAGELIB
|| libmod
== LIBLIB
) {
1776 XDefineCursor (dpy
, areawin
->window
, DEFAULTCURSOR
);
1777 eventmode
= CATALOG_MODE
;
1779 else if (eventmode
!= CATMOVE_MODE
) {
1780 /* Don't know why I put this here---causes xcircuit to redraw */
1781 /* the schematic view when switching between library pages. */
1782 // finish_op(XCF_Cancel, 0, 0);
1783 eventmode
= CATALOG_MODE
;
1786 /* Push the current page onto the push stack, unless we're going */
1787 /* to a library from the library directory or vice versa, or */
1788 /* library to library. */
1790 if (!(((is_library(topobject
) >= 0)
1791 || (areawin
->topinstance
== xobjs
.libtop
[LIBLIB
])
1792 || (areawin
->topinstance
== xobjs
.libtop
[PAGELIB
]))
1793 && libmod
>= PAGELIB
)) {
1794 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
1797 /* set library as new object */
1799 topobject
->viewscale
= areawin
->vscale
;
1800 topobject
->pcorner
= areawin
->pcorner
;
1801 areawin
->topinstance
= xobjs
.libtop
[libmod
];
1803 if (libmod
== FONTLIB
)
1810 /* draw the new screen */
1812 refresh(NULL
, NULL
, NULL
);
1815 /*-------------------------------------------------------------------------*/