--------------------------------------------------------------------------------
SELECT.TXT -- This text file comes with the program: SELECT.PRG, from the
BORBBS file: SELECT.ZIP. The contents include the complete article from
Technotes (March, 1991): 'Betcha Can't Pick Just One', and some notes (at 
the end) from Ken Mayer on modifications to the program. (The original program
was heavily modified from the one in the article to the one attached.)
--------------------------------------------------------------------------------

Betcha Can't Pick Just One
Lena Tjandra

Popups are a welcome addition to the functionality of the dBASE language. 
By their nature, once you press Return on a highlighted selection in the
popup, it disappears and an action is taken.  You cannot make more than one
selection at a time, but there is an alternate and sometimes preferable way
of utilizing a popup.   

Suppose you have a list of salespersons, and you would like to generate a
year-to-date sales report on specific salespersons only.   You'd ideally
like to go through a popup list, pressing Return (or some other key to mark
the records) on those you want selected for a certain operation.  When you
are done, a specific exit key would clear the popup and perform your task. 
How would you do this and still incorporate the use of a popup?  The
program that follows shows you how.

The purpose of this program is to create a popup from which the user can
make multiple selections.  The popup is created from values stored in a
database.  When the user makes a selection, the popup is redefined with a
character marker that indicates a selection.  At the same time, a logical
true (.T.) value is replaced into the field, "Selected" which corresponds
to the selected option in the database.  If an option on the popup is
de-selected, then a logical false (.F.) value is replaced into the
"Selected" field and the popup is redefined without the character marker.

If your popup contains a lot of options to choose from, then your best bet
is to store them in a database and create the popup based on the values in
that database.  There are several good reasons for doing this such as code
brevity, modularity, and clarity.  For instance, instead of having to
DEFINE BARs for each option in the popup, you can define all the BARs in
just a few statements as shown on lines 19 - 22.  Second, it makes the
program more modular because  now you can modify the options through the
database rather than through the program, thus, giving your program more
flexibility.  Third, you can create an additional field in the database to
store marked selections, thus, saving you from declaring an array of
unnecessary size.  Furthermore, it makes the goal easier to process. 
Suppose you stored selected values in an array.  The consequence would be
having to look in each element to see which options have been selected and
create a macro expression for the report.  If the values were marked in the
database by assigning .T. to a field called SELECTED, then a single command
will suffice:

REPORT FORM sales FOR selected

I would also like to point out a few tips contained in this program.  You
may  wonder why a SHOW POPUP on line 35 is issued before an ACTIVATE
POPUP.  For those of you who have worked with popups a lot, you may notice
that the popup will flicker very quickly when control is returned to the
ACTIVATE POPUP statement or when the popup is re-activated.  By issuing a
SHOW POPUP, we can alleviate the flickers.

Lines 53 - 54 may seem peculiar, but since the database has an active
index, we can only move to the record relative to the top of the database. 
However,  if the database were in natural order, we can reference it
directly with a  GOTO <record no> statement.  Another method is to do a
SEEK, but doing a SKIP is the only way that works with both an indexed or
un-indexed database.

Additionally, you may also notice that the F9 and F10 keys have been
defined  as hotkeys to allow the user the choice of selecting or
de-selecting all the  options on the popup at once.  This brings me to one
final point.  In the procedure entitled PSelect, the bar is redefined, but
it is not necessary to deactivate and reactivate the popup.  Since this
procedure was called from an ON SELECTION POPUP, the ON SELECTION takes
care of reactivating the popup with the current bar definitions.  On the
other hand, the procedure Sel All was called from an ON KEY, so we need to
deactivate the popup manually as on line 77, and reactivate it again in
order for the new bars to display. 

 1 CLEAR
 2 SET STATUS OFF
 3 SET TALK OFF
 4  
 5 * Store ASCII value of {down-arrow} and {Esc} to variables
 6 dnarrow = CHR(24)
 7 escape = 27
 8 
 9 * Open database
10 SELECT 1
11 USE salesrep ORDER name
12 
13 * Define popup, pop1
14 DEFINE POPUP pop1 FROM 5, 15 TO 23, LEN(name) + 15
15 
16 bar cnt = 1
17 
18 * Define bars of popup from the "name" field in database
19 SCAN
20  DEFINE BAR bar cnt OF pop1 PROMPT TRIM(Name) + IIF(selected, CHR(17),
"")
21  bar cnt = bar cnt + 1
22 ENDSCAN
23 
24 * Define popup action
25 ON SELECTION POPUP pop1 DO PSelect
26 
27 * Define hotkey <F10> for selecting all options
28 ON KEY LABEL F10 DO Sel All WITH .T.
29 
30 * Define hotkey <F9> for de-selecting all options
31 ON KEY LABEL F9 DO Sel All WITH .F.
32 
33 * Activate popup
34 DO WHILE LASTKEY() <> escape 
35   SHOW POPUP pop1
36   ACTIVATE POPUP pop1
37 ENDDO
38 
39 CLEAR
40 CLEAR ALL
41 SET STATUS ON
42 SET TALK ON
43 
44 
45 PROCEDURE pselect
46 
47 * Redefine bar based on selection/de-selection
48 DEFINE BAR BAR() OF pop1 PROMPT IIF(RIGHT(PROMPT(), 1) = CHR(17),;
49   SUBSTR(PROMPT(), 1, AT(CHR(17), PROMPT()) - 1), PROMPT() + CHR(17))
50 
51 * Change the "Selected" field to .T. if option has been selected 
52 * or .F. if option has been de-selected.
53 GO TOP
54 SKIP BAR() - 1
55 REPLACE selected WITH IIF(selected, .F., .T.)
56 
57 * Move highlight in popup down to the next option
58 KEYBOARD dnarrow
59 
60 RETURN
61 
62 PROCEDURE Sel All
63 
64 PARAMETER s key
65 
66 * Change all values in the "Selected" field .T. or .F. in database
67 REPLACE ALL Selected WITH s key
68 
69 bar cnt = 1
70 
71 * Re-define bars of popup from the "Name" field in database
72 SCAN
73   DEFINE BAR bar cnt OF pop1 PROMPT TRIM(name) + IIF(selected, CHR(17),
"")
74   bar cnt = bar cnt + 1
75 ENDSCAN
76 
77 DEACTIVATE POPUP
78 
79 RETURN

--------------------------------------------------------------------------------
End of article.
--------------------------------------------------------------------------------

The program described above, is all well and good, but I couldn't resist
reprogramming the whole thing, adding my own touches, and making it easier
to use. So, the program file: SELECT.PRG is attached.

This program assumes that there is a field in the currently open database, 
called: SELECT, which is a logical field. It does not perform error checking,
and will bomb if this field does not exist, or if no database is open when
you run the program. Otherwise, it is about as 'black-box' as I could make it, 
requiring several parameters to function properly. I added Jay Parsons' routine
COLOROF() to this, so that I could save the current settings and restore the
environment as best as possible to it's original state before calling the
the SELECT program.

Hope this is useful. I know I have used a different form of this in one system,
but it was hardcoded, and handle a few other things differently. I learned
a lot from this, though. Ken Mayer (KENMAYER)

--------------------------------------------------------------------------------
End of File: SELECT.TXT
--------------------------------------------------------------------------------

