═══ 1. Introduction ═══ As an interpreted, high level language, REXX is supposed to be one of the easiest languages to use. This means that a programmer can write useful programs with a minimal investment of time and effort. Unfortunately, REXX has one very big drawback; its facilities to get input and output from an enduser are positively primitive. It can do little more than poll the command line (ie, the enduser has to type in his input, one line at a time), and display text messages to that same command line. REXX certainly doesn't support any of the features that OS/2's Presentation Manager makes possible, such as using the mouse and keyboard to manipulate scrolling lists of text, menus, sliders, buttons, etc, as well as being able to arrange all of these in multiple windows that also can be manipulated with the mouse and keyboard. With such PM controls and dialogs, a programmer can create a much easier to use, and more sophisticated, interface. Wouldn't it be nice to be able to combine PM's flexibility with REXX's simplicity? Sure it would, and that's why there are a few products that "extend" REXX to give it a PM interface (ie, add new REXX commands that interface to PM, by having the REXX interpreter call C compiled code in custom Dynamic Link Libraries which implements those new commands). Rexx Dialog is one more such product; except that it's free, and it's small and memory efficient because it doesn't try to do too much. It's sort of my version of VREXX and PMREXX, but a lot more flexible in the way that it lets you create and manage a PM interface for your REXX script. Using Rexx Dialog, you can quickly create a PM program in REXX. It is hoped that, by making a tool such as Rexx Dialog freely available (and some of the other freebies that I've created such as FILEREXX), other programmers will continue that spirit and create even more OS/2 native software (which is very much needed right now) and freely distribute such. Some of the words in this manual are highlighted in bold text, such as Group Type. These are words that refer to something that you have to setup in your REXX script to use Rexx Dialog to create and manage a PM interface. Other words are in colored text such as RXVAL. These refer to actual REXX variables in your script (ie, the names of variables). Underlined words, such as RXSAY, refer to actual REXX commands created by Rexx Dialog, which your REXX script calls to create and manage a PM interface. Some words are in colored text such as Read This are meant to be emphasized. Words in italics refer to aspects of OS/2. ═══ 2. License ═══ Rexx Dialog (comprised of the files RXDLG.DLL, RX.EXE, RX.INF, RXCAPP.INF and all example REXX scripts written by Jeff Glatt) is copyright 1995 by Jeff Glatt. Rexx Dialog is freely redistributable. It can be used by and distributed along with any other program be it a shareware, freeware, or even commercial product, as long as this documentation is included with the program. There are no pagan user fees, surreptitious financial charges, or other devious capitalist trickery associated with the use of these files. There are also no warranties of any kind with this software. If swallowed, induce vomiting immediately (by contemplating the aesthetics of Windows). You can do anything you like with this archive, except reverse engineer or modify RXDLG.DLL, RX.EXE, RX.INF, or RXCAPP.INF, nor can you poke it with a sharp stick. But you can print it out on flimsy paper stock, wrap it around your privates, and go to work like that as long as you don't blame the author for your actions. You are not allowed to think nasty thoughts about the author, even if the software somehow causes the erasure of your collection of smutty picture files. You may have more or less protections in certain states of the union, depending upon how far your local politicians bend over for a bribe from some business lobbyist. Just remember that I have no money, so don't bother suing me for any damages as a result of using this software. Tell your greasy lawyer to go after IBM, and make sure that you pick 12 really stupid pinheads for the jury. I can be contacted at: 6 Sycamore Drive East New Hartford, NY 13413 (315) 735-5350 Report bug fixes, or shut up. Whose says that writing software licenses is no fun? ═══ 3. Initial Setup and Requirements ═══ There are 2 files that comprise the Rexx Dialog facility; RX.EXE and RXDLG.DLL. These must be present upon any system that runs scripts which utilize Rexx Dialog's new commands to create and manage a PM interface. Of course, the OS/2 REXX Interpreter must also be installed upon the system (although PMREXX does not need to be -- especially now that you have Rexx Dialog). RX.EXE is an executable that you use to start up your REXX script. At an OS/2 command prompt, you type RX, followed by the name of your REXX script (with full path if necessary). For example, to start the REXX script "blort.cmd", you would type: rx blort and then press ENTER. Note: It's not necessary to type the .exe extension on rx.exe, nor the cmd extension on the script name. You must use RX.EXE to start (and run) your REXX script, or the REXX interpreter won't understand the special, new commands that Rexx Dialog makes available to your script, and you'll get an error message saying that "The name specified is not recognized as an internal or external command, operable program, or batch file". RX.EXE takes care of all of the details of telling the REXX interpreter what the new commands are (so that your script can use them) and also runs your script. RX.DLL is a Dynamic Link Library used by RX.EXE. RX.EXE must be able to find this DLL, so you should copy it to some place that is specified on the LIBPATH statement of your config.sys file. A good place is C:\OS2\DLL. Also, it's recommended that RX.EXE be copied to some place that is specified by the PATH statement. A good place is C:\OS2. If you would like to setup your script so that it runs by clicking upon a Desktop icon (ie, object), that's easy to do. Open the Templates folder on the Desktop. Drag the Program object to whichever place you want to put the icon for your script, and release the mouse button (ie, drop the icon there). A Notebook should pop up, with the Settings page displayed. In the Path and Filename entry, type RX.EXE. If you didn't copy RX.EXE to some place specified in your config.sys PATH, then you'll need to specify the complete path, for example, C:\OS2\RX.EXE. Make sure that RXDLG.DLL is copied to some place specified in your config.sys LIBPATH (or you can usually place it in the same directory as the scripts that use Rexx Dialog). In the Parameters field of the Notebook, type the name of your REXX script. Again, you may need to specify the full path. Now whenever you click upon that icon, your script will run, and be able to use Rexx Dialog's new commands. Repeat the above process with every REXX script for which you'd like to setup a Desktop icon, and which will use Rexx Dialog. Note: It doesn't matter whether you launch your REXX script from the OS/2 command prompt (as described above) or a Desktop icon. Your script will run as if it were a real PM program regardless. ═══ 4. Rexx ═══ REXX is a computer language. It's interpreted, like BASIC, which means that you simply write your program as an ordinary text file, and some interpreter runs that text file directly. There's no need for you to compile and link your source code into an executable program. Your text file *IS* your program (and can be created with any text editor such as the OS/2 System Editor, or the Enhanced Editor). So, REXX is a script language. But, it has lots of features, including variables, string processing, looping, etc. Consult the "Rexx User's Guide" on the OS/2 PDK, or the "Rexx Procedures/2" online book for a description of fundamental things that can be done with REXX. The REXX interpreter is built into OS/2. That's why you can run a REXX script (ie, text file containing REXX instructions) just by typing its name from an OS/2 Command Prompt window. OS/2 programs may be written to also start up REXX scripts. RX.EXE is one such program. It is used to start your REXX script so that your script has 9 special commands to call in order to create and manage a PM interface. There's a very important difference between running a REXX script using RX.EXE, and running a script from a Command Prompt window. When you run a REXX script using RX.EXE, RX.EXE takes care of all of the details of letting the REXX interpreter know what the new commands are. Your REXX script can immediately use those new commands. RX.EXE also helps your script create and manage the PM interface that your script specifies. RX.EXE does not pass any args to your REXX script. Note: It's advisable to first read the OS/2 documentation on REXX, and experiment with the standard commands and features. The REXX examples here may use some standard features without explaining them. Mostly, the examples will illustrate the 9, special commands that Rexx Dialog makes available to create and manage a PM interface. ═══ 5. Rexx Dialog Commands ═══ The 9 special Rexx Dialog commands that your script can call to create and manage a PM interface all begin with the 2 letters RX. Here are the 4 commands: RXACTIVE RXDLG RXERR RXFILE RXHELP RXQUERY RXSAY RXSET RXVERS You can begin a line in your REXX script with one of these commands. Then, when the script is run, the REXX interpreter executes the command when it gets to that line. Most of the commands will have arguments. This is just additional text that you place after the command, on the same line. Arguments modify the way that a Rexx Dialog command works, or provide necessary additional information for the command to use. Note: It's OK to put blank spaces before and after commands, and inbetween arguments. This makes your script easier for you to read. All Rexx Dialog commands return either a string or number (depending upon which you specify via RXERR, but some commands always return strings). The return is stored in the special REXX symbol RC. As each command is issued, RC reflects what that command returns. The return usually tells you whether a command worked or failed (although sometimes the return provides other info instead such as which button was used to dismiss a RXSAY box). In the case of a command that could fail as a result of something that goes wrong within the command, you should always check RC after issuing that command. Alternately, since all Rexx Dialog commands set the REXX FAILURE or ERROR flags for any possible errors, you can SIGNAL ON ERROR or SIGNAL ON FAILURE to an appropriate place in your REXX script to handle such an error situation. An RC of 0 (for error numbers) or an empty string, ie "" (for error strings) is considered to be a successful return. The following descriptions of each command tell what the template for the command is (ie, how you notate it in your script), what the command does, what the arguments are, what it returns to your REXX script, and examples of using the command. ═══ 5.1. RXACTIVE ═══ Template RXACTIVE Description This command determines which open window is the active one, and sets the REXX variable RXWIND to that window's title. It also sets the REXX variables RXID and RXSUBID to the Group # and Control # that have the focus. For example, if the user happened to be using the first control of the first Group in a window titled "Window 1", then RXWIND is 'Window 1', RXID is 1, and RXSUBID is 1. If the window itself has the focus (ie, the window is active but the user has not activated any particular control inside of that window), then RXID and RXSUBID are set to 0. If none of the open windows are active, this indicates that the user has made some other application's window active. In this case, RXWIND is set to a NULL string (ie, ''). Args None. Returns Sets RXWIND, RXID, and RXSUBID. Examples /* This gets and displays RXWIND, RXID and RXSUBID for the active window */ RXACTIVE RXSAY 'Active Window = "'RXWIND'"' RXSAY 'Active Group = 'RXID RXSAY 'Active Control = 'RXSUBID ═══ 5.2. RXDEV ═══ Template RXDEV DeviceTitle Operation Value Description This command is used to setup for reading from devices or pipes. The input will be returned when your script calls RXDLG. Note: You must have a Main Window open before calling RXDEV. Closing the Main Window also performs RXDEV's CLOSE Operation upon any opened and initialized devices. PM applications (including REXX scripts written for Rexx Dialog) must approach reading from devices differently than non-PM apps (ie, REXX scripts launched like they normally are; without a PM interface). This is due to 2 design limitations of OS/2. First of all, PM has a single system queue which requires a PM app's window procedure to complete its work in 1/10 of a second. If a PM app doesn't do this, it will appear to "lock up" the desktop. The other design limitation of OS/2 is its very awful 16-bit Physical Device Driver model, which is essentially a more convoluted version of MS-DOS 2.0's driver model. This model lacks standardized approaches to such things as querying if any input is available for reading, or setting a time-out for reads (ie, if no input is received within a certain amount of time, the read is aborted). As might be expected, communication between an archaic 16-bit driver model and modern 32-bit application software is grotesquely crude and inflexible, and therefore, driver programmers have resorted to all manner of proprietary schemes to implement these features that IBM never wrote into OS/2's PDD model. Worse, many drivers don't even bother to implement the features at all. So, a call to DosRead input from a device may result in the app being "blocked" (ie, halted) until input is available for reading, and this may take much longer than 1/10 of a second. Therefore, a PM app must have a separate thread to read input from a device. Its main thread must not call any function that ultimately calls DosRead when reading from a device. (ie, Standard functions such as STREAM, CHARIN, and LINEIN must not be used when reading from a device. Neither can you use FileRexx's FileRead, FileGets, or FileReadValue, nor any other function library's input routines that call DosRead, such as RXASYNC. Hey, if you don't like it, tell IBM to fix PM's single system queue, and implement a more modern PDD model, preferably 32-bit). In lieu of these functions, you'll use RXDEV to setup a device for reading, and then retrieve input from the device via RXDLG. To make things easier, Rexx Dialog's device reading has such features as being able to read whole blocks of data (ie, more than 1 character at a time), and discard input that doesn't begin or end with certain patterns, parse input into several REXX variables, and perform binary to REXX variable conversion. So, it's sort of like a combination of FileGets, FileRead, and FileReadValue, which should handle the bulk of your needs. Args DeviceTitle The title (ie, string) of the device, which can be any title of your choosing. If there are blank spaces in the title, then enclose the string with two pairs of quotes '"' (or "'") if the title is a variable, or '" and "' (or "' and '") if a literal string. For example, these are legal titles: '"'title'"' /* title would be some variable that you initialized earlier, for example, title='My Device Title' */ '"My Device Title"' This is used to identify the device in the same way that the WindowTitle arg to RXDLG identifies a window. The DeviceTitle should be unique from any other device that you have setup for reading with RXDEV. If you specify a DeviceTitle of '""', then this refers to the first device that has been initialized (and is not yet closed) with RXDEV. Value The meaning of the Value arg depends upon the Operation arg (and may not need to be supplied for some Operations). Operation Operation is one of the following: INIT This operation must be performed before any other operations. It sets up a device for reading (and will begin the reading unless the PAUSE Flag is set). Prior to performing this operation, you must setup several REXX variables to desired values. After the INIT operation, these variables can be discarded. First, you must open the device for reading using FILEREXX's (ie, my REXX function library for doing device I/O, available separately) FileOpen. If you're going to also be doing writes to the device (ie, using FILEREXX's FileWrite, FilePuts, or FileWriteValue), you can open the device for both reading and writing, and use this one handle for both FILEREXX and Rexx Dialog. You must store the handle returned by FileOpen in the REXX variable RXINFO before doing the INIT operation. The REXX variable RXCOUNT contains the size of the input buffer, and a count limit. Rexx Dialog can return blocks of data (ie, more than 1 character or 8-bit byte) to your script. For example, you can ask Rexx Dialog to return the next 64 bytes of data read from the device, when you call RXDLG once. The count limit is how many bytes to input before they are returned to your script. For example, a count of limit of 64 would mean that after reading 64 bytes, a call to RXDLG returns those 64 bytes to your script. The input buffer must be at least 4 bytes larger than the count limit. Rexx Dialog implements a circular buffer. This helps to speed up device reads, but unless your script can receive and process input faster than Rexx Dialog reads it, further device input may overwrite previous input. You can work around this either by using the PAUSE Flag, or by setting the size of the input buffer to be at least twice your count limit (plus 4 bytes that Rexx Dialog uses for bookkeeping). So, if your count limit is 64, and you want double-buffering, then set the input buffer size to (64+4)*2. If you need triple buffering, set the buffer size to (count limit + 4)*3. Etc. If you specify a buffer size of 0, then 4096 bytes is used. This corresponds to a page of memory. It's best to round up your buffer size to a multiple of 4096 (or use a default of 0 if you don't need more than 4096 bytes), as that won't use any more memory, due to OS/2's paging system. If you don't specify the count limit, it defaults to a setting appropriate for double buffering. The buffer size and count limit are restricted to 65,535 or less. RXLABEL is set to the name of the REXX stem variable where the device input is returned. The variable name should be limited to 22 characters. All of the returned bytes are stored in that variable name with a .0 extension. For example, if you specify RXLABEL = 'MYINPUT', and a count limit of 3, then a call to RXDLG returns those 3 characters in MYINPUT.0. If the NUM flag is set, then each byte is expressed as an ascii numeric value (in decimal, a range of 0 to 255), with a space inbetween each value. For example, if a line feed and carriage return were returned, MYINPUT.0 would be '13 10'. If the SIGN Flag is set (in addition to NUM), then the ascii numeric values are expressed as signed (instead of unsigned) values (ie, a range of -128 to 127). The returned string is limited to 255 characters. If the PARSE Flag is set, then each byte is returned in a different stem variable (and the 255 character limit is not applicable). For example, the first byte is returned in MYINPUT.0, the second byte is returned in MYINPUT.1, and the third byte is returned in MYINPUT.2. Both the NUM and PARSE flags can be set. RXSTARTPAT is set to a string containing various patterns, one of which must be matched before device input is saved. This makes it possible to discard device input until a certain pattern is spotted, and then start collecting all data at that point. Each pattern in the start string must be separated by a | character. If RXSTARTPAT is a null string, then all device input is saved (ie, start pattern match is disabled). Each pattern can contain one or more characters or values. A pattern begins with a "Format" letter. This is an 'H' if you're expressing the values in hexadecimal, a 'B' if you're expressing the values in binary, a 'D' if you're expressing the values in decimal, or an 'L' if the characters are not to be translated in any way (ie, a literal string). For 'H', 'B', or 'D', Rexx Dialog translates each value to its binary equivalent when used in a start pattern. For example, if you want to set a start pattern that looks for a line feed and a carriage return characters, you could express the LF and CR in decimal as so: 'D 13 10' Or, you could express them each in hexidecimal: 'H D A' Or, you could even express them in binary: 'B 1101 1010' If the "Format" is 'L', then the value string is used verbatim without any translation to binary values. For example, to set a start pattern that looks for the string 'hello': 'L hello' The Format can have an extension, which I'll refer to as the "Count". This will be how many values of that type follow. If the Count arg is omitted, then the field's size is ultimately determined by however many values follow. For example, if you had a field that consisted of 32 decimal values, you could define the Format and Count as D.32 and then list the 32 values after that. If you don't supply as many values as "Count", then null bytes are used to pad out to Count. There can be an additional extension after the Count, which I'll refer to as an "Initialization". This will be either a numeric value that it is to be duplicated for Count times, or a (non-numeric) character that it is to be duplicated Count times. For example, if you wanted to specify 32 decimal values and set them all to the value 16, the Format, Count, and Initialization would be D.32.16 with no need to specify any values after that. If you wanted to specify 4 'A' chars, the Format, Count, and Initialization would be L.4.A with no need to specify any chars after that. It's also permissible to have more than one Format, Count, and values (or Initialization) per field. But, all of the Formats must also have a Count, except for the last Format (which may or may not have a Count). For example, say that you want to set a start pattern of 'hello' followed by a line feed and carriage return: 'L.5 hello D 13 10' Here's an example of setting 2 start patterns. One pattern is 'OK', and the other pattern is 'NO'. So, device input is ignored until either string is detected. 'L OK | L NO' The returned input starts with the matching start pattern (ie, it's part of the returned input) unless the TRIM Flag is set (in which case the start pattern is trimmed from the returned input). If the WATCH Flag is set, then the device input is returned as soon as a start pattern is matched (ie, the returned input consists only of the matching start pattern). This is useful if you need to throw away all device input except for a particular set of patterns. RXENDPAT is also set to a string containing various patterns. If one of these patterns is matched, then the device input is returned to the script at that point, regardless of whether the count limit has been met. This makes it possible to force device input to be returned as soon as a certain pattern is spotted. Each pattern in the end string must be separated by a | character. The format of the string is the same as per RXSTARTPAT. If RXENDPAT is a null string, then device input isn't returned until the count limit is reached (ie, end pattern match is disabled). The returned input ends with the matching end pattern (ie, it's part of the returned input) unless the TRIM Flag is set (in which case the end pattern is trimmed from the returned input). RXFLAGS is any or all of the following, with each flag separated by a | character. TRIM Trim any matching start and/or end pattern from the returned input. NUM Translate each returned byte to an ascii numeric value. SIGN Return ascii numeric values as signed. The NUM Flag must be also set. PARSE Return each byte in its own REXX stem variable. PAUSE Rexx Dialog's device reading pauses after returning each block to the script. It will not read the next block until the script performs a RESUME operation. This allows the script to start/stop the device reads at will, thereby preventing Rexx Dialog from reading input faster than the script can handle it. WATCH Return input as soon as one of the start patterns is matched. End patterns are ignored (as is all input except for an exact match to one of the start patterns). PARTIAL Some drivers do not block reads. That is to say that if there is no more input to be read, the driver indicates that to Rexx Dialog. For example, COM drivers support setting up reads to have a time-out (via an IOCTL interface), in which case if there is no more data to be read, control is returned to Rexx Dialog. In this case, setting the PARTIAL Flag will cause Rexx Dialog to return (to your script) whatever data it has collected up to the point when no more data is available, even though an end pattern may not be matched (ie, RXENDPAT=0) or the count limit has not been met. In other words, Rexx Dialog always ends up returning input data back to your script as soon as that data is available from the device, rather than waiting to fulfill the count limit or finding a matching end pattern before returning a data block. COUNT This operation sets a new count limit for the specified device. The input buffer size can't be altered after INIT. The Value arg is the new count limit (which should be at least 4 bytes less than the input buffer size). VAR This operation sets a new REXX stem variable name to return input for the specified device. The Value arg is the new variable name. START This operation sets a new start string for the specified device. The Value arg is the new start string (expressed in the same format as per the INIT operation). END This operation sets a new end string for the specified device. The Value arg is the new end string (expressed in the same format as per the INIT operation). FLAGS This operation sets the new Flags for the specified device. The Value arg is the new Flags (expressed in the same manner as per the INIT operation). RESUME This operation tells Rexx Dialog to read another block of data for the specified device. There is no Value arg. You must do a RESUME Operation each time after RXDLG returns device input if you wish to receive another block of data upon the next RXDLG call. Otherwise, device reading is paused. CLOSE This operation closes the file handle for the specified device, and frees any resources allocated for it. There is no Value arg. After a CLOSE operation, you do not need to FILEREXX FileClose any handle that was setup on the INIT operation. Neither can you subsequently use that same handle with other FILEREXX routines. (You'd have to FileOpen the device again). Returns A large variety of error messages or numbers could be returned by RXDLG. See Errors for details. The actual device input is returned upon a call to RXDLG. RXDLG will setup the REXX stem variable you specified during INIT (or VAR) with the device input. RXWIND will be set to the DeviceName of the device whose input is being returned. RXID will be 1000 + the device number (where the first device initialized is 0, the second device initialized is 1, etc). So, you can either use RXWIND or RXID to differentiate between RXDLG returning device input, or some user input. RXSUBID will be set to how many input bytes are being returned. RXSTARTPAT will be set to the number of whichever start pattern matched the input (where the first start pattern is 1, the second pattern is 2, etc). RXSTARTPAT is 0 if no pattern was matched (ie, there was no start string specified). RXENDPAT will be set to the number of whichever end pattern matched the input. RXENDPAT is 0 if no pattern was matched (ie, there was no end string specified or the count limit was reached before a matching end pattern could be detected). ═══ 5.3. RXDLG ═══ Template RXDLG NumGroups WindowTitle Dimensions Flags RXDLG WindowTitle Operation Description This command is the major function that is used to create and manage the PM Interface. It creates, manages, and finally destroys a window which can contain many different kinds of PM controls such as push buttons, radio buttons, checkmark buttons, result buttons, list boxes, drop boxes, entry boxes, sliders, menus, etc) that the user manipulates in order to enter data, or which your script uses to display data. RXDLG has 2 different calling templates. The first is used when you want to create a window. The second template is used when you want to perform user input or output with, or perform some other operation such as destroying, a window. RXDLG also returns device input (if you've opened a device for reading). RXDLG can be called many times to create multiple windows, each with their own (perhaps unique) Groups of controls; all managed by a collaborative communication between Rexx Dialog and your script (mostly using RXDLG). RXDLG requires that you set up various REXX Variables to describe all of the controls/menus/etc that you want within a particular window prior to issuing a RXDLG command to create a window. Rexx Dialog then queries the state of those REXX variables on its own, and creates your window. Subsequent calls to RXDLG can perform some other operation upon an open window that your script specifies. RXDLG is a very complex command, so the next sections deal with various topics that concern RXDLG. This page simply gives a brief, reference summary. You may wish to skip to the next page now, and use this page simply as a reference after becoming familiar with RXDLG. Note: Rexx Dialog assumes that the system font has a point size of 10 (ie, as does the default System Proportional). Args NumGroups How many Groups of controls are described. For example, if you specify 2 Groups, then you need to set up two sets of variables for 2 Groups (ie, RXVAL.1, RXINFO.1, RXLABEL.1, etc, for the first Group, and RXVAL.2, RXINFO.2, RXLABEL.2, etc, for the second Group) or RXDLG will fail to create the window and return an error message. Note that if you were to describe two Groups, but only passed a NumGroups of 1 to RXDLG, then a window would be created with only 1 Group in it. You'd never see that second Group that you specified. Make sure that NumGroups is set respective to how many sets of variables (ie, Groups of controls) that you've described, and vice versa. Only the first 127 Groups in a window can have groupboxes automatically created around them (if desired). For subsequent Groups, you'll have to use separate GROUP Types to encompass the desired controls. Note: If you don't supply a NumGroups arg, then Rexx Dialog automatically knows that you're using the second template of RXDLG (ie, where the WindowTitle comes first). In this case, you're not creating a window, but rather, performing an operation upon an already open Window. In order to create a window, NumGroups must not be 0 (ie, you always have to specify at least 1 Group of controls). If you truly want an "empty" window, then specify an empty MENU Group. WindowTitle The title (ie, string) of the window. If there are blank spaces in the title, then enclose the string with two pairs of quotes '"' (or "'") if the title is a variable, or '" and "' (or "' and '") if a literal string. For example, these are legal titles: '"'title'"' /* title would be some variable that you initialized earlier, for example, title='My Window Title' */ '"My Window Title"' Note: You must not name a window where the first character is a numeric digit (ie, 0 to 9) although numeric digits can appear later in the title. If you're using the first RXDLG template, then a window will be created with this title. If you're using the second RXDLG template, then WindowTitle is the title of the window upon which you wish to perform an operation. In the second template, the WindowTitle can be an empty string, ie '""', in which case, the Main Window is used for Operations 2, 3, and 4, and for Operations 0 and 1, an empty string allows user interaction to resume with the window that was active upon the previous call to RXDLG. The WindowTitle that you pass must match the title of some open window, or RXDLG will return a "Can't find Rexx Dialog" error message. (If you pass an empty string, then the Main Window must be open). Note: If you specify a particular window title for Operations 0 or 1, that window will be brought to the front and made active. Operation This arg is for the second template of RXDLG. Operation will be one of the following: 0 Perform user interaction (only upon the specified window if its MODAL flag is set). Note that if there are multiple windows open and the specified window is not MODAL, then the user may choose to interact with a different window which may cause RXDLG to return. In such a case, you should always check the RXWIND variable after a call to RXDLG. 1 Perform user interaction (only upon the specified window if its MODAL flag is set), and also tell Rexx Dialog that it's OK to close that window when RXDLG returns. Note that if there are multiple windows open and the specified window is not MODAL, then the user may choose to interact with a different window which causes RXDLG to return. In such a case, the specified window will not be closed, and you should always check the RXWIND variable after a call to RXDLG. 2 Set up the REXX return values as per the state of the specified window and return immediately without performing any user interaction nor window closing. This operation does not set up the RXID, RXSUBID, and RXWIND variables. 3 Set up the REXX return values as per the state of the specified window, close that window, and return immediately without performing any user interaction. This operation does not set up the RXID, RXSUBID, and RXWIND variables. 4 Close the specified window, and return immediately without performing any user interaction. Do not set up the REXX return values as per the state of that window. If you want to close all open windows, including the Main Window, then pass a WindowTitle arg of '""' (ie, two double quotes inside of two single quotes). 255 Clear out the PM message queue without performing any user interaction nor closing any windows nor setting up any REXX variables. This is just to prevent PM lockups if you have windows open, and your script is not "sleeping" (ie, doing some call to RXDLG that performs user interaction). Dimensions The name of a REXX variable that is a string containing the desired Width, Height, X Position, and Y Position of the window. These are measured in screen pixels. X and Y positions are referenced to the bottom left corner of the Desktop if the window is a Main Window (ie, the very first window that you create upon the Desktop). For example, specifying X and Y of 0 means that the Main Window opens at the bottom left corner of the Desktop. All other windows that you create after the Main Window are Child Dialogs, and their X and Y positions are referenced to the bottom left corner of the Main Window (as opposed to the Desktop itself). For example, specifying X and Y of 0 means that the Child Dialog opens at the bottom left corner of the Main Window (ie, inside of the Main Window itself). Specifying a Width of 0 means that you want Rexx Dialog to determine a default size and position for the window (and the Height, X, and Y are ignored). In this case, you also get a window that can be resized and maximized, and so the SIZE flag is redundant. For example, if you wanted a window with Width=300, Height=200, X=10, and Y=10, then setup a variable with these values enclosed in quotes, and pass the name of that variable as the Dimensions arg: Note: Whenever Rexx Dialog closes a window, it updates the Dimensions string for that window. This is handy if you want to reopen the window later. If you pass the same Dimensions string to RXDLG (without reinitializing it), then the window will open with the same size and position as it had when it was closed. Rexx Dialog also updates a window's Dimensions string if you specify that window in Operations 2, 3, or 4. MyWinDimensions = '300 200 10 10' RXDLG 1 '"My Window Title"' 'MyWinDimensions' The variable containing the dimensions can be any legal variable name that you wish. Flags A string that describes the various display and management options for the window. You can specify any or all of these Flags, and each one must be separated by a | character, enclosed in quotes. The various Flags are: SIZE You want a window that can be resized by the user (ie, has a border that he can grab with the mouse and move to resize the window). The window will also have a maximize/restore button in the titlebar. MIN You want a window that can be minimized by the user. Main Windows are always created with a minimize button in the titlebar, and this flag need not be specified. A Main Window minimizes into an icon on the bottom of the Desktop. If a Child Dialog has a minimize control, it doesn't minimize to the bottom of the Desktop, but rather, the bottom left of the Main Window. (Be careful to not place controls there in the Main Window, or the child window will fall behind them). SMALL When a window is first created, it starts out minimized. The MIN Flag must also be set. MODAL When the window is created or when performing an operation upon it, all other Child Dialogs and controls in the Main Window are disabled. Note: A Main Window cannot be created MODAL. The MODAL Flag is ignored in this case. NOCLOSE When a call to RXDLG returns as a result of the user doing something with this window, Rexx Dialog automatically closes this window. NOCLOSE simply is a way of telling Rexx Dialog to close a window when it causes RXDLG to return, so that your script doesn't have to perform that extra operation (which would be done if the window was a one-shot type of deal, ie, where you wanted to get a set of data from the user once, and then dismiss the window). Whenever the Main Window is closed, either automatically due to not specifying NOCLOSE, or by doing an operation upon the Main Window which causes it to close, all Child Dialogs are also automatically closed. Note: All windows have a CLOSE ICON (ie, on the left side of the titlebar). RXDLG always returns when a user clicks upon a CLOSE ICON (with RXID = -98). But a window is not closed if the NOCLOSE Flag is specified. If you specify NOCLOSE, your script always has to eventually perform an END operation upon a particular window in order to close it (although if your script exits with any windows still open, those windows are automatically closed). RESULT When the window has the focus, and the user presses the ESC or ENTER key, RXDLG returns control to your script (ie, your script "wakes up" from a call to RXDLG). See ESC and ENTER Keys. KEYS When the window has the focus, and the user presses some key combination, RXDLG returns control to your script (ie, your script "wakes up" from a call to RXDLG). The RESULT Flag has precedence over KEYS (for ESC and ENTER), although both Flags can be set. See Keyboard Input. ONCE After the timer for the window times out, the timer is automatically disabled. See Time-out. NEWSIZE After the user resizes a window, the REXX script is notified of the new size. See Resizing a window. Here's an example of a Flags arg that might be passed to RXDLG: 'SIZE|MODAL|MIN' Of course, you could also use a variable: myflags = 'SIZE|MODAL|MIN' RXDLG 1 '"My Window Title"' 'DIMENSIONS' myflags If you don't specify a Flags arg, then none of the above flags are enabled (ie, you get a window that can't be sized, nor minimized if not a Main Window, nor maximized, is not modal, won't recognize the ESC and ENTER keys when that window is active to return from RXDLG, and when it does cause RXDLG to return, Rexx Dialog automatically closes the window. Note: It doesn't matter in what order you specify the Flags, but each must be separated from another using a | character. Returns A large variety of error messages or numbers could be returned by RXDLG. See Errors for details. Examples See the following sections. ═══ 5.3.1. Groups ═══ A PM control is some graphical object (inside of a window) which the user can manipulate with the mouse or keyboard in order to enter data. Controls can also be used to display data to the user. Rexx Dialog arranges controls into Groups. A Group is simply one or more instances of the same type of PM control. For example, you can have a Group of 3 sliders. Or you can have a Group of 2 list boxes. Or you can have a Group of 16 push buttons. Etc. Arranging similiar controls into Groups makes it easier for your script to define many instances of the same type of control. That's why I defined a Group. Of course, you could have only 1 control per each Group, but that sort of defeats the purpose of a Group. How does Rexx Dialog make it easier to define a Group of controls rather than 1 control at a time? One thing that Rexx Dialog does is intelligently arrange and space controls in the window. So, if you have a Group of 32 push buttons, you don't have to specify the width, height, X and Y positions of each one (as well as where to place and size the label of each button). You simply tell Rexx Dialog where the first button is located, how many buttons there are, how many buttons should appear upon each line, and what the width of a button is. Rexx Dialog will take care of positioning and spacing the other 31 push buttons, and will arrange them symmetrically. Secondly, if you desire a group box (ie, a rectangular border that surrounds all of the controls in the group, and which has its own label), Rexx Dialog intelligently figures out how to size and position that group box. You merely have to specify the label for that group box. Also, you typically may want the same kind of behavior for all of the same type of controls. For example, maybe you want 10 list boxes, and you want them all to be able to select multiple items in their lists. You don't have to specify that you want multiple select for each list box. You simply define all the list boxes within one group, and say that you want the group to be multiple select. Finally, Rexx Dialog allows you to apply certain types of editing or initializing to an entire group. For example, if you have 32 push buttons and you want to clear the checkmarks of all of them, you simply say that you want to clear the Group. Rexx Dialog doesn't limit you to only one Group within a window, nor one Group Type within a window. For example, you can have a Group of 3 sliders, and then above them, in the same window, have a Group of list boxes. As another example, you can have a Group of list boxes that are multiple select, and in the same window, have another Group of list boxes that are single select. Defining controls in Groups is an easy way to define lots of similiar controls. But, because a Group can be merely 1 control, you can also have plenty of flexibility on an individual control basis if need be. Also, because you only need specify the X and Y position of the entire Group (and Rexx Dialog does positioning of individual controls), it's easy to change the position of Grouped controls. There are several Types of Groups. They are: Push Button (PUSH) Radio Button (RADIO) Checkmark Button (CHECK) Result Button (RESULT) Entry (ENTRY) List Box (LIST) Drop Box (DROP) Spin Button (SPIN) Slider (SLIDER) Text (TEXT) Group Box (GROUP) Menu (MENU) Each Type has its own options (ie, Flags) and a particular way in which you must setup REXX variables to define that Group. You must use particular REXX stem variables when you define the Groups in a window. These stem variables are: RXTYPE RXX RXY RXFLAGS RXLABEL RXINFO RXVAL RXTYPE The Group Type. If you look at the above list of Types, you'll see the values for Type in parentheses. So, to define a Spin Button Group, you would set RXTYPE to 'SPIN'. RXFLAGS May be interpreted differently for various Types. It describes particular behavior and display options you want for this Group. For example, a Group of list boxes may have RXFLAGS set to 'INDEX|MULTIPLE'. Each Group Type's Flags will be described further in later sections. RXLABEL May also be interpreted a little differently for various Types, but for most Types, it is simply the Text Labels for all of the controls within the Group, and the Label for any group box which surrounds this Group. It will be set to one string that contains the label for each control, starting with the first control, and each label is separated from the next by a | character. The group box label will be last (if it is specified at all. If not specified, then no group box is created around the controls). For example, if you have 3 list boxes named "Fruits", "Vegetables", and "Meats" respectively, plus a surrounding group box labeled "Food Groups", then RXLABEL would be set to 'Fruits | Vegetables | Meats | Food Groups'. Note: You can omit or add blank spaces between the labels and | character. The above example could also be: 'Fruits|Vegetables|Meats|Food Groups' or ' Fruits | Vegetables | Meats | Food Groups' with the same results. Rexx Dialog trims leading and trailing spaces off of each label. If a particular control is not to be labeled, then simply leave a blank space where its label would go. For example, to create the "Meats" list box unlabeled, set RXLABEL to 'Fruits | Vegetables | | Food Groups". You can omit the spaces and it becomes 'Fruits|Vegetables||Food Groups'. If you don't want the group box, simply omit its label, ie, 'Fruits|Vegetable|Meats'. In fact, if you specify less labels than there are controls within a Group, then the remaining controls are unlabeled. For example, to only label the first 2 list boxes, not label the third one, and omit the group box, set RXINFO to 'Fruits|Vegetables'. Placing a ~ character before any letter in the label causes that letter to be underlined. This is handy for identifying "keyboard shortcuts" to the user (which your script will implement using the window's KEYS Flag, and processing Keyboard Input). The first control in the group appears closest to the lower left corner of the Desktop or Main Window. This is how OS/2 defines coordinates. (I would have preferred a top-down approach). RXINFO A string that may be interpreted differently for various Types, but in some way, it describes how many controls are contained in the Group. It may also describe things like how wide (in pixels) a control should be, how many controls should be placed upon each line, and also any other information particular to a certain Group Type. For most all Group Types, the first 3 components in the RXINFO string are the number of controls in the Group (ie, which I'll refer to as TotalControls), how many controls appear per line (ControlsPerLine), and how wide a control should be (WidthOfControl). (You only have to describe the control height for certain Types. Most Types have a standard height). For some controls, such as PUSH, RESULT, CHECK, RADIO, and TEXT, a width of 0 tells Rexx Dialog to calculate the best fit. How each Group Type utilizes RXINFO will be described further in later sections. RXVAL A string that may be interpreted differently for various Types, but in some way, it initializes the values of the controls (ie, it's either a string that contains the value of each control, or contains the names of stem variables where Rexx Dialog finds the values for the controls). Rexx Dialog also uses the same RXVAL to return the data that the user enters via the controls in that Group. How each Group Type utilizes RXVAL will be described further in later sections. RXX The X position of the Group (ie, where along the X axis the first control within the Group should be positioned in a window). This is measured relative to the lower left corner of the Desktop (if a Main Window) or the Main Window's lower left corner (if a Child Dialog). In other words, this is how far away from the left border of the Desktop or Main Window, you want the Group of controls to be displayed. If a group box is to be included, move the group farther to the right in order to make room for the box. RXY The Y position of the Group (ie, where along the Y axis the first control within the Group should be positioned in a window). This is measured relative to the lower left corner of the Desktop (if a Main Window) or the Main Window's lower left corner (if a Child Dialog). In other words, this is how far up, from the bottom border of the Desktop or Main Window, you want the Group of controls to be displayed. If a group box is to be included, move the group up higher in order to make room for the box. The stem on these variable names pertains to which Group you're defining. Don't get nervous. I'm going to explain this. Haven't I done OK so far? For example, let's say that you want a Group of 3 sliders, a Group of 2 spin buttons, and a Group of 4 push buttons in a window. That's 3 Groups. Let's say that you want the sliders to be Group 1, the spin buttons are Group 2, and the push buttons are Group 3. That means that, when you describe the slider group, the variables names that you use are RXTYPE.1, RXX.1, RXY.1, RXFLAGS.1, RXLABEL.1, RXINFO.1, and RXVAL.1. When you describe the spin button group, the variables names that you use are RXTYPE.2, RXX.2, RXY.2, RXFLAGS.2, RXLABEL.2, RXINFO.2, and RXVAL.2. When you describe the push button group, the variables names that you use are RXTYPE.3, RXX.3, RXY.3, RXFLAGS.3, RXLABEL.3, RXINFO.3, and RXVAL.3. What variables would you use to describe a fourth Group of controls in the window? Yep. RXVAL.4, etc. See, that wasn't so bad, was it? OK, now it's time for an example. Let's implement the above example. Don't worry about what the particular strings for RXVAL, RXINFO, and RXFLAGS mean for each Type. Just note how I define the 3 Groups (which can be done in any order, or at any time as long as this is done before the call to RXDLG). Pay attention to the commented lines. /* First Group (ie, the 3 sliders) */ RXTYPE.1 = 'SLIDER' /* SLIDER Type */ RXFLAGS.1 = ' ' RXLABEL.1 = '128 255 Slider 1: | 64 0 Slider 2: | 128 0 Slider 3: | Slide Us' RXVAL.1 = '64 32' RXINFO.1 = '3 1 142' /* TotalControls, ControlsPerLine, WidthOfControl */ RXX.1 = 80 /* X position of first control (ie, the Group) */ RXY.1 = 18 /* X position of first control (ie, the Group) */ /* Second Group (ie, the 2 spin buttons) */ RXTYPE.2 = 'SPIN' /* SPIN Type */ RXFLAGS.2 = ' ' RXLABEL.2 = '128 0 Spin 1: | 64 0 Spin 2: | Spin Us' RXVAL.2 = '10 20' RXINFO.2 = '2 1 90' /* TotalControls, ControlsPerLine, WidthOfControl */ RXX.2 = 320 /* X position of first control (ie, the Group) */ RXY.2 = 18 /* X position of first control (ie, the Group) */ /* Third Group (ie, the 4 push buttons) */ RXTYPE.3 = 'PUSH' /* PUSH Type */ RXFLAGS.3 = ' ' RXLABEL.3 = 'Push 1 | Push 2 | Push 3 | Push Us' RXVAL.3 = '' RXINFO.3 = '3 3 0' /* TotalControls, ControlsPerLine, WidthOfControl (best fit) */ RXX.3 = 90 /* X position of first control (ie, the Group) */ RXY.3 = 100 /* X position of first control (ie, the Group) */ /* Now that you've defined the 3 Groups, you can create a window containing them. Let's call it "Main Window" (since it will be the first window that we open, and therefore, the Main Window). Note that I specify NumGroups arg as 3 */ windowSize = '' /* Default */ RXDLG 3 '"Main Window"' 'windowSize' 'RESULT' /* After the window is created, you can DROP those REXX variables used for such if desired, in order to conserve memory. It's recommended that you leave RXVAL and all windows Dimensions strings. */ DROP RXTYPE. RXFLAGS. RXLABEL. RXINFO. RXX. RXY. /* Perform user interaction, such as wait for him to click the window CLOSE ICON */ RXDLG Copy the above example to a file and run it with RX.EXE. Note: It doesn't matter in what order you assign the variables. For example, you can setup the variable RXINFO.1 before you setup RXTYPE.1. The only important consideration is setting up all variables before the call to RXDLG. ═══ 5.3.2. Managing a PM Interface ═══ In order to interact with the user (ie, get input from him and display output to him), your script will need to use one or more PM windows (with PM controls inside of them). To create a window, you use the first template of RXDLG. Call RXDLG with the NumGroups parameter greater than 0 (ie, you always have to specify at least 1 Group of controls). This tells RXDLG that you wish to create a window with that many Groups of controls inside of it. RXDLG will query all of the variables that your script setup in order to create, initialize, and display that window and its controls. If this is the first window to be displayed, it becomes the Main Window and all other windows (ie, Child Dialogs) open inside of this window. The window is given the title that you specified to RXDLG. Note: Each window should have a distinct title. After RXDLG creates the window, it will return immediately. Although the window is displayed, the user will not be able to interact with it yet. At that point, you can do further initialization if desired. One thing that you can do is call RXDLG again, using its first template, to create another window. You can have as many windows simultaneously open as desired (PM resources permitting), each containing its own (perhaps unique) Groups of controls. Then, you'll make one or more calls to RXDLG using the second template to manage the PM interface. In the second template of RXDLG, you specify what operation you wish to perform on the PM interface, where such operations include allowing the user to interact with one or all open windows and perhaps return user input to the script, and eventually closing down windows. The following discussion is for RXDLG Operations that perform user interaction (ie, 0 and 1), and may not pertain to other RXDLG Operations. When you perform an RXDLG Operation that allows the user to interact with the windows (and the PM controls within them), RXDLG does not return immediately. Instead, your script "goes to sleep" while Rexx Dialog manages the user's interaction and all of the PM processing associated with that. In other words, while the user is interacting with the windows\controls, your script is locked inside of that call to RXDLG. (The exception to this is RXDLG Operations that don't perform user interaction, such as operations 2, 3, 4, and 255). When RXDLG returns control to your script, then the user can't interact with the windows anymore (until you again call RXDLG to perform an Operation that allows the user to interact with the windows\controls). So, think of RXDLG as a way for you to pass control to Rexx Dialog (and the user). When RXDLG returns, it is passing control back to your script (and away from the user). While Rexx Dialog has control, the user is free to manipulate the windows (and controls within them) in any order that he wishes. (The exception to this is for a window with its MODAL Flag set). For example, if there are 3 windows open, the user can click upon any one of them to make it the active window, and then activate any control inside of that window. Therefore, your script can never make any assumptions about which window and control the user has manipulated. Instead, Rexx Dialog will keep track of that information, and sets some REXX variables in your script which you can then examine (after RXDLG returns) to determine which window and control has been manipulated. There are a number of actions the user could do which would cause RXDLG to return (ie, and therefore return control to your script). They are: 1. If the script is launched by some application other than RX.EXE, and that app wants the script to abort (ie, EXIT). 2. He clicks upon the CLOSE ICON of a window. 3. If the window's RESULT Flag is set, and the window itself has the focus (ie, the window is active, but no control within it is activated), he presses the ESC key. 4. If the window's RESULT Flag is set, and the window itself has the focus, he presses the ENTER key. 5. The window's timeout is enabled, and the timeout expires. 6. If the window's KEYS Flag is set, and the window itself has the focus, he presses some key on the computer's keyboard. 7. He clicks upon some button in a RESULT Group. 8. He finishes using some control that is in a Group with its END Flag set. Before RXDLG returns control to your script, it sets up all returned variables (ie, RXVAL, RXWIND, RXID, RXSUBID, the window's Dimensions string, etc) per the state of this window (and its Groups). (The exception to this is RXDLG Operations that specifically don't want the return values setup, such as operation 4). RXDLG will also close the window that caused the return unless the window's NOCLOSE Flag is set. (The exception to this is with KEYS processing. Although RXDLG returns control to your script when the user presses a key, the window is not closed, and only the variables RXID, RXSUBID, and RXWIND are setup. Another exception is for action #1, an app indicating to abort. In this case, only RXWIND, RXID, and RXSUBID are setup). If the user was able to interact with more than one window during the call to RXDLG, then your script needs to examine the RXWIND variable. This is set to the title of the window which caused RXDLG to return. Typically, each window would be associated with some operation that your script performs. You'd do a SELECT on RXWIND, comparing it to the titles of all of your windows, and when you found the match, you'd carry out the operation associated with that window. There are 2 variables that let you determine exactly what the user did to cause RXDLG to return (from the above list). Those variables are RXID and RXSUBID. First, you examine RXID. If the user manipulated some control in the window, then RXID is set to the Group number that control is within (where the first Group is number 1). For example, if the first Group in the window contains 5 PUSH buttons, and the user pressed one of those buttons, then RXID will be 1 to indicate that he used a control in Group 1. (This assumes that the Group has its END Flag set so that it causes RXDLG to return). RXSUBID is set to the control number that was manipulated in that Group (where the first control is number 1). Let's say that he pushed the third button in that Group. RXSUBID will be 3. If RXID is 0 or some negative number, this indicates that what caused RXDLG to return wasn't due to the user manipulating some control within a Group, but rather, one of the first 6 actions listed above occurred. Both RXID and RXSUBID are 0 if a timeout occurred (ie, the window timer timed out before any of the other 6 actions could occur). RXID will be -98 if the window's CLOSE ICON was clicked. RXID will be -12 if the ESC key was pressed. RXID will be -20 if the window was resized (and you specified the NEWSIZE Flag). If the script is launched by some application other than RX.EXE (the app must be written to specifically use RXDLG.DLL), and that app wants the script to abort (ie, EXIT), then RXID will be -99. If the user pressed some other key on the keyboard, RXID will be between 0 and -11 (depending upon whether the ALT, SHIFT, and\or CTRL keys were held down too, and whether the key is a printable character such as "s" or unprintable such as the HOME key), and RXSUBID will identify that particular key (as described in Keyboard Input). Based upon RXWIND, RXID, and RXSUBID, your script will decide what operation it wishes to perform (perhaps using the other REXX variables which were setup to the "values" of all of the controls in the window specified by RXWIND). It's possible that this operation could involve opening more windows and getting even more user input. After this operation is complete, the script will either terminate, or loop back to calling RXDLG to do some more user interaction (ie, if you want to give the user an opportunity to repeat an operation with a new set of input). If the script does continually loop around, getting new sets of user input, you'll need a method of breaking out of the loop and exiting from your REXX script. Typical ways include checking if the user has clicked upon the Main Window's CLOSE ICON, checking if the user has selected a "Quit" menu label (if you add such to the window), or checking if the user has pressed the ESC key (or pressed some key combo, or manipulated some control, that you have deemed will be interpreted as a signal to quit the program). If your script is launched by some app other than RX.EXE, you'll also want to check for a signal to abort. Refer to the RXDLG section for details on the args passed to RXDLG. ═══ 5.3.3. Group Types ═══ The next sections explain the details about each Group Type (ie, and offer a detailed explanation of some of the variables mentioned in Groups, which can be interpreted differently for each Group). ═══ 5.3.3.1. Push Button ═══ Type PUSH Description A push button is a graphical, square button with the label inside of the button itself. A user can move the mouse pointer over the button and press (and hold down) the mouse button. The button will visually depress as if the mouse pointer were a finger pushing down upon the button. When the user releases the mouse button, so too does the mouse release the push button, and that's when it becomes activated (ie, like a "momentary switch"). Alternately, pressing the SPACE BAR will activate the button which currently has the focus (ie, is highlighted). When the user activates a push button, RXDLG returns if the END Flag for its Group is specified. There are a maximum of 32 buttons per Group. Uses Push buttons are usually used to launch operations, such as to begin a file save or load, or initiate an action such as to create another window. REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, and WidthOfControl. If WidthOfControl is 0, then Rexx Dialog calculates a "best fit". If you specify a non-zero width, make sure that it is large enough or the button's label will be visually clipped. RXLABEL is as described in Groups. But, if a Label for a particular button is omitted, then that button is not placed upon the display, and its number is skipped. In this way, you can determine how you want to number the buttons upon the display. For example, let's say that you want 3 buttons on the display. But, you want the first button (which we'll label as "One") to be #1, the second button ("Two") to actually count itself as #3, and the third button ("Three") to count itself as #5 (ie, you want to skip #2 and #4). You would omit labels for buttons 2 and 4. Therefore, RXLABEL would be 'One | | Two | | Three'. In this way, the "values" of the second and third buttons are 3 and 5. Note that if you skip buttons, you still have to count them in RXINFO's TotalControls. For example, here TotalControls would be 5 (ie, TotalControls reflects how many labels you supply, not how many buttons are displayed). Note: OS/2 REXX appears to have a bug in it regarding null strings. A null string is supposed to simply be quotes without any characters in between, but OS/2 REXX doesn't like this in assignments (ie, when you assign a variable to be a null string). It likes to see at least 1 character between the quotes. So instead of myvar = '', use myvar = ' ' whenever assigning a null string to a label variable (or any other variable that specifies a string rather than a numeric value). RXVAL is a string specifying which button is initially selected by default. For example, if the first button is to be selected, then RXVAL = '1'. If you don't want any default selection, then set RXVAL to a null string (ie, ''). By doing the latter, you can examine the return that Rexx Dialog gives for this Group, and determine whether the user selected any button at all. Note that you must consider any skipped values when specifying button numbers in the RXVAL string. RXFLAGS can be any, all, or none of the following: 'NUMBERED' Rexx Dialog automatically labels the buttons with numbers, (ie, the first button has a label of '1', the second button is '2', etc). Therefore, you don't have to specify any of the button labels in RXLABEL. RXLABEL will simply be the group box label (or a null string if no group box is desired). 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this button group) when the user selects one of the buttons in this group. REXX Return Rexx Dialog returns this Group's RXVAL variable set to which button was pushed. For example, if the second button was pushed, then RXVAL is set to '2'. Note that if buttons were skipped, the numbering reflects that. In the above example, if the user pushed the third button, it really has a value of 5 (because 2 and 4 were skipped), and so RXVAL is set to '5'. If you initially specified no default, and the user never pushed any button before the dialog window containing this group caused RXDLG to return, then RXVAL would be a null string. Examples /* This creates a window called "Push Stuff" containing 1 Group of 3 push buttons labeled "High", "Mid", "Low", with a group box labeled "Tone". Each button appears upon its own line (ie, they are stacked in a column), ie, ControlsPerLine=1. Rexx Dialog calculates a best fit for width of each button. Selecting one of the buttons in this Group causes RXDLG to return (and also causes the dialog containing these buttons to be destroyed if the dialog isn't NOCLOSE). There is no initial default selection. */ RXTYPE.1 = 'PUSH' /* Cause RXDLG to return */ RXFLAGS.1 = 'END' /* NumOfControls, ControlsPerLine, WidthOfControl */ RXINFO.1 = '3 1 0' /* Labels for buttons, and group box */ RXLABEL.1 = 'High|Mid|Low|Tone' /* No default */ RXVAL.1 = '' /* Position */ RXX.1 = 10 RXY.1 = 10 /* Create "Push Stuff" window */ RXDIM = '80 160 50 50' RXDLG 1 '"Push Stuff"' 'RXDIM' 'RESULT' /* Display the selection */ RXSAY 'Chose button #'RXVAL.1 ═══ 5.3.3.2. Radio Button ═══ Type RADIO Description A radio button is a graphical, round button that is filled in with a different color depending upon whether the button is "on" or "off". The label is immediately to the right of the button. A radio button's state turns "on", and stays "on", when the user activates it. Like the push button, the user activates a radio button when he clicks the mouse upon it. Alternately, pressing the SPACE BAR will activate the button which currently has the focus (ie, is highlighted). But, only one radio button in a group can be activated (ie, turned "on") at any given moment. When a particular radio button is activated, any other button that was "on" is automatically turned off, and only the newly activated button is turned "on". In other words, only one button is ever "on" at any given moment, and all others in the Group are "off". When the user activates a radio button, RXDLG returns if the END Flag for its Group is specified. There are a maximum of 32 buttons per Group. Uses Radio buttons are used to allow the user to choose one (and only one) item from several available choices. For example, there may several radio buttons, each offering a different "paper size" for a printing job, and the user must choose one size. REXX Setup Setup is exactly the same as per the Push Button Group. REXX Return Return is exactly the same as per the Push Button Group. Examples /* This creates a window called "Radio" containing 1 Group of 4 radio buttons. Rexx Dialog labels them with numbers (ie, 'NUMBERED' Flag), so RXLABEL is the group box label only. There are 2 buttons per line. We specify a width of 30. Selecting a button in this Group DOESN'T cause RXDLG to return because we didn't specify 'END' Flag. When the Group first appears, button 3 is selected */ RXTYPE.1 = 'RADIO' /* Let Rexx Dialog label all of the buttons with numbers */ RXFLAGS.1 = 'NUMBERED' /* NumOfControls, ControlsPerLine, WidthOfControl */ RXINFO.1 = '4 2 30' /* Group box label */ RXLABEL.1 = 'Numbers' /* Default is button 3 */ RXVAL.1 = '3' /* Position */ RXX.1 = 10 RXY.1 = 7 /* Create "Radio" window */ RXDIM = '100 110 50 50' RXDLG 1 '"Radio"' 'RXDIM' 'RESULT' /* Display the selection */ RXSAY 'Chose button #'RXVAL.1 ═══ 5.3.3.3. Checkmark Button ═══ Type CHECK Description A checkmark button is a graphical, square button that is filled in with a graphical checkmark depending upon whether the button is "on" or "off". The label is immediately to the right of the button. A checkmark button's state toggles between "on" and "off" each time that the user activates it. (ie, If it's currently "off" when he activates it, it turns "on" and stays "on", and vice versa). Like the push button, the user activates a checkmark button when he clicks the mouse upon it. Alternately, pressing the SPACE BAR will activate the button which currently has the focus (ie, is highlighted). But, unlike radio buttons, each checkmark's state is independent of the others in the Group. So, all of them can be turned "on", or all of them can be turned "off", or any combination inbetween. When the user activates a checkmark button, RXDLG returns if the END Flag for its Group is specified. There are a maximum of 32 buttons per Group. Uses Checkmark buttons are used to allow the user to choose any, all, or no items from several available choices. For example, there may several checkmark buttons, each offering a different style for a font (ie, underlined, italic, boldface), and the user can choose any/all/none of those choices to be applied to the font simultaneously. REXX Setup Setup is exactly the same as per the Push Button Group, except that more than one button can be specified for the RXVAL string. For example, if you want checkmark buttons 1, 4, and 6 checked initially, then set RXVAL to '1 4 6'. It doesn't matter in which order you specify the selected buttons, so '6 4 1' would be the same as '1 6 4'. Also, RXFLAGS has one more option: ALLNONE Two push buttons are displayed above all of the checkmark buttons. One push button is labeled "All". If this is pushed, it automatically forces all of the checkmark buttons to be selected (ie, checked). The other button is "None", and forces all checkmark buttons to be deselected (ie, clears the checks). REXX Return Rexx Dialog returns this Group's RXVAL variable set to only those buttons that are checked (ie, selected). For example, if the user selected buttons 4 and 5, then RXVAL is '4 5'. The buttons are always ordered from lowest to highest numbers. Examples /* This creates a window called "Checks" containing a Group of 3 checkmarks labeled "Bold", "Italic", and "Underline", with no group box. There are 3 buttons per line (so all 3 are on one line). We let Rexx Dialog calculate a best fit. Selecting a button in this Group DOESN'T cause RXDLG to return because we didn't specify 'END' Flag. When the Group first appears, buttons 1 and 3 are selected. There are also "All" and "None" push buttons */ RXTYPE.1 = 'CHECK' /* Add ALL\NONE push buttons */ RXFLAGS.1 = 'ALLNONE' /* NumOfControls, ControlsPerLine, WidthOfControl (best fit) */ RXINFO.1 = '3 3 0' /* Label for checkmarks, and group box */ RXLABEL.1 = 'Bold|Italic|Underline' /* Check buttons 1 and 3 */ RXVAL.1 = '1 3' /* Position */ RXX.1 = 7 RXY.1 = 7 /* Create "Checks" window */ RXDIM = '260 80 40 40' RXDLG 1 '"Checks"' 'RXDIM' 'RESULT' /* Display the selections (ie, more than 1 button can be selected. We need to parse the RXVAL string to remove each selected button number, and then we simply display its respective label */ DO UNTIL RXVAL.1 <= '' PARSE VAR RXVAL.1 button RXVAL.1 IF button = 1 THEN RXSAY 'Chose Bold' IF button = 2 THEN RXSAY 'Chose Italic' IF button = 3 THEN RXSAY 'Chose Underline' END ═══ 5.3.3.4. Result Button ═══ Type RESULT Description A result button is a special, preset collection of push buttons. You have a choice of labeled buttons, including OK, CANCEL, YES, NO, RETRY, IGNORE, ON, OFF, START, or STOP. Any or all of these buttons can be specified, and they are created upon one line. When the user activates a result button, it always causes RXDLG to return. Uses Used mostly to end a dialog, after the user has set up all other controls in the dialog window to desired values. Depending upon which one of the result buttons was selected, the script can then perform an operation using the values of the dialog's controls, or abort a pending operation. REXX Setup RXINFO is a string containing which preset buttons to display. Here are the values for the available buttons: CANCEL 1 OK 2 NO 3 YES 4 ABORT 5 RETRY 6 IGNORE 7 ENTER 8 OFF 9 ON 10 STOP 11 START 12 For example, if you want the OK, CANCEL, and ABORT buttons, specify RXINFO is set to '1 2 5'. It doesn't matter in what order you specify the button numbers. Note: All of the buttons normally associated with "positive" responses are even numbers. All of the buttons normally associated with "negative" response are odd numbers. I refer to the positive buttons as SUCCESS buttons, and the negative buttons as FAILURE buttons. RXLABEL is the simply the group box label (or a null string if none). RXVAL need not be initialized. RXFLAGS can be any, all, or none of the following: 'BOOL' Only return a 0 or 1. If the user clicks upon one of the SUCCESS buttons, return a 1. If the user clicks upon one of the FAILURE buttons, return a 0. Note: It's not necessary to specify the 'END' Flag for a RESULT Group. A RESULT Group always causes RXDLG to return. REXX Return Rexx Dialog returns this Group's RXVAL variable set to which button was pushed. For example, if the NO button was pushed, then RXVAL is set to '3' (unless BOOL Flag is specified, in which case RXVAL would be set to '0'). Note: If a dialog is created with its RESULT Flag specified, when the user presses ESC (while the dialog has the focus), any RESULTBUTTON has its RXVAL return set to the lowest numbered FAILURE button in the Group. For example, if you have a NO button in the Group, RXVAL is set to '3' (unless BOOL Flag is specified). When the user presses ENTER (while the dialog has the focus), any RESULTBUTTON has its RXVAL return set to the lowest numbered SUCCESS button in the Group. For example, if you have an OK button in the Group, RXVAL is set to '2' (unless BOOL Flag is specified, in which case RXVAL is 1). Examples /* This creates a window called "Result" containing a Result button Group with OK, CANCEL, and ABORT. There is no group box */ RXTYPE.1 = 'RESULT' /* Default */ RXFLAGS.1 = ' ' /* 1=OK, 2=CANCEL, 5=ABORT */ RXINFO.1 = '1 2 5' /* Group box label */ RXLABEL.1 = ' ' /* Leave a space. See note on REXX bug in "Groups" */ /* Position */ RXX.1 = 7 RXY.1 = 7 /* Create "Result" window */ RXDIM = '226 60 40 40' RXDLG 1 '"Result"' 'RXDIM' 'RESULT' /* Display the selection */ IF RXVAL.1 = 2 THEN RXSAY 'Pressed OK' IF RXVAL.1 = 1 THEN RXSAY 'Pressed CANCEL' IF RXVAL.1 = 5 THEN RXSAY 'Pressed ABORT' ═══ 5.3.3.5. Entry ═══ Type ENTRY Description A box into which the user can type and edit (using the left and right cursor, Delete, Insert, and Backspace keys) text, or which can display text for the user to edit. The user clicks inside of the box, and a cursor appears (ie, the entry gets the focus). He can then type keys and text will be entered into the box. When he presses the ENTER key, the text is "accepted", and the entry will cause RXDLG to return if the END Flag is set for this Group. He can press the ESC key to stop entering text into the entry (and return focus to the dialog window). Uses To obtain a line of text from the user, or present a line of text to be edited by the user. It could be used in the same way that a REXX PULL statement would be used, except that a dialog can contain many entries, so that the user can choose which ones he wants to interact with, and which he doesn't. REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, and WidthOfControl. WidthOfControl specifies only the size of the entry box (not any label for it too), and therefore will determine how many characters can be displayed in the entry box simultaneously. If there are more characters in the line than can fit into the box, the user can press the right or left cursor keys to scroll other characters into view. RXLABEL is as described in Groups. RXVAL is a string specifying the name of a REXX stem variable where all of the initial contents of the entries are stored. The variable name should be limited to 22 characters. For example, if you set RXVAL to 'STRS', then the first entry in the Group will be initialized to whatever the value of STRS.1 is (ie, the string assigned to STRS.1 will be placed into the entry box when it is created, for the user to edit). The second entry will be initialized to whatever the value of STRS.2 is. Etc. If you don't want any text initially placed into a particular entry (ie, you want it created empty), set its variable to a null string. For example, if you wanted the second entry to be blank, assign STRS.2 = ' '. Note: OS/2 REXX appears to have a bug in it regarding null strings. A null string is supposed to simply be quotes without any characters in between, but OS/2 REXX doesn't like this in assignments (ie, when you assign a variable to be a null string). It likes to see at least 1 character between the quotes. So instead of '', use ' ' whenever assigning a null string to any variable that specifies a string rather than a numeric value). RXFLAGS can be any, all, or none of the following: 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this entry group) when the ENTER key is pressed while one of the entries in this group has the focus. RXX reflects the position of the first entry box, not its label (which needs room to the left of the entry in order to be displayed). Therefore, set RXX far enough to the left to leave room for the label. REXX Return Rexx Dialog returns each entry's text in the same variable that was used to fetch its text. In other words, if you specified RXVAL as 'STRS' when the Group was created, then the first entry's text is returned in STRS.1. Note: Currently, an entry is limited to entering 31 characters maximum. There is a limit of 256 entries per Group, or if Labels are specified, 128 entries per Group. Examples /* This creates a window called "Enter Stuff" containing a group of 3 entries with labels of "One", "Two", and "Three", and a groupbox of "All". The first is initialized to contain "Hello", and the second and third are blank */ RXTYPE.1 = 'ENTRY' /* Default */ RXFLAGS.1 = ' ' /* Labels for each entry, and Groupbox */ RXLABEL.1 = 'One:|Two:|Three:|All' /* Variable name where the text "typed into" the entries is stored */ RXVAL.1 = 'TEXT' /* TotalControls, ControlsPerLine, WidthOfControls */ RXINFO.1 = '3 3 45' /* Position of Group */ RXX.1 = 60 RXY.1 = 16 /* The text for the 3 entries */ TEXT.1 = 'Hello' TEXT.2 = ' ' TEXT.3 = ' ' /* Create "Enter Stuff" window */ RXDIM = '256 106 20 20' RXDLG 1 '"Enter Stuff"' 'RXDIM' 'RESULT' /* Display the selection for each entry */ RXSAY 'Entry One is "'TEXT.1'"' RXSAY 'Entry Two is "'TEXT.2'"' RXSAY 'Entry Three is "'TEXT.3'"' ═══ 5.3.3.6. List Box ═══ Type LIST Description A box containing numerous lines of text. Each line is an "item" that the user can select (ie, highlight). There is a scroll bar immediately to the right which, if there are more items than can be simultaneously displayed in the box, can be used to scroll those other items into view. (The scroll bar is inoperable if all of the items in the list can be simultaneously displayed in the box). The user can select an item by clicking upon it with the mouse. By holding the mouse button down, and moving the mouse up and down, he can also scroll the list. Alternately, the up and down cursor keys can be used to cursor through the list, and the ENTER key will select an item. For multiple select list boxes, more than one item can be selected simultaneously. When an item is selected, its state toggles. (ie, If the item was not selected, selecting it highlights it. If the item was highlighted, selecting it unhighlights, or deselects it). Clicking the mouse twice on an item very fast (ie, double-clicking) causes RXDLG to return if the END Flag is set for this control's group. Alternately, pressing the ENTER key does the same. Uses List boxes are used to present items that a user can choose from, much like checkmark or radio buttons, except that list boxes use up less area if you have lots of items from which the user can choose. Multiple select lists function like checkmarks, and single select lists function like radio buttons. REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, WidthOfControl, and NumVisibleItems. WidthOfControl specifies the width of the list box, and therefore will determine how many characters of an item can be displayed in the list box. NumVisibleItems determines how many items can be displayed simultaneously in the list box, and therefore this determines the height of the box. RXLABEL is as described in Groups. RXVAL is a string specifying the name of the REXX stem variables where all of the initial items of each list box are stored. Each variable name should be limited to 22 characters. Each list box has its own stem variable associated with it. That stem variable contains all of the items that get added to that list box. RXVAL specifies the REXX variable name for the first list box, then the REXX variable name for the second list box, then the REXX variable name for the third list box, etc. Each list box's variable name is separated from the next by a | character. For example, if you set RXVAL to 'ONE|TWO|THREE', then the first list box in the Group will be initialized to contain all of the items starting with ONE.1, the second list box will be initialized to contain all of the items starting with TWO.1, and the third list box will be initialized to contain all of the items starting with THREE.1. Rexx Dialog reads items until it comes to an item that is a null string. That marks the end of a list box's item. For example, if you wanted to put 3 strings into the first list box; "Hello", "Hi", and 'Goodbye", then you would set ONE.1 to 'Hello', ONE.2 to 'Hi', and ONE.3 to to 'Goodbye'. ONE.4 would be set to ' ' to mark the end of the list. Note: OS/2 REXX appears to have a bug in it regarding null strings. A null string is supposed to simply be quotes without any characters in between, but OS/2 REXX doesn't like this in assignments (ie, when you assign a variable to be a null string). It likes to see at least 1 character between the quotes. So instead of '', use ' ' whenever assigning a null string to any variable that specifies a string rather than a numeric value). RXFLAGS can be any, all, or none of the following: 'MULTIPLE' Allows more than one item to be selected simultaneously (ie, multiple select), rather than single select. ALLNONE This is only applicable to a multiple select list box. Two push buttons are displayed above the list box. One push button is labeled "All". If this is pushed, it automatically forces all of the items in the list to be selected (ie, highlighted). The other button is "None", and forces all items to be deselected. If the END Flag is also set for this Group, then RXDLG returns. There is a limit of 40 list boxes per Group if the ALLNONE Flag is used. INDEX Instead of returning the actual text of an item when it is selected, Rexx Dialog returns its index number (ie, where it appears in the list). The first item in the list has an index of 0. 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this list box group) when an item from a list is selected (or also unselected for multiple select lists). REXX Return For single select list boxes, Rexx Dialog returns each list box's selected item in the same variable that was used to fetch its items, but with a .0 extension. Using the above example, the selected item for the first list box would be returned in ONE.0, the selected item for the second list box would be returned in TWO.0, and the selected item for the third list box would be returned in THREE.0. For multiple select list boxes, Rexx Dialog returns a count of how many items were selected in the list in the same variable that was used to fetch its items, but with a .0 extension. Using the above example, the count for the first list box would be returned in ONE.0, the count for the second list box would be returned in TWO.0, and the count for the third list box would be returned in THREE.0. The selections for each list box are then returned in compound variables (ie, a second extension is added to the variable name). For example, the first selected item in the first list is returned in ONE.0.1, the second selected item in the first list is returned in ONE.0.2, etc. The first selected item in the second list is returned in TWO.0.1, the second selected item in the second list is returned in TWO.0.2, etc. Note: Currently, a list box item is limited to 31 characters maximum. There is a limit of 256 list boxes per group, or if Labels are specified, 128 list boxes per Group, or if ALL\NONE push buttons are included, 40 list boxes per Group. Examples /* This creates a window called "List Me" containing a Group of 1 single select list box with a label of "One", and a groupbox of "Choices". The list box's 6 items are stored in the ONE variable. Those 6 items are "This is one", "This is two", "This is three", "This is four", "This is five", and "This is six". */ RXTYPE.1 = 'LIST' /* Default */ RXFLAGS.1 = ' ' /* Labels for each list box, and Groupbox */ RXLABEL.1 = 'One:|Choices' /* Variable names where the items are stored */ RXVAL.1 = 'ONE' /* TotalControls, ControlsPerLine, WidthOfControls, NumVisibleItems */ RXINFO.1 = '1 1 110 4' /* Position of Group */ RXX.1 = 10 RXY.1 = 10 /* The items for list 1 */ ONE.1 = 'This is one' ONE.2 = 'This is two' ONE.3 = 'This is three' ONE.4 = 'This is four' ONE.5 = 'This is five' ONE.6 = 'This is six' ONE.7 = ' ' /* End of List */ /* Create "List Me" window */ RXDIM = '140 146 30 30' RXDLG 1 '"List Me"' 'RXDIM' 'RESULT' /* Display the selection */ RXSAY 'Selection is "'ONE.0'"' ═══ 5.3.3.7. Drop Box ═══ Type DROP Description A combination of an ENTRY and LIST. The list is not visible until you click the mouse upon a small arrow immediately to the right of the entry. Then, the list drops down, and the user can manipulate it like a list. Otherwise, if he clicks inside of the entry box, he can then manipulate that part of it just like an entry. Whenever an item in the list is selected, it is automatically copied to the entry. Clicking the mouse on an item in the list causes RXDLG to return if the END Flag is set for this control's group. Also, pressing the ENTER key does the same. Uses Like a list box, this displays many choices to the user, but the entry also gives him the opportunity to type in some text that isn't currently in the list. So, it might be used for a situation where you want to present some default choices to the user, but then allow him to reject those and specify his own choice. REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, and WidthOfControl. WidthOfControl specifies the width of the drop box, and therefore will determine how many characters of an item can be displayed in the drop box. RXVAL is exactly as in a List Box Group. RXLABEL is as described in Groups. RXFLAGS can be any, all, or none of the following: SHOWLIST Instead of list box that drops down, the list box is always visible. In this case, the RXINFO must be setup like a list box (ie, with a NumVisibleItems parameter too). READONLY The user cannot type anything into the entry, but must select an item for the list. If READONLY is set, then SHOWLIST should not be set (ie, if you don't want a drop down list and want it readonly, just use a LIST Group). The real difference between a READONLY DROP and a LIST is that the former takes up less area because its list is only displayed when dropped down. INDEX Instead of returning the actual text of a drop box item when it is selected, Rexx Dialog returns its index number (ie, where it appears in the list). The first item in the list has an index of 0. 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this drop box group) when an item from a list is selected or user types into the entry and presses ENTER. RXX and RXY reflect the position of the entry box of the first drop box, not its drop down list (which needs room beneath the entry in order to "drop down"), nor the drop box's label (which needs room to the left of the entry in order to be displayed). Therefore, set RXX far enough to the left to leave room for the label, and set RXY far enough above the bottom border of the window in which the Group is placed in order for the drop boxes to have room to drop down. The RXY variable should be 30 or more. REXX Return The return is exactly as in a single select List Box Group. Note: Currently, a drop box is limited to 31 characters maximum. There is a limit of 256 drop boxes per Group, or if Labels are specified, 128 drop boxes per Group. Examples /* This creates a window called "Drop Me" containing a Group of 1 drop box with a label of "One" and no groupbox. The drop box's list items are stored in the ONE variable. Those 3 items are "Hello", "Hi", and "Goodbye" */ RXTYPE.1 = 'DROP' /* Default */ RXFLAGS.1 = ' ' /* Labels for each drop box, and Groupbox */ RXLABEL.1 = 'One:' /* Variable names where the items are stored */ RXVAL.1 = 'ONE' /* TotalControls, ControlsPerLine, WidthOfControls */ RXINFO.1 = '1 1 90' /* Position of Group */ RXX.1 = 40 RXY.1 = 60 /* The items for list 1 */ ONE.1 = 'Hello' ONE.2 = 'Hi' ONE.3 = 'Goodbye' ONE.4 = ' ' /* End of List */ /* Create "Drop Me" window */ RXDIM = '140 104 30 30' RXDLG 1 '"Drop Me"' 'RXDIM' 'RESULT' /* Display the selection */ RXSAY 'Selection is "'ONE.0'"' ═══ 5.3.3.8. Spin Button ═══ Type SPIN Description A spin button is an entry that deals with numeric values. It consists of an entry, plus two up and down arrows immediately to the right of the entry. The up and down arrows will cycle the spin through its numeric range (and roll over when a lower or upper numeric limit is surpassed). Alternately, the user can click inside of the entry box, and type a number in just as he would manipulate an entry. His input is checked against the spin's upper and lower limit, and forced to fall within that range. When the entry is activated, he can also use the up and down cursor keys to cycle through the range. If the user changes the numeric value of a spin (either by using the arrow buttons, or typing a new value, or using the cursor keys), RXDLG will return if the END Flag is set for this control's Group. There is a limit of 256 spin buttons per Group, or if Labels are specified, 128 spin buttons per Group. Uses Useful for allowing the user to specify some numeric parameter such as how many copies of a document he would like printed. Because the user can type a specific value into the entry, this offers an easy way to pick out one particular value (ie, it's easy to make fine adjustments with a spin). REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, and WidthOfControl. The string for RXLABEL has some extra information in addition to the labels for all of the spin buttons in the Group, as well as the Group box label. Every spin button has a minimum and maximum value that restricts the numeric range of the spin. For example, you could have a spin that did not allow numbers greater than 100 nor less than 10. The maximum and minimum limits for a particular spin must be specified, in that order, before the spin's label. One spin's parameters must be separated from the next spin's parameters by a | character. So, the order of the parameters in the RXLABEL string is: First spin's maximum limit First spin's minimum limit First spin's label | Second spin's maximum limit Second spin's minimum limit Second spin's label | etc. Group box label If you desire no groupbox label, simply omit it. If you desire a spin with no label, then omit that spin's label (although you still must specify a maximum and minimum limit). Note: The maximum limit of a spin is limited to 255 (ie, it can span 256 different values). The low limit is 0. The limits are inclusive. That is, if you set the low limit to 10 and the high limit to 20, then the spin can be set to the value 10 or 20, as well as any number inbetween. RXVAL is a string containing the initial values of all the spin buttons in the group starting with the first. You must specify an initial value for each spin. For example, if you have 3 spin buttons, and you want to set the first spin initially to 30, the second spin to 5, and the third spin to 0, set RXVAL to '30 5 0'. Note: Don't forget to put quotes around the numeric values in the RXVAL string. You need to specify all of numbers as one string. RXFLAGS can be any, all, or none of the following: 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this drop box group) when an item from a list is selected or user types into the entry and presses ENTER. RXX reflects the position of the entry box of the first spin, not its label (which needs room to the left of the entry in order to be displayed). Therefore, set RXX far enough to the left to leave room for the label. REXX Return Rexx Dialog sets the Group's RXVAL string to contain the current values of all the spin buttons in the group, starting with the first. Examples /* This creates a window called "Spin Me" containing a Group of 1 spin button, labeled "Range:" with a group box labeled "Value". The spin has a max limit of 20 and a min limit of 10, and is initially set to 19. */ RXTYPE.1 = 'SPIN' /* Default */ RXFLAGS.1 = ' ' /* Max, Min, Label for each slider, and groupbox */ RXLABEL.1 = '20 10 Range:|Value' /* Values for each spin */ RXVAL.1 = '19' /* TotalControls, ControlsPerLine, WidthOfControls */ RXINFO.1 = '1 1 70' /* Position */ RXX.1 = 80 RXY.1 = 18 /* Create "Spin Me" window */ RXDIM = '190 86 30 30' RXDLG 1 '"Spin Me"' 'RXDIM' 'RESULT' /* Now display the value the spin. Since there's only 1 in this Group, we don't need to parse the RXVAL string for the Group to extract the spin's value */ RXSAY 'value =' RXVAL.1 ═══ 5.3.3.9. Slider ═══ Type SLIDER Description Like a spin, the slider also deals with numeric values. A slider has a shaft, and a knob that can be "grabbed" with the mouse (ie, place the mouse pointer over the knob, and press and hold down the mouse button) and moved along the shaft. The numeric value of the slider will change as the knob moves, with the far left position being 0 and the far right position being the maximum range of the slider. Alternately, when a slider has the focus (ie, its knob has a black dot on it), the knob can be moved with the left and right cursor keys. There are also two arrows immediately to the right of the shaft, which can be used to adjust the value in fine amounts (ie, single steps). Alternately, if the mouse is clicked to either side of the knob (but not on the knob itself), the value will increment or decrement (depending upon which side of the knob the mouse was clicked). The slider may also have a "detent", which is a small black marker above the shaft, which if the user clicks upon, forces the knob to jump to that position. If the user changes the value of a slider (either by moving and releasing the knob, pressing the ENTER key when the knob is highlighted, clicking upon the arrows, clicking to either side of the knob, or clicking upon a detent), RXDLG will return if the END Flag is set for this control's group. There is a limit of 256 sliders per Group. If Labels are specified, there is a limit of 128 sliders per Group. If values are printed out, then there is a limit of 64 sliders per Group. Uses Allows the user to cycle through a wide range of numeric values very quickly, albeit hard to pinpoint specific settings, and therefore is more appropriate to use for setting parameters where very fine adjustments aren't as important as being able to quickly cycle through a large range. REXX Setup RXINFO is a string specifying the TotalControls, ControlsPerLine, and WidthOfControl. The WidthOfControl must be wide enough for OS/2 to have enough pixel resolution to display the range of values (ie, steps) that you want the slider to encompass. If the width is not wide enough to accomodate the range of values, then OS/2 will not display the slider shaft. Only the knob may be visible, and subsequent updating of the slider display will be bizarre to say the least. PM's slider needs fixing. The string for RXLABEL has some extra information in addition to the labels for all of the sliders in the Group, as well as the Group box label. Every slider button has a value that determines how many steps the slider can move (ie, its range of values). For example, you could have a slider that could be set to one of 20 different steps. Also, a slider may have a detent. The NumOfSteps and Detent for a particular slider must be specified, in that order, before the slider's label. One slider's parameters must be separated from the next slider's parameters by a | character. So, the order of the parameters in the RXLABEL string is: First slider's NumOfSteps First slider's Detent First slider's label | Second slider's NumOfSteps Second slider's Detent Second slider's label | etc. Group box label If you desire no groupbox label, simply omit it. If you desire a slider with no label, then omit that slider's label (although you still must specify NumOfSteps and Detent). If you desire no Detent, then set Detent to 255. The Detent value is not in terms of steps, but rather pixels from the left of the slider shaft. Therefore, if the slider WidthOfControl is 128, and you wish to place a Detent halfway across the slider, then set Detent to 64. Note: The maximum range of a slider is 0 to 254 (ie, 255 steps). The NumOfSteps setting is exclusive. That is, if you set NumOfSteps to 20, then the slider can be set to a value from 0 to 19 (ie, a total of 20 steps). RXVAL is a string containing the initial values of all the sliders in the group starting with the first. You must specify an initial value for each slider. For example, if you have 3 sliders, and you want to set the first slider initially to 30, the second slider to 5, and the third slider to 0, set RXVAL to '30 5 0'. Note: Don't forget to put quotes around the numeric values in the RXVAL string. You need to specify all of numbers as one string. RXFLAGS can be any, all, or none of the following: 'VALUE' Automatically prints out the current value of the slider to the right of the shaft. 'END' Causes RXDLG to return (with all RXVALs set for all Groups in the active dialog window, including this drop box group) when an item from a list is selected or user types into the entry and presses ENTER. RXX reflects the position of the shaft of the first slider, not its label (which needs room to the left of the shaft in order to be displayed). Therefore, set RXX far enough to the left to leave room for the label. REXX Return Rexx Dialog sets the Group's RXVAL string to contain the current values of all the sliders buttons in the group, starting with the first. Examples /* This creates a window called "Slide Me" containing a Group of 1 slide button, labeled "Range:" with a group box labeled "Value". The slider has 20 steps, a detect at 45 (ie, in the center), and is initially set to 12 */ RXTYPE.1 = 'SLIDER' /* Print value as slider moves */ RXFLAGS.1 = 'VALUE' /* NumOfSteps, Detent, Label for each slider, and groupbox */ RXLABEL.1 = '20 45 Range:|Value' /* Values for each slider */ RXVAL.1 = '12' /* TotalControls, ControlsPerLine, WidthOfControls */ RXINFO.1 = '1 1 90' /* Position */ RXX.1 = 80 RXY.1 = 18 /* Create "Slide Me" window */ RXDIM = '230 86 30 30' RXDLG 1 '"Slide Me"' 'RXDIM' 'RESULT' /* Now display the value of the slider. Since there's only 1 in this Group, we don't need to parse the RXVAL string for the Group to extract the slider's value */ RXSAY 'value =' RXVAL.1 ═══ 5.3.3.10. Text ═══ Type TEXT Description This merely displays phrases of text. A phrase is any number of words and punctuation that is not broken by a line feed. The user can't edit nor select the text in any way. It's simply for the purpose of displaying text in a window. There is a limit of 256 phrases per Group. A TEXT Group can't cause RXDLG to return. Uses Can be used to display instructions, or label things in a window, or display some message to the user. REXX Setup RXINFO is a string specifying the TotalPhrases, PhrasesPerLine, and WidthOfPhrase, and SpaceBetweenPhrases. SpaceBetweenPhrases is only effective if PhrasesPerLine is greater than 1 (ie, you're putting more than one phrase on a line). In this case, SpaceBetweenPhrases allows you to evenly space out the phrases, which is handy if you need to make columns of data (where SpaceBetweenPhrases would be the space between columns). If you're going to place more than one phrase upon a line, then SpaceBetweenPhrases should be 8 or more. If WidthOfPhrase is 0, then Rexx Dialog automatically sets up all of the phrases to be as wide as the longest phrase, which ensures that no phrase will be visually clipped. Otherwise, if you specify a WidthOfPhrase, make sure that is wide enough to accomodate the widest phrase. WidthOfPhrase is limited to 255 pels maximum. (If you need to set a wider default, use RXSET's SIZE command after creating the Group). If you're going to be changing a phrase later with the RXSET command, then either make sure that you aren't going to change it to some phrase that is wider than the widest original phrase in the group, or specify a WidthOfPhrase to accomodate any changes that will be made to the phrase, or use RXSET's SIZE command to size a particular phrase as desired (the 255 pel limit does not apply to RXSET's SIZE command). The string for RXLABEL contains all of the phrases in the Group, as well as the Group box label. Each phrase is separated from the next by a | character. The group box label is last (or omitted if no group box is desired). If you want a blank area where a phrase would go (this would be a blank line if PhrasesPerLine=0), then simply put a space where that phrase would be specified. RXVAL is not used, and need not be initialized. RXFLAGS can be any, all, or none of the following: 'CENTER' Each phrase is centered relative to the other phrases on lines above or below. 'RIGHT' All phrases are aligned along the right margin. Note: If neither RIGHT nor CENTER flags are specified, then all phrases are aligned along the left margin. REXX Return None. A TEXT Group doesn't interact with the user in any way, nor does it cause RXDLG to return. Examples /* This creates a window called "Text" containing 1 TEXT Group with 3 lines of centered text with a groupbox */ RXTYPE.1 = 'TEXT' /* Center the text */ RXFLAGS.1 = 'CENTER' /* Text lines */ RXLABEL.1 = 'PLEASE READ!|This is a REXX example of|centered text.|Text Stuff' /* TotalPhrases, PhrasesPerLine, WidthOfPhrase, BetweenPhrases. Note: because we want WidthOfPhrase and BetweenPhrases to be 0, then we can omit both args. Rexx Dialog sets omitted args to 0 */ RXINFO.1 = '3 1' /* Position */ RXX.1 = 10 RXY.1 = 10 RXDIM = ' ' RXDLG 1 '"Text"' 'RXDIM' 'SIZE|RESULT' ═══ 5.3.3.11. Group Box ═══ Type GROUP Description This is a rectangular box, within which other controls can be placed. The box can have its own label, which usually pertains to whatever is the purpose of the controls within the box. A group box can't cause RXDLG to return. Uses Identifies controls that "belong together" usually because they are all related to one operation. REXX Setup A GROUP Type only describes one group box. In other words, it isn't a group of group boxes. You can have more than 1 GROUP in a window, but of course, you'll have to specify each separately. RXINFO is a string specifying the Width and Height of the group box (in pixels). RXLABEL is the label for the group box (or a null string if no label desired, ie, the group box is simply a rectangular box). RXVAL is not used, and need not be initialized. RXFLAGS is not used, and should be set to a null string. Note: A GROUP must be specified before any of the controls that will be displayed inside of it, otherwise the group box will draw over those controls and visually wipe them from the display. REXX Return None. A GROUP doesn't interact with the user in any way, nor does it cause RXDLG to return. Examples /* This creates a window called "Group" that contains a GROUP box */ RXTYPE.1 = 'GROUP' /* Default */ RXFLAGS.1 = ' ' /* Label */ RXLABEL.1 = 'Everything' /* Width, Height */ RXINFO.1 = '240 220' /* Position */ RXX.1 = 6 RXY.1 = 6 RXDIM = ' ' RXDLG 1 '"Group"' 'RXDIM' 'SIZE|RESULT' ═══ 5.3.3.12. Menu ═══ Type MENU Description A menu attaches to the titlebar of the window, and will drop down when the user clicks the mouse on a Menu Heading in the titlebar (ie, the menu attached to that Menu Heading drops down). The user can then make selections with the mouse. Alternately, if the menus have "mnemonic keys", those keys can be used to open and select menu items. Note: There must only be 1 MENU Group per window, and there is a limit of 256 Labels in a menu. Uses Operations that can be arranged into groups lend themselves well to being put into a menu. For example, all file load and save operations may be placed into a menu with a heading of "File". REXX Setup RXINFO is a string specifying the TotalMenus (ie, total Menu Headings), and then the REXX stem variable names (where the menu labels are fetched) for all of the menus (headings). Each variable name is separated from the next by a | character. If TotalMenus is 0, then an "empty" menu is created, and the variable names do not need to be supplied. This is more memory efficient if you plan upon using the RXSET ADD Operation to later create a new menu bar. Note: Placing a ~ character before some letter in a Label, means that, when the menu is displayed, pressing that letter on the keyboard activates the menu item\subitem associated with that label. This is a mnemonic. RXLABEL need not be initialized. RXVAL need not be initialized. RXFLAGS can be any, all, or none of the following: 'HELP' A "Help" menu is automatically added to the end of the menu bar, containing 4 Help Items labeled "Help index", "General Help", "Using Help", and "Keys Help". Whenever the user selects one of these Items, Rexx Dialog automatically handles this (ie, and RXDLG doesn't return) by displaying an appropriate panel in any help file attached to the window. See RXHELP. The Help File that you write should have a panel with the name KEYS that lists any keyboard commands for the program. If there are no such keyboard commands, then do not name any panel KEYS. REXX Return RXID is the Group number for this MENU Group (ie, if the MENU Group is the First Group in the window, then RXID is 1). RXSUBID is the menu label number. This will depend upon which item or subitem was chosen. The menu labels are numbered from top to bottom, and left to right. For example, assume that you have w Menu Headings labeled "File" and "Edit". "File" has 2 items labeled "Open" and "Save". The first item ("Open") has 2 subitems labeled "All" and "Excerpt". Here's how the menu would look displayed: ╒════════╕ ╒════════╕ │ File │ │ Edit │ ├────────┤╒═══════╕ │ Open->││All │ │ Save ││Excerpt│ ╘════════╛╘═══════╛ "File" is label 1. "Open" is label 2. But, since "Open" has two subitems, we count those before moving on to "Save". So, "All" is label 3, and "Excerpt" is label 4. "Save" is label 5. That's all of the items\subitems in the first menu, so moving on to the next menu, "Edit" is label 6. The first item in the "Edit" menu would be label 7. Etc. If you specify the HELP Flag, then the first 5 label numbers correspond to the Help Heading, and the 4 Help Items, "Help index", "General Help", "Using Help", and "Keys Help", even though the Help menu appears last on the menu bar. Therefore, the menu label that actually appears on the left side of the menu bar is label number 6. So, if we had a HELP menu in the above example, then the label numbering would be changed to be "File" = 6, "Open" = 7, "All" = 8, "Excerpt" = 9, "Save" = 10, and "Edit" = 11. Examples The REXX stem variable for a particular menu is setup such that a stem of 0 is assigned the heading of the menu. Subsequent stems starting at 1 are the item labels. A null string must mark the end of the items. For example, if you have a menu with a heading of "File" and 2 items labeled "Item 1" and "Item 2", and the REXX variable name you supplied in the RXINFO string is 'MENU', then here is the setup: /* Menu Structure */ MENU.0 = 'File' /* Heading */ MENU.1 = 'Item 1' /* First Item */ MENU.2 = 'Item 2' /* Second Item */ MENU.3 = ' ' /* End of Items */ If an item has any subitems, the number of subitems should be placed after that item's label, separated by a | character. The labels for those subitems are assigned to compound variables where an extra stem is added to the item's variable name. The extra stem is the subitem number, starting with 1. For example, if "Item 1" had 2 subitems labeled "Sub 1" and "Sub 2": /* Menu Structure */ MENU.0 = 'File' /* Heading */ MENU.1 = 'Item 1|2' /* First Item, # of subitems */ MENU.2 = 'Item 2' /* Second Item */ MENU.3 = ' ' /* End of Items */ MENU.1.1 = 'Sub 1' /* First SubItem for Item 1 */ MENU.1.2 = 'Sub 2' /* Second SubItem for Item 1 */ As a further example, assume "Item 2" had 1 subitem labeled "hello": /* Menu Structure */ MENU.0 = 'File' /* Heading */ MENU.1 = 'Item 1|2' /* First Item, # of subitems */ MENU.2 = 'Item 2|1' /* Second Item, # of subitems */ MENU.3 = ' ' /* End of Items */ MENU.1.1 = 'Sub 1' /* First SubItem for Item 1 */ MENU.1.2 = 'Sub 2' /* Second SubItem for Item 1 */ MENU.2.1 = 'hello' /* First SubItem for Item 2 */ ═══ 5.3.4. The TAB key ═══ Pressing the TAB key causes the focus (ie, which control is active) to switch to the next control in the window (regardless of whether the next control is within the same Group as the control that currently has the focus). This allows using the computer keyboard to select which control is active. In conjunction with the ENTER and SPACE BAR (for buttons and multiple select lists), any control can be activated, manipulated, and then selected without requiring a mouse. Holding down the CTRL key while pressing TAB causes the focus to jump to the first control of the next Group within a window. This allows quickly jumping from Group to Group. If no control has the focus (ie, the window itself has the focus), then pressing the TAB key causes the focus to jump to the first control of the first Group. Even if the END flag is set for a Group, when the user switches the focus from a control in that Group, RXDLG does not return. Therefore, it's possible for the user to select various controls via the TAB key, changing their values, and never having to cause RXDLG to return. In order to have a control (in a Group with its END Flag set) cause RXDLG to return, the user must explicitly indicate that he is done manipulating the control (for example, he has to press the ENTER key when he's done entering text into an ENTRY. If he instead presses TAB to switch to another control, RXDLG doesn't return for that ENTRY). ═══ 5.3.5. NOCLOSE Flag ═══ There are a few reasons why you may want to specify NOCLOSE when creating a window. Let's assume that you want to get input from the user, perform some operation using that input, and then get some more of the same type of input from the user. You could open a window without NOCLOSE, and when RXDLG returns, it will have returned the user input and closed the window. You could then perform the operation, and subsequently call RXDLG to reopen the same window. Here's an example of that approach: /* =============== Create "Main Window" ================= */ /* Just put 1 Group of checkmark buttons in it */ RXTYPE.1 = 'CHECK' RXFLAGS.1 = 'NUMBERED' RXLABEL.1 = 'Pick one' RXINFO.1 = '16 4 0' RXVAL.1 = '1' RXX.1 = 10 RXY.1 = 10 RXWIN1 = ' ' here: /* Don't specify NOCLOSE */ RXDLG 1 '"Main Window"' 'RXWIN1' /* No Flags arg needed, as there's nothing to specify */ /* Now we use RXDLG's second template to perform user interaction. No window or operation arg means "Use Main Window" and "Operation 0" (ie, perform user interaction, but don't clear any NOCLOSE Flag -- not applicable here since we never set that flag anyway) */ RXDLG /* The window is now closed */ /* At this point, we examine the REXX return values, and perform some operation. Then we jump back to "here" */ SIGNAL here In the above example, the window would be opening and closing for each iteration. What if you wanted the window to stay open until you had completed as many iterations as desired? Well, that's where NOCLOSE comes in. Here's the revamped version (from the label "here" -- everything up to that point remains the same): here: /* Specify NOCLOSE, so RXDLG doesn't close the window when it returns */ RXDLG 1 '"Main Window"' 'RXWIN1' 'NOCLOSE' more: /* Now we need to use RXDLG's second template to perform user interaction. No window or operation arg means "Use Main Window" and "Operation 0" (ie, perform user interaction, but don't tell Rexx Dialog that it's OK to close the window) */ RXDLG /* The window is still open */ /* At this point, we examine the REXX return values, and perform some operation. Then, we can jump back to the label "more" to do more user interaction. We don't jump back to "here" because we don't need to open the window again */ SIGNAL more Another reason to use NOCLOSE is if you have a Group which you want to cause RXDLG to return (ie, you specified the 'END' Flag for the Group), but you don't want that to cause the window to be closed. For example, maybe each checkmark button in the above group causes the REXX script to turn on/off something, and you want this action to be performed in realtime. (ie, As soon as the user selects a checkmark, turning it on or off, you want control to return to the REXX script so that you can carry out that operation immediately. Therefore, you have to specify the END Flag for the Group, because otherwise, RXDLG wouldn't return after each click on a checkmark -- it would only return when the user clicked on the CLOSE ICON for the window). But, you don't want the window to close down everytime that he clicks on a checkmark in that Group either. So, you need to specify NOCLOSE too. ═══ 5.3.6. MODAL Flag ═══ Normally, the WindowTitle arg for the second template of RXDLG will either be omitted (if also doing an Operation of 0), or specified as a pair of double quotes inside of single quotes (ie, '""') meaning that you wish Rexx Dialog to initiate user interaction upon the window that was active during the previous call to RXDLG. There may be times when you have multiple windows open, but you want to force the user to interact with only one of the windows (ie, disable interaction with the other windows). You do this by specifying the MODAL Flag when you create the window, and then passing that window's title to RXDLG when doing an Operation that performs user interaction (ie, 0 or 1). Rexx Dialog will disable all other windows (and any controls in the Main Window). The user must interact with only that window (although he is allowed to minimize or resize the Main Window, and perhaps switch to another app). Only when that window is destroyed will this "Modal State" also be ended. Note: The Main Window can't be made MODAL. By making Child Dialogs modal, and then passing the title of the specific window that you wish to be the "active" window to RXDLG, you can control the user's interaction with multiple open windows. ═══ 5.3.7. Opening windows within a message loop ═══ For windows that are going to be open during the life of your script, you normally will make a series of calls to RXDLG, using the first template, to create all of those windows. Then, after all windows are open, you'll drop into a "message loop" around a call to RXDLG using its second template to do user interaction upon the windows. But, you can call RXDLG, using the first template, to create new windows at any time, including within that message loop. For example, you could have a button in the Main Window which causes RXDLG to return. When your message loop detects that this button in Main Window has been pressed, you could call RXDLG to create a new window. But, your message loop should also contain instructions to specifically handle any situation where RXWIND is returned as the name of that new window. After all, that will be one more open window that the user can choose to interact with. ═══ 5.3.8. A message loop within a message loop ═══ Let's assume that you have a button in the Main Window labeled "Players names" which causes RXDLG to return. When your message loop detects that this button in Main Window has been pressed, you want to call RXDLG to create a new window with an ENTRY for the user to type in some person's name. Each time that the person types in a name, you want to add this to a stem variable, clear the ENTRY, and let him type in another player's name. During this entire process, you want to prevent him from interacting with other windows. When he finally enters a blank name, or clicks upon the window's CLOSE ICON, then you'll close the window, and return to allowing the user to interact with whatever other windows are open at his discretion. For that ENTRY window, you'll make it MODAL, and then do what appears to be a message loop (on that MODAL window) inside of the larger message loop. /* =============== Create "Main Window" ================= */ /* Just put 1 Push button in it */ RXTYPE.1 = 'PUSH' RXFLAGS.1 = 'END' RXLABEL.1 = 'Players names' RXINFO.1 = '1 1 0' RXVAL.1 = '1' RXX.1 = 10 RXY.1 = 10 RXWIN1 = ' ' RXDLG 1 '"Main Window"' 'RXWIN1' 'NOCLOSE' /* Perhaps open more windows now... */ /* Put any window's Dimensions strings outside of the message loop so it only gets initialized once */ RXWIN2 = '150 70 50 50' more: /* Do user interaction upon main (and any other open) windows */ RXDLG /* Did the user click on the Main Window's CLOSE ICON? If so, end the program */ IF RXID < 0 THEN DO IF RXWIND = 'Main Window' THEN EXIT END ELSE SELECT WHEN RXWIND = 'Main Window' THEN DO /* There's only 1 button in Main, so don't bother checking RXID and RXSUBID */ /* Open that Child Dialog with the ENTRY. NOCLOSE and MODAL */ RXTYPE.1 = 'ENTRY' RXFLAGS.1 = 'END' RXLABEL.1 = 'Name:' RXINFO.1 = '1 1 60' RXVAL.1 = 'TEXT' RXX.1 = 50 RXY.1 = 10 TEXT.1 = ' ' RXDLG 1 '"Player Name"' 'RXWIN2' 'NOCLOSE|MODAL' /* Get the next name */ name = 1 DO WHILE name > 0 RXDLG '"Player Name"' /* Did the user click on window's CLOSE ICON? If so, return to main loop */ IF RXID < 0 | TEXT.1 = 0 THEN DO RXDLG '"Player Name"' 4 name = 0 END ELSE DO NAMES.name = TEXT.1 name = name + 1 RXSET '"Player Name"' 1 1 'VAL' END END END END /* Go back to the "main" message loop */ SIGNAL more ═══ 5.4. RXERR ═══ Template RXERR Flags Description This command controls whether Rexx Dialog automatically displays error message boxes when an error occurs (as a result of calling some Rexx Dialog command). It also controls whether error messages or error numbers are returned to a script. Sometimes, it's easier for a script to deal with error numbers rather than messages when trying to recover from some error situation. If Rexx Dialog is allowed to automatically display, this also controls whether just the error message is displayed, or whether the line number and REXX source where the error occurred is also displayed in a message box. RXERR can be called at any time. (ie, You can change the error behavior at any time via a call to RXERR). Args Flags A string that describes the various display and control options for error returns. You can specify any or all of these Flags, and each one must be separated by a | character, enclosed in quotes. The various Flags are: NUM Return error numbers instead of error messages. For example, if you pass the title of a window that isn't open to RXDLG (ie, using its second template), then RXDLG will return, setting the special variable RC to error number 10011 rather than the message "Can't find Rexx Dialog.". FULL If Rexx Dialog is automatically displaying error messages for a particular error number, then you want the line number and REXX source where the error occurred to also be displayed. (Without this flag, Rexx Dialog displays only the error message). A display level (ie, numeric arg) can also be specified. Rexx Dialog displays error messages for all errors that have a display level less than or equal the specified level. If display level is 0, then Rexx Dialog never displays error messages (having to do with calls to Rexx Dialog functions -- the REXX Interpreter may still present message boxes for such things as syntax errors, etc). If display level is not specified, then Rexx Dialog will display any error message having to do with a Rexx Dialog function. Note: A particular error's display level is simply the rightmost two digits of the error number. For example, the "Can't find Rexx Dialog" error has an error number of 10011. It's display level is therefore 11. If you specify a display level of 10 to RXERR, then Rexx Dialog will not automatically display the "Can't find Rexx Dialog" error message (nor any error messages with higher display levels). See Errors for details on the error number for all Rexx Dialog error messages. It doesn't matter in which order flags are specified. When you specify FULL, any Rexx Dialog errors that are to be automatically displayed generate a REXX FAILURE condition. Otherwise, Rexx Dialog errors generate a REXX ERROR condition. Returns None Examples /* This specifies that Rexx Dialog is not to display any error messages (ie, display level is 0), and is to return error numbers for RC */ RXERR 'NUM|0' ═══ 5.5. RXFILE ═══ Template RXFILE Type FilenameVar ButtonLabel '|' Title Description This command presents the OS/2 File Dialog, whereby the user can pick out a filename (complete with path), which is returned to the script. The File Dialog will open on the Desktop if there are no windows open. Otherwise, it will open in the Main Window, and will be a modal dialog (ie, user can't interact with any windows until the File Dialog is dismissed). Args Type is either 'LOAD' or 'SAVE'. If 'LOAD', then the user is allowed to click upon a filename in the list of files in the displayed directory, and that selection is copied to the filename entry. If 'SAVE', the user can't click upon a filename in the list. The list is just for reference, and the user must manually type in the desired name. The latter scheme makes it more difficult to accidentally click on an existing file, which would be dangerous for a save operation. FilenameVar is the name of the REXX variable where the filename will be returned. Before the call to RXFILE, this must be initialized with a file or path name in order to bring up the File Dialog displaying the contents of that directory. For example, assume that FilenameVar will be RXNAME. Setting RXNAME to 'C:\OS2\*.exe' will display all of the files in the 'C:\OS2' directory that end in an '.exe' extension. If you want to display all files in a directory then use '*.*', for example 'C:\OS2\*.*'. If you want to display the current directory, with no filtering, then set the variable to a null string (ie, ' '). ButtonLabel is a string that you want displayed in the "OK" button of the File Dialog. If omitted, the default string is "OK". Title is the string that you want displayed in the titlebar of the File Dialog. If omitted, then the titlebar is blank. If this is specified, you must place a | character in quotes inbetween the ButtonLabel and Title. (It's ok to omit any ButtonLabel before the | character, if desired). Returns If Rexx Dialog is returning strings (ie, the NUM flag has not been specified to RXERR), then a null string '' is returned if the user clicked upon the "OK" button to end the dialog. "Cancel" is returned if the user clicked upon the CANCEL button to end the dialog. (The CANCEL button does not raise a REXX FAILURE or ERROR, nor does it automatically display an error message, so you must explicitly check the RC return of RXFILE in order to determine if the user cancelled the filename selection. If Rexx Dialog is returning numbers, then 0 is OK, and 350 is CANCEL. This may return other errors as described in Errors, which raise a REXX FAILURE or ERROR. If an OK selection, the filename is returned in the REXX variable specified by the FilenameVar arg. This will be a fully qualified filename (ie, with the drive and directory too). Examples /* This gets a filename selection and checks for 'OK' selection */ /* Store the filename in the variable FN. Initialize it to '*.cmd' in order to initially display all filenames in the current directory that end in '.cmd' */ FN = '*.cmd' RXFILE 'LOAD' 'FN' 'Load Me|' 'This is the title' IF RC = '' THEN DO /* check for 0 if Rexx Dialog returning numbers */ /* Do some operation with the filename in FN */ END ═══ 5.6. RXHELP ═══ Template RXHELP 'CREATE' WindowTitle HelpFilename RXHELP 'FREE' WindowTitle RXHELP Panel WindowTitle Description This command attaches or detaches an OS/2 Help file to a window, and then can to be used to display a help "panel" from that help file (ie, page within the book). It has 3 templates depending upon whether you want to attach a help file, detach a help file, or display a panel within a help file. RXHELP uses OS/2's Information Presentation Manager Facility. For example, this book that you're reading is an example of IPF. You use OS/2's Information Presentation Facility Compiler, IPFC.EXE, to create a .HLP file (ie, write a script with the imbedded IPF "tags" and compile it into a HLP file). Then, you can attach such a file to a window using RXHELP. Each window can have a different HLP file attached to it. Only one help file can be attached to a given window. Note: You can attach a help file to a window, and then later attach a different help file to that same window. But, if there are any Child Dialogs that share the same help file as the Main Window (ie, you didn't supply the HelpFilename arg when attaching a help file to the Child Dialog), then you should do a 'FREE' upon those Child Dialogs before ever changing the Main Window's help file. Args If the first template is being used (ie, first arg is 'CREATE'), then this attaches a Help file to a window. If HelpFilename is omitted, then it doesn't attach a new file, but instead shares the same help file that is attached to the Main Window. Otherwise, this attaches the specified HelpFilename (ie, the name of some OS/2 Help file) to the window whose title matches WindowTitle. WindowTitle must be enclosed in quotes if there are spaces within the window title. If WindowTitle is a null string (ie, use '""'), then the Main Window will be the one to which the help file is being attached. You can call 'CREATE' at any time to change the help file attached to a window. You do not need to 'FREE' a previous help file, except as noted above for Child Dialogs that share the Main Window, when you wish to subsequently change the Main Window's help file. If the second template is being used (ie, first arg is 'FREE'), then this detaches a Help file from the window whose title matches WindowTitle. WindowTitle must be enclosed in quotes if there are spaces within the window title. If WindowTitle is a null string (ie, use '""'), then any help file is detached from the Main Window. 'FREE' only ever needs to be done as noted above. If the third template is being used, Panel is the panel number or name within the help file that you want displayed. Panel must be enclosed in quotes if there are spaces within the panel name. WindowTitle is the window whose help file is to be used to find the panel. WindowTitle must be enclosed in quotes if there are spaces within the window title. If WindowTitle is omitted, the Main Window is used. Note: The name of a panel should not start with a numeric character, although these may appear later in the name. Also, you must not name a panel such that the first 4 letters are CREA or FREE. Returns This may return some errors as described in Errors. Examples /* This attaches the file "test.hlp" (in the current dir, or along the help path) to a window named "Main", and brings up a panel named "INFO" */ RXHELP 'CREATE' 'Main' 'test.hlp' RXHELP 'INFO' 'Main' ═══ 5.7. RXQUERY ═══ Template RXQUERY WindowTitle Description This command returns (in the special REXX variable RC) a 0 if the passed WindowTitle does not match an open window, or 1 if a window with that title is open. This can be used to check whether a particular window is open. Args WindowTitle is a string to match with the title of any open window. This must be enclosed in quotes if there are spaces within the window title. Returns 0 if the specified window is not open, or 1 if that window is open. Examples /* This gets the version and revision numbers and displays each separately */ RXVERS rev = RC PARSE rev ver rev RXSAY 'Version = 'ver RXSAY 'Revision = 'rev ═══ 5.8. RXSAY ═══ Template RXSAY Message '|' Type Heading Description This command pops up a message box on the Desktop, displaying the text that you specified after the RXSAY command keyword. There will be one or more push buttons that the user can click the mouse upon in order to manually dismiss the message box. The box remains displayed, and your script is suspended, until the user dismisses that box, at which time your script resumes its processing (on the next REXX line after the call to RXSAY). Use this instead of the REXX standard SAY command. The SAY command won't display anything because the REXX script isn't being run from an OS/2 Command Prompt window, (and that's where the standard SAY command tries to send its output, with the net result that the output gets discarded). In fact, you can't use the PULL nor PARSE PULL commands either, or any other REXX standard command that tries to get input or output from a command line. But then, that's why Rexx Dialog exists -- because the former method is a lousy way to get user input and display output, and you're going to want to use Rexx Dialog's PM Interface instead. Since Rexx Dialog offers other facilities to open windows and display text, there are other ways of displaying such, but RXSAY is the easiest and is a direct replacement for the standard SAY command (mostly). Just change any reference from SAY to RXSAY, and you've changed a REXX script to output via Desktop message boxes. RXSAY doesn't recognize any ANSI sequences to change color or move the cursor. And sometimes programmers use the fact that SAY outputs to only 1 window in order to spread output of one "statement" across several calls to SAY. On the other hand, each call to RXSAY produces a distinct message box. So, the translation isn't exact, but it's close enough. Generally, what RXSAY is used for is to display error messages, or to offer the user a simple prompt, such as to ask him if he wants to overwrite an existing file. If you have a Main Window open (via the RXDLG command), then the message box is attached to that window. In this case, it won't suspend other OS/2 applications, nor lockup the Desktop until the message box is dismissed. If no Main Window is open, the message box pops up directly upon the Desktop, and the user must dismiss it before he can do anything else from the Desktop. RXSAY offers a choice of various pushbuttons that can be created at the bottom of the message box, which the user can click upon to dismiss the message box. RXSAY will then return different values depending upon which button the user clicked. For example, you can use RXSAY to present a box that displays a question and offers the user a YES or NO button, and write your REXX script to do different things based upon the returned RC. Args Message The string that you want displayed. Just like with the standard SAY command, it can be a literal string, or a variable. If you intend to supply the Type arg, then you must put a | character after the Message. This character must be enclosed in quotes in order to prevent the REXX Interpreter from misinterpreting it as a mathematical OR symbol. It's OK to omit blank spaces inbetween the | and the Message and Type args, or even to enclose all 3 in one set of quotes if you're supplying a literal string for Message. For example, all of the following are the same: RXSAY 'hello' '|' 1 RXSAY 'hello''|'1 RXSAY 'hello|' 1 RXSAY 'hello|1' Type What Buttons (ie, OK, CANCEL, YES, NO, etc) to place at the bottom of the message box, and also what graphic symbol to display next to the message (ie, Question Mark, Stop Sign, Warning Sign, etc). If Type is omitted, then there are only an OK button and a Stop Sign. For the Type arg, pick any 1 of the following button groups, and then pick out 1 of the graphic symbols, and add the two values together. BUTTONS OK 0 OK and CANCEL 1 RETRY and CANCEL 2 ABORT, RETRY and IGNORE 3 YES and NO 4 YES, NO, and CANCEL 5 CANCEL 6 ENTER 7 ENTER and CANCEL 8 GRAPHIC SYMBOLS None 0 Question Mark 16 Exclamation Mark 32 Asterisk 48 Stop Symbol 64 For example, set Type as 4+16 if you want YES and NO buttons with a Question Mark symbol. Heading The Heading that appears above the message. If you don't supply any Heading text, then a default heading is used which consists of "Rexx Dialog x.x" where x.x is the version and revision number of the Rexx Dialog release. Returns A number which represents which button the user pressed to dismiss the message box. Each of the different buttons that you can include in the box not only dismisses the box, but also returns a different value, so your script knows which one the user selected. Here are the values that each button returns. OK 1 CANCEL 2 ABORT 3 RETRY 4 IGNORE 5 YES 6 NO 7 ENTER 9 Examples /* Pop up a dialog with the question "Is your name Marvin"? Note that we stored the name in a variable. We also include YES and NO buttons, and a Question Mark symbol. */ txt='Marvin' RXSAY 'Is your name 'txt'?|' 20 IF RC = 6 THEN RXSAY 'Yes, your name is 'txt'.' Note: Don't forget the | character, somewhere within quotes, inbetween the Message and the Type args. Otherwise, the Type will be misinterpreted as part of the message and displayed in the message box after the Message. ═══ 5.9. RXSET ═══ Template RXSET WindowTitle GroupNum ControlNum Operation Value RXSET WindowTitle WindowOperation Value Description This command sets the specified control within the specified Group and Window to a particular value. In other words, it can be used to set a currently displayed control to a new value. The second template is used to change a window's characteristics. Args WindowTitle is a string to match with the title of any open window. This must be enclosed in quotes if there are spaces within the window title. WindowTitle can be an empty string, ie '""', in which case, the Main Window is used for the operation. GroupNum is the Group containing the desired control, where the first Group in the window is 1. ControlNum is the desired control, where the first control in the Group is 1. If you want the Operation to be performed upon all controls within the Group, then pass a ControlNum of 0. Operation is the operation that you desire as so: VAL Change the value of the control to the Value string. HIDE Hide the control (ie, visually remove it from the display). The Value string is a 1 if you want to hide the Label for the control (as well as the Value printout for a slider, and ALL\NONE buttons with multiple select lists and checkmark Groups), or 0 if you only want to hide the control itself. If ControlNum is 0, then all controls in the Group are hidden, as well as any surrounding groupbox. For a MENU group, the whole menu is always hidden. SHOW Show the control (if it was hidden). The Value string is a 1 if you want to show the Label for the control (as well as the Value printout for a slider, and ALL\NONE buttons with multiple select lists and checkmark Groups), or 0 if you only want to show the control itself. If ControlNum is 0, then all controls in the Group are shown, as well as any surrounding groupbox. For a MENU group, the whole menu is always shown. SIZE Size a control (ie, visually change its width and/or height). The Value string specifies the new width and height (in pels) for the control. If the width is set to 0, then the width is not changed (ie, the original width is retained). If the height is set to 0 (or omitted), then the height is not changed. If ControlNum is 0, then all controls in the Group are sized to the specified width and height, as well as any surrounding groupbox. A MENU group can't be sized. Note: The SIZE command doesn't properly relocate labels and groupboxes for ENTRY nor SLIDER controls. Furthermore, a LIST box's Height should be set to some multiple of 16. The SIZE command is provided primarily for sizing the width of TEXT or DROPBOX controls, or the width and height of LISTBOX controls. MOVE Move a control (ie, visually change its position). The Value string specifies the X and Y offsets (in pels from the current position) to move the control. If X is set to 0, then the vertical position is not changed. If Y is set to 0 (or omitted), then the horizontal position is not changed. If ControlNum is 0, then all controls in the Group are moved the specified amount, as well as any surrounding groupbox. A MENU group can't be moved. Note: If you're using the SIZE or MOVE commands upon only 1 control within a group, and that control is encircled by a groupbox, then you should HIDE the control before issuing the SIZE or MOVE commands, and then SHOW the control afterwards. This is necessary due a peculiarity in the way that OS/2 GroupBoxes handle repainting. Failure to follow this guideline may result in seeing remnants of the original control's graphic not properly erased inside of the groupbox. If the encircling groupbox is a separate GROUP from the control, then HIDE/SHOW the groupbox instead of the control. If you're issuing several SIZE and/or MOVE commands, upon several controls within a group, but one control at a time, you only need to HIDE those controls (or the groupbox) once before the MOVE/SIZE commands, and SHOW them afterwards. ADD Add the value string (ie, text for an item) to a LIST or DROP box, or add a new MENU bar. When adding a new menu bar, the old menu bar is deleted. DEL Delete a particular item (or all items) from a LIST or DROP box, or a MENU label. When deleting a menu label, if it happens to be a Menu Heading, all of the drop down items\subitems for that heading are also deleted. If the label happens to be an Item with SubItems, all of the SubItems are deleted. Note that the numbering of the labels doesn't change simply because you deleted items, subitems, or headings. You still must count those deleted labels when counting the menu labels (unless you create an entirely new menubar -- then the numbering of the labels is reset). FLAG Set Flags for the Group. In this case, the Value string will be the Flags arg as you would specify it for RXFLAGS. But, the only Flags you may set via RXSET are END, INDEX, and BOOL. The ControlNum arg is irrelevant. For the second template of RXSET, WindowOperation can be one of the following: HIDE Hide the window and all of its controls (ie, visually remove it from the display). If the Main Window, then all of the child dialogs get hidden too. SHOW Show the window (if it was hidden). MOVE Move the window. In this case, the Value string will be the X position and Y position. SIZE Resize the window. In this case, the Value string will be the Width and Height. STATE Change the window's state. In this case, the Value string will be a 0 to minimize the window, 1 to maximize the window, or 2 to restore the window. If Value arg is omitted, the window is minimized. ACTIVE Brings the window to the front of the screen, and makes it active. FLAG Set Flags for the window. In this case, the Value string will be the Flags arg as you would specify it to RXDLG. But, the only Flags you may set via RXSET are NOCLOSE, MODAL, KEYS, ONCE, and RESULT. TIME Sets the time-out for the window. In this case, the Value string will be the desired time-out in milliseconds. (1000 milliseconds = 1 second, 1000*60 milliseconds = 1 minute, etc). If you pass a Value of 0 (or omit the Value arg), then the time-out function for the window is turned off, and the timer is stopped. A non-zero time-out will start the timer. See Time out. Value is the value for the Operation. Note that you do not need to place any Value string inside of 2 sets of quotes, even if it is a literal string with imbedded spaces. Here is what Value string specifies for each Group Type when the Operation is VAL: PUSH Value is a 1 if the button is to be chosen as the default, or a 0 if the button is to be unselected. Note that if a button is selected for default, all other buttons in the Group are automatically unselected. RADIO Value is a 1 if the button is to be selected, or a 0 if the button is to be unselected. Note that if a button is selected, all other buttons in the Group are automatically unselected. CHECK Value is a 1 if the button is to be checked, or a 0 if the button is to be unchecked. ENTRY Value is the text to set into the entry box. The text should not contain a | character. Omitting the text will blank the box. DROP Value is the text to set into the entry box. The text should not contain a | character. Omitting the text will blank the box. LIST Value is the text of the item to select or deselect. This text should be followed by a | character, and then either a 1 or 0 to select or deselect any item that matches the text. If you omit the text before the | character, then all items are selected if a 1 follows the |, or all items are deselected if a 0 follows the |. Note: For single-select list boxes, only 1 item can be selected at a time, and all other items will be automatically deselected. SPIN Value is the numeric value to which the spin will be set. SLIDER Value is the numeric value to which the slider (knob) will be set. TEXT Value is the phrase to display, and ControlNum is the phrase number to replace. If the new phrase isn't as wide as the original WidthOfPhrase (ie, when the TEXT Group was created), text may be visually clipped. MENU Value is the text to set into the menu label. The text should not contain a | character. The ControlNum arg to RXSET is the menu label number. See Menu Group for how to count the labels. GROUP Value is the text to set for the groupbox label. The text should not contain a | character. Note: RESULT Type can't be used with a VAL Operation. Here is what Value string specifies for each Group Type when the Operation is DEL: LIST or DROP Value is the text of the item (in the list) to delete. If you omit the Value arg (ie, don't supply a string to match), then all items in the list are deleted (ie, the list is "emptied"). MENU There is no Value arg. The ControlNum arg specifies the menu label to delete. Note that you can delete the entire menu bar by passing ControlNum of 0 (ie, specify that you want the delete action applied to all menus in the Group). Note: Other Types can't be used with a DEL Operation. Here is what Value string specifies for each Group Type when the Operation is ADD: LIST or DROP Value is the text of the item to add to the list. This text should be followed by a | character, and then a number that specifies how you want the item added to the list. If you want the item added to the end of the list, specify -1. If you want the item added in ascending alphabetical order, specify -2. If you want the item added in descending alphabetical order, specify -3. All positive numbers represent the offset in the list where you want the item placed, with 0 being at the beginning of the list. For example, if you want to add the item as the tenth item in the list, specify 9 (because 0 is the first). Note: Put quotes around any negative numbers that you pass, for example '-1'. OS/2 REXX appears to have another bug related to recognizing the minus sign for negative numbers. MENU The Value arg are the HELP Flag, followed by the REXX variable names where each dropdown menu is defined. In other words, the Value arg is just like how you would specify the RXINFO string for a MENU Group, except that instead of the TotalMenus count in front of the variable names, you specify the 'HELP' flag followed by a | character (or just omit the 'HELP' before the | character if you don't desire a help menu). Note that you must set up all of the stem variables as you would if you were creating a MENU Group in a window. Note: Other Types can't be used with a ADD Operation. Returns This could return an error. See Errors for details. Examples /* Assume that the first Group in a window called "Window 1" is an ENTRY Group, and we want to change the contents of the 3rd entry to the string "hello there" */ RXSET '"Window 1"' 1 3 'VAL' 'hello there' ═══ 5.10. RXVERS ═══ Template RXVERS Description This command returns a string (in the special REXX variable RC) that identifies the version and revision numbers (separated by a space) of RXDLG.DLL. For example, if the version/revision number of Rexx Dialog is 1.0, then the returned string is '1 0'. Args None. Returns The version and revision numbers as one string. Examples /* This gets the version and revision numbers and displays each separately */ RXVERS rev = RC PARSE rev ver rev RXSAY 'Version = 'ver RXSAY 'Revision = 'rev ═══ 6. PM Lockups ═══ While your script is not "sleeping" within a call to RXDLG, and the script has (NOCLOSE) windows open, it may be preventing other PM apps from multitasking (due to OS/2 2.X PM having a single-threaded message queue). Only when RXDLG is allowed to perform user interaction (ie, when you call RXDLG to perform some operation that allows user interaction with those open windows) can you be assured that your script isn't locking up PM. So, if your script opens NOCLOSE windows, then whenever RXDLG returns, your script should either close all open windows (so that the user can't interact with them and perhaps cause a PM lockup while your script is busy doing something), or finish its work quickly and get back to calling RXDLG with some operation that allows user interaction. But, what if your script doesn't want to close all windows, and yet, needs to do some processing that may take a long time? In order to avoid any lockup situation, you should periodically call RXDLG with the following call: RXDLG '""' 255 Note that the WindowTitle arg is 2 double-quotes inside of single quotes. An operation of 255 cleans out the PM message queue so that no PM lockup will occur. The user will not be allowed to interact with any open windows in this call to RXDLG (other than to resize/maximize/minimize the main window), so it doesn't effect REXX variables or the window states at all. For example, assume that you have some open windows, but you need to read in the lines of a text file. Here's an example where RXDLG is called after reading in every 10 lines in order to clean out the PM message queue. This will allow the user to switch to and use other PM apps while your script is reading in the lines of the text file. IF ''\=STREAM(FileName,'c','query exists') THEN DO code=LINEIN(FileName,1,0) nLines=0 DO WHILE LINES(FileName) Lin.nLines=LINEIN(FileName) nLines=nLines+1 IF (nLines%10) = 0 THEN RXDLG '""' 255 END code=STREAM(FName,'c','close') END Note: Never use any REXX function library "sleep" function that makes a call to OS/2's DosSleep() routine. PM programs are not allowed to use DosSleep() and doing so will lockup the Desktop. Calling RXDLG automatically puts your program to sleep when the user is not interacting with it, so there is no need to use any sleep function to halt your script at any point. Simply call RXDLG with an operation that does user interaction. If you need to wakeup at a certain time in order to check upon some condition, then setup a time-out on a window (perhaps making it MODAL so that the user won't be able to change to another window). Then check the return RXID and RXSUBID both for 0 in order to detect a time-out. If you need to ensure that the user can't interfere with the time-out, then I suggest creating a window with something simple, like a TEXT group, making the window MODAL, and hiding that window. Then, when you need to do a time-out, use RXSET to set the time-out, and then call RXDLG with an operation of 0 and specify that window. After the time-out, you can use RXSET to disable further time-outs for that window. ═══ 7. Time-out ═══ A time-out can be set for a window which, when your script is sleeping in RXDLG (ie, you performed some operation that does user interaction) and the user has not done anything with that window that would case RXDLG to return during that specified time-out, then RXDLG automatically returns to your script. In this case, RXID is set to 0 (ie, just like with the ENTER key if the RESULT Flag is set, or other keys if the KEYS Flag is set), and RXSUBID is set to 0. If you wish to change the time-out value, you can do so by calling RXSET with a WindowOperation of 'TIME' and the desired time-out value. If you set a time-out value of 0, then the time-out function for that window is disabled (and any time-out that may have already occurred is cleared). Setting a time-out value of anything but 0 causes a time-out for that window to be enabled (and if the time-out was previously enabled, any time-out that may have already occurred is cleared). While your script is not sleeping in RXDLG, the timer will still be counting down for the next time-out. So, if another time-out occurs while your script is doing some processing, then upon the next call to RXDLG, your script will immediately return with another time-out. Even if more than 1 time-out occurs while your script is doing some processing (ie, you have a time-out of 10 milliseconds, but your script takes 50 milliseconds to do some processing before calling RXDLG again), you'll only be notified of a single time-out. So, the time-out should not be used as an accurate clock of elapsed time. Setting a time-out value of anything but 0 clears out any time-out that may have occurred while your script was doing some processing. So, if you wish to "rearm" the time-out before calling RXDLG, simply set the time-out value with RXSET before calling RXDLG. If you want a countdown timer (ie, the timer counts down once, and then is automatically disabled), then set the ONCE Flag for the Window. This ensures that each time you set a time-out with RXSET, you'll receive one time-out at most. The time-out value is specified in milliseconds. ═══ 8. Keyboard Input ═══ If you set the KEYS Flag for a window, whenever that window has the focus (ie, the window itself and not some control within it) and the user presses some key combo upon the computer's keyboard, RXDLG will return. RXWIND will be set to the title of the window which was active when the user pressed the key combo. RXID will be 0 or a negative number depending upon whether the user held down the ALT, SHIFT, and/or CTRL keys when he pressed another key, and whether the key is a printable key (such as "s") or an unprintable key (such as the HOME key). Note: The ALT, SHIFT, or CTRL keys, pressed by themselves, do not cause RXDLG to return. These are "modifier" keys, and only effect the value of RXID returned when the user presses another key in combination with these modifiers. When RXDLG returns, it does NOT close the window, even if that window did not specify the NOCLOSE flag. The exception to this is pressing the ESC or ENTER keys if the window's RESULT Flag is set. When the user presses a printable key, without the CTRL or ALT keys held down, then RXID is 0, and RXSUBID is that character. For example, if he presses the 'd' key alone, then RXSUBID is 'd'. If he holds down the shift key, then the shifted character printed on the key is returned. For example, if he holds down the SHIFT while pressing 'd', then RXSUBID is 'D'. If he holds the SHIFT while pressing the '1' key, then RXSUBID is '!'. If the user holds the ALT key while pressing a printable character, then RXID is -1, and RXSUBID is that character. If he also holds the SHIFT key, that will cause RXSUBID to be the shifted character as above. If the user holds the CTRL key while pressing a printable character, then RXID is -2, and RXSUBID is that character. If he also holds the SHIFT key, that will cause RXSUBID to be the shifted character as above. If the user holds both the ALT and CTRL keys while pressing a printable character, then RXID is -3, and RXSUBID is that character. If he also holds the SHIFT key, that will cause RXSUBID to be the shifted character as above. If the user presses an unprintable character without the CTRL, ALT, or SHIFT keys held down, then RXID is -4, and RXSUBID is a "virtual key number". Here are the virtual key numbers for the following unprintable characters: Break 4 BackSpace 5 TAB 6 BackTAB 7 Pause 13 Caps Lock 14 Page Up 17 Page Down 18 End 19 Home 20 Left 21 Up 22 Right 23 Down 24 Print Screen 25 Insert 26 Delete 27 Scroll Lock 28 Num Lock 29 SysRq 31 F1 32 F2 33 F3 34 F4 35 F5 36 F6 37 F7 38 F8 39 F9 40 F10 41 F11 42 F12 43 F13 44 F14 45 F15 46 F16 47 F17 48 F18 49 F19 50 F20 51 F21 52 F22 53 F23 54 F24 55 If the user holds the ALT key while pressing an unprintable character, then RXID is -5, and RXSUBID is the virtual key number as described above. If the user holds the CTRL key while pressing an unprintable character, then RXID is -6, and RXSUBID is the virtual key number as described above. If the user holds both the ALT and CTRL keys while pressing an unprintable character, then RXID is -7, and RXSUBID is the virtual key number as described above. If the user holds the SHIFT key while pressing an unprintable character, then RXID is -8, and RXSUBID is the virtual key number as described above. If the user holds both the ALT and SHIFT keys while pressing an unprintable character, then RXID is -9, and RXSUBID is the virtual key number as described above. If the user holds both the CTRL and SHIFT keys while pressing an unprintable character, then RXID is -10, and RXSUBID is the virtual key number as described above. If the user holds the ALT, CTRL, and SHIFT keys while pressing an unprintable character, then RXID is -11, and RXSUBID is the virtual key number as described above. If the user presses the ESC key, RXID is -12, and RXSUBID is 0. If the user presses the ENTER key, RXID is 0, and RXSUBID is 10. Note: If the user clicks upon the window's CLOSE ICON, RXID is -98, and RXSUBID is 0. If the window's NEWSIZE flag is set, and the window is resized, RXID is -20 and RXSUBID is 0. If the script is launched by an app other than RX.EXE, and the app wants the script to abort, RXID is - 99, and RXSUBID is 0. PM siphons off some key combos for operation of windows. For example, pressing the ALT key usually activates a window's menu bar. And CTRL + ESC switches between sessions. F1 activates any Help file attached to a window. Etc. These key combos are never seen by your script. Normally, you'll use ENTRY, DROP, and other PM controls to get strings of user input. Use of KEYS flag is meant to be used for "keyboard commands". For example, you can set KEYS for your Main Window, and when the user presses the ALT and "f" keys, you can bring up the File Dialog (ie, via RXFILE) as part of some sort of file operation. Each key combo will initiate a different operation in your script. By using mnuemonic symbols (ie, ~ placed before the letter that you wish underlined in any label for a control), and setting the KEYS Flag, you can identity and implement keyboard shortcuts that will implement the same operations as the controls in that window. Rexx Dialog ignores key releases. Only key down is detected. ═══ 8.1. ESC and ENTER Keys ═══ If the RESULT Flag is set for a window, then when the window has the focus and the user presses the ESC or ENTER key, RXDLG returns. RXID and RXSUBID are set as described in Keyboard Input. But, all of the other variables are set per this window's Groups as well, and if the window doesn't have its NOCLOSE Flag set, the window is closed. Also, the first RESULT Group (if present) in that window is setup in a FAILURE state if ESC was pressed, or SUCCESS state if the ENTER key was pressed. Note: When a control within the window has the focus, the ESC and ENTER keys instead work with that control (regardless of whether you specified the RESULT Flag). The dialog window itself must have the focus (ie, which happens automatically after the user has finished manipulating a control by pressing the ENTER or ESC keys. The ESC and ENTER keys can always be used to deactivate a control and return the focus back to the window itself. The ENTER key will usually cause a Group with its END Flag to force RXDLG to return, whereas the ESC key will not). ═══ 9. Positioning a window ═══ If you double-click the mouse 2 button anywhere in a window, this pushs the window down to the lower left corner of the Main Window (if a Child Dialog) or the Desktop (if a Main Window). Since Child Dialogs open inside of the Main Window, sometimes a situation may happen where the titlebar of the Child Dialog is beyond the border of the Main Window (and therefore inaccessible by the mouse unless you can resize the Main Window to get to that titlebar). Clicking the mouse 2 button twice is an easy way to drop the window down to the lower left corner, where the Child Dialog's controls will usually be more accessible. ═══ 10. Resizing a window ═══ If the window's NEWSIZE flag is set, then after the user resizes that window, RXDLG returns with RXWIND set to the name of the window that was resized, RXID = -20 (and RXSUBID = 0), and the window's Dimensions string is updated with the width and height (as well as X and Y position of the lower left corner relative to the Desktop). A use for this might be to issue a RXSET SIZE command to resize any LISTBOX height, or TEXT or DROPBOX width in accordance with the size of the window. Here's an example of detecting that a window has been resized, and parsing the new width and height. /* Creates a window called "Text" containing 1 TEXT Group with 1 line of centered text */ RXTYPE.1 = 'TEXT' /* Center the text */ RXFLAGS.1 = 'CENTER' /* Text lines */ RXLABEL.1 = 'Hello' /* TotalPhrases, PhrasesPerLine, WidthOfPhrase, BetweenPhrases */ RXINFO.1 = '1 1' /* Position */ RXX.1 = 10 RXY.1 = 10 RXDIM = ' ' RXDLG 1 '"Text"' 'RXDIM' 'SIZE|NEWSIZE' /* Do user interaction */ RXDLG /* Is this a resize? */ IF RXID = -14 THEN DO /* We only have 1 window, but if we had several open, we'd need to check which one was resized so that we'd know which one's Dimensions string to parse */ IF RXWIND = 'Text' THEN DO PARSE VAR RXDIM width height x y /* Now width, height, x, and y hold the window dimensions */ END END ═══ 11. Aborting a script ═══ If a script is going to be launched by an app other than RX.EXE (the app must be written to specifically use RXDLG.DLL), then upon return from an RXDLG Operation 0 or 1, you should check if RXID = -99, and immediately EXIT if so. This is the app's way of indicating that it would like your script to prematurely abort. ═══ 12. Errors ═══ All Rexx Dialog commands return either a string or number (depending upon which you specify via RXERR, but some commands always return strings). The return is stored in the special REXX symbol RC. As each command is issued, RC reflects what that command returns. The return usually tells you whether a command worked or failed (although sometimes the return provides other info instead such as which button was used to dismiss a RXSAY box). An RC of 0 (for error numbers) or an empty string, ie "" (for error strings) is considered to be a successful return. In the case of a command that could fail as a result of something that goes wrong within the command, you should always check RC after issuing that command. Alternately, since all Rexx Dialog commands set the REXX FAILURE or ERROR flags for any possible errors, you can SIGNAL ON ERROR or SIGNAL ON FAILURE to an appropriate place in your REXX script to handle such an error situation. Some Rexx Dialog commands always work if they make it past the REXX interpreter to RX.EXE. But of course, any command can fail as a result of some syntax error (ie, you typed it in incorrectly) or other errors that occur before the REXX interpreter ships the command off to RX.EXE. In this case, the ERROR or FAILURE flag is usually raised by the REXX interpreter itself, and it will return an RC value (usually a number that is not 0, instead of an empty string). Or, the interpreter may abort the script and return an error number to RX.EXE. In the case of these errors, RX.EXE displays a PM message box containing the error. The heading of the dialog will be "REXX INTERPRETER ERROR". (When you use RXSAY, the PM message box default heading is "Rexx Dialog x.x" where x.x is the version and revision number of the Rexx Dialog release). The error message provided by the interpreter usually identifies the line number in your script where the error occurred, and may also display the text upon that line. Note: The interpreter doesn't count blank lines, or lines that only contain comments. So when it reports that an error occurred upon line 5, that doesn't mean that it actually is line 5 in your text file. You need to count the lines, skipping any blank lines or lines that contain only comments in order to find the "real" line 5. If REXX aborts the script (ie, perhaps REXX detected an error with it before even starting the script running), then RX.EXE will display an error message in a PM message box. Once again, the message box will have a heading that says "REXX INTERPRETER ERROR:". If the problem was with RX.EXE being unable to set itself up or find the script that you specified to run, then the message box heading will be "Rexx Dialog x.x". The 2 different headings allow you to visually differentiate between errors with the REXX interpreter (ie, usually with the standard REXX commands, or syntax problems, etc), and errors with processing the 9 special Rexx Dialog commands (errors that occur in creating and managing the PM interface). For the meaning of REXX INTERPRETER ERROR messages, consult your REXX documentation. When developing a script, it may be advantageous to include this line at the top: RXERR 'FULL' This will force the REXX interpreter to supply the line number and REXX source where the error occurred. Here are the error messages (and corresponding error numbers) that each Rexx Dialog command may return. The bottom two (highlighted) digits of the error number indicate the "display level" for that message (to be used as a reference when you set the display level with RXERR). RXDLG When you use the first template of RXDLG, it could return any of the following errors: 211 "Can't create dialog." Rexx Dialog couldn't create the window (into which all of the Groups of controls are placed). Possible problems are: you have too many windows open and OS/2 has run out of certain PM resources, or you may have specified a window size that is too big for the display or X and Y positions that cause problems (ie, try setting the windows Dimensions string to a null string for default size and position). 212 "Can't create control: Group XXX, Control XXX." Rexx Dialog couldn't create a particular control within a Group. The XXX after "Group" will indicate which Group number the control belonged to. For example, if the control was in the first Group that you defined for the window, then XXX would be 1. The XXX after "Control" will indicate which control within the group couldn't be created. For example, if the control was in the first in the group, then XXX would be 1. Possible problems are: you have too many windows/controls open and OS/2 has run out of certain PM resources, or you specified some incorrect width for the control, or you specified some strange X and Y position for the group, or made some other error in the setup of REXX variables particularly for that one control within the Group. 213 "Bad Group Type: Group XXX, Control 1.." An unknown Group Type was encountered. The XXX after "Group" will indicate which Group number had an unknown Type. For example, if the first Group that you defined for the window had a bad Type, then XXX would be 1. Possible problems are: you specified some incorrect Type for this Group (ie, check its RXTYPE variable), or you're using an old version of RXDLG.DLL that doesn't support this Group Type (ie, use the RXVERS command to discover whether the DLL's version and revision is equal or greater than the version/revision in the title of this book). 214 "Can't create control Label: Group XXX, Control XXX." Rexx Dialog couldn't create a label for a particular control within a Group. The XXX after "Group" will indicate which Group number the control belonged to. For example, if the control was in the first group that you defined for the window, then XXX would be 1. The XXX after "Control" will indicate for which control within the Group the label couldn't be created. For example, if the control was the first in the Group, then XXX would be 1. Possible problems are: you have too many windows/controls open and OS/2 has run out of certain PM resources, or you specified some strange X position for the Group which maybe didn't leave room for a label to the left of the control, or you didn't properly specify the label for the control (ie, check the RXLABEL string for the Group to make sure that you have enough labels for all controls). 215 "Can't create Groupbox: Group XXX, Control XXX." Rexx Dialog couldn't create a particular Groupbox around a Group (or if the Type for a group is GROUP, then it couldn't create that Groupbox). The XXX after "Group" will indicate the Group number for which the Groupbox couldn't be created. For example, if the Groupbox was to encircle the first group that you defined for the window, then XXX would be 1. Possible problems are: you have too many windows/controls open and OS/2 has run out of certain PM resources, or you specified some incorrect width for the control, or you specified some strange X and Y position for the group, or you didn't properly specify the label for the Groupbox (ie, check the RXLABEL string for the Group to make sure that you have enough labels for all controls as well as the Groupbox). If the indicated "Control" number is not equal to the TotalControls parameter in the Group's RXLABEL string (with the exception of RESULT Group, or button Groups where there are "skipped" buttons), then this indicates a potential problem with not enough or too many labels in the RXLABEL string. ??? "Failed to create/set REXX variable XXX." Rexx Dialog couldn't setup some REXX return variable (for example, the RXVAL return for a Group, or RXWIND, etc). The error number can be one of several different values depending upon what the REXX Interpreter returns. This error indicates an internal problem with the REXX Interpreter, and could be anything from a memory problem to what-have-you. But, when receiving any such error, your script should assume that RXDLG has not returned a good set of values. The XXX tells which REXX variable in particular couldn't be setup. Although this message is associated with a range of error numbers, its display level is 16. ??? "Can't fetch REXX variable XXX." Rexx Dialog couldn't find some REXX variable that your script was supposed to setup prior to a call to RXDLG. (for example, the RXTYPE for a Group, etc). The error number can be one of several different values depending upon what the REXX Interpreter returns. The XXX tells which REXX variable in particular couldn't be fetched. Check to make sure that you have either defined that REXX variable in your script (ie, sometimes, with copying and pasting source code, it's easy to forget to change the extension on a stem variable to reflect the Group number), or that the NumGroups arg to RXDLG reflects how many Groups you have defined. This error message cannot be surpressed, and the REXX Interpreter forces a message box display. 10008 "Not enough memory." There is not enough free RAM in your system to setup some structures needed to create window/controls. You'll have to close down other running programs. When you use the second template of RXDLG, it could return any of the following errors: 10017 "Can't find REXX dialog." RXDLG couldn't find the specified window to perform an operation upon. Possible problems are: you've passed a WindowTitle arg to RXDLG that doesn't match any of the open windows (or perhaps omitted the WindowTitle arg, but included the Operation arg -- you must supply both, or neither). If the passed WindowTitle arg is '""' (or not supplied), then you must have at least a Main Window open. The exception to this is an operation of 255, which will never return this (or any other Rexx Dialog) error. 10007 "Too much device input to return: XXX." The string to be returned is larger than 256 characters. You might try trimming the start or end patterns, or parsing each value into its own variable. Also, the "Failed to create/set REXX variable XXX" error message\number may be encountered for Operations of 0, 1, 2, 3, and 4 (although it's a trivial problem with Operation 4 -- this just means that the Window's Dimensions string hasn't been updated). RXDEV 10005 "Can't find/setup device: XXX." RXDEV couldn't find the specified device to perform an operation upon. Possible problems are: you've passed a DevTitle arg to RXDEV that doesn't match any of the open devices (or perhaps omitted the DevTitle arg, but included the Operation arg -- you must supply both, or neither). If the passed DevTitle arg is '""' (or not supplied), then you must have at least 1 device open. Also, you must have a Main Window open in order to open a device, and the device must be opened for reading using FILEREXX's FileOpen. XXX will be the device name passed to RXDEV. 10006 "Can't start REXX device thread." Can't start a thread to read data from the device. Try closing down other OS/2 apps. 10020 "XXX Operation not supported." The operation that you specified is not recognized by this version of Rexx Dialog. XXX will be the operation that Rexx Dialog doesn't understand. Make sure that you spelled it correctly, and have a current version of RXDLG.DLL. Also, you will see this error if you forget to do an OPEN Operation on the specified DevName before attempting to do some other operation. 10009 "Bad read NNN, Device: XXX." There was an error reading the next byte from a device. XXX will be the device name (as you specified during the OPEN Operation). This error may happen when accessing a device that returns immediately when it has no bytes to return to Rexx Dialog (ie, it doesn't "block" reads). In this case, you'll have to find some way of querying the device to determine if it has any input bytes queued (ie, usually via some IOCTL vector that you'll access using FILEREXX), and read only that many bytes (using FILEREXX's reading functions). This error may also happen if CTRL-C or CTRL-BREAK is pressed, or some other operation causes the device to abort a read (if the device supports that). NNN is the error number returned from OS/2, and can be: 5 Access denied 6 Invalid handle 26 Not a DOS disk 33 Lock violation 109 Broken pipe connection 234 More data -1 Can't get a semaphore for the device thread. Try closing down other OS/2 apps. RXFILE 311 "Can't create dialog." Rexx Dialog couldn't open the File Dialog. Possible problems are: you have too many windows open and OS/2 has run out of certain PM resources, or you may have specified a bizarre filename (ie, try setting to a null string). The "Failed to create/set REXX variable XXX" error message\number may be returned if Rexx Dialog couldn't return the filename. The "Can't fetch REXX variable XXX" error message\number may be returned if Rexx Dialog couldn't fetch the initial filename. Make sure that you initialize the FilenameVar arg to RXFILE, even if you set it to a null string. RXHELP 10022 "Can't attach help file." Rexx Dialog couldn't attach the help file to the window. Possible problems are: OS/2 has run out of certain PM resources, or you didn't properly specify the help filename (ie, make sure that you spelled it correctly, and supplied a complete path if that is needed). 10021 "Can't find help panel XXX." Rexx Dialog couldn't find the specified panel number or name within the help file for the window. Possible problems are: OS/2 has run out of certain PM resources, or you didn't properly specify the panel name or number (ie, make sure that you spelled it correctly), or no such panel name or number exists within the help file that is attached to the Window specified to RXHELP (ie, make sure that you have the correct window and help file). The "Can't find REXX dialog." error message\number may be returned if the WindowTitle you specified doesn't match any open window. RXSAY RXSAY never causes a REXX FAILURE or ERROR, but always returns a number (regardless of RXERR's NUM flag) as described in RXSAY. RXSET 10018 "Can't find group XXX" The window that you specified doesn't contain the GroupNum that you specified. Make sure that you haven't asked for a Group number larger than the number of Groups in the window, nor a Group number of 0. 10019 "Can't find control XXX" The Group that you specified doesn't contain the control that you specified. Make sure that you haven't asked for a control number larger than the number of controls in the Group, nor a control number of 0. 10010 "Can't start timer." If you do a TIME operation to setup a timer for a window, and the timer can't be setup, this error may be returned. OS/2 has a limited number of timers available, so shut down other apps that may be using timers. The "Operation not supported." error message\number may be returned if the operation that you specified is not recognized by this version of Rexx Dialog. The "Can't find REXX dialog." error message\number may be returned if the WindowTitle you specified doesn't match any open window. RXVERS RXVERS never causes a REXX FAILURE or ERROR, but always returns a string (regardless of RXERR's NUM flag) as described in RXVERS. Other Rexx Dialog commands All other Rexx dialog commands do not return anything except successful returns (ie, 0 error numbers, or null strings). There are a few error messages that you may see that aren't related to specific Rexx Dialog commands. Unless otherwise mentioned, these will happen before your script starts executing, and usually reflect a problem in RX.EXE's setup. These error messages are always displayed unless otherwise mentioned. 20001 "Can't find REXX script to run." The script name that you specified for RX.EXE to run can't be found. Check that you spelled the script name correctly and/or supplied the correct path. If you didn't supply a path, then the script must be in the same directory as RX.EXE, or must be in the directory specified in the Working Directory or specified in the Parameters field of the Program Object for the script (if launched from a Desktop object). 20003 "Window registration failed." RXDLG.DLL couldn't properly register its special window class. Perhaps there is another running app that happens to have a similiarly named public window class. (Unlikely, but try closing down other running apps). 20004 "Can't install REXX." RXDLG.DLL couldn't properly register its REXX handler. Perhaps there is another running app that happens to have a similiarly named handler. (Unlikely, but try closing down other running apps). 10002 "REXX dialog unknown command: XXX" This error may occur while your script is running. It indicates that your script contains a command that isn't some built-in REXX command, but also isn't a Rexx Dialog command. It may be that you're trying to run some executable, for example, OS/2's DIR command. So, you have this line in your script: 'dir' The problem is that REXX is passing this command to Rexx Dialog, and Rexx Dialog doesn't have a DIR command. Normally, REXX scripts are run from the OS/2 command line, and so REXX would pass this command to the OS/2 command line, which does have a DIR command. But, when running a script with RX.EXE, REXX passes everything that it doesn't recognize as a built-in command to Rexx Dialog. In this case, you need to specifically direct that command to the OS/2 shell. You do so by putting ADDRESS CMD before the line that you want to send to the OS/2 shell (ie, CMD is the REXX environment name for the OS/2 shell, and ADDRESS tells REXX to send the following line to that environment instead of letting Rexx Dialog try to implement that line). So the line would be: ADDRESS CMD 'dir' This error message has a display level of 2. Rexx Dialog's environment name is RXDLG.