Version 1 of A vertical-tab notebook

Updated 2001-10-02 11:51:26

set docu(VNotebook) { Richard Suchenwirth - This is a study in using the BWidgets toolkit, in particular using their PagesManager to implement a notebook with vertically-stacked tabs, by default to the right. The demo at end shows a usage example which may be used as a telephone booklet. As added goodie (if you have the code from An i15d date chooser and A little calculator available), the last page contains one of each - just to show that you can pack other things than text widgets. Enjoy! }

 package require BWidget

 proc VNotebook {w args} {
        frame $w         ;# container around the whole
        frame $w.tabs    ;# will hold tab buttons
        # dummy button, not managed, to keep font info
    set opt(-font) [[button $w.tabs.0] cget -font]
    set defaults {-side right}
    array set opt [concat $defaults $args]
    foreach i {font side} {
        set $i $opt(-$i); unset opt(-$i)
    } ;# so PageManager won't see those
    $w.tabs.0 config -font $font ;# so others can cget it
        eval PagesManager $w.nb [array get opt]
        pack $w.tabs -side $side -fill both
        pack $w.nb   -side $side -fill both -expand 1 -padx 0
        rename $w _$w  ;# won't use it anymore, but must survive
        proc $w {cmd args} {
            set fileopt {-filetypes {{Notebook .not} {{All files} .*}}\
                -defaultextension .not}
            set w [lindex [info level 0] 0] ;# retrieve own name
            switch -- $cmd {
            add    {
                    set font [$w.tabs.0 cget -font]
                    set b [button $w.tabs.b$args -text $args -font $font\
                        -command [list $w raise $args] -bg white \
                        -borderwidth 1 -pady 0]
                    pack $b -fill both -expand 1
            delete {destroy $w.tabs.b$args}
            open {
                set file [eval tk_getOpenFile $fileopt]
                if {$file!=""} {
                    foreach {page content} [source $file] {
                        set t [$w.nb getframe $page].t
                        $t delete 1.0 end
                        $t insert end $content
                return $file
            raise  {
                set bg [$w.tabs.0 cget -bg]
                foreach i [winfo children $w.tabs] {
                    $i configure -bg $bg
                $w.tabs.b$args configure -bg white
                catch {focus [$w.nb getframe $args].t}
            raisewhere {
                foreach page [$w.nb pages] {
                    set f [$w.nb getframe $page]
                    if [regexp -nocase $args [$f.t get 1.0 end]] {
                        $w raise $page
                return ;# this command is not known to P.M.
            save {
                set file [eval tk_getSaveFile $fileopt]
                if {$file!=""} {
                    set fp [open $file w]
                    puts $fp "return {"
                    foreach page [$w.nb pages] {
                        set t [$w.nb getframe $page].t
                        catch {puts $fp [list $page [$t get 1.0 end-1c]]}
                    puts $fp "}"
                    close $fp
                return $file
            eval $w.nb $cmd $args ;# let PagesManager do the rest
        set w
 if {[file tail [info script]]==[file tail $argv0]} {
    # demo and example code, runs when sourced alone
    proc img {name} {
        image create photo -file $::env(BWIDGET_LIBRARY)/images/$name
    frame .0
    button .0.load -image [img open.gif] -command ".v open"
    button -image [img save.gif] -command ".v save"
    LabelEntry .0.f -label " Find: " -textvariable Find
    .0.f bind <Return> {.v raisewhere $Find}
    eval pack [winfo children .0] -side left -fill y
    pack .0.f -fill x -expand 1
    VNotebook     .v ;#-side left
    pack       .0 .v -fill both -expand 1 -pady 2
    foreach i {AB CD EF GH IJ KL MN OPQ RS TU VW XYZ} {
         set w [.v add $i]
         pack [text $w.t -wrap word -width 40] -fill both -expand 1
    # remove next 3 lines if you don't have/want these goodies
    set w [.v add +]
    source Calendar.tcl; pack [date::chooser $w.c] -fill both -expand 1
    source sep_calc.tcl; pack [calculator $w.f] -fill both -expand 1

    tkwait visibility .v
    set p0 [lindex [.v pages] 0]
    [.v.nb getframe $p0].t insert end [string map {\n " "} $docu(VNotebook)]
    wm protocol . WM_DELETE_WINDOW {.v save; exit}
    after 100 .v raise $p0 ;# delay so top page is correct