File: script_file_tools

package info (click to toggle)
grass 6.0.2-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 40,044 kB
  • ctags: 31,303
  • sloc: ansic: 321,125; tcl: 25,676; sh: 11,176; cpp: 10,098; makefile: 5,025; fortran: 1,846; yacc: 493; lex: 462; perl: 133; sed: 1
file content (1040 lines) | stat: -rwxr-xr-x 34,245 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
#!nviz -f
# Please log changes in the ChangeLog file in this directory
# (Use "C-x 4 a" from emacs to add an entry)

global src_boot

catch {destroy .wait_ok}

source $src_boot/etc/nviz2.2/scripts/config.tcl

# Create a simple list of script tools which are invoked by pressing
# the specified buttons

# Globals
global ScriptState FieldsChanged
global source_files source_index
global state_file Nv_

# Source_files is a list of (map_name map_id) tuples
# Source index represents the index of the source_file chosen
# Field_Data is a list containing a tuple of the form
#   (window map_type map_att map_source) for each field

set ScriptState 0
set FieldsChanged 0
set source_files [list]
set source_index 0
set Field_Data [list]
set state_file ""
set Nv_(APP) "."

# Make the top-level window "width" resizable only
wm resizable . true false

# Titlebar
label .title -text "Map Object File Sequencing" -relief raised
pack .title -side top -fill x -expand yes
frame .controls 

# Create buttons for adding fields
frame .controls.fields -relief groove -bd 2
set rname .controls.fields
label $rname.title -text "Fields:"
button $rname.add -text "Add" -command "add_field"
button $rname.delete -text "Delete" -command "delete_field"
button $rname.state -text "State File: None" -command "change_state_file"
pack $rname.title $rname.add $rname.delete $rname.state \
    -fill x -expand no -padx 2 -pady 2 

# Create buttons for cancelling or accepting
frame .controls.options -relief groove -bd 2
set rname .controls.options
label $rname.title -text "Options:"
button $rname.cancel -text "Done" -command "done_script"
button $rname.accept -text "Add To Script" -command "build_script"
button $rname.build -text "Build Script..." -command "build_standalone_script"
button $rname.load -text "Load Fields..." -command "load_fields"
button $rname.save -text "Save Fields..." -command "save_fields"

pack $rname.title $rname.cancel $rname.accept \
    $rname.build $rname.load $rname.save\
    -fill x -expand no -padx 2 -pady 2 
pack .controls.fields .controls.options -side left \
    -fill x -expand yes -padx 1 -pady 1 -anchor n

# Create area to display fields
frame .fields -relief groove -bd 2
canvas .fields.display_area -width 10c -height 6c \
    -xscrollcommand ".fields.scrollx set" -confine true \
    -xscrollincrement 1

# This frame created to display frame numbers next to the list of 
# files in fields
frame .fields.display_area.frames -relief groove -bd 2 -width 2c -height 6c
label .fields.display_area.frames.l1 -text "Frame"
label .fields.display_area.frames.l2 -text "     "
listbox .fields.display_area.frames.frame_list \
    -yscrollcommand ".fields.scrolly set" -height 9
place .fields.display_area.frames.l1 -relx 0.5 -rely 0.0 -anchor n
place .fields.display_area.frames.l2 \
    -in .fields.display_area.frames.l1 -relx 0.5 -rely 1.0 -anchor n
place .fields.display_area.frames.frame_list \
    -in .fields.display_area.frames.l2 -relx 0.5 -rely 2.0 \
    -relwidth 2.0 -anchor n

frame .fields.display_area.hold
.fields.display_area configure -scrollregion [list 0 0 28c 28c]
.fields.display_area create window 0 0 -anchor nw \
    -window .fields.display_area.frames -tags frames
set bound [.fields.display_area bbox frames]
.fields.display_area create window [lindex $bound 2] 0 -anchor nw \
    -window .fields.display_area.hold

scrollbar .fields.scrolly -orient vertical -command "canvas_scroll_height"
scrollbar .fields.scrollx -orient horizontal -command ".fields.display_area xview"
pack .fields.display_area -fill both
pack .fields.scrolly -side left -fill y -padx 2 -pady 2 -before .fields.display_area
pack .fields.scrollx -side bottom -fill x -padx 2 -pady 2

# pack everything
pack .controls .fields -fill x -expand yes

