gui.tcl 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. # Read README.GUI !
  2. lappend auto_path $env(GISBASE)/bwidget
  3. package require -exact BWidget 1.2.1
  4. source $env(GISBASE)/etc/gtcltk/gmsg.tcl
  5. source $env(GISBASE)/etc/gtcltk/options.tcl
  6. source $env(GISBASE)/etc/gtcltk/select.tcl
  7. source $env(GISBASE)/etc/gtcltk/gronsole.tcl
  8. if {[catch {set env(GISDBASE) [exec g.gisenv get=GISDBASE]} error]} {
  9. tk_messageBox -type ok -icon error -title [G_msg "Error"] -message [G_msg $error]
  10. return
  11. }
  12. if {[catch {set env(LOCATION_NAME) [exec g.gisenv get=LOCATION_NAME]} error]} {
  13. tk_messageBox -type ok -icon error -title [G_msg "Error"] -message [G_msg $error]
  14. return
  15. }
  16. if {[catch {set env(MAPSET) [exec g.gisenv get=MAPSET]} error]} {
  17. tk_messageBox -type ok -icon error -title [G_msg "Error"] -message [G_msg $error]
  18. return
  19. }
  20. set dlg 0
  21. set path {}
  22. set iconpath $env(GISBASE)/etc/gui/icons/
  23. ################################################################################
  24. # Miscellanious
  25. # Icons
  26. proc icon {class member} {
  27. global iconpath
  28. set name "::img::icon-$class-$member"
  29. if {! [catch {image type $name}]} {
  30. return $name
  31. }
  32. if {! [catch {image create photo $name -file "$iconpath/$class-$member.gif"}]} {
  33. return $name
  34. }
  35. if {$class == "module" && $member != ""} {
  36. set memberparts [split $member "."]
  37. # tcl/tk8.0: Can't use end-1
  38. set memberparts [lrange $memberparts 0 [expr [llength $memberparts] - 2]]
  39. set member [join $memberparts "."]
  40. return [icon $class $member]
  41. }
  42. if {$class == "element" && [string first "/" $member] != -1} {
  43. # Only use the part after the slash
  44. set memberparts [split $member "/"]
  45. set member [lindex $memberparts end]
  46. return [icon $class $member]
  47. }
  48. return 0
  49. }
  50. proc icon_configure {path class member} {
  51. if {[set icon [icon $class $member]] != 0} {
  52. $path configure -image $icon
  53. }
  54. }
  55. # Make text in a label wrap:
  56. proc wrap_text_in_label {path} {
  57. bind $path <Configure> "$path configure -wraplength \[expr {\[winfo width $path\] - 5}\]"
  58. }
  59. ################################################################################
  60. # Colors
  61. # This almost belongs in a seperate file, and possibly a seperate namespace
  62. # These are the colors from lib/gis/color_str.c
  63. array set grass_named_colors {
  64. black {0 0 0 255}
  65. red {255 0 0 255}
  66. green {0 255 0 255}
  67. blue {0 0 255 255}
  68. yellow {255 255 0 255}
  69. magenta {255 0 255 255}
  70. cyan {0 255 255 255}
  71. white {255 255 255 255}
  72. grey {128 128 128 255}
  73. gray {128 128 128 255}
  74. orange {255 128 0 255}
  75. aqua {100 128 255 255}
  76. indigo {0 128 255 255}
  77. violet {128 0 255 255}
  78. purple {128 0 255 255}
  79. brown {180 75 25 255}
  80. none {255 255 255 255}
  81. }
  82. # This procedure takes a string like yellow, none, or 124:36:98 and
  83. # returns a list of four values for red, green, blue, and alpha
  84. proc color_grass_to_rgba255 {string} {
  85. global grass_named_colors
  86. set string [string tolower $string]
  87. if {[info exists grass_named_colors($string)]} {
  88. set color $grass_named_colors($string)
  89. } else {
  90. set incolor [split $string :]
  91. # Make sure we have good values:
  92. set color {}
  93. for {set i 0} {$i < 4} {incr i} {
  94. set inpart [lindex $incolor $i]
  95. if {[catch {expr $inpart < 0}] || $inpart == ""} {
  96. # This is what will be alpha
  97. # So it defaults to 255
  98. lappend color 255
  99. } elseif {$inpart < 0} {
  100. lappend color 0
  101. } elseif {$inpart > 255} {
  102. lappend color 255
  103. } else {
  104. lappend color $inpart
  105. }
  106. }
  107. }
  108. return $color
  109. }
  110. proc color_rgba255_to_grass {list} {
  111. global grass_named_colors
  112. if {[lindex $list 3] == 0} {
  113. return "none"
  114. } else {
  115. # Convert numebrs back to names if possible
  116. foreach name [array names grass_named_colors] {
  117. if {$list == $grass_named_colors($name)} {
  118. return $name
  119. }
  120. }
  121. set rgb [lrange $list 0 2]
  122. return [join $rgb :]
  123. }
  124. }
  125. proc color_rgba255_to_tcltk {color} {
  126. eval format #%02X%02X%02X $color
  127. }
  128. proc color_tcltk_to_rgba255 {string} {
  129. scan $string "#%2x%2x%2x" red green blue
  130. return [list $red $green $blue 255]
  131. }
  132. proc color_grass_to_tcltk {string} {
  133. return [color_rgba255_to_tcltk [color_grass_to_rgba255 $string]]
  134. }
  135. proc color_tcltk_to_grass {string} {
  136. return [color_rgba255_to_grass [color_tcltk_to_rgba255 $string]]
  137. }
  138. ################################################################################
  139. proc mkcmd {dlg} {
  140. global opt
  141. set pgm_name $opt($dlg,pgm_name)
  142. set nopt $opt($dlg,nopt)
  143. set cmd [list $pgm_name]
  144. for {set i 1} {$i <= $nopt} {incr i} {
  145. switch -- $opt($dlg,$i,class) {
  146. multi {
  147. set nmulti $opt($dlg,$i,nmulti)
  148. set opts {}
  149. for {set j 1} {$j <= $nmulti} {incr j} {
  150. if {$opt($dlg,$i,val,$j) == 1} {
  151. lappend opts $opt($dlg,$i,valname,$j)
  152. }
  153. }
  154. if {$opts != {}} {
  155. lappend cmd "$opt($dlg,$i,name)=[join $opts ,]"
  156. }
  157. }
  158. opt {
  159. # Tempting, but buggy: && [string compare $opt($dlg,$i,val) $opt($dlg,$i,answer) ] != 0
  160. if {[string length $opt($dlg,$i,val)] > 0} {
  161. lappend cmd "$opt($dlg,$i,name)=$opt($dlg,$i,val)"
  162. }
  163. }
  164. flag {
  165. if {$opt($dlg,$i,val) == 1} {
  166. lappend cmd "-$opt($dlg,$i,name)"
  167. }
  168. }
  169. xflag {
  170. if {$opt($dlg,$i,val) == 1} {
  171. lappend cmd "--$opt($dlg,$i,name)"
  172. }
  173. }
  174. }
  175. }
  176. return $cmd
  177. }
  178. proc mkcmd_string {dlg} {
  179. set cmd [mkcmd $dlg]
  180. set cmd_string {}
  181. foreach word $cmd {
  182. if {[llength $word] > 1} {
  183. regsub -all -- {'} $word {'\''} newword
  184. append cmd_string {'} $newword {' }
  185. } {
  186. append cmd_string $word { }
  187. }
  188. }
  189. return $cmd_string
  190. }
  191. # Display the current command text in the label
  192. proc show_cmd {dlg} {
  193. global opt
  194. set opt($dlg,cmd_string) [mkcmd_string $dlg]
  195. }
  196. proc get_file {dlg optn new} {
  197. global opt
  198. if {$new == 1} {
  199. set filename [tk_getSaveFile -title [G_msg "Save File"]]
  200. } else {
  201. set filename [tk_getOpenFile -title [G_msg "Load File"]]
  202. }
  203. if {$filename != ""} {
  204. if {$opt($dlg,$optn,multi) && $opt($dlg,$optn,val) != ""} {
  205. append opt($dlg,$optn,val) "," $filename
  206. } {
  207. set opt($dlg,$optn,val) $filename
  208. }
  209. }
  210. show_cmd $dlg
  211. }
  212. proc get_map {dlg optn elem} {
  213. global opt
  214. global path
  215. if {$opt($dlg,$optn,multi)} {
  216. set val [GSelect_::create $elem multiple parent $opt($dlg,root) title $opt($dlg,pgm_name)]
  217. } else {
  218. set val [GSelect_::create $elem parent $opt($dlg,root) title $opt($dlg,pgm_name)]
  219. }
  220. if {$val != ""} {
  221. if {$opt($dlg,$optn,multi) && $opt($dlg,$optn,val) != ""} {
  222. foreach i [split $val ","] {
  223. if {[string first $i $opt($dlg,$optn,val)] > -1} { continue }
  224. append opt($dlg,$optn,val) "," $i
  225. }
  226. } {
  227. set opt($dlg,$optn,val) $val
  228. }
  229. }
  230. show_cmd $dlg
  231. }
  232. proc get_color {dlg optn type} {
  233. global opt
  234. if {(! $opt($dlg,$optn,multi)) && $opt($dlg,$optn,val) != ""} {
  235. # Convert from grass color type
  236. set init [color_grass_to_tcltk $opt($dlg,$optn,val)]
  237. } else {
  238. set init [format "#%06X" [expr {int(rand() * 0xFFFFFF)}]]
  239. }
  240. set val [tk_chooseColor -initialcolor $init]
  241. if {$val != ""} {
  242. # Convert it to the correct type
  243. set val [color_tcltk_to_grass $val]
  244. # Write it back to the answer
  245. if {$opt($dlg,$optn,multi) && $opt($dlg,$optn,val) != ""} {
  246. append opt($dlg,$optn,val) "," $val
  247. } {
  248. set opt($dlg,$optn,val) $val
  249. }
  250. }
  251. show_cmd $dlg
  252. }
  253. proc run_cmd {dlg} {
  254. global opt
  255. set gronsole $opt($dlg,gronsole)
  256. set title [G_msg "Output"]
  257. layout_raise_special_frame $dlg {Output} $title]
  258. set cmd [mkcmd $dlg]
  259. catch {$opt($dlg,run_button) configure -state disabled}
  260. $gronsole run $cmd {} "catch {$opt($dlg,run_button) configure -state active}"
  261. }
  262. proc help_cmd {dlg} {
  263. global opt env
  264. set pgm_name $opt($dlg,pgm_name)
  265. if {[catch {exec $env(GRASS_HTML_BROWSER) $env(GISBASE)/docs/html/$pgm_name.html &} error]} {
  266. tk_messageBox -type ok -icon error -title [G_msg "Error"] -message [G_msg $error]
  267. return
  268. }
  269. }
  270. proc clear_cmd {dlg} {
  271. global opt
  272. set gronsole $opt($dlg,gronsole)
  273. $gronsole clear
  274. }
  275. proc close_cmd {dlg} {
  276. global opt
  277. set root $opt($dlg,root)
  278. destroy $root
  279. }
  280. proc progress {dlg percent} {
  281. global opt
  282. set opt($dlg,percent) $percent
  283. # it seems that there is a bug in ProgressBar and it is not always updated ->
  284. $opt($dlg,progress) _modify
  285. }
  286. ################################################################################
  287. # Default layout rule:
  288. # Section based notebook layout
  289. # Make a frame for part of the layout tree
  290. proc layout_make_frame {dlg guisection optn glabel} {
  291. global opt
  292. global bgcolor
  293. if {$guisection == {}} {set guisection {{}}}
  294. if {[llength $guisection] == 1} {
  295. # A frame for a toplevel section
  296. # This uses a scrolled frame in a notebook tab
  297. # Ungrouped options go under Options
  298. if {$glabel == {}} {
  299. set glabel [G_msg "Options"]
  300. set guisection {Options}
  301. }
  302. set path $opt($dlg,path)
  303. set optpane [$path.nb insert end $guisection -text $glabel]
  304. # Specials don't get scrolling frames:
  305. if {$optn == -1} {
  306. $path.nb raise $guisection
  307. return $optpane
  308. }
  309. # And the frames and scrollers:
  310. set optwin [ScrolledWindow $optpane.optwin -relief sunken -borderwidth 1]
  311. set optfra [ScrollableFrame $optwin.fra -height 200 -constrainedwidth true]
  312. $optwin setwidget $optfra
  313. pack $optwin -fill both -expand yes
  314. # Bindings for scrolling the frame
  315. bind_scroll $optfra
  316. set suf [$optfra getframe]
  317. # Binding magic to make the whole program start at an appropriate size
  318. # bind $suf <Configure> {+[winfo parent %W] configure -width [winfo reqwidth %W]}
  319. $path.nb raise $guisection
  320. return $suf
  321. } else {
  322. # Make a frame for things in this guisection
  323. # We could add labels, but I fear it would just make a clutter
  324. # tcl/tk8.0: Can't use end-1
  325. set parent_section [lrange $guisection 0 [expr [llength $guisection]-2]]
  326. set parent_frame [layout_get_frame $dlg $parent_section $optn $glabel]
  327. set id [llength [winfo children $parent_frame]]
  328. set suf [frame $parent_frame.fra$id]
  329. pack $suf -side top -fill x
  330. return $suf
  331. }
  332. }
  333. # Get the frame for an option, or make it if it doesn't exist yet
  334. proc layout_get_frame {dlg guisection optn glabel} {
  335. global opt
  336. if {! [info exists opt($dlg,layout_frame,$guisection)] } {
  337. set frame [layout_make_frame $dlg $guisection $optn $glabel]
  338. set opt($dlg,layout_frame,$guisection) $frame
  339. }
  340. return $opt($dlg,layout_frame,$guisection)
  341. }
  342. proc layout_get_special_frame {dlg guisection key glabel} {
  343. return [layout_get_frame $dlg $guisection -1 $glabel]
  344. }
  345. proc layout_raise_frame {dlg guisection optn} {
  346. global opt
  347. set path $opt($dlg,path)
  348. if {$guisection == {}} {
  349. set guisection {{}}
  350. set guisection {Options}
  351. }
  352. $path.nb raise $guisection
  353. }
  354. proc layout_raise_special_frame {dlg guisection key} {
  355. layout_raise_frame $dlg $guisection -1
  356. }
  357. # Make the layout:
  358. proc make_layout {dlg path root} {
  359. # Make the tabs (notebook)
  360. set pw [NoteBook $path.nb -side top]
  361. pack $pw -fill both -expand yes
  362. }
  363. ################################################################################
  364. # Make widgets
  365. proc make_module_description {dlg path root} {
  366. global opt
  367. if {$opt($dlg,label) != {}} {
  368. set l1 $opt($dlg,label)
  369. set l2 $opt($dlg,desc)
  370. } else {
  371. set l1 $opt($dlg,desc)
  372. set l2 {}
  373. }
  374. frame $path.module
  375. set icon [icon module $opt($dlg,pgm_name)]
  376. if {$icon != 0} {
  377. button $path.module.icon -relief flat -image $icon -anchor n
  378. pack $path.module.icon -side left
  379. }
  380. frame $path.module.r
  381. set label1 [label $path.module.r.labdesc1 -text $l1 -anchor w -justify left -width 10]
  382. set label2 [label $path.module.r.labdesc2 -text $l2 -anchor w -justify left -width 10]
  383. wrap_text_in_label $label1
  384. wrap_text_in_label $label2
  385. pack $label1 $label2 -side top -fill x
  386. pack $path.module.r -side top -fill x
  387. pack $path.module -side top -fill x
  388. }
  389. proc make_command_label {dlg path root} {
  390. # Widget for displaying current command
  391. frame $path.cmd
  392. set cmdlabel [label $path.cmd.label -textvariable opt($dlg,cmd_string) -anchor w -justify left]
  393. wrap_text_in_label $cmdlabel
  394. button $path.cmd.copy -text [G_msg "Copy"] -anchor n -command "show_cmd $dlg\nclipboard clear -displayof $cmdlabel\nclipboard append -displayof $cmdlabel \$opt($dlg,cmd_string)"
  395. icon_configure $path.cmd.copy edit copy
  396. pack $path.cmd.copy -side left
  397. pack $cmdlabel -fill x -side top
  398. pack $path.cmd -expand no -fill x -side bottom
  399. # Bindings for updating command
  400. bind [winfo toplevel $root] <Button> "+show_cmd $dlg"
  401. bind [winfo toplevel $root] <Key> "+show_cmd $dlg"
  402. bind [winfo toplevel $root] <ButtonRelease> "+show_cmd $dlg"
  403. bind [winfo toplevel $root] <KeyRelease> "+show_cmd $dlg"
  404. }
  405. proc make_output {dlg path root} {
  406. global opt
  407. set title [G_msg "Output"]
  408. set outpane [layout_get_special_frame $dlg {Output} -1 $title]
  409. set gronsole [Gronsole $outpane.gronsole -height 5 -width 60 -bg white]
  410. pack $gronsole -expand yes -fill both
  411. set opt($dlg,gronsole) $gronsole
  412. }
  413. proc make_progress {dlg path root} {
  414. global opt
  415. # Progress bar
  416. set opt($dlg,percent) -1
  417. set progress [ProgressBar $path.progress -fg green -height 20 -relief raised -maximum 100 -variable opt($dlg,percent) ]
  418. pack $progress -expand no -fill x
  419. set opt($dlg,progress) $progress
  420. }
  421. proc make_buttons {dlg path root} {
  422. global opt env
  423. set pgm_name $opt($dlg,pgm_name)
  424. set buttonframe [frame $path.buttonframe]
  425. button $buttonframe.run -text [G_msg "Run"] -command "run_cmd $dlg" -width 5 -bd 1
  426. button $buttonframe.help -text [G_msg "Help"] -command "help_cmd $dlg" -width 5 -bd 1
  427. button $buttonframe.clear -text [G_msg "Clear"] -command "clear_cmd $dlg" -width 5 -bd 1
  428. button $buttonframe.close -text [G_msg "Close"] -command "close_cmd $dlg" -width 5 -bd 1
  429. set opt($dlg,run_button) $buttonframe.run
  430. # Turn off help button if the help file doesn't exist
  431. if {! [file exists $env(GISBASE)/docs/html/$pgm_name.html]} {
  432. $buttonframe.help configure -state disabled
  433. }
  434. pack $buttonframe.run $buttonframe.help $buttonframe.clear $buttonframe.close \
  435. -side left -expand yes -padx 5 -pady 5
  436. pack $buttonframe -expand no -fill x -side bottom
  437. }
  438. proc make_dialog {dlg path root} {
  439. make_module_description $dlg $path $root
  440. make_buttons $dlg $path $root
  441. make_command_label $dlg $path $root
  442. make_layout $dlg $path $root
  443. }
  444. proc make_dialog_end {dlg path root} {
  445. make_output $dlg $path $root
  446. # A progress bar is now wasted space as progress is displayed in gronsole
  447. # make_progress $dlg $path $root
  448. }
  449. proc do_button_file {dlg optn suf new} {
  450. global opt
  451. button $suf.val$optn.sel -text {>} -command [list get_file $dlg $optn $new]
  452. icon_configure $suf.val$optn.sel file open
  453. pack $suf.val$optn.sel -side left -fill x
  454. }
  455. proc do_button_old {dlg optn suf elem} {
  456. global opt
  457. button $suf.val$optn.sel -text {>} -command [list get_map $dlg $optn $elem]
  458. icon_configure $suf.val$optn.sel element $elem
  459. pack $suf.val$optn.sel -side left -fill x
  460. }
  461. proc do_button_color {dlg optn suf type} {
  462. global opt
  463. button $suf.val$optn.sel -text {>} -command [list get_color $dlg $optn $type]
  464. icon_configure $suf.val$optn.sel edit color
  465. pack $suf.val$optn.sel -side left -fill x
  466. }
  467. proc do_entry {dlg optn suf} {
  468. global opt
  469. Entry $suf.val$optn.val -textvariable opt($dlg,$optn,val)
  470. pack $suf.val$optn.val -side left -fill x -expand yes
  471. }
  472. proc do_label {dlg optn suf} {
  473. global opt
  474. set label $opt($dlg,$optn,label_text)
  475. set type $opt($dlg,$optn,type)
  476. set req $opt($dlg,$optn,required)
  477. set multi $opt($dlg,$optn,multi)
  478. set name $opt($dlg,$optn,name)
  479. set typestring [expr {$multi ? "$type\[,$type,...\]" : $type}]
  480. set typestring "$name=$typestring"
  481. set typestring [expr {$req ? "$typestring" : "\[$typestring\]"}]
  482. set reqtext [expr {$req ? [G_msg "required"] : [G_msg "optional"]}]
  483. set multitext [expr {$multi ? [G_msg "multiple"] : ""}]
  484. set typehelp "$name: $multitext $type, $reqtext"
  485. set frame [frame $suf.lab$optn]
  486. label $frame.label -text "$label:" -anchor w -justify left
  487. label $frame.req -text "($typehelp)" -anchor e -justify right
  488. DynamicHelp::register $frame.req balloon $typestring
  489. pack $frame.req -side right
  490. pack $frame.label -side left -fill x -expand yes
  491. pack $frame -side top -fill x
  492. DynamicHelp::register $frame balloon $opt($dlg,$optn,help_text)
  493. # Make the label text wrap
  494. wrap_text_in_label $frame.label
  495. }
  496. proc do_check {dlg optn suf i s} {
  497. global opt
  498. checkbutton $suf.val$optn.val$i -text $s -variable opt($dlg,$optn,val,$i) -onvalue 1 -offvalue 0
  499. pack $suf.val$optn.val$i -side left
  500. set opt($dlg,$optn,valname,$i) $s
  501. }
  502. proc do_combo {dlg optn suf vals} {
  503. global opt
  504. ComboBox $suf.val$optn.val -underline 0 -labelwidth 0 -width 25 -textvariable opt($dlg,$optn,val) -values $vals -helptext $opt($dlg,$optn,help_text)
  505. pack $suf.val$optn.val -side left
  506. }
  507. ################################################################################
  508. # Input clean-up and normalization
  509. # Make guisections match up with different spacing near delimiters:
  510. proc normalize_guisection {dlg optn} {
  511. global opt
  512. #TODO: Trim each part
  513. set trimmed {}
  514. foreach untrimmed [split $opt($dlg,$optn,guisection) ";"] {
  515. lappend trimmed [string trim $untrimmed]
  516. }
  517. set opt($dlg,$optn,guisection) $trimmed
  518. }
  519. # Pick the text to use for visible labels and balloon help.
  520. proc choose_help_text {dlg optn} {
  521. global opt
  522. # Set label text and help text
  523. # Use description for label if label is absent
  524. set opt($dlg,$optn,label_text) $opt($dlg,$optn,label)
  525. set opt($dlg,$optn,help_text) $opt($dlg,$optn,desc)
  526. if {$opt($dlg,$optn,label_text) == {}} {
  527. set opt($dlg,$optn,label_text) $opt($dlg,$optn,help_text)
  528. set opt($dlg,$optn,help_text) {}
  529. }
  530. }
  531. ################################################################################
  532. # Options interface
  533. proc dialog_set_command {dlg cmd} {
  534. global opt
  535. set pgm_name $opt($dlg,pgm_name)
  536. set nopt $opt($dlg,nopt)
  537. if {[lindex $cmd 0] != $pgm_name} {
  538. return -1
  539. }
  540. # "Parse" the command
  541. # Note that these commands shan't have quotes around them
  542. foreach argv [lrange $cmd 1 end] {
  543. if {[string length $argv] < 2} continue
  544. if {[string index $argv 0] == "-"} {
  545. foreach char [split [string range $argv 1 end] {}] {
  546. set args(-$char) 1
  547. }
  548. } else {
  549. set eq_idx [string first "=" $argv]
  550. set name [string range $argv 0 [expr $eq_idx - 1]]
  551. set value [string range $argv [expr $eq_idx + 1] end]
  552. set args($name) $value
  553. }
  554. }
  555. # Query the command for each part of every option
  556. for {set i 1} {$i <= $nopt} {incr i} {
  557. switch -- $opt($dlg,$i,class) {
  558. multi {
  559. set name $opt($dlg,$i,name)
  560. if {! [info exists args($name)] } continue
  561. set nmulti $opt($dlg,$i,nmulti)
  562. for {set j 1} {$j <= $nmulti} {incr j} {
  563. set opt($dlg,$i,valname,$j) [expr ([lsearch -exact $args($name) $opt($dlg,$i,valname,$j)] != -1) ? 1 : 0]
  564. }
  565. }
  566. opt {
  567. set name $opt($dlg,$i,name)
  568. if {! [info exists args($name)] } continue
  569. set opt($dlg,$i,val) $args($name)
  570. }
  571. xflag {
  572. set name --$opt($dlg,$i,name)
  573. set opt($dlg,$i,val) [expr [info exists args($name)] ? 1 : 0]
  574. }
  575. flag {
  576. set name -$opt($dlg,$i,name)
  577. set opt($dlg,$i,val) [expr [info exists args($name)] ? 1 : 0]
  578. }
  579. }
  580. }
  581. show_cmd $dlg
  582. update
  583. return 0
  584. }
  585. proc dialog_get_command {dlg} {
  586. return [mkcmd $dlg]
  587. }
  588. ################################################################################
  589. proc begin_dialog {pgm optlist} {
  590. global opt dlg path
  591. incr dlg
  592. array set opts $optlist
  593. foreach key {label desc} {
  594. set opt($dlg,$key) $opts($key)
  595. }
  596. # Replace all non-ascii chars, spaces, $ and braces in path with undescore
  597. set path [regsub -all {[][{}\$\s\u0100-\uffff]} $path "_"]
  598. set root [expr {$path == "" ? "." : $path}]
  599. set opt($dlg,path) $path
  600. set opt($dlg,root) $root
  601. set opt($dlg,pgm_name) $pgm
  602. if {[winfo toplevel $root] == $root} {
  603. wm title $root $pgm
  604. }
  605. make_dialog $dlg $path $root
  606. }
  607. proc end_dialog {n} {
  608. global opt dlg
  609. set opt($dlg,nopt) $n
  610. set path $opt($dlg,path)
  611. set root $opt($dlg,root)
  612. make_dialog_end $dlg $path $root
  613. if {$n > 0} {
  614. layout_raise_frame $dlg $opt($dlg,1,guisection) 1
  615. }
  616. update
  617. show_cmd $dlg
  618. }
  619. proc add_option {optn optlist} {
  620. global opt dlg
  621. array set opts $optlist
  622. set opts(class) [expr {$opts(multi) && $opts(options) != {} ? "multi" : "opt"}]
  623. foreach key {class name type multi desc required options answer prompt label guisection} {
  624. set opt($dlg,$optn,$key) $opts($key)
  625. if { $key == {guisection} } {
  626. set glabel $opts($key)
  627. set opt($dlg,$optn,$key) [regsub -all {[][{}\$\s\u0100-\uffff]} \
  628. [string trim $opt($dlg,$optn,$key)] "_"]
  629. }
  630. }
  631. set opt($dlg,optn_index,$opts(name)) $optn
  632. choose_help_text $dlg $optn
  633. normalize_guisection $dlg $optn
  634. set suf [layout_get_frame $dlg $opt($dlg,$optn,guisection) $optn $glabel]
  635. do_label $dlg $optn $suf
  636. frame $suf.val$optn
  637. if {$opts(options) != {}} {
  638. set vals [split $opts(options) ,]
  639. set answers [split $opts(answer) ,]
  640. set opt($dlg,$optn,nmulti) [llength $vals]
  641. if {$opts(multi)} {
  642. set i 1
  643. foreach x $vals {
  644. do_check $dlg $optn $suf $i $x
  645. if { [lsearch $answers $x] >= 0 } {
  646. set opt($dlg,$optn,val,$i) 1
  647. }
  648. incr i
  649. }
  650. } else {
  651. do_combo $dlg $optn $suf $vals
  652. set opt($dlg,$optn,val) $opts(answer)
  653. }
  654. } else {
  655. set prompt $opts(prompt)
  656. set prompt_list [split $prompt ,]
  657. if {$prompt != {}} {
  658. if {[string match old_file,* $prompt]} {
  659. do_button_file $dlg $optn $suf 0
  660. } elseif {[string match new_file,* $prompt]} {
  661. do_button_file $dlg $optn $suf 1
  662. } elseif {[string match old,* $prompt]} {
  663. do_button_old $dlg $optn $suf [lindex $prompt_list 1]
  664. } elseif {[string match color,* $prompt]} {
  665. do_button_color $dlg $optn $suf [lindex $prompt_list 1]
  666. }
  667. }
  668. do_entry $dlg $optn $suf
  669. if {$opts(answer) != {}} {
  670. set opt($dlg,$optn,val) $opts(answer)
  671. }
  672. }
  673. pack $suf.val$optn -side top -fill x
  674. DynamicHelp::register $suf.val$optn balloon $opt($dlg,$optn,help_text)
  675. }
  676. proc add_flag {optn optlist} {
  677. global opt dlg
  678. array set opts $optlist
  679. set opt($dlg,$optn,class) flag
  680. foreach key {name desc label guisection} {
  681. set opt($dlg,$optn,$key) $opts($key)
  682. if { $key == {guisection} } {
  683. set glabel $opts($key)
  684. set opt($dlg,$optn,$key) [regsub -all {[][{}\$\s\u0100-\uffff]} \
  685. [string trim $opt($dlg,$optn,$key)] "_"]
  686. }
  687. }
  688. set opt($dlg,$optn,val) $opts(answer)
  689. set opt($dlg,optn_index,-$opts(name)) $optn
  690. choose_help_text $dlg $optn
  691. normalize_guisection $dlg $optn
  692. set suf [layout_get_frame $dlg $opt($dlg,$optn,guisection) $optn $glabel]
  693. frame $suf.val$optn
  694. checkbutton $suf.val$optn.chk -text $opt($dlg,$optn,label_text) -variable opt($dlg,$optn,val) -onvalue 1 -offvalue 0 -anchor w
  695. pack $suf.val$optn.chk -side left
  696. pack $suf.val$optn -side top -fill x
  697. DynamicHelp::register $suf.val$optn balloon $opt($dlg,$optn,help_text)
  698. }
  699. proc add_xflag {optn optlist} {
  700. global opt dlg
  701. array set opts $optlist
  702. set opt($dlg,$optn,class) xflag
  703. foreach key {name desc label guisection} {
  704. set opt($dlg,$optn,$key) $opts($key)
  705. if { $key == {guisection} } {
  706. set glabel $opts($key)
  707. set opt($dlg,$optn,$key) [regsub -all {[][{}\$\s\u0100-\uffff]} \
  708. [string trim $opt($dlg,$optn,$key)] "_"]
  709. }
  710. }
  711. set opt($dlg,$optn,val) $opts(answer)
  712. set opt($dlg,optn_index,-$opts(name)) $optn
  713. choose_help_text $dlg $optn
  714. normalize_guisection $dlg $optn
  715. set suf [layout_get_frame $dlg $opt($dlg,$optn,guisection) $optn $glabel]
  716. frame $suf.val$optn
  717. checkbutton $suf.val$optn.chk -text $opt($dlg,$optn,label_text) -variable opt($dlg,$optn,val) -onvalue 1 -offvalue 0 -anchor w
  718. pack $suf.val$optn.chk -side left
  719. pack $suf.val$optn -side top -fill x
  720. DynamicHelp::register $suf.val$optn balloon $opt($dlg,$optn,help_text)
  721. }
  722. ################################################################################