RYGCBM Color Animation ; Color Array Generator ; 'miniscaleH' widget

uniquename - 2012nov17

I indicated in April 2012, on my 'biography page' at uniquename, that I was inspired by Mark Stucky and Gerhard Sookahet to create some 3D model viewing utilities --- complete with fairly robust 3D model data importers (for a variety of 3D data formats --- such as CAD-like data files, Wavefront OBJ files, Cyberware PLY files, STL stereolithography files, etc.).

Well, I am getting started on some 3D viewing projects, and I am starting to put together some test 3D models. I would like to have some nice colors for the facets (polygons) and/or vertices of these models so I have been giving some thought to the nice colors that can be made from the RGB ('primary', 'additive') colors and the CMY ('complementary', 'subtractive') colors.

If you have seen an image of the 'HSV hexcone', like the following, you probably know what I am talking about.

hsv_hexcone_358x300.jpg

In fact, I am talking about 'going through' the colors on the perimeter of the circle at the top of that cone --- as seen in this image.

RYGCBM_colorDisk_225x225.jpg

I decided to put together a GUI utility that shows me those colors --- AND gradations between them --- along with the capability to generate a set of Tcl 'set' statements that can be used to set up a 'color array' variable that can be used as a 'look up table' to assign colors to facets and vertices.

Note that in 'going through' the RYGCBM colors, I mean going through the colors on the outer periphery of the top of the HSV cone. The diagram below (a side view of the HSV cone) shows that colors toward the center of the top of the cone are 'tints' (whitened) and the colors below the top of the cone are 'shades' (blackened).

HSVcone_tints-tones-shades_390x212.gif

Here is an animated GIF image of the GUI that gives an idea of what I am talking about.

RYGCBM_colorDisk_494x96_ani.gif

The actual GUI goes through the colors more smoothly. (In fact, I may replace this animated GIF by a movie file someday. With the good compression ratios of movies nowadays, using H.264 format, for example, it is possible to get movie files that are actually more compact than their corresponding, but not so smooth, GIF animations --- in cases where the successive images are not changing in very many pixel locations. Unfortunately, that may not be the case with this animation.)


HELP Text

Here is the text from the 'Help' button in the GUI --- to give you more clarity on what this Tk script does:

** HELP for this RYGCMB Color Circle Animation and Tcl-Color-Array-Setting-Statements Generator Utility **

This Tk GUI script 'travels around' the 'color circle' --- through the 6 primary and complementary colors --- Red-Yellow-Green-Cyan-Blue-Magenta --- and back to Red, then repeating.

The phrase 'travel around', in this particular GUI, means that a sequence of colors, gradiating between pairs of the 6 RYGCBM colors, is displayed in a 'color swatch' on the GUI.

The animation continues until the user clicks the Stop button --- or the user can click the Exit button --- or close the window.

Thus this script provides a repeating color-sequence animation.

The color sequence is somewhat similar to the color spectrum of a prism or rainbow.

This animation gives the user a quick, dynamic overview of the color combinations of the primary and complementary colors as one blends the colors in the rather natural sequence RYGCBMR.

---

A SECOND (probably more useful) PURPOSE of this GUI is to generate a file containing 'set' statements for an ARRAY OF 1530 COLORS.

In addition to the animation, this GUI provides an array of the the 6 x 255 = 1530 hexcolors traversed. The 'set' statements for the array are put in a text file.

The 'set' statements can be used in other Tk scripts to set up a 'look-up table' of colors. For example, in a 3D modeling application, one may wish to apply colors to the facets (polygons) or vertices of a 3D model --- either randomly or via some pattern.

Integers in the range 1 to 1530 (or some subset thereof) can be generated --- randomly or in some algorithmic pattern --- to apply look-up colors to facets of the model.

(Note that since 1530 has many factors --- 1530 = 5 x 2 x 3 x 3 x 17 --- there are quite a few subsets of 'equally-spaced' colors that you can use to cycle 'nicely' through those 1530 colors. Every 2 colors, every 3, every 5, every 6, every 9, every 10, every 15, every 17, every 18, ...)

---

A THIRD PURPOSE of this GUI - demo of a NEW WIDGET:

This script also introduces a new scale-like widget, dubbed 'miniscaleH' (for miniscale-horizontal) --- to control the speed of the color transition (color steps per second --- from about 50 to 1000 per second).

(At 1 per second, it would take 25 minutes to traverse the 1530 steps and start over. A setting in the range of 50 to 400 is probably more suited to those with other things to do.)

The 'miniscaleH' widget is made up of 4 'button' widgets and one 'label' widget --- arrayed from left to right --- the label in the middle, with 2 buttons on either side.

The '+' and '++' buttons on the right increment the scale numbers; the '-' and '--' buttons on the left decrement. The '++' and '--' buttons are for high-speed incrementing/decrementing.

The 'miniscaleH' widget is more compact than the 'scale' widget --- and its labels and buttons can be decorated with background images, via the '-image' and '-compound center' options. So the 'miniscaleH' widget may have some use in 'embellished' Tk GUI's. In contrast, the 'scale' widget does not have a '-image' option.

* END OF THE HELP text


miniscaleH widget

On the subject of the 'miniscaleH' widget, I would just like to point out that it is a 'horizontal' variation on the 'miniscale' widget that I devised for the GUI that I presented at A color-gradient-button-maker GUI with 6 'miniscale' widgets.

AND ... because I can decorate the 'miniscaleH' widget with background images on the 4 buttons and the label from which the 'miniscaleH' widget is made, I may return to the Tk-GUI-embellishment project that I published at Version 2 of a demo of THEMES for Tk GUI's, using images and colors and replace the 'scale' widget in that demo GUI with the 'miniscaleH' widget --- but enhanced with background images.


The code

I provide the code for this 1530-color RYGCBMR animation (and color-array 'set'-statements generator) GUI below.

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.

  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 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 Tk scripts (code re-use).

Since this script also includes a proc to generate the 'miniscaleH' widget, I have added the following step to the typical code structure outline above:

  1c) Provide proc(s) to be used to define widget(s) made from other Tk widgets.

In addition, I call your attention to step-zero. One new thing that I have started doing recently 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.

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.

___

In addition, 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.


Some features of the code

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

