Posted to tcl by patthoyts at Mon Apr 28 10:41:54 GMT 2008view pretty
# Replace the standard notebook tab with one that includes a close
# button.
# In future versions of ttk this will be supported more directly when
# the identify command will be able to identify parts of the tab.
namespace eval ::ButtonNotebook {
}
# Tk 8.6 has the Visual Styles element engine on windows. If this is
# available we use it to get proper windows close buttons.
#
proc ::ButtonNotebook::CreateElements {} {
if {[lsearch -exact [ttk::style element names] close] == -1} {
if {[catch {
# WINDOW WP_SMALLCLOSEBUTTON (19)
# WINDOW WP_MDICLOSEBUTTON (20)
# WINDOW WP_MDIRESTOREBUTTON (22)
ttk::style element create close vsapi \
WINDOW 20 {disabled 4 {active pressed} 3 active 2 {} 1}
ttk::style element create detach vsapi \
WINDOW 22 {disabled 4 {active pressed} 3 active 2 {} 1}
}]} then {
CreateImageElements
}
}
}
proc ::ButtonNotebook::CreateImageElements {} {
# Create two image based elements to provide buttons to close the
# tabs or to detach a tab and turn it into a toplevel.
namespace eval ::img {}
set imgdir [file join [file dirname [info script]] images]
image create photo ::img::close -file [file join $imgdir xhn.gif]
image create photo ::img::closepressed -file [file join $imgdir xhd.gif]
image create photo ::img::closeactive -file [file join $imgdir xhu.gif]
image create photo ::img::detach -file [file join $imgdir dhn.gif]
image create photo ::img::detachup -file [file join $imgdir dhu.gif]
image create photo ::img::detachdown -file [file join $imgdir dhd.gif]
if {[lsearch -exact [ttk::style element names] close] == -1} {
if {[catch {
ttk::style element create close image \
[list ::img::close \
{active pressed !disabled} ::img::closepressed \
{active !disabled} ::img::closeactive] \
-border 3 -sticky {}
ttk::style element create detach image \
[list ::img::detach \
{active pressed !disabled} ::img::detachdown \
{active !disabled} ::img::detachup] \
-border 3 -sticky {}
} err]} { puts stderr $err }
}
}
proc ::ButtonNotebook::Init {{pertab 0}} {
CreateElements
# This places the buttons on the right end of the tab area -- but in
# Tk 8.5 we cannot identify these elements.
if {!$pertab} {
ttk::style layout ButtonNotebook {
ButtonNotebook.client -sticky nswe
ButtonNotebook.close -side right -sticky ne
ButtonNotebook.detach -side right -sticky ne
}
}
# This places the button elements on each tab which uses quite a
# lot of space but we can identify the elements. Changes to the
# widget state affect all the button elements though.
if {$pertab} {
ttk::style layout ButtonNotebook {
ButtonNotebook.client -sticky nswe
}
ttk::style layout ButtonNotebook.Tab {
ButtonNotebook.tab -sticky nswe -children {
ButtonNotebook.padding -side top -sticky nswe -children {
ButtonNotebook.focus -side top -sticky nswe -children {
ButtonNotebook.label -side left -sticky {}
ButtonNotebook.detach -side left -sticky {}
ButtonNotebook.close -side left -sticky {}
}
}
}
}
}
if {$::ttk::currentTheme eq "xpnative"} {
ttk::style configure ButtonNotebook.Tab -width -8
}
bind TNotebook <ButtonPress-1> {+::ButtonNotebook::Press %W %x %y}
bind TNotebook <ButtonRelease-1> {+::ButtonNotebook::Release %W %x %y}
bind TNotebook <<ThemeChanged>> [namespace code [list Init $pertab]]
}
# Hook in some event extras:
# set the state to pressed if button down over a button element.
proc ::ButtonNotebook::Press {w x y} {
set e [$w identify $x $y]
if {[string match "*close" $e] || [string match "*detach" $e]} {
$w state pressed
}
}
# On release, do the button action if any.
proc ::ButtonNotebook::Release {w x y} {
$w state !pressed
set e [$w identify $x $y]
set index [$w index @$x,$y]
if {[string match "*close" $e]} {
$w forget $index
event generate $w <<NotebookClosedTab>>
} elseif {[string match "*detach" $e]} {
set tab [lindex [$w tabs] $index]
set title [$w tab $index -text]
$w forget $index
wm manage $tab
wm title $tab $title
wm protocol $tab WM_DELETE_WINDOW \
[namespace code [list Attach $w $tab $index]]
event generate $tab <<DetachedTab>>
}
}
proc ::ButtonNotebook::Attach {notebook tab {index end}} {
set title [wm title $tab]
wm forget $tab
if {[catch {
if {[catch {$notebook insert $index $tab -text $title} err]} {
$notebook add $tab -text $title
}
$notebook select $tab
} err]} {
puts stderr "AttachWindow: $err"
wm manage $w
wm title $w $title
}
}
proc ::ButtonNotebook::Test {} {
variable tabtest
set dlg [toplevel .test[incr tabtest]]
wm title $dlg "Notebook test"
wm withdraw $dlg
set nb [ttk::notebook $dlg.nb -style ButtonNotebook]
frame $nb.page0 -background red -width 100 -height 100
frame $nb.page1 -background blue -width 100 -height 100
$nb add $nb.page0 -text One
$nb add $nb.page1 -text Two
grid $dlg.nb -sticky news
grid rowconfigure $dlg 0 -weight 1
grid columnconfigure $dlg 0 -weight 1
bind TNotebook <Motion> {puts stderr [%W identify %x %y]}
bind $dlg <Control-F2> {console show}
wm deiconify $dlg
}
::ButtonNotebook::Init 1
#::ButtonNotebook::Test; tkwait window .