home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activetcltk / ActiveTcl8.3.4.1-8.win32-ix86.exe / ActiveTcl8.3.4.1-win32-ix86 / demos / Snack / tomAmp.tcl < prev    next >
Encoding:
Text File  |  2001-10-22  |  42.2 KB  |  1,251 lines

  1. #!/bin/sh
  2. # the next line restarts using wish \
  3. exec wish8.3 "$0" "$@"
  4. # derived from Snack snamp.tcl demo player by Tom Wilkason
  5. #
  6. global taFiles tomAmp
  7. set tomAmp(settingsFile) "~/.tomAmpDefaults"
  8. set tomAmp(cacheFile) "~/.tomAmpCache"
  9. set tomAmp(defaultFolderFile) "~/default.tafs"
  10. set tomAmp(Console) 0
  11. set tomAmp(p) 0
  12. set tomAmp(pause) 0
  13. set tomAmp(elapsed) 0
  14. set tomAmp(current) {}
  15. set tomAmp(currentMP3) {}
  16. ;# Setup sound settings
  17. package require -exact snack 2.1
  18. # Buttons
  19. option add *font {Helvetica 10 bold}
  20. option add *Button.activeBackground yellow
  21. option add *Button.borderwidth 1
  22. option add *Button.relief raised
  23. option add *Entry.background lightyellow
  24. option add *Entry.foreground black
  25. option add *Entry.font {Helvetica 9 bold}
  26. option add *Entry.relief sunken
  27. #option add *Entry.borderwidth 2
  28. option add *Label.font {Helvetica 9 bold}
  29. option add *Listbox.background black
  30. option add *Listbox.foreground green
  31. option add *Listbox.font {Helvetica 9 bold}
  32. if {$::tcl_platform(os) == "Linux"} {
  33.     option add *Scale.font {Helvetica 8}
  34. } else {
  35.     option add *Scale.font {Helvetica 7}
  36. }
  37. option add *Scale.activebackground blue
  38. option add *troughcolor black
  39.  
  40. snack::debug 0
  41. snack::sound s -debug 0
  42. snack::audio playLatency 1200
  43.  
  44. ###############################################################################
  45. # Function   : buildGui
  46. # Description: Build the player Gui
  47. # Author     : Tom Wilkason
  48. # Date       : 12/27/2000
  49. ###############################################################################
  50. proc buildGui {args} {
  51.  
  52.    global tomAmp taFiles LB SS
  53.    set tomAmp(timestr) "Snack MP3 Player"
  54.    wm title . "SnackAmp MPEG Player"
  55.    wm protocol . WM_DELETE_WINDOW exit
  56.    ;##
  57.    ;# Control Panel
  58.    ;#
  59.    pack [frame .panel -borderwidth 2 -relief ridge] -side top -fill x -expand false -anchor w
  60.    ;# Display name and current status
  61.    label .panel.l -background black -foreground green -borderwidth 2 -relief ridge \
  62.    -font {Helvetica 12 bold} -height 4 -textvar tomAmp(timestr) -wraplength 550
  63.    set tomAmp(Mute) 0
  64.    bind .panel.l <ButtonPress-1> {toggleMute .panel.l}
  65.    grid .panel.l -row 0 -column 1 -columnspan 2 -sticky ew
  66.  
  67.    snack::createIcons
  68.  
  69.    grid [frame .panel.player -borderwidth 2 -relief ridge] -row 1 -column 1 -sticky news
  70.    ;# Amp controls
  71.    pack [button .panel.player.prev -bitmap snackPlayPrev -command Prev] -side left
  72.    balloon .panel.player.prev "Play previous in list"
  73.    pack [button .panel.player.bp -bitmap snackPlay -command Play] -side left
  74.    balloon .panel.player.bp "Play Selection"
  75.    pack [button .panel.player.pause -bitmap snackPause -command {Pause}] -side left
  76.    balloon .panel.player.pause "Pause/Resume playback"
  77.    proc pauseRelief {down} {
  78.       global tomAmp
  79.       if {$down} {
  80.          .panel.player.pause configure -relief sunken
  81.       } else {
  82.          .panel.player.pause configure -relief raised
  83.       } ;# end if
  84.       set tomAmp(pause) $down
  85.    }
  86.    pack [button .panel.player.bs -bitmap snackStop -command Stop] -side left
  87.    balloon .panel.player.bs "Stop playing"
  88.    pack [button .panel.player.next -bitmap snackPlayNext -command Next] -side left
  89.    balloon .panel.player.next "Play next in list"
  90.    pack [button .panel.player.bo -image snackOpen -command OpenFile] -side left
  91.    balloon .panel.player.bo "Add a file to play list"
  92.  
  93.    ;# Offset within file
  94.    set SS [scale .panel.ss -show yes -orient horiz -width 10 -len 250 -from 0. -to 60. \
  95.       -var tomAmp(p) -tickinterval 30 -sliderlength 15 -relief ridge -borderwidth 2 \
  96.       -activebackground blue -troughcolor black]
  97.    balloon $SS "Show/Adjust playback location within file"
  98.    grid $SS -column 2 -row 1 -sticky ew
  99.  
  100.    ;# Sound level
  101.    set tomAmp(gain) [snack::audio play_gain]
  102.    scale .panel.sv -show no -orient vert -width 10 -command {snack::audio play_gain}\
  103.          -len 85 -var tomAmp(gain) -from 130. -to 0. -sliderlength 15 \
  104.          -activebackground blue -troughcolor black
  105.  
  106.    grid .panel.sv -column 0 -row 0 -rowspan 3 -sticky ns
  107.    balloon .panel.sv "Adjust the playback level"
  108.    # Adjust grid resize behavior
  109.    grid columnconfigure .panel 0 -weight 0
  110.    grid columnconfigure .panel 1 -weight 0
  111.    grid columnconfigure .panel 2 -weight 1
  112.  
  113.    ;# Allow time to be addjusted
  114.    set tomAmp(setdrag) 1
  115.    bind $SS <ButtonPress-1> {set tomAmp(setdrag) 0}
  116.    bind $SS <ButtonRelease-1> {set tomAmp(setdrag) 1 ; PlayOffset}
  117.  
  118.    ;# Collapsable frame
  119.    set CF [cframe .hull "MP3 Files"]
  120.    pack .hull -side top -fill both -expand true
  121.    cframe.close $CF
  122.  
  123.    ;# Filter box
  124.    pack [frame $CF.filter -borderwidth 2 -relief ridge] -side top -expand no -fill x
  125.    pack [label $CF.filter.label -text "Filter Selection"] -side left -expand no -fill x
  126.    pack [entry $CF.filter.entry -textvariable tomAmp(filter) -width 50] -side left -expand no -fill x
  127.    bind $CF.filter.entry <Return>   "filterMusic"
  128.    bind $CF.filter.entry <Double-1>   {set tomAmp(filter) "";filterMusic}
  129.    balloon $CF.filter.entry "Enter text to restrict files to play,\nEnter or 'Replace' to replace list\n'Append' to add to bottom of current list\nDouble-click to clear"
  130.  
  131.    ;# Append/Replace buttons for filter
  132.    pack [button $CF.filter.btApp -text "Append" -command {filterMusic append} -pady 0] -side left
  133.    balloon $CF.filter.btApp "Modify the filter box and then press this to append files to files below"
  134.    pack [button $CF.filter.btRep -text "Replace" -command {filterMusic replace} -pady 0] -side left
  135.    balloon $CF.filter.btApp "Modify the filter box and then press this to replace list below with newly filtered files"
  136.  
  137.    ;##
  138.    ;# Scrolled Listbox
  139.    ;#
  140.    set LB [Scrolled_Listbox $CF.frame -selectmode extended -exportselection no -height 20 \
  141.       -background black -foreground green -font {Helvetica 9 bold}]
  142.    pack $CF.frame -side top -expand yes -fill both
  143.    # set w $LB
  144.  
  145.    # Listbox popup menu
  146.    set m $LB.popup
  147.    menu $m -tearoff 0
  148.    $m add command -label "Play"  -command {Play}
  149.    $m add command -label "Remove"  -command {Cut}
  150.    $m add command -label "Delete from Disk"  -command {Delete}
  151.    $m add command -label "Append to Config File"  -command {}
  152.  
  153.    bind $LB <ButtonPress-3> {
  154.       tk_popup %W.popup %X %Y
  155.    }
  156.  
  157.    # Bindings
  158.    bind $LB <Double-ButtonPress-1> Play
  159.    bind $LB <B1-Motion> {Drag %y}
  160.    bind $LB <ButtonPress-1> {focus %W;Select %y}
  161.    bind $LB <BackSpace> Cut
  162.    bind $LB <Delete> Cut
  163.  
  164.    ;# Entry box to allow renaming of current selection
  165.    pack [frame $CF.fname] -side top -expand no -fill x
  166.    pack [label $CF.fname.fname -textvariable tomAmp(fullName) -justify left -borderwidth 2 -relief ridge] -side top -expand no -fill x
  167.    pack [entry $CF.fname.name -textvariable tomAmp(entryName) ] -side top -expand false -fill x
  168.    balloon $CF.fname.name "Change the file name here and press enter when complete"
  169.    bind $CF.fname.name <Return> {
  170.       if {$tomAmp(entryName) != $tomAmp(origEntryName)} {
  171.          if {$tomAmp(currentMP3)==$taFiles($tomAmp(origEntryName))} {
  172.             Stop
  173.             s destroy
  174.             snack::sound s
  175.          } ;# end if
  176.          set newFileName [file join [file dirname $taFiles($tomAmp(origEntryName))] $tomAmp(entryName)]
  177.          # puts "$tomAmp(entryName) vs $tomAmp(origEntryName) -> '$newFileName'"
  178.          file rename -force $taFiles($tomAmp(origEntryName)) $newFileName
  179.          unset taFiles($tomAmp(origEntryName))
  180.          set tomAmp(origEntryName) $tomAmp(entryName)
  181.          set taFiles($tomAmp(entryName))  $newFileName
  182.          $LB delete $tomAmp(entryIndex)
  183.          ;# Insert either with or without folder name
  184.          $LB insert $tomAmp(entryIndex) $tomAmp(entryName)
  185.          Highlight $tomAmp(entryIndex)
  186.       } ;# end if
  187.    }
  188.  
  189.    InstallMenu
  190.  
  191. }
  192. proc Scrolled_Listbox { f args } {
  193.    frame $f
  194.    listbox $f.list \
  195.       -xscrollcommand [list Scrolled_Listbox.set $f.xscroll  [list grid $f.xscroll -row 1 -column 0 -sticky news]] \
  196.       -yscrollcommand [list Scrolled_Listbox.set $f.yscroll  [list grid $f.yscroll -row 0 -column 1 -sticky news]]
  197.    eval {$f.list configure} $args
  198.    scrollbar $f.xscroll -orient horizontal -command [list $f.list xview]
  199.    scrollbar $f.yscroll -orient vertical   -command [list $f.list yview]
  200.    grid $f.list -sticky news
  201.    ;##
  202.    ;# Only the data should expand, not the scroll bars
  203.    ;#
  204.    grid rowconfigure    $f 0 -weight 1
  205.    grid columnconfigure $f 0 -weight 1
  206.    ;##
  207.    ;# Modify to not resize when the scroll bars go away (make a minimum size)
  208.    ;#
  209.    grid columnconfigure $f 1 -minsize 18
  210.    grid rowconfigure    $f 1 -minsize 18
  211.    return $f.list
  212. }
  213. #******************************************************#
  214. # Function   : Scroll_set
  215. # Description: callback for the scroll list box, hide
  216. #              scroll bars if they aren't needed
  217. # Author     : Tom Wilkason
  218. # Date       : 6/4/1999
  219. #*******************************************************#
  220. proc Scrolled_Listbox.set {scrollbar geoCmd offset size} {
  221.    if {$offset != 0.0 || $size != 1.0} {
  222.       eval $geoCmd
  223.       $scrollbar set $offset $size
  224.    } else {
  225.       set manager [lindex $geoCmd 0]
  226.       $manager forget $scrollbar
  227.    } ;# end if
  228. }
  229.  
  230. ;##
  231. ;# Build the menu bar at the top of the GUI
  232. ;#
  233. proc InstallMenu {} {
  234.    global taFiles tomAmp LB tomAmpSettings tcl_platform
  235.    set M .bRmenubar
  236.    catch {menu $M}
  237.    # attach it to the main window
  238.    . config -menu $M
  239.    # Create more cascade menus
  240.    foreach m {File Play-Lists Folders Settings Help} {
  241.       if {$m == "Play-Lists"} {
  242.          set $m [menu $M.m$m -postcommand [list configFiles $M.m$m]]
  243.          $M.m$m add command -label "Clear" -command {Clear}
  244.          $M.m$m add command -label "Save..." -command {SavePlaylistFile}
  245.          $M.m$m add separator
  246.          $M.m$m add cascade -label "Append" -menu [menu $M.m$m.mAppend -tearoff 0]
  247.          $M.m$m add cascade -label "Replace" -menu [menu $M.m$m.mReplace -tearoff 0]
  248.  
  249.       } else {
  250.          set $m [menu $M.m$m]
  251.       }
  252.       $M add cascade -label $m -menu $M.m$m
  253.    }
  254.    $Folders add command -label "Clear All" -command {
  255.       global taFolders
  256.       foreach {item} [array name taFolders *] {
  257.          set taFolders($item) 0
  258.       } ;# end foreach
  259.       filterMusic
  260.    }
  261.    $Folders add command -label "Set All" -command {
  262.       global taFolders
  263.       foreach {item} [array name taFolders *] {
  264.          set taFolders($item) 1
  265.       } ;# end foreach
  266.       filterMusic
  267.    }
  268.    $Folders add command -label "Save Folder List..." -command {SaveFolderFile}
  269.    $Folders add cascade -label "Folder Lists..." -menu [menu $Folders.settings -tearoff 0 -postcommand [list folderFiles $Folders.settings]]
  270.  
  271.    $Folders add separator
  272.    set tomAmp(FolderMenu) $Folders
  273.    set tomAmp(FolderSettings) $Folders.settings
  274.  
  275.  
  276.    $File add command -label "Add a file to playlist" -command {OpenFile}
  277.    $File add command -label "Rescan Folders" -command {Rescan}
  278.    $File add separator
  279.    $File add command -label "Exit" -command {exit}
  280.  
  281.    if {$tcl_platform(platform) == "windows"} {
  282.       $Settings add check -label "Show Console" -variable tomAmp(Console) -command Console
  283.       $Settings add separator
  284.    } ;# end if
  285.    $Settings add check -label "Random Play" -variable tomAmpSettings(randomPlay) -command filterMusic
  286.    $Settings add check -label "Continuous Play" -variable tomAmpSettings(ContinuousPlay)
  287.    $Settings add check -label "Rescan Folders on Startup" -variable tomAmpSettings(AutoRescan)
  288.    $Settings add check -label "Show folder names with files" -variable tomAmpSettings(ShowFolder) -command showFolders
  289.    $Settings add check -label "Monitor base folders for new files" -variable tomAmpSettings(MonitorFolders) -command MonitorFolders
  290.    $Settings add separator
  291.    $Settings add command -label "Set Defaults"  -command settingsGui
  292. }
  293. ###############################################################################
  294. # Function   : Console
  295. # Description: Toggle the console for debugging purposes (WIN32 only)
  296. # Author     : Tom Wilkason
  297. # Date       : 12/27/2000
  298. ###############################################################################
  299. proc Console {args} {
  300.    global taFiles tomAmp LB
  301.    if {$tomAmp(Console)==0} {
  302.       console hide
  303.    } else {
  304.       console show
  305.    }
  306. }
  307. ;##
  308. ;# Callback to show config files on menu, called from postcommand
  309. ;#
  310. proc configFiles {menu} {
  311.    global taFiles tomAmp LB
  312.    # Rescan
  313.    if {[catch {set Files [glob ~/*.taf]} result]} {
  314.       return
  315.    }
  316.  
  317.    $menu.mAppend delete 0 end
  318.    $menu.mReplace delete 0 end
  319.    ;##
  320.    ;# Need to sort the list by decending date
  321.    ;#
  322.    foreach File $Files {
  323.       set Date [file mtime $File]
  324.       lappend FileList [list $File $Date]
  325.    }
  326.    set FileList [lsort -index 1 -decreasing $FileList]
  327.    foreach {File} $FileList {
  328.       ;##
  329.       ;# Pull out only the file name and add it to the menu
  330.       ;#
  331.       set F [lindex $File 0]
  332.       $menu.mAppend add command -label "[file tail $F]" -command [list ReadPlaylistFile $F "append"]
  333.       $menu.mReplace add command -label "[file tail $F]" -command [list ReadPlaylistFile $F "replace"]
  334.    }
  335. }
  336. ;##
  337. ;# Callback to show folder setting files
  338. ;#
  339. proc folderFiles {menu} {
  340.    global taFiles tomAmp LB
  341.    # Rescan
  342.    if {[catch {set Files [glob ~/*.tafs]} result]} {
  343.       return
  344.    }
  345.  
  346.    $menu delete 0 end
  347.    ;##
  348.    ;# Need to sort the list by decending date
  349.    ;#
  350.    foreach File $Files {
  351.       set Date [file mtime $File]
  352.       lappend FileList [list $File $Date]
  353.    }
  354.    set FileList [lsort -index 1 -decreasing $FileList]
  355.    foreach {File} $FileList {
  356.       ;##
  357.       ;# Pull out only the file name and add it to the menu
  358.       ;#
  359.       set F [lindex $File 0]
  360.       $menu add command -label "[file tail $F]" -command [list ReadFolderFile $F]
  361.    }
  362. }
  363. ###############################################################################
  364. # Function   : toggleMute
  365. # Description: Toggle muting of sound, bound to click on main label
  366. # Author     : Tom Wilkason
  367. # Date       : 12/31/2000
  368. ###############################################################################
  369. proc toggleMute {widget} {
  370.    global tomAmp
  371.    if {$tomAmp(Mute)} {
  372.       set tomAmp(Mute) 0
  373.       $widget configure -foreground green
  374.       snack::audio play_gain $tomAmp(saveGain)
  375.    } else {
  376.       set tomAmp(Mute) 1
  377.       set tomAmp(saveGain) [snack::audio play_gain]
  378.       snack::audio play_gain 0
  379.       $widget configure -foreground red
  380.    } ;# end if
  381.    set tomAmp(saveMute) $tomAmp(Mute)
  382.  
  383. }
  384. ###############################################################################
  385. # Function   : settingsGui
  386. # Description: Small GUI to allow the user to set the defaults
  387. # Author     : Tom Wilkason
  388. # Date       : 12/30/2000
  389. ###############################################################################
  390. proc settingsGui {args} {
  391.    global taFiles tomAmp LB tomAmpSettings
  392.    set B .settings
  393.    toplevel $B
  394.    set i 0
  395.    grid [label $B.[incr i] -text "Please set the defaults below and press OK to save\nRescan folders if you change them here" ]\
  396.     -columnspan 2
  397.    grid [frame $B.[incr i] -height 2 -borderwidth 2 -relief sunken] -columnspan 2 -sticky nsew
  398.    #----------------------------------------------------------------------------------------------
  399.    grid [label $B.[incr i] -text "List of base directories to scan" -justify left] \
  400.       [entry $B.[incr i] -textvariable tomAmpSettings(mediaDirs) -width 50]  -sticky ew
  401.    grid [label $B.[incr i] -text "Start with random play" -justify left] \
  402.       [checkbutton $B.[incr i] -variable tomAmpSettings(randomPlay)] -sticky ew
  403.    grid [label $B.[incr i] -text "Continuous Play Mode" -justify left] \
  404.       [checkbutton $B.[incr i] -variable tomAmpSettings(ContinuousPlay)] -sticky ew
  405.    grid [label $B.[incr i] -text "Rescan Folders on Startup" -justify left] \
  406.       [checkbutton $B.[incr i] -variable tomAmpSettings(AutoRescan)] -sticky ew
  407.    grid [label $B.[incr i] -text "Show folder names with song names" -justify left] \
  408.       [checkbutton $B.[incr i] -variable tomAmpSettings(ShowFolder)] -sticky ew
  409.    grid [label $B.[incr i] -text "Monitor base folders for changes" -justify left] \
  410.       [checkbutton $B.[incr i] -variable tomAmpSettings(MonitorFolders)] -sticky ew
  411.    grid [label $B.[incr i] -text "Folder level to show on Folder Menu" -justify left] \
  412.       [entry $B.[incr i] -textvariable tomAmpSettings(FolderDepth)] -sticky ew
  413.    grid [label $B.[incr i] -text "Subfolders to show in Song List" -justify left] \
  414.       [entry $B.[incr i] -textvariable tomAmpSettings(ListDepth)] -sticky ew
  415.    #----------------------------------------------------------------------------------------------
  416.    grid [frame $B.[incr i] -height 2 -borderwidth 2 -relief sunken] -columnspan 2 -sticky nsew
  417.    grid [button $B.[incr i] -text "OK" -command saveSettings] \
  418.       [button $B.[incr i] -text "Cancel" -command {destroy .settings}]
  419.    after idle raise $B
  420. }
  421. ###############################################################################
  422. # Function   : saveSettings
  423. # Description: Save the settings from the settingsGui
  424. # Author     : Tom Wilkason
  425. # Date       : 12/30/2000
  426. ###############################################################################
  427. proc saveSettings {args} {
  428.    global tomAmpSettings tomAmp
  429.    set fid [open $tomAmp(settingsFile) w]
  430.    puts $fid [array get tomAmpSettings]
  431.    close $fid
  432.    destroy .settings
  433.    MonitorFolders
  434. }
  435. ###############################################################################
  436. # Function   : MonitorFolders
  437. # Description: Monitor the base folders for incoming data, useful
  438. #              for napaster adding files.
  439. # Author     : Tom Wilkason
  440. # Date       : 12/30/2000
  441. ###############################################################################
  442. proc MonitorFolders {args} {
  443.    global tomAmpSettings tomAmp
  444.    if {$tomAmpSettings(MonitorFolders)} {
  445.       foreach {Folder} $tomAmpSettings(mediaDirs) {
  446.          ;# First time will be empty
  447.          set tomAmp($Folder,thisData) [glob -nocomplain [file join $Folder *.mp3]]
  448.          if {![info exists tomAmp($Folder,lastData)]} {
  449.             set tomAmp($Folder,lastData) $tomAmp($Folder,thisData)
  450.          } elseif {$tomAmp($Folder,lastData) != $tomAmp($Folder,thisData)} {
  451.             puts "Changes detected"
  452.             foreach {item} $tomAmp($Folder,thisData) {
  453.                if {[lsearch $tomAmp($Folder,lastData) $item] < 0} {
  454.                   Append $item
  455.                   puts "Detected new file $item"
  456.                } ;# end if
  457.             } ;# end foreach
  458.             set tomAmp($Folder,lastData) $tomAmp($Folder,thisData)
  459.          } ;# end if
  460.       } ;# end foreach
  461.       after cancel MonitorFolders
  462.       after 5000 MonitorFolders
  463.    }
  464. }
  465. ;##
  466. ;# Read the default settings from the user home dir
  467. ;#
  468. proc readSettings {args} {
  469.    global tomAmpSettings tomAmp
  470.    set tomAmpSettings(mediaDirs) ~
  471.    set tomAmpSettings(randomPlay) 0
  472.    set tomAmpSettings(ContinuousPlay) 1
  473.    set tomAmpSettings(AutoRescan) 0
  474.    set tomAmpSettings(ShowFolder) 0
  475.    set tomAmpSettings(MonitorFolders) 0
  476.    set tomAmpSettings(ListDepth) 10       ;# Will show last folder
  477.    set tomAmpSettings(FolderDepth) 10     ;# Will show last folder
  478.    if {[catch {
  479.       set fid [open $tomAmp(settingsFile) r]
  480.       array set tomAmpSettings [read $fid]
  481.    } result]} {
  482.       settingsGui
  483.    } else {
  484.       close $fid
  485.    }
  486. }
  487. ;##
  488. ;# Save the current folder settings to a file
  489. ;#
  490. proc SaveFolderFile {args} {
  491.    global taFiles tomAmp LB taFolders
  492.    ;##
  493.    ;# If a list for GlobData is passed in, the second item should be the name to save as (if different)
  494.    ;#
  495.    set types [list [list "Tom Amp Files" .tafs] [list "All Files" "*"]]
  496.    set fName [tk_getSaveFile -title "Save Folder Setting File" -filetypes $types \
  497.       -initialdir ~ -defaultextension tafs]
  498.    catch {focus $ThisWin}
  499.    if { $fName == "" } {
  500.       return  ""
  501.    }
  502.    if {[catch {open $fName w} InFile]} {
  503.       return -code error "Save Error: Unable to open '$fName' for writing\n"
  504.    }
  505.  
  506.    if {$InFile!=0} {
  507.       foreach {File} [array names taFolders] {
  508.          puts $InFile [list $File $taFolders($File)]
  509.       } ;# end foreach
  510.       close $InFile
  511.       return $fName
  512.    } else {
  513.       return -1
  514.    }
  515. }
  516. ;##
  517. ;# Read a file and change the favorate folders
  518. ;#
  519. proc ReadFolderFile {fName} {
  520.    global taFolders
  521.    if {[file exists $fName]} {
  522.       set fid [open $fName r]
  523.       set full [split [read $fid] \n]
  524.       ;# Insert the files if they are not already in the list
  525.       foreach line $full {
  526.          set taFolders([lindex $line 0]) [lindex $line 1]
  527.       } ;# end foreach
  528.       close $fid
  529.    } ;# end if
  530.    filterMusic
  531. }
  532. ;##
  533. ;# Save current files in list
  534. ;#
  535. proc SavePlaylistFile {args} {
  536.    global taFiles tomAmp LB
  537.    ;##
  538.    ;# If a list for GlobData is passed in, the second item should be the name to save as (if different)
  539.    ;#
  540.    set types [list [list "Tom Amp Files" .taf] [list "All Files" "*"]]
  541.    set fName [tk_getSaveFile -title "Save Configuration File" -filetypes $types \
  542.       -initialdir ~ -defaultextension taf]
  543.    catch {focus $ThisWin}
  544.    if { $fName == "" } {
  545.       return  ""
  546.    }
  547.    if {[catch {open $fName w} InFile]} {
  548.       return -code error "Save Error: Unable to open '$fName' for writing\n"
  549.    }
  550.  
  551.    if {$InFile!=0} {
  552.       foreach {File} [getSelection 0 end] {
  553.          puts $InFile $taFiles($File)
  554.       } ;# end foreach
  555.       close $InFile
  556.       return $fName
  557.    } else {
  558.       return -1
  559.    }
  560. }
  561. ;##
  562. ;# Read a file and append/replace current list
  563. ;#
  564. proc ReadPlaylistFile {fName {how "replace"}} {
  565.    global taFiles tomAmp LB tomAmpSettings
  566.    set fid [open $fName r]
  567.    set full [split [read $fid] \n]
  568.    if {$how == "replace"} {
  569.       $LB delete 0 end
  570.    } ;# end if
  571.    ;# Insert the files if they are not already in the list
  572.    foreach file $full {
  573.       if {[file exists $file]} {
  574.          set name [getListName $file]
  575.          $LB insert end $name
  576.          set taFiles($name) $file
  577.       } ;# end if
  578.    } ;# end foreach
  579.    close $fid
  580. }
  581. ###############################################################################
  582. # Function   : Clear
  583. # Description: Clear the playlist
  584. # Author     : Tom Wilkason
  585. # Date       : 12/27/2000
  586. ###############################################################################
  587. proc Clear {args} {
  588.    global taFiles tomAmp LB
  589.    # catch {unset taFiles} result
  590.    $LB delete 0 end
  591. }
  592. ;##
  593. ;# Open a single file for playing, add to play list (should we play immed?)
  594. ;#
  595. proc OpenFile {} {
  596.    global taFiles tomAmp LB
  597.    set file [snack::getOpenFile -format MP3]
  598.    if {$file != ""} {
  599.       Append $file
  600.    }
  601. }
  602. ;# Play a list item.
  603. proc Play {{offset 0}} {
  604.    global taFiles tomAmp LB SS
  605.    if {[$LB index active] == ""} {
  606.       set i 0
  607.    } else {
  608.       set i [$LB index active]
  609.    }
  610.    ;# Note: Using current selection causes a problem if the song didn't change
  611.    ;# but the selection did an time scale change that changes the time.
  612.    # if no offset specified then see if random play
  613.    Highlight $i
  614.    Stop
  615.    ;# Check file existance
  616.    set Selection [getSelection $i]
  617.    if {$Selection!={}} {
  618.       if {! [file exists $taFiles($Selection)]} {
  619.          after 10 Next
  620.          return
  621.       } ;# end if
  622.       set errorInfo ""
  623.       ;##
  624.       ;# It seems faster on play -start to have the short file name and cd to that directory
  625.       ;# Also, UNC names are really slow (on Win2K anyway)!
  626.       ;# Strangly, network drive mappings are also fast (if not using UNC)
  627.       ;#
  628.       set tomAmp(currentMP3) $taFiles($Selection)
  629.       cd [file dirname $taFiles($Selection)]
  630.       s config -file $Selection
  631. #     length samprate "maximum sample" "minimum sample" "STRencoding" "number of channels" "file format" "header size in bytes"
  632.       set Info [s info]
  633.       ;# This can check for an invalid header
  634.       if {[lindex $Info 0] == -1} {
  635.          puts stderr "Invalid file: $taFiles($Selection)\n $Info"
  636.          set tomAmp(timestr) "Invalid header for:\n$Selection"
  637.          update
  638.          after 10 Next
  639.          return
  640.       } else {
  641.          #puts "OK: $taFiles($Selection)\n $Info"
  642.          #update
  643.       }
  644.       ;# See if user changed the slider to adjust where to play
  645.       if {$offset == 0} {
  646.          s play -command Next        ;# After complete call 'Next' function
  647.       } else {
  648.          ;# Fires Next command at end of this file
  649.          s play -start $offset -command Next
  650.       }
  651.       ;# What ~10 ticks on 5 or multiple sec intervals
  652.       set trackTime  [s length -units SECONDS]
  653.       set Interval [expr {(round($trackTime/10)/5)*5}]
  654.       if {$Interval == 0} {
  655.          set interval 5
  656.       } ;# end if
  657.       $SS configure -to $trackTime -tickinterval $Interval
  658.  
  659.       set songTitle [file root $Selection]
  660.       wm title . "$songTitle"
  661.       set tomAmp(current) $songTitle
  662.  
  663.       file stat $tomAmp(currentMP3) Stat
  664.       append tomAmp(current) " - ($Stat(size))"
  665.       balloon .panel.l "$taFiles($Selection)"
  666.  
  667.       Timer
  668.    }
  669. }
  670.  
  671. ;##
  672. ;# Play next sound file in list
  673. ;#
  674. proc Next {} {
  675.    global taFiles tomAmp LB tomAmpSettings
  676.    catch {
  677. #      puts "$tomAmp(elapsed) of [s length -units sec] - $tomAmp(current)"
  678.    }
  679.    set i [$LB index active]
  680.    if {$i == ""} {
  681.       set i 0
  682.    } else {
  683.       incr i
  684.    }
  685.    ;# check for continouos play
  686.    if {$i >= [$LB index end]} {
  687.       if {$tomAmpSettings(ContinuousPlay)} {
  688.          set i 0
  689.       }  else {
  690.          return
  691.       }
  692.    } ;# end if
  693.    Highlight $i
  694.    after 10 Play
  695. }
  696. ;##
  697. ;# Play previous sound file in list
  698. ;#
  699. proc Prev {} {
  700.    global taFiles tomAmp LB tomAmpSettings
  701.    set i [$LB index active]
  702.    if {$i == ""} {
  703.       set i 0
  704.    } elseif {$i==0} {
  705.       set i [$LB index end]
  706.    } else {
  707.       if {$i > 0} {
  708.          incr i -1
  709.       } ;# end if
  710.    }
  711.    Highlight $i
  712.    after 10 Play
  713. }
  714. ;##
  715. ;# Play a mp3 at some offset, likely bound to slider control
  716. ;#
  717. proc PlayOffset {{manual 0}} {
  718.    global taFiles tomAmp LB
  719.    ;# Make sure we have an open file
  720.    if {[s length] > 0} {
  721.       Stop
  722.       ;# Some files are fast and some are slow to respond to -start = 0
  723.       if {$manual == 0} {
  724.          set offset [expr {int(double($tomAmp(p))/[s length -units sec]*[s length])}]
  725.       } else {
  726.          set offset $manual
  727.       }
  728.       s play -start $offset -command Next
  729.       Timer
  730.    } ;# end if
  731. }
  732. ###############################################################################
  733. # Function   : Highlight
  734. # Description: Highlight only one selection
  735. # Author     : Tom Wilkason
  736. # Date       : 12/27/2000
  737. ###############################################################################
  738. proc Highlight {i} {
  739.    global taFiles tomAmp LB
  740.    $LB selection clear 0 end
  741.    $LB selection set $i
  742.    $LB activate $i
  743.    $LB see $i
  744.    set Entry [getSelection $i]
  745.    catch {
  746.       set tomAmp(entryName) $Entry
  747.       set tomAmp(fullName) [file dirname $taFiles($Entry)]
  748.    }
  749. }
  750. ###############################################################################
  751. # Function   : getSelection
  752. # Description: Return the selection(s) with no folder names (for index use)
  753. # Author     : Tom Wilkason
  754. # Date       : 1/1/2001
  755. ###############################################################################
  756. proc getSelection {start {end ""}} {
  757.    global LB
  758.    if {$end==""} {
  759.       return [file tail [$LB get $start]]
  760.    } else {
  761.       foreach {item} [$LB get $start $end] {
  762.          lappend result [file tail $item]
  763.       } ;# end foreach
  764.       return $result
  765.    } ;# end if
  766. }
  767. proc showFolders {args} {
  768.    global LB tomAmpSettings taFiles
  769.    foreach {item} [getSelection 0 end] {
  770.       lappend insertList [getListName $taFiles($item)]
  771.    }
  772.    $LB delete 0 end
  773.    if {[llength $insertList] > 0} {
  774.       eval $LB insert end $insertList
  775.    }
  776. }
  777.  
  778. ;##
  779. ;# Apend a file to the bottom of the play list
  780. ;#
  781. proc Append {file} {
  782.    global taFiles tomAmp LB
  783.    set name [file tail $file]
  784.    if {$file != "" && ![info exists taFiles($name)]} {
  785.       $LB insert end $name
  786.       set taFiles($name) $file
  787.    } ;# end if
  788. }
  789. ;##
  790. ;# Stop playback of a file and cancle the update timer
  791. ;#
  792. proc Stop {} {
  793.    global taFiles tomAmp LB
  794.    pauseRelief 0
  795.    s stop
  796.    after cancel Timer
  797. }
  798. ;##
  799. ;# Pause/resume playback
  800. ;#
  801. proc Pause {args} {
  802.    global taFiles tomAmp LB
  803.    s pause
  804.    if {$tomAmp(pause)} {
  805.       pauseRelief 0
  806.       Timer
  807.    } else {
  808.       pauseRelief 1
  809.       after cancel Timer
  810.    }
  811.    set tomAmp(savePause) $tomAmp(pause)
  812.  
  813. }
  814. ;##
  815. ;# Timer to update the display data, active while MP3 playing
  816. ;#
  817. proc Timer {} {
  818.    global taFiles tomAmp LB SS
  819.    # Time is curren pos/total len * total time
  820.    # set elapsed [expr {round(double([s current_position])/[s length]*[s length -units sec])}]
  821.    set elapsed [expr {round([s current_position -units sec])}]
  822.    set tomAmp(elapsed) $elapsed
  823.    set tomAmp(timestr) "$tomAmp(current)\n[clock format $elapsed -format %M:%S] of [clock format [expr {int([s length -units sec])}] -format %M:%S]"
  824.    ;# If user dragging slider, don't also try to set slider
  825.    if $tomAmp(setdrag) {
  826.       catch {
  827.          $SS set $elapsed
  828.       }
  829.    }
  830.    #    Draw
  831.    after 500 Timer
  832. }
  833. ;##
  834. ;# GUI Bindings
  835. ;#
  836. proc Cut {} {
  837.    global taFiles tomAmp LB
  838.    if {[$LB curselection] != ""} {
  839.       set Index [$LB index active]
  840.       if {$Index} {incr Index -1}
  841.       foreach {ind} [lsort -decreasing [$LB curselection]] {
  842.          set cut [getSelection $ind]
  843.          unset taFiles($cut)
  844.          $LB delete $ind
  845.       } ;# end foreach
  846.       Highlight $Index
  847.    }
  848. }
  849. ;##
  850. ;# Callback to remove the current selections from the display
  851. ;#
  852. proc Delete {} {
  853.    global taFiles tomAmp LB
  854.    if {[$LB curselection] != ""} {
  855.       set Index [$LB index active]
  856.       if {$Index} {incr Index -1}
  857.       foreach {ind} [lsort -decreasing [$LB curselection]] {
  858.          set File [getSelection $ind]
  859.          if {$tomAmp(currentMP3)==$taFiles($File)} {
  860.             Stop
  861.             s destroy
  862.             snack::sound s
  863.          } ;# end if
  864.          file delete $taFiles($File)
  865.          unset taFiles($File)
  866.          $LB delete $ind
  867.       } ;# end foreach
  868.       Highlight $Index
  869.    }
  870. }
  871. ;##
  872. ;# Select/Drag
  873. ;#
  874. proc Select y {
  875.    global taFiles tomAmp LB
  876.    set tomAmp(old) [$LB nearest $y]
  877.    set Value [$LB get $tomAmp(old)]
  878.    if {$Value != {}} {
  879.       set tomAmp(entryName) [file tail $Value]
  880.       set tomAmp(fullName) [file dirname $taFiles([file tail $Value])]
  881.       set tomAmp(origEntryName) [file tail $Value] ;# for renaming
  882.       set tomAmp(entryIndex) $tomAmp(old)
  883.    } ;# end if
  884.  
  885. }
  886.  
  887. proc Drag y {
  888.    global taFiles tomAmp LB
  889.    set new [$LB nearest $y]
  890.    if {$new == -1} return
  891.    set tmp [$LB get $tomAmp(old)]
  892.    $LB delete $tomAmp(old)
  893.    $LB insert $new $tmp
  894.    $LB selection set $new
  895.    set tomAmp(old) $new
  896. }
  897. ###############################################################################
  898. # Function   : filterMusic
  899. # Description: Restrict files shown based on the filter & folder settings
  900. # Author     : Tom Wilkason
  901. # Date       : 12/26/2000
  902. ###############################################################################
  903. proc filterMusic {{how replace}} {
  904.    global taFiles tomAmp LB tomAmpSettings taFolders
  905.    if {$how == "replace"} {
  906.       $LB delete 0 end
  907.    } ;# end if
  908.    set insertList [list]
  909.  
  910.    ;# Below will prevent duplicates due to hashing
  911.    foreach {File} [array names taFiles *] {
  912.       if {$File != "" && [string match -nocase "*$tomAmp(filter)*" $taFiles($File)]} {
  913.          ;# Verify this file is in a checked folder
  914.          if {[catch {
  915.             # See if this file matches folder menu entry
  916.             if {$taFolders([getFolderName [file dirname $taFiles($File)]])} {
  917.                set File [getListName $taFiles($File)]
  918.                lappend insertList $File
  919.             } ;# end if
  920.          } result]} {
  921.             puts stderr $result
  922.          }
  923.       } ;# end if
  924.    } ;# end foreach
  925.    ;# Shuffle if needed
  926.    if {$tomAmpSettings(randomPlay)} {
  927.       set insertList [shuffle $insertList]
  928.    } else {
  929.       set insertList [lsort -dictionary $insertList]
  930.    }
  931.    if {[llength $insertList] > 0} {
  932.       eval $LB insert end $insertList
  933.    } ;# end if
  934.    Highlight 0
  935. }
  936. ;##
  937. ;# Shuffle a list, used to randomize play list
  938. ;#
  939. proc shuffle {list} {
  940.    set tmp [list]
  941.    foreach item $list {
  942.       lappend tmp [list $item [expr {rand()}]]
  943.    }
  944.    set res [list]
  945.    foreach item [lsort -real -index 1 $tmp] {
  946.       foreach {orig num} $item {
  947.          lappend res $orig
  948.       } ;# end foreach
  949.    }
  950.    return $res
  951. }
  952. ###############################################################################
  953. # Function   : getListName
  954. # Description: Return a song name with the appropriate folders prepended
  955. # Author     : Tom Wilkason
  956. # Date       : 1/3/2001
  957. ###############################################################################
  958. proc getListName {File} {
  959.    global tomAmpSettings
  960.    set File [string map {// /} $File]      ;# remove UNC stuff
  961.    if {$tomAmpSettings(ShowFolder)} {
  962.       set parts [lrange [file split $File] end-$tomAmpSettings(ListDepth) end]
  963.       set name [join $parts /]
  964.    } else {
  965.       set name [file tail $File]
  966.    }
  967.    return $name
  968. }
  969. ###############################################################################
  970. # Function   : getListName
  971. # Description: Return a folder name with the appropriate depth away from base
  972. # Author     : Tom Wilkason
  973. # Date       : 1/3/2001
  974. ###############################################################################
  975. proc getFolderName {File} {
  976.    global tomAmpSettings
  977.    set File [string map {// /} $File]      ;# remove UNC stuff
  978.    set parts [file split $File]
  979.    set len [llength $parts]
  980.    if {$tomAmpSettings(FolderDepth) >= $len} {
  981.       set name [lindex $parts end]
  982.    }  else {
  983.       set name [lindex $parts $tomAmpSettings(FolderDepth)]
  984.    }
  985.    # puts "getFolderName:($tomAmpSettings(FolderDepth)) $name - $File"
  986.    return $name
  987. }
  988. ###############################################################################
  989. # Function   : buildFolderMenu
  990. # Description: Build the folder menu base on folder names in taFolders
  991. # Author     : Tom Wilkason
  992. # Date       : 12/26/2000
  993. ###############################################################################
  994. proc buildFolderMenu {args} {
  995.    global taFiles tomAmp LB tomAmpSettings taFolders
  996.    $LB delete 0 end
  997.    # Remove after the last fixed menu
  998.    $tomAmp(FolderMenu) delete 5 end
  999.    $tomAmp(FolderMenu) add separator
  1000.    foreach {folder} [lsort -dictionary [array names taFolders *]] {
  1001.       $tomAmp(FolderMenu) add check -label "$folder" -variable taFolders($folder) -command filterMusic
  1002.    } ;# end foreach
  1003. }
  1004. ###############################################################################
  1005. # Function   : Rescan
  1006. # Description: Reread the directories for files, include subdirectories
  1007. #              For each folder, add a menu entry
  1008. # Author     : Tom Wilkason
  1009. # Date       : 12/26/2000
  1010. ###############################################################################
  1011. proc Rescan {args} {
  1012.    global taFiles tomAmp LB tomAmpSettings taFolders
  1013.    set here [pwd]
  1014.    catch {unset taFiles} result
  1015.    ;# save folder settings
  1016.    catch {array set saveTaFolders [array get taFolders]}
  1017.    catch {unset taFolders} result
  1018.    foreach dir $tomAmpSettings(mediaDirs) {
  1019.       # set taFolders([file tail $dir]) 1
  1020.       set taFolders([getFolderName $dir]) 1
  1021.       Rescan.getRecurseFiles $dir
  1022.    } ;# end foreach
  1023.    ;# Restore folder settings
  1024.    foreach {index dir} [array get taFolders] {
  1025.       if {[info exists saveTaFolders($index)]} {
  1026.             set taFolders($index) $saveTaFolders($index)
  1027.       }
  1028.    } ;# end foreach
  1029.    ;##
  1030.    ;# Build the folder list for the menu
  1031.    ;#
  1032.    buildFolderMenu
  1033.    filterMusic
  1034.    ;##
  1035.    ;# Save the settings
  1036.    ;#
  1037.    set fid [open $tomAmp(cacheFile) w]
  1038.    puts $fid [array get taFiles]
  1039.    puts $fid [array get taFolders]
  1040.    close $fid
  1041.  
  1042. }
  1043. ;##
  1044. ;# Recursively scan a directory and build a list of all files
  1045. ;#
  1046. proc Rescan.getRecurseFiles {dir} {
  1047.    global taFiles tomAmp LB taFolders
  1048.    set dirList [list]
  1049.    set fileCount 0
  1050.  
  1051.    foreach file [glob -nocomplain [file join $dir *]] {
  1052.       if {[file isdirectory $file]} {
  1053.          lappend dirList $file
  1054.       } else {
  1055.          if {[string match -nocase "*.mp3" $file]} {
  1056.             set name [file tail $file]
  1057.             set taFiles($name) [file join $dir $file]
  1058.             incr fileCount
  1059.          } ;# end if
  1060.       }
  1061.    }
  1062.    ;# If this dir contained files, the create a menu entry for it
  1063.    if {$fileCount} {
  1064.       set taFolders([getFolderName $dir]) 1    ;# checkbox on menu
  1065.    } ;# end if
  1066.    ;# process each directory recursively
  1067.    foreach {file} $dirList {
  1068.       Rescan.getRecurseFiles [file join $dir $file]
  1069.    } ;# end foreach
  1070. }
  1071. ;####################################################################################
  1072. ;#                   C O L L A P S A B L E    F R A M E
  1073. ;####################################################################################
  1074. ;# cframe: Collapsable frame
  1075. ;# base: name of outer collapsable frame, user is responsible for packing
  1076. ;# text: title for the window frame, next to collapse button
  1077. ;# args: additional user settings passed to inner frame
  1078. ;# returns hull: user can pack into this frame
  1079. ;#
  1080. proc cframe {base text args} {
  1081.    #-----------------------------------------------------------
  1082.    # Add the widget to the parent.
  1083.    #-----------------------------------------------------------
  1084.    # create button icons
  1085.    image create photo im_Close -data {
  1086.       R0lGODlhEAAQAKIAAP///9TQyICAgEBAQAAAAAAAAAAAAAAAACwAAAAAEAAQAAADNhi63BMg
  1087.       yinFAy0HC3Xj2EJoIEOM32WeaSeeqFK+say+2azUi+5ttx/QJeQIjshkcsBsOp/MBAA7
  1088.    }
  1089.  
  1090.    image create photo im_Open -data {
  1091.       R0lGODlhEAAQAKIAAP///9TQyICAgEBAQAAAAAAAAAAAAAAAACwAAAAAEAAQAAADMxi63BMg
  1092.       yinFAy0HC3XjmLeA4ngpRKoSZoeuDLmo38mwtVvKu93rIo5gSCwWB8ikcolMAAA7
  1093.    }
  1094.  
  1095.    frame $base
  1096.    # let the user pack the outside base frame
  1097.    frame $base.ohull  -borderwidth 2 -height 16 -relief ridge
  1098.  
  1099.    label $base.button  -borderwidth 0 -image im_Open -relief raised -text "101"
  1100.  
  1101.    bind $base.button <Button-1> {cframe.toggle [winfo parent %W].ohull.ihull}
  1102.    label $base.label  -anchor w -borderwidth 1 -text $text
  1103.  
  1104.    #
  1105.    # pack special frame/button
  1106.    #
  1107.    pack $base.ohull -anchor nw -expand 1 -fill both -side left  -ipadx 2 -ipady 8
  1108.    place $base.button  -x 5 -y -1 -width 21 -height 21 -anchor nw -bordermode ignore
  1109.    place $base.label  -x 23 -y 3  -height 13 -anchor nw -bordermode ignore
  1110.  
  1111.    #
  1112.    # Create a label underneath the "title" to prevent overlap
  1113.    # then pack a frame in below that which will be the hull i.e. childsite for users
  1114.    #
  1115.    label $base.ohull.padder -text ""
  1116.    pack $base.ohull.padder -side top
  1117.    eval set hull $base.ohull.ihull
  1118.    ;# Create the inner frame using any additional arguments passed in
  1119.    eval frame $hull $args
  1120.    pack $hull -expand true -fill both
  1121.    return $hull
  1122. }
  1123. #-----------------------------------------------------------
  1124. # Toggle the widget, toggle the 'can be opened' icon.
  1125. # can also called as cframe.toggle $cframeWidget
  1126. #-----------------------------------------------------------
  1127. proc cframe.toggle {ihull} {
  1128.    set button "[winfo parent [winfo parent $ihull]].button"
  1129.    set a [$button cget -image]
  1130.    if { $a == "im_Open" } {
  1131.       cframe.close $ihull
  1132.    } else {
  1133.       cframe.open $ihull
  1134.    }
  1135. }
  1136. #-----------------------------------------------------------
  1137. # Collapse the widget, display the 'can be opened' icon.
  1138. # can also called as cframe.close $cframeWidget
  1139. #-----------------------------------------------------------
  1140. proc cframe.close {ihull} {
  1141.    set base [winfo parent [winfo parent $ihull]]
  1142.    $base.button configure -image im_Close
  1143.    pack forget $base.ohull
  1144.    ;# Make outer frame just small enough for button and title
  1145.    $base configure -height 16 -width 50
  1146.    # Force the screen back to its requested size in case the
  1147.    # user manually changed it's size.
  1148.    wm geometry [winfo toplevel $base] {}
  1149. }
  1150.  
  1151. #-----------------------------------------------------------
  1152. # Open the widget, display the 'can be closed' icon.
  1153. # cal also called as cframe.open $cframeWidget
  1154. #-----------------------------------------------------------
  1155. proc cframe.open {ihull} {
  1156.    set base [winfo parent [winfo parent $ihull]]
  1157.    $base.button configure -image im_Open
  1158.    pack $base.ohull -anchor nw -expand 1 -fill both -side left -ipadx 2 -ipady 10
  1159.    ;# Below will force the toplevel to refresh it's size incase the user
  1160.    ;# Manually resized the toplevel. In those cases the packing areas
  1161.    ;# won't automatically contract unless you tell the toplevel to
  1162.    ;# use it's requested size.
  1163.    wm geometry [winfo toplevel $base] {}
  1164. }
  1165. #//////////////////////////////////////////////////////////////////////////////
  1166. #                   B A L L O O N    H E L P
  1167. #//////////////////////////////////////////////////////////////////////////////
  1168. ###############################################################################
  1169. # Function   : balloon
  1170. # Description: Bind ballon help to some widget
  1171. # Author     : Tom Wilkason
  1172. # Date       : 1/2/2000
  1173. ###############################################################################
  1174. proc balloon {w help} {
  1175.     bind $w <Any-Enter> "after 300 [list balloon:show %W [list $help]]"
  1176.     bind $w <Any-Leave> "destroy %W.balloon"
  1177. }
  1178. ###############################################################################
  1179. # Function   : balloon:show
  1180. # Description: Pop-up the ballon help based on a callback for the widget enter
  1181. # Author     : Tom Wilkason
  1182. # Date       : 1/2/2000
  1183. ###############################################################################
  1184. proc balloon:show {w arg} {
  1185.    if {[eval winfo containing  [winfo pointerxy .]]!=$w} {return}
  1186.    set top $w.balloon
  1187.    catch {destroy $top}
  1188.    toplevel $top -bd 1 -bg black
  1189.    wm overrideredirect $top 1
  1190.    pack [message $top.txt -aspect 10000 -bg lightyellow \
  1191.          -font {Arial 8} -text $arg]
  1192.    set wmx [winfo rootx $w]
  1193.    set wmy [expr [winfo rooty $w]+[winfo height $w]]
  1194.    wm geometry $top \
  1195.       [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy
  1196.    raise $top
  1197. }
  1198. #
  1199. ###############################################################################
  1200. # Fire it up
  1201. ###############################################################################
  1202. #
  1203. buildGui
  1204. readSettings
  1205. if {$tomAmpSettings(AutoRescan)} {
  1206.    Rescan
  1207.    ;##
  1208.    ;# Apply the default folder settings
  1209.    ;#
  1210.    ReadFolderFile $tomAmp(defaultFolderFile)
  1211.  
  1212. } else {
  1213.    if {[catch {set fid [open $tomAmp(cacheFile) r]} result]} {
  1214.       Rescan
  1215.    } else {
  1216.       ;##
  1217.       ;# Read the cached data
  1218.       ;#
  1219.       gets $fid TaFiles
  1220.       array set taFiles $TaFiles
  1221.       gets $fid TaFolders
  1222.       array set taFolders $TaFolders
  1223.       close $fid
  1224.  
  1225.       buildFolderMenu
  1226.       ReadFolderFile $tomAmp(defaultFolderFile)
  1227.    }
  1228. }
  1229. MonitorFolders
  1230.  
  1231. ###############################################################################
  1232. # Function   : tst
  1233. # Description:
  1234. # Author     : Tom Wilkason
  1235. # Date       : 12/31/2000
  1236. ###############################################################################
  1237. proc tst {{offset 0}} {
  1238.    set file "d:/media/incoming/Classic Rock/Crosby, Stills, Nash & Young - Everybody I Love You.mp3"
  1239.    set file "//Toms/K6 D/Media/Incoming/Classic Rock/Crosby, Stills, Nash & Young - Everybody I Love You.mp3"
  1240.    Stop
  1241.    s config -file $file
  1242.    set now [clock seconds]
  1243.    set xxx [expr {int(double(100.)/[s length -units sec]*[s length])}]
  1244.    s play -start $offset -command Next
  1245.    puts "Time:[expr {[clock seconds] - $now}]"
  1246.    puts [s info]
  1247.    Timer
  1248.    after 3000 s stop
  1249. }
  1250.  
  1251.