uniquename - 2013dec15

I recently contributed code at tkImageViewer - for Mask-Selecting Images from a Directory Hierarchy --- to provide a Tk GUI 'front end' to a combination of the 'find' command and a user-selectable image viewer command/program.

The GUI was designed to offer the user a choice from several image viewer programs --- such as ImageMagick 'display' or 'ffplay' or 'eog' (Eye of Gnome). It is quite easy to switch out any of these viewer programs/commands to replace them with another image viewer that is available in a user's operating environment.

The 'tkImageViewer' utility was implemented as a Tk script and 2 shell scripts. As such, it should be implementable with very few changes in various Linux/BSD/Mac/Unix operating system environments.

I added the 'Tk Batch Image Viewer' utility to the list of 'done and to-do' utilities in the 'CFE' (Code - Front Ends) section near the bottom of my 'bio' page at uniquename. And soon I was thinking about another utility that I would like to add to that list.

Soon after submitting (and updating/enhancing) the 'find'-and-imageViewer' FrontEnd utility, I realized that, with relatively few changes, the Tk script and the 2 shell scripts could be altered to provide a way to 'find' movie (and/or audio) files and play them with any of the many 'media-player' programs that are available on Linux and other such systems.

Some of the 'media-player' programs that I was aware of were:

  • mplayer
  • ffplay
  • totem
  • gnome-mplayer
  • VLC
  • smplayer
  • gmplayer

Several of these are GUI front-ends to the 'mplayer' program --- or they use media library routines that were used to implement the 'mplayer' program. At least one uses the 'Gstreamer' media library.

Like for the 'find-and-image-viewer' utility, I made a 'text-sketch' for the GUI for the 'find-and-media-player' utility:

   ---------------------------------------------------------------------------
   'find'-mediaplayer Front End -  a Tk Multi-Movie/Audio-File-Player Utility   [window title]
   ---------------------------------------------------------------------------

   {Exit} {Help} {LaunchPlayerJob}            {CountFilenames} {ShowFilenames}

   Full Filename Mask (for movie/audio): ________________________  {Browse...}

   MediaPlayer : O 'mplayer'   O 'ffplay'  O 'gnome-mplayer'  O 'totem'  O 'VLC'

   DisplaySize: O DEFAULT-size (up to fullscreen)  O FULLSCREEN (without toolbars)

   Search Levels for Mask:  O ONE  O ALL subdirectories of selected directory

   Case Sense for Mask Search:  O case-sensitive  O case-INsensitive

   File Size (MegaBytes):  _________  O bigger-than  O smaller-than

   File Age (Days) : ________________ O older-than  O younger-than

   File Type: ___________   (Warning: SLOW) Examples: 'MPEG v4' or 'MPEG sequence'
   or  'Flash'  or  'Apple QuickTime'  or  'Microsoft ASF'  or  'layer III'  or 'PCM'
   ---------------------------------------------------------------------------------------------------------------

where

   Braces indicate a Tk 'button' widget.
   Underscores indicate a Tk 'entry' widget.
   A colon indicates that the text before the colon is on a 'label' widget.
   Capital-O indicates a Tk 'radiobutton' widget.
   Capital-X indicates a Tk 'checkbutton' widget.
   Square brackets indicate a comment (not to be placed on the GUI).

---

GUI Components

From the GUI 'sketch' above, it is seen that the GUI consists of about

   -  5 button widgets
   -  9 label widgets
   -  4 entry widgets
   - 15 radiobutton widgets in 6 groups
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets

There are a couple of lines added to this GUI, compared to the GUI for the 'find-and-image-viewer' utility:

   - a 'Display Size' line, to specify whether the 'player' should start in
     a full-screen mode (which, for most media-players means that toolbars
     are not shown, so that the full screen can be used for the movie)

   - an additional 'label' line at the bottom, to allow for displaying more
     examples of strings that can be specified for the FileType search option.

---

Front-End-for-Two ; the Players ; Beauty (or lack thereof)

This 'Front End' Tk script is essentially a 'wrapper' for TWO commands --- the 'find' command that assembles the files to be 'played' and a media-player command (of the user's choice, from among several).

NOTE that among the 8 'parameter-lines' of this GUI, only 2 have to do with the media-player:

  • the line of radiobuttons used to select the 'player'

and

  • the 'Display Size' line (fullscreen or not).

The other parameters are for the 'find' command.

---

As far as choosing which movie player to use, I am partial to using ones based on the 'mplayer' program, because I have encountered a few movies that would not play with 'VLC' but would play with 'mplayer'. And I have never experienced the opposite.

However, in various Linux forums, I have seen many people express their preference for the VLC player. This may partly be because there seems to have been quite a bit of development time spent on handling streaming media via various Internet protocols.

Since this 'find-and-mediaPlayer' utility is intended mainly for finding-and-playing files on 'local' disk drives, those Internet features do not come into play here. But there are still going to be those who prefer 'VLC', so 'VLC' is presented as an option on this GUI.

---

I should point out here that I was not especially interested in coming up with a 'beautiful utility'. I just wanted a utility that would be able to sweep through a hierarchy of sub-directories and pick out movie and/or audio files to 'play' based on a rather 'rich' set of selection capabilities --- such as 'file-mask' and/or 'file-size' and/or 'file-age' and/or 'file-type'.

I am certainly interested in making pretty GUI's --- as I have expressed on my 'bio' page at uniquename, and as my pages at Experiments in making embellished GUI's and Version 2 of a demo of THEMES for Tk GUI's, using images and colors have indicated.

But at this time, I am satisfied to implement the 'functionality', and let the 'beauty' go for a later date (when I have more beauty tools/code at hand).


SOME GUI IMAGES

On the basis of the sketch above, I ended up with the GUI seen in the following image.

find-mediaplayer_FrontEnd_initial_screenshot_670x337.jpg

Note that there are a couple of radiobuttons that allow you to choose whether application of the file-mask is 'case-sensitive' or 'case-INsensitive'. For example, if you chose 'case-INsensitive' and the mask were set to '*.mp3', then files with the suffix '.MP3' would also be selected.

And there are a couple of radiobuttons that allow you to choose whether to do the 'mask-search' at the current directory level only --- or to sweep through all sub-directories of the current 'base' directory, looking for media files that satisfy the criteria chosen via this GUI.

Here is a place where I MAY make a future enhancement: I may change the 'ONE' radiobutton to an 'N-levels' radiobutton --- and if that radiobutton is selected, an entry field will be activated where the user can enter a choice of N (with the entry field being initialized with '1').

---

Here is another image of the GUI, showing a different setting of most of the radiobuttons --- and entries placed in the file-size and file-age entry fields.

find-mediaplayer_FrontEnd_changedRadiobuttonsEtc_screenshot_669x336.jpg

NOTE that most simple media-players --- like 'ffplay' --- are oriented toward playing a single file at a time. And the more complex media-players --- like 'mplayer', 'totem', and 'VLC' --- are oriented toward playing a single large movie file or a lot of smaller media files via a 'playlist'.

This 'find-and-media-player' utility is oriented toward SELECTING media files (based on criteria such as a file-mask, file-size, file-age, and/or file-type) from an ENTIRE HIERARCHY OF SUB-DIRECTORIES --- as well as allowing mask-search in a SINGLE directory.

This utility SORTS the found-files by filename and then starts a loop in which each file is shown by the user-selected media player. When the user closes the media-player window, the next file is started up in the media-player.

So this utility does not have the flexibility of a 'playlist' approach. The user is not given an opportunity to change the order in which the selected files are played. (I will offer that capability when I make a Tk GUI 'front end' for the 'mplayer' command --- which is on my 'to-do' list.)

On the other hand, this utility offers the user the ability to quickly and auto-magically sweep through a directory hierarchy, selecting files by a 'rich' set of criteria, and 'play' the selected movie files (and audio files) --- which may be scattered throughout that hierarchy.

By using the file-mask option (and file-age and file-size and file-type options), the user has quite a bit of selection ability. The user can avoid a lot of 'manual' searching for files by letting the 'find' command find the desired files --- in a flash (pun intended).

ALSO, note that this utility can be useful without even using any of the 'player' programs. Say you want to know the NUMBER or NAMES of the media files satisfying a set of criteria (file-mask, file-size, file-age, file-type). Then set the criteria and click on the 'CountFilenames' or 'ShowFilenames' button.

IN FACT, by using the 'ShowFilenames' button you can get a list from which to build a 'playlist' file. The filenames are shown in a popup Tk 'text' widget --- from which you can paste the names into a text-editor window of your choice.

---

Note also that this utility can be used to 'play' a single file. Just select a full filename and do not change the last part of the filename to a mask. Then click the 'LaunchPlayer' button. (Remember to unset any criteria which the selected file would not satisfy. Note that you can click on the 'CountFilenames' button to see if it returns a value of 1, rather than 0.)

The File-Type search option

The 'file-type' search capability is based on using the 'file' command to return a file-type string --- FOR EACH FILE being processed by the 'find' command.

The 'file' command returns text strings like the following, for MOVIE files:

  Typical file suffix      'find' output (not the video or audio
  ('container' indicator)         format, but the 'container' format)
  ----------------------   -----------------------------------------

  mp4                      ISO Media, MPEG v4 system, version 1
  mpg or mpeg              MPEG sequence, v1, system multiplex
  flv                      Macromedia Flash Video
  mov                      ISO Media, Apple QuickTime movie
  wmv                      Microsoft ASF

And 'file' returns text strings like the following, for AUDIO files:

  Typical
  suffix  'find' output
  ------- -----------------------------------------

  mp3     MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
  wav     RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 22050 Hz

Although the file-mask and file-size and file-age options can reduce the number of files to which the 'file' command is applied, adding 'file' command processing to files processed by the 'find' command will add a lot of processing to the find-search.

So be aware that specifying 'FileType' on the GUI will often result in much slower response than when leaving that field blank.

But the FileType capability is useful when one is dealing with media files for which the WRONG SUFFIX was supplied --- OR media files that were NOT PROVIDED WITH A SUFFIX.

The following image shows the 'File-Type' entry field being employed.

See the 'ASF' entry at the bottom of the GUI --- and the '*' file-mask being used in the entry field near the top of the GUI.

find-mediaplayer_FrontEnd_filetypeASF_screenshot_670x337.jpg


The code

Below, I provide the Tk script code for this 'multi-subdirectory tkMediaPlayer' utility.

I follow my usual 'canonical' structure for Tk code for this Tk script:

  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control,
     text-array-for-labels-etc).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).

