File: README

package info (click to toggle)
dstooltk 2.0-4
  • links: PTS
  • area: main
  • in suites: woody
  • size: 2,520 kB
  • ctags: 3,169
  • sloc: ansic: 27,185; tcl: 4,770; makefile: 588; sh: 81; csh: 7
file content (1243 lines) | stat: -rw-r--r-- 50,281 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
Instructions for creating your own version of DsTool
====================================================

Table of Contents:

I.    Motivation
II.   Creating your own version of DsTool
III.  Executing your own version of DsTool
IV.   Linking external libraries into DsTool
V.    Adding your own model to DsTool
VI.   Adding animation to your model
VII.  Adding your own computational code to DsTool
    A.   Scripting in Tcl/Tk 
    B.   Adding model-specific code
    C.   Adding general purpose code
    D.   Incorporating your code into DsTool
    E.   Accessing data already computed by DsTool
VIII. Adding your own Tcl/Tk code to DsTool
    A.   Changing default colors and fonts
    B.   Changing external program calls
    C.   Changing default values of other global variables
    D.   Creating Tcl/Tk windows in DsTool


I. Motivation
-------------

This file describes how to create a custom version of DsTool.  You might want
to do this for many reasons.  For example, you may want to change the default
color or font settings for DsTool, or use a different image or postscript 
viewer than the default one.  Maybe you want to add models that you are 
studying in your own research to DsTool, and you want those models to have 
accompanying animations.  Perhaps you're feeling adventurous and want to 
extend the capabilities of DsTool by writing your own Tcl/Tk windows or your 
own computational code.  All of these procedures (and more!) are described in
this file. 


II. Creating your own version of DsTool
---------------------------------------

0) This assumes that DsTool has already been installed and compiled on your 
   network and that you have been able to run it!  This file, before you 
   possibly copied it into your own directory, is stored in a subdirectory of
   the DsTool directory called my_dstool.

1) You must first define some environmental variables:

	setenv DSTOOL <the DsTool code directory>
	setenv MY_DSTOOL <directory in which you will put your DsTool stuff>
	setenv ARCH <hardware type -- should be: sun4 or solaris or iris or linux>

   For example:

	setenv DSTOOL /usr/local/src/dstool_tk
	setenv MY_DSTOOL $HOME/my_dstool
	setenv ARCH `cputype`

   These environmental variables should be set for both compilation and 
   runtime so you may want to add them to your .cshrc file or another 
   appropriate place.

2) Now make sure the directory MY_DSTOOL exists and copy the source code in 
   $DSTOOL/my_dstool into $MY_DSTOOL.

	mkdir $MY_DSTOOL
	cp -r $DSTOOL/my_dstool/* $MY_DSTOOL

3) Now make your personal version of DsTool.

	cd $MY_DSTOOL
	make


III. Executing your own version of DsTool
-----------------------------------------

1) You must first define an environmental variable:

	setenv MY_DSTOOL <directory where you put your DsTool stuff>

   For example:

	setenv MY_DSTOOL $HOME/my_dstool

2) Test it by running:

	dstool_tk

   There should be a message saying that the following binary is being 
   executed:  $MY_DSTOOL/bin/$ARCH/my_dstool

Notes on running dstool_tk:

dstool_tk is a script distributed with DsTool which should already be 
installed in someplace accessible to you.  This script determines where to 
look for the dstool_tk binary and the data files which DsTool needs.  It uses
the environmental variables MY_DSTOOL, DSTOOL, and ARCH.  If the MY_DSTOOL 
environmental variable is set, then it tries to execute the binary 
$MY_DSTOOL/bin/$ARCH/my_dstool, otherwise it will try to execute 
$DSTOOL/bin/$ARCH/dstool_tk.  A message is printed which gives the expanded 
pathname of the binary which is being executed when the dstool_tk script is 
run.


IV. Linking external libraries into DsTool
------------------------------------------

When you write the C code to define your model or execute your computational 
code, you may want to use external libraries (NAG, IMSL, ADOLC, etc).  To 
compile them into DsTool, you will need to modify the file 
$MY_DSTOOL/Makefile.  Specifically, you will need to add the external library
to the list of user libraries.  This might look something like the following:

     NAGLIB = /usr/local/lib/libnag.a
     USER_LIBS = $(NAGLIB) \
                 /usr/local/lang/SC1.0/libF77.a 

These lines tell the compiler to link to the appropriate NAG and Fortran 77 
libraries.  If you compile DsTool on a different architecture, you may need 
to change these lines to refer to the appropriate architecture-specific 
libraries.


V. Adding your own model to DsTool
----------------------------------

We will describe how to compile a new model into DsTool.  Please see the 
User's manual for a description of how to write the C code for the model.  
These instructions simply describe how to create the new executable.  You may
find that you can simply modify a model already in DsTool - look in the 
directory $DSTOOL/src/models.

1) Write the new model definition in a file which we shall assume is called 
   new_model_def.c and put this file in the directory $MY_DSTOOL.  We shall 
   assume that the initialization procedure is called new_model_init().

2) Edit the file $MY_DSTOOL/user.c so that the new model is incorporated into
   the list of known models.  This involves first declaring the initialization
   procedure:

	extern int new_model_init();

   then adding it to the list of user dynamical systems.  This might now look 
   like:

	struct DS_DataS USER_DS_Sel[]= {
	  { 0, "Lorenz system", lorenz_init },
	  { 0, "My new model", new_model_init }
	};

   The first number is an integer which indicates the category under which the
   model should be listed.  Initially, there is just one category, but 
   multiple categories can be set up by modifying the category list in the 
   following manner:

	char *USER_DS_Category[] = { "User models", /* Category 0 */
			     "Project with Bob", /* Category 1 */
			     "My favorite dynamical systems" /* Category 2 */
			   };

3) Edit the file $MY_DSTOOL/Makefile to add new_model_def.c to the USER_SRCS 
   line and new_model_def.o to the USER_OBJS line.  For example:
 
	USER_SRCS = user.c new_model_def.c
	USER_OBJS = user.o new_model_def.o

   If your model file uses an external library, modify the file 
   $MY_DSTOOL/Makefile to include the appropriate library, as described in the
   above section.