The code that generates the 1530 colors for the animation and the code that does the animation and the code for writing the color-arrays file is in three procs:

  • load_colorArray1530
  • animate_RYGCBM
  • writeColorTables_groupsOfSetStatements

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 --- and perhaps learn to make new widgets (such as even more variations on the 'miniscale' widget). Without the comments, it might not be clear how the 'stopani0or1' flag, for example, is being used to stop the animation as needed.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch LFHV (Luxembourg's Funniest Home Videos).


 Code for the Tk script 'aniColorCircle_RYGCBM_in1530steps_miniscaleH.tk' :
#!/usr/bin/wish -f
##
## SCRIPT: aniColorCircle_RYGCBM_in1530steps_miniscaleH.tk
##
## PURPOSE:  This TkGUI script creates a color animation by
##           'traveling around' a 'color circle' ---
##           through the 6 'interspersed' primary and complementary colors
##           --- Red-Yellow-Green-Cyan-Blue-Magenta --- and back to Red.
##
##           The phrase 'travel around' means to convey that a
##           sequence of colors, gradiating between pairs of the
##           6 RYGCBM colors, is displayed in a 'color swatch' on the GUI.
##
##           By default, the color display will keep cycling --- 
##           at a rate that is changeable by the user.
##
##           I.e. this is a color animation that keeps cycling through
##           a sequence of colors (blended from the primary and complementary
##           colors), and the user can control the number of color changes
##           per second.
##
##           The 'swatch' is simply a Tk 'frame' widget for which the
##           background color is being reset as this Tk script 'marches'
##           through the sequence of colors.
##
##           This GUI provides an animation that 'cycles' through a series
##           of pretty nice looking colors --- somewhat similar to the color
##           spectrum of a prism or rainbow.
##
##           This gives the user a quick, dynamic overview of the color
##           combinations of the primary and complementary colors as one
##           blends the colors in the rather natural sequence RYGCBMR.
##
##     A second purpose of this GUI is to WRITE A TEXT FILE of COLOR-TABLE
##     MAKING Tcl 'set' STATEMENTS from a COLOR-ARRAY of 1,530 colors
##     interpolated from the RYGCBMR sequence:
##
##           In addition to the animation, this GUI can provide Color Tables
##           made from the 6 x 255 = 1,530 colors traversed in the animation.
##           The Tcl 'set' statements for loading the array are put in a
##           text file.
##
##           The 'set' statements can be used in other Tk scripts to
##           set up a 'look-up table' of colors. For example, in a 3D
##           modeling application, one may wish to apply colors to the
##           facets (polygons) of a 3D model --- either randomly or
##           via some pattern.
##
##           Integers in the range 1 to 1530 (or some subset thereof)
##           can be generated --- randomly or in some algorithmic
##           pattern --- to apply 'look-up colors' to facets of the model.
##
##     A third purpose of this GUI - demo of a NEW 'scale'-type WIDGET:
##
##           This script introduces a new scale-like widget,
##           dubbed 'miniscaleH' (for miniscale-horizontal) ---
##           to control the speed of the color transition (color
##           steps per second --- from about 10 to 1000 per second).
##
##           (At 1 per second, it would take 25 minutes to traverse
##            the 1530 steps and start over. A setting in the range
##            of 100 to 400 per sec is probably more suited to those with
##            other things to do. At 1,000 colors-per-second, the animation
##            would go through a complete cycle in less than 2 seconds.)
##
##           The 'miniscaleH' widget is made up of 4 'button' widgets
##           and one 'label' widget --- arrayed from left to right ---
##           the label in the middle, with 2 buttons on either side.
##
##           The '+' and '++' buttons on the right increment the scale
##           numbers; the '-' and '--' buttons on the left decrement.
##           The '++' and '--' buttons are for high-speed
##           incrementing/decrementing.
##
##           The 'miniscaleH' widget is more compact than the 'scale'
##           widget --- and its labels and buttons can be decorated
##           with background images, via the '-image' and
##           '-compound center' options. So the 'miniscaleH' widget
##           may have some use in 'embellished' Tk GUI's. In contrast,
##           the 'scale' widget does not have a '-image' option.
##
#########
## METHOD:   The script builds a color array by 'marching' through the
##           6 basic colors --- RYGCBM --- taking 255 steps between
##           the successive pairs of colors in the sequence RYGCBMR
##           for a total of 6 x 255 = 1,530 steps.
##
##           The color array is used to change the color of the 'color
##           swatch', going through each successive color in the array.
##
##           The display of the colors in the 'color swatch' is repeated
##           (i.e. keeps cycling) until the user stops the cycle.
##
##           The user can use 'Stop' or 'Exit' buttons on the GUI to 
##           stop the color-cycle animation.
##
##           A 'WriteTables' button on the GUI will write a file of Tcl
##           'set' statements. The 'set' statements can be used to load
##           a Tcl array with subsets of the 1,530 distinct colors.
##
##           The file is written in a fraction of a second and the file
##           is shown to the user in a GUI text-editor. (The user can
##           edit this script to change an 'EDITOR_text' variable
##           to set the GUI text-editor to use.)
##
##           The following diagram indicates how the 'load' proc builds
##           the 1,530-color array via passage through the 6 RYGCBM
##           colors, transitioning from color to color in 255 steps
##           for each pair. Note that we alternately increment an RGB
##           color component from 0-to-254, then decrement from 255-to-1.
##
##                              R   G   B
##                             --- --- ---
##                       R =   255   0   0
##                             255   1   0
##                             255   .   0
##                             255   .   0   R=255 , G = 0 to 254 , B=0
##                             255   .   0
##                             255 254   0
##                       Y =   255 255   0
##                             254 255   0
##                               . 255   0
##                               . 255   0   R = 255 to 1 , G=255 , B=0 
##                               . 255   0
##                               1 255   0
##                       G =     0 255   0
##                               0 255   1
##                               0 255   .
##                               0 255   .   R=0 , G = 255 , B = 0 to 254
##                               0 255   .
##                               0 255 254
##                       C =     0 255 255
##                               0 254 255
##                               0   . 255
##                               0   . 255   R=0 , G = 255 to 1 , B=255
##                               0   . 255
##                               0   1 255
##                       B =     0   0 255
##                               1   0 255
##                               .   0 255
##                               .   0 255   R = 0 to 254, G=0 , B=255
##                               .   0 255
##                             254   0 255
##                       M =   255   0 255
##                             255   0 254
##                             255   0   .
##                             255   0   .  R=255 , G=0 , B = 255 to 1
##                             255   0   .
##                             255   0   1
##        and we are ready to start again at:
##                       R =   255   0   0
##
##        When the user uses the 'WriteTables' button, subsets of these
##        1,530 colors are used to make Tcl 'set' statements.
##        The 'set' statements can be used in Tcl-Tk scripts to make
##        color-tables whose sizes are factors of 1,530 ---
##        whose prime factorization is 2 x 3 x 3 x 5 x 17.
##
##        (Of course, the user can change the name used for the color-table
##         arrays with a change-all in a text editor.)
##
#############
## GUI LAYOUT:
##       There are 2 frames in the GUI --- TOP and BOTTOM.
##
##       The TOP frame contains some buttons, such as 'Exit', 'Help',
##       'Stop', 'Start', and 'WriteTables' --- as well as the 'miniscaleH'
##        widget for controlling the speed of the color animation.
##
##       The BOTTOM frame contains nothing. It is the 'color-swatch'
##       and is used simply by changing its background color.
##
##+######################################################################
## 'CANONICAL' STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, color-scheme,
##     fonts, widget-geometry-parms, win-size-control, text-for-labels-etc).
##  1a) Define ALL frames (and sub-frames, if any).
##  1b) Pack the frames and sub-frames.
##
##  1c) Procs to define new widgets go here, if any.
##
##  2) Define all widgets in the frames, frame by frame.
##     After defining ALL the widgets for a frame, pack the widgets
##     in the frame.
##
##  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.
##
############################
## The code-structure detail for this particular script:
##
##  1a) Define ALL frames:
## 
##      Top-level : '.fRbuttons' , '.fRswatch'
##
##      Sub-frames: none
##
##  1b) Pack ALL frames.
##
##  1c) Provide the 'miniscaleH' proc to be used to define a 'miniscaleH'
##      widget in the '.fRbuttons' frame.
##
##  2) Define all widgets in the frames (and pack them):
##
##       - In '.fRbuttons': 5 button widgets ('Exit','Stop','Start','Help',''WriteTables')
##                          and a 'miniscaleH' widget (consisting of
##                          2buttons-1label-2buttons),
##
##       - In '.fRswatch' frame:  no widgets
##
##  3) Define BINDINGS:  none in this section, but there are bindings
##                            built-into the miniscaleH widget
##
##  4) Define PROCS:
##
##     - 'load_colorArray1530'  Loads an array with 1530 hex-colors.
##                              Invoked in the added-GUI-initialization section
##                              at the bottom of the script
##
##     - 'animate_RYGCBM'       Animates a 'swatch' (frame) on the GUI by
##                              changing its color every few milliseconds,
##                              cycling through the 1530 colors.
##
##                              Invoked in the added-GUI-initialization section
##                              at the bottom of the script and by a 
##                              'Start' button on the GUI (after a stop).
##
##     - 'writeColorTables_groupsOfSetStatements'
##                              Writes groups of Tcl 'set' statements to a
##                              text file and brings the text file up in a
##                              GUI text editor.
##                              Invoked by a 'WriteTables' button on the GUI.
##
##     - 'popup_msg_var_scroll'   invoked by the 'Help' button
##
##  5) Additional GUI initialization:  Execute 'load_colorArray1530' and
##                                     'animate_RYGCBM' to start off
##                                     the animation.
##+########################################################################
## 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   on Ubuntu 9.10.
##+#######################################################################
## MAINTENANCE HISTORY:
## Created by: Blaise Montandon 2012nov16
## Changed by: Blaise Montandon 2013jan26 1) Chgd the 'milsecs' var of the
##                                          'miniscaleH' proc to 'delay_milsecs'
##                                           and fixed some increment/decrement
##                                           settings in the proc.
##                                        2) Broke the proc 'DrawRYGCBM' into
##                                           three procs:
##                                           - load_colorArray1530
##                                           - animate_RYGCBM
##                                           - writeColorTables_groupsOfSetStatements
##                                         3) Added many sub-groups of the
##                                            original 1,530 colors to the
##                                            'set' statements in the output
##                                            'ColorTables' text file.
##                                         4) Added an entry widget by which
##                                            to request animating every Nth
##                                            color of the 1530 colors, rather
##                                            than just every color (N=1).
##+#######################################################################


##+#######################################################################
## Set WINDOW TITLES and POSITION.
##+#######################################################################

# wm title    . "Animate color circle: Red-Yellow-Green-Cyan-Blue-Magenta-Red"
wm title    . "Animate color circle: R-Y-G-C-B-M-R"
wm iconname . "RYGCBMcircle"

wm geometry . +15+30

##+#############################################################
## Set the COLOR SCHEME (palette) for the window and its widgets.
##
## Also set BACKGROUND OF WIDGETS like entry, listbox,
## radiobutton, checkbutton, ...
##+#############################################################

set R255pal 210
set G255pal 210
set B255pal 210

## chartreuse2
# set R255pal 118
# set G255pal 238
# set B255pal 0

set hexCOLORpal [format "#%02X%02X%02X" $R255pal $G255pal $B255pal]
tk_setPalette "$hexCOLORpal"


set BKGD_entry "#f0f0f0"


##+###########################################################
## Set FONT-NAMES.
## We use a VARIABLE-WIDTH font for text on labels and buttons.
##
## We use a FIXED-WIDTH font for listbox and text widgets,
## so that the line-up of columns is preserved.
##+###########################################################

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

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -10 \
   -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 -10 \
   -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. padding and borderwidth for buttons, labels)