I call your attention to step-zero. One thing that I have started doing in 2013 is using a text-array for text in labels, buttons, and other widgets in the GUI. This can make it easier for people to internationalize my scripts. I will be using a text-array like this in most of my scripts in the future.


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.

That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.

I think that I have used a pretty nice choice of the 'pack' parameters. The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the entry widgets expand/contract horizontally whenever the window is re-sized horizontally.

You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.

___

Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

If you find the gray 'palette' of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.


Some features in the code

That said, here's the code --- with plenty of comments to describe what most of the code-sections are doing.

You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.

The main procs are

  'get_filemask'         - called by the 'Browse...' button
                           next to the filemask entry field

  'getFiles_andCountPrintOrPlay'
                        - called by the 'LaunchPlayerJob', 'CountFilenames',
                          and 'ShowFilenames' buttons

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
                             Also used via the 'CountFilenames' and
                             'ShowFilenames' buttons.

Like with the 'find-and-imageViewer' Tk GUI utility, I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.

   wm resizable . 1 0

It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch videos from cameras that Russians seem to commonly have mounted in their cars --- and which, thanks to that, provide us with many videos of irate Russian motorists pounding on other Russian motorists.


 Code for Tk script 'find_and_mediaPlayer_FrontEnd.tk' : (the 'front end')
#!/usr/bin/wish -f
##
## Tk SCRIPT NAME: find_and_mediaPlayer_FrontEnd.tk
##
##+#######################################################################
## PURPOSE:  This Tk script provides a GUI for starting up a movie/audio player
##           program --- such as  'mplayer'  or  'totem'  or  'VLC'  or
##           'gmplayer' or  'gnome-mplayer' or 'smplayer'  or  'ffplay' ---
##           according to user-specified parameters that are prompted for
##           via radiobutton widgets and entry widgets on the GUI.
##
##           The GUI is coded as a front-end for starting up a
##           user-selectable media-player command --- along with use of the
##           'find' command --- to provide names of files to be played.
##
##           The GUI is intended to make the user aware of the main
##           (most useful) options available without the user needing
##           to reference the 'man mplayer'/'man ffplay'/'man totem'
##           and 'man find' commands --- and other media-player and
##           'find' documentation, for example, via web searches.
##
##           The intent of this utility is to allow the user to easily
##           specify movie/audio files to be played --- via specifying:
##            1  - a directory-and-filename (the latter can be a mask)
##            2  - whether files in sub-directories should be mask-searched
##            3  - whether the mask-search should be case-INsensitive
##            4  - whether to use a file-size limitation
##            5  - whether to use a file-age limitation
##            6  - whether to search based on file-type, according to
##                 output from the 'file' command.
##
##           In addition, the GUI allows the user to specify:
##              - which of several media-player programs to use
##              - whether to run the media-player program at fullscreen-size
##
##           NOTE that most movie/audio-players, like 'mplayer' and more
##           complex 'media' players, are oriented toward playing a single
##           movie/audio file --- or playing files selected from
##           movie/audio names (and associated filenames) in a
##           'playlist'.  In contrast ...
##
##           This utility is oriented toward AUTO-SELECTING 'media' files
##           (based on criteria such as a file-mask, file-size, file-age,
##           and/or file-type) from an ENTIRE HIERARCHY OF SUB-DIRECTORIES ---
##           as well as allowing mask-search in a SINGLE directory.
##
##           This utility SORTS the selected files ACCORDING TO their 
##           filenames and then starts playing the files. 
##            
##+######################
## NOTES ON MOVIE PLAYERS:
##
##           Most movie players are 'media' players that play 
##                - audio-only files, and
##                - video-only files, and
##                - video+audio ('talkie' movie) files.
##           In other words, most movie players are also audio players.
##
##           One consequence of this is that this GUI front-end could be
##           used to select audio files for playing, instead of movie files.
##
##           Some movie players are GUI front-ends for a command-line
##           movie player program that does not provide a GUI. Example:
##           'gnome-mplayer' and 'smplayer' and 'gmplayer' are GUI
##           front-ends for the 'mplayer' program.
##
##           And some movie/media players are 'bare bones' players without
##           a lot of startup or play options --- such as 'ffplay'.
##
##           Almost any kind of movie player program, like the ones mentioned
##           above, could be used as the player program for this utility.
##
##           Note that this utility is designed so that the user is required
##           to close the media-player window when finished playing a movie
##           or audio file. When the player window closes, the media-player is
##           started up on the next media-file in the sequence. Any
##           media-player that is used in this utility would need to
##           support that type of operating mode.
##
##           At least 3 movie-and-audio-players are selectable via the GUI.
##           Other 'media' players could be switched for players currently
##           made selectable on the GUI. For example, 'smplayer' could
##           be used in place of 'gnome-mplayer'. To perform the switch ...
##
##           The 'core' media-player changes would be to the shell script ---
##           'getFiles_andCountListOrPlay.sh' ---
##           that this Tk script calls. That shell script currently offers
##           several media-players to use, along with the 'find' command
##           --- and along with parameters supplied from this GUI.
##
##           Only a 'superficial' change would be required to the Tk GUI
##           script --- changing the player-name on the GUI --- in a text
##           string for a 'radiobutton' widget.
##
##+################
## THE GUI WIDGETS:
##
##           The GUI offers a generous set of user specifications.
##           The options available to the user are compactly indicated
##           by the following 'text-sketch' of the GUI:
##
## ---------------------------------------------------------------------------
## 'find'-mediaplayer Front End -  a Tk Multi-Movie/Audio-File-Player Utility   [window title]
## ---------------------------------------------------------------------------
## 
## {Exit} {Help} {LaunchPlayerJob}            {CountFilenames} {ShowFilenames}
## 
## Full Filename Mask (for movie/audio): ________________________  {Browse...}
##  
## MediaPlayer : O 'mplayer'   O 'ffplay'  O 'gnome-mplayer'  O 'totem'  O 'VLC'
## 
## DisplaySize: O DEFAULT-size (up to fullscreen)  O FULLSCREEN (without toolbars)
## 
## Search Levels for Mask:  O ONE  O ALL subdirectories of selected directory
## 
## Case Sense for Mask Search:  O case-sensitive  O case-INsensitive
## 
## File Size (MegaBytes):  _________  O bigger-than  O smaller-than
## 
## File Age (Days) : ________________ O older-than  O younger-than
## 
## File Type: ___________   (Warning: SLOW) Examples: 'MPEG v4' or 'MPEG sequence'
## or  'Flash'  or  'Apple QuickTime'  or  'Microsoft ASF'  or  'layer III'  or 'PCM'
## ---------------------------------------------------------------------------------------------------------------
##
## Braces indicate a Tk 'button' widget.
## Underscores indicate a Tk 'entry' widget.
## A colon indicates that the text before the colon is on a 'label' widget.
## Capital-O indicates a Tk 'radiobutton' widget.
## Capital-X indicates a Tk 'checkbutton' widget.
## Square brackets indicate a comment (not to be placed on the GUI).
##
## NOTE that only at the 'MediaPlayer:' and 'DisplaySize:' prompts
## are there parameters involving the media-player.
##
## The other parameters (the majority of the parameters) are for
## the 'find' command.
##
##+##############
## GUI components:
##
## From the GUI 'sketch' above, it is seen that the GUI consists of
## about
##   
##   -  5 button widgets
##   -  9 label widgets
##   -  4 entry widgets
##   - 15 radiobutton widgets in 6 groups
##   -  0 checkbutton widgets
##   -  0 scale widgets
##   -  0 listbox widgets
##
##+#####################################################################
## CALLED BY:  This script could be put in a sub-directory of the
##             user's home directory, such as $HOME/apps/tkFind-MediaPlayer.
##
##             Then the user can use their desktop system (such as
##             Gnome or KDE) to set up the Tk script as an icon on the
##             desktop. Then the user can click on the icon to startup
##             the Tk script.
##+########################################################################
## STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, win-color-scheme,
##     fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc).
##
##  1a) Define ALL frames (and sub-frames, if any).
##  1b) Pack the frames.
##
##  2) Define & pack all widgets in the frames, frame by frame.
##     After all the widgets for a frame are defined, pack them in the frame.
##
##  3) Define keyboard and/or mouse/touchpad/touch-sensitive-screen 'event'
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or more of
##     the procs), if needed.
##
## In more detail:
##
##  1a) Define ALL frames -- and sub-frames:
## 
##   Top-level :
##       'fRbuttons'     for Exit, Help, Launch, ... buttons
##       'fRfileMask'    for a directory-and-filemask entry field
##       'fRdisplayPgm'  for several radiobuttons, with a label
##       'fRdisplaySize' for 2 radiobuttons, with a label
##       'fRlevels'      for 2 radiobuttons, with a label
##       'fRsense'       for 2 radiobuttons, with a label
##       'fRfileSize'    for 1 entry field and 2 radiobuttons, with a label
##       'fRfileAge'     for 1 entry field and 2 radiobuttons, with a label
##       'fRfiletype'    for 1 entry field, with a label before and after 
##       'fRfiletype2'   for a label (continuation)
##
##  1b) Pack ALL frames, including sub-frames (if any).
##
##  2) Define & pack all widgets in the frames -- basically going through
##     frames & their interiors in  left-to-right, top-to-bottom order:
##
##  3) Define bindings:  See BINDINGS section below.
##
##  4) Define procs:
##
##    'get_filemask'          - called by the 'Browse...' button
##
##    'getFiles_andCountListOrPlay'    - called by the 'LaunchPlayerJob' button,
##                                       and by the 'CountFilenames' and the
##                                       'ShowFilenames' buttons.                    
##
##   'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##                                         Also used via the 'CountFilenames'
##                                         and 'ShowFilenames' buttons.
##
##     For other procs, see the PROCS section below.
##
##  5) Additional GUI initialization:  See this section at the bottom
##                                     of this script.
##+#######################################################################
## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala')
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##
## showed
##     8.5 8.5
## but this script should work in most previous 8.x versions, and probably
## even in some 7.x versions (if font handling is made 'old-style').
##+########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2013dec15 Started development, on Ubuntu 9.10,
##                                        based on the code of a Tk script
##                                        of mine that contains most of the
##                                        widgets needed.
## Updated by: Blaise Montandon 2013
##+#######################################################################

