| 1 | #
 | 
|---|
| 2 | # tabnotebook.tcl
 | 
|---|
| 3 | #
 | 
|---|
| 4 | # ----------------------------------------------------------------------
 | 
|---|
| 5 | # Bindings for the BLT tabnotebook widget
 | 
|---|
| 6 | # ----------------------------------------------------------------------
 | 
|---|
| 7 | #   AUTHOR:  George Howlett
 | 
|---|
| 8 | #            Bell Labs Innovations for Lucent Technologies
 | 
|---|
| 9 | #            gah@bell-labs.com
 | 
|---|
| 10 | #            http://www.tcltk.com/blt
 | 
|---|
| 11 | # ----------------------------------------------------------------------
 | 
|---|
| 12 | # Copyright (c) 1998  Lucent Technologies, Inc.
 | 
|---|
| 13 | # ======================================================================
 | 
|---|
| 14 | #
 | 
|---|
| 15 | # Permission to use, copy, modify, and distribute this software and its
 | 
|---|
| 16 | # documentation for any purpose and without fee is hereby granted,
 | 
|---|
| 17 | # provided that the above copyright notice appear in all copies and that
 | 
|---|
| 18 | # both that the copyright notice and warranty disclaimer appear in
 | 
|---|
| 19 | # supporting documentation, and that the names of Lucent Technologies
 | 
|---|
| 20 | # any of their entities not be used in advertising or publicity
 | 
|---|
| 21 | # pertaining to distribution of the software without specific, written
 | 
|---|
| 22 | # prior permission.
 | 
|---|
| 23 | #
 | 
|---|
| 24 | # Lucent Technologies disclaims all warranties with regard to this
 | 
|---|
| 25 | # software, including all implied warranties of merchantability and
 | 
|---|
| 26 | # fitness.  In no event shall Lucent be liable for any special, indirect
 | 
|---|
| 27 | # or consequential damages or any damages whatsoever resulting from loss
 | 
|---|
| 28 | # of use, data or profits, whether in an action of contract, negligence
 | 
|---|
| 29 | # or other tortuous action, arising out of or in connection with the use
 | 
|---|
| 30 | # or performance of this software.
 | 
|---|
| 31 | #
 | 
|---|
| 32 | # ======================================================================
 | 
|---|
| 33 | 
 | 
|---|
| 34 | #
 | 
|---|
| 35 | # Indicates whether to activate (highlight) tabs when the mouse passes
 | 
|---|
| 36 | # over them.  This is turned off during scan operations.
 | 
|---|
| 37 | #
 | 
|---|
| 38 | set bltTabnotebook(activate) yes
 | 
|---|
| 39 | 
 | 
|---|
| 40 | # ----------------------------------------------------------------------
 | 
|---|
| 41 | # 
 | 
|---|
| 42 | # ButtonPress assignments
 | 
|---|
| 43 | #
 | 
|---|
| 44 | #   <ButtonPress-2>     Starts scan mechanism (pushes the tabs)
 | 
|---|
| 45 | #   <B2-Motion>         Adjust scan
 | 
|---|
| 46 | #   <ButtonRelease-2>   Stops scan
 | 
|---|
| 47 | #
 | 
|---|
| 48 | # ----------------------------------------------------------------------
 | 
|---|
| 49 | bind Tabnotebook <B2-Motion> {
 | 
|---|
| 50 |     %W scan dragto %x %y
 | 
|---|
| 51 | }
 | 
|---|
| 52 | 
 | 
|---|
| 53 | bind Tabnotebook <ButtonPress-2> {
 | 
|---|
| 54 |     set bltTabnotebook(cursor) [%W cget -cursor]
 | 
|---|
| 55 |     set bltTabnotebook(activate) no
 | 
|---|
| 56 |     %W configure -cursor hand1
 | 
|---|
| 57 |     %W scan mark %x %y
 | 
|---|
| 58 | }
 | 
|---|
| 59 | 
 | 
|---|
| 60 | bind Tabnotebook <ButtonRelease-2> {
 | 
|---|
| 61 |     %W configure -cursor $bltTabnotebook(cursor)
 | 
|---|
| 62 |     set bltTabnotebook(activate) yes
 | 
|---|
| 63 |     %W activate @%x,%y
 | 
|---|
| 64 | }
 | 