###################################################
# Load fields data from a file...
###################################################
proc load_fields {} {
    global Field_Data FieldsChanged state_file

    # First make sure we're not overwriting something...
    if {$FieldsChanged} then {
	if {[tk_dialog .verify "Verify" "Current fields have not been saved, really load new fields?" \
		 @/usr/local/lib/tk/bitmaps/warning \
		 1 "Ok" "Cance'"] == 1} then {
	    # Cancel the exit
	    return
	}
    }

    # Have user select a file
    set new_file [create_file_browser .fields_file 1 0]
    if {$new_file == -1} then return

    # Read in each of the file fields one at a time, and create
    # Field_Data as appropriate
    if {[catch {set file_hook [open $new_file r]} error_code] != 0} then {
	display_error "While opening file: $error_code"
	return
    }

    # Delete the old set of fields
    set Field_Data [list]

    # Read in state file
    if {[catch {gets $file_hook state_file} error_code] != 0} then {
	display_error "While reading state_file: $error_code"
	return
    }
    set_new_state_file $state_file

    # Get number of fields
    if {[catch {gets $file_hook num_fields} error_code] != 0} then {
	display_error "While reading number of fields: $error_code"
	return
    }

    # For each field create a field segment which automatically
    # updates Field_Data
    for {set i 0} {$i < $num_fields} {incr i} {
	# Input field type
	if {[catch {gets $file_hook field_type} error_code] != 0} then {
	    display_error "While reading field type: $error_code"
	    return
	}

	# Input field attribute
	if {[catch {gets $file_hook field_att} error_code] != 0} then {
	    display_error "While reading field attribute: $error_code"
	    return
	}

	# Input field source
	if {[catch {gets $file_hook field_source} error_code] != 0} then {
	    display_error "While reading field source: $error_code"
	    return
	}

	# Input number of map files in file sequence
	if {[catch {gets $file_hook num_map_files} error_code] != 0} then {
	    display_error "While reading map sequence: $error_code"
	    return
	}

	# Output each of the map files in the sequence
	set map_files [list]
	for {set j 0} {$j < $num_map_files} {incr j} {
	    if {[catch {gets $file_hook this_map} error_code] != 0} then {
		display_error "While reading map sequence: $error_code"
		return
	    }
	    lappend map_files $this_map
	}

	# Finally create the new segment
	add_field_segment $field_type $field_source "$map_files" $field_att
    }

    # If load successful then unset FieldsChanged and exit
    close $file_hook
    set FieldsChanged 0
}

###################################################
# Save the fields data into a file...
###################################################
proc save_fields {} {
    global FieldsChanged Field_Data state_file
    
    # Check to see if there are any fields to save
    if {[llength $Field_Data] == 0} then return

    # Have user select a file
    set new_file [create_file_browser .fields_file 1 0]
    if {$new_file == -1} then return

    # For each field, save the following info:
    # 1. Type: Surface, Vect or Site
    # 2. Attribute: Topography, Color, Mask, Transparency, Shininess,
    #     Emission (only valid if type=surface)
    # 3. Source map: name of source file + logical name of map object
    # 4. Number of elements in map sequence
    # 4. List of map sequence
    if {[catch {set file_hook [open $new_file w+]} error_code] != 0} then {
	display_error "While opening file: $error_code"
	return
    }

    # Write out state file first
    if {[catch {puts $file_hook "$state_file"} error_code] != 0} then {
	display_error "While writing state_file: $error_code"
	return
    }

    # Output number of fields
    if {[catch {puts $file_hook "[llength $Field_Data]"} error_code] != 0} then {
	display_error "While writing number of fields: $error_code"
	return
    }

    foreach i $Field_Data {
	# Output field type
	if {[catch {puts $file_hook "[lindex $i 1]"} error_code] != 0} then {
	    display_error "While writing field type: $error_code"
	    return
	}

	# Output field attribute
	if {[catch {puts $file_hook "[lindex $i 2]"} error_code] != 0} then {
	    display_error "While writing field attribute: $error_code"
	    return
	}

	# Output field source
	if {[catch {puts $file_hook "[lindex $i 3]"} error_code] != 0} then {
	    display_error "While writing field source: $error_code"
	    return
	}

	# Output number of map files in file sequence
	if {[catch {puts $file_hook "[[lindex $i 0].files size]"} error_code] != 0} then {
	    display_error "While writing map sequence: $error_code"
	    return
	}

	# Output each of the map files in the sequence
	for {set j 0} {$j < [[lindex $i 0].files size]} {incr j} {
	    if {[catch {puts $file_hook "[[lindex $i 0].files get $j]"} error_code] != 0} then {
		display_error "While writing map sequence: $error_code"
		return
	    }
	}
    }
    
    # If save successful then unset FieldsChanged and exit
    close $file_hook
    set FieldsChanged 0
}