##+######################################################
## Set WINDOW TITLE and POSITION.
##+######################################################

wm title    . \
   "'find'-mediaplayer FrontEnd - Select-and-Batch-Play Movie/Audio Files"
#  "'find'-mediaplayer Front End - a Tk Multi Movie/Audio FilePlayer Utility"


wm iconname . "tkMediaPlay"

# wm geometry . +15+30
# wm geometry . +250+285
wm geometry . -10-10


##+######################################################
## Set the COLOR SCHEME for the window and its widgets ---
## such as listbox and entry field background color.
##+######################################################

tk_setPalette "#e0e0e0"


  set entryBKGD "#ffffff"
  set textBKGD  "#f0f0f0"
  set radbuttBKGD  "#ffffff"
# set chkbuttBKGD  "#ffffff"
# set scaleBKGD   "#f0f0f0"
# set listboxBKGD "#f0f0f0"


##+########################################################
## DEFINE (temporary) FONT NAMES.
##
## We use a VARIABLE-WIDTH font for text on LABEL and
## BUTTON widgets.
##
## We use a FIXED-WIDTH font for LISTBOX lists,
## for text in ENTRY fields --- and often for text in
## TEXT widgets.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible (similar) variable width fonts:
##  Arial
##  Bitstream Vera Sans
##  DejaVu Sans
##  Droid Sans
##  FreeSans
##  Liberation Sans
##  Nimbus Sans L
##  Trebuchet MS
##  Verdana


font create fontTEMP_fixedwidth  \
   -family {liberation mono} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {liberation mono} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible fixed width fonts (esp. on Linux):
##  Andale Mono
##  Bitstream Vera Sans Mono
##  Courier 10 Pitch
##  DejaVu Sans Mono
##  Droid Sans Mono
##  FreeMono
##  Nimbus Mono L
##  TlwgMono


##+###########################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. width and height of canvas, and padding for Buttons)
##+###########################################################

## LABEL widget geom settings:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2


## BUTTON widget geom settings:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2


## ENTRY widget geom settings:

set BDwidthPx_entry 2


## RADIOBUTTON widget geom settings:

set PADXpx_radbutton 0
set PADYpx_radbutton 0
set BDwidthPx_radbutt 2


## CHECKBUTTON widget geom settings:

# set PADXpx_chkbutton 0
# set PADYpx_chkbutton 0
# set BDwidthPx_chkbutt 2

## TEXT widget geom settings:

set BDwidthPx_text 2


## SCALE widget geom parameters:

# set BDwidthPx_scale 2
# set scaleThicknessPx 10


##+######################################################################
## Set a MIN-SIZE of the window (roughly).
##
## For WIDTH, allow for the min-width of the '.fRbuttons' frame.
##
## For HEIGHT, allow for the stacked frames:
##      1 char   high for the '.fRbuttons'     frame
##      1 char   high for the '.fRfileMask'    frame
##      1 char   high for the '.fRdisplayPgm'  frame
##      1 char   high for the '.fRdisplaySize' frame
##      1 char   high for the '.fRlevels'      frame
##      1 char   high for the '.fRsense'       frame   
##      1 char   high for the '.fRfileSize'    frame
##      1 char   high for the '.fRfileAge'     frame
##      1 char   high for the '.fRfileType'    frame
##      1 char   high for the '.fRfileType2'   frame
##    --------
##     10 chars  high for the 10 frames
##+#####################################################################

## FOR WIDTH: (allow for widgets in the '.fRbuttons' or '.fRfileMask' frame)

set minWidthPx [font measure fontTEMP_varwidth \
   " Exit  Help  LaunchPlayerJob   CountFilenames ShowFilenames "]

## We add some pixels to account for right-left-size of
## window-manager decoration (~8 pixels) and some pixels for
## frame/widget borders (~5 widgets x 4 pixels/widget = 20 pixels).

set minWinWidthPx [expr {28 + $minWidthPx}]


## For HEIGHT --- 10 chars high for the 10 frames.

set charHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {10 * $charHeightPx}]


## Add about 20 pixels for top-and-bottom window decoration --
## and some pixels for top-and-bottom of frame/widget borders
## (~10 widgets x 4 pixels/widget = 32 pixels).

set minWinHeightPx [expr {60 + $minWinHeightPx}]


## FOR TESTING:
#   puts "minWinWidthPx = $minWinWidthPx"
#   puts "minWinHeightPx = $minWinHeightPx"

wm minsize . $minWinWidthPx $minWinHeightPx


## We may allow the window to be resizable.  We pack the canvases
## (and the frames that contain them) with '-fill both -expand 1'
## so that the canvases can be enlarged by enlarging the window.

## If you want to make the window un-resizable, 
## you can use the following statement.
#   wm resizable . 0 0

## We fix the y-size of the window, but allow the x-size to vary.
wm resizable . 1 0

##+##############################################################
## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI.
##     NOTE: This can aid INTERNATIONALIZATION. This array can
##           be set according to a nation/region parameter.
##+##############################################################

## if { "$VARlocale" == "en"}

## For '.fRbuttons' frame:

set aRtext(buttonEXIT)    "Exit"
set aRtext(buttonHELP)    "Help"
set aRtext(buttonLAUNCH)  "LaunchPlayerJob"
# set aRtext(buttonKILLJOB) "KillPlayerJob"

set aRtext(buttonCOUNT)  "CountFilenames"
set aRtext(buttonPRINT)  "ShowFilenames"

## For '.fRfileMask' frame:

set aRtext(labelFILEMASK) "Full Filename Mask (for movie/audio):"
set aRtext(buttonBROWSE)  "Browse..."


## For '.fRdisplayPgm' frame:

set aRtext(labelDISPLAYPGM)   "MediaPlayer:"
set aRtext(radbuttDPGM1) "1 mplayer"
set aRtext(radbuttDPGM2) "2 ffplay"
set aRtext(radbuttDPGM3) "3 totem"
set aRtext(radbuttDPGM4) "4 gnome-mplayer"
set aRtext(radbuttDPGM5) "5 VLC"

## For '.fRdisplaySize' frame:

set aRtext(labelDISPLAYSIZE)   "DisplaySize:"
set aRtext(radbuttDSIZEFULL)   "FULLSCREEN (no toolbars)"
set aRtext(radbuttDSIZEDEFAULT) "DEFAULT-size, up to fullscreen"

## For '.fRlevels' frame:

set aRtext(labelLEVELS)       "Search LEVELS for mask:"
set aRtext(radbuttLEVELSone)  "ONE"
set aRtext(radbuttLEVELSall)  "ALL subdirectories of selected directory"

## For '.fRsense' frame:

set aRtext(labelCASESENSE) "Case Sense for Mask Search:"
set aRtext(radbuttSENSE)     "case-sensitive"
set aRtext(radbuttNOSENSE)   "case-INsensitive"


## For '.fRfileSize' frame:

set aRtext(labelFILESIZE)   "Files Size (MegaBytes):"
set aRtext(radbuttBIGGER)   "bigger-than"
set aRtext(radbuttSMALLER)  "smaller-than"

## For '.fRfileAge' frame:

set aRtext(labelFILEAGE)  "Files Age (Days):"
set aRtext(radbuttOLDER)  "older-than"
set aRtext(radbuttYOUNGER)  "younger-than"

## For '.fRfileType' frame:

set aRtext(labelFILETYPE)  "Files Type:"
set aRtext(labelFILETYPE2) "(Warning: SLOW) Examples: 'MPEG v4' or 'MPEG sequence'"


## For '.fRfileType2' frame:

set aRtext(labelFILETYPE3) \
"or 'MPEG'  or  'Flash'  or  'Apple QuickTime'  or  'Microsoft ASF'  or  'layer III'  or 'PCM'"

## END OF  if { "$VARlocale" == "en"}



##+####################################################################
##+####################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :
##       'fRbuttons'     for Exit, Help, and Launch buttons
##       'fRfileMask'    for a filename/mask entry field
##       'fRdisplayPgm'  for several radiobuttons, with a label
##       'fRdisplaySize' for 2 radiobuttons, with a label
##       'fRlevels'      for 2 radiobuttons, with a label
##       'fRsense'       for 2 radiobuttons, with a label
##       'fRfileSize'    for 1 entry field and 2 radiobuttons, with a label
##       'fRfileAge'     for 1 entry field and 2 radiobuttons, with a label
##       'fRfileType'    for 1 entry field, with a label before and after
##       'fRfileType2'   for a label widget (continuation)
##+####################################################################
##+####################################################################

## FOR TESTING of expansion of frames (esp. during window expansion):

# set feRELIEF_frame raised
# set feBDwidth_frame 2

 set feRELIEF_frame flat
 set feBDwidth_frame 0

frame .fRbuttons     -relief $feRELIEF_frame  -bd $feBDwidth_frame

frame .fRfileMask    -relief raised           -bd 2

frame .fRdisplayPgm  -relief raised           -bd 2

frame .fRdisplaySize -relief raised           -bd 2

frame .fRlevels      -relief $feRELIEF_frame  -bd $feBDwidth_frame
# frame .fRlevels      -relief raised           -bd 2

frame .fRsense       -relief $feRELIEF_frame  -bd $feBDwidth_frame
# frame .fRsense       -relief raised           -bd 2

