OpenCores
URL https://opencores.org/ocsvn/openmsp430/openmsp430/trunk

Subversion Repositories openmsp430

[/] [openmsp430/] [trunk/] [tools/] [lib/] [tcl-lib/] [combobox.tcl] - Diff between revs 87 and 214

Only display areas with differences | Details | Blame | View Log

Rev 87 Rev 214
# Copyright (c) 1998-2003, Bryan Oakley
# Copyright (c) 1998-2003, Bryan Oakley
# All Rights Reservered
# All Rights Reservered
#
#
# Bryan Oakley
# Bryan Oakley
# oakley@bardo.clearlight.com
# oakley@bardo.clearlight.com
#
#
# combobox v2.3 August 16, 2003
# combobox v2.3 August 16, 2003
#
#
# a combobox / dropdown listbox (pick your favorite name) widget 
# a combobox / dropdown listbox (pick your favorite name) widget
# written in pure tcl
# written in pure tcl
#
#
# this code is freely distributable without restriction, but is 
# this code is freely distributable without restriction, but is
# provided as-is with no warranty expressed or implied. 
# provided as-is with no warranty expressed or implied.
#
#
# thanks to the following people who provided beta test support or
# thanks to the following people who provided beta test support or
# patches to the code (in no particular order):
# patches to the code (in no particular order):
#
#
# Scott Beasley     Alexandre Ferrieux      Todd Helfter
# Scott Beasley     Alexandre Ferrieux      Todd Helfter
# Matt Gushee       Laurent Duperval        John Jackson
# Matt Gushee       Laurent Duperval        John Jackson
# Fred Rapp         Christopher Nelson
# Fred Rapp         Christopher Nelson
# Eric Galluzzo     Jean-Francois Moine     Oliver Bienert
# Eric Galluzzo     Jean-Francois Moine     Oliver Bienert
#
#
# A special thanks to Martin M. Hunt who provided several good ideas, 
# A special thanks to Martin M. Hunt who provided several good ideas,
# and always with a patch to implement them. Jean-Francois Moine, 
# and always with a patch to implement them. Jean-Francois Moine,
# Todd Helfter and John Jackson were also kind enough to send in some 
# Todd Helfter and John Jackson were also kind enough to send in some
# code patches.
# code patches.
#
#
# ... and many others over the years.
# ... and many others over the years.
 
 
package require Tk 8.3
package require Tk 8.3
package provide combobox 2.3
package provide combobox 2.3
 
 
namespace eval ::combobox {
namespace eval ::combobox {
 
 
    # this is the public interface
    # this is the public interface
    namespace export combobox
    namespace export combobox
 
 
    # these contain references to available options
    # these contain references to available options
    variable widgetOptions
    variable widgetOptions
 
 
    # these contain references to available commands and subcommands
    # these contain references to available commands and subcommands
    variable widgetCommands
    variable widgetCommands
    variable scanCommands
    variable scanCommands
    variable listCommands
    variable listCommands
}
}
 
 
# ::combobox::combobox --
# ::combobox::combobox --
#
#
#     This is the command that gets exported. It creates a new
#     This is the command that gets exported. It creates a new
#     combobox widget.
#     combobox widget.
#
#
# Arguments:
# Arguments:
#
#
#     w        path of new widget to create
#     w        path of new widget to create
#     args     additional option/value pairs (eg: -background white, etc.)
#     args     additional option/value pairs (eg: -background white, etc.)
#
#
# Results:
# Results:
#
#
#     It creates the widget and sets up all of the default bindings
#     It creates the widget and sets up all of the default bindings
#
#
# Returns:
# Returns:
#
#
#     The name of the newly create widget
#     The name of the newly create widget
 
 
proc ::combobox::combobox {w args} {
proc ::combobox::combobox {w args} {
    variable widgetOptions
    variable widgetOptions
    variable widgetCommands
    variable widgetCommands
    variable scanCommands
    variable scanCommands
    variable listCommands
    variable listCommands
 
 
    # perform a one time initialization
    # perform a one time initialization
    if {![info exists widgetOptions]} {
    if {![info exists widgetOptions]} {
        Init
        Init
    }
    }
 
 
    # build it...
    # build it...
    eval Build $w $args
    eval Build $w $args
 
 
    # set some bindings...
    # set some bindings...
    SetBindings $w
    SetBindings $w
 
 
    # and we are done!
    # and we are done!
    return $w
    return $w
}
}
 
 
 
 
# ::combobox::Init --
# ::combobox::Init --
#
#
#     Initialize the namespace variables. This should only be called
#     Initialize the namespace variables. This should only be called
#     once, immediately prior to creating the first instance of the
#     once, immediately prior to creating the first instance of the
#     widget
#     widget
#
#
# Arguments:
# Arguments:
#
#
#    none
#    none
#
#
# Results:
# Results:
#
#
#     All state variables are set to their default values; all of 
#     All state variables are set to their default values; all of
#     the option database entries will exist.
#     the option database entries will exist.
#
#
# Returns:
# Returns:
# 
#
#     empty string
#     empty string
 
 
proc ::combobox::Init {} {
proc ::combobox::Init {} {
    variable widgetOptions
    variable widgetOptions
    variable widgetCommands
    variable widgetCommands
    variable scanCommands
    variable scanCommands
    variable listCommands
    variable listCommands
    variable defaultEntryCursor
    variable defaultEntryCursor
 
 
    array set widgetOptions [list \
    array set widgetOptions [list \
            -background          {background          Background} \
            -background          {background          Background} \
            -bd                  -borderwidth \
            -bd                  -borderwidth \
            -bg                  -background \
            -bg                  -background \
            -borderwidth         {borderWidth         BorderWidth} \
            -borderwidth         {borderWidth         BorderWidth} \
            -buttonbackground    {buttonBackground    Background} \
            -buttonbackground    {buttonBackground    Background} \
            -command             {command             Command} \
            -command             {command             Command} \
            -commandstate        {commandState        State} \
            -commandstate        {commandState        State} \
            -cursor              {cursor              Cursor} \
            -cursor              {cursor              Cursor} \
            -disabledbackground  {disabledBackground  DisabledBackground} \
            -disabledbackground  {disabledBackground  DisabledBackground} \
            -disabledforeground  {disabledForeground  DisabledForeground} \
            -disabledforeground  {disabledForeground  DisabledForeground} \
            -dropdownwidth       {dropdownWidth       DropdownWidth} \
            -dropdownwidth       {dropdownWidth       DropdownWidth} \
            -editable            {editable            Editable} \
            -editable            {editable            Editable} \
            -elementborderwidth  {elementBorderWidth  BorderWidth} \
            -elementborderwidth  {elementBorderWidth  BorderWidth} \
            -fg                  -foreground \
            -fg                  -foreground \
            -font                {font                Font} \
            -font                {font                Font} \
            -foreground          {foreground          Foreground} \
            -foreground          {foreground          Foreground} \
            -height              {height              Height} \
            -height              {height              Height} \
            -highlightbackground {highlightBackground HighlightBackground} \
            -highlightbackground {highlightBackground HighlightBackground} \
            -highlightcolor      {highlightColor      HighlightColor} \
            -highlightcolor      {highlightColor      HighlightColor} \
            -highlightthickness  {highlightThickness  HighlightThickness} \
            -highlightthickness  {highlightThickness  HighlightThickness} \
            -image               {image               Image} \
            -image               {image               Image} \
            -listvar             {listVariable        Variable} \
            -listvar             {listVariable        Variable} \
            -maxheight           {maxHeight           Height} \
            -maxheight           {maxHeight           Height} \
            -opencommand         {opencommand         Command} \
            -opencommand         {opencommand         Command} \
            -relief              {relief              Relief} \
            -relief              {relief              Relief} \
            -selectbackground    {selectBackground    Foreground} \
            -selectbackground    {selectBackground    Foreground} \
            -selectborderwidth   {selectBorderWidth   BorderWidth} \
            -selectborderwidth   {selectBorderWidth   BorderWidth} \
            -selectforeground    {selectForeground    Background} \
            -selectforeground    {selectForeground    Background} \
            -state               {state               State} \
            -state               {state               State} \
            -takefocus           {takeFocus           TakeFocus} \
            -takefocus           {takeFocus           TakeFocus} \
            -textvariable        {textVariable        Variable} \
            -textvariable        {textVariable        Variable} \
            -value               {value               Value} \
            -value               {value               Value} \
            -width               {width               Width} \
            -width               {width               Width} \
            -xscrollcommand      {xScrollCommand      ScrollCommand} \
            -xscrollcommand      {xScrollCommand      ScrollCommand} \
    ]
    ]
 
 
 
 
    set widgetCommands [list \
    set widgetCommands [list \
            bbox      cget     configure    curselection \
            bbox      cget     configure    curselection \
            delete    get      icursor      index        \
            delete    get      icursor      index        \
            insert    list     scan         selection    \
            insert    list     scan         selection    \
            xview     select   toggle       open         \
            xview     select   toggle       open         \
            close    subwidget  \
            close    subwidget  \
    ]
    ]
 
 
    set listCommands [list \
    set listCommands [list \
            delete       get      \
            delete       get      \
            index        insert       size \
            index        insert       size \
    ]
    ]
 
 
    set scanCommands [list mark dragto]
    set scanCommands [list mark dragto]
 
 
    # why check for the Tk package? This lets us be sourced into 
    # why check for the Tk package? This lets us be sourced into
    # an interpreter that doesn't have Tk loaded, such as the slave
    # an interpreter that doesn't have Tk loaded, such as the slave
    # interpreter used by pkg_mkIndex. In theory it should have no
    # interpreter used by pkg_mkIndex. In theory it should have no
    # side effects when run 
    # side effects when run
    if {[lsearch -exact [package names] "Tk"] != -1} {
    if {[lsearch -exact [package names] "Tk"] != -1} {
 
 
        ##################################################################
        ##################################################################
        #- this initializes the option database. Kinda gross, but it works
        #- this initializes the option database. Kinda gross, but it works
        #- (I think). 
        #- (I think).
        ##################################################################
        ##################################################################
 
 
        # the image used for the button...
        # the image used for the button...
        if {$::tcl_platform(platform) == "windows"} {
        if {$::tcl_platform(platform) == "windows"} {
            image create bitmap ::combobox::bimage -data {
            image create bitmap ::combobox::bimage -data {
                #define down_arrow_width 12
                #define down_arrow_width 12
                #define down_arrow_height 12
                #define down_arrow_height 12
                static char down_arrow_bits[] = {
                static char down_arrow_bits[] = {
                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                    0xfc,0xf1,0xf8,0xf0,0x70,0xf0,0x20,0xf0,
                    0xfc,0xf1,0xf8,0xf0,0x70,0xf0,0x20,0xf0,
                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
                    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
                }
                }
            }
            }
        } else {
        } else {
            image create bitmap ::combobox::bimage -data  {
            image create bitmap ::combobox::bimage -data  {
                #define down_arrow_width 15
                #define down_arrow_width 15
                #define down_arrow_height 15
                #define down_arrow_height 15
                static char down_arrow_bits[] = {
                static char down_arrow_bits[] = {
                    0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
                    0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
                    0x00,0x80,0xf8,0x8f,0xf0,0x87,0xe0,0x83,
                    0x00,0x80,0xf8,0x8f,0xf0,0x87,0xe0,0x83,
                    0xc0,0x81,0x80,0x80,0x00,0x80,0x00,0x80,
                    0xc0,0x81,0x80,0x80,0x00,0x80,0x00,0x80,
                    0x00,0x80,0x00,0x80,0x00,0x80
                    0x00,0x80,0x00,0x80,0x00,0x80
                }
                }
            }
            }
        }
        }
 
 
        # compute a widget name we can use to create a temporary widget
        # compute a widget name we can use to create a temporary widget
        set tmpWidget ".__tmp__"
        set tmpWidget ".__tmp__"
        set count 0
        set count 0
        while {[winfo exists $tmpWidget] == 1} {
        while {[winfo exists $tmpWidget] == 1} {
            set tmpWidget ".__tmp__$count"
            set tmpWidget ".__tmp__$count"
            incr count
            incr count
        }
        }
 
 
        # get the scrollbar width. Because we try to be clever and draw our
        # get the scrollbar width. Because we try to be clever and draw our
        # own button instead of using a tk widget, we need to know what size
        # own button instead of using a tk widget, we need to know what size
        # button to create. This little hack tells us the width of a scroll
        # button to create. This little hack tells us the width of a scroll
        # bar.
        # bar.
        #
        #
        # NB: we need to be sure and pick a window  that doesn't already
        # NB: we need to be sure and pick a window  that doesn't already
        # exist... 
        # exist...
        scrollbar $tmpWidget
        scrollbar $tmpWidget
        set sb_width [winfo reqwidth $tmpWidget]
        set sb_width [winfo reqwidth $tmpWidget]
        set bbg [$tmpWidget cget -background]
        set bbg [$tmpWidget cget -background]
        destroy $tmpWidget
        destroy $tmpWidget
 
 
        # steal options from the entry widget
        # steal options from the entry widget
        # we want darn near all options, so we'll go ahead and do
        # we want darn near all options, so we'll go ahead and do
        # them all. No harm done in adding the one or two that we
        # them all. No harm done in adding the one or two that we
        # don't use.
        # don't use.
        entry $tmpWidget
        entry $tmpWidget
        foreach foo [$tmpWidget configure] {
        foreach foo [$tmpWidget configure] {
            # the cursor option is special, so we'll save it in
            # the cursor option is special, so we'll save it in
            # a special way
            # a special way
            if {[lindex $foo 0] == "-cursor"} {
            if {[lindex $foo 0] == "-cursor"} {
                set defaultEntryCursor [lindex $foo 4]
                set defaultEntryCursor [lindex $foo 4]
            }
            }
            if {[llength $foo] == 5} {
            if {[llength $foo] == 5} {
                set option [lindex $foo 1]
                set option [lindex $foo 1]
                set value [lindex $foo 4]
                set value [lindex $foo 4]
                option add *Combobox.$option $value widgetDefault
                option add *Combobox.$option $value widgetDefault
 
 
                # these options also apply to the dropdown listbox
                # these options also apply to the dropdown listbox
                if {[string compare $option "foreground"] == 0 \
                if {[string compare $option "foreground"] == 0 \
                        || [string compare $option "background"] == 0 \
                        || [string compare $option "background"] == 0 \
                        || [string compare $option "font"] == 0} {
                        || [string compare $option "font"] == 0} {
                    option add *Combobox*ComboboxListbox.$option $value \
                    option add *Combobox*ComboboxListbox.$option $value \
                            widgetDefault
                            widgetDefault
                }
                }
            }
            }
        }
        }
        destroy $tmpWidget
        destroy $tmpWidget
 
 
        # these are unique to us...
        # these are unique to us...
        option add *Combobox.elementBorderWidth  1      widgetDefault
        option add *Combobox.elementBorderWidth  1      widgetDefault
        option add *Combobox.buttonBackground    $bbg   widgetDefault
        option add *Combobox.buttonBackground    $bbg   widgetDefault
        option add *Combobox.dropdownWidth       {}     widgetDefault
        option add *Combobox.dropdownWidth       {}     widgetDefault
        option add *Combobox.openCommand         {}     widgetDefault
        option add *Combobox.openCommand         {}     widgetDefault
        option add *Combobox.cursor              {}     widgetDefault
        option add *Combobox.cursor              {}     widgetDefault
        option add *Combobox.commandState        normal widgetDefault
        option add *Combobox.commandState        normal widgetDefault
        option add *Combobox.editable            1      widgetDefault
        option add *Combobox.editable            1      widgetDefault
        option add *Combobox.maxHeight           10     widgetDefault
        option add *Combobox.maxHeight           10     widgetDefault
        option add *Combobox.height              0
        option add *Combobox.height              0
    }
    }
 
 
    # set class bindings
    # set class bindings
    SetClassBindings
    SetClassBindings
}
}
 
 
# ::combobox::SetClassBindings --
# ::combobox::SetClassBindings --
#
#
#    Sets up the default bindings for the widget class
#    Sets up the default bindings for the widget class
#
#
#    this proc exists since it's The Right Thing To Do, but
#    this proc exists since it's The Right Thing To Do, but
#    I haven't had the time to figure out how to do all the
#    I haven't had the time to figure out how to do all the
#    binding stuff on a class level. The main problem is that
#    binding stuff on a class level. The main problem is that
#    the entry widget must have focus for the insertion cursor
#    the entry widget must have focus for the insertion cursor
#    to be visible. So, I either have to have the entry widget
#    to be visible. So, I either have to have the entry widget
#    have the Combobox bindtag, or do some fancy juggling of
#    have the Combobox bindtag, or do some fancy juggling of
#    events or some such. What a pain.
#    events or some such. What a pain.
#
#
# Arguments:
# Arguments:
#
#
#    none
#    none
#
#
# Returns:
# Returns:
#
#
#    empty string
#    empty string
 
 
proc ::combobox::SetClassBindings {} {
proc ::combobox::SetClassBindings {} {
 
 
    # make sure we clean up after ourselves...
    # make sure we clean up after ourselves...
    bind Combobox <Destroy> [list ::combobox::DestroyHandler %W]
    bind Combobox <Destroy> [list ::combobox::DestroyHandler %W]
 
 
    # this will (hopefully) close (and lose the grab on) the
    # this will (hopefully) close (and lose the grab on) the
    # listbox if the user clicks anywhere outside of it. Note
    # listbox if the user clicks anywhere outside of it. Note
    # that on Windows, you can click on some other app and
    # that on Windows, you can click on some other app and
    # the listbox will still be there, because tcl won't see
    # the listbox will still be there, because tcl won't see
    # that button click
    # that button click
    set this {[::combobox::convert %W -W]}
    set this {[::combobox::convert %W -W]}
    bind Combobox <Any-ButtonPress>   "$this close"
    bind Combobox <Any-ButtonPress>   "$this close"
    bind Combobox <Any-ButtonRelease> "$this close"
    bind Combobox <Any-ButtonRelease> "$this close"
 
 
    # this helps (but doesn't fully solve) focus issues. The general
    # this helps (but doesn't fully solve) focus issues. The general
    # idea is, whenever the frame gets focus it gets passed on to
    # idea is, whenever the frame gets focus it gets passed on to
    # the entry widget
    # the entry widget
    bind Combobox <FocusIn> {::combobox::tkTabToWindow \
    bind Combobox <FocusIn> {::combobox::tkTabToWindow \
                                 [::combobox::convert %W -W].entry}
                                 [::combobox::convert %W -W].entry}
 
 
    # this closes the listbox if we get hidden
    # this closes the listbox if we get hidden
    bind Combobox <Unmap> {[::combobox::convert %W -W] close}
    bind Combobox <Unmap> {[::combobox::convert %W -W] close}
 
 
    return ""
    return ""
}
}
 
 
# ::combobox::SetBindings --
# ::combobox::SetBindings --
#
#
#    here's where we do most of the binding foo. I think there's probably
#    here's where we do most of the binding foo. I think there's probably
#    a few bindings I ought to add that I just haven't thought
#    a few bindings I ought to add that I just haven't thought
#    about...
#    about...
#
#
#    I'm not convinced these are the proper bindings. Ideally all
#    I'm not convinced these are the proper bindings. Ideally all
#    bindings should be on "Combobox", but because of my juggling of
#    bindings should be on "Combobox", but because of my juggling of
#    bindtags I'm not convinced thats what I want to do. But, it all
#    bindtags I'm not convinced thats what I want to do. But, it all
#    seems to work, its just not as robust as it could be.
#    seems to work, its just not as robust as it could be.
#
#
# Arguments:
# Arguments:
#
#
#    w    widget pathname
#    w    widget pathname
#
#
# Returns:
# Returns:
#
#
#    empty string
#    empty string
 
 
proc ::combobox::SetBindings {w} {
proc ::combobox::SetBindings {w} {
    upvar ::combobox::${w}::widgets  widgets
    upvar ::combobox::${w}::widgets  widgets
    upvar ::combobox::${w}::options  options
    upvar ::combobox::${w}::options  options
 
 
    # juggle the bindtags. The basic idea here is to associate the
    # juggle the bindtags. The basic idea here is to associate the
    # widget name with the entry widget, so if a user does a bind
    # widget name with the entry widget, so if a user does a bind
    # on the combobox it will get handled properly since it is
    # on the combobox it will get handled properly since it is
    # the entry widget that has keyboard focus.
    # the entry widget that has keyboard focus.
    bindtags $widgets(entry) \
    bindtags $widgets(entry) \
            [concat $widgets(this) [bindtags $widgets(entry)]]
            [concat $widgets(this) [bindtags $widgets(entry)]]
 
 
    bindtags $widgets(button) \
    bindtags $widgets(button) \
            [concat $widgets(this) [bindtags $widgets(button)]]
            [concat $widgets(this) [bindtags $widgets(button)]]
 
 
    # override the default bindings for tab and shift-tab. The
    # override the default bindings for tab and shift-tab. The
    # focus procs take a widget as their only parameter and we
    # focus procs take a widget as their only parameter and we
    # want to make sure the right window gets used (for shift-
    # want to make sure the right window gets used (for shift-
    # tab we want it to appear as if the event was generated
    # tab we want it to appear as if the event was generated
    # on the frame rather than the entry. 
    # on the frame rather than the entry.
    bind $widgets(entry) <Tab> \
    bind $widgets(entry) <Tab> \
            "::combobox::tkTabToWindow \[tk_focusNext $widgets(entry)\]; break"
            "::combobox::tkTabToWindow \[tk_focusNext $widgets(entry)\]; break"
    bind $widgets(entry) <Shift-Tab> \
    bind $widgets(entry) <Shift-Tab> \
            "::combobox::tkTabToWindow \[tk_focusPrev $widgets(this)\]; break"
            "::combobox::tkTabToWindow \[tk_focusPrev $widgets(this)\]; break"
 
 
    # this makes our "button" (which is actually a label)
    # this makes our "button" (which is actually a label)
    # do the right thing
    # do the right thing
    bind $widgets(button) <ButtonPress-1> [list $widgets(this) toggle]
    bind $widgets(button) <ButtonPress-1> [list $widgets(this) toggle]
 
 
    # this lets the autoscan of the listbox work, even if they
    # this lets the autoscan of the listbox work, even if they
    # move the cursor over the entry widget.
    # move the cursor over the entry widget.
    bind $widgets(entry) <B1-Enter> "break"
    bind $widgets(entry) <B1-Enter> "break"
 
 
    bind $widgets(listbox) <ButtonRelease-1> \
    bind $widgets(listbox) <ButtonRelease-1> \
        "::combobox::Select [list $widgets(this)] \
        "::combobox::Select [list $widgets(this)] \
         \[$widgets(listbox) nearest %y\]; break"
         \[$widgets(listbox) nearest %y\]; break"
 
 
    bind $widgets(vsb) <ButtonPress-1>   {continue}
    bind $widgets(vsb) <ButtonPress-1>   {continue}
    bind $widgets(vsb) <ButtonRelease-1> {continue}
    bind $widgets(vsb) <ButtonRelease-1> {continue}
 
 
    bind $widgets(listbox) <Any-Motion> {
    bind $widgets(listbox) <Any-Motion> {
        %W selection clear 0 end
        %W selection clear 0 end
        %W activate @%x,%y
        %W activate @%x,%y
        %W selection anchor @%x,%y
        %W selection anchor @%x,%y
        %W selection set @%x,%y @%x,%y
        %W selection set @%x,%y @%x,%y
        # need to do a yview if the cursor goes off the top
        # need to do a yview if the cursor goes off the top
        # or bottom of the window... (or do we?)
        # or bottom of the window... (or do we?)
    }
    }
 
 
    # these events need to be passed from the entry widget
    # these events need to be passed from the entry widget
    # to the listbox, or otherwise need some sort of special
    # to the listbox, or otherwise need some sort of special
    # handling. 
    # handling.
    foreach event [list <Up> <Down> <Tab> <Return> <Escape> \
    foreach event [list <Up> <Down> <Tab> <Return> <Escape> \
            <Next> <Prior> <Double-1> <1> <Any-KeyPress> \
            <Next> <Prior> <Double-1> <1> <Any-KeyPress> \
            <FocusIn> <FocusOut>] {
            <FocusIn> <FocusOut>] {
        bind $widgets(entry) $event \
        bind $widgets(entry) $event \
            [list ::combobox::HandleEvent $widgets(this) $event]
            [list ::combobox::HandleEvent $widgets(this) $event]
    }
    }
 
 
    # like the other events, <MouseWheel> needs to be passed from
    # like the other events, <MouseWheel> needs to be passed from
    # the entry widget to the listbox. However, in this case we
    # the entry widget to the listbox. However, in this case we
    # need to add an additional parameter
    # need to add an additional parameter
    catch {
    catch {
        bind $widgets(entry) <MouseWheel> \
        bind $widgets(entry) <MouseWheel> \
            [list ::combobox::HandleEvent $widgets(this) <MouseWheel> %D]
            [list ::combobox::HandleEvent $widgets(this) <MouseWheel> %D]
    }
    }
}
}
 
 
# ::combobox::Build --
# ::combobox::Build --
#
#
#    This does all of the work necessary to create the basic
#    This does all of the work necessary to create the basic
#    combobox. 
#    combobox.
#
#
# Arguments:
# Arguments:
#
#
#    w        widget name
#    w        widget name
#    args     additional option/value pairs
#    args     additional option/value pairs
#
#
# Results:
# Results:
#
#
#    Creates a new widget with the given name. Also creates a new
#    Creates a new widget with the given name. Also creates a new
#    namespace patterened after the widget name, as a child namespace
#    namespace patterened after the widget name, as a child namespace
#    to ::combobox
#    to ::combobox
#
#
# Returns:
# Returns:
#
#
#    the name of the widget
#    the name of the widget
 
 
proc ::combobox::Build {w args } {
proc ::combobox::Build {w args } {
    variable widgetOptions
    variable widgetOptions
 
 
    if {[winfo exists $w]} {
    if {[winfo exists $w]} {
        error "window name \"$w\" already exists"
        error "window name \"$w\" already exists"
    }
    }
 
 
    # create the namespace for this instance, and define a few
    # create the namespace for this instance, and define a few
    # variables
    # variables
    namespace eval ::combobox::$w {
    namespace eval ::combobox::$w {
 
 
        variable ignoreTrace 0
        variable ignoreTrace 0
        variable oldFocus    {}
        variable oldFocus    {}
        variable oldGrab     {}
        variable oldGrab     {}
        variable oldValue    {}
        variable oldValue    {}
        variable options
        variable options
        variable this
        variable this
        variable widgets
        variable widgets
 
 
        set widgets(foo) foo  ;# coerce into an array
        set widgets(foo) foo  ;# coerce into an array
        set options(foo) foo  ;# coerce into an array
        set options(foo) foo  ;# coerce into an array
 
 
        unset widgets(foo)
        unset widgets(foo)
        unset options(foo)
        unset options(foo)
    }
    }
 
 
    # import the widgets and options arrays into this proc so
    # import the widgets and options arrays into this proc so
    # we don't have to use fully qualified names, which is a
    # we don't have to use fully qualified names, which is a
    # pain.
    # pain.
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    # this is our widget -- a frame of class Combobox. Naturally,
    # this is our widget -- a frame of class Combobox. Naturally,
    # it will contain other widgets. We create it here because
    # it will contain other widgets. We create it here because
    # we need it in order to set some default options.
    # we need it in order to set some default options.
    set widgets(this)   [frame  $w -class Combobox -takefocus 0]
    set widgets(this)   [frame  $w -class Combobox -takefocus 0]
    set widgets(entry)  [entry  $w.entry -takefocus 1]
    set widgets(entry)  [entry  $w.entry -takefocus 1]
    set widgets(button) [label  $w.button -takefocus 0]
    set widgets(button) [label  $w.button -takefocus 0]
 
 
    # this defines all of the default options. We get the
    # this defines all of the default options. We get the
    # values from the option database. Note that if an array
    # values from the option database. Note that if an array
    # value is a list of length one it is an alias to another
    # value is a list of length one it is an alias to another
    # option, so we just ignore it
    # option, so we just ignore it
    foreach name [array names widgetOptions] {
    foreach name [array names widgetOptions] {
        if {[llength $widgetOptions($name)] == 1} continue
        if {[llength $widgetOptions($name)] == 1} continue
 
 
        set optName  [lindex $widgetOptions($name) 0]
        set optName  [lindex $widgetOptions($name) 0]
        set optClass [lindex $widgetOptions($name) 1]
        set optClass [lindex $widgetOptions($name) 1]
 
 
        set value [option get $w $optName $optClass]
        set value [option get $w $optName $optClass]
        set options($name) $value
        set options($name) $value
    }
    }
 
 
    # a couple options aren't available in earlier versions of
    # a couple options aren't available in earlier versions of
    # tcl, so we'll set them to sane values. For that matter, if
    # tcl, so we'll set them to sane values. For that matter, if
    # they exist but are empty, set them to sane values.
    # they exist but are empty, set them to sane values.
    if {[string length $options(-disabledforeground)] == 0} {
    if {[string length $options(-disabledforeground)] == 0} {
        set options(-disabledforeground) $options(-foreground)
        set options(-disabledforeground) $options(-foreground)
    }
    }
    if {[string length $options(-disabledbackground)] == 0} {
    if {[string length $options(-disabledbackground)] == 0} {
        set options(-disabledbackground) $options(-background)
        set options(-disabledbackground) $options(-background)
    }
    }
 
 
    # if -value is set to null, we'll remove it from our
    # if -value is set to null, we'll remove it from our
    # local array. The assumption is, if the user sets it from
    # local array. The assumption is, if the user sets it from
    # the option database, they will set it to something other
    # the option database, they will set it to something other
    # than null (since it's impossible to determine the difference
    # than null (since it's impossible to determine the difference
    # between a null value and no value at all).
    # between a null value and no value at all).
    if {[info exists options(-value)] \
    if {[info exists options(-value)] \
            && [string length $options(-value)] == 0} {
            && [string length $options(-value)] == 0} {
        unset options(-value)
        unset options(-value)
    }
    }
 
 
    # we will later rename the frame's widget proc to be our
    # we will later rename the frame's widget proc to be our
    # own custom widget proc. We need to keep track of this
    # own custom widget proc. We need to keep track of this
    # new name, so we'll define and store it here...
    # new name, so we'll define and store it here...
    set widgets(frame) ::combobox::${w}::$w
    set widgets(frame) ::combobox::${w}::$w
 
 
    # gotta do this sooner or later. Might as well do it now
    # gotta do this sooner or later. Might as well do it now
    pack $widgets(button) -side right -fill y    -expand no
    pack $widgets(button) -side right -fill y    -expand no
    pack $widgets(entry)  -side left  -fill both -expand yes
    pack $widgets(entry)  -side left  -fill both -expand yes
 
 
    # I should probably do this in a catch, but for now it's
    # I should probably do this in a catch, but for now it's
    # good enough... What it does, obviously, is put all of
    # good enough... What it does, obviously, is put all of
    # the option/values pairs into an array. Make them easier
    # the option/values pairs into an array. Make them easier
    # to handle later on...
    # to handle later on...
    array set options $args
    array set options $args
 
 
    # now, the dropdown list... the same renaming nonsense
    # now, the dropdown list... the same renaming nonsense
    # must go on here as well...
    # must go on here as well...
    set widgets(dropdown)   [toplevel  $w.top]
    set widgets(dropdown)   [toplevel  $w.top]
    set widgets(listbox) [listbox   $w.top.list]
    set widgets(listbox) [listbox   $w.top.list]
    set widgets(vsb)     [scrollbar $w.top.vsb]
    set widgets(vsb)     [scrollbar $w.top.vsb]
 
 
    pack $widgets(listbox) -side left -fill both -expand y
    pack $widgets(listbox) -side left -fill both -expand y
 
 
    # fine tune the widgets based on the options (and a few
    # fine tune the widgets based on the options (and a few
    # arbitrary values...)
    # arbitrary values...)
 
 
    # NB: we are going to use the frame to handle the relief
    # NB: we are going to use the frame to handle the relief
    # of the widget as a whole, so the entry widget will be 
    # of the widget as a whole, so the entry widget will be
    # flat. This makes the button which drops down the list
    # flat. This makes the button which drops down the list
    # to appear "inside" the entry widget.
    # to appear "inside" the entry widget.
 
 
    $widgets(vsb) configure \
    $widgets(vsb) configure \
            -borderwidth 1 \
            -borderwidth 1 \
            -command "$widgets(listbox) yview" \
            -command "$widgets(listbox) yview" \
            -highlightthickness 0
            -highlightthickness 0
 
 
    $widgets(button) configure \
    $widgets(button) configure \
            -background $options(-buttonbackground) \
            -background $options(-buttonbackground) \
            -highlightthickness 0 \
            -highlightthickness 0 \
            -borderwidth $options(-elementborderwidth) \
            -borderwidth $options(-elementborderwidth) \
            -relief raised \
            -relief raised \
            -width [expr {[winfo reqwidth $widgets(vsb)] - 2}]
            -width [expr {[winfo reqwidth $widgets(vsb)] - 2}]
 
 
    $widgets(entry) configure \
    $widgets(entry) configure \
            -borderwidth 0 \
            -borderwidth 0 \
            -relief flat \
            -relief flat \
            -highlightthickness 0
            -highlightthickness 0
 
 
    $widgets(dropdown) configure \
    $widgets(dropdown) configure \
            -borderwidth $options(-elementborderwidth) \
            -borderwidth $options(-elementborderwidth) \
            -relief sunken
            -relief sunken
 
 
    $widgets(listbox) configure \
    $widgets(listbox) configure \
            -selectmode browse \
            -selectmode browse \
            -background [$widgets(entry) cget -bg] \
            -background [$widgets(entry) cget -bg] \
            -yscrollcommand "$widgets(vsb) set" \
            -yscrollcommand "$widgets(vsb) set" \
            -exportselection false \
            -exportselection false \
            -borderwidth 0
            -borderwidth 0
 
 
 
 
#    trace variable ::combobox::${w}::entryTextVariable w \
#    trace variable ::combobox::${w}::entryTextVariable w \
#           [list ::combobox::EntryTrace $w]
#           [list ::combobox::EntryTrace $w]
 
 
    # do some window management foo on the dropdown window
    # do some window management foo on the dropdown window
    wm overrideredirect $widgets(dropdown) 1
    wm overrideredirect $widgets(dropdown) 1
    wm transient        $widgets(dropdown) [winfo toplevel $w]
    wm transient        $widgets(dropdown) [winfo toplevel $w]
    wm group            $widgets(dropdown) [winfo parent $w]
    wm group            $widgets(dropdown) [winfo parent $w]
    wm resizable        $widgets(dropdown) 0 0
    wm resizable        $widgets(dropdown) 0 0
    wm withdraw         $widgets(dropdown)
    wm withdraw         $widgets(dropdown)
 
 
    # this moves the original frame widget proc into our
    # this moves the original frame widget proc into our
    # namespace and gives it a handy name
    # namespace and gives it a handy name
    rename ::$w $widgets(frame)
    rename ::$w $widgets(frame)
 
 
    # now, create our widget proc. Obviously (?) it goes in
    # now, create our widget proc. Obviously (?) it goes in
    # the global namespace. All combobox widgets will actually
    # the global namespace. All combobox widgets will actually
    # share the same widget proc to cut down on the amount of
    # share the same widget proc to cut down on the amount of
    # bloat. 
    # bloat.
    proc ::$w {command args} \
    proc ::$w {command args} \
        "eval ::combobox::WidgetProc $w \$command \$args"
        "eval ::combobox::WidgetProc $w \$command \$args"
 
 
 
 
    # ok, the thing exists... let's do a bit more configuration. 
    # ok, the thing exists... let's do a bit more configuration.
    if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} {
    if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} {
        catch {destroy $w}
        catch {destroy $w}
        error "internal error: $error"
        error "internal error: $error"
    }
    }
 
 
    return ""
    return ""
 
 
}
}
 
 
# ::combobox::HandleEvent --
# ::combobox::HandleEvent --
#
#
#    this proc handles events from the entry widget that we want
#    this proc handles events from the entry widget that we want
#    handled specially (typically, to allow navigation of the list
#    handled specially (typically, to allow navigation of the list
#    even though the focus is in the entry widget)
#    even though the focus is in the entry widget)
#
#
# Arguments:
# Arguments:
#
#
#    w       widget pathname
#    w       widget pathname
#    event   a string representing the event (not necessarily an
#    event   a string representing the event (not necessarily an
#            actual event)
#            actual event)
#    args    additional arguments required by particular events
#    args    additional arguments required by particular events
 
 
proc ::combobox::HandleEvent {w event args} {
proc ::combobox::HandleEvent {w event args} {
    upvar ::combobox::${w}::widgets  widgets
    upvar ::combobox::${w}::widgets  widgets
    upvar ::combobox::${w}::options  options
    upvar ::combobox::${w}::options  options
    upvar ::combobox::${w}::oldValue oldValue
    upvar ::combobox::${w}::oldValue oldValue
 
 
    # for all of these events, if we have a special action we'll
    # for all of these events, if we have a special action we'll
    # do that and do a "return -code break" to keep additional 
    # do that and do a "return -code break" to keep additional
    # bindings from firing. Otherwise we'll let the event fall
    # bindings from firing. Otherwise we'll let the event fall
    # on through. 
    # on through.
    switch $event {
    switch $event {
 
 
        "<MouseWheel>" {
        "<MouseWheel>" {
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                set D [lindex $args 0]
                set D [lindex $args 0]
                # the '120' number in the following expression has
                # the '120' number in the following expression has
                # it's genesis in the tk bind manpage, which suggests
                # it's genesis in the tk bind manpage, which suggests
                # that the smallest value of %D for mousewheel events
                # that the smallest value of %D for mousewheel events
                # will be 120. The intent is to scroll one line at a time.
                # will be 120. The intent is to scroll one line at a time.
                $widgets(listbox) yview scroll [expr {-($D/120)}] units
                $widgets(listbox) yview scroll [expr {-($D/120)}] units
            }
            }
        }
        }
 
 
        "<Any-KeyPress>" {
        "<Any-KeyPress>" {
            # if the widget is editable, clear the selection. 
            # if the widget is editable, clear the selection.
            # this makes it more obvious what will happen if the 
            # this makes it more obvious what will happen if the
            # user presses <Return> (and helps our code know what
            # user presses <Return> (and helps our code know what
            # to do if the user presses return)
            # to do if the user presses return)
            if {$options(-editable)} {
            if {$options(-editable)} {
                $widgets(listbox) see 0
                $widgets(listbox) see 0
                $widgets(listbox) selection clear 0 end
                $widgets(listbox) selection clear 0 end
                $widgets(listbox) selection anchor 0
                $widgets(listbox) selection anchor 0
                $widgets(listbox) activate 0
                $widgets(listbox) activate 0
            }
            }
        }
        }
 
 
        "<FocusIn>" {
        "<FocusIn>" {
            set oldValue [$widgets(entry) get]
            set oldValue [$widgets(entry) get]
        }
        }
 
 
        "<FocusOut>" {
        "<FocusOut>" {
            if {![winfo ismapped $widgets(dropdown)]} {
            if {![winfo ismapped $widgets(dropdown)]} {
                # did the value change?
                # did the value change?
                set newValue [$widgets(entry) get]
                set newValue [$widgets(entry) get]
                if {$oldValue != $newValue} {
                if {$oldValue != $newValue} {
                    CallCommand $widgets(this) $newValue
                    CallCommand $widgets(this) $newValue
                }
                }
            }
            }
        }
        }
 
 
        "<1>" {
        "<1>" {
            set editable [::combobox::GetBoolean $options(-editable)]
            set editable [::combobox::GetBoolean $options(-editable)]
            if {!$editable} {
            if {!$editable} {
                if {[winfo ismapped $widgets(dropdown)]} {
                if {[winfo ismapped $widgets(dropdown)]} {
                    $widgets(this) close
                    $widgets(this) close
                    return -code break;
                    return -code break;
 
 
                } else {
                } else {
                    if {$options(-state) != "disabled"} {
                    if {$options(-state) != "disabled"} {
                        $widgets(this) open
                        $widgets(this) open
                        return -code break;
                        return -code break;
                    }
                    }
                }
                }
            }
            }
        }
        }
 
 
        "<Double-1>" {
        "<Double-1>" {
            if {$options(-state) != "disabled"} {
            if {$options(-state) != "disabled"} {
                $widgets(this) toggle
                $widgets(this) toggle
                return -code break;
                return -code break;
            }
            }
        }
        }
 
 
        "<Tab>" {
        "<Tab>" {
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                ::combobox::Find $widgets(this) 0
                ::combobox::Find $widgets(this) 0
                return -code break;
                return -code break;
            } else {
            } else {
                ::combobox::SetValue $widgets(this) [$widgets(this) get]
                ::combobox::SetValue $widgets(this) [$widgets(this) get]
            }
            }
        }
        }
 
 
        "<Escape>" {
        "<Escape>" {
#           $widgets(entry) delete 0 end
#           $widgets(entry) delete 0 end
#           $widgets(entry) insert 0 $oldValue
#           $widgets(entry) insert 0 $oldValue
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                $widgets(this) close
                $widgets(this) close
                return -code break;
                return -code break;
            }
            }
        }
        }
 
 
        "<Return>" {
        "<Return>" {
            # did the value change?
            # did the value change?
            set newValue [$widgets(entry) get]
            set newValue [$widgets(entry) get]
            if {$oldValue != $newValue} {
            if {$oldValue != $newValue} {
                CallCommand $widgets(this) $newValue
                CallCommand $widgets(this) $newValue
            }
            }
 
 
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                ::combobox::Select $widgets(this) \
                ::combobox::Select $widgets(this) \
                        [$widgets(listbox) curselection]
                        [$widgets(listbox) curselection]
                return -code break;
                return -code break;
            }
            }
 
 
        }
        }
 
 
        "<Next>" {
        "<Next>" {
            $widgets(listbox) yview scroll 1 pages
            $widgets(listbox) yview scroll 1 pages
            set index [$widgets(listbox) index @0,0]
            set index [$widgets(listbox) index @0,0]
            $widgets(listbox) see $index
            $widgets(listbox) see $index
            $widgets(listbox) activate $index
            $widgets(listbox) activate $index
            $widgets(listbox) selection clear 0 end
            $widgets(listbox) selection clear 0 end
            $widgets(listbox) selection anchor $index
            $widgets(listbox) selection anchor $index
            $widgets(listbox) selection set $index
            $widgets(listbox) selection set $index
 
 
        }
        }
 
 
        "<Prior>" {
        "<Prior>" {
            $widgets(listbox) yview scroll -1 pages
            $widgets(listbox) yview scroll -1 pages
            set index [$widgets(listbox) index @0,0]
            set index [$widgets(listbox) index @0,0]
            $widgets(listbox) activate $index
            $widgets(listbox) activate $index
            $widgets(listbox) see $index
            $widgets(listbox) see $index
            $widgets(listbox) selection clear 0 end
            $widgets(listbox) selection clear 0 end
            $widgets(listbox) selection anchor $index
            $widgets(listbox) selection anchor $index
            $widgets(listbox) selection set $index
            $widgets(listbox) selection set $index
        }
        }
 
 
        "<Down>" {
        "<Down>" {
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                ::combobox::tkListboxUpDown $widgets(listbox) 1
                ::combobox::tkListboxUpDown $widgets(listbox) 1
                return -code break;
                return -code break;
 
 
            } else {
            } else {
                if {$options(-state) != "disabled"} {
                if {$options(-state) != "disabled"} {
                    $widgets(this) open
                    $widgets(this) open
                    return -code break;
                    return -code break;
                }
                }
            }
            }
        }
        }
        "<Up>" {
        "<Up>" {
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                ::combobox::tkListboxUpDown $widgets(listbox) -1
                ::combobox::tkListboxUpDown $widgets(listbox) -1
                return -code break;
                return -code break;
 
 
            } else {
            } else {
                if {$options(-state) != "disabled"} {
                if {$options(-state) != "disabled"} {
                    $widgets(this) open
                    $widgets(this) open
                    return -code break;
                    return -code break;
                }
                }
            }
            }
        }
        }
    }
    }
 
 
    return ""
    return ""
}
}
 
 
# ::combobox::DestroyHandler {w} --
# ::combobox::DestroyHandler {w} --
# 
#
#    Cleans up after a combobox widget is destroyed
#    Cleans up after a combobox widget is destroyed
#
#
# Arguments:
# Arguments:
#
#
#    w    widget pathname
#    w    widget pathname
#
#
# Results:
# Results:
#
#
#    The namespace that was created for the widget is deleted,
#    The namespace that was created for the widget is deleted,
#    and the widget proc is removed.
#    and the widget proc is removed.
 
 
proc ::combobox::DestroyHandler {w} {
proc ::combobox::DestroyHandler {w} {
 
 
    catch {
    catch {
        # if the widget actually being destroyed is of class Combobox,
        # if the widget actually being destroyed is of class Combobox,
        # remove the namespace and associated proc.
        # remove the namespace and associated proc.
        if {[string compare [winfo class $w] "Combobox"] == 0} {
        if {[string compare [winfo class $w] "Combobox"] == 0} {
            # delete the namespace and the proc which represents
            # delete the namespace and the proc which represents
            # our widget
            # our widget
            namespace delete ::combobox::$w
            namespace delete ::combobox::$w
            rename $w {}
            rename $w {}
        }
        }
    }
    }
    return ""
    return ""
}
}
 
 
# ::combobox::Find
# ::combobox::Find
#
#
#    finds something in the listbox that matches the pattern in the
#    finds something in the listbox that matches the pattern in the
#    entry widget and selects it
#    entry widget and selects it
#
#
#    N.B. I'm not convinced this is working the way it ought to. It
#    N.B. I'm not convinced this is working the way it ought to. It
#    works, but is the behavior what is expected? I've also got a gut
#    works, but is the behavior what is expected? I've also got a gut
#    feeling that there's a better way to do this, but I'm too lazy to
#    feeling that there's a better way to do this, but I'm too lazy to
#    figure it out...
#    figure it out...
#
#
# Arguments:
# Arguments:
#
#
#    w      widget pathname
#    w      widget pathname
#    exact  boolean; if true an exact match is desired
#    exact  boolean; if true an exact match is desired
#
#
# Returns:
# Returns:
#
#
#    Empty string
#    Empty string
 
 
proc ::combobox::Find {w {exact 0}} {
proc ::combobox::Find {w {exact 0}} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    ## *sigh* this logic is rather gross and convoluted. Surely
    ## *sigh* this logic is rather gross and convoluted. Surely
    ## there is a more simple, straight-forward way to implement
    ## there is a more simple, straight-forward way to implement
    ## all this. As the saying goes, I lack the time to make it
    ## all this. As the saying goes, I lack the time to make it
    ## shorter...
    ## shorter...
 
 
    # use what is already in the entry widget as a pattern
    # use what is already in the entry widget as a pattern
    set pattern [$widgets(entry) get]
    set pattern [$widgets(entry) get]
 
 
    if {[string length $pattern] == 0} {
    if {[string length $pattern] == 0} {
        # clear the current selection
        # clear the current selection
        $widgets(listbox) see 0
        $widgets(listbox) see 0
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection anchor 0
        $widgets(listbox) selection anchor 0
        $widgets(listbox) activate 0
        $widgets(listbox) activate 0
        return
        return
    }
    }
 
 
    # we're going to be searching this list...
    # we're going to be searching this list...
    set list [$widgets(listbox) get 0 end]
    set list [$widgets(listbox) get 0 end]
 
 
    # if we are doing an exact match, try to find,
    # if we are doing an exact match, try to find,
    # well, an exact match
    # well, an exact match
    set exactMatch -1
    set exactMatch -1
    if {$exact} {
    if {$exact} {
        set exactMatch [lsearch -exact $list $pattern]
        set exactMatch [lsearch -exact $list $pattern]
    }
    }
 
 
    # search for it. We'll try to be clever and not only
    # search for it. We'll try to be clever and not only
    # search for a match for what they typed, but a match for
    # search for a match for what they typed, but a match for
    # something close to what they typed. We'll keep removing one
    # something close to what they typed. We'll keep removing one
    # character at a time from the pattern until we find a match
    # character at a time from the pattern until we find a match
    # of some sort.
    # of some sort.
    set index -1
    set index -1
    while {$index == -1 && [string length $pattern]} {
    while {$index == -1 && [string length $pattern]} {
        set index [lsearch -glob $list "$pattern*"]
        set index [lsearch -glob $list "$pattern*"]
        if {$index == -1} {
        if {$index == -1} {
            regsub {.$} $pattern {} pattern
            regsub {.$} $pattern {} pattern
        }
        }
    }
    }
 
 
    # this is the item that most closely matches...
    # this is the item that most closely matches...
    set thisItem [lindex $list $index]
    set thisItem [lindex $list $index]
 
 
    # did we find a match? If so, do some additional munging...
    # did we find a match? If so, do some additional munging...
    if {$index != -1} {
    if {$index != -1} {
 
 
        # we need to find the part of the first item that is 
        # we need to find the part of the first item that is
        # unique WRT the second... I know there's probably a
        # unique WRT the second... I know there's probably a
        # simpler way to do this... 
        # simpler way to do this...
 
 
        set nextIndex [expr {$index + 1}]
        set nextIndex [expr {$index + 1}]
        set nextItem [lindex $list $nextIndex]
        set nextItem [lindex $list $nextIndex]
 
 
        # we don't really need to do much if the next
        # we don't really need to do much if the next
        # item doesn't match our pattern...
        # item doesn't match our pattern...
        if {[string match $pattern* $nextItem]} {
        if {[string match $pattern* $nextItem]} {
            # ok, the next item matches our pattern, too
            # ok, the next item matches our pattern, too
            # now the trick is to find the first character
            # now the trick is to find the first character
            # where they *don't* match...
            # where they *don't* match...
            set marker [string length $pattern]
            set marker [string length $pattern]
            while {$marker <= [string length $pattern]} {
            while {$marker <= [string length $pattern]} {
                set a [string index $thisItem $marker]
                set a [string index $thisItem $marker]
                set b [string index $nextItem $marker]
                set b [string index $nextItem $marker]
                if {[string compare $a $b] == 0} {
                if {[string compare $a $b] == 0} {
                    append pattern $a
                    append pattern $a
                    incr marker
                    incr marker
                } else {
                } else {
                    break
                    break
                }
                }
            }
            }
        } else {
        } else {
            set marker [string length $pattern]
            set marker [string length $pattern]
        }
        }
 
 
    } else {
    } else {
        set marker end
        set marker end
        set index 0
        set index 0
    }
    }
 
 
    # ok, we know the pattern and what part is unique;
    # ok, we know the pattern and what part is unique;
    # update the entry widget and listbox appropriately
    # update the entry widget and listbox appropriately
    if {$exact && $exactMatch == -1} {
    if {$exact && $exactMatch == -1} {
        # this means we didn't find an exact match
        # this means we didn't find an exact match
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) see $index
        $widgets(listbox) see $index
 
 
    } elseif {!$exact}  {
    } elseif {!$exact}  {
        # this means we found something, but it isn't an exact
        # this means we found something, but it isn't an exact
        # match. If we find something that *is* an exact match we
        # match. If we find something that *is* an exact match we
        # don't need to do the following, since it would merely 
        # don't need to do the following, since it would merely
        # be replacing the data in the entry widget with itself
        # be replacing the data in the entry widget with itself
        set oldstate [$widgets(entry) cget -state]
        set oldstate [$widgets(entry) cget -state]
        $widgets(entry) configure -state normal
        $widgets(entry) configure -state normal
        $widgets(entry) delete 0 end
        $widgets(entry) delete 0 end
        $widgets(entry) insert end $thisItem
        $widgets(entry) insert end $thisItem
        $widgets(entry) selection clear
        $widgets(entry) selection clear
        $widgets(entry) selection range $marker end
        $widgets(entry) selection range $marker end
        $widgets(listbox) activate $index
        $widgets(listbox) activate $index
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection anchor $index
        $widgets(listbox) selection anchor $index
        $widgets(listbox) selection set $index
        $widgets(listbox) selection set $index
        $widgets(listbox) see $index
        $widgets(listbox) see $index
        $widgets(entry) configure -state $oldstate
        $widgets(entry) configure -state $oldstate
    }
    }
}
}
 
 
# ::combobox::Select --
# ::combobox::Select --
#
#
#    selects an item from the list and sets the value of the combobox
#    selects an item from the list and sets the value of the combobox
#    to that value
#    to that value
#
#
# Arguments:
# Arguments:
#
#
#    w      widget pathname
#    w      widget pathname
#    index  listbox index of item to be selected
#    index  listbox index of item to be selected
#
#
# Returns:
# Returns:
#
#
#    empty string
#    empty string
 
 
proc ::combobox::Select {w index} {
proc ::combobox::Select {w index} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    # the catch is because I'm sloppy -- presumably, the only time
    # the catch is because I'm sloppy -- presumably, the only time
    # an error will be caught is if there is no selection. 
    # an error will be caught is if there is no selection.
    if {![catch {set data [$widgets(listbox) get [lindex $index 0]]}]} {
    if {![catch {set data [$widgets(listbox) get [lindex $index 0]]}]} {
        ::combobox::SetValue $widgets(this) $data
        ::combobox::SetValue $widgets(this) $data
 
 
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection clear 0 end
        $widgets(listbox) selection anchor $index
        $widgets(listbox) selection anchor $index
        $widgets(listbox) selection set $index
        $widgets(listbox) selection set $index
 
 
    }
    }
    $widgets(entry) selection range 0 end
    $widgets(entry) selection range 0 end
    $widgets(entry) icursor end
    $widgets(entry) icursor end
 
 
    $widgets(this) close
    $widgets(this) close
 
 
    return ""
    return ""
}
}
 
 
# ::combobox::HandleScrollbar --
# ::combobox::HandleScrollbar --
# 
#
#    causes the scrollbar of the dropdown list to appear or disappear
#    causes the scrollbar of the dropdown list to appear or disappear
#    based on the contents of the dropdown listbox
#    based on the contents of the dropdown listbox
#
#
# Arguments:
# Arguments:
#
#
#    w       widget pathname
#    w       widget pathname
#    action  the action to perform on the scrollbar
#    action  the action to perform on the scrollbar
#
#
# Returns:
# Returns:
#
#
#    an empty string
#    an empty string
 
 
proc ::combobox::HandleScrollbar {w {action "unknown"}} {
proc ::combobox::HandleScrollbar {w {action "unknown"}} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    if {$options(-height) == 0} {
    if {$options(-height) == 0} {
        set hlimit $options(-maxheight)
        set hlimit $options(-maxheight)
    } else {
    } else {
        set hlimit $options(-height)
        set hlimit $options(-height)
    }
    }
 
 
    switch $action {
    switch $action {
        "grow" {
        "grow" {
            if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
            if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
                pack forget $widgets(listbox)
                pack forget $widgets(listbox)
                pack $widgets(vsb) -side right -fill y -expand n
                pack $widgets(vsb) -side right -fill y -expand n
                pack $widgets(listbox) -side left -fill both -expand y
                pack $widgets(listbox) -side left -fill both -expand y
            }
            }
        }
        }
 
 
        "shrink" {
        "shrink" {
            if {$hlimit > 0 && [$widgets(listbox) size] <= $hlimit} {
            if {$hlimit > 0 && [$widgets(listbox) size] <= $hlimit} {
                pack forget $widgets(vsb)
                pack forget $widgets(vsb)
            }
            }
        }
        }
 
 
        "crop" {
        "crop" {
            # this means the window was cropped and we definitely 
            # this means the window was cropped and we definitely
            # need a scrollbar no matter what the user wants
            # need a scrollbar no matter what the user wants
            pack forget $widgets(listbox)
            pack forget $widgets(listbox)
            pack $widgets(vsb) -side right -fill y -expand n
            pack $widgets(vsb) -side right -fill y -expand n
            pack $widgets(listbox) -side left -fill both -expand y
            pack $widgets(listbox) -side left -fill both -expand y
        }
        }
 
 
        default {
        default {
            if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
            if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} {
                pack forget $widgets(listbox)
                pack forget $widgets(listbox)
                pack $widgets(vsb) -side right -fill y -expand n
                pack $widgets(vsb) -side right -fill y -expand n
                pack $widgets(listbox) -side left -fill both -expand y
                pack $widgets(listbox) -side left -fill both -expand y
            } else {
            } else {
                pack forget $widgets(vsb)
                pack forget $widgets(vsb)
            }
            }
        }
        }
    }
    }
 
 
    return ""
    return ""
}
}
 
 
# ::combobox::ComputeGeometry --
# ::combobox::ComputeGeometry --
#
#
#    computes the geometry of the dropdown list based on the size of the
#    computes the geometry of the dropdown list based on the size of the
#    combobox...
#    combobox...
#
#
# Arguments:
# Arguments:
#
#
#    w     widget pathname
#    w     widget pathname
#
#
# Returns:
# Returns:
#
#
#    the desired geometry of the listbox
#    the desired geometry of the listbox
 
 
proc ::combobox::ComputeGeometry {w} {
proc ::combobox::ComputeGeometry {w} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    if {$options(-height) == 0 && $options(-maxheight) != "0"} {
    if {$options(-height) == 0 && $options(-maxheight) != "0"} {
        # if this is the case, count the items and see if
        # if this is the case, count the items and see if
        # it exceeds our maxheight. If so, set the listbox
        # it exceeds our maxheight. If so, set the listbox
        # size to maxheight...
        # size to maxheight...
        set nitems [$widgets(listbox) size]
        set nitems [$widgets(listbox) size]
        if {$nitems > $options(-maxheight)} {
        if {$nitems > $options(-maxheight)} {
            # tweak the height of the listbox
            # tweak the height of the listbox
            $widgets(listbox) configure -height $options(-maxheight)
            $widgets(listbox) configure -height $options(-maxheight)
        } else {
        } else {
            # un-tweak the height of the listbox
            # un-tweak the height of the listbox
            $widgets(listbox) configure -height 0
            $widgets(listbox) configure -height 0
        }
        }
        update idletasks
        update idletasks
    }
    }
 
 
    # compute height and width of the dropdown list
    # compute height and width of the dropdown list
    set bd [$widgets(dropdown) cget -borderwidth]
    set bd [$widgets(dropdown) cget -borderwidth]
    set height [expr {[winfo reqheight $widgets(dropdown)] + $bd + $bd}]
    set height [expr {[winfo reqheight $widgets(dropdown)] + $bd + $bd}]
    if {[string length $options(-dropdownwidth)] == 0 ||
    if {[string length $options(-dropdownwidth)] == 0 ||
        $options(-dropdownwidth) == 0} {
        $options(-dropdownwidth) == 0} {
        set width [winfo width $widgets(this)]
        set width [winfo width $widgets(this)]
    } else {
    } else {
        set m [font measure [$widgets(listbox) cget -font] "m"]
        set m [font measure [$widgets(listbox) cget -font] "m"]
        set width [expr {$options(-dropdownwidth) * $m}]
        set width [expr {$options(-dropdownwidth) * $m}]
    }
    }
 
 
    # figure out where to place it on the screen, trying to take into
    # figure out where to place it on the screen, trying to take into
    # account we may be running under some virtual window manager
    # account we may be running under some virtual window manager
    set screenWidth  [winfo screenwidth $widgets(this)]
    set screenWidth  [winfo screenwidth $widgets(this)]
    set screenHeight [winfo screenheight $widgets(this)]
    set screenHeight [winfo screenheight $widgets(this)]
    set rootx        [winfo rootx $widgets(this)]
    set rootx        [winfo rootx $widgets(this)]
    set rooty        [winfo rooty $widgets(this)]
    set rooty        [winfo rooty $widgets(this)]
    set vrootx       [winfo vrootx $widgets(this)]
    set vrootx       [winfo vrootx $widgets(this)]
    set vrooty       [winfo vrooty $widgets(this)]
    set vrooty       [winfo vrooty $widgets(this)]
 
 
    # the x coordinate is simply the rootx of our widget, adjusted for
    # the x coordinate is simply the rootx of our widget, adjusted for
    # the virtual window. We won't worry about whether the window will
    # the virtual window. We won't worry about whether the window will
    # be offscreen to the left or right -- we want the illusion that it
    # be offscreen to the left or right -- we want the illusion that it
    # is part of the entry widget, so if part of the entry widget is off-
    # is part of the entry widget, so if part of the entry widget is off-
    # screen, so will the list. If you want to change the behavior,
    # screen, so will the list. If you want to change the behavior,
    # simply change the if statement... (and be sure to update this
    # simply change the if statement... (and be sure to update this
    # comment!)
    # comment!)
    set x  [expr {$rootx + $vrootx}]
    set x  [expr {$rootx}]
    if {0} {
    if {0} {
        set rightEdge [expr {$x + $width}]
        set rightEdge [expr {$x + $width}]
        if {$rightEdge > $screenWidth} {
        if {$rightEdge > $screenWidth} {
            set x [expr {$screenWidth - $width}]
            set x [expr {$screenWidth - $width}]
        }
        }
        if {$x < 0} {set x 0}
        if {$x < 0} {set x 0}
    }
    }
 
 
    # the y coordinate is the rooty plus vrooty offset plus 
    # the y coordinate is the rooty plus vrooty offset plus
    # the height of the static part of the widget plus 1 for a 
    # the height of the static part of the widget plus 1 for a
    # tiny bit of visual separation...
    # tiny bit of visual separation...
    set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
    set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}]
    set bottomEdge [expr {$y + $height}]
    set bottomEdge [expr {$y + $height}]
 
 
    if {$bottomEdge >= $screenHeight} {
    if {$bottomEdge >= $screenHeight} {
        # ok. Fine. Pop it up above the entry widget isntead of
        # ok. Fine. Pop it up above the entry widget isntead of
        # below.
        # below.
        set y [expr {($rooty - $height - 1) + $vrooty}]
        set y [expr {($rooty - $height - 1) + $vrooty}]
 
 
        if {$y < 0} {
        if {$y < 0} {
            # this means it extends beyond our screen. How annoying.
            # this means it extends beyond our screen. How annoying.
            # Now we'll try to be real clever and either pop it up or
            # Now we'll try to be real clever and either pop it up or
            # down, depending on which way gives us the biggest list. 
            # down, depending on which way gives us the biggest list.
            # then, we'll trim the list to fit and force the use of
            # then, we'll trim the list to fit and force the use of
            # a scrollbar
            # a scrollbar
 
 
            # (sadly, for windows users this measurement doesn't
            # (sadly, for windows users this measurement doesn't
            # take into consideration the height of the taskbar,
            # take into consideration the height of the taskbar,
            # but don't blame me -- there isn't any way to detect
            # but don't blame me -- there isn't any way to detect
            # it or figure out its dimensions. The same probably
            # it or figure out its dimensions. The same probably
            # applies to any window manager with some magic windows
            # applies to any window manager with some magic windows
            # glued to the top or bottom of the screen)
            # glued to the top or bottom of the screen)
 
 
            if {$rooty > [expr {$screenHeight / 2}]} {
            if {$rooty > [expr {$screenHeight / 2}]} {
                # we are in the lower half of the screen -- 
                # we are in the lower half of the screen --
                # pop it up. Y is zero; that parts easy. The height
                # pop it up. Y is zero; that parts easy. The height
                # is simply the y coordinate of our widget, minus
                # is simply the y coordinate of our widget, minus
                # a pixel for some visual separation. The y coordinate
                # a pixel for some visual separation. The y coordinate
                # will be the topof the screen.
                # will be the topof the screen.
                set y 1
                set y 1
                set height [expr {$rooty - 1 - $y}]
                set height [expr {$rooty - 1 - $y}]
 
 
            } else {
            } else {
                # we are in the upper half of the screen --
                # we are in the upper half of the screen --
                # pop it down
                # pop it down
                set y [expr {$rooty + $vrooty + \
                set y [expr {$rooty + $vrooty + \
                        [winfo reqheight $widgets(this)] + 1}]
                        [winfo reqheight $widgets(this)] + 1}]
                set height [expr {$screenHeight - $y}]
                set height [expr {$screenHeight - $y}]
 
 
            }
            }
 
 
            # force a scrollbar
            # force a scrollbar
            HandleScrollbar $widgets(this) crop
            HandleScrollbar $widgets(this) crop
        }
        }
    }
    }
 
 
    if {$y < 0} {
    if {$y < 0} {
        # hmmm. Bummer.
        # hmmm. Bummer.
        set y 0
        set y 0
        set height $screenheight
        set height $screenheight
    }
    }
 
 
    set geometry [format "=%dx%d+%d+%d" $width $height $x $y]
    set geometry [format "=%dx%d+%d+%d" $width $height $x $y]
 
 
    return $geometry
    return $geometry
}
}
 
 
# ::combobox::DoInternalWidgetCommand --
# ::combobox::DoInternalWidgetCommand --
#
#
#    perform an internal widget command, then mung any error results
#    perform an internal widget command, then mung any error results
#    to look like it came from our megawidget. A lot of work just to
#    to look like it came from our megawidget. A lot of work just to
#    give the illusion that our megawidget is an atomic widget
#    give the illusion that our megawidget is an atomic widget
#
#
# Arguments:
# Arguments:
#
#
#    w           widget pathname
#    w           widget pathname
#    subwidget   pathname of the subwidget 
#    subwidget   pathname of the subwidget
#    command     subwidget command to be executed
#    command     subwidget command to be executed
#    args        arguments to the command
#    args        arguments to the command
#
#
# Returns:
# Returns:
#
#
#    The result of the subwidget command, or an error
#    The result of the subwidget command, or an error
 
 
proc ::combobox::DoInternalWidgetCommand {w subwidget command args} {
proc ::combobox::DoInternalWidgetCommand {w subwidget command args} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    set subcommand $command
    set subcommand $command
    set command [concat $widgets($subwidget) $command $args]
    set command [concat $widgets($subwidget) $command $args]
    if {[catch $command result]} {
    if {[catch $command result]} {
        # replace the subwidget name with the megawidget name
        # replace the subwidget name with the megawidget name
        regsub $widgets($subwidget) $result $widgets(this) result
        regsub $widgets($subwidget) $result $widgets(this) result
 
 
        # replace specific instances of the subwidget command
        # replace specific instances of the subwidget command
        # with our megawidget command
        # with our megawidget command
        switch $subwidget,$subcommand {
        switch $subwidget,$subcommand {
            listbox,index  {regsub "index"  $result "list index"  result}
            listbox,index  {regsub "index"  $result "list index"  result}
            listbox,insert {regsub "insert" $result "list insert" result}
            listbox,insert {regsub "insert" $result "list insert" result}
            listbox,delete {regsub "delete" $result "list delete" result}
            listbox,delete {regsub "delete" $result "list delete" result}
            listbox,get    {regsub "get"    $result "list get"    result}
            listbox,get    {regsub "get"    $result "list get"    result}
            listbox,size   {regsub "size"   $result "list size"   result}
            listbox,size   {regsub "size"   $result "list size"   result}
        }
        }
        error $result
        error $result
 
 
    } else {
    } else {
        return $result
        return $result
    }
    }
}
}
 
 
 
 
# ::combobox::WidgetProc --
# ::combobox::WidgetProc --
#
#
#    This gets uses as the widgetproc for an combobox widget. 
#    This gets uses as the widgetproc for an combobox widget.
#    Notice where the widget is created and you'll see that the
#    Notice where the widget is created and you'll see that the
#    actual widget proc merely evals this proc with all of the
#    actual widget proc merely evals this proc with all of the
#    arguments intact.
#    arguments intact.
#
#
#    Note that some widget commands are defined "inline" (ie:
#    Note that some widget commands are defined "inline" (ie:
#    within this proc), and some do most of their work in 
#    within this proc), and some do most of their work in
#    separate procs. This is merely because sometimes it was
#    separate procs. This is merely because sometimes it was
#    easier to do it one way or the other.
#    easier to do it one way or the other.
#
#
# Arguments:
# Arguments:
#
#
#    w         widget pathname
#    w         widget pathname
#    command   widget subcommand
#    command   widget subcommand
#    args      additional arguments; varies with the subcommand
#    args      additional arguments; varies with the subcommand
#
#
# Results:
# Results:
#
#
#    Performs the requested widget command
#    Performs the requested widget command
 
 
proc ::combobox::WidgetProc {w command args} {
proc ::combobox::WidgetProc {w command args} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::oldFocus oldFocus
    upvar ::combobox::${w}::oldFocus oldFocus
    upvar ::combobox::${w}::oldFocus oldGrab
    upvar ::combobox::${w}::oldFocus oldGrab
 
 
    set command [::combobox::Canonize $w command $command]
    set command [::combobox::Canonize $w command $command]
 
 
    # this is just shorthand notation...
    # this is just shorthand notation...
    set doWidgetCommand \
    set doWidgetCommand \
            [list ::combobox::DoInternalWidgetCommand $widgets(this)]
            [list ::combobox::DoInternalWidgetCommand $widgets(this)]
 
 
    if {$command == "list"} {
    if {$command == "list"} {
        # ok, the next argument is a list command; we'll 
        # ok, the next argument is a list command; we'll
        # rip it from args and append it to command to
        # rip it from args and append it to command to
        # create a unique internal command
        # create a unique internal command
        #
        #
        # NB: because of the sloppy way we are doing this,
        # NB: because of the sloppy way we are doing this,
        # we'll also let the user enter our secret command
        # we'll also let the user enter our secret command
        # directly (eg: listinsert, listdelete), but we
        # directly (eg: listinsert, listdelete), but we
        # won't document that fact
        # won't document that fact
        set command "list-[lindex $args 0]"
        set command "list-[lindex $args 0]"
        set args [lrange $args 1 end]
        set args [lrange $args 1 end]
    }
    }
 
 
    set result ""
    set result ""
 
 
    # many of these commands are just synonyms for specific
    # many of these commands are just synonyms for specific
    # commands in one of the subwidgets. We'll get them out
    # commands in one of the subwidgets. We'll get them out
    # of the way first, then do the custom commands.
    # of the way first, then do the custom commands.
    switch $command {
    switch $command {
        bbox -
        bbox -
        delete -
        delete -
        get -
        get -
        icursor -
        icursor -
        index -
        index -
        insert -
        insert -
        scan -
        scan -
        selection -
        selection -
        xview {
        xview {
            set result [eval $doWidgetCommand entry $command $args]
            set result [eval $doWidgetCommand entry $command $args]
        }
        }
        list-get        {set result [eval $doWidgetCommand listbox get $args]}
        list-get        {set result [eval $doWidgetCommand listbox get $args]}
        list-index      {set result [eval $doWidgetCommand listbox index $args]}
        list-index      {set result [eval $doWidgetCommand listbox index $args]}
        list-size       {set result [eval $doWidgetCommand listbox size $args]}
        list-size       {set result [eval $doWidgetCommand listbox size $args]}
 
 
        select {
        select {
            if {[llength $args] == 1} {
            if {[llength $args] == 1} {
                set index [lindex $args 0]
                set index [lindex $args 0]
                set result [Select $widgets(this) $index]
                set result [Select $widgets(this) $index]
            } else {
            } else {
                error "usage: $w select index"
                error "usage: $w select index"
            }
            }
        }
        }
 
 
        subwidget {
        subwidget {
            set knownWidgets [list button entry listbox dropdown vsb]
            set knownWidgets [list button entry listbox dropdown vsb]
            if {[llength $args] == 0} {
            if {[llength $args] == 0} {
                return $knownWidgets
                return $knownWidgets
            }
            }
 
 
            set name [lindex $args 0]
            set name [lindex $args 0]
            if {[lsearch $knownWidgets $name] != -1} {
            if {[lsearch $knownWidgets $name] != -1} {
                set result $widgets($name)
                set result $widgets($name)
            } else {
            } else {
                error "unknown subwidget $name"
                error "unknown subwidget $name"
            }
            }
        }
        }
 
 
        curselection {
        curselection {
            set result [eval $doWidgetCommand listbox curselection]
            set result [eval $doWidgetCommand listbox curselection]
        }
        }
 
 
        list-insert {
        list-insert {
            eval $doWidgetCommand listbox insert $args
            eval $doWidgetCommand listbox insert $args
            set result [HandleScrollbar $w "grow"]
            set result [HandleScrollbar $w "grow"]
        }
        }
 
 
        list-delete {
        list-delete {
            eval $doWidgetCommand listbox delete $args
            eval $doWidgetCommand listbox delete $args
            set result [HandleScrollbar $w "shrink"]
            set result [HandleScrollbar $w "shrink"]
        }
        }
 
 
        toggle {
        toggle {
            # ignore this command if the widget is disabled...
            # ignore this command if the widget is disabled...
            if {$options(-state) == "disabled"} return
            if {$options(-state) == "disabled"} return
 
 
            # pops down the list if it is not, hides it
            # pops down the list if it is not, hides it
            # if it is...
            # if it is...
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                set result [$widgets(this) close]
                set result [$widgets(this) close]
            } else {
            } else {
                set result [$widgets(this) open]
                set result [$widgets(this) open]
            }
            }
        }
        }
 
 
        open {
        open {
 
 
            # if this is an editable combobox, the focus should
            # if this is an editable combobox, the focus should
            # be set to the entry widget
            # be set to the entry widget
            if {$options(-editable)} {
            if {$options(-editable)} {
                focus $widgets(entry)
                focus $widgets(entry)
                $widgets(entry) select range 0 end
                $widgets(entry) select range 0 end
                $widgets(entry) icursor end
                $widgets(entry) icursor end
            }
            }
 
 
            # if we are disabled, we won't allow this to happen
            # if we are disabled, we won't allow this to happen
            if {$options(-state) == "disabled"} {
            if {$options(-state) == "disabled"} {
                return 0
                return 0
            }
            }
 
 
            # if there is a -opencommand, execute it now
            # if there is a -opencommand, execute it now
            if {[string length $options(-opencommand)] > 0} {
            if {[string length $options(-opencommand)] > 0} {
                # hmmm... should I do a catch, or just let the normal
                # hmmm... should I do a catch, or just let the normal
                # error handling handle any errors? For now, the latter...
                # error handling handle any errors? For now, the latter...
                uplevel \#0 $options(-opencommand)
                uplevel \#0 $options(-opencommand)
            }
            }
 
 
            # compute the geometry of the window to pop up, and set
            # compute the geometry of the window to pop up, and set
            # it, and force the window manager to take notice
            # it, and force the window manager to take notice
            # (even if it is not presently visible).
            # (even if it is not presently visible).
            #
            #
            # this isn't strictly necessary if the window is already
            # this isn't strictly necessary if the window is already
            # mapped, but we'll go ahead and set the geometry here
            # mapped, but we'll go ahead and set the geometry here
            # since its harmless and *may* actually reset the geometry
            # since its harmless and *may* actually reset the geometry
            # to something better in some weird case.
            # to something better in some weird case.
            set geometry [::combobox::ComputeGeometry $widgets(this)]
            set geometry [::combobox::ComputeGeometry $widgets(this)]
            wm geometry $widgets(dropdown) $geometry
            wm geometry $widgets(dropdown) $geometry
            update idletasks
            update idletasks
 
 
            # if we are already open, there's nothing else to do
            # if we are already open, there's nothing else to do
            if {[winfo ismapped $widgets(dropdown)]} {
            if {[winfo ismapped $widgets(dropdown)]} {
                return 0
                return 0
            }
            }
 
 
            # save the widget that currently has the focus; we'll restore
            # save the widget that currently has the focus; we'll restore
            # the focus there when we're done
            # the focus there when we're done
            set oldFocus [focus]
            set oldFocus [focus]
 
 
            # ok, tweak the visual appearance of things and 
            # ok, tweak the visual appearance of things and
            # make the list pop up
            # make the list pop up
            $widgets(button) configure -relief sunken
            $widgets(button) configure -relief sunken
            wm deiconify $widgets(dropdown)
            wm deiconify $widgets(dropdown)
            update idletasks
            update idletasks
            raise $widgets(dropdown)
            raise $widgets(dropdown)
 
 
            # force focus to the entry widget so we can handle keypress
            # force focus to the entry widget so we can handle keypress
            # events for traversal
            # events for traversal
            focus -force $widgets(entry)
            focus -force $widgets(entry)
 
 
            # select something by default, but only if its an
            # select something by default, but only if its an
            # exact match...
            # exact match...
            ::combobox::Find $widgets(this) 1
            ::combobox::Find $widgets(this) 1
 
 
            # save the current grab state for the display containing
            # save the current grab state for the display containing
            # this widget. We'll restore it when we close the dropdown
            # this widget. We'll restore it when we close the dropdown
            # list
            # list
            set status "none"
            set status "none"
            set grab [grab current $widgets(this)]
            set grab [grab current $widgets(this)]
            if {$grab != ""} {set status [grab status $grab]}
            if {$grab != ""} {set status [grab status $grab]}
            set oldGrab [list $grab $status]
            set oldGrab [list $grab $status]
            unset grab status
            unset grab status
 
 
            # *gasp* do a global grab!!! Mom always told me not to
            # *gasp* do a global grab!!! Mom always told me not to
            # do things like this, but sometimes a man's gotta do
            # do things like this, but sometimes a man's gotta do
            # what a man's gotta do.
            # what a man's gotta do.
            grab -global $widgets(this)
            grab -global $widgets(this)
 
 
            # fake the listbox into thinking it has focus. This is 
            # fake the listbox into thinking it has focus. This is
            # necessary to get scanning initialized properly in the
            # necessary to get scanning initialized properly in the
            # listbox.
            # listbox.
            event generate $widgets(listbox) <B1-Enter>
            event generate $widgets(listbox) <B1-Enter>
 
 
            return 1
            return 1
        }
        }
 
 
        close {
        close {
            # if we are already closed, don't do anything...
            # if we are already closed, don't do anything...
            if {![winfo ismapped $widgets(dropdown)]} {
            if {![winfo ismapped $widgets(dropdown)]} {
                return 0
                return 0
            }
            }
 
 
            # restore the focus and grab, but ignore any errors...
            # restore the focus and grab, but ignore any errors...
            # we're going to be paranoid and release the grab before
            # we're going to be paranoid and release the grab before
            # trying to set any other grab because we really really
            # trying to set any other grab because we really really
            # really want to make sure the grab is released.
            # really want to make sure the grab is released.
            catch {focus $oldFocus} result
            catch {focus $oldFocus} result
            catch {grab release $widgets(this)}
            catch {grab release $widgets(this)}
            catch {
            catch {
                set status [lindex $oldGrab 1]
                set status [lindex $oldGrab 1]
                if {$status == "global"} {
                if {$status == "global"} {
                    grab -global [lindex $oldGrab 0]
                    grab -global [lindex $oldGrab 0]
                } elseif {$status == "local"} {
                } elseif {$status == "local"} {
                    grab [lindex $oldGrab 0]
                    grab [lindex $oldGrab 0]
                }
                }
                unset status
                unset status
            }
            }
 
 
            # hides the listbox
            # hides the listbox
            $widgets(button) configure -relief raised
            $widgets(button) configure -relief raised
            wm withdraw $widgets(dropdown)
            wm withdraw $widgets(dropdown)
 
 
            # select the data in the entry widget. Not sure
            # select the data in the entry widget. Not sure
            # why, other than observation seems to suggest that's
            # why, other than observation seems to suggest that's
            # what windows widgets do.
            # what windows widgets do.
            set editable [::combobox::GetBoolean $options(-editable)]
            set editable [::combobox::GetBoolean $options(-editable)]
            if {$editable} {
            if {$editable} {
                $widgets(entry) selection range 0 end
                $widgets(entry) selection range 0 end
                $widgets(button) configure -relief raised
                $widgets(button) configure -relief raised
            }
            }
 
 
 
 
            # magic tcl stuff (see tk.tcl in the distribution 
            # magic tcl stuff (see tk.tcl in the distribution
            # lib directory)
            # lib directory)
            ::combobox::tkCancelRepeat
            ::combobox::tkCancelRepeat
 
 
            return 1
            return 1
        }
        }
 
 
        cget {
        cget {
            if {[llength $args] != 1} {
            if {[llength $args] != 1} {
                error "wrong # args: should be $w cget option"
                error "wrong # args: should be $w cget option"
            }
            }
            set opt [::combobox::Canonize $w option [lindex $args 0]]
            set opt [::combobox::Canonize $w option [lindex $args 0]]
 
 
            if {$opt == "-value"} {
            if {$opt == "-value"} {
                set result [$widgets(entry) get]
                set result [$widgets(entry) get]
            } else {
            } else {
                set result $options($opt)
                set result $options($opt)
            }
            }
        }
        }
 
 
        configure {
        configure {
            set result [eval ::combobox::Configure {$w} $args]
            set result [eval ::combobox::Configure {$w} $args]
        }
        }
 
 
        default {
        default {
            error "bad option \"$command\""
            error "bad option \"$command\""
        }
        }
    }
    }
 
 
    return $result
    return $result
}
}
 
 
# ::combobox::Configure --
# ::combobox::Configure --
#
#
#    Implements the "configure" widget subcommand
#    Implements the "configure" widget subcommand
#
#
# Arguments:
# Arguments:
#
#
#    w      widget pathname
#    w      widget pathname
#    args   zero or more option/value pairs (or a single option)
#    args   zero or more option/value pairs (or a single option)
#
#
# Results:
# Results:
#    
#
#    Performs typcial "configure" type requests on the widget
#    Performs typcial "configure" type requests on the widget
 
 
proc ::combobox::Configure {w args} {
proc ::combobox::Configure {w args} {
    variable widgetOptions
    variable widgetOptions
    variable defaultEntryCursor
    variable defaultEntryCursor
 
 
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    if {[llength $args] == 0} {
    if {[llength $args] == 0} {
        # hmmm. User must be wanting all configuration information
        # hmmm. User must be wanting all configuration information
        # note that if the value of an array element is of length
        # note that if the value of an array element is of length
        # one it is an alias, which needs to be handled slightly
        # one it is an alias, which needs to be handled slightly
        # differently
        # differently
        set results {}
        set results {}
        foreach opt [lsort [array names widgetOptions]] {
        foreach opt [lsort [array names widgetOptions]] {
            if {[llength $widgetOptions($opt)] == 1} {
            if {[llength $widgetOptions($opt)] == 1} {
                set alias $widgetOptions($opt)
                set alias $widgetOptions($opt)
                set optName $widgetOptions($alias)
                set optName $widgetOptions($alias)
                lappend results [list $opt $optName]
                lappend results [list $opt $optName]
            } else {
            } else {
                set optName  [lindex $widgetOptions($opt) 0]
                set optName  [lindex $widgetOptions($opt) 0]
                set optClass [lindex $widgetOptions($opt) 1]
                set optClass [lindex $widgetOptions($opt) 1]
                set default [option get $w $optName $optClass]
                set default [option get $w $optName $optClass]
                if {[info exists options($opt)]} {
                if {[info exists options($opt)]} {
                    lappend results [list $opt $optName $optClass \
                    lappend results [list $opt $optName $optClass \
                            $default $options($opt)]
                            $default $options($opt)]
                } else {
                } else {
                    lappend results [list $opt $optName $optClass \
                    lappend results [list $opt $optName $optClass \
                            $default ""]
                            $default ""]
                }
                }
            }
            }
        }
        }
 
 
        return $results
        return $results
    }
    }
 
 
    # one argument means we are looking for configuration
    # one argument means we are looking for configuration
    # information on a single option
    # information on a single option
    if {[llength $args] == 1} {
    if {[llength $args] == 1} {
        set opt [::combobox::Canonize $w option [lindex $args 0]]
        set opt [::combobox::Canonize $w option [lindex $args 0]]
 
 
        set optName  [lindex $widgetOptions($opt) 0]
        set optName  [lindex $widgetOptions($opt) 0]
        set optClass [lindex $widgetOptions($opt) 1]
        set optClass [lindex $widgetOptions($opt) 1]
        set default [option get $w $optName $optClass]
        set default [option get $w $optName $optClass]
        set results [list $opt $optName $optClass \
        set results [list $opt $optName $optClass \
                $default $options($opt)]
                $default $options($opt)]
        return $results
        return $results
    }
    }
 
 
    # if we have an odd number of values, bail. 
    # if we have an odd number of values, bail.
    if {[expr {[llength $args]%2}] == 1} {
    if {[expr {[llength $args]%2}] == 1} {
        # hmmm. An odd number of elements in args
        # hmmm. An odd number of elements in args
        error "value for \"[lindex $args end]\" missing"
        error "value for \"[lindex $args end]\" missing"
    }
    }
 
 
    # Great. An even number of options. Let's make sure they 
    # Great. An even number of options. Let's make sure they
    # are all valid before we do anything. Note that Canonize
    # are all valid before we do anything. Note that Canonize
    # will generate an error if it finds a bogus option; otherwise
    # will generate an error if it finds a bogus option; otherwise
    # it returns the canonical option name
    # it returns the canonical option name
    foreach {name value} $args {
    foreach {name value} $args {
        set name [::combobox::Canonize $w option $name]
        set name [::combobox::Canonize $w option $name]
        set opts($name) $value
        set opts($name) $value
    }
    }
 
 
    # process all of the configuration options
    # process all of the configuration options
    # some (actually, most) options require us to
    # some (actually, most) options require us to
    # do something, like change the attributes of
    # do something, like change the attributes of
    # a widget or two. Here's where we do that...
    # a widget or two. Here's where we do that...
    #
    #
    # note that the handling of disabledforeground and
    # note that the handling of disabledforeground and
    # disabledbackground is a little wonky. First, we have
    # disabledbackground is a little wonky. First, we have
    # to deal with backwards compatibility (ie: tk 8.3 and below
    # to deal with backwards compatibility (ie: tk 8.3 and below
    # didn't have such options for the entry widget), and
    # didn't have such options for the entry widget), and
    # we have to deal with the fact we might want to disable
    # we have to deal with the fact we might want to disable
    # the entry widget but use the normal foreground/background
    # the entry widget but use the normal foreground/background
    # for when the combobox is not disabled, but not editable either.
    # for when the combobox is not disabled, but not editable either.
 
 
    set updateVisual 0
    set updateVisual 0
    foreach option [array names opts] {
    foreach option [array names opts] {
        set newValue $opts($option)
        set newValue $opts($option)
        if {[info exists options($option)]} {
        if {[info exists options($option)]} {
            set oldValue $options($option)
            set oldValue $options($option)
        }
        }
 
 
        switch -- $option {
        switch -- $option {
            -buttonbackground {
            -buttonbackground {
                $widgets(button) configure -background $newValue
                $widgets(button) configure -background $newValue
            }
            }
            -background {
            -background {
                set updateVisual 1
                set updateVisual 1
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -borderwidth {
            -borderwidth {
                $widgets(frame) configure -borderwidth $newValue
                $widgets(frame) configure -borderwidth $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -command {
            -command {
                # nothing else to do...
                # nothing else to do...
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -commandstate {
            -commandstate {
                # do some value checking...
                # do some value checking...
                if {$newValue != "normal" && $newValue != "disabled"} {
                if {$newValue != "normal" && $newValue != "disabled"} {
                    set options($option) $oldValue
                    set options($option) $oldValue
                    set message "bad state value \"$newValue\";"
                    set message "bad state value \"$newValue\";"
                    append message " must be normal or disabled"
                    append message " must be normal or disabled"
                    error $message
                    error $message
                }
                }
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -cursor {
            -cursor {
                $widgets(frame) configure -cursor $newValue
                $widgets(frame) configure -cursor $newValue
                $widgets(entry) configure -cursor $newValue
                $widgets(entry) configure -cursor $newValue
                $widgets(listbox) configure -cursor $newValue
                $widgets(listbox) configure -cursor $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -disabledforeground {
            -disabledforeground {
                set updateVisual 1
                set updateVisual 1
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -disabledbackground {
            -disabledbackground {
                set updateVisual 1
                set updateVisual 1
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -dropdownwidth {
            -dropdownwidth {
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -editable {
            -editable {
                set updateVisual 1
                set updateVisual 1
                if {$newValue} {
                if {$newValue} {
                    # it's editable...
                    # it's editable...
                    $widgets(entry) configure \
                    $widgets(entry) configure \
                            -state normal \
                            -state normal \
                            -cursor $defaultEntryCursor
                            -cursor $defaultEntryCursor
                } else {
                } else {
                    $widgets(entry) configure \
                    $widgets(entry) configure \
                            -state disabled \
                            -state disabled \
                            -cursor $options(-cursor)
                            -cursor $options(-cursor)
                }
                }
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -elementborderwidth {
            -elementborderwidth {
                $widgets(button) configure -borderwidth $newValue
                $widgets(button) configure -borderwidth $newValue
                $widgets(vsb) configure -borderwidth $newValue
                $widgets(vsb) configure -borderwidth $newValue
                $widgets(dropdown) configure -borderwidth $newValue
                $widgets(dropdown) configure -borderwidth $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -font {
            -font {
                $widgets(entry) configure -font $newValue
                $widgets(entry) configure -font $newValue
                $widgets(listbox) configure -font $newValue
                $widgets(listbox) configure -font $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -foreground {
            -foreground {
                set updateVisual 1
                set updateVisual 1
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -height {
            -height {
                $widgets(listbox) configure -height $newValue
                $widgets(listbox) configure -height $newValue
                HandleScrollbar $w
                HandleScrollbar $w
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -highlightbackground {
            -highlightbackground {
                $widgets(frame) configure -highlightbackground $newValue
                $widgets(frame) configure -highlightbackground $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -highlightcolor {
            -highlightcolor {
                $widgets(frame) configure -highlightcolor $newValue
                $widgets(frame) configure -highlightcolor $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -highlightthickness {
            -highlightthickness {
                $widgets(frame) configure -highlightthickness $newValue
                $widgets(frame) configure -highlightthickness $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -image {
            -image {
                if {[string length $newValue] > 0} {
                if {[string length $newValue] > 0} {
                    puts "old button width: [$widgets(button) cget -width]"
                    puts "old button width: [$widgets(button) cget -width]"
                    $widgets(button) configure \
                    $widgets(button) configure \
                        -image $newValue \
                        -image $newValue \
                        -width [expr {[image width $newValue] + 2}]
                        -width [expr {[image width $newValue] + 2}]
                    puts "new button width: [$widgets(button) cget -width]"
                    puts "new button width: [$widgets(button) cget -width]"
 
 
                } else {
                } else {
                    $widgets(button) configure -image ::combobox::bimage
                    $widgets(button) configure -image ::combobox::bimage
                }
                }
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -listvar {
            -listvar {
                if {[catch {$widgets(listbox) cget -listvar}]} {
                if {[catch {$widgets(listbox) cget -listvar}]} {
                    return -code error \
                    return -code error \
                        "-listvar not supported with this version of tk"
                        "-listvar not supported with this version of tk"
                }
                }
                $widgets(listbox) configure -listvar $newValue
                $widgets(listbox) configure -listvar $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -maxheight {
            -maxheight {
                # ComputeGeometry may dork with the actual height
                # ComputeGeometry may dork with the actual height
                # of the listbox, so let's undork it
                # of the listbox, so let's undork it
                $widgets(listbox) configure -height $options(-height)
                $widgets(listbox) configure -height $options(-height)
                HandleScrollbar $w
                HandleScrollbar $w
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -opencommand {
            -opencommand {
                # nothing else to do...
                # nothing else to do...
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -relief {
            -relief {
                $widgets(frame) configure -relief $newValue
                $widgets(frame) configure -relief $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -selectbackground {
            -selectbackground {
                $widgets(entry) configure -selectbackground $newValue
                $widgets(entry) configure -selectbackground $newValue
                $widgets(listbox) configure -selectbackground $newValue
                $widgets(listbox) configure -selectbackground $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -selectborderwidth {
            -selectborderwidth {
                $widgets(entry) configure -selectborderwidth $newValue
                $widgets(entry) configure -selectborderwidth $newValue
                $widgets(listbox) configure -selectborderwidth $newValue
                $widgets(listbox) configure -selectborderwidth $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -selectforeground {
            -selectforeground {
                $widgets(entry) configure -selectforeground $newValue
                $widgets(entry) configure -selectforeground $newValue
                $widgets(listbox) configure -selectforeground $newValue
                $widgets(listbox) configure -selectforeground $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -state {
            -state {
                if {$newValue == "normal"} {
                if {$newValue == "normal"} {
                    set updateVisual 1
                    set updateVisual 1
                    # it's enabled
                    # it's enabled
 
 
                    set editable [::combobox::GetBoolean \
                    set editable [::combobox::GetBoolean \
                            $options(-editable)]
                            $options(-editable)]
                    if {$editable} {
                    if {$editable} {
                        $widgets(entry) configure -state normal
                        $widgets(entry) configure -state normal
                        $widgets(entry) configure -takefocus 1
                        $widgets(entry) configure -takefocus 1
                    }
                    }
 
 
                    # note that $widgets(button) is actually a label,
                    # note that $widgets(button) is actually a label,
                    # not a button. And being able to disable labels
                    # not a button. And being able to disable labels
                    # wasn't possible until tk 8.3. (makes me wonder
                    # wasn't possible until tk 8.3. (makes me wonder
                    # why I chose to use a label, but that answer is
                    # why I chose to use a label, but that answer is
                    # lost to antiquity)
                    # lost to antiquity)
                    if {[info patchlevel] >= 8.3} {
                    if {[info patchlevel] >= 8.3} {
                        $widgets(button) configure -state normal
                        $widgets(button) configure -state normal
                    }
                    }
 
 
                } elseif {$newValue == "disabled"}  {
                } elseif {$newValue == "disabled"}  {
                    set updateVisual 1
                    set updateVisual 1
                    # it's disabled
                    # it's disabled
                    $widgets(entry) configure -state disabled
                    $widgets(entry) configure -state disabled
                    $widgets(entry) configure -takefocus 0
                    $widgets(entry) configure -takefocus 0
                    # note that $widgets(button) is actually a label,
                    # note that $widgets(button) is actually a label,
                    # not a button. And being able to disable labels
                    # not a button. And being able to disable labels
                    # wasn't possible until tk 8.3. (makes me wonder
                    # wasn't possible until tk 8.3. (makes me wonder
                    # why I chose to use a label, but that answer is
                    # why I chose to use a label, but that answer is
                    # lost to antiquity)
                    # lost to antiquity)
                    if {$::tcl_version >= 8.3} {
                    if {$::tcl_version >= 8.3} {
                        $widgets(button) configure -state disabled
                        $widgets(button) configure -state disabled
                    }
                    }
 
 
                } else {
                } else {
                    set options($option) $oldValue
                    set options($option) $oldValue
                    set message "bad state value \"$newValue\";"
                    set message "bad state value \"$newValue\";"
                    append message " must be normal or disabled"
                    append message " must be normal or disabled"
                    error $message
                    error $message
                }
                }
 
 
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -takefocus {
            -takefocus {
                $widgets(entry) configure -takefocus $newValue
                $widgets(entry) configure -takefocus $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -textvariable {
            -textvariable {
                $widgets(entry) configure -textvariable $newValue
                $widgets(entry) configure -textvariable $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -value {
            -value {
                ::combobox::SetValue $widgets(this) $newValue
                ::combobox::SetValue $widgets(this) $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -width {
            -width {
                $widgets(entry) configure -width $newValue
                $widgets(entry) configure -width $newValue
                $widgets(listbox) configure -width $newValue
                $widgets(listbox) configure -width $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
 
 
            -xscrollcommand {
            -xscrollcommand {
                $widgets(entry) configure -xscrollcommand $newValue
                $widgets(entry) configure -xscrollcommand $newValue
                set options($option) $newValue
                set options($option) $newValue
            }
            }
        }
        }
 
 
        if {$updateVisual} {UpdateVisualAttributes $w}
        if {$updateVisual} {UpdateVisualAttributes $w}
    }
    }
}
}
 
 
# ::combobox::UpdateVisualAttributes --
# ::combobox::UpdateVisualAttributes --
#
#
# sets the visual attributes (foreground, background mostly) 
# sets the visual attributes (foreground, background mostly)
# based on the current state of the widget (normal/disabled, 
# based on the current state of the widget (normal/disabled,
# editable/non-editable)
# editable/non-editable)
#
#
# why a proc for such a simple thing? Well, in addition to the
# why a proc for such a simple thing? Well, in addition to the
# various states of the widget, we also have to consider the 
# various states of the widget, we also have to consider the
# version of tk being used -- versions from 8.4 and beyond have
# version of tk being used -- versions from 8.4 and beyond have
# the notion of disabled foreground/background options for various
# the notion of disabled foreground/background options for various
# widgets. All of the permutations can get nasty, so we encapsulate
# widgets. All of the permutations can get nasty, so we encapsulate
# it all in one spot.
# it all in one spot.
#
#
# note also that we don't handle all visual attributes here; just
# note also that we don't handle all visual attributes here; just
# the ones that depend on the state of the widget. The rest are 
# the ones that depend on the state of the widget. The rest are
# handled on a case by case basis
# handled on a case by case basis
#
#
# Arguments:
# Arguments:
#    w          widget pathname
#    w          widget pathname
#
#
# Returns:
# Returns:
#    empty string
#    empty string
 
 
proc ::combobox::UpdateVisualAttributes {w} {
proc ::combobox::UpdateVisualAttributes {w} {
 
 
    upvar ::combobox::${w}::widgets     widgets
    upvar ::combobox::${w}::widgets     widgets
    upvar ::combobox::${w}::options     options
    upvar ::combobox::${w}::options     options
 
 
    if {$options(-state) == "normal"} {
    if {$options(-state) == "normal"} {
 
 
        set foreground $options(-foreground)
        set foreground $options(-foreground)
        set background $options(-background)
        set background $options(-background)
 
 
    } elseif {$options(-state) == "disabled"} {
    } elseif {$options(-state) == "disabled"} {
 
 
        set foreground $options(-disabledforeground)
        set foreground $options(-disabledforeground)
        set background $options(-disabledbackground)
        set background $options(-disabledbackground)
    }
    }
 
 
    $widgets(entry)   configure -foreground $foreground -background $background
    $widgets(entry)   configure -foreground $foreground -background $background
    $widgets(listbox) configure -foreground $foreground -background $background
    $widgets(listbox) configure -foreground $foreground -background $background
    $widgets(button)  configure -foreground $foreground
    $widgets(button)  configure -foreground $foreground
    $widgets(vsb)     configure -background $background -troughcolor $background
    $widgets(vsb)     configure -background $background -troughcolor $background
    $widgets(frame)   configure -background $background
    $widgets(frame)   configure -background $background
 
 
    # we need to set the disabled colors in case our widget is disabled. 
    # we need to set the disabled colors in case our widget is disabled.
    # We could actually check for disabled-ness, but we also need to 
    # We could actually check for disabled-ness, but we also need to
    # check whether we're enabled but not editable, in which case the 
    # check whether we're enabled but not editable, in which case the
    # entry widget is disabled but we still want the enabled colors. It's
    # entry widget is disabled but we still want the enabled colors. It's
    # easier just to set everything and be done with it.
    # easier just to set everything and be done with it.
 
 
    if {$::tcl_version >= 8.4} {
    if {$::tcl_version >= 8.4} {
        $widgets(entry) configure \
        $widgets(entry) configure \
            -disabledforeground $foreground \
            -disabledforeground $foreground \
            -disabledbackground $background
            -disabledbackground $background
        $widgets(button)  configure -disabledforeground $foreground
        $widgets(button)  configure -disabledforeground $foreground
        $widgets(listbox) configure -disabledforeground $foreground
        $widgets(listbox) configure -disabledforeground $foreground
    }
    }
}
}
 
 
# ::combobox::SetValue --
# ::combobox::SetValue --
#
#
#    sets the value of the combobox and calls the -command, 
#    sets the value of the combobox and calls the -command,
#    if defined
#    if defined
#
#
# Arguments:
# Arguments:
#
#
#    w          widget pathname
#    w          widget pathname
#    newValue   the new value of the combobox
#    newValue   the new value of the combobox
#
#
# Returns
# Returns
#
#
#    Empty string
#    Empty string
 
 
proc ::combobox::SetValue {w newValue} {
proc ::combobox::SetValue {w newValue} {
 
 
    upvar ::combobox::${w}::widgets     widgets
    upvar ::combobox::${w}::widgets     widgets
    upvar ::combobox::${w}::options     options
    upvar ::combobox::${w}::options     options
    upvar ::combobox::${w}::ignoreTrace ignoreTrace
    upvar ::combobox::${w}::ignoreTrace ignoreTrace
    upvar ::combobox::${w}::oldValue    oldValue
    upvar ::combobox::${w}::oldValue    oldValue
 
 
    if {[info exists options(-textvariable)] \
    if {[info exists options(-textvariable)] \
            && [string length $options(-textvariable)] > 0} {
            && [string length $options(-textvariable)] > 0} {
        set variable ::$options(-textvariable)
        set variable ::$options(-textvariable)
        set $variable $newValue
        set $variable $newValue
    } else {
    } else {
        set oldstate [$widgets(entry) cget -state]
        set oldstate [$widgets(entry) cget -state]
        $widgets(entry) configure -state normal
        $widgets(entry) configure -state normal
        $widgets(entry) delete 0 end
        $widgets(entry) delete 0 end
        $widgets(entry) insert 0 $newValue
        $widgets(entry) insert 0 $newValue
        $widgets(entry) configure -state $oldstate
        $widgets(entry) configure -state $oldstate
    }
    }
 
 
    # set our internal textvariable; this will cause any public
    # set our internal textvariable; this will cause any public
    # textvariable (ie: defined by the user) to be updated as
    # textvariable (ie: defined by the user) to be updated as
    # well
    # well
#    set ::combobox::${w}::entryTextVariable $newValue
#    set ::combobox::${w}::entryTextVariable $newValue
 
 
    # redefine our concept of the "old value". Do it before running
    # redefine our concept of the "old value". Do it before running
    # any associated command so we can be sure it happens even
    # any associated command so we can be sure it happens even
    # if the command somehow fails.
    # if the command somehow fails.
    set oldValue $newValue
    set oldValue $newValue
 
 
 
 
    # call the associated command. The proc will handle whether or 
    # call the associated command. The proc will handle whether or
    # not to actually call it, and with what args
    # not to actually call it, and with what args
    CallCommand $w $newValue
    CallCommand $w $newValue
 
 
    return ""
    return ""
}
}
 
 
# ::combobox::CallCommand --
# ::combobox::CallCommand --
#
#
#   calls the associated command, if any, appending the new
#   calls the associated command, if any, appending the new
#   value to the command to be called.
#   value to the command to be called.
#
#
# Arguments:
# Arguments:
#
#
#    w         widget pathname
#    w         widget pathname
#    newValue  the new value of the combobox
#    newValue  the new value of the combobox
#
#
# Returns
# Returns
#
#
#    empty string
#    empty string
 
 
proc ::combobox::CallCommand {w newValue} {
proc ::combobox::CallCommand {w newValue} {
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::widgets widgets
    upvar ::combobox::${w}::options options
    upvar ::combobox::${w}::options options
 
 
    # call the associated command, if defined and -commandstate is
    # call the associated command, if defined and -commandstate is
    # set to "normal"
    # set to "normal"
    if {$options(-commandstate) == "normal" && \
    if {$options(-commandstate) == "normal" && \
            [string length $options(-command)] > 0} {
            [string length $options(-command)] > 0} {
        set args [list $widgets(this) $newValue]
        set args [list $widgets(this) $newValue]
        uplevel \#0 $options(-command) $args
        uplevel \#0 $options(-command) $args
    }
    }
}
}
 
 
 
 
# ::combobox::GetBoolean --
# ::combobox::GetBoolean --
#
#
#     returns the value of a (presumably) boolean string (ie: it should
#     returns the value of a (presumably) boolean string (ie: it should
#     do the right thing if the string is "yes", "no", "true", 1, etc
#     do the right thing if the string is "yes", "no", "true", 1, etc
#
#
# Arguments:
# Arguments:
#
#
#     value       value to be converted 
#     value       value to be converted
#     errorValue  a default value to be returned in case of an error
#     errorValue  a default value to be returned in case of an error
#
#
# Returns:
# Returns:
#
#
#     a 1 or zero, or the value of errorValue if the string isn't
#     a 1 or zero, or the value of errorValue if the string isn't
#     a proper boolean value
#     a proper boolean value
 
 
proc ::combobox::GetBoolean {value {errorValue 1}} {
proc ::combobox::GetBoolean {value {errorValue 1}} {
    if {[catch {expr {([string trim $value])?1:0}} res]} {
    if {[catch {expr {([string trim $value])?1:0}} res]} {
        return $errorValue
        return $errorValue
    } else {
    } else {
        return $res
        return $res
    }
    }
}
}
 
 
# ::combobox::convert --
# ::combobox::convert --
#
#
#     public routine to convert %x, %y and %W binding substitutions.
#     public routine to convert %x, %y and %W binding substitutions.
#     Given an x, y and or %W value relative to a given widget, this
#     Given an x, y and or %W value relative to a given widget, this
#     routine will convert the values to be relative to the combobox
#     routine will convert the values to be relative to the combobox
#     widget. For example, it could be used in a binding like this:
#     widget. For example, it could be used in a binding like this:
#
#
#     bind .combobox <blah> {doSomething [::combobox::convert %W -x %x]}
#     bind .combobox <blah> {doSomething [::combobox::convert %W -x %x]}
#
#
#     Note that this procedure is *not* exported, but is intended for
#     Note that this procedure is *not* exported, but is intended for
#     public use. It is not exported because the name could easily 
#     public use. It is not exported because the name could easily
#     clash with existing commands. 
#     clash with existing commands.
#
#
# Arguments:
# Arguments:
#
#
#     w     a widget path; typically the actual result of a %W 
#     w     a widget path; typically the actual result of a %W
#           substitution in a binding. It should be either a
#           substitution in a binding. It should be either a
#           combobox widget or one of its subwidgets
#           combobox widget or one of its subwidgets
#
#
#     args  should one or more of the following arguments or 
#     args  should one or more of the following arguments or
#           pairs of arguments:
#           pairs of arguments:
#
#
#           -x <x>      will convert the value <x>; typically <x> will
#           -x <x>      will convert the value <x>; typically <x> will
#                       be the result of a %x substitution
#                       be the result of a %x substitution
#           -y <y>      will convert the value <y>; typically <y> will
#           -y <y>      will convert the value <y>; typically <y> will
#                       be the result of a %y substitution
#                       be the result of a %y substitution
#           -W (or -w)  will return the name of the combobox widget
#           -W (or -w)  will return the name of the combobox widget
#                       which is the parent of $w
#                       which is the parent of $w
#
#
# Returns:
# Returns:
#
#
#     a list of the requested values. For example, a single -w will
#     a list of the requested values. For example, a single -w will
#     result in a list of one items, the name of the combobox widget.
#     result in a list of one items, the name of the combobox widget.
#     Supplying "-x 10 -y 20 -W" (in any order) will return a list of
#     Supplying "-x 10 -y 20 -W" (in any order) will return a list of
#     three values: the converted x and y values, and the name of 
#     three values: the converted x and y values, and the name of
#     the combobox widget.
#     the combobox widget.
 
 
proc ::combobox::convert {w args} {
proc ::combobox::convert {w args} {
    set result {}
    set result {}
    if {![winfo exists $w]} {
    if {![winfo exists $w]} {
        error "window \"$w\" doesn't exist"
        error "window \"$w\" doesn't exist"
    }
    }
 
 
    while {[llength $args] > 0} {
    while {[llength $args] > 0} {
        set option [lindex $args 0]
        set option [lindex $args 0]
        set args [lrange $args 1 end]
        set args [lrange $args 1 end]
 
 
        switch -exact -- $option {
        switch -exact -- $option {
            -x {
            -x {
                set value [lindex $args 0]
                set value [lindex $args 0]
                set args [lrange $args 1 end]
                set args [lrange $args 1 end]
                set win $w
                set win $w
                while {[winfo class $win] != "Combobox"} {
                while {[winfo class $win] != "Combobox"} {
                    incr value [winfo x $win]
                    incr value [winfo x $win]
                    set win [winfo parent $win]
                    set win [winfo parent $win]
                    if {$win == "."} break
                    if {$win == "."} break
                }
                }
                lappend result $value
                lappend result $value
            }
            }
 
 
            -y {
            -y {
                set value [lindex $args 0]
                set value [lindex $args 0]
                set args [lrange $args 1 end]
                set args [lrange $args 1 end]
                set win $w
                set win $w
                while {[winfo class $win] != "Combobox"} {
                while {[winfo class $win] != "Combobox"} {
                    incr value [winfo y $win]
                    incr value [winfo y $win]
                    set win [winfo parent $win]
                    set win [winfo parent $win]
                    if {$win == "."} break
                    if {$win == "."} break
                }
                }
                lappend result $value
                lappend result $value
            }
            }
 
 
            -w -
            -w -
            -W {
            -W {
                set win $w
                set win $w
                while {[winfo class $win] != "Combobox"} {
                while {[winfo class $win] != "Combobox"} {
                    set win [winfo parent $win]
                    set win [winfo parent $win]
                    if {$win == "."} break;
                    if {$win == "."} break;
                }
                }
                lappend result $win
                lappend result $win
            }
            }
        }
        }
    }
    }
    return $result
    return $result
}
}
 
 
# ::combobox::Canonize --
# ::combobox::Canonize --
#
#
#    takes a (possibly abbreviated) option or command name and either 
#    takes a (possibly abbreviated) option or command name and either
#    returns the canonical name or an error
#    returns the canonical name or an error
#
#
# Arguments:
# Arguments:
#
#
#    w        widget pathname
#    w        widget pathname
#    object   type of object to canonize; must be one of "command",
#    object   type of object to canonize; must be one of "command",
#             "option", "scan command" or "list command"
#             "option", "scan command" or "list command"
#    opt      the option (or command) to be canonized
#    opt      the option (or command) to be canonized
#
#
# Returns:
# Returns:
#
#
#    Returns either the canonical form of an option or command,
#    Returns either the canonical form of an option or command,
#    or raises an error if the option or command is unknown or
#    or raises an error if the option or command is unknown or
#    ambiguous.
#    ambiguous.
 
 
proc ::combobox::Canonize {w object opt} {
proc ::combobox::Canonize {w object opt} {
    variable widgetOptions
    variable widgetOptions
    variable columnOptions
    variable columnOptions
    variable widgetCommands
    variable widgetCommands
    variable listCommands
    variable listCommands
    variable scanCommands
    variable scanCommands
 
 
    switch $object {
    switch $object {
        command {
        command {
            if {[lsearch -exact $widgetCommands $opt] >= 0} {
            if {[lsearch -exact $widgetCommands $opt] >= 0} {
                return $opt
                return $opt
            }
            }
 
 
            # command names aren't stored in an array, and there
            # command names aren't stored in an array, and there
            # isn't a way to get all the matches in a list, so
            # isn't a way to get all the matches in a list, so
            # we'll stuff the commands in a temporary array so
            # we'll stuff the commands in a temporary array so
            # we can use [array names]
            # we can use [array names]
            set list $widgetCommands
            set list $widgetCommands
            foreach element $list {
            foreach element $list {
                set tmp($element) ""
                set tmp($element) ""
            }
            }
            set matches [array names tmp ${opt}*]
            set matches [array names tmp ${opt}*]
        }
        }
 
 
        {list command} {
        {list command} {
            if {[lsearch -exact $listCommands $opt] >= 0} {
            if {[lsearch -exact $listCommands $opt] >= 0} {
                return $opt
                return $opt
            }
            }
 
 
            # command names aren't stored in an array, and there
            # command names aren't stored in an array, and there
            # isn't a way to get all the matches in a list, so
            # isn't a way to get all the matches in a list, so
            # we'll stuff the commands in a temporary array so
            # we'll stuff the commands in a temporary array so
            # we can use [array names]
            # we can use [array names]
            set list $listCommands
            set list $listCommands
            foreach element $list {
            foreach element $list {
                set tmp($element) ""
                set tmp($element) ""
            }
            }
            set matches [array names tmp ${opt}*]
            set matches [array names tmp ${opt}*]
        }
        }
 
 
        {scan command} {
        {scan command} {
            if {[lsearch -exact $scanCommands $opt] >= 0} {
            if {[lsearch -exact $scanCommands $opt] >= 0} {
                return $opt
                return $opt
            }
            }
 
 
            # command names aren't stored in an array, and there
            # command names aren't stored in an array, and there
            # isn't a way to get all the matches in a list, so
            # isn't a way to get all the matches in a list, so
            # we'll stuff the commands in a temporary array so
            # we'll stuff the commands in a temporary array so
            # we can use [array names]
            # we can use [array names]
            set list $scanCommands
            set list $scanCommands
            foreach element $list {
            foreach element $list {
                set tmp($element) ""
                set tmp($element) ""
            }
            }
            set matches [array names tmp ${opt}*]
            set matches [array names tmp ${opt}*]
        }
        }
 
 
        option {
        option {
            if {[info exists widgetOptions($opt)] \
            if {[info exists widgetOptions($opt)] \
                    && [llength $widgetOptions($opt)] == 2} {
                    && [llength $widgetOptions($opt)] == 2} {
                return $opt
                return $opt
            }
            }
            set list [array names widgetOptions]
            set list [array names widgetOptions]
            set matches [array names widgetOptions ${opt}*]
            set matches [array names widgetOptions ${opt}*]
        }
        }
 
 
    }
    }
 
 
    if {[llength $matches] == 0} {
    if {[llength $matches] == 0} {
        set choices [HumanizeList $list]
        set choices [HumanizeList $list]
        error "unknown $object \"$opt\"; must be one of $choices"
        error "unknown $object \"$opt\"; must be one of $choices"
 
 
    } elseif {[llength $matches] == 1} {
    } elseif {[llength $matches] == 1} {
        set opt [lindex $matches 0]
        set opt [lindex $matches 0]
 
 
        # deal with option aliases
        # deal with option aliases
        switch $object {
        switch $object {
            option {
            option {
                set opt [lindex $matches 0]
                set opt [lindex $matches 0]
                if {[llength $widgetOptions($opt)] == 1} {
                if {[llength $widgetOptions($opt)] == 1} {
                    set opt $widgetOptions($opt)
                    set opt $widgetOptions($opt)
                }
                }
            }
            }
        }
        }
 
 
        return $opt
        return $opt
 
 
    } else {
    } else {
        set choices [HumanizeList $list]
        set choices [HumanizeList $list]
        error "ambiguous $object \"$opt\"; must be one of $choices"
        error "ambiguous $object \"$opt\"; must be one of $choices"
    }
    }
}
}
 
 
# ::combobox::HumanizeList --
# ::combobox::HumanizeList --
#
#
#    Returns a human-readable form of a list by separating items
#    Returns a human-readable form of a list by separating items
#    by columns, but separating the last two elements with "or"
#    by columns, but separating the last two elements with "or"
#    (eg: foo, bar or baz)
#    (eg: foo, bar or baz)
#
#
# Arguments:
# Arguments:
#
#
#    list    a valid tcl list
#    list    a valid tcl list
#
#
# Results:
# Results:
#
#
#    A string which as all of the elements joined with ", " or 
#    A string which as all of the elements joined with ", " or
#    the word " or "
#    the word " or "
 
 
proc ::combobox::HumanizeList {list} {
proc ::combobox::HumanizeList {list} {
 
 
    if {[llength $list] == 1} {
    if {[llength $list] == 1} {
        return [lindex $list 0]
        return [lindex $list 0]
    } else {
    } else {
        set list [lsort $list]
        set list [lsort $list]
        set secondToLast [expr {[llength $list] -2}]
        set secondToLast [expr {[llength $list] -2}]
        set most [lrange $list 0 $secondToLast]
        set most [lrange $list 0 $secondToLast]
        set last [lindex $list end]
        set last [lindex $list end]
 
 
        return "[join $most {, }] or $last"
        return "[join $most {, }] or $last"
    }
    }
}
}
 
 
# This is some backwards-compatibility code to handle TIP 44
# This is some backwards-compatibility code to handle TIP 44
# (http://purl.org/tcl/tip/44.html). For all private tk commands
# (http://purl.org/tcl/tip/44.html). For all private tk commands
# used by this widget, we'll make duplicates of the procs in the
# used by this widget, we'll make duplicates of the procs in the
# combobox namespace. 
# combobox namespace.
#
#
# I'm not entirely convinced this is the right thing to do. I probably
# I'm not entirely convinced this is the right thing to do. I probably
# shouldn't even be using the private commands. Then again, maybe the
# shouldn't even be using the private commands. Then again, maybe the
# private commands really should be public. Oh well; it works so it
# private commands really should be public. Oh well; it works so it
# must be OK...
# must be OK...
foreach command {TabToWindow CancelRepeat ListboxUpDown} {
foreach command {TabToWindow CancelRepeat ListboxUpDown} {
    if {[llength [info commands ::combobox::tk$command]] == 1} break;
    if {[llength [info commands ::combobox::tk$command]] == 1} break;
 
 
    set tmp [info commands tk$command]
    set tmp [info commands tk$command]
    set proc ::combobox::tk$command
    set proc ::combobox::tk$command
    if {[llength [info commands tk$command]] == 1} {
    if {[llength [info commands tk$command]] == 1} {
        set command [namespace which [lindex $tmp 0]]
        set command [namespace which [lindex $tmp 0]]
        proc $proc {args} "uplevel $command \$args"
        proc $proc {args} "uplevel $command \$args"
    } else {
    } else {
        if {[llength [info commands ::tk::$command]] == 1} {
        if {[llength [info commands ::tk::$command]] == 1} {
            proc $proc {args} "uplevel ::tk::$command \$args"
            proc $proc {args} "uplevel ::tk::$command \$args"
        }
        }
    }
    }
}
}
 
 
# end of combobox.tcl
# end of combobox.tcl
 
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.