gooderp18绿色标准版
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

721 行
16KB

  1. # iconlist.tcl
  2. #
  3. # Implements the icon-list megawidget used in the "Tk" standard file
  4. # selection dialog boxes.
  5. #
  6. # Copyright (c) 1994-1998 Sun Microsystems, Inc.
  7. # Copyright (c) 2009 Donal K. Fellows
  8. #
  9. # See the file "license.terms" for information on usage and redistribution of
  10. # this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11. #
  12. # API Summary:
  13. # tk::IconList <path> ?<option> <value>? ...
  14. # <path> add <imageName> <itemList>
  15. # <path> cget <option>
  16. # <path> configure ?<option>? ?<value>? ...
  17. # <path> deleteall
  18. # <path> destroy
  19. # <path> get <itemIndex>
  20. # <path> index <index>
  21. # <path> invoke
  22. # <path> see <index>
  23. # <path> selection anchor ?<int>?
  24. # <path> selection clear <first> ?<last>?
  25. # <path> selection get
  26. # <path> selection includes <item>
  27. # <path> selection set <first> ?<last>?
  28. package require Tk
  29. ::tk::Megawidget create ::tk::IconList ::tk::FocusableWidget {
  30. variable w canvas sbar accel accelCB fill font index \
  31. itemList itemsPerColumn list maxIH maxIW maxTH maxTW noScroll \
  32. numItems oldX oldY options rect selected selection textList
  33. constructor args {
  34. next {*}$args
  35. set accelCB {}
  36. }
  37. destructor {
  38. my Reset
  39. next
  40. }
  41. method GetSpecs {} {
  42. concat [next] {
  43. {-command "" "" ""}
  44. {-font "" "" "TkIconFont"}
  45. {-multiple "" "" "0"}
  46. }
  47. }
  48. # ----------------------------------------------------------------------
  49. method index i {
  50. if {![info exist list]} {
  51. set list {}
  52. }
  53. switch -regexp -- $i {
  54. "^-?[0-9]+$" {
  55. if {$i < 0} {
  56. set i 0
  57. }
  58. if {$i >= [llength $list]} {
  59. set i [expr {[llength $list] - 1}]
  60. }
  61. return $i
  62. }
  63. "^anchor$" {
  64. return $index(anchor)
  65. }
  66. "^end$" {
  67. return [llength $list]
  68. }
  69. "@-?[0-9]+,-?[0-9]+" {
  70. scan $i "@%d,%d" x y
  71. set item [$canvas find closest \
  72. [$canvas canvasx $x] [$canvas canvasy $y]]
  73. return [lindex [$canvas itemcget $item -tags] 1]
  74. }
  75. }
  76. }
  77. method selection {op args} {
  78. switch -exact -- $op {
  79. anchor {
  80. if {[llength $args] == 1} {
  81. set index(anchor) [$w index [lindex $args 0]]
  82. } else {
  83. return $index(anchor)
  84. }
  85. }
  86. clear {
  87. switch [llength $args] {
  88. 2 {
  89. lassign $args first last
  90. }
  91. 1 {
  92. set first [set last [lindex $args 0]]
  93. }
  94. default {
  95. return -code error -errorcode {TCL WRONGARGS} \
  96. "wrong # args: should be\
  97. \"[lrange [info level 0] 0 1] first ?last?\""
  98. }
  99. }
  100. set first [$w index $first]
  101. set last [$w index $last]
  102. if {$first > $last} {
  103. set tmp $first
  104. set first $last
  105. set last $tmp
  106. }
  107. set ind 0
  108. foreach item $selection {
  109. if {$item >= $first} {
  110. set first $ind
  111. break
  112. }
  113. incr ind
  114. }
  115. set ind [expr {[llength $selection] - 1}]
  116. for {} {$ind >= 0} {incr ind -1} {
  117. set item [lindex $selection $ind]
  118. if {$item <= $last} {
  119. set last $ind
  120. break
  121. }
  122. }
  123. if {$first > $last} {
  124. return
  125. }
  126. set selection [lreplace $selection $first $last]
  127. event generate $w <<ListboxSelect>>
  128. my DrawSelection
  129. }
  130. get {
  131. return $selection
  132. }
  133. includes {
  134. return [expr {[lindex $args 0] in $selection}]
  135. }
  136. set {
  137. switch [llength $args] {
  138. 2 {
  139. lassign $args first last
  140. }
  141. 1 {
  142. set first [set last [lindex $args 0]]
  143. }
  144. default {
  145. return -code error -errorcode {TCL WRONGARGS} \
  146. "wrong # args: should be\
  147. \"[lrange [info level 0] 0 1] first ?last?\""
  148. }
  149. }
  150. set first [$w index $first]
  151. set last [$w index $last]
  152. if {$first > $last} {
  153. set tmp $first
  154. set first $last
  155. set last $tmp
  156. }
  157. for {set i $first} {$i <= $last} {incr i} {
  158. lappend selection $i
  159. }
  160. set selection [lsort -integer -unique $selection]
  161. event generate $w <<ListboxSelect>>
  162. my DrawSelection
  163. }
  164. }
  165. }
  166. method get item {
  167. set rTag [lindex $list $item 2]
  168. lassign $itemList($rTag) iTag tTag text serial
  169. return $text
  170. }
  171. # Deletes all the items inside the canvas subwidget and reset the
  172. # iconList's state.
  173. #
  174. method deleteall {} {
  175. $canvas delete all
  176. unset -nocomplain selected rect list itemList
  177. set maxIW 1
  178. set maxIH 1
  179. set maxTW 1
  180. set maxTH 1
  181. set numItems 0
  182. set noScroll 1
  183. set selection {}
  184. set index(anchor) ""
  185. $sbar set 0.0 1.0
  186. $canvas xview moveto 0
  187. }
  188. # Adds an icon into the IconList with the designated image and text
  189. #
  190. method add {image items} {
  191. foreach text $items {
  192. set iID item$numItems
  193. set iTag [$canvas create image 0 0 -image $image -anchor nw \
  194. -tags [list icon $numItems $iID]]
  195. set tTag [$canvas create text 0 0 -text $text -anchor nw \
  196. -font $options(-font) -fill $fill \
  197. -tags [list text $numItems $iID]]
  198. set rTag [$canvas create rect 0 0 0 0 -fill "" -outline "" \
  199. -tags [list rect $numItems $iID]]
  200. lassign [$canvas bbox $iTag] x1 y1 x2 y2
  201. set iW [expr {$x2 - $x1}]
  202. set iH [expr {$y2 - $y1}]
  203. if {$maxIW < $iW} {
  204. set maxIW $iW
  205. }
  206. if {$maxIH < $iH} {
  207. set maxIH $iH
  208. }
  209. lassign [$canvas bbox $tTag] x1 y1 x2 y2
  210. set tW [expr {$x2 - $x1}]
  211. set tH [expr {$y2 - $y1}]
  212. if {$maxTW < $tW} {
  213. set maxTW $tW
  214. }
  215. if {$maxTH < $tH} {
  216. set maxTH $tH
  217. }
  218. lappend list [list $iTag $tTag $rTag $iW $iH $tW $tH $numItems]
  219. set itemList($rTag) [list $iTag $tTag $text $numItems]
  220. set textList($numItems) [string tolower $text]
  221. incr numItems
  222. }
  223. my WhenIdle Arrange
  224. return
  225. }
  226. # Gets called when the user invokes the IconList (usually by
  227. # double-clicking or pressing the Return key).
  228. #
  229. method invoke {} {
  230. if {$options(-command) ne "" && [llength $selection]} {
  231. uplevel #0 $options(-command)
  232. }
  233. }
  234. # If the item is not (completely) visible, scroll the canvas so that it
  235. # becomes visible.
  236. #
  237. method see rTag {
  238. if {$noScroll} {
  239. return
  240. }
  241. set sRegion [$canvas cget -scrollregion]
  242. if {$sRegion eq ""} {
  243. return
  244. }
  245. if {$rTag < 0 || $rTag >= [llength $list]} {
  246. return
  247. }
  248. set bbox [$canvas bbox item$rTag]
  249. set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}]
  250. set x1 [lindex $bbox 0]
  251. set x2 [lindex $bbox 2]
  252. incr x1 [expr {$pad * -2}]
  253. incr x2 [expr {$pad * -1}]
  254. set cW [expr {[winfo width $canvas] - $pad*2}]
  255. set scrollW [expr {[lindex $sRegion 2]-[lindex $sRegion 0]+1}]
  256. set dispX [expr {int([lindex [$canvas xview] 0]*$scrollW)}]
  257. set oldDispX $dispX
  258. # check if out of the right edge
  259. #
  260. if {($x2 - $dispX) >= $cW} {
  261. set dispX [expr {$x2 - $cW}]
  262. }
  263. # check if out of the left edge
  264. #
  265. if {($x1 - $dispX) < 0} {
  266. set dispX $x1
  267. }
  268. if {$oldDispX ne $dispX} {
  269. set fraction [expr {double($dispX) / double($scrollW)}]
  270. $canvas xview moveto $fraction
  271. }
  272. }
  273. # ----------------------------------------------------------------------
  274. # Places the icons in a column-major arrangement.
  275. #
  276. method Arrange {} {
  277. if {![info exists list]} {
  278. if {[info exists canvas] && [winfo exists $canvas]} {
  279. set noScroll 1
  280. $sbar configure -command ""
  281. }
  282. return
  283. }
  284. set W [winfo width $canvas]
  285. set H [winfo height $canvas]
  286. set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}]
  287. if {$pad < 2} {
  288. set pad 2
  289. }
  290. incr W [expr {$pad*-2}]
  291. incr H [expr {$pad*-2}]
  292. set dx [expr {$maxIW + $maxTW + 8}]
  293. if {$maxTH > $maxIH} {
  294. set dy $maxTH
  295. } else {
  296. set dy $maxIH
  297. }
  298. incr dy 2
  299. set shift [expr {$maxIW + 4}]
  300. set x [expr {$pad * 2}]
  301. set y [expr {$pad * 1}] ; # Why * 1 ?
  302. set usedColumn 0
  303. foreach sublist $list {
  304. set usedColumn 1
  305. lassign $sublist iTag tTag rTag iW iH tW tH
  306. set i_dy [expr {($dy - $iH)/2}]
  307. set t_dy [expr {($dy - $tH)/2}]
  308. $canvas coords $iTag $x [expr {$y + $i_dy}]
  309. $canvas coords $tTag [expr {$x + $shift}] [expr {$y + $t_dy}]
  310. $canvas coords $rTag $x $y [expr {$x+$dx}] [expr {$y+$dy}]
  311. incr y $dy
  312. if {($y + $dy) > $H} {
  313. set y [expr {$pad * 1}] ; # *1 ?
  314. incr x $dx
  315. set usedColumn 0
  316. }
  317. }
  318. if {$usedColumn} {
  319. set sW [expr {$x + $dx}]
  320. } else {
  321. set sW $x
  322. }
  323. if {$sW < $W} {
  324. $canvas configure -scrollregion [list $pad $pad $sW $H]
  325. $sbar configure -command ""
  326. $canvas xview moveto 0
  327. set noScroll 1
  328. } else {
  329. $canvas configure -scrollregion [list $pad $pad $sW $H]
  330. $sbar configure -command [list $canvas xview]
  331. set noScroll 0
  332. }
  333. set itemsPerColumn [expr {($H-$pad) / $dy}]
  334. if {$itemsPerColumn < 1} {
  335. set itemsPerColumn 1
  336. }
  337. my DrawSelection
  338. }
  339. method DrawSelection {} {
  340. $canvas delete selection
  341. $canvas itemconfigure selectionText -fill black
  342. $canvas dtag selectionText
  343. set cbg [ttk::style lookup TEntry -selectbackground focus]
  344. set cfg [ttk::style lookup TEntry -selectforeground focus]
  345. foreach item $selection {
  346. set rTag [lindex $list $item 2]
  347. foreach {iTag tTag text serial} $itemList($rTag) {
  348. break
  349. }
  350. set bbox [$canvas bbox $tTag]
  351. $canvas create rect $bbox -fill $cbg -outline $cbg \
  352. -tags selection
  353. $canvas itemconfigure $tTag -fill $cfg -tags selectionText
  354. }
  355. $canvas lower selection
  356. return
  357. }
  358. # Creates an IconList widget by assembling a canvas widget and a
  359. # scrollbar widget. Sets all the bindings necessary for the IconList's
  360. # operations.
  361. #
  362. method Create {} {
  363. variable hull
  364. set sbar [ttk::scrollbar $hull.sbar -orient horizontal -takefocus 0]
  365. catch {$sbar configure -highlightthickness 0}
  366. set canvas [canvas $hull.canvas -highlightthick 0 -takefocus 1 \
  367. -width 400 -height 120 -background white]
  368. pack $sbar -side bottom -fill x -padx 2 -pady {0 2}
  369. pack $canvas -expand yes -fill both -padx 2 -pady {2 0}
  370. $sbar configure -command [list $canvas xview]
  371. $canvas configure -xscrollcommand [list $sbar set]
  372. # Initializes the max icon/text width and height and other variables
  373. #
  374. set maxIW 1
  375. set maxIH 1
  376. set maxTW 1
  377. set maxTH 1
  378. set numItems 0
  379. set noScroll 1
  380. set selection {}
  381. set index(anchor) ""
  382. set fg [option get $canvas foreground Foreground]
  383. if {$fg eq ""} {
  384. set fill black
  385. } else {
  386. set fill $fg
  387. }
  388. # Creates the event bindings.
  389. #
  390. bind $canvas <Configure> [namespace code {my WhenIdle Arrange}]
  391. bind $canvas <Button-1> [namespace code {my Btn1 %x %y}]
  392. bind $canvas <B1-Motion> [namespace code {my Motion1 %x %y}]
  393. bind $canvas <B1-Leave> [namespace code {my Leave1 %x %y}]
  394. bind $canvas <Control-Button-1> [namespace code {my CtrlBtn1 %x %y}]
  395. bind $canvas <Shift-Button-1> [namespace code {my ShiftBtn1 %x %y}]
  396. bind $canvas <B1-Enter> [list tk::CancelRepeat]
  397. bind $canvas <ButtonRelease-1> [list tk::CancelRepeat]
  398. bind $canvas <Double-ButtonRelease-1> \
  399. [namespace code {my Double1 %x %y}]
  400. bind $canvas <Control-B1-Motion> {;}
  401. bind $canvas <Shift-B1-Motion> [namespace code {my ShiftMotion1 %x %y}]
  402. if {[tk windowingsystem] eq "aqua"} {
  403. bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel [expr {40 * (%D)}]}]
  404. bind $canvas <Option-Shift-MouseWheel> [namespace code {my MouseWheel [expr {400 * (%D)}]}]
  405. bind $canvas <Command-Key> {# nothing}
  406. bind $canvas <Mod4-Key> {# nothing}
  407. } else {
  408. bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel %D}]
  409. }
  410. if {[tk windowingsystem] eq "x11"} {
  411. bind $canvas <Shift-Button-4> [namespace code {my MouseWheel 120}]
  412. bind $canvas <Shift-Button-5> [namespace code {my MouseWheel -120}]
  413. }
  414. bind $canvas <<PrevLine>> [namespace code {my UpDown -1}]
  415. bind $canvas <<NextLine>> [namespace code {my UpDown 1}]
  416. bind $canvas <<PrevChar>> [namespace code {my LeftRight -1}]
  417. bind $canvas <<NextChar>> [namespace code {my LeftRight 1}]
  418. bind $canvas <Return> [namespace code {my ReturnKey}]
  419. bind $canvas <Key> [namespace code {my KeyPress %A}]
  420. bind $canvas <Alt-Key> {# nothing}
  421. bind $canvas <Meta-Key> {# nothing}
  422. bind $canvas <Control-Key> {# nothing}
  423. bind $canvas <FocusIn> [namespace code {my FocusIn}]
  424. bind $canvas <FocusOut> [namespace code {my FocusOut}]
  425. return $w
  426. }
  427. # This procedure is invoked when the mouse leaves an entry window with
  428. # button 1 down. It scrolls the window up, down, left, or right,
  429. # depending on where the mouse left the window, and reschedules itself
  430. # as an "after" command so that the window continues to scroll until the
  431. # mouse moves back into the window or the mouse button is released.
  432. #
  433. method AutoScan {} {
  434. if {![winfo exists $w]} return
  435. set x $oldX
  436. set y $oldY
  437. if {$noScroll} {
  438. return
  439. }
  440. if {$x >= [winfo width $canvas]} {
  441. $canvas xview scroll 1 units
  442. } elseif {$x < 0} {
  443. $canvas xview scroll -1 units
  444. } elseif {$y >= [winfo height $canvas]} {
  445. # do nothing
  446. } elseif {$y < 0} {
  447. # do nothing
  448. } else {
  449. return
  450. }
  451. my Motion1 $x $y
  452. set ::tk::Priv(afterId) [after 50 [namespace code {my AutoScan}]]
  453. }
  454. # ----------------------------------------------------------------------
  455. # Event handlers
  456. method MouseWheel {amount} {
  457. if {$noScroll || $::tk_strictMotif} {
  458. return
  459. }
  460. if {$amount > 0} {
  461. $canvas xview scroll [expr {(-119-$amount) / 120}] units
  462. } else {
  463. $canvas xview scroll [expr {-($amount / 120)}] units
  464. }
  465. }
  466. method Btn1 {x y} {
  467. focus $canvas
  468. set i [$w index @$x,$y]
  469. if {$i eq ""} {
  470. return
  471. }
  472. $w selection clear 0 end
  473. $w selection set $i
  474. $w selection anchor $i
  475. }
  476. method CtrlBtn1 {x y} {
  477. if {$options(-multiple)} {
  478. focus $canvas
  479. set i [$w index @$x,$y]
  480. if {$i eq ""} {
  481. return
  482. }
  483. if {[$w selection includes $i]} {
  484. $w selection clear $i
  485. } else {
  486. $w selection set $i
  487. $w selection anchor $i
  488. }
  489. }
  490. }
  491. method ShiftBtn1 {x y} {
  492. if {$options(-multiple)} {
  493. focus $canvas
  494. set i [$w index @$x,$y]
  495. if {$i eq ""} {
  496. return
  497. }
  498. if {[$w index anchor] eq ""} {
  499. $w selection anchor $i
  500. }
  501. $w selection clear 0 end
  502. $w selection set anchor $i
  503. }
  504. }
  505. # Gets called on button-1 motions
  506. #
  507. method Motion1 {x y} {
  508. set oldX $x
  509. set oldY $y
  510. set i [$w index @$x,$y]
  511. if {$i eq ""} {
  512. return
  513. }
  514. $w selection clear 0 end
  515. $w selection set $i
  516. }
  517. method ShiftMotion1 {x y} {
  518. set oldX $x
  519. set oldY $y
  520. set i [$w index @$x,$y]
  521. if {$i eq ""} {
  522. return
  523. }
  524. $w selection clear 0 end
  525. $w selection set anchor $i
  526. }
  527. method Double1 {x y} {
  528. if {[llength $selection]} {
  529. $w invoke
  530. }
  531. }
  532. method ReturnKey {} {
  533. $w invoke
  534. }
  535. method Leave1 {x y} {
  536. set oldX $x
  537. set oldY $y
  538. my AutoScan
  539. }
  540. method FocusIn {} {
  541. $w state focus
  542. if {![info exists list]} {
  543. return
  544. }
  545. if {[llength $selection]} {
  546. my DrawSelection
  547. }
  548. }
  549. method FocusOut {} {
  550. $w state !focus
  551. $w selection clear 0 end
  552. }
  553. # Moves the active element up or down by one element
  554. #
  555. # Arguments:
  556. # amount - +1 to move down one item, -1 to move back one item.
  557. #
  558. method UpDown amount {
  559. if {![info exists list]} {
  560. return
  561. }
  562. set curr [$w selection get]
  563. if {[llength $curr] == 0} {
  564. set i 0
  565. } else {
  566. set i [$w index anchor]
  567. if {$i eq ""} {
  568. return
  569. }
  570. incr i $amount
  571. }
  572. $w selection clear 0 end
  573. $w selection set $i
  574. $w selection anchor $i
  575. $w see $i
  576. }
  577. # Moves the active element left or right by one column
  578. #
  579. # Arguments:
  580. # amount - +1 to move right one column, -1 to move left one
  581. # column
  582. #
  583. method LeftRight amount {
  584. if {![info exists list]} {
  585. return
  586. }
  587. set curr [$w selection get]
  588. if {[llength $curr] == 0} {
  589. set i 0
  590. } else {
  591. set i [$w index anchor]
  592. if {$i eq ""} {
  593. return
  594. }
  595. incr i [expr {$amount * $itemsPerColumn}]
  596. }
  597. $w selection clear 0 end
  598. $w selection set $i
  599. $w selection anchor $i
  600. $w see $i
  601. }
  602. # Gets called when user enters an arbitrary key in the listbox.
  603. #
  604. method KeyPress key {
  605. append accel $key
  606. my Goto $accel
  607. after cancel $accelCB
  608. set accelCB [after 500 [namespace code {my Reset}]]
  609. }
  610. method Goto text {
  611. if {![info exists list]} {
  612. return
  613. }
  614. if {$text eq "" || $numItems == 0} {
  615. return
  616. }
  617. if {[llength [$w selection get]]} {
  618. set start [$w index anchor]
  619. } else {
  620. set start 0
  621. }
  622. set theIndex -1
  623. set less 0
  624. set len [string length $text]
  625. set len0 [expr {$len - 1}]
  626. set i $start
  627. # Search forward until we find a filename whose prefix is a
  628. # case-insensitive match with $text
  629. while {1} {
  630. if {[string equal -nocase -length $len0 $textList($i) $text]} {
  631. set theIndex $i
  632. break
  633. }
  634. incr i
  635. if {$i == $numItems} {
  636. set i 0
  637. }
  638. if {$i == $start} {
  639. break
  640. }
  641. }
  642. if {$theIndex >= 0} {
  643. $w selection clear 0 end
  644. $w selection set $theIndex
  645. $w selection anchor $theIndex
  646. $w see $theIndex
  647. }
  648. }
  649. method Reset {} {
  650. unset -nocomplain accel
  651. }
  652. }
  653. return
  654. # Local Variables:
  655. # mode: tcl
  656. # fill-column: 78
  657. # End:
上海开阖软件有限公司 沪ICP备12045867号-1