|---|
| 65 | 
 | 
|---|
| 66 | # ----------------------------------------------------------------------
 | 
|---|
| 67 | # 
 | 
|---|
| 68 | # KeyPress assignments
 | 
|---|
| 69 | #
 | 
|---|
| 70 | #   <KeyPress-Up>       Moves focus to the tab immediately above the 
 | 
|---|
| 71 | #                       current.
 | 
|---|
| 72 | #   <KeyPress-Down>     Moves focus to the tab immediately below the 
 | 
|---|
| 73 | #                       current.
 | 
|---|
| 74 | #   <KeyPress-Left>     Moves focus to the tab immediately left of the 
 | 
|---|
| 75 | #                       currently focused tab.
 | 
|---|
| 76 | #   <KeyPress-Right>    Moves focus to the tab immediately right of the 
 | 
|---|
| 77 | #                       currently focused tab.
 | 
|---|
| 78 | #   <KeyPress-space>    Invokes the commands associated with the current
 | 
|---|
| 79 | #                       tab.
 | 
|---|
| 80 | #   <KeyPress-Return>   Same as above.
 | 
|---|
| 81 | #   <KeyPress>          Go to next tab starting with the ASCII character.
 | 
|---|
| 82 | #
 | 
|---|
| 83 | # ----------------------------------------------------------------------
 | 
|---|
| 84 | bind Tabnotebook <KeyPress-Up> { blt::SelectTab %W "up" }
 | 
|---|
| 85 | bind Tabnotebook <KeyPress-Down> { blt::SelectTab %W "down" }
 | 
|---|
| 86 | bind Tabnotebook <KeyPress-Right> { blt::SelectTab %W "right" }
 | 
|---|
| 87 | bind Tabnotebook <KeyPress-Left> { blt::SelectTab %W "left" }
 | 
|---|
| 88 | bind Tabnotebook <KeyPress-space> { %W invoke focus }
 | 
|---|
| 89 | bind Tabnotebook <KeyPress-Return> { %W invoke focus }
 | 
|---|
| 90 | 
 | 
|---|
| 91 | bind Tabnotebook <KeyPress> {
 | 
|---|
| 92 |     if { [string match {[A-Za-z0-9]*} "%A"] } {
 | 
|---|
| 93 |         blt::FindMatchingTab %W %A
 | 
|---|
| 94 |     }
 | 
|---|
| 95 | }
 | 
|---|
| 96 | 
 | 
|---|
| 97 | # ----------------------------------------------------------------------
 | 
|---|
| 98 | #
 | 
|---|
| 99 | # FirstMatchingTab --
 | 
|---|
| 100 | #
 | 
|---|
| 101 | #       Find the first tab (from the tab that currently has focus) 
 | 
|---|
| 102 | #       starting with the same first letter as the tab.  It searches
 | 
|---|
| 103 | #       in order of the tab positions and wraps around. If no tab
 | 
|---|
| 104 | #       matches, it stops back at the current tab.
 | 
|---|
| 105 | #
 | 
|---|
| 106 | # Arguments:    
 | 
|---|
| 107 | #       widget          Tabnotebook widget.
 | 
|---|
| 108 | #       key             ASCII character of key pressed
 | 
|---|
| 109 | #
 | 
|---|
| 110 | # ----------------------------------------------------------------------
 | 
|---|
| 111 | proc blt::FindMatchingTab { widget key } {
 | 
|---|
| 112 |     set key [string tolower $key]
 | 
|---|
| 113 |     set itab [$widget index focus]
 | 
|---|
| 114 |     set numTabs [$widget size]
 | 
|---|
| 115 |     for { set i 0 } { $i < $numTabs } { incr i } {
 | 
|---|
| 116 |         if { [incr itab] >= $numTabs } {
 | 
|---|
| 117 |             set itab 0
 | 
|---|
| 118 |         }
 | 
|---|
| 119 |         set label [string tolower [$widget tab cget $itab -text]]
 | 
|---|
| 120 |         if { [string index $label 0] == $key } {
 | 
|---|
| 121 |             break
 | 
|---|
| 122 |         }
 | 
|---|
| 123 |     }
 | 
|---|
| 124 |     $widget focus $itab
 | 
|---|
| 125 |     $widget see focus
 | 
|---|
| 126 | }
 | 
