1 /*--------------------------------------------------------------*/
3 /* Tcl routines for xcircuit command-line functions */
4 /* Copyright (c) 2003 Tim Edwards, Johns Hopkins University */
5 /* Copyright (c) 2004 Tim Edwards, MultiGiG, Inc. */
6 /*--------------------------------------------------------------*/
8 #if defined(TCL_WRAPPER) && !defined(HAVE_PYTHON)
11 #include <stdarg.h> /* for va_copy() */
12 #include <stdlib.h> /* for atoi() and others */
15 #include <sys/types.h>
22 #include <cairo/cairo-xlib.h>
26 #include <X11/Intrinsic.h>
27 #include <X11/StringDefs.h>
31 #include "colordefs.h"
33 #include "prototypes.h"
35 Tcl_HashTable XcTagTable
;
37 extern Tcl_Interp
*xcinterp
;
38 extern Tcl_Interp
*consoleinterp
;
41 extern Pixmap STIPPLE
[STIPPLES
]; /* Polygon fill-style stipple patterns */
42 extern char _STR
[150], _STR2
[250];
43 extern XCWindowData
*areawin
;
44 extern Globaldata xobjs
;
45 extern int number_colors
;
46 extern colorindex
*colorlist
;
47 extern Cursor appcursors
[NUM_CURSORS
];
48 extern ApplicationData appdata
;
49 extern fontinfo
*fonts
;
50 extern short fontcount
;
51 extern u_char param_select
[];
52 extern keybinding
*keylist
;
53 extern Boolean spice_end
;
56 extern u_char undo_collect
;
58 char STIPDATA
[STIPPLES
][4] = {
73 #define COLOROVERRIDE 4
74 #define FONTOVERRIDE 8
75 #define KEYOVERRIDE 16
77 /*-----------------------*/
78 /* Tcl 8.4 compatibility */
79 /*-----------------------*/
85 /*----------------------------------------------------------------------*/
86 /* Procedure for waiting on X to map a window */
87 /* This code copied from Tk sources, where it is used for the "tkwait" */
89 /*----------------------------------------------------------------------*/
92 WaitVisibilityProc(ClientData clientData
, XEvent
*eventPtr
)
94 int *donePtr
= (int *) clientData
;
96 if (eventPtr
->type
== VisibilityNotify
) {
99 if (eventPtr
->type
== DestroyNotify
) {
104 /*----------------------------------------------------------------------*/
105 /* Deal with systems which don't define va_copy(). */
106 /*----------------------------------------------------------------------*/
109 #ifdef HAVE___VA_COPY
110 #define va_copy(a, b) __va_copy(a, b)
112 #define va_copy(a, b) a = b
117 extern int SetDebugLevel(int *level
);
120 /*----------------------------------------------------------------------*/
121 /* Reimplement strdup() to use Tcl_Alloc(). */
122 /* Note that "strdup" is defined as "Tcl_Strdup" in xcircuit.h. */
123 /*----------------------------------------------------------------------*/
125 char *Tcl_Strdup(const char *s
)
130 slen
= 1 + strlen(s
);
131 snew
= Tcl_Alloc(slen
);
133 memcpy(snew
, s
, slen
);
138 /*----------------------------------------------------------------------*/
139 /* Reimplement vfprintf() as a call to Tcl_Eval(). */
140 /*----------------------------------------------------------------------*/
142 void tcl_vprintf(FILE *f
, const char *fmt
, va_list args_in
)
145 static char outstr
[128] = "puts -nonewline std";
146 char *outptr
, *bigstr
= NULL
, *finalstr
= NULL
;
147 int i
, nchars
, result
, escapes
= 0;
149 /* If we are printing an error message, we want to bring attention */
150 /* to it by mapping the console window and raising it, as necessary. */
151 /* I'd rather do this internally than by Tcl_Eval(), but I can't */
152 /* find the right window ID to map! */
154 if ((f
== stderr
) && (consoleinterp
!= xcinterp
)) {
156 tkwind
= Tk_MainWindow(consoleinterp
);
157 if ((tkwind
!= NULL
) && (!Tk_IsMapped(tkwind
)))
158 result
= Tcl_Eval(consoleinterp
, "wm deiconify .\n");
159 result
= Tcl_Eval(consoleinterp
, "raise .\n");
162 strcpy (outstr
+ 19, (f
== stderr
) ? "err \"" : "out \"");
165 /* This mess circumvents problems with systems which do not have */
166 /* va_copy() defined. Some define __va_copy(); otherwise we must */
167 /* assume that args = args_in is valid. */
169 va_copy(args
, args_in
);
170 nchars
= vsnprintf(outptr
+ 24, 102, fmt
, args
);
174 va_copy(args
, args_in
);
175 bigstr
= Tcl_Alloc(nchars
+ 26);
176 strncpy(bigstr
, outptr
, 24);
178 vsnprintf(outptr
+ 24, nchars
+ 2, fmt
, args
);
181 else if (nchars
== -1) nchars
= 126;
183 for (i
= 24; *(outptr
+ i
) != '\0'; i
++) {
184 if (*(outptr
+ i
) == '\"' || *(outptr
+ i
) == '[' ||
185 *(outptr
+ i
) == ']' || *(outptr
+ i
) == '\\')
190 finalstr
= Tcl_Alloc(nchars
+ escapes
+ 26);
191 strncpy(finalstr
, outptr
, 24);
193 for (i
= 24; *(outptr
+ i
) != '\0'; i
++) {
194 if (*(outptr
+ i
) == '\"' || *(outptr
+ i
) == '[' ||
195 *(outptr
+ i
) == ']' || *(outptr
+ i
) == '\\') {
196 *(finalstr
+ i
+ escapes
) = '\\';
199 *(finalstr
+ i
+ escapes
) = *(outptr
+ i
);
204 *(outptr
+ 24 + nchars
+ escapes
) = '\"';
205 *(outptr
+ 25 + nchars
+ escapes
) = '\0';
207 result
= Tcl_Eval(consoleinterp
, outptr
);
209 if (bigstr
!= NULL
) Tcl_Free(bigstr
);
210 if (finalstr
!= NULL
) Tcl_Free(finalstr
);
213 /*------------------------------------------------------*/
214 /* Console output flushing which goes along with the */
215 /* routine tcl_vprintf() above. */
216 /*------------------------------------------------------*/
218 void tcl_stdflush(FILE *f
)
220 Tcl_SavedResult state
;
221 static char stdstr
[] = "::flush stdxxx";
222 char *stdptr
= stdstr
+ 11;
224 if ((f
!= stderr
) && (f
!= stdout
)) {
228 Tcl_SaveResult(xcinterp
, &state
);
229 strcpy(stdptr
, (f
== stderr
) ? "err" : "out");
230 Tcl_Eval(xcinterp
, stdstr
);
231 Tcl_RestoreResult(xcinterp
, &state
);
235 /*----------------------------------------------------------------------*/
236 /* Reimplement fprintf() as a call to Tcl_Eval(). */
237 /* Make sure that files (not stdout or stderr) get treated normally. */
238 /*----------------------------------------------------------------------*/
240 void tcl_printf(FILE *f
, const char *format
, ...)
244 va_start(ap
, format
);
245 if ((f
!= stderr
) && (f
!= stdout
))
246 vfprintf(f
, format
, ap
);
248 tcl_vprintf(f
, format
, ap
);
252 /*----------------------------------------------------------------------*/
253 /* Fill in standard areas of a key event structure. This includes */
254 /* everything necessary except type, keycode, and state (although */
255 /* state defaults to zero). This is also good for button events, which */
256 /* share the same structure as key events (except that keycode is */
257 /* changed to button). */
258 /*----------------------------------------------------------------------*/
260 void make_new_event(XKeyEvent
*event
)
262 XPoint newpos
, wpoint
;
264 newpos
= UGetCursorPos();
265 user_to_window(newpos
, &wpoint
);
269 event
->same_screen
= TRUE
;
270 event
->send_event
= TRUE
;
271 event
->display
= dpy
;
272 event
->window
= Tk_WindowId(areawin
->area
);
277 /*----------------------------------------------------------------------*/
278 /* Implement tag callbacks on functions */
279 /* Find any tags associated with a command and execute them. */
280 /*----------------------------------------------------------------------*/
282 int XcTagCallback(Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
284 int objidx
, result
= TCL_OK
;
285 char *postcmd
, *substcmd
, *newcmd
, *sptr
, *sres
;
286 char *croot
= Tcl_GetString(objv
[0]);
287 Tcl_HashEntry
*entry
;
288 Tcl_SavedResult state
;
292 /* Skip over technology qualifier, if any */
294 if (!strncmp(croot
, "::", 2)) croot
+= 2;
295 if (!strncmp(croot
, "xcircuit::", 10)) croot
+= 10;
297 entry
= Tcl_FindHashEntry(&XcTagTable
, croot
);
298 postcmd
= (entry
) ? (char *)Tcl_GetHashValue(entry
) : NULL
;
302 substcmd
= (char *)Tcl_Alloc(strlen(postcmd
) + 1);
303 strcpy(substcmd
, postcmd
);
306 /*--------------------------------------------------------------*/
307 /* Parse "postcmd" for Tk-substitution escapes */
308 /* Allowed escapes are: */
309 /* %W substitute the tk path of the calling window */
310 /* %r substitute the previous Tcl result string */
311 /* %R substitute the previous Tcl result string and */
312 /* reset the Tcl result. */
313 /* %[0-5] substitute the argument to the original command */
314 /* %N substitute all arguments as a list */
315 /* %% substitute a single percent character */
316 /* %# substitute the number of arguments passed */
317 /* %* (all others) no action: print as-is. */
318 /*--------------------------------------------------------------*/
320 while ((sptr
= strchr(sptr
, '%')) != NULL
)
326 Tk_Window tkwind
= Tk_MainWindow(interp
);
327 if (tkwind
!= NULL
) tkpath
= Tk_PathName(tkwind
);
329 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
));
331 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
) + strlen(tkpath
));
333 strcpy(newcmd
, substcmd
);
336 strcpy(newcmd
+ (int)(sptr
- substcmd
), sptr
+ 2);
339 strcpy(newcmd
+ (int)(sptr
- substcmd
), tkpath
);
340 strcat(newcmd
, sptr
+ 2);
350 sres
= (char *)Tcl_GetStringResult(interp
);
351 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
)
353 strcpy(newcmd
, substcmd
);
354 sprintf(newcmd
+ (int)(sptr
- substcmd
), "\"%s\"", sres
);
355 strcat(newcmd
, sptr
+ 2);
363 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
) + 3);
364 strcpy(newcmd
, substcmd
);
365 sprintf(newcmd
+ (int)(sptr
- substcmd
), "%d", objc
);
366 strcat(newcmd
, sptr
+ 2);
373 case '0': case '1': case '2': case '3': case '4': case '5':
374 objidx
= (int)(*(sptr
+ 1) - '0');
375 if ((objidx
>= 0) && (objidx
< objc
))
377 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
)
378 + strlen(Tcl_GetString(objv
[objidx
])) + 1);
379 strcpy(newcmd
, substcmd
);
380 strcpy(newcmd
+ (int)(sptr
- substcmd
),
381 Tcl_GetString(objv
[objidx
]));
382 strcat(newcmd
, sptr
+ 2);
387 else if (objidx
>= objc
)
389 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
) + 1);
390 strcpy(newcmd
, substcmd
);
391 strcpy(newcmd
+ (int)(sptr
- substcmd
), sptr
+ 2);
401 for (i
= 1; i
< objc
; i
++)
402 llen
+= (1 + strlen(Tcl_GetString(objv
[i
])));
403 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
) + llen
);
404 strcpy(newcmd
, substcmd
);
405 strcpy(newcmd
+ (int)(sptr
- substcmd
), "{");
406 for (i
= 1; i
< objc
; i
++) {
407 strcat(newcmd
, Tcl_GetString(objv
[i
]));
412 strcat(newcmd
, sptr
+ 2);
419 newcmd
= (char *)Tcl_Alloc(strlen(substcmd
) + 1);
420 strcpy(newcmd
, substcmd
);
421 strcpy(newcmd
+ (int)(sptr
- substcmd
), sptr
+ 1);
433 /* Fprintf(stderr, "Substituted tag callback is \"%s\"\n", substcmd); */
436 Tcl_SaveResult(interp
, &state
);
437 result
= Tcl_Eval(interp
, substcmd
);
438 if ((result
== TCL_OK
) && (reset
== FALSE
))
439 Tcl_RestoreResult(interp
, &state
);
441 Tcl_DiscardResult(&state
);
448 /*--------------------------------------------------------------*/
449 /* XcInternalTagCall --- */
451 /* Execute the tag callback for a command without actually */
452 /* evaluating the command itself. The command and arguments */
453 /* are passed as a variable number or char * arguments, since */
454 /* usually this routine will called with constant arguments */
455 /* (e.g., XcInternalTagCall(interp, 2, "set", "color");) */
457 /* objv declared static because this routine is used a lot */
458 /* (e.g., during select/unselect operations). */
459 /*--------------------------------------------------------------*/
461 int XcInternalTagCall(Tcl_Interp
*interp
, int argc
, ...)
464 static Tcl_Obj
**objv
= NULL
;
469 if (objv
== (Tcl_Obj
**)NULL
)
470 objv
= (Tcl_Obj
**)malloc(argc
* sizeof(Tcl_Obj
*));
472 objv
= (Tcl_Obj
**)realloc(objv
, argc
* sizeof(Tcl_Obj
*));
475 for (i
= 0; i
< argc
; i
++) {
476 aptr
= va_arg(ap
, char *);
477 /* We are depending on Tcl's heap allocation of objects */
478 /* so that we do not have to manage memory for these */
479 /* string representations. . . */
481 objv
[i
] = Tcl_NewStringObj(aptr
, -1);
485 return XcTagCallback(interp
, argc
, objv
);
488 /*--------------------------------------------------------------*/
489 /* Return the event mode */
490 /* Event mode can be set in specific cases. */
491 /*--------------------------------------------------------------*/
493 int xctcl_eventmode(ClientData clientData
,
494 Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
496 static char *modeNames
[] = {
497 "normal", "undo", "move", "copy", "pan",
498 "selarea", "rescale", "catalog", "cattext",
499 "fontcat", "efontcat", "text", "wire", "box",
500 "arc", "spline", "etext", "epoly", "earc",
501 "espline", "epath", "einst", "assoc", "catmove",
505 /* This routine is diagnostic only */
507 if (objc
!= 1) return TCL_ERROR
;
509 Tcl_SetResult(interp
, modeNames
[eventmode
], NULL
);
513 /*--------------------------------------------------------------*/
514 /* Add a command tag callback */
515 /*--------------------------------------------------------------*/
517 int xctcl_tag(ClientData clientData
,
518 Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
520 Tcl_HashEntry
*entry
;
524 if (objc
!= 2 && objc
!= 3)
527 entry
= Tcl_CreateHashEntry(&XcTagTable
, Tcl_GetString(objv
[1]), &new);
528 if (entry
== NULL
) return TCL_ERROR
;
530 hstring
= (char *)Tcl_GetHashValue(entry
);
533 Tcl_SetResult(interp
, hstring
, NULL
);
537 if (strlen(Tcl_GetString(objv
[2])) == 0)
539 Tcl_DeleteHashEntry(entry
);
543 hstring
= strdup(Tcl_GetString(objv
[2]));
544 Tcl_SetHashValue(entry
, hstring
);
549 /*----------------------------------------------------------------------*/
550 /* Turn a selection list into a Tcl List object (may be empty list) */
551 /*----------------------------------------------------------------------*/
553 Tcl_Obj
*SelectToTclList(Tcl_Interp
*interp
, short *slist
, int snum
)
556 Tcl_Obj
*objPtr
, *listPtr
;
559 objPtr
= Tcl_NewHandleObj(SELTOGENERIC(slist
));
563 listPtr
= Tcl_NewListObj(0, NULL
);
564 for (i
= 0; i
< snum
; i
++) {
565 objPtr
= Tcl_NewHandleObj(SELTOGENERIC(slist
+ i
));
566 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
571 /*----------------------------------------------------------------------*/
572 /* Get an x,y position (as an XPoint structure) from a list of size 2 */
573 /*----------------------------------------------------------------------*/
575 int GetPositionFromList(Tcl_Interp
*interp
, Tcl_Obj
*list
, XPoint
*rpoint
)
578 Tcl_Obj
*lobj
, *tobj
;
581 if (!strcmp(Tcl_GetString(list
), "here")) {
582 if (rpoint
) *rpoint
= UGetCursorPos();
585 result
= Tcl_ListObjLength(interp
, list
, &numobjs
);
586 if (result
!= TCL_OK
) return result
;
589 /* Try decomposing the object into a list */
590 result
= Tcl_ListObjIndex(interp
, list
, 0, &tobj
);
591 if (result
== TCL_OK
) {
592 result
= Tcl_ListObjLength(interp
, tobj
, &numobjs
);
596 if (result
!= TCL_OK
) Tcl_ResetResult(interp
);
599 Tcl_SetResult(interp
, "list must contain x y positions", NULL
);
602 result
= Tcl_ListObjIndex(interp
, list
, 0, &lobj
);
603 if (result
!= TCL_OK
) return result
;
604 result
= Tcl_GetIntFromObj(interp
, lobj
, &pos
);
605 if (result
!= TCL_OK
) return result
;
606 if (rpoint
) rpoint
->x
= pos
;
608 result
= Tcl_ListObjIndex(interp
, list
, 1, &lobj
);
609 if (result
!= TCL_OK
) return result
;
610 result
= Tcl_GetIntFromObj(interp
, lobj
, &pos
);
611 if (result
!= TCL_OK
) return result
;
612 if (rpoint
) rpoint
->y
= pos
;
617 /*--------------------------------------------------------------*/
618 /* Convert color index to a list of 3 elements */
619 /* We assume that this color exists in the color table. */
620 /*--------------------------------------------------------------*/
622 Tcl_Obj
*TclIndexToRGB(int cidx
)
626 if (cidx
< 0) { /* Handle "default color" */
627 return Tcl_NewStringObj("Default", 7);
629 else if (cidx
>= number_colors
) {
630 Tcl_SetResult(xcinterp
, "Bad color index", NULL
);
634 RGBTuple
= Tcl_NewListObj(0, NULL
);
635 Tcl_ListObjAppendElement(xcinterp
, RGBTuple
,
636 Tcl_NewIntObj((int)(colorlist
[cidx
].color
.red
/ 256)));
637 Tcl_ListObjAppendElement(xcinterp
, RGBTuple
,
638 Tcl_NewIntObj((int)(colorlist
[cidx
].color
.green
/ 256)));
639 Tcl_ListObjAppendElement(xcinterp
, RGBTuple
,
640 Tcl_NewIntObj((int)(colorlist
[cidx
].color
.blue
/ 256)));
645 /*--------------------------------------------------------------*/
646 /* Convert a stringpart* to a Tcl list object */
647 /*--------------------------------------------------------------*/
649 Tcl_Obj
*TclGetStringParts(stringpart
*thisstring
)
651 Tcl_Obj
*lstr
, *sdict
, *stup
;
655 lstr
= Tcl_NewListObj(0, NULL
);
656 for (strptr
= thisstring
, i
= 0; strptr
!= NULL
;
657 strptr
= strptr
->nextpart
, i
++) {
658 switch(strptr
->type
) {
660 sdict
= Tcl_NewListObj(0, NULL
);
661 Tcl_ListObjAppendElement(xcinterp
, sdict
, Tcl_NewStringObj("Text", 4));
662 Tcl_ListObjAppendElement(xcinterp
, sdict
,
663 Tcl_NewStringObj(strptr
->data
.string
,
664 strlen(strptr
->data
.string
)));
665 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
668 sdict
= Tcl_NewListObj(0, NULL
);
669 Tcl_ListObjAppendElement(xcinterp
, sdict
, Tcl_NewStringObj("Parameter", 9));
670 Tcl_ListObjAppendElement(xcinterp
, sdict
,
671 Tcl_NewStringObj(strptr
->data
.string
,
672 strlen(strptr
->data
.string
)));
673 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
676 Tcl_ListObjAppendElement(xcinterp
, lstr
,
677 Tcl_NewStringObj("End Parameter", 13));
680 sdict
= Tcl_NewListObj(0, NULL
);
681 Tcl_ListObjAppendElement(xcinterp
, sdict
, Tcl_NewStringObj("Font", 4));
682 Tcl_ListObjAppendElement(xcinterp
, sdict
,
683 Tcl_NewStringObj(fonts
[strptr
->data
.font
].psname
,
684 strlen(fonts
[strptr
->data
.font
].psname
)));
685 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
688 sdict
= Tcl_NewListObj(0, NULL
);
689 Tcl_ListObjAppendElement(xcinterp
, sdict
,
690 Tcl_NewStringObj("Font Scale", 10));
691 Tcl_ListObjAppendElement(xcinterp
, sdict
,
692 Tcl_NewDoubleObj((double)strptr
->data
.scale
));
693 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
696 sdict
= Tcl_NewListObj(0, NULL
);
697 stup
= Tcl_NewListObj(0, NULL
);
698 Tcl_ListObjAppendElement(xcinterp
, stup
,
699 Tcl_NewIntObj((int)strptr
->data
.kern
[0]));
700 Tcl_ListObjAppendElement(xcinterp
, stup
,
701 Tcl_NewIntObj((int)strptr
->data
.kern
[1]));
703 Tcl_ListObjAppendElement(xcinterp
, sdict
, Tcl_NewStringObj("Kern", 4));
704 Tcl_ListObjAppendElement(xcinterp
, sdict
, stup
);
705 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
708 stup
= TclIndexToRGB(strptr
->data
.color
);
710 sdict
= Tcl_NewListObj(0, NULL
);
711 Tcl_ListObjAppendElement(xcinterp
, sdict
,
712 Tcl_NewStringObj("Color", 5));
713 Tcl_ListObjAppendElement(xcinterp
, sdict
, stup
);
714 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
718 sdict
= Tcl_NewListObj(0, NULL
);
719 Tcl_ListObjAppendElement(xcinterp
, sdict
,
720 Tcl_NewStringObj("Margin Stop", 11));
721 Tcl_ListObjAppendElement(xcinterp
, sdict
,
722 Tcl_NewIntObj((int)strptr
->data
.width
));
723 Tcl_ListObjAppendElement(xcinterp
, lstr
, sdict
);
726 Tcl_ListObjAppendElement(xcinterp
, lstr
,
727 Tcl_NewStringObj("Tab Stop", 8));
730 Tcl_ListObjAppendElement(xcinterp
, lstr
,
731 Tcl_NewStringObj("Tab Forward", 11));
734 Tcl_ListObjAppendElement(xcinterp
, lstr
,
735 Tcl_NewStringObj("Tab Backward", 12));
738 // Don't show automatically interted line breaks
739 if (strptr
->data
.flags
== 0)
740 Tcl_ListObjAppendElement(xcinterp
, lstr
,
741 Tcl_NewStringObj("Return", 6));
744 Tcl_ListObjAppendElement(xcinterp
, lstr
,
745 Tcl_NewStringObj("Subscript", 9));
748 Tcl_ListObjAppendElement(xcinterp
, lstr
,
749 Tcl_NewStringObj("Superscript", 11));
752 Tcl_ListObjAppendElement(xcinterp
, lstr
,
753 Tcl_NewStringObj("Normalscript", 12));
756 Tcl_ListObjAppendElement(xcinterp
, lstr
,
757 Tcl_NewStringObj("Underline", 9));
760 Tcl_ListObjAppendElement(xcinterp
, lstr
,
761 Tcl_NewStringObj("Overline", 8));
764 Tcl_ListObjAppendElement(xcinterp
, lstr
,
765 Tcl_NewStringObj("No Line", 7));
768 Tcl_ListObjAppendElement(xcinterp
, lstr
,
769 Tcl_NewStringObj("Half Space", 10));
772 Tcl_ListObjAppendElement(xcinterp
, lstr
,
773 Tcl_NewStringObj("Quarter Space", 13));
780 /*----------------------------------------------------------------------*/
781 /* Get a stringpart linked list from a Tcl list */
782 /*----------------------------------------------------------------------*/
784 int GetXCStringFromList(Tcl_Interp
*interp
, Tcl_Obj
*list
, stringpart
**rstring
)
786 int result
, j
, k
, numobjs
, idx
, numparts
, ptype
, ival
;
787 Tcl_Obj
*lobj
, *pobj
, *tobj
, *t2obj
;
792 static char *partTypes
[] = {"Text", "Subscript", "Superscript",
793 "Normalscript", "Underline", "Overline", "No Line", "Tab Stop",
794 "Tab Forward", "Tab Backward", "Half Space", "Quarter Space",
795 "Return", "Font", "Font Scale", "Color", "Margin Stop", "Kern",
796 "Parameter", "End Parameter", "Special", NULL
};
798 static int partTypesIdx
[] = {TEXT_STRING
, SUBSCRIPT
, SUPERSCRIPT
,
799 NORMALSCRIPT
, UNDERLINE
, OVERLINE
, NOLINE
, TABSTOP
, TABFORWARD
,
800 TABBACKWARD
, HALFSPACE
, QTRSPACE
, RETURN
, FONT_NAME
, FONT_SCALE
,
801 FONT_COLOR
, MARGINSTOP
, KERN
, PARAM_START
, PARAM_END
, SPECIAL
};
803 /* No place to put result! */
804 if (rstring
== NULL
) return TCL_ERROR
;
806 result
= Tcl_ListObjLength(interp
, list
, &numobjs
);
807 if (result
!= TCL_OK
) return result
;
810 for (j
= 0; j
< numobjs
; j
++) {
811 result
= Tcl_ListObjIndex(interp
, list
, j
, &lobj
);
812 if (result
!= TCL_OK
) return result
;
814 result
= Tcl_ListObjLength(interp
, lobj
, &numparts
);
815 if (result
!= TCL_OK
) return result
;
817 result
= Tcl_ListObjIndex(interp
, lobj
, 0, &pobj
);
818 if (result
!= TCL_OK
) return result
;
820 /* Must define TCL_EXACT in flags, or else, for instance, "u" gets */
821 /* interpreted as "underline", which is usually not intended. */
825 else if (Tcl_GetIndexFromObj(interp
, pobj
, (CONST84
char **)partTypes
,
826 "string part types", TCL_EXACT
, &idx
) != TCL_OK
) {
827 Tcl_ResetResult(interp
);
830 // If there's only one object and the first item doesn't match
831 // a stringpart itentifying word, then assume that "list" is a
832 // single text string.
837 result
= Tcl_ListObjIndex(interp
, lobj
, 0, &tobj
);
840 result
= Tcl_ListObjIndex(interp
, lobj
, (numparts
> 1) ? 1 : 0, &tobj
);
842 if (result
!= TCL_OK
) return result
;
845 if ((newpart
== NULL
) || (newpart
->type
!= TEXT_STRING
))
848 /* We have an implicit text string which should be appended */
849 /* to the previous text string with a space character. */
850 newpart
->data
.string
= (char *)realloc(newpart
->data
.string
,
851 strlen(newpart
->data
.string
) + strlen(Tcl_GetString(tobj
))
853 strcat(newpart
->data
.string
, " ");
854 strcat(newpart
->data
.string
, Tcl_GetString(tobj
));
858 ptype
= partTypesIdx
[idx
];
860 newpart
= makesegment(rstring
, NULL
);
861 newpart
->nextpart
= NULL
;
862 newpart
->type
= ptype
;
867 newpart
->data
.string
= strdup(Tcl_GetString(tobj
));
870 fname
= Tcl_GetString(tobj
);
871 for (k
= 0; k
< fontcount
; k
++) {
872 if (!strcmp(fonts
[k
].psname
, fname
)) {
873 newpart
->data
.font
= k
;
877 if (k
== fontcount
) {
878 Tcl_SetResult(interp
, "Bad font name", NULL
);
883 result
= Tcl_GetDoubleFromObj(interp
, tobj
, &fscale
);
884 if (result
!= TCL_OK
) return result
;
885 newpart
->data
.scale
= (float)fscale
;
888 result
= Tcl_GetIntFromObj(interp
, tobj
, &ival
);
889 if (result
!= TCL_OK
) return result
;
890 newpart
->data
.width
= ival
;
893 result
= Tcl_ListObjLength(interp
, tobj
, &numparts
);
894 if (result
!= TCL_OK
) return result
;
896 Tcl_SetResult(interp
, "Bad kern list: need 2 values", NULL
);
899 result
= Tcl_ListObjIndex(interp
, tobj
, 0, &t2obj
);
900 if (result
!= TCL_OK
) return result
;
901 result
= Tcl_GetIntFromObj(interp
, t2obj
, &ival
);
902 if (result
!= TCL_OK
) return result
;
903 newpart
->data
.kern
[0] = (short)ival
;
905 result
= Tcl_ListObjIndex(interp
, tobj
, 1, &t2obj
);
906 if (result
!= TCL_OK
) return result
;
907 result
= Tcl_GetIntFromObj(interp
, t2obj
, &ival
);
908 if (result
!= TCL_OK
) return result
;
909 newpart
->data
.kern
[1] = (short)ival
;
913 /* Not implemented: Need TclRGBToIndex() function */
916 /* All other types have no arguments */
922 /*----------------------------------------------------------------------*/
923 /* Handle (integer representation of internal xcircuit object) checking */
924 /* if "checkobject" is NULL, then */
925 /*----------------------------------------------------------------------*/
927 genericptr
*CheckHandle(pointertype eaddr
, objectptr checkobject
)
934 if (checkobject
!= NULL
) {
935 for (gelem
= checkobject
->plist
; gelem
< checkobject
->plist
+
936 checkobject
->parts
; gelem
++)
937 if ((pointertype
)(*gelem
) == eaddr
) goto exists
;
941 /* Look through all the pages. */
943 for (i
= 0; i
< xobjs
.pages
; i
++) {
944 if (xobjs
.pagelist
[i
]->pageinst
== NULL
) continue;
945 thisobj
= xobjs
.pagelist
[i
]->pageinst
->thisobject
;
946 for (gelem
= thisobj
->plist
; gelem
< thisobj
->plist
+ thisobj
->parts
; gelem
++)
947 if ((pointertype
)(*gelem
) == eaddr
) goto exists
;
950 /* Not found? Maybe in a library */
952 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
953 thislib
= xobjs
.userlibs
+ i
;
954 for (j
= 0; j
< thislib
->number
; j
++) {
955 thisobj
= thislib
->library
[j
];
956 for (gelem
= thisobj
->plist
; gelem
< thisobj
->plist
+ thisobj
->parts
; gelem
++)
957 if ((pointertype
)(*gelem
) == eaddr
) goto exists
;
961 /* Either in the delete list (where we don't want to go) or */
962 /* is an invalid number. */
969 /*----------------------------------------------------------------------*/
970 /* Find the index into the "plist" list of elements */
971 /* Part number must be of a type in "mask" or no selection occurs. */
972 /* return values: -1 = no object found, -2 = found, but wrong type */
973 /*----------------------------------------------------------------------*/
975 short GetPartNumber(genericptr egen
, objectptr checkobject
, int mask
)
978 objectptr thisobject
= checkobject
;
981 if (checkobject
== NULL
) thisobject
= topobject
;
983 for (i
= 0, gelem
= thisobject
->plist
; gelem
< thisobject
->plist
+
984 thisobject
->parts
; gelem
++, i
++) {
985 if ((*gelem
) == egen
) {
986 if ((*gelem
)->type
& mask
)
995 /*----------------------------------------------------------------------*/
996 /* This routine is used by a number of menu functions. It looks for */
997 /* the arguments "selected" or an integer (object handle). If the */
998 /* argument is a valid object handle, it is added to the select list. */
999 /* The argument can be a list of handles, of which each is checked and */
1000 /* added to the select list. */
1001 /* "extra" indicates the number of required arguments beyond 2. */
1002 /* "next" returns the integer of the argument after the handle, or the */
1003 /* argument after the command, if there is no handle. If the handle is */
1004 /* specified as a hierarchical list of element handles then */
1005 /* areawin->hierstack contains the hierarchy of object instances. */
1006 /*----------------------------------------------------------------------*/
1008 int ParseElementArguments(Tcl_Interp
*interp
, int objc
,
1009 Tcl_Obj
*CONST objv
[], int *next
, int mask
) {
1013 int i
, j
, result
, numobjs
;
1014 pointertype ehandle
;
1016 int extra
= 0, goodobjs
= 0;
1023 if ((objc
> (2 + extra
)) || (objc
== 1)) {
1024 Tcl_WrongNumArgs(interp
, 1, objv
, "[selected | <element_handle>] <option>");
1027 else if (objc
== 1) {
1032 argstr
= Tcl_GetString(objv
[1]);
1034 if (strcmp(argstr
, "selected")) {
1036 /* check for object handle (special type) */
1038 result
= Tcl_ListObjLength(interp
, objv
[1], &numobjs
);
1039 if (result
!= TCL_OK
) return result
;
1042 /* Non-integer, non-list types: assume operation is to be applied */
1043 /* to currently selected elements, and return to caller. */
1046 result
= Tcl_GetHandleFromObj(interp
, objv
[1], (void *)&ehandle
);
1047 if (result
!= TCL_OK
) {
1048 Tcl_ResetResult(interp
);
1053 Tcl_SetResult(interp
, "No elements.", NULL
);
1057 newselect
= (short *)malloc(numobjs
* sizeof(short));
1059 /* Prepare a new selection, in case the new selection is */
1060 /* smaller than the original selection, but don't blanket */
1061 /* delete an existing selection, which will destroy cycle */
1064 for (j
= 0; j
< numobjs
; j
++) {
1065 result
= Tcl_ListObjIndex(interp
, objv
[1], j
, &lobj
);
1066 if (result
!= TCL_OK
) {
1070 result
= Tcl_GetHandleFromObj(interp
, lobj
, (void *)&ehandle
);
1071 if (result
!= TCL_OK
) {
1075 if (areawin
->hierstack
!= NULL
)
1076 i
= GetPartNumber((genericptr
)ehandle
,
1077 areawin
->hierstack
->thisinst
->thisobject
, mask
);
1079 i
= GetPartNumber((genericptr
)ehandle
, topobject
, mask
);
1082 free_stack(&areawin
->hierstack
);
1083 Tcl_SetResult(interp
, "No such element exists.", NULL
);
1088 *(newselect
+ goodobjs
) = i
;
1089 if (next
!= NULL
) *next
= 2;
1093 if (goodobjs
== 0) {
1094 Tcl_SetResult(interp
, "No element matches required type.", NULL
);
1100 selection aselect
, bselect
;
1102 /* To avoid unnecessarily blasting the existing selection */
1103 /* and its cycles, we compare the two selection lists. */
1104 /* This is not an excuse for not fixing the selection list */
1105 /* mess in general! */
1107 aselect
.selectlist
= newselect
;
1108 aselect
.selects
= goodobjs
;
1109 bselect
.selectlist
= areawin
->selectlist
;
1110 bselect
.selects
= areawin
->selects
;
1111 if (compareselection(&aselect
, &bselect
)) {
1116 areawin
->selects
= goodobjs
;
1117 areawin
->selectlist
= newselect
;
1121 draw_normal_selected(topobject
, areawin
->topinstance
);
1123 else if (next
!= NULL
) *next
= 2;
1128 /*----------------------------------------------------------------------*/
1129 /* Generate a transformation matrix according to the object instance */
1130 /* hierarchy left on the hierstack. */
1131 /*----------------------------------------------------------------------*/
1133 void MakeHierCTM(Matrix
*hierCTM
)
1135 objinstptr thisinst
;
1139 for (cs
= areawin
->hierstack
; cs
!= NULL
; cs
= cs
->next
) {
1140 thisinst
= cs
->thisinst
;
1141 UMultCTM(hierCTM
, thisinst
->position
, thisinst
->scale
, thisinst
->rotation
);
1145 /*----------------------------------------------------------------------*/
1146 /* This routine is similar to ParseElementArguments. It looks for a */
1147 /* page number or page name in the second argument position. If it */
1148 /* finds one, it sets the page number in the return value. Otherwise, */
1149 /* it sets the return value to the value of areawin->page. */
1150 /*----------------------------------------------------------------------*/
1152 int ParsePageArguments(Tcl_Interp
*interp
, int objc
,
1153 Tcl_Obj
*CONST objv
[], int *next
, int *pageret
) {
1156 int i
, page
, result
;
1159 if (next
!= NULL
) *next
= 1;
1160 if (pageret
!= NULL
) *pageret
= areawin
->page
; /* default */
1162 if ((objc
== 1) || ((objc
== 2) && !strcmp(Tcl_GetString(objv
[1]), ""))) {
1163 objPtr
= Tcl_NewIntObj(areawin
->page
+ 1);
1164 Tcl_SetObjResult(interp
, objPtr
);
1165 if (next
) *next
= -1;
1169 pagename
= Tcl_GetString(objv
[1]);
1170 if (strcmp(pagename
, "directory")) {
1172 /* check for page number (integer) */
1174 result
= Tcl_GetIntFromObj(interp
, objv
[1], &page
);
1175 if (result
!= TCL_OK
) {
1176 Tcl_ResetResult(interp
);
1178 /* check for page name (string) */
1180 for (i
= 0; i
< xobjs
.pages
; i
++) {
1181 if (xobjs
.pagelist
[i
]->pageinst
== NULL
) continue;
1182 if (!strcmp(pagename
, xobjs
.pagelist
[i
]->pageinst
->thisobject
->name
)) {
1183 if (pageret
) *pageret
= i
;
1187 if (i
== xobjs
.pages
) {
1188 if (next
!= NULL
) *next
= 0;
1193 Tcl_SetResult(interp
, "Illegal page number: zero or negative", NULL
);
1196 else if (page
> xobjs
.pages
) {
1197 Tcl_SetResult(interp
, "Illegal page number: page does not exist", NULL
);
1198 if (pageret
) *pageret
= (page
- 1);
1201 else if (pageret
) *pageret
= (page
- 1);
1211 /*----------------------------------------------------------------------*/
1212 /* This routine is similar to ParsePageArguments. It looks for a */
1213 /* library number or library name in the second argument position. If */
1214 /* it finds one, it sets the page number in the return value. */
1215 /* Otherwise, if a library page is currently being viewed, it sets the */
1216 /* return value to that library. Otherwise, it sets the return value */
1217 /* to the User Library. */
1218 /*----------------------------------------------------------------------*/
1220 int ParseLibArguments(Tcl_Interp
*interp
, int objc
,
1221 Tcl_Obj
*CONST objv
[], int *next
, int *libret
) {
1224 int library
, result
;
1227 if (next
!= NULL
) *next
= 1;
1230 library
= is_library(topobject
);
1232 Tcl_SetResult(interp
, "No current library.", NULL
);
1235 objPtr
= Tcl_NewIntObj(library
+ 1);
1236 Tcl_SetObjResult(interp
, objPtr
);
1237 if (next
) *next
= -1;
1241 libname
= Tcl_GetString(objv
[1]);
1242 if (strcmp(libname
, "directory")) {
1244 /* check for library number (integer) or name */
1246 result
= Tcl_GetIntFromObj(interp
, objv
[1], &library
);
1247 if (result
!= TCL_OK
) {
1248 Tcl_ResetResult(xcinterp
);
1249 *libret
= NameToLibrary(libname
);
1252 if (next
!= NULL
) *next
= 0;
1257 Tcl_SetResult(interp
, "Illegal library number: zero or negative", NULL
);
1260 else if (library
> xobjs
.numlibs
) {
1261 Tcl_SetResult(interp
, "Illegal library number: library "
1262 "does not exist", NULL
);
1265 else *libret
= (library
- 1);
1273 /*----------------------------------------------------------------------*/
1274 /* Schematic and symbol creation and association */
1275 /*----------------------------------------------------------------------*/
1277 int xctcl_symschem(ClientData clientData
, Tcl_Interp
*interp
,
1278 int objc
, Tcl_Obj
*CONST objv
[])
1280 int i
, idx
, result
, stype
;
1281 objectptr otherobj
= NULL
;
1284 static char *subCmds
[] = {
1285 "associate", "disassociate", "make", "goto", "get", "type", NULL
1288 AssocIdx
, DisAssocIdx
, MakeIdx
, GoToIdx
, NameIdx
, TypeIdx
1291 /* The order of these must match the definitions in xcircuit.h */
1292 static char *schemTypes
[] = {
1293 "primary", "secondary", "trivial", "symbol", "fundamental",
1294 "nonetwork", NULL
/* (jdk) */
1297 if (objc
== 1 || objc
> 4) {
1298 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
1301 else if ((result
= Tcl_GetIndexFromObj(interp
, objv
[1],
1302 (CONST84
char **)subCmds
, "option", 0, &idx
)) != TCL_OK
) {
1310 /* To do: accept name for association */
1311 objname
= Tcl_GetString(objv
[2]);
1313 if (topobject
->schemtype
== PRIMARY
) {
1315 /* Name has to be that of a library object */
1317 otherobj
= NameToObject(Tcl_GetString(objv
[2]), NULL
, FALSE
);
1318 if (otherobj
== NULL
) {
1319 Tcl_SetResult(interp
, "Name is not a known object", NULL
);
1325 /* Name has to be that of a page label */
1328 for (i
= 0; i
< xobjs
.pages
; i
++) {
1329 pageobj
= xobjs
.pagelist
[i
]->pageinst
->thisobject
;
1330 if (!strcmp(objname
, pageobj
->name
)) {
1335 if (otherobj
== NULL
)
1337 Tcl_SetResult(interp
, "Name is not a known page label", NULL
);
1341 if (schemassoc(topobject
, otherobj
) == False
)
1345 startschemassoc(NULL
, 0, NULL
);
1351 if (topobject
->symschem
!= NULL
)
1352 Wprintf("Error: Schematic already has an associated symbol.");
1353 else if (topobject
->schemtype
!= PRIMARY
)
1354 Wprintf("Error: Current page is not a primary schematic.");
1355 else if (!strncmp(topobject
->name
, "Page ", 5))
1356 Wprintf("Error: Schematic page must have a valid name.");
1361 objname
= Tcl_GetString(objv
[2]);
1364 ParseLibArguments(xcinterp
, 2, &objv
[2], NULL
, &libnum
);
1366 Tcl_SetResult(interp
, "Invalid library name.", NULL
);
1372 /* Use this error condition to generate the popup prompt */
1373 Tcl_SetResult(interp
, "Must supply a name for the page", NULL
);
1376 swapschem(1, libnum
, objname
);
1382 /* This is supposed to specifically go to the specified type, */
1383 /* so don't call swapschem to change views if we're already */
1384 /* on the right view. */
1386 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
1387 if (!strncmp(Tcl_GetString(objv
[0]), "sym", 3)) {
1388 swapschem(0, -1, NULL
);
1392 if (!strncmp(Tcl_GetString(objv
[0]), "sch", 3)) {
1393 swapschem(0, -1, NULL
);
1398 if (topobject
->symschem
!= NULL
)
1399 Tcl_AppendElement(interp
, topobject
->symschem
->name
);
1403 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
1404 Tcl_SetResult(interp
, "Make object to change from schematic to symbol",
1408 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[2],
1409 (CONST84
char **)schemTypes
, "schematic types",
1410 0, &stype
)) != TCL_OK
)
1412 if (stype
== PRIMARY
|| stype
== SECONDARY
) {
1413 Tcl_SetResult(interp
, "Cannot change symbol into a schematic", NULL
);
1416 topobject
->schemtype
= stype
;
1417 if (topobject
->symschem
) schemdisassoc();
1420 Tcl_AppendElement(interp
, schemTypes
[topobject
->schemtype
]);
1424 return XcTagCallback(interp
, objc
, objv
);
1427 /*----------------------------------------------------------------------*/
1428 /* Generate netlist into a Tcl hierarchical list */
1429 /* (plus other netlist functions) */
1430 /*----------------------------------------------------------------------*/
1432 int xctcl_netlist(ClientData clientData
, Tcl_Interp
*interp
,
1433 int objc
, Tcl_Obj
*CONST objv
[])
1436 int idx
, result
, mpage
, spage
, bvar
, j
;
1437 Boolean valid
, quiet
;
1438 char *option
, *extension
, *mode
= NULL
;
1440 objectptr master
, slave
;
1441 objinstptr schemtopinst
;
1443 static char *subCmds
[] = {
1444 "write", "highlight", "unhighlight", "goto", "get", "select", "parse",
1445 "position", "make", "connect", "unconnect", "autonumber", "ratsnest",
1449 WriteIdx
, HighLightIdx
, UnHighLightIdx
, GoToIdx
, GetIdx
, SelectIdx
,
1450 ParseIdx
, PositionIdx
, MakeIdx
, ConnectIdx
, UnConnectIdx
,
1451 AutoNumberIdx
, RatsNestIdx
, UpdateIdx
1455 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
1458 else if ((result
= Tcl_GetIndexFromObj(interp
, objv
[1],
1459 (CONST84
char **)subCmds
, "option", 0, &idx
)) != TCL_OK
) {
1463 /* Look for the "-quiet" option (more options processed by "netlist get") */
1467 while (option
= Tcl_GetString(objv
[objc
- (j
++)]), option
[0] == '-') {
1468 if (!strncmp(option
+ 1, "quiet", 5))
1472 /* Make sure a valid netlist exists for the current schematic */
1473 /* for those commands which require a valid netlist (non-ASG */
1474 /* functions). Some functions (e.g., "parse") require that */
1475 /* the next object up in the hierarchy have a valid netlist, */
1476 /* if we have descended to the current symbol from there. */
1481 /* Specifically avoid calling updatenets() */
1482 if ((topobject
->labels
!= NULL
) || (topobject
->polygons
!= NULL
))
1490 /* Ignore libraries */
1491 if (is_library(topobject
) >= 0 || (eventmode
== CATALOG_MODE
))
1494 if ((topobject
->schemtype
) != PRIMARY
&& (areawin
->stack
!= NULL
))
1495 tinst
= areawin
->stack
->thisinst
;
1497 tinst
= areawin
->topinstance
;
1499 if ((result
= updatenets(tinst
, quiet
)) < 0) {
1500 Tcl_SetResult(interp
, "Check circuit for infinite recursion.", NULL
);
1503 else if (result
== 0) {
1504 Tcl_SetResult(interp
, "No netlist.", NULL
);
1510 case WriteIdx
: /* write netlist formats */
1512 Tcl_WrongNumArgs(interp
, 1, objv
, "write format [extension] "
1513 "[spice_end] [-option]");
1517 /* Check for forcing option */
1519 option
= Tcl_GetString(objv
[objc
- 1]);
1520 if (option
[0] == '-')
1523 if (!strncmp(option
, "flat", 4) || !strncmp(option
, "pseu", 4))
1525 mode
= (char *)malloc(5 + strlen(Tcl_GetString(objv
[2])));
1527 sprintf(mode
, "%s%s", option
, Tcl_GetString(objv
[2]));
1529 else if (strncmp(option
, "hier", 4))
1531 Tcl_SetResult(interp
, "Unknown netlist option.", NULL
);
1537 if ((result
= Tcl_GetBooleanFromObj(interp
, objv
[objc
- 1], &bvar
))
1540 Tcl_ResetResult(interp
);
1543 spice_end
= (Boolean
)bvar
;
1547 /* If no extension is specified, the extension is the same as */
1548 /* the format name. */
1551 extension
= Tcl_GetString(objv
[2]);
1553 extension
= Tcl_GetString(objv
[3]);
1554 writenet(topobject
, (mode
== NULL
) ? Tcl_GetString(objv
[2]) : mode
,
1556 if (mode
!= NULL
) free(mode
);
1559 case GoToIdx
: /* go to top-level page having specified name */
1560 if (objc
!= 2 && objc
!= 3) {
1561 Tcl_WrongNumArgs(interp
, 1, objv
, "goto [hierarchical-network-name]");
1565 /* Find the top of the schematic hierarchy, regardless of */
1566 /* where the current page is in it. */
1568 if (areawin
->stack
== NULL
)
1569 schemtopinst
= areawin
->topinstance
;
1571 pushlistptr sstack
= areawin
->stack
;
1572 while (sstack
->next
!= NULL
) sstack
= sstack
->next
;
1573 schemtopinst
= sstack
->thisinst
;
1577 push_stack(&stack
, schemtopinst
, NULL
);
1580 valid
= HierNameToObject(schemtopinst
, Tcl_GetString(objv
[2]), &stack
);
1583 /* Add the current edit object to the push stack, then append */
1584 /* the new push stack */
1585 free_stack(&areawin
->stack
);
1586 topobject
->viewscale
= areawin
->vscale
;
1587 topobject
->pcorner
= areawin
->pcorner
;
1588 areawin
->topinstance
= stack
->thisinst
;
1590 areawin
->stack
= stack
;
1593 refresh(NULL
, NULL
, NULL
);
1596 /* If the current object is a symbol that has a schematic, */
1597 /* go to the schematic. */
1599 if (topobject
->schemtype
!= PRIMARY
&& topobject
->symschem
!= NULL
)
1600 swapschem(0, -1, NULL
);
1603 Tcl_SetResult(interp
, "Not a valid network.", NULL
);
1608 case GetIdx
: { /* return hierarchical name of selected network */
1609 int stype
, netid
, lbus
;
1610 Boolean uplevel
, hier
, canon
;
1611 char *prefix
= NULL
;
1614 Genericlist
*netlist
;
1616 objinstptr refinstance
;
1617 objectptr refobject
;
1618 XPoint refpoint
, *refptptr
;
1624 option
= Tcl_GetString(objv
[objc
- 1]);
1629 while (option
[0] == '-') {
1630 if (!strncmp(option
+ 1, "up", 2)) {
1633 else if (!strncmp(option
+ 1, "hier", 4)) {
1636 else if (!strncmp(option
+ 1, "canon", 5)) {
1639 else if (!strncmp(option
+ 1, "quiet", 5)) {
1642 else if (sscanf(option
, "%hd", &refpoint
.x
) == 1) {
1643 break; /* This is probably a negative point position! */
1646 option
= Tcl_GetString(objv
[objc
- 1]);
1649 refinstance
= (areawin
->hierstack
) ? areawin
->hierstack
->thisinst
1650 : areawin
->topinstance
;
1653 if (areawin
->hierstack
== NULL
) {
1654 if (areawin
->stack
== NULL
) {
1655 if (quiet
) return TCL_OK
;
1656 Fprintf(stderr
, "Option \"up\" used, but current page is the"
1657 " top of the schematic\n");
1662 UPreMultCTM(&locctm
, refinstance
->position
, refinstance
->scale
,
1663 refinstance
->rotation
);
1664 refinstance
= areawin
->stack
->thisinst
;
1665 refobject
= refinstance
->thisobject
;
1669 if (areawin
->hierstack
->next
== NULL
) {
1670 if (quiet
) return TCL_OK
;
1671 Fprintf(stderr
, "Option \"up\" used, but current page is the"
1672 " top of the drawing stack\n");
1677 UPreMultCTM(&locctm
, refinstance
->position
, refinstance
->scale
,
1678 refinstance
->rotation
);
1679 refinstance
= areawin
->hierstack
->next
->thisinst
;
1680 refobject
= refinstance
->thisobject
;
1685 refobject
= topobject
;
1687 if ((objc
!= 2) && (objc
!= 3)) {
1688 Tcl_WrongNumArgs(interp
, 1, objv
,
1689 "get [selected|here|<name>] [-up][-hier][-canon][-quiet]");
1692 if ((objc
== 3) && !strcmp(Tcl_GetString(objv
[2]), "here")) {
1693 /* If "here", make a selection. */
1694 areawin
->save
= UGetCursorPos();
1695 newselect
= select_element(POLYGON
| LABEL
| OBJINST
);
1698 if ((objc
== 2) || (!strcmp(Tcl_GetString(objv
[2]), "selected"))) {
1699 /* If no argument, or "selected", use the selected element */
1700 newselect
= areawin
->selectlist
;
1701 if (areawin
->selects
== 0) {
1703 Tcl_SetResult(interp
, GetHierarchy(&areawin
->stack
, canon
),
1708 Fprintf(stderr
, "Either select an element or use \"-hier\"\n");
1712 if (areawin
->selects
!= 1) {
1713 Fprintf(stderr
, "Choose only one network element\n");
1717 stype
= SELECTTYPE(newselect
);
1718 if (stype
== LABEL
) {
1719 labelptr nlabel
= SELTOLABEL(newselect
);
1720 refptptr
= &(nlabel
->position
);
1721 if ((nlabel
->pin
!= LOCAL
) && (nlabel
->pin
!= GLOBAL
)) {
1722 Fprintf(stderr
, "Selected label is not a pin\n");
1726 else if (stype
== POLYGON
) {
1727 polyptr npoly
= SELTOPOLY(newselect
);
1728 refptptr
= npoly
->points
;
1729 if (nonnetwork(npoly
)) {
1730 Fprintf(stderr
, "Selected polygon is not a wire\n");
1734 else if (stype
== OBJINST
) {
1735 objinstptr ninst
= SELTOOBJINST(newselect
);
1738 for (calls
= topobject
->calls
; calls
!= NULL
; calls
= calls
->next
)
1739 if (calls
->callinst
== ninst
)
1741 if (calls
== NULL
) {
1742 Fprintf(stderr
, "Selected instance is not a circuit component\n");
1745 else if (calls
->devindex
== -1) {
1746 cleartraversed(topobject
);
1747 resolve_indices(topobject
, FALSE
);
1749 push_stack(&areawin
->stack
, ninst
, NULL
);
1750 prefix
= GetHierarchy(&areawin
->stack
, canon
);
1751 pop_stack(&areawin
->stack
);
1752 if (prefix
== NULL
) break;
1755 devptr
= strrchr(prefix
, '/');
1761 Tcl_SetResult(interp
, devptr
, TCL_VOLATILE
);
1767 else if ((objc
== 3) && (result
= GetPositionFromList(interp
, objv
[2],
1768 &refpoint
)) == TCL_OK
) {
1769 /* Find net at indicated position in reference object. */
1770 /* This allows us to query points without generating a pin */
1771 /* at the position, which can alter the netlist under */
1773 refptptr
= &refpoint
;
1776 /* If a name, find the pin label element matching the name */
1778 objinstptr instofname
= (areawin
->hierstack
) ?
1779 areawin
->hierstack
->thisinst
:
1780 areawin
->topinstance
;
1782 Tcl_ResetResult(interp
);
1784 if (NameToPinLocation(instofname
, Tcl_GetString(objv
[2]),
1786 refpoint
.x
= x
; /* conversion from int to short */
1788 refptptr
= &refpoint
;
1791 /* This is not necessarily an error. Use "-quiet" to shut it up */
1792 if (quiet
) return TCL_OK
;
1793 Tcl_SetResult(interp
, "Cannot find position for pin ", NULL
);
1794 Tcl_AppendElement(interp
, Tcl_GetString(objv
[2]));
1799 /* Now that we have a reference point, convert it to a netlist */
1801 UTransformbyCTM(&locctm
, refptptr
, &refpoint
, 1);
1802 refptptr
= &refpoint
;
1804 netlist
= pointtonet(refobject
, refinstance
, refptptr
);
1805 if (netlist
== NULL
) {
1806 if (quiet
) return TCL_OK
;
1807 Fprintf(stderr
, "Error: No network found!\n");
1811 /* If refobject is a secondary schematic, we need to find the */
1812 /* corresponding primary page to call nettopin(). */
1813 master
= (refobject
->schemtype
== SECONDARY
) ?
1814 refobject
->symschem
: refobject
;
1816 /* Now that we have a netlist, convert it to a name */
1817 /* Need to get prefix from the current call stack so we */
1818 /* can represent flat names as well as hierarchical names. */
1822 prefix
= GetHierarchy(&areawin
->stack
, canon
);
1824 plen
= strlen(prefix
);
1825 if (*(prefix
+ plen
- 1) != '/') {
1826 prefix
= realloc(prefix
, plen
+ 2);
1827 strcat(prefix
, "/");
1832 if (netlist
->subnets
== 0) {
1833 netid
= netlist
->net
.id
;
1834 ppin
= nettopin(netid
, master
, (prefix
== NULL
) ? "" : prefix
);
1835 snew
= textprint(ppin
, refinstance
);
1836 Tcl_SetResult(interp
, snew
, TCL_DYNAMIC
);
1838 else if (netlist
->subnets
== 1) {
1840 /* Need to get prefix from the current call stack! */
1841 sbus
= netlist
->net
.list
;
1842 netid
= sbus
->netid
;
1843 ppin
= nettopin(netid
, master
, (prefix
== NULL
) ? "" : prefix
);
1844 snew
= textprintsubnet(ppin
, refinstance
, sbus
->subnetid
);
1845 Tcl_SetResult(interp
, snew
, TCL_DYNAMIC
);
1848 tlist
= Tcl_NewListObj(0, NULL
);
1849 for (lbus
= 0; lbus
< netlist
->subnets
; lbus
++) {
1850 sbus
= netlist
->net
.list
+ lbus
;
1851 netid
= sbus
->netid
;
1852 ppin
= nettopin(netid
, master
, (prefix
== NULL
) ? "" : prefix
);
1853 snew
= textprintsubnet(ppin
, refinstance
, sbus
->subnetid
);
1854 Tcl_ListObjAppendElement(interp
, tlist
, Tcl_NewStringObj(snew
, -1));
1855 Tcl_SetObjResult(interp
, tlist
);
1859 if (prefix
!= NULL
) free(prefix
);
1862 case ParseIdx
: { /* generate output from info labels */
1867 Tcl_WrongNumArgs(interp
, 1, objv
, "parse <mode>");
1870 mode
= Tcl_GetString(objv
[2]);
1872 if ((master
->schemtype
== SECONDARY
) && (master
->symschem
!= NULL
))
1873 master
= master
->symschem
;
1875 if (master
->schemtype
!= PRIMARY
&& areawin
->stack
!= NULL
) {
1876 cfrom
= areawin
->stack
->thisinst
->thisobject
;
1877 snew
= parseinfo(cfrom
, master
, cfrom
->calls
, NULL
, mode
, FALSE
, TRUE
);
1882 loccalls
.cschem
= NULL
;
1883 loccalls
.callobj
= master
;
1884 loccalls
.callinst
= areawin
->topinstance
;
1885 loccalls
.devindex
= -1;
1886 loccalls
.ports
= NULL
;
1887 loccalls
.next
= NULL
;
1889 snew
= parseinfo(NULL
, master
, &loccalls
, NULL
, mode
, FALSE
, TRUE
);
1891 Tcl_SetResult(interp
, snew
, TCL_DYNAMIC
);
1895 case UnConnectIdx
: /* disassociate the page with another one */
1896 if ((objc
!= 2) && (objc
!= 3)) {
1897 Tcl_WrongNumArgs(interp
, 1, objv
, "unconnect [<secondary>]");
1900 else if (objc
== 3) {
1901 result
= Tcl_GetIntFromObj(interp
, objv
[2], &spage
);
1902 if (result
!= TCL_OK
) {
1903 Tcl_ResetResult(interp
);
1904 slave
= NameToPageObject(Tcl_GetString(objv
[2]), NULL
, &spage
);
1907 if (spage
>= xobjs
.pages
) {
1908 Tcl_SetResult(interp
, "Bad page number for secondary schematic", NULL
);
1911 slave
= xobjs
.pagelist
[spage
]->pageinst
->thisobject
;
1913 if ((slave
== NULL
) || (is_page(slave
) < 0)) {
1914 Tcl_SetResult(interp
, "Error determining secondary schematic", NULL
);
1920 spage
= areawin
->page
;
1922 if (slave
->symschem
== NULL
|| slave
->symschem
->schemtype
!=
1924 Tcl_SetResult(interp
, "Page is not a secondary schematic", NULL
);
1928 destroynets(slave
->symschem
);
1929 slave
->schemtype
= PRIMARY
;
1930 slave
->symschem
= NULL
;
1933 case ConnectIdx
: /* associate the page with another one */
1934 if ((objc
!= 3) && (objc
!= 4)) {
1935 Tcl_WrongNumArgs(interp
, 1, objv
, "connect <primary> [<secondary>]");
1938 else if (objc
== 4) {
1939 result
= Tcl_GetIntFromObj(interp
, objv
[3], &spage
);
1940 if (result
!= TCL_OK
) {
1941 Tcl_ResetResult(interp
);
1942 slave
= NameToPageObject(Tcl_GetString(objv
[3]), NULL
, &spage
);
1945 if (spage
>= xobjs
.pages
) {
1946 Tcl_SetResult(interp
, "Bad page number for secondary schematic", NULL
);
1949 slave
= xobjs
.pagelist
[spage
]->pageinst
->thisobject
;
1951 if ((slave
== NULL
) || (is_page(slave
) < 0)) {
1952 Tcl_SetResult(interp
, "Error determining secondary schematic", NULL
);
1958 spage
= areawin
->page
;
1962 result
= Tcl_GetIntFromObj(interp
, objv
[2], &mpage
);
1963 if (result
!= TCL_OK
) {
1964 Tcl_ResetResult(interp
);
1965 master
= NameToPageObject(Tcl_GetString(objv
[2]), NULL
, &mpage
);
1970 if ((mpage
>= xobjs
.pages
) || (xobjs
.pagelist
[mpage
]->pageinst
== NULL
)) {
1971 Tcl_SetResult(interp
, "Bad page number for master schematic", NULL
);
1974 else if (mpage
== areawin
->page
) {
1975 Tcl_SetResult(interp
, "Attempt to specify schematic "
1976 "as its own master", NULL
);
1979 if (xobjs
.pagelist
[mpage
]->pageinst
->thisobject
->symschem
== slave
) {
1980 Tcl_SetResult(interp
, "Attempt to create recursive "
1981 "primary/secondary schematic relationship", NULL
);
1984 master
= xobjs
.pagelist
[mpage
]->pageinst
->thisobject
;
1985 destroynets(master
);
1987 if ((master
== NULL
) || (is_page(master
) < 0)) {
1988 Tcl_SetResult(interp
, "Error determining master schematic", NULL
);
1992 slave
->schemtype
= SECONDARY
;
1993 slave
->symschem
= master
;
1996 case UnHighLightIdx
: /* remove network connectivity highlight */
1998 highlightnetlist(topobject
, areawin
->topinstance
, 0);
2001 Tcl_WrongNumArgs(interp
, 1, objv
, "(no options)");
2006 case HighLightIdx
: /* highlight network connectivity */
2008 startconnect(NULL
, NULL
, NULL
);
2013 case SelectIdx
: /* select the first element in the indicated net */
2016 XPoint newpos
, *netpos
;
2018 Genericlist
*lnets
, *netlist
;
2025 Tcl_WrongNumArgs(interp
, 1, objv
, "network");
2029 result
= GetPositionFromList(interp
, objv
[2], &newpos
);
2030 if (result
== TCL_OK
) { /* find net at indicated position */
2031 areawin
->save
= newpos
;
2032 connectivity(NULL
, NULL
, NULL
);
2033 /* should there be any result here? */
2036 else { /* assume objv[2] is net name */
2037 Tcl_ResetResult(interp
);
2038 tname
= Tcl_GetString(objv
[2]);
2039 lnets
= nametonet(topobject
, areawin
->topinstance
, tname
);
2040 if (lnets
== NULL
) {
2041 Tcl_SetResult(interp
, "No such network ", NULL
);
2042 Tcl_AppendElement(interp
, tname
);
2047 netlist
= (Genericlist
*)malloc(sizeof(Genericlist
));
2049 /* Erase any existing highlights first */
2050 highlightnetlist(topobject
, areawin
->topinstance
, 0);
2051 netlist
->subnets
= 0;
2052 copy_bus(netlist
, lnets
);
2053 topobject
->highlight
.netlist
= netlist
;
2054 topobject
->highlight
.thisinst
= areawin
->topinstance
;
2055 highlightnetlist(topobject
, areawin
->topinstance
, 1);
2056 if (netlist
->subnets
== 0) {
2057 netid
= netlist
->net
.id
;
2058 Tcl_SetObjResult(interp
, Tcl_NewIntObj(netlist
->net
.id
));
2061 rdict
= Tcl_NewListObj(0, NULL
);
2062 for (lbus
= 0; lbus
< netlist
->subnets
; lbus
++) {
2063 sbus
= netlist
->net
.list
+ lbus
;
2064 netid
= sbus
->netid
;
2065 Tcl_ListObjAppendElement(interp
, rdict
, Tcl_NewIntObj(netid
));
2067 Tcl_SetObjResult(interp
, rdict
);
2071 /* Return a position belonging to the net. If this is a bus, */
2072 /* we return the position of the 1st subnet. At some point, */
2073 /* this should be expanded to return a point per subnet. */
2076 if (lnets
->subnets
== 0)
2077 netid
= lnets
->net
.id
;
2079 netid
= (lnets
->net
.list
)->netid
;
2081 netpos
= NetToPosition(lnets
->net
.id
, topobject
);
2082 rdict
= Tcl_NewListObj(0, NULL
);
2083 Tcl_ListObjAppendElement(interp
, rdict
, Tcl_NewIntObj(netpos
->x
));
2084 Tcl_ListObjAppendElement(interp
, rdict
, Tcl_NewIntObj(netpos
->y
));
2085 Tcl_SetObjResult(interp
, rdict
);
2088 /* Select everything in the network. To-do: allow specific */
2089 /* selection of labels, wires, or a single element in the net */
2093 rdict
= Tcl_NewListObj(0, NULL
);
2094 for (llist
= topobject
->labels
; llist
!= NULL
;
2095 llist
= llist
->next
) {
2096 if (match_buses((Genericlist
*)llist
, (Genericlist
*)lnets
, 0)) {
2097 i
= GetPartNumber((genericptr
)llist
->label
, topobject
, LABEL
);
2099 newselect
= allocselect();
2101 Tcl_ListObjAppendElement(interp
, rdict
,
2102 Tcl_NewHandleObj((genericptr
)llist
->label
));
2106 for (plist
= topobject
->polygons
; plist
!= NULL
;
2107 plist
= plist
->next
) {
2108 if (match_buses((Genericlist
*)plist
, (Genericlist
*)lnets
, 0)) {
2109 i
= GetPartNumber((genericptr
)plist
->poly
, topobject
, POLYGON
);
2111 newselect
= allocselect();
2113 Tcl_ListObjAppendElement(interp
, rdict
,
2114 Tcl_NewHandleObj((genericptr
)plist
->poly
));
2118 Tcl_SetObjResult(interp
, rdict
);
2119 refresh(NULL
, NULL
, NULL
);
2125 case UpdateIdx
: /* destroy and regenerate the current netlist */
2126 destroynets(areawin
->topinstance
->thisobject
);
2127 if ((result
= updatenets(areawin
->topinstance
, quiet
)) < 0) {
2128 Tcl_SetResult(interp
, "Check circuit for infinite recursion.", NULL
);
2131 else if (result
== 0) {
2132 Tcl_SetResult(interp
, "Failure to generate a network.", NULL
);
2137 case MakeIdx
: /* generate Tcl-list netlist */
2138 rdict
= Tcl_NewListObj(0, NULL
);
2139 Tcl_ListObjAppendElement(interp
, rdict
, Tcl_NewStringObj("globals", 7));
2140 Tcl_ListObjAppendElement(interp
, rdict
, tclglobals(areawin
->topinstance
));
2141 Tcl_ListObjAppendElement(interp
, rdict
, Tcl_NewStringObj("circuit", 7));
2142 Tcl_ListObjAppendElement(interp
, rdict
, tcltoplevel(areawin
->topinstance
));
2144 Tcl_SetObjResult(interp
, rdict
);
2147 case AutoNumberIdx
: /* auto-number circuit components */
2148 if (checkvalid(topobject
) == -1) {
2149 destroynets(topobject
);
2150 createnets(areawin
->topinstance
, FALSE
);
2153 cleartraversed(topobject
);
2154 clear_indices(topobject
);
2156 if ((objc
== 3) && !strcmp(Tcl_GetString(objv
[2]), "-forget")) {
2157 cleartraversed(topobject
);
2158 unnumber(topobject
);
2161 cleartraversed(topobject
);
2162 resolve_indices(topobject
, FALSE
); /* Do fixed assignments first */
2163 cleartraversed(topobject
);
2164 resolve_indices(topobject
, TRUE
); /* Now do the auto-numbering */
2169 /* Experimental netlist stuff! */
2170 ratsnest(areawin
->topinstance
);
2173 return XcTagCallback(interp
, objc
, objv
);
2176 /*----------------------------------------------------------------------*/
2177 /* Return current position */
2178 /*----------------------------------------------------------------------*/
2180 int xctcl_here(ClientData clientData
, Tcl_Interp
*interp
,
2181 int objc
, Tcl_Obj
*CONST objv
[])
2183 Tcl_Obj
*listPtr
, *objPtr
;
2187 Tcl_WrongNumArgs(interp
, 0, objv
, "(no arguments)");
2190 newpos
= UGetCursorPos();
2192 listPtr
= Tcl_NewListObj(0, NULL
);
2193 objPtr
= Tcl_NewIntObj((int)newpos
.x
);
2194 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
2196 objPtr
= Tcl_NewIntObj((int)newpos
.y
);
2197 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
2199 Tcl_SetObjResult(interp
, listPtr
);
2201 return XcTagCallback(interp
, objc
, objv
);
2205 /*----------------------------------------------------------------------*/
2206 /* Argument-converting wrappers from Tcl command callback to xcircuit */
2207 /*----------------------------------------------------------------------*/
2209 int xctcl_pan(ClientData clientData
, Tcl_Interp
*interp
,
2210 int objc
, Tcl_Obj
*CONST objv
[])
2214 XPoint newpos
, wpoint
;
2215 static char *directions
[] = {"here", "left", "right", "up", "down",
2216 "center", "follow", NULL
};
2218 DirHere
, DirLeft
, DirRight
, DirUp
, DirDown
, DirCenter
, DirFollow
2221 if (objc
!= 2 && objc
!= 3) {
2222 Tcl_WrongNumArgs(interp
, 0, objv
, "option ?arg ...?");
2226 /* Check against keywords */
2228 if (Tcl_GetIndexFromObj(interp
, objv
[1], (CONST84
char **)directions
,
2229 "option", 0, &idx
) != TCL_OK
) {
2230 result
= GetPositionFromList(interp
, objv
[1], &newpos
);
2231 if (result
!= TCL_OK
) return result
;
2235 newpos
= UGetCursorPos();
2237 user_to_window(newpos
, &wpoint
);
2244 Tcl_WrongNumArgs(interp
, 0, objv
, "(no arguments)");
2248 if (objc
== 2) frac
= 0.3;
2250 Tcl_GetDoubleFromObj(interp
, objv
[2], &frac
);
2253 panbutton((u_int
)idx
, wpoint
.x
, wpoint
.y
, (float)frac
);
2254 return XcTagCallback(interp
, objc
, objv
);
2257 /*----------------------------------------------------------------------*/
2259 int xctcl_zoom(ClientData clientData
, Tcl_Interp
*interp
,
2260 int objc
, Tcl_Obj
*CONST objv
[])
2265 XPoint newpos
, wpoint
;
2267 static char *subCmds
[] = {"in", "out", "view", "factor", NULL
};
2269 InIdx
, OutIdx
, ViewIdx
, FactorIdx
2272 newpos
= UGetCursorPos();
2273 user_to_window(newpos
, &wpoint
);
2276 zoomview(NULL
, NULL
, NULL
);
2277 else if ((result
= Tcl_GetDoubleFromObj(interp
, objv
[1], &factor
)) != TCL_OK
)
2279 Tcl_ResetResult(interp
);
2280 if (Tcl_GetIndexFromObj(interp
, objv
[1], (CONST84
char **)subCmds
,
2281 "option", 0, &idx
) != TCL_OK
) {
2282 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
2287 zoominrefresh(wpoint
.x
, wpoint
.y
);
2290 zoomoutrefresh(wpoint
.x
, wpoint
.y
);
2293 zoomview(NULL
, NULL
, NULL
);
2297 Tcl_Obj
*objPtr
= Tcl_NewDoubleObj((double)areawin
->zoomfactor
);
2298 Tcl_SetObjResult(interp
, objPtr
);
2301 else if (objc
!= 3) {
2302 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
2305 if (!strcmp(Tcl_GetString(objv
[2]), "default"))
2308 result
= Tcl_GetDoubleFromObj(interp
, objv
[2], &factor
);
2309 if (result
!= TCL_OK
) return result
;
2311 Tcl_SetResult(interp
, "Negative/Zero zoom factors not allowed.",
2315 if (factor
< 1.0) factor
= 1.0 / factor
;
2317 if ((float)factor
== areawin
->zoomfactor
) break;
2318 Wprintf("Zoom factor changed from %2.1f to %2.1f",
2319 areawin
->zoomfactor
, (float)factor
);
2320 areawin
->zoomfactor
= (float) factor
;
2325 save
= areawin
->zoomfactor
;
2328 areawin
->zoomfactor
= (float)(1.0 / factor
);
2329 zoomout(wpoint
.x
, wpoint
.y
);
2332 areawin
->zoomfactor
= (float)factor
;
2333 zoomin(wpoint
.x
, wpoint
.y
);
2335 refresh(NULL
, NULL
, NULL
);
2336 areawin
->zoomfactor
= save
;
2338 return XcTagCallback(interp
, objc
, objv
);
2341 /*----------------------------------------------------------------------*/
2342 /* Get a color, either by name or by integer index. */
2343 /* If "append" is TRUE, then if the color is not in the existing list */
2344 /* of colors, it will be added to the list. */
2345 /*----------------------------------------------------------------------*/
2347 int GetColorFromObj(Tcl_Interp
*interp
, Tcl_Obj
*obj
, int *cindex
, Boolean append
)
2352 if (cindex
== NULL
) return TCL_ERROR
;
2354 cname
= Tcl_GetString(obj
);
2355 if (!strcmp(cname
, "inherit")) {
2356 *cindex
= DEFAULTCOLOR
;
2359 result
= Tcl_GetIntFromObj(interp
, obj
, cindex
);
2360 if (result
!= TCL_OK
) {
2361 Tcl_ResetResult(interp
);
2362 *cindex
= query_named_color(cname
);
2363 if (*cindex
== BADCOLOR
) {
2364 *cindex
= ERRORCOLOR
;
2365 Tcl_SetResult(interp
, "Unknown color name ", NULL
);
2366 Tcl_AppendElement(interp
, cname
);
2369 else if (*cindex
== ERRORCOLOR
) {
2371 *cindex
= addnewcolorentry(xc_alloccolor(cname
));
2373 Tcl_SetResult(interp
, "Color ", NULL
);
2374 Tcl_AppendElement(interp
, cname
);
2375 Tcl_AppendElement(interp
, "is not in the color table.");
2382 if ((*cindex
>= number_colors
) || (*cindex
< DEFAULTCOLOR
)) {
2383 Tcl_SetResult(interp
, "Color index out of range", NULL
);
2390 /*----------------------------------------------------------------------*/
2392 int xctcl_color(ClientData clientData
, Tcl_Interp
*interp
,
2393 int objc
, Tcl_Obj
*CONST objv
[])
2395 int result
, nidx
, cindex
, ccol
, idx
, i
;
2396 char *colorname
, *option
;
2398 static char *subCmds
[] = {"set", "index", "value", "get", "add",
2400 enum SubIdx
{ SetIdx
, IndexIdx
, ValueIdx
, GetIdx
, AddIdx
, OverrideIdx
};
2403 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2404 if (result
!= TCL_OK
) return result
;
2406 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
2407 (CONST84
char **)subCmds
, "option", 0,
2413 if ((objc
- nidx
) == 2) {
2414 result
= GetColorFromObj(interp
, objv
[nidx
+ 1], &cindex
, TRUE
);
2415 if (result
!= TCL_OK
) return result
;
2416 setcolor((Tk_Window
)clientData
, cindex
);
2417 /* Tag callback performed by setcolormarks() via setcolor() */
2421 Tcl_WrongNumArgs(interp
, 1, objv
, "set <color> | inherit");
2427 /* Return the index of the color. For use with parameterized color */
2428 if ((objc
- nidx
) == 2) {
2429 result
= GetColorFromObj(interp
, objv
[nidx
+ 1], &cindex
, TRUE
);
2430 if (result
!= TCL_OK
) return result
;
2431 Tcl_SetObjResult(interp
, Tcl_NewIntObj(cindex
));
2435 Tcl_WrongNumArgs(interp
, 1, objv
, "index <color> | inherit");
2441 /* Return the value of the color as an {R G B} list */
2442 if ((objc
- nidx
) == 2) {
2443 result
= GetColorFromObj(interp
, objv
[nidx
+ 1], &cindex
, TRUE
);
2444 if (result
!= TCL_OK
) return result
;
2445 else if (cindex
< 0 || cindex
>= number_colors
) {
2446 Tcl_SetResult(interp
, "Color index out of range", NULL
);
2449 Tcl_SetObjResult(interp
, TclIndexToRGB(cindex
));
2453 Tcl_WrongNumArgs(interp
, 1, objv
, "value <color>");
2459 /* Check for "-all" switch */
2460 if ((objc
- nidx
) == 2) {
2461 option
= Tcl_GetString(objv
[nidx
+ 1]);
2462 if (!strncmp(option
, "-all", 4)) {
2463 for (i
= NUMBER_OF_COLORS
; i
< number_colors
; i
++) {
2465 sprintf(colorstr
, "#%04x%04x%04x",
2466 colorlist
[i
].color
.red
,
2467 colorlist
[i
].color
.green
,
2468 colorlist
[i
].color
.blue
);
2469 Tcl_AppendElement(interp
, colorstr
);
2473 Tcl_WrongNumArgs(interp
, 1, objv
, "get [-all]");
2479 if (areawin
->selects
> 0) { /* operation on element */
2480 genericptr genobj
= SELTOGENERIC(areawin
->selectlist
);
2481 ccol
= (int)genobj
->color
;
2483 else /* global setting */
2484 ccol
= areawin
->color
;
2486 /* Find and return the index of the color */
2487 if (ccol
== DEFAULTCOLOR
)
2488 Tcl_SetObjResult(interp
, Tcl_NewStringObj("inherit", 7));
2490 for (i
= NUMBER_OF_COLORS
; i
< number_colors
; i
++)
2491 if (colorlist
[i
].color
.pixel
== ccol
)
2493 Tcl_SetObjResult(interp
, Tcl_NewIntObj(i
));
2498 if ((objc
- nidx
) == 2) {
2499 colorname
= Tcl_GetString(objv
[nidx
+ 1]);
2500 if (strlen(colorname
) == 0) return TCL_ERROR
;
2501 cindex
= addnewcolorentry(xc_alloccolor(colorname
));
2502 Tcl_SetObjResult(interp
, Tcl_NewIntObj(cindex
));
2505 Tcl_WrongNumArgs(interp
, 1, objv
, "add <color_name>");
2511 flags
|= COLOROVERRIDE
;
2512 return TCL_OK
; /* no tag callback */
2515 return XcTagCallback(interp
, objc
, objv
);
2518 /*----------------------------------------------------------------------*/
2520 int xctcl_delete(ClientData clientData
, Tcl_Interp
*interp
,
2521 int objc
, Tcl_Obj
*CONST objv
[])
2523 int result
= ParseElementArguments(interp
, objc
, objv
, NULL
, ALL_TYPES
);
2525 if (result
!= TCL_OK
) return result
;
2527 /* delete element (call library delete if in catalog) */
2528 if (areawin
->selects
> 0) {
2529 if (eventmode
== CATALOG_MODE
)
2532 deletebutton(0, 0); /* Note: arguments are not used */
2535 return XcTagCallback(interp
, objc
, objv
);
2538 /*----------------------------------------------------------------------*/
2539 /* Note that when using "undo series", it is the responsibility of the */
2540 /* caller to make sure that every "start" is matched by an "end". */
2541 /*----------------------------------------------------------------------*/
2543 int xctcl_undo(ClientData clientData
, Tcl_Interp
*interp
,
2544 int objc
, Tcl_Obj
*CONST objv
[])
2546 if ((objc
== 3) && !strcmp(Tcl_GetString(objv
[1]), "series")) {
2548 if (!strcmp(Tcl_GetString(objv
[2]), "start")) {
2549 if (undo_collect
< 255) undo_collect
++;
2551 else if (!strcmp(Tcl_GetString(objv
[2]), "end")) {
2552 if (undo_collect
> 0) undo_collect
--;
2553 undo_finish_series();
2555 else if (!strcmp(Tcl_GetString(objv
[2]), "cancel")) {
2556 undo_collect
= (u_char
)0;
2557 undo_finish_series();
2560 Tcl_SetResult(interp
, "Usage: undo series <start|end|cancel>", NULL
);
2564 else if (objc
== 1) {
2568 Tcl_WrongNumArgs(interp
, 1, objv
, "[series <start|end>");
2571 return XcTagCallback(interp
, objc
, objv
);
2574 /*----------------------------------------------------------------------*/
2576 int xctcl_redo(ClientData clientData
, Tcl_Interp
*interp
,
2577 int objc
, Tcl_Obj
*CONST objv
[])
2580 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
2584 return XcTagCallback(interp
, objc
, objv
);
2587 /*----------------------------------------------------------------------*/
2589 int xctcl_move(ClientData clientData
, Tcl_Interp
*interp
,
2590 int objc
, Tcl_Obj
*CONST objv
[])
2594 int result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2596 if (result
!= TCL_OK
) return result
;
2598 if (areawin
->selects
== 0) {
2599 Tcl_SetResult(interp
, "Error in move setup: nothing selected.", NULL
);
2603 if ((objc
- nidx
) == 0) {
2604 eventmode
= MOVE_MODE
;
2605 u2u_snap(&areawin
->save
);
2606 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
,
2607 (Tk_EventProc
*)xctk_drag
, NULL
);
2609 else if ((objc
- nidx
) >= 1) {
2610 if ((objc
- nidx
) == 2) {
2611 if (!strcmp(Tcl_GetString(objv
[nidx
]), "relative")) {
2612 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 1],
2613 &position
)) != TCL_OK
) {
2614 Tcl_SetResult(interp
, "Position must be {x y} list", NULL
);
2619 Tcl_WrongNumArgs(interp
, 1, objv
, "relative {x y}");
2624 if ((result
= GetPositionFromList(interp
, objv
[nidx
],
2625 &position
)) != TCL_OK
) {
2626 Tcl_SetResult(interp
, "Position must be {x y} list", NULL
);
2629 position
.x
-= areawin
->save
.x
;
2630 position
.y
-= areawin
->save
.y
;
2632 placeselects(position
.x
, position
.y
, NULL
);
2635 Tcl_WrongNumArgs(interp
, 1, objv
, "[relative] {x y}");
2638 return XcTagCallback(interp
, objc
, objv
);
2641 /*----------------------------------------------------------------------*/
2643 int xctcl_copy(ClientData clientData
, Tcl_Interp
*interp
,
2644 int objc
, Tcl_Obj
*CONST objv
[])
2649 int result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2651 if (result
!= TCL_OK
) return result
;
2653 if ((objc
- nidx
) == 0) {
2654 if (areawin
->selects
> 0) {
2659 else if ((objc
- nidx
) >= 1) {
2660 if (areawin
->selects
== 0) {
2661 Tcl_SetResult(interp
, "Error in copy: nothing selected.", NULL
);
2664 if ((objc
- nidx
) == 2) {
2665 if (!strcmp(Tcl_GetString(objv
[nidx
]), "relative")) {
2666 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 1],
2667 &position
)) != TCL_OK
) {
2668 Tcl_SetResult(interp
, "Position must be {x y} list", NULL
);
2673 Tcl_WrongNumArgs(interp
, 1, objv
, "relative {x y}");
2678 if ((result
= GetPositionFromList(interp
, objv
[nidx
],
2679 &position
)) != TCL_OK
) {
2680 Tcl_SetResult(interp
, "Position must be {x y} list", NULL
);
2683 position
.x
-= areawin
->save
.x
;
2684 position
.y
-= areawin
->save
.y
;
2688 listPtr
= SelectToTclList(interp
, areawin
->selectlist
, areawin
->selects
);
2689 Tcl_SetObjResult(interp
, listPtr
);
2691 placeselects(position
.x
, position
.y
, NULL
);
2694 Tcl_WrongNumArgs(interp
, 1, objv
, "[relative] {x y}");
2697 return XcTagCallback(interp
, objc
, objv
);
2700 /*----------------------------------------------------------------------*/
2702 int xctcl_flip(ClientData clientData
, Tcl_Interp
*interp
,
2703 int objc
, Tcl_Obj
*CONST objv
[])
2707 int result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2710 if (result
!= TCL_OK
) return result
;
2712 if ((objc
- nidx
) == 2) {
2713 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 1],
2714 &position
)) != TCL_OK
)
2717 else if ((objc
- nidx
) == 1) {
2718 if (areawin
->selects
> 1)
2719 position
= UGetCursorPos();
2722 Tcl_WrongNumArgs(interp
, 1, objv
, "horizontal|vertical [<center>]");
2726 teststr
= Tcl_GetString(objv
[nidx
]);
2728 switch(teststr
[0]) {
2730 elementflip(&position
);
2733 elementvflip(&position
);
2736 Tcl_SetResult(interp
, "Error: options are horizontal or vertical", NULL
);
2739 return XcTagCallback(interp
, objc
, objv
);
2742 /*----------------------------------------------------------------------*/
2744 int xctcl_rotate(ClientData clientData
, Tcl_Interp
*interp
,
2745 int objc
, Tcl_Obj
*CONST objv
[])
2748 int result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2751 if (result
!= TCL_OK
) return result
;
2753 /* No options --- return the rotation value(s) */
2754 if ((objc
- nidx
) == 0) {
2755 int i
, numfound
= 0;
2756 Tcl_Obj
*listPtr
, *objPtr
;
2757 for (i
= 0; i
< areawin
->selects
; i
++) {
2759 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
2760 objinstptr pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
2761 objPtr
= Tcl_NewDoubleObj((double)(pinst
->rotation
));
2763 else if (SELECTTYPE(areawin
->selectlist
+ i
) == LABEL
) {
2764 labelptr plab
= SELTOLABEL(areawin
->selectlist
+ i
);
2765 objPtr
= Tcl_NewDoubleObj((double)(plab
->rotation
));
2767 else if (SELECTTYPE(areawin
->selectlist
+ i
) == GRAPHIC
) {
2768 graphicptr gp
= SELTOGRAPHIC(areawin
->selectlist
+ i
);
2769 objPtr
= Tcl_NewDoubleObj((double)(gp
->rotation
));
2771 if (objPtr
!= NULL
) {
2773 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
2774 if ((++numfound
) == 1)
2780 Tcl_SetResult(interp
, "Error: no object instances, graphic "
2781 "images, or labels selected", NULL
);
2785 Tcl_SetObjResult(interp
, objPtr
);
2788 Tcl_SetObjResult(interp
, listPtr
);
2791 return XcTagCallback(interp
, objc
, objv
);
2794 result
= Tcl_GetIntFromObj(interp
, objv
[nidx
], &rval
);
2795 if (result
!= TCL_OK
) return result
;
2797 if ((objc
- nidx
) == 2) {
2798 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 1],
2799 &position
)) != TCL_OK
)
2802 elementrotate(rval
, &position
);
2803 return XcTagCallback(interp
, objc
, objv
);
2806 else if ((objc
- nidx
) == 1) {
2807 position
= UGetCursorPos();
2808 elementrotate(rval
, &position
);
2809 return XcTagCallback(interp
, objc
, objv
);
2812 Tcl_WrongNumArgs(interp
, 1, objv
, "<angle> [<center>]");
2816 /*----------------------------------------------------------------------*/
2818 int xctcl_edit(ClientData clientData
, Tcl_Interp
*interp
,
2819 int objc
, Tcl_Obj
*CONST objv
[])
2821 int result
= ParseElementArguments(interp
, objc
, objv
, NULL
, ALL_TYPES
);
2823 if (result
!= TCL_OK
) return result
;
2825 /* To be done---edit element */
2827 return XcTagCallback(interp
, objc
, objv
);
2830 /*----------------------------------------------------------------------*/
2831 /* Support procedure for xctcl_param: Given a pointer to a parameter, */
2832 /* return the value of the parameter as a pointer to a Tcl object. */
2833 /* This takes care of the fact that the parameter value can be a */
2834 /* string, integer, or float, depending on the parameter type. */
2836 /* If "verbatim" is true, then expression parameters return the string */
2837 /* representation of the expression, not the result, and indirect */
2838 /* parameters return the parameter name referenced, not the value. */
2840 /* refinst, if non-NULL, is the instance containing ops, used when */
2841 /* "verbatim" is true and the parameter is indirectly referenced. */
2842 /*----------------------------------------------------------------------*/
2844 Tcl_Obj
*GetParameterValue(objectptr refobj
, oparamptr ops
, Boolean verbatim
,
2850 if (verbatim
&& (refinst
!= NULL
) &&
2851 ((refkey
= find_indirect_param(refinst
, ops
->key
)) != NULL
)) {
2852 robj
= Tcl_NewStringObj(refkey
, strlen(refkey
));
2856 switch (ops
->type
) {
2858 robj
= TclGetStringParts(ops
->parameter
.string
);
2862 robj
= Tcl_NewStringObj(ops
->parameter
.expr
,
2863 strlen(ops
->parameter
.expr
));
2865 robj
= evaluate_raw(refobj
, ops
, refinst
, NULL
);
2868 robj
= Tcl_NewIntObj(ops
->parameter
.ivalue
);
2871 robj
= Tcl_NewDoubleObj((double)ops
->parameter
.fvalue
);
2877 /*----------------------------------------------------------------------*/
2878 /* Given a pointer to a parameter and a Tcl object, set the parameter */
2879 /* to the value of the object. Return the standard Tcl return type */
2881 /* If searchinst is non-NULL, then it refers to the level above in the */
2882 /* hierarchy, and we are supposed to set an indirect reference. */
2883 /*----------------------------------------------------------------------*/
2885 int SetParameterValue(Tcl_Interp
*interp
, oparamptr ops
, Tcl_Obj
*objv
)
2889 stringpart
*strptr
= NULL
, *newpart
;
2892 Tcl_SetResult(interp
, "Cannot set parameter value", NULL
);
2895 switch (ops
->type
) {
2897 result
= Tcl_GetDoubleFromObj(interp
, objv
, &dvalue
);
2898 if (result
!= TCL_OK
) return result
;
2899 ops
->parameter
.fvalue
= (float)dvalue
;
2902 result
= Tcl_GetIntFromObj(interp
, objv
, &ivalue
);
2903 if (result
!= TCL_OK
) return result
;
2904 ops
->parameter
.ivalue
= ivalue
;
2907 ops
->parameter
.expr
= strdup(Tcl_GetString(objv
));
2910 result
= GetXCStringFromList(interp
, objv
, &strptr
);
2911 if (result
!= TCL_OK
) return result
;
2912 freelabel(ops
->parameter
.string
);
2913 /* Must add a "param end" */
2914 newpart
= makesegment(&strptr
, NULL
);
2915 newpart
->nextpart
= NULL
;
2916 newpart
->type
= PARAM_END
;
2917 newpart
->data
.string
= (u_char
*)NULL
;
2918 ops
->parameter
.string
= strptr
;
2924 /*----------------------------------------------------------------------*/
2925 /* Translate the numeric parameter types to a string that the Tcl */
2926 /* "parameter" routine will recognize from the command line. */
2927 /*----------------------------------------------------------------------*/
2930 translateparamtype(int type
)
2932 const char *param_types
[] = {"numeric", "substring", "x position",
2933 "y position", "style", "anchoring", "start angle", "end angle",
2934 "radius", "minor axis", "rotation", "scale", "linewidth", "color",
2935 "expression", "position", NULL
};
2937 if (type
< 0) return NULL
;
2938 return (char *)param_types
[type
];
2941 /*----------------------------------------------------------------------*/
2942 /* Parameter command: */
2944 /* Normally, a selected element will produce a list of backwards- */
2945 /* referenced parameters (eparam). However, it is useful to pick up */
2946 /* the forwards-referenced parameters of an object instance, so that */
2947 /* parameters can be modified from the level above (e.g., to change */
2948 /* circuit component values, component indices, etc.). The optional */
2949 /* final argument "-forward" can be used to access this mode. */
2950 /*----------------------------------------------------------------------*/
2952 int xctcl_param(ClientData clientData
, Tcl_Interp
*interp
,
2953 int objc
, Tcl_Obj
*CONST objv
[])
2955 int i
, j
, value
, idx
, nidx
= 4;
2956 int result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
2957 oparamptr ops
, instops
;
2960 genericptr thiselem
= NULL
;
2961 Tcl_Obj
*plist
, *kpair
, *exprres
;
2965 Boolean verbatim
= FALSE
, indirection
= FALSE
, forwarding
= FALSE
;
2967 static char *subCmds
[] = {"allowed", "get", "type", "default", "set", "make",
2968 "replace", "forget", "delete", NULL
};
2970 AllowedIdx
, GetIdx
, TypeIdx
, DefaultIdx
, SetIdx
, MakeIdx
, ReplaceIdx
,
2971 ForgetIdx
, DeleteIdx
2974 /* The order of these type names must match the enumeration in xcircuit.h */
2976 static char *param_types
[] = {"numeric", "substring", "x position",
2977 "y position", "style", "anchoring", "start angle", "end angle",
2978 "radius", "minor axis", "rotation", "scale", "linewidth", "color",
2979 "expression", "position", NULL
}; /* (jdk) */
2981 /* The first object instance in the select list becomes "thiselem", */
2982 /* if such exists. Otherwise, it remains null. */
2984 for (j
= 0; j
< areawin
->selects
; j
++) {
2985 if (SELECTTYPE(areawin
->selectlist
+ j
) == OBJINST
) {
2986 thiselem
= SELTOGENERIC(areawin
->selectlist
+ j
);
2991 if (objc
- nidx
< 1)
2994 dash_opt
= Tcl_GetString(objv
[nidx
]);
2995 if (*dash_opt
== '-')
2998 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
2999 (CONST84
char **)subCmds
, "option", 0, &idx
)) != TCL_OK
)
3004 /* Use the topobject by default */
3005 refinst
= areawin
->topinstance
;
3008 /* command-line switches */
3010 dash_opt
= Tcl_GetString(objv
[objc
- 1]);
3011 while (*dash_opt
== '-') {
3013 /* If an object instance is selected, we list backwards-referenced */
3014 /* (eparam) parameters, unless the command ends in "-forward". */
3016 if (!strncmp(dash_opt
+ 1, "forw", 4)) {
3025 if (thiselem
&& IS_OBJINST(thiselem
)) {
3026 refinst
= (objinstptr
)thiselem
;
3027 refobj
= refinst
->thisobject
;
3034 else if (!strncmp(dash_opt
+ 1, "verb", 4)) {
3037 else if (!strncmp(dash_opt
+ 1, "ind", 3)) {
3043 Tcl_SetResult(interp
, "Must have a valid option", NULL
);
3046 dash_opt
= Tcl_GetString(objv
[objc
- 1]);
3052 for (i
= 0; i
< (sizeof(param_types
) / sizeof(char *)); i
++)
3053 if ((thiselem
== NULL
) || (param_select
[i
] & thiselem
->type
))
3054 Tcl_AppendElement(interp
, param_types
[i
]);
3061 if (objc
== nidx
+ 2) {
3063 /* Check argument against all parameter keys */
3064 ops
= find_param(refinst
, Tcl_GetString(objv
[nidx
+ 1]));
3066 /* Otherwise, the argument must be a parameter type. */
3067 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
3068 (CONST84
char **)param_types
, "parameter type",
3069 0, &value
)) != TCL_OK
) {
3070 Tcl_SetResult(interp
, "Must have a valid key or parameter type",
3076 /* Return the value of the indicated parameter */
3078 plist
= Tcl_NewListObj(0, NULL
);
3079 if (thiselem
== NULL
) {
3082 Tcl_ListObjAppendElement(interp
, plist
,
3083 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3085 Tcl_ListObjAppendElement(interp
, plist
,
3086 Tcl_NewStringObj(param_types
[ops
->which
],
3087 strlen(param_types
[ops
->which
])));
3090 for (ops
= refobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
3091 instops
= find_param(refinst
, ops
->key
);
3092 if (instops
->which
== value
) {
3093 kpair
= Tcl_NewListObj(0, NULL
);
3094 Tcl_ListObjAppendElement(interp
, kpair
,
3095 Tcl_NewStringObj(instops
->key
, strlen(instops
->key
)));
3097 Tcl_ListObjAppendElement(interp
, kpair
,
3098 GetParameterValue(refobj
, instops
, verbatim
,
3101 Tcl_ListObjAppendElement(interp
, kpair
,
3102 Tcl_NewStringObj(param_types
[instops
->which
],
3103 strlen(param_types
[instops
->which
])));
3104 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3110 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
3111 instops
= find_param(refinst
, epp
->key
);
3112 if (instops
->which
== value
) {
3114 Tcl_ListObjAppendElement(interp
, plist
,
3115 GetParameterValue(refobj
, instops
, verbatim
, refinst
));
3117 Tcl_ListObjAppendElement(interp
, plist
,
3118 Tcl_NewStringObj(param_types
[instops
->which
],
3119 strlen(param_types
[instops
->which
])));
3123 /* Search label for parameterized substrings. These are */
3124 /* backwards-referenced parameters, although they are */
3125 /* not stored in the eparam record of the label. */
3127 if ((value
== P_SUBSTRING
) && IS_LABEL(thiselem
)) {
3129 labelptr clab
= (labelptr
)thiselem
;
3130 for (cstr
= clab
->string
; cstr
!= NULL
; cstr
= cstr
->nextpart
) {
3131 if (cstr
->type
== PARAM_START
) {
3132 kpair
= Tcl_NewListObj(0, NULL
);
3133 ops
= find_param(refinst
, cstr
->data
.string
);
3134 Tcl_ListObjAppendElement(interp
, kpair
,
3135 Tcl_NewStringObj(ops
->key
, strlen(ops
->key
)));
3137 Tcl_ListObjAppendElement(interp
, kpair
,
3138 GetParameterValue(refobj
, ops
, verbatim
,
3141 Tcl_ListObjAppendElement(interp
, kpair
,
3142 Tcl_NewStringObj(param_types
[ops
->which
],
3143 strlen(param_types
[ops
->which
])));
3144 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3149 Tcl_SetObjResult(interp
, plist
);
3152 plist
= Tcl_NewListObj(0, NULL
);
3153 if (thiselem
== NULL
) {
3154 for (ops
= refobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
3155 kpair
= Tcl_NewListObj(0, NULL
);
3156 Tcl_ListObjAppendElement(interp
, kpair
,
3157 Tcl_NewStringObj(ops
->key
, strlen(ops
->key
)));
3158 if (idx
== GetIdx
) {
3159 instops
= find_param(refinst
, ops
->key
);
3160 Tcl_ListObjAppendElement(interp
, kpair
,
3161 GetParameterValue(refobj
, instops
, verbatim
, refinst
));
3164 Tcl_ListObjAppendElement(interp
, kpair
,
3165 Tcl_NewStringObj(param_types
[ops
->which
],
3166 strlen(param_types
[ops
->which
])));
3167 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3171 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
3172 kpair
= Tcl_NewListObj(0, NULL
);
3173 ops
= find_param(refinst
, epp
->key
);
3174 Tcl_ListObjAppendElement(interp
, kpair
,
3175 Tcl_NewStringObj(ops
->key
, strlen(ops
->key
)));
3177 Tcl_ListObjAppendElement(interp
, kpair
,
3178 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3180 Tcl_ListObjAppendElement(interp
, kpair
,
3181 Tcl_NewStringObj(param_types
[ops
->which
],
3182 strlen(param_types
[ops
->which
])));
3183 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3186 /* Search label for parameterized substrings. These are */
3187 /* backwards-referenced parameters, although they are */
3188 /* not stored in the eparam record of the label. */
3190 if (IS_LABEL(thiselem
)) {
3192 labelptr clab
= (labelptr
)thiselem
;
3193 for (cstr
= clab
->string
; cstr
!= NULL
; cstr
= cstr
->nextpart
) {
3194 if (cstr
->type
== PARAM_START
) {
3195 kpair
= Tcl_NewListObj(0, NULL
);
3196 ops
= find_param(refinst
, cstr
->data
.string
);
3197 Tcl_ListObjAppendElement(interp
, kpair
,
3198 Tcl_NewStringObj(ops
->key
, strlen(ops
->key
)));
3200 Tcl_ListObjAppendElement(interp
, kpair
,
3201 GetParameterValue(refobj
, ops
, verbatim
,
3204 Tcl_ListObjAppendElement(interp
, kpair
,
3205 Tcl_NewStringObj(param_types
[ops
->which
],
3206 strlen(param_types
[ops
->which
])));
3207 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3212 Tcl_SetObjResult(interp
, plist
);
3217 if (objc
== nidx
+ 2) {
3218 /* Check against keys */
3219 ops
= match_param(refobj
, Tcl_GetString(objv
[nidx
+ 1]));
3221 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
3222 (CONST84
char **)param_types
, "parameter type",
3223 0, &value
)) != TCL_OK
) {
3224 Tcl_SetResult(interp
, "Must have a valid key or parameter type",
3229 else { /* get default value(s) */
3230 plist
= Tcl_NewListObj(0, NULL
);
3231 if (thiselem
== NULL
) {
3233 Tcl_ListObjAppendElement(interp
, plist
,
3234 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3237 for (ops
= refobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
3238 if (ops
->which
== value
) {
3239 Tcl_ListObjAppendElement(interp
, plist
,
3240 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3246 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
3247 ops
= match_param(refobj
, epp
->key
);
3248 if (ops
->which
== value
) {
3249 Tcl_ListObjAppendElement(interp
, plist
,
3250 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3254 /* search label for parameterized substrings */
3256 if ((value
== P_SUBSTRING
) && IS_LABEL(thiselem
)) {
3258 labelptr clab
= (labelptr
)thiselem
;
3259 for (cstr
= clab
->string
; cstr
!= NULL
; cstr
= cstr
->nextpart
) {
3260 if (cstr
->type
== PARAM_START
) {
3261 ops
= match_param(refobj
, cstr
->data
.string
);
3263 Tcl_ListObjAppendElement(interp
, plist
,
3264 GetParameterValue(refobj
, ops
, verbatim
,
3270 Tcl_SetObjResult(interp
, plist
);
3273 else if (objc
== nidx
+ 1) { /* list all parameters and their defaults */
3274 plist
= Tcl_NewListObj(0, NULL
);
3275 for (ops
= refobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
3276 kpair
= Tcl_NewListObj(0, NULL
);
3277 Tcl_ListObjAppendElement(interp
, kpair
,
3278 Tcl_NewStringObj(ops
->key
, strlen(ops
->key
)));
3279 Tcl_ListObjAppendElement(interp
, kpair
,
3280 GetParameterValue(refobj
, ops
, verbatim
, refinst
));
3281 Tcl_ListObjAppendElement(interp
, plist
, kpair
);
3283 Tcl_SetObjResult(interp
, plist
);
3286 Tcl_WrongNumArgs(interp
, 1, objv
, "default <type|key> [<value>]");
3291 case SetIdx
: /* currently, instances only. . .*/
3292 if (objc
== nidx
+ 3) { /* possibly to be expanded. . . */
3293 char *key
= Tcl_GetString(objv
[nidx
+ 1]);
3294 objinstptr searchinst
= NULL
;
3296 /* Allow option "set" to act on more than one selection */
3298 if (areawin
->selects
== 0) goto keycheck
;
3300 while (j
< areawin
->selects
) {
3302 refinst
= SELTOOBJINST(areawin
->selectlist
+ j
);
3303 refobj
= refinst
->thisobject
;
3305 /* Check against keys */
3307 instops
= match_instance_param(refinst
, key
);
3308 ops
= match_param(refobj
, key
);
3309 if (instops
== NULL
) {
3311 if (!forwarding
|| (areawin
->selects
<= 1)) {
3312 Tcl_SetResult(interp
, "Invalid key ", NULL
);
3313 Tcl_AppendElement(interp
, key
);
3319 copyparams(refinst
, refinst
);
3320 instops
= match_instance_param(refinst
, key
);
3322 else if (ops
->type
== XC_EXPR
) {
3323 /* If the expression is currently the default expression */
3324 /* but the instance value is holding the last evaluated */
3325 /* result, then we have to delete and regenerate the */
3326 /* existing instance parameter ("verbatim" assumed even */
3327 /* if not declared because you can't change the result */
3328 /* of the expression). */
3330 free_instance_param(refinst
, instops
);
3331 instops
= copyparameter(ops
);
3332 instops
->next
= refinst
->params
;
3333 refinst
->params
= instops
;
3336 char *refkey
= Tcl_GetString(objv
[nidx
+ 2]);
3338 if (refinst
!= areawin
->topinstance
)
3339 searchinst
= areawin
->topinstance
;
3340 else if (areawin
->stack
) {
3341 searchinst
= areawin
->stack
->thisinst
;
3344 resolveparams(refinst
);
3345 Tcl_SetResult(interp
, "On top-level page: "
3346 "no indirection possible!", NULL
);
3349 if (match_param(searchinst
->thisobject
, refkey
) == NULL
) {
3350 resolveparams(refinst
);
3351 Tcl_SetResult(interp
, "Invalid indirect reference key", NULL
);
3354 /* Create an eparam record in the instance */
3355 epp
= make_new_eparam(refkey
);
3356 epp
->flags
|= P_INDIRECT
;
3357 epp
->pdata
.refkey
= strdup(key
);
3358 epp
->next
= refinst
->passed
;
3359 refinst
->passed
= epp
;
3362 SetParameterValue(interp
, instops
, objv
[nidx
+ 2]);
3363 resolveparams(refinst
);
3365 /* Check if there are more selections to modify */
3368 if (!forwarding
) break;
3369 while (++j
!= areawin
->selects
)
3370 if (SELECTTYPE(areawin
->selectlist
+ j
) == OBJINST
)
3374 /* Redraw everything (this could be finessed. . .) */
3375 areawin
->redraw_needed
= True
;
3376 drawarea(areawin
->area
, (caddr_t
)NULL
, (caddr_t
)NULL
);
3379 Tcl_WrongNumArgs(interp
, 1, objv
, "set <key>");
3385 if (objc
>= (nidx
+ 2) && objc
<= (nidx
+ 4)) {
3386 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
3387 (CONST84
char **)param_types
, "parameter type",
3388 0, &value
)) != TCL_OK
)
3391 if ((value
== P_SUBSTRING
) && (objc
== (nidx
+ 4))) {
3392 stringpart
*strptr
= NULL
, *newpart
;
3393 result
= GetXCStringFromList(interp
, objv
[nidx
+ 3], &strptr
);
3394 if (result
!= TCL_ERROR
) {
3395 if (makestringparam(refobj
, Tcl_GetString(objv
[nidx
+ 2]),
3398 /* Add the "parameter end" marker to this string */
3399 newpart
= makesegment(&strptr
, NULL
);
3400 newpart
->nextpart
= NULL
;
3401 newpart
->type
= PARAM_END
;
3402 newpart
->data
.string
= (u_char
*)NULL
;
3405 else if (value
== P_SUBSTRING
) {
3406 /* Get parameter value from selection */
3407 startparam((Tk_Window
)clientData
, (pointertype
)value
,
3408 (caddr_t
)Tcl_GetString(objv
[nidx
+ 2]));
3410 else if ((value
== P_EXPRESSION
) && (objc
== (nidx
+ 4))) {
3411 temps
.type
= XC_EXPR
;
3412 temps
.parameter
.expr
= Tcl_GetString(objv
[nidx
+ 3]);
3413 exprres
= evaluate_raw(refobj
, &temps
, refinst
, &result
);
3415 if (result
!= TCL_OK
) {
3416 Tcl_SetResult(xcinterp
, "Bad result from expression!", NULL
);
3417 /* Not fatal to have a bad expression result. . . */
3418 /* return result; */
3420 if (makeexprparam(refobj
, Tcl_GetString(objv
[nidx
+ 2]),
3421 temps
.parameter
.expr
, P_EXPRESSION
) == NULL
)
3425 /* All other types are parsed as either a numeric value */
3426 /* (integer or float), or an expression that evaluates */
3427 /* to a numeric value. */
3429 else if (((value
== P_NUMERIC
) && (objc
== (nidx
+ 4))) ||
3430 objc
== (nidx
+ 3)) {
3433 i
= (value
== P_NUMERIC
) ? 3 : 2;
3435 result
= Tcl_GetDoubleFromObj(interp
, objv
[nidx
+ i
], &tmpdbl
);
3436 if (result
!= TCL_ERROR
) {
3437 if (makefloatparam(refobj
, Tcl_GetString(objv
[nidx
+ i
- 1]),
3438 (float)tmpdbl
) == -1)
3444 /* This may be an expression. Do a quick check to */
3445 /* see if the string can be evaluated as a Tcl */
3446 /* expression. If it returns a valid numeric result, */
3447 /* then accept the expression. */
3449 Tcl_ResetResult(interp
);
3450 temps
.type
= XC_EXPR
;
3451 temps
.parameter
.expr
= Tcl_GetString(objv
[nidx
+ i
]);
3453 exprres
= evaluate_raw(refobj
, &temps
, refinst
, &result
);
3454 if (result
!= TCL_OK
) {
3455 Tcl_SetResult(xcinterp
, "Bad result from expression!", NULL
);
3458 result
= Tcl_GetDoubleFromObj(interp
, exprres
, &tmpdbl
);
3459 if (result
!= TCL_ERROR
) {
3460 if ((newkey
= makeexprparam(refobj
, (value
== P_NUMERIC
) ?
3461 Tcl_GetString(objv
[nidx
+ i
- 1]) : NULL
,
3462 temps
.parameter
.expr
, value
)) == NULL
)
3464 else if (value
!= P_NUMERIC
) {
3465 /* Link the expression parameter to the element */
3466 /* To-do: Handle cycles (one extra argument) */
3468 for (i
= 0; i
< areawin
->selects
; i
++) {
3469 pgen
= SELTOGENERIC(areawin
->selectlist
+ i
);
3470 makenumericalp(&pgen
, value
, newkey
, 0);
3475 Tcl_SetResult(xcinterp
, "Expression evaluates to "
3476 "non-numeric type!", NULL
);
3481 else if (((value
!= P_NUMERIC
) && (objc
== (nidx
+ 4))) ||
3482 objc
== (nidx
+ 3)) {
3485 if (value
== P_POSITION
|| value
== P_POSITION_X
||
3486 value
== P_POSITION_Y
) {
3487 if (objc
== nidx
+ 4) {
3488 result
= Tcl_GetIntFromObj(interp
, objv
[i
- 1], &cycle
);
3489 if (result
== TCL_ERROR
) {
3490 Tcl_ResetResult(interp
);
3491 startparam((Tk_Window
)clientData
, (pointertype
)value
,
3492 Tcl_GetString(objv
[i
]));
3495 parameterize(value
, NULL
, (short)cycle
);
3499 Tcl_WrongNumArgs(interp
, 1, objv
, "make position cycle <value>");
3504 if (objc
== nidx
+ 3)
3505 startparam((Tk_Window
)clientData
, (pointertype
)value
,
3506 Tcl_GetString(objv
[i
]));
3508 Tcl_WrongNumArgs(interp
, 1, objv
, "make <numeric_type> <value>");
3514 if ((value
== P_SUBSTRING
) || (value
== P_NUMERIC
) ||
3515 (value
== P_EXPRESSION
)) {
3516 Tcl_WrongNumArgs(interp
, 1, objv
,
3517 "make substring|numeric|expression <key>");
3521 startparam((Tk_Window
)clientData
, (pointertype
)value
, NULL
);
3525 Tcl_WrongNumArgs(interp
, 1, objv
, "make <type> [<key>]");
3531 /* Calls unparameterize---replaces text with the instance value, */
3532 /* or replaces a numeric parameter with the instance values by */
3533 /* unparameterizing the element. Don't use with parameter keys. */
3535 if (objc
== nidx
+ 2) {
3536 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
3537 (CONST84
char **)param_types
, "parameter type",
3538 0, &value
)) != TCL_OK
)
3540 unparameterize(value
);
3543 Tcl_WrongNumArgs(interp
, 1, objv
, "replace <type>");
3551 if (objc
== nidx
+ 2) {
3552 /* Check against keys */
3553 ops
= match_param(refobj
, Tcl_GetString(objv
[nidx
+ 1]));
3555 Tcl_SetResult(interp
, "Invalid parameter key", NULL
);
3559 free_object_param(refobj
, ops
);
3560 /* Redraw everything */
3561 drawarea(areawin
->area
, (caddr_t
)NULL
, (caddr_t
)NULL
);
3565 Tcl_WrongNumArgs(interp
, 1, objv
, "forget <key>");
3570 return XcTagCallback(interp
, objc
, objv
);
3573 /*----------------------------------------------------------------------*/
3575 int xctcl_select(ClientData clientData
, Tcl_Interp
*interp
,
3576 int objc
, Tcl_Obj
*CONST objv
[])
3580 int selected_prior
, selected_new
, nidx
, result
;
3585 /* Special case: "select" by itself returns the number of */
3586 /* selected objects. */
3587 Tcl_SetObjResult(interp
, Tcl_NewIntObj((int)areawin
->selects
));
3588 return XcTagCallback(interp
, objc
, objv
);
3592 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
3593 if (result
!= TCL_OK
) return result
;
3597 Tcl_WrongNumArgs(interp
, 1, objv
, "here | get | <element_handle>");
3602 argstr
= Tcl_GetString(objv
[1]);
3603 if (!strcmp(argstr
, "here")) {
3604 newpos
= UGetCursorPos();
3605 areawin
->save
= newpos
;
3606 selected_prior
= areawin
->selects
;
3607 newselect
= select_element(ALL_TYPES
);
3608 selected_new
= areawin
->selects
- selected_prior
;
3610 else if (!strcmp(argstr
, "get")) {
3611 newselect
= areawin
->selectlist
;
3612 selected_new
= areawin
->selects
;
3615 Tcl_WrongNumArgs(interp
, 1, objv
, "here | get | <object_handle>");
3619 listPtr
= SelectToTclList(interp
, newselect
, selected_new
);
3620 Tcl_SetObjResult(interp
, listPtr
);
3622 return XcTagCallback(interp
, objc
, objv
);
3625 /*----------------------------------------------------------------------*/
3627 int xctcl_deselect(ClientData clientData
, Tcl_Interp
*interp
,
3628 int objc
, Tcl_Obj
*CONST objv
[])
3630 int i
, j
, k
, result
, numobjs
;
3631 pointertype ehandle
;
3636 Tcl_WrongNumArgs(interp
, 1, objv
, "[element_handle]");
3639 else if (objc
== 3 || (objc
== 2 && !strcmp(Tcl_GetString(objv
[0]), "deselect"))) {
3641 argstr
= Tcl_GetString(objv
[1]);
3642 if (strcmp(argstr
, "selected")) {
3644 /* check for object handles (integer list) */
3646 result
= Tcl_ListObjLength(interp
, objv
[1], &numobjs
);
3647 if (result
!= TCL_OK
) return result
;
3649 for (j
= 0; j
< numobjs
; j
++) {
3650 result
= Tcl_ListObjIndex(interp
, objv
[1], j
, &lobj
);
3651 if (result
!= TCL_OK
) return result
;
3652 result
= Tcl_GetHandleFromObj(interp
, lobj
, (void *)&ehandle
);
3653 if (result
!= TCL_OK
) return result
;
3654 i
= GetPartNumber((genericptr
)ehandle
, topobject
, ALL_TYPES
);
3656 Tcl_SetResult(interp
, "No such element exists.", NULL
);
3659 for (i
= 0; i
< areawin
->selects
; i
++) {
3660 short *newselect
= areawin
->selectlist
+ i
;
3661 if ((genericptr
)ehandle
== SELTOGENERIC(newselect
)) {
3662 XTopSetForeground(SELTOCOLOR(newselect
));
3663 geneasydraw(*newselect
, DEFAULTCOLOR
, topobject
,
3664 areawin
->topinstance
);
3667 for (k
= i
; k
< areawin
->selects
; k
++)
3668 *(areawin
->selectlist
+ k
) = *(areawin
->selectlist
+ k
+ 1);
3669 if (areawin
->selects
== 0) {
3670 free(areawin
->selectlist
);
3671 freeselects(); /* specifically, free hierstack */
3681 startdesel((Tk_Window
)clientData
, NULL
, NULL
);
3683 return XcTagCallback(interp
, objc
, objv
);
3686 /*----------------------------------------------------------------------*/
3688 int xctcl_push(ClientData clientData
, Tcl_Interp
*interp
,
3689 int objc
, Tcl_Obj
*CONST objv
[])
3691 int result
= ParseElementArguments(interp
, objc
, objv
, NULL
, OBJINST
);
3693 if (result
!= TCL_OK
) return result
;
3697 return XcTagCallback(interp
, objc
, objv
);
3700 /*----------------------------------------------------------------------*/
3702 int xctcl_pop(ClientData clientData
, Tcl_Interp
*interp
,
3703 int objc
, Tcl_Obj
*CONST objv
[])
3706 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
3709 popobject((Tk_Window
)clientData
, 0, NULL
);
3711 return XcTagCallback(interp
, objc
, objv
);
3714 /*----------------------------------------------------------------------*/
3715 /* Object queries */
3716 /*----------------------------------------------------------------------*/
3718 int xctcl_object(ClientData clientData
, Tcl_Interp
*interp
,
3719 int objc
, Tcl_Obj
*CONST objv
[])
3721 int i
, j
, idx
, result
, nidx
, libno
;
3723 Tcl_Obj
**newobjv
, *ilist
, *plist
, *hobj
;
3724 pointertype ehandle
;
3725 objinstptr thisinst
;
3726 Boolean forceempty
= FALSE
;
3728 static char *subCmds
[] = {"make", "name", "parts", "library",
3729 "handle", "hide", "unhide", "bbox", NULL
};
3731 MakeIdx
, NameIdx
, PartsIdx
, LibraryIdx
, HandleIdx
, HideIdx
,
3735 /* Check for option "-force" (create an object even if it has no contents) */
3736 if (!strncmp(Tcl_GetString(objv
[objc
- 1]), "-forc", 5)) {
3741 /* (revision) "object handle <name>" returns a handle (or null), so */
3742 /* all commands can unambiguously operate on a handle (or nothing) */
3743 /* in the second position. */
3747 /* 2nd argument may be a handle, object name, or nothing. */
3748 /* If nothing, the instance of the top-level page is assumed. */
3751 Tcl_WrongNumArgs(interp
, 0, objv
, "object [handle] <option> ...");
3755 result
= Tcl_GetHandleFromObj(interp
, objv
[1], (void *)&ehandle
);
3756 if (result
!= TCL_OK
) {
3757 Tcl_ResetResult(interp
);
3758 ehandle
= (pointertype
)(areawin
->topinstance
);
3764 egen
= (genericptr
)ehandle
;
3766 if (ELEMENTTYPE(egen
) != OBJINST
) {
3767 Tcl_SetResult(interp
, "handle does not point to an object instance!", NULL
);
3771 Tcl_WrongNumArgs(interp
, 0, objv
, "object <handle> <option> ...");
3774 thisinst
= (objinstptr
)egen
;
3776 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[1 + nidx
],
3777 (CONST84
char **)subCmds
, "option", 0, &idx
)) != TCL_OK
)
3785 if ((libno
= libfindobject(thisinst
->thisobject
, &j
)) < 0) {
3786 Tcl_SetResult(interp
, "No such object.", NULL
);
3794 ilist
= Tcl_NewListObj(0, NULL
);
3795 hobj
= Tcl_NewIntObj((int)thisinst
->thisobject
->bbox
.lowerleft
.x
);
3796 Tcl_ListObjAppendElement(interp
, ilist
, hobj
);
3797 hobj
= Tcl_NewIntObj((int)thisinst
->thisobject
->bbox
.lowerleft
.y
);
3798 Tcl_ListObjAppendElement(interp
, ilist
, hobj
);
3799 hobj
= Tcl_NewIntObj((int)(thisinst
->thisobject
->bbox
.lowerleft
.x
+
3800 thisinst
->thisobject
->bbox
.width
));
3801 Tcl_ListObjAppendElement(interp
, ilist
, hobj
);
3802 hobj
= Tcl_NewIntObj((int)(thisinst
->thisobject
->bbox
.lowerleft
.y
+
3803 thisinst
->thisobject
->bbox
.height
));
3804 Tcl_ListObjAppendElement(interp
, ilist
, hobj
);
3805 Tcl_SetObjResult(interp
, ilist
);
3809 if ((objc
== 3) && (!NameToObject(Tcl_GetString(objv
[nidx
+ 2]),
3810 (objinstptr
*)&ehandle
, TRUE
))) {
3811 Tcl_SetResult(interp
, "Object is not loaded.", NULL
);
3815 Tcl_SetObjResult(interp
, Tcl_NewHandleObj((genericptr
)ehandle
));
3822 if (ParseLibArguments(xcinterp
, 2, &objv
[objc
- 2 + nidx
], NULL
,
3823 &libtarget
) == TCL_ERROR
)
3825 else if (libno
!= libtarget
) {
3826 libmoveobject(thisinst
->thisobject
, libtarget
);
3827 /* Regenerate the source and target library pages */
3828 composelib(libno
+ LIBRARY
);
3829 composelib(libtarget
+ LIBRARY
);
3832 Tcl_SetObjResult(interp
, Tcl_NewIntObj(libno
+ 1));
3836 thisinst
->thisobject
->hidden
= True
;
3837 composelib(libno
+ LIBRARY
);
3841 thisinst
->thisobject
->hidden
= False
;
3842 composelib(libno
+ LIBRARY
);
3847 if ((areawin
->selects
== 0) && (nidx
== 0)) {
3848 /* h = object make "name" [{element_list}] [library]*/
3849 newobjv
= (Tcl_Obj
**)(&objv
[2]);
3850 result
= ParseElementArguments(interp
, objc
- 2, newobjv
, NULL
, ALL_TYPES
);
3851 if (forceempty
&& result
!= TCL_OK
) Tcl_ResetResult(interp
);
3852 else if (!forceempty
&& result
== TCL_OK
&& areawin
->selects
== 0)
3854 Tcl_SetResult(interp
, "Cannot create empty object. Use "
3855 "\"-force\" option.", NULL
);
3858 else if (result
!= TCL_OK
) return result
;
3860 else if (nidx
== 1) {
3861 Tcl_SetResult(interp
, "\"object <handle> make\" is illegal", NULL
);
3864 else if (objc
< 3) {
3865 Tcl_WrongNumArgs(interp
, 1, objv
, "make <name> [element_list] [<library>]");
3869 ParseLibArguments(xcinterp
, 2, &objv
[objc
- 2], NULL
, &libno
);
3872 thisinst
= domakeobject(libno
, Tcl_GetString(objv
[nidx
+ 2]), forceempty
);
3873 Tcl_SetObjResult(interp
, Tcl_NewHandleObj(thisinst
));
3877 if (nidx
== 1 || areawin
->selects
== 0) {
3879 sprintf(thisinst
->thisobject
->name
, Tcl_GetString(objv
[nidx
+ 2]));
3880 checkname(thisinst
->thisobject
);
3882 Tcl_AppendElement(interp
, thisinst
->thisobject
->name
);
3885 for (i
= 0; i
< areawin
->selects
; i
++) {
3886 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
3887 thisinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
3888 Tcl_AppendElement(interp
, thisinst
->thisobject
->name
);
3894 /* Make a list of the handles of all parts in the object */
3895 if (nidx
== 1 || areawin
->selects
== 0) {
3896 plist
= Tcl_NewListObj(0, NULL
);
3897 for (j
= 0; j
< thisinst
->thisobject
->parts
; j
++) {
3898 hobj
= Tcl_NewHandleObj(*(thisinst
->thisobject
->plist
+ j
));
3899 Tcl_ListObjAppendElement(interp
, plist
, hobj
);
3901 Tcl_SetObjResult(interp
, plist
);
3904 ilist
= Tcl_NewListObj(0, NULL
);
3905 for (i
= 0; i
< areawin
->selects
; i
++) {
3906 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
3907 objinstptr thisinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
3908 Tcl_ListObjAppendElement(interp
, ilist
,
3909 Tcl_NewStringObj(thisinst
->thisobject
->name
,
3910 strlen(thisinst
->thisobject
->name
)));
3911 plist
= Tcl_NewListObj(0, NULL
);
3912 for (j
= 0; j
< thisinst
->thisobject
->parts
; j
++) {
3913 hobj
= Tcl_NewHandleObj(*(thisinst
->thisobject
->plist
+ j
));
3914 Tcl_ListObjAppendElement(interp
, plist
, hobj
);
3916 Tcl_ListObjAppendElement(interp
, ilist
, plist
);
3919 Tcl_SetObjResult(interp
, ilist
);
3923 return XcTagCallback(interp
, objc
, objv
);
3926 /*----------------------------------------------------------------------*/
3927 /* Get anchoring (or associated fields) global setting, or apply */
3928 /* to selected labels. */
3929 /*----------------------------------------------------------------------*/
3932 getanchoring(Tcl_Interp
*interp
, short bitfield
)
3937 if (areawin
->selects
== 0) {
3938 if (bitfield
& RIGHT
) {
3939 Tcl_AppendElement(interp
, (areawin
->anchor
& RIGHT
) ?
3940 "right" : (areawin
->anchor
& NOTLEFT
) ? "center" : "left");
3942 else if (bitfield
& TOP
) {
3943 Tcl_AppendElement(interp
, (areawin
->anchor
& TOP
) ?
3944 "top" : (areawin
->anchor
& NOTBOTTOM
) ? "middle" : "bottom");
3946 else if (bitfield
& JUSTIFYRIGHT
) {
3947 Tcl_AppendElement(interp
, (areawin
->anchor
& JUSTIFYRIGHT
) ? "right" :
3948 (areawin
->anchor
& TEXTCENTERED
) ? "center" :
3949 (areawin
->anchor
& JUSTIFYBOTH
) ? "both" :
3953 Tcl_AppendElement(interp
, (areawin
->anchor
& bitfield
) ?
3956 return (areawin
->anchor
& bitfield
);
3958 for (i
= 0; i
< areawin
->selects
; i
++) {
3959 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
3960 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
3961 if (bitfield
== PINVISIBLE
&& tlab
->pin
== NORMAL
) continue;
3962 if (bitfield
& RIGHT
) {
3963 Tcl_AppendElement(interp
, (tlab
->anchor
& RIGHT
) ?
3964 "right" : (tlab
->anchor
& NOTLEFT
) ? "center" : "left");
3966 else if (bitfield
& TOP
) {
3967 Tcl_AppendElement(interp
, (tlab
->anchor
& TOP
) ?
3968 "top" : (tlab
->anchor
& NOTBOTTOM
) ? "middle" : "bottom");
3970 else if (bitfield
& JUSTIFYRIGHT
) {
3971 Tcl_AppendElement(interp
, (tlab
->anchor
& JUSTIFYRIGHT
) ? "right" :
3972 (tlab
->anchor
& TEXTCENTERED
) ? "center" :
3973 (tlab
->anchor
& JUSTIFYBOTH
) ? "both" :
3977 Tcl_AppendElement(interp
, (tlab
->anchor
& bitfield
) ? "true" : "false");
3979 rval
= tlab
->anchor
;
3981 return (rval
& bitfield
);
3985 /*----------------------------------------------------------------------*/
3986 /* Set anchoring (and associated fields) global setting, or apply */
3987 /* to selected labels. */
3988 /*----------------------------------------------------------------------*/
3991 setanchoring(short bitfield
, short value
)
3996 if (areawin
->selects
== 0) {
3997 areawin
->anchor
&= (~bitfield
);
3998 if (value
> 0) areawin
->anchor
|= value
;
4001 for (i
= 0; i
< areawin
->selects
; i
++) {
4002 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4003 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4004 if (bitfield
== PINVISIBLE
&& tlab
->pin
== NORMAL
) continue;
4005 tlab
->anchor
&= (~bitfield
);
4006 if (value
> 0) tlab
->anchor
|= value
;
4010 /*----------------------------------------------------------------------*/
4011 /* Translate the label encoding bits to a string that the Tcl routine */
4012 /* will recognize from the command line. */
4014 /* (note to self---is there a good way to not have to declare these */
4015 /* constant character arrays twice in two different routines?) */
4016 /*----------------------------------------------------------------------*/
4019 translateencoding(int psfont
)
4021 const char *encValues
[] = {"Standard", "special", "ISOLatin1",
4022 "ISOLatin2", "ISOLatin3", "ISOLatin4", "ISOLatin5",
4023 "ISOLatin6", "ISO8859-5", NULL
};
4026 i
= (fonts
[psfont
].flags
& 0xf80) >> 7;
4027 if (i
< 0) return NULL
;
4028 return (char *)encValues
[i
];
4031 /*----------------------------------------------------------------------*/
4032 /* Translate the label style bits to a string that the Tcl routine */
4033 /* will recognize from the command line. */
4034 /*----------------------------------------------------------------------*/
4037 translatestyle(int psfont
)
4039 const char *styValues
[] = {"normal", "bold", "italic", "bolditalic", NULL
};
4042 i
= fonts
[psfont
].flags
& 0x3;
4043 if (i
< 0) return NULL
;
4044 return (char *)styValues
[i
];
4047 /*----------------------------------------------------------------------*/
4048 /* Individual element handling. */
4049 /*----------------------------------------------------------------------*/
4051 int xctcl_label(ClientData clientData
, Tcl_Interp
*interp
,
4052 int objc
, Tcl_Obj
*CONST objv
[])
4054 int i
, idx
, idx2
, nidx
, result
, value
, jval
, jval2
;
4057 Tcl_Obj
*objPtr
, *listPtr
;
4060 static char *subCmds
[] = {"make", "type", "insert", "anchor", "justify",
4061 "flipinvariant", "visible", "font", "scale", "encoding", "style",
4062 "family", "substring", "text", "latex", "list", "replace", "position",
4065 MakeIdx
, TypeIdx
, InsertIdx
, AnchorIdx
, JustifyIdx
, FlipIdx
, VisibleIdx
,
4066 FontIdx
, ScaleIdx
, EncodingIdx
, StyleIdx
, FamilyIdx
, SubstringIdx
,
4067 TextIdx
, LaTeXIdx
, ListIdx
, ReplaceIdx
, PositionIdx
4070 /* These must match the order of string part types defined in xcircuit.h */
4071 static char *subsubCmds
[] = {"text", "subscript", "superscript",
4072 "normalscript", "underline", "overline", "noline", "stop",
4073 "forward", "backward", "halfspace", "quarterspace", "return",
4074 "name", "scale", "color", "margin", "kern", "parameter",
4077 static char *pinTypeNames
[] = {"normal", "text", "local", "pin", "global",
4078 "info", "netlist", NULL
};
4080 static int pinTypes
[] = {NORMAL
, NORMAL
, LOCAL
, LOCAL
, GLOBAL
, INFO
, INFO
};
4082 static char *anchorValues
[] = {"left", "center", "right", "top", "middle",
4085 static char *justifyValues
[] = {"left", "center", "right", "both", NULL
};
4087 const char *styValues
[] = {"normal", "bold", "italic", "bolditalic", NULL
};
4089 const char *encValues
[] = {"Standard", "special", "ISOLatin1",
4090 "ISOLatin2", "ISOLatin3", "ISOLatin4", "ISOLatin5",
4091 "ISOLatin6", "ISO8859-5", NULL
};
4093 /* Tk "label" has been renamed to "tcl_label", but we want to */
4094 /* consider the "label" command to be overloaded, such that the */
4095 /* command "label" may be used without reference to technology. */
4097 Tcl_Obj
**newobjv
= (Tcl_Obj
**)Tcl_Alloc(objc
* sizeof(Tcl_Obj
*));
4099 newobjv
[0] = Tcl_NewStringObj("tcl_label", 9);
4100 Tcl_IncrRefCount(newobjv
[0]);
4101 for (i
= 1; i
< objc
; i
++) {
4102 if (Tcl_IsShared(objv
[i
]))
4103 newobjv
[i
] = Tcl_DuplicateObj(objv
[i
]);
4105 newobjv
[i
] = objv
[i
];
4106 Tcl_IncrRefCount(newobjv
[i
]);
4109 result
= Tcl_EvalObjv(interp
, objc
, newobjv
, 0);
4111 for (i
= 0; i
< objc
; i
++)
4112 Tcl_DecrRefCount(newobjv
[i
]);
4113 Tcl_Free((char *)newobjv
);
4115 if (result
== TCL_OK
) return result
;
4116 Tcl_ResetResult(interp
);
4118 /* Now, assuming that Tcl didn't like the syntax, we continue on with */
4119 /* our own version. */
4122 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, LABEL
);
4123 if (result
!= TCL_OK
) return result
;
4125 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
4126 (CONST84
char **)subCmds
, "option", 0, &idx
)) != TCL_OK
)
4129 /* If there are no selections at this point, check if the command is */
4130 /* appropriate for setting a default value. */
4134 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4136 result
= Tcl_GetIndexFromObj(interp
, objv
[2],
4137 (CONST84
char **)pinTypeNames
, "pin type", 0, &idx2
);
4138 if (result
!= TCL_OK
) {
4139 if (objc
== 3) return result
;
4141 Tcl_ResetResult(interp
);
4147 idx2
= pinTypes
[idx2
]; /* idx2 now matches defs in xcircuit.h */
4150 if ((objc
!= 4) && (objc
!= 5)) {
4151 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
4156 stringpart
*strptr
= NULL
;
4159 if ((result
= GetXCStringFromList(interp
, objv
[nidx
+ 1],
4160 &strptr
)) != TCL_OK
)
4163 /* Should probably have some mechanism to create an empty */
4164 /* string from a script, even though empty strings are */
4165 /* disallowed from the GUI. */
4167 if (strptr
== NULL
) {
4168 Tcl_SetResult(interp
, "Empty string. No element created.", NULL
);
4171 if ((objc
- nidx
) <= 2) {
4172 Tcl_WrongNumArgs(interp
, 3, objv
, "<text> {position}");
4176 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 2],
4177 &position
)) != TCL_OK
)
4180 newlab
= new_label(NULL
, strptr
, idx2
, position
.x
, position
.y
,
4182 singlebbox((genericptr
*)&newlab
);
4183 objPtr
= Tcl_NewHandleObj(newlab
);
4184 Tcl_SetObjResult(interp
, objPtr
);
4187 else if (nidx
== 2) {
4188 Tcl_SetResult(interp
, "\"label <handle> make\" is illegal", NULL
);
4192 Tcl_SetResult(interp
, "No selections allowed", NULL
);
4199 if ((areawin
->selects
== 0) && (nidx
== 1) &&
4200 eventmode
!= TEXT_MODE
&& eventmode
!= ETEXT_MODE
) {
4201 objPtr
= Tcl_NewDoubleObj((double)areawin
->textscale
);
4202 Tcl_SetObjResult(interp
, objPtr
);
4206 gettextsize(&floatptr
);
4207 objPtr
= Tcl_NewDoubleObj((double)((float)(*floatptr
)));
4208 Tcl_SetObjResult(interp
, objPtr
);
4211 else if (objc
>= 3) {
4212 result
= Tcl_GetDoubleFromObj(interp
, objv
[2], &tmpdbl
);
4213 if (result
!= TCL_OK
) return result
;
4214 if (tmpdbl
<= 0.0) {
4215 Tcl_SetResult(interp
, "Illegal scale value", NULL
);
4219 if ((areawin
->selects
== 0) && (nidx
== 1) && (eventmode
!= TEXT_MODE
)
4220 && (eventmode
!= ETEXT_MODE
))
4221 areawin
->textscale
= (float)tmpdbl
;
4223 changetextscale((float)tmpdbl
);
4229 tmpstr
= fonts
[areawin
->psfont
].psname
;
4230 objPtr
= Tcl_NewStringObj(tmpstr
, strlen(tmpstr
));
4231 Tcl_SetObjResult(interp
, objPtr
);
4234 tmpstr
= Tcl_GetString(objv
[2]);
4235 for (i
= 0; i
< fontcount
; i
++)
4236 if (!strcmp(fonts
[i
].psname
, tmpstr
)) break;
4237 setfont((Tk_Window
)clientData
, (u_int
)i
, NULL
);
4243 /* Check for "-all" switch */
4244 if ((objc
- nidx
) == 2) {
4245 tmpstr
= Tcl_GetString(objv
[nidx
+ 1]);
4246 if (!strncmp(tmpstr
, "-all", 4)) {
4248 /* Create a list of all font families. This does a simple */
4249 /* check against contiguous entries, but the result is not */
4250 /* guaranteed to be a list of unique entries (i.e., the */
4251 /* calling script should sort the list) */
4253 for (i
= 0; i
< fontcount
; i
++) {
4254 if (i
== 0 || strcmp(fonts
[i
].family
, fonts
[i
-1].family
))
4255 Tcl_AppendElement(interp
, fonts
[i
].family
);
4262 tmpstr
= fonts
[areawin
->psfont
].family
;
4263 objPtr
= Tcl_NewStringObj(tmpstr
, strlen(tmpstr
));
4264 Tcl_SetObjResult(interp
, objPtr
);
4267 tmpstr
= Tcl_GetString(objv
[2]);
4268 for (i
= 0; i
< fontcount
; i
++)
4269 if (!strcmp(fonts
[i
].family
, tmpstr
)) break;
4270 setfont((Tk_Window
)clientData
, (u_int
)i
, NULL
);
4276 tmpstr
= translateencoding(areawin
->psfont
);
4277 objPtr
= Tcl_NewStringObj(tmpstr
, -1);
4278 Tcl_SetObjResult(interp
, objPtr
);
4281 if (Tcl_GetIndexFromObj(interp
, objv
[2],
4282 (CONST84
char **)encValues
, "encodings", 0,
4286 fontencoding((Tk_Window
)clientData
, idx2
, NULL
);
4287 refresh(NULL
, NULL
, NULL
);
4293 tmpstr
= translatestyle(areawin
->psfont
);
4294 objPtr
= Tcl_NewStringObj(tmpstr
, -1);
4295 Tcl_SetObjResult(interp
, objPtr
);
4298 if (Tcl_GetIndexFromObj(interp
, objv
[2],
4299 (CONST84
char **)styValues
,
4300 "styles", 0, &idx2
) != TCL_OK
) {
4303 fontstyle((Tk_Window
)clientData
, idx2
, NULL
);
4307 case TypeIdx
: /* Change type of label */
4308 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4309 Tcl_SetResult(interp
, "Must have a label selection.", NULL
);
4312 if (objc
== nidx
+ 1) { /* Return pin type(s) */
4313 for (i
= 0; i
< areawin
->selects
; i
++) {
4314 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4315 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4316 for (idx2
= 0; idx2
< sizeof(pinTypeNames
); idx2
++) {
4317 if (tlab
->pin
== pinTypes
[idx2
]) {
4318 Tcl_AppendElement(interp
, pinTypeNames
[idx2
]);
4325 if (Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
4326 (CONST84
char **)pinTypeNames
,
4327 "pin types", 0, &idx2
) != TCL_OK
) {
4330 for (i
= 0; i
< areawin
->selects
; i
++) {
4331 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4332 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4333 tlab
->pin
= pinTypes
[idx2
];
4334 pinconvert(tlab
, tlab
->pin
);
4335 setobjecttype(topobject
);
4340 case InsertIdx
: /* Text insertion */
4342 Tcl_SetResult(interp
, "Insertion into handle or selection"
4343 " not supported (yet)", NULL
);
4346 if (eventmode
!= TEXT_MODE
&& eventmode
!= ETEXT_MODE
) {
4347 Tcl_SetResult(interp
, "Must be in edit mode to insert into label.",
4351 if (objc
<= nidx
+ 1) {
4352 Tcl_WrongNumArgs(interp
, 2, objv
, "insert_type");
4355 if (Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
4356 (CONST84
char **)subsubCmds
,
4357 "insertions", 0, &idx2
) != TCL_OK
) {
4360 if ((idx2
> TEXT_STRING
) && (idx2
< FONT_NAME
) && (objc
- nidx
== 2)) {
4361 labeltext(idx2
, (char *)1);
4363 else if (idx2
== MARGINSTOP
) {
4364 if (objc
- nidx
== 3) {
4365 result
= Tcl_GetIntFromObj(interp
, objv
[nidx
+ 2], &value
);
4366 if (result
!= TCL_OK
) return result
;
4369 labeltext(idx2
, (char *)&value
);
4371 else if ((idx2
== PARAM_START
) && (objc
- nidx
== 3)) {
4372 labeltext(idx2
, Tcl_GetString(objv
[nidx
+ 2]));
4374 else if ((idx2
== FONT_COLOR
) && (objc
- nidx
== 3)) {
4375 result
= GetColorFromObj(interp
, objv
[nidx
+ 2], &value
, TRUE
);
4376 if (result
!= TCL_OK
) return result
;
4377 labeltext(idx2
, (char *)&value
);
4379 else if ((idx2
== FONT_NAME
) && (objc
- nidx
== 3)) {
4380 tmpstr
= Tcl_GetString(objv
[nidx
+ 2]);
4381 for (i
= 0; i
< fontcount
; i
++)
4382 if (!strcmp(fonts
[i
].psname
, tmpstr
)) break;
4383 if (i
== fontcount
) {
4384 Tcl_SetResult(interp
, "Invalid font name.", NULL
);
4388 labeltext(idx2
, (char *)&i
);
4390 else if ((idx2
== FONT_SCALE
) && (objc
- nidx
== 3)) {
4393 result
= Tcl_GetDoubleFromObj(interp
, objv
[nidx
+ 2], &dvalue
);
4394 if (result
!= TCL_OK
) return result
;
4395 fvalue
= (float)dvalue
;
4396 labeltext(idx2
, (char *)&fvalue
);
4398 else if ((idx2
== KERN
) && (objc
- nidx
== 3)) {
4399 strcpy(_STR2
, Tcl_GetString(objv
[nidx
+ 2]));
4400 setkern(NULL
, NULL
);
4402 else if ((idx2
== TEXT_STRING
) && (objc
- nidx
== 3)) {
4403 char *substring
= Tcl_GetString(objv
[nidx
+ 2]);
4404 for (i
= 0; i
< strlen(substring
); i
++) {
4405 /* Special handling allows newlines from cutbuffer selections */
4406 /* to be translated into embedded carriage returns. */
4407 if (substring
[i
] == '\012')
4408 labeltext(RETURN
, (char *)1);
4410 labeltext(substring
[i
], NULL
);
4414 /* PARAM_END in xcircuit.h is actually mapped to the same */
4415 /* position as "special" in subsubCommands[] above; don't */
4416 /* be confused. . . */
4418 else if ((idx2
== PARAM_END
) && (objc
- nidx
== 2)) {
4421 else if ((idx2
== PARAM_END
) && (objc
- nidx
== 3)) {
4422 result
= Tcl_GetIntFromObj(interp
, objv
[nidx
+ 2], &value
);
4423 if (result
!= TCL_OK
) return result
;
4424 labeltext(value
, NULL
);
4427 Tcl_WrongNumArgs(interp
, 2, objv
, "insertion_type ?arg ...?");
4433 objPtr
= Tcl_NewListObj(0, NULL
);
4434 if (areawin
!= NULL
&& areawin
->selects
== 1) {
4435 if (SELECTTYPE(areawin
->selectlist
) == LABEL
) {
4436 Tcl_ListObjAppendElement(interp
, objPtr
, Tcl_NewIntObj(areawin
->textend
));
4437 Tcl_ListObjAppendElement(interp
, objPtr
, Tcl_NewIntObj(areawin
->textpos
));
4440 Tcl_SetObjResult(interp
, objPtr
);
4443 case VisibleIdx
: /* Change visibility of pin */
4444 if (objc
== nidx
+ 1)
4445 jval
= getanchoring(interp
, PINVISIBLE
);
4447 if ((result
= Tcl_GetBooleanFromObj(interp
, objv
[nidx
+ 1],
4451 setanchoring(PINVISIBLE
, (value
) ? PINVISIBLE
: NORMAL
);
4456 if (objc
== nidx
+ 1)
4457 jval
= getanchoring(interp
, FLIPINV
);
4459 if ((result
= Tcl_GetBooleanFromObj(interp
, objv
[nidx
+ 1],
4463 setanchoring(FLIPINV
, (value
) ? FLIPINV
: NORMAL
);
4468 if (objc
== nidx
+ 1)
4469 jval
= getanchoring(interp
, LATEXLABEL
);
4471 if ((result
= Tcl_GetBooleanFromObj(interp
, objv
[nidx
+ 1],
4475 setanchoring(LATEXLABEL
, (value
) ? LATEXLABEL
: NORMAL
);
4480 if (objc
== nidx
+ 1) {
4481 jval
= getanchoring(interp
, JUSTIFYRIGHT
| JUSTIFYBOTH
| TEXTCENTERED
);
4484 if (Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
4485 (CONST84
char **)justifyValues
,
4486 "justification", 0, &idx2
) != TCL_OK
) {
4490 case 0: value
= NORMAL
; break;
4491 case 1: value
= TEXTCENTERED
; break;
4492 case 2: value
= JUSTIFYRIGHT
; break;
4493 case 3: value
= JUSTIFYBOTH
; break;
4495 jval
= getanchoring(interp
, JUSTIFYRIGHT
| JUSTIFYBOTH
| TEXTCENTERED
);
4496 if (jval
!= value
) {
4497 setanchoring(JUSTIFYRIGHT
| JUSTIFYBOTH
| TEXTCENTERED
, value
);
4498 refresh(NULL
, NULL
, NULL
);
4504 if (objc
== nidx
+ 1) {
4505 jval
= getanchoring(interp
, RIGHT
| NOTLEFT
);
4506 jval2
= getanchoring(interp
, TOP
| NOTBOTTOM
);
4509 if (Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
4510 (CONST84
char **)anchorValues
,
4511 "anchoring", 0, &idx2
) != TCL_OK
) {
4515 case 0: value
= NORMAL
; break;
4516 case 1: value
= NOTLEFT
; break;
4517 case 2: value
= NOTLEFT
| RIGHT
; break;
4518 case 3: value
= NOTBOTTOM
| TOP
; break;
4519 case 4: value
= NOTBOTTOM
; break;
4520 case 5: value
= NORMAL
; break;
4523 case 0: case 1: case 2:
4524 jval
= getanchoring(interp
, RIGHT
| NOTLEFT
);
4525 if (jval
!= value
) {
4526 setanchoring(RIGHT
| NOTLEFT
, value
);
4527 refresh(NULL
, NULL
, NULL
);
4530 case 3: case 4: case 5:
4531 jval2
= getanchoring(interp
, TOP
| NOTBOTTOM
);
4532 if (jval2
!= value
) {
4533 setanchoring(TOP
| NOTBOTTOM
, value
);
4534 refresh(NULL
, NULL
, NULL
);
4542 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4543 Tcl_SetResult(interp
, "Must have a label selection.", NULL
);
4546 if (objc
== nidx
+ 1) { /* Return label as printable string */
4548 objPtr
= Tcl_NewListObj(0, NULL
);
4549 for (i
= 0; i
< areawin
->selects
; i
++) {
4550 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4551 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4552 tstr
= textprint(tlab
->string
, areawin
->topinstance
);
4553 Tcl_ListObjAppendElement(interp
, objPtr
,
4554 Tcl_NewStringObj(tstr
, strlen(tstr
)));
4557 Tcl_SetObjResult(interp
, objPtr
);
4562 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4563 Tcl_SetResult(interp
, "Must have a label selection.", NULL
);
4566 if (objc
== nidx
+ 1) { /* Return label as printable string */
4567 listPtr
= Tcl_NewListObj(0, NULL
);
4568 for (i
= 0; i
< areawin
->selects
; i
++) {
4569 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4570 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4571 objPtr
= TclGetStringParts(tlab
->string
);
4572 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
4574 Tcl_SetObjResult(interp
, listPtr
);
4578 case ReplaceIdx
: /* the opposite of "list" */
4579 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4580 Tcl_SetResult(interp
, "Must have a label selection.", NULL
);
4583 if (objc
== nidx
+ 2) { /* Replace string from list */
4584 stringpart
*strptr
= NULL
;
4586 if ((result
= GetXCStringFromList(interp
, objv
[nidx
+ 1],
4587 &strptr
)) != TCL_OK
)
4590 for (i
= 0; i
< areawin
->selects
; i
++) {
4591 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4592 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4593 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
, tlab
);
4594 freelabel(tlab
->string
);
4595 tlab
->string
= stringcopy(strptr
);
4598 undo_finish_series();
4599 refresh(NULL
, NULL
, NULL
);
4604 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4605 Tcl_SetResult(interp
, "Must have a label selection.", NULL
);
4608 if (objc
== nidx
+ 1) { /* Return position of label */
4611 listPtr
= Tcl_NewListObj(0, NULL
);
4612 for (i
= 0; i
< areawin
->selects
; i
++) {
4613 if (SELECTTYPE(areawin
->selectlist
+ i
) != LABEL
) continue;
4614 tlab
= SELTOLABEL(areawin
->selectlist
+ i
);
4615 cpair
= Tcl_NewListObj(0, NULL
);
4616 objPtr
= Tcl_NewIntObj((int)tlab
->position
.x
);
4617 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
4618 objPtr
= Tcl_NewIntObj((int)tlab
->position
.y
);
4619 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
4620 Tcl_ListObjAppendElement(interp
, listPtr
, cpair
);
4622 Tcl_SetObjResult(interp
, listPtr
);
4624 else if (objc
== nidx
+ 2) { /* Change position of label */
4627 if ((areawin
->selects
!= 1) || (SELECTTYPE(areawin
->selectlist
)
4629 Tcl_SetResult(interp
, "Must have exactly one selected label", NULL
);
4632 if ((result
= GetPositionFromList(interp
, objv
[nidx
+ 1],
4633 &position
)) != TCL_OK
)
4636 tlab
= SELTOLABEL(areawin
->selectlist
);
4637 tlab
->position
.x
= position
.x
;
4638 tlab
->position
.y
= position
.y
;
4642 return XcTagCallback(interp
, objc
, objv
);
4645 /*----------------------------------------------------------------------*/
4646 /* Element Fill Styles */
4647 /*----------------------------------------------------------------------*/
4649 int xctcl_dofill(ClientData clientData
, Tcl_Interp
*interp
,
4650 int objc
, Tcl_Obj
*CONST objv
[])
4653 int i
, idx
, result
, rval
= -1;
4655 static char *Styles
[] = {"opaque", "transparent", "filled", "unfilled",
4658 OpaqueIdx
, TransparentIdx
, FilledIdx
, UnfilledIdx
, SolidIdx
4662 value
= areawin
->style
;
4663 Tcl_AppendElement(interp
, ((value
& OPAQUE
) ? "opaque" : "transparent"));
4664 if (value
& FILLED
) {
4665 Tcl_AppendElement(interp
, "filled");
4666 switch (value
& FILLSOLID
) {
4668 Tcl_AppendElement(interp
, "12"); break;
4670 Tcl_AppendElement(interp
, "25"); break;
4672 Tcl_AppendElement(interp
, "37"); break;
4674 Tcl_AppendElement(interp
, "50"); break;
4676 Tcl_AppendElement(interp
, "62"); break;
4678 Tcl_AppendElement(interp
, "75"); break;
4680 Tcl_AppendElement(interp
, "87"); break;
4682 Tcl_AppendElement(interp
, "solid"); break;
4686 Tcl_AppendElement(interp
, "unfilled");
4691 for (i
= 1; i
< objc
; i
++) {
4692 if (Tcl_GetIndexFromObj(interp
, objv
[i
],
4693 (CONST84
char **)Styles
, "fill styles",
4694 0, &idx
) != TCL_OK
) {
4695 Tcl_ResetResult(interp
);
4696 result
= Tcl_GetIntFromObj(interp
, objv
[i
], &value
);
4697 if (result
!= TCL_OK
) {
4698 Tcl_SetResult(interp
, "Expected fill style or fillfactor 0 to 100", NULL
);
4702 if (value
>= 0 && value
< 6) value
= FILLSOLID
;
4703 else if (value
>= 6 && value
< 19) value
= FILLED
;
4704 else if (value
>= 19 && value
< 31) value
= FILLED
| STIP0
;
4705 else if (value
>= 31 && value
< 44) value
= FILLED
| STIP1
;
4706 else if (value
>= 44 && value
< 56) value
= FILLED
| STIP0
| STIP1
;
4707 else if (value
>= 56 && value
< 69) value
= FILLED
| STIP2
;
4708 else if (value
>= 69 && value
< 81) value
= FILLED
| STIP2
| STIP0
;
4709 else if (value
>= 81 && value
< 94) value
= FILLED
| STIP2
| STIP1
;
4710 else if (value
>= 94 && value
<= 100) value
= FILLED
| FILLSOLID
;
4712 Tcl_SetResult(interp
, "Fill value should be 0 to 100", NULL
);
4715 rval
= setelementstyle((Tk_Window
)clientData
, (pointertype
)value
,
4716 FILLED
| FILLSOLID
);
4722 rval
= setelementstyle((Tk_Window
)clientData
, OPAQUE
, OPAQUE
);
4724 case TransparentIdx
:
4725 rval
= setelementstyle((Tk_Window
)clientData
, NORMAL
, OPAQUE
);
4728 rval
= setelementstyle((Tk_Window
)clientData
, FILLSOLID
,
4729 FILLED
| FILLSOLID
);
4732 rval
= setelementstyle((Tk_Window
)clientData
, FILLED
| FILLSOLID
,
4733 FILLED
| FILLSOLID
);
4743 return XcTagCallback(interp
, objc
, objv
);
4746 /*----------------------------------------------------------------------*/
4747 /* Element border styles */
4748 /*----------------------------------------------------------------------*/
4750 int xctcl_doborder(ClientData clientData
, Tcl_Interp
*interp
,
4751 int objc
, Tcl_Obj
*CONST objv
[])
4753 int result
, i
, idx
, value
, rval
= -1;
4757 static char *borderStyles
[] = {"solid", "dashed", "dotted", "none",
4758 "unbordered", "unclosed", "closed", "bbox", "set", "get", "square",
4759 "round", "clipmask", NULL
};
4761 SolidIdx
, DashedIdx
, DottedIdx
, NoneIdx
, UnborderedIdx
,
4762 UnclosedIdx
, ClosedIdx
, BBoxIdx
, SetIdx
, GetIdx
, SquareIdx
,
4763 RoundIdx
, ClipMaskIdx
4768 listPtr
= Tcl_NewListObj(0, NULL
);
4769 value
= areawin
->style
;
4770 wvalue
= (double)areawin
->linewidth
;
4771 switch (value
& (DASHED
| DOTTED
| NOBORDER
| SQUARECAP
)) {
4773 Tcl_ListObjAppendElement(interp
, listPtr
,
4774 Tcl_NewStringObj("solid", 5)); break;
4776 Tcl_ListObjAppendElement(interp
, listPtr
,
4777 Tcl_NewStringObj("dashed", 6)); break;
4779 Tcl_ListObjAppendElement(interp
, listPtr
,
4780 Tcl_NewStringObj("dotted", 6)); break;
4782 Tcl_ListObjAppendElement(interp
, listPtr
,
4783 Tcl_NewStringObj("unbordered", 10)); break;
4785 Tcl_ListObjAppendElement(interp
, listPtr
,
4786 Tcl_NewStringObj("square-endcaps", 10)); break;
4788 if (value
& UNCLOSED
)
4789 Tcl_ListObjAppendElement(interp
, listPtr
, Tcl_NewStringObj("unclosed", 8));
4791 Tcl_ListObjAppendElement(interp
, listPtr
, Tcl_NewStringObj("closed", 6));
4794 Tcl_ListObjAppendElement(interp
, listPtr
,
4795 Tcl_NewStringObj("bounding box", 12));
4797 if (value
& CLIPMASK
)
4798 Tcl_ListObjAppendElement(interp
, listPtr
,
4799 Tcl_NewStringObj("clipmask", 8));
4801 Tcl_ListObjAppendElement(interp
, listPtr
, Tcl_NewDoubleObj(wvalue
));
4802 Tcl_SetObjResult(interp
, listPtr
);
4806 for (i
= 1; i
< objc
; i
++) {
4807 result
= Tcl_GetIndexFromObj(interp
, objv
[i
],
4808 (CONST84
char **)borderStyles
,
4809 "border style", 0, &idx
);
4810 if (result
!= TCL_OK
)
4816 int j
, numfound
= 0;
4818 Tcl_Obj
*objPtr
, *listPtr
= NULL
;
4820 for (j
= 0; j
< areawin
->selects
; j
++) {
4821 setel
= SELTOGENERIC(areawin
->selectlist
+ j
);
4822 if (IS_ARC(setel
) || IS_POLYGON(setel
) ||
4823 IS_SPLINE(setel
) || IS_PATH(setel
)) {
4824 switch(ELEMENTTYPE(setel
)) {
4825 case ARC
: wvalue
= ((arcptr
)setel
)->width
; break;
4826 case POLYGON
: wvalue
= ((polyptr
)setel
)->width
; break;
4827 case SPLINE
: wvalue
= ((splineptr
)setel
)->width
; break;
4828 case PATH
: wvalue
= ((pathptr
)setel
)->width
; break;
4830 if ((++numfound
) == 2) {
4831 listPtr
= Tcl_NewListObj(0, NULL
);
4832 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
4834 objPtr
= Tcl_NewDoubleObj(wvalue
);
4836 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
4841 objPtr
= Tcl_NewDoubleObj(areawin
->linewidth
);
4844 Tcl_SetObjResult(interp
, objPtr
);
4847 Tcl_SetObjResult(interp
, listPtr
);
4853 if ((objc
- i
) != 2) {
4854 Tcl_SetResult(interp
, "Error: no linewidth given.", NULL
);
4857 result
= Tcl_GetDoubleFromObj(interp
, objv
[++i
], &wvalue
);
4858 if (result
== TCL_OK
) {
4859 sprintf(_STR2
, "%f", wvalue
);
4860 setwwidth((Tk_Window
)clientData
, NULL
);
4863 Tcl_SetResult(interp
, "Error: invalid border linewidth.", NULL
);
4867 case SolidIdx
: value
= NORMAL
; mask
= DASHED
| DOTTED
| NOBORDER
; break;
4868 case DashedIdx
: value
= DASHED
; mask
= DASHED
| DOTTED
| NOBORDER
; break;
4869 case DottedIdx
: value
= DOTTED
; mask
= DASHED
| DOTTED
| NOBORDER
; break;
4870 case NoneIdx
: case UnborderedIdx
:
4871 value
= NOBORDER
; mask
= DASHED
| DOTTED
| NOBORDER
; break;
4872 case UnclosedIdx
: value
= UNCLOSED
; mask
= UNCLOSED
; break;
4873 case ClosedIdx
: value
= NORMAL
; mask
= UNCLOSED
; break;
4874 case SquareIdx
: value
= SQUARECAP
; mask
= SQUARECAP
; break;
4875 case RoundIdx
: value
= NORMAL
; mask
= SQUARECAP
; break;
4878 if ((objc
- i
) < 2) value
= BBOX
;
4880 char *yesno
= Tcl_GetString(objv
[++i
]);
4881 value
= (tolower(yesno
[0]) == 'y' || tolower(yesno
[0]) == 't') ?
4887 if ((objc
- i
) < 2) value
= CLIPMASK
;
4889 char *yesno
= Tcl_GetString(objv
[++i
]);
4890 value
= (tolower(yesno
[0]) == 'y' || tolower(yesno
[0]) == 't') ?
4895 if (idx
!= SetIdx
&& idx
!= GetIdx
)
4896 rval
= setelementstyle((Tk_Window
)clientData
, (u_short
)value
, mask
);
4899 return XcTagCallback(interp
, objc
, objv
);
4902 /*----------------------------------------------------------------------*/
4904 int xctcl_polygon(ClientData clientData
, Tcl_Interp
*interp
,
4905 int objc
, Tcl_Obj
*CONST objv
[])
4907 int idx
, nidx
, result
, npoints
, j
;
4908 polyptr newpoly
, ppoly
;
4911 Tcl_Obj
*objPtr
, *coord
, *cpair
, **newobjv
;
4912 Boolean is_box
= FALSE
;
4915 static char *subCmds
[] = {"make", "border", "fill", "points", "number", NULL
};
4917 MakeIdx
, BorderIdx
, FillIdx
, PointsIdx
, NumberIdx
4921 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, POLYGON
);
4922 if (result
!= TCL_OK
) return result
;
4924 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
4925 (CONST84
char **)subCmds
,
4926 "option", 0, &idx
)) != TCL_OK
)
4931 if ((areawin
->selects
== 0) && (nidx
== 1)) {
4933 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
4936 if (!strcmp(Tcl_GetString(objv
[2]), "box")) {
4939 if (npoints
!= 4 && npoints
!= 2) {
4940 Tcl_SetResult(interp
, "Box must have 2 or 4 points", NULL
);
4945 result
= Tcl_GetIntFromObj(interp
, objv
[2], &npoints
);
4946 if (result
!= TCL_OK
) return result
;
4948 if (objc
!= npoints
+ 3) {
4949 Tcl_WrongNumArgs(interp
, 1, objv
, "N {x1 y1}...{xN yN}");
4952 points
= (pointlist
)malloc(npoints
* sizeof(XPoint
));
4953 for (j
= 0; j
< npoints
; j
++) {
4954 result
= GetPositionFromList(interp
, objv
[3 + j
], &ppt
);
4955 if (result
== TCL_OK
) {
4956 points
[j
].x
= ppt
.x
;
4957 points
[j
].y
= ppt
.y
;
4960 if (is_box
&& (npoints
== 2)) {
4962 points
= (pointlist
)realloc(points
, npoints
* sizeof(XPoint
));
4963 points
[2].x
= points
[1].x
;
4964 points
[2].y
= points
[1].y
;
4965 points
[1].y
= points
[0].y
;
4966 points
[3].x
= points
[0].x
;
4967 points
[3].y
= points
[2].y
;
4969 newpoly
= new_polygon(NULL
, &points
, npoints
);
4970 if (!is_box
) newpoly
->style
|= UNCLOSED
;
4971 singlebbox((genericptr
*)&newpoly
);
4973 objPtr
= Tcl_NewHandleObj(newpoly
);
4974 Tcl_SetObjResult(interp
, objPtr
);
4976 else if (nidx
== 2) {
4977 Tcl_SetResult(interp
, "\"polygon <handle> make\" is illegal", NULL
);
4981 Tcl_SetResult(interp
, "No selections allowed", NULL
);
4987 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
4988 result
= xctcl_doborder(clientData
, interp
, objc
- nidx
, newobjv
);
4992 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
4993 result
= xctcl_dofill(clientData
, interp
, objc
- nidx
, newobjv
);
4997 if (areawin
->selects
!= 1) {
4998 Tcl_SetResult(interp
, "Must have exactly one selection to "
4999 "query points", NULL
);
5003 if (SELECTTYPE(areawin
->selectlist
) != POLYGON
) {
5004 Tcl_SetResult(interp
, "Selected element is not a polygon", NULL
);
5008 ppoly
= SELTOPOLY(areawin
->selectlist
);
5010 if ((objc
- nidx
) == 1) {
5011 objPtr
= Tcl_NewIntObj(ppoly
->number
);
5012 Tcl_SetObjResult(interp
, objPtr
);
5016 Tcl_SetResult(interp
, "Cannot change number of points.\n", NULL
);
5023 if (areawin
->selects
!= 1) {
5024 Tcl_SetResult(interp
, "Must have exactly one selection to "
5025 "query or manipulate points", NULL
);
5029 ppoly
= SELTOPOLY(areawin
->selectlist
);
5030 MakeHierCTM(&hierCTM
);
5031 if (ppoly
->type
!= POLYGON
) {
5032 Tcl_SetResult(interp
, "Selected element is not a polygon", NULL
);
5035 points
= ppoly
->points
;
5037 if ((objc
- nidx
) == 1) /* Return a list of all points */
5039 objPtr
= Tcl_NewListObj(0, NULL
);
5040 for (npoints
= 0; npoints
< ppoly
->number
; npoints
++) {
5041 cpair
= Tcl_NewListObj(0, NULL
);
5042 UTransformbyCTM(&hierCTM
, points
+ npoints
, &ppt
, 1);
5043 coord
= Tcl_NewIntObj((int)ppt
.x
);
5044 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5045 coord
= Tcl_NewIntObj((int)ppt
.y
);
5046 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5047 Tcl_ListObjAppendElement(interp
, objPtr
, cpair
);
5049 Tcl_SetObjResult(interp
, objPtr
);
5051 else if ((objc
- nidx
) == 2) /* Return a specific point */
5053 result
= Tcl_GetIntFromObj(interp
, objv
[2], &npoints
);
5054 if (result
!= TCL_OK
) return result
;
5055 if (npoints
>= ppoly
->number
) {
5056 Tcl_SetResult(interp
, "Point number out of range", NULL
);
5059 objPtr
= Tcl_NewListObj(0, NULL
);
5060 UTransformbyCTM(&hierCTM
, points
+ npoints
, &ppt
, 1);
5061 coord
= Tcl_NewIntObj((int)ppt
.x
);
5062 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5063 coord
= Tcl_NewIntObj((int)ppt
.y
);
5064 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5065 Tcl_SetObjResult(interp
, objPtr
);
5069 Tcl_SetResult(interp
, "Individual point setting unimplemented\n", NULL
);
5075 return XcTagCallback(interp
, objc
, objv
);
5078 /*----------------------------------------------------------------------*/
5080 int xctcl_spline(ClientData clientData
, Tcl_Interp
*interp
,
5081 int objc
, Tcl_Obj
*CONST objv
[])
5083 int idx
, nidx
, result
, j
, npoints
;
5084 splineptr newspline
, pspline
;
5085 XPoint ppt
, ctrlpoints
[4];
5086 Tcl_Obj
*objPtr
, *cpair
, *coord
, **newobjv
;
5089 static char *subCmds
[] = {"make", "border", "fill", "points", NULL
};
5091 MakeIdx
, BorderIdx
, FillIdx
, PointsIdx
5095 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, SPLINE
);
5096 if (result
!= TCL_OK
) return result
;
5098 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
5099 (CONST84
char **)subCmds
,
5100 "option", 0, &idx
)) != TCL_OK
)
5103 /* h = spline make {x1 y1} ... {x4 y4} */
5107 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5109 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
5112 for (j
= 0; j
< 4; j
++) {
5113 result
= GetPositionFromList(interp
, objv
[2 + j
], &ppt
);
5114 if (result
== TCL_OK
) {
5115 ctrlpoints
[j
].x
= ppt
.x
;
5116 ctrlpoints
[j
].y
= ppt
.y
;
5119 newspline
= new_spline(NULL
, ctrlpoints
);
5120 singlebbox((genericptr
*)&newspline
);
5122 objPtr
= Tcl_NewHandleObj(newspline
);
5123 Tcl_SetObjResult(interp
, objPtr
);
5125 else if (areawin
->selects
== 1) {
5126 if (ELEMENTTYPE(*(topobject
->plist
+ (*areawin
->selectlist
))) == POLYGON
) {
5130 Tcl_SetResult(interp
, "\"spline make\": must have a polygon selected",
5135 else if (nidx
== 2) {
5136 Tcl_SetResult(interp
, "\"spline <handle> make\" is illegal", NULL
);
5140 Tcl_SetResult(interp
, "No selections allowed except single polygon", NULL
);
5146 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5147 result
= xctcl_doborder(clientData
, interp
, objc
- nidx
, newobjv
);
5151 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5152 result
= xctcl_dofill(clientData
, interp
, objc
- nidx
, newobjv
);
5156 if (areawin
->selects
!= 1) {
5157 Tcl_SetResult(interp
, "Must have exactly one selection to "
5158 "query or manipulate points", NULL
);
5162 /* check for ESPLINE mode? */
5163 if (SELECTTYPE(areawin
->selectlist
) != SPLINE
) {
5164 Tcl_SetResult(interp
, "Selected element is not a spline", NULL
);
5168 pspline
= SELTOSPLINE(areawin
->selectlist
);
5170 MakeHierCTM(&hierCTM
);
5172 if ((objc
- nidx
) == 1) /* Return a list of all points */
5174 objPtr
= Tcl_NewListObj(0, NULL
);
5175 for (npoints
= 0; npoints
< 4; npoints
++) {
5176 cpair
= Tcl_NewListObj(0, NULL
);
5177 UTransformbyCTM(&hierCTM
, pspline
->ctrl
+ npoints
, &ppt
, 1);
5178 coord
= Tcl_NewIntObj((int)ppt
.x
);
5179 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5180 coord
= Tcl_NewIntObj((int)ppt
.y
);
5181 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5182 Tcl_ListObjAppendElement(interp
, objPtr
, cpair
);
5184 Tcl_SetObjResult(interp
, objPtr
);
5186 else if ((objc
- nidx
) == 2) /* Return a specific point */
5188 result
= Tcl_GetIntFromObj(interp
, objv
[objc
- nidx
+ 1], &npoints
);
5189 if (result
!= TCL_OK
) return result
;
5191 Tcl_SetResult(interp
, "Point number out of range", NULL
);
5194 objPtr
= Tcl_NewListObj(0, NULL
);
5195 UTransformbyCTM(&hierCTM
, pspline
->ctrl
+ npoints
, &ppt
, 1);
5196 coord
= Tcl_NewIntObj((int)ppt
.x
);
5197 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5198 coord
= Tcl_NewIntObj((int)ppt
.y
);
5199 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5200 Tcl_SetObjResult(interp
, objPtr
);
5204 Tcl_SetResult(interp
, "Individual control point setting "
5205 "unimplemented\n", NULL
);
5210 return XcTagCallback(interp
, objc
, objv
);
5213 /*----------------------------------------------------------------------*/
5215 int xctcl_graphic(ClientData clientData
, Tcl_Interp
*interp
,
5216 int objc
, Tcl_Obj
*CONST objv
[])
5218 int i
, idx
, nidx
, result
;
5220 graphicptr newgp
, gp
;
5222 Tcl_Obj
*objPtr
, *listPtr
;
5225 static char *subCmds
[] = {"make", "scale", "position", NULL
};
5227 MakeIdx
, ScaleIdx
, PositionIdx
5231 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, GRAPHIC
);
5232 if (result
!= TCL_OK
) return result
;
5234 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
5235 (CONST84
char **)subCmds
,
5236 "option", 0, &idx
)) != TCL_OK
)
5241 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5242 if ((objc
!= 5) && (objc
!= 7)) {
5243 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
5247 filename
= Tcl_GetString(objv
[2]);
5249 result
= GetPositionFromList(interp
, objv
[3], &ppt
);
5250 if (result
!= TCL_OK
) return result
;
5252 result
= Tcl_GetDoubleFromObj(interp
, objv
[4], &dvalue
);
5253 if (result
!= TCL_OK
) return result
;
5255 if (!strcmp(filename
, "gradient")) {
5258 result
= GetColorFromObj(interp
, objv
[5], &c1
, TRUE
);
5259 if (result
!= TCL_OK
) return result
;
5260 result
= GetColorFromObj(interp
, objv
[6], &c2
, TRUE
);
5261 if (result
!= TCL_OK
) return result
;
5262 newgp
= gradient_field(NULL
, ppt
.x
, ppt
.y
, c1
, c2
);
5265 newgp
= gradient_field(NULL
, ppt
.x
, ppt
.y
, 0, 1);
5267 else if (objc
!= 5) {
5268 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
5272 newgp
= new_graphic(NULL
, filename
, ppt
.x
, ppt
.y
);
5274 if (newgp
== NULL
) return TCL_ERROR
;
5276 newgp
->scale
= (float)dvalue
;
5277 singlebbox((genericptr
*)&newgp
);
5279 objPtr
= Tcl_NewHandleObj(newgp
);
5280 Tcl_SetObjResult(interp
, objPtr
);
5282 else if (nidx
== 2) {
5283 Tcl_SetResult(interp
, "\"graphic <handle> make\" is illegal", NULL
);
5287 Tcl_SetResult(interp
, "No selections allowed", NULL
);
5294 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5295 Tcl_SetResult(interp
, "Must have a graphic selection.", NULL
);
5298 if (objc
== nidx
+ 1) { /* Return position of graphic origin */
5302 listPtr
= Tcl_NewListObj(0, NULL
);
5303 for (i
= 0; i
< areawin
->selects
; i
++) {
5304 if (SELECTTYPE(areawin
->selectlist
+ i
) != GRAPHIC
) continue;
5305 gp
= SELTOGRAPHIC(areawin
->selectlist
+ i
);
5309 objPtr
= Tcl_NewDoubleObj(gp
->scale
);
5310 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5313 cpair
= Tcl_NewListObj(0, NULL
);
5314 objPtr
= Tcl_NewIntObj((int)gp
->position
.x
);
5315 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5316 objPtr
= Tcl_NewIntObj((int)gp
->position
.y
);
5317 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5318 Tcl_ListObjAppendElement(interp
, listPtr
, cpair
);
5322 Tcl_SetObjResult(interp
, listPtr
);
5324 else if (objc
== nidx
+ 2) { /* Change position or scale */
5325 if (idx
== ScaleIdx
) {
5326 result
= Tcl_GetDoubleFromObj(interp
, objv
[nidx
+ 1], &dvalue
);
5327 if (result
== TCL_OK
) {
5328 for (i
= 0; i
< areawin
->selects
; i
++) {
5331 if (SELECTTYPE(areawin
->selectlist
+ i
) != GRAPHIC
) continue;
5332 gp
= SELTOGRAPHIC(areawin
->selectlist
+ i
);
5333 oldscale
= gp
->scale
;
5334 gp
->scale
= (float)dvalue
;
5335 if (gp
->scale
!= oldscale
) {
5338 #endif /* !HAVE_CAIRO */
5339 drawarea(areawin
->area
, (caddr_t
)clientData
, (caddr_t
)NULL
);
5340 calcbboxvalues(areawin
->topinstance
,
5341 topobject
->plist
+ *(areawin
->selectlist
+ i
));
5342 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
5343 (genericptr
)gp
, (double)oldscale
);
5346 undo_finish_series();
5350 result
= GetPositionFromList(interp
, objv
[nidx
+ 1], &ppt
);
5351 if (result
== TCL_OK
) {
5352 for (i
= 0; i
< areawin
->selects
; i
++) {
5353 if (SELECTTYPE(areawin
->selectlist
+ i
) != GRAPHIC
) continue;
5354 gp
= SELTOGRAPHIC(areawin
->selectlist
+ i
);
5355 gp
->position
.x
= ppt
.x
;
5356 gp
->position
.y
= ppt
.y
;
5357 calcbboxvalues(areawin
->topinstance
,
5358 topobject
->plist
+ *(areawin
->selectlist
+ i
));
5362 updatepagebounds(topobject
);
5363 incr_changes(topobject
);
5367 return XcTagCallback(interp
, objc
, objv
);
5370 /*----------------------------------------------------------------------*/
5372 int xctcl_arc(ClientData clientData
, Tcl_Interp
*interp
,
5373 int objc
, Tcl_Obj
*CONST objv
[])
5375 int idx
, nidx
, result
, value
;
5379 Tcl_Obj
*objPtr
, *listPtr
, **newobjv
;
5381 static char *subCmds
[] = {"make", "border", "fill", "radius", "minor",
5382 "angle", "position", NULL
};
5384 MakeIdx
, BorderIdx
, FillIdx
, RadiusIdx
, MinorIdx
, AngleIdx
,
5389 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ARC
);
5390 if (result
!= TCL_OK
) return result
;
5392 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
5393 (CONST84
char **)subCmds
,
5394 "option", 0, &idx
)) != TCL_OK
)
5399 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5400 if ((objc
< 4) || (objc
> 7)) {
5401 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
5404 result
= GetPositionFromList(interp
, objv
[2], &ppt
);
5405 if (result
!= TCL_OK
) return result
;
5407 result
= Tcl_GetIntFromObj(interp
, objv
[3], &value
);
5408 if (result
!= TCL_OK
) return result
;
5410 newarc
= new_arc(NULL
, value
, ppt
.x
, ppt
.y
);
5414 result
= Tcl_GetDoubleFromObj(interp
, objv
[4], &angle
);
5415 if (result
== TCL_OK
) newarc
->angle1
= (float)angle
;
5416 result
= Tcl_GetDoubleFromObj(interp
, objv
[5], &angle
);
5417 if (result
== TCL_OK
) newarc
->angle2
= (float)angle
;
5420 result
= Tcl_GetDoubleFromObj(interp
, objv
[5], &angle
);
5421 if (result
== TCL_OK
) newarc
->angle1
= (float)angle
;
5422 result
= Tcl_GetDoubleFromObj(interp
, objv
[6], &angle
);
5423 if (result
== TCL_OK
) newarc
->angle2
= (float)angle
;
5425 result
= Tcl_GetIntFromObj(interp
, objv
[4], &value
);
5426 if (result
== TCL_OK
) newarc
->yaxis
= value
;
5430 /* Check that angle2 > angle1. Swap if necessary. */
5431 if (newarc
->angle2
< newarc
->angle1
) {
5432 int tmp
= newarc
->angle2
;
5433 newarc
->angle2
= newarc
->angle1
;
5434 newarc
->angle1
= tmp
;
5437 /* Check for 0 length chords (assume full circle was intended) */
5438 if (newarc
->angle1
== newarc
->angle2
) {
5439 Tcl_SetResult(interp
, "Changed zero-length arc chord!\n", NULL
);
5440 newarc
->angle2
= newarc
->angle1
+ 360;
5444 if (newarc
->angle1
>= 360) {
5445 newarc
->angle1
-= 360;
5446 newarc
->angle2
-= 360;
5448 else if (newarc
->angle2
<= 0) {
5449 newarc
->angle1
+= 360;
5450 newarc
->angle2
+= 360;
5455 singlebbox((genericptr
*)&newarc
);
5457 objPtr
= Tcl_NewHandleObj(newarc
);
5458 Tcl_SetObjResult(interp
, objPtr
);
5460 else if (nidx
== 2) {
5461 Tcl_SetResult(interp
, "\"arc <handle> make\" is illegal", NULL
);
5465 Tcl_SetResult(interp
, "No selections allowed", NULL
);
5471 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5472 result
= xctcl_doborder(clientData
, interp
, objc
- nidx
, newobjv
);
5476 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5477 result
= xctcl_dofill(clientData
, interp
, objc
- nidx
, newobjv
);
5484 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5485 Tcl_SetResult(interp
, "Must have an arc selection.", NULL
);
5488 if (objc
== nidx
+ 1) { /* Return position of arc center */
5493 listPtr
= Tcl_NewListObj(0, NULL
);
5494 for (i
= 0; i
< areawin
->selects
; i
++) {
5495 if (SELECTTYPE(areawin
->selectlist
+ i
) != ARC
) continue;
5496 parc
= SELTOARC(areawin
->selectlist
+ i
);
5500 objPtr
= Tcl_NewIntObj(parc
->radius
);
5501 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5504 objPtr
= Tcl_NewIntObj(parc
->yaxis
);
5505 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5508 cpair
= Tcl_NewListObj(0, NULL
);
5509 objPtr
= Tcl_NewDoubleObj(parc
->angle1
);
5510 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5511 objPtr
= Tcl_NewDoubleObj(parc
->angle2
);
5512 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5513 Tcl_ListObjAppendElement(interp
, listPtr
, cpair
);
5516 cpair
= Tcl_NewListObj(0, NULL
);
5517 objPtr
= Tcl_NewIntObj((int)parc
->position
.x
);
5518 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5519 objPtr
= Tcl_NewIntObj((int)parc
->position
.y
);
5520 Tcl_ListObjAppendElement(interp
, cpair
, objPtr
);
5521 Tcl_ListObjAppendElement(interp
, listPtr
, cpair
);
5525 Tcl_SetObjResult(interp
, listPtr
);
5529 return XcTagCallback(interp
, objc
, objv
);
5532 /*----------------------------------------------------------------------*/
5534 int xctcl_path(ClientData clientData
, Tcl_Interp
*interp
,
5535 int objc
, Tcl_Obj
*CONST objv
[])
5537 int idx
, nidx
, result
, j
, i
;
5538 genericptr newgen
, *eptr
;
5540 Tcl_Obj
*elist
, *objPtr
, *cpair
, *coord
, **newobjv
;
5544 static char *subCmds
[] = {"join", "make", "border", "fill", "point", "unjoin",
5547 JoinIdx
, MakeIdx
, BorderIdx
, FillIdx
, PointIdx
, UnJoinIdx
, PointsIdx
5551 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, PATH
);
5552 if (result
!= TCL_OK
) return result
;
5554 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
5555 (CONST84
char **)subCmds
,
5556 "option", 0, &idx
)) != TCL_OK
)
5560 case MakeIdx
: case JoinIdx
:
5561 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5562 /* h = path make {element_list} */
5563 newobjv
= (Tcl_Obj
**)(&objv
[1]);
5564 result
= ParseElementArguments(interp
, objc
- 1, newobjv
, NULL
,
5565 POLYGON
| ARC
| SPLINE
| PATH
);
5566 if (result
!= TCL_OK
) return result
;
5568 else if (nidx
== 2) {
5569 Tcl_SetResult(interp
, "\"path <handle> make\" is illegal", NULL
);
5574 newgen
= *(topobject
->plist
+ topobject
->parts
- 1);
5575 objPtr
= Tcl_NewHandleObj(newgen
);
5576 Tcl_SetObjResult(interp
, objPtr
);
5580 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5581 result
= xctcl_doborder(clientData
, interp
, objc
- nidx
, newobjv
);
5585 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
5586 result
= xctcl_dofill(clientData
, interp
, objc
- nidx
, newobjv
);
5590 Tcl_SetResult(interp
, "Unimplemented function.", NULL
);
5596 /* Would be nice to return the list of constituent elements. . . */
5600 /* Make a list of the polygon and spline elements in the path, */
5601 /* returning a nested list enumerating the points. This is */
5602 /* ad-hoc, as it does not match any other method of returning */
5603 /* point information about a part. This is because returning */
5604 /* a handle list is useless, since the handles cannot be */
5605 /* accessed directly. */
5607 if (areawin
->selects
!= 1) {
5608 Tcl_SetResult(interp
, "Must have exactly one selection to "
5609 "query parts", NULL
);
5613 if (SELECTTYPE(areawin
->selectlist
) != PATH
) {
5614 Tcl_SetResult(interp
, "Selected element is not a path", NULL
);
5618 ppath
= SELTOPATH(areawin
->selectlist
);
5620 MakeHierCTM(&hierCTM
);
5622 objPtr
= Tcl_NewListObj(0, NULL
);
5623 for (j
= 0; j
< ppath
->parts
; j
++) {
5624 eptr
= (genericptr
*)(ppath
->plist
+ j
);
5625 elist
= Tcl_NewListObj(0, NULL
);
5626 if ((*eptr
)->type
== POLYGON
) {
5628 ppoly
= (polyptr
)(*eptr
);
5629 Tcl_ListObjAppendElement(interp
, elist
,
5630 Tcl_NewStringObj("polygon", -1));
5631 for (i
= 0; i
< ppoly
->number
; i
++) {
5632 cpair
= Tcl_NewListObj(0, NULL
);
5633 UTransformbyCTM(&hierCTM
, ppoly
->points
+ i
, &ppt
, 1);
5634 coord
= Tcl_NewIntObj((int)ppt
.x
);
5635 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5636 coord
= Tcl_NewIntObj((int)ppt
.y
);
5637 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5638 Tcl_ListObjAppendElement(interp
, elist
, cpair
);
5643 pspline
= (splineptr
)(*eptr
);
5644 Tcl_ListObjAppendElement(interp
, elist
,
5645 Tcl_NewStringObj("spline", -1));
5646 for (i
= 0; i
< 4; i
++) {
5647 cpair
= Tcl_NewListObj(0, NULL
);
5648 UTransformbyCTM(&hierCTM
, pspline
->ctrl
+ i
, &ppt
, 1);
5649 coord
= Tcl_NewIntObj((int)ppt
.x
);
5650 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5651 coord
= Tcl_NewIntObj((int)ppt
.y
);
5652 Tcl_ListObjAppendElement(interp
, cpair
, coord
);
5653 Tcl_ListObjAppendElement(interp
, elist
, cpair
);
5656 Tcl_ListObjAppendElement(interp
, objPtr
, elist
);
5658 Tcl_SetObjResult(interp
, objPtr
);
5662 return XcTagCallback(interp
, objc
, objv
);
5665 /*----------------------------------------------------------------------*/
5667 int xctcl_instance(ClientData clientData
, Tcl_Interp
*interp
,
5668 int objc
, Tcl_Obj
*CONST objv
[])
5670 int i
, numfound
, idx
, nidx
, result
;
5672 objinstptr pinst
, newinst
;
5678 static char *subCmds
[] = {"make", "object", "scale", "center", "linewidth",
5681 MakeIdx
, ObjectIdx
, ScaleIdx
, CenterIdx
, LineWidthIdx
, BBoxIdx
5684 static char *lwsubCmds
[] = {"scale_variant", "variant", "scale_invariant",
5688 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, OBJINST
);
5689 if (result
!= TCL_OK
) return result
;
5691 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
],
5692 (CONST84
char **)subCmds
,
5693 "option", 0, &idx
)) != TCL_OK
)
5698 if ((areawin
->selects
== 0) && (nidx
== 1)) {
5700 pobj
= NameToObject(Tcl_GetString(objv
[2]), &pinst
, False
);
5702 Tcl_SetResult(interp
, "no such object", NULL
);
5705 newpos
= UGetCursorPos();
5707 newinst
= new_objinst(NULL
, pinst
, newpos
.x
, newpos
.y
);
5708 newinst
->color
= areawin
->color
;
5709 newselect
= allocselect();
5710 *newselect
= (short)(topobject
->parts
- 1);
5711 draw_normal_selected(topobject
, areawin
->topinstance
);
5712 eventmode
= COPY_MODE
;
5713 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
,
5714 (Tk_EventProc
*)xctk_drag
, NULL
);
5715 return XcTagCallback(interp
, objc
, objv
);
5717 else if (objc
!= 4) {
5718 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
5721 pobj
= NameToObject(Tcl_GetString(objv
[2]), &pinst
, False
);
5723 Tcl_SetResult(interp
, "no such object", NULL
);
5726 result
= GetPositionFromList(interp
, objv
[3], &newpos
);
5727 if (result
!= TCL_OK
) return result
;
5729 newinst
= new_objinst(NULL
, pinst
, newpos
.x
, newpos
.y
);
5730 newinst
->color
= areawin
->color
;
5731 singlebbox((genericptr
*)&newinst
);
5732 objPtr
= Tcl_NewHandleObj(newinst
);
5733 Tcl_SetObjResult(interp
, objPtr
);
5735 else if (nidx
== 2) {
5736 Tcl_SetResult(interp
, "\"instance <handle> make\" is illegal", NULL
);
5740 Tcl_SetResult(interp
, "No selections allowed.", NULL
);
5746 if ((objc
- nidx
) == 1) {
5749 for (i
= 0; i
< areawin
->selects
; i
++) {
5750 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5751 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5752 objPtr
= Tcl_NewStringObj(pinst
->thisobject
->name
, -1);
5754 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5755 if ((++numfound
) == 1)
5761 Tcl_SetResult(interp
, "Error: no object instances selected", NULL
);
5765 Tcl_SetObjResult(interp
, objPtr
);
5768 Tcl_SetObjResult(interp
, listPtr
);
5777 /* If the number of additional arguments matches the number */
5778 /* of selected items, or if there is one additional item */
5779 /* that is a list with a number of items equal to the */
5780 /* number of selected items, then change each element to */
5781 /* the corresponding object in the list. If there is only */
5782 /* one additional item, change all elements to that object. */
5784 if ((objc
- nidx
) == 1 + areawin
->selects
) {
5785 // Change each element in turn to the corresponding object
5786 // taken from the command arguments
5787 for (i
= 0; i
< areawin
->selects
; i
++) {
5788 pobj
= NameToObject(Tcl_GetString(objv
[2 + i
]), NULL
, FALSE
);
5790 Tcl_SetResult(interp
, "Name is not a known object", NULL
);
5793 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5794 pinst
->thisobject
= pobj
;
5795 calcbboxinst(pinst
);
5798 else if ((objc
- nidx
) == 2) {
5799 result
= Tcl_ListObjLength(interp
, objv
[2], &listlen
);
5800 if (result
!= TCL_OK
) return result
;
5802 // Check if the indicated object exists
5803 pobj
= NameToObject(Tcl_GetString(objv
[2]), NULL
, FALSE
);
5805 Tcl_SetResult(interp
, "Name is not a known object", NULL
);
5809 // Change all selected elements to the object specified
5810 for (i
= 0; i
< areawin
->selects
; i
++) {
5811 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5812 pinst
->thisobject
= pobj
;
5813 calcbboxinst(pinst
);
5816 else if (listlen
!= areawin
->selects
) {
5817 Tcl_SetResult(interp
, "Error: list length does not match"
5818 "the number of selected elements.", NULL
);
5822 // Change each element in turn to the corresponding object
5824 for (i
= 0; i
< areawin
->selects
; i
++) {
5825 result
= Tcl_ListObjIndex(interp
, objv
[2], i
, &listPtr
);
5826 if (result
!= TCL_OK
) return result
;
5828 pobj
= NameToObject(Tcl_GetString(listPtr
), NULL
, FALSE
);
5830 Tcl_SetResult(interp
, "Name is not a known object", NULL
);
5833 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5834 pinst
->thisobject
= pobj
;
5835 calcbboxinst(pinst
);
5839 drawarea(areawin
->area
, NULL
, NULL
);
5844 if ((objc
- nidx
) == 1) {
5847 for (i
= 0; i
< areawin
->selects
; i
++) {
5848 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5849 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5850 objPtr
= Tcl_NewDoubleObj(pinst
->scale
);
5852 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5853 if ((++numfound
) == 1)
5859 Tcl_SetResult(interp
, "Error: no object instances selected", NULL
);
5863 Tcl_SetObjResult(interp
, objPtr
);
5866 Tcl_SetObjResult(interp
, listPtr
);
5871 strcpy(_STR2
, Tcl_GetString(objv
[2]));
5872 setosize((Tk_Window
)clientData
, NULL
);
5878 if ((objc
- nidx
) == 1) {
5879 Tcl_Obj
*listPtr
, *coord
;
5881 for (i
= 0; i
< areawin
->selects
; i
++) {
5882 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5883 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5884 MakeHierCTM(&hierCTM
);
5885 objPtr
= Tcl_NewListObj(0, NULL
);
5886 UTransformbyCTM(&hierCTM
, &pinst
->position
, &ppt
, 1);
5887 coord
= Tcl_NewIntObj((int)ppt
.x
);
5888 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5889 coord
= Tcl_NewIntObj((int)ppt
.y
);
5890 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5892 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5893 if ((++numfound
) == 1)
5899 Tcl_SetResult(interp
, "Error: no object instances selected", NULL
);
5903 Tcl_SetObjResult(interp
, objPtr
);
5906 Tcl_SetObjResult(interp
, listPtr
);
5910 else if (((objc
- nidx
) == 2) && (areawin
->selects
== 1)) {
5911 result
= GetPositionFromList(interp
, objv
[objc
- 1], &newpos
);
5912 if (result
!= TCL_OK
) return result
;
5913 if (SELECTTYPE(areawin
->selectlist
) == OBJINST
) {
5914 pinst
= SELTOOBJINST(areawin
->selectlist
);
5915 MakeHierCTM(&hierCTM
);
5916 UTransformbyCTM(&hierCTM
, &newpos
, &pinst
->position
, 1);
5920 Tcl_SetResult(interp
, "Usage: instance center {x y}; only one"
5921 "instance should be selected.", NULL
);
5927 if ((objc
- nidx
) == 1) {
5930 for (i
= 0; i
< areawin
->selects
; i
++) {
5931 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5932 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5933 if (pinst
->style
& LINE_INVARIANT
)
5934 objPtr
= Tcl_NewStringObj("scale_invariant", -1);
5936 objPtr
= Tcl_NewStringObj("scale_variant", -1);
5938 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5939 if ((++numfound
) == 1)
5945 Tcl_SetResult(interp
, "Error: no object instances selected", NULL
);
5949 Tcl_SetObjResult(interp
, objPtr
);
5952 Tcl_SetObjResult(interp
, listPtr
);
5958 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[nidx
+ 1],
5959 (CONST84
char **)lwsubCmds
,
5960 "value", 0, &subidx
)) == TCL_OK
) {
5961 for (i
= 0; i
< areawin
->selects
; i
++) {
5962 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5963 pinst
= SELTOOBJINST(areawin
->selectlist
);
5965 pinst
->style
&= ~LINE_INVARIANT
;
5967 pinst
->style
|= LINE_INVARIANT
;
5975 if ((objc
- nidx
) == 1) {
5976 Tcl_Obj
*listPtr
, *coord
;
5978 for (i
= 0; i
< areawin
->selects
; i
++) {
5979 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
5980 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
5981 objPtr
= Tcl_NewListObj(0, NULL
);
5982 coord
= Tcl_NewIntObj((int)pinst
->bbox
.lowerleft
.x
);
5983 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5984 coord
= Tcl_NewIntObj((int)pinst
->bbox
.lowerleft
.y
);
5985 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5986 coord
= Tcl_NewIntObj((int)(pinst
->bbox
.lowerleft
.x
+
5987 pinst
->bbox
.width
));
5988 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5989 coord
= Tcl_NewIntObj((int)(pinst
->bbox
.lowerleft
.y
+
5990 pinst
->bbox
.height
));
5991 Tcl_ListObjAppendElement(interp
, objPtr
, coord
);
5993 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
5994 if ((++numfound
) == 1)
6000 Tcl_SetResult(interp
, "Error: no object instances selected", NULL
);
6004 Tcl_SetObjResult(interp
, objPtr
);
6007 Tcl_SetObjResult(interp
, listPtr
);
6012 /* e.g., "instance bbox recompute" */
6013 for (i
= 0; i
< areawin
->selects
; i
++) {
6014 if (SELECTTYPE(areawin
->selectlist
+ i
) == OBJINST
) {
6015 pinst
= SELTOOBJINST(areawin
->selectlist
+ i
);
6022 return XcTagCallback(interp
, objc
, objv
);
6025 /*----------------------------------------------------------------------*/
6026 /* "element" configures properties of elements. Note that if the */
6027 /* second argument is not an element handle (pointer), then operations */
6028 /* will be applied to all selected elements. If there is no element */
6029 /* handle and no objects are selected, the operation will be applied */
6030 /* to default settings, like the "xcircuit::set" command. */
6031 /*----------------------------------------------------------------------*/
6033 int xctcl_element(ClientData clientData
, Tcl_Interp
*interp
,
6034 int objc
, Tcl_Obj
*CONST objv
[])
6036 int result
, nidx
, idx
, i
, flags
;
6041 short *newselect
, *tempselect
, *orderlist
;
6044 static char *subCmds
[] = {
6045 "delete", "copy", "flip", "rotate", "edit", "select", "snap", "move",
6046 "color", "parameters", "raise", "lower", "exchange", "hide", "show",
6047 "handle", "deselect", NULL
6050 DeleteIdx
, CopyIdx
, FlipIdx
, RotateIdx
, EditIdx
, SelectIdx
, SnapIdx
,
6051 MoveIdx
, ColorIdx
, ParamIdx
, RaiseIdx
, LowerIdx
, ExchangeIdx
,
6052 HideIdx
, ShowIdx
, HandleIdx
, DeselectIdx
6055 static char *etypes
[] = {
6056 "Label", "Polygon", "Bezier Curve", "Object Instance", "Path",
6057 "Arc", "Graphic", NULL
/* (jdk) */
6060 /* Before doing a standard parse, we need to check for the single case */
6061 /* "element X deselect"; otherwise, calling ParseElementArguements() */
6062 /* is going to destroy the selection list. */
6064 if ((objc
== 3) && (!strcmp(Tcl_GetString(objv
[2]), "deselect"))) {
6065 result
= xctcl_deselect(clientData
, interp
, objc
, objv
);
6069 /* All other commands are dispatched to individual element commands */
6070 /* for the indicated element or for each selected element. */
6073 result
= ParseElementArguments(interp
, objc
, objv
, &nidx
, ALL_TYPES
);
6074 if (result
!= TCL_OK
) return result
;
6076 if ((objc
- nidx
) < 1) {
6077 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
6081 if (!strcmp(Tcl_GetString(objv
[nidx
]), "type")) {
6082 /* Return a list of types of the selected elements */
6084 if (areawin
->selects
> 1)
6085 listPtr
= Tcl_NewListObj(0, NULL
);
6087 for (i
= 0; i
< areawin
->selects
; i
++) {
6089 int idx2
, type
= SELECTTYPE(areawin
->selectlist
+ i
);
6091 case LABEL
: idx2
= 0; break;
6092 case POLYGON
: idx2
= 1; break;
6093 case SPLINE
: idx2
= 2; break;
6094 case OBJINST
: idx2
= 3; break;
6095 case PATH
: idx2
= 4; break;
6096 case ARC
: idx2
= 5; break;
6097 case GRAPHIC
: idx2
= 6; break;
6098 default: return TCL_ERROR
;
6100 objPtr
= Tcl_NewStringObj(etypes
[idx2
], strlen(etypes
[idx2
]));
6101 if (areawin
->selects
== 1) {
6102 Tcl_SetObjResult(interp
, objPtr
);
6106 Tcl_ListObjAppendElement(interp
, listPtr
, objPtr
);
6108 Tcl_SetObjResult(interp
, listPtr
);
6110 return XcTagCallback(interp
, objc
, objv
);
6112 else if (!strcmp(Tcl_GetString(objv
[nidx
]), "handle")) {
6113 /* Return a list of handles of the selected elements */
6115 listPtr
= SelectToTclList(interp
, areawin
->selectlist
, areawin
->selects
);
6116 Tcl_SetObjResult(interp
, listPtr
);
6117 return XcTagCallback(interp
, objc
, objv
);
6120 if (Tcl_GetIndexFromObj(interp
, objv
[nidx
],
6121 (CONST84
char **)subCmds
,
6122 "option", 0, &idx
) == TCL_OK
) {
6124 newobjv
= (Tcl_Obj
**)(&objv
[nidx
]);
6125 newobjc
= objc
- nidx
;
6127 /* Shift the argument list and call the indicated function. */
6131 result
= xctcl_delete(clientData
, interp
, newobjc
, newobjv
);
6134 result
= xctcl_copy(clientData
, interp
, newobjc
, newobjv
);
6137 result
= xctcl_flip(clientData
, interp
, newobjc
, newobjv
);
6140 result
= xctcl_rotate(clientData
, interp
, newobjc
, newobjv
);
6143 result
= xctcl_edit(clientData
, interp
, newobjc
, newobjv
);
6146 result
= xctcl_param(clientData
, interp
, newobjc
, newobjv
);
6149 for (i
= 0; i
< areawin
->selects
; i
++) {
6150 newselect
= areawin
->selectlist
+ i
;
6151 egen
= SELTOGENERIC(newselect
);
6152 egen
->type
|= DRAW_HIDE
;
6154 refresh(NULL
, NULL
, NULL
);
6158 if (!strcmp(Tcl_GetString(newobjv
[1]), "all")) {
6159 for (i
= 0; i
< topobject
->parts
; i
++) {
6160 egen
= *(topobject
->plist
+ i
);
6161 egen
->type
&= (~DRAW_HIDE
);
6166 for (i
= 0; i
< areawin
->selects
; i
++) {
6167 newselect
= areawin
->selectlist
+ i
;
6168 egen
= SELTOGENERIC(newselect
);
6169 egen
->type
&= (~DRAW_HIDE
);
6172 refresh(NULL
, NULL
, NULL
);
6176 if (!strncmp(Tcl_GetString(newobjv
[1]), "hide", 4)) {
6177 for (i
= 0; i
< areawin
->selects
; i
++) {
6178 newselect
= areawin
->selectlist
+ i
;
6179 egen
= SELTOGENERIC(newselect
);
6180 egen
->type
|= SELECT_HIDE
;
6183 else if (!strncmp(Tcl_GetString(newobjv
[1]), "allow", 5)) {
6184 for (i
= 0; i
< topobject
->parts
; i
++) {
6185 egen
= *(topobject
->plist
+ i
);
6186 egen
->type
&= (~SELECT_HIDE
);
6190 Tcl_SetResult(interp
, "Select options are \"hide\" "
6191 "and \"allow\"", NULL
);
6195 /* If nidx == 2, then we've already done the selection! */
6197 result
= xctcl_select(clientData
, interp
, newobjc
, newobjv
);
6202 /* case nidx == 2 was already taken care of. case nidx == 1 */
6203 /* implies "deselect all". */
6208 result
= xctcl_color(clientData
, interp
, newobjc
, newobjv
);
6218 /* Improved method thanks to Dimitri Princen */
6220 /* First move the selected parts to the bottom. This sets */
6221 /* all the values pointed by (selectlist + i) to zero, and */
6222 /* inverts the order between the selected elements. */
6223 /* Finally *tempselect += i inverts the original numbering, */
6224 /* so the second loop inverts the placing again, regaining */
6225 /* the correct order (and writes it so). */
6227 /* RaiseIdx works similar but starts from the top. */
6230 if (!strcmp(Tcl_GetString(newobjv
[1]), "all")) {
6231 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
6232 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
6234 for (i
= 0; i
< areawin
->selects
; i
++) {
6235 tempselect
= areawin
->selectlist
+ i
;
6236 xc_bottom(tempselect
, orderlist
);
6239 for (i
= 0; i
< areawin
->selects
; i
++) {
6240 tempselect
= areawin
->selectlist
+ i
;
6241 xc_bottom(tempselect
, orderlist
);
6242 *tempselect
+= (areawin
->selects
- 1 - i
);
6244 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
6245 orderlist
, topobject
->parts
);
6255 /* Improved method thanks to Dimitri Princen */
6258 if (!strcmp(Tcl_GetString(newobjv
[1]), "all")) {
6259 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
6260 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
6262 for (i
= areawin
->selects
- 1; i
>= 0 ; i
--) {
6263 tempselect
= areawin
->selectlist
+ i
;
6264 xc_top(tempselect
, orderlist
);
6265 *tempselect
-= (areawin
->selects
- 1 - i
);
6267 for (i
= areawin
->selects
- 1; i
>= 0 ; i
--) {
6268 tempselect
= areawin
->selectlist
+ i
;
6269 xc_top(tempselect
, orderlist
);
6272 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
6273 orderlist
, topobject
->parts
);
6282 result
= xctcl_move(clientData
, interp
, newobjc
, newobjv
);
6288 /* Call each individual element function. */
6289 /* Each function is responsible for filtering the select list to */
6290 /* choose only the appropriate elements. However, we first check */
6291 /* if at least one of that type exists in the list, so the function */
6292 /* won't return an error. */
6294 Tcl_ResetResult(interp
);
6296 newobjv
= (Tcl_Obj
**)(&objv
[nidx
- 1]);
6297 newobjc
= objc
- nidx
+ 1;
6300 for (i
= 0; i
< areawin
->selects
; i
++)
6301 flags
|= SELECTTYPE(areawin
->selectlist
+ i
);
6303 if (flags
& LABEL
) {
6304 result
= xctcl_label(clientData
, interp
, newobjc
, newobjv
);
6305 if (result
!= TCL_OK
) return result
;
6307 if (flags
& POLYGON
) {
6308 result
= xctcl_polygon(clientData
, interp
, newobjc
, newobjv
);
6309 if (result
!= TCL_OK
) return result
;
6311 if (flags
& OBJINST
) {
6312 result
= xctcl_instance(clientData
, interp
, newobjc
, newobjv
);
6313 if (result
!= TCL_OK
) return result
;
6315 if (flags
& SPLINE
) {
6316 result
= xctcl_spline(clientData
, interp
, newobjc
, newobjv
);
6317 if (result
!= TCL_OK
) return result
;
6320 result
= xctcl_path(clientData
, interp
, newobjc
, newobjv
);
6321 if (result
!= TCL_OK
) return result
;
6324 result
= xctcl_arc(clientData
, interp
, newobjc
, newobjv
);
6326 if (flags
& GRAPHIC
) {
6327 result
= xctcl_graphic(clientData
, interp
, newobjc
, newobjv
);
6332 /*----------------------------------------------------------------------*/
6333 /* "config" manipulates a whole bunch of option settings. */
6334 /*----------------------------------------------------------------------*/
6336 int xctcl_config(ClientData clientData
, Tcl_Interp
*interp
,
6337 int objc
, Tcl_Obj
*CONST objv
[])
6341 char *tmpstr
, buffer
[30], **sptr
;
6344 static char *boxsubCmds
[] = {"manhattan", "rhomboidx", "rhomboidy",
6345 "rhomboida", "normal", NULL
};
6346 static char *pathsubCmds
[] = {"tangents", "normal", NULL
};
6347 static char *coordsubCmds
[] = {"decimal inches", "fractional inches",
6348 "centimeters", "internal units", NULL
};
6349 static char *filterTypes
[] = {"instances", "labels", "polygons", "arcs",
6350 "splines", "paths", "graphics", NULL
};
6351 static char *searchOpts
[] = {"files", "lib", "libs", "library", "libraries", NULL
};
6353 static char *subCmds
[] = {
6354 "axis", "axes", "grid", "snap", "bbox", "editinplace",
6355 "pinpositions", "pinattach", "clipmasks", "boxedit", "pathedit", "linewidth",
6356 "colorscheme", "coordstyle", "drawingscale", "manhattan", "centering",
6357 "filter", "buschar", "backup", "search", "focus", "init",
6358 "delete", "windownames", "hold", "database", "suspend",
6359 "technologies", "fontnames", "debug", NULL
6362 AxisIdx
, AxesIdx
, GridIdx
, SnapIdx
, BBoxIdx
, EditInPlaceIdx
,
6363 PinPosIdx
, PinAttachIdx
, ShowClipIdx
, BoxEditIdx
, PathEditIdx
, LineWidthIdx
,
6364 ColorSchemeIdx
, CoordStyleIdx
, ScaleIdx
, ManhattanIdx
, CenteringIdx
,
6365 FilterIdx
, BusCharIdx
, BackupIdx
, SearchIdx
, FocusIdx
,
6366 InitIdx
, DeleteIdx
, WindowNamesIdx
, HoldIdx
, DatabaseIdx
,
6367 SuspendIdx
, TechnologysIdx
, FontNamesIdx
, DebugIdx
6370 if ((objc
== 1) || (objc
> 5)) {
6371 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
6374 if (Tcl_GetIndexFromObj(interp
, objv
[1],
6375 (CONST84
char **)subCmds
,
6376 "option", 0, &idx
) != TCL_OK
) {
6380 /* Set curpage for those routines that need it */
6388 if (areawin
== NULL
) {
6389 Tcl_SetResult(interp
, "No current window set, assuming default\n",
6391 curpage
= xobjs
.pagelist
[0];
6392 if (curpage
== NULL
) return TCL_ERROR
;
6395 curpage
= xobjs
.pagelist
[areawin
->page
];
6399 /* Check number of arguments wholesale (to be done) */
6404 switch (xobjs
.suspend
) {
6406 Tcl_SetResult(interp
, "normal drawing", NULL
);
6409 Tcl_SetResult(interp
, "drawing suspended", NULL
);
6412 Tcl_SetResult(interp
, "refresh pending", NULL
);
6415 Tcl_SetResult(interp
, "drawing locked", NULL
);
6420 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6421 if (result
!= TCL_OK
) return result
;
6424 /* Pending drawing */
6426 if (xobjs
.suspend
== 1) {
6428 refresh(NULL
, NULL
, NULL
);
6434 /* Calling "config suspend true" twice effectively */
6435 /* locks the graphics in a state that can only be */
6436 /* removed by a call to "config suspend false". */
6437 if (xobjs
.suspend
>= 0)
6446 /* Regenerate the database of colors, fonts, etc. from Tk options */
6448 Tk_Window tkwind
, tktop
;
6450 tktop
= Tk_MainWindow(interp
);
6451 tkwind
= Tk_NameToWindow(interp
, Tcl_GetString(objv
[2]), tktop
);
6452 build_app_database(tkwind
);
6453 setcolorscheme(!areawin
->invert
);
6458 /* To do: Return a list of known font names. The Tk wrapper uses */
6459 /* this list to regenerate the font menu for each new window. */
6462 case WindowNamesIdx
:
6463 /* Generate and return a list of existing window names */
6466 XCWindowData
*winptr
;
6467 for (winptr
= xobjs
.windowlist
; winptr
!= NULL
; winptr
= winptr
->next
)
6468 Tcl_AppendElement(interp
, Tk_PathName(winptr
->area
));
6474 XCWindowData
*winptr
;
6475 Tk_Window tkwind
, tktop
;
6477 tktop
= Tk_MainWindow(interp
);
6478 tkwind
= Tk_NameToWindow(interp
, Tcl_GetString(objv
[2]), tktop
);
6479 for (winptr
= xobjs
.windowlist
; winptr
!= NULL
; winptr
= winptr
->next
) {
6480 if (winptr
->area
== tkwind
) {
6481 delete_window(winptr
);
6485 if (winptr
== NULL
) {
6486 Tcl_SetResult(interp
, "No such window\n", NULL
);
6495 result
= Tcl_GetIntFromObj(interp
, objv
[2], &tmpint
);
6496 if (result
!= TCL_OK
) return result
;
6497 SetDebugLevel(&tmpint
);
6500 Tcl_SetObjResult(interp
, Tcl_NewIntObj(SetDebugLevel(NULL
)));
6507 /* Create a data structure for a new drawing window. */
6508 /* Give it the same page number and view as the current window */
6511 XCWindowData
*newwin
, *savewin
;
6512 savewin
= areawin
; // In case focus callback overwrites areawin.
6513 newwin
= GUI_init(objc
- 2, objv
+ 2);
6514 if (newwin
!= NULL
) {
6515 newwin
->page
= savewin
->page
;
6516 newwin
->vscale
= savewin
->vscale
;
6517 newwin
->pcorner
= savewin
->pcorner
;
6518 newwin
->topinstance
= savewin
->topinstance
;
6521 Tcl_SetResult(interp
, "Unable to create new window structure\n", NULL
);
6529 Tcl_SetResult(interp
, Tk_PathName(areawin
->area
), NULL
);
6531 else if (objc
== 3) {
6532 Tk_Window tkwind
, tktop
;
6533 XCWindowData
*winptr
;
6536 tktop
= Tk_MainWindow(interp
);
6537 tkwind
= Tk_NameToWindow(interp
, Tcl_GetString(objv
[2]), tktop
);
6539 /* printf("Focusing: %s\n", Tcl_GetString(objv[2])); */
6540 for (winptr
= xobjs
.windowlist
; winptr
!= NULL
; winptr
= winptr
->next
) {
6541 if (winptr
->area
== tkwind
) {
6543 objectptr savestack
;
6545 if (areawin
== winptr
) break;
6546 else if (areawin
== NULL
) {
6550 if ((eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
) &&
6551 winptr
->editstack
->parts
== 0) {
6552 locsave
= areawin
->save
;
6553 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
6554 /* Swap editstacks */
6555 savestack
= winptr
->editstack
;
6556 winptr
->editstack
= areawin
->editstack
;
6557 areawin
->editstack
= savestack
;
6558 savemode
= eventmode
;
6559 eventmode
= NORMAL_MODE
;
6561 /* Change event handlers */
6562 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6563 (xcEventHandler
)xctk_drag
, NULL
);
6564 drawarea(areawin
->area
, NULL
, NULL
);
6565 Tk_CreateEventHandler(winptr
->area
, PointerMotionMask
,
6566 (Tk_EventProc
*)xctk_drag
, NULL
);
6568 /* Set new window */
6570 eventmode
= savemode
;
6571 areawin
->save
= locsave
;
6573 drawarea(areawin
->area
, NULL
, NULL
);
6580 if (winptr
== NULL
) {
6581 Tcl_SetResult(interp
, "No such xcircuit drawing window\n", NULL
);
6586 Tcl_WrongNumArgs(interp
, 2, objv
, "[window]");
6591 case AxisIdx
: case AxesIdx
:
6593 Tcl_SetResult(interp
, (areawin
->axeson
) ? "true" : "false", NULL
);
6597 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6598 if (result
!= TCL_OK
) return result
;
6599 areawin
->axeson
= (Boolean
) tmpint
;
6605 Tcl_SetResult(interp
, (areawin
->gridon
) ? "true" : "false", NULL
);
6609 if (!strncmp("spac", Tcl_GetString(objv
[2]), 4)) {
6611 measurestr((float)curpage
->gridspace
, buffer
);
6612 Tcl_SetObjResult(interp
, Tcl_NewStringObj(buffer
, strlen(buffer
)));
6616 strcpy(_STR2
, Tcl_GetString(objv
[3]));
6617 setgrid(NULL
, &(curpage
->gridspace
));
6621 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6622 if (result
!= TCL_OK
) return result
;
6623 areawin
->gridon
= (Boolean
) tmpint
;
6630 Tcl_SetResult(interp
, (areawin
->snapto
) ? "true" : "false", NULL
);
6633 if (!strncmp("spac", Tcl_GetString(objv
[2]), 4)) {
6635 measurestr((float)curpage
->snapspace
, buffer
);
6636 Tcl_SetObjResult(interp
, Tcl_NewStringObj(buffer
, strlen(buffer
)));
6640 strcpy(_STR2
, Tcl_GetString(objv
[3]));
6641 setgrid(NULL
, &(curpage
->snapspace
));
6645 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6646 if (result
!= TCL_OK
) return result
;
6647 areawin
->snapto
= (Boolean
) tmpint
;
6654 switch (areawin
->boxedit
) {
6655 case MANHATTAN
: idx
= 0; break;
6656 case RHOMBOIDX
: idx
= 1; break;
6657 case RHOMBOIDY
: idx
= 2; break;
6658 case RHOMBOIDA
: idx
= 3; break;
6659 case NORMAL
: idx
= 4; break;
6661 Tcl_SetObjResult(interp
, Tcl_NewStringObj(boxsubCmds
[idx
],
6662 strlen(boxsubCmds
[idx
])));
6664 else if (objc
!= 3) {
6665 Tcl_WrongNumArgs(interp
, 2, objv
, "boxedit ?arg ...?");
6669 if (Tcl_GetIndexFromObj(interp
, objv
[2],
6670 (CONST84
char **)boxsubCmds
,
6671 "option", 0, &idx
) != TCL_OK
) {
6675 case 0: tmpint
= MANHATTAN
; break;
6676 case 1: tmpint
= RHOMBOIDX
; break;
6677 case 2: tmpint
= RHOMBOIDY
; break;
6678 case 3: tmpint
= RHOMBOIDA
; break;
6679 case 4: tmpint
= NORMAL
; break;
6681 areawin
->boxedit
= tmpint
;
6687 switch (areawin
->pathedit
) {
6688 case TANGENTS
: idx
= 0; break;
6689 case NORMAL
: idx
= 1; break;
6691 Tcl_SetObjResult(interp
, Tcl_NewStringObj(pathsubCmds
[idx
],
6692 strlen(pathsubCmds
[idx
])));
6694 else if (objc
!= 3) {
6695 Tcl_WrongNumArgs(interp
, 2, objv
, "pathedit ?arg ...?");
6699 if (Tcl_GetIndexFromObj(interp
, objv
[2],
6700 (CONST84
char **)pathsubCmds
,
6701 "option", 0, &idx
) != TCL_OK
) {
6705 case 0: tmpint
= TANGENTS
; break;
6706 case 1: tmpint
= NORMAL
; break;
6708 areawin
->pathedit
= tmpint
;
6714 Tcl_SetObjResult(interp
,
6715 Tcl_NewDoubleObj((double)curpage
->wirewidth
/ 2.0));
6717 else if (objc
!= 3) {
6718 Tcl_WrongNumArgs(interp
, 3, objv
, "linewidth");
6722 strcpy(_STR2
, Tcl_GetString(objv
[2]));
6723 setwidth(NULL
, &(curpage
->wirewidth
));
6729 Tcl_SetResult(interp
, (areawin
->bboxon
) ? "visible" : "invisible", NULL
);
6732 tmpstr
= Tcl_GetString(objv
[2]);
6733 if (strstr(tmpstr
, "visible"))
6734 tmpint
= (tmpstr
[0] == 'i') ? False
: True
;
6736 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6737 if (result
!= TCL_OK
) return result
;
6739 areawin
->bboxon
= (Boolean
) tmpint
;
6745 Tcl_SetResult(interp
, (xobjs
.hold
) ? "true" : "false", NULL
);
6748 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6749 if (result
!= TCL_OK
) return result
;
6750 xobjs
.hold
= (Boolean
) tmpint
;
6754 case EditInPlaceIdx
:
6756 Tcl_SetResult(interp
, (areawin
->editinplace
) ? "true" : "false", NULL
);
6759 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6760 if (result
!= TCL_OK
) return result
;
6761 areawin
->editinplace
= (Boolean
) tmpint
;
6767 Tcl_SetResult(interp
, (areawin
->showclipmasks
) ? "show" : "hide", NULL
);
6770 tmpstr
= Tcl_GetString(objv
[2]);
6771 if (!strcmp(tmpstr
, "show"))
6773 else if (!strcmp(tmpstr
, "hide"))
6776 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6777 if (result
!= TCL_OK
) return result
;
6779 areawin
->showclipmasks
= (Boolean
) tmpint
;
6785 Tcl_SetResult(interp
, (areawin
->pinpointon
) ? "visible" : "invisible", NULL
);
6788 tmpstr
= Tcl_GetString(objv
[2]);
6789 if (strstr(tmpstr
, "visible"))
6790 tmpint
= (tmpstr
[0] == 'i') ? False
: True
;
6792 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6793 if (result
!= TCL_OK
) return result
;
6795 areawin
->pinpointon
= (Boolean
) tmpint
;
6801 Tcl_SetResult(interp
, (areawin
->pinattach
) ? "true" : "false", NULL
);
6804 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6805 if (result
!= TCL_OK
) return result
;
6806 areawin
->pinattach
= (Boolean
) tmpint
;
6810 case ColorSchemeIdx
:
6812 Tcl_SetResult(interp
, (areawin
->invert
) ? "inverse" : "normal", NULL
);
6815 tmpstr
= Tcl_GetString(objv
[2]);
6816 if (!strcmp(tmpstr
, "normal") || !strcmp(tmpstr
, "standard"))
6818 else if (!strcmp(tmpstr
, "inverse") || !strcmp(tmpstr
, "alternate"))
6821 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6822 if (result
!= TCL_OK
) return result
;
6824 areawin
->invert
= (Boolean
) tmpint
;
6825 setcolorscheme(!areawin
->invert
);
6831 switch (curpage
->coordstyle
) {
6832 case DEC_INCH
: idx
= 0; break;
6833 case FRAC_INCH
: idx
= 1; break;
6834 case CM
: idx
= 2; break;
6835 case INTERNAL
: idx
= 3; break;
6837 Tcl_SetObjResult(interp
, Tcl_NewStringObj(coordsubCmds
[idx
],
6838 strlen(coordsubCmds
[idx
])));
6840 else if (objc
!= 3) {
6841 Tcl_WrongNumArgs(interp
, 2, objv
, "coordstyle ?arg ...?");
6845 if (Tcl_GetIndexFromObj(interp
, objv
[2],
6846 (CONST84
char **)coordsubCmds
,
6847 "option", 0, &idx
) != TCL_OK
) {
6851 case 0: tmpint
= DEC_INCH
; break;
6852 case 1: tmpint
= FRAC_INCH
; break;
6853 case 2: tmpint
= CM
; break;
6854 case 3: tmpint
= INTERNAL
; break;
6856 getgridtype(NULL
, tmpint
, NULL
);
6862 Tcl_Obj
*objPtr
= Tcl_NewListObj(0, NULL
);
6863 Tcl_ListObjAppendElement(interp
, objPtr
,
6864 Tcl_NewIntObj((int)curpage
->drawingscale
.x
));
6865 Tcl_ListObjAppendElement(interp
, objPtr
,
6866 Tcl_NewStringObj(":", 1));
6867 Tcl_ListObjAppendElement(interp
, objPtr
,
6868 Tcl_NewIntObj((int)curpage
->drawingscale
.y
));
6869 Tcl_SetObjResult(interp
, objPtr
);
6871 else if (objc
== 3) {
6872 strcpy(_STR2
, Tcl_GetString(objv
[2]));
6873 setdscale(NULL
, &(curpage
->drawingscale
));
6876 Tcl_WrongNumArgs(interp
, 2, objv
, "drawingscale ?arg ...?");
6881 case TechnologysIdx
:
6883 Tcl_SetResult(interp
, (xobjs
.showtech
) ? "true" : "false", NULL
);
6888 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6889 if (result
!= TCL_OK
) return result
;
6890 if (xobjs
.showtech
!= (Boolean
) tmpint
) {
6891 xobjs
.showtech
= (Boolean
) tmpint
;
6893 /* When namespaces are included, the length of the printed */
6894 /* name may cause names to overlap, so recompose each */
6895 /* library when the showtech flag is changed. */
6896 for (libnum
= 0; libnum
< xobjs
.numlibs
; libnum
++)
6897 composelib(LIBRARY
+ libnum
);
6899 if (eventmode
== CATALOG_MODE
) refresh(NULL
, NULL
, NULL
);
6906 Tcl_SetResult(interp
, (areawin
->manhatn
) ? "true" : "false", NULL
);
6909 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6910 if (result
!= TCL_OK
) return result
;
6911 areawin
->manhatn
= (Boolean
) tmpint
;
6917 Tcl_SetResult(interp
, (areawin
->center
) ? "true" : "false", NULL
);
6920 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6921 if (result
!= TCL_OK
) return result
;
6922 areawin
->center
= (Boolean
) tmpint
;
6928 for (i
= 0; i
< 6; i
++) {
6930 if (areawin
->filter
& tmpint
) {
6931 Tcl_AppendElement(interp
, filterTypes
[i
]);
6935 else if (objc
>= 3) {
6936 if (Tcl_GetIndexFromObj(interp
, objv
[2],
6937 (CONST84
char **)filterTypes
,
6938 "filter_type", 0, &tmpint
) != TCL_OK
) {
6942 if (areawin
->filter
& (1 << tmpint
))
6943 Tcl_SetResult(interp
, "true", NULL
);
6945 Tcl_SetResult(interp
, "false", NULL
);
6948 int ftype
= 1 << tmpint
;
6949 if (!strcmp(Tcl_GetString(objv
[3]), "true"))
6950 areawin
->filter
|= ftype
;
6952 areawin
->filter
&= (~ftype
);
6960 buffer
[1] = areawin
->buschar
;
6962 Tcl_SetResult(interp
, buffer
, TCL_VOLATILE
);
6964 else if (objc
== 3) {
6965 tmpstr
= Tcl_GetString(objv
[2]);
6966 areawin
->buschar
= (tmpstr
[0] == '\\') ? tmpstr
[1] : tmpstr
[0];
6972 Tcl_SetResult(interp
, (xobjs
.retain_backup
) ? "true" : "false", NULL
);
6975 result
= Tcl_GetBooleanFromObj(interp
, objv
[2], &tmpint
);
6976 if (result
!= TCL_OK
) return result
;
6977 xobjs
.retain_backup
= (Boolean
) tmpint
;
6983 Tcl_WrongNumArgs(interp
, 2, objv
, "search files|libraries ?arg ...?");
6986 if (Tcl_GetIndexFromObj(interp
, objv
[2],
6987 (CONST84
char **)searchOpts
, "options", 0, &idx
) != TCL_OK
) {
6990 sptr
= (idx
== 0) ? &xobjs
.filesearchpath
: &xobjs
.libsearchpath
;
6992 if (*sptr
!= NULL
) Tcl_SetResult(interp
, *sptr
, TCL_VOLATILE
);
6995 if (*sptr
!= NULL
) free(*sptr
);
6997 tmpstr
= Tcl_GetString(objv
[3]);
6998 if (strlen(tmpstr
) > 0)
6999 *sptr
= strdup(Tcl_GetString(objv
[3]));
7003 return XcTagCallback(interp
, objc
, objv
);
7006 /*----------------------------------------------------------------------*/
7008 int xctcl_promptsavepage(ClientData clientData
, Tcl_Interp
*interp
,
7009 int objc
, Tcl_Obj
*CONST objv
[])
7011 int page
= areawin
->page
;
7015 struct stat statbuf
;
7017 /* save page popup */
7020 Tcl_WrongNumArgs(interp
, 1, objv
, "[page_number]");
7023 else if (objc
== 2) {
7024 result
= Tcl_GetIntFromObj(interp
, objv
[1], &page
);
7025 if (result
!= TCL_OK
) return result
;
7027 else page
= areawin
->page
;
7029 curpage
= xobjs
.pagelist
[page
];
7030 if (curpage
->pageinst
== NULL
) {
7031 Tcl_SetResult(interp
, "Page does not exist. . . cannot save.", NULL
);
7034 pageobj
= curpage
->pageinst
->thisobject
;
7036 /* recompute bounding box and auto-scale, if set */
7038 calcbbox(xobjs
.pagelist
[page
]->pageinst
);
7039 if (curpage
->pmode
& 2) autoscale(page
);
7041 /* get file information, if filename is set */
7043 if (curpage
->filename
!= NULL
) {
7044 if (strstr(curpage
->filename
, ".") == NULL
)
7045 sprintf(_STR2
, "%s.ps", curpage
->filename
);
7046 else sprintf(_STR2
, "%s", curpage
->filename
);
7047 if (stat(_STR2
, &statbuf
) == 0) {
7048 Wprintf(" Warning: File exists");
7051 if (errno
== ENOTDIR
)
7052 Wprintf("Error: Incorrect pathname");
7053 else if (errno
== EACCES
)
7054 Wprintf("Error: Path not readable");
7059 Tcl_SetObjResult(interp
, Tcl_NewIntObj((int)page
));
7061 return XcTagCallback(interp
, objc
, objv
);
7064 /*----------------------------------------------------------------------*/
7066 int xctcl_quit(ClientData clientData
, Tcl_Interp
*interp
,
7067 int objc
, Tcl_Obj
*CONST objv
[])
7069 Boolean is_intr
= False
;
7071 /* quit, without checks */
7073 if (strncasecmp(Tcl_GetString(objv
[0]), "intr", 4))
7076 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
7080 quit(areawin
->area
, NULL
);
7082 if (consoleinterp
== interp
)
7083 Tcl_Exit(XcTagCallback(interp
, objc
, objv
));
7085 /* Ham-fisted, but prevents hanging on Ctrl-C kill */
7086 if (is_intr
) exit(1);
7087 Tcl_Eval(interp
, "catch {tkcon eval exit}\n");
7090 return TCL_OK
; /* Not reached */
7093 /*----------------------------------------------------------------------*/
7095 int xctcl_promptquit(ClientData clientData
, Tcl_Interp
*interp
,
7096 int objc
, Tcl_Obj
*CONST objv
[])
7100 /* quit, with checks */
7102 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
7105 if (areawin
!= NULL
) {
7106 result
= quitcheck(areawin
->area
, NULL
, NULL
);
7108 /* Immediate exit */
7109 if (consoleinterp
== interp
)
7110 Tcl_Exit(XcTagCallback(interp
, objc
, objv
));
7112 Tcl_Eval(interp
, "catch {tkcon eval exit}\n");
7115 return XcTagCallback(interp
, objc
, objv
);
7118 /*----------------------------------------------------------------------*/
7120 int xctcl_refresh(ClientData clientData
, Tcl_Interp
*interp
,
7121 int objc
, Tcl_Obj
*CONST objv
[])
7125 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
7128 areawin
->redraw_needed
= True
;
7129 drawarea(areawin
->area
, (caddr_t
)clientData
, (caddr_t
)NULL
);
7130 if (areawin
->scrollbarh
)
7131 drawhbar(areawin
->scrollbarh
, NULL
, NULL
);
7132 if (areawin
->scrollbarv
)
7133 drawvbar(areawin
->scrollbarv
, NULL
, NULL
);
7134 printname(topobject
);
7135 return XcTagCallback(interp
, objc
, objv
);
7138 /*----------------------------------------------------------------------*/
7139 /* Load a schematic that belongs to a symbol referenced by the current */
7140 /* schematic by loading the file pointed to by the "link" parameter */
7141 /* in the symbol. */
7143 /* Return 1 on success, 0 if the link has already been loaded, and -1 */
7144 /* on failure to find, open, or read the link's schematic. */
7145 /*----------------------------------------------------------------------*/
7147 int loadlinkfile(objinstptr tinst
, char *filename
, int target
, Boolean do_load
)
7151 char file_return
[150];
7155 /* Shorthand: "%n" can be used to indicate that the link filename is */
7156 /* the same as the name of the object, minus technology prefix. */
7157 /* While unlikely to be used, "%N" includes the technology prefix. */
7159 if (!strcmp(filename
, "%n")) {
7160 char *suffix
= strstr(tinst
->thisobject
->name
, "::");
7162 suffix
= tinst
->thisobject
->name
;
7165 strcpy(_STR
, suffix
);
7167 else if (!strcmp(filename
, "%N"))
7168 strcpy(_STR
, tinst
->thisobject
->name
);
7170 strcpy(_STR
, filename
);
7172 /* When loading links, we want to avoid */
7173 /* loading the same file more than once, so */
7174 /* compare filename against all existing */
7175 /* page filenames. Also compare links; any */
7176 /* page with a link to the same object is a */
7179 ps
= fileopen(_STR
, ".ps", file_return
, 149);
7187 for (j
= 0; j
< xobjs
.pages
; j
++) {
7188 if (xobjs
.pagelist
[j
]->filename
== NULL
)
7190 else if (!strcmp(file_return
, xobjs
.pagelist
[j
]->filename
))
7192 else if ((strlen(xobjs
.pagelist
[j
]->filename
) > 0) &&
7193 !strcmp(file_return
+ strlen(file_return
) - 3, ".ps")
7194 && !strncmp(xobjs
.pagelist
[j
]->filename
, file_return
,
7195 strlen(file_return
) - 3))
7197 else if ((xobjs
.pagelist
[j
]->pageinst
!= NULL
) && (tinst
->thisobject
==
7198 xobjs
.pagelist
[j
]->pageinst
->thisobject
->symschem
))
7201 if (j
< xobjs
.pages
) {
7203 /* Duplicate page. Don't load it, but make sure that an association */
7204 /* exists between the symbol and schematic. */
7206 if (tinst
->thisobject
->symschem
== NULL
) {
7207 tinst
->thisobject
->symschem
=
7208 xobjs
.pagelist
[j
]->pageinst
->thisobject
;
7209 if (xobjs
.pagelist
[j
]->pageinst
->thisobject
->symschem
== NULL
)
7210 xobjs
.pagelist
[j
]->pageinst
->thisobject
->symschem
= tinst
->thisobject
;
7215 if (fgood
== FALSE
) {
7216 Fprintf(stderr
, "Failed to open dependency \"%s\"\n", _STR
);
7220 /* Report that a pending link exists, but do not load it. */
7221 if (!do_load
) return 1;
7223 savepage
= areawin
->page
;
7224 while (areawin
->page
< xobjs
.pages
&&
7225 xobjs
.pagelist
[areawin
->page
]->pageinst
!= NULL
&&
7226 xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
->parts
> 0)
7229 changepage(areawin
->page
);
7230 result
= (loadfile(0, (target
>= 0) ? target
+ LIBRARY
: -1) == TRUE
) ? 1 : -1;
7232 /* Make symschem link if not done by loadfile() */
7234 if (tinst
->thisobject
->symschem
== NULL
) {
7235 tinst
->thisobject
->symschem
=
7236 xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
;
7238 /* Many symbols may link to one schematic, but a schematic can */
7239 /* only link to one symbol (the first one associated). */
7241 if (xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
->symschem
== NULL
)
7242 xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
->symschem
7243 = tinst
->thisobject
;
7245 changepage(savepage
);
7249 /*----------------------------------------------------------------------*/
7251 int xctcl_page(ClientData clientData
, Tcl_Interp
*interp
,
7252 int objc
, Tcl_Obj
*CONST objv
[])
7254 int result
, idx
, nidx
, aval
, i
, locidx
;
7255 int cpage
, multi
, savepage
, pageno
= -1, linktype
, importtype
;
7256 char *filename
, *froot
, *astr
;
7258 double newheight
, newwidth
, newscale
;
7260 int newrot
, newmode
;
7263 char *oldstr
, *newstr
, *key
, *argv
;
7264 Pagedata
*curpage
, *lpage
;
7268 Boolean forcepage
= FALSE
;
7271 "load", "list", "import", "save", "saveonly", "make", "directory",
7272 "reset", "links", "fit", "filename", "label", "scale", "width",
7273 "height", "size", "margins", "bbox", "goto", "orientation",
7274 "encapsulation", "handle", "update", "changes", NULL
7277 LoadIdx
, ListIdx
, ImportIdx
, SaveIdx
, SaveOnlyIdx
, MakeIdx
, DirIdx
,
7278 ResetIdx
, LinksIdx
, FitIdx
, FileIdx
, LabelIdx
, ScaleIdx
,
7279 WidthIdx
, HeightIdx
, SizeIdx
, MarginsIdx
, BBoxIdx
, GoToIdx
,
7280 OrientIdx
, EPSIdx
, HandleIdx
, UpdateIdx
, ChangesIdx
7283 char *importTypes
[] = {"xcircuit", "postscript", "background", "spice", NULL
};
7285 XCircuitIdx
, PostScriptIdx
, BackGroundIdx
, SPICEIdx
7288 char *linkTypes
[] = {"independent", "dependent", "total", "linked",
7289 "pagedependent", "all", "pending", "sheet", "load", NULL
};
7291 IndepIdx
, DepIdx
, TotalIdx
, LinkedIdx
, PageDepIdx
, AllIdx
, PendingIdx
,
7292 SheetIdx
, LinkLoadIdx
7294 char *psTypes
[] = {"eps", "full", NULL
};
7296 if (areawin
== NULL
) {
7297 Tcl_SetResult(interp
, "No database!", NULL
);
7300 savepage
= areawin
->page
;
7302 /* Check for option "-force" (create page if it doesn't exist) */
7303 if (!strncmp(Tcl_GetString(objv
[objc
- 1]), "-forc", 5)) {
7308 result
= ParsePageArguments(interp
, objc
, objv
, &nidx
, &pageno
);
7309 if ((result
!= TCL_OK
) || (nidx
< 0)) {
7310 if (forcepage
&& (pageno
== xobjs
.pages
)) {
7311 /* For now, allow a page to be created only if the page number */
7312 /* is one higher than the current last page. */
7313 Tcl_ResetResult(interp
);
7316 pageno
= areawin
->page
; /* so we don't get a segfault */
7321 else if (nidx
== 1 && objc
== 2) {
7324 else if (Tcl_GetIndexFromObj(interp
, objv
[1 + nidx
],
7325 (CONST84
char **)subCmds
, "option", 0, &idx
) != TCL_OK
) {
7331 curpage
= xobjs
.pagelist
[pageno
];
7333 if (curpage
->pageinst
!= NULL
)
7334 pageobj
= curpage
->pageinst
->thisobject
;
7336 if (idx
!= LoadIdx
&& idx
!= MakeIdx
&& idx
!= DirIdx
&& idx
!= GoToIdx
) {
7337 Tcl_SetResult(interp
, "Cannot do function on non-initialized page.", NULL
);
7344 /* return handle of page instance */
7345 objPtr
= Tcl_NewHandleObj(curpage
->pageinst
);
7346 Tcl_SetObjResult(interp
, objPtr
);
7351 resetbutton(NULL
, (pointertype
)(pageno
+ 1), NULL
);
7355 /* return a list of all non-empty pages */
7356 objPtr
= Tcl_NewListObj(0, NULL
);
7357 for (i
= 0; i
< xobjs
.pages
; i
++) {
7358 lpage
= xobjs
.pagelist
[i
];
7359 if ((lpage
!= NULL
) && (lpage
->pageinst
!= NULL
)) {
7360 Tcl_ListObjAppendElement(interp
, objPtr
, Tcl_NewIntObj(i
+ 1));
7363 Tcl_SetObjResult(interp
, objPtr
);
7368 sprintf(_STR2
, Tcl_GetString(objv
[2 + nidx
]));
7369 for (i
= 3 + nidx
; i
< objc
; i
++) {
7370 argv
= Tcl_GetString(objv
[i
]);
7371 if ((*argv
== '-') && !strncmp(argv
, "-repl", 5)) {
7373 char *techstr
= Tcl_GetString(objv
[i
+ 1]);
7374 if (!strcmp(techstr
, "all") || !strcmp(techstr
, "any"))
7376 else if (!strcmp(techstr
, "none")) TechReplaceNone();
7378 TechPtr nsptr
= LookupTechnology(techstr
);
7379 if (nsptr
!= NULL
) nsptr
->flags
|= TECH_REPLACE
;
7384 TechReplaceAll(); /* replace ALL */
7386 else if ((*argv
== '-') && !strncmp(argv
, "-targ", 5)) {
7388 ParseLibArguments(interp
, 2, &objv
[i
], NULL
, &target
);
7394 strcat(_STR2
, argv
);
7398 if (savepage
!= pageno
) newpage(pageno
);
7399 startloadfile((target
>= 0) ? target
+ LIBRARY
: -1);
7400 if (savepage
!= pageno
) newpage(savepage
);
7401 TechReplaceRestore();
7405 if ((objc
- nidx
) < 3) {
7406 Tcl_WrongNumArgs(interp
, 2, objv
, "option");
7410 if (Tcl_GetIndexFromObj(interp
, objv
[2 + nidx
],
7411 (CONST84
char **)importTypes
, "file type",
7412 0, &importtype
) != TCL_OK
)
7415 /* First check the number of arguments, which varies by option. */
7417 switch (importtype
) {
7419 /* Xcircuit imports may specify any number of files > 1. */
7422 if ((objc
- nidx
) == 3) {
7423 Tcl_SetResult(interp
, "Must specify a filename to import!", NULL
);
7428 /* Postscript imports may specify 1 or 0 files. 0 causes */
7429 /* the function to report back what file is the background. */
7433 if ((objc
- nidx
) != 3 && (objc
- nidx
) != 4) {
7434 Tcl_SetResult(interp
, "Can only specify one filename "
7435 "for background", NULL
);
7439 /* All other import types must specify exactly one filename. */
7442 if ((objc
- nidx
) != 4) {
7443 Tcl_SetResult(interp
, "Must specify one filename "
7444 "for import", NULL
);
7450 /* Now process the option */
7452 switch (importtype
) {
7454 sprintf(_STR2
, Tcl_GetString(objv
[3 + nidx
]));
7455 for (i
= 4; i
< objc
; i
++) {
7457 strcat(_STR2
, Tcl_GetString(objv
[i
+ nidx
]));
7459 if (savepage
!= pageno
) newpage(pageno
);
7461 if (savepage
!= pageno
) newpage(savepage
);
7463 case PostScriptIdx
: /* replaces "background" */
7465 if (objc
- nidx
== 2) {
7466 objPtr
= Tcl_NewStringObj(curpage
->background
.name
,
7467 strlen(curpage
->background
.name
));
7468 Tcl_SetObjResult(interp
, objPtr
);
7469 return XcTagCallback(interp
, objc
, objv
);
7471 sprintf(_STR2
, Tcl_GetString(objv
[3 + nidx
]));
7472 if (savepage
!= pageno
) newpage(pageno
);
7474 if (savepage
!= pageno
) newpage(savepage
);
7479 /* Make sure that the ASG library is present */
7481 if (NameToLibrary(ASG_SPICE_LIB
) < 0) {
7484 strcpy(_STR
, ASG_SPICE_LIB
);
7485 ilib
= createlibrary(FALSE
);
7486 if (loadlibrary(ilib
) == FALSE
) {
7487 Tcl_SetResult(interp
, "Error loading library.\n", NULL
);
7493 sprintf(_STR2
, Tcl_GetString(objv
[3 + nidx
]));
7494 if (savepage
!= pageno
) newpage(pageno
);
7496 if (savepage
!= pageno
) newpage(savepage
);
7498 Tcl_SetResult(interp
, "ASG not compiled in; "
7499 "function is unavailable.\n", NULL
);
7506 drawarea(areawin
->area
, NULL
, NULL
);
7511 Tcl_SetResult(interp
, "syntax is: \"page make [<name>]\"", NULL
);
7514 if (objc
!= 2 && objc
!= 3) {
7515 Tcl_WrongNumArgs(interp
, 2, objv
, "make [<name>]");
7518 newpage((short)255);
7520 curpage
= xobjs
.pagelist
[areawin
->page
];
7521 strcpy(curpage
->pageinst
->thisobject
->name
,
7522 Tcl_GetString(objv
[2]));
7524 updatepagelib(PAGELIB
, areawin
->page
);
7525 printname(topobject
);
7529 if (objc
- nidx
> 3) {
7530 Tcl_WrongNumArgs(interp
, 2, objv
, "[filename]");
7533 else if (objc
- nidx
== 3) {
7534 filename
= Tcl_GetString(objv
[nidx
+ 2]);
7535 if (strcmp(filename
, curpage
->filename
)) {
7536 Wprintf("Warning: Filename is \"%s\" but will be "
7537 "saved as \"%s\"\n", curpage
->filename
, filename
);
7540 else if (curpage
->filename
== NULL
) {
7541 Fprintf(stderr
, "Warning: Filename created to match object name\n");
7542 filename
= curpage
->pageinst
->thisobject
->name
;
7545 filename
= curpage
->filename
;
7547 if (savepage
!= pageno
) newpage(pageno
);
7548 if (!strncmp(Tcl_GetString(objv
[nidx
+ 1]), "saveo", 5))
7549 setfile(filename
, NO_SUBCIRCUITS
);
7551 setfile(filename
, CURRENT_PAGE
);
7552 if (savepage
!= pageno
) newpage(savepage
);
7556 if ((objc
- nidx
) < 2 && (objc
- nidx
) > 6) {
7557 Tcl_WrongNumArgs(interp
, 1, objv
, "links");
7560 if ((objc
- nidx
) == 2)
7561 linktype
= TOTAL_PAGES
;
7563 if (Tcl_GetIndexFromObj(interp
, objv
[2 + nidx
],
7564 (CONST84
char **)linkTypes
,
7565 "link type", 0, &linktype
) != TCL_OK
)
7569 pagelist
= pagetotals(pageno
, (linktype
>= PendingIdx
) ?
7570 LINKED_PAGES
: linktype
);
7574 /* Load any pending links, that is, objects that have a */
7575 /* "link" parameter containing a string indicating a file */
7576 /* defining the schematic for that symbol. Allow the use */
7577 /* of the same "-replace" flag used by "page load". */
7581 argv
= Tcl_GetString(objv
[locidx
]);
7582 if (*argv
!= '-') argv
= Tcl_GetString(objv
[--locidx
]);
7583 if ((*argv
== '-') && !strncmp(argv
, "-repl", 5)) {
7584 if (locidx
< objc
- 1) {
7585 char *techstr
= Tcl_GetString(objv
[locidx
+ 1]);
7586 if (!strcmp(techstr
, "all")) TechReplaceAll();
7587 else if (!strcmp(techstr
, "none")) TechReplaceNone();
7589 TechPtr nsptr
= LookupTechnology(techstr
);
7591 nsptr
->flags
|= TECH_REPLACE
;
7596 TechReplaceAll(); /* replace ALL */
7599 if ((*argv
== '-') && !strncmp(argv
, "-targ", 5)) {
7600 if (locidx
< objc
- 1) {
7601 ParseLibArguments(interp
, 2, &objv
[locidx
], NULL
, &target
);
7609 key
= ((objc
- nidx
) == 4) ? Tcl_GetString(objv
[3 + nidx
]) : "link";
7610 for (i
= 0; i
< xobjs
.pages
; i
++) {
7611 if (pagelist
[i
] > 0) {
7613 objectptr tpage
= xobjs
.pagelist
[i
]->pageinst
->thisobject
;
7616 for (tgen
= tpage
->plist
; tgen
< tpage
->plist
7617 + tpage
->parts
; tgen
++) {
7618 if ((*tgen
)->type
== OBJINST
) {
7619 tinst
= TOOBJINST(tgen
);
7620 /* Corrected 8/31/07: Instance value of "link" has */
7621 /* priority over any default value in the object! */
7622 ops
= find_param(tinst
, key
);
7623 if ((ops
!= NULL
) && (ops
->type
== XC_STRING
)) {
7624 filename
= textprint(ops
->parameter
.string
, tinst
);
7625 if (strlen(filename
) > 0) {
7626 if ((result
= loadlinkfile(tinst
, filename
, target
,
7627 (linktype
== LinkLoadIdx
))) > 0) {
7629 setsymschem(); /* Update GUI */
7632 else if (result
< 0) {
7633 Tcl_SetResult(interp
, "Cannot load link", NULL
);
7636 else result
= TCL_OK
;
7646 for (i
= 0; i
< xobjs
.pages
; i
++) {
7647 if (pagelist
[i
] > 0) {
7649 if ((linktype
== SheetIdx
) && (i
== pageno
) && (pagelist
[i
] > 0))
7655 TechReplaceRestore();
7656 free((char *)pagelist
);
7657 if (result
== TCL_ERROR
) return result
;
7658 Tcl_SetObjResult(interp
, Tcl_NewIntObj(multi
));
7662 startcatalog(NULL
, PAGELIB
, NULL
);
7666 newpage((short)pageno
);
7670 calcbbox(curpage
->pageinst
);
7671 if (curpage
->pmode
& 2) autoscale(pageno
);
7675 if (((objc
- nidx
) == 2) || ((objc
- nidx
) == 3)) {
7680 bbox
= &curpage
->pageinst
->bbox
;
7682 bbox
= &curpage
->pageinst
->thisobject
->bbox
;
7685 if ((objc
- nidx
) == 3) {
7686 sbbox
= curpage
->pageinst
->schembbox
;
7687 if (sbbox
== NULL
) sbbox
= bbox
;
7690 objPtr
= Tcl_NewListObj(0, NULL
);
7692 tuple
= Tcl_NewListObj(0, NULL
);
7693 value
= min(sbbox
->lowerleft
.x
, bbox
->lowerleft
.x
);
7694 Tcl_ListObjAppendElement(interp
, tuple
, Tcl_NewIntObj(value
));
7695 value
= min(sbbox
->lowerleft
.y
, bbox
->lowerleft
.y
);
7696 Tcl_ListObjAppendElement(interp
, tuple
, Tcl_NewIntObj(value
));
7697 Tcl_ListObjAppendElement(interp
, objPtr
, tuple
);
7699 tuple
= Tcl_NewListObj(0, NULL
);
7700 value
= max(sbbox
->lowerleft
.x
+ sbbox
->width
,
7701 bbox
->lowerleft
.x
+ bbox
->width
);
7702 Tcl_ListObjAppendElement(interp
, tuple
, Tcl_NewIntObj(value
));
7703 value
= max(sbbox
->lowerleft
.y
+ sbbox
->height
,
7704 bbox
->lowerleft
.y
+ bbox
->height
);
7705 Tcl_ListObjAppendElement(interp
, tuple
, Tcl_NewIntObj(value
));
7706 Tcl_ListObjAppendElement(interp
, objPtr
, tuple
);
7708 Tcl_SetObjResult(interp
, objPtr
);
7709 return XcTagCallback(interp
, objc
, objv
);
7712 Tcl_WrongNumArgs(interp
, 1, objv
, "bbox [all]");
7718 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7719 Tcl_WrongNumArgs(interp
, 1, objv
, "size ?\"width x height\"?");
7722 if ((objc
- nidx
) == 2) {
7723 float xsize
, ysize
, cfact
;
7725 objPtr
= Tcl_NewListObj(0, NULL
);
7727 cfact
= (curpage
->coordstyle
== CM
) ? IN_CM_CONVERT
7729 xsize
= (float)curpage
->pagesize
.x
/ cfact
;
7730 ysize
= (float)curpage
->pagesize
.y
/ cfact
;
7732 Tcl_ListObjAppendElement(interp
, objPtr
,
7733 Tcl_NewDoubleObj((double)xsize
));
7734 Tcl_ListObjAppendElement(interp
, objPtr
,
7735 Tcl_NewStringObj("x", 1));
7736 Tcl_ListObjAppendElement(interp
, objPtr
,
7737 Tcl_NewDoubleObj((double)ysize
));
7738 Tcl_ListObjAppendElement(interp
, objPtr
,
7739 Tcl_NewStringObj(((curpage
->coordstyle
== CM
) ?
7741 Tcl_SetObjResult(interp
, objPtr
);
7743 return XcTagCallback(interp
, objc
, objv
);
7746 strcpy(_STR2
, Tcl_GetString(objv
[2 + nidx
]));
7747 setoutputpagesize(&curpage
->pagesize
);
7749 /* Only need to recompute values and refresh if autoscaling is enabled */
7750 if (curpage
->pmode
& 2) autoscale(pageno
);
7754 if ((objc
- nidx
) < 2 && (objc
- nidx
) > 4) {
7755 Tcl_WrongNumArgs(interp
, 1, objv
, "margins ?x y?");
7758 if ((objc
- nidx
) == 2) {
7759 newwidth
= (double)curpage
->margins
.x
/ 72.0;
7760 newheight
= (double)curpage
->margins
.y
/ 72.0;
7761 objPtr
= Tcl_NewListObj(0, NULL
);
7762 Tcl_ListObjAppendElement(interp
, objPtr
,
7763 Tcl_NewDoubleObj(newwidth
));
7764 Tcl_ListObjAppendElement(interp
, objPtr
,
7765 Tcl_NewDoubleObj(newheight
));
7766 Tcl_SetObjResult(interp
, objPtr
);
7767 return XcTagCallback(interp
, objc
, objv
);
7769 newwidth
= (double)parseunits(Tcl_GetString(objv
[2 + nidx
]));
7770 if ((objc
- nidx
) == 4)
7771 newheight
= (double)parseunits(Tcl_GetString(objv
[3 + nidx
]));
7773 newheight
= newwidth
;
7777 curpage
->margins
.x
= (int)newwidth
;
7778 curpage
->margins
.y
= (int)newheight
;
7782 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7783 Tcl_WrongNumArgs(interp
, 1, objv
, "height ?output_height?");
7786 if ((objc
- nidx
) == 2) {
7787 newheight
= toplevelheight(curpage
->pageinst
, NULL
);
7788 newheight
*= getpsscale(curpage
->outscale
, pageno
);
7789 newheight
/= (curpage
->coordstyle
== CM
) ? IN_CM_CONVERT
: 72.0;
7790 objPtr
= Tcl_NewDoubleObj((double)newheight
);
7791 Tcl_SetObjResult(interp
, objPtr
);
7792 return XcTagCallback(interp
, objc
, objv
);
7794 newheight
= (double)parseunits(Tcl_GetString(objv
[2 + nidx
]));
7795 if (newheight
<= 0 || topobject
->bbox
.height
== 0) {
7796 Tcl_SetResult(interp
, "Illegal height value", NULL
);
7799 newheight
= (newheight
* ((curpage
->coordstyle
== CM
) ?
7800 IN_CM_CONVERT
: 72.0)) / topobject
->bbox
.height
;
7801 newheight
/= getpsscale(1.0, pageno
);
7802 curpage
->outscale
= (float)newheight
;
7804 if (curpage
->pmode
& 2) autoscale(pageno
);
7808 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7809 Tcl_WrongNumArgs(interp
, 1, objv
, "output_width");
7812 if ((objc
- nidx
) == 2) {
7813 newwidth
= toplevelwidth(curpage
->pageinst
, NULL
);
7814 newwidth
*= getpsscale(curpage
->outscale
, pageno
);
7815 newwidth
/= (curpage
->coordstyle
== CM
) ? IN_CM_CONVERT
: 72.0;
7816 objPtr
= Tcl_NewDoubleObj((double)newwidth
);
7817 Tcl_SetObjResult(interp
, objPtr
);
7818 return XcTagCallback(interp
, objc
, objv
);
7820 newwidth
= (double)parseunits(Tcl_GetString(objv
[2 + nidx
]));
7821 if (newwidth
<= 0 || topobject
->bbox
.width
== 0) {
7822 Tcl_SetResult(interp
, "Illegal width value", NULL
);
7826 newwidth
= (newwidth
* ((curpage
->coordstyle
== CM
) ?
7827 IN_CM_CONVERT
: 72.0)) / topobject
->bbox
.width
;
7828 newwidth
/= getpsscale(1.0, pageno
);
7829 curpage
->outscale
= (float)newwidth
;
7831 if (curpage
->pmode
& 2) autoscale(pageno
);
7835 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7836 Tcl_WrongNumArgs(interp
, 1, objv
, "output_scale");
7839 if ((objc
- nidx
) == 2) {
7840 objPtr
= Tcl_NewDoubleObj((double)curpage
->outscale
);
7841 Tcl_SetObjResult(interp
, objPtr
);
7842 return XcTagCallback(interp
, objc
, objv
);
7844 result
= Tcl_GetDoubleFromObj(interp
, objv
[2 + nidx
], &newscale
);
7845 if (result
!= TCL_OK
) return result
;
7847 oldscale
= curpage
->outscale
;
7849 if (oldscale
== (float)newscale
) return TCL_OK
; /* nothing to do */
7850 else curpage
->outscale
= (float)newscale
;
7852 if (curpage
->pmode
& 2) autoscale(pageno
);
7856 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7857 Tcl_WrongNumArgs(interp
, 1, objv
, "orientation");
7860 if ((objc
- nidx
) == 2) {
7861 objPtr
= Tcl_NewIntObj((int)curpage
->orient
);
7862 Tcl_SetObjResult(interp
, objPtr
);
7863 return XcTagCallback(interp
, objc
, objv
);
7865 result
= Tcl_GetIntFromObj(interp
, objv
[2 + nidx
], &newrot
);
7866 if (result
!= TCL_OK
) return result
;
7867 curpage
->orient
= (short)newrot
;
7869 /* rescale after rotation if "auto-scale" is set */
7870 if (curpage
->pmode
& 2) autoscale(pageno
);
7874 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7875 Tcl_WrongNumArgs(interp
, 1, objv
, "encapsulation");
7878 if ((objc
- nidx
) == 2) {
7879 newstr
= psTypes
[curpage
->pmode
& 1];
7880 Tcl_SetResult(interp
, newstr
, NULL
);
7881 return XcTagCallback(interp
, objc
, objv
);
7883 newstr
= Tcl_GetString(objv
[2 + nidx
]);
7884 if (Tcl_GetIndexFromObj(interp
, objv
[2 + nidx
],
7885 (CONST84
char **)psTypes
,
7886 "encapsulation", 0, &newmode
) != TCL_OK
) {
7889 curpage
->pmode
&= 0x2; /* preserve auto-fit flag */
7890 curpage
->pmode
|= (short)newmode
;
7894 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7895 Tcl_WrongNumArgs(interp
, 1, objv
, "label ?name?");
7898 if ((objc
- nidx
) == 2) {
7899 objPtr
= Tcl_NewStringObj(pageobj
->name
, strlen(pageobj
->name
));
7900 Tcl_SetObjResult(interp
, objPtr
);
7901 return XcTagCallback(interp
, objc
, objv
);
7904 /* Whitespace and non-printing characters not allowed */
7906 strcpy(_STR2
, Tcl_GetString(objv
[2 + nidx
]));
7907 for (i
= 0; i
< strlen(_STR2
); i
++) {
7908 if ((!isprint(_STR2
[i
])) || (isspace(_STR2
[i
]))) {
7910 Wprintf("Replaced illegal whitespace in name with underscore");
7914 if (!strcmp(pageobj
->name
, _STR2
)) return TCL_OK
; /* no change in string */
7915 if (strlen(_STR2
) == 0)
7916 sprintf(pageobj
->name
, "Page %d", areawin
->page
+ 1);
7918 sprintf(pageobj
->name
, "%.79s", _STR2
);
7920 /* For schematics, all pages with associations to symbols must have */
7922 if (pageobj
->symschem
!= NULL
) checkpagename(pageobj
);
7924 if (pageobj
== topobject
) printname(pageobj
);
7930 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
7931 Tcl_WrongNumArgs(interp
, 1, objv
, "filename ?name?");
7935 oldstr
= curpage
->filename
;
7937 if ((objc
- nidx
) == 2) {
7939 objPtr
= Tcl_NewStringObj(oldstr
, strlen(oldstr
));
7941 objPtr
= Tcl_NewListObj(0, NULL
); /* NULL list */
7942 Tcl_SetObjResult(interp
, objPtr
);
7943 return XcTagCallback(interp
, objc
, objv
);
7946 newstr
= Tcl_GetString(objv
[2 + nidx
]);
7947 if (strlen(newstr
) > 0) {
7948 froot
= strrchr(newstr
, '/');
7949 if (froot
== NULL
) froot
= newstr
;
7950 if (strchr(froot
, '.') == NULL
) {
7951 astr
= malloc(strlen(newstr
) + 4);
7952 sprintf(astr
, "%s.ps", newstr
);
7957 if (oldstr
&& (!strcmp(oldstr
, newstr
))) { /* no change in string */
7958 if (newstr
== astr
) free(astr
);
7959 return XcTagCallback(interp
, objc
, objv
);
7962 if (strlen(newstr
) == 0) { /* empty string */
7963 Tcl_SetResult(interp
, "Warning: No filename!", NULL
);
7967 multi
= pagelinks(pageno
); /* Are there multiple pages? */
7970 /* Make the change to the current page */
7971 curpage
->filename
= strdup(newstr
);
7972 if (newstr
== astr
) free(astr
);
7974 /* All existing filenames which match the old string should */
7975 /* also be changed unless the filename has been set to the */
7976 /* null string, which unlinks the page. */
7978 if ((strlen(curpage
->filename
) > 0) && (multi
> 1)) {
7979 for (cpage
= 0; cpage
< xobjs
.pages
; cpage
++) {
7980 lpage
= xobjs
.pagelist
[cpage
];
7981 if ((lpage
->pageinst
!= NULL
) && (cpage
!= pageno
)) {
7982 if (lpage
->filename
&& (!filecmp(lpage
->filename
, oldstr
))) {
7983 free(lpage
->filename
);
7984 lpage
->filename
= strdup(newstr
);
7992 /* Run pagelinks again; this checks if a page has been attached */
7993 /* to existing schematics by being renamed to match. */
7995 if ((strlen(curpage
->filename
) > 0) && (multi
<= 1)) {
7996 for (cpage
= 0; cpage
< xobjs
.pages
; cpage
++) {
7997 lpage
= xobjs
.pagelist
[cpage
];
7998 if ((lpage
->pageinst
!= NULL
) && (cpage
!= pageno
)) {
7999 if (lpage
->filename
&& (!filecmp(lpage
->filename
,
8000 curpage
->filename
))) {
8001 free(curpage
->filename
);
8002 curpage
->filename
= strdup(lpage
->filename
);
8011 if ((objc
- nidx
) > 3) {
8012 Tcl_WrongNumArgs(interp
, 1, objv
, "fit ?true|false?");
8015 else if ((objc
- nidx
) == 3) {
8016 result
= Tcl_GetBooleanFromObj(interp
, objv
[2 + nidx
], &aval
);
8017 if (result
!= TCL_OK
) return result
;
8019 curpage
->pmode
|= 2;
8021 curpage
->pmode
&= 1;
8024 Tcl_SetResult(interp
, ((curpage
->pmode
& 2) > 0) ? "true" : "false", NULL
);
8026 /* Refresh values (does autoscale if specified) */
8031 if ((objc
- nidx
) != 2 && (objc
- nidx
) != 3) {
8032 Tcl_WrongNumArgs(interp
, 1, objv
, "changes");
8035 /* Allow changes to be set, so that a page can be forced to be */
8036 /* recognized as either modified or unmodified. */
8038 if ((objc
- nidx
) == 3) {
8040 Tcl_GetIntFromObj(interp
, objv
[2 + nidx
], &value
);
8041 curpage
->pageinst
->thisobject
->changes
= (u_short
)value
;
8043 changes
= getchanges(curpage
->pageinst
->thisobject
);
8044 objPtr
= Tcl_NewIntObj((double)changes
);
8045 Tcl_SetObjResult(interp
, objPtr
);
8046 return XcTagCallback(interp
, objc
, objv
);
8049 return XcTagCallback(interp
, objc
, objv
);
8052 /*----------------------------------------------------------------------*/
8053 /* The "technology" command deals with library *technologies*, where */
8054 /* they differ from files or pages (see the "library" command */
8055 /* xctcl_library, below). Specifically, "library load" loads a file */
8056 /* (containing object defintions in a specific technology) onto a page, */
8057 /* whereas "technology save" writes back the object definitions that */
8058 /* came from the specified file. Although one would typically have one */
8059 /* library page per technology, this is not necessarily the case. */
8061 /* Only one technology is defined by a library file, but the library */
8062 /* may contain (copies of) dependent objects from another technology. */
8063 /*----------------------------------------------------------------------*/
8065 int xctcl_tech(ClientData clientData
, Tcl_Interp
*interp
,
8066 int objc
, Tcl_Obj
*CONST objv
[])
8068 char *technology
, *filename
, *libobjname
;
8070 int idx
, ilib
, j
, pageno
, nidx
, result
;
8071 TechPtr nsptr
= NULL
;
8074 Boolean usertech
= FALSE
;
8078 "save", "list", "objects", "filename", "changed", "used", "writable",
8082 SaveIdx
, ListIdx
, ObjectsIdx
, FileNameIdx
, ChangedIdx
, UsedIdx
,
8083 WritableIdx
, WriteableIdx
8087 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
8090 if (Tcl_GetIndexFromObj(interp
, objv
[1],
8091 (CONST84
char **)subCmds
, "option", 0, &idx
) != TCL_OK
) {
8095 /* All options except "list" and "used" expect a technology argument */
8096 if (idx
!= ListIdx
&& idx
!= UsedIdx
) {
8098 technology
= Tcl_GetString(objv
[2]);
8099 nsptr
= LookupTechnology(technology
);
8100 if (nsptr
== NULL
) {
8102 /* If the command is "objects" and has one or more */
8103 /* additional arguments, then a NULL nsptr is okay (new */
8104 /* technology will be created and added to the list). */
8106 if (idx
!= ObjectsIdx
|| objc
<= 3) {
8108 /* If nsptr is NULL, then the technology should be */
8109 /* "none" or "user" */
8111 if ((strstr(technology
, "none") == NULL
) &&
8112 (strstr(technology
, "user") == NULL
)) {
8113 Tcl_SetResult(interp
, "Error: Unknown technology name!", NULL
);
8120 /* And if the user technology has been saved to a file, the technology */
8121 /* will have a NULL string. Also check for technology name "(user)", */
8122 /* although that is not supposed to happen. */
8124 else if (*nsptr
->technology
== '\0')
8127 else if (!strcmp(nsptr
->technology
, "(user)"))
8131 Tcl_WrongNumArgs(interp
, 1, objv
, "<option> technology ?args ...?");
8138 /* List all of the known technologies */
8139 olist
= Tcl_NewListObj(0, NULL
);
8140 for (nsptr
= xobjs
.technologies
; nsptr
!= NULL
; nsptr
= nsptr
->next
) {
8141 Tcl_ListObjAppendElement(interp
, olist
,
8142 Tcl_NewStringObj(nsptr
->technology
,
8143 strlen(nsptr
->technology
)));
8145 Tcl_SetObjResult(interp
, olist
);
8149 /* List all of the technologies used by the schematic of the */
8150 /* indicated (or current) page. That is, enumerate all */
8151 /* in the hierarchy of the schematic, and list all unique */
8152 /* technology prefixes. */
8154 result
= ParsePageArguments(interp
, objc
- 1, objv
+ 1, &nidx
, &pageno
);
8155 if (result
!= TCL_OK
) return result
;
8156 olist
= Tcl_NewListObj(0, NULL
);
8158 pagelist
= pagetotals(pageno
, TOTAL_PAGES
);
8159 for (j
= 0; j
< xobjs
.pages
; j
++) {
8160 if (pagelist
[j
] > 0) {
8162 objectptr tpage
= xobjs
.pagelist
[j
]->pageinst
->thisobject
;
8165 for (tgen
= tpage
->plist
; tgen
< tpage
->plist
+ tpage
->parts
; tgen
++) {
8166 if ((*tgen
)->type
== OBJINST
) {
8167 tinst
= TOOBJINST(tgen
);
8168 nsptr
= GetObjectTechnology(tinst
->thisobject
);
8169 if (nsptr
!= NULL
) {
8170 if ((nsptr
->technology
== NULL
) ||
8171 (strlen(nsptr
->technology
) == 0)) continue;
8172 if (!(nsptr
->flags
& TECH_USED
)) {
8173 Tcl_ListObjAppendElement(interp
, olist
,
8174 Tcl_NewStringObj(nsptr
->technology
,
8175 strlen(nsptr
->technology
)));
8176 nsptr
->flags
|= TECH_USED
;
8183 Tcl_SetObjResult(interp
, olist
);
8184 for (nsptr
= xobjs
.technologies
; nsptr
!= NULL
; nsptr
= nsptr
->next
)
8185 nsptr
->flags
&= ~TECH_USED
;
8186 free((char *)pagelist
);
8192 int numobjs
, objnamelen
, technamelen
;
8197 /* Check that 4th argument is a list of objects or that */
8198 /* 4th and higher arguments are all names of objects, and */
8199 /* that these objects are valid existing objects. */
8202 result
= Tcl_ListObjLength(interp
, objv
[3], &numobjs
);
8203 if (result
!= TCL_OK
) return result
;
8204 for (j
= 0; j
< numobjs
; j
++) {
8205 result
= Tcl_ListObjIndex(interp
, objv
[3], j
, &tobj
);
8206 if (result
!= TCL_OK
) return result
;
8207 libobj
= NameToObject(Tcl_GetString(tobj
), NULL
, FALSE
);
8208 if (libobj
== NULL
) {
8209 Tcl_SetResult(interp
, "No such object name", NULL
);
8215 for (j
= 0; j
< objc
- 4; j
++) {
8216 libobj
= NameToObject(Tcl_GetString(objv
[3 + j
]), NULL
, FALSE
);
8217 if (libobj
== NULL
) {
8218 Tcl_SetResult(interp
, "No such object name", NULL
);
8224 /* Create a new technology if needed */
8225 technology
= Tcl_GetString(objv
[2]);
8226 if ((nsptr
== NULL
) && !usertech
)
8227 AddNewTechnology(technology
, NULL
);
8229 nsptr
= LookupTechnology(technology
);
8230 technamelen
= (usertech
) ? 0 : strlen(technology
);
8233 /* Change the technology prefix of all the objects listed */
8236 result
= Tcl_ListObjLength(interp
, objv
[3], &numobjs
);
8237 if (result
!= TCL_OK
) return result
;
8238 for (j
= 0; j
< numobjs
; j
++) {
8239 result
= Tcl_ListObjIndex(interp
, objv
[3], j
, &tobj
);
8240 if (result
!= TCL_OK
) return result
;
8241 libobj
= NameToObject(Tcl_GetString(tobj
), NULL
, FALSE
);
8242 cptr
= strstr(libobj
->name
, "::");
8244 objnamelen
= strlen(libobj
->name
);
8245 memmove(libobj
->name
+ technamelen
+ 2,
8246 libobj
->name
, (size_t)strlen(libobj
->name
));
8249 otech
= GetObjectTechnology(libobj
);
8250 otech
->flags
|= TECH_CHANGED
;
8251 objnamelen
= strlen(cptr
+ 2);
8252 memmove(libobj
->name
+ technamelen
+ 2,
8253 cptr
+ 2, (size_t)strlen(cptr
+ 2));
8256 if (!usertech
) strcpy(libobj
->name
, technology
);
8257 *(libobj
->name
+ technamelen
) = ':';
8258 *(libobj
->name
+ technamelen
+ 1) = ':';
8259 *(libobj
->name
+ technamelen
+ 2 + objnamelen
) = '\0';
8263 for (j
= 0; j
< objc
- 4; j
++) {
8264 libobj
= NameToObject(Tcl_GetString(objv
[3 + j
]), NULL
, FALSE
);
8265 cptr
= strstr(libobj
->name
, "::");
8267 objnamelen
= strlen(libobj
->name
);
8268 memmove(libobj
->name
+ technamelen
+ 2,
8269 libobj
->name
, (size_t)strlen(libobj
->name
));
8272 otech
= GetObjectTechnology(libobj
);
8273 otech
->flags
|= TECH_CHANGED
;
8274 objnamelen
= strlen(cptr
+ 2);
8275 memmove(libobj
->name
+ technamelen
+ 2,
8276 cptr
+ 2, (size_t)strlen(cptr
+ 2));
8279 if (!usertech
) strcpy(libobj
->name
, technology
);
8280 *(libobj
->name
+ technamelen
) = ':';
8281 *(libobj
->name
+ technamelen
+ 1) = ':';
8282 *(libobj
->name
+ technamelen
+ 2 + objnamelen
) = '\0';
8285 if (nsptr
!= NULL
) nsptr
->flags
|= TECH_CHANGED
;
8289 /* List all objects having this technology */
8291 olist
= Tcl_NewListObj(0, NULL
);
8292 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
8293 for (j
= 0; j
< xobjs
.userlibs
[ilib
].number
; j
++) {
8294 libobj
= *(xobjs
.userlibs
[ilib
].library
+ j
);
8295 if (GetObjectTechnology(libobj
) == nsptr
) {
8296 libobjname
= strstr(libobj
->name
, "::");
8297 if (libobjname
== NULL
)
8298 libobjname
= libobj
->name
;
8301 Tcl_ListObjAppendElement(interp
, olist
,
8302 Tcl_NewStringObj(libobjname
, strlen(libobjname
)));
8306 Tcl_SetObjResult(interp
, olist
);
8310 if (nsptr
!= NULL
) {
8312 if (nsptr
->filename
== NULL
)
8313 Tcl_SetResult(interp
, "(no associated file)", NULL
);
8315 Tcl_SetResult(interp
, nsptr
->filename
, NULL
);
8318 if (nsptr
->filename
!= NULL
) free(nsptr
->filename
);
8319 nsptr
->filename
= strdup(Tcl_GetString(objv
[3]));
8323 Tcl_SetResult(interp
, "Valid technology is required", NULL
);
8331 if (Tcl_GetBooleanFromObj(interp
, objv
[3], &bval
) != TCL_OK
)
8334 nsptr
->flags
|= TECH_CHANGED
;
8336 nsptr
->flags
&= ~TECH_CHANGED
;
8339 tech_set_changes(nsptr
); /* Ensure change flags are updated */
8340 Tcl_SetObjResult(interp
,
8341 Tcl_NewBooleanObj(((nsptr
->flags
& TECH_CHANGED
)
8342 == 0) ? FALSE
: TRUE
));
8350 Tcl_SetObjResult(interp
,
8351 Tcl_NewBooleanObj(((nsptr
->flags
& TECH_READONLY
) == 0)
8354 else if (objc
== 4) {
8357 Tcl_GetBooleanFromObj(interp
, objv
[3], &bval
);
8359 nsptr
->flags
|= TECH_READONLY
;
8361 nsptr
->flags
&= (~TECH_READONLY
);
8365 Tcl_SetResult(interp
, "Valid technology is required", NULL
);
8372 /* technology save [filename] */
8373 if ((objc
== 3) && ((nsptr
== NULL
) || (nsptr
->filename
== NULL
))) {
8374 Tcl_SetResult(interp
, "Error: Filename is required.", NULL
);
8377 else if ((nsptr
!= NULL
) && (objc
== 4)) {
8378 /* Technology being saved under a different filename. */
8379 filename
= Tcl_GetString(objv
[3]);
8381 /* Re-check read-only status of the file */
8382 nsptr
->flags
&= ~(TECH_READONLY
);
8383 chklib
= fopen(filename
, "a");
8385 nsptr
->flags
|= TECH_READONLY
;
8389 else if (objc
== 4) {
8390 filename
= Tcl_GetString(objv
[3]);
8391 if (!usertech
) AddNewTechnology(technology
, filename
);
8394 filename
= nsptr
->filename
;
8396 savetechnology((usertech
) ? NULL
: technology
, filename
);
8399 return XcTagCallback(interp
, objc
, objv
);
8402 /*----------------------------------------------------------------------*/
8403 /* The "library" command deals with library *pages* */
8404 /*----------------------------------------------------------------------*/
8406 int xctcl_library(ClientData clientData
, Tcl_Interp
*interp
,
8407 int objc
, Tcl_Obj
*CONST objv
[])
8409 char *filename
= NULL
, *objname
, *argv
;
8410 int j
= 0, libnum
= -1;
8411 int idx
, nidx
, result
, res
;
8414 int newobjc
, hidmode
;
8418 "load", "make", "directory", "next", "goto", "override",
8419 "handle", "import", "list", "compose", NULL
8422 LoadIdx
, MakeIdx
, DirIdx
, NextIdx
, GoToIdx
, OverrideIdx
,
8423 HandleIdx
, ImportIdx
, ListIdx
, ComposeIdx
8426 result
= ParseLibArguments(interp
, objc
, objv
, &nidx
, &libnum
);
8427 if ((result
!= TCL_OK
) || (nidx
< 0)) return result
;
8428 else if ((objc
- nidx
) > 5) {
8429 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
8432 else if (objc
<= (1 + nidx
)) { /* No subcommand */
8434 /* return index if name given; return name if index given. */
8435 /* return index if neither is given (current library) */
8438 int lnum
; /* unused; only checks if argument is integer */
8440 result
= Tcl_GetIntFromObj(interp
, objv
[1], &lnum
);
8441 if (result
== TCL_OK
) {
8442 lname
= xobjs
.libtop
[libnum
+ LIBRARY
]->thisobject
->name
;
8443 Tcl_SetObjResult(interp
, Tcl_NewStringObj(lname
, strlen(lname
)));
8447 Tcl_SetObjResult(interp
, Tcl_NewIntObj(libnum
+ 1));
8451 Tcl_SetObjResult(interp
, Tcl_NewIntObj(libnum
+ 1));
8454 else if (Tcl_GetIndexFromObj(interp
, objv
[1 + nidx
],
8455 (CONST84
char **)subCmds
, "option", 0, &idx
) != TCL_OK
) {
8457 /* Backwards compatibility: "library filename [number]" is */
8458 /* the same as "library [number] load filename" */
8460 Tcl_ResetResult(interp
);
8461 newobjv
= (Tcl_Obj
**)(&objv
[1]);
8464 result
= ParseLibArguments(interp
, newobjc
, newobjv
, &nidx
, &libnum
);
8465 if (result
!= TCL_OK
) return result
;
8468 filename
= Tcl_GetString(newobjv
[0]);
8471 /* libnum = -1 is equivalent to "USER LIBRARY" */
8472 if (libnum
< 0) libnum
= xobjs
.numlibs
- 1;
8478 /* library [<name>|<number>] load <filename> [-replace [library]] */
8479 if (objc
< (3 + nidx
)) {
8480 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
8483 if (filename
== NULL
) filename
= Tcl_GetString(objv
[2 + nidx
]);
8485 /* if loading of default libraries is not overridden, load them first */
8487 if (!(flags
& (LIBOVERRIDE
| LIBLOADED
))) {
8488 result
= defaultscript();
8492 /* If library number is out of range, create a new library */
8493 /* libnum = -1 is equivalent to the user library page. */
8495 if (libnum
> (xobjs
.numlibs
- 1))
8496 libnum
= createlibrary(FALSE
);
8497 else if (libnum
< 0)
8502 if (objc
> (3 + nidx
)) {
8503 argv
= Tcl_GetString(objv
[3 + nidx
]);
8504 if ((*argv
== '-') && !strncmp(argv
, "-repl", 5)) {
8505 if (objc
> (4 + nidx
)) {
8506 char *techstr
= Tcl_GetString(objv
[3 + nidx
]);
8507 if (!strcmp(techstr
, "all")) TechReplaceAll();
8508 else if (!strcmp(techstr
, "none")) TechReplaceNone();
8510 TechPtr nsptr
= LookupTechnology(techstr
);
8512 nsptr
->flags
|= TECH_REPLACE
;
8516 TechReplaceAll(); /* replace ALL */
8520 strcpy(_STR
, filename
);
8521 res
= loadlibrary(libnum
);
8523 res
= loadfile(2, libnum
);
8524 TechReplaceRestore();
8526 Tcl_SetResult(interp
, "Error loading library.\n", NULL
);
8530 TechReplaceRestore();
8534 /* library [<name>|<number>] import <filename> <objectname> */
8535 if (objc
!= (4 + nidx
)) {
8536 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
8539 if (filename
== NULL
) filename
= Tcl_GetString(objv
[2 + nidx
]);
8541 /* if loading of default libraries is not overridden, load them first */
8543 if (!(flags
& (LIBOVERRIDE
| LIBLOADED
))) {
8548 if ((libnum
>= xobjs
.numlibs
) || (libnum
< 0))
8549 libnum
= createlibrary(FALSE
);
8553 objname
= Tcl_GetString(objv
[3 + nidx
]);
8554 importfromlibrary(libnum
, filename
, objname
);
8559 if (!strncmp(Tcl_GetString(objv
[objc
- 1]), "-vis", 4))
8560 hidmode
= 1; /* list visible objects only */
8561 else if (!strncmp(Tcl_GetString(objv
[objc
- 1]), "-hid", 4))
8562 hidmode
= 2; /* list hidden objects only */
8564 hidmode
= 3; /* list everything */
8566 /* library [name|number] list [-visible|-hidden] */
8567 olist
= Tcl_NewListObj(0, NULL
);
8568 for (j
= 0; j
< xobjs
.userlibs
[libnum
].number
; j
++) {
8569 libobj
= *(xobjs
.userlibs
[libnum
].library
+ j
);
8570 if (((libobj
->hidden
) && (hidmode
& 2)) ||
8571 ((!libobj
->hidden
) && (hidmode
& 1)))
8572 Tcl_ListObjAppendElement(interp
, olist
,
8573 Tcl_NewStringObj(libobj
->name
, strlen(libobj
->name
)));
8575 Tcl_SetObjResult(interp
, olist
);
8580 if (objc
== (3 + nidx
)) {
8581 /* library [name|number] handle <object name> */
8583 olist
= Tcl_NewListObj(0, NULL
);
8584 for (spec
= xobjs
.userlibs
[libnum
].instlist
; spec
!= NULL
;
8585 spec
= spec
->next
) {
8586 libobj
= spec
->thisinst
->thisobject
;
8587 if (!strcmp(libobj
->name
, Tcl_GetString(objv
[objc
- 1])))
8588 Tcl_ListObjAppendElement(interp
, olist
,
8589 Tcl_NewHandleObj((genericptr
)spec
->thisinst
));
8591 Tcl_SetObjResult(interp
, olist
);
8593 else if (objc
== (2 + nidx
)) {
8594 /* library [name|number] handle */
8596 olist
= Tcl_NewListObj(0, NULL
);
8597 for (spec
= xobjs
.userlibs
[libnum
].instlist
; spec
!= NULL
;
8598 spec
= spec
->next
) {
8599 Tcl_ListObjAppendElement(interp
, olist
,
8600 Tcl_NewHandleObj((genericptr
)spec
->thisinst
));
8602 Tcl_SetObjResult(interp
, olist
);
8605 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg ...?");
8611 composelib(libnum
+ LIBRARY
);
8612 centerview(xobjs
.libtop
[libnum
+ LIBRARY
]);
8616 /* library make [name] */
8618 Tcl_SetResult(interp
, "syntax is: library make [<name>]", NULL
);
8622 /* If the (named or numbered) library exists, don't create it. */
8623 /* ParseLibArguments() returns the library number for the User */
8624 /* Library. The User Library always exists and cannot be */
8625 /* created or destroyed, so it's okay to use it as a check for */
8626 /* "no library found". */
8628 if (libnum
== xobjs
.numlibs
- 1)
8629 libnum
= createlibrary(TRUE
);
8632 strcpy(xobjs
.libtop
[libnum
]->thisobject
->name
, Tcl_GetString(objv
[2]));
8636 /* Don't go to the library page---use "library goto" instead */
8637 /* startcatalog((Tk_Window)clientData, libnum, NULL); */
8641 /* library directory */
8642 if ((nidx
== 0) && (objc
== 2)) {
8643 startcatalog(NULL
, LIBLIB
, NULL
);
8645 else if ((nidx
== 0) && (objc
== 3) &&
8646 !strcmp(Tcl_GetString(objv
[2]), "list")) {
8647 olist
= Tcl_NewListObj(0, NULL
);
8648 for (j
= 0; j
< xobjs
.numlibs
; j
++) {
8649 libobj
= xobjs
.libtop
[j
+ LIBRARY
]->thisobject
;
8650 Tcl_ListObjAppendElement(interp
, olist
,
8651 Tcl_NewStringObj(libobj
->name
, strlen(libobj
->name
)));
8653 Tcl_SetObjResult(interp
, olist
);
8656 Tcl_SetResult(interp
, "syntax is: library directory [list]", NULL
);
8662 libnum
= is_library(topobject
);
8663 if (++libnum
>= xobjs
.numlibs
) libnum
= 0; /* fall through */
8667 startcatalog(NULL
, LIBRARY
+ libnum
, NULL
);
8670 flags
|= LIBOVERRIDE
;
8671 return TCL_OK
; /* no tag callback */
8674 return (result
== TCL_OK
) ? XcTagCallback(interp
, objc
, objv
) : result
;
8677 /*----------------------------------------------------------------------*/
8678 /* "bindkey" command --- this is a direct implementation of the same */
8679 /* key binding found in the "ad-hoc" and Python interfaces; it is */
8680 /* preferable to make use of the Tk "bind" command directly, and work */
8681 /* from the event handler. */
8682 /*----------------------------------------------------------------------*/
8684 int xctcl_bind(ClientData clientData
, Tcl_Interp
*interp
,
8685 int objc
, Tcl_Obj
*CONST objv
[])
8687 Tk_Window window
= (Tk_Window
)NULL
;
8688 XCWindowDataPtr searchwin
;
8689 char *keyname
, *commandname
, *binding
;
8690 int keywstate
, func
= -1, value
= -1;
8692 Boolean compat
= FALSE
;
8695 keyname
= Tcl_GetString(objv
[1]);
8696 if (!strcmp(keyname
, "override")) {
8697 flags
|= KEYOVERRIDE
;
8698 return TCL_OK
; /* no tag callback */
8702 if (!(flags
& KEYOVERRIDE
)) {
8703 default_keybindings();
8704 flags
|= KEYOVERRIDE
;
8711 list
= Tcl_NewListObj(0, NULL
);
8712 for (i
= 0; i
< NUM_FUNCTIONS
; i
++) {
8713 commandname
= func_to_string(i
);
8714 Tcl_ListObjAppendElement(interp
, list
,
8715 Tcl_NewStringObj(commandname
, strlen(commandname
)));
8717 Tcl_SetObjResult(interp
, list
);
8720 else if (objc
> 5) {
8721 Tcl_WrongNumArgs(interp
, 1, objv
,
8722 "[<key> [<window>] [<command> [<value>|forget]]]");
8726 /* If 1st argument matches a window name, create a window-specific */
8727 /* binding. Otherwise, create a binding for all windows. */
8730 window
= Tk_NameToWindow(interp
, Tcl_GetString(objv
[1]), Tk_MainWindow(interp
));
8731 if (window
== (Tk_Window
)NULL
)
8732 Tcl_ResetResult(interp
);
8734 for (searchwin
= xobjs
.windowlist
; searchwin
!= NULL
; searchwin
=
8736 if (searchwin
->area
== window
)
8738 if (searchwin
!= NULL
) {
8739 /* Shift arguments */
8744 window
= (xcWidget
)NULL
;
8748 /* 1st argument can be option "-compatible" */
8749 if ((objc
> 1) && !strncmp(Tcl_GetString(objv
[1]), "-comp", 5)) {
8755 keyname
= Tcl_GetString(objv
[1]);
8756 keywstate
= string_to_key(keyname
);
8758 /* 1st arg may be a function, not a key, if we want the binding returned */
8759 if ((objc
== 3) && !strncmp(keyname
, "-func", 5)) {
8761 func
= string_to_func(Tcl_GetString(objv
[2]), NULL
);
8764 Tcl_SetResult(interp
, "Invalid function name\n", NULL
);
8768 else if ((objc
== 2) && (keywstate
== 0)) {
8770 func
= string_to_func(keyname
, NULL
);
8773 if ((keywstate
== -1 || keywstate
== 0) && func
== -1) {
8774 Tcl_SetResult(interp
, "Invalid key name ", NULL
);
8775 Tcl_AppendElement(interp
, keyname
);
8780 if (keywstate
== -1)
8781 binding
= function_binding_to_string(window
, func
);
8783 binding
= compat_key_to_string(window
, keywstate
);
8785 binding
= key_binding_to_string(window
, keywstate
);
8786 Tcl_SetResult(interp
, binding
, TCL_VOLATILE
);
8792 Tcl_SetResult(interp
, "Usage: bindkey <key> [<function>]\n", NULL
);
8796 commandname
= Tcl_GetString(objv
[2]);
8797 if (strlen(commandname
) == 0)
8800 func
= string_to_func(commandname
, NULL
);
8803 result
= Tcl_GetIntFromObj(interp
, objv
[3], &value
);
8804 if (result
!= TCL_OK
)
8806 if (strcmp(Tcl_GetString(objv
[3]), "forget"))
8809 /* Unbind command */
8810 Tcl_ResetResult(interp
);
8811 result
= remove_binding(window
, keywstate
, func
);
8815 Tcl_SetResult(interp
, "Key/Function pair not found "
8816 "in binding list.\n", NULL
);
8822 result
= add_vbinding(window
, keywstate
, func
, value
);
8824 Tcl_SetResult(interp
, "Key is already bound to a command.\n", NULL
);
8827 return (result
== TCL_OK
) ? XcTagCallback(interp
, objc
, objv
) : result
;
8830 /*----------------------------------------------------------------------*/
8832 int xctcl_font(ClientData clientData
, Tcl_Interp
*interp
,
8833 int objc
, Tcl_Obj
*CONST objv
[])
8840 Tcl_WrongNumArgs(interp
, 1, objv
, "fontname");
8843 fontname
= Tcl_GetString(objv
[1]);
8845 /* Allow overrides of the default font loading mechanism */
8846 if (!strcmp(fontname
, "override")) {
8847 flags
|= FONTOVERRIDE
;
8851 /* If we need to load the default font "Helvetica" because no fonts */
8852 /* have been loaded yet, then we call this function twice, so that */
8853 /* the command tag callback gets applied both times. */
8855 if (!(flags
& FONTOVERRIDE
)) {
8856 flags
|= FONTOVERRIDE
;
8857 xctcl_font(clientData
, interp
, objc
, objv
);
8858 loadfontfile("Helvetica");
8860 result
= loadfontfile((char *)fontname
);
8862 Tcl_SetObjResult(interp
, Tcl_NewStringObj(fonts
[fontcount
- 1].family
,
8863 strlen(fonts
[fontcount
- 1].family
)));
8867 return XcTagCallback(interp
, objc
, objv
);
8873 return TCL_ERROR
; /* (jdk) */
8876 /*----------------------------------------------------------------------*/
8877 /* Set the X11 cursor to one of those defined in the XCircuit cursor */
8878 /* set (cursors.h) */
8879 /*----------------------------------------------------------------------*/
8881 int xctcl_cursor(ClientData clientData
, Tcl_Interp
*interp
,
8882 int objc
, Tcl_Obj
*CONST objv
[])
8886 static char *cursNames
[] = {
8887 "arrow", "cross", "scissors", "copy", "rotate", "edit",
8888 "text", "circle", "question", "wait", "hand", NULL
8891 if (!areawin
) return TCL_ERROR
;
8895 Tcl_WrongNumArgs(interp
, 1, objv
, "cursor name");
8898 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[1],
8899 (CONST84
char **)cursNames
,
8900 "cursor name", 0, &idx
)) != TCL_OK
)
8903 XDefineCursor(dpy
, areawin
->window
, appcursors
[idx
]);
8904 areawin
->defaultcursor
= &appcursors
[idx
];
8905 return XcTagCallback(interp
, objc
, objv
);
8908 /*----------------------------------------------------------------------*/
8910 int xctcl_filerecover(ClientData clientData
, Tcl_Interp
*interp
,
8911 int objc
, Tcl_Obj
*CONST objv
[])
8914 Tcl_WrongNumArgs(interp
, 1, objv
, "(no arguments)");
8918 return XcTagCallback(interp
, objc
, objv
);
8921 /*----------------------------------------------------------------------*/
8922 /* Replace the functions of the simple rcfile.c interpreter. */
8923 /*----------------------------------------------------------------------*/
8925 /*----------------------------------------------------------------------*/
8926 /* Execute a single command from a script or from the command line */
8927 /*----------------------------------------------------------------------*/
8929 short execcommand(short pflags
, char *cmdptr
)
8932 Tcl_Eval(xcinterp
, cmdptr
);
8933 refresh(NULL
, NULL
, NULL
);
8937 /*----------------------------------------------------------------------*/
8938 /* Load the default script (like execscript() but don't allow recursive */
8939 /* loading of the startup script) */
8940 /*----------------------------------------------------------------------*/
8945 char *tmp_s
= getenv((const char *)"XCIRCUIT_SRC_DIR");
8948 flags
= LIBOVERRIDE
| LIBLOADED
| FONTOVERRIDE
;
8950 if (!tmp_s
) tmp_s
= SCRIPTS_DIR
;
8951 sprintf(_STR2
, "%s/%s", tmp_s
, STARTUP_FILE
);
8953 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
8954 sprintf(_STR2
, "%s/%s", SCRIPTS_DIR
, STARTUP_FILE
);
8955 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
8956 sprintf(_STR2
, "%s/tcl/%s", SCRIPTS_DIR
, STARTUP_FILE
);
8957 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
8958 Wprintf("Failed to open startup script \"%s\"\n", STARTUP_FILE
);
8964 result
= Tcl_EvalFile(xcinterp
, _STR2
);
8968 /*----------------------------------------------------------------------*/
8969 /* Execute a script */
8970 /*----------------------------------------------------------------------*/
8978 xc_tilde_expand(_STR2
, 249);
8979 if ((fd
= fopen(_STR2
, "r")) != NULL
) {
8981 Tcl_EvalFile(xcinterp
, _STR2
);
8982 refresh(NULL
, NULL
, NULL
);
8985 Wprintf("Failed to open script file \"%s\"\n", _STR2
);
8989 /*----------------------------------------------------------------------*/
8990 /* Evaluate an expression from a parameter and return the result as a */
8991 /* Tcl object. The actual return value (TCL_OK, TCL_ERROR) is stored */
8992 /* in pointer "eval_status", if it is non-NULL. */
8993 /*----------------------------------------------------------------------*/
8995 Tcl_Obj
*evaluate_raw(objectptr thisobj
, oparamptr ops
, objinstptr pinst
,
8998 Tcl_SavedResult state
;
9001 char *exprptr
, *pptr
, *pkey
, *pnext
;
9004 if (ops
->type
!= XC_EXPR
) return NULL
;
9005 exprptr
= ops
->parameter
.expr
;
9007 if (pnext
== NULL
) return NULL
;
9009 /* Check for "@<parameter>" notation and substitute parameter values */
9010 while ((pptr
= strchr(pnext
, '@')) != NULL
)
9014 char psave
, *promoted
, *newexpr
;
9017 for (pkey
= pptr
; *pkey
&& !isspace(*pkey
); pkey
++)
9018 if (*pkey
== '{' || *pkey
== '}' || *pkey
== '[' || *pkey
== ']' ||
9019 *pkey
== '(' || *pkey
== ')' || *pkey
== ',')
9026 ips
= find_param(pinst
, pptr
);
9028 ips
= match_param(thisobj
, pptr
);
9030 /* Avoid infinite recursion by treating a reference */
9031 /* to oneself as plain text. */
9034 if ((ips
== NULL
) && !strncmp(pptr
, "p_", 2)) {
9036 if (!strcmp(pptr
+ 2, "rotation")) {
9037 temps
.type
= XC_FLOAT
;
9038 temps
.parameter
.fvalue
= pinst
? pinst
->rotation
: 0;
9040 else if (!strcmp(pptr
+ 2, "xposition")) {
9041 temps
.type
= XC_INT
;
9042 temps
.parameter
.ivalue
= pinst
? pinst
->position
.x
: 0;
9044 else if (!strcmp(pptr
+ 2, "yposition")) {
9045 temps
.type
= XC_INT
;
9046 temps
.parameter
.ivalue
= pinst
? pinst
->position
.y
: 0;
9048 else if (!strcmp(pptr
+ 2, "scale")) {
9049 temps
.type
= XC_FLOAT
;
9050 temps
.parameter
.fvalue
= pinst
? pinst
->scale
: 1.0;
9052 else if (!strcmp(pptr
+ 2, "color")) {
9053 temps
.type
= XC_INT
;
9054 temps
.parameter
.ivalue
= pinst
? pinst
->color
: DEFAULTCOLOR
;
9056 else if (!strcmp(pptr
+ 2, "top_xposition")) {
9057 temps
.type
= XC_INT
;
9058 UTopDrawingOffset(&temps
.parameter
.ivalue
, NULL
);
9060 else if (!strcmp(pptr
+ 2, "top_yposition")) {
9061 temps
.type
= XC_INT
;
9062 UTopDrawingOffset(NULL
, &temps
.parameter
.ivalue
);
9064 else if (!strcmp(pptr
+ 2, "top_rotation")) {
9065 temps
.type
= XC_FLOAT
;
9066 temps
.parameter
.fvalue
= UTopRotation();
9068 else if (!strcmp(pptr
+ 2, "top_scale")) {
9069 temps
.type
= XC_FLOAT
;
9070 temps
.parameter
.fvalue
= UTopDrawingScale();
9077 switch (ips
->type
) {
9079 promoted
= malloc(12);
9080 snprintf(promoted
, 12, "%d", ips
->parameter
.ivalue
);
9083 promoted
= malloc(12);
9084 snprintf(promoted
, 12, "%g", ips
->parameter
.fvalue
);
9087 promoted
= textprint(ips
->parameter
.string
, pinst
);
9090 /* We really ought to prevent infinite loops here. . .*/
9091 promoted
= evaluate_expr(thisobj
, ips
, pinst
);
9094 if (promoted
== NULL
) break;
9095 newexpr
= (char *)malloc(1 + strlen(exprptr
) +
9096 (max(strlen(promoted
), strlen(pkey
))));
9098 strcpy(newexpr
, exprptr
);
9100 strcat(newexpr
, promoted
);
9101 pnext
= newexpr
+ strlen(newexpr
); /* For next search of '@' escape */
9102 strcat(newexpr
, pkey
);
9104 if (exprptr
!= ops
->parameter
.expr
) free(exprptr
);
9108 /* Ignore the keyword and move to the end */
9114 /* Evaluate the expression in TCL */
9116 Tcl_SaveResult(xcinterp
, &state
);
9117 status
= Tcl_Eval(xcinterp
, exprptr
);
9118 robj
= Tcl_GetObjResult(xcinterp
);
9119 Tcl_IncrRefCount(robj
);
9120 Tcl_RestoreResult(xcinterp
, &state
);
9121 if (eval_status
) *eval_status
= status
;
9122 if (exprptr
!= ops
->parameter
.expr
) free(exprptr
);
9126 /*----------------------------------------------------------------------*/
9127 /* Evaluate an expression from a parameter and return the result as an */
9128 /* allocated string. */
9129 /*----------------------------------------------------------------------*/
9131 char *evaluate_expr(objectptr thisobj
, oparamptr ops
, objinstptr pinst
)
9137 stringpart
*tmpptr
, *promote
= NULL
;
9138 oparamptr ips
= (pinst
== NULL
) ? NULL
: match_instance_param(pinst
, ops
->key
);
9140 robj
= evaluate_raw(thisobj
, ops
, pinst
, &status
);
9142 rexpr
= strdup(Tcl_GetString(robj
));
9143 Tcl_DecrRefCount(robj
);
9146 if ((status
== TCL_ERROR
) && (ips
!= NULL
)) {
9149 rexpr
= textprint(ips
->parameter
.string
, pinst
);
9152 fp
= ips
->parameter
.fvalue
;
9157 /* If an instance redefines an expression, don't preserve */
9158 /* the result. It is necessary in this case that the */
9159 /* expression does not reference objects during redisplay, */
9160 /* or else the correct result will not be written to the */
9163 if ((ips
!= NULL
) && (ips
->type
== XC_EXPR
))
9166 /* Preserve the result in the object instance; this will be */
9167 /* used when writing the output or when the result cannot */
9168 /* be evaluated (see above). */
9170 if ((rexpr
!= NULL
) && (status
== TCL_OK
) && (pinst
!= NULL
)) {
9171 switch (ops
->which
) {
9172 case P_SUBSTRING
: case P_EXPRESSION
:
9174 ips
= make_new_parameter(ops
->key
);
9175 ips
->which
= ops
->which
;
9176 ips
->type
= XC_STRING
;
9177 ips
->next
= pinst
->params
;
9178 pinst
->params
= ips
;
9181 free(ips
->parameter
.string
);
9183 /* Promote the expression result to an XCircuit string type */
9184 tmpptr
= makesegment(&promote
, NULL
);
9185 tmpptr
->type
= TEXT_STRING
;
9186 tmpptr
= makesegment(&promote
, NULL
);
9187 tmpptr
->type
= PARAM_END
;
9188 promote
->data
.string
= strdup(rexpr
);
9189 ips
->parameter
.string
= promote
;
9192 case P_COLOR
: /* must be integer, exact to 32 bits */
9194 ips
= make_new_parameter(ops
->key
);
9195 ips
->which
= ops
->which
;
9196 ips
->next
= pinst
->params
;
9197 pinst
->params
= ips
;
9199 /* Promote the expression result to type float */
9200 if (rexpr
!= NULL
) {
9201 if (sscanf(rexpr
, "%i", &ip
) == 1)
9202 ips
->parameter
.ivalue
= ip
;
9204 ips
->parameter
.ivalue
= 0;
9207 ips
->parameter
.ivalue
= ip
;
9211 default: /* all others convert to type float */
9213 ips
= make_new_parameter(ops
->key
);
9214 ips
->which
= ops
->which
;
9215 ips
->next
= pinst
->params
;
9216 pinst
->params
= ips
;
9218 /* Promote the expression result to type float */
9219 if (rexpr
!= NULL
) {
9220 if (sscanf(rexpr
, "%g", &fp
) == 1)
9221 ips
->parameter
.fvalue
= fp
;
9223 ips
->parameter
.fvalue
= 0.0;
9226 ips
->parameter
.fvalue
= fp
;
9227 ips
->type
= XC_FLOAT
;
9234 /*----------------------------------------------------------------------*/
9235 /* Execute the .xcircuitrc startup script */
9236 /*----------------------------------------------------------------------*/
9240 char *userdir
= getenv((const char *)"HOME");
9243 int result
= TCL_OK
, result1
= TCL_OK
;
9245 /* Initialize flags */
9249 /* Try first in current directory, then look in user's home directory */
9250 /* First try looking for a file .xcircuitrc followed by a dash and */
9251 /* the program version; this allows backward compatibility of the rc */
9252 /* file in cases where a new version (e.g., 3 vs. 2) introduces */
9253 /* incompatible syntax. Thanks to Romano Giannetti for this */
9254 /* suggestion plus provided code. */
9256 /* (names USER_RC_FILE and PROG_VERSION imported from Makefile) */
9258 sprintf(_STR2
, "%s-%s", USER_RC_FILE
, PROG_VERSION
);
9259 xc_tilde_expand(_STR2
, 249);
9260 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
9261 /* Not found; check for the same in $HOME directory */
9262 if (userdir
!= NULL
) {
9263 sprintf(_STR2
, "%s/%s-%s", userdir
, USER_RC_FILE
, PROG_VERSION
);
9264 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
9265 /* Not found again; check for rc file w/o version # in CWD */
9266 sprintf(_STR2
, "%s", USER_RC_FILE
);
9267 xc_tilde_expand(_STR2
, 249);
9268 if ((fd
= fopen(_STR2
, "r")) == NULL
) {
9269 /* last try: plain USER_RC_FILE in $HOME */
9270 sprintf(_STR2
, "%s/%s", userdir
, USER_RC_FILE
);
9271 fd
= fopen(_STR2
, "r");
9278 result
= Tcl_EvalFile(xcinterp
, _STR2
);
9279 if (result
!= TCL_OK
) {
9280 Fprintf(stderr
, "Encountered error in startup file.");
9281 Fprintf(stderr
, "%s\n", Tcl_GetStringResult(xcinterp
));
9282 Fprintf(stderr
, "Running default startup script instead.\n");
9286 /* Add the default font if not loaded already */
9288 if (!(flags
& FONTOVERRIDE
)) {
9289 loadfontfile("Helvetica");
9290 if (areawin
->psfont
== -1)
9291 for (i
= 0; i
< fontcount
; i
++)
9292 if (!strcmp(fonts
[i
].psname
, "Helvetica")) {
9293 areawin
->psfont
= i
;
9297 if (areawin
->psfont
== -1) areawin
->psfont
= 0;
9299 setdefaultfontmarks();
9301 /* arrange the loaded libraries */
9303 if ((result
!= TCL_OK
) || !(flags
& (LIBOVERRIDE
| LIBLOADED
))) {
9304 result1
= defaultscript();
9307 /* Add the default colors */
9309 if (!(flags
& COLOROVERRIDE
)) {
9310 addnewcolorentry(xc_alloccolor("Gray40"));
9311 addnewcolorentry(xc_alloccolor("Gray60"));
9312 addnewcolorentry(xc_alloccolor("Gray80"));
9313 addnewcolorentry(xc_alloccolor("Gray90"));
9314 addnewcolorentry(xc_alloccolor("Red"));
9315 addnewcolorentry(xc_alloccolor("Blue"));
9316 addnewcolorentry(xc_alloccolor("Green2"));
9317 addnewcolorentry(xc_alloccolor("Yellow"));
9318 addnewcolorentry(xc_alloccolor("Purple"));
9319 addnewcolorentry(xc_alloccolor("SteelBlue2"));
9320 addnewcolorentry(xc_alloccolor("Red3"));
9321 addnewcolorentry(xc_alloccolor("Tan"));
9322 addnewcolorentry(xc_alloccolor("Brown"));
9323 addnewcolorentry(xc_alloccolor("#d20adc"));
9324 addnewcolorentry(xc_alloccolor("Pink"));
9327 if ((result
!= TCL_OK
) || !(flags
& KEYOVERRIDE
)) {
9328 default_keybindings();
9330 return (result1
!= TCL_OK
) ? result1
: result
;
9333 /*----------------------------------------------------------------------*/
9334 /* Alternative button handler for use with Tk "bind" */
9335 /*----------------------------------------------------------------------*/
9337 int xctcl_standardaction(ClientData clientData
,
9338 Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
9340 int idx
, result
, knum
, kstate
;
9342 static char *updown
[] = {"up", "down", NULL
};
9344 if ((objc
!= 3) && (objc
!= 4)) goto badargs
;
9346 if ((result
= Tcl_GetIntFromObj(interp
, objv
[1], &knum
)) != TCL_OK
)
9349 if ((result
= Tcl_GetIndexFromObj(interp
, objv
[2],
9350 (CONST84
char **)updown
, "direction", 0, &idx
)) != TCL_OK
)
9354 if ((result
= Tcl_GetIntFromObj(interp
, objv
[3], &kstate
)) != TCL_OK
)
9360 make_new_event(&kevent
);
9361 kevent
.state
= kstate
;
9365 kevent
.type
= KeyRelease
;
9367 kevent
.type
= KeyPress
;
9371 kevent
.state
|= Button1Mask
;
9374 kevent
.state
|= Button2Mask
;
9377 kevent
.state
|= Button3Mask
;
9380 kevent
.state
|= Button4Mask
;
9383 kevent
.state
|= Button5Mask
;
9386 kevent
.keycode
= knum
;
9390 if (kevent
.state
& Mod1Mask
) {
9391 kevent
.state
&= ~Mod1Mask
;
9393 if (kevent
.state
& (AnyModifier
<<2)) {
9394 kevent
.state
&= ~(AnyModifier
<<2);
9395 kevent
.state
|= Mod1Mask
;
9398 keyhandler((xcWidget
)NULL
, (caddr_t
)NULL
, &kevent
);
9402 Tcl_SetResult(interp
, "Usage: standardaction <button_num> up|down [<keystate>]\n"
9403 "or standardaction <keycode> up|down [<keystate>]\n", NULL
);
9407 /*----------------------------------------------------------------------*/
9408 /* Action handler for use with Tk "bind" */
9409 /* This dispatches events based on specific named actions that xcircuit */
9410 /* knows about, rather than by named key. This bypasses xcircuit's */
9412 /*----------------------------------------------------------------------*/
9414 int xctcl_action(ClientData clientData
,
9415 Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
9418 int function
, result
, ival
;
9419 XPoint newpos
, wpoint
;
9421 if (objc
>= 2 && objc
<= 4) {
9422 function
= string_to_func(Tcl_GetString(objv
[1]), &value
);
9424 result
= (short)Tcl_GetIntFromObj(interp
, objv
[2], &ival
);
9425 if (result
== TCL_ERROR
) return TCL_ERROR
;
9426 value
= (short)ival
;
9429 newpos
= UGetCursorPos();
9430 user_to_window(newpos
, &wpoint
);
9432 result
= compatible_function(function
);
9434 Tcl_SetResult(interp
, "Action not allowed\n", NULL
);
9436 result
= functiondispatch(function
, value
, wpoint
.x
, wpoint
.y
);
9438 Tcl_SetResult(interp
, "Action not handled\n", NULL
);
9441 Tcl_SetResult(interp
, "Usage: action <action_name> [<value>]\n", NULL
);
9444 return XcTagCallback(interp
, objc
, objv
);
9448 /*----------------------------------------------------------------------*/
9449 /* Argument-converting wrappers from Tk callback to Xt callback format */
9450 /*----------------------------------------------------------------------*/
9452 void xctk_drawarea(ClientData clientData
, XEvent
*eventPtr
)
9455 if (areawin
->topinstance
!= NULL
)
9456 drawarea(areawin
->area
, (caddr_t
)clientData
, (caddr_t
)NULL
);
9459 /*----------------------------------------------------------------------*/
9461 void xctk_resizearea(ClientData clientData
, XEvent
*eventPtr
)
9463 resizearea(areawin
->area
, (caddr_t
)clientData
, (caddr_t
)NULL
);
9464 /* Callback to function "arrangetoolbar" */
9465 Tcl_Eval(xcinterp
, "catch {xcircuit::arrangetoolbar $XCOps(focus)}");
9468 /*----------------------------------------------------------------------*/
9469 /* Because Tk doesn't filter MotionEvent events based on context, we */
9470 /* have to filter the context here. */
9471 /*----------------------------------------------------------------------*/
9473 void xctk_panhbar(ClientData clientData
, XEvent
*eventPtr
)
9475 XMotionEvent
*mevent
= (XMotionEvent
*)eventPtr
;
9476 u_int state
= mevent
->state
;
9477 if (state
& (Button1Mask
| Button2Mask
))
9478 panhbar(areawin
->scrollbarh
, (caddr_t
)clientData
, (XButtonEvent
*)eventPtr
);
9481 /*----------------------------------------------------------------------*/
9483 void xctk_panvbar(ClientData clientData
, XEvent
*eventPtr
)
9485 XMotionEvent
*mevent
= (XMotionEvent
*)eventPtr
;
9486 u_int state
= mevent
->state
;
9487 if (state
& (Button1Mask
| Button2Mask
))
9488 panvbar(areawin
->scrollbarv
, (caddr_t
)clientData
, (XButtonEvent
*)eventPtr
);
9491 /*----------------------------------------------------------------------*/
9493 void xctk_drawhbar(ClientData clientData
, XEvent
*eventPtr
)
9495 if (areawin
->topinstance
)
9496 drawhbar(areawin
->scrollbarh
, (caddr_t
)clientData
, (caddr_t
)NULL
);
9499 /*----------------------------------------------------------------------*/
9501 void xctk_drawvbar(ClientData clientData
, XEvent
*eventPtr
)
9503 if (areawin
->topinstance
)
9504 drawvbar(areawin
->scrollbarv
, (caddr_t
)clientData
, (caddr_t
)NULL
);
9507 /*----------------------------------------------------------------------*/
9509 void xctk_endhbar(ClientData clientData
, XEvent
*eventPtr
)
9511 if (areawin
->topinstance
)
9512 endhbar(areawin
->scrollbarh
, (caddr_t
)clientData
, (XButtonEvent
*)eventPtr
);
9515 /*----------------------------------------------------------------------*/
9517 void xctk_endvbar(ClientData clientData
, XEvent
*eventPtr
)
9519 if (areawin
->topinstance
)
9520 endvbar(areawin
->scrollbarv
, (caddr_t
)clientData
, (XButtonEvent
*)eventPtr
);
9523 /*----------------------------------------------------------------------*/
9525 void xctk_zoomview(ClientData clientData
, XEvent
*eventPtr
)
9527 zoomview((xcWidget
)NULL
, (caddr_t
)clientData
, (caddr_t
)NULL
);
9530 /*----------------------------------------------------------------------*/
9532 void xctk_swapschem(ClientData clientData
, XEvent
*eventPtr
)
9534 swapschem((int)((pointertype
)clientData
), -1, NULL
);
9537 /*----------------------------------------------------------------------*/
9539 void xctk_drag(ClientData clientData
, XEvent
*eventPtr
)
9541 XButtonEvent
*b_event
= (XButtonEvent
*)eventPtr
;
9543 drag((int)b_event
->x
, (int)b_event
->y
);
9546 if (areawin
->redraw_needed
)
9547 drawarea(NULL
, NULL
, NULL
);
9548 #endif /* HAVE_CAIRO */
9551 /*----------------------------------------------------------------------*/
9552 /* This really should be set up so that the "okay" button command tcl */
9553 /* procedure does the job of lookdirectory(). */
9554 /*----------------------------------------------------------------------*/
9556 void xctk_fileselect(ClientData clientData
, XEvent
*eventPtr
)
9558 XButtonEvent
*beventPtr
= (XButtonEvent
*)eventPtr
;
9559 popupstruct
*listp
= (popupstruct
*)clientData
;
9562 if (beventPtr
->button
== Button2
) {
9563 Tcl_Eval(xcinterp
, ".filelist.textent.txt get");
9564 sprintf(curentry
, "%.149s", (char *)Tcl_GetStringResult(xcinterp
));
9566 if (strlen(curentry
) > 0) {
9567 if (lookdirectory(curentry
, 149))
9568 newfilelist(listp
->filew
, listp
);
9570 Tcl_Eval(xcinterp
, ".filelist.bbar.okay invoke");
9573 else if (beventPtr
->button
== Button4
) { /* scroll wheel binding */
9575 showlscroll(listp
->scroll
, NULL
, NULL
);
9576 listfiles(listp
->filew
, listp
, NULL
);
9578 else if (beventPtr
->button
== Button5
) { /* scroll wheel binding */
9580 showlscroll(listp
->scroll
, NULL
, NULL
);
9581 listfiles(listp
->filew
, listp
, NULL
);
9584 fileselect(listp
->filew
, listp
, beventPtr
);
9587 /*----------------------------------------------------------------------*/
9589 void xctk_listfiles(ClientData clientData
, XEvent
*eventPtr
)
9591 popupstruct
*listp
= (popupstruct
*)clientData
;
9594 Tcl_Eval(xcinterp
, ".filelist.listwin.win cget -data");
9595 filter
= (char *)Tcl_GetStringResult(xcinterp
);
9597 if (filter
!= NULL
) {
9598 if ((listp
->filter
== NULL
) || (strcmp(filter
, listp
->filter
))) {
9599 if (listp
->filter
!= NULL
)
9600 free(listp
->filter
);
9601 listp
->filter
= strdup(filter
);
9602 newfilelist(listp
->filew
, listp
);
9605 listfiles(listp
->filew
, listp
, NULL
);
9608 if (listp
->filter
!= NULL
) {
9609 free(listp
->filter
);
9610 listp
->filter
= NULL
;
9612 listfiles(listp
->filew
, listp
, NULL
);
9616 /*----------------------------------------------------------------------*/
9618 void xctk_startfiletrack(ClientData clientData
, XEvent
*eventPtr
)
9620 startfiletrack((Tk_Window
)clientData
, NULL
, (XCrossingEvent
*)eventPtr
);
9623 /*----------------------------------------------------------------------*/
9625 void xctk_endfiletrack(ClientData clientData
, XEvent
*eventPtr
)
9627 endfiletrack((Tk_Window
)clientData
, NULL
, (XCrossingEvent
*)eventPtr
);
9630 /*----------------------------------------------------------------------*/
9632 void xctk_dragfilebox(ClientData clientData
, XEvent
*eventPtr
)
9634 dragfilebox((Tk_Window
)clientData
, NULL
, (XMotionEvent
*)eventPtr
);
9637 /*----------------------------------------------------------------------*/
9639 void xctk_draglscroll(ClientData clientData
, XEvent
*eventPtr
)
9641 popupstruct
*listp
= (popupstruct
*)clientData
;
9642 XMotionEvent
*mevent
= (XMotionEvent
*)eventPtr
;
9643 u_int state
= mevent
->state
;
9645 if (state
& (Button1Mask
| Button2Mask
))
9646 draglscroll(listp
->scroll
, listp
, (XButtonEvent
*)eventPtr
);
9649 /*----------------------------------------------------------------------*/
9651 void xctk_showlscroll(ClientData clientData
, XEvent
*eventPtr
)
9653 showlscroll((Tk_Window
)clientData
, NULL
, NULL
);
9656 /*----------------------------------------------------------------------*/
9657 /* Build or rebuild the database of colors, fonts, and other settings */
9658 /* from the Tk option settings. */
9659 /*----------------------------------------------------------------------*/
9661 void build_app_database(Tk_Window tkwind
)
9665 /*--------------------------*/
9666 /* Build the color database */
9667 /*--------------------------*/
9669 if ((xcuid
= Tk_GetOption(tkwind
, "globalpincolor", "Color")) == NULL
)
9671 appdata
.globalcolor
= xc_alloccolor((char *)xcuid
);
9672 if ((xcuid
= Tk_GetOption(tkwind
, "localpincolor", "Color")) == NULL
)
9674 appdata
.localcolor
= xc_alloccolor((char *)xcuid
);
9675 if ((xcuid
= Tk_GetOption(tkwind
, "infolabelcolor", "Color")) == NULL
)
9677 appdata
.infocolor
= xc_alloccolor((char *)xcuid
);
9678 if ((xcuid
= Tk_GetOption(tkwind
, "ratsnestcolor", "Color")) == NULL
)
9680 appdata
.ratsnestcolor
= xc_alloccolor((char *)xcuid
);
9682 if ((xcuid
= Tk_GetOption(tkwind
, "bboxcolor", "Color")) == NULL
)
9683 xcuid
= "greenyellow";
9684 appdata
.bboxpix
= xc_alloccolor((char *)xcuid
);
9686 if ((xcuid
= Tk_GetOption(tkwind
, "fixedbboxcolor", "Color")) == NULL
)
9688 appdata
.fixedbboxpix
= xc_alloccolor((char *)xcuid
);
9690 if ((xcuid
= Tk_GetOption(tkwind
, "clipcolor", "Color")) == NULL
)
9691 xcuid
= "powderblue";
9692 appdata
.clipcolor
= xc_alloccolor((char *)xcuid
);
9694 if ((xcuid
= Tk_GetOption(tkwind
, "paramcolor", "Color")) == NULL
)
9696 appdata
.parampix
= xc_alloccolor((char *)xcuid
);
9697 if ((xcuid
= Tk_GetOption(tkwind
, "auxiliarycolor", "Color")) == NULL
)
9699 appdata
.auxpix
= xc_alloccolor((char *)xcuid
);
9700 if ((xcuid
= Tk_GetOption(tkwind
, "axescolor", "Color")) == NULL
)
9701 xcuid
= "Antique White";
9702 appdata
.axespix
= xc_alloccolor((char *)xcuid
);
9703 if ((xcuid
= Tk_GetOption(tkwind
, "filtercolor", "Color")) == NULL
)
9704 xcuid
= "SteelBlue3";
9705 appdata
.filterpix
= xc_alloccolor((char *)xcuid
);
9706 if ((xcuid
= Tk_GetOption(tkwind
, "selectcolor", "Color")) == NULL
)
9708 appdata
.selectpix
= xc_alloccolor((char *)xcuid
);
9709 if ((xcuid
= Tk_GetOption(tkwind
, "snapcolor", "Color")) == NULL
)
9711 appdata
.snappix
= xc_alloccolor((char *)xcuid
);
9712 if ((xcuid
= Tk_GetOption(tkwind
, "gridcolor", "Color")) == NULL
)
9714 appdata
.gridpix
= xc_alloccolor((char *)xcuid
);
9715 if ((xcuid
= Tk_GetOption(tkwind
, "pagebackground", "Color")) == NULL
)
9717 appdata
.bg
= xc_alloccolor((char *)xcuid
);
9718 if ((xcuid
= Tk_GetOption(tkwind
, "pageforeground", "Color")) == NULL
)
9720 appdata
.fg
= xc_alloccolor((char *)xcuid
);
9722 if ((xcuid
= Tk_GetOption(tkwind
, "paramcolor2", "Color")) == NULL
)
9724 appdata
.parampix2
= xc_alloccolor((char *)xcuid
);
9725 if ((xcuid
= Tk_GetOption(tkwind
, "auxiliarycolor2", "Color")) == NULL
)
9727 appdata
.auxpix2
= xc_alloccolor((char *)xcuid
);
9728 if ((xcuid
= Tk_GetOption(tkwind
, "selectcolor2", "Color")) == NULL
)
9730 appdata
.selectpix2
= xc_alloccolor((char *)xcuid
);
9731 if ((xcuid
= Tk_GetOption(tkwind
, "filtercolor2", "Color")) == NULL
)
9732 xcuid
= "SteelBlue1";
9733 appdata
.gridpix2
= xc_alloccolor((char *)xcuid
);
9734 if ((xcuid
= Tk_GetOption(tkwind
, "snapcolor2", "Color")) == NULL
)
9736 appdata
.snappix2
= xc_alloccolor((char *)xcuid
);
9737 if ((xcuid
= Tk_GetOption(tkwind
, "axescolor2", "Color")) == NULL
)
9738 xcuid
= "NavajoWhite4";
9739 appdata
.axespix2
= xc_alloccolor((char *)xcuid
);
9740 if ((xcuid
= Tk_GetOption(tkwind
, "background2", "Color")) == NULL
)
9741 xcuid
= "DarkSlateGray";
9742 appdata
.bg2
= xc_alloccolor((char *)xcuid
);
9743 if ((xcuid
= Tk_GetOption(tkwind
, "foreground2", "Color")) == NULL
)
9745 appdata
.fg2
= xc_alloccolor((char *)xcuid
);
9746 if ((xcuid
= Tk_GetOption(tkwind
, "barcolor", "Color")) == NULL
)
9748 appdata
.barpix
= xc_alloccolor((char *)xcuid
);
9750 /* These are GUI colors---unused by Tcl */
9751 appdata
.buttonpix
= xc_alloccolor("Gray85");
9752 appdata
.buttonpix2
= xc_alloccolor("Gray50");
9754 /* Get some default fonts (Should be using Tk calls here. . . ) */
9756 if ((xcuid
= Tk_GetOption(tkwind
, "filelistfont", "Font")) == NULL
)
9757 xcuid
= "-*-helvetica-medium-r-normal--14-*";
9758 appdata
.filefont
= XLoadQueryFont(dpy
, (char *)xcuid
);
9760 if (appdata
.filefont
== NULL
)
9762 appdata
.filefont
= XLoadQueryFont(dpy
, "-*-*-medium-r-normal--14-*");
9763 if (appdata
.filefont
== NULL
)
9764 appdata
.filefont
= XLoadQueryFont(dpy
, "-*-*-*-*-*--*-*");
9767 /* Other defaults */
9769 if ((xcuid
= Tk_GetOption(tkwind
, "timeout", "TimeOut")) == NULL
)
9771 appdata
.timeout
= atoi((char *)xcuid
);
9774 /*--------------------------------------------------------------*/
9775 /* GUI Initialization under Tk */
9776 /* First argument is the Tk path name of the drawing window. */
9777 /* This function should be called for each new window created. */
9778 /*--------------------------------------------------------------*/
9780 XCWindowData
*GUI_init(int objc
, Tcl_Obj
*CONST objv
[])
9782 Tk_Window tkwind
, tktop
, tkdraw
, tksb
;
9783 Tk_Window wsymb
, wschema
, corner
;
9784 int i
, locobjc
, done
= 1;
9787 popupstruct
*fileliststruct
;
9788 char *xctopwin
, *xcdrawwin
;
9790 XCWindowData
*newwin
;
9792 tktop
= Tk_MainWindow(xcinterp
);
9793 if (tktop
== (Tk_Window
)NULL
) {
9794 Fprintf(stderr
, "No Top-Level Tk window available. . .\n");
9796 /* No top level window, assuming batch mode. To get */
9797 /* access to font information requires that cairo be set */
9798 /* up with a surface, even if it is not an xlib target. */
9800 newwin
= create_new_window();
9801 newwin
->area
= NULL
;
9802 newwin
->scrollbarv
= NULL
;
9803 newwin
->scrollbarh
= NULL
;
9804 newwin
->width
= 100;
9805 newwin
->height
= 100;
9808 newwin
->surface
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
,
9809 newwin
->width
, newwin
->height
);
9810 newwin
->cr
= cairo_create(newwin
->surface
);
9811 #endif /* !HAVE_CAIRO */
9813 number_colors
= NUMBER_OF_COLORS
;
9814 colorlist
= (colorindex
*)malloc(NUMBER_OF_COLORS
* sizeof(colorindex
));
9819 /* Check if any parameter is a Tk window name */
9822 while (locobjc
> 0) {
9823 xctopwin
= Tcl_GetString(objv
[locobjc
- 1]);
9824 tkwind
= Tk_NameToWindow(xcinterp
, xctopwin
, tktop
);
9825 if (tkwind
!= (Tk_Window
)NULL
)
9831 /* Okay to have no GUI wrapper. However, if this is the case, */
9832 /* then the variable "XCOps(window)" must be set to the Tk path */
9833 /* name of the drawing window. */
9835 xcdrawwin
= (char *)Tcl_GetVar2(xcinterp
, "XCOps", "window", 0);
9836 if (xcdrawwin
== NULL
) {
9837 Fprintf(stderr
, "The Tk window hierarchy must be rooted at"
9838 " .xcircuit, or XCOps(top)");
9839 Fprintf(stderr
, " must point to the hierarchy. If XCOps(top)"
9840 " is NULL, then XCOps(window) must");
9841 Fprintf(stderr
, " point to the drawing window.\n");
9844 tkwind
= Tk_NameToWindow(xcinterp
, xcdrawwin
, tktop
);
9845 if (tkwind
== NULL
) {
9846 Fprintf(stderr
, "Error: XCOps(window) is set but does not point to"
9847 " a valid Tk window.\n");
9851 /* Create new window data structure */
9852 newwin
= create_new_window();
9853 newwin
->area
= tkwind
;
9855 /* No GUI---GUI widget pointers need to be NULL'd */
9856 newwin
->scrollbarv
= NULL
;
9857 newwin
->scrollbarh
= NULL
;
9861 /* Expect a top-level window name passed as the first argument. */
9862 /* Having a fixed hierarchy is a total kludge and needs to be */
9863 /* rewritten. . . */
9865 if (tkwind
== NULL
) {
9866 Fprintf(stderr
, "Error: config init given a bad window name!\n");
9870 /* Make sure that this window does not already exist */
9871 XCWindowDataPtr searchwin
;
9872 sprintf(winpath
, "%s.mainframe.mainarea.drawing", xctopwin
);
9873 tkdraw
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9874 for (searchwin
= xobjs
.windowlist
; searchwin
!= NULL
; searchwin
=
9876 if (searchwin
->area
== tkdraw
) {
9877 Fprintf(stderr
, "Error: window already exists!\n");
9883 /* Create new window data structure and */
9884 /* fill in global variables from the Tk window values */
9886 newwin
= create_new_window();
9887 sprintf(winpath
, "%s.mainframe.mainarea.sbleft", xctopwin
);
9888 newwin
->scrollbarv
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9889 sprintf(winpath
, "%s.mainframe.mainarea.sbbottom", xctopwin
);
9890 newwin
->scrollbarh
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9891 sprintf(winpath
, "%s.mainframe.mainarea.drawing", xctopwin
);
9892 newwin
->area
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9894 sprintf(winpath
, "%s.mainframe.mainarea.corner", xctopwin
);
9895 corner
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9897 sprintf(winpath
, "%s.infobar.symb", xctopwin
);
9898 wsymb
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9900 sprintf(winpath
, "%s.infobar.schem", xctopwin
);
9901 wschema
= Tk_NameToWindow(xcinterp
, winpath
, tktop
);
9903 Tk_CreateEventHandler(newwin
->scrollbarh
, ButtonMotionMask
,
9904 (Tk_EventProc
*)xctk_panhbar
, NULL
);
9905 Tk_CreateEventHandler(newwin
->scrollbarv
, ButtonMotionMask
,
9906 (Tk_EventProc
*)xctk_panvbar
, NULL
);
9907 Tk_CreateEventHandler(newwin
->scrollbarh
, StructureNotifyMask
| ExposureMask
,
9908 (Tk_EventProc
*)xctk_drawhbar
, NULL
);
9909 Tk_CreateEventHandler(newwin
->scrollbarv
, StructureNotifyMask
| ExposureMask
,
9910 (Tk_EventProc
*)xctk_drawvbar
, NULL
);
9911 Tk_CreateEventHandler(newwin
->scrollbarh
, ButtonReleaseMask
,
9912 (Tk_EventProc
*)xctk_endhbar
, NULL
);
9913 Tk_CreateEventHandler(newwin
->scrollbarv
, ButtonReleaseMask
,
9914 (Tk_EventProc
*)xctk_endvbar
, NULL
);
9916 Tk_CreateEventHandler(corner
, ButtonPressMask
,
9917 (Tk_EventProc
*)xctk_zoomview
, Number(1));
9918 Tk_CreateEventHandler(wsymb
, ButtonPressMask
,
9919 (Tk_EventProc
*)xctk_swapschem
, Number(0));
9920 Tk_CreateEventHandler(wschema
, ButtonPressMask
,
9921 (Tk_EventProc
*)xctk_swapschem
, Number(0));
9923 /* Setup event handlers for the drawing area and scrollbars */
9924 /* There are purposely no callback functions for these windows---they are */
9925 /* defined as type "simple" to keep down the cruft, as I will define my */
9926 /* own event handlers. */
9928 Tk_CreateEventHandler(newwin
->area
, StructureNotifyMask
,
9929 (Tk_EventProc
*)xctk_resizearea
, NULL
);
9930 Tk_CreateEventHandler(newwin
->area
, ExposureMask
,
9931 (Tk_EventProc
*)xctk_drawarea
, NULL
);
9934 if ((locobjc
> 0) || !Tk_IsMapped(newwin
->area
)) {
9936 /* This code copied from code for the "tkwait" command */
9938 Tk_CreateEventHandler(newwin
->area
,
9939 VisibilityChangeMask
|StructureNotifyMask
,
9940 WaitVisibilityProc
, (ClientData
) &done
);
9944 /* Make sure the window is mapped */
9946 Tk_MapWindow(tkwind
);
9947 win
= Tk_WindowId(tkwind
);
9948 Tk_MapWindow(newwin
->area
);
9951 while (!done
) Tcl_DoOneEvent(0);
9952 Tk_DeleteEventHandler(newwin
->area
,
9953 VisibilityChangeMask
|StructureNotifyMask
,
9954 WaitVisibilityProc
, (ClientData
) &done
);
9957 newwin
->window
= Tk_WindowId(newwin
->area
);
9958 newwin
->width
= Tk_Width(newwin
->area
);
9959 newwin
->height
= Tk_Height(newwin
->area
);
9961 /* Things to set once only */
9964 dpy
= Tk_Display(tkwind
);
9965 cmap
= Tk_Colormap(tkwind
);
9966 // (The following may be required on some systems where
9967 // Tk will not report a valid colormap after Tk_MapWindow())
9968 // cmap = DefaultColormap(dpy, DefaultScreen(dpy));
9970 /*-------------------------*/
9971 /* Create stipple patterns */
9972 /*-------------------------*/
9974 for (i
= 0; i
< STIPPLES
; i
++)
9975 STIPPLE
[i
] = XCreateBitmapFromData(dpy
, win
, STIPDATA
[i
], 4, 4);
9977 /*----------------------------------------*/
9978 /* Allocate space for the basic color map */
9979 /*----------------------------------------*/
9981 number_colors
= NUMBER_OF_COLORS
;
9982 colorlist
= (colorindex
*)malloc(NUMBER_OF_COLORS
* sizeof(colorindex
));
9984 build_app_database(tkwind
);
9987 /* Create the filelist window and its event handlers */
9989 tksb
= Tk_NameToWindow(xcinterp
, ".filelist.listwin.sb", tktop
);
9990 tkdraw
= Tk_NameToWindow(xcinterp
, ".filelist.listwin.win", tktop
);
9992 fileliststruct
= (popupstruct
*) malloc(sizeof(popupstruct
));
9993 fileliststruct
->popup
= Tk_NameToWindow(xcinterp
, ".filelist", tktop
);
9994 fileliststruct
->textw
= Tk_NameToWindow(xcinterp
, ".filelist.textent",
9995 fileliststruct
->popup
);
9996 fileliststruct
->filew
= tkdraw
;
9997 fileliststruct
->scroll
= tksb
;
9998 fileliststruct
->setvalue
= NULL
;
9999 fileliststruct
->filter
= NULL
;
10001 if (tksb
!= NULL
) {
10002 Tk_CreateEventHandler(tksb
, ButtonMotionMask
,
10003 (Tk_EventProc
*)xctk_draglscroll
, (ClientData
)fileliststruct
);
10004 Tk_CreateEventHandler(tksb
, ExposureMask
,
10005 (Tk_EventProc
*)xctk_showlscroll
, (ClientData
)tksb
);
10007 if (tkdraw
!= NULL
) {
10008 Tk_CreateEventHandler(tkdraw
, ButtonPressMask
,
10009 (Tk_EventProc
*)xctk_fileselect
, (ClientData
)fileliststruct
);
10010 Tk_CreateEventHandler(tkdraw
, ExposureMask
,
10011 (Tk_EventProc
*)xctk_listfiles
, (ClientData
)fileliststruct
);
10012 Tk_CreateEventHandler(tkdraw
, EnterWindowMask
,
10013 (Tk_EventProc
*)xctk_startfiletrack
, (ClientData
)tkdraw
);
10014 Tk_CreateEventHandler(tkdraw
, LeaveWindowMask
,
10015 (Tk_EventProc
*)xctk_endfiletrack
, (ClientData
)tkdraw
);
10019 /*-------------------------------------------------------------------*/
10020 /* Generate the GC */
10021 /* Set "graphics_exposures" to False. Every XCopyArea function */
10022 /* copies from virtual memory (dbuf pixmap), which can never be */
10023 /* obscured. Otherwise, the server gets flooded with useless */
10024 /* NoExpose events. */
10025 /*-------------------------------------------------------------------*/
10027 values
.foreground
= BlackPixel(dpy
, DefaultScreen(dpy
));
10028 values
.background
= WhitePixel(dpy
, DefaultScreen(dpy
));
10029 values
.graphics_exposures
= False
;
10030 newwin
->gc
= XCreateGC(dpy
, win
, GCForeground
| GCBackground
10031 | GCGraphicsExposures
, &values
);
10034 newwin
->surface
= cairo_xlib_surface_create(dpy
, newwin
->window
,
10035 DefaultVisual(dpy
, 0), newwin
->width
, newwin
->height
);
10036 newwin
->cr
= cairo_create(newwin
->surface
);
10037 #else /* HAVE_CAIRO */
10038 newwin
->clipmask
= XCreatePixmap(dpy
, win
, newwin
->width
,
10039 newwin
->height
, 1);
10041 values
.foreground
= 0;
10042 values
.background
= 0;
10043 newwin
->cmgc
= XCreateGC(dpy
, newwin
->clipmask
, GCForeground
10044 | GCBackground
, &values
);
10045 #endif /* HAVE_CAIRO */
10047 XDefineCursor (dpy
, win
, *newwin
->defaultcursor
);
10051 /*--------------------------------------*/
10052 /* Inline the main wrapper prodedure */
10053 /*--------------------------------------*/
10055 int xctcl_start(ClientData clientData
, Tcl_Interp
*interp
,
10056 int objc
, Tcl_Obj
*CONST objv
[])
10058 int result
= TCL_OK
;
10059 Boolean rcoverride
= False
;
10060 char *filearg
= NULL
;
10061 Tcl_Obj
*cmdname
= objv
[0];
10063 Fprintf(stdout
, "Starting xcircuit under Tcl interpreter\n");
10065 /* xcircuit initialization routines --- these assume that the */
10066 /* GUI has been created by the startup script; otherwise bad */
10067 /* things will probably occur. */
10070 areawin
= GUI_init(--objc
, ++objv
);
10071 if (areawin
== NULL
) {
10072 /* Create new window data structure */
10073 areawin
= create_new_window();
10074 areawin
->area
= NULL
;
10075 areawin
->scrollbarv
= NULL
;
10076 areawin
->scrollbarh
= NULL
;
10078 Tcl_SetResult(interp
, "Invalid or missing top-level windowname"
10079 " given to start command, assuming batch mode.\n", NULL
);
10085 /* The Tcl version accepts some command-line arguments. Due */
10086 /* to the way ".wishrc" is processed, all arguments are */
10087 /* glommed into one Tcl (list) object, objv[1]. */
10089 filearg
= (char *)malloc(sizeof(char));
10096 Tcl_SplitList(interp
, Tcl_GetString(objv
[1]), &argc
,
10097 (CONST84
char ***)&argv
);
10099 if (**argv
== '-') {
10100 if (!strncmp(*argv
, "-exec", 5)) {
10103 result
= Tcl_EvalFile(interp
, *argv
);
10104 if (result
!= TCL_OK
) {
10112 Tcl_SetResult(interp
, "No filename given to exec argument.", NULL
);
10117 else if (!strncmp(*argv
, "-2", 2)) {
10118 /* 2-button mouse bindings option */
10122 else if (strcmp(*argv
, ".xcircuit")) {
10123 filearg
= (char *)realloc(filearg
, sizeof(char) *
10124 (strlen(filearg
) + strlen(*argv
) + 2));
10125 strcat(filearg
, ",");
10126 strcat(filearg
, *argv
);
10133 /* Except---this appears to be no longer true. When did it change? */
10137 for (argc
= 0; argc
< objc
; argc
++) {
10138 argv
= Tcl_GetString(objv
[argc
]);
10139 if (*argv
== '-') {
10140 if (!strncmp(argv
, "-exec", 5)) {
10141 if (++argc
< objc
) {
10142 argv
= Tcl_GetString(objv
[argc
]);
10143 result
= Tcl_EvalFile(interp
, argv
);
10144 if (result
!= TCL_OK
) {
10152 Tcl_SetResult(interp
, "No filename given to exec argument.", NULL
);
10157 else if (!strncmp(argv
, "-2", 2)) {
10158 /* 2-button mouse bindings option */
10162 else if (strcmp(argv
, ".xcircuit")) {
10163 filearg
= (char *)realloc(filearg
, sizeof(char) *
10164 (strlen(filearg
) + strlen(argv
) + 2));
10165 strcat(filearg
, ",");
10166 strcat(filearg
, argv
);
10172 result
= loadrcfile();
10174 composelib(PAGELIB
); /* make sure we have a valid page list */
10175 composelib(LIBLIB
); /* and library directory */
10176 if ((objc
>= 2) && (*filearg
!= '\0')) {
10180 strcpy(_STR2
, filearg
);
10181 libname
= (char *)Tcl_GetVar2(xcinterp
, "XCOps", "library", 0);
10182 if (libname
!= NULL
) {
10183 target
= NameToLibrary(libname
);
10185 startloadfile((target
>= 0) ? target
+ LIBRARY
: -1);
10190 pressmode
= 0; /* Done using this to track 2-button bindings */
10192 /* Note that because the setup has the windows generated and */
10193 /* mapped prior to calling the xcircuit routines, nothing */
10194 /* gets CreateNotify, MapNotify, or other definitive events. */
10195 /* So, we have to do all the drawing once. */
10197 xobjs
.suspend
= -1; /* Release from suspend mode */
10198 if (areawin
->scrollbarv
)
10199 drawvbar(areawin
->scrollbarv
, NULL
, NULL
);
10200 if (areawin
->scrollbarh
)
10201 drawhbar(areawin
->scrollbarh
, NULL
, NULL
);
10202 drawarea(areawin
->area
, NULL
, NULL
);
10204 /* Return back to the interpreter; Tk is handling the GUI */
10206 return (result
== TCL_OK
) ? XcTagCallback(interp
, 1, &cmdname
) : result
;
10209 /*--------------------------------------------------------------*/
10210 /* Message printing procedures for the Tcl version */
10212 /* Evaluate the variable-length argument, and make a call to */
10213 /* the routine xcircuit::print, which should be defined. */
10214 /*--------------------------------------------------------------*/
10216 void W0vprintf(char *window
, const char *format
, va_list args_in
)
10218 char tstr
[128], *bigstr
= NULL
, *strptr
;
10222 if (window
!= NULL
) {
10223 sprintf(tstr
, "catch {xcircuit::print %s {", window
);
10224 size
= strlen(tstr
);
10226 va_copy(args
, args_in
);
10227 n
= vsnprintf(tstr
+ size
, 128 - size
, format
, args
);
10230 if (n
<= -1 || n
> 125 - size
) {
10231 bigstr
= malloc(n
+ size
+ 4);
10232 strncpy(bigstr
, tstr
, size
);
10233 va_copy(args
, args_in
);
10234 vsnprintf(bigstr
+ size
, n
+ 1, format
, args
);
10237 strcat(bigstr
, "}}");
10241 strcat(tstr
, "}}");
10243 Tcl_Eval(xcinterp
, strptr
);
10244 if (bigstr
!= NULL
) free(bigstr
);
10248 /* Prints to pagename window */
10250 void W1printf(char *format
, ...)
10253 va_start(args
, format
);
10254 W0vprintf("coord", format
, args
);
10258 /* Prints to coordinate window */
10260 void W2printf(char *format
, ...)
10263 va_start(args
, format
);
10264 W0vprintf("page", format
, args
);
10268 /* Prints to status window but does not tee output to the console. */
10270 void W3printf(char *format
, ...)
10273 va_start(args
, format
);
10274 W0vprintf("stat", format
, args
);
10278 /* Prints to status window and duplicates the output to stdout. */
10280 void Wprintf(char *format
, ...)
10283 va_start(args
, format
);
10284 W0vprintf("stat", format
, args
);
10285 if (strlen(format
) > 0) {
10286 if (strstr(format
, "Error")) {
10287 tcl_vprintf(stderr
, format
, args
);
10288 tcl_printf(stderr
, "\n");
10291 tcl_vprintf(stdout
, format
, args
);
10292 tcl_printf(stdout
, "\n");
10298 /*------------------------------------------------------*/
10300 #endif /* defined(TCL_WRAPPER) && !defined(HAVE_PYTHON) */