##+###########################################################

## For LABEL widgets:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2


## For BUTTON widgets:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2


## For ENTRY widgets:

set BDwidthPx_entry 2


##+#######################################################
## Set a MINSIZE of the WINDOW (roughly), according to the
## approx max WIDTH of the chars in the 'fRbuttons' frame
## --- about 4 buttons and a 'miniscaleH' widget.
##
## --- and according to the approx HEIGHT of the 2 frames
## --- 'fRbuttons' and 'fRswatch'.
##+#######################################################

set minWinWidthPx [font measure fontTEMP_varwidth \
   "Exit  Stop  Start  WriteTables  Help  ++ + 100 + ++"]

## Add some to account for right-left window border (about
## 6 pixels) and for widget border-widths and padding ---
## about 8 widgets x 2 pixels/widget.

set minWinWidthPx [expr {22 + $minWinWidthPx}]


## Allow 1 char   high for 'fRbuttons',
##     100 pixels high for 'fRswatch'.

set minCharHeightPx [font metrics fontTEMP_SMALL_fixedwidth -linespace]

set minWinHeightPx [expr { 100 + $minCharHeightPx}]

## Add some to account for top-bottom window decoration (about 23 pixels)
## and frame/widget padding (about 3 pixels/frame x 2 frames).

set minWinHeightPx [expr 29 + $minWinHeightPx]

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

wm minsize . $minWinWidthPx $minWinHeightPx


## We may allow the window to be resizable and we pack the swatch frame with
## '-fill both' so that the swatch-frame 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


#######################################################################
## 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"}

set aRtext(buttonEXIT)   "Exit"
set aRtext(buttonHELP)   "Help"
set aRtext(buttonSTOP)   "Stop"
set aRtext(buttonSTART)  "Start"
set aRtext(buttonWRITE)  "WriteTables"
set aRtext(labelSPEED)   "   ColorsPerSecond:"
set aRtext(labelNTH)     "N, to animate every
Nth of 1,530 colors:"


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


##+################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :  'fRbuttons', 'fRswatch'
##
##   Sub-frames: none
##+################################################################

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

# set RELIEF_frame raised
# set BDwidth_frame 2


set RELIEF_frame flat
set BDwidth_frame 0


frame .fRbuttons  -relief $RELIEF_frame  -borderwidth $BDwidth_frame

frame .fRswatch   -relief $RELIEF_frame  -borderwidth $BDwidth_frame


##+##############################
## PACK the 2 top-level FRAMES. 
##+##############################

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

pack .fRswatch \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1

## OK. All frames are defined and packed.



##+#########################
## DEFINE PROC 'miniscaleH'
## (for use in making an animation-speed-control widget below)
##+##############################################################
## By using font-name and widget-geometry global variables 
##          - fontTEMP_SMALL_varwidth
##          - PADXpx_label
##          - PADYpx_label
##          - BDwidthPx_label
##          - PADXpx_button
##          - PADYpx_button
##          - BDwidthPx_button
## for the decorative & geometric elements/parameters of the GUI,
## we keep the arguments of this widget-made-on-the-fly down
## to 8 MAIN ELEMENTS/VARIABLES:
##
## - 'w' - the parent widget/window --- a (sub)frame widget,
##
## - 'scalevar' - the name of the variable that is to hold the current scale value,
##
## - 'minval' & 'maxval' - the min value of the range of the scale, and
##                         the max value of the range of the scale,
##   
## - 'initval' - an initial value at which to initially set the scale variable value
##   --- and show in the 'label' widget of this 'miniscaleH' widget,
##
## - 'unit' - a 'resolution' of the scale, such as 1 or 5 or 0.1 or 0.25 or 0.002.
##   Each click on the '++' or '+' or '-' or '--' button of the 'miniscaleH'
##   widget increases or decreases the variable associated with this
##   'miniscaleH' widget, by an amount equal to this resolution value
##   (or a multiple thereof).
##   The '++' and '--' buttons use 8 times this increment.
##   The '+' and '-' buttons use this increment.
##   See the details in the bind statements and increment/decrement procs below.
##   Also see 'delay_milsecs' below.
##
## - 'nonfracdigits' - a number-of-digits/chars specification to allow space for
##   the digits/chars to the left of a decimal point --- which can keep the
##   right-most digit in the same place, instead of shifting left/right as
##   the magnitude of the scale value decreases/increases.
##   Example: 3 to allow for values 0 to 255 to stay justified right.
##            and 4 to allow values -1.0 to +1.0 in tenths to stay justified.
##
## - 'fracdigits' - a fractional digits specification to make sure arithmetic
##    precision errors do not result in numbers like  0.30000000000000004
##    instead of 0.3.
##    Example values: 0 for integers and 1 for tenths.
##
## - 'delay_milsecs' - a delay-time to wait after a ButtonPress
##                     event before incrementing/decrementing the scale
##                     AGAIN by the 'unit' (or 8 times 'unit') amount.
##    See the details in the bind statements and the increment/decrement procs below.
##+#################################################################################

