1 /*----------------------------------------------------------------------*/
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*----------------------------------------------------------------------*/
6 /*----------------------------------------------------------------------*/
7 /* written by Tim Edwards, 10/26/99 */
8 /* revised for segmented strings, 3/8/01 */
9 /*----------------------------------------------------------------------*/
16 #include <X11/Intrinsic.h>
17 #include <X11/StringDefs.h>
28 /*----------------------------------------------------------------------*/
30 /*----------------------------------------------------------------------*/
35 /*----------------------------------------------------------------------*/
36 /* Function prototype declarations */
37 /*----------------------------------------------------------------------*/
38 #include "prototypes.h"
40 /*----------------------------------------------------------------------*/
41 /* Externally declared global variables */
42 /*----------------------------------------------------------------------*/
45 extern Tcl_Interp
*xcinterp
;
47 extern Globaldata xobjs
;
48 extern XCWindowData
*areawin
;
50 extern Widget menuwidgets
[];
52 extern char _STR
[150];
54 /*----------------------------------------------------------------------*/
55 /* The following u_char array matches parameterization types to element */
56 /* types which are able to accept the given parameterization. */
57 /*----------------------------------------------------------------------*/
59 u_char param_select
[] = {
60 ALL_TYPES
, /* P_NUMERIC */
61 LABEL
, /* P_SUBSTRING */
62 POLYGON
| SPLINE
| LABEL
| OBJINST
| ARC
, /* P_POSITION_X */
63 POLYGON
| SPLINE
| LABEL
| OBJINST
| ARC
, /* P_POSITION_Y */
64 POLYGON
| SPLINE
| ARC
| PATH
, /* P_STYLE */
69 ARC
, /* P_MINOR_AXIS */
70 LABEL
| OBJINST
, /* P_ROTATION */
71 LABEL
| OBJINST
, /* P_SCALE */
72 POLYGON
| SPLINE
| ARC
| PATH
, /* P_LINEWIDTH */
73 ALL_TYPES
, /* P_COLOR */
74 ALL_TYPES
, /* P_EXPRESSION */
75 POLYGON
| SPLINE
| LABEL
| OBJINST
| ARC
/* P_POSITION */
80 xcWidget
*param_buttons
[] = { NULL
/* (jdk) */
81 /* To be done---map buttons to Tk_Windows! */
84 xcWidget
*param_buttons
[];
87 Widget
*param_buttons
[] = {
88 &ParametersNumericButton
, /* P_NUMERIC */
89 &ParametersSubstringButton
, /* P_SUBSTRING */
90 &ParametersPositionButton
, /* P_POSITION_X */
91 &ParametersPositionButton
, /* P_POSITION_Y */
92 &ParametersStyleButton
, /* P_STYLE */
93 &ParametersAnchoringButton
, /* P_ANCHOR */
94 &ParametersStartAngleButton
, /* P_ANGLE1 */
95 &ParametersEndAngleButton
, /* P_ANGLE2 */
96 &ParametersRadiusButton
, /* P_RADIUS */
97 &ParametersMinorAxisButton
, /* P_MINOR_AXIS */
98 &ParametersRotationButton
, /* P_ROTATION */
99 &ParametersScaleButton
, /* P_SCALE */
100 &ParametersLinewidthButton
, /* P_LINEWIDTH */
101 &ParametersColorButton
, /* P_COLOR */
102 &ParametersPositionButton
, /* P_POSITION */
106 /*----------------------------------------------------------------------*/
107 /* Basic routines for matching parameters by key values. Note that */
108 /* this really, really ought to be replaced by a hash table search! */
109 /*----------------------------------------------------------------------*/
111 /*----------------------------------------------------------------------*/
112 /* Check for the existance of a parameter with key "key" in object */
113 /* "thisobj". Return true if the parameter exists. */
114 /*----------------------------------------------------------------------*/
116 Boolean
check_param(objectptr thisobj
, char *key
)
120 for (tops
= thisobj
->params
; tops
!= NULL
; tops
= tops
->next
)
121 if (!strcmp(tops
->key
, key
))
127 /*----------------------------------------------------------------------*/
128 /* Create a new parameter; allocate memory for the parameter and the */
130 /*----------------------------------------------------------------------*/
132 oparamptr
make_new_parameter(char *key
)
136 newops
= (oparamptr
)malloc(sizeof(oparam
));
138 newops
->key
= (char *)malloc(1 + strlen(key
));
139 strcpy(newops
->key
, key
);
143 /*----------------------------------------------------------------------*/
144 /* Create a new element (numeric) parameter. Fill in essential values */
145 /*----------------------------------------------------------------------*/
147 eparamptr
make_new_eparam(char *key
)
151 newepp
= (eparamptr
)malloc(sizeof(eparam
));
153 newepp
->key
= (char *)malloc(1 + strlen(key
));
154 strcpy(newepp
->key
, key
);
155 newepp
->pdata
.refkey
= NULL
; /* equivalently, sets pointno=0 */
161 /*----------------------------------------------------------------------*/
162 /* Determine if a parameter is indirectly referenced. If so, return */
163 /* the parameter name. If not, return NULL. */
164 /*----------------------------------------------------------------------*/
166 char *find_indirect_param(objinstptr thisinst
, char *refkey
)
170 for (epp
= thisinst
->passed
; epp
!= NULL
; epp
= epp
->next
) {
171 if ((epp
->flags
& P_INDIRECT
) && !strcmp(epp
->pdata
.refkey
, refkey
))
177 /*----------------------------------------------------------------------*/
178 /* Find the parameter in the indicated object by key */
179 /*----------------------------------------------------------------------*/
181 oparamptr
match_param(objectptr thisobj
, char *key
)
185 for (fparam
= thisobj
->params
; fparam
!= NULL
; fparam
= fparam
->next
)
186 if (!strcmp(fparam
->key
, key
))
189 return NULL
; /* No parameter matched the key---error condition */
192 /*----------------------------------------------------------------------*/
193 /* Find the parameter in the indicated instance by key. If no such */
194 /* instance value exists, return NULL. */
195 /*----------------------------------------------------------------------*/
197 oparamptr
match_instance_param(objinstptr thisinst
, char *key
)
201 for (fparam
= thisinst
->params
; fparam
!= NULL
; fparam
= fparam
->next
)
202 if (!strcmp(fparam
->key
, key
))
205 return NULL
; /* No parameter matched the key---error condition */
208 /*----------------------------------------------------------------------*/
209 /* Find the parameter in the indicated instance by key. If no such */
210 /* instance value exists, return the object (default) parameter. */
212 /* find_param() hides instances of expression parameters, returning the */
213 /* default parameter value. In cases where the instance value (last */
214 /* evaluated expression result) is needed, use match_instance_param(). */
215 /* An exception is made when the instance param has type XC_EXPR, */
216 /* indicating that the instance redefines the entire expression. */
217 /*----------------------------------------------------------------------*/
219 oparamptr
find_param(objinstptr thisinst
, char *key
)
221 oparamptr fparam
, ops
;
222 fparam
= match_instance_param(thisinst
, key
);
223 ops
= match_param(thisinst
->thisobject
, key
);
224 if ((fparam
== NULL
) || ((ops
->type
== XC_EXPR
) && (fparam
->type
!= XC_EXPR
)))
230 /*----------------------------------------------------------------------*/
231 /* Find the total number of parameters in an object */
232 /*----------------------------------------------------------------------*/
234 int get_num_params(objectptr thisobj
)
239 for (fparam
= thisobj
->params
; fparam
!= NULL
; fparam
= fparam
->next
)
244 /*----------------------------------------------------------------------*/
245 /* Remove all element parameters from an element */
246 /*----------------------------------------------------------------------*/
248 void free_all_eparams(genericptr thiselem
)
250 while (thiselem
->passed
!= NULL
)
251 free_element_param(thiselem
, thiselem
->passed
);
254 /*----------------------------------------------------------------------*/
255 /* Remove an element parameter (eparam) and free memory associated with */
256 /* the parameter key. */
257 /*----------------------------------------------------------------------*/
259 void free_element_param(genericptr thiselem
, eparamptr thisepp
)
261 eparamptr epp
, lastepp
= NULL
;
263 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
264 if (epp
== thisepp
) {
266 lastepp
->next
= epp
->next
;
268 thiselem
->passed
= epp
->next
;
270 /* If object is an instance and the pdata record is not NULL, */
271 /* then this is an indirect reference with the reference key */
272 /* stored as an allocated string in pdata.refkey, which needs */
275 if ((epp
->flags
& P_INDIRECT
) && (epp
->pdata
.refkey
!= NULL
))
276 free(epp
->pdata
.refkey
);
286 /*----------------------------------------------------------------------*/
287 /* Free an instance parameter. Note that this routine does not free */
288 /* any strings associated with string parameters! */
290 /* Return a pointer to the entry before the one deleted, so we can use */
291 /* free_instance_param() inside a loop over an instance's parameters */
292 /* without having to keep track of the previous pointer position. */
293 /*----------------------------------------------------------------------*/
295 oparamptr
free_instance_param(objinstptr thisinst
, oparamptr thisparam
)
297 oparamptr ops
, lastops
= NULL
;
299 for (ops
= thisinst
->params
; ops
!= NULL
; ops
= ops
->next
) {
300 if (ops
== thisparam
) {
302 lastops
->next
= ops
->next
;
304 thisinst
->params
= ops
->next
;
314 /*----------------------------------------------------------------------*/
315 /* Convenience function used by files.c to set a color parameter. */
316 /*----------------------------------------------------------------------*/
318 void std_eparam(genericptr gen
, char *key
)
322 if (key
== NULL
) return;
324 epp
= make_new_eparam(key
);
325 epp
->next
= gen
->passed
;
329 /*----------------------------------------------*/
330 /* Draw a circle at all parameter positions */
331 /*----------------------------------------------*/
333 void indicateparams(genericptr thiselem
)
340 if (thiselem
!= NULL
) {
341 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
342 ops
= match_param(topobject
, epp
->key
);
343 if (ops
== NULL
) continue; /* error condition */
344 if (ELEMENTTYPE(thiselem
) == PATH
)
345 k
= epp
->pdata
.pathpt
[1];
347 k
= epp
->pdata
.pointno
;
350 case P_POSITION
: case P_POSITION_X
: case P_POSITION_Y
:
351 switch(thiselem
->type
) {
353 UDrawCircle(&TOARC(&thiselem
)->position
, ops
->which
);
356 UDrawCircle(&TOLABEL(&thiselem
)->position
, ops
->which
);
359 UDrawCircle(&TOOBJINST(&thiselem
)->position
, ops
->which
);
362 UDrawCircle(TOPOLY(&thiselem
)->points
+ k
, ops
->which
);
365 UDrawCircle(&TOSPLINE(&thiselem
)->ctrl
[k
], ops
->which
);
368 if (epp
->pdata
.pathpt
[0] < 0)
369 pgen
= ((pathptr
)thiselem
)->plist
;
371 pgen
= ((pathptr
)thiselem
)->plist
+ epp
->pdata
.pathpt
[0];
372 if (ELEMENTTYPE(*pgen
) == POLYGON
)
373 UDrawCircle(TOPOLY(pgen
)->points
+ k
, ops
->which
);
375 UDrawCircle(&TOSPLINE(pgen
)->ctrl
[k
], ops
->which
);
384 /*----------------------------------------------*/
385 /* Set the menu marks according to properties */
386 /* which are parameterized. Unmanage the */
387 /* buttons which do not apply. */
389 /* pgen = NULL returns menu to default settings */
390 /*----------------------------------------------*/
393 void setparammarks(genericptr thiselem
)
395 /* Set GUI variables associated with the "parameter" menu. */
400 Boolean ptest
[NUM_PARAM_TYPES
];
402 for (i
= 0; i
< NUM_PARAM_TYPES
; i
++)
405 /* For each parameter declared, set the corresponding Tcl variable */
406 if (thiselem
!= NULL
) {
407 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
408 ops
= match_param(topobject
, epp
->key
);
409 if (ops
== NULL
) continue; /* error condition */
410 XcInternalTagCall(xcinterp
, 3, "parameter", "make",
411 translateparamtype(ops
->which
));
412 ptest
[ops
->which
] = TRUE
;
416 /* Now reset all of those parameters that were not set above. */
417 /* Note that the parameters that we want to mark ignore the following types: */
418 /* "numeric", "substring", "expression", and "position". */
420 for (i
= P_POSITION_X
; i
<= P_COLOR
; i
++)
421 if (ptest
[i
] != TRUE
)
422 XcInternalTagCall(xcinterp
, 3, "parameter", "replace", translateparamtype(i
));
426 void setparammarks(genericptr thiselem
)
430 const int rlength
= sizeof(param_buttons
) / sizeof(Widget
*);
435 /* Clear all checkmarks */
437 for (i
= 0; i
< rlength
; i
++) {
438 XtSetArg(wargs
[0], XtNsetMark
, False
);
439 XtSetValues(*param_buttons
[i
], wargs
, 1);
442 /* Check those properties which are parameterized in the element */
444 if (thiselem
!= NULL
) {
445 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
446 ops
= match_param(topobject
, epp
->key
);
447 w
= *param_buttons
[ops
->which
];
448 XtSetArg(wargs
[0], XtNsetMark
, True
);
449 XtSetValues(w
, wargs
, 1);
453 /* Unmanage widgets which do not apply to the element type */
455 for (i
= 0; i
< rlength
; i
++) {
456 if ((thiselem
== NULL
) || (param_select
[i
] & thiselem
->type
))
457 XtManageChild(*param_buttons
[i
]);
459 XtUnmanageChild(*param_buttons
[i
]);
465 /*------------------------------------------------------*/
466 /* This function is like epsubstitute() below it, but */
467 /* only substitutes those values that are expression */
468 /* types. This allows constraints to be applied when */
469 /* editing elements. */
470 /*------------------------------------------------------*/
472 void exprsub(genericptr thiselem
)
482 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
483 ops
= match_param(topobject
, epp
->key
);
484 dps
= find_param(areawin
->topinstance
, epp
->key
);
488 if ((promoted
= evaluate_expr(topobject
, dps
, areawin
->topinstance
))
490 if (sscanf(promoted
, "%g", &fval
) == 1)
491 ival
= (int)(fval
+ 0.5);
493 if (ELEMENTTYPE(thiselem
) == PATH
)
494 k
= epp
->pdata
.pathpt
[1];
496 k
= epp
->pdata
.pointno
;
497 if (ops
->which
== P_POSITION_X
) {
498 switch(thiselem
->type
) {
500 pgen
= TOPATH(&thiselem
)->plist
+ epp
->pdata
.pathpt
[0];
501 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
502 setpt
= TOPOLY(pgen
)->points
+ k
;
506 TOSPLINE(pgen
)->ctrl
[k
].x
= ival
;
510 setpt
= TOPOLY(&thiselem
)->points
+ k
;
514 TOSPLINE(&thiselem
)->ctrl
[k
].x
= ival
;
518 else if (ops
->which
== P_POSITION_Y
) {
519 switch(thiselem
->type
) {
521 pgen
= TOPATH(&thiselem
)->plist
+ epp
->pdata
.pathpt
[0];
522 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
523 setpt
= TOPOLY(pgen
)->points
+ k
;
527 TOSPLINE(pgen
)->ctrl
[k
].y
= ival
;
531 setpt
= TOPOLY(&thiselem
)->points
+ k
;
535 TOSPLINE(&thiselem
)->ctrl
[k
].y
= ival
;
544 /*------------------------------------------------------*/
545 /* Make numerical parameter substitutions into an */
547 /*------------------------------------------------------*/
549 int epsubstitute(genericptr thiselem
, objectptr thisobj
, objinstptr pinst
,
556 int i
, k
, ival
, diff
;
562 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
564 /* Use the parameter from the instance, if available. */
565 /* Otherwise, revert to the type of the object. */
566 /* Normally they will be the same. */
568 ops
= match_param(thisobj
, epp
->key
);
569 dps
= (pinst
!= NULL
) ? find_param(pinst
, epp
->key
) : ops
;
573 /* Get integer and float values. Promote types if necessary */
577 ival
= dps
->parameter
.ivalue
;
578 fval
= (float)(ival
);
581 fval
= dps
->parameter
.fvalue
;
582 ival
= (int)(fval
+ ((fval
< 0) ? -0.5 : 0.5));
585 promoted
= textprint(dps
->parameter
.string
, pinst
);
586 if (sscanf(promoted
, "%g", &fval
) == 1)
587 ival
= (int)(fval
+ ((fval
< 0) ? -0.5 : 0.5));
593 if ((promoted
= evaluate_expr(thisobj
, dps
, pinst
)) == NULL
) continue;
594 if (sscanf(promoted
, "%g", &fval
) == 1)
595 ival
= (int)(fval
+ ((fval
< 0) ? -0.5 : 0.5));
600 else if (ops
== NULL
)
603 if ((epp
->flags
& P_INDIRECT
) && (epp
->pdata
.refkey
!= NULL
)) {
604 key
= epp
->pdata
.refkey
;
607 oparamptr refop
, newop
;
609 thisinst
= (objinstptr
)thiselem
;
611 /* Sanity check: refkey must exist in object */
612 refop
= match_param(thisinst
->thisobject
, key
);
614 Fprintf(stderr
, "Error: Reference key %s does not"
615 " exist in object %s\n",
616 key
, thisinst
->thisobject
->name
);
620 /* If an instance value already exists, remove it */
621 newop
= match_instance_param(thisinst
, refop
->key
);
623 free_instance_param(thisinst
, newop
);
625 /* Create a new instance parameter */
626 newop
= copyparameter(dps
);
627 newop
->next
= thisinst
->params
;
628 thisinst
->params
= newop
;
630 /* Change the key from the parent to the child */
631 if (strcmp(ops
->key
, refop
->key
)) {
633 newop
->key
= strdup(refop
->key
);
639 if (ELEMENTTYPE(thiselem
) == PATH
)
640 k
= epp
->pdata
.pathpt
[1];
642 k
= epp
->pdata
.pointno
;
645 retval
= max(retval
, 1);
646 switch(thiselem
->type
) {
649 pgen
= TOPATH(&thiselem
)->plist
;
650 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
651 setpt
= TOPOLY(pgen
)->points
;
652 diff
= ival
- setpt
->x
;
655 diff
= ival
- TOSPLINE(pgen
)->ctrl
[0].x
;
657 for (pgen
= TOPATH(&thiselem
)->plist
; pgen
<
658 TOPATH(&thiselem
)->plist
+
659 TOPATH(&thiselem
)->parts
; pgen
++) {
660 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
661 for (i
= 0; i
< TOPOLY(pgen
)->number
; i
++) {
662 setpt
= TOPOLY(pgen
)->points
+ i
;
667 for (i
= 0; i
< 4; i
++) {
668 TOSPLINE(pgen
)->ctrl
[i
].x
+= diff
;
670 if (needrecalc
) *needrecalc
= True
;
675 pgen
= TOPATH(&thiselem
)->plist
+ epp
->pdata
.pathpt
[0];
676 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
677 setpt
= TOPOLY(pgen
)->points
+ k
;
681 TOSPLINE(pgen
)->ctrl
[k
].x
= ival
;
682 if (needrecalc
) *needrecalc
= True
;
688 setpt
= TOPOLY(&thiselem
)->points
;
689 diff
= ival
- setpt
->x
;
690 for (i
= 0; i
< TOPOLY(&thiselem
)->number
; i
++) {
691 setpt
= TOPOLY(&thiselem
)->points
+ i
;
696 setpt
= TOPOLY(&thiselem
)->points
+ k
;
702 setpt
= &(TOSPLINE(&thiselem
)->ctrl
[0]);
703 diff
= ival
- setpt
->x
;
704 for (i
= 0; i
< 4; i
++) {
705 setpt
= &(TOSPLINE(&thiselem
)->ctrl
[i
]);
710 TOSPLINE(&thiselem
)->ctrl
[k
].x
= ival
;
712 if (needrecalc
) *needrecalc
= True
;
715 TOLABEL(&thiselem
)->position
.x
= ival
;
718 TOOBJINST(&thiselem
)->position
.x
= ival
;
721 TOARC(&thiselem
)->position
.x
= ival
;
726 retval
= max(retval
, 1);
727 switch(thiselem
->type
) {
730 pgen
= TOPATH(&thiselem
)->plist
;
731 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
732 setpt
= TOPOLY(pgen
)->points
;
733 diff
= ival
- setpt
->y
;
736 diff
= ival
- TOSPLINE(pgen
)->ctrl
[0].y
;
738 for (pgen
= TOPATH(&thiselem
)->plist
; pgen
<
739 TOPATH(&thiselem
)->plist
+
740 TOPATH(&thiselem
)->parts
; pgen
++) {
741 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
742 for (i
= 0; i
< TOPOLY(pgen
)->number
; i
++) {
743 setpt
= TOPOLY(pgen
)->points
+ i
;
748 for (i
= 0; i
< 4; i
++) {
749 TOSPLINE(pgen
)->ctrl
[i
].y
+= diff
;
751 if (needrecalc
) *needrecalc
= True
;
756 pgen
= TOPATH(&thiselem
)->plist
+ epp
->pdata
.pathpt
[0];
757 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
758 setpt
= TOPOLY(pgen
)->points
+ k
;
762 TOSPLINE(pgen
)->ctrl
[k
].y
= ival
;
763 if (needrecalc
) *needrecalc
= True
;
769 setpt
= TOPOLY(&thiselem
)->points
;
770 diff
= ival
- setpt
->y
;
771 for (i
= 0; i
< TOPOLY(&thiselem
)->number
; i
++) {
772 setpt
= TOPOLY(&thiselem
)->points
+ i
;
777 setpt
= TOPOLY(&thiselem
)->points
+ k
;
783 setpt
= &(TOSPLINE(&thiselem
)->ctrl
[0]);
784 diff
= ival
- setpt
->y
;
785 for (i
= 0; i
< 4; i
++) {
786 setpt
= &(TOSPLINE(&thiselem
)->ctrl
[i
]);
791 TOSPLINE(&thiselem
)->ctrl
[k
].y
= ival
;
793 if (needrecalc
) *needrecalc
= True
;
796 TOLABEL(&thiselem
)->position
.y
= ival
;
799 TOOBJINST(&thiselem
)->position
.y
= ival
;
802 TOARC(&thiselem
)->position
.y
= ival
;
807 retval
= max(retval
, 0);
808 switch(thiselem
->type
) {
810 TOPOLY(&thiselem
)->style
= ival
;
813 TOSPLINE(&thiselem
)->style
= ival
;
816 TOARC(&thiselem
)->style
= ival
;
819 TOPATH(&thiselem
)->style
= ival
;
824 retval
= max(retval
, 1);
825 switch(thiselem
->type
) {
827 TOLABEL(&thiselem
)->anchor
= ival
;
832 retval
= max(retval
, 1);
833 switch(thiselem
->type
) {
835 TOARC(&thiselem
)->angle1
= fval
;
836 if (needrecalc
) *needrecalc
= True
;
841 retval
= max(retval
, 1);
842 switch(thiselem
->type
) {
844 TOARC(&thiselem
)->angle1
= fval
;
845 if (needrecalc
) *needrecalc
= True
;
850 retval
= max(retval
, 1);
851 switch(thiselem
->type
) {
853 TOARC(&thiselem
)->radius
= ival
;
854 TOARC(&thiselem
)->yaxis
= ival
;
855 if (needrecalc
) *needrecalc
= True
;
860 retval
= max(retval
, 1);
861 switch(thiselem
->type
) {
863 TOARC(&thiselem
)->yaxis
= ival
;
864 if (needrecalc
) *needrecalc
= True
;
869 retval
= max(retval
, 1);
870 switch(thiselem
->type
) {
872 TOLABEL(&thiselem
)->rotation
= fval
;
875 TOOBJINST(&thiselem
)->rotation
= fval
;
880 retval
= max(retval
, 1);
881 switch(thiselem
->type
) {
883 TOLABEL(&thiselem
)->scale
= fval
;
886 TOOBJINST(&thiselem
)->scale
= fval
;
891 retval
= max(retval
, 0);
892 switch(thiselem
->type
) {
894 TOPOLY(&thiselem
)->width
= fval
;
897 TOSPLINE(&thiselem
)->width
= fval
;
900 TOARC(&thiselem
)->width
= fval
;
903 TOPATH(&thiselem
)->width
= fval
;
908 retval
= max(retval
, 0);
909 thiselem
->color
= ival
;
917 /*------------------------------------------------------*/
918 /* Make numerical parameter substitutions into all */
919 /* elements of an object. "thisinst" may be NULL, in */
920 /* which case all default values are used in the */
924 /* -1 if the instance declares no parameters */
925 /* 0 if parameters do not change the instance's bbox */
926 /* 1 if parameters change instance's bbox */
927 /* 2 if parameters change instance's netlist */
928 /*------------------------------------------------------*/
930 int opsubstitute(objectptr thisobj
, objinstptr pinst
)
932 genericptr
*eptr
, *pgen
, thiselem
;
935 Boolean needrecalc
; /* for arcs and splines */
937 /* Perform expression parameter substitutions on all labels. */
938 /* Note that this used to be done on an immediate basis as */
939 /* labels were parsed. The main difference is that only one */
940 /* expression parameter can be used per label if it is to */
941 /* compute the result of some aspect of the label, such as */
942 /* position; this is a tradeoff for much simplified handling */
943 /* of expression results, like having to avoid infinite */
944 /* recursion in an expression result. */
946 for (eptr
= thisobj
->plist
; eptr
< thisobj
->plist
+ thisobj
->parts
; eptr
++)
947 if ((*eptr
)->type
== LABEL
)
948 for (strptr
= (TOLABEL(eptr
))->string
; strptr
!= NULL
; strptr
=
949 nextstringpartrecompute(strptr
, pinst
));
951 if (thisobj
->params
== NULL
)
952 return -1; /* object has no parameters */
954 for (eptr
= thisobj
->plist
; eptr
< thisobj
->plist
+ thisobj
->parts
; eptr
++) {
958 if (thiselem
->passed
== NULL
) continue; /* Nothing to substitute */
959 retval
= epsubstitute(thiselem
, thisobj
, pinst
, &needrecalc
);
961 /* substitutions into arcs and splines require that the */
962 /* line segments be recalculated. */
965 switch(thiselem
->type
) {
967 calcarc((arcptr
)thiselem
);
970 calcspline((splineptr
)thiselem
);
973 for (pgen
= ((pathptr
)thiselem
)->plist
; pgen
< ((pathptr
)thiselem
)->plist
974 + ((pathptr
)thiselem
)->parts
; pgen
++)
975 if (ELEMENTTYPE(*pgen
) == SPLINE
)
976 calcspline((splineptr
)*pgen
);
984 /*------------------------------------------------------*/
985 /* Same as above, but determines the object from the */
986 /* current page hierarchy. */
987 /*------------------------------------------------------*/
989 int psubstitute(objinstptr thisinst
)
994 pinst
= (thisinst
== areawin
->topinstance
) ? areawin
->topinstance
: thisinst
;
995 if (pinst
== NULL
) return -1; /* there is no instance */
996 thisobj
= pinst
->thisobject
;
998 return opsubstitute(thisobj
, pinst
);
1001 /*----------------------------------------------*/
1002 /* Check if an element contains a parameter. */
1003 /*----------------------------------------------*/
1005 Boolean
has_param(genericptr celem
)
1007 if (IS_LABEL(celem
)) {
1009 labelptr clab
= (labelptr
)celem
;
1010 for (cstr
= clab
->string
; cstr
!= NULL
; cstr
= cstr
->nextpart
)
1011 if (cstr
->type
== PARAM_START
)
1014 if (celem
->passed
!= NULL
) return TRUE
;
1018 /*------------------------------------------------------*/
1019 /* Find "current working values" in the element list of */
1020 /* an object, and write them into the instance's */
1021 /* parameter list. */
1022 /* This is just the opposite of "psubstitute()", except */
1023 /* that instance values are created prior to writeback, */
1024 /* and resolved afterward. */
1025 /*------------------------------------------------------*/
1027 void pwriteback(objinstptr thisinst
)
1029 genericptr
*eptr
, *pgen
, thiselem
;
1034 int k
, type
, *destivalptr
, found
;
1036 Boolean changed
, need_redraw
= FALSE
;
1043 thisobj
= (pinst
== NULL
) ? topobject
: pinst
->thisobject
;
1045 /* Make sure that all instance values exist */
1046 if (pinst
!= NULL
) copyparams(pinst
, pinst
);
1048 /* Because more than one element can point to the same parameter, we search */
1049 /* through each (numerical) parameter declared in the object. If any */
1050 /* element has a different value, the parameter is changed to match. This */
1051 /* operates on the assumption that no more than one element will change the */
1052 /* value of any one parameter on a single call to pwriteback(). */
1054 for (ops
= thisobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
1055 /* handle pre-assigned numeric parameters only */
1056 if ((ops
->which
== P_SUBSTRING
) || (ops
->which
== P_EXPRESSION
) ||
1057 (ops
->which
== P_NUMERIC
))
1061 ips
= (pinst
!= NULL
) ? match_instance_param(pinst
, ops
->key
) : NULL
;
1062 for (eptr
= thisobj
->plist
; eptr
< thisobj
->plist
+ thisobj
->parts
; eptr
++) {
1064 if (thiselem
->passed
== NULL
) continue; /* Nothing to write back */
1065 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
1066 if (!strcmp(epp
->key
, ops
->key
)) {
1068 if (ELEMENTTYPE(thiselem
) == PATH
)
1069 k
= epp
->pdata
.pathpt
[1];
1071 k
= epp
->pdata
.pointno
;
1073 switch(ops
->which
) {
1075 switch(thiselem
->type
) {
1077 wtemp
.ival
= TOOBJINST(eptr
)->position
.x
;
1080 wtemp
.ival
= TOLABEL(eptr
)->position
.x
;
1083 setpt
= TOPOLY(eptr
)->points
+ k
;
1084 wtemp
.ival
= setpt
->x
;
1087 wtemp
.ival
= TOARC(eptr
)->position
.x
;
1090 wtemp
.ival
= TOSPLINE(eptr
)->ctrl
[k
].x
;
1093 if (epp
->pdata
.pathpt
[0] < 0)
1094 pgen
= TOPATH(eptr
)->plist
;
1096 pgen
= TOPATH(eptr
)->plist
+ epp
->pdata
.pathpt
[0];
1097 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
1098 setpt
= TOPOLY(pgen
)->points
+ k
;
1099 wtemp
.ival
= setpt
->x
;
1102 wtemp
.ival
= TOSPLINE(pgen
)->ctrl
[k
].x
;
1107 switch(thiselem
->type
) {
1109 wtemp
.ival
= TOOBJINST(eptr
)->position
.y
;
1112 wtemp
.ival
= TOLABEL(eptr
)->position
.y
;
1115 setpt
= TOPOLY(eptr
)->points
+ k
;
1116 wtemp
.ival
= setpt
->y
;
1119 wtemp
.ival
= TOARC(eptr
)->position
.y
;
1122 wtemp
.ival
= TOSPLINE(eptr
)->ctrl
[k
].y
;
1125 if (epp
->pdata
.pathpt
[0] < 0)
1126 pgen
= TOPATH(eptr
)->plist
;
1128 pgen
= TOPATH(eptr
)->plist
+ epp
->pdata
.pathpt
[0];
1129 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
1130 setpt
= TOPOLY(pgen
)->points
+ k
;
1131 wtemp
.ival
= setpt
->y
;
1134 wtemp
.ival
= TOSPLINE(pgen
)->ctrl
[k
].y
;
1139 switch(thiselem
->type
) {
1141 wtemp
.ival
= TOPOLY(eptr
)->style
;
1144 wtemp
.ival
= TOARC(eptr
)->style
;
1147 wtemp
.ival
= TOSPLINE(eptr
)->style
;
1150 wtemp
.ival
= TOPATH(eptr
)->style
;
1155 switch(thiselem
->type
) {
1157 wtemp
.ival
= TOLABEL(eptr
)->anchor
;
1162 switch(thiselem
->type
) {
1164 wtemp
.fval
= TOARC(eptr
)->angle1
;
1169 switch(thiselem
->type
) {
1171 wtemp
.fval
= TOARC(eptr
)->angle1
;
1176 switch(thiselem
->type
) {
1178 wtemp
.ival
= TOARC(eptr
)->radius
;
1183 switch(thiselem
->type
) {
1185 wtemp
.ival
= TOARC(eptr
)->yaxis
;
1190 switch(thiselem
->type
) {
1192 wtemp
.fval
= TOOBJINST(eptr
)->rotation
;
1195 wtemp
.fval
= TOLABEL(eptr
)->rotation
;
1200 switch(thiselem
->type
) {
1202 wtemp
.fval
= TOOBJINST(eptr
)->scale
;
1205 wtemp
.fval
= TOLABEL(eptr
)->scale
;
1210 switch(thiselem
->type
) {
1212 wtemp
.fval
= TOPOLY(eptr
)->width
;
1215 wtemp
.fval
= TOARC(eptr
)->width
;
1218 wtemp
.fval
= TOSPLINE(eptr
)->width
;
1221 wtemp
.fval
= TOPATH(eptr
)->width
;
1226 wtemp
.ival
= thiselem
->color
;
1229 type
= (ips
!= NULL
) ? ips
->type
: ops
->type
;
1230 if (type
!= XC_FLOAT
&& type
!= XC_INT
) break;
1232 destivalptr
= (ips
!= NULL
) ? &ips
->parameter
.ivalue
1233 : &ops
->parameter
.ivalue
;
1234 if ((!changed
) && (wtemp
.ival
!= *destivalptr
)) {
1235 *destivalptr
= wtemp
.ival
;
1238 else if (found
> 1) need_redraw
= TRUE
;
1245 /* Any instance values which are identical to the default value */
1246 /* get erased (so they won't be written to the output unnecessarily) */
1248 if (pinst
!= NULL
) resolveparams(pinst
);
1251 incr_changes(thisobj
);
1252 invalidate_netlist(thisobj
);
1255 /* Because more than one element may use the same parameter, */
1256 /* pwriteback checks for cases in which a change in one element */
1257 /* precipitates a change in another. If so, force a redraw. */
1259 if (need_redraw
&& (thisinst
== areawin
->topinstance
))
1260 drawarea(NULL
, NULL
, NULL
);
1263 /*------------------------------------------------------*/
1264 /* If the instance comes from the library, replace the */
1265 /* default value with the instance value. */
1266 /*------------------------------------------------------*/
1268 void replaceparams(objinstptr thisinst
)
1272 /* int i, nullparms = 0; (jdk) */
1274 thisobj
= thisinst
->thisobject
;
1276 for (ops
= thisobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
1277 ips
= match_instance_param(thisinst
, ops
->key
);
1278 if (ips
== NULL
) continue; /* this parameter is already default */
1282 if (stringcomp(ops
->parameter
.string
, ips
->parameter
.string
)) {
1283 freelabel(ops
->parameter
.string
);
1284 ops
->parameter
.string
= ips
->parameter
.string
;
1285 free_instance_param(thisinst
, ips
);
1289 /* Expression parameters should be replaced *only* if the
1290 * instance value is also an expression, and not an evaluated
1293 if ((ips
->type
== XC_EXPR
) &&
1294 strcmp(ops
->parameter
.expr
, ips
->parameter
.expr
)) {
1295 free(ops
->parameter
.expr
);
1296 ops
->parameter
.expr
= ips
->parameter
.expr
;
1297 free_instance_param(thisinst
, ips
);
1300 case XC_INT
: case XC_FLOAT
:
1301 if (ops
->parameter
.ivalue
!= ips
->parameter
.ivalue
) {
1302 ops
->parameter
.ivalue
= ips
->parameter
.ivalue
;
1303 free_instance_param(thisinst
, ips
);
1310 /*------------------------------------------------------*/
1311 /* Resolve differences between the object instance */
1312 /* parameters and the default parameters. If they */
1313 /* are the same for any parameter, delete that instance */
1314 /* such that the instance reverts to the default value. */
1315 /*------------------------------------------------------*/
1317 void resolveparams(objinstptr thisinst
)
1324 /* If the instance has no parameters itself, ignore it. */
1325 if (thisinst
== NULL
|| thisinst
->params
== NULL
) return;
1327 /* If the object was pushed into from a library, we want to change */
1328 /* the default, not the instanced, parameter values. However, this */
1329 /* is not true for "virtual" library objects (in the instlist) */
1331 if ((i
= checklibtop()) >= 0) {
1332 for (spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
;
1334 if (spec
->thisinst
== thisinst
)
1337 if ((spec
== NULL
) || (spec
->virtual == FALSE
)) {
1338 /* Fprintf(stdout, "Came from library: changing default value\n"); */
1339 replaceparams(thisinst
);
1344 /* Parameters which are changed on a top-level page must also change */
1345 /* the default value; otherwise, the instance value shadows the page */
1346 /* object's value but the page object's value is the one written to */
1347 /* the output file. */
1349 else if (is_page(thisinst
->thisobject
) >= 0) {
1350 replaceparams(thisinst
);
1354 thisobj
= thisinst
->thisobject
;
1356 for (ops
= thisobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
1357 ips
= match_instance_param(thisinst
, ops
->key
);
1358 if (ips
== NULL
) continue; /* this parameter is already default */
1360 /* If type or which fields do not match, then we don't need to look */
1361 /* any further; object and instance have different parameters. */
1362 if ((ips
->type
!= ops
->type
) || (ips
->which
!= ops
->which
)) continue;
1366 if (!stringcomp(ops
->parameter
.string
, ips
->parameter
.string
)) {
1367 freelabel(ips
->parameter
.string
);
1368 free_instance_param(thisinst
, ips
);
1372 if (!strcmp(ops
->parameter
.expr
, ips
->parameter
.expr
)) {
1373 free(ips
->parameter
.expr
);
1374 free_instance_param(thisinst
, ips
);
1377 case XC_INT
: case XC_FLOAT
:
1378 if (ops
->parameter
.ivalue
== ips
->parameter
.ivalue
) {
1379 free_instance_param(thisinst
, ips
);
1385 if (thisinst
->params
!= NULL
) {
1386 /* Object must recompute bounding box if any instance */
1387 /* uses a non-default parameter. */
1389 calcbboxvalues(thisinst
, NULL
);
1393 /*--------------------------------------------------------------*/
1394 /* Return a copy of the single eparameter "cepp" */
1395 /*--------------------------------------------------------------*/
1397 eparamptr
copyeparam(eparamptr cepp
, genericptr thiselem
)
1401 newepp
= make_new_eparam(cepp
->key
);
1402 if ((cepp
->flags
& P_INDIRECT
) && (cepp
->pdata
.refkey
!= NULL
))
1403 newepp
->pdata
.refkey
= strdup(cepp
->pdata
.refkey
);
1405 newepp
->pdata
.pointno
= cepp
->pdata
.pointno
; /* also covers pathpt[] */
1406 newepp
->flags
= cepp
->flags
;
1410 /*------------------------------------------------------*/
1411 /* Copy all element parameters from source to dest */
1412 /*------------------------------------------------------*/
1414 void copyalleparams(genericptr destinst
, genericptr sourceinst
)
1416 eparamptr cepp
, newepp
;
1418 for (cepp
= sourceinst
->passed
; cepp
!= NULL
; cepp
= cepp
->next
) {
1419 newepp
= copyeparam(cepp
, sourceinst
);
1420 newepp
->next
= destinst
->passed
;
1421 destinst
->passed
= newepp
;
1425 /*--------------------------------------------------------------*/
1426 /* Return a copy of the single parameter "cops" */
1427 /*--------------------------------------------------------------*/
1429 oparamptr
copyparameter(oparamptr cops
)
1433 newops
= make_new_parameter(cops
->key
);
1434 newops
->type
= cops
->type
;
1435 newops
->which
= cops
->which
;
1436 switch(cops
->type
) {
1438 newops
->parameter
.string
= stringcopy(cops
->parameter
.string
);
1441 newops
->parameter
.expr
= strdup(cops
->parameter
.expr
);
1443 case XC_INT
: case XC_FLOAT
:
1444 newops
->parameter
.ivalue
= cops
->parameter
.ivalue
;
1447 Fprintf(stderr
, "Error: bad parameter\n");
1453 /*------------------------------------------------------*/
1454 /* Fill any NULL instance parameters with the values */
1455 /* from the calling instance, or from the instance */
1456 /* object's defaults if destinst = sourceinst. */
1458 /* Expression parameters get special treatment because */
1459 /* the instance value may be holding the last evaluated */
1460 /* expression, not an instance value of the expression. */
1461 /* If so, its type will be XC_STRING or XC_FLOAT, not */
1463 /*------------------------------------------------------*/
1465 void copyparams(objinstptr destinst
, objinstptr sourceinst
)
1467 oparamptr psource
, cops
, newops
, ips
;
1469 if (sourceinst
== NULL
) return;
1470 if (destinst
== sourceinst
)
1471 psource
= sourceinst
->thisobject
->params
;
1473 psource
= sourceinst
->params
;
1475 for (cops
= psource
; cops
!= NULL
; cops
= cops
->next
) {
1476 if ((ips
= match_instance_param(destinst
, cops
->key
)) == NULL
) {
1477 newops
= copyparameter(cops
);
1478 newops
->next
= destinst
->params
;
1479 destinst
->params
= newops
;
1481 else if ((cops
->type
== XC_EXPR
) && (ips
->type
!= XC_EXPR
))
1482 free_instance_param(destinst
, ips
);
1486 /*--------------------------------------------------------------*/
1487 /* Make an unreferenced parameter expression in the object */
1489 /* The expression may have either a numeric or string result. */
1490 /* the proper "which" value is passed as an argument. */
1492 /* Return NULL if unsuccessful, the parameter key (which may */
1493 /* have been modified by checkvalidname()) otherwise. */
1494 /*--------------------------------------------------------------*/
1496 char *makeexprparam(objectptr refobject
, char *key
, char *value
, int which
)
1499 char *newkey
, stkey
[20];
1502 /* Check against object names, which are reserved words */
1505 strcpy(stkey
, getnumericalpkey(which
));
1507 while (check_param(refobject
, stkey
)) {
1509 sprintf(stkey
, "%s%d", getnumericalpkey(which
), pidx
);
1514 /* Check parameter key for valid name syntax */
1516 newkey
= checkvalidname(key
, NULL
);
1517 if (newkey
== NULL
) newkey
= key
;
1519 /* Ensure that no two parameters have the same name! */
1521 if (check_param(refobject
, newkey
)) {
1522 Wprintf("There is already a parameter named %s!", newkey
);
1523 if (newkey
!= key
) free(newkey
);
1528 newops
= make_new_parameter(newkey
);
1529 newops
->next
= refobject
->params
;
1530 refobject
->params
= newops
;
1531 newops
->type
= XC_EXPR
; /* expression requiring evaluation */
1532 newops
->which
= which
;
1533 newops
->parameter
.expr
= strdup(value
);
1534 incr_changes(refobject
);
1535 if ((newkey
!= key
) && (newkey
!= stkey
)) free(newkey
);
1540 /*------------------------------------------------------------------*/
1541 /* Make an unreferenced numerical parameter in the object refobject */
1543 /* Return FALSE if unsuccessful, TRUE otherwise. */
1544 /*------------------------------------------------------------------*/
1546 Boolean
makefloatparam(objectptr refobject
, char *key
, float value
)
1551 /* Check against object names, which are reserved words */
1553 newkey
= checkvalidname(key
, NULL
);
1554 if (newkey
== NULL
) newkey
= key
;
1556 /* Ensure that no two parameters have the same name! */
1558 if (check_param(refobject
, newkey
)) {
1559 Wprintf("There is already a parameter named %s!", newkey
);
1560 if (newkey
!= key
) free(newkey
);
1564 newops
= make_new_parameter(key
);
1565 newops
->next
= refobject
->params
;
1566 refobject
->params
= newops
;
1567 newops
->type
= XC_FLOAT
; /* general-purpose numeric */
1568 newops
->which
= P_NUMERIC
;
1569 newops
->parameter
.fvalue
= value
;
1570 incr_changes(refobject
);
1571 if (newkey
!= key
) free(newkey
);
1576 /*----------------------------------------------------------------*/
1577 /* Make an unreferenced string parameter in the object refobject. */
1578 /* Return FALSE if unsuccessful, TRUE otherwise. */
1579 /*----------------------------------------------------------------*/
1581 Boolean
makestringparam(objectptr refobject
, char *key
, stringpart
*strptr
)
1586 /* Check against object names, which are reserved words */
1588 newkey
= checkvalidname(key
, NULL
);
1589 if (newkey
== NULL
) newkey
= key
;
1591 /* Ensure that no two parameters have the same name! */
1593 if (check_param(refobject
, newkey
)) {
1594 Wprintf("There is already a parameter named %s!", newkey
);
1595 if (newkey
!= key
) free(newkey
);
1599 newops
= make_new_parameter(newkey
);
1600 newops
->next
= refobject
->params
;
1601 refobject
->params
= newops
;
1602 newops
->type
= XC_STRING
;
1603 newops
->which
= P_SUBSTRING
;
1604 newops
->parameter
.string
= strptr
;
1605 incr_changes(refobject
);
1606 if (newkey
!= key
) free(newkey
);
1611 /*--------------------------------------------------------------*/
1612 /* Return the built-in parameter key corresponding to a */
1613 /* parameter type (as defined in xcircuit.h). */
1615 /* Numerical parameters have designated keys to avoid the */
1616 /* necessity of having to specify a key, to avoid conflicts */
1617 /* with PostScript predefined keys, and other good reasons. */
1618 /*--------------------------------------------------------------*/
1620 char *getnumericalpkey(u_int mode
)
1622 static char *param_keys
[] = {
1623 "p_gps", "p_str", "p_xps", "p_yps", "p_sty", "p_jst", "p_an1",
1624 "p_an2", "p_rad", "p_axs", "p_rot", "p_scl", "p_wid", "p_col",
1628 if (mode
< 0 || mode
> 13) return param_keys
[14];
1629 return param_keys
[mode
];
1632 /*--------------------------------------------------------------*/
1633 /* Make a numerical (integer or float) parameter. */
1634 /* If "key" is non-NULL, then the parameter key will be set */
1635 /* from this rather than from the list "param_keys". If the */
1636 /* key is an existing key with the same type as "mode", then */
1637 /* the new parameter will be linked to the existing one. */
1638 /*--------------------------------------------------------------*/
1640 void makenumericalp(genericptr
*gelem
, u_int mode
, char *key
, short cycle
)
1642 genericptr pgen
, *pathpgen
;
1643 oparamptr ops
, newops
;
1646 char new_key
[7], *keyptr
;
1648 short loccycle
= cycle
;
1650 /* Parameterized strings are handled by makeparam() */
1652 if (IS_LABEL(*gelem
) && mode
== P_SUBSTRING
) {
1653 Fprintf(stderr
, "Error: String parameter passed to makenumericalp()\n");
1657 /* Make sure the parameter doesn't already exist. */
1659 for (epp
= (*gelem
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
1660 ops
= match_param(topobject
, epp
->key
);
1661 if (ops
->which
== (u_char
)mode
) {
1662 if ((mode
== P_POSITION_X
|| mode
== P_POSITION_Y
) &&
1663 ((*gelem
)->type
== POLYGON
|| (*gelem
)->type
== SPLINE
) &&
1664 (TOPOLY(gelem
)->cycle
!= NULL
))
1666 if ((cycle
< 0) || (TOPOLY(gelem
)->cycle
->number
!= cycle
)) {
1667 Fprintf(stderr
, "Cannot duplicate a point parameter!\n");
1672 Fprintf(stderr
, "Cannot duplicate a parameter!\n");
1678 /* Ensure that no two parameters have the same name! */
1681 keyptr
= checkvalidname(key
, NULL
);
1682 if (keyptr
== NULL
) keyptr
= key
;
1685 strcpy(new_key
, getnumericalpkey(mode
));
1687 while (check_param(topobject
, new_key
)) {
1689 sprintf(new_key
, "%s%d", getnumericalpkey(mode
), pidx
);
1694 /* Add the parameter to the element's parameter list */
1696 epp
= make_new_eparam(keyptr
);
1697 epp
->next
= (*gelem
)->passed
;
1698 (*gelem
)->passed
= epp
;
1700 /* If keyptr does not point to an existing parameter, then we need */
1701 /* to create it in the object's parameter list and set the default */
1702 /* value to the existing value of the element. */
1704 ops
= match_param(topobject
, keyptr
);
1706 newops
= make_new_parameter(keyptr
);
1707 newops
->next
= topobject
->params
;
1708 topobject
->params
= newops
;
1709 newops
->type
= XC_INT
; /* most commonly used value */
1710 newops
->which
= (u_char
)mode
; /* what kind of parameter */
1711 incr_changes(topobject
);
1714 if (ops
->which
!= (u_char
)mode
) {
1715 free_element_param(*gelem
, epp
);
1716 Fprintf(stderr
, "Error: Attempt to link a parameter to "
1717 "a parameter of a different type\n");
1720 else if (ops
->type
== XC_EXPR
)
1723 if ((newops
= match_instance_param(areawin
->topinstance
, keyptr
)) == NULL
) {
1724 newops
= make_new_parameter(keyptr
);
1725 newops
->next
= areawin
->topinstance
->params
;
1726 areawin
->topinstance
->params
= newops
;
1727 newops
->type
= ops
->type
;
1728 newops
->which
= ops
->which
;
1731 /* If the parameter exists and the instance has a non-default */
1732 /* value for it, we will not change the instance record. If */
1733 /* the element value is different, then it will change, so we */
1734 /* should redraw. */
1735 drawarea(NULL
, NULL
, NULL
);
1741 if (mode
== P_COLOR
)
1742 newops
->parameter
.ivalue
= (int)((*gelem
)->color
);
1744 switch((*gelem
)->type
) {
1748 newops
->parameter
.ivalue
= (int)TOLABEL(gelem
)->position
.x
;
1751 newops
->parameter
.ivalue
= (int)TOLABEL(gelem
)->position
.y
;
1754 newops
->parameter
.ivalue
= (int)TOLABEL(gelem
)->anchor
;
1757 newops
->type
= XC_FLOAT
;
1758 newops
->parameter
.fvalue
= TOLABEL(gelem
)->rotation
;
1761 newops
->type
= XC_FLOAT
;
1762 newops
->parameter
.fvalue
= TOLABEL(gelem
)->scale
;
1769 newops
->parameter
.ivalue
= (int)TOARC(gelem
)->position
.x
;
1772 newops
->parameter
.ivalue
= (int)TOARC(gelem
)->position
.y
;
1775 newops
->type
= XC_FLOAT
;
1776 newops
->parameter
.fvalue
= TOARC(gelem
)->angle1
;
1779 newops
->type
= XC_FLOAT
;
1780 newops
->parameter
.fvalue
= TOARC(gelem
)->angle2
;
1783 newops
->parameter
.ivalue
= (int)TOARC(gelem
)->radius
;
1786 newops
->parameter
.ivalue
= (int)TOARC(gelem
)->yaxis
;
1789 newops
->parameter
.ivalue
= (int)TOARC(gelem
)->style
;
1792 newops
->type
= XC_FLOAT
;
1793 newops
->parameter
.fvalue
= TOARC(gelem
)->width
;
1800 newops
->parameter
.ivalue
= (int)TOOBJINST(gelem
)->position
.x
;
1803 newops
->parameter
.ivalue
= (int)TOOBJINST(gelem
)->position
.y
;
1806 newops
->type
= XC_FLOAT
;
1807 newops
->parameter
.fvalue
= TOOBJINST(gelem
)->rotation
;
1810 newops
->type
= XC_FLOAT
;
1811 newops
->parameter
.fvalue
= TOOBJINST(gelem
)->scale
;
1817 loccycle
= (TOPOLY(gelem
)->cycle
!= NULL
) ?
1818 TOPOLY(gelem
)->cycle
->number
: -1;
1821 if (loccycle
== -1) {
1822 pptr
= TOPOLY(gelem
)->points
;
1823 newops
->parameter
.ivalue
= (int)pptr
->x
;
1824 for (i
= 0; i
< TOPOLY(gelem
)->number
; i
++) {
1825 pptr
= TOPOLY(gelem
)->points
+ i
;
1826 pptr
->x
-= newops
->parameter
.ivalue
;
1829 pptr
= TOPOLY(gelem
)->points
+ loccycle
;
1830 newops
->parameter
.ivalue
= (int)pptr
->x
;
1832 epp
->pdata
.pointno
= loccycle
;
1835 if (loccycle
== -1) {
1836 pptr
= TOPOLY(gelem
)->points
;
1837 newops
->parameter
.ivalue
= (int)pptr
->y
;
1838 for (i
= 0; i
< TOPOLY(gelem
)->number
; i
++) {
1839 pptr
= TOPOLY(gelem
)->points
+ i
;
1840 pptr
->y
-= newops
->parameter
.ivalue
;
1843 pptr
= TOPOLY(gelem
)->points
+ loccycle
;
1844 newops
->parameter
.ivalue
= (int)pptr
->y
;
1846 epp
->pdata
.pointno
= loccycle
;
1849 newops
->parameter
.ivalue
= (int)TOPOLY(gelem
)->style
;
1852 newops
->type
= XC_FLOAT
;
1853 newops
->parameter
.fvalue
= TOPOLY(gelem
)->width
;
1859 loccycle
= (TOSPLINE(gelem
)->cycle
!= NULL
) ?
1860 TOSPLINE(gelem
)->cycle
->number
: -1;
1863 if (loccycle
== -1) {
1864 pptr
= &(TOSPLINE(gelem
)->ctrl
[0]);
1865 newops
->parameter
.ivalue
= (int)pptr
->x
;
1866 for (i
= 0; i
< 4; i
++) {
1867 pptr
= &(TOSPLINE(gelem
)->ctrl
[i
]);
1868 pptr
->x
-= newops
->parameter
.ivalue
;
1871 pptr
= TOSPLINE(gelem
)->ctrl
+ loccycle
;
1872 newops
->parameter
.ivalue
= (int)pptr
->x
;
1874 epp
->pdata
.pointno
= loccycle
;
1877 if (loccycle
== -1) {
1878 pptr
= &(TOSPLINE(gelem
)->ctrl
[0]);
1879 newops
->parameter
.ivalue
= (int)pptr
->y
;
1880 for (i
= 0; i
< 4; i
++) {
1881 pptr
= &(TOSPLINE(gelem
)->ctrl
[i
]);
1882 pptr
->y
-= newops
->parameter
.ivalue
;
1885 pptr
= TOSPLINE(gelem
)->ctrl
+ loccycle
;
1886 newops
->parameter
.ivalue
= (int)pptr
->y
;
1888 epp
->pdata
.pointno
= loccycle
;
1891 newops
->parameter
.ivalue
= (int)TOSPLINE(gelem
)->style
;
1894 newops
->type
= XC_FLOAT
;
1895 newops
->parameter
.fvalue
= TOSPLINE(gelem
)->width
;
1900 if (loccycle
== -1 && (mode
== P_POSITION_X
|| mode
== P_POSITION_Y
)) {
1901 pgen
= getsubpart(TOPATH(gelem
), &pidx
);
1902 if (ELEMENTTYPE(pgen
) == POLYGON
)
1903 loccycle
= (((polyptr
)pgen
)->cycle
!= NULL
) ?
1904 ((polyptr
)pgen
)->cycle
->number
: -1;
1906 loccycle
= (((splineptr
)pgen
)->cycle
!= NULL
) ?
1907 ((splineptr
)pgen
)->cycle
->number
: -1;
1910 Fprintf(stderr
, "Can't parameterize a path point from "
1911 "the command line.\n");
1916 newops
->parameter
.ivalue
= (int)TOPATH(gelem
)->style
;
1919 newops
->type
= XC_FLOAT
;
1920 newops
->parameter
.fvalue
= TOPATH(gelem
)->width
;
1923 newops
->type
= XC_INT
;
1924 if (loccycle
== -1) {
1925 pathpgen
= TOPATH(gelem
)->plist
;
1926 if (ELEMENTTYPE(*pathpgen
) == POLYGON
) {
1927 pptr
= TOPOLY(pathpgen
)->points
;
1928 newops
->parameter
.ivalue
= (int)pptr
->x
;
1931 pptr
= &(TOSPLINE(pathpgen
)->ctrl
[0]);
1932 newops
->parameter
.ivalue
= (int)pptr
->x
;
1934 for (pathpgen
= TOPATH(gelem
)->plist
; pathpgen
<
1935 TOPATH(gelem
)->plist
+ TOPATH(gelem
)->parts
;
1937 if (ELEMENTTYPE(*pathpgen
) == POLYGON
) {
1938 for (i
= 0; i
< TOPOLY(pathpgen
)->number
; i
++) {
1939 pptr
= TOPOLY(pathpgen
)->points
+ i
;
1940 pptr
->x
-= newops
->parameter
.ivalue
;
1944 for (i
= 0; i
< 4; i
++) {
1945 pptr
= &(TOSPLINE(pathpgen
)->ctrl
[i
]);
1946 pptr
->x
-= newops
->parameter
.ivalue
;
1952 if (ELEMENTTYPE(pgen
) == POLYGON
)
1953 newops
->parameter
.ivalue
= ((polyptr
)pgen
)->points
[loccycle
].x
;
1955 newops
->parameter
.ivalue
= ((splineptr
)pgen
)->ctrl
[loccycle
].x
;
1956 epp
->pdata
.pathpt
[1] = loccycle
;
1957 epp
->pdata
.pathpt
[0] = pidx
;
1961 newops
->type
= XC_INT
;
1962 if (loccycle
== -1) {
1963 pathpgen
= TOPATH(gelem
)->plist
;
1964 if (ELEMENTTYPE(*pathpgen
) == POLYGON
) {
1965 pptr
= TOPOLY(pathpgen
)->points
;
1966 newops
->parameter
.ivalue
= (int)pptr
->y
;
1969 pptr
= &(TOSPLINE(pathpgen
)->ctrl
[0]);
1970 newops
->parameter
.ivalue
= (int)pptr
->y
;
1972 for (pathpgen
= TOPATH(gelem
)->plist
; pathpgen
<
1973 TOPATH(gelem
)->plist
+ TOPATH(gelem
)->parts
;
1975 if (ELEMENTTYPE(*pathpgen
) == POLYGON
) {
1976 for (i
= 0; i
< TOPOLY(pathpgen
)->number
; i
++) {
1977 pptr
= TOPOLY(pathpgen
)->points
+ i
;
1978 pptr
->y
-= newops
->parameter
.ivalue
;
1982 for (i
= 0; i
< 4; i
++) {
1983 pptr
= &(TOSPLINE(pathpgen
)->ctrl
[i
]);
1984 pptr
->y
-= newops
->parameter
.ivalue
;
1990 if (ELEMENTTYPE(pgen
) == POLYGON
)
1991 newops
->parameter
.ivalue
= ((polyptr
)pgen
)->points
[loccycle
].y
;
1993 newops
->parameter
.ivalue
= ((splineptr
)pgen
)->ctrl
[loccycle
].y
;
1994 epp
->pdata
.pathpt
[1] = loccycle
;
1995 epp
->pdata
.pathpt
[0] = pidx
;
2004 if ((keyptr
!= new_key
) && (keyptr
!= key
)) free(keyptr
);
2007 /*--------------------------------------------------------------*/
2008 /* Remove a numerical (integer or float) parameter. Remove by */
2009 /* type, rather than key. There may be several keys associated */
2010 /* with a particular type, so we want to remove all of them. */
2011 /*--------------------------------------------------------------*/
2013 void removenumericalp(genericptr
*gelem
, u_int mode
)
2019 Boolean done
= False
, is_last
= True
;
2021 /* Parameterized strings are handled by makeparam() */
2022 if (mode
== P_SUBSTRING
) {
2023 Fprintf(stderr
, "Error: Unmakenumericalp called on a string parameter.\n");
2027 /* Avoid referencing the object by only looking at the element. */
2028 /* But, avoid dereferencing the pointer! */
2033 for (epp
= (*gelem
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
2034 ops
= match_param(topobject
, epp
->key
);
2035 if (ops
== NULL
) break; /* Error---no such parameter */
2036 else if (ops
->which
== (u_char
)mode
) {
2038 free_element_param(*gelem
, epp
);
2040 /* check for any other references to the parameter. If there */
2041 /* are none, remove all instance records of the eparam, then */
2042 /* remove the parameter itself from the object. */
2044 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
2045 + topobject
->parts
; pgen
++) {
2046 if (*pgen
== *gelem
) continue;
2047 for (epp
= (*pgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
2048 if (!strcmp(epp
->key
, key
)) {
2053 if (!is_last
) break;
2056 free_object_param(topobject
, ops
);
2067 /*--------------------------------------------------------------*/
2068 /* Insert an existing parameter into a string. */
2069 /* This code needs to be replaced in the non-Tcl version with */
2070 /* a new pop-up window using a callback to labeltext(). */
2072 /* This routine has been replaced in the Tcl version with a */
2073 /* callback to command "label insert parameter" from the */
2074 /* parameter-select pop-up window. */
2075 /*--------------------------------------------------------------*/
2083 char *newstr
, *sptr
;
2084 char *sstart
= (char *)malloc(1024);
2085 oparamptr chosen_ops
=NULL
;
2087 /* Don't allow nested parameters */
2089 tlab
= TOLABEL(EDITPART
);
2090 if (paramcross(topobject
, tlab
)) {
2091 Wprintf("Parameters cannot be nested!");
2096 strcpy(sstart
, "Choose: ");
2098 for (ops
= topobject
->params
; ops
!= NULL
; ops
= ops
->next
) {
2099 if (ops
->type
== XC_STRING
) {
2106 newstr
= stringprint(ops
->parameter
.string
, NULL
);
2107 sprintf(sptr
, "%d = %s = <%s", nparms
, ops
->key
, newstr
);
2110 sptr
+= strlen(sptr
);
2114 /* If only one parameter, then automatically use it. Otherwise, */
2115 /* prompt for which parameter to use. */
2118 int i
=0, select_int
;
2120 Wprintf("%s", sstart
);
2121 select_int
= getkeynum();
2122 for (ops
= topobject
->params
; ops
!= NULL
; ops
= ops
->next
) {
2123 if (ops
->type
== XC_STRING
) {
2124 if (i
==select_int
) chosen_ops
= ops
;
2132 if (ops
!= NULL
) selparm
= ops
->key
;
2135 labeltext(PARAM_START
, selparm
);
2137 Wprintf("No such parameter.");
2142 /*--------------------------------------------------------------*/
2143 /* Parameterize a label string. */
2144 /*--------------------------------------------------------------*/
2146 void makeparam(labelptr thislabel
, char *key
)
2149 stringpart
*begpart
, *endpart
;
2152 /* Ensure that no two parameters have the same name! */
2154 if (check_param(topobject
, key
)) {
2155 Wprintf("There is already a parameter named %s!", key
);
2156 areawin
->textend
= 0;
2160 /* make sure this does not overlap another parameter */
2162 if (paramcross(topobject
, thislabel
)) {
2163 Wprintf("Parameters cannot be nested!");
2164 areawin
->textend
= 0;
2168 /* Check parameter for valid name syntax */
2170 newkey
= checkvalidname(key
, NULL
);
2171 if (newkey
== NULL
) newkey
= key
;
2173 /* First, place PARAM_START and PARAM_END structures at the */
2174 /* intended parameter boundaries */
2176 if (areawin
->textend
> 0 && areawin
->textend
< areawin
->textpos
) {
2177 /* partial string */
2178 splitstring(areawin
->textend
, &thislabel
->string
, areawin
->topinstance
);
2179 splitstring(areawin
->textpos
, &thislabel
->string
, areawin
->topinstance
);
2181 /* Because "splitstring" changes all the pointers, find the */
2182 /* stringpart structures at textend and textpos positions. */
2184 begpart
= findstringpart(areawin
->textend
, NULL
, thislabel
->string
,
2185 areawin
->topinstance
);
2186 endpart
= findstringpart(areawin
->textpos
, NULL
, thislabel
->string
,
2187 areawin
->topinstance
);
2189 /* Make the new segments for PARAM_START and PARAM_END. */
2191 begpart
= makesegment(&thislabel
->string
, begpart
);
2192 endpart
= makesegment(&thislabel
->string
, endpart
);
2194 else { /* full string */
2195 /* Don't include the first font designator as part of the */
2196 /* parameter or else havoc ensues. */
2197 if (thislabel
->string
->type
== FONT_NAME
&& thislabel
->string
->nextpart
2199 makesegment(&thislabel
->string
, thislabel
->string
->nextpart
);
2200 begpart
= thislabel
->string
->nextpart
;
2203 makesegment(&thislabel
->string
, thislabel
->string
);
2204 begpart
= thislabel
->string
;
2206 endpart
= makesegment(&thislabel
->string
, NULL
);
2208 begpart
->type
= PARAM_START
;
2209 begpart
->data
.string
= (char *)malloc(1 + strlen(newkey
));
2210 strcpy(begpart
->data
.string
, newkey
);
2211 endpart
->type
= PARAM_END
;
2212 endpart
->data
.string
= (u_char
*)NULL
;
2214 /* Now move the sections of string to the object parameter */
2216 newops
= make_new_parameter(newkey
);
2217 newops
->next
= topobject
->params
;
2218 topobject
->params
= newops
;
2219 newops
->type
= XC_STRING
;
2220 newops
->which
= P_SUBSTRING
;
2221 newops
->parameter
.string
= begpart
->nextpart
;
2222 begpart
->nextpart
= endpart
->nextpart
;
2223 endpart
->nextpart
= NULL
;
2225 areawin
->textend
= 0;
2226 incr_changes(topobject
);
2227 if (newkey
!= key
) free(newkey
);
2230 /*--------------------------------------------------------------*/
2231 /* Destroy the selected parameter in the indicated instance */
2232 /*--------------------------------------------------------------*/
2234 void destroyinst(objinstptr tinst
, objectptr refobj
, char *key
)
2237 /* short k; (jdk) */
2239 if (tinst
->thisobject
== refobj
) {
2240 ops
= match_instance_param(tinst
, key
);
2242 if (ops
->type
== XC_STRING
)
2243 freelabel(ops
->parameter
.string
);
2244 else if (ops
->type
== XC_EXPR
)
2245 free(ops
->parameter
.expr
);
2246 free_instance_param(tinst
, ops
);
2251 /*--------------------------------------------------------------*/
2252 /* Search and destroy the selected parameter in all instances */
2253 /* of the specified object. */
2254 /*--------------------------------------------------------------*/
2256 void searchinst(objectptr topobj
, objectptr refobj
, char *key
)
2261 if (topobj
== NULL
) return;
2263 for (pgen
= topobj
->plist
; pgen
< topobj
->plist
+ topobj
->parts
; pgen
++) {
2264 if (IS_OBJINST(*pgen
)) {
2265 tinst
= TOOBJINST(pgen
);
2266 destroyinst(tinst
, refobj
, key
);
2271 /*--------------------------------------------------------------*/
2272 /* Destroy the object parameter with key "key" in the object */
2273 /* "thisobj". This requires first tracking down and removing */
2274 /* all instances of the parameter which may exist anywhere in */
2276 /*--------------------------------------------------------------*/
2278 void free_object_param(objectptr thisobj
, oparamptr thisparam
)
2282 oparamptr ops
, lastops
= NULL
;
2284 char *key
= thisparam
->key
;
2286 /* Find all instances of this object and remove any parameter */
2287 /* substitutions which may have been made. */
2289 for (k
= 0; k
< xobjs
.pages
; k
++) {
2290 if (xobjs
.pagelist
[k
]->pageinst
!= NULL
)
2291 searchinst(xobjs
.pagelist
[k
]->pageinst
->thisobject
, thisobj
, key
);
2293 for (j
= 0; j
< xobjs
.numlibs
; j
++) {
2294 for (k
= 0; k
< xobjs
.userlibs
[j
].number
; k
++) {
2295 if (*(xobjs
.userlibs
[j
].library
+ k
) == thisobj
)
2298 searchinst(*(xobjs
.userlibs
[j
].library
+ k
), thisobj
, key
);
2302 /* Ensure that this parameter is not referred to in the undo records */
2303 /* We could be kinder and gentler to the undo record here. . . */
2306 /* Also check through all instances on the library page */
2308 for (spec
= xobjs
.userlibs
[l
].instlist
; spec
!= NULL
; spec
= spec
->next
)
2309 destroyinst(spec
->thisinst
, thisobj
, key
);
2311 /* Remove the parameter from any labels that it might occur in */
2313 for (pgen
= thisobj
->plist
; pgen
< thisobj
->plist
+ thisobj
->parts
; pgen
++) {
2314 if (IS_LABEL(*pgen
)) {
2315 Boolean pending
= TRUE
;
2317 labelptr plab
= TOLABEL(pgen
);
2321 for (strptr
= plab
->string
; strptr
!= NULL
; strptr
= strptr
->nextpart
) {
2322 if (strptr
->type
== PARAM_START
) {
2323 if (!strcmp(strptr
->data
.string
, key
)) {
2324 unmakeparam(plab
, NULL
, strptr
);
2334 /* Remove the parameter from the object itself, tidying up */
2335 /* the linked list after it. */
2337 for (ops
= thisobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
2338 if (ops
== thisparam
) {
2339 if (lastops
!= NULL
)
2340 lastops
->next
= ops
->next
;
2342 thisobj
->params
= ops
->next
;
2350 incr_changes(thisobj
);
2353 /*--------------------------------------------------------------*/
2354 /* Check if this string contains a parameter */
2355 /*--------------------------------------------------------------*/
2357 stringpart
*searchparam(stringpart
*tstr
)
2359 stringpart
*rval
= tstr
;
2360 for (rval
= tstr
; rval
!= NULL
; rval
= rval
->nextpart
)
2361 if (rval
->type
== PARAM_START
)
2366 /*--------------------------------------------------------------*/
2367 /* Remove parameterization from a label string or substring. */
2368 /*--------------------------------------------------------------*/
2370 void unmakeparam(labelptr thislabel
, objinstptr thisinst
, stringpart
*thispart
)
2374 stringpart
*strptr
, *lastpart
, *endpart
, *newstr
, *subs
;
2377 /* make sure there is a parameter here */
2379 if (thispart
->type
!= PARAM_START
) {
2380 Wprintf("There is no parameter here.");
2383 key
= thispart
->data
.string
;
2385 /* Unparameterizing can cause a change in the string */
2386 undrawtext(thislabel
);
2388 /* Methodology change 7/20/06: Remove only the instance of the */
2389 /* parameter. The parameter itself will be deleted by a different */
2390 /* method, using free_object_param(). */
2392 ops
= (thisinst
!= NULL
) ? match_instance_param(thisinst
, key
) :
2393 match_param(topobject
, key
);
2395 if (ops
== NULL
) ops
= match_param(topobject
, key
);
2397 if (ops
== NULL
) return; /* Report error? */
2399 /* Copy the default parameter into the place we are unparameterizing */
2400 /* Promote first to a string type if necessary */
2402 if (ops
->type
== XC_STRING
) {
2403 subs
= ops
->parameter
.string
;
2405 newstr
= stringcopy(subs
);
2407 /* Delete the "PARAM_END" off of the copied string and link it */
2408 /* into the existing string. */
2409 /* (NOTE: If parameter is an empty string, there may be nothing */
2410 /* before PARAM_END. . .) */
2412 if (newstr
->type
!= PARAM_END
) {
2413 for (endpart
= newstr
; endpart
->nextpart
->type
!= PARAM_END
;
2414 endpart
= endpart
->nextpart
);
2415 free(endpart
->nextpart
);
2416 endpart
->nextpart
= thispart
->nextpart
;
2420 newstr
= newstr
->nextpart
;
2425 /* Remove dangling link from instance parameter */
2426 /* (If this was a global parameter, it will have no effect) */
2427 for (strptr
= ops
->parameter
.string
; strptr
->type
!= PARAM_END
;
2428 strptr
= strptr
->nextpart
);
2429 strptr
->nextpart
= NULL
;
2432 /* This should not happen */
2433 Fprintf(stderr
, "Error: String contains non-string parameter!\n");
2434 redrawtext(thislabel
);
2439 for (strptr
= thislabel
->string
; strptr
!= NULL
&& strptr
!= thispart
;
2440 strptr
= strptr
->nextpart
) {
2443 if (lastpart
== NULL
)
2444 thislabel
->string
= newstr
;
2446 lastpart
->nextpart
= newstr
;
2449 /* Merge strings at boundaries, if possible. */
2450 if (endpart
) mergestring(endpart
);
2451 mergestring(lastpart
);
2453 redrawtext(thislabel
);
2456 /*----------------------------------------------------------------------*/
2457 /* Wrapper for unmakeparam(). Remove a parameterized substring from a */
2458 /* label, or remove a numeric parameter from an element. */
2460 /* NOTE: This routine should not combine the instance-only string */
2461 /* parameter removal and the numeric parameter deletion, which is */
2462 /* fundamentally different in nature. */
2463 /*----------------------------------------------------------------------*/
2465 void unparameterize(int mode
)
2467 short *fselect
, ptype
;
2469 stringpart
*strptr
, *tmpptr
, *lastptr
;
2473 ptype
= (short)param_select
[mode
];
2474 if (!checkselect(ptype
)) select_element(ptype
);
2475 if (!checkselect(ptype
)) return;
2480 // NOTE: Need a different method for interactive edit; remove only the
2481 // parameter under the cursor.
2483 if (eventmode
== ETEXT_MODE
) {
2484 /* ETEXT_MODE implies there is only one selected label */
2485 settext
= SELTOLABEL(areawin
->selectlist
);
2486 strptr
= findstringpart(areawin
->textpos
, &locpos
, settext
->string
,
2487 areawin
->topinstance
);
2489 /* Assume the cursor is inside a parameter and find the end */
2490 while (strptr
!= NULL
&& strptr
->type
!= PARAM_START
&& strptr
->type
!= PARAM_END
)
2491 strptr
= strptr
->nextpart
;
2493 if (strptr
&& (strptr
->type
== PARAM_END
)) {
2494 strptr
= strptr
->nextpart
;
2495 tmpptr
= settext
->string
;
2496 while (tmpptr
!= NULL
) {
2497 if (tmpptr
->type
== PARAM_START
) {
2498 if (tmpptr
->nextpart
== strptr
) {
2499 /* tmpptr now points to the parameter to be removed */
2500 unmakeparam(settext
, areawin
->topinstance
, tmpptr
);
2504 tmpptr
= tmpptr
->nextpart
;
2509 else if ((areawin
->selects
== 1) && (mode
== P_SUBSTRING
) && areawin
->textend
> 0
2510 && areawin
->textend
< areawin
->textpos
) {
2511 if (SELECTTYPE(areawin
->selectlist
) != LABEL
) return; /* Not a label */
2512 settext
= SELTOLABEL(areawin
->selectlist
);
2513 strptr
= findstringpart(areawin
->textend
, &locpos
, settext
->string
,
2514 areawin
->topinstance
);
2515 while (strptr
!= NULL
&& strptr
->type
!= PARAM_END
)
2516 strptr
= strptr
->nextpart
;
2517 if (strptr
== NULL
) return; /* No parameters */
2518 tmpptr
= settext
->string
;
2521 /* Search for parameter boundary, in case selection doesn't include */
2522 /* the whole parameter or the parameter start marker. */
2524 for (tmpptr
= settext
->string
; tmpptr
!= NULL
&& tmpptr
!= strptr
;
2525 tmpptr
= nextstringpart(tmpptr
, areawin
->topinstance
))
2526 if (tmpptr
->type
== PARAM_START
) lastptr
= tmpptr
;
2527 /* Finish search, unlinking any parameter we might be inside */
2528 for (; tmpptr
!= NULL
; tmpptr
= nextstringpart(tmpptr
, areawin
->topinstance
));
2530 if (lastptr
!= NULL
) unmakeparam(settext
, areawin
->topinstance
, lastptr
);
2533 for (fselect
= areawin
->selectlist
; fselect
< areawin
->selectlist
+
2534 areawin
->selects
; fselect
++) {
2535 if ((mode
== P_SUBSTRING
) && SELECTTYPE(fselect
) == LABEL
) {
2538 settext
= SELTOLABEL(fselect
);
2540 // Remove all parameters from the string.
2542 while (found
== (u_char
)1) {
2544 strptr
= settext
->string
;
2545 while (strptr
!= NULL
) {
2546 if (strptr
->type
== PARAM_START
) {
2547 unmakeparam(settext
, areawin
->topinstance
, strptr
);
2551 strptr
= strptr
->nextpart
;
2555 else if (mode
== P_POSITION
) {
2556 removenumericalp(topobject
->plist
+ (*fselect
), P_POSITION_X
);
2557 removenumericalp(topobject
->plist
+ (*fselect
), P_POSITION_Y
);
2560 removenumericalp(topobject
->plist
+ (*fselect
), mode
);
2562 setparammarks(NULL
);
2566 /*--------------------------------------------------------------*/
2567 /* Wrapper for makeparam() */
2568 /*--------------------------------------------------------------*/
2570 void parameterize(int mode
, char *key
, short cycle
)
2572 short *fselect
, ptype
;
2574 Boolean preselected
;
2576 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2578 ptype
= (short)param_select
[mode
];
2579 if (!checkselect(ptype
)) select_element(ptype
);
2580 if (!checkselect(ptype
)) return;
2585 for (fselect
= areawin
->selectlist
; fselect
< areawin
->selectlist
+
2586 areawin
->selects
; fselect
++) {
2587 if ((mode
== P_SUBSTRING
) && (areawin
->selects
== 1) &&
2588 (SELECTTYPE(fselect
) == LABEL
)) {
2589 settext
= SELTOLABEL(fselect
);
2590 makeparam(settext
, key
);
2592 else if (mode
== P_POSITION
) {
2593 makenumericalp(topobject
->plist
+ (*fselect
), P_POSITION_X
, key
, cycle
);
2594 makenumericalp(topobject
->plist
+ (*fselect
), P_POSITION_Y
, key
, cycle
);
2597 makenumericalp(topobject
->plist
+ (*fselect
), mode
, key
, cycle
);
2599 if (!preselected
) unselect_all();
2600 setparammarks(NULL
);
2603 /*----------------------------------------------------------------------*/
2604 /* Looks for a parameter overlapping the textend <--> textpos space. */
2605 /* Returns True if there is a parameter in this space. */
2606 /*----------------------------------------------------------------------*/
2608 Boolean
paramcross(objectptr tobj
, labelptr tlab
)
2610 stringpart
*firstptr
, *lastptr
;
2613 lastptr
= findstringpart(areawin
->textpos
, &locpos
, tlab
->string
,
2614 areawin
->topinstance
);
2616 /* This text position can't be inside another parameter */
2617 for (firstptr
= lastptr
; firstptr
!= NULL
; firstptr
= firstptr
->nextpart
)
2618 if (firstptr
->type
== PARAM_END
) return True
;
2620 /* The area between textend and textpos cannot contain a parameter */
2621 if (areawin
->textend
> 0)
2622 for (firstptr
= findstringpart(areawin
->textend
, &locpos
, tlab
->string
,
2623 areawin
->topinstance
); firstptr
!= lastptr
;
2624 firstptr
= firstptr
->nextpart
)
2625 if (firstptr
->type
== PARAM_START
|| firstptr
->type
== PARAM_END
)
2631 /*----------------------------------------------------------------------*/
2632 /* Check whether this page object was entered via a library page */
2633 /*----------------------------------------------------------------------*/
2638 pushlistptr thispush
;
2640 for (thispush
= areawin
->stack
; thispush
!= NULL
; thispush
= thispush
->next
)
2641 if ((i
= is_library(thispush
->thisinst
->thisobject
)) >= 0)
2647 /*----------------------------------------------------------------------*/
2648 /* Remove all parameters from an object instance */
2649 /* (Reverts all parameters to default value) */
2650 /*----------------------------------------------------------------------*/
2652 void removeinstparams(objinstptr thisinst
)
2656 while (thisinst
->params
!= NULL
) {
2657 ops
= thisinst
->params
;
2658 thisinst
->params
= ops
->next
;
2660 if (ops
->type
== XC_STRING
)
2661 freelabel(ops
->parameter
.string
);
2662 else if (ops
->type
== XC_EXPR
)
2663 free(ops
->parameter
.expr
);
2668 /*----------------------------------------------------------------------*/
2669 /* Remove all parameters from an object. */
2670 /*----------------------------------------------------------------------*/
2672 void removeparams(objectptr thisobj
)
2676 while (thisobj
->params
!= NULL
) {
2677 ops
= thisobj
->params
;
2678 thisobj
->params
= ops
->next
;
2680 if (ops
->type
== XC_STRING
)
2681 freelabel(ops
->parameter
.string
);
2682 else if (ops
->type
== XC_EXPR
)
2683 free(ops
->parameter
.expr
);
2686 thisobj
->params
= NULL
;
2689 /*-----------------------------------------------------------------------*/