PageRenderTime 69ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/tcl/interface/tk/packages/BWidget/tree.tcl

http://chattcl.googlecode.com/
TCL | 2000 lines | 1450 code | 239 blank | 311 comment | 317 complexity | 3435cd54c360dc1eda64abe518982591 MD5 | raw file
Possible License(s): Unlicense, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. # ----------------------------------------------------------------------------
  2. # tree.tcl
  3. # This file is part of Unifix BWidget Toolkit
  4. # $Id: tree.tcl,v 1.1 2006/10/29 14:40:41 sabosbru Exp $
  5. # ----------------------------------------------------------------------------
  6. # Index of commands:
  7. # - Tree::create
  8. # - Tree::configure
  9. # - Tree::cget
  10. # - Tree::insert
  11. # - Tree::itemconfigure
  12. # - Tree::itemcget
  13. # - Tree::bindArea
  14. # - Tree::bindText
  15. # - Tree::bindImage
  16. # - Tree::delete
  17. # - Tree::move
  18. # - Tree::reorder
  19. # - Tree::selection
  20. # - Tree::exists
  21. # - Tree::parent
  22. # - Tree::index
  23. # - Tree::nodes
  24. # - Tree::see
  25. # - Tree::opentree
  26. # - Tree::closetree
  27. # - Tree::edit
  28. # - Tree::xview
  29. # - Tree::yview
  30. # - Tree::_update_edit_size
  31. # - Tree::_destroy
  32. # - Tree::_see
  33. # - Tree::_recexpand
  34. # - Tree::_subdelete
  35. # - Tree::_update_scrollregion
  36. # - Tree::_cross_event
  37. # - Tree::_draw_node
  38. # - Tree::_draw_subnodes
  39. # - Tree::_update_nodes
  40. # - Tree::_draw_tree
  41. # - Tree::_redraw_tree
  42. # - Tree::_redraw_selection
  43. # - Tree::_redraw_idle
  44. # - Tree::_drag_cmd
  45. # - Tree::_drop_cmd
  46. # - Tree::_over_cmd
  47. # - Tree::_auto_scroll
  48. # - Tree::_scroll
  49. # ----------------------------------------------------------------------------
  50. namespace eval Tree {
  51. Widget::define Tree tree DragSite DropSite DynamicHelp
  52. namespace eval Node {
  53. Widget::declare Tree::Node {
  54. {-text String "" 0}
  55. {-font TkResource "" 0 listbox}
  56. {-image TkResource "" 0 label}
  57. {-window String "" 0}
  58. {-fill TkResource black 0 {listbox -foreground}}
  59. {-data String "" 0}
  60. {-open Boolean 0 0}
  61. {-selectable Boolean 1 0}
  62. {-drawcross Enum auto 0 {auto always never allways}}
  63. {-padx Int -1 0 "%d >= -1"}
  64. {-deltax Int -1 0 "%d >= -1"}
  65. {-anchor String "w" 0 ""}
  66. }
  67. }
  68. DynamicHelp::include Tree::Node balloon
  69. Widget::tkinclude Tree canvas .c \
  70. remove {
  71. -insertwidth -insertbackground -insertborderwidth -insertofftime
  72. -insertontime -selectborderwidth -closeenough -confine -scrollregion
  73. -xscrollincrement -yscrollincrement -width -height
  74. } \
  75. initialize {
  76. -relief sunken -borderwidth 2 -takefocus 1
  77. -highlightthickness 1 -width 200
  78. }
  79. Widget::declare Tree {
  80. {-deltax Int 10 0 "%d >= 0"}
  81. {-deltay Int 15 0 "%d >= 0"}
  82. {-padx Int 20 0 "%d >= 0"}
  83. {-background TkResource "" 0 listbox}
  84. {-selectbackground TkResource "" 0 listbox}
  85. {-selectforeground TkResource "" 0 listbox}
  86. {-selectcommand String "" 0}
  87. {-width TkResource "" 0 listbox}
  88. {-height TkResource "" 0 listbox}
  89. {-selectfill Boolean 0 0}
  90. {-showlines Boolean 1 0}
  91. {-linesfill TkResource black 0 {listbox -foreground}}
  92. {-linestipple TkResource "" 0 {label -bitmap}}
  93. {-crossfill TkResource black 0 {listbox -foreground}}
  94. {-redraw Boolean 1 0}
  95. {-opencmd String "" 0}
  96. {-closecmd String "" 0}
  97. {-dropovermode Flag "wpn" 0 "wpn"}
  98. {-bg Synonym -background}
  99. {-crossopenimage String "" 0}
  100. {-crosscloseimage String "" 0}
  101. {-crossopenbitmap String "" 0}
  102. {-crossclosebitmap String "" 0}
  103. }
  104. DragSite::include Tree "TREE_NODE" 1
  105. DropSite::include Tree {
  106. TREE_NODE {copy {} move {}}
  107. }
  108. Widget::addmap Tree "" .c {-deltay -yscrollincrement}
  109. # Trees on windows have a white (system window) background
  110. if { $::tcl_platform(platform) == "windows" } {
  111. option add *Tree.c.background SystemWindow widgetDefault
  112. option add *TreeNode.fill SystemWindowText widgetDefault
  113. }
  114. bind Tree <FocusIn> [list after idle {BWidget::refocus %W %W.c}]
  115. bind Tree <Destroy> [list Tree::_destroy %W]
  116. bind Tree <Configure> [list Tree::_update_scrollregion %W]
  117. bind TreeSentinalStart <Button-1> {
  118. if { $::Tree::sentinal(%W) } {
  119. set ::Tree::sentinal(%W) 0
  120. break
  121. }
  122. }
  123. bind TreeSentinalEnd <Button-1> {
  124. set ::Tree::sentinal(%W) 0
  125. }
  126. bind TreeFocus <Button-1> [list focus %W]
  127. variable _edit
  128. }
  129. # ----------------------------------------------------------------------------
  130. # Command Tree::create
  131. # ----------------------------------------------------------------------------
  132. proc Tree::create { path args } {
  133. variable $path
  134. upvar 0 $path data
  135. Widget::init Tree $path $args
  136. set ::Tree::sentinal($path.c) 0
  137. if {[Widget::cget $path -crossopenbitmap] == ""} {
  138. set file [file join $::BWIDGET::LIBRARY images "minus.xbm"]
  139. Widget::configure $path [list -crossopenbitmap @$file]
  140. }
  141. if {[Widget::cget $path -crossclosebitmap] == ""} {
  142. set file [file join $::BWIDGET::LIBRARY images "plus.xbm"]
  143. Widget::configure $path [list -crossclosebitmap @$file]
  144. }
  145. set data(root) {{}}
  146. set data(selnodes) {}
  147. set data(upd,level) 0
  148. set data(upd,nodes) {}
  149. set data(upd,afterid) ""
  150. set data(dnd,scroll) ""
  151. set data(dnd,afterid) ""
  152. set data(dnd,selnodes) {}
  153. set data(dnd,node) ""
  154. frame $path -class Tree -bd 0 -highlightthickness 0 -relief flat \
  155. -takefocus 0
  156. # For 8.4+ we don't want to inherit the padding
  157. catch {$path configure -padx 0 -pady 0}
  158. eval [list canvas $path.c] [Widget::subcget $path .c] -xscrollincrement 8
  159. bindtags $path.c [list TreeSentinalStart TreeFocus $path.c Canvas \
  160. [winfo toplevel $path] all TreeSentinalEnd]
  161. pack $path.c -expand yes -fill both
  162. $path.c bind cross <ButtonPress-1> [list Tree::_cross_event $path]
  163. # Added by ericm@scriptics.com
  164. # These allow keyboard traversal of the tree
  165. bind $path.c <KeyPress-Up> [list Tree::_keynav up $path]
  166. bind $path.c <KeyPress-Down> [list Tree::_keynav down $path]
  167. bind $path.c <KeyPress-Right> [list Tree::_keynav right $path]
  168. bind $path.c <KeyPress-Left> [list Tree::_keynav left $path]
  169. bind $path.c <KeyPress-space> [list +Tree::_keynav space $path]
  170. # These allow keyboard control of the scrolling
  171. bind $path.c <Control-KeyPress-Up> [list $path.c yview scroll -1 units]
  172. bind $path.c <Control-KeyPress-Down> [list $path.c yview scroll 1 units]
  173. bind $path.c <Control-KeyPress-Left> [list $path.c xview scroll -1 units]
  174. bind $path.c <Control-KeyPress-Right> [list $path.c xview scroll 1 units]
  175. # ericm@scriptics.com
  176. BWidget::bindMouseWheel $path.c
  177. DragSite::setdrag $path $path.c Tree::_init_drag_cmd \
  178. [Widget::cget $path -dragendcmd] 1
  179. DropSite::setdrop $path $path.c Tree::_over_cmd Tree::_drop_cmd 1
  180. Widget::create Tree $path
  181. set w [Widget::cget $path -width]
  182. set h [Widget::cget $path -height]
  183. set dy [Widget::cget $path -deltay]
  184. $path.c configure -width [expr {$w*8}] -height [expr {$h*$dy}]
  185. # ericm
  186. # Bind <Button-1> to select the clicked node -- no reason not to, right?
  187. ## Bind button 1 to select the node via the _mouse_select command.
  188. ## This command will generate the proper <<TreeSelect>> virtual event
  189. ## when necessary.
  190. set selectcmd Tree::_mouse_select
  191. Tree::bindText $path <Button-1> [list $selectcmd $path set]
  192. Tree::bindImage $path <Button-1> [list $selectcmd $path set]
  193. Tree::bindText $path <Control-Button-1> [list $selectcmd $path toggle]
  194. Tree::bindImage $path <Control-Button-1> [list $selectcmd $path toggle]
  195. # Add sentinal bindings for double-clicking on items, to handle the
  196. # gnarly Tk bug wherein:
  197. # ButtonClick
  198. # ButtonClick
  199. # On a canvas item translates into button click on the item, button click
  200. # on the canvas, double-button on the item, single button click on the
  201. # canvas (which can happen if the double-button on the item causes some
  202. # other event to be handled in between when the button clicks are examined
  203. # for the canvas)
  204. $path.c bind TreeItemSentinal <Double-Button-1> \
  205. [list set ::Tree::sentinal($path.c) 1]
  206. # ericm
  207. return $path
  208. }
  209. # ----------------------------------------------------------------------------
  210. # Command Tree::configure
  211. # ----------------------------------------------------------------------------
  212. proc Tree::configure { path args } {
  213. variable $path
  214. upvar 0 $path data
  215. set res [Widget::configure $path $args]
  216. set ch1 [expr {[Widget::hasChanged $path -deltax val] |
  217. [Widget::hasChanged $path -deltay dy] |
  218. [Widget::hasChanged $path -padx val] |
  219. [Widget::hasChanged $path -showlines val]}]
  220. set ch2 [expr {[Widget::hasChanged $path -selectbackground val] |
  221. [Widget::hasChanged $path -selectforeground val]}]
  222. if { [Widget::hasChanged $path -linesfill fill] |
  223. [Widget::hasChanged $path -linestipple stipple] } {
  224. $path.c itemconfigure line -fill $fill -stipple $stipple
  225. }
  226. if { [Widget::hasChanged $path -crossfill fill] } {
  227. $path.c itemconfigure cross -foreground $fill
  228. }
  229. if {[Widget::hasChanged $path -selectfill fill]} {
  230. # Make sure that the full-width boxes have either all or none
  231. # of the standard node bindings
  232. if {$fill} {
  233. foreach event [$path.c bind "node"] {
  234. $path.c bind "box" $event [$path.c bind "node" $event]
  235. }
  236. } else {
  237. foreach event [$path.c bind "node"] {
  238. $path.c bind "box" $event {}
  239. }
  240. }
  241. }
  242. if { $ch1 } {
  243. _redraw_idle $path 3
  244. } elseif { $ch2 } {
  245. _redraw_idle $path 1
  246. }
  247. if { [Widget::hasChanged $path -height h] } {
  248. $path.c configure -height [expr {$h*$dy}]
  249. }
  250. if { [Widget::hasChanged $path -width w] } {
  251. $path.c configure -width [expr {$w*8}]
  252. }
  253. if { [Widget::hasChanged $path -redraw bool] && $bool } {
  254. set upd $data(upd,level)
  255. set data(upd,level) 0
  256. _redraw_idle $path $upd
  257. }
  258. set force [Widget::hasChanged $path -dragendcmd dragend]
  259. DragSite::setdrag $path $path.c Tree::_init_drag_cmd $dragend $force
  260. DropSite::setdrop $path $path.c Tree::_over_cmd Tree::_drop_cmd
  261. return $res
  262. }
  263. # ----------------------------------------------------------------------------
  264. # Command Tree::cget
  265. # ----------------------------------------------------------------------------
  266. proc Tree::cget { path option } {
  267. return [Widget::cget $path $option]
  268. }
  269. # ----------------------------------------------------------------------------
  270. # Command Tree::insert
  271. # ----------------------------------------------------------------------------
  272. proc Tree::insert { path index parent node args } {
  273. variable $path
  274. upvar 0 $path data
  275. set node [_node_name $path $node]
  276. set node [Widget::nextIndex $path $node]
  277. if { [info exists data($node)] } {
  278. return -code error "node \"$node\" already exists"
  279. }
  280. if { ![info exists data($parent)] } {
  281. return -code error "node \"$parent\" does not exist"
  282. }
  283. Widget::init Tree::Node $path.$node $args
  284. if {[string equal $index "end"]} {
  285. lappend data($parent) $node
  286. } else {
  287. incr index
  288. set data($parent) [linsert $data($parent) $index $node]
  289. }
  290. set data($node) [list $parent]
  291. if { [string equal $parent "root"] } {
  292. _redraw_idle $path 3
  293. } elseif { [visible $path $parent] } {
  294. # parent is visible...
  295. if { [Widget::getMegawidgetOption $path.$parent -open] } {
  296. # ...and opened -> redraw whole
  297. _redraw_idle $path 3
  298. } else {
  299. # ...and closed -> redraw cross
  300. lappend data(upd,nodes) $parent 8
  301. _redraw_idle $path 2
  302. }
  303. }
  304. return $node
  305. }
  306. # ----------------------------------------------------------------------------
  307. # Command Tree::itemconfigure
  308. # ----------------------------------------------------------------------------
  309. proc Tree::itemconfigure { path node args } {
  310. variable $path
  311. upvar 0 $path data
  312. set node [_node_name $path $node]
  313. if { [string equal $node "root"] || ![info exists data($node)] } {
  314. return -code error "node \"$node\" does not exist"
  315. }
  316. set result [Widget::configure $path.$node $args]
  317. _set_help $path $node
  318. if { [visible $path $node] } {
  319. set lopt {}
  320. set flag 0
  321. foreach opt {-window -image -drawcross -font -text -fill} {
  322. set flag [expr {$flag << 1}]
  323. if { [Widget::hasChanged $path.$node $opt val] } {
  324. set flag [expr {$flag | 1}]
  325. }
  326. }
  327. if { [Widget::hasChanged $path.$node -open val] } {
  328. if {[llength $data($node)] > 1} {
  329. # node have subnodes - full redraw
  330. _redraw_idle $path 3
  331. } else {
  332. # force a redraw of the plus/minus sign
  333. set flag [expr {$flag | 8}]
  334. }
  335. }
  336. if {$data(upd,level) < 3 && [Widget::hasChanged $path.$node -padx x]} {
  337. _redraw_idle $path 3
  338. }
  339. if { $data(upd,level) < 3 && $flag } {
  340. if { [set idx [lsearch -exact $data(upd,nodes) $node]] == -1 } {
  341. lappend data(upd,nodes) $node $flag
  342. } else {
  343. incr idx
  344. set flag [expr {[lindex $data(upd,nodes) $idx] | $flag}]
  345. set data(upd,nodes) [lreplace $data(upd,nodes) $idx $idx $flag]
  346. }
  347. _redraw_idle $path 2
  348. }
  349. }
  350. return $result
  351. }
  352. # ----------------------------------------------------------------------------
  353. # Command Tree::itemcget
  354. # ----------------------------------------------------------------------------
  355. proc Tree::itemcget { path node option } {
  356. # Instead of upvar'ing $path as data for this test, just directly refer to
  357. # it, as that is faster.
  358. set node [_node_name $path $node]
  359. if { [string equal $node "root"] || \
  360. ![info exists ::Tree::${path}($node)] } {
  361. return -code error "node \"$node\" does not exist"
  362. }
  363. return [Widget::cget $path.$node $option]
  364. }
  365. # ----------------------------------------------------------------------------
  366. # Command Tree::bindArea
  367. # ----------------------------------------------------------------------------
  368. proc Tree::bindArea { path event script } {
  369. bind $path.c $event $script
  370. }
  371. # ----------------------------------------------------------------------------
  372. # Command Tree::bindText
  373. # ----------------------------------------------------------------------------
  374. proc Tree::bindText { path event script } {
  375. if {[string length $script]} {
  376. append script " \[Tree::_get_node_name [list $path] current 2\]"
  377. }
  378. $path.c bind "node" $event $script
  379. if {[Widget::getoption $path -selectfill]} {
  380. $path.c bind "box" $event $script
  381. } else {
  382. $path.c bind "box" $event {}
  383. }
  384. }
  385. # ----------------------------------------------------------------------------
  386. # Command Tree::bindImage
  387. # ----------------------------------------------------------------------------
  388. proc Tree::bindImage { path event script } {
  389. if {[string length $script]} {
  390. append script " \[Tree::_get_node_name [list $path] current 2\]"
  391. }
  392. $path.c bind "img" $event $script
  393. if {[Widget::getoption $path -selectfill]} {
  394. $path.c bind "box" $event $script
  395. } else {
  396. $path.c bind "box" $event {}
  397. }
  398. }
  399. # ----------------------------------------------------------------------------
  400. # Command Tree::delete
  401. # ----------------------------------------------------------------------------
  402. proc Tree::delete { path args } {
  403. variable $path
  404. upvar 0 $path data
  405. set sel 0
  406. foreach lnodes $args {
  407. foreach node $lnodes {
  408. set node [_node_name $path $node]
  409. if { ![string equal $node "root"] && [info exists data($node)] } {
  410. set parent [lindex $data($node) 0]
  411. set idx [lsearch -exact $data($parent) $node]
  412. set data($parent) [lreplace $data($parent) $idx $idx]
  413. incr sel [_subdelete $path [list $node]]
  414. }
  415. }
  416. }
  417. if {$sel} {
  418. # if selection changed, call the selectcommand
  419. __call_selectcmd $path
  420. }
  421. _redraw_idle $path 3
  422. }
  423. # ----------------------------------------------------------------------------
  424. # Command Tree::move
  425. # ----------------------------------------------------------------------------
  426. proc Tree::move { path parent node index } {
  427. variable $path
  428. upvar 0 $path data
  429. set node [_node_name $path $node]
  430. if { [string equal $node "root"] || ![info exists data($node)] } {
  431. return -code error "node \"$node\" does not exist"
  432. }
  433. if { ![info exists data($parent)] } {
  434. return -code error "node \"$parent\" does not exist"
  435. }
  436. set p $parent
  437. while { ![string equal $p "root"] } {
  438. if { [string equal $p $node] } {
  439. return -code error "node \"$parent\" is a descendant of \"$node\""
  440. }
  441. set p [parent $path $p]
  442. }
  443. set oldp [lindex $data($node) 0]
  444. set idx [lsearch -exact $data($oldp) $node]
  445. set data($oldp) [lreplace $data($oldp) $idx $idx]
  446. set data($node) [concat [list $parent] [lrange $data($node) 1 end]]
  447. if { [string equal $index "end"] } {
  448. lappend data($parent) $node
  449. } else {
  450. incr index
  451. set data($parent) [linsert $data($parent) $index $node]
  452. }
  453. if { ([string equal $oldp "root"] ||
  454. ([visible $path $oldp] && [Widget::getoption $path.$oldp -open])) ||
  455. ([string equal $parent "root"] ||
  456. ([visible $path $parent] && [Widget::getoption $path.$parent -open])) } {
  457. _redraw_idle $path 3
  458. }
  459. }
  460. # ----------------------------------------------------------------------------
  461. # Command Tree::reorder
  462. # ----------------------------------------------------------------------------
  463. proc Tree::reorder { path node neworder } {
  464. variable $path
  465. upvar 0 $path data
  466. set node [_node_name $path $node]
  467. if { ![info exists data($node)] } {
  468. return -code error "node \"$node\" does not exist"
  469. }
  470. set children [lrange $data($node) 1 end]
  471. if { [llength $children] } {
  472. set children [BWidget::lreorder $children $neworder]
  473. set data($node) [linsert $children 0 [lindex $data($node) 0]]
  474. if { [visible $path $node] && [Widget::getoption $path.$node -open] } {
  475. _redraw_idle $path 3
  476. }
  477. }
  478. }
  479. # ----------------------------------------------------------------------------
  480. # Command Tree::selection
  481. # ----------------------------------------------------------------------------
  482. proc Tree::selection { path cmd args } {
  483. variable $path
  484. upvar 0 $path data
  485. switch -- $cmd {
  486. toggle {
  487. foreach node $args {
  488. set node [_node_name $path $node]
  489. if {![info exists data($node)]} {
  490. return -code error \
  491. "$path selection toggle: Cannot toggle unknown node \"$node\"."
  492. }
  493. }
  494. foreach node $args {
  495. set node [_node_name $path $node]
  496. if {[$path selection includes $node]} {
  497. $path selection remove $node
  498. } else {
  499. $path selection add $node
  500. }
  501. }
  502. }
  503. set {
  504. foreach node $args {
  505. set node [_node_name $path $node]
  506. if {![info exists data($node)]} {
  507. return -code error \
  508. "$path selection set: Cannot select unknown node \"$node\"."
  509. }
  510. }
  511. set data(selnodes) {}
  512. foreach node $args {
  513. set node [_node_name $path $node]
  514. if { [Widget::getoption $path.$node -selectable] } {
  515. if { [lsearch -exact $data(selnodes) $node] == -1 } {
  516. lappend data(selnodes) $node
  517. }
  518. }
  519. }
  520. __call_selectcmd $path
  521. }
  522. add {
  523. foreach node $args {
  524. set node [_node_name $path $node]
  525. if {![info exists data($node)]} {
  526. return -code error \
  527. "$path selection add: Cannot select unknown node \"$node\"."
  528. }
  529. }
  530. foreach node $args {
  531. set node [_node_name $path $node]
  532. if { [Widget::getoption $path.$node -selectable] } {
  533. if { [lsearch -exact $data(selnodes) $node] == -1 } {
  534. lappend data(selnodes) $node
  535. }
  536. }
  537. }
  538. __call_selectcmd $path
  539. }
  540. range {
  541. # Here's our algorithm:
  542. # make a list of all nodes, then take the range from node1
  543. # to node2 and select those nodes
  544. #
  545. # This works because of how this widget handles redraws:
  546. # The tree is always completely redrawn, and always from
  547. # top to bottom. So the list of visible nodes *is* the
  548. # list of nodes, and we can use that to decide which nodes
  549. # to select.
  550. if {[llength $args] != 2} {
  551. return -code error \
  552. "wrong#args: Expected $path selection range node1 node2"
  553. }
  554. foreach {node1 node2} $args break
  555. set node1 [_node_name $path $node1]
  556. set node2 [_node_name $path $node2]
  557. if {![info exists data($node1)]} {
  558. return -code error \
  559. "$path selection range: Cannot start range at unknown node \"$node1\"."
  560. }
  561. if {![info exists data($node2)]} {
  562. return -code error \
  563. "$path selection range: Cannot end range at unknown node \"$node2\"."
  564. }
  565. set nodes {}
  566. foreach nodeItem [$path.c find withtag node] {
  567. set node [Tree::_get_node_name $path $nodeItem 2]
  568. if { [Widget::getoption $path.$node -selectable] } {
  569. lappend nodes $node
  570. }
  571. }
  572. # surles: Set the root string to the first element on the list.
  573. if {$node1 == "root"} {
  574. set node1 [lindex $nodes 0]
  575. }
  576. if {$node2 == "root"} {
  577. set node2 [lindex $nodes 0]
  578. }
  579. # Find the first visible ancestor of node1, starting with node1
  580. while {[set index1 [lsearch -exact $nodes $node1]] == -1} {
  581. set node1 [lindex $data($node1) 0]
  582. }
  583. # Find the first visible ancestor of node2, starting with node2
  584. while {[set index2 [lsearch -exact $nodes $node2]] == -1} {
  585. set node2 [lindex $data($node2) 0]
  586. }
  587. # If the nodes were given in backwards order, flip the
  588. # indices now
  589. if { $index2 < $index1 } {
  590. incr index1 $index2
  591. set index2 [expr {$index1 - $index2}]
  592. set index1 [expr {$index1 - $index2}]
  593. }
  594. set data(selnodes) [lrange $nodes $index1 $index2]
  595. __call_selectcmd $path
  596. }
  597. remove {
  598. foreach node $args {
  599. set node [_node_name $path $node]
  600. if { [set idx [lsearch -exact $data(selnodes) $node]] != -1 } {
  601. set data(selnodes) [lreplace $data(selnodes) $idx $idx]
  602. }
  603. }
  604. __call_selectcmd $path
  605. }
  606. clear {
  607. if {[llength $args] != 0} {
  608. return -code error \
  609. "wrong#args: Expected $path selection clear"
  610. }
  611. set data(selnodes) {}
  612. __call_selectcmd $path
  613. }
  614. get {
  615. if {[llength $args] != 0} {
  616. return -code error \
  617. "wrong#args: Expected $path selection get"
  618. }
  619. return $data(selnodes)
  620. }
  621. includes {
  622. if {[llength $args] != 1} {
  623. return -code error \
  624. "wrong#args: Expected $path selection includes node"
  625. }
  626. set node [lindex $args 0]
  627. set node [_node_name $path $node]
  628. return [expr {[lsearch -exact $data(selnodes) $node] != -1}]
  629. }
  630. default {
  631. return
  632. }
  633. }
  634. _redraw_idle $path 1
  635. }
  636. proc Tree::getcanvas { path } {
  637. return $path.c
  638. }
  639. proc Tree::__call_selectcmd { path } {
  640. variable $path
  641. upvar 0 $path data
  642. set selectcmd [Widget::getoption $path -selectcommand]
  643. if {[llength $selectcmd]} {
  644. lappend selectcmd $path
  645. lappend selectcmd $data(selnodes)
  646. uplevel \#0 $selectcmd
  647. }
  648. return
  649. }
  650. # ----------------------------------------------------------------------------
  651. # Command Tree::exists
  652. # ----------------------------------------------------------------------------
  653. proc Tree::exists { path node } {
  654. variable $path
  655. upvar 0 $path data
  656. set node [_node_name $path $node]
  657. return [info exists data($node)]
  658. }
  659. # ----------------------------------------------------------------------------
  660. # Command Tree::visible
  661. # ----------------------------------------------------------------------------
  662. proc Tree::visible { path node } {
  663. set node [_node_name $path $node]
  664. set idn [$path.c find withtag n:$node]
  665. return [llength $idn]
  666. }
  667. # ----------------------------------------------------------------------------
  668. # Command Tree::parent
  669. # ----------------------------------------------------------------------------
  670. proc Tree::parent { path node } {
  671. variable $path
  672. upvar 0 $path data
  673. set node [_node_name $path $node]
  674. if { ![info exists data($node)] } {
  675. return -code error "node \"$node\" does not exist"
  676. }
  677. return [lindex $data($node) 0]
  678. }
  679. # ----------------------------------------------------------------------------
  680. # Command Tree::index
  681. # ----------------------------------------------------------------------------
  682. proc Tree::index { path node } {
  683. variable $path
  684. upvar 0 $path data
  685. set node [_node_name $path $node]
  686. if { [string equal $node "root"] || ![info exists data($node)] } {
  687. return -code error "node \"$node\" does not exist"
  688. }
  689. set parent [lindex $data($node) 0]
  690. return [expr {[lsearch -exact $data($parent) $node] - 1}]
  691. }
  692. # ----------------------------------------------------------------------------
  693. # Tree::find
  694. # Returns the node given a position.
  695. # findInfo @x,y ?confine?
  696. # lineNumber
  697. # ----------------------------------------------------------------------------
  698. proc Tree::find {path findInfo {confine ""}} {
  699. if {[regexp -- {^@([0-9]+),([0-9]+)$} $findInfo match x y]} {
  700. set x [$path.c canvasx $x]
  701. set y [$path.c canvasy $y]
  702. } elseif {[regexp -- {^[0-9]+$} $findInfo lineNumber]} {
  703. set dy [Widget::getoption $path -deltay]
  704. set y [expr {$dy*($lineNumber+0.5)}]
  705. set confine ""
  706. } else {
  707. return -code error "invalid find spec \"$findInfo\""
  708. }
  709. set found 0
  710. set region [$path.c bbox all]
  711. if {[llength $region]} {
  712. set xi [lindex $region 0]
  713. set xs [lindex $region 2]
  714. foreach id [$path.c find overlapping $xi $y $xs $y] {
  715. set ltags [$path.c gettags $id]
  716. set item [lindex $ltags 1]
  717. if { [string equal $item "node"] ||
  718. [string equal $item "img"] ||
  719. [string equal $item "win"] } {
  720. # item is the label or image/window of the node
  721. set node [Tree::_get_node_name $path $id 2]
  722. set found 1
  723. break
  724. }
  725. }
  726. }
  727. if {$found} {
  728. if {![string equal $confine ""]} {
  729. # test if x stand inside node bbox
  730. set padx [_get_node_padx $path $node]
  731. set xi [expr {[lindex [$path.c coords n:$node] 0] - $padx}]
  732. set xs [lindex [$path.c bbox n:$node] 2]
  733. if {$x >= $xi && $x <= $xs} {
  734. return $node
  735. }
  736. } else {
  737. return $node
  738. }
  739. }
  740. return ""
  741. }
  742. # ----------------------------------------------------------------------------
  743. # Command Tree::line
  744. # Returns the line where a node was drawn.
  745. # ----------------------------------------------------------------------------
  746. proc Tree::line {path node} {
  747. set node [_node_name $path $node]
  748. set item [$path.c find withtag n:$node]
  749. if {[string length $item]} {
  750. set dy [Widget::getoption $path -deltay]
  751. set y [lindex [$path.c coords $item] 1]
  752. set line [expr {int($y/$dy)}]
  753. } else {
  754. set line -1
  755. }
  756. return $line
  757. }
  758. # ----------------------------------------------------------------------------
  759. # Command Tree::nodes
  760. # ----------------------------------------------------------------------------
  761. proc Tree::nodes { path node {first ""} {last ""} } {
  762. variable $path
  763. upvar 0 $path data
  764. set node [_node_name $path $node]
  765. if { ![info exists data($node)] } {
  766. return -code error "node \"$node\" does not exist"
  767. }
  768. if { ![string length $first] } {
  769. return [lrange $data($node) 1 end]
  770. }
  771. if { ![string length $last] } {
  772. return [lindex [lrange $data($node) 1 end] $first]
  773. } else {
  774. return [lrange [lrange $data($node) 1 end] $first $last]
  775. }
  776. }
  777. # Tree::visiblenodes --
  778. #
  779. # Retrieve a list of all the nodes in a tree.
  780. #
  781. # Arguments:
  782. # path tree to retrieve nodes for.
  783. #
  784. # Results:
  785. # nodes list of nodes in the tree.
  786. proc Tree::visiblenodes { path } {
  787. variable $path
  788. upvar 0 $path data
  789. # Root is always open (?), so all of its children automatically get added
  790. # to the result, and to the stack.
  791. set st [lrange $data(root) 1 end]
  792. set result $st
  793. while {[llength $st]} {
  794. set node [lindex $st end]
  795. set st [lreplace $st end end]
  796. # Danger, danger! Using getMegawidgetOption is fragile, but much
  797. # much faster than going through cget.
  798. if { [Widget::getMegawidgetOption $path.$node -open] } {
  799. set nodes [lrange $data($node) 1 end]
  800. set result [concat $result $nodes]
  801. set st [concat $st $nodes]
  802. }
  803. }
  804. return $result
  805. }
  806. # ----------------------------------------------------------------------------
  807. # Command Tree::see
  808. # ----------------------------------------------------------------------------
  809. proc Tree::see { path node } {
  810. variable $path
  811. upvar 0 $path data
  812. set node [_node_name $path $node]
  813. if { [Widget::getoption $path -redraw] && $data(upd,afterid) != "" } {
  814. after cancel $data(upd,afterid)
  815. _redraw_tree $path
  816. }
  817. set idn [$path.c find withtag n:$node]
  818. if { $idn != "" } {
  819. Tree::_see $path $idn
  820. }
  821. }
  822. # ----------------------------------------------------------------------------
  823. # Command Tree::opentree
  824. # ----------------------------------------------------------------------------
  825. # JDC: added option recursive
  826. proc Tree::opentree { path node {recursive 1} } {
  827. variable $path
  828. upvar 0 $path data
  829. set node [_node_name $path $node]
  830. if { [string equal $node "root"] || ![info exists data($node)] } {
  831. return -code error "node \"$node\" does not exist"
  832. }
  833. _recexpand $path $node 1 $recursive [Widget::getoption $path -opencmd]
  834. _redraw_idle $path 3
  835. }
  836. # ----------------------------------------------------------------------------
  837. # Command Tree::closetree
  838. # ----------------------------------------------------------------------------
  839. proc Tree::closetree { path node {recursive 1} } {
  840. variable $path
  841. upvar 0 $path data
  842. set node [_node_name $path $node]
  843. if { [string equal $node "root"] || ![info exists data($node)] } {
  844. return -code error "node \"$node\" does not exist"
  845. }
  846. _recexpand $path $node 0 $recursive [Widget::getoption $path -closecmd]
  847. _redraw_idle $path 3
  848. }
  849. proc Tree::toggle { path node } {
  850. if {[$path itemcget $node -open]} {
  851. $path closetree $node 0
  852. } else {
  853. $path opentree $node 0
  854. }
  855. }
  856. # ----------------------------------------------------------------------------
  857. # Command Tree::edit
  858. # ----------------------------------------------------------------------------
  859. proc Tree::edit { path node text {verifycmd ""} {clickres 0} {select 1}} {
  860. variable _edit
  861. variable $path
  862. upvar 0 $path data
  863. set node [_node_name $path $node]
  864. if { [Widget::getoption $path -redraw] && $data(upd,afterid) != "" } {
  865. after cancel $data(upd,afterid)
  866. _redraw_tree $path
  867. }
  868. set idn [$path.c find withtag n:$node]
  869. if { $idn != "" } {
  870. Tree::_see $path $idn
  871. set oldfg [$path.c itemcget $idn -fill]
  872. set sbg [Widget::getoption $path -selectbackground]
  873. set coords [$path.c coords $idn]
  874. set x [lindex $coords 0]
  875. set y [lindex $coords 1]
  876. set bd [expr {[$path.c cget -borderwidth]+[$path.c cget -highlightthickness]}]
  877. set w [expr {[winfo width $path] - 2*$bd}]
  878. set wmax [expr {[$path.c canvasx $w]-$x}]
  879. set _edit(text) $text
  880. set _edit(wait) 0
  881. $path.c itemconfigure $idn -fill [Widget::getoption $path -background]
  882. $path.c itemconfigure s:$node -fill {} -outline {}
  883. set frame [frame $path.edit \
  884. -relief flat -borderwidth 0 -highlightthickness 0 \
  885. -background [Widget::getoption $path -background]]
  886. set ent [entry $frame.edit \
  887. -width 0 \
  888. -relief solid \
  889. -borderwidth 1 \
  890. -highlightthickness 0 \
  891. -foreground [Widget::getoption $path.$node -fill] \
  892. -background [Widget::getoption $path -background] \
  893. -selectforeground [Widget::getoption $path -selectforeground] \
  894. -selectbackground $sbg \
  895. -font [Widget::getoption $path.$node -font] \
  896. -textvariable Tree::_edit(text)]
  897. pack $ent -ipadx 8 -anchor w
  898. set idw [$path.c create window $x $y -window $frame -anchor w]
  899. trace variable Tree::_edit(text) w \
  900. [list Tree::_update_edit_size $path $ent $idw $wmax]
  901. tkwait visibility $ent
  902. grab $frame
  903. BWidget::focus set $ent
  904. _update_edit_size $path $ent $idw $wmax
  905. update
  906. if { $select } {
  907. $ent selection range 0 end
  908. $ent icursor end
  909. $ent xview end
  910. }
  911. bindtags $ent [list $ent Entry]
  912. bind $ent <Escape> {set Tree::_edit(wait) 0}
  913. bind $ent <Return> {set Tree::_edit(wait) 1}
  914. if { $clickres == 0 || $clickres == 1 } {
  915. bind $frame <Button> [list set Tree::_edit(wait) $clickres]
  916. }
  917. set ok 0
  918. while { !$ok } {
  919. tkwait variable Tree::_edit(wait)
  920. if { !$_edit(wait) || [llength $verifycmd]==0 ||
  921. [uplevel \#0 $verifycmd [list $_edit(text)]] } {
  922. set ok 1
  923. }
  924. }
  925. trace vdelete Tree::_edit(text) w \
  926. [list Tree::_update_edit_size $path $ent $idw $wmax]
  927. grab release $frame
  928. BWidget::focus release $ent
  929. destroy $frame
  930. $path.c delete $idw
  931. $path.c itemconfigure $idn -fill $oldfg
  932. $path.c itemconfigure s:$node -fill $sbg -outline $sbg
  933. if { $_edit(wait) } {
  934. return $_edit(text)
  935. }
  936. }
  937. return ""
  938. }
  939. # ----------------------------------------------------------------------------
  940. # Command Tree::xview
  941. # ----------------------------------------------------------------------------
  942. proc Tree::xview { path args } {
  943. return [eval [linsert $args 0 $path.c xview]]
  944. }
  945. # ----------------------------------------------------------------------------
  946. # Command Tree::yview
  947. # ----------------------------------------------------------------------------
  948. proc Tree::yview { path args } {
  949. return [eval [linsert $args 0 $path.c yview]]
  950. }
  951. # ----------------------------------------------------------------------------
  952. # Command Tree::_update_edit_size
  953. # ----------------------------------------------------------------------------
  954. proc Tree::_update_edit_size { path entry idw wmax args } {
  955. set entw [winfo reqwidth $entry]
  956. if { $entw+8 >= $wmax } {
  957. $path.c itemconfigure $idw -width $wmax
  958. } else {
  959. $path.c itemconfigure $idw -width 0
  960. }
  961. }
  962. # ----------------------------------------------------------------------------
  963. # Command Tree::_see
  964. # ----------------------------------------------------------------------------
  965. proc Tree::_see { path idn } {
  966. set bbox [$path.c bbox $idn]
  967. set scrl [$path.c cget -scrollregion]
  968. set ymax [lindex $scrl 3]
  969. set dy [$path.c cget -yscrollincrement]
  970. set yv [$path yview]
  971. set yv0 [expr {round([lindex $yv 0]*$ymax/$dy)}]
  972. set yv1 [expr {round([lindex $yv 1]*$ymax/$dy)}]
  973. set y [expr {int([lindex [$path.c coords $idn] 1]/$dy)}]
  974. if { $y < $yv0 } {
  975. $path.c yview scroll [expr {$y-$yv0}] units
  976. } elseif { $y >= $yv1 } {
  977. $path.c yview scroll [expr {$y-$yv1+1}] units
  978. }
  979. set xmax [lindex $scrl 2]
  980. set dx [$path.c cget -xscrollincrement]
  981. set xv [$path xview]
  982. set x0 [expr {int([lindex $bbox 0]/$dx)}]
  983. set xv0 [expr {round([lindex $xv 0]*$xmax/$dx)}]
  984. set xv1 [expr {round([lindex $xv 1]*$xmax/$dx)}]
  985. if { $x0 >= $xv1 || $x0 < $xv0 } {
  986. $path.c xview scroll [expr {$x0-$xv0}] units
  987. }
  988. }
  989. # ----------------------------------------------------------------------------
  990. # Command Tree::_recexpand
  991. # ----------------------------------------------------------------------------
  992. # JDC : added option recursive
  993. proc Tree::_recexpand { path node expand recursive cmd } {
  994. variable $path
  995. upvar 0 $path data
  996. if { [Widget::getoption $path.$node -open] != $expand } {
  997. Widget::setoption $path.$node -open $expand
  998. if {[llength $cmd]} {
  999. uplevel \#0 $cmd [list $node]
  1000. }
  1001. }
  1002. if { $recursive } {
  1003. foreach subnode [lrange $data($node) 1 end] {
  1004. _recexpand $path $subnode $expand $recursive $cmd
  1005. }
  1006. }
  1007. }
  1008. # ----------------------------------------------------------------------------
  1009. # Command Tree::_subdelete
  1010. # ----------------------------------------------------------------------------
  1011. proc Tree::_subdelete { path lnodes } {
  1012. variable $path
  1013. upvar 0 $path data
  1014. set sel $data(selnodes)
  1015. set selchanged 0
  1016. while { [llength $lnodes] } {
  1017. set lsubnodes [list]
  1018. foreach node $lnodes {
  1019. foreach subnode [lrange $data($node) 1 end] {
  1020. lappend lsubnodes $subnode
  1021. }
  1022. unset data($node)
  1023. set idx [lsearch -exact $sel $node]
  1024. if { $idx >= 0 } {
  1025. set sel [lreplace $sel $idx $idx]
  1026. incr selchanged
  1027. }
  1028. if { [set win [Widget::getoption $path.$node -window]] != "" } {
  1029. destroy $win
  1030. }
  1031. Widget::destroy $path.$node
  1032. }
  1033. set lnodes $lsubnodes
  1034. }
  1035. set data(selnodes) $sel
  1036. # return number of sel items changes
  1037. return $selchanged
  1038. }
  1039. # ----------------------------------------------------------------------------
  1040. # Command Tree::_update_scrollregion
  1041. # ----------------------------------------------------------------------------
  1042. proc Tree::_update_scrollregion { path } {
  1043. set bd [expr {2*([$path.c cget -borderwidth]+[$path.c cget -highlightthickness])}]
  1044. set w [expr {[winfo width $path] - $bd}]
  1045. set h [expr {[winfo height $path] - $bd}]
  1046. set xinc [$path.c cget -xscrollincrement]
  1047. set yinc [$path.c cget -yscrollincrement]
  1048. set bbox [$path.c bbox node]
  1049. if { [llength $bbox] } {
  1050. set xs [lindex $bbox 2]
  1051. set ys [lindex $bbox 3]
  1052. if { $w < $xs } {
  1053. set w [expr {int($xs)}]
  1054. if { [set r [expr {$w % $xinc}]] } {
  1055. set w [expr {$w+$xinc-$r}]
  1056. }
  1057. }
  1058. if { $h < $ys } {
  1059. set h [expr {int($ys)}]
  1060. if { [set r [expr {$h % $yinc}]] } {
  1061. set h [expr {$h+$yinc-$r}]
  1062. }
  1063. }
  1064. }
  1065. $path.c configure -scrollregion [list 0 0 $w $h]
  1066. if {[Widget::getoption $path -selectfill]} {
  1067. _redraw_selection $path
  1068. }
  1069. }
  1070. # ----------------------------------------------------------------------------
  1071. # Command Tree::_cross_event
  1072. # ----------------------------------------------------------------------------
  1073. proc Tree::_cross_event { path } {
  1074. variable $path
  1075. upvar 0 $path data
  1076. set node [Tree::_get_node_name $path current 1]
  1077. if { [Widget::getoption $path.$node -open] } {
  1078. Tree::itemconfigure $path $node -open 0
  1079. if {[llength [set cmd [Widget::getoption $path -closecmd]]]} {
  1080. uplevel \#0 $cmd [list $node]
  1081. }
  1082. } else {
  1083. Tree::itemconfigure $path $node -open 1
  1084. if {[llength [set cmd [Widget::getoption $path -opencmd]]]} {
  1085. uplevel \#0 $cmd [list $node]
  1086. }
  1087. }
  1088. }
  1089. proc Tree::_draw_cross { path node open x y } {
  1090. set idc [$path.c find withtag c:$node]
  1091. if { $open } {
  1092. set img [Widget::cget $path -crossopenimage]
  1093. set bmp [Widget::cget $path -crossopenbitmap]
  1094. } else {
  1095. set img [Widget::cget $path -crosscloseimage]
  1096. set bmp [Widget::cget $path -crossclosebitmap]
  1097. }
  1098. ## If we already have a cross for this node, we just adjust the image.
  1099. if {$idc != ""} {
  1100. if {$img == ""} {
  1101. $path.c itemconfigure $idc -bitmap $bmp
  1102. } else {
  1103. $path.c itemconfigure $idc -image $img
  1104. }
  1105. return
  1106. }
  1107. ## Create a new image for the cross. If the user has specified an
  1108. ## image, it overrides a bitmap.
  1109. if {$img == ""} {
  1110. $path.c create bitmap $x $y \
  1111. -bitmap $bmp \
  1112. -background [$path.c cget -background] \
  1113. -foreground [Widget::getoption $path -crossfill] \
  1114. -tags [list cross c:$node] -anchor c
  1115. } else {
  1116. $path.c create image $x $y \
  1117. -image $img \
  1118. -tags [list cross c:$node] -anchor c
  1119. }
  1120. }
  1121. # ----------------------------------------------------------------------------
  1122. # Command Tree::_draw_node
  1123. # ----------------------------------------------------------------------------
  1124. proc Tree::_draw_node { path node x0 y0 deltax deltay padx showlines } {
  1125. variable $path
  1126. upvar 0 $path data
  1127. set x1 [expr {$x0+$deltax+5}]
  1128. set y1 $y0
  1129. if { $showlines } {
  1130. $path.c create line $x0 $y0 $x1 $y0 \
  1131. -fill [Widget::getoption $path -linesfill] \
  1132. -stipple [Widget::getoption $path -linestipple] \
  1133. -tags line
  1134. }
  1135. $path.c create text [expr {$x1+$padx}] $y0 \
  1136. -text [Widget::getoption $path.$node -text] \
  1137. -fill [Widget::getoption $path.$node -fill] \
  1138. -font [Widget::getoption $path.$node -font] \
  1139. -anchor w \
  1140. -tags [Tree::_get_node_tags $path $node [list node n:$node]]
  1141. set len [expr {[llength $data($node)] > 1}]
  1142. set dc [Widget::getoption $path.$node -drawcross]
  1143. set exp [Widget::getoption $path.$node -open]
  1144. if { $len && $exp } {
  1145. set y1 [_draw_subnodes $path [lrange $data($node) 1 end] \
  1146. [expr {$x0+$deltax}] $y0 $deltax $deltay $padx $showlines]
  1147. }
  1148. if {![string equal $dc "never"]
  1149. && ($len || [string equal $dc "always"] || [string equal $dc "allways"])} {
  1150. _draw_cross $path $node $exp $x0 $y0
  1151. }
  1152. if { [set win [Widget::getoption $path.$node -window]] != "" } {
  1153. set a [Widget::cget $path.$node -anchor]
  1154. $path.c create window $x1 $y0 -window $win -anchor $a \
  1155. -tags [Tree::_get_node_tags $path $node [list win i:$node]]
  1156. } elseif { [set img [Widget::getoption $path.$node -image]] != "" } {
  1157. set a [Widget::cget $path.$node -anchor]
  1158. $path.c create image $x1 $y0 -image $img -anchor $a \
  1159. -tags [Tree::_get_node_tags $path $node [list img i:$node]]
  1160. }
  1161. set box [$path.c bbox n:$node i:$node]
  1162. set id [$path.c create rect 0 [lindex $box 1] \
  1163. [winfo screenwidth $path] [lindex $box 3] \
  1164. -tags [Tree::_get_node_tags $path $node [list box b:$node]] \
  1165. -fill {} -outline {}]
  1166. $path.c lower $id
  1167. _set_help $path $node
  1168. return $y1
  1169. }
  1170. # ----------------------------------------------------------------------------
  1171. # Command Tree::_draw_subnodes
  1172. # ----------------------------------------------------------------------------
  1173. proc Tree::_draw_subnodes { path nodes x0 y0 deltax deltay padx showlines } {
  1174. set y1 $y0
  1175. foreach node $nodes {
  1176. set padx [_get_node_padx $path $node]
  1177. set deltax [_get_node_deltax $path $node]
  1178. set yp $y1
  1179. set y1 [_draw_node $path $node $x0 [expr {$y1+$deltay}] $deltax $deltay $padx $showlines]
  1180. }
  1181. if { $showlines && [llength $nodes] } {
  1182. if {$y0 < 0} {
  1183. # Adjust the drawing of the line to the first root node
  1184. # to start at the vertical point (not go up).
  1185. incr y0 $deltay
  1186. }
  1187. set id [$path.c create line $x0 $y0 $x0 [expr {$yp+$deltay}] \
  1188. -fill [Widget::getoption $path -linesfill] \
  1189. -stipple [Widget::getoption $path -linestipple] \
  1190. -tags line]
  1191. $path.c lower $id
  1192. }
  1193. return $y1
  1194. }
  1195. # ----------------------------------------------------------------------------
  1196. # Command Tree::_update_nodes
  1197. # ----------------------------------------------------------------------------
  1198. proc Tree::_update_nodes { path } {
  1199. variable $path
  1200. upvar 0 $path data
  1201. foreach {node flag} $data(upd,nodes) {
  1202. set idn [$path.c find withtag "n:$node"]
  1203. if { $idn == "" } {
  1204. continue
  1205. }
  1206. set padx [_get_node_padx $path $node]
  1207. set deltax [_get_node_deltax $path $node]
  1208. set c [$path.c coords $idn]
  1209. set x1 [expr {[lindex $c 0]-$padx}]
  1210. set x0 [expr {$x1-$deltax-5}]
  1211. set y0 [lindex $c 1]
  1212. if { $flag & 48 } {
  1213. # -window or -image modified
  1214. set win [Widget::getoption $path.$node -window]
  1215. set img [Widget::getoption $path.$node -image]
  1216. set anc [Widget::cget $path.$node -anchor]
  1217. set idi [$path.c find withtag i:$node]
  1218. set type [lindex [$path.c gettags $idi] 1]
  1219. if { [string length $win] } {
  1220. if { [string equal $type "win"] } {
  1221. $path.c itemconfigure $idi -window $win
  1222. } else {
  1223. $path.c delete $idi
  1224. $path.c create window $x1 $y0 -window $win -anchor $anc \
  1225. -tags [_get_node_tags $path $node [list win i:$node]]
  1226. }
  1227. } elseif { [string length $img] } {
  1228. if { [string equal $type "img"] } {
  1229. $path.c itemconfigure $idi -image $img
  1230. } else {
  1231. $path.c delete $idi
  1232. $path.c create image $x1 $y0 -image $img -anchor $anc \
  1233. -tags [_get_node_tags $path $node [list img i:$node]]
  1234. }
  1235. } else {
  1236. $path.c delete $idi
  1237. }
  1238. }
  1239. if { $flag & 8 } {
  1240. # -drawcross modified
  1241. set len [expr {[llength $data($node)] > 1}]
  1242. set dc [Widget::getoption $path.$node -drawcross]
  1243. set exp [Widget::getoption $path.$node -open]
  1244. if {![string equal $dc "never"]
  1245. && ($len || [string equal $dc "always"] || [string equal $dc "allways"])} {
  1246. _draw_cross $path $node $exp $x0 $y0
  1247. } else {
  1248. set idc [$path.c find withtag c:$node]
  1249. $path.c delete $idc
  1250. }
  1251. }
  1252. if { $flag & 7 } {
  1253. # -font, -text or -fill modified
  1254. $path.c itemconfigure $idn \
  1255. -text [Widget::getoption $path.$node -text] \
  1256. -fill [Widget::getoption $path.$node -fill] \
  1257. -font [Widget::getoption $path.$node -font]
  1258. }
  1259. }
  1260. }
  1261. # ----------------------------------------------------------------------------
  1262. # Command Tree::_draw_tree
  1263. # ----------------------------------------------------------------------------
  1264. proc Tree::_draw_tree { path } {
  1265. variable $path
  1266. upvar 0 $path data
  1267. $path.c delete all
  1268. set cursor [$path.c cget -cursor]
  1269. $path.c configure -cursor watch
  1270. _draw_subnodes $path [lrange $data(root) 1 end] 8 \
  1271. [expr {-[Widget::getoption $path -deltay]/2}] \
  1272. [Widget::getoption $path -deltax] \
  1273. [Widget::getoption $path -deltay] \
  1274. [Widget::getoption $path -padx] \
  1275. [Widget::getoption $path -showlines]
  1276. $path.c configure -cursor $cursor
  1277. }
  1278. # ----------------------------------------------------------------------------
  1279. # Command Tree::_redraw_tree
  1280. # ----------------------------------------------------------------------------
  1281. proc Tree::_redraw_tree { path } {
  1282. variable $path
  1283. upvar 0 $path data
  1284. if { [Widget::getoption $path -redraw] } {
  1285. if { $data(upd,level) == 2 } {
  1286. _update_nodes $path
  1287. } elseif { $data(upd,level) == 3 } {
  1288. _draw_tree $path
  1289. }
  1290. _redraw_selection $path
  1291. _update_scrollregion $path
  1292. set data(upd,nodes) {}
  1293. set data(upd,level) 0
  1294. set data(upd,afterid) ""
  1295. }
  1296. }
  1297. # ----------------------------------------------------------------------------
  1298. # Command Tree::_redraw_selection
  1299. # ----------------------------------------------------------------------------
  1300. proc Tree::_redraw_selection { path } {
  1301. variable $path
  1302. upvar 0 $path data
  1303. set selbg [Widget::getoption $path -selectbackground]
  1304. set selfg [Widget::getoption $path -selectforeground]
  1305. set fill [Widget::getoption $path -selectfill]
  1306. if {$fill} {
  1307. set scroll [$path.c cget -scrollregion]
  1308. if {[llength $scroll]} {
  1309. set xmax [expr {[lindex $scroll 2]-1}]
  1310. } else {
  1311. set xmax [winfo width $path]
  1312. }
  1313. }
  1314. foreach id [$path.c find withtag sel] {
  1315. set node [Tree::_get_node_name $path $id 1]
  1316. $path.c itemconfigure "n:$node" -fill [Widget::getoption $path.$node -fill]
  1317. }
  1318. $path.c delete sel
  1319. foreach node $data(selnodes) {
  1320. set bbox [$path.c bbox "n:$node"]
  1321. if { [llength $bbox] } {
  1322. if {$fill} {
  1323. # get the image to (if any), as it may have different height
  1324. set bbox [$path.c bbox "n:$node" "i:$node"]
  1325. set bbox [list 0 [lindex $bbox 1] $xmax [lindex $bbox 3]]
  1326. }
  1327. set id [$path.c create rectangle $bbox -tags [list sel s:$node] \
  1328. -fill $selbg -outline $selbg]
  1329. $path.c itemconfigure "n:$node" -fill $selfg
  1330. $path.c lower $id
  1331. }
  1332. }
  1333. }
  1334. # -----------------------------------------------------------

Large files files are truncated, but you can click here to view the full file