proc miniscaleH {w scalevar minval maxval initval unit nonfracdigits fracdigits delay_milsecs} {

   global PADXpx_button PADYpx_button BDwidthPx_button \
          PADXpx_label  PADYpx_label  BDwidthPx_label

   ## The font-names are also available: fontTEMP_varwidth fontTEMP_SMALL_varwidth

   ##+###############################################################
   ## NOTE: Since the 4 buttons and label are laid out side-by-side,
   ## left-to-right, we do not need to define any extra subframes.
   ## We can simply pack them within the specified parent widget, $w.
   ## From left to right, we have
   ## '--' button, '-' button, label , '+' button , '++' button.
   ##+###############################################################

   ##+####################################################
   ## Initialize the 'miniscaleH' variable.
   #######################################################

   set $scalevar $initval

   ## FOR TESTING:
   #   puts "$scalevar : [set $scalevar]"


   ##+####################################################
   ## In FRAME '$w',
   ## DEFINE the '--' BUTTON.
   ##+####################################################

   button $w.buttMINUSMINUS \
      -text "--" \
      -font fontTEMP_varwidth \
      -width 2 -height 1 \
      -pady 0 \
      -padx 0 \
      -command ""

   #  -command "increment_miniscaleH $w $scalevar $minval $maxval $unit $nonfracdigits $fracdigits $delay_milsecs"

   ##+####################################################
   ## In FRAME '$w',
   ## DEFINE the '-' BUTTON.
   ##+####################################################

   button $w.buttMINUS \
      -text "-" \
      -font fontTEMP_varwidth \
      -width 1  -height 1 \
      -pady 0 \
      -padx 0 \
      -command ""

   ##+####################################################
   ## In FRAME '$w',
   ## DEFINE a LABEL widget to show the current
   ## 'miniscaleH' widget value.
   ##+####################################################

   label $w.labelVAL \
      -text "$initval" \
      -font fontTEMP_varwidth \
      -justify right \
      -anchor e \
      -width [expr $nonfracdigits + $fracdigits] \
      -relief flat \
      -fg red \
      -bd $BDwidthPx_label


   ##+####################################################
   ## In FRAME '$w',
   ## DEFINE a '+' BUTTON.
   ##+####################################################

   button $w.buttPLUS \
      -text "+" \
      -font fontTEMP_varwidth \
      -width 1 -height 1 \
      -pady 0 \
      -padx 0 \
      -command ""

   #  -command "increment_miniscaleH $w $scalevar $minval $maxval $unit $nonfracdigits $fracdigits $delay_milsecs"

   ##+####################################################
   ## In FRAME '$w',
   ## DEFINE a '++' BUTTON.
   ##+####################################################

   button $w.buttPLUSPLUS \
      -text "++" \
      -width 2  -height 1 \
      -font fontTEMP_varwidth \
      -pady 0 \
      -padx 0 \
      -command ""

   #  -command "decrement_miniscaleH $w $scalevar $minval $maxval $unit $nonfracdigits $fracdigits $delay_milsecs"


   ##################################################
   ## Pack the 4 buttons and 1 label within frame $w.
   ##################################################

   pack $w.buttMINUSMINUS \
        $w.buttMINUS \
        $w.labelVAL \
        $w.buttPLUS \
        $w.buttPLUSPLUS \
      -side left \
      -anchor w \
      -fill none \
      -expand 0


   ##+#####################################################
   ## SET BINDINGS on the buttons in this new-widget so that
   ##         <ButtonPress-1> increments/decrements the
   ##         scalevar rapidly as the button continues to
   ##         be pressed.
   ##
   ##  These bindings could be  COMMENTED --- if we implement
   ##  the '-command' option on the 4 buttons to call on
   ##  these commands.
   ##
   ##  The <ButtonRelease-1> bindings are to stop
   ##  the scale incrementing/decrementing in spite of
   ##  pent-up requests for incrementing/decrementing.
   ##+#####################################################

   bind  $w.buttMINUSMINUS  <ButtonPress-1> \
         "decrement_miniscaleH $w $scalevar $minval $maxval [expr 8 * $unit] $nonfracdigits $fracdigits $delay_milsecs"

   bind  $w.buttMINUS  <ButtonPress-1> \
         "decrement_miniscaleH $w $scalevar $minval $maxval $unit $nonfracdigits $fracdigits $delay_milsecs"

   bind  $w.buttPLUS  <ButtonPress-1> \
         "increment_miniscaleH $w $scalevar $minval $maxval $unit $nonfracdigits $fracdigits $delay_milsecs"

   bind  $w.buttPLUSPLUS  <ButtonPress-1> \
         "increment_miniscaleH $w $scalevar $minval $maxval [expr 8 * $unit] $nonfracdigits $fracdigits $delay_milsecs"


   bind  $w.buttMINUSMINUS  <ButtonRelease-1> "set STOPminiscaleH 1"

   bind  $w.buttMINUS  <ButtonRelease-1>  "set STOPminiscaleH 1"

   bind  $w.buttPLUS  <ButtonRelease-1>  "set STOPminiscaleH 1"

   bind  $w.buttPLUSPLUS  <ButtonRelease-1>  "set STOPminiscaleH 1"

   ## Initialize STOPminiscaleH.
   global STOPminiscaleH
   set STOPminiscaleH 0


   ##+#############################################################
   ## PROC 'increment_miniscale' -
   ##
   ## CALLED BY: 'ButtonPress-1' binding on the '+' or '++' button.
   ##+#############################################################

   proc increment_miniscaleH {w scalevar minval maxval unit nonfracdigits fracdigits delay_milsecs} {

      ## This 'upvar' associates the local var 'cur_scale_var' with
      ## the outer var 'scalevar' that is to contain the scale value.
      ## It is like an EQUIVALENCE statement in FORTRAN.

      upvar #0 $scalevar cur_scale_val

      global STOPminiscaleH
 
      while { $STOPminiscaleH != 1} {

         ## FOR TESTING:
         #   puts "cur_scale_val: $cur_scale_val"

         set cur_scale_val [expr  $cur_scale_val + $unit]

         if { $cur_scale_val > $maxval} {
            set cur_scale_val $maxval
         }

         set cur_scale_val  [format %${nonfracdigits}.${fracdigits}f  $cur_scale_val]

         $w.labelVAL configure -text "$cur_scale_val"

         ## Slow down the change of the scale to human reaction time levels.
         after $delay_milsecs

         ## 'update' is needed to check for a button-release that sets STOPminiscaleH to 1.
         update

         ## FOR TESTING:
         #   puts "cur_scale_val: $cur_scale_val"

      }
      ## END OF LOOP while { $STOPminiscaleH != 1}

      set STOPminiscaleH 0

      ## The following are not needed.
      # set $scalevar $cur_scale_val
      ## FOR TESTING:
      #    puts "$scalevar : [set $scalevar]"

   }
   ## END OF proc 'increment_miniscale'


   ##+###############################################################
   ## PROC 'decrement_miniscale' -
   ##
   ## CALLED BY: 'ButtonPress-1' binding on the '-' and '--' buttons.
   ##+###############################################################

   proc decrement_miniscaleH {w scalevar minval maxval unit nonfracdigits fracdigits delay_milsecs} {

      ## This 'upvar' associates the local var 'cur_scale_var' with
      ## the outer var 'scalevar' that is to contain the scale value.
      ## It is like an EQUIVALENCE statement in FORTRAN.

      upvar #0 $scalevar cur_scale_val

      global STOPminiscaleH

      while { $STOPminiscaleH != 1} {

         ## FOR TESTING:
         #   puts "cur_scale_val: $cur_scale_val"

         set cur_scale_val [expr  $cur_scale_val - $unit]

         if { $cur_scale_val < $minval} {
            set cur_scale_val $minval
         }

         set cur_scale_val  [format %${nonfracdigits}.${fracdigits}f  $cur_scale_val]

         $w.labelVAL configure -text "$cur_scale_val"

         ## Slow down the change of the scale to human reaction time levels.
         after $delay_milsecs

         ## 'update' is needed to check for a button-release that sets STOPminiscaleH to 1.
         update

         ## FOR TESTING:
         #   puts "cur_scale_val: $cur_scale_val"

      }
      ## END OF LOOP while { $STOPminiscaleH != 1}

      set STOPminiscaleH 0

      ## The following are not needed.
      # set $scalevar $cur_scale_val
      ## FOR TESTING:
      #    puts "$scalevar : [set $scalevar]"

   }
   ## END OF proc 'decrement_miniscale'


}
## END OF 'miniscaleH' PROC


##+#########################################################
## OK. Now we are ready to define the widgets in the frames.
##+#########################################################


##+################################################################
## IN THE '.fRbuttons' frame -
## DEFINE the several BUTTONS --- 'Exit' 'Help' 'Stop' 'Start' ---
## and one 'miniscaleH' widget for 'colors-per-sec' speed control,
## with a label widget in front for 'ColorsPerSec:' text.
##+################################################################

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_msg_var_scroll "$HELPtext"}

button .fRbuttons.buttSTOP \
   -text "$aRtext(buttonSTOP)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {set stopani0or1 1}

button .fRbuttons.buttSTART \
   -text "$aRtext(buttonSTART)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {set stopani0or1 0 ; animate_RYGCBM}

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


####################################################################
## Define 1 label widget and 1 'miniscaleH' widget.
##
## NOTE: We define a frame here to hold the 'miniscaleH' widget ---
##       instead of in the 'define-and-pack-all-frames' section above.
##       We define a frame here rather than above, because this
##       frames is actually the widget (at least, the container
##       of the widget).
##+#################################################################

label .fRbuttons.labSPEED \
   -text "$aRtext(labelSPEED)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_label

## DEFINE the 'miniscaleH' widget for var 'colorsPERsec'.

frame .fRbuttons.fRspeed -relief flat -bd 0

set colorsPERsec 200


## miniscaleH Parameters:
##                       w scalevar minval maxval initval unit nonfracdigit fracdigit delay_milsecs

## Worked well before adding entry widget for VAReveryNth:
# miniscaleH .fRbuttons.fRspeed colorsPERsec 50 1000 $colorsPERsec  50 4 0 200

## Need to allow a smaller 'minval' and 'unit'.
  miniscaleH .fRbuttons.fRspeed colorsPERsec 1 1000 $colorsPERsec  1 4 0 200


####################################################################
## Define 1 LABEL widget and 1 ENTRY widget ---
## for requesting every Nth color of the 1530-color array
## to be used for the color animation.
####################################################################

