

set ButtonBoxFont -adobe-courier-bold-r-*-*-*-120-75-75-*-*-*-*

proc MakeFrameOrWindow {widget args} {
    set toplevel 1
    set title ""
    set packOption "-side bottom"
    APSStrictParseArguments {toplevel title packOption}
    if {$toplevel} {
        # create a top level window $widget
        if {[winfo exists $widget]} {destroy $widget}
        toplevel $widget
        raise $widget
        wm title $widget $title
    } else {
        # create a frame with the given name
        if {[winfo exists $widget]} {destroy $widget}
        frame $widget -relief raised -bd 4 
        eval pack $widget $packOption
    }
    return $widget
}

proc RunSDDSListboxDataTaker {DataTaker widget LBID count x y} {
    global apsColData$LBID
    set selection [$widget nearest $y]
    set data {}
    for {set idata 0} {$idata<$count} {incr idata} {
        set varname apsColData${LBID}($idata)
        set elem [eval lindex \$$varname $selection]
        lappend data $elem
    }
    eval $DataTaker $data
}

proc APSRemoveColData {count ID } {
    global apsColData$ID
    for {set i 0} {$i<$count} {incr i} {
        unset apsColData${ID}($i)
    }
}

proc APSDefaultLabelMaker {data width} {
    set count [llength $data]
    set result {}
    for {set i 0} {$i<$count} {incr i} {
        set d0 [lindex $data  $i]
        set w0 [lindex $width $i]
        set sform [format "%%%lds" $w0]
        lappend result [format $sform $d0]
    }
    return [join $result "  "]
}

#
# Brings up listbox containing data from an SDDS file
# usage: APSMakeSDDSListbox <filename> <widget> [-toplevel 0 | 1]
#               [-title <string>] [-page <number>] [-labelmaker <procName>]
#               [-callback <procName>] <column-name> ...
#
set ColDataID 0
proc APSMakeSDDSListbox {filename widget args} {
    global ColDataID sddsListboxVar
    set count 0
    incr ColDataID
    global apsColData$ColDataID

    set toplevel 1
    set title "Listbox for SDDS file $filename"
    set page 0
    set labelmaker APSDefaultLabelMaker
    set callback ""
    APSParseArguments {toplevel title page labelmaker callback}
    APSClearOptions
    if {[llength $args]==0} {
        APSErrorPopUp "No columns named for SDDS listbox for file $filename"
        return {}
    }

    set LabelMaker $labelmaker
    set DataTaker $callback

    set maxlen {}
    foreach name $args {
        if {[string length $name]==0} {
            break;
        }
        set apsColData${ColDataID}($count) [APSGetSDDSColumn -fileName $filename -column $name -page $page]
        set width [APSMaxStringLength [eval lrange \$apsColData${ColDataID}($count) 0 end]]
        lappend maxlen $width
        incr count
    }

    set w [MakeFrameOrWindow $widget -toplevel $toplevel -title $title \
             -packOption "-side bottom -expand 1 -fill both"]

    set pane 0
    frame $w.list
    frame $w.ops
    pack $w.list -side top -expand 1 -fill y
    pack $w.ops -side top
    
   # listbox $w.list.lbox -font "-adobe-courier-bold-r-normal-*-*-120-75-75-*-*-*-*" \
    #  -yscrollcommand "$w.list.scroll set"
    listbox $w.list.lbox  -yscrollcommand "$w.list.scroll set"
    scrollbar $w.list.scroll -command "$w.list.lbox yview"
    set i 0
    set maxwidth 0
    set varname apsColData${ColDataID}(0)
    foreach col [eval lrange \$$varname 0 end] {
        set data {}
        for {set idata 0} {$idata<$count} {incr idata} {
            set varname apsColData${ColDataID}($idata)
            set elem [eval lindex \$$varname $i]
            lappend data $elem
        }
        set label [$LabelMaker $data $maxlen]
        set width [string length $label]
        if {$width>$maxwidth} { 
            set maxwidth $width
            $w.list.lbox configure -width [expr {$maxwidth+2}]
        }
        $w.list.lbox insert end $label
        incr i
    }
    pack $w.list.lbox $w.list.scroll -side left -fill y
    if {$DataTaker != ""} {
        bind $w.list.lbox <Double-ButtonPress-1> \
          "RunSDDSListboxDataTaker $DataTaker $w.list.lbox $ColDataID $count %x %y"
        APSButton .cancel -parent $w.ops -text CANCEL -command "destroy $w; APSRemoveColData $count $ColDataID" \
          -contextHelp "Remove listbox without choosing anything."

    } else {
        APSButton .ok -parent $w.ops -text OK -command "set sddsListboxVar OK" \
          -contextHelp "Remove listbox and return highlighted entry as choice."
        APSButton .cancel -parent $w.ops -text CANCEL -command "set sddsListboxVar CANCEL" \
          -contextHelp "Remove listbox without choosing anything."
    }

    if {$DataTaker == ""} {
        set oldFocus [focus]
        catch {grab set $w}
        focus $w
        update
        
        set sddsListboxVar ""
        tkwait variable sddsListboxVar
        set selection [$w.list.lbox curselection]
        destroy $w
        focus $oldFocus
        update
        
        if {$selection == ""} {
            return {}
        }
        
        if {$sddsListboxVar == "OK"} {
            set data {}
            for {set idata 0} {$idata<$count} {incr idata} {
                set varname apsColData${ColDataID}($idata)
                set elem [eval lindex \$$varname $selection]
                unset $varname
                lappend data $elem
            }
            return $data
        }
        return {}
    }
    return {}
}