frame .fRfileSize    -relief raised           -bd 2

frame .fRfileAge     -relief raised           -bd 2

frame .fRfileType    -relief raised           -bd 2

frame .fRfileType2   -relief raised           -bd 2


##+########################################################
## PACK *ALL* the FRAMES.
##+########################################################

pack .fRbuttons \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileMask \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRdisplayPgm \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRdisplaySize \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRlevels \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRsense \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileSize \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileAge \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileType \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileType2 \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0


##+################################################################
##+################################################################
## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. 
##+################################################################
##+################################################################

##+########################################################
## IN THE '.fRbuttons' frame -- DEFINE several buttons
## --- Exit, Help, Launch.
##+########################################################

button .fRbuttons.buttEXIT \
   -text "$aRtext(buttonEXIT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exit}

button .fRbuttons.buttHELP \
   -text "$aRtext(buttonHELP)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {popup_msgVarWithScroll .topHelp "$HELPtext"}

## Set a variable to hold the process-ID of the player process.
## NOT NEEDED. See 'Kill' button attempt below.
# set PlayerPID ""

button .fRbuttons.buttLAUNCH \
   -text "$aRtext(buttonLAUNCH)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {getFiles_andCountListOrPlay play}


##+########################################################
## THE FOLLOWING ATTEMPT DID NOT WORK OUT.
## The intent was to use a 'Kill' button on the GUI
## to allow for killing the 'getFiles_andCountListOrPlay.sh' script
## --- if it finds lots of files to play and the user wants out.
##
## It seems the process-ID of the script soon disappeared,
## leaving the 'find' process, which had a different 
## process-ID. 
##
## It turned out to be easier to add an 'xterm' window in
## the 'getFiles_andCountListOrPlay.sh' script, to run the
## command that starts the media playing sequence.
## Closing the 'xterm' window 'kills' the playing sequence.
##+##########################################################


if {0} {

##+############################################################
## We could try using various kill signals:
##          -HUP/-SIGHUP/-1 (to kill all child processes too)
## AND/OR   -KILL/-SIGKILL/-9
## AND/OR   -TERM/-SIGTERM/-15
##+###########################################################
## References: 'man signal' and 'man kill' and 'kill -l'
##             http://wiki.tcl.tk/735 - 'getPid'
##+###########################################################

button .fRbuttons.buttKILLJOB \
   -text "$aRtext(buttonKILLJOB)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {
      global PlayerPID
         puts "Trying to kill PlayerPID: $PlayerPID"
      if {"$PlayerPID" != ""} {
         # exec kill -TERM $PlayerPID
         exec kill -15 $PlayerPID
         # exec kill -KILL $PlayerPID
         exec kill -9 $PlayerPID
         # set PlayerPID ""
      }
      # exit
    }

}
## END OF 'if {0}'


button .fRbuttons.buttCOUNT \
   -text "$aRtext(buttonCOUNT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {getFiles_andCountListOrPlay count}

button .fRbuttons.buttPRINT \
   -text "$aRtext(buttonPRINT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {getFiles_andCountListOrPlay print}

##+########################################
## Pack the widgets in the 'fRbuttons' frame
##+########################################

pack .fRbuttons.buttEXIT \
     .fRbuttons.buttHELP \
     .fRbuttons.buttLAUNCH \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

#     .fRbuttons.buttKILLJOB \

pack .fRbuttons.buttPRINT \
     .fRbuttons.buttCOUNT \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRfileMask' frame -- DEFINE 1 LABEL widget,
## 1 ENTRY widget, and 1 BUTTON.
##+########################################################

label .fRfileMask.labelFILEMASK \
   -text "$aRtext(labelFILEMASK)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileMask.entryFILEMASK \
   -textvariable ENTRYfileMask \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## Set an initial value for the entry var.

set curDIR "$env(HOME)"

## FOR TESTING:
#   set curDIR [pwd]

set ENTRYfileMask "$curDIR/*.mp4"
# set ENTRYfileMask "$curDIR/*.mpg"
# set ENTRYfileMask "$curDIR/*.mp3"

## Put the end of the filename in view.

.fRfileMask.entryFILEMASK xview end


button .fRfileMask.buttBROWSE \
   -text "$aRtext(buttonBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_filemask}

## PACK the widgets in the 'fRfileMask' frame.

pack  .fRfileMask.labelFILEMASK \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 

pack .fRfileMask.entryFILEMASK \
   -side left \
   -anchor w \
   -fill x \
   -expand 1 

pack .fRfileMask.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE '.fRdisplayPgm' frame -- DEFINE
## several RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRdisplayPgm.labelDISPLAYPGM \
   -text "$aRtext(labelDISPLAYPGM)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for display program :

radiobutton  .fRdisplayPgm.radbuttDPGM1 \
   -text "$aRtext(radbuttDPGM1)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "1" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM2 \
   -text "$aRtext(radbuttDPGM2)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "2" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM3 \
   -text "$aRtext(radbuttDPGM3)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "3" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM4 \
   -text "$aRtext(radbuttDPGM4)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "4" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM5 \
   -text "$aRtext(radbuttDPGM5)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "5" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARdisplaypgm is the var for these 2 or 3 radiobuttons.
## Set an initial value.
  set RADVARdisplaypgm "1"
# set RADVARdisplaypgm "2"

## PACK the widgets in the 'fRdisplayPgm' frame.

pack  .fRdisplayPgm.labelDISPLAYPGM \
      .fRdisplayPgm.radbuttDPGM1 \
      .fRdisplayPgm.radbuttDPGM2 \
      .fRdisplayPgm.radbuttDPGM3 \
      .fRdisplayPgm.radbuttDPGM4 \
      .fRdisplayPgm.radbuttDPGM5 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE '.fRdisplaySize' frame -- DEFINE
##  2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRdisplaySize.labelDISPLAYSIZE \
   -text "$aRtext(labelDISPLAYSIZE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for display sizes :

radiobutton  .fRdisplaySize.radbuttDSIZEDEFAULT \
   -text "$aRtext(radbuttDSIZEDEFAULT)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaysize \
   -value "default" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplaySize.radbuttDSIZEFULL \
   -text "$aRtext(radbuttDSIZEFULL)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaysize \
   -value "fullscreen" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARdisplaysize is the var for these 2 radiobuttons.
## Set an initial value.
   set RADVARdisplaysize "default"
#  set RADVARdisplaysize "fullscreen"

## PACK the widgets in the 'fRdisplaySize' frame.

pack  .fRdisplaySize.labelDISPLAYSIZE \
      .fRdisplaySize.radbuttDSIZEDEFAULT \
      .fRdisplaySize.radbuttDSIZEFULL \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE '.fRlevels' frame -- DEFINE
## 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRlevels.labelLEVELS \
   -text "$aRtext(labelLEVELS)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for Levels :

radiobutton  .fRlevels.radbuttLEVELSone \
   -text "$aRtext(radbuttLEVELSone)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARlevels \
   -value "one" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRlevels.radbuttLEVELSall \
   -text "$aRtext(radbuttLEVELSall)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARlevels \
   -value "all" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

## RADVARlevels is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARlevels "one"
# set RADVARlevels "all"

## PACK the widgets in the 'fRlevels' frame.

pack  .fRlevels.labelLEVELS \
      .fRlevels.radbuttLEVELSone \
      .fRlevels.radbuttLEVELSall \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE 'fRsense' frame -- DEFINE
## 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRsense.labelCASESENSE \
   -text "$aRtext(labelCASESENSE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for CaseSensitivity :

radiobutton  .fRsense.radbuttSENSE \
   -text "$aRtext(radbuttSENSE)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARcasesense \
   -value "case-sensitive" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRsense.radbuttNOSENSE \
   -text "$aRtext(radbuttNOSENSE)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARcasesense \
   -value "case-INsensitive" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARcasesense is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARcasesense "case-sensitive"
# set RADVARcasesense "case-INsensitive"


## PACK the widgets in the 'fRsense' frame:

pack  .fRsense.labelCASESENSE \
      .fRsense.radbuttSENSE \
      .fRsense.radbuttNOSENSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+############################################################
## IN THE 'fRfileSize' frame -- DEFINE
## 1 ENTRY field and 2 RADIOBUTTONS, preceded by a LABEL widget.
##+############################################################

label .fRfileSize.labelFILESIZE \
   -text "$aRtext(labelFILESIZE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileSize.entryFILESIZE \
   -textvariable ENTRYfileSize \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## DEFINE Radiobuttons for File Size :