###################################################
# Routine to display error 
###################################################
proc display_error { err_string } {
    tk_dialog .file_error "File Error" "$err_string" \
	error 0 "Dismiss"
}

###################################################
# First checks that the fields have been saved, then exits
###################################################
proc done_script {} {
    global FieldsChanged

    if {$FieldsChanged} then {
	if {[tk_dialog .verify "Verify" "Fields have not been saved, really exit?" \
		 @/usr/local/lib/tk/bitmaps/warning \
		 1 "Ok" "Cancel"] == 1} then {
	    # Cancel the exit
	    return
	}
    }

    # Otherwise just exit
    exit
}

###################################################
# Given the current list of fields, build a script
# for displaying all the given segments
###################################################
proc build_script {} {
    global Field_Data state_file
    global ProcessName

    # Tasks
    #   1. Determine the number of frames we need.  By definition, fields
    #      which specify no entry for a frame (i.e. file list smaller than
    #      total number of frames) are not changed for that frame.
    #   2. Output preliminary code for outer loop, generate uniques ids
    #      for each file in the file list which will hold the map_id handle
    #   3. Loop over fields, for each field do the following:
    #      a. Output code to find the map id for the source of
    #         this field.
    #      b. Based on the loop index, output code to set the appropriate
    #         attribute for this map based on the list of fields.
    #   4. Output loop termination code and comments

    # 1.
    set num_frames [.fields.display_area.frames.frame_list size]
    send $ProcessName "Nv_script_add_string \"\\n\# Start of file sequence code\""

    # Output command to load the state file if present
    if {"$state_file" != ""} then {
	send $ProcessName "Nv_script_add_string \"SendScriptLineWait \\\"load_state_aux $state_file\\\" script_play\""
    }

    # 2.
    set loop_id [unique_id iloop]
    set field_list [list]
    foreach field $Field_Data {
	set new_id [unique_id mhandle]
	set temp $field
	lappend temp "$new_id"
	lappend field_list "$temp"
	set field_source [lindex $field 3]
	set field_type [lindex $field 1]
	send $ProcessName "Nv_script_add_string \"set $new_id \\\[ReturnMapHandle $field_source\\\]\""
    }

    send $ProcessName "Nv_script_add_string \"for \{set $loop_id 0\} \{\\\$$loop_id < $num_frames\} \{incr $loop_id\} \{\""
    send $ProcessName "Nv_script_add_string \" SendScriptLine \\\"global NVIZ_BLANK_MAPS\\\"\""
    send $ProcessName "Nv_script_add_string \" SendScriptLine \\\"set NVIZ_BLANK_MAPS \{\}\\\"\""

    # 3.
    foreach field $field_list {
	# Extract map handle for this field
	set map_handle [lindex $field [expr [llength $field] - 1]]

	# Get list of files
	set file_list [list]
	for {set i 0} {$i < [[lindex $field 0].files size]} {incr i} {
	    lappend file_list "[[lindex $field 0].files get $i]"
	}

	# Create list of indices wich correspond to blank files
	set blanks [list]
	set j 0
	foreach i $file_list {
	    if [regexp -- "\-\- blank \-\-" "$i"] then {
		if {[regexp "\(NO CHANGE\)" "$i"] == 0} then {
		    lappend blanks $j
		}
	    }
	    incr j
	}

	# Create list of indices which correspond to NO CHANGE
	set no_changes [list]
	set j 0
	foreach i $file_list {
	    if [regexp "\(NO CHANGE\)" "$i"] then {
		lappend no_changes $j
	    }
	    incr j
	}

	# Map attribute type to a value
	set att_type map
	switch [lindex $field 2] {
	    Topography     { set att_type topo }
	    Color          { set att_type color }
	    Mask           { set att_type mask }
	    Transparency   { set att_type transp }
	    Shininess      { set att_type shin }
	    Emission       { set att_type emi }
	}

	# Now output code to handle the current frame for this field
	send $ProcessName "Nv_script_add_string \" if \{\\\$$loop_id < [llength $file_list]\} then \{\""
	send $ProcessName "Nv_script_add_string \"  if \{\\\[lsearch \\\{$no_changes\\\} \\\$$loop_id\\\] == -1\} then \{\""
	send $ProcessName "Nv_script_add_string \"   if \{\\\[lsearch \\\{$blanks\\\} \\\$$loop_id\\\] > -1\}  then \{\""

	# Blanking a map object is a little tricky, heres the code to do it
	send $ProcessName "Nv_script_add_string \"    SendScriptLine \\\"lappend NVIZ_BLANK_MAPS \\\[ExtractMapID \\\$$map_handle\\\]\\\"\""
	
 	# Finally close off with the rest of the code for this frame
 	send $ProcessName "Nv_script_add_string \"   \} else \{\""
 	send $ProcessName "Nv_script_add_string \"    SendScriptLine \\\"\\\$$map_handle set_att $att_type \\\[lindex \\\{$file_list\\\} \\\$$loop_id\\\]\\\"\""
 	send $ProcessName "Nv_script_add_string \"   \}\""
 	send $ProcessName "Nv_script_add_string \"  \}\""
 	send $ProcessName "Nv_script_add_string \" \}\""

    }
    # End foreach field ...

    # 4.
    send $ProcessName "Nv_script_add_string \" \# Put image saving code here\""
    send $ProcessName "Nv_script_add_string \"\}\\n\""
}

