Upgrade to Tcl/Tk 8.5b2
[msysgit.git] / mingw / lib / tk8.5 / ttk / combobox.tcl
blobdf76c04cb928f027a49fd9666f69b8485e3ab2be
2 # $Id: combobox.tcl,v 1.7 2007/10/23 23:24:09 hobbs Exp $
4 # Combobox bindings.
6 # Each combobox $cb has a child $cb.popdown, which contains
7 # a listbox $cb.popdown.l and a scrollbar. The listbox -listvariable
8 # is set to a namespace variable, which is used to synchronize the
9 # combobox values with the listbox values.
12 namespace eval ttk::combobox {
13 variable Values ;# Values($cb) is -listvariable of listbox widget
14 variable State
15 set State(entryPress) 0
18 ### Combobox bindings.
20 # Duplicate the Entry bindings, override if needed:
23 ttk::copyBindings TEntry TCombobox
25 bind TCombobox <KeyPress-Down> { ttk::combobox::Post %W }
26 bind TCombobox <KeyPress-Escape> { ttk::combobox::Unpost %W }
28 bind TCombobox <ButtonPress-1> { ttk::combobox::Press "" %W %x %y }
29 bind TCombobox <Shift-ButtonPress-1> { ttk::combobox::Press "s" %W %x %y }
30 bind TCombobox <Double-ButtonPress-1> { ttk::combobox::Press "2" %W %x %y }
31 bind TCombobox <Triple-ButtonPress-1> { ttk::combobox::Press "3" %W %x %y }
32 bind TCombobox <B1-Motion> { ttk::combobox::Drag %W %x }
34 bind TCombobox <MouseWheel> { ttk::combobox::Scroll %W [expr {%D/-120}] }
35 if {[tk windowingsystem] eq "x11"} {
36 bind TCombobox <ButtonPress-4> { ttk::combobox::Scroll %W -1 }
37 bind TCombobox <ButtonPress-5> { ttk::combobox::Scroll %W 1 }
40 bind TCombobox <<TraverseIn>> { ttk::combobox::TraverseIn %W }
42 ### Combobox listbox bindings.
44 bind ComboboxListbox <ButtonPress-1> { focus %W ; continue }
45 bind ComboboxListbox <ButtonRelease-1> { ttk::combobox::LBSelected %W }
46 bind ComboboxListbox <KeyPress-Return> { ttk::combobox::LBSelected %W }
47 bind ComboboxListbox <KeyPress-Escape> { ttk::combobox::LBCancel %W }
48 bind ComboboxListbox <KeyPress-Tab> { ttk::combobox::LBTab %W next }
49 bind ComboboxListbox <<PrevWindow>> { ttk::combobox::LBTab %W prev }
50 bind ComboboxListbox <Destroy> { ttk::combobox::LBCleanup %W }
51 bind ComboboxListbox <Motion> { ttk::combobox::LBHover %W %x %y }
53 switch -- [tk windowingsystem] {
54 win32 {
55 # Dismiss listbox when user switches to a different application.
56 # NB: *only* do this on Windows (see #1814778)
57 bind ComboboxListbox <FocusOut> { ttk::combobox::LBCancel %W }
61 ### Combobox popdown window bindings.
63 bind ComboboxPopdown <Map> { ttk::combobox::MapPopdown %W }
64 bind ComboboxPopdown <Unmap> { ttk::combobox::UnmapPopdown %W }
65 bind ComboboxPopdown <ButtonPress> \
66 { ttk::combobox::Unpost [winfo parent %W] }
68 ### Option database settings.
71 option add *TCombobox*Listbox.font TkTextFont
72 option add *TCombobox*Listbox.relief flat
73 option add *TCombobox*Listbox.highlightThickness 0
75 ## Platform-specific settings.
77 switch -- [tk windowingsystem] {
78 x11 {
79 option add *TCombobox*Listbox.background white
81 aqua {
82 option add *TCombobox*Listbox.borderWidth 0
86 ### Binding procedures.
89 ## Press $mode $x $y -- ButtonPress binding for comboboxes.
90 # Either post/unpost the listbox, or perform Entry widget binding,
91 # depending on widget state and location of button press.
93 proc ttk::combobox::Press {mode w x y} {
94 variable State
95 set State(entryPress) [expr {
96 [$w instate {!readonly !disabled}]
97 && [string match *textarea [$w identify $x $y]]
100 focus $w
101 if {$State(entryPress)} {
102 switch -- $mode {
103 s { ttk::entry::Shift-Press $w $x ; # Shift }
104 2 { ttk::entry::Select $w $x word ; # Double click}
105 3 { ttk::entry::Select $w $x line ; # Triple click }
106 "" -
107 default { ttk::entry::Press $w $x }
109 } else {
110 Post $w
114 ## Drag -- B1-Motion binding for comboboxes.
115 # If the initial ButtonPress event was handled by Entry binding,
116 # perform Entry widget drag binding; otherwise nothing.
118 proc ttk::combobox::Drag {w x} {
119 variable State
120 if {$State(entryPress)} {
121 ttk::entry::Drag $w $x
125 ## TraverseIn -- receive focus due to keyboard navigation
126 # For editable comboboxes, set the selection and insert cursor.
128 proc ttk::combobox::TraverseIn {w} {
129 $w instate {!readonly !disabled} {
130 $w selection range 0 end
131 $w icursor end
135 ## SelectEntry $cb $index --
136 # Set the combobox selection in response to a user action.
138 proc ttk::combobox::SelectEntry {cb index} {
139 $cb current $index
140 $cb selection range 0 end
141 $cb icursor end
142 event generate $cb <<ComboboxSelected>>
145 ## Scroll -- Mousewheel binding
147 proc ttk::combobox::Scroll {cb dir} {
148 $cb instate disabled { return }
149 set max [llength [$cb cget -values]]
150 set current [$cb current]
151 incr current $dir
152 if {$max != 0 && $current == $current % $max} {
153 SelectEntry $cb $current
157 ## LBSelected $lb -- Activation binding for listbox
158 # Set the combobox value to the currently-selected listbox value
159 # and unpost the listbox.
161 proc ttk::combobox::LBSelected {lb} {
162 set cb [LBMaster $lb]
163 LBSelect $lb
164 Unpost $cb
165 focus $cb
168 ## LBCancel --
169 # Unpost the listbox.
171 proc ttk::combobox::LBCancel {lb} {
172 Unpost [LBMaster $lb]
175 ## LBTab -- Tab key binding for combobox listbox.
176 # Set the selection, and navigate to next/prev widget.
178 proc ttk::combobox::LBTab {lb dir} {
179 set cb [LBMaster $lb]
180 switch -- $dir {
181 next { set newFocus [tk_focusNext $cb] }
182 prev { set newFocus [tk_focusPrev $cb] }
185 if {$newFocus ne ""} {
186 LBSelect $lb
187 Unpost $cb
188 # The [grab release] call in [Unpost] queues events that later
189 # re-set the focus. [update] to make sure these get processed first:
190 update
191 ttk::traverseTo $newFocus
195 ## LBHover -- <Motion> binding for combobox listbox.
196 # Follow selection on mouseover.
198 proc ttk::combobox::LBHover {w x y} {
199 $w selection clear 0 end
200 $w activate @$x,$y
201 $w selection set @$x,$y
204 ## MapPopdown -- <Map> binding for ComboboxPopdown
206 proc ttk::combobox::MapPopdown {w} {
207 [winfo parent $w] state pressed
208 ttk::globalGrab $w
211 ## UnmapPopdown -- <Unmap> binding for ComboboxPopdown
213 proc ttk::combobox::UnmapPopdown {w} {
214 [winfo parent $w] state !pressed
215 ttk::releaseGrab $w
221 namespace eval ::ttk::combobox {
222 # @@@ Until we have a proper native scrollbar on Aqua, use
223 # @@@ the regular Tk one. Use ttk::scrollbar on other platforms.
224 variable scrollbar ttk::scrollbar
225 if {[tk windowingsystem] eq "aqua"} {
226 set scrollbar ::scrollbar
230 ## PopdownWindow --
231 # Returns the popdown widget associated with a combobox,
232 # creating it if necessary.
234 proc ttk::combobox::PopdownWindow {cb} {
235 variable scrollbar
237 set popdown $cb.popdown
238 if {![winfo exists $popdown]} {
239 PopdownToplevel $popdown
241 $scrollbar $popdown.sb \
242 -orient vertical -command [list $popdown.l yview]
243 listbox $popdown.l \
244 -listvariable ttk::combobox::Values($cb) \
245 -yscrollcommand [list $popdown.sb set] \
246 -exportselection false \
247 -selectmode browse \
248 -activestyle none \
251 bindtags $popdown.l \
252 [list $popdown.l ComboboxListbox Listbox $popdown all]
254 grid $popdown.l $popdown.sb -sticky news
255 grid columnconfigure $popdown 0 -weight 1
256 grid rowconfigure $popdown 0 -weight 1
258 # to handle reparented frame/toplevel, recalculate transient each time
259 switch -- [tk windowingsystem] {
260 x11 {
261 wm transient $popdown [winfo toplevel [winfo parent $popdown]]
263 win32 {
264 wm transient $popdown [winfo toplevel [winfo parent $popdown]]
267 return $popdown
270 ## PopdownToplevel -- Create toplevel window for the combobox popdown
272 # NOTES:
273 # On Windows: setting [wm transient] prevents the parent
274 # toplevel from becoming inactive when the popdown is posted
275 # (Tk 8.4.8+)
277 # On X11: WM_TRANSIENT_FOR on override-redirect windows
278 # may be used by compositing managers and by EWMH-aware
279 # window managers (even though the older ICCCM spec says
280 # it's meaningless).
282 # On OSX: for MacWindowStyle "help", "noActivates" prevents
283 # the parent toplevel from deactivating when the popdown
284 # is posted, and is necessary for the popdown to receive
285 # mouse events. "hideOnSuspend" makes the popdown disappear
286 # (resp. reappear) when the parent toplevel is deactivated.
288 proc ttk::combobox::PopdownToplevel {w} {
289 if {![winfo exists $w]} {
290 toplevel $w -class ComboboxPopdown
292 wm withdraw $w
293 switch -- [tk windowingsystem] {
294 default -
295 x11 {
296 $w configure -relief solid -borderwidth 1
297 wm overrideredirect $w true
299 win32 {
300 $w configure -relief solid -borderwidth 1
301 wm overrideredirect $w true
303 aqua {
304 $w configure -relief solid -borderwidth 0
305 tk::unsupported::MacWindowStyle style $w \
306 help {noActivates hideOnSuspend}
309 return $w
312 ## ConfigureListbox --
313 # Set listbox values, selection, height, and scrollbar visibility
314 # from current combobox values.
316 proc ttk::combobox::ConfigureListbox {cb} {
317 variable Values
319 set popdown [PopdownWindow $cb]
320 set values [$cb cget -values]
321 set current [$cb current]
322 if {$current < 0} {
323 set current 0 ;# no current entry, highlight first one
325 set Values($cb) $values
326 $popdown.l selection clear 0 end
327 $popdown.l selection set $current
328 $popdown.l activate $current
329 $popdown.l see $current
330 set height [llength $values]
331 if {$height > [$cb cget -height]} {
332 set height [$cb cget -height]
333 grid $popdown.sb
334 } else {
335 grid remove $popdown.sb
337 $popdown.l configure -height $height
340 ## PlacePopdown --
341 # Set popdown window geometry.
343 # @@@TODO: factor with menubutton::PostPosition
345 proc ttk::combobox::PlacePopdown {cb popdown} {
346 set x [winfo rootx $cb]
347 set y [winfo rooty $cb]
348 set w [winfo width $cb]
349 set h [winfo height $cb]
350 set postoffset [ttk::style lookup TCombobox -postoffset {} {0 0 0 0}]
351 foreach var {x y w h} delta $postoffset {
352 incr $var $delta
355 set H [winfo reqheight $popdown]
356 if {$y + $h + $H > [winfo screenheight $popdown]} {
357 set Y [expr {$y - $H}]
358 } else {
359 set Y [expr {$y + $h}]
361 wm geometry $popdown ${w}x${H}+${x}+${Y}
364 ## Post $cb --
365 # Pop down the associated listbox.
367 proc ttk::combobox::Post {cb} {
368 # Don't do anything if disabled:
370 $cb instate disabled { return }
372 # ASSERT: ![$cb instate pressed]
374 # Run -postcommand callback:
376 uplevel #0 [$cb cget -postcommand]
378 set popdown [PopdownWindow $cb]
379 ConfigureListbox $cb
380 update idletasks
381 PlacePopdown $cb $popdown
383 # Post the listbox:
385 wm deiconify $popdown
386 raise $popdown
387 focus $popdown.l
390 ## Unpost $cb --
391 # Unpost the listbox.
393 proc ttk::combobox::Unpost {cb} {
394 wm withdraw $cb.popdown
395 grab release $cb.popdown ;# in case of stuck or unexpected grab [#1239190]
398 ## LBMaster $lb --
399 # Return the combobox main widget that owns the listbox.
401 proc ttk::combobox::LBMaster {lb} {
402 winfo parent [winfo parent $lb]
405 ## LBSelect $lb --
406 # Transfer listbox selection to combobox value.
408 proc ttk::combobox::LBSelect {lb} {
409 set cb [LBMaster $lb]
410 set selection [$lb curselection]
411 if {[llength $selection] == 1} {
412 SelectEntry $cb [lindex $selection 0]
416 ## LBCleanup $lb --
417 # <Destroy> binding for combobox listboxes.
418 # Cleans up by unsetting the linked textvariable.
420 # Note: we can't just use { unset [%W cget -listvariable] }
421 # because the widget command is already gone when this binding fires).
422 # [winfo parent] still works, fortunately.
424 proc ttk::combobox::LBCleanup {lb} {
425 variable Values
426 unset Values([LBMaster $lb])
429 #*EOF*