radiobutton  .fRfileSize.radbuttBIGGER \
   -text "$aRtext(radbuttBIGGER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfilesize \
   -value "bigger" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRfileSize.radbuttSMALLER \
   -text "$aRtext(radbuttSMALLER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfilesize \
   -value "smaller" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARfilesize is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARfilesize "bigger"
# set RADVARfilesize "smaller"


## PACK the widgets in the 'fRfileSize' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileSize.labelFILESIZE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileSize.entryFILESIZE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileSize.radbuttBIGGER \
     .fRfileSize.radbuttSMALLER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0



##+########################################################
## IN THE 'fRfileAge' frame -- DEFINE 
## 1 ENTRY field and 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRfileAge.labelFILEAGE \
   -text "$aRtext(labelFILEAGE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileAge.entryFILEAGE \
   -textvariable ENTRYfileAge \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry


## DEFINE Radiobuttons for File Age :

radiobutton  .fRfileAge.radbuttOLDER \
   -text "$aRtext(radbuttOLDER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfileage \
   -value "older" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRfileAge.radbuttYOUNGER \
   -text "$aRtext(radbuttYOUNGER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfileage \
   -value "younger" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARfileage is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARfileage "older"
# set RADVARfileage "younger"


## PACK the widgets in the 'fRfileAge' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileAge.labelFILEAGE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileAge.entryFILEAGE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileAge.radbuttOLDER \
     .fRfileAge.radbuttYOUNGER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRfileType' frame -- DEFINE 
## 1 ENTRY field, with 2 LABEL widgets, before and after.
## PACK them.
##+########################################################

label .fRfileType.labelFILETYPE \
   -text "$aRtext(labelFILETYPE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileType.entryFILETYPE \
   -textvariable ENTRYfileType \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRfileType.labelFILETYPE2 \
   -text "$aRtext(labelFILETYPE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label


## PACK the widgets in the 'fRfileType' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileType.labelFILETYPE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileType.entryFILETYPE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileType.labelFILETYPE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

##+########################################################
## IN THE 'fRfileType2' frame -- DEFINE 
## one LABEL widget. PACK it.
##+########################################################

label .fRfileType2.labelFILETYPE3 \
   -text "$aRtext(labelFILETYPE3)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRfileType2' frame:

pack .fRfileType2.labelFILETYPE3 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+#####################################################################
## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS.
##+#####################################################################

##+#####################################################################
##+#####################################################################
## DEFINE BINDINGS:  button1-release bindings on some widgets ???
##                   Return-key bindings on some entry widgets ???
##+#####################################################################

# bind .fR?????.???widget???  <ButtonRelease-1>  {??proc??}
# bind .fR?????.???widget???  <Return>  {??proc??}

## As the user types in the entry field, make sure the area
## near the insertion cursor or the character entry is showing.

# bind .fRfileMask.entryFILEMASK <KeyPress> \
#    {.fRfileMask.entryFILEMASK xview insert}

bind .fRfileMask.entryFILEMASK <KeyPress> \
   {.fRfileMask.entryFILEMASK xview [expr {%x - 3}]}

##+#####################################################################
##+#####################################################################
## DEFINE PROCEDURES:
##
##  'get_filemask'         - called by the 'Browse...' button
##                           next to the filemask entry field
##
##  'getFiles_andCountListOrPlay'   - called by the 'LaunchPlayerJob' button
##                                    --- and the 'CountFilenames' and
##                                    'ShowFilenames' buttons
##
##  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##                             Also called via the  'CountFilenames' and
##                             'ShowFilenames' buttons
##+#####################################################################
##+#####################################################################

##+#####################################################################
## Proc 'get_filemask'
##
## PURPOSE: To get the fully-qualified name of a file and put the
##          name into global var 'ENTRYfileMask'.
##
##          The user may change the filename (after the end of the
##          directory name) to change it into a file-mask. 
##
## CALLED BY: the '-command' option of the 'Browse ...' button.
##+#####################################################################


proc get_filemask {} {

   global ENTRYfileMask env curDIR

   ## Get a file name (possibly to make a mask).

   set fName [tk_getOpenFile -parent .  \
      -title "Select Directory-and-Filename - the latter as basis for a mask" \
      -initialdir "$curDIR" ]

   ## FOR TESTING:
   #   puts "fName : $fName"

   ## Check if fName var is empty.

   if {"$fName" == ""} {return}

   ## Put $fName in ENTRYfileMask. Reset the curDIR var.

   if {[file exists "$fName"]} {
      set ENTRYfileMask "$fName"

      ## Put the end of the filename in view.
      .fRfileMask.entryFILEMASK xview end

      set curDIR [ get_chars_before_last / in "$ENTRYfileMask" ]
   }
   ## END OF if directory-exists

}
## END OF proc 'get_filemask'


##+###################################################################
## Proc 'get_chars_before_last' -
##+###################################################################
## INPUT:  A character and a string.
##         Note: The "in" parameter is there only for clarity.
##
## OUTPUT: Returns all of the characters in the string "strng" that
##         are BEFORE the last occurence of the characater "char".
##
## CALLED BY: proc 'get_img_filename'
##
##+##################################################################

proc get_chars_before_last { char in strng } {

   set endIDX [ expr [string last $char $strng ] - 1 ]
   set output [ string range $strng 0 $endIDX ]

   ## FOR TESTING:
   # puts "From 'get_chars_before_last' proc:"
   # puts "STRING: $strng"
   # puts "CHAR: $char"
   # puts "RANGE up to LAST CHAR - start: 0   endIDX: $endIDX"

   return $output

}
## END OF 'get_chars_before_last' PROCEDURE


##+#############################################################
## proc getFiles_andCountListOrPlay
##
## PURPOSE: The function of this proc depends on the value of
##          the 'option' parm passed to this proc. Its values
##          can be 'play' or 'count' or 'print'.
##
##          For all 3 options,
##          this proc does some checking of the GUI interface
##          parameters, especially from the 'entry' widgets.
##
##          For option='play', this proc runs the
##          'getFiles_andCountListOrPlay.sh' shell script
##          with parm 'play'.
##
##          In that case, the shell script builds a 'find' command
##          that calls on the user-specified media-player program ---
##          to start off the playing of the found files.
##          The shell script uses an 'xterm' technique to provide
##          the user an easy way to kill the 'find' process if
##          the user wants to interrupt a (long) sequence of displays.
##
##          For option='count', this proc runs the
##          'getFiles_andCountListOrPlay.sh' shell script
##          with parm 'count'.
##
##          The shell script returns a count of the to-be-selected
##          files, so that this proc can display the count
##          in a small popup Tk window.
##
##          For option='print', this proc runs the
##          'getFiles_andCountListOrPlay.sh' shell script
##          with parm 'print'.
##
##          The shell script returns the names of the to-be-selected
##          files, so that this proc can display the list
##          in a popupTk window.
##
## CALLED BY: - 'Launch' button with option='play'
##            - 'Count'  button with option='count'
##            - 'List'   button with option='print'
##+#############################################################

proc getFiles_andCountListOrPlay {option} {

   global PlayerPID DIRscripts ENTRYfileMask \
      RADVARdisplaypgm RADVARdisplaysize \
      RADVARlevels RADVARcasesense \
      RADVARfilesize ENTRYfileSize \
      RADVARfileage  ENTRYfileAge \
      ENTRYfileType

   #######################################################
   ## Remove trailing and leading blanks (if any) from the
   ## user entries in the 'entry' widgets.
   #######################################################

   set ENTRYfileMask [string trim $ENTRYfileMask]
   set ENTRYfileSize [string trim $ENTRYfileSize]
   set ENTRYfileAge  [string trim $ENTRYfileAge]
   set ENTRYfileType [string trim $ENTRYfileType]

   #################################################################
   ## The variables RADVARdisplaypgm, RADVARdisplaysize,
   ## RADVARlevels, RADVARcasesense,
   ## RADVARfilesize, and RADVARfileage are set as single
   ## words in this script and should not need any editing
   ## or checking (if bug-free).
   #################################################################

   ##########################################################
   ## Check that ENTRYfileSize and ENTRYfileAge are integers,
   ## if they are not blank (null).
   ##########################################################

   if {"$ENTRYfileSize" != ""} {
      if {![string is integer -strict "$ENTRYfileSize"]} {
         popup_msgVarWithScroll .topErr \
            "File Size: $ENTRYfileSize  is NOT NUMERIC."
         return
      }
   }
   

   if {"$ENTRYfileAge" != ""} {
      if {![string is integer -strict "$ENTRYfileAge"]} {
         popup_msgVarWithScroll .topErr \
            "File Age: $ENTRYfileAge  is NOT NUMERIC."
         return
      }
   }


   ## FOR TESTING:  (to dummy out the rest of this proc)

   # return

   ###############################################################
   ## If option = 'count',
   ## run the 'getFiles_andCountListOrPlay.sh' shell script with
   ## the 'count' option. The shell script returns a count of the
   ## 'to-be-selected' filenames, which this proc displays
   ## in a small popup Tk window.
   ###############################################################

   if {"$option" == "count"} {
      set FILEScount [exec $DIRscripts/getFiles_andCountListOrPlay.sh \
         "$RADVARdisplaypgm" "$RADVARdisplaysize" \
         "$RADVARlevels" "$RADVARcasesense" \
         "$RADVARfilesize" "$ENTRYfileSize" \
         "$RADVARfileage"  "$ENTRYfileAge" \
         "$ENTRYfileType" \
         count "$ENTRYfileMask"]

      popup_msgVarWithScroll .topCount \
        "$FILEScount files 'would-be-selected' with the
current file mask and other GUI settings."

      return
   }
   ## END OF  if {"$option" == "count"}


   ###############################################################
   ## If option = 'print',
   ## run the 'getFiles_andCountListOrPlay.sh' shell script with
   ## the 'print' option.   The shell script returns a list of
   ## the 'to-be-selected' filenames, which this proc displays
   ## in a popup Tk window.
   ###############################################################
   ## NOTE: We could change this function slightly to
   ##       let the user put the filenames in a text file,
   ##       say in a '/tmp' directory. This would be better
   ##       in cases when the list is huge.
   ############################################################

   if {"$option" == "print"} {
      set FILESlist [exec $DIRscripts/getFiles_andCountListOrPlay.sh \
         "$RADVARdisplaypgm" "$RADVARdisplaysize" \
         "$RADVARlevels" "$RADVARcasesense" \
         "$RADVARfilesize" "$ENTRYfileSize" \
         "$RADVARfileage"  "$ENTRYfileAge" \
         "$ENTRYfileType" \
         print "$ENTRYfileMask"]

      popup_msgVarWithScroll .topList \
         "Filenames that 'would-be-selected' with the
current file mask and other GUI settings:

$FILESlist"

      return
   }
   ## END OF  if {"$option" == "print"}


   ###############################################################
   ## If option = 'play',
   ## run the 'getFiles_andCountListOrPlay.sh' shell script with
   ## the 'play' option, to select the media files and to run the
   ## specified media player program on the selected files.
   ###############################################################
   ## Attempts were made to use the 'PlayerPID' process ID
   ## which is set below, to allow the user to cancel the
   ## playing sequence by means of a 'Kill' button on this GUI.
   ## THOSE ATTEMPTS DID NOT WORK.
   ####################################################################
   ## SOME SYNTAX NOTES on storing the process-ID from a Tcl 'exec':
   ##
   ## A couple of examples of using a PID (process ID) with Tcl:
   ##
   ## catch {eval exec $feREADER_text \"$FULFILname\"  &} PlayerPID
   ##
   ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \
   ##    "$FULFILname" &} PlayerPID ]
   ##
   ## An alternative from of trying 'exec':
   ##    exec  /bin/sh -c "$...."
   #######################################################################
   ## From page 107 of 4th edition of 'Practical Programming in Tcl & Tk',
   ## on the Tcl 'exec' command:
   ## "A trailing & causes the program to run in the background.
   ##  In this case, the process identifier is returned by the 'exec'
   ##  command. Otherwise, the 'exec' command blocks during execution
   ##  of the program, and the standard output of the program is the
   ##  return code of 'exec'."
   ## Page 83 of the same book says:
   ## "'catch' returns zero if there was no error caught,
   ##   or a nonzero error code if it did catch an error."
   ###############################################################

   if {"$option" == "play"} {

      set RETcode [catch {exec $DIRscripts/getFiles_andCountListOrPlay.sh \
         "$RADVARdisplaypgm" "$RADVARdisplaysize" \
         "$RADVARlevels" "$RADVARcasesense" \
         "$RADVARfilesize" "$ENTRYfileSize" \
         "$RADVARfileage"  "$ENTRYfileAge" \
         "$ENTRYfileType" \
         play "$ENTRYfileMask" &}  PlayerPID]

      ## FOR TESTING:
      #   puts "PlayerPID: $PlayerPID"

      if { $RETcode != 0 } then {
         popup_msgVarWithScroll .topErr \
            "ERROR from attempt to run the 'getFiles_andCountListOrPlay.sh' script.

RETcode: $RETcode"
         return
      }
      ## END OF   if { $RETcode != 0 }
   }
   ## END OF  if {"$option" == "play"}

}
## END OF proc 'getFiles_andCountListOrPlay'


##+########################################################################
## PROC 'popup_msgVarWithScroll'
##+########################################################################
## PURPOSE: Report help or error conditions to the user.
##
##       We do not use focus,grab,tkwait in this proc,
##       because we use it to show help when the GUI is idle,
##       and we may want the user to be able to keep the Help
##       window open while doing some other things with the GUI
##       such as putting a filename in the filename entry field
##       or clicking on a radiobutton.
##
##       For a similar proc with focus-grab-tkwait added,
##       see the proc 'popup_msgVarWithScroll_wait' in a
##       3DterrainGeneratorExaminer Tk script.
##
## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk',
##            4th edition, by Welch, Jones, Hobbs.
##
## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg)
##            and a variable holding text (many lines, if needed).
##
## CALLED BY: 'help' button
##+########################################################################
## To have more control over the formatting of the message (esp.
## words per line), we use this 'toplevel-text' method, 
## rather than the 'tk_dialog' method -- like on page 574 of the book 
## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications
## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor".
##+########################################################################

proc popup_msgVarWithScroll { toplevName VARtext } {

   ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global.
   ## global env

   # bell
   # bell
  
   #################################################
   ## Set VARwidth & VARheight from $VARtext.
   #################################################
   ## To get VARheight,
   ##    split at '\n' (newlines) and count 'lines'.
   #################################################
 
   set VARlist [ split $VARtext "\n" ]

   ## For testing:
   #  puts "VARlist: $VARlist"

   set VARheight [ llength $VARlist ]

   ## For testing:
   #  puts "VARheight: $VARheight"


   #################################################
   ## To get VARwidth,
   ##    loop through the 'lines' getting length
   ##     of each; save max.
   #################################################

   set VARwidth 0

   #############################################
   ## LOOK AT EACH LINE IN THE LIST.
   #############################################
   foreach line $VARlist {

      #############################################
      ## Get the length of the line.
      #############################################
      set LINEwidth [ string length $line ]

      if { $LINEwidth > $VARwidth } {
         set VARwidth $LINEwidth 
      }

   }
   ## END OF foreach line $VARlist

   ## For testing:
   #    puts "VARwidth: $VARwidth"


   ###############################################################
   ## NOTE: VARwidth works for a fixed-width font used for the
   ##       text widget ... BUT the programmer may need to be
   ##       careful that the contents of VARtext are all
   ##       countable characters by the 'string length' command.
   ###############################################################


   #####################################
   ## SETUP 'TOP LEVEL' HELP WINDOW.
   #####################################

   catch {destroy $toplevName}
   toplevel  $toplevName

   # wm geometry $toplevName 600x400+100+50

   wm geometry $toplevName +100+50

   wm title     $toplevName "Note"
   # wm title   $toplevName "Note to $env(USER)"

   wm iconname  $toplevName "Note"


   #####################################
   ## In the frame '$toplevName' -
   ## DEFINE THE TEXT WIDGET and
   ## its two scrollbars --- and
   ## DEFINE an OK BUTTON widget.
   #####################################

   if {$VARheight > 10 || $VARwidth > 100} {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 \
         -yscrollcommand "$toplevName.scrolly set" \
         -xscrollcommand "$toplevName.scrollx set"

      scrollbar $toplevName.scrolly \
         -orient vertical \
         -command "$toplevName.text yview"

      scrollbar $toplevName.scrollx \
         -orient horizontal \
         -command "$toplevName.text xview"
   } else {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 
   }

   button $toplevName.butt \
      -text "OK" \
      -font fontTEMP_varwidth \
      -command  "destroy $toplevName"

   ###############################################
   ## PACK *ALL* the widgets in frame '$toplevName'.
   ###############################################

   ## Pack the bottom button BEFORE the
   ## bottom x-scrollbar widget,

   pack  $toplevName.butt \
      -side bottom \
      -anchor center \
      -fill none \
      -expand 0


   if {$VARheight > 10 || $VARwidth > 100} {
      ## Pack the scrollbars BEFORE the text widget,
      ## so that the text does not monopolize the space.

      pack $toplevName.scrolly \
         -side right \
         -anchor center \
         -fill y \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the Y-scrollbar.
      ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS
      ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA.
                
      pack $toplevName.scrollx \
         -side bottom \
         -anchor center \
         -fill x  \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the X-scrollbar.
      ## THAT KEEPS THE TEXT AREA FROM EXPANDING.

      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   } else {
      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   }


   #####################################
   ## LOAD MSG INTO TEXT WIDGET.
   #####################################

   ##  $toplevName.text delete 1.0 end
 
   $toplevName.text insert end $VARtext
   
   $toplevName.text configure -state disabled
  
}
## END OF PROC 'popup_msgVarWithScroll'


##+########################
## END of PROC definitions.
##+########################
## Set HELPtext var.
##+########################


set HELPtext "\
\ \ ** HELP for this 'Tk Movie/Audio Player' Utility **

** essentially a 'wrapper' for the 'find' command and a 'media' player **

This utility provides a GUI for starting up a movie/audio player
--- such as 'mplayer' or 'ffplay' or 'gnome-mplayer' or 'totem'
--- according to user-specified parameters that are prompted for
via radiobutton widgets and entry widgets on the GUI.

The GUI is currently coded as a front-end for starting up a
user-selectable media-player program (along with use of the
'find' command). The Tk GUI script runs a shell script to handle
formulating the 'find' command and running it.

A different media-player program could be added by some simple
label-text changes in the Tk script --- 'find_and_mediaPlayer_FrontEnd.tk'
--- and, additionally, a few coding changes in the shell script
--- 'getFiles_andCountListOrPlay.sh'.

The Tk GUI is intended to make the user aware of the main
(most useful) options available --- without the user needing
to reference 'man mplayer'/'man ffplay'/'man totem' and 'man find'
commands and other media-player and 'find' documentation,
for example, via web searches.

The intent of this utility is to allow the user to easily
specify movie or audio files to be played --- via specifying:
 1  - a directory-and-filename (the latter can be a mask)
 2  - whether files in sub-directories should be mask-searched
 3  - whether the mask-search should be case-INsensitive
 4  - an optional file-size limitation
 5  - an optional file-age limitation
 6  - an optional file-type string (such as 'MPEG v4' or 'QuickTime').
These are parameters for the 'find' operation.

In addition, the GUI prompts for
   - which media-player program to use
and
   - whether to play the movie (or audio 'fireworks' display) at
     fullscreen-size

NOTE that most movie/audio-players, like 'mplayer' and more
complex 'media' players, are oriented toward playing a single
movie/audio file --- or playing files selected from
movie/audio names (and associated filenames) in a
'playlist'.  In contrast ...

This utility is oriented toward AUTO-SELECTING 'media' files
(based on criteria such as a file-mask, file-size, file-age,
and/or file-type) from an ENTIRE HIERARCHY OF SUB-DIRECTORIES ---
as well as allowing mask-search in a SINGLE directory.

This utility SORTS the selected files ACCORDING TO their 
filenames and then starts playing the files. 

NOTE that a single movie/audio file can be played by selecting
a single filename and NOT changing the name to a mask --- like
*.mp4  OR A*.WMV  OR  *beatles*.mp3. 
           
******************
NOTES ON 'PLAYERS':
******************

Most movie players are 'media' players that play 
     - audio-only files, and
     - video-only files, and
     - video+audio ('talkie' movie) files.
In other words, most movie players are also audio players.

One consequence of this is that this GUI front-end could be
used to select audio files for playing, instead of movie files.

Some movie players are GUI front-ends for a command-line
movie player program that does not provide a GUI. Example:
'gnome-mplayer' and 'smplayer' and 'gmplayer' are GUI
front-ends for the 'mplayer' program (or the utility routines
used by the 'mplayer' program).

And some movie/media players are 'bare bones' players without
a lot of startup or play options --- such as 'ffplay'.

Almost any kind of movie player program, like the ones mentioned
above, could be used as the player program for this utility.

Note that this utility is designed so that the user is required
to close the media-player window when finished playing a movie
or audio file. When the player window closes, the media-player is
started up on the next media-file in the sequence. Any
media-player that is used in this utility would need to
support that type of operating mode.


***************
THE GUI WIDGETS:
***************

The GUI offers a generous set of hints, help, and options
for the user.  In fact, the GUI consists of about

   -  5 button widgets
   -  9 label widgets
   -  4 entry widgets
   - 15 radiobutton widgets in 6 groups
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets


**************
TYPICAL USAGE:
*************

You can use the 'Browse...' button to retrieve a full filename
to the file/mask name entry field. This allows one to establish
a 'base' directory for the 'find' command. And the user can change
the filename after the directory name, to a mask. Examples:
*.mpg   OR   Reunion*.mp4  OR   *school*.mov   OR   *aerosmith*.mp3

Before clicking on the 'LaunchPlayerJob' button,
you can also change radiobutton settings as needed --- and
enter an integer in the FileSize and/or FileAge entry fields,
if you want to use size or age to reduce the filenames found
via the specified mask.

The FileType field is useful if you are dealing with movie
files that may have been named with the wrong suffix ---
or movie files that have no suffix at all. However, be
aware that using this option will generally be much slower
that using a file-mask, because the 'file' command is run
for each file in the chosen directory structure, in order
to determine its file type.

File-Type-Field Considerations:

If you want to select files via the FileType entry field
(rather than a file-mask involving a file-suffix), you can
make the file mask something like '*' or '*OLD*' (no file
suffix) and put a string in the file-type field ---
typically 'MPEG v4' or 'QuickTime' or 'layer III'.

When you put an entry in the 'FileType' field, the 'file' command
is executed on every file scanned, throughout the directory structure.
The 'file' command returns text strings like the following on MOVIE files:

Typical file suffix   'find' output
-------------------   -----------------------------------------

mp4                   ISO Media, MPEG v4 system, version 1
mpg or mpeg           MPEG sequence, v1, system multiplex
flv                   Macromedia Flash Video
mov                   ISO Media, Apple QuickTime movie
wmv                   Microsoft ASF


and 'file' returns text strings like the following on AUDIO files:

Typical
suffix  'find' output
------- -----------------------------------------

mp3     MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo
wav     RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 22050 Hz

A movie file actually consists of 3 formats:
  - the video stream format
  - the audio stream format
  - the 'container' format.

The 'file' command is typically reporting on the 'container' format
of movie files.

The string that you entered for file-type is compared against the
'file' command output for each file, to see if 'your string' is in
that output string.

So you may enter 'MPEG v4' to retrieve movie files that are
packaged in that container format.

Or enter 'MPEG' to retrieve movie files of 'MPEG v4' and 
'MPEG sequence' format.

And you may enter 'layer III' in order to retrieve audio files
that are typically called 'mp3' files.

NOTE: The first time a query is done on a directory containing
many-many files, a count/print/play operation may respond very
SLOWLY --- when there is an entry in the FileType field.

**********
CALLED BY:

The set of scripts for this utility (a Tk script and 2 shell scripts)
could be put in a sub-directory of the user's home directory,
such as \$HOME/apps/tkFind-MediaPlayer.

Then the user can use their desktop system (such as Gnome or KDE)
to set up the Tk script as an icon on the desktop. Then the user
can click on the icon to startup the Tk script.
"


##+######################################################
## ADDITIONAL GUI INITIALIZATION section.
##+######################################################

##+########################################################################
## Get the directory that this Tk script is in. That will be the
## directory that the 2 'external' utility shell scripts should be
## in. This directory is used to call one of the shell scripts ---
## the one that is used to perform the 'play', 'count', and 'print' options.
##+########################################################################

## FOR TESTING:
#  puts "argv0: $argv0"

# set DIRscripts "."
# set DIRscripts "[pwd]"
# set DIRscripts "$env(HOME)/apps/tkUtils"
  set DIRscripts "[file dirname $argv0]"


##+###########################################
## Disable/enable widgets according to initial
## GUI settings. (NOT IMPLMENTED, yet)
##+##########################################

# disable_enable_widgets


Shell script #1 (called by the Tk script) :

And here is the code for the shell script called by this Tk script. This is a wrapper script for the 'find' command, along with a choice of the 'player' program.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell script by extracting the name of the directory in which the Tk script lies.

 Code for shell-script-1 'getFiles_andCountPrintOrPlay.sh' :
#!/bin/sh
##
## SCRIPT NAME: getFiles_andCountListOrPlay.sh
##
##+#######
## PURPOSE:
##  This script
##  1) finds a set of user-specified 'media' files --- according to
##     a fully-qualified file mask (directory and mask) and other
##     'find' parameters passed to this script
##  AND
##  2) runs a user-selected media-player program
##     (with user-selected parameters) to show each media file.
##
##     Alternatively, a count of the 'find'-selected files is returned ---
##     or the names of the 'find'-selected files are returned from this
##     script --- according to whether 'play' or 'count' or 'print' is
##     passed to this script. See INPUTS below.
##
##  When the user closes the player window, the next media-file is played.
##
##  This shell script is meant to be issued from the Tk GUI 'wrapper' script
##  'find_and_mediaPlayer_FrontEnd.tk'. The purpose of that Tk script is to
##    - get parameters for the 'find' command
##  and
##    - to determine which media-player program to use and parameters
##      to supply to the player (such as whether to run fullscreen-size).
##
##+######
## INPUTS:
##
##  The parameters passed to this script, from the
##  'find_and_mediaPlayer_FrontEnd.tk' Tk GUI script, are:
##
##   Var1: A 'media-player program' indicator - from a Tk radiobuttons var.
##         (possible values: '1' or '2' or '3' or '4' or '5')  
##
##          The player programs corresponding to these integers are
##          set in the code below.
##
##          Some comments on the pros and cons of these programs
##          (as used in this utility) may be placed here in the future.
##
##   Var2: A display-size indicator - from a Tk radiobuttons var.
##         (possible values: 'fullscreen' or 'default')
##
##         To be used to set a parameter for the 'media-player program'.
##
##  The following are used to set parameters of the 'find' command:
##
##   Var3: A 'levels' indicator - from a Tk radiobuttons var.
##         (possible values: 'one' or 'all').
##
##   Var4: A 'case-sensitivity' indicator - from a Tk radiobuttons var.
##         (possible values: 'case-sensitive' or 'case-INsensitive')
##
##   Var5: A 'bigger/smaller' indicator from a Tk radiobuttons var
##.        (possible values: 'bigger' or 'smaller')
##
##   Var6: An integer file-size-cutoff value (in MegaBytes)
##         (could be null, indicating no size limitation)
##
##   Var7: An 'older/younger' indicator - from a Tk radiobuttons var.
##.        (possible values: 'older' or 'younger')
##
##   Var8: An integer file-age-cutoff value (in days)
##         (could be null, indicating no age limitation)
##
##   Var9: A file-type string --- such as 'MPEG v4' or 'Flash' or 'ASF'
##                                or 'QuickTime' or 'layer III' or 'PCM'
##
##  Var10: A string with value 'print' or 'count' or 'play',
##         to indicate the type of 'find' command to run:
##            - to return a selected-files list to stdout
##                 OR
##            - to return a count of the selected files to stdout
##                 OR
##            - to start running the media-player program against
##              each of the selected files.
## 
##  Var11: 'Base'-directory name and file mask. Examples:
##          /home/fred/MOVIES/*vacation*.mp4
##                    or
##          /home/fred/MUSIC/*Lennon*.mp3
##
## In this script, we will put those parameters in shell script variables
## VARdisplaypgm, VARdisplaysize,
## VARlevels, VARsense,
## VARbigsmall,  VARfilesize,
## VARoldyoung,  VARfileage,
## VARfiletype,  VARperform and  VARfilemask --- respectively.
##
##+#########################################################################
## MAINTENANCE HISTORY:
## Updated by: Blaise Montandon 2013dec15 Started this script on Linux,
##                                        using Ubuntu 9.10 (2009 October,
##                                        'Karmic Koala').
## Updated by: Blaise Montandon 2013 
##+#########################################################################

## FOR TESTING: (to show statements as they execute)
#  set -x

VARdisplaypgm="$1"
VARdisplaysize="$2"
VARlevels="$3" 
VARsense="$4"
VARbigsmall="$5"
VARfilesize="$6"
VARoldyoung="$7"
VARfileage="$8"
VARfiletype="$9"
VARperform="$10"
VARfilemask="$11"

## FOR TESTING of this script without the Tk wrapper:
## (For stand-alone testing, change 'if test 1 = 0' to 'if test 1 = 1'.)

if test 1 = 0
then
   VARdisplaypgm="1"
   # VARdisplaypgm="2"
   # VARdisplaypgm="3"

   VARdisplaysize="fullscreen"
   # VARdisplaysize="default"

   VARlevels="one"
   # VARlevels="all"

   VARsense="case-sensitive"
   # VARsense="case-INsensitive"

   VARbigsmall="bigger"
   VARfilesize=""

   VARoldyoung="older"
   VARfileage=""

     VARfiletype="MPEG v4"
   # VARfiletype="MPEG"
   # VARfiletype="layer III"

   # VARperform="count"
   # VARperform="print"
     VARperform="play"

   # VARfilemask="$HOME/apps/tkGooies_linux_PREP/tkGUIs/.PREP_tkGooies/00_CFE_find_and_mediaplayer_FrontEnd_2013dec_PREP/*"
   VARfilemask="$HOME/TESTfilesMOVIES/*.flv"
   # VARfilemask="$HOME/TESTfilesAUDIO/*.mp3"
fi

## FOR TESTING:
#   echo "VARfilemask: $VARfilemask"


## Simply exit if there is no filemask passed to this script.

if test "$VARfilemask" = ""
then
   exit
fi

DIRNAME=`dirname "$VARfilemask"`
FILEMASK=`basename "$VARfilemask"`

## Set the PLAYER program to use, along with some parameters
## such as whether to run at fullscreen-size.

if test "$VARdisplaypgm" = "1"
then
   if test "$VARdisplaysize" = "fullscreen"
   then
      PLAYER="/usr/bin/mplayer -fs"
   else
      PLAYER="/usr/bin/mplayer -geometry +15+30"
   fi
elif test "$VARdisplaypgm" = "2"
then
   ## With 'ffplay', user can interactively toggle fullscreen
   ## with the 'f' key.
   PLAYER="/usr/bin/ffplay"
elif test "$VARdisplaypgm" = "3"
then
   if test "$VARdisplaysize" = "fullscreen"
   then
      PLAYER="/usr/bin/totem --fullscreen"
   else
      PLAYER="/usr/bin/totem"
   fi
elif test "$VARdisplaypgm" = "4"
then
   if test "$VARdisplaysize" = "fullscreen"
   then
      PLAYER="/usr/bin/gnome-mplayer --fullscreen"
   else
      PLAYER="/usr/bin/gnome-mplayer"
   fi
elif test "$VARdisplaypgm" = "5"
then
   if test "$VARdisplaysize" = "fullscreen"
   then
      PLAYER="/usr/bin/vlc --fullscreen"
   else
      PLAYER="/usr/bin/vlc"
   fi
fi


if test "$VARlevels" = "one"
then 
   DEPTHPARM="-maxdepth 1"
else
   DEPTHPARM=""
fi


if test "$VARsense" = "case-sensitive"
then 
   NAMEPARM="-name"
else
   NAMEPARM="-iname"
fi


## The FILESIZE_PARM can be a parameter like
##      -size +${SIZE_MINinBYTES}c
## for the 'find' command.

if test "$VARfilesize" = ""
then
   FILESIZE_PARM=""
else
   if test "$VARbigsmall" = "bigger"
   then
      FILESIZE_PARM="-size +${VARfilesize}M"
   else
      FILESIZE_PARM="-size -${VARfilesize}M"
   fi
fi


## The FILEAGE_PARM can be a parameter like
##     -mtime +$NDAYS
## for the 'find' command.

if test "$VARfileage" = ""
then
   FILEAGE_PARM=""
else
   if test "$VARoldyoung" = "older"
   then
      FILEAGE_PARM="-mtime +$VARfileage"
   else
      FILEAGE_PARM="-mtime -$VARfileage"
   fi
fi



##+##################################################
## Call on the 'find' command, which 
##  1) 'prints' the selected filenames
## or
##  2) shows a count of the selected filenames
## or
##  3) executes the user-specified media-player program
##     on each selected filename,
##
## depending on whether $VARperform is
##  1) 'print'
## or
##  2) 'count'
## or
##  3) some other string, such as 'play'.
##
##+#################################################

## FOR TESTING: (to show the 'find' commands as they execute)
## (When called from within the Tk wrapper script,
##  this output may interfere with proper processing.)
#  set -x

if test "$VARperform" = "print"
then
   ## FOR TESTING: (to show the 'find' command)
   #   set -x

   ## NOTE: Do not escape the quotes around $FILEMASK.
   ##       If you do, no filenames are returned.


   if test "$VARfiletype" = ""
   then
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -print | sort
   else
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -exec file {} \; | \
         grep ":.*$VARfiletype" | sort
      ## Could add pipe to 'cut -d: -f1' to show filenames
      ## without the filetype info.
   fi

elif test  "$VARperform" = "count"
then
   ## FOR TESTING: (to show the 'find' command)
   #   set -x

   ## NOTE: Do not escape the quotes around $FILEMASK.
   ##       If you do, no filenames are returned.

   if test "$VARfiletype" = ""
   then
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -print | wc -l
   else
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -exec file {} \; | \
         grep ":.*$VARfiletype" | wc -l
   fi


elif test  "$VARperform" = "play"
then

   ## FOR TESTING: (to show the 'find' command)
   #  set -x

   #########################################################
   ## Prepare to use a temp file to hold the filenames.
   ## This file is processed with a 'for' loop below.
   ## Using 'for' avoids problems in trying to use 'xargs'.
   ##
   ## Additionally, use of a temp-file and 'for' can avoid
   ## buffer-size-limit problems in trying to pass too many
   ## arguments on a shell command line.
   ########################################################
 
   TEMPFILE="/tmp/${USER}_tkMediaPlayer_filenames.lis"
   rm -f "$TEMPFILE"

   ########################################################
   ## Get the media filenames for a given set of criteria
   ## and put the filenames in $TEMPFILE --- SORTED.
   ##
   ## NOTE: Do not escape the quotes around $FILEMASK.
   ##       If you do, no filenames are returned.
   ########################################################

   if test "$VARfiletype" = ""
   then
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -print | sort > "$TEMPFILE"
   else
      find "$DIRNAME"  $DEPTHPARM  -type f \
         $NAMEPARM "$FILEMASK" \
         $FILESIZE_PARM $FILEAGE_PARM -exec file {} \; | \
         grep ":.*$VARfiletype" | cut -d: -f1 | sort > "$TEMPFILE"
   fi

   #########################################################
   ## Provide an 'xterm' window in which to run the media-playing
   ## loop --- so that the user can easily cancel out of the
   ## loop by simply closing the 'xterm' window.
   ##
   ## Attempts to use a pipe of the 'sort' output to 'xargs'
   ## were not successful. So this technique of putting
   ## the sorted filenames in a temporary file and then using
   ## a 'for' loop (in a separate script) was implemented.
   #########################################################

   DIR_SCRIPTS=`dirname $0`

   xterm -fg white -bg black -hold \
      -title "To 'kill' the display of media files, close this window." \
      -geometry 90x5-30-30 -e \
      $DIR_SCRIPTS/forLoop_playListOfFiles.sh "$PLAYER" "$TEMPFILE"


   ## Without 'sort' (and without '-exec file' --- i.e. without the
   ## FileType selection feature), the following should work:
   # xterm -fg white -bg black -hold \
   #   -title "To 'kill' the display of media files, close this window." \
   #   -geometry 90x5-30-30 -e \
   #   find "$DIRNAME"  $DEPTHPARM  -type f \
   #   $NAMEPARM "$FILEMASK" \
   #   $FILESIZE_PARM $FILEAGE_PARM \
   #   -exec $PLAYER {} 2> /dev/null \;
   ## But without 'sort', this utility is not very satisfying.
   ## The files seem to be playing in a 'random' order.

fi


Shell script #2 (called by shell script #1) :

And here is the code for the shell script that provides the 'for' loop that feeds each media filename to the chosen player program.

You can put this script in the same directory with the Tk script. Shell script #1 includes some code (involving the '$0' variable) to determine the location of the directory containing this shell script (and all 3 scripts) by extracting the name of the directory in which shell-script-1 lies.

 Code for shell-script-2 'forLoop_playListOfFiles.sh' :
#!/bin/sh
##
## SCRIPT: forLoop_playListOfFiles.sh
##
## PURPOSE: For a given
##          1) media-player command string (program and some arguments)
##          and
##          2) a text-file name (in which the file contains the
##             fully-qualified names of media files),
##          this script uses a 'for' loop to play each of the
##          media files via the media-player command string.
##
##          It is assumed that the media-player works such that
##          when the user closes the media-player window, the
##          next media-file can be played by a call to the media-player.
##
## CALLED BY: A script that uses the 'find' command to build the list
##            of media filenames.
##
##+#######################################################################
## Created: 2013dec15 For use in a calling shell script:
##                       getFiles_andCountListOrPlay.sh
##                    which in turn, is called by a 'wrapper' Tk script:
##                       find_and_mediaPlayer_FrontEnd.tk.
## Changed: 2013
##+#######################################################################

## FOR TESTING: (show statements as they execute)
#  set -x

##+##########################################################
## Put the 2 arguments into variables with descriptive names.
##+##########################################################

PLAYER="$1"
TEMPFILE="$2"

##+######################################################
## Use the media-player program (and any parms that are to
## be used with it) to play each of the media files whose
## names are in $TEMPFILE.
##+######################################################

for FILENAME in `cat  "$TEMPFILE"`
do
   $PLAYER "$FILENAME" 2> /dev/null
done


INSTALLING THESE SCRIPTS:

This set of 3 scripts could be put in a sub-directory of the user's home directory, such as $HOME/apps/tkBatchMediaPlayer.

Then the user can use their desktop system (such as Gnome or KDE) to set up the Tk script as an icon on the desktop. Then the user can click on the icon to startup the 'front end'.


SOME ENHANCEMENTS :

This set of 3 scripts adds another 'Front End' utility at the bottom of my 'bio' page at uniquename --- in the 'CFE' (Code for Front Ends) group.

I plan to work on front ends for 'mplayer', 'ffmpeg', and 'find'. But I may return to this set of 3 scripts to provide some enhancements.

maxdepth N

I indicated near the top of this page that I may change the 'ONE' radiobutton to an 'N-levels' radiobutton. If that radiobutton is selected, an entry field will be activated where the user can enter a choice of N (with the entry field being initialized with '1'). This capability would be implemented via the '-maxdepth' parameter of the 'find' command.

There is also a '-mindepth' parameter of the 'find' command. But I have never encountered a situation where I felt I needed to use that parameter.

prune

Probably even more useful than the 'maxdepth' capability would be allowing on the GUI for use of the '-prune' parameter of the 'find' command.

To implement the '-prune' feature would require adding yet another entry widget to the GUI --- to allow for entering one or more sub-directory names (or masks).

---

I leave the 'N-levels' and '-prune' enhancement possiblities to a future date. These two features are similar in that they allow the user avoid 'dropping into' a (large) sub-directory of image files which the user does not wish to process.

I will install these 3 scripts in a $HOME/apps/tkBatchMediaPlayer directory, as suggested above in an 'install' section. I will define an icon on my desktop by which I can start up this GUI and keep testing it in coming months.

Then, if I encounter a need for either of those features, I may implement them and update the code on this page.

---

There are a lot of parameters available with the 'find' command, but I think I have probably implemented the ones that are most useful to use for this 'multiple-subdirectory media-file-select-and-display' utility.

That said, I will probably find a '-prune' capability to be quite desirable.


IN CONCLUSION

As I have said on several other code-donation pages on this wiki ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.