4) Recompile your DsTool binary by executing the 'make' command in the 
   directory $MY_DSTOOL.  See the above section on creating your own version 
   of DsTool for more details on this and a list of the environmental 
   variables which must be set for it to work.


VI. Adding animation to your model
----------------------------------

This will assume that you already know how to use Geomview and a little bit 
about Geomview's oogl language.  You may also find it helpful to look at some
of the system examples.

There are two types of animations.  The first is where objects are moved 
simply by sending new transformation matrices to Geomview.  This is how the 
pendulum and restricted three body problem are implemented.  Another way is 
to write out a new Geomview object every time replacing an existing one.  This
is how you make simulated water waves.

We will discuss how to animate using transformation objects first.  We will 
suppose that you have just created (and installed) a new dynamical system 
called "mymodel" and saved it in the file $MY_DSTOOL/mymodel_def.c

1) Create an oogl file for Geomview where the transformation matrices that 
   need to be updated for animation have names ttt0, ttt1, ttt2, ....  Save 
   this file in $MY_DSTOOL/oogl/mymodel.oogl

2) Edit the model file $MY_DSTOOL/mymodel_def.c by including the following 
   code before the "#include <ds_define.c>" statement:

	#define GV
		int (*gv_funct)() = mymodel_gv;
		int (*gv_custom_funct)() = NULL;
		int gv_n = 3;
		static char *gv_filename = "mymodel.oogl";

   The value of gv_n should be adjusted to reflect the number of 
   transformation matrices to be sent to geomview.

3) Continue editing the file $MY_DSTOOL/mymodel_def.c and create the function
   mymodel_gv.  This function should provide a mapping between the phase and 
   parameter spaces to the transformation matrices.  Each transformation 
   matrix is 16 doubles which are arranged in a vector so that 
   f[4*i+j] = T[i][j] (i=0..3, j=0..3).  The vectors for each transformation 
   matrix are concatenated together to make one vector of length 16*gv_n, 
   where gv_n is the number of transformation matrices.  Here is a simple 
   example where two transformation matrices are used:

	/* function used for geomview transformation matrices */
	int
	mymodel_gv(double *f, double *x, double *p)
	{
		int i;

		/* zero matrix */
		for (i=0; i<32; i++) f[i] = 0.0;

		/* simply scale first object using p[0] */
		f[0] = f[5] = f[10] = 1.0;
		f[15] = p[0];

		/* rotate second object in the x-y plane by theta=x[0] */
		f[0] = f[5] = cos(x[0]);
		f[1] = sin(x[0]);
		f[4] = -f[1];
		f[10] = f[15] = 1.0;

		return 0;
	}

4) Recompile your personal version of DsTool and see if it works!

If you need more complicated commands sent to Geomview than simply pumping out
transformation matrices in order to provide an animation then you need to 
write a custom animation routine for the model.

1) Create an oogl file for Geomview which will be loaded when the model is 
   selected or through the animation window.  Save this file in 
   $MY_DSTOOL/oogl/mymodel.oogl.

2) Edit the model file $MY_DSTOOL/mymodel_def.c by including the following 
   code before the "#include <ds_define.c>" statement:

	#define GV
		int (*gv_funct)() = NULL;
		int (*gv_custom_funct)() = mymodel_gv_custom;
		int gv_n = 0;
		static char *gv_filename = "mymodel.oogl";

   In this example we use no transformation matrices, but the two methods can
   be combined!

3) Continue editing the file $MY_DSTOOL/mymodel_def.c and create the function
   mymodel_gv_custom.  This function should use the supplied phase space and 
   parameter values to write a Geomview object.  It should use the procedure 
   geomview_send(char *) to send strings to Geomview.  An example function 
   would look something like this:

	/* function used for geomview animations */
	int
	mymodel_gv_custom(double *x, double *p)
	{
		/* wrap commands in progn so that no partial 
		   updates are performed */
		geomview_send("(progn\n");

		/* send stuff now */
		geomview_send("(read geometry {define ");
		... AND SO ON ...
		
		geomview_send(")\n");
		return 0;
	}

4) Recompile your personal version of DsTool and see if it works!


VII. Adding your own computational code to DsTool
-------------------------------------------------

Custom analysis code may be added to DsTool on a model-by-model basis or on a
general purpose basis.  The installation of the computational routines in 
these two cases is similar.  In writing your computational code, you should 
check the utility routines in $DSTOOL/src/math_utilities and 
$DSTOOL/src/utilities to look for helpful routines.  Many matrix utilities 
(LU-factorization, Singular value decomposition, etc.) are included in these 
directories.  In addition, eigenvalue and eigenvector routines can be found in
the directory $DSTOOL/src/eigen. 


VII.A. Scripting in Tcl/Tk
--------------------------
 
As mentioned in the User's manual (section 3.2.2), DsTool can be run entirely
by typing commands at the command prompt.  For this reason, when doing simple
computations, it is probably easiest to write them as Tcl/Tk scripts.  
Scripting can also be useful for developing routines, since you can modify 
scripts and re-execute the same binary, without recompiling every time you 
modify your code.  Of course, due to the overhead of Tcl/Tk, routines 
scripted in Tcl/Tk will be much slower than their C counterparts.

You can run scripts from the terminal by typing "source <filename>", or you 
can create Tcl/Tk windows which run the scripts when a button is pressed.  For
information on writing Tcl/Tk scripts, consult a comprehensive Tcl/Tk source.
A good on-line reference guide is:

	http://www.sco.com/Technology/tcl/Tcl.html


VII.B. Adding model-specific code
---------------------------------

