home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / combobox.itk < prev    next >
Text File  |  2003-09-01  |  46KB  |  1,444 lines

  1. # Combobox
  2. # ----------------------------------------------------------------------
  3. # Implements a Combobox widget. A Combobox has 2 basic styles: simple and
  4. # dropdown. Dropdowns display an entry field with an arrow button to the 
  5. # right of it. When the arrow button is pressed a selectable list of
  6. # items is popped up. A simple Combobox displays an entry field and a listbox 
  7. # just beneath it which is always displayed. In both types, if the user 
  8. # selects an item in the listbox, the contents of the entry field are 
  9. # replaced with the text from the selected item. If the Combobox is 
  10. # editable, the user can type in the entry field and when <Return> is
  11. # pressed the item will be inserted into the list.
  12. #
  13. # WISH LIST:
  14. #    This section lists possible future enhancements.  
  15. #
  16. #      Combobox 1.x:
  17. #          - convert bindings to bindtags.
  18. #
  19. # ----------------------------------------------------------------------
  20. #  ORIGINAL AUTHOR: John S. Sigler
  21. # ----------------------------------------------------------------------
  22. #  CURRENT MAINTAINER: Chad Smith    EMAIL: csmith@adc.com, itclguy@yahoo.com
  23. #
  24. #                    Copyright (c) 1995    John S. Sigler
  25. #                    Copyright (c) 1997    Mitch Gorman
  26. # ======================================================================
  27. # Permission is hereby granted, without written agreement and without
  28. # license or royalty fees, to use, copy, modify, and distribute this
  29. # software and its documentation for any purpose, provided that the
  30. # above copyright notice and the following two paragraphs appear in
  31. # all copies of this software.
  32. # IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  33. # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 
  34. # ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 
  35. # IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
  36. # DAMAGE.
  37. #
  38. # THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 
  39. # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  40. # FITNESS FOR A PARTICULAR PURPOSE.     THE SOFTWARE PROVIDED HEREUNDER IS
  41. # ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  42. # PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  43. # ======================================================================
  44.  
  45. #
  46. # Default resources.
  47. #
  48. option add *Combobox.borderWidth 2 widgetDefault
  49. option add *Combobox.labelPos wn widgetDefault
  50. option add *Combobox.listHeight 150 widgetDefault
  51. option add *Combobox.hscrollMode dynamic widgetDefault
  52. option add *Combobox.vscrollMode dynamic widgetDefault
  53.  
  54. #
  55. # Usual options.
  56. #
  57. itk::usual Combobox {
  58.     keep -background -borderwidth -cursor -foreground -highlightcolor \
  59.     -highlightthickness -insertbackground -insertborderwidth \
  60.     -insertofftime -insertontime -insertwidth -labelfont -popupcursor \
  61.     -selectbackground -selectborderwidth -selectforeground \
  62.     -textbackground -textfont
  63. }
  64.  
  65. # ------------------------------------------------------------------
  66. #                             COMBOBOX
  67. # ------------------------------------------------------------------
  68. itcl::class iwidgets::Combobox {
  69.     inherit iwidgets::Entryfield
  70.     
  71.     constructor {args} {}
  72.     destructor {}
  73.  
  74.     itk_option define -arrowrelief arrowRelief Relief raised
  75.     itk_option define -completion completion Completion true
  76.     itk_option define -dropdown dropdown Dropdown true
  77.     itk_option define -editable editable Editable true
  78.     itk_option define -grab grab Grab local
  79.     itk_option define -listheight listHeight Height 150
  80.     itk_option define -margin margin Margin 1
  81.     itk_option define -popupcursor popupCursor Cursor arrow
  82.     itk_option define -selectioncommand selectionCommand SelectionCommand {}
  83.     itk_option define -state state State normal
  84.     itk_option define -unique unique Unique true
  85.  
  86.     public method clear {{component all}}
  87.     public method curselection {}
  88.     public method delete {component first {last {}}}
  89.     public method get {{index {}}}
  90.     public method getcurselection {}
  91.     public method insert {component index args}
  92.     public method invoke {}
  93.     public method justify {direction}
  94.     public method see {index}
  95.     public method selection {option first {last {}}}
  96.     public method size {}
  97.     public method sort {{mode ascending}}
  98.     public method xview {args}
  99.     public method yview {args}
  100.  
  101.     protected method _addToList {}
  102.     protected method _createComponents {}
  103.     protected method _deleteList {first {last {}}}
  104.     protected method _deleteText {first {last {}}}
  105.     protected method _doLayout {{when later}}
  106.     protected method _drawArrow {}
  107.     protected method _dropdownBtnRelease {{window {}} {x 1} {y 1}}
  108.     protected method _ignoreNextBtnRelease {ignore}
  109.     protected method _next {}
  110.     protected method _packComponents {{when later}}
  111.     protected method _positionList {}
  112.     protected method _postList {}
  113.     protected method _previous {}
  114.     protected method _resizeArrow {}
  115.     protected method _selectCmd {}
  116.     protected method _toggleList {}
  117.     protected method _unpostList {}
  118.     protected method _commonBindings {}
  119.     protected method _dropdownBindings {}
  120.     protected method _simpleBindings {}
  121.     protected method _listShowing {{val ""}}
  122.  
  123.     private method _bs {}
  124.     private method _lookup {key}
  125.     private method _slbListbox {}
  126.     private method _stateSelect {}
  127.  
  128.     private variable _doit 0;
  129.     private variable _inbs 0;
  130.     private variable _inlookup 0;
  131.     private variable _currItem {};             ;# current selected item.
  132.     private variable _ignoreRelease false     ;# next button release ignored.
  133.     private variable _isPosted false;         ;# is the dropdown popped up.
  134.     private variable _repacking {}      ;# non-null => _packComponents pending.
  135.     private variable _grab                ;# used to restore grabs
  136.     private variable _next_prevFLAG 0 ;# Used in _lookup to fix SF Bug 501300
  137.     private common _listShowing
  138.     private common count 0
  139. }     
  140.  
  141. #
  142. # Provide a lowercase access method for the Combobox class.
  143. proc ::iwidgets::combobox {pathName args} {
  144.     uplevel ::iwidgets::Combobox $pathName $args
  145. }
  146.  
  147. # ------------------------------------------------------------------
  148. #                        CONSTRUCTOR
  149. # ------------------------------------------------------------------
  150. itcl::body iwidgets::Combobox::constructor {args} {
  151.     set _listShowing($this) 0
  152.     set _grab(window) ""
  153.     set _grab(status) ""
  154.  
  155.     # combobox is different as all components are created 
  156.     # after determining what the dropdown style is...
  157.  
  158.     # configure args
  159.     eval itk_initialize $args
  160.     
  161.     # create components that are dependent on options 
  162.     # (Scrolledlistbox, arrow button) and pack them.
  163.     if {$count == 0} {
  164.     image create bitmap downarrow -data {
  165.         #define down_width 16
  166.         #define down_height 16
  167.         static unsigned char down_bits[] = {
  168.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  169.         0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0xf8, 0x3f, 
  170.         0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 
  171.         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  172.         };
  173.     }
  174.     image create bitmap uparrow -data {
  175.         #define up_width 16
  176.         #define up_height 16
  177.         static unsigned char up_bits[] = {
  178.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 
  179.         0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 
  180.         0xfc, 0x1f, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x00,
  181.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  182.         };
  183.     }
  184.     }
  185.     incr count
  186.     _doLayout
  187. }
  188.  
  189. # ------------------------------------------------------------------
  190. #                           DESTRUCTOR
  191. # ------------------------------------------------------------------
  192. itcl::body iwidgets::Combobox::destructor {} {
  193.     # catch any repacking that may be waiting for idle time
  194.     if {$_repacking != ""} {
  195.     after cancel $_repacking
  196.     }
  197.     incr count -1
  198.     if {$count == 0} {
  199.     image delete uparrow
  200.     image delete downarrow
  201.     }
  202. }
  203.  
  204. # ================================================================
  205. #                            OPTIONS
  206. # ================================================================
  207.  
  208. # --------------------------------------------------------------------
  209. # OPTION:  -arrowrelief
  210. #
  211. # Relief style used on the arrow button.
  212. # --------------------------------------------------------------------
  213. itcl::configbody iwidgets::Combobox::arrowrelief {}
  214.  
  215. # --------------------------------------------------------------------
  216. # OPTION:  -completion
  217. #
  218. # Relief style used on the arrow button.
  219. # --------------------------------------------------------------------
  220. itcl::configbody iwidgets::Combobox::completion {
  221.     switch -- $itk_option(-completion) {
  222.     0 - no - false - off { }
  223.     1 - yes - true - on { }
  224.     default {
  225.         error "bad completion option \"$itk_option(-completion)\":\
  226.                        should be boolean"
  227.     }
  228.     }
  229. }
  230.  
  231. # --------------------------------------------------------------------
  232. # OPTION:  -dropdown  
  233. #
  234. # Boolean which determines the Combobox style: dropdown or simple.
  235. # Because the two style's lists reside in different toplevel widgets
  236. # this is more complicated than it should be.
  237. # --------------------------------------------------------------------
  238. itcl::configbody iwidgets::Combobox::dropdown {
  239.     switch -- $itk_option(-dropdown) {
  240.     1 - yes - true - on {
  241.         if {[winfo exists $itk_interior.list]} {
  242.         set vals [$itk_component(list) get 0 end]
  243.         destroy $itk_component(list)
  244.         _doLayout
  245.         if [llength $vals] {
  246.             eval insert list end $vals
  247.         }
  248.         }
  249.     }
  250.     0 - no - false - off {
  251.         if {[winfo exists $itk_interior.popup.list]} {
  252.         set vals [$itk_component(list) get 0 end]
  253.         catch {destroy $itk_component(arrowBtn)}
  254.         destroy $itk_component(popup)  ;# this deletes the list too
  255.         _doLayout
  256.         if [llength $vals] {
  257.             eval insert list end $vals
  258.         }
  259.         }
  260.     }
  261.     default {
  262.         error "bad dropdown option \"$itk_option(-dropdown)\":\
  263.                        should be boolean"
  264.     }
  265.     }
  266. }
  267.  
  268. # --------------------------------------------------------------------
  269. # OPTION: -editable     
  270. #
  271. # Boolean which allows/disallows user input to the entry field area.
  272. # --------------------------------------------------------------------
  273. itcl::configbody iwidgets::Combobox::editable {
  274.     switch -- $itk_option(-editable) {
  275.     1 - true - yes - on {
  276.         switch -- $itk_option(-state) {
  277.         normal {
  278.             $itk_component(entry) configure -state normal
  279.         }
  280.         }
  281.     }
  282.     0 - false - no - off {
  283.         $itk_component(entry) configure -state disabled
  284.     }
  285.     default {
  286.         error "bad editable option \"$itk_option(-editable)\":\
  287.                    should be boolean"
  288.     }
  289.     }
  290. }
  291.  
  292. # --------------------------------------------------------------------
  293. # OPTION:  -grab
  294. #
  295. # grab-state of megawidget
  296. # --------------------------------------------------------------------
  297. itcl::configbody iwidgets::Combobox::grab {
  298.     switch -- $itk_option(-grab) {
  299.     local { }
  300.     global { }
  301.     default {
  302.         error "bad grab value \"$itk_option(-grab)\":\
  303.                    must be global or local"
  304.     }
  305.     }
  306. }
  307.  
  308. # --------------------------------------------------------------------
  309. # OPTION: -listheight  
  310. #
  311. # Listbox height in pixels. (Need to integrate the scrolledlistbox
  312. # -visibleitems option here - at least for simple listbox.)
  313. # --------------------------------------------------------------------
  314. itcl::configbody iwidgets::Combobox::listheight {}
  315.  
  316. # --------------------------------------------------------------------
  317. # OPTION:  -margin
  318. #
  319. # Spacer between the entry field and arrow button of dropdown style
  320. # Comboboxes.
  321. # --------------------------------------------------------------------
  322. itcl::configbody iwidgets::Combobox::margin {
  323.     grid columnconfigure $itk_interior 0 -minsize $itk_option(-margin)
  324. }
  325.  
  326. # --------------------------------------------------------------------
  327. # OPTION:  -popupcursor
  328. #
  329. # Set the cursor for the popup list.
  330. # --------------------------------------------------------------------
  331. itcl::configbody iwidgets::Combobox::popupcursor {}
  332.  
  333. # --------------------------------------------------------------------
  334. # OPTION:  -selectioncommand
  335. #
  336. # Defines the proc to be called when an item is selected in the list.
  337. # --------------------------------------------------------------------
  338. itcl::configbody iwidgets::Combobox::selectioncommand {}
  339.  
  340. # --------------------------------------------------------------------
  341. # OPTION:  -state
  342. #
  343. # overall state of megawidget
  344. # --------------------------------------------------------------------
  345. itcl::configbody iwidgets::Combobox::state {
  346.     switch -- $itk_option(-state) {
  347.     disabled {
  348.         $itk_component(entry) configure -state disabled
  349.     }
  350.     normal {
  351.         switch -- $itk_option(-editable) {
  352.         1 - true - yes - on {
  353.             $itk_component(entry) configure -state normal
  354.         }
  355.         0 - false - no - off {
  356.             $itk_component(entry) configure -state disabled
  357.         }
  358.         }
  359.     }
  360.     readonly {
  361.       $itk_component(entry) configure -state readonly
  362.     }
  363.     default {
  364.         error "bad state value \"$itk_option(-state)\":\
  365.                    must be normal  or disabled"
  366.     }
  367.     }
  368.     if {[info exists itk_component(arrowBtn)]} {
  369.     $itk_component(arrowBtn) configure -state $itk_option(-state)
  370.     }
  371. }
  372.  
  373. # --------------------------------------------------------------------
  374. # OPTION: -unique  
  375. #
  376. # Boolean which disallows/allows adding duplicate items to the listbox.
  377. # --------------------------------------------------------------------
  378. itcl::configbody iwidgets::Combobox::unique {
  379.     # boolean error check
  380.     switch -- $itk_option(-unique) {
  381.     1 - true - yes - on { }
  382.     0 - false - no - off { }
  383.     default {
  384.         error "bad unique value \"$itk_option(-unique)\":\
  385.                    should be boolean"
  386.     }
  387.     }
  388. }
  389.  
  390. # =================================================================
  391. #                             METHODS
  392. # =================================================================
  393.  
  394. # ------------------------------------------------------
  395. #  PUBLIC METHOD: clear ?component?
  396. #
  397. #  Remove all elements from the listbox, all contents
  398. #  from the entry component, or both (if all).
  399. #
  400. # ------------------------------------------------------
  401. itcl::body iwidgets::Combobox::clear {{component all}} {
  402.     switch -- $component {
  403.     entry {
  404.         iwidgets::Entryfield::clear
  405.     }
  406.     list {
  407.         delete list 0 end
  408.     }
  409.     all {
  410.         delete list 0 end
  411.         iwidgets::Entryfield::clear
  412.     }
  413.     default {
  414.         error "bad Combobox component \"$component\":\
  415.                    must be entry, list, or all."
  416.     }
  417.     }
  418.     return
  419. }
  420.  
  421. # ------------------------------------------------------
  422. # PUBLIC METHOD: curselection
  423. #
  424. # Return the current selection index.
  425. #
  426. # ------------------------------------------------------
  427. itcl::body iwidgets::Combobox::curselection {} {
  428.     return [$itk_component(list) curselection]
  429. }
  430.  
  431. # ------------------------------------------------------
  432. # PUBLIC METHOD: delete component first ?last?
  433. #
  434. # Delete an item or items from the listbox OR delete
  435. # text from the entry field. First argument determines
  436. # which component deletion occurs in - valid values are
  437. # entry or list.
  438. #
  439. # ------------------------------------------------------
  440. itcl::body iwidgets::Combobox::delete {component first {last {}}} {
  441.     switch -- $component {
  442.     entry {
  443.         if {$last == {}} {
  444.           set last [expr {$first + 1}]
  445.         }
  446.         iwidgets::Entryfield::delete $first $last
  447.     }
  448.     list {
  449.         _deleteList $first $last
  450.     }
  451.     default {
  452.         error "bad Combobox component \"$component\":\
  453.                    must be entry or list."
  454.     }
  455.     }
  456. }
  457.  
  458. # ------------------------------------------------------
  459. # PUBLIC METHOD: get ?index?
  460. #
  461. #
  462. # Retrieve entry contents if no args OR use args as list 
  463. # index and retrieve list item at index .
  464. #
  465. # ------------------------------------------------------
  466. itcl::body iwidgets::Combobox::get {{index {}}} {
  467.     # no args means to get the current text in the entry field area
  468.     if {$index == {}} {
  469.     iwidgets::Entryfield::get
  470.     } else {
  471.     eval $itk_component(list) get $index
  472.     }
  473. }
  474.  
  475. # ------------------------------------------------------
  476. # PUBLIC METHOD: getcurselection
  477. #
  478. # Return currently selected item in the listbox. Shortcut
  479. # version of get curselection command combination.
  480. #
  481. # ------------------------------------------------------
  482. itcl::body iwidgets::Combobox::getcurselection {} {
  483.     return [$itk_component(list) getcurselection]
  484. }
  485.  
  486. # ------------------------------------------------------------------
  487. # PUBLIC METHOD: invoke
  488. #
  489. # Pops up or down a dropdown combobox.
  490. # ------------------------------------------------------------------
  491. itcl::body iwidgets::Combobox::invoke {} {
  492.     if {$itk_option(-dropdown)} {
  493.     return [_toggleList]
  494.     }
  495.     return 
  496. }
  497.  
  498. # ------------------------------------------------------------
  499. # PUBLIC METHOD: insert comonent index string ?string ...?
  500. #
  501. # Insert an item into the listbox OR text into the entry area.
  502. # Valid component names are entry or list.
  503. #
  504. # ------------------------------------------------------------
  505. itcl::body iwidgets::Combobox::insert {component index args} {
  506.     set nargs [llength $args]
  507.  
  508.     if {$nargs == 0} {
  509.     error "no value given for parameter \"string\" in function\
  510.                \"Combobox::insert\""
  511.     } 
  512.  
  513.     switch -- $component {
  514.     entry {
  515.         if { $nargs > 1} {
  516.         error "called function \"Combobox::insert entry\"\
  517.                        with too many arguments"
  518.         } else {
  519.         if {$itk_option(-state) == "normal"} {
  520.             eval iwidgets::Entryfield::insert $index $args
  521.             [itcl::code $this _lookup ""]
  522.         }
  523.         }
  524.     }
  525.     list {
  526.         if {$itk_option(-state) == "normal"} {
  527.         eval $itk_component(list) insert $index $args
  528.         }
  529.     }
  530.     default {
  531.         error "bad Combobox component \"$component\": must\
  532.                    be entry or list."
  533.     }
  534.     }
  535. }
  536.  
  537. # ------------------------------------------------------
  538. # PUBLIC METHOD: justify direction
  539. #
  540. # Wrapper for justifying the listbox items in one of
  541. # 4 directions:     top, bottom, left, or right.
  542. #
  543. # ------------------------------------------------------
  544. itcl::body iwidgets::Combobox::justify {direction} {
  545.     return [$itk_component(list) justify $direction]
  546. }
  547.  
  548. # ------------------------------------------------------------------
  549. # PUBLIC METHOD: see index
  550. #
  551. # Adjusts the view such that the element given by index is visible.
  552. # ------------------------------------------------------------------
  553. itcl::body iwidgets::Combobox::see {index} {
  554.     return [$itk_component(list) see $index]
  555. }
  556.  
  557. # ------------------------------------------------------------------
  558. # PUBLIC METHOD: selection option first ?last?
  559. #
  560. # Adjusts the selection within the listbox and changes the contents
  561. # of the entry component to be the value of the selected list item.
  562. # ------------------------------------------------------------------
  563. itcl::body iwidgets::Combobox::selection {option first {last {}}} {
  564.     # thin wrap
  565.     if {$option == "set"} {
  566.     $itk_component(list) selection clear 0 end
  567.     $itk_component(list) selection set $first
  568.     set rtn ""
  569.     } else {
  570.     set rtn [eval $itk_component(list) selection $option $first $last]
  571.     }
  572.     set _currItem $first
  573.  
  574.     # combobox additions
  575.     set theText [getcurselection]
  576.     if {$theText != [$itk_component(entry) get]} {
  577.     clear entry
  578.     if {$theText != ""} {
  579.         insert entry 0 $theText
  580.     }
  581.     }
  582.     return $rtn
  583. }
  584.  
  585. # ------------------------------------------------------------------
  586. # PUBLIC METHOD: size 
  587. #
  588. # Returns a decimal string indicating the total number of elements 
  589. # in the listbox.
  590. # ------------------------------------------------------------------
  591. itcl::body iwidgets::Combobox::size {} {
  592.     return [$itk_component(list) size]
  593. }
  594.  
  595. # ------------------------------------------------------
  596. # PUBLIC METHOD: sort ?mode?
  597. #
  598. # Sort the current list in either "ascending" or "descending" order.
  599. #
  600. #    jss: how should i handle selected items?
  601. #
  602. # ------------------------------------------------------
  603. itcl::body iwidgets::Combobox::sort {{mode ascending}} {
  604.     $itk_component(list) sort $mode
  605.     #     return [$itk_component(list) sort $mode]
  606. }
  607.  
  608.  
  609. # ------------------------------------------------------------------
  610. # PUBLIC METHOD: xview ?arg arg ...?
  611. #
  612. # Change or query the vertical position of the text in the list box.
  613. # ------------------------------------------------------------------
  614. itcl::body iwidgets::Combobox::xview {args} {
  615.     return [eval $itk_component(list) xview $args]
  616. }
  617.  
  618. # ------------------------------------------------------------------
  619. # PUBLIC METHOD: yview ?arg arg ...?
  620. #
  621. # Change or query the horizontal position of the text in the list box.
  622. # ------------------------------------------------------------------
  623. itcl::body iwidgets::Combobox::yview {args} {
  624.     return [eval $itk_component(list) yview $args]
  625. }
  626.  
  627. # ------------------------------------------------------
  628. # PROTECTED METHOD: _addToList
  629. #
  630. # Add the current item in the entry to the listbox.
  631. #
  632. # ------------------------------------------------------
  633. itcl::body iwidgets::Combobox::_addToList {} {
  634.     set input [get]
  635.     if {$input != ""} {
  636.     if {$itk_option(-unique)} {
  637.         # if item is already in list, select it and exit
  638.         set item [lsearch -exact [$itk_component(list) get 0 end] $input]
  639.         if {$item != -1} {
  640.         selection clear 0 end
  641.         if {$item != {}} {
  642.             selection set $item $item
  643.             set _currItem $item
  644.         }
  645.         return
  646.         }
  647.     }
  648.     # add the item to end of list
  649.     selection clear 0 end
  650.     insert list end $input
  651.     selection set end end
  652.     }
  653. }
  654.  
  655. # ------------------------------------------------------
  656. # PROTECTED METHOD:      _createComponents
  657. #
  658. # Create deferred combobox components and add bindings.
  659. #
  660. # ------------------------------------------------------
  661. itcl::body iwidgets::Combobox::_createComponents {} {
  662.     if {$itk_option(-dropdown)} {
  663.     # --- build a dropdown combobox ---
  664.  
  665.     # make the arrow childsite be on the right hand side
  666.  
  667.       #-------------------------------------------------------------
  668.     # BUG FIX: csmith (Chad Smith: csmith@adc.com), 3/4/99
  669.       #-------------------------------------------------------------
  670.     # The following commented line of code overwrites the -command
  671.     # option when passed into the constructor.  The order of calls
  672.     # in the constructor is:
  673.     #     1) eval itk_initalize $args (initializes -command)
  674.     #       2) _doLayout
  675.     #       3) _createComponents (overwrites -command)
  676.     # The solution is to only set the -command option if it hasn't
  677.     # already been set.  The following 4 lines of code do this.
  678.       #-------------------------------------------------------------
  679.     # ** configure -childsitepos e -command [code $this _addToList]
  680.       #-------------------------------------------------------------
  681.     configure -childsitepos e
  682.     if ![llength [cget -command]] {
  683.       configure -command [itcl::code $this _addToList]
  684.     }
  685.     
  686.     # arrow button to popup the list
  687.     itk_component add arrowBtn {
  688.         button $itk_interior.arrowBtn -borderwidth 2 \
  689.         -width 15 -height 15 -image downarrow \
  690.         -command [itcl::code $this _toggleList] -state $itk_option(-state)
  691.     } {
  692.         keep -background -borderwidth -cursor  -state \
  693.         -highlightcolor -highlightthickness
  694.         rename -relief -arrowrelief arrowRelief Relief
  695.         rename -highlightbackground -background background Background
  696.     }
  697.     
  698.     # popup list container
  699.     itk_component add popup {
  700.         toplevel $itk_interior.popup
  701.     } {
  702.         keep -background -cursor
  703.     }
  704.     wm withdraw $itk_interior.popup
  705.     
  706.     # the listbox
  707.     itk_component add list {
  708.         iwidgets::Scrolledlistbox $itk_interior.popup.list -exportselection no \
  709.         -vscrollmode dynamic -hscrollmode dynamic -selectmode browse
  710.     } {
  711.         keep -background -borderwidth -cursor -foreground \
  712.         -highlightcolor -highlightthickness \
  713.         -hscrollmode -selectbackground \
  714.         -selectborderwidth -selectforeground -textbackground \
  715.         -textfont -vscrollmode
  716.         rename -height -listheight listHeight Height
  717.         rename -cursor -popupcursor popupCursor Cursor
  718.     }
  719.     # mode specific bindings
  720.     _dropdownBindings
  721.  
  722.     # Ugly hack to avoid tk buglet revealed in _dropdownBtnRelease where 
  723.     # relief is used but not set in scrollbar.tcl. 
  724.     global tkPriv
  725.     set tkPriv(relief) raise
  726.  
  727.     } else {
  728.     # --- build a simple combobox ---
  729.     configure -childsitepos s
  730.     itk_component add list {
  731.         iwidgets::Scrolledlistbox $itk_interior.list -exportselection no \
  732.         -vscrollmode dynamic -hscrollmode dynamic 
  733.     } {
  734.         keep -background -borderwidth -cursor -foreground \
  735.         -highlightcolor -highlightthickness \
  736.         -hscrollmode -selectbackground \
  737.         -selectborderwidth -selectforeground -textbackground \
  738.         -textfont -visibleitems -vscrollmode 
  739.         rename -height -listheight listHeight Height
  740.     }
  741.     # add mode specific bindings
  742.     _simpleBindings
  743.     }
  744.  
  745.     # popup cursor applies only to the list within the combobox
  746.     configure -popupcursor $itk_option(-popupcursor)
  747.  
  748.     # add mode independent bindings
  749.     _commonBindings
  750. }
  751.  
  752. # ------------------------------------------------------
  753. # PROTECTED METHOD: _deleteList first ?last?
  754. #
  755. # Delete an item or items from the listbox. Called via 
  756. # "delete list args".
  757. #
  758. # ------------------------------------------------------
  759. itcl::body iwidgets::Combobox::_deleteList {first {last {}}} {
  760.  
  761.     if {$last == {}} {
  762.     set last $first
  763.     }
  764.     $itk_component(list) delete $first $last
  765.  
  766.     # remove the item if it is no longer in the list
  767.     set text [$this get]
  768.     if {$text != ""} {
  769.     set index [lsearch -exact [$itk_component(list) get 0 end] $text ]
  770.     if {$index == -1} {
  771.         clear entry
  772.     }
  773.     }
  774.     return
  775. }
  776.  
  777. # ------------------------------------------------------
  778. # PROTECTED METHOD: _deleteText first ?last?
  779. #
  780. # Renamed Entryfield delete method. Called via "delete entry args".
  781. #
  782. # ------------------------------------------------------
  783. itcl::body iwidgets::Combobox::_deleteText {first {last {}}} {
  784.     $itk_component(entry) configure -state normal 
  785.     set rtrn [delete $first $last]
  786.     switch -- $itk_option(-editable) {
  787.     0 - false - no - off {
  788.         $itk_component(entry) configure -state disabled
  789.     }
  790.     }
  791.     return $rtrn
  792. }
  793.  
  794. # ------------------------------------------------------
  795. # PROTECTED METHOD:      _doLayout ?when?
  796. #
  797. # Call methods to create and pack the Combobox components.
  798. #
  799. # ------------------------------------------------------
  800. itcl::body iwidgets::Combobox::_doLayout {{when later}} {
  801.     _createComponents
  802.     _packComponents $when
  803. }
  804.  
  805.  
  806. # ------------------------------------------------------
  807. # PROTECTED METHOD:      _drawArrow 
  808. #
  809. # Draw the arrow button. Determines packing according to
  810. # -labelpos.
  811. #
  812. # ------------------------------------------------------
  813. itcl::body iwidgets::Combobox::_drawArrow {} {
  814.     set flip false
  815.     set relief ""
  816.     set fg [cget -foreground]
  817.     if {$_isPosted} {
  818.     set flip true
  819.     set relief "-relief sunken"
  820.     } else {
  821.     set relief "-relief $itk_option(-arrowrelief)"
  822.     }
  823.  
  824.     if {$flip} {
  825.     #     
  826.     #                draw up arrow
  827.     #
  828.     eval $itk_component(arrowBtn) configure -image uparrow $relief
  829.     } else {
  830.     #     
  831.     #                draw down arrow
  832.     #
  833.     eval $itk_component(arrowBtn) configure -image downarrow $relief
  834.     }
  835. }
  836.  
  837. # ------------------------------------------------------
  838. # PROTECTED METHOD: _dropdownBtnRelease window x y
  839. #
  840. # Event handler for button releases while a dropdown list
  841. # is posted.
  842. #
  843. # ------------------------------------------------------
  844. itcl::body iwidgets::Combobox::_dropdownBtnRelease {{window {}} {x 1} {y 1}} {
  845.  
  846.     # if it's a scrollbar then ignore the release
  847.     if {($window == [$itk_component(list) component vertsb]) ||
  848.     ($window == [$itk_component(list) component horizsb])} {
  849.     return
  850.     }
  851.  
  852.     # 1st release allows list to stay up unless we are in listbox
  853.     if {$_ignoreRelease} {
  854.     _ignoreNextBtnRelease false
  855.     return
  856.     }
  857.     
  858.     # should I use just the listbox or also include the scrollbars
  859.     if { ($x >= 0) && ($x < [winfo width [_slbListbox]])
  860.      && ($y >= 0) && ($y < [winfo height [_slbListbox]])} {
  861.     _stateSelect
  862.     }
  863.     
  864.     _unpostList
  865.  
  866.     # execute user command
  867.     if {$itk_option(-selectioncommand) != ""} {
  868.     uplevel #0 $itk_option(-selectioncommand)
  869.     }
  870. }
  871.  
  872. # ------------------------------------------------------
  873. # PROTECTED METHOD: _ignoreNextBtnRelease ignore
  874. #
  875. # Set private variable _ignoreRelease. If this variable
  876. # is true then the next button release will not remove
  877. # a dropdown list.
  878. #
  879. # ------------------------------------------------------
  880. itcl::body iwidgets::Combobox::_ignoreNextBtnRelease {ignore} {
  881.     set _ignoreRelease $ignore
  882. }
  883.  
  884. # ------------------------------------------------------
  885. # PROTECTED METHOD:      _next
  886. #
  887. # Select the next item in the list.
  888. #
  889. # ------------------------------------------------------
  890. itcl::body iwidgets::Combobox::_next {} {
  891.  
  892.     set _next_prevFLAG 1
  893.  
  894.     if {[size] <= 1} {
  895.     return
  896.     }
  897.     set i [curselection]
  898.     if {($i == {}) || ($i == ([size]-1)) } {
  899.     set i 0
  900.     } else {
  901.     incr i
  902.     }
  903.     selection clear 0 end
  904.     selection set $i $i
  905.     see $i
  906.     set _currItem $i
  907. }
  908.  
  909. # ------------------------------------------------------
  910. # PROTECTED METHOD:      _packComponents ?when?
  911. #
  912. # Pack the components of the combobox and add bindings.
  913. #
  914. # ------------------------------------------------------
  915. itcl::body iwidgets::Combobox::_packComponents {{when later}} {
  916.     if {$when == "later"} {
  917.     if {$_repacking == ""} {
  918.         set _repacking [after idle [itcl::code $this _packComponents now]]
  919.         return
  920.     }
  921.     } elseif {$when != "now"} {
  922.     error "bad option \"$when\": should be now or later"
  923.     }
  924.  
  925.     if {$itk_option(-dropdown)} {
  926.     grid configure $itk_component(list) -row 1 -column 0 -sticky news
  927.     _resizeArrow
  928.         grid config $itk_component(arrowBtn) -row 0 -column 1 -sticky nsew
  929.     } else {
  930.     # size and pack list hack
  931.     grid configure $itk_component(entry) -row 0 -column 0 -sticky ew
  932.     grid configure $itk_component(efchildsite) -row 1 -column 0 -sticky nsew
  933.     grid configure $itk_component(list) -row 0 -column 0 -sticky nsew
  934.  
  935.     grid rowconfigure $itk_component(efchildsite) 1 -weight 1
  936.     grid columnconfigure $itk_component(efchildsite) 0 -weight 1
  937.     }
  938.     set _repacking ""
  939. }
  940.  
  941. # ------------------------------------------------------
  942. # PROTECTED METHOD:      _positionList
  943. #
  944. # Determine the position (geometry) for the popped up list
  945. # and map it to the screen.
  946. #
  947. # ------------------------------------------------------
  948. itcl::body iwidgets::Combobox::_positionList {} {
  949.  
  950.     set x [winfo rootx $itk_component(entry) ]
  951.     set y [expr {[winfo rooty $itk_component(entry) ] + \
  952.            [winfo height $itk_component(entry) ]}]
  953.     set w [winfo width $itk_component(entry) ]
  954.     set h [winfo height [_slbListbox] ]
  955.     set sh [winfo screenheight .]
  956.  
  957.     if {(($y+$h) > $sh) && ($y > ($sh/2))} {
  958.     set y [expr {[winfo rooty $itk_component(entry) ] - $h}]
  959.     }
  960.     
  961.     $itk_component(list) configure -width $w
  962.     wm overrideredirect $itk_component(popup) 0
  963.     wm geometry $itk_component(popup) +$x+$y
  964.     wm overrideredirect $itk_component(popup) 1
  965. }
  966.  
  967. # ------------------------------------------------------
  968. # PROTECTED METHOD:      _postList
  969. #
  970. # Pop up the list in a dropdown style Combobox.
  971. #
  972. # ------------------------------------------------------
  973. itcl::body iwidgets::Combobox::_postList {} {
  974.     if {[$itk_component(list) size] == ""} {
  975.     return
  976.     }
  977.  
  978.     set _isPosted true
  979.     _positionList
  980.  
  981.     # map window and do a grab
  982.     wm deiconify $itk_component(popup)
  983.     _listShowing -wait
  984.  
  985.     # Added by csmith, 12/19/00.  Thanks to Erik Leunissen for
  986.     # finding this problem.  We need to restore any previous
  987.     # grabs after the dropdown listbox is withdrawn.  To do this,
  988.     # save the currently grabbed window.  It is then restored in
  989.     # the _unpostList method.
  990.     set _grab(window) [::grab current]
  991.     if {$_grab(window) != ""} {
  992.       set _grab(status) [::grab status $_grab(window)]
  993.     }
  994.  
  995.     # Now grab the dropdown listbox.
  996.     if {$itk_option(-grab) == "global"} {
  997.     ::grab -global $itk_component(popup) 
  998.     } else {
  999.     ::grab $itk_component(popup) 
  1000.     }
  1001.     raise $itk_component(popup)
  1002.     focus $itk_component(popup)
  1003.     _drawArrow
  1004.  
  1005.     # Added by csmith, 10/26/00.  This binding keeps the listbox
  1006.     # from staying mapped if the window in which the combobox
  1007.     # is packed is iconified.
  1008.     bind $itk_component(entry) <Unmap> [itcl::code $this _unpostList]
  1009. }
  1010.  
  1011. # ------------------------------------------------------
  1012. # PROTECTED METHOD:       _previous
  1013. #
  1014. # Select the previous item in the list. Wraps at front
  1015. # and end of list. 
  1016. #
  1017. # ------------------------------------------------------
  1018. itcl::body iwidgets::Combobox::_previous {} {
  1019.  
  1020.     set _next_prevFLAG 1
  1021.  
  1022.     if {[size] <= 1} {
  1023.     return
  1024.     }
  1025.     set i [curselection]
  1026.     if {$i == "" || $i == 0} {
  1027.     set i [expr {[size] - 1}]
  1028.     } else {
  1029.     incr i -1
  1030.     }
  1031.     selection clear 0 end
  1032.     selection set $i $i
  1033.     see $i
  1034.     set _currItem $i
  1035. }
  1036.  
  1037. # ------------------------------------------------------
  1038. # PROTECTED METHOD:      _resizeArrow
  1039. #
  1040. # Recalculate the arrow button size and then redraw it.
  1041. #
  1042. # ------------------------------------------------------
  1043. itcl::body iwidgets::Combobox::_resizeArrow {} {
  1044.     set bw [expr {[$itk_component(arrowBtn) cget -borderwidth]+ \
  1045.         [$itk_component(arrowBtn) cget -highlightthickness]}]
  1046.     set newHeight [expr {[winfo reqheight $itk_component(entry)]-(2*$bw) - 2}]
  1047.     $itk_component(arrowBtn) configure -width $newHeight -height $newHeight
  1048.     _drawArrow
  1049. }
  1050.  
  1051. # ------------------------------------------------------
  1052. # PROTECTED METHOD:      _selectCmd
  1053. #
  1054. # Called when list item is selected to insert new text 
  1055. # in entry, and call user -command callback if defined.
  1056. #
  1057. # ------------------------------------------------------
  1058. itcl::body iwidgets::Combobox::_selectCmd {} {
  1059.     $itk_component(entry) configure -state normal
  1060.     
  1061.     set _currItem [$itk_component(list) curselection]
  1062.     set item [$itk_component(list) getcurselection]
  1063.     clear entry
  1064.     $itk_component(entry) insert 0 $item
  1065.     switch -- $itk_option(-editable) {
  1066.     0 - false - no - off {
  1067.         $itk_component(entry) configure -state disabled
  1068.     }
  1069.     }
  1070. }
  1071.  
  1072. # ------------------------------------------------------
  1073. # PROTECTED METHOD:     _toggleList
  1074. #
  1075. # Post or unpost the dropdown listbox (toggle).
  1076. #
  1077. # ------------------------------------------------------
  1078. itcl::body iwidgets::Combobox::_toggleList {} {
  1079.     if {[winfo ismapped $itk_component(popup)] } {
  1080.     _unpostList
  1081.     } else {
  1082.     _postList
  1083.     }
  1084. }
  1085.  
  1086. # ------------------------------------------------------
  1087. # PROTECTED METHOD:      _unpostList
  1088. #
  1089. # Unmap the listbox (pop it down).
  1090. #
  1091. # ------------------------------------------------------
  1092. itcl::body iwidgets::Combobox::_unpostList {} {
  1093.     # Determine if event occured in the scrolledlistbox and, if it did, 
  1094.     # don't unpost it. (A selection in the list unposts it correctly and 
  1095.     # in the scrollbar we don't want to unpost it.)
  1096.     set x [winfo x $itk_component(list)]
  1097.     set y [winfo y $itk_component(list)]
  1098.     set w [winfo width $itk_component(list)]
  1099.     set h [winfo height $itk_component(list)]
  1100.  
  1101.     wm withdraw $itk_component(popup)
  1102.     ::grab release $itk_component(popup)    
  1103.  
  1104.     # Added by csmith, 12/19/00.  Thanks to Erik Leunissen for finding
  1105.     # this problem.  We need to restore any previous grabs when the
  1106.     # dropdown listbox is unmapped.
  1107.     if {$_grab(window) != ""} {
  1108.       if {$_grab(status) == "global"} {
  1109.         ::grab -global $_grab(window)
  1110.       } else {
  1111.     ::grab $_grab(window)
  1112.       }
  1113.       set _grab(window) ""
  1114.       set _grab(status) ""
  1115.     }
  1116.  
  1117.     # Added by csmith, 10/26/00.  This binding resets the binding
  1118.     # created in _postList - see that method for further details.
  1119.     bind $itk_component(entry) <Unmap> {}
  1120.     
  1121.     set _isPosted false
  1122.     
  1123.     $itk_component(list) selection clear 0 end
  1124.     if {$_currItem != {}} {
  1125.     $itk_component(list) selection set $_currItem $_currItem
  1126.     $itk_component(list) activate $_currItem
  1127.     }
  1128.  
  1129.     switch -- $itk_option(-editable) {
  1130.     1 - true - yes - on {
  1131.         $itk_component(entry) configure -state normal
  1132.     }
  1133.     0 - false - no - off {
  1134.         $itk_component(entry) configure -state disabled
  1135.     }
  1136.     }
  1137.  
  1138.     _drawArrow
  1139.     update
  1140. }
  1141.  
  1142. # ------------------------------------------------------
  1143. # PROTECTED METHOD:      _commonBindings
  1144. #
  1145. # Bindings that are used by both simple and dropdown
  1146. # style Comboboxes.
  1147. #
  1148. # ------------------------------------------------------
  1149. itcl::body iwidgets::Combobox::_commonBindings {} {
  1150.     bind $itk_component(entry) <KeyPress-BackSpace> [itcl::code $this _bs]
  1151.     bind $itk_component(entry) <KeyRelease> [itcl::code $this _lookup %K]
  1152.     bind $itk_component(entry) <Down>       [itcl::code $this _next]
  1153.     bind $itk_component(entry) <Up>         [itcl::code $this _previous]
  1154.     bind $itk_component(entry) <Control-n>  [itcl::code $this _next]
  1155.     bind $itk_component(entry) <Control-p>  [itcl::code $this _previous]
  1156.     bind [_slbListbox]         <Control-n>  [itcl::code $this _next]
  1157.     bind [_slbListbox]         <Control-p>  [itcl::code $this _previous]
  1158. }
  1159.  
  1160.  
  1161. # ------------------------------------------------------
  1162. # PROTECTED METHOD: _dropdownBindings
  1163. #
  1164. # Bindings used only by the dropdown type Combobox.
  1165. #
  1166. # ------------------------------------------------------
  1167. itcl::body iwidgets::Combobox::_dropdownBindings {} {
  1168.     bind $itk_component(popup)  <Escape> [itcl::code $this _unpostList]
  1169.     bind $itk_component(popup)  <space>  \
  1170.     "[itcl::code $this _stateSelect]; [itcl::code $this _unpostList]"
  1171.     bind $itk_component(popup)  <Return> \
  1172.     "[itcl::code $this _stateSelect]; [itcl::code $this _unpostList]"
  1173.     bind $itk_component(popup)  <ButtonRelease-1> \
  1174.         [itcl::code $this _dropdownBtnRelease %W %x %y]
  1175.  
  1176.     bind $itk_component(list)  <Map> \
  1177.     [itcl::code $this _listShowing 1]
  1178.     bind $itk_component(list)  <Unmap> \
  1179.         [itcl::code $this _listShowing 0]
  1180.  
  1181.     # once in the listbox, we drop on the next release (unless in scrollbar)
  1182.     bind [_slbListbox]   <Enter>   \
  1183.     [itcl::code $this _ignoreNextBtnRelease false]
  1184.  
  1185.     bind $itk_component(arrowBtn) <3>          [itcl::code $this _next]
  1186.     bind $itk_component(arrowBtn) <Shift-3>    [itcl::code $this _previous]
  1187.     bind $itk_component(arrowBtn) <Down>       [itcl::code $this _next]
  1188.     bind $itk_component(arrowBtn) <Up>         [itcl::code $this _previous]
  1189.     bind $itk_component(arrowBtn) <Control-n>  [itcl::code $this _next]
  1190.     bind $itk_component(arrowBtn) <Control-p>  [itcl::code $this _previous]
  1191.     bind $itk_component(arrowBtn) <Shift-Down> [itcl::code $this _toggleList]
  1192.     bind $itk_component(arrowBtn) <Shift-Up>   [itcl::code $this _toggleList]
  1193.     bind $itk_component(arrowBtn) <Return>     [itcl::code $this _toggleList]
  1194.     bind $itk_component(arrowBtn) <space>      [itcl::code $this _toggleList]
  1195.  
  1196.     bind $itk_component(entry)    <Configure>  [itcl::code $this _resizeArrow]
  1197.     bind $itk_component(entry)    <Shift-Down> [itcl::code $this _toggleList]
  1198.     bind $itk_component(entry)    <Shift-Up>   [itcl::code $this _toggleList]
  1199. }
  1200.  
  1201. # ------------------------------------------------------
  1202. # PROTECTED METHOD: _simpleBindings
  1203. #
  1204. # Bindings used only by the simple type Comboboxes.
  1205. #
  1206. # ------------------------------------------------------
  1207. itcl::body iwidgets::Combobox::_simpleBindings {} {
  1208.     bind [_slbListbox]         <ButtonRelease-1> [itcl::code $this _stateSelect]
  1209.     bind [_slbListbox]         <space>     [itcl::code $this _stateSelect]
  1210.     bind [_slbListbox]         <Return>    [itcl::code $this _stateSelect]
  1211.     bind $itk_component(entry) <Escape>     ""
  1212.     bind $itk_component(entry) <Shift-Down> ""
  1213.     bind $itk_component(entry) <Shift-Up>   ""
  1214.     bind $itk_component(entry) <Configure>  ""
  1215. }
  1216.  
  1217. # ------------------------------------------------------
  1218. # PROTECTED METHOD: _listShowing ?val?
  1219. #
  1220. # Used instead of "tkwait visibility" to make sure that
  1221. # the dropdown list is visible.     Whenever the list gets
  1222. # mapped or unmapped, this method is called to keep
  1223. # track of it.    When it is called with the value "-wait",
  1224. # it waits for the list to be mapped.
  1225. # ------------------------------------------------------
  1226. itcl::body iwidgets::Combobox::_listShowing {{val ""}} {
  1227.     if {$val == ""} {
  1228.     return $_listShowing($this)
  1229.     } elseif {$val == "-wait"} {
  1230.     while {!$_listShowing($this)} {
  1231.         tkwait variable [itcl::scope _listShowing($this)]
  1232.     }
  1233.     return
  1234.     }
  1235.     set _listShowing($this) $val
  1236. }
  1237.  
  1238. # ------------------------------------------------------
  1239. # PRIVATE METHOD:     _slbListbox
  1240. #
  1241. # Access the tk listbox window out of the scrolledlistbox.
  1242. #
  1243. # ------------------------------------------------------
  1244. itcl::body iwidgets::Combobox::_slbListbox {} {
  1245.     return [$itk_component(list) component listbox]
  1246. }
  1247.  
  1248. # ------------------------------------------------------
  1249. # PRIVATE METHOD:     _stateSelect
  1250. #
  1251. # only allows a B1 release in the listbox to have an effect if -state is
  1252. #    normal.
  1253. #
  1254. # ------------------------------------------------------
  1255. itcl::body iwidgets::Combobox::_stateSelect {} {
  1256.     switch --  $itk_option(-state) {
  1257.     normal {
  1258.         [itcl::code $this _selectCmd]
  1259.     }
  1260.     }
  1261. }
  1262.  
  1263. # ------------------------------------------------------
  1264. # PRIVATE METHOD:     _bs
  1265. #
  1266. # A part of the auto-completion code, this function sets a flag when the
  1267. #    Backspace key is hit and there is a selection in the entry field.
  1268. # Note that it's probably buggy to assume that a selection being present
  1269. #    means that that selection came from auto-completion.
  1270. #
  1271. # ------------------------------------------------------
  1272. itcl::body iwidgets::Combobox::_bs {} {
  1273.     #
  1274.     #        exit if completion is turned off
  1275.     #
  1276.     switch -- $itk_option(-completion) {
  1277.     0 - no - false - off {
  1278.         return
  1279.     }
  1280.     }
  1281.     #
  1282.     #        critical section flag.  it ain't perfect, but for most usage it'll
  1283.     #        keep us from being in this code "twice" at the same time
  1284.     #        (auto-repeated keystrokes are a pain!)
  1285.     #
  1286.     if {$_inbs} {
  1287.     return
  1288.     } else {
  1289.     set _inbs 1
  1290.     }
  1291.  
  1292.     #
  1293.     #        set the _doit flag if there is a selection set in the entry field
  1294.     #
  1295.     set _doit 0
  1296.     if [$itk_component(entry) selection present] {
  1297.     set _doit 1
  1298.     }
  1299.  
  1300.     #
  1301.     #        clear the semaphore and return
  1302.     #
  1303.     set _inbs 0
  1304. }
  1305.  
  1306. # ------------------------------------------------------
  1307. # PRIVATE METHOD:     _lookup
  1308. #
  1309. # handles auto-completion of text typed (or insert'd) into the entry field.
  1310. #
  1311. # ------------------------------------------------------
  1312. itcl::body iwidgets::Combobox::_lookup {key} {
  1313.  
  1314.     #
  1315.     # Don't process auto-completion stuff if navigation key was released
  1316.     # Fixes SF bug 501300
  1317.     #
  1318.     if {$_next_prevFLAG} {
  1319.         set _next_prevFLAG 0
  1320.         return
  1321.     }
  1322.  
  1323.     #
  1324.     #        exit if completion is turned off
  1325.     #
  1326.     switch -- $itk_option(-completion) {
  1327.     0 - no - false - off {
  1328.         return
  1329.     }
  1330.     }
  1331.  
  1332.     #
  1333.     #        critical section flag.  it ain't perfect, but for most usage it'll
  1334.     #        keep us from being in this code "twice" at the same time
  1335.     #        (auto-repeated keystrokes are a pain!)
  1336.     #
  1337.     if {$_inlookup} {
  1338.     return
  1339.     } else {
  1340.     set _inlookup 1
  1341.     }
  1342.  
  1343.     #
  1344.     #        if state of megawidget is disabled, or the entry is not editable,
  1345.     #        clear the semaphore and exit
  1346.     #
  1347.     if {$itk_option(-state) == "disabled" \
  1348.         || [lsearch {on 1 true yes} $itk_option(-editable)] == -1} {
  1349.     set _inlookup 0
  1350.     return
  1351.     }
  1352.  
  1353.     #
  1354.     #        okay, *now* we can get to work
  1355.     #        the _bs function is called on keyPRESS of BackSpace, and will set
  1356.     #        the _doit flag if there's a selection set in the entryfield.  If
  1357.     #        there is, we're assuming that it's generated by completion itself
  1358.     #        (this is probably a Bad Assumption), so we'll want to whack the
  1359.     #        selected text, as well as the character immediately preceding the
  1360.     #        insertion cursor.
  1361.     #
  1362.     if {$key == "BackSpace"} {
  1363.     if {$_doit} {
  1364.         set first [expr {[$itk_component(entry) index insert] -1}]
  1365.         $itk_component(entry) delete $first end
  1366.         $itk_component(entry) icursor $first
  1367.     }
  1368.     }
  1369.  
  1370.     #
  1371.     #        get the text left in the entry field, and its length.  if
  1372.     #        zero-length, clear the selection in the listbox, clear the
  1373.     #        semaphore, and boogie.
  1374.     #
  1375.     set text [get]
  1376.     set len [string length $text]
  1377.     if {$len == 0} {
  1378.     $itk_component(list) selection clear 0 end
  1379.     set _inlookup 0
  1380.     return
  1381.     }
  1382.  
  1383.     # No need to do lookups for Shift keys or Arrows.  The up/down
  1384.     # arrow keys should walk up/down the listbox entries.
  1385.     switch $key {
  1386.       Shift_L - Shift_R - Up - Down - Left - Right {
  1387.         set _inlookup 0
  1388.         return
  1389.       }
  1390.       default { }
  1391.     }
  1392.  
  1393.     # Added by csmith 12/11/01 to resolve SF ticket #474817.  It's an unusual
  1394.     # circumstance, but we need to make sure the character passed into this
  1395.     # method matches the last character in the entry's text string.  It's
  1396.     # possible to type fast enough that the _lookup method gets invoked
  1397.     # *after* multiple characters have been typed and *before* the first
  1398.     # character has been processed.  For example, you can type "bl" very
  1399.     # quickly, and by the time the interpreter processes "b", the "l" has
  1400.     # already been placed in the entry field.  This causes problems as noted
  1401.     # in the SF ticket.
  1402.     #
  1403.     # Thus, if the character currently being processed does not match the
  1404.     # last character in the entry field, reset the _inlookup flag and return.
  1405.     # Also, note that we're only concerned with single characters here, not
  1406.     # keys such as backspace, delete, etc.
  1407.     if {$key != [string range $text end end] && [string match ? $key]} {
  1408.       set _inlookup 0
  1409.       return
  1410.     }
  1411.  
  1412.     #
  1413.     #        okay, so we have to do a lookup.  find the first match in the
  1414.     #        listbox to the text we've got in the entry field (glob).
  1415.     #        if one exists, clear the current listbox selection, and set it to
  1416.     #        the one we just found, making that one visible in the listbox.
  1417.     #        then, pick off the text from the listbox entry that hadn't yet been
  1418.     #        entered into the entry field.  we need to tack that text onto the
  1419.     #        end of the entry field, select it, and then set the insertion cursor
  1420.     #        back to just before the point where we just added that text.
  1421.     #        if one didn't exist, then just clear the listbox selection
  1422.     #
  1423.     set item [lsearch [$itk_component(list) get 0 end] "$text*" ]
  1424.     if {$item != -1} {
  1425.     $itk_component(list) selection clear 0 end
  1426.     $itk_component(list) selection set $item $item
  1427.     see $item
  1428.     set remainder [string range [$itk_component(list) get $item] $len end]
  1429.     $itk_component(entry) insert end $remainder
  1430.     $itk_component(entry) selection range $len end
  1431.     $itk_component(entry) icursor $len
  1432.     } else {
  1433.     $itk_component(list) selection clear 0 end
  1434.     }
  1435.     #
  1436.     #        clear the semaphore and return
  1437.     #
  1438.     set _inlookup 0
  1439.     return
  1440. }
  1441.