|---|
| 127 | 
 | 
|---|
| 128 | # ----------------------------------------------------------------------
 | 
|---|
| 129 | #
 | 
|---|
| 130 | # SelectTab --
 | 
|---|
| 131 | #
 | 
|---|
| 132 | #       Invokes the command for the tab.  If the widget associated tab 
 | 
|---|
| 133 | #       is currently torn off, the tearoff is raised.
 | 
|---|
| 134 | #
 | 
|---|
| 135 | # Arguments:    
 | 
|---|
| 136 | #       widget          Tabnotebook widget.
 | 
|---|
| 137 | #       x y             Unused.
 | 
|---|
| 138 | #
 | 
|---|
| 139 | # ----------------------------------------------------------------------
 | 
|---|
| 140 | proc blt::SelectTab { widget tab } {
 | 
|---|
| 141 |     set index [$widget index $tab]
 | 
|---|
| 142 |     if { $index != "" } {
 | 
|---|
| 143 |         $widget select $index
 | 
|---|
| 144 |         $widget focus $index
 | 
|---|
| 145 |         $widget see $index
 | 
|---|
| 146 |         set w [$widget tab tearoff $index]
 | 
|---|
| 147 |         if { ($w != "") && ($w != "$widget") } {
 | 
|---|
| 148 |             raise [winfo toplevel $w]
 | 
|---|
| 149 |         }
 | 
|---|
| 150 |         $widget invoke $index
 | 
|---|
| 151 |     }
 | 
|---|
| 152 | }
 | 
|---|
| 153 | 
 | 
|---|
| 154 | # ----------------------------------------------------------------------
 | 
|---|
| 155 | #
 | 
|---|
| 156 | # DestroyTearoff --
 | 
|---|
| 157 | #
 | 
|---|
| 158 | #       Destroys the toplevel window and the container tearoff 
 | 
|---|
| 159 | #       window holding the embedded widget.  The widget is placed
 | 
|---|
| 160 | #       back inside the tab.
 | 
|---|
| 161 | #
 | 
|---|
| 162 | # Arguments:    
 | 
|---|
| 163 | #       widget          Tabnotebook widget.
 | 
|---|
| 164 | #       tab             Tab selected.
 | 
|---|
| 165 | #
 | 
|---|
| 166 | # ----------------------------------------------------------------------
 | 
|---|
| 167 | proc blt::DestroyTearoff { widget tab } {
 | 
|---|
| 168 |     set id [$widget id $tab]
 | 
|---|
| 169 |     set top "$widget.toplevel-$id"
 | 
|---|
| 170 |     if { [winfo exists $top] } {
 | 
|---|
| 171 |         wm withdraw $top
 | 
|---|
| 172 |         update
 | 
|---|
| 173 |         $widget tab tearoff $tab $widget
 | 
|---|
| 174 |         destroy $top
 | 
|---|
| 175 |     }
 | 
|---|
| 176 | }
 | 
|---|
| 177 | 
 | 
|---|
| 178 | # ----------------------------------------------------------------------
 | 
|---|
| 179 | #
 | 
|---|
| 180 | # CreateTearoff --
 | 
|---|
| 181 | #
 | 
|---|
| 182 | #       Creates a new toplevel window and moves the embedded widget
 | 
|---|
| 183 | #       into it.  The toplevel is placed just below the tab.  The
 | 
|---|
| 184 | #       DELETE WINDOW property is set so that if the toplevel window 
 | 
|---|
| 185 | #       is requested to be deleted by the window manager, the embedded
 | 
|---|
| 186 | #       widget is placed back inside of the tab.  Note also that 
 | 
|---|
| 187 | #       if the tabnotebook container is ever destroyed, the toplevel is
 | 
|---|
| 188 | #       also destroyed.  
 | 
|---|
| 189 | #
 | 
|---|
| 190 | # Arguments:    
 | 
|---|
| 191 | #       widget          Tabnotebook widget.
 | 