To add model-specific code, two extra C code routines need to be written.  The
first should be thought of as initialization code which gets called when the 
model is selected.  This routine will install your computational code so that
it is usable.  The second is cleanup code which gets called when the user 
selects some other model.  This routine will remove your computational code, 
so that the user does not try to use it with another model.  Throughout this 
and the following sections, we will adhere to the following convention:  
procedures using the name "mycode" will refer to the computational 
(model-specific or general purpose) routines, and procedures using the name 
"mymodel" will refer to routines which perform the operations of adding and 
removing objects when the specified model is selected.  Hence, procedures 
using the name "mymodel" will appear only in this section.

0) Since your code may consist of several files, it would be nice to have it 
   all together in a subdirectory. Therefore, assume you have created a 
   subdirectory called MYCODE.  Assume further that you have created a new 
   model definition called mymodel and it is in the file 
   $MY_DSTOOL/MYCODE/mymodel_def.c.

1) The initialization mymodel_init() in user.c should be as in section V, so 
   do not mention the subdirectory MYCODE there. However, do not add 
   mymodel_def.c to USER_SRCS in the Makefile, and do not add mymodel_def.o 
   to USER_OBJS. Instead, fill out in $MY_DSTOOL/Makefile:

	SUBDIRS = tcl MYCODE
   and
	USER_LIBS = MYCODE/libmycode.a

   The idea is to compile the files of MYCODE into the library libmycode.a. 
   This will happen by using the command "make all", which first creates the 
   library libmycode.a and then compiles your personal version of DsTool.

2) Edit $MY_DSTOOL/MYCODE/mymodel_def.c to include the following before the 
   "#include <ds_define.c>" line:

	pm(PUT, "Model.Install", mymodel_install,
	   PUT, "Model.Clean", mymodel_clean,
	   NULL);

   Include declarations for these routines right after the 
   "#include <model_headers.h>" line:

	void mymodel_install(void);
	void mymodel_clean(void);

3) Now create a new file, say mymodel.c, in the directory MYCODE, and write 
   the routine mymodel_install(). This routine can do whatever it wants, even
   calling Tcl/Tk code to modify the interface.  This is commonly done to add
   new menu items to the window menu.  The tcl_script(char *) command is used
   for Tcl/Tk code.  Tcl/Tk procedures may be written and put in files in the
   $MY_DSTOOL/tcl/ directory. Here is a simple example: 

	/* file: mymodel.c */

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

	#include "pm.h"           /* these two files are needed to */
	#include "utilities.h"    /* use the procedure tcl_script  */

	#include "mymodel.h"      /* you create these files  */
	#include "mycode.h"	  /* see 4) */

	void
	mymodel_install()
	{
		fprintf(stderr, "Executing mymodel_install.\n");
                mycode_install();
		tcl_script("mymodel(install)");
	}

   The procedure mycode_install() will install the Postmaster entries 
   necessary for the computational routines.  It is important that this 
   routine is called before tcl_script("mymodel(install)") to set up the 
   interaction between the Postmaster and the Tcl/Tk variables correctly.  
   We will describe this further in section VII.D.

4) Now write the routine mymodel_clean(), also in $MY_DSTOOL/MYCODE/mymodel.c
   to deallocate memory assigned in mymodel_install() or revert changes to the
   interface. For example: 

	void
	mymodel_clean()
	{
		fprintf(stderr, "Executing mymodel_clean.\n");
		tcl_script("mymodel(clean)");
	}

5) The file "mymodel.h" should be created and should contain something like:

	/* file: mymodel.h */

	#ifndef MYMODEL_H
	#define MYMODEL_H

	void mymodel_install(void);
	void mymodel_clean(void);

	#endif

6) The file "mycode.h" should be created and should contain something like:

	/* file: mycode.h */

	#ifndef MYCODE_H
	#define MYCODE_H

	void mycode_compute(void);
	void mycode_install(void);

	#endif

7) In order for all these files to communicate, you should write a Makefile in
   the directory $MY_DSTOOL/MYCODE/ that links them together and defines the 
   library libmymodel.a.  This should look like:
 
        #
        # Makefile for library
        #
 
                 TOP = $(DSTOOL)
              CONFIG = $(TOP)/config
         CURRENT_DIR = ./MYCODE
         INCLUDE_DIR = $(TOP)/src/include
 
        include $(CONFIG)/Makefile.defs
 
          LIB_NAME = libmycode.a              
              SRCS = mymodel_def.c mymodel.c mycode.c 
              OBJS = mymodel_def.o mymodel.o mycode.o
        
          INCLUDE_FILES = mymodel.h mycode.h
 
 
        all:: $(LIB_NAME)
 
        include $(CONFIG)/Makefile.rules
 
8) You still need to write the two procedures called by tcl_script, 
   mymodel(install) and mymodel(clean). This is done in the file mymodel.tk, 
   in the directory $MY_DSTOOL/tcl/. As an example, we write the two 
   procedures such that when you select the model "mymodel" in DsTool, a new 
   menu option in "Panels" appears that causes a window to pop up.  The Tcl/Tk
   procedure that creates the window will be discussed below, but the command
   that will cause the window to pop up is "window(open) mycode".

   The first part of the file mymodel.tk looks like this:

	# file: mymodel.tk

	# procedure that gets called when mymodel is selected
	proc mymodel(install) {} {
		new_tcl_pm MyCode
		cmd(add_to_panels) "Example menu item..." \
			"window(open) mycode"
	}

	# procedure that gets called when another model is selected
	# it must undo what the above procedure did
	proc mymodel(clean) {} {
		if [winfo exists [build_Wname mymodel]] {
			window(dismiss) mymodel
		}
		remove_tcl_pm MyCode
		cmd(remove_from_panels) "Example menu item..."
	}

   The procedures new_tcl_pm, remove_tcl_pm, cmd(add_to_panels), and 
   cmd(remove_from_panels) are known to DsTool already.  The first two 
   procedures respectively create and remove Postmaster objects in Tcl/Tk 
   named MyCode.  The latter two commands respectively add and remove a menu 
   item to the command ("cmd") window's popup menu "Panels". 

   One final note: Tcl/Tk is very picky about syntax.  If you just cut and 
   paste the routines above into the file mycode.tk (with the spaces before
   each line), Tcl/Tk will not pick up that they are procedures, and the 
   program will crash.  