###################################################
# Routine to edit a field
###################################################
proc edit_field { field_window field_type } {
    global FieldsChanged

    # Tasks
    #   1. Get the current list of entries 
    #   2. Call the filemapBrowser with the old list of entries
    #   3. On return, if not cancel then use the returned
    #      list of maps to reset the list for this field

    set old_list [list]
    for {set i 0} { $i < [$field_window.files size] } {incr i} {
	lappend old_list [$field_window.files get $i]
    }

    set map_sequence [create_filemap_browser .map_seq $field_type 1 "$old_list"]
    if {$map_sequence == -1} then {
	return 
    }

    $field_window.files delete 0 end
    foreach i $map_sequence {
	$field_window.files insert end "$i"
    }

    fix_frame_numbers

    # Note that we have changed...
    set FieldsChanged 1
}

###################################################
# Routine to delete a field
###################################################
proc delete_field {} {
    global deleted_field Field_Data FieldsChanged

    # Tasks:
    #   1. Change button highlights to reflect delete mode
    #      and change button bindings to cause a delete
    #   2. Popup dialog telling user to press the button of
    #      the field they wish to delete.
    #   3. Ask if they really want to delete field such-and-such
    #   4. On affirmitive delete the given field
    #   5. Restore the button bindings

    # Save the old bindings and define new ones
    set old_bindings [list]
    foreach i [pack slaves .fields.display_area.hold] {
	lappend old_bindings \
	    [list $i "[lindex [$i.header configure -command] 4]" \
		 "[lindex [$i.header configure -bg] 4]"]
 	$i.header configure -command "set deleted_field $i"
 	$i.header configure -bg burlywood
    }
    
    # Popup information dialog
    if {[tk_dialog .delete_info \
	     "Info" "Press the button of the field you wish to delete" \
	     {} 0 "Ok" "Cancel"] == 1} then {
	# Cancel the delete
 	cancel_delete "$old_bindings"
	return
    }

    set deleted_field -1
    tkwait variable deleted_field

    # Verify delete
    # Extract source and attribute info
    set source_name [lindex [$deleted_field.header configure -text] 4]
    set att_name [lindex [$deleted_field.header2 configure -text] 4]
    if {[tk_dialog .delete_verify \
	     "Verify" "Really delete <$source_name $att_name> ?" \
	     @/usr/local/lib/tk/bitmaps/warning \
	     1 "Ok" "Cancel"] == 1} then {
	# Cancel the delete
 	cancel_delete "$old_bindings"
	return
    }

    # Restore bindings
    cancel_delete "$old_bindings"

    # and proceed with the delete (also remove from Field_Data list)
    destroy $deleted_field
    set index -1
    set j 0
    foreach i $Field_Data {
	if {$deleted_field == [lindex $i 0]} then {
	    set index $j
 	}
 	incr j
    }
    set Field_Data [lreplace $Field_Data $index $index]

    # Note that we have changed...
    set FieldsChanged 1
}