|---|
| 192 | #       tab             Tab selected.
 | 
|---|
| 193 | #       x y             The coordinates of the mouse pointer.
 | 
|---|
| 194 | #
 | 
|---|
| 195 | # ----------------------------------------------------------------------
 | 
|---|
| 196 | proc blt::CreateTearoff { widget tab rootX rootY } {
 | 
|---|
| 197 | 
 | 
|---|
| 198 |     # ------------------------------------------------------------------
 | 
|---|
| 199 |     # When reparenting the window contained in the tab, check if the
 | 
|---|
| 200 |     # window or any window in its hierarchy currently has focus.
 | 
|---|
| 201 |     # Since we're reparenting windows behind its back, Tk can
 | 
|---|
| 202 |     # mistakenly activate the keyboard focus when the mouse enters the
 | 
|---|
| 203 |     # old toplevel.  The simplest way to deal with this problem is to
 | 
|---|
| 204 |     # take the focus off the window and set it to the tabnotebook widget
 | 
|---|
| 205 |     # itself.
 | 
|---|
| 206 |     # ------------------------------------------------------------------
 | 
|---|
| 207 | 
 | 
|---|
| 208 |     set focus [focus]
 | 
|---|
| 209 |     set window [$widget tab cget $tab -window]
 | 
|---|
| 210 |     set index [$widget index $tab]
 | 
|---|
| 211 |     if { ($focus == $window) || ([string match  $window.* $focus]) } {
 | 
|---|
| 212 |         focus -force $widget
 | 
|---|
| 213 |     }
 | 
|---|
| 214 |     set id [$widget id $index]
 | 
|---|
| 215 |     set top "$widget.toplevel-$id"
 | 
|---|
| 216 |     toplevel $top
 | 
|---|
| 217 |     $widget tab tearoff $tab $top.container
 | 
|---|
| 218 |     table $top $top.container -fill both
 | 
|---|
| 219 | 
 | 
|---|
| 220 |     incr rootX 10 ; incr rootY 10
 | 
|---|
| 221 |     wm geometry $top +$rootX+$rootY
 | 
|---|
| 222 | 
 | 
|---|
| 223 |     set parent [winfo toplevel $widget]
 | 
|---|
| 224 |     wm title $top "[wm title $parent]: [$widget tab cget $index -text]"
 | 
|---|
| 225 |     wm transient $top $parent
 | 
|---|
| 226 | 
 | 
|---|
| 227 |     # If the user tries to delete the toplevel, put the window back
 | 
|---|
| 228 |     # into the tab folder.  
 | 
|---|
| 229 | 
 | 
|---|
| 230 |     wm protocol $top WM_DELETE_WINDOW [list blt::DestroyTearoff $widget $tab]
 | 
|---|
| 231 | 
 | 
|---|
| 232 |     # If the container is ever destroyed, automatically destroy the
 | 
|---|
| 233 |     # toplevel too.  
 | 
|---|
| 234 | 
 | 
|---|
| 235 |     bind $top.container <Destroy> [list destroy $top]
 | 
|---|
| 236 | }
 | 
|---|
| 237 | 
 | 
|---|
| 238 | # ----------------------------------------------------------------------
 | 
|---|
| 239 | #
 | 
|---|
| 240 | # ToggleTearoff --
 | 
|---|
| 241 | #
 | 
|---|
| 242 | #       Toggles the tab tearoff.  If the tab contains a embedded widget, 
 | 
|---|
| 243 | #       it is placed inside of a toplevel window.  If the widget has 
 | 
|---|
| 244 | #       already been torn off, the widget is replaced back in the tab.
 | 
|---|
| 245 | #
 | 
|---|
| 246 | # Arguments:    
 | 
|---|
| 247 | #       widget          tabnotebook widget.
 | 
|---|
| 248 | #       x y             The coordinates of the mouse pointer.
 | 
|---|
| 249 | #
 | 
|---|
| 250 | # ----------------------------------------------------------------------
 | 
