mainframe.tcl 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. # ------------------------------------------------------------------------------
  2. # mainframe.tcl
  3. # This file is part of Unifix BWidget Toolkit
  4. # $Id$
  5. # ------------------------------------------------------------------------------
  6. # Index of commands:
  7. # - MainFrame::create
  8. # - MainFrame::configure
  9. # - MainFrame::cget
  10. # - MainFrame::getframe
  11. # - MainFrame::addtoolbar
  12. # - MainFrame::gettoolbar
  13. # - MainFrame::addindicator
  14. # - MainFrame::getindicator
  15. # - MainFrame::getmenu
  16. # - MainFrame::showtoolbar
  17. # - MainFrame::showstatusbar
  18. # - MainFrame::_create_menubar
  19. # - MainFrame::_create_entries
  20. # - MainFrame::_parse_name
  21. # - MainFrame::_parse_accelerator
  22. # ------------------------------------------------------------------------------
  23. if [catch {package require msgcat}] {
  24. proc G_msg {message} {
  25. return $message
  26. }
  27. } else {
  28. ::msgcat::mcload $env(GISBASE)/etc/msgs
  29. proc G_msg {message} {
  30. return [::msgcat::mc $message]
  31. }
  32. }
  33. namespace eval MainFrame {
  34. ProgressBar::use
  35. Widget::bwinclude MainFrame ProgressBar .status.prg \
  36. remove {
  37. -fg -bg -bd -troughcolor -background -borderwidth
  38. -relief -orient -width -height
  39. } \
  40. rename {
  41. -maximum -progressmax
  42. -variable -progressvar
  43. -type -progresstype
  44. -foreground -progressfg
  45. }
  46. Widget::declare MainFrame {
  47. {-width TkResource 0 0 frame}
  48. {-height TkResource 0 0 frame}
  49. {-background TkResource "" 0 frame}
  50. {-textvariable String "" 0}
  51. {-menu String {} 1}
  52. {-separator Enum both 1 {none top bottom both}}
  53. {-bg Synonym -background}
  54. }
  55. Widget::addmap MainFrame "" .frame {-width {} -height {} -background {}}
  56. Widget::addmap MainFrame "" .topf {-background {}}
  57. Widget::addmap MainFrame "" .botf {-background {}}
  58. Widget::addmap MainFrame "" .status {-background {}}
  59. Widget::addmap MainFrame "" .status.label {-background {}}
  60. Widget::addmap MainFrame "" .status.indf {-background {}}
  61. Widget::addmap MainFrame "" .status.prgf {-background {}}
  62. Widget::addmap MainFrame ProgressBar .status.prg {-background {} -background -troughcolor}
  63. proc ::MainFrame { path args } { return [eval MainFrame::create $path $args] }
  64. proc use {} {}
  65. variable _widget
  66. }
  67. # ------------------------------------------------------------------------------
  68. # Command MainFrame::create
  69. # ------------------------------------------------------------------------------
  70. proc MainFrame::create { path args } {
  71. global tcl_platform
  72. variable _widget
  73. set path [frame $path -takefocus 0 -highlightthickness 0]
  74. set top [winfo parent $path]
  75. if { [string compare [winfo toplevel $path] $top] } {
  76. destroy $path
  77. return -code error "parent must be a toplevel"
  78. }
  79. Widget::init MainFrame $path $args
  80. set bg [Widget::getoption $path -background]
  81. if { $tcl_platform(platform) == "unix" } {
  82. set relief raised
  83. set bd 1
  84. } else {
  85. set relief flat
  86. set bd 0
  87. }
  88. $path configure -background $bg
  89. set topframe [frame $path.topf -relief flat -borderwidth 0 -background $bg]
  90. set userframe [eval frame $path.frame [Widget::subcget $path .frame] \
  91. -relief $relief -borderwidth $bd]
  92. set botframe [frame $path.botf -relief $relief -borderwidth $bd -background $bg]
  93. pack $topframe -fill x
  94. grid columnconfigure $topframe 0 -weight 1
  95. if { $tcl_platform(platform) != "unix" } {
  96. set sepopt [Widget::getoption $path -separator]
  97. if { $sepopt == "both" || $sepopt == "top" } {
  98. set sep [Separator::create $path.sep -orient horizontal -background $bg]
  99. pack $sep -fill x
  100. }
  101. if { $sepopt == "both" || $sepopt == "bottom" } {
  102. set sep [Separator::create $botframe.sep -orient horizontal -background $bg]
  103. pack $sep -fill x
  104. }
  105. }
  106. # --- status bar -------------------------------------------------------------------------
  107. set status [frame $path.status -relief flat -borderwidth 0 \
  108. -takefocus 0 -highlightthickness 0 -background $bg]
  109. set label [label $status.label -textvariable [Widget::getoption $path -textvariable] \
  110. -takefocus 0 -highlightthickness 0 -background $bg]
  111. set indframe [frame $status.indf -relief flat -borderwidth 0 \
  112. -takefocus 0 -highlightthickness 0 -background $bg]
  113. set prgframe [frame $status.prgf -relief flat -borderwidth 0 \
  114. -takefocus 0 -highlightthickness 0 -background $bg]
  115. place $label -anchor w -x 0 -rely 0.5
  116. place $indframe -anchor e -relx 1 -rely 0.5
  117. pack $prgframe -in $indframe -side left -padx 2
  118. $status configure -height [winfo reqheight $label]
  119. set progress [eval ProgressBar::create $status.prg [Widget::subcget $path .status.prg] \
  120. -width 50 \
  121. -height [expr {[winfo reqheight $label]-2}] \
  122. -borderwidth 1 \
  123. -relief sunken]
  124. pack $status -in $botframe -fill x -pady 2
  125. pack $botframe -side bottom -fill x
  126. pack $userframe -fill both -expand yes
  127. set _widget($path,top) $top
  128. set _widget($path,ntoolbar) 0
  129. set _widget($path,nindic) 0
  130. set menu [Widget::getoption $path -menu]
  131. if { [llength $menu] } {
  132. _create_menubar $path $menu
  133. }
  134. bind $path <Destroy> {MainFrame::_destroy %W}
  135. rename $path ::$path:cmd
  136. proc ::$path { cmd args } "return \[eval MainFrame::\$cmd $path \$args\]"
  137. return $path
  138. }
  139. # ------------------------------------------------------------------------------
  140. # Command MainFrame::configure
  141. # ------------------------------------------------------------------------------
  142. proc MainFrame::configure { path args } {
  143. variable _widget
  144. set res [Widget::configure $path $args]
  145. if { [Widget::hasChanged $path -textvariable newv] } {
  146. uplevel \#0 $path.status.label configure -textvariable [list $newv]
  147. }
  148. if { [Widget::hasChanged $path -background bg] } {
  149. set listmenu [$_widget($path,top) cget -menu]
  150. while { [llength $listmenu] } {
  151. set newlist {}
  152. foreach menu $listmenu {
  153. $menu configure -background $bg
  154. set newlist [concat $newlist [winfo children $menu]]
  155. }
  156. set listmenu $newlist
  157. }
  158. foreach sep {.sep .botf.sep} {
  159. if { [winfo exists $path.$sep] } {
  160. Separator::configure $path.$sep -background $bg
  161. }
  162. }
  163. foreach w [winfo children $path.topf] {
  164. $w configure -background $bg
  165. }
  166. }
  167. return $res
  168. }
  169. # ------------------------------------------------------------------------------
  170. # Command MainFrame::cget
  171. # ------------------------------------------------------------------------------
  172. proc MainFrame::cget { path option } {
  173. return [Widget::cget $path $option]
  174. }
  175. # ------------------------------------------------------------------------------
  176. # Command MainFrame::getframe
  177. # ------------------------------------------------------------------------------
  178. proc MainFrame::getframe { path } {
  179. return $path.frame
  180. }
  181. # ------------------------------------------------------------------------------
  182. # Command MainFrame::addtoolbar
  183. # ------------------------------------------------------------------------------
  184. proc MainFrame::addtoolbar { path } {
  185. global tcl_platform
  186. variable _widget
  187. set index $_widget($path,ntoolbar)
  188. set toolframe $path.topf.f$index
  189. set toolbar $path.topf.tb$index
  190. set bg [Widget::getoption $path -background]
  191. if { $tcl_platform(platform) == "unix" } {
  192. frame $toolframe -relief raised -borderwidth 1 \
  193. -takefocus 0 -highlightthickness 0 -background $bg
  194. } else {
  195. frame $toolframe -relief flat -borderwidth 0 -takefocus 0 \
  196. -highlightthickness 0 -background $bg
  197. set sep [Separator::create $toolframe.sep -orient horizontal -background $bg]
  198. pack $sep -fill x
  199. }
  200. set toolbar [frame $toolbar -relief flat -borderwidth 2 \
  201. -takefocus 0 -highlightthickness 0 -background $bg]
  202. pack $toolbar -in $toolframe -anchor w
  203. incr _widget($path,ntoolbar)
  204. grid $toolframe -column 0 -row $index -sticky ew
  205. return $toolbar
  206. }
  207. # ------------------------------------------------------------------------------
  208. # Command MainFrame::gettoolbar
  209. # ------------------------------------------------------------------------------
  210. proc MainFrame::gettoolbar { path index } {
  211. return $path.topf.tb$index
  212. }
  213. # ------------------------------------------------------------------------------
  214. # Command MainFrame::addindicator
  215. # ------------------------------------------------------------------------------
  216. proc MainFrame::addindicator { path args } {
  217. variable _widget
  218. set index $_widget($path,nindic)
  219. set indic $path.status.indf.f$index
  220. eval label $indic $args -relief sunken -borderwidth 1 \
  221. -takefocus 0 -highlightthickness 0
  222. pack $indic -side left -anchor w -padx 2
  223. incr _widget($path,nindic)
  224. return $indic
  225. }
  226. # ------------------------------------------------------------------------------
  227. # Command MainFrame::getindicator
  228. # ------------------------------------------------------------------------------
  229. proc MainFrame::getindicator { path index } {
  230. return $path.status.indf.f$index
  231. }
  232. # ------------------------------------------------------------------------------
  233. # Command MainFrame::getmenu
  234. # ------------------------------------------------------------------------------
  235. proc MainFrame::getmenu { path menuid } {
  236. variable _widget
  237. if { [info exists _widget($path,menuid,$menuid)] } {
  238. return $_widget($path,menuid,$menuid)
  239. }
  240. return ""
  241. }
  242. # ------------------------------------------------------------------------------
  243. # Command MainFrame::setmenustate
  244. # ------------------------------------------------------------------------------
  245. proc MainFrame::setmenustate { path tag state } {
  246. variable _widget
  247. if { [info exists _widget($path,tags,$tag)] } {
  248. foreach {menu entry} $_widget($path,tags,$tag) {
  249. $menu entryconfigure $entry -state $state
  250. }
  251. }
  252. }
  253. # ------------------------------------------------------------------------------
  254. # Command MainFrame::showtoolbar
  255. # ------------------------------------------------------------------------------
  256. proc MainFrame::showtoolbar { path index bool } {
  257. variable _widget
  258. set toolframe $path.topf.f$index
  259. if { [winfo exists $toolframe] } {
  260. if { !$bool && [llength [grid info $toolframe]] } {
  261. grid forget $toolframe
  262. $path.topf configure -height 1
  263. } elseif { $bool && ![llength [grid info $toolframe]] } {
  264. grid $toolframe -column 0 -row $index -sticky ew
  265. }
  266. }
  267. }
  268. # ------------------------------------------------------------------------------
  269. # Command MainFrame::showstatusbar
  270. # ------------------------------------------------------------------------------
  271. proc MainFrame::showstatusbar { path name } {
  272. set status $path.status
  273. if { ![string compare $name "none"] } {
  274. pack forget $status
  275. } else {
  276. pack $status -fill x
  277. switch -- $name {
  278. status {
  279. catch {pack forget $status.prg}
  280. }
  281. progression {
  282. pack $status.prg -in $status.prgf
  283. }
  284. }
  285. }
  286. }
  287. # ------------------------------------------------------------------------------
  288. # Command MainFrame::_destroy
  289. # ------------------------------------------------------------------------------
  290. proc MainFrame::_destroy { path } {
  291. variable _widget
  292. Widget::destroy $path
  293. catch {destroy [$_widget($path,top) cget -menu]}
  294. $_widget($path,top) configure -menu {}
  295. unset _widget($path,top)
  296. unset _widget($path,ntoolbar)
  297. unset _widget($path,nindic)
  298. rename $path {}
  299. }
  300. # ------------------------------------------------------------------------------
  301. # Command MainFrame::_create_menubar
  302. # ------------------------------------------------------------------------------
  303. proc MainFrame::_create_menubar { path descmenu } {
  304. variable _widget
  305. global tcl_platform
  306. set bg [Widget::getoption $path -background]
  307. set top $_widget($path,top)
  308. if { $tcl_platform(platform) == "unix" } {
  309. set menubar [menu $top.menubar -tearoff 0 -background $bg -borderwidth 1]
  310. } else {
  311. set menubar [menu $top.menubar -tearoff 0 -background $bg]
  312. }
  313. $top configure -menu $menubar
  314. set count 0
  315. foreach {name tags menuid tearoff entries} $descmenu {
  316. set opt [_parse_name [G_msg $name]]
  317. if { [string length $menuid] && ![info exists _widget($path,menuid,$menuid)] } {
  318. # menu has identifier
  319. # we use it for its pathname, to enable special menu entries
  320. # (help, system, ...)
  321. set menu $menubar.$menuid
  322. } else {
  323. set menu $menubar.menu$count
  324. }
  325. eval $menubar add cascad $opt -menu $menu
  326. menu $menu -tearoff $tearoff -background $bg
  327. foreach tag $tags {
  328. lappend _widget($path,tags,$tag) $menubar $count
  329. }
  330. if { [string length $menuid] } {
  331. # menu has identifier
  332. set _widget($path,menuid,$menuid) $menu
  333. }
  334. _create_entries $path $menu $bg $entries
  335. incr count
  336. }
  337. }
  338. # ------------------------------------------------------------------------------
  339. # Command MainFrame::_create_entries
  340. # ------------------------------------------------------------------------------
  341. proc MainFrame::_create_entries { path menu bg entries } {
  342. variable _widget
  343. set count [$menu cget -tearoff]
  344. set registered 0
  345. foreach entry $entries {
  346. set len [llength $entry]
  347. set type [lindex $entry 0]
  348. if { ![string compare $type "separator"] } {
  349. $menu add separator
  350. incr count
  351. continue
  352. }
  353. # entry name and tags
  354. set opt [_parse_name [G_msg [lindex $entry 1]]]
  355. set tags [lindex $entry 2]
  356. foreach tag $tags {
  357. lappend _widget($path,tags,$tag) $menu $count
  358. }
  359. if { ![string compare $type "cascad"] } {
  360. set menuid [lindex $entry 3]
  361. set tearoff [lindex $entry 4]
  362. set submenu $menu.menu$count
  363. eval $menu add cascad $opt -menu $submenu
  364. menu $submenu -tearoff $tearoff -background $bg
  365. if { [string length $menuid] } {
  366. # menu has identifier
  367. set _widget($path,menuid,$menuid) $submenu
  368. }
  369. _create_entries $path $submenu $bg [lindex $entry 5]
  370. incr count
  371. continue
  372. }
  373. # entry help description
  374. set desc [G_msg [lindex $entry 3]]
  375. if { [string length $desc] } {
  376. if { !$registered } {
  377. DynamicHelp::register $menu menu [Widget::getoption $path -textvariable]
  378. set registered 1
  379. }
  380. DynamicHelp::register $menu menuentry $count $desc
  381. }
  382. # entry accelerator
  383. set accel [_parse_accelerator [lindex $entry 4]]
  384. if { [llength $accel] } {
  385. lappend opt -accelerator [lindex $accel 0]
  386. bind $_widget($path,top) [lindex $accel 1] "$menu invoke $count"
  387. }
  388. # user options
  389. set useropt [lrange $entry 5 end]
  390. if { ![string compare $type "command"] ||
  391. ![string compare $type "radiobutton"] ||
  392. ![string compare $type "checkbutton"] } {
  393. eval $menu add $type $opt $useropt
  394. } else {
  395. return -code error "invalid menu type \"$type\""
  396. }
  397. incr count
  398. }
  399. }
  400. # ------------------------------------------------------------------------------
  401. # Command MainFrame::_parse_name
  402. # ------------------------------------------------------------------------------
  403. proc MainFrame::_parse_name { menuname } {
  404. set idx [string first "&" $menuname]
  405. if { $idx == -1 } {
  406. return [list -label $menuname]
  407. } else {
  408. set beg [string range $menuname 0 [expr $idx-1]]
  409. set end [string range $menuname [expr $idx+1] end]
  410. append beg $end
  411. return [list -label $beg -underline $idx]
  412. }
  413. }
  414. # ------------------------------------------------------------------------------
  415. # Command MainFrame::_parse_accelerator
  416. # ------------------------------------------------------------------------------
  417. proc MainFrame::_parse_accelerator { desc } {
  418. if { [llength $desc] == 2 } {
  419. set seq [lindex $desc 0]
  420. set key [lindex $desc 1]
  421. switch -- $seq {
  422. Ctrl {
  423. set accel "Ctrl+[string toupper $key]"
  424. set event "<Control-Key-[string tolower $key]>"
  425. }
  426. Alt {
  427. set accel "Atl+[string toupper $key]"
  428. set event "<Alt-Key-[string tolower $key]>"
  429. }
  430. CtrlAlt {
  431. set accel "Ctrl+Alt+[string toupper $key]"
  432. set event "<Control-Alt-Key-[string tolower $key]>"
  433. }
  434. default {
  435. return -code error "invalid accelerator code $seq"
  436. }
  437. }
  438. return [list $accel $event]
  439. }
  440. return {}
  441. }