###################################################
# Routine to restore button bindings which were created
# for a delete
###################################################
proc cancel_delete { prev_bindings } {
    foreach i $prev_bindings {
	set field [lindex $i 0]
	set cmd [lindex $i 1]
	set bg [lindex $i 2]
	$field.header configure -command "$cmd" -bg "$bg"
    }
}

###################################################
# Routine to add a new field
###################################################
proc add_field {} {
    global FieldsChanged

    # Two things are done here.  First the user fills in field type,
    # attribute, and source fields, this builds the skeleton for the
    # field.  Second, the user chooses a set of files in order to use
    # for this field.  The user may edit this list later if necessary.

    # Create frame for adding a new field to the field list
    # This popup has three entries: field type, attribute and existing surface
    toplevel .add_field
    
    # Field type frame
    set rname .add_field.field_type
    frame $rname
    label $rname.lbl -text "Field Type: " 
    menubutton $rname.mb -text "Surface" -menu $rname.mb.m -relief raised
    menu $rname.mb.m
    foreach i {Surface Vector Site} {
	$rname.mb.m add command -label "$i" -command "set_field_type $i"
    }
    pack $rname.lbl -side left -anchor w
    pack $rname.mb -side right -anchor e

    # Field attribute frame
    set rname .add_field.field_att
    frame $rname
    label $rname.lbl -text "Field Attribute: "
    menubutton $rname.mb -text "Topography" -menu $rname.mb.m -relief raised
    menu $rname.mb.m
    foreach i {Topography Color Mask Transparency Shininess Emission} {
	$rname.mb.m add command -label "$i" -command "set_field_att $i"
    }
    pack $rname.lbl -side left -anchor w
    pack $rname.mb -side right -anchor e

    # Field source frame
    set rname .add_field.source
    frame $rname
    label $rname.lbl -text "Use Nviz Map: "
    menubutton $rname.mb -text "None" -menu $rname.mb.m -relief raised
    menu $rname.mb.m 
    set_sources Surface
    pack $rname.lbl -side left -anchor w
    pack $rname.mb -side right -anchor e

    # Accept and Cancel buttons
    button .add_field.accept -text "Accept" -command "create_new_field"
    button .add_field.cancel -text "Cancel" -command "destroy .add_field"
    
    # Pack everything in
    pack .add_field.field_type .add_field.field_att .add_field.source \
	.add_field.accept .add_field.cancel -anchor w -expand yes -fill x

    # Grab focus to avoid user pressing other buttons
    grab .add_field
    tkwait window .add_field
    grab release .add_field

}

###################################################
# Routine to create a new field from the add_field option
###################################################
proc create_new_field {} {
    global source_files source_index FieldsChanged
    global ProcessName

    # Extract field type, attribute and set from information.
    # If set-from is none then popup a warning and exit
    if {[llength $source_files] == 0 } then {
	# Error, need to set from existing source file
	tk_dialog .no_source "No Source" \
	    "Error - \"Use Nviz Map\" can not be \"None\"" {} 0 "Ok"
	return
    }
    set map_from [lindex $source_files $source_index]
    set map_type [lindex [.add_field.field_type.mb configure -text] 4]
    set map_att  [lindex [.add_field.field_att.mb configure -text] 4]

    # Call the filemapBrowser to get a list of files
    # then create the new field entry
    switch $map_type {
	Surface { set filemap_type rast }
	Vector  { set filemap_type vect }
	Site    { set filemap_type site }
    }
    set map_sequence [create_filemap_browser .map_seq $filemap_type 1]

    # Check for cancel option from create_filemap_browser
    if {$map_sequence == -1} then {
	return
    }

    # Figure out logical name
    switch $map_type {
	Surface { set log_name [send $ProcessName "Nlogical_from_literal Nsurf[lindex $map_from 1]"] }
	Vector   { set log_name [send $ProcessName "Nlogical_from_literal Nvect[lindex $map_from 1]"] }
	Site        { set log_name [send $ProcessName "Nlogical_from_literal Nsite[lindex $map_from 1]"] } 
    }

    # Create the new field entry with the given maps
    add_field_segment $map_type \
	    "$log_name" "$map_sequence" $map_att

    # Last thing, delete the add_field window 
    destroy .add_field

    # Note that we have changed...
    set FieldsChanged 1
}