9) You need to edit the Makefile in $MY_DSTOOL/tcl/ in order to let DsTool 
   know about your mymodel.tk file. In $MY_DSTOOL/tcl/Makefile, fill out:
 
        TK_SRCS = mymodel.tk
 
   Now type "make" in the directory $MY_DSTOOL/tcl/.

10) The preceding steps have developed the framework for adding computational
   code in the model-specific case.  When your new model is selected, a new 
   option appears in the Panels menu which will cause a window to pop up.  
   When you select a different model, that option disappears.  We have yet to 
   implement the computations that we want to perform, and write Tcl/Tk code
   for the windows.  Skip ahead to section VII.D to continue the installation.


VII.C. Adding general purpose code
----------------------------------

The procedure for adding general purpose code is much simpler than in the 
model-specific case.  Instead of editing model files so that menu options are
added and removed when different models are selected, you only need to add the
menu option once.  The drawback, of course, is that you either have to make 
your code more general, or realize that it won't be reliable and might crash 
the program (or worse!) if you try to use it with another model.  To make 
things even more complicated, remember that DsTool models can either be 
mappings or vector fields, so if you want your routine to be fully general, 
you should prepare it for both of these types of models.  An alternative is to
make your window appear differently for mappings and vector fields.  For 
example, assume you have a computational routine that will work only for 
vector fields.  When your window is opened (by mycode(build) -- see below), 
you can first check whether the current model is a mapping or a vector field. 
If it is a mapping, instead of opening your window, you can open a message 
window saying that your routines will not work for mappings.  Neglecting this
difficulty, the steps we take are:

0) Since your code may consist of several files, it would be nice to have it 
   all together in a subdirectory. Therefore, assume you have created a 
   subdirectory called MYCODE.  
 
1) Fill out in $MY_DSTOOL/Makefile:
 
        SUBDIRS = tcl MYCODE
   and
        USER_LIBS = MYCODE/libmycode.a
 
   The idea is to compile the files of MYCODE into the library libmycode.a. 
   This will happen by using the command "make all", which first creates the 
   library libmycode.a and then compiles your personal version of DsTool.
 
2) Edit the file $MY_DSTOOL/user.c to include your installation procedure 
   (which we will describe how to write below).  For now, assume it is called
   mycode_install().  The appropriate lines in user.c should now look 
   something like:

	/* ----------------------------------------------------------------
 	 *
 	 * INCLUDE USER COMPUTATIONAL MODULES HERE
 	 *
 	 * ----------------------------------------------------------------
	 */
 
	extern void mycode_install();
	 
	typedef void (*PFV)();
	 
	PFV user_install_procs[] = {
	   mycode_install,
	  (PFV) NULL
	};

   Be sure not to remove the "(PFV) NULL" entry.  DsTool uses this to signal 
   the end of the array.  The procedures in user_install_procs will be called
   when your custom version of DsTool starts up, installing your code once and
   for all.

3) Edit the file $MY_DSTOOL/tcl/my_app_init.tcl to make the menu option 
   appear.  This should look something like:

	proc my_app_init {} {
	    global COLOR FONT EXT
 
	    # Add changes to colors and fonts here

	    window(open) cmd

	    # Add new panel items here
	    cmd(add_to_panels) "Example menu item..." \
		"window(open) mycode"
	}

   This line will cause a new option to appear in the Panels list, which when
   pressed will execute the command "window(open) mycode", which opens the 
   window "mycode".   Note that this line must go after the line 
   "window(open) cmd", since we are changing entries in the Command window.

4) The file "mycode.h" should be created in the directory $MY_DSTOOL/MYCODE,
   and should contain something like:
 
        /* file: mycode.h */
 
        #ifndef MYCODE_H
        #define MYCODE_H
 
        void mycode_compute(void);
	void mycode_install(void);
 
        #endif
 
5) In order for all these files to communicate, you should write a Makefile in
   the directory $MY_DSTOOL/MYCODE/ that links them together and defines the 
   library libmycode.a.  This should look like:
 
        #
        # Makefile for library
        #
 
                 TOP = $(DSTOOL)
              CONFIG = $(TOP)/config
         CURRENT_DIR = ./MYCODE
         INCLUDE_DIR = $(TOP)/src/include
 
        include $(CONFIG)/Makefile.defs
 
          LIB_NAME = libmycode.a              
              SRCS = mycode.c  
              OBJS = mycode.o  
        
          INCLUDE_FILES = mycode.h
 
 
        all:: $(LIB_NAME)
 
        include $(CONFIG)/Makefile.rules

6) The preceding steps have developed the framework for adding computational
   code in the general purpose case.  When DsTool starts up, your custom 
   version will have an additional option in the Panels menu which will cause
   a window to pop up.  We have yet to implement the computations that we want
   to perform, and write the Tcl/Tk code for the windows.  Move on to the next
   section to continue the installation.
 

VII.D. Incorporating your code into DsTool
------------------------------------------

If you followed the steps above, you have set up the necessary framework to 
include your computational code.  You still must build the Tk window and write
the computational procedures.

To do this, you will need to know a little about DsTool's memory storage 
facility, the Postmaster.  The Postmaster is the keeper of most of DsTool's 
information, and offers an efficient way to pass information from DsTool to 
Tcl/Tk and vice versa.  All of the non-memory entries of the Postmaster are 
shadowed in Tcl/Tk as parts of global arrays.  For example, the Postmaster 
entry Defaults.Precision is shadowed in Tcl/Tk by the global variable 
Defaults(Precision).  The command "tcl_to_pm <Obj>" sends the values of the 
Tcl/Tk global array <Obj> to the Postmaster, and the command "pm_to_tcl <Obj>"
sends the values of the Postmaster entries of the object <Obj> to the Tcl/Tk 
global array <Obj>.  By using these commands together: first tcl_to_pm, then 
pm_to_tcl, you can update the Postmaster with all of the current information 
displayed in the Tcl/Tk interface windows, and return the information to 
confirm the values contained in the Postmaster.