|---|
| 251 | proc blt::ToggleTearoff { widget x y index } {
 | 
|---|
| 252 |     set tab [$widget index $index]
 | 
|---|
| 253 |     if { $tab == "" } {
 | 
|---|
| 254 |         return
 | 
|---|
| 255 |     }
 | 
|---|
| 256 |     $widget invoke $tab
 | 
|---|
| 257 | 
 | 
|---|
| 258 |     set container [$widget tab tearoff $index]
 | 
|---|
| 259 |     if { $container == "$widget" } {
 | 
|---|
| 260 |         blt::CreateTearoff $widget $tab $x $y
 | 
|---|
| 261 |     } elseif { $container != "" } {
 | 
|---|
| 262 |         blt::DestroyTearoff $widget $tab
 | 
|---|
| 263 |     }
 | 
|---|
| 264 | }
 | 
|---|
| 265 | 
 | 
|---|
| 266 | # ----------------------------------------------------------------------
 | 
|---|
| 267 | #
 | 
|---|
| 268 | # TabnotebookInit
 | 
|---|
| 269 | #
 | 
|---|
| 270 | #       Invoked from C whenever a new tabnotebook widget is created.
 | 
|---|
| 271 | #       Sets up the default bindings for the all tab entries.  
 | 
|---|
| 272 | #       These bindings are local to the widget, so they can't be 
 | 
|---|
| 273 | #       set through the usual widget class bind tags mechanism.
 | 
|---|
| 274 | #
 | 
|---|
| 275 | #       <Enter>         Activates the tab.
 | 
|---|
| 276 | #       <Leave>         Deactivates all tabs.
 | 
|---|
| 277 | #       <ButtonPress-1> Selects the tab and invokes its command.
 | 
|---|
| 278 | #       <Control-ButtonPress-1> 
 | 
|---|
| 279 | #                       Toggles the tab tearoff.  If the tab contains
 | 
|---|
| 280 | #                       a embedded widget, it is placed inside of a
 | 
|---|
| 281 | #                       toplevel window.  If the widget has already
 | 
|---|
| 282 | #                       been torn off, the widget is replaced back
 | 
|---|
| 283 | #                       in the tab.
 | 
|---|
| 284 | #
 | 
|---|
| 285 | # Arguments:    
 | 
|---|
| 286 | #       widget          tabnotebook widget
 | 
|---|
| 287 | #
 | 
|---|
| 288 | # ----------------------------------------------------------------------
 | 
|---|
| 289 | proc blt::TabnotebookInit { widget } {
 | 
|---|
| 290 |     $widget bind all <Enter> { 
 | 
|---|
| 291 |         if { $bltTabnotebook(activate) } {
 | 
|---|
| 292 |             %W activate current
 | 
|---|
| 293 |         }
 | 
|---|
| 294 |     }
 | 
|---|
| 295 |     $widget bind all <Leave> { 
 | 
|---|
| 296 |         %W activate "" 
 | 
|---|
| 297 |     }
 | 
|---|
| 298 |     $widget bind all <ButtonPress-1> { 
 | 
|---|
| 299 |         blt::SelectTab %W "current"
 | 
|---|
| 300 |     }
 | 
|---|
| 301 |     $widget bind all <Control-ButtonPress-1> { 
 | 
|---|
| 302 |         blt::ToggleTearoff %W %X %Y active
 | 
|---|
| 303 |     }
 | 
|---|
| 304 |     $widget configure -perforationcommand {
 | 
|---|
| 305 |         blt::ToggleTearoff %W $bltTabnotebook(x) $bltTabnotebook(y) select
 | 
|---|
| 306 |     }
 | 
|---|
| 307 |     $widget bind Perforation <Enter> { 
 | 
|---|
| 308 |         %W perforation activate on
 | 
|---|
| 309 |     }
 | 
|---|
| 310 |     $widget bind Perforation <Leave> { 
 | 
|---|
| 311 |         %W perforation activate off
 | 
|---|
| 312 |     }
 | 
|---|
| 313 |     $widget bind Perforation <ButtonPress-1> { 
 | 
|---|
| 314 |         set bltTabnotebook(x) %X
 | 
|---|
| 315 |         set bltTabnotebook(y) %Y
 | 
|---|
| 316 |         %W perforation invoke
 | 
|---|
| 317 |     }
 | 
|---|
| 318 | }
 | 
|---|