###################################################
# Routine to get list of available entries for the set-from field
###################################################
proc set_sources {type} {
    global source_files source_index ProcessName

    set source_list [list]
    set source_files [list]
    set source_index 0
    set rname .add_field.source

    switch $type {
	Surface { 
	    foreach i [send $ProcessName "Nget_map_list surf" ] {
		set map_name [lindex [send $ProcessName "Nsurf$i get_att topo"] 1]
		lappend source_list "$map_name"
		lappend source_files [list "$map_name" $i]
	    }
	}
	Vector  { 
	    foreach i [send $ProcessName "Nget_map_list vect" ] {
		set map_name [send $ProcessName "Nvect$i get_att map" ]
		lappend source_list "$map_name"
		lappend source_files [list "$map_name" $i]
	    }
	}
	Site    { 
	    foreach i [send $ProcessName "Nget_map_list site" ] {
		set map_name [send $ProcessName "Nsite$i get_att map" ]
		lappend source_list "$map_name"
		lappend source_files [list "$map_name" $i]
	    }
	}
    }

    $rname.mb.m delete 0 last
    if {[llength $source_list] == 0} then {
	$rname.mb.m add command -label "None" -command "set_source_file None 0"
	set_source_file "None" 0
    } else {
	set j 0
	foreach i $source_list {
	    $rname.mb.m add command -label "$i" -command "set_source_file \"$i\" $j"
	    incr j
	}
	set_source_file "[lindex $source_list 0]" 0
    }
}

###################################################
# Routine to update source field on menu event
###################################################
proc set_source_file {name index} {
    global source_index

    # Just set the menubutton to the appropriate field
    .add_field.source.mb configure -text "$name"
    set source_index $index
}

###################################################
# Routine to update appropriate fields in add_field display
###################################################
proc set_field_type {name} {
    # Two things: change text on menubutton, and change field 
    # attributes according to the type of field set
    .add_field.field_type.mb configure -text "$name"

    # Change attribute field based on type
    switch $name {
	Surface { set blist {Topography Color Mask Transparency Shininess Emission}}
	Vector  { set blist {File}}
	Site    { set blist {File}}
    }
    set_field_att [lindex $blist 0]
    .add_field.field_att.mb.m delete 0 last
    foreach i $blist {
	.add_field.field_att.mb.m add command -label "$i" -command "set_field_att $i"
    }

    # Reload new list of possible sources
    set_sources $name
}

###################################################
# Routine to update appropriate fields in add_field display
###################################################
proc set_field_att {name} {
    # Change text on menubutton
    .add_field.field_att.mb configure -text "$name"
}

###################################################
# Routine to create field segment from a field description
# Returns the window which holds this field
###################################################
proc add_field_segment {type file file_list {att Topography}} {
    global Field_Data

    # Create a frame to hold a button and list for this field
    set slave [unique_id .fields.display_area.hold.field_]
    set fd_tuple [list]
    lappend fd_type $slave

    frame $slave -relief groove -bd 2
    switch $type {
	Surface { 
	    set bname "Surface: $file"
	    set lname "Attribute: $att" 
	    set map_type rast
	    lappend fd_type Surface $att $file
	}
	Vector  { 
	    set bname "Vector: $file" 
	    set lname ""
	    set map_type vect
	    lappend fd_type Vector file $file
	}
	Site    { 
	    set bname "Site: $file" 
	    set lname ""
	    set map_type site
	    lappend fd_type Site file $file
	}
    }
    lappend Field_Data "$fd_type"
    button $slave.header -text "$bname" -command "edit_field $slave $map_type"
    label $slave.header2 -text "$lname"

    listbox $slave.files -yscrollcommand ".fields.scrolly set" -height 9
    foreach i $file_list {
	$slave.files insert end $i
    }

    pack $slave.header $slave.header2 $slave.files -fill x -expand yes

    # Pack the new field and readjust the scroll region
    pack $slave -side left -anchor n
    set cur_width [lindex [lindex [.fields.display_area configure -scrollregion] 4] 2]
    set cur_height [lindex [lindex [.fields.display_area configure -scrollregion] 4] 3]
    set cur_width [expr int([string trimright $cur_width c])]
    set cur_height [expr int([string trimright $cur_height c])]

    set slave_width [expr [llength [pack slaves .fields.display_area.hold]] * 5]
    if {$cur_width < $slave_width} then {
	set cur_width [expr $slave_width + 1]
    }

    append cur_width "c"
    append cur_height "c"
    .fields.display_area configure -scrollregion [list 0 0 $cur_width $cur_height]

    fix_frame_numbers
}