1) You first need to let DsTool know about your new Tcl/Tk routines.  Edit the
   Makefile in $MY_DSTOOL/tcl/ by adding the routine mycode.tk to the TK_SRCS
   line.  In the model-specific case, you will have two entries on that line 
   now, and in the general purpose case, you will have only one.

2) Write the procedure that creates the new window that is supposed to pop up
   when we select "Example menu item...".  Put this procedure in the file 
   mycode.tk.  Our example will be a window with a read-write text field and 
   two buttons.  The read-write text field will illustrate how to use the 
   Postmaster to send information from Tcl/Tk to DsTool and back again.  One 
   of the buttons will be the "Dismiss" button to close the window.  You can 
   choose to have the other button (for the computations) next to this button,
   or right above it. In the first case, the procedure looks like this:

	# procedure to open MyCode window
	proc mycode(build) name {
	     global MyCode
	
	     build_Title $name "Example window"

	     build_LabelEntryColumns $name le0 \
                {text "" {Number:}} \
		{ientry "" {MyCode(Number)}}
	     bind_LabelEntryColumns $name.le0 1 <Return> mycode(update)

    	     build_DismissButtonbar $name dbbar \
		"window(dismiss) mycode" \
		{"My Code" mycode(compute_mycode) }
	}
		
   If you want them above each other, write something like this:

	# procedure to open MyCode window
	proc mycode(build) name {
             global MyCode
	
	     build_Title $name "Example window"

    	     build_DismissButtonbar $name dbbar \
		"window(dismiss) mycode" {}

             build_LabelEntryColumns $name le0 \
                {text "" {Number:}} \
                {ientry "" {MyCode(Number)}}
             bind_LabelEntryColumns $name.le0 1 <Return> mycode(update)

	     build_Buttonbar $name bb0 \
             	{"My Code" mycode(compute_mycode) }

	     pack $name.le0 -side top
	     pack $name.bb0 -side bottom
	}

   The standard routines build_DismissButtonbar, build_Buttonbar, 
   build_LabelEntryColumns, and bind_LabelEntryColumns are located in the file
   $DSTOOL/tcl/utils.tk.  The first three routines build the Tcl/Tk structures   with the specified callbacks.  The last command binds execution of the 
   command mycode(update) to the pressing of Return in column 1 (the entry 
   column) of the LabelEntryColumns widget.

   The "global MyCode" line is important for accessing the global variable 
   MyCode(Number), instead of a new local variable that would be otherwise
   automatically created by Tcl/Tk.  Recall that the global variable 
   MyCode(Number) shadows a Postmaster entry, which will be used by our 
   example computational code.

   As with the note in section VII.B.8, if you patch the above into a file,
   make sure you remove the preceding white space, to conform to proper Tcl/Tk
   syntax. 

3) To finish the window, you should write enter, leave, and update procedures 
   for the mycode window.  These should all go in the file mycode.tk, and 
   should look like the following:

	proc mycode(enter) {} {
	    pm_to_tcl MyCode
	}

	proc mycode(leave) {} {
	    tcl_to_pm MyCode
	}

	proc mycode(update) {} {
	    tcl_to_pm MyCode
	    pm_to_tcl MyCode
	}

   These procedures update the Postmaster and/or the Tcl/Tk interface entries
   when the user leaves, enters, or presses return in the mycode window.

4) In the previous two steps, you created the procedures that build and update
   the window. In the procedure mycode(build), it says:

	{"My Code" mycode(compute_mycode) }

   The build routine interprets this as saying that when you click the 
   "My Code" button, the routine mycode(compute_mycode) should be called.  
   Write this procedure also in the file mycode.tk: 

	proc mycode(compute_mycode) {} {
		begin_wait "Computing my code..."
		tcl_to_pm MyCode
		pm_to_tcl MyCode
		pm EXEC MyCode.compute_mycode
		end_wait "Done..."
	}

   The begin_wait and end_wait commands create messages on DsTool's Command 
   window to inform the user of the progress of the calculation.  The tcl_to_pm 
   and pm_to_tcl commands update the Postmaster and the Tcl/Tk variables as 
   described above.  Finally, the line "pm EXEC MyCode.compute_mycode" tells 
   the Postmaster to execute the command MyCode.compute_mycode.

5) The next step is to let the Postmaster know what the objects MyCode and 
   MyCode.compute_mycode are. This should be done in the procedure 
   mycode_install() in the new file $MY_DSTOOL/MYCODE/mycode.c.  The file 
   should look like:

	/* file: mycode.c */

        #include <math.h>
        #include <stdlib.h>
        #include <stdio.h>
	#include <pm.h>
        #include "mycode.h"

	void 
	mycode_install()
	{
	  fprintf(stderr, "Executing mycode_install.\n");

	  /* create elements for window values in the Postmaster */
	  pm(CREATE_OBJ,  "MyCode",
	     CREATE_ELEM, "MyCode.compute_mycode", FNCT,
	     CREATE_ELEM, "MyCode.Number", INT,
	     NULL);

	  /* initialize the function pointers in the Postmaster */
	  pm(INIT, "MyCode.compute_mycode",
	     PUT, "MyCode.compute_mycode", mycode_compute,
	     NULL);

	}

   The Postmaster will now execute the procedure mycode_compute when 
   "pm EXEC MyCode.compute_mycode" is called, which happens when the button 
   "My Code" is pressed.  In DsTool, each Postmaster object has an 
   installation routine similar to the one above, but most are significantly 
   more complex.  

6) It remains to write the procedure mycode_compute, which is the actual
   computational code you want to execute.  For our example, we simply put it
   inside mycode.c.  Recall the declaration of the procedure in mycode.h: 

	void mycode_compute(void);

   Please note that Postmaster functions cannot have any parameters.  If 
   information from DsTool is necessary, the procedure should get this 
   information from the Postmaster, via the MyCode or other Postmaster 
   objects.  For demonstration, we just print something. Edit 
   $MY_DSTOOL/MYCODE/mycode.c by adding:

	void mycode_compute()
	{
	  fprintf(stderr, "Hello World\n");
	}