label .fRbuttons.labelNTH \
   -text "$aRtext(labelNTH)" \
   -font fontTEMP_SMALL_varwidth \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -justify left \
   -anchor w \
   -relief raised \
   -bd $BDwidthPx_label

set VAReveryNth "1"

entry .fRbuttons.entryNTH \
   -textvariable VAReveryNth \
   -font fontTEMP_fixedwidth \
   -width 5 \
   -bg "$BKGD_entry" \
   -relief sunken \
   -bd $BDwidthPx_entry


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

pack .fRbuttons.buttEXIT \
     .fRbuttons.buttHELP \
     .fRbuttons.buttSTOP \
     .fRbuttons.buttSTART \
     .fRbuttons.buttWRITE \
     .fRbuttons.labSPEED \
     .fRbuttons.fRspeed \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRbuttons.labelNTH \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 \
   -padx {20 0}

pack .fRbuttons.entryNTH \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+#######################################################
## END OF DEFINING-and-PACKING ALL FRAMES and WIDGETS.
## END OF DEFINING the GUI.
## Now define BINDINGS and PROCS.
##+#######################################################


##+#######################################################################
##  BINDINGS SECTION:
##      Set some bindings to allow for putting a new N in the entry field,
##      without causing the '' proc to crash.
##
##  Note: There are also bindings within the 'miniscaleH' proc.
##+#######################################################################

bind .fRbuttons.entryNTH <Enter> "set stopani0or1 1"
bind .fRbuttons.entryNTH <FocusIn> "set stopani0or1 1"

bind .fRbuttons.entryNTH <Return> "set stopani0or1 0 ; animate_RYGCBM"


##+######################################################################
## PROCS SECTION:
##
##   - 'load_colorArray1530' Loads 1530 'equally-spaced' colors into 2 arrays,
##                           by interpolating between the RYGCMBR colors.
##
##                           For the array names, we use 'aRrygcbmr1530hex'
##                           and 'aRrygcbmr1530rgb255'.
##                            
##    - 'animate_RYGCBM'     Performs the color animation by 'marching'
##                           thru the RYGCMBR color cycle, changing the
##                           background color of frame '.fRswatch'.
##
##                           We access the colors in the global var
##                          'aRrygcbmr1530hex'.
##
##    - 'writeColorTables_groupsOfSetStatements'
##                           Writes groups of 'set' statements into
##                           a text file that is then brought up in a
##                           GUI text editor.
##
##                           This script can be edited to change the
##                           'EDITOR_text' var to a GUI text editor
##                           preferred by the user.
##
##                           For details on this 'write' proc, see the comments
##                           at the top of and within that proc, below.
##
##     - 'popup_msg_var_scroll'   Invoked by the 'Help' button to show
##                                a 'HELPtext' var.
##
##+######################################################################


###############################################################################
## PROC 'load_colorArray1530'
###############################################################################
## PURPOSE: Loads 1530 'equally-spaced' colors into two arrays
##          by interpolating between the RYGCMBR colors.
##
##          One array is for hex-colors --- one hex-color for each element of
##          the array.
##
##          The other array is for triplets of RGB colors (0 to 255) ---
##          a 3-element Tcl list for each element of the array.
##
##          For the array names, we use 'aRrygcbmr1530hex' and
##          'aRrygcbmr1530rgb255'.
##
## OVERVIEW OF THE METHOD:
##           The following diagram indicates the passage through the
##           6 RYGCBM colors, transitioning from color to color in 255 steps
##           for each pair --- for a total of 6 x 255 = 1530 steps.
##
##           Note that we alternately increase from 0-to-254, then
##           decrease from 255-to-1.
##
##                              R   G   B
##                             --- --- ---
##                       R =   255   0   0
##                             255   1   0
##                             255   .   0
##                             255   .   0   R=255 , G = 0 to 254 , B=0
##                             255   .   0
##                             255 254   0
##                       Y =   255 255   0
##                             254 255   0
##                               . 255   0
##                               . 255   0   R = 255 to 1 , G=255 , B=0 
##                               . 255   0
##                               1 255   0
##                       G =     0 255   0
##                               0 255   1
##                               0 255   .
##                               0 255   .   R=0 , G = 255 , B = 0 to 254
##                               0 255   .
##                               0 255 254
##                       C =     0 255 255
##                               0 254 255
##                               0   . 255
##                               0   . 255   R=0 , G = 255 to 1 , B=255
##                               0   . 255
##                               0   1 255
##                       B =     0   0 255
##                               1   0 255
##                               .   0 255
##                               .   0 255   R = 0 to 254, G=0 , B=255
##                               .   0 255
##                             254   0 255
##                       M =   255   0 255
##                             255   0 254
##                             255   0   .
##                             255   0   .  R=255 , G=0 , B = 255 to 1
##                             255   0   .
##                             255   0   1
##        and we are ready to start again at:
##                       R =   255   0   0
##
## CALLED BY: the added-GUI-initialization section at the bottom of the script.
###############################################################################

proc load_colorArray1530 {} {

   global aRrygcbmr1530hex aRrygcbmr1530rgb255

   ###################################################################
   ## Initialize the counter that we will use to index into the array,
   ## from 1 thru 1530.
   ###################################################################

   set CNT1530 0

   #########################################################################
   ## LOAD COLORS FROM R TO Y:   (not including Y)
   ##                              R   G   B
   ##                             --- --- ---
   ##                       R =   255   0   0
   ##                             255   1   0
   ##                             255   .   0
   ##                             255   .   0   R=255 , G = 0 to 254 , B=0
   ##                             255   .   0
   ##                             255 254   0
   ##        not including  Y =   255 255   0
   #######################################################################

   set r255 255
   set g255 0
   set b255 0

   ## G = 0 thru 254
   for {set i 0} {$i < 255} {incr i} {

      set g255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 0} {$i < 255} {incr i}
   ## G = 0 thru 254


   #########################################################################
   ## LOAD COLORS FROM Y TO G:   (not including G)
   ##                       Y =   255 255   0
   ##                             254 255   0
   ##                               . 255   0
   ##                               . 255   0   R = 255 to 1 , G=255 , B=0 
   ##                               . 255   0
   ##                               1 255   0
   ##       not including   G =     0 255   0
   ########################################################################

   ## set r255 255
      set g255 255
   ## set b255 0

   ## R = 255 thru 1 
   for {set i 255} {$i > 0} {incr i -1} {

      set r255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 255} {$i > 0} {incr i -1}
   ## R = 255 thru 1 


   #########################################################################
   ## LOAD COLORS FROM G TO C:   (not including C)
   ##                       G =     0 255   0
   ##                               0 255   1
   ##                               0 255   .
   ##                               0 255   .   R=0 , G = 255 , B = 0 to 254
   ##                               0 255   .
   ##                               0 255 254
   ##       not including   C =     0 255 255
   #########################################################################

      set r255 0
   ## set g255 255
   ## set b255 0

   ## B = 0 thru 254
   for {set i 0} {$i < 255} {incr i} {

      set b255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 0} {$i < 255} {incr i}
   ## B = 0 thru 254



   #########################################################################
   ## LOAD COLORS FROM C TO B:   (not including B)
   ##                       C =     0 255 255
   ##                               0 254 255
   ##                               0   . 255
   ##                               0   . 255   R=0 , G = 255 to 1 , B=255
   ##                               0   . 255
   ##                               0   1 255
   ##        not including  B =     0   0 255
   ########################################################################

   ## set r255 0
   ## set g255 255
      set b255 255

   ## G = 255 thru 1 
   for {set i 255} {$i > 0} {incr i -1} {

      set g255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 255} {$i > 0} {incr i -1}
   ## G = 255 thru 1 


   #########################################################################
   ## LOAD COLORS FROM B TO M:   (not including M)
   ##                       B =     0   0 255
   ##                               1   0 255
   ##                               .   0 255
   ##                               .   0 255   R = 0 to 254, G=0 , B=255
   ##                               .   0 255
   ##                             254   0 255
   ##     not including     M =   255   0 255
   ########################################################################

   ## set r255 0
      set g255 0
   ## set b255 255

   ## R = 0 thru 254
   for {set i 0} {$i < 255} {incr i} {

      set r255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 0} {$i < 255} {incr i}
   ## R = 0 thru 254


   #########################################################################
   ## LOAD COLORS FROM M TO R:   (not including R)
   ##                       M =   255   0 255
   ##                             255   0 254
   ##                             255   0   .
   ##                             255   0   .  R=255 , G=0 , B = 255 to 1
   ##                             255   0   .
   ##                             255   0   1
   ##        not including  R =   255   0   0
   ##        and we are back where we started.
   ########################################################################

      set r255 255
   ## set g255 0
   ## set b255 255

   ## B = 255 thru 1 
   for {set i 255} {$i > 0} {incr i -1} {

      set b255 $i
      set hexcolor [format "#%02X%02X%02X" $r255 $g255 $b255]
      incr CNT1530
      set aRrygcbmr1530hex($CNT1530) "$hexcolor"
      set aRrygcbmr1530rgb255($CNT1530) [list $r255 $g255 $b255]

   }
   ## END OF  for {set i 255} {$i > 0} {incr i -1}
   ## B = 255 thru 1 


}
## END OF proc 'load_colorArray1530'