###################################################
# Routine to determine if we have enough frame numbers
# displayed for the current set of fields
###################################################
proc fix_frame_numbers {} {

    # Fix the frames field if necessary
    set num_frames [.fields.display_area.frames.frame_list size]
    set max 0
    foreach i [pack slaves .fields.display_area.hold] {
	if {[$i.files size] > $max} then {
	    set max [$i.files size]
	}
    }

    if {$num_frames != $max} then {
	.fields.display_area.frames.frame_list delete 0 end
	for {set i 1} {$i <= $max} {incr i} {
	    .fields.display_area.frames.frame_list insert end $i
	}
    }
}

###################################################
# Routine to handle canvas scrollbar.  This is a sort of
# odd scroll bar since it controls scrolling of internal listboxes
###################################################
proc canvas_scroll_height {args} {
    # get the list of all current canvas slaves, this in turn gives
    # us the set of listboxes we need to scroll
    foreach i [pack slaves .fields.display_area.hold] {
	# For each slaved listbox, call the yview command
	eval "$i.files yview" "$args"
    }

    # Don't forget to set the frame number listbox as well
    eval ".fields.display_area.frames.frame_list yview" "$args"
}

###################################################
# Change the name of the state file to load before
# generating the given sequence
###################################################
proc change_state_file {} {
    set new_file [create_file_browser .state_file 1 0]

    if {$new_file == -1} then return
    
    set_new_state_file $new_file
}

proc set_new_state_file { name } {
    global state_file
   
    set state_file "$name"
    if {"$name" == ""} then {
	set name None
    }

    .controls.fields.state configure -text "State File: $name"
}

###################################################
# Generate a unique id
###################################################
proc unique_id { base } {
    global _unique_id_num

    if {[catch {puts "$_unique_id_num"}] != 0} then {
	set _unique_id_num 0
    }

    incr _unique_id_num
    return $base$_unique_id_num
}