7) Recompile your personal version of DsTool with the command "make all" and 
   see if it works!


VII.E. Accessing data already computed by DsTool
------------------------------------------------

Of course you want your computational code to interact with DsTool. For 
example, you would like to use the function defined in mymodel_def.c, or use 
the fixed points that you computed in DsTool. To give some intuition what 
needs to be done, we give an example. The procedure executed when you click on
"My Code" is going to print the eigenvectors of the fixed point specified by 
the read-write text field in the MyCode window (or nothing, if there haven't 
been enough fixed points computed).

1) Just as you created the object "MyCode" that knows about all the things you
   implemented so far, there is an object "Model", defined in 
   $DSTOOL/src/init/model_install.c, that knows all parameters in the current
   model, that is, in mymodel_def.c. Similarly, the object "Fixed", defined in
   $DSTOOL/src/fixed/fixed_install.c,  knows the parameters in the Fixed
   Points window, etc. Moreover, there is an object "Memory" that has access 
   to the data from previous computations in DsTool. 

   The file mycode.c needs the following additional include files:

	#include "memory.h"	 /* memory handling routines */
	#include "utilities.h"	 /* definitions used by tcl */
	#include "math_utils.h"  /* more definition for tcl */
	#include "flow.h"        /* used for computing the jacobian */
	#include "eigen.h"	 /* eigenvalue routines -- includes rg */

   and the following definition:

        #define WORK_SIZE 5000

2) Our example function mycode_compute is basically a combination of the 
   routines in $DSTOOL/src/browser/browser.c and $DSTOOL/src/cont/cont_state.c.
   First we find the right fixed point, then compute its eigenvalues and
   print them out.  Replace the trivial version of mycode_compute above with:

	void mycode_compute(void)
	{
          int    i,j,mode,ierror,*iwork,status = 0;
          int    format = *((int *) pm(GET, "Defaults.Precision", NULL));
          memory m = (memory) pm(GET, "Memory.Fixed", NULL);
          int n_varb, n_param, n_funcs, n_flows, number,
                *p_color, *p_bi;
          double *fd_step,*p_varb, *p_param, *p_bd,*wr,*wi,
                **jac2,*dwork,**B;
          Manifold *manifold;
 
          /* check for NULL memory item */
          if (m == NULL) return;
 
          n_varb = *((int *) pm(GET, "Model.Varb_Dim", NULL))-1;
          n_param = *((int *) pm(GET, "Model.Param_Dim", NULL));
          n_funcs = *((int *) pm(GET, "Model.Funct_Dim", NULL));
          n_flows = memory_nflows(m);
 
          /* find correct fixed point */
          number = *((int *) pm(GET, "MyCode.Number", NULL));
          if ((number < 1) || (number > n_flows)) return;
 
          status = memory_reset_read(m);
	  if (status) return;
          status = memory_set_read(m, number, 1, 1,
                             NULL, NULL, NULL, NULL, NULL, NULL);
          if (status) return;
 
          /* read it */
          status = memory_read_next_point(m, &p_varb, &p_param, &p_color,
                                    &p_bd, &p_bi);
 
          /* Set up manifold structure */ 
          manifold = (Manifold *) calloc(1, sizeof(Manifold));
          manifold->periodic_varb = ivector(0,n_varb);
          manifold->period_start = dvector(0,n_varb);
          manifold->period_end = dvector(0,n_varb);
          manifold->type = *((int *) pm( GET, "Manifold.Type", NULL ));
          pm( GET_LIST, "Manifold.Periodic_Varb", 0, n_varb-1,
                manifold->periodic_varb, NULL);
          pm( GET_LIST, "Manifold.Period_Start", 0, n_varb-1,
                manifold->period_start, NULL);
          pm( GET_LIST, "Manifold.Period_End", 0, n_varb-1,
                manifold->period_end, NULL);
 
          wr = dvector(0,n_varb);
          wi = dvector(0,n_varb);
          jac2 = dmatrix(0,n_varb+1,0,n_varb+1);
          fd_step = dvector(0,n_varb);
          dwork = dvector(0,WORK_SIZE);
          for(i=0; i<n_varb; i++) fd_step[i] = 1.0e-6;
 
          /* How do we compute the Jacobian? */
          if( (void *) pm( GET, "Model.DfDx", NULL ) == NULL )
            mode = FORW_DIFF;
          else mode = ANALYTIC;
 
          /* Compute it! */
          if (*((int *) pm( GET, "Model.Mapping_Flag", NULL )))   {
            ierror = dfdx( jac2, n_varb, fd_step, p_varb, p_param,
                          *((int *) pm( GET, "Flow.Skip_Size", NULL )),
                          manifold, FORWARD,
                          (void *) pm( GET, "Model.DS_Def", NULL ),
                          (void *) pm( GET, "Model.DfDx", NULL ), 
			  mode, dwork );
          } else {
            ierror = dfdx( jac2, n_varb, fd_step, p_varb, p_param, 0,
                          manifold, FALSE,
                          (void *) pm( GET, "Model.DS_Def", NULL ),
                          (void *) pm( GET, "Model.DfDx", NULL ), 
			  mode, dwork );
            }
 
          /* Now, find the eigenvalues */
          iwork = ivector(0,WORK_SIZE);
          B = dmatrix(0,n_varb+1,0,n_varb+1);
          for(i=0; i<n_varb; i++)
             for(j=0; j<n_varb; j++)
                B[i+1][j+1] = jac2[i][j];
 
	  /* rg is the eigenvalue finder: it's based upon eispack routines,
	   * and is located in $DSTOOL/src/eigen/rg.c 
	   */
          ierror = rg( n_varb , n_varb , B , &wr[0]-1 , &wi[0]-1 , FALSE ,
		       NULL , iwork , dwork );
 
          /* Print out ev's */
          for(i=0; i<n_varb; i++) {
            fprintf (stdout, "%.*f + %.*fi\n", format, wr[i], format,wi[i]);
            }

	  /* Free memory allocated by dvector and ivector */
          free_ivector(iwork,0,WORK_SIZE);
          free_dvector(fd_step,0,n_varb);
          free_dvector(dwork,0,WORK_SIZE);
          free_dvector(wr,0,n_varb);
          free_dvector(wi,0,n_varb);
          free_dmatrix(jac2,0,n_varb+1,0,n_varb+1);
 
          /* Free memory from manifold */
          free_ivector(manifold->periodic_varb,0,n_varb);
          free_dvector(manifold->period_start,0,n_varb);
          free_dvector(manifold->period_end,0,n_varb);
          free(manifold);
 
	}

