treeview.tcl 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #
  2. # ttk::treeview widget bindings and utilities.
  3. #
  4. namespace eval ttk::treeview {
  5. variable State
  6. # Enter/Leave/Motion
  7. #
  8. set State(activeWidget) {}
  9. set State(activeHeading) {}
  10. # Press/drag/release:
  11. #
  12. set State(pressMode) none
  13. set State(pressX) 0
  14. # For pressMode == "resize"
  15. set State(resizeColumn) #0
  16. # For pressmode == "heading"
  17. set State(heading) {}
  18. }
  19. ### Widget bindings.
  20. #
  21. bind Treeview <Motion> { ttk::treeview::Motion %W %x %y }
  22. bind Treeview <B1-Leave> { #nothing }
  23. bind Treeview <Leave> { ttk::treeview::ActivateHeading {} {}}
  24. bind Treeview <ButtonPress-1> { ttk::treeview::Press %W %x %y }
  25. bind Treeview <Double-ButtonPress-1> { ttk::treeview::DoubleClick %W %x %y }
  26. bind Treeview <ButtonRelease-1> { ttk::treeview::Release %W %x %y }
  27. bind Treeview <B1-Motion> { ttk::treeview::Drag %W %x %y }
  28. bind Treeview <KeyPress-Up> { ttk::treeview::Keynav %W up }
  29. bind Treeview <KeyPress-Down> { ttk::treeview::Keynav %W down }
  30. bind Treeview <KeyPress-Right> { ttk::treeview::Keynav %W right }
  31. bind Treeview <KeyPress-Left> { ttk::treeview::Keynav %W left }
  32. bind Treeview <KeyPress-Prior> { %W yview scroll -1 pages }
  33. bind Treeview <KeyPress-Next> { %W yview scroll 1 pages }
  34. bind Treeview <KeyPress-Return> { ttk::treeview::ToggleFocus %W }
  35. bind Treeview <KeyPress-space> { ttk::treeview::ToggleFocus %W }
  36. bind Treeview <Shift-ButtonPress-1> \
  37. { ttk::treeview::Select %W %x %y extend }
  38. bind Treeview <<ToggleSelection>> \
  39. { ttk::treeview::Select %W %x %y toggle }
  40. ttk::copyBindings TtkScrollable Treeview
  41. ### Binding procedures.
  42. #
  43. ## Keynav -- Keyboard navigation
  44. #
  45. # @@@ TODO: verify/rewrite up and down code.
  46. #
  47. proc ttk::treeview::Keynav {w dir} {
  48. set focus [$w focus]
  49. if {$focus eq ""} { return }
  50. switch -- $dir {
  51. up {
  52. if {[set up [$w prev $focus]] eq ""} {
  53. set focus [$w parent $focus]
  54. } else {
  55. while {[$w item $up -open] && [llength [$w children $up]]} {
  56. set up [lindex [$w children $up] end]
  57. }
  58. set focus $up
  59. }
  60. }
  61. down {
  62. if {[$w item $focus -open] && [llength [$w children $focus]]} {
  63. set focus [lindex [$w children $focus] 0]
  64. } else {
  65. set up $focus
  66. while {$up ne "" && [set down [$w next $up]] eq ""} {
  67. set up [$w parent $up]
  68. }
  69. set focus $down
  70. }
  71. }
  72. left {
  73. if {[$w item $focus -open] && [llength [$w children $focus]]} {
  74. CloseItem $w $focus
  75. } else {
  76. set focus [$w parent $focus]
  77. }
  78. }
  79. right {
  80. OpenItem $w $focus
  81. }
  82. }
  83. if {$focus != {}} {
  84. SelectOp $w $focus choose
  85. }
  86. }
  87. ## Motion -- pointer motion binding.
  88. # Sets cursor, active element ...
  89. #
  90. proc ttk::treeview::Motion {w x y} {
  91. set cursor {}
  92. set activeHeading {}
  93. switch -- [$w identify region $x $y] {
  94. separator { set cursor hresize }
  95. heading { set activeHeading [$w identify column $x $y] }
  96. }
  97. ttk::setCursor $w $cursor
  98. ActivateHeading $w $activeHeading
  99. }
  100. ## ActivateHeading -- track active heading element
  101. #
  102. proc ttk::treeview::ActivateHeading {w heading} {
  103. variable State
  104. if {$w != $State(activeWidget) || $heading != $State(activeHeading)} {
  105. if {$State(activeHeading) != {}} {
  106. $State(activeWidget) heading $State(activeHeading) state !active
  107. }
  108. if {$heading != {}} {
  109. $w heading $heading state active
  110. }
  111. set State(activeHeading) $heading
  112. set State(activeWidget) $w
  113. }
  114. }
  115. ## Select $w $x $y $selectop
  116. # Binding procedure for selection operations.
  117. # See "Selection modes", below.
  118. #
  119. proc ttk::treeview::Select {w x y op} {
  120. if {[set item [$w identify row $x $y]] ne "" } {
  121. SelectOp $w $item $op
  122. }
  123. }
  124. ## DoubleClick -- Double-ButtonPress-1 binding.
  125. #
  126. proc ttk::treeview::DoubleClick {w x y} {
  127. if {[set row [$w identify row $x $y]] ne ""} {
  128. Toggle $w $row
  129. } else {
  130. Press $w $x $y ;# perform single-click action
  131. }
  132. }
  133. ## Press -- ButtonPress binding.
  134. #
  135. proc ttk::treeview::Press {w x y} {
  136. focus $w
  137. switch -- [$w identify region $x $y] {
  138. nothing { }
  139. heading { heading.press $w $x $y }
  140. separator { resize.press $w $x $y }
  141. tree -
  142. cell {
  143. set item [$w identify item $x $y]
  144. SelectOp $w $item choose
  145. switch -glob -- [$w identify element $x $y] {
  146. *indicator -
  147. *disclosure { Toggle $w $item }
  148. }
  149. }
  150. }
  151. }
  152. ## Drag -- B1-Motion binding
  153. #
  154. proc ttk::treeview::Drag {w x y} {
  155. variable State
  156. switch $State(pressMode) {
  157. resize { resize.drag $w $x }
  158. heading { heading.drag $w $x $y }
  159. }
  160. }
  161. proc ttk::treeview::Release {w x y} {
  162. variable State
  163. switch $State(pressMode) {
  164. resize { resize.release $w $x }
  165. heading { heading.release $w }
  166. }
  167. set State(pressMode) none
  168. Motion $w $x $y
  169. }
  170. ### Interactive column resizing.
  171. #
  172. proc ttk::treeview::resize.press {w x y} {
  173. variable State
  174. set State(pressMode) "resize"
  175. set State(resizeColumn) [$w identify column $x $y]
  176. }
  177. proc ttk::treeview::resize.drag {w x} {
  178. variable State
  179. $w drag $State(resizeColumn) $x
  180. }
  181. proc ttk::treeview::resize.release {w x} {
  182. # no-op
  183. }
  184. ### Heading activation.
  185. #
  186. proc ttk::treeview::heading.press {w x y} {
  187. variable State
  188. set column [$w identify column $x $y]
  189. set State(pressMode) "heading"
  190. set State(heading) $column
  191. $w heading $column state pressed
  192. }
  193. proc ttk::treeview::heading.drag {w x y} {
  194. variable State
  195. if { [$w identify region $x $y] eq "heading"
  196. && [$w identify column $x $y] eq $State(heading)
  197. } {
  198. $w heading $State(heading) state pressed
  199. } else {
  200. $w heading $State(heading) state !pressed
  201. }
  202. }
  203. proc ttk::treeview::heading.release {w} {
  204. variable State
  205. if {[lsearch -exact [$w heading $State(heading) state] pressed] >= 0} {
  206. after 0 [$w heading $State(heading) -command]
  207. }
  208. $w heading $State(heading) state !pressed
  209. }
  210. ### Selection modes.
  211. #
  212. ## SelectOp $w $item [ choose | extend | toggle ] --
  213. # Dispatch to appropriate selection operation
  214. # depending on current value of -selectmode.
  215. #
  216. proc ttk::treeview::SelectOp {w item op} {
  217. select.$op.[$w cget -selectmode] $w $item
  218. }
  219. ## -selectmode none:
  220. #
  221. proc ttk::treeview::select.choose.none {w item} { $w focus $item }
  222. proc ttk::treeview::select.toggle.none {w item} { $w focus $item }
  223. proc ttk::treeview::select.extend.none {w item} { $w focus $item }
  224. ## -selectmode browse:
  225. #
  226. proc ttk::treeview::select.choose.browse {w item} { BrowseTo $w $item }
  227. proc ttk::treeview::select.toggle.browse {w item} { BrowseTo $w $item }
  228. proc ttk::treeview::select.extend.browse {w item} { BrowseTo $w $item }
  229. ## -selectmode multiple:
  230. #
  231. proc ttk::treeview::select.choose.extended {w item} {
  232. BrowseTo $w $item
  233. }
  234. proc ttk::treeview::select.toggle.extended {w item} {
  235. $w selection toggle [list $item]
  236. }
  237. proc ttk::treeview::select.extend.extended {w item} {
  238. if {[set anchor [$w focus]] ne ""} {
  239. $w selection set [between $w $anchor $item]
  240. } else {
  241. BrowseTo $w $item
  242. }
  243. }
  244. ### Tree structure utilities.
  245. #
  246. ## between $tv $item1 $item2 --
  247. # Returns a list of all items between $item1 and $item2,
  248. # in preorder traversal order. $item1 and $item2 may be
  249. # in either order.
  250. #
  251. # NOTES:
  252. # This routine is O(N) in the size of the tree.
  253. # There's probably a way to do this that's O(N) in the number
  254. # of items returned, but I'm not clever enough to figure it out.
  255. #
  256. proc ttk::treeview::between {tv item1 item2} {
  257. variable between [list]
  258. variable selectingBetween 0
  259. ScanBetween $tv $item1 $item2 {}
  260. return $between
  261. }
  262. ## ScanBetween --
  263. # Recursive worker routine for ttk::treeview::between
  264. #
  265. proc ttk::treeview::ScanBetween {tv item1 item2 item} {
  266. variable between
  267. variable selectingBetween
  268. if {$item eq $item1 || $item eq $item2} {
  269. lappend between $item
  270. set selectingBetween [expr {!$selectingBetween}]
  271. } elseif {$selectingBetween} {
  272. lappend between $item
  273. }
  274. foreach child [$tv children $item] {
  275. ScanBetween $tv $item1 $item2 $child
  276. }
  277. }
  278. ### User interaction utilities.
  279. #
  280. ## OpenItem, CloseItem -- Set the open state of an item, generate event
  281. #
  282. proc ttk::treeview::OpenItem {w item} {
  283. $w focus $item
  284. event generate $w <<TreeviewOpen>>
  285. $w item $item -open true
  286. }
  287. proc ttk::treeview::CloseItem {w item} {
  288. $w item $item -open false
  289. $w focus $item
  290. event generate $w <<TreeviewClose>>
  291. }
  292. ## Toggle -- toggle opened/closed state of item
  293. #
  294. proc ttk::treeview::Toggle {w item} {
  295. if {[$w item $item -open]} {
  296. CloseItem $w $item
  297. } else {
  298. OpenItem $w $item
  299. }
  300. }
  301. ## ToggleFocus -- toggle opened/closed state of focus item
  302. #
  303. proc ttk::treeview::ToggleFocus {w} {
  304. set item [$w focus]
  305. if {$item ne ""} {
  306. Toggle $w $item
  307. }
  308. }
  309. ## BrowseTo -- navigate to specified item; set focus and selection
  310. #
  311. proc ttk::treeview::BrowseTo {w item} {
  312. $w see $item
  313. $w focus $item
  314. $w selection set [list $item]
  315. }
  316. #*EOF*