C:\upload\java\Life\source\java\HowGameIsPlayedScreen.java
  /* ******************************************************************
      This class fires up the window that is the "real" UI. The class < UI >
      merely does a few initializations and sets us up. The real dirty
      work takes place in this big class.

      Note: this class is long and bothersome.
     ****************************************************************** */

  import java.awt.*;
  import java.awt.event.*;

  final class HowGameIsPlayedScreen extends Dialog
                                    implements ActionListener,
                               // qz     WindowListener,
                                    Constants,
                                    Strings
  {
      private Vars vars;
      private Objects objects;
      private Frame parentFrame;

      private PopupWindow error;
      /* This class gives values back to the main class < Vars vars > in
         which "master" copies of variables live. These local 
         variables follow.

         Also, these values are fed defaults from the main program.
      */
      private boolean inputByRowsAndColumns;  /* Do we input board by 
                                               rows & columns, or size
                                               of an individual cell? */
      private String title;               // Name of Dialog
      private boolean modal;              // Will be "true."qz

      /* Note < TextFieldObject > is an inner class, -- no other class uses it -- 
         defined below. It encapsulates a TextField, as well as three values:
         current value, min, and max. It also overrides < toStrin() > to return a 
         meaningful string representation of the TextField.
      */
      private TextFieldObject numRowsTextField;         // These textfields
      private TextFieldObject numColumnsTextField;      // store game info
      private TextFieldObject timeDelayTextField;       // fed back to main 
      private TextFieldObject probabilityTextField;     // program.
      private TextFieldObject pixelsPerCellTextField;

      private Button byMouseClickButton;                  // Buttons
      private Button byTimeDelayButton;                   // used
      private Button clickToSayWhoIsAliveAndDeadButton;   // in
      private Button byRowsAndColumnsButton;              // the
      private Button byPixelsButton;                      // UI.
      private Button probalisticButton;
      private Button okButton;
      private Button quitButton;
    
      private boolean quit; // If the user decides to quit.

    /* ***************************************************************
       Constructor follows:
       *************************************************************** */

      HowGameIsPlayedScreen(String title,     // Title
                            boolean modal,    /* Do anything until
                                                 window is dismissed? */
                            Frame parentFrame,
                            Objects objects,
                            Vars vars)        // Where objects live.
      {
          // The vast majority of this routine is setting up the Grid
          // Bag Layout.

          super(parentFrame, title, modal);   // Talk to our prent class
                                              // < Dialog >.

          String errorString = ((title       != null) &&
                                (parentFrame != null) &&
                                (objects     != null) &&
                                (vars        != null))?
                                NULL_STRING : "title = " + title +
                                             "parentFrame = " + parentFrame + 
                                             "objects = " + objects +
                                             "vars = " + vars;
          if (!errorString.equals(NULL_STRING))
          {
              System.out.println("Error, null pointer, HowGameIsPlayedScreen " +
                                  errorString);
              return;
          }

          this.parentFrame = parentFrame;
          this.title       = title;
          this.modal       = modal;
          this.objects     = objects;
          this.vars        = vars;
 
          quit = false; // Assume we wish to play.
 
        /* Assume we input board by rows and columns. This is local to
           this class, and never communicated to the outside world. The
           user may of course change this by pressing buttons.
        */
          inputByRowsAndColumns = true;

          setFont(SMALL_FONT);
            
         /* Instantiate buttons. The string constants live in *Strings.java*,
            numeric constants in *Constants.java*.

            First has string: "by mouse click" -- go from 
            generation to generation by mouse click on a button?
        */
/*  1 */   byMouseClickButton = new Button(BY_MOUSE_CLICK); 

        // Next has String: "by time delay" -- wait between generations?

/*  2 */   byTimeDelayButton  = new Button(BY_TIME_DELAY);

        // Next asks, "set alive & dead via mouse clicks?"

/*  3 */   clickToSayWhoIsAliveAndDeadButton = 
                                    new Button(INPUT_ALIVE_OR_DEAD_BY_MOUSE_CLICK);

           byRowsAndColumnsButton  = new Button(BY_ROWS_AND_COLUMNS);
           byPixelsButton          = new Button(BY_PIXELS);

        // Next asks: "set alive via probalistic means?"

/*  4 */   probalisticButton = new Button(INPUT_VIA_PROBALISTIC);

        // Next is "accept current game plan; proceed."

/*  5 */   okButton = new Button(OK);

/*  6 */   quitButton = new Button(QUIT);

        // Instantiate labels. These are self-explanatory.

/*  6 */   Label buttonOrTimeLabel = new Label(
                                           HOW_DO_WE_GO_FROM_GENERATION_TO_GENERATION, 
                                           Label.LEFT); 

/*  7 */   Label millisecondsLabel = new Label(MILLISECONDS_COMMA_MIN_EQUALS + 
                                              MIN_TIME_DELAY, Label.LEFT);

/*  8 */   Label rowColInfoLabel =  new Label(
                                          INPUT_SIZE_OF_BOARD_BY_ROWS_AND_COLUMNS_PLUS_RANGE + 
                                          " " + vars.GetMinNumberOfRows() + " " +
                                          TO + " " + vars.GetMaxNumberOfRows() + " " + 
                                          ROWS + ", " + vars.GetMinNumberOfColumns() + " " +
                                          TO + " " +
                                          vars.GetMaxNumberOfColumns() + " " + COLUMNS +
                                          ", " + OR + ", ");

/*  9 */   Label pixelsLabel =  new Label(INPUT_SIZE_OF_BOARD_BY_PIXELS_PER_SIDE_PLUS_COMMA +
                                        vars.GetMinPixelsPerCell() + " " + TO + " " + 
                                        vars.GetMaxPixelsPerCell() + ".");

/* 10 */   Label inputRowsLabel = new Label(NUMBER_OF_ROWS_COLON, Label.LEFT);

/* 11 */   Label inputColsLabel = new Label(NUMBER_OF_COLUMNS);
/* 12 */   Label inputByMouseClickOrProbabilityLabel = new Label(
                                           INPUT_GAME_BY_CLICKING_ON_CELLS_OR_PROBALISTICALLY);
 
/* 13 */   Label asPercentLabel = new Label(AS_A_PERCENT_WITH_LEFT_PARENS + MIN_PROBABILITY +
                                        DASHES + MAX_PROBABILITY + DOUBLE_RIGHT_PARENS, Label.LEFT);

        // Instantiate text fields:

/* 14 */   pixelsPerCellTextField  = new TextFieldObject(vars.GetPixelsPerCell(), // Current value
                                           vars.GetMinPixelsPerCell(),      // Lower bound  
                                           vars.GetMaxPixelsPerCell(),      // Upper bound
                                           PIXELS_PER_CELL);                // Name

/* 15 */   timeDelayTextField      = new TextFieldObject(vars.GetTimeBetweenGenerations(), // Current value
                                           MIN_TIME_DELAY,                      // Lower bound
                                           MAX_INT,                             // Upper bound
                                           TIME_BETWEEN_GENERATIONS);           // Name

/* 16 */   probabilityTextField    = new TextFieldObject(vars.GetProbability(), // Current value
                                           MIN_PROBABILITY,             // Lower bound  
                                           MAX_PROBABILITY,             // Upper bound
                                           PROBABILITY);                // Name

/* 17 */   numRowsTextField        = new TextFieldObject(vars.GetRows(), // Current value
                                           vars.GetMinNumberOfRows(),  // Lower bound
                                           vars.GetMaxNumberOfRows(),  // Upper bound
                                           ROWS);

/* 18 */   numColumnsTextField     = new TextFieldObject(vars.GetColumns(), // Current value
                                           vars.GetMinNumberOfColumns(),  // Bounds
                                           vars.GetMaxNumberOfColumns(),  // Bounds
                                           COLUMNS);                      // Name.

        // Now add everybody:
            
        // Go from one generation to another via mouse click or
        // time delay?
            
           add(buttonOrTimeLabel);  /* Label: info about how we go
                                     from generation to generation. */
           add(byMouseClickButton); // Via mouse click?
           add(byTimeDelayButton);  // Via a time delay?

        // How do we decide the size of the board?
            
           add(byRowsAndColumnsButton);
           add(byPixelsButton);
           
        // If a time delay, how long?

           add(timeDelayTextField);   // Text field: inputs number
           add(millisecondsLabel);    // Label, "milliseconds"

        // Input rows & columns & "pixels per cell" textfield:

           add(pixelsPerCellTextField);
           add(rowColInfoLabel);      // Label: General info, "how many 
                                    // rows & columns"
           add(pixelsLabel);          // Label for pixels info: how
                                    // many per cell side?
           add(inputColsLabel);       // Label: "Rows"
           add(inputRowsLabel);       // Label: "Columns"
           add(numRowsTextField);     // Input text field for rows
           add(numColumnsTextField);  // Input text field for columns
            
        // Input "live & "dead" via mouse clicks or probalistic?

           add(inputByMouseClickOrProbabilityLabel); /* Label: clicks 
                                                        on "live" cells,
                                                        or via  probalistic
                                                        means?              */

           add(clickToSayWhoIsAliveAndDeadButton);  // Button: by mouse 
                                                    // clicks
           add(probalisticButton);    // Button: probalistically
           add(probabilityTextField); // Text field: input probability.
           add(asPercentLabel);       // Label: "(as a percent (1-100))"
        
           add(okButton);
           add(quitButton);

        // Set each button's cursor:
           quitButton.                       setCursor(vars.GetHandCursor());
           okButton.                         setCursor(vars.GetHandCursor());
           byMouseClickButton.               setCursor(vars.GetHandCursor());
           byTimeDelayButton.                setCursor(vars.GetHandCursor()); 
           byRowsAndColumnsButton.           setCursor(vars.GetHandCursor());
           byPixelsButton.                   setCursor(vars.GetHandCursor());
           clickToSayWhoIsAliveAndDeadButton.setCursor(vars.GetHandCursor());
           probalisticButton.                setCursor(vars.GetHandCursor());

        // Set up the action listeners:

        // Go from one generation to another via mouse click or
        // time delay?

           byMouseClickButton.addActionListener(this);
           byTimeDelayButton.addActionListener(this);
            
        // How do we decide the size of the board?

           byRowsAndColumnsButton.addActionListener(this);
           byPixelsButton.addActionListener(this);
           pixelsPerCellTextField.addActionListener(this);
        // If time delay, how long?
            
           timeDelayTextField.addActionListener(this);

        // Input number or rows & columns:

           numRowsTextField.addActionListener(this);
           numColumnsTextField.addActionListener(this);

        // Input "live & "dead" via mouse clicks or probalistic?

           clickToSayWhoIsAliveAndDeadButton.addActionListener(this);
           probalisticButton.addActionListener(this);

        // If probalistic, what probability?

           probabilityTextField.addActionListener(this);

        // The "OK" button, i.e., "use this input":
           okButton.addActionListener(this);
           quitButton.addActionListener(this);

           setButtonColors();  // Which buttons are "default?"

    // Now: The setting of the Grid Bag Layout is painfully messy and
    // bothersome.

           GridBagLayout gridbag = new GridBagLayout();
           setBackground(Color.gray);
           GridBagConstraints constraints = new GridBagConstraints();
           setLayout(gridbag);

        /* Now handle the individual UI components. This code is 
           long and tedious, so we here describe the grid in ASCII.

           Remember, columns and rows are switched from order below in actual code.
        */
/*
0,0                     0,1                 0,2         0,3
Text message: click on a button or set a time delay?
            
1,0                     1,1                 1,2         1,3
Button: click        Button: time delay    time input  text: "milliseconds"

2,0                     2,1                 2,2         2,3
Text message: Input by rows and columns? Give ranges.
    
3,0                     3,1                 3,2         3,3
Text message: Or input by pixels per cell?
4,0                     4,1                 4,2         4,2
Button: by rows     Button: by      pixels per cell
& columns           pixels          text field
            
5,0                     5,1                 5,2         5,3
Rows                    row input        Columns     col input

6,0                     6,1
Text message: input board by hand, or let the system decide probalistically?

7,0                     7,1                 7,2
Button: by hand         Button: probalistically
                                        text field: probability
            
8,0                     8,1
        "OK" button
*/
// Need the next two in setting weights in Grid Bag Layout:

           int numberOfColumnComponents = 100 / 12;
           int numberOfRowComponents = 100 / 18;

    // The setting of this Grid Bag Layout is bothersome There are
    // sixteen components total.

        // First the text, "click on a button or set a time delay," spanning four columns.
           buildConstraints(constraints, 0,      // Column one
                                         0,      // Row one
                                         4,      // Eats four columns
                                         1,      // Eats all columns, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.BOTH;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(buttonOrTimeLabel, constraints);  // Set contraints for
                                                            // "time delay or button click" text.
        // Next, "click on a button" button
           buildConstraints(constraints, 0,      // Column one
                                         1,      // Row two
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(byMouseClickButton, constraints);  // Set contraints for "time
                                                        // delay or button click" text.
// For time delay button
           buildConstraints(constraints, 1,      // Column two
                                         1,      // Row two
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(byTimeDelayButton, constraints); 

// For time delay text input field
           buildConstraints(constraints, 2,      // Column three
                                         1,      // Row two
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.EAST;
           gridbag.setConstraints(timeDelayTextField, constraints); 

// For time delay string "milliseconds":
           buildConstraints(constraints, 3,      // Column four
                                         1,      // Row two
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.EAST;
           gridbag.setConstraints(millisecondsLabel, constraints); 

        // Text about inputing columns and rows
           buildConstraints(constraints, 0,      // Column one
                                         2,      // Row three
                                         4,      // Eats four columns
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents, // Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.BOTH;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(rowColInfoLabel, constraints);
            
        // Text about inputing by pixels
           buildConstraints(constraints, 0,      // Column one
                                         3,      // Row four
                                         4,      // Eats four columns
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents, // Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.BOTH;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(pixelsLabel, constraints);            
            

        // Input by rows & columns button?
           buildConstraints(constraints, 0,      // Column one
                                         4,      // Row five
                                         1,      // Eats one column
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(byRowsAndColumnsButton, constraints);
            
        // Input by pixels button
           buildConstraints(constraints, 1,      // Column two
                                         4,      // Row five
                                         1,      // Eats one column
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(byPixelsButton, constraints);
            
        // Pixels per cell text field
           buildConstraints(constraints, 2,      // Column one
                                         4,      // Row five
                                         1,      // Eats one column
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(pixelsPerCellTextField, constraints);            

        // Row label, saying, "input rows"
           buildConstraints(constraints, 0,      // Column one
                                         5,      // Row six
                                         1,      // Eats one column
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(inputRowsLabel, constraints);

        // input field for rows
           buildConstraints(constraints, 1,      // Column two
                                         5,      // Row six
                                         1,      // Eats one row
                                         1,      // Eats one columns, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(numRowsTextField, constraints);

        // input column label
           buildConstraints(constraints, 2,      // Column three
                                         5,      // Row six
                                         1,      // Eats one row
                                         1,      // Eats one column, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.EAST;
           gridbag.setConstraints(inputColsLabel, constraints);

        // Actual column input field
           buildConstraints(constraints, 3,      // Column four
                                         5,      // Row six
                                         1,      // Eats one row
                                         2,      // Eats two columns, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.NORTHEAST;
           gridbag.setConstraints(numColumnsTextField, constraints);

        // Label field, "input probalistically or via mouse clicks?"
           buildConstraints(constraints, 0,      // Column one
                                         6,      // Row seven
                                         4,      // Eats four colmns
                                         1,      // Eats one row
                                         numberOfColumnComponents,
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.BOTH;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(inputByMouseClickOrProbabilityLabel, constraints);

        // Button: via mouse click
           buildConstraints(constraints, 0,      // Column one
                                         7,      // Row eight
                                         1,      // Eats one column
                                         1,      // Eats one row
                                         numberOfColumnComponents,// Twelve such components.  
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(clickToSayWhoIsAliveAndDeadButton, constraints);

        // Button: via probablistic means
           buildConstraints(constraints, 1,      // Column two
                                         7,      // Row eight
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.VERTICAL;
           constraints.anchor = GridBagConstraints.WEST;
           gridbag.setConstraints(probalisticButton, constraints);
            
        // Text field: probability.
           buildConstraints(constraints, 2,      // Column three
                                         7,      // Row eight
                                         1,      // Eats one column
                                         1,      // Eats one row, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.EAST;
           gridbag.setConstraints(probabilityTextField, constraints);
            
        // Label: "(as a percent (1-100))"
           buildConstraints(constraints, 3,      // Column four
                                         7,      // Row eight
                                         1,      // Eats one row
                                         2,      // Eats two columns, and ...
                                         numberOfColumnComponents,// Twelve such components.
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING); 
           constraints.fill = GridBagConstraints.NONE;
           constraints.anchor = GridBagConstraints.NORTHEAST;
           gridbag.setConstraints(asPercentLabel, constraints);

        // OK Button:
           buildConstraints(constraints, 0,      // Column one
                                         8,      // Row nine
                                         4,      // Eats all columns
                                         0,      // Eats one row,
                                         0,      // Eats all columns
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.HORIZONTAL;
           constraints.anchor = GridBagConstraints.CENTER;
           gridbag.setConstraints(okButton, constraints);
        
        // Lastly the "Quit" button, at very bottom, spanning four columns.
           buildConstraints(constraints, 4,      // Column one
                                         8,      // Row ten
                                         2,      // Eats all columns
                                         0,      // Eats one row,
                                         0,      // Eats all columns
                                         numberOfRowComponents,// Sixteen total.
                                         SMALL_PADDING,
                                         SMALL_PADDING);
           constraints.fill = GridBagConstraints.HORIZONTAL;
           constraints.anchor = GridBagConstraints.CENTER;
           gridbag.setConstraints(quitButton, constraints);    
    }

/* **********************************************************************
    Get local copy of variables.
********************************************************************** */
      
    protected void SetVars(Vars vars)
    {
        this.vars = vars;
    }
/* **********************************************************************
    Next sets button colors depending upon whom is currently selected.
********************************************************************** */

    private void setButtonColors()
    {
        if (vars.GetWaitForTimeDelay())
        {
            byMouseClickButton.setBackground(DE_SELECTED_BUTTON_COLOR);
            byTimeDelayButton.setBackground(SELECTED_BUTTON_COLOR);
        }
        else
        {
            byMouseClickButton.setBackground(SELECTED_BUTTON_COLOR);
            byTimeDelayButton.setBackground(DE_SELECTED_BUTTON_COLOR);
        }
        if (vars.GetClickLiveCellsViaMouse())
        {
            clickToSayWhoIsAliveAndDeadButton.setBackground(SELECTED_BUTTON_COLOR);
            probalisticButton.setBackground(DE_SELECTED_BUTTON_COLOR);
        }
        else
        {
            clickToSayWhoIsAliveAndDeadButton.setBackground(DE_SELECTED_BUTTON_COLOR);
            probalisticButton.setBackground(SELECTED_BUTTON_COLOR);
        }
        if (inputByRowsAndColumns)
        {
            byRowsAndColumnsButton.setBackground(SELECTED_BUTTON_COLOR);
            byPixelsButton.setBackground(DE_SELECTED_BUTTON_COLOR);
        }
        else
        {
            byRowsAndColumnsButton.setBackground(DE_SELECTED_BUTTON_COLOR);
            byPixelsButton.setBackground(SELECTED_BUTTON_COLOR);
        }
    }

/* **********************************************************************
    Routine < actionPerformed > follows. This in a bit messy due to the
    verification of input.
********************************************************************** */
 
    public void actionPerformed (ActionEvent e)
    {
        if (vars == null)
        {
            System.out.println("Vars null, actionPerformed, HowGameIsPlayedScreen");
            System.exit(0);
        }
        else                                        // Variables at least are good. 
            if (!(e.getSource() instanceof Button))
        {
            error.ShowMessage(UNRECOVERABLE_ERROR + " " +
                              INPUT_NOT_A_BUTTON + ", " +
                              " < HowGameIsPlayedScreen : actionPerformed >",
                              OK);
        }
        else    // All is well.
        {
            String label = ((Button)e.getSource()).getLabel();
            if (label.equals(OK))
            {
                if (OKButtonSucceeded())
                {
                   setVisible(false);
                }
            }   // End "OK" button's code.
            else if (label.equals(BY_MOUSE_CLICK))
            {
                vars.SetWaitForTimeDelay(false);
                if (verifyInput(timeDelayTextField))            // Input good?
                {
                    // Save current value, all the same:

                    vars.SetTimeBetweenGenerations(timeDelayTextField.getCurrentVal());

                    timeDelayTextField.setText(INVALID);        // Remove this field.
                    setButtonColors(); // Re-set, as selected button may have changed.
                }
            }
            else if (label.equals(BY_TIME_DELAY))
            {
                vars.SetWaitForTimeDelay(true);
                if (verifyInput(timeDelayTextField))  // Input good?
                {
                    vars.SetTimeBetweenGenerations(timeDelayTextField.getCurrentVal());

                    setButtonColors(); // Re-set, as selected button may have changed.
                }
            }
            else if (label.equals(INPUT_VIA_PROBALISTIC))
            {
                vars.SetClickLiveCellsViaMouse(false);

                if (verifyInput(probabilityTextField))  // Input good?
                {
                    vars.SetProbability(probabilityTextField.getCurrentVal());
                    setButtonColors(); // Re-set, as selected button may have changed.
                }
            }
            else if (label.equals(INPUT_ALIVE_OR_DEAD_BY_MOUSE_CLICK))
            {
                vars.SetClickLiveCellsViaMouse(true);

                if (verifyInput(probabilityTextField))  // Input good?
                {
                    // Save value, all the same:
                    vars.SetProbability(probabilityTextField.getCurrentVal());

                    probabilityTextField.setText(INVALID); // Remove this field.
                    setButtonColors(); // Re-set, as selected button may have changed.
                }
            }
            else if (label.equals(BY_ROWS_AND_COLUMNS))
            {
                inputByRowsAndColumns = true;

                if (verifyInput(numColumnsTextField) &&
                    verifyInput(numRowsTextField))
                {
                    setBoardParameters(); // Gets current board size & sets things
                                          // like pixels per cell (next).
                    // Update the next:

                    pixelsPerCellTextField.setText("" + vars.GetPixelsPerCell());

                    // Set value of pixels per cell we will have:
                    setButtonColors(); // Re-set, as selected button may have changed.
                }
            }
            else if (label.equals(BY_PIXELS))
            {
                inputByRowsAndColumns = false;  // User sets pixels per cell side.

                if (verifyInput(pixelsPerCellTextField))  // Input good?
                {
                    setBoardParameters(); // Gets current board size
                    setButtonColors();    // Re-set, as selected button may have changed.

                    numRowsTextField.setText("" + vars.GetRows());
                    numColumnsTextField.setText("" + vars.GetColumns());
                }
            }
            else if (label.equals(QUIT))
            {
                quit = true;       // User chose not to play.
                setVisible(false); // Time to get out.
                return;
            }
            else    // Don't recognize the button? This is nonsense.
            {
                error.ShowMessage(UNRECOVERABLE_ERROR + " " +
                                  UNRECOGNIZED_BUTTON + " " +
                                  "HowGameIsPlayedScreen: " +
                                   "\"" + label + ".\" ",
                                    OK);
            }
        }
    }   // End routine < actionPerformed >.

/*******************************************************************
Next is a quick routine to set the insets.
******************************************************************** */

    public Insets getInsets()
    {
        return new Insets(DEFAULT_INSET, DEFAULT_INSET, 
                          DEFAULT_INSET, DEFAULT_INSET);
    }

/*******************************************************************
Next sets the size of the board. Note the routine does this 
regardless of whether we input rows and columns explicitely, or
the number of pixels per cell. 

In the case of number of pixels per cell, the routine makes the
board as big as possible.

This modifies global data.  Public, as it is called from class < UI >.
******************************************************************** */

    public final void setBoardParameters()
    {
        if (inputByRowsAndColumns)  // We are given explicit row and column information.
        {
            vars.SetColumns(numColumnsTextField.getCurrentVal());
            vars.SetRows(numRowsTextField.getCurrentVal());
            // Now: set pixels per cell.
            int colPixels = vars.GetBoardWidth() / vars.GetColumns();   // Note: integer
            int rowPixels = vars.GetBoardHeight() / vars.GetRows();     // division.

            vars.SetPixelsPerCell(Math.min(rowPixels, colPixels));
        }
        else   // We have been told how many pixels to allocate per cell side.
        {
            vars.SetPixelsPerCell(pixelsPerCellTextField.getCurrentVal());
            vars.SetColumns(vars.GetBoardWidth() / vars.GetPixelsPerCell());// Note: integer
            vars.SetRows(  vars.GetBoardHeight() / vars.GetPixelsPerCell());// division.
        }
        // Tell the User Interface our values; display them:

        numRowsTextField.setText("" + vars.GetRows());
        numColumnsTextField.setText("" + vars.GetColumns());
        pixelsPerCellTextField.setText("" + vars.GetPixelsPerCell());
    }   // End routine < setBoardSize() >.

/*******************************************************************
Next is the "verify input good" routine. We are very rigourous.
******************************************************************** */  

    private final boolean verifyInput(TextFieldObject theTextFieldObject)
    {
        boolean inputGood = true;  /* Set "false" if the user gives bad
                                      input -- such as inputting too large 
                                      or small of numbers, or junk like 
                                      "sgf" for a number field. 
                                     */
        PopupWindow inputError; // For user input exceptions.

        inputError = new PopupWindow(parentFrame, 
                                     objects.GetScreenLocations(), 
                                     INPUT_ERROR_STRING);// For user-input
                                                         // errors like
                                                         // "rows = -1."
         
        int currentVal = theTextFieldObject.getCurrentVal();  // Set this for now.
        int minVal     = theTextFieldObject.getMinVal();
        int maxVal     = theTextFieldObject.getMaxVal();

        // Now for the real dirt of this routine. First get value from
        // the passed-in text field.

        String text = theTextFieldObject.getText();   // What's in the text field's
                                                      // window?

        if (text.equals(INVALID))   // Field has been nulled out. Re-instate it.
        {
            theTextFieldObject.setText(""+ currentVal);
        }
        else    // Get the text & verify it:
        {
            int answer = -1;

            try
            {
                answer = Integer.parseInt(text);
                if ((answer < minVal) || (answer > maxVal)) 
                {
                    throw new IndexOutOfBoundsException();
                }
            }
            catch(NumberFormatException exception) // The user gave bad input.
            {
                inputError.ShowMessage(MALFORMED_INPUT_COLON + " " +
                                       theTextFieldObject.toString(),   // Who?
                                       OK);                             // Button name.
                inputGood = false;
            }
            catch(IndexOutOfBoundsException exception) // The user did something naughty.
            {
                inputError.ShowMessage(INPUT_OUT_OF_RANGE_COLON + " " + 
                                       theTextFieldObject.toString() + " " +
                                       GOES_FROM + " " + minVal + " " + TO + " " +
                                       maxVal + ". ",
                                       OK);// Button.
            
                inputGood = false;
            }
            catch(Exception e)
            {
                inputError.ShowMessage("some crash " + e.toString() +
                                       theTextFieldObject.toString(),   // Who?
                                       OK);
                inputGood = false;
            }
            finally
            {
                if (!inputGood) // The user gave bad input.
                {
                    theTextFieldObject.setText(""+ currentVal); // Re-set current val.
                    theTextFieldObject.requestFocus();          // And focus on the field
                    theTextFieldObject.selectAll();             // Color it
                }
                else    // All is well. See to it our caller knows.
                {
                    theTextFieldObject.setCurrentVal(answer); // Save the new value.
                }
            }
        }
        return (inputGood);
    }

/* ********************************************************
    Have we pushed the OK button?
   *********************************************************/ 
public boolean OKButtonSucceeded()
{
    boolean succeeded;
// Get the info from the text fields of game parameters:

    succeeded = verifyInput(numRowsTextField)     &
                verifyInput(numColumnsTextField)  &
                verifyInput(probabilityTextField) & 
                verifyInput(timeDelayTextField)   &
                verifyInput(pixelsPerCellTextField);

    if (succeeded)  // Input good?
    {
        setBoardParameters(); // Sizes board.
        setButtonColors();    // Re-set, as selected button may have changed.
        
        vars.SetTimeBetweenGenerations(timeDelayTextField.getCurrentVal());
        vars.SetProbability(probabilityTextField.getCurrentVal());      
    }
    return succeeded;
}

/* ********************************************************
    The next inner class makes certain things simpler, as
    several fields have common charactaristics: max value,
    min value, current value, and a name. It's ultimately more
    code, but simpler.
 
    Defined as inner class, as no one outside this class uses it.
   *********************************************************/ 

    private class TextFieldObject extends TextField
    {
        private int min, max, currentVal;
        private String name;

        TextFieldObject(int currentVal, int min, int max, String name)
        {
            super("" + currentVal);
            this.min        = min;
            this.max        = max;
            this.currentVal = currentVal;
            this.name       = name;
        }
        public String toString()    // Over-ridden.
        {
            return name;
        }
        public int getMinVal()
        {
            return min;
        }
        public int getMaxVal()
        {
            return max;
        }
        public int getCurrentVal()
        {
            return currentVal;
        }
        public void setCurrentVal(int currentVal)
        {
            this.currentVal = currentVal;
        }
    }

/* *****************************************************************
    We use Grid Bag Layouts.
   ***************************************************************** */ 

    private final void buildConstraints(GridBagConstraints gbc, 
                          int gx, 
                          int gy, 
                          int gw, 
                          int gh, 
                          int wx, 
                          int wy,
                          int padx,
                          int pady)
    {
        gbc.gridx       = gx;
        gbc.gridy       = gy;
        gbc.gridwidth   = gw;
        gbc.gridheight  = gh;
        gbc.weightx     = wx;
        gbc.weighty     = wy;
        gbc.ipadx       = padx;
        gbc.ipady       = pady;
    }

    public String toString()
    {
        return "class HowGameIsPlayedScreen";
    }
    
    public boolean playGame()
    {
        return !quit;
    }
}