3) Recompile your personal version of DsTool with the command "make all" and 
   see if it works!


VIII. Adding your own Tcl/Tk code to DsTool
-------------------------------------------

You may want to add your own Tcl/Tk code to DsTool for many reasons, ranging 
from simply wanting to change the default color scheme to wanting to create 
your own windows to control computations.   


VIII.A. Changing default colors and fonts
-----------------------------------------

The simplest kind of customization is changing default colors or fonts.  Since
the Tcl/Tk procedure my_app_init (in the file $MY_DSTOOL/tcl/my_app_init.tcl)
is called *after* app_init_tk and app_init_tcl, changes to default values of 
global variables which are initialized on start-up can be made by adding the 
appropriate lines to my_app_init.   In the case of colors or fonts, a command
like:

     set COLOR(views) white

will change the default background color for twoD and oneD view windows to 
white.  Note that changes to default colors and fonts must be made *before* 
the line "window(open) cmd", so that the Command window is built with the new
defaults.  Fonts should be changed to font names in standard notation, and 
colors can be changed to either standard color names or hexadecimal notation.
The complete color and font lists (with defaults in parentheses) are:

Colors:
-------
COLOR(bg) 	-- widget background color (#acf)
COLOR(abg) 	-- active background color (#57f)
COLOR(hbg)	-- not currently used
COLOR(views)	-- background color for view windows (black)
COLOR(entry)	-- entry widget background color (white)
COLOR(info)	-- info (messages/entries) color (blue)

Fonts:
------
FONT(button)	-- button font (-Adobe-Helvetica-Medium-R-Normal--*-120-*)
FONT(label)	-- label font (-Adobe-Helvetica-Medium-R-Normal--*-120-*)
FONT(biglabel)	-- big label font (-Adobe-Helvetica-Medium-R-Normal--*-140-*)
FONT(boldlabel)	-- bold label font (-Adobe-Helvetica-Bold-R-Normal--*-120-*)


VIII.B. Changing external program calls
---------------------------------------

While DsTool is mostly self-contained, it is designed to use external programs
for some tasks.  Specifically, DsTool calls external programs for viewing
images, postscript files, and html documentation, and for creating GIF and 
TIFF files (actually, converting to those formats from X11 bitmaps).  The 
global Tcl/Tk array EXT contains the calls for all of the external programs 
that DsTool will use.  It contains the following entries (defaults in 
brackets):

EXT(imgview)	-- image (GIF, TIFF, PPM, X11 Bitmap) viewer [xv]
EXT(psview)	-- postscript viewer [gs]
EXT(convertgif)	-- image conversion tool, PPM -> GIF [convert]
EXT(converttiff)-- image conversion tool, PPM -> TIFF [convert]
EXT(browser)	-- web browser [netscape]

and the actual default calls are (from app_init.tk):

     set EXT(browser) {exec netscape $Html(Url) &}
     set EXT(convertgif) {exec convert "ppm:$Snap(Directory)/snaptempgif" \
          "tiff:$Snap(Directory)/$Snap(Filename)"}
     set EXT(converttiff) {exec convert "ppm:$Snap(Directory)/snaptemptiff" \
          "tiff:$Snap(Directory)/$Snap(Filename)"}
     set EXT(imgview) {exec xv $fpath &}
     set EXT(psview) {exec gs $fpath &}

To change an external program, you need to change the complete call.  A 
convenient place to do this is the procedure my_app_init (in the file 
$MY_DSTOOL/tcl/my_app_init.tcl).  The new calls can be placed anywhere in 
that procedure, since the Command window does not use any external programs.  
For example, the lines

     set EXT(psview) {exec imagetool $fpath &}
     set EXT(convertgif) {exec ppmtogif "$Snap(Directory)/snaptempgif" > \
          "$Snap(Directory)/$Snap(Filename)"}

would change the external postscript viewer to imagetool, and the conversion
(PPM->GIF) utility to ppmtogif.

The syntax for these calls is important!  The call needs to be enclosed in 
curly braces.  This keeps it from being evaluated until it is needed.  
Eventually, it will be called using the "eval" command.  The "exec" command 
tells Tcl/Tk to execute the command which follows.  The remainder of the line 
should be the proper syntax for the external program, with dollar signs in 
front of names of files which are to be accessed (e.g. fname for postscript 
and image files, and Html(Url) for URLs). The quotes around the filenames are 
important, as they force Tcl/Tk to evaluate the contained variables.  Without 
them, ppmtogif would be looking for the file $Save(Directory)/snaptempgif, and
would not be able to find it.  The trailing ampersand is important so that
DsTool doesn't lose control to the external program.  Note that the syntax for
the above calls had to be modified to conform to the appropriate calling 
syntax for the new programs.   


VIII.C. Changing default values of other global variables
---------------------------------------------------------

If you want to change another global variable, you should:

1) be very careful that you know what you're doing and how it will affect
   the program.  For example, you may want to change the Postmaster entry 
   Defaults.Precision, which controls the number of digits which are 
   displayed in the Tk windows, among other things.  This is *not* advisable.
   Due to the frequent interaction between Tcl/Tk and the Postmaster (via the 
   tcl_to_pm and pm_to_tcl commands), you will be introducing (possibly large)
   roundoff errors into the Postmaster.  Depending upon your application, 
   these errors may not be significant, but you should be aware of them.

2) be sure to declare it a global variable via the "global" statement, or if 
   it is part of an array, declare the array as a global variable (as with 
   COLOR, FONT, etc).  If you fail to do this, Tcl/Tk will introduce a local 
   variable with the same name, and the global variable will not be changed.  

