PageRenderTime 96ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/tcl/BWidget-1.9.0/listbox.tcl

http://github.com/angal/arcadia
TCL | 1693 lines | 1206 code | 218 blank | 269 comment | 261 complexity | 887f174297535195a6f1c4767297a8ec MD5 | raw file
Possible License(s): AGPL-3.0

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

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

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