##+########################################################################
## PROC 'animate_RYGCBM'
##+########################################################################
## PURPOSE: Performs the color animation by 'marching'
##          thru the RYGCMBR color cycle, changing the
##          background color of frame '.fRswatch'.
##
##          Uses the 1530 colors in the global array 'aRrygcbmr1530hex'.
##
## CALLED BY: the 'Start' button and in the added-GUI-initialization
##            section at the bottom of the script.
###########################################################################

proc animate_RYGCBM {} {

   global aRrygcbmr1530hex colorsPERsec stopani0or1 VAReveryNth

   ## Following var not needed?
   # global writing0or1

   ##################################################
   ## If VAReveryNth is out of range, set it to one.
   ##################################################

   if {"$VAReveryNth" == ""} {set VAReveryNth 1}
   if {$VAReveryNth < 1 || $VAReveryNth > 1530} {set VAReveryNth 1}


   ##########################################################################
   ## THE COLOR ANIMATION LOOP:
   ## Loop until the user hits the 'Stop' button.
   ## The 'Stop' button sets var 'stopani0or1' to 1.
   ##     The animation also will stop if the user hits the Exit button,
   ##     or closes the window.
   ##########################################################################

   ## Initialize an index we will use into the array of 1,530 hex-colors.

   set IDXcolor 1

   while {1} {

      #############################################################
      ## Alternatively, this 'while' loop could be based on the
      ## value of $stopani0or1:      while {$stopani0or1 == 0}
      ## Instead, we continually check on the value of $stopani0or1
      ## below and 'return' if it is not zero.
      #############################################################

      #################################################
      ## Stop immediately if the stop flag is set.
      #################################################
         
      if {$stopani0or1 != 0} {return}

      ## Similarly, we could stop the animation if the 'write' proc
      ## is running. (Not needed?)

      # if {$writing0or1 == 1} {return}

      ##########################################################
      ## Change the swatch color and force its display.
      ##########################################################

      .fRswatch configure -bg "$aRrygcbmr1530hex($IDXcolor)"
      update


      ###################################################################
      ## Increment the color index, but reset it to 1 if it exceeds 1530.
      ###################################################################
      ## We use 'catch' in case the user is blanking out and resetting
      ## VAReveryNth just before this section executes.
      ###################################################################

      catch {incr IDXcolor $VAReveryNth}

      if {$IDXcolor > 1530} {set IDXcolor 1}


      ###################################################################
      ## Recalculate the 'WAITmillisecs', in case 'colorsPERsec' has been
      ## changed by the user, using the 'miniscaleH' widget.
      ###################################################################

      set WAITmillisecs [expr { 1000 / $colorsPERsec }]

      ## FOR TESTING:
      #   puts "proc 'animate_RYGCBM' > WAITmillisecs: $WAITmillisecs   colorsPERsec: $colorsPERsec"
      #   exit

      ##########################################################
      ## Wait $WAITmillisecs before continuing the loop.
      ##########################################################

      after $WAITmillisecs

      ##################################################
      ## If VAReveryNth is out of range, set it to one.
      ##################################################

      if {"$VAReveryNth" == ""} {set VAReveryNth 1}
      if {$VAReveryNth < 1 || $VAReveryNth > 1530} {set VAReveryNth 1}


   }
   ## END OF 'while' (color-animation) LOOP.

}
## END OF proc 'animate_RYGCBM'


##########################################################################
## PROC 'writeColorTables_groupsOfSetStatements'
##########################################################################
## PURPOSE:  Writes groups of 'set' statements into a text file that is
##           then brought up in a GUI text editor.
##
##           This script can be edited to change the GUI
##           text editor to one preferred by the user.
##
##           The 'set' statements are meant to eventually
##           be used in Tcl scripts to load a color table
##           variable with colors.
##
##           The 'set' statements use an array name like
##           'aRcolorTableHEX'. Of course, anyone using
##           the 'set' statements in a Tcl script could
##           do a global change to change the name of
##           that array variable.
##
## METHOD:   The colors in the 'set' statements come from the  global vars
##           'aRrygcbmr1530hex' and 'aRrygcbmr1530rgb255'.
##                           
##           Note that the integer 1530 = 6 x 255 can be factored
##           into the prime integers: 2 x 3 x 3 x 5 x 17.
##
##           The groups of 'set' statements are generated from
##           the 1,530 color array by using:
##
##               - every 170 (2x5x17), for a total of 1530/170 =  9 colors
##               - every 153 (3x3x17), for a total of 1530/153 = 10 colors
##               - every 102 (2x3x17), for a total of 1530/102 = 15 colors
##               - every 90 (2x3x3x5), for a total of 1530/90  = 17 colors
##               - every 85 (5x17)   , for a total of 1530/85  = 18 colors
##               - every 51 (3x17)   , for a total of 1530/51  = 30 colors
##               - every 45 (3x3x5)  , for a total of 1530/45  = 34 colors
##               - every 34 (2x17)   , for a total of 1530/34  = 45 colors
##               - every 30 (2x3x5)  , for a total of 1530/30  = 51 colors
##               - every 18 (2x3x3)  , for a total of 1530/18  = 85 colors
##               - every 17          , for a total of 1530/17  = 90 colors
##               - every 15 (3x5)    , for a total of 1530/15  = 102 colors
##               - every 10 (2x5)    , for a total of 1530/10  = 153 colors
##               - every 9 (3x3)     , for a total of 1530/9   = 170 colors
##               - every 6 (2x3)     , for a total of 1530/6   = 255 colors
##               - every 5           , for a total of 1530/5   = 306 colors
##               - every 3           , for a total of 1530/3   = 510 colors
##               - every 2           , for a total of 1530/2   = 765 colors
##               - evary 1           , for a total of 1530 colors.
##
## CALLED BY: by the 'WriteTables' button on the GUI
#############################################################################