#
# Used by MakeSDDSButtons... to advance a page
#
proc GoToNextButtonPage {w pane} {
    pack forget $w.p${pane}
    incr pane
    pack $w.p$pane -side top -fill x
    update
}

#
# Used by MakeSDDSButtons... to back up a page
#
proc GoToLastButtonPage {w pane} {
    pack forget $w.p${pane}
    incr pane -1
    pack $w.p$pane -side top -fill x
    update
}

#
# Brings up buttons labeled with data from an SDDS file
# usage: APSMakeSDDSButtons <filename> <widget> -callback <procName>
#       [-toplevel 0 | 1] [-title <string>] [-limit <number>]
#       [page <number>] [-labelmaker <procName>] 
#       <columnName> ...
#
proc APSMakeSDDSButtons {filename widget args} {
    global ButtonBoxFont

    set callback ""
    set toplevel 1
    set title "Buttons for SDDS file $filename"
    set limit 10
    set page 0
    set labelmaker APSDefaultLabelMaker
    APSParseArguments {callback toplevel title limit page labelmaker}
    APSClearOptions
    if {[llength $args]==0} {
        APSErrorPopUp "No columns named for SDDS button list for file $filename"
        return {}
    }
    if {[string length $callback]==0} {
        APSErrorPopUp "No callback named for SDDS button list for file $filename"
        return {}
    }

    set count 0
    set maxwidth 0
    set maxlen {}
    foreach name $args {
        if {[string length $name]==0} {
            break;
        }
        set colData($count) [APSGetSDDSColumn -fileName $filename -column $name -page $page]
        set width [APSMaxStringLength $colData($count)]
        lappend maxlen $width
        incr count
    }
    set i 0
    foreach col0 $colData(0) {
        set data {}
        for {set idata 0} {$idata<$count} {incr idata} {
            set elem [lindex $colData($idata) $i]
            lappend data $elem
        }
        set label [$labelmaker $data $maxlen]
        set length [string length $label]
        if {$length>$maxwidth} { set maxwidth $length}
        incr i
    }
    set width $maxwidth

    set w [MakeFrameOrWindow $widget -title $title -toplevel $toplevel]

    set pane 0
    frame $w.p${pane} 
    frame $w.p${pane}.np -bd 4 
    pack $w.p${pane}.np -side top -fill x

    set i 0
    set madeNP -1
    foreach col0 $colData(0) {
        if {$i!=0} {
            if {$i%$limit==0} {
                APSButton .next -parent $w.p${pane}.np -text "NEXT PAGE" \
                  -command "{GoToNextButtonPage} $w ${pane}" \
                  -contextHelp "Go to the next page of buttons."
                APSButton .ok -parent $w.p${pane}.np -text "OK" \
                  -command "destroy $w" \
                  -contextHelp "Destroy button pages and continue."
                if {$pane != 0} {
                    APSButton .previous -parent $w.p${pane}.np -text "PREVIOUS PAGE" \
                      -command "GoToLastButtonPage $w ${pane}" \
                      -contextHelp "Go to the previous page of buttons."
                }
                set madeNP $pane
                incr pane
                frame $w.p${pane} 
                frame $w.p${pane}.np -bd 4 
                pack $w.p${pane}.np -side top -fill x
            }
        }   
        set data {}
        for {set idata 0} {$idata<$count} {incr idata} {
            set elem [lindex $colData($idata) $i]
            lappend data $elem
        }
        APSButton .b$i -parent $w.p${pane} \
          -text  [$labelmaker $data $maxlen ] \
          -command "$callback $data" \
          -contextHelp "Invoke processing of with the data indicated on the label."    \
          -noPack 1
        $w.p${pane}.b$i.button configure -font $ButtonBoxFont 
        pack $w.p${pane}.b$i -side top -fill x
        incr i
    }
    if {$madeNP != $pane} {
        if {$pane != 0} {
            APSButton .previous -parent $w.p${pane}.np -text "PREVIOUS PAGE" \
              -command "pack forget $w.p${pane}; pack $w.p[expr $pane-1]" \
              -contextHelp "Go to the previous page of buttons."
            APSButton .ok -parent $w.p${pane}.np -text "OK" \
              -command "destroy $w" \
              -contextHelp "Destroy button pages and continue."
        }
    }                
    pack $w.p0 -side top -fill x
}