3) be aware that my_app_init is called only once.  The importance of this is 
   that if you wish to change default values for variables which are 
   initialized when windows are opened, you may not be able to change them.  
   You should check the appropriate Tcl/Tk script to see how the variable is 
   initialized.  If it is initialized from the Postmaster, you can change the
   default in the Postmaster by issuing the proper Postmaster commands in 
   my_app_init.  For example, to have the auto-scaling factor default to 1.0,
   put the command "pm PUT Defaults.Plot_Scale_Factor 1.0" in my_app_init.  
   When the Defaults window is opened, the auto-scaling factor will be 1.0.  
   However, if the variable is initialized in a different way, you may not be
   able to change it easily.


VIII.D. Creating Tcl/Tk windows in DsTool
-----------------------------------------

The code for all of the user interface windows is located in the $DSTOOL/tcl 
directory.  Several utility routines are in utils.tk and utils.tcl.  These
routines are used to create windows and widgets.  It is recommended that you 
use these routines in order to preserve continuity of the interface features.

For more information on Tcl/Tk and the use and design of widgets, a good 
on-line reference is available at:

	http://www.sco.com/Technology/tcl/Tcl.html

There are two basic steps involved in creating a window:

1) Write the user interface code in Tcl/Tk.  Create a file, say my_panel.tk.
   This file must contain a procedure called my_panel(build) that contains the
   code for building the user interface components of the window.  Each window
   should have a dismiss button to close it.  In addition, if Postmaster 
   entries are involved, you should write procedures my_panel(enter), 
   my_panel(leave), and my_panel(update), which update the Tcl/Tk variables 
   to their Postmaster counterparts, and vice versa.  

2) Create a menu entry for the window.  The command "cmd(add_to_panels) 
   'Example' 'window(open) my_panel'" adds an entry to the panel list which 
   has label "Example" and calls "window(open) my_panel" when selected.  This 
   line can either be added to my_app_init or called from mymodel(install), as
   described in sections VII.B and VII.C.  The command "window(open) my_panel"
   calls my_panel(build) to build the window.


An example: Selected Point window:

The Selected Point window code is in $DSTOOL/tcl/selected.tk, and contains six
procedures:

    selected(build)      -- builds the window.  
    selected(update)     -- updates the Postmaster and Tcl/Tk variables 
                            when the user presses the Return key.
    selected(enter)      -- updates the Postmaster and Tcl/Tk variables 
                            when the user enters the window.
    selected(leave)      -- updates the Postmaster and Tcl/Tk variables 
    			    when the user leaves the window.
    selected(copy)       -- copies the final column to the initial column.
    selected(save_point) -- saves the initial column point in the Postmaster's
			    memory.

For illustrative purposes, we now give a detailed description of some of the 
procedures which are used in the Selected Point window. The first two are 
utility routines; the next three are postmaster communication routines, and 
the final five are for building the objects in the window. 

     array_to_list Model Varb_Names

Converts an array object into a list object.  The list returned contains the 
entries Model(Varb_Names,<i>) where <i> runs over all valid entries.

     message_show "Initial point saved."
 
Displays the message "Initial point saved." in the command window.

 
     tcl_to_pm Selected

Updates the Tcl/Tk variables in the global array Selected from their 
corresponding Postmaster entries.
 
     pm EXEC Selected.Copy

Executes the Postmaster command Selected.Copy, which copies the point in the 
final point memory (of the Postmaster's Selected Point object) into the 
initial point memory.
 
     pm_to_tcl Selected Memory

Updates the entries in the Postmaster objects Selected and Memory from their 
corresponding Tcl/Tk global variables. 
 

     build_Title $name "Selected point"

Builds the title of the window on the top frame border.  The name of the 
parent widget is $name, and "Selected point" is the string used for the title.

     build_DismissButtonbar $name dbbar "window(dismiss) selected" \
          {"Copy final to initial" selected(copy) } \
          {"Save point" selected(save_point)}

Builds a dismiss button bar at the bottom of the window.  The button bar has 
a dismiss button, which calls "window(dismiss) selected" when pressed.  In 
addition, the button bar contains a button labelled "Copy final to initial", 
which calls selected(copy) when pressed, and a button labelled "Save point",
which calls selected(save_point) when pressed.  The name of the parent window
is $name, and $name.dbbar will be the name of the button bar.

     build_CmdFrame $name cmd

Builds a command frame to contain other widgets.  The name of the parent frame
is $name, and $name.cmd will be the name of the command frame.

     build_LabelEntryColumnsScroll $cmd le0 250 \
             [list label " " [ concat \
                                         [array_to_list Model Varb_Names] \
                                         [array_to_list Model Param_Names] ] \
                 ] \
             [list dentry "Initial" [ concat \
                                         [array_to_list Selected Varb_Ic] \
                                         [array_to_list Selected Param_Ic] ] \
                  ] \
             [list dlabel "Final" [ concat \
                                         [array_to_list Selected Varb_Fc] \
                                         [array_to_list Selected Param_Fc] ] \
                  ]

Builds a scrollable widget consisting of three columns.  The first column has
an empty header label, and then a list of the variables and parameters from 
the current system.  The second column is labelled "Initial", and consists of
the Tcl/Tk variables Selected(Varb_Ic,<i>) and Selected(Param_Ic,<i>).  The 
last column is labelled "Final", and consists of the Tcl/Tk variables 
Selected(Varb_Fc,<i>) and Selected(Param_Ic,<i>).  The name of the parent 
widget is $cmd, and $cmd.le0 will be the name of the new widget.  The number 
250 specifies the height of the widget.
	
     bind_LabelEntryColumns $cmd.le0 1 <Return> selected(update) 

Binds the execution of a command to a key press in a column of the 
LabelEntryColumns widget $cmd.le0.  In this case, the column is 1 (the 
"initial" column), the key is Return, and the command which is executed is 
the Tcl/Tk procedure selected(update).