###################################################
# Given the current list of fields, build a script
# for displaying all the given segments
###################################################
proc build_standalone_script {} {
    global Field_Data state_file
    global Build_Image_Name

    # Get a file name for the new script
    set new_file [create_file_browser .script_file 1 0]
    if {$new_file == -1} then return

    # Get a name for frames
    set R .build_frame_name
    toplevel $R
    label $R.l -text "Enter an image root name" -relief raised
    entry $R.e -width 20 -relief sunken
    button $R.accept -text "accept" -command "set Build_Image_Name \[$R.e get\] ; destroy $R"
    button $R.cancel -text "cancel" -command "set Build_Image_Name -1 ; destroy $R"
    pack $R.l $R.e $R.accept $R.cancel -padx 1 -pady 1 -fill x -expand yes
    grab $R
    tkwait window $R
    grab release $R

    if {$Build_Image_Name == -1} then return

    # Open the file
    if {[catch {set file_hook [open $new_file w]} error_code] != 0} then {
	display_error "While opening script file: $error_code"
	return
    }
    
    # Output script file header
    puts $file_hook "\# This script created by the script_file_tools program"
    puts $file_hook "global Nv_mapLoopMode Nv_mapLoopFile"
    puts $file_hook "set Nv_mapLoopMode 0"
    puts $file_hook "set Nv_mapLoopFile \"\""
    puts $file_hook "SendScriptLine \"Nunset_cancel_func\"\n"

    # Define a function useful for padding values
    puts $file_hook "proc pad { x } {"
    puts $file_hook " while {\[string length \"\$x\"\] < 5} {"
    puts $file_hook "  set x \"0\$x\""
    puts $file_hook " }"
    puts $file_hook " return \$x"
    puts $file_hook "}\n"

    # Tasks
    #   1. Determine the number of frames we need.  By definition, fields
    #      which specify no entry for a frame (i.e. file list smaller than
    #      total number of frames) are not changed for that frame.
    #   2. Output preliminary code for outer loop, generate uniques ids
    #      for each file in the file list which will hold the map_id handle
    #   3. Loop over fields, for each field do the following:
    #      a. Output code to find the map id for the source of
    #         this field.
    #      b. Based on the loop index, output code to set the appropriate
    #         attribute for this map based on the list of fields.
    #   4. Output loop termination code and comments

    # 1.
    set num_frames [.fields.display_area.frames.frame_list size]
    puts $file_hook "\n\# Start of file sequence code"

    # Output command to load the state file if present
    if {"$state_file" != ""} then {
	puts $file_hook "SendScriptLineWait \"load_state_aux $state_file\" script_play"
    }

    # 2.
    set loop_id [unique_id iloop]
    set field_list [list]
    foreach field $Field_Data {
	set new_id [unique_id mhandle]
	set temp $field
	lappend temp "$new_id"
	lappend field_list "$temp"
	set field_source [lindex $field 3]
	set field_type [lindex $field 1]

	puts $file_hook "set $new_id \[ReturnMapHandle $field_source\]"
    }

    puts $file_hook "for {set $loop_id 0} {\$$loop_id < $num_frames} {incr $loop_id} {"
    puts $file_hook " SendScriptLine \"global NVIZ_BLANK_MAPS\""
    puts $file_hook " SendScriptLine \"set NVIZ_BLANK_MAPS {}\""

    # 3.
    foreach field $field_list {
	# Extract map handle for this field
	set map_handle [lindex $field [expr [llength $field] - 1]]

	# Get list of files
	set file_list [list]
	for {set i 0} {$i < [[lindex $field 0].files size]} {incr i} {
	    lappend file_list "[[lindex $field 0].files get $i]"
	}

	# Create list of indices wich correspond to blank files
	set blanks [list]
	set j 0
	foreach i $file_list {
	    if [regexp -- "\-\- blank \-\-" "$i"] then {
		if {[regexp "\(NO CHANGE\)" "$i"] == 0} then {
		    lappend blanks $j
		}
	    }
	    incr j
	}

	# Create list of indices which correspond to NO CHANGE
	set no_changes [list]
	set j 0
	foreach i $file_list {
	    if [regexp "\(NO CHANGE\)" "$i"] then {
		lappend no_changes $j
	    }
	    incr j
	}

	# Map attribute type to a value
	set att_type map
	switch [lindex $field 2] {
	    Topography     { set att_type topo }
	    Color          { set att_type color }
	    Mask           { set att_type mask }
	    Transparency   { set att_type transp }
	    Shininess      { set att_type shin }
	    Emission       { set att_type emi }
	}

	# Now output code to handle the current frame for this field
	puts $file_hook " if {\$$loop_id < [llength $file_list]} then {"
	puts $file_hook "  if {\[lsearch \{$no_changes\} \$$loop_id\] == -1} then {"
	puts $file_hook "   if {\[lsearch \{$blanks\} \$$loop_id\] > -1}  then {"

	# Blanking a map object is a little tricky, heres the code to do it
	puts $file_hook "    SendScriptLine \"lappend NVIZ_BLANK_MAPS \[ExtractMapID \$$map_handle\]\""
	
 	# Finally close off with the rest of the code for this frame
 	puts $file_hook "   } else {"
 	puts $file_hook "    SendScriptLine \"\$$map_handle set_att $att_type \[lindex \{$file_list\} \$$loop_id\]\""
 	puts $file_hook "   }"
 	puts $file_hook "  }"
 	puts $file_hook " }"

    }
    # End foreach field ...

    # 4.
    puts $file_hook " \# Image saving code here"
    puts $file_hook " if {\[catch {set Frame_Num}\]} then { set Frame_Num 0 }"
    puts $file_hook " SendScriptLine \"Nsurf_draw_all\""
    puts $file_hook " SendScriptLine \"Nvect_draw_all\""
    puts $file_hook " SendScriptLine \"Nsite_draw_all\""
    puts $file_hook " SendScriptLine \"Nwrite_rgb $Build_Image_Name\[pad \$Frame_Num\].rgb\""
    puts $file_hook " incr Frame_Num"
    puts $file_hook " after 1000"
    puts $file_hook "}\n"

    # Close file and quit
    close $file_hook
}