#
# Make check buttons for a column of SDDS data
# usage: APSMakeSDDSCheckButtons <filename> <widget> <columnName> <arrayName> 
#       [-toplevel {0 | 1}] [-title <title>] [-page <page>] [-limit <number>] 
#       [-callback <procName>]
#

proc APSMakeSDDSCheckButtons {filename widget column arrayName args} {
    global $arrayName sddsCheckbuttonVar

    set toplevel 1
    set title "Check buttons for column $column of file $filename"
    set page 0
    set limit 8
    set callback ""
    set nograb 0
    APSStrictParseArguments {toplevel title page limit callback nograb}

    set data [APSGetSDDSColumn -fileName $filename -column $column -page $page]
    
    set w [MakeFrameOrWindow $widget -title $title -toplevel $toplevel]

    frame $w.op 
    pack $w.op -side top
    if {[string length $callback]==0} {
        APSButton .ok -parent $w.op -text OK -command "set sddsCheckbuttonVar OK" \
          -contextHelp "Return with selected checkbuttons as choices."
        APSButton .cancel -parent $w.op -text CANCEL -command "set sddsCheckbuttonVar CANCEL" \
          -contextHelp "Return without making a choice."
        APSButton .clear -parent $w.op -text CLEAR -command "APSSetAllArrayEntries $arrayName 0" \
          -contextHelp "Clear all selected checkbuttons."
        APSButton .set -parent $w.op   -text "SET ALL" -command "APSSetAllArrayEntries $arrayName 1" \
          -contextHelp "Choose all checkbuttons."
    } else {
        APSButton .ok -parent $w.op -text OK -command "destroy $w" \
          -contextHelp "Return with selected checkbuttons as choices."
        APSButton .clear -parent $w.op -text CLEAR -command "APSSetAllArrayEntries $arrayName 0; $callback" \
          -contextHelp "Clear all selected checkbuttons."
        APSButton .set -parent $w.op   -text "SET ALL" -command "APSSetAllArrayEntries $arrayName 1; $callback" \
          -contextHelp "Choose all checkbuttons."
    }

    set i 0
    set row 0
    foreach elem $data {
        if {$i%$limit==0} {
            incr row
            frame $w.row$row -bd 2
            pack $w.row$row -side top
        }
        set vname [join [concat $arrayName ( $elem )] ""]
        checkbutton $w.row$row.cb$i -variable $vname -text $elem
        if {[string length $callback]} {
            bind $w.row$row.cb$i <ButtonPress-1> "$callback"
            bindtags $w.row$row.cb$i "Checkbutton $w.row$row.cb$i $w all"
        }
        set $vname 0
        pack $w.row$row.cb$i -side left
        incr i
    }
    if {[string length $callback]==0} {
        if {!$nograb} {
            set oldFocus [focus]
            catch {grab set $w}
            focus $w
            update
        }

        set sddsCheckbuttonVar ""
        tkwait variable sddsCheckbuttonVar
        destroy $w
        if {!$nograb} {
            focus $oldFocus
            update
        }
        if {$sddsCheckbuttonVar == "OK"} { return 1 }
        return 0
    }
}