proc writeColorTables_groupsOfSetStatements {} {

   global env outDIR EDITOR_text aRrygcbmr1530hex aRrygcbmr1530rgb255

   ## Following var not needed?
   # global writing0or1 

   ######################################################################
   ## Open a file to which to write the 'set-color-array' statements
   ## for the groups of 'set' statements constituting each color table.
   ######################################################################

   set userID "$env(USER)"
      
   if {"$outDIR" == ""} {set outDIR "/tmp"}

   set OUTfilename "$outDIR/${userID}_RYGCMBcolorTables_setStatements.tcl"

   set f [open $OUTfilename w]

   ########################################################################
   ## Write the group of 'set' statements, from the 1530 HEX color array,
   ## by stepping every 170 (2x5x17), for a total of 1530/170 =  9 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 9-COLOR HEX-color table (every 170 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 170
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 9-COLOR RGB255-color table (every 170 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor) \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 170
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 153 (3x3x17), for a total of 1530/153 = 10 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 10-COLOR HEX-color table (every 153 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 153
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 10-COLOR RGB255-color table (every 153 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor) \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 153
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 102 (2x3x17), for a total of 1530/102 = 15 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 15-COLOR HEX-color table (every 102 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 102
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 15-COLOR RGB255-color table (every 102 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 102
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## every 90 (2x3x3x5), for a total of 1530/90  = 17 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 17-COLOR HEX-color table (every 90 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 90
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 17-COLOR RGB255-color table (every 90 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 90
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## every 85 (5x17)   , for a total of 1530/85  = 18 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 18-COLOR HEX-color table (every 85 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 85
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 18-COLOR RGB255-color table (every 85 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 85
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 51 (3x17)   , for a total of 1530/51  = 30 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 30-COLOR HEX-color table (every 51 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 51
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 30-COLOR RGB255-color table (every 51 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 51
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 45 (3x3x5)  , for a total of 1530/45  = 34 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 34-COLOR HEX-color table (every 45 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 45
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 34-COLOR RGB255-color table (every 45 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 45
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 34 (2x17)   , for a total of 1530/34  = 45 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 45-COLOR HEX-color table (every 34 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 34
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 45-COLOR RGB255-color table (every 34 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 34
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 30 (2x3x5)  , for a total of 1530/30  = 51 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 51-COLOR HEX-color table (every 30 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 30
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 51-COLOR RGB255-color table (every 30 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 30
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 18 (2x3x3)  , for a total of 1530/18  = 85 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 85-COLOR HEX-color table (every 18 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 18
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 85-COLOR RGB255-color table (every 18 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 18
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 17          , for a total of 1530/17  = 90 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 90-COLOR HEX-color table (every 17 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 17
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 90-COLOR RGB255-color table (every 17 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 17
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 15 (3x5)    , for a total of 1530/15  = 102 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 102-COLOR HEX-color table (every 15 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 15
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 102-COLOR RGB255-color table (every 15 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 15
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 10 (2x5)    , for a total of 1530/10  = 153 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 153-COLOR HEX-color table (every 10 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 10
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 153-COLOR RGB255-color table (every 10 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 10
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 9 (3x3)     , for a total of 1530/9   = 170 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 170-COLOR HEX-color table (every 9 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 9
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 170-COLOR RGB255-color table (every 9 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 9
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 6 (2x3)     , for a total of 1530/6   = 255 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 255-COLOR HEX-color table (every 6 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 6
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 255-COLOR RGB255-color table (every 6 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 6
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 5           , for a total of 1530/5   = 306 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 306-COLOR HEX-color table (every 5 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 5
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 306-COLOR RGB255-color table (every 5 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 5
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 3           , for a total of 1530/3   = 510 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 510-COLOR HEX-color table (every 3 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 3
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 510-COLOR RGB255-color table (every 3 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 3
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 2           , for a total of 1530/2   = 765 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 765-COLOR HEX-color table (every 2 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor 2
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 765-COLOR RGB255-color table (every 2 colors of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor 2
      incr CNTcolor
   }


   ########################################################################
   ## Write the group of 'set' statements, from the 1530 color array,
   ## by stepping every 1, for a total of 1530 colors
   ## in the color table.
   ########################################################################

   puts $f  ""
   puts $f  "## 1530-COLOR HEX-color table (every color of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableHEX($CNTcolor) \"$aRrygcbmr1530hex($IDXcolor)\""
      incr IDXcolor
      incr CNTcolor
   }

   puts $f  ""
   puts $f  "## 1530-COLOR RGB255-color table (every color of a 1530-color RYGCBMR cycle):"
   puts $f  ""

   set IDXcolor 1
   set CNTcolor 1

   while {$IDXcolor <= 1530} {
      puts $f "set aRcolorTableRGB255($CNTcolor)  \[ list $aRrygcbmr1530rgb255($IDXcolor) \]"
      incr IDXcolor
      incr CNTcolor
   }


   ##########################################################
   ## We done writing the 'set' statement groups to a file.
   ## We close the file and show it in a text editor.
   ##########################################################

   close $f

   # exec /usr/bin/sh -c "$EDITOR_text "$OUTfilename" > /dev/null  2>&1"

   exec $EDITOR_text "$OUTfilename"

   ## Exit this proc. We have generated the requested file.

}
## END OF proc 'writeColorTables_groupsOfSetStatements'


##+########################################################################
## PROC 'popup_msg_var_scroll'
##+########################################################################
## PURPOSE: Report help or error conditions to the user.
## 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_msg_var_scroll { 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 .fRtopmsg}
   toplevel  .fRtopmsg

   # wm geometry .fRtopmsg 600x400+100+50

   wm geometry .fRtopmsg +100+50

   wm title     .fRtopmsg "Note"
   # wm title   .fRtopmsg "Note to $env(USER)"

   wm iconname  .fRtopmsg "Note"


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

   text .fRtopmsg.text \
      -wrap none \
      -font fontTEMP_varwidth \
      -width  $VARwidth \
      -height $VARheight \
      -bg "#f0f0f0" \
      -relief raised \
      -bd 2 \
      -yscrollcommand ".fRtopmsg.scrolly set" \
      -xscrollcommand ".fRtopmsg.scrollx set"

   scrollbar .fRtopmsg.scrolly \
                 -orient vertical \
      -command ".fRtopmsg.text yview"

   scrollbar .fRtopmsg.scrollx \
                -orient horizontal \
                -command ".fRtopmsg.text xview"

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

   ###############################################
   ## PACK *ALL* the widgets in frame '.fRtopmsg'.
   ###############################################

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

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

   ## Pack the scrollbars BEFORE the text widget,
   ## so that the text does not monopolize the space.

   pack .fRtopmsg.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 .fRtopmsg.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 .fRtopmsg.text \
      -side top \
      -anchor center \
      -fill both \
      -expand 1


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

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


set HELPtext "\
** HELP for this
 ** RYGCBM 'Color Circle' Animation Utility 
 ** and
 ** Tcl-Color-Array 'set'-Statements Generator Utility **

IMPLEMENTATION OF THE COLOR ANIMATION:

This Tk GUI script provides a color animation by
'traveling around' a 'color circle' ---
through the 6 primary and complementary colors ---
Red-Yellow-Green-Cyan-Blue-Magenta --- and back to Red,
then repeating.

The phrase 'travel around', in this particular GUI, means
that a sequence of colors, interpolated between pairs of the
6 RYGCBM colors, is displayed in a 'color swatch' on the GUI.

A set of 6 x 255 = 1,530 colors is generated --- graduating
from Red to Yellow, then Yellow to Green, then Green to Cyan,
then Cyan to Blue, then Blue to Magenta, then Magenta back to Red.

Those colors are displayed in sequence to make the color animation.

The animation continues until the user clicks the 'Stop' button.
OR the user can click the 'Exit' button --- or close the window.
 
Thus this script provides a repeating color-sequence animation.

The color sequence is somewhat similar to the color spectrum
of a prism or rainbow.

This animation gives the user a quick, dynamic overview of the
color combinations of the primary and complementary colors as one
blends the colors in the rather natural sequence --- RYGCBMR.

---

CONTROLLING THE SPEED OF THE COLOR ANIMATION:

The '+' '++' '-' and '--' buttons on the GUI allow you to
control the number of COLORS-PER-SECOND shown during the
color animation.

You can SPEED UP the color animation by clicking the '+' or '++'
buttons of the GUI. The '++' button increments the animation
speed by an 8-times bigger factor than the '+' button.

Similarly, you can SLOW DOWN  the color animation by clicking the
'-' or '--' buttons of the GUI. The '--' button decrements the
animation speed by an 8-times bigger factor than the '-' button.

---

CHANGING THE COLORS SHOWN IN THE ANIMATION:

An entry field on the GUI allows you to choose to go through
every Nth one of the 1,530 colors, instead of every one.

When the mouse cursor goes over the entry field, the animation
stops. When you enter an integer and press the Enter/Return key,
the animation restarts using the new value of N.

The integer 1530 can be factored into the product of primes:
2 x 3 x 3 x 5 x 17.

The entry field was intended to allow for entering combinations
of these factors, like 2 or 3 or 5 or 6 or 9 or 10 or 15 or 17
or 18 or 30 or ...

But you can enter any integer between 1 and 1530.

---

THE 'WRITE-TABLES' OPTION:

A SECOND (probably more useful) PURPOSE of this GUI is to generate
a file containing 'set' statements for making COLOR TABLE ARRAYS
from the 1,530 colors.

The 'WriteTables' button provides a way of generating tables of
'equally spaced colors' taken from the the 6 x 255 = 1530 colors 
that were generated to make the initial color animation.

The color tables consist of 'set' statements to make array variables
that contain 9 or 10 or 18 or ... or 765 or 1530 colors.

Two kinds of arrays are made: arrays of hex-colors and arrays of
triplets of RGB values (0 to 255).

The 'set' statements for the 'HEX' and 'RGB255' color arrays
are put in a text file.

The user can select any group of the 'set' statements to be used
in other Tk scripts to set up a 'look-up table' of colors.

For example, in a 3D modeling application, one may wish to apply
colors to the facets (polygons) or vertices of a 3D model ---
either via some pattern or randomly chosen from the table.

Integers in the range 1 to 1530 (or some subset thereof) can be
generated --- randomly or in some algorithmic pattern --- to
look-up colors to apply to faces/vertices of the model.

Of course, the user can adjust the color values in the 'set'
statements as needed. The 'set' statements are meant as
a convenient starting point for further experimentation in
any particular application.

---

A THIRD PURPOSE of this GUI - demo of a NEW WIDGET:

This script also introduces a new, compact 'scale'-like widget,
dubbed 'miniscaleH' (for miniscale-horizontal).

In this application, the widget is used to control
the speed of the color transition in the animation ---
in units of color-steps per second --- from about
1 to 1,000 per second, in this paricular application.

At 1 per second, it would take 25 minutes to traverse the
1,530 color steps and start over. A colors-per-second setting
in the range of 50 to 400 is probably more suited to those
people with other things to do.

However, if you choose to set N=90 to show every 90th
color of the 1530, only 17 colors are being traversed,
repeatedly. In this case, a colors-per-second setting
of around 1 or 2 or 3 may be more suitable to keep the colors
from changing too fast.

The 'miniscaleH' widget is made up of 4 'button' widgets
and one 'label' widget --- arrayed from left to right ---
the label in the middle, with 2 buttons on either side.

The '+' and '++' buttons on the right increment the scale number;
the '-' and '--' buttons on the left decrement. The '++' and
'--' buttons are for high-speed incrementing/decrementing.

The '++' button is currently set to increment the value of
the 'scale' in 8 times bigger 'jumps' than the '+' button.

The '--' button is currently set to decrement the value of
the 'scale' in 8 times bigger 'jumps' than the '-' button.

The 'miniscaleH' widget is more compact than the Tk 'scale'
widget --- and its labels and buttons can be decorated
with background images, via the '-image' and
'-compound center' options. So the 'miniscaleH' widget
may have some use in 'embellished' Tk GUI's. In contrast,
the 'scale' widget does not have a '-image' option.
"



##+#####################################################
## Additional-GUI-INITIALIZATION SECTION.
##+#####################################################

########################################################################
## Set the output directory for the file of ColorTable 'set' statements.
########################################################################

set outDIR "/tmp"

################################################################
## Set the editor with which to view the ColorTables text file.
################################################################

#   set EDITOR_text "gedit"
#   set EDITOR_text "/usr/bin/gedit"
set EDITOR_text "$env(HOME)/apps/gscite_2.27/SciTE"


########################################################
## Load the 1530-color array variables that will be used
## by the 'animate' and 'write' procs.
########################################################

load_colorArray1530


#####################################################
## Show the GUI before starting the animation loop.
#####################################################

update

########################################################
## Make sure the stop-animation flag is not set to stop.
########################################################

set stopani0or1 0

########################################################
## Start with the write-file status-flag turned off.
## (Not needed?)
########################################################

# set writing0or1 0

#######################################################
## Start the animation so that it starts automatically
## after the GUI shows up.
#######################################################

animate_RYGCBM 


Setting the Text Editor to use

Note that the user can set the variable 'EDITOR_text' at the bottom of the script to choose an appropriate GUI text editor in which the file of Tcl 'set' statements will be shown.

The editor is called up from within the Tk script by using the Tcl 'exec' command.

___

The 1530-set-statments generation is so fast that IMMEDIATELY after clicking on the 'WriteTables' button, the text-editor pops up displaying the 'set'-statements file. You can change the name of an array variable if you wish, and save the file in a directory of your choice.


Sensitivity to Color Components

I find it interesting to note that a lot of the reason we center our attention on the RGB colors (and the pigments CMY that 'suck' those colors out of reflected light) is because of the way our eyes react to the wavelengths of light and because of the position of the wavelengths of visible light in the frequency/wavelength spectrum --- in particular, they are within an 'octave' of each other.

RGB_waveLengths_blackONwhite_552x276.jpg

The 3 sensitivity curves correspond to the three types of light-sensitive 'cones' on the retina of the human eye. The peaks of the 'Red' and 'Green' curves do not actually occur at the defined frequencies of Red and Green.

It is reported that some animals do not see all the colors that we see. Unlucky them.

In my case, I am partially red-green blind. I think if my sensitivity to red and green were plotted like this, my red and green 'humps' might be about as tall as that 'blue' hump. Maybe that is why yellow text on a white background is usually unreadable to me --- my sensitivity to a combination of red and green is low.

I find it interesting that we can get any color by a combination of 2 colors or 3 colors or more, as indicated in the following CIE Chromaticity diagram.

cieChromaticityPlot_593x344.png

And it was an eye-opener to me that choosing to combine 3 colors, like Red and Green and Blue, to generate colors leaves a lot of colors that we cannot generate with that combination ... as indicated by the following diagram.

cieChromaticityDiagram_withColorTriangles_557x455.jpg

We cannot attain, on our computer monitors, the humanly visible colors outside the RGB color triangle.

I would put a link here to a good discussion of chromaticity and generating the humanly visible colors via combinations of multiple colors, but the discussions that I see on Wikipedia and elsewhere are overly complex.

You may find the discussion in a computer graphics book like 'Computer Graphics' by Hearn and Baker, Prentice-Hall (1986) more readable.


Possible Enhancements

I plan to enhance this script so that it puts out smaller groups of 'set' statements --- corresponding to subsets of the 1,530 set statements --- all in the same output file.

Then, when I need an array of about 20 'set' statements, say, to make an array of about 20 'equally spaced' colors for another Tk script, I can run this utility and extract out the group of 'set' statements that I need.

I pointed out above that 1530 has many factors --- 1530 = 5 x 2 x 3 x 3 x 17. So there are quite a few subsets of 'equally-spaced' colors that you can use to cycle 'nicely' through those 1530 colors.

I will probably make subsets of 'set' statements from every 2 colors, every 3, every 5, every 6, every 9, every 10, every 15, every 17, every 18, every 30, every 34, every 51, every 85, every 90, every 102, every 153, every 170 of the 1,530 color array.

I may find that I use the 'every 85' set (18 colors) and 'every 90' (17 colors) and 'every 102' (15 colors) and 'every 153' (10 colors) and 'every 170' (9 colors) most often.

And I may use some variations --- like replace some magentas with browns --- for terrain colors.


Conclusion

It took a couple of days to get this code in shape. But now I am in a position to generate some 3D model files and liven them up some with a variety of colors. Tcl-Tk, you make me :-) .


uniquename 2013jan26 UPDATE

I have implemented the 'Possible Enhancements' listed above --- namely, I have added many sub-groups of the original 1,530 colors to the 'set' statements in the output 'ColorTables' text file.

In addition, I have made a few other changes:

** Changed the 'milsecs' var of the 'miniscaleH' proc to 'delay_milsecs' and, more importantly, fixed some increment/decrement settings in that widget-making proc.

** Split the proc 'DrawRYGCBM' into three procs:

  • load_colorArray1530
  • animate_RYGCBM
  • writeColorTables_groupsOfSetStatements

This makes the logic much less complicated, and thus makes the script easier to modify or enhance.

** I have added an entry widget by which to request animating every Nth color of the 1530 colors, rather than just every color (N=1).

I replaced the old code above with the new code with these enhancements and fixes.

I plan to replace the image above with a new GUI image --- that is, replace the crude animated GIF above with a small movie file that shows the the color transition more smoothly, and without the visual artifacts.

In the meantime, here is a static image of the GUI with the new entry field to prompt for N --- to animate every Nth color of the 1530 colors.

RYGCBMcolorTablesGUI_animationAtGreen_screenshot_688x164.jpg

___

I have found that the color animation is not the best way of getting a good idea of the 'spread' of colors in any of the approximately 20 color tables generated by this script.

It may be better to devise a script that shows each of the color tables as a stack of colored rectangles, like the color stack below. Someday I may provide such a script as an alternative to this way of generating and viewing some color tables.

___

Of course, the color tables that you use depend on the application, and perhaps on your audience.

TwoColorTables_forGirlsGuys_450x487.jpg

Guys who have been shopping at the cosmetic counters of department stores may also be inclined toward the richer color table on the left (rather than a 7-color table), having been exposed to the richness of the world of color ... :-).