Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

#### 22.4.6.3 Writing Data Line by Line

The SMG$PUT_LINE and SMG$PUT_LINE_MULTI routines write lines to virtual displays one line after another. If the display area is full, it is scrolled. You do not have to keep track of which line you are on. All routines permit you to scroll forward (up); SMG$PUT_LINE and SMG$PUT_LINE_MULTI permit you to scroll backward (down) as well. SMG$PUT_LINE permits spacing other than single spacing.

Example 22-7 writes lines from a buffer to a display area. The output is scrolled forward if the buffer contains more lines than the display area.

Example 22-7 Scrolling Forward Through a Display

    INTEGER*4     BUFF_COUNT,
    2             BUFF_SIZE (4096)
    CHARACTER*512 BUFF (4096)
       .
       .
       .
    DO I = 1, BUFF_COUNT
      STATUS = SMG$PUT_LINE (VDID,
    2                        BUFF (I) (1:BUFF_SIZE (I)))
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    END DO

Example 22-8 scrolls the output backward.

Example 22-8 Scrolling Backward Through a Display

    DO I = BUFF_COUNT, 1, -1
      STATUS = SMG$PUT_LINE (VDID,
    2                        BUFF (I) (1:BUFF_SIZE (I)),
    2                        SMG$M_DOWN)
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    END DO

Cursor Movement and Scrolling

To maintain precise control over cursor movement and scrolling, you can write with SMG$PUT_CHARS and scroll explicitly with SMG$SCROLL_DISPLAY_AREA. SMG$PUT_CHARS leaves the cursor after the last character written and does not force scrolling; SMG$SCROLL_DISPLAY_AREA scrolls the current contents of the display forward, backward, or sideways without writing to the display. To restrict the scrolling region to a portion of the display area, use the SMG$SET_DISPLAY_SCROLL_REGION routine.

Inserting and Overwriting Text

To insert text rather than overwrite the current contents of the screen, use the SMG$INSERT_LINE routine. Existing lines are shifted up or down to open space for the new text. If the text is longer than a single line, you can specify whether or not you want the excess characters to be truncated or wrapped.

Using Double-Width Characters

In addition, you can use SMG$PUT_LINE_WIDE to write a line of text to the screen using double-width characters. You must allot two spaces for each double-width character on the line. You cannot mix single- and double-width characters on a line.

Specifying Special Video Attributes

All line routines provide rendition-set and rendition-complement arguments, which allow you to specify special video attributes for the text being written. SMG$PUT_LINE_MULTI allows you to specify more than one video attribute for the text. The explanation of the SMG$CHANGE_RENDITION routine in Section 22.4.4.5 discusses how to use the rendition-set and rendition-complement arguments.

#### 22.4.6.4 Drawing Lines

The routine SMG$DRAW_LINE draws solid lines on the screen. Appropriate corner and crossing marks are drawn when lines join or intersect. The routine SMG$DRAW_CHARACTER draws a single character. You can also use the routine SMG$DRAW_RECTANGLE to draw a solid rectangle. Suppose that you want to draw an object such as that shown in Figure 22-5 in the statistics display area (an area of 10 rows by 55 columns).

Figure 22-5 Statistics Display

Example 22-9 shows how you can create a statistics display using SMG$DRAW_LINE and SMG$DRAW_RECTANGLE.

Example 22-9 Creating a Statistics Display

    STATUS = SMG$CREATE_VIRTUAL_DISPLAY (10,
    2                                    55,
    2                                    STATS_VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Draw rectangle with upper left corner at row 1 column 1
    ! and lower right corner at row 10 column 55
    STATUS =SMG$DRAW_RECTANGLE (STATS_VDID,
    2                           1, 1,
    2                           10, 55)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Draw vertical lines at columns 11, 21, and 31
    DO I = 11, 31, 10
      STATUS = SMG$DRAW_LINE (STATS_VDID,
    2                         1, I,
    2                         10, I)
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    END DO
    ! Draw horizontal line at row 3
    STATUS = SMG$DRAW_LINE (STATS_VDID,
    2                       3, 1,
    2                       3, 55)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$PASTE_VIRTUAL_DISPLAY (STATS_VDID,
    2                                   PBID,
    2                                   3,
    2                                   2)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))

#### 22.4.6.5 Deleting Text

The following routines erase specified characters, leaving the rest of the screen intact:

- SMG$ERASE_CHARS---Erases specified characters on one line.
- SMG$ERASE_LINE---Erases the characters on one line starting from a specified position.
- SMG$ERASE_DISPLAY---Erases specified characters on one or more lines.
- SMG$ERASE_COLUMN---Erases a column from the specified row to the end of the column from the virtual display.

The following routines perform delete operations. In a delete operation, characters following the deleted characters are shifted into the empty space.

- SMG$DELETE_CHARS---Deletes specified characters on one line. Any characters to the right of the deleted characters are shifted left.
- SMG$DELETE_LINE---Deletes one or more full lines. Any remaining lines in the display are scrolled up to fill the empty space.

The following example erases the remaining characters on the line whose line number is specified by LINE_NO, starting at the column specified by COLUMN_NO:

    STATUS = SMG$ERASE_LINE (STATS_VDID,
    2                        LINE_NO,
    2                        COLUMN_NO)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))

### 22.4.7 Using Menus

You can use SMG$ routines to set up menus to read user input. The type of menus you can create include the following:

- Block menu---Selections are in matrix format. This is the type of menu often used.
- Vertical menu---Each selection is on its own line.
- Horizontal menu---All selections are on one line.

Menus are associated with a virtual display, and only one menu can be used for each virtual display.

The menu routines include the following:

- SMG$CREATE_MENU---Creates a menu associated with a virtual display. This routine allows you to specify the type of menu, the position in which the menu is displayed, the format of the menu (single or double spaced), and video attributes.
- SMG$SELECT_FROM_MENU---Sets up menu selection capability. You can specify a default menu selection (which is shown in reverse video), whether online help is available, a maximum time limit for making a menu selection, a key indicating read termination, whether to send the text of the menu item selected to a string, and a video attribute.
- SMG$DELETE_MENU---Discontinues access to the menu and erases it.

When you are using menus, no other output should be sent to the menu area; otherwise, unpredictable results may occur.

The default SMG$SELECT_FROM_MENU allows specific operations, such as use of the arrow keys to move up and down the menu selections, keys to make a menu selection, ability to select more than one item at a time, ability to reselect an item already selected, and the key sequence to invoke online help. By using the flags argument to modify this operation, you have the option of disallowing reselection of a menu item and of allowing any key pressed to select an item.

### 22.4.8 Reading Data

You can read text from a virtual display (SMG$READ_FROM_DISPLAY) or from a virtual keyboard (SMG$READ_STRING, SMG$READ_COMPOSED_LINE, or SMG$READ_KEYSTROKE). The three routines for virtual keyboard input are known as the SMG$ input routines. SMG$READ_FROM_DISPLAY is not a true input routine because it reads text from the virtual display rather than from a user.

The SMG$ input routines can be used alone or with the SMG$ output routines. This section assumes that you are using the input routines with the output routines. Section 22.5 describes how to use the input routines without the output routines.

When you use the SMG$ input routines with the SMG$ output routines, always specify the optional vdid argument of the input routine, which specifies the virtual display in which the input is to occur. The specified virtual display must be pasted to the device associated with the virtual keyboard that is specified as the first argument of the input routine. The display must be pasted in column 1, cannot be occluded, and cannot have any other display to its right; input begins at the current cursor position, but the cursor must be in column 1.

#### 22.4.8.1 Reading from a Display

You can read the contents of the display using the routine SMG$READ_FROM_DISPLAY. By default, the read operation reads all of the characters from the current cursor position to the end of that line. The row argument of SMG$READ_FROM_DISPLAY allows you to choose the starting point of the read operation, that is, the contents of the specified row to the rightmost column in that row.

If the terminator-string argument is specified, SMG$READ_FROM_DISPLAY searches backward from the current cursor position and reads the line beginning at the first terminator encountered (or at the beginning of the line). A terminator is a character string. You must calculate the length of the character string read operation yourself.

The following example reads the current contents of the first line in the STATS_VDID display:

    CHARACTER*4 STRING
    INTEGER*4   SIZE
       .
       .
       .
    STATUS = SMG$HOME_CURSOR (STATS_VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    STATUS = SMG$READ_FROM_DISPLAY (STATS_VDID,
    2                               STRING)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    SIZE = 55
    DO WHILE ((STRING (SIZE:SIZE) .EQ. ' ') .AND.
    2         (SIZE .GT. 1))
      SIZE = SIZE - 1
    END DO

#### 22.4.8.2 Reading from a Virtual Keyboard

The SMG$CREATE_VIRTUAL_KEYBOARD routine establishes a device for input operations; the default device is the user's terminal. The routine SMG$READ_STRING reads characters typed on the screen either until the user types a terminator or until the maximum size (which defaults to 512 characters) is exceeded. (The terminator is usually a carriage return; see the routine description in the OpenVMS RTL Screen Management (SMG$) Manual for a complete list of terminators.) The current cursor location for the display determines where the read operation begins.

The operating system's terminal driver processes carriage returns differently than the SMG$ routines. Therefore, in order to scroll input accurately, you must keep track of your vertical position in the display area. Explicitly set the cursor position and scroll the display. If a read operation takes place on a row other than the last row of the display, advance the cursor to the beginning of the next row before the next operation. If a read operation takes place on the last row of the display, scroll the display with SMG$SCROLL_DISPLAY_AREA and then set the cursor to the beginning of the row. Modify the read operation with TRM$M_TM_NOTRMECHO to ensure that no extraneous scrolling occurs.

Example 22-10 reads input until Ctrl/Z is pressed.

Example 22-10 Reading Data from a Virtual Keyboard

       .
       .
       .
    ! Read first record
    STATUS = SMG$HOME_CURSOR (VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$READ_STRING (KBID,
    2                         TEXT,
    2                         'Prompt: ',
    2                         4,
    2                         TRM$M_TM_TRMNOECHO,,,
    2                         TEXT_SIZE,,
    2                         VDID)
    ! Read remaining records until CTRL/Z
    DO WHILE (STATUS .NE. SMG$_EOF)
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
      ! Process record
       .
       .
       .
      ! Set up screen for next read
      ! Display area contains four rows
      STATUS = SMG$RETURN_CURSOR_POS (VDID, ROW, COL)
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
      IF (ROW .EQ. 4) THEN
        STATUS = SMG$SCROLL_DISPLAY_AREA (VDID)
        IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
        STATUS = SMG$SET_CURSOR_ABS (VDID, 4, 1)
        IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
      ELSE
        STATUS = SMG$SET_CURSOR_ABS (VDID,, 1)
        IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
        STATUS = SMG$SET_CURSOR_REL (VDID, 1)
        IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
      END IF
      ! Read next record
      STATUS = SMG$READ_STRING (KBID,
    2                           TEXT,
    2                           'Prompt: ',
    2                           4,
    2                           TRM$M_TM_TRMNOECHO,,,
    2                           TEXT_SIZE,,
    2                           VDID)
    END DO

Note Because you are controlling the scrolling, SMG$PUT_LINE and SMG$PUT_LINE_MULTI might not scroll as expected. When scrolling a mix of input and output, you can prevent problems by using SMG$PUT_CHARS.

#### 22.4.8.3 Reading from the Keypad

To read from the keypad in keypad mode (that is, pressing a keypad character to perform some special action rather than entering data), modify the read operation with TRM$M_TM_ESCAPE and TRM$M_TM_NOECHO. Examine the terminator to determine which key was pressed.

Example 22-11 moves the cursor on the screen in response to the user's pressing the keys surrounding the keypad 5 key. The keypad 8 key moves the cursor north (up); the keypad 9 key moves the cursor northeast; the keypad 6 key moves the cursor east (right); and so on. The SMG$SET_CURSOR_REL routine is called, instead of being invoked as a function, because you do not want to abort the program on an error. (The error attempts to move the cursor out of the display area and, if this error occurs, you do not want the cursor to move.) The read operation is also modified with TRM$M_TM_PURGE to prevent the user from getting ahead of the cursor.

See Section 22.4.8.1 for the guidelines for reading from the display.

Example 22-11 Reading Data from the Keypad

       .
       .
       .
    INTEGER STATUS,
    2       PBID,
    2       ROWS,
    2       COLUMNS,
    2       VDID,     ! Virtual display ID
    2       KID,      ! Keyboard ID
    2       SMG$CREATE_PASTEBOARD,
    2       SMG$CREATE_VIRTUAL_DISPLAY,
    2       SMG$CREATE_VIRTUAL_KEYBOARD,
    2       SMG$PASTE_VIRTUAL_DISPLAY,
    2       SMG$HOME_CURSOR,
    2       SMG$SET_CURSOR_REL,
    2       SMG$READ_STRING,
    2       SMG$ERASE_PASTEBOARD,
    2       SMG$PUT_CHARS,
    2       SMG$READ_FROM_DISPLAY
    CHARACTER*31 INPUT_STRING,
    2            MENU_STRING
    INTEGER*2    TERMINATOR
    INTEGER*4    MODIFIERS
    INCLUDE '($SMGDEF)'
    INCLUDE '($TRMDEF)'
    ! Set up screen and keyboard
    STATUS = SMG$CREATE_PASTEBOARD (PBID,
    2                               'SYS$OUTPUT',
    2                               ROWS,
    2                               COLUMNS)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$CREATE_VIRTUAL_DISPLAY (ROWS,
    2                                    COLUMNS,
    2                                    VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$PUT_CHARS (VDID,
    2                       '__ MENU CHOICE ONE',
    2                       10,30)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$PUT_CHARS (VDID,
    2                       '__ MENU CHOICE TWO',
    2                       15,30)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (KID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$PASTE_VIRTUAL_DISPLAY (VDID,
    2                                   PBID,
    2                                   1,
    2                                   1)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Put cursor in NW corner
    STATUS = SMG$HOME_CURSOR (VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Read character from keyboard
    MODIFIERS = TRM$M_TM_ESCAPE .OR.
    2           TRM$M_TM_NOECHO .OR.
    2           TRM$M_TM_PURGE
    STATUS = SMG$READ_STRING (KID,
    2                         INPUT_STRING,
    2                         ,
    2                         6,
    2                         MODIFIERS,
    2                         ,
    2                         ,
    2                         ,
    2                         TERMINATOR)
    DO WHILE ((STATUS) .AND.
    2         (TERMINATOR .NE. SMG$K_TRM_CR))
      ! Check status of last read
      IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
      ! North
      IF (TERMINATOR .EQ. SMG$K_TRM_KP8) THEN
        CALL SMG$SET_CURSOR_REL (VDID, -1, 0)
      ! Northeast
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP9) THEN
        CALL SMG$SET_CURSOR_REL (VDID, -1, 1)
      ! Northwest
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP7) THEN
        CALL SMG$SET_CURSOR_REL (VDID, -1, -1)
      ! South
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP2) THEN
        CALL SMG$SET_CURSOR_REL (VDID, 1, 0)
      ! Southeast
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP3) THEN
        CALL SMG$SET_CURSOR_REL (VDID, 1, 1)
      ! Southwest
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP1) THEN
        CALL SMG$SET_CURSOR_REL (VDID, 1, -1)
      ! East
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP6) THEN
        CALL SMG$SET_CURSOR_REL (VDID, 0, 1)
      ! West
      ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP4) THEN
        CALL SMG$SET_CURSOR_REL (VDID, 0, -1)
      END IF
      ! Read another character
      STATUS = SMG$READ_STRING (KID,
    2                           INPUT_STRING,
    2                           ,
    2                           6,
    2                           MODIFIERS,
    2                           ,
    2                           ,
    2                           ,
    2                           TERMINATOR)
    END DO
    ! Read menu entry and process
    !
    STATUS = SMG$READ_FROM_DISPLAY (VDID,
    2                               MENU_STRING)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
       .
       .
       .
    ! Clear screen
    STATUS = SMG$ERASE_PASTEBOARD (PBID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))

    END

#### 22.4.8.4 Reading Composed Input

The SMG$CREATE_KEY_TABLE routine creates a table that equates keys to character strings. When you read input using the routine SMG$READ_COMPOSED_LINE and the user presses a defined key, the corresponding character string in the table is substituted for the key. You can use the SMG$ADD_KEY_DEF routine to load the table. Composed input also permits the following:

- If states---You can define the same key to mean different things in different states. You can define a key to cause a change in state. The change in state can be temporary (until after the next defined key is pressed) or permanent (until a key that changes states is pressed).
- Input termination---You can define the key to cause termination of the input transmission (as if the Return key were pressed after the character string). If the key is not defined to cause termination of the input, the user must press a terminator or another key that does cause termination.

Example 22-12 defines keypad keys 1 through 9 and permits the user to change state temporarily by pressing the PF1 key. Pressing the keypad 1 key is equivalent to typing 1000 and pressing the Return key. Pressing PF1 key and then the keypad 1 key is equivalent to typing 10000 and pressing the Return key.

Example 22-12 Redefining Keys

    INTEGER*4 TABLEID
       .
       .
       .
    ! Create table for key definitions
    STATUS = SMG$CREATE_KEY_TABLE (TABLEID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Load table
    ! If user presses PF1, the state changes to BYTEN
    ! The BYTEN state is in effect only for the very next key
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'PF1',
    2                         ,,,'BYTEN')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Pressing KP1 through Kp9 in the null state is like typing
    ! 1000 through 9000 and pressing return
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP1',
    2                         ,
    2                         SMG$M_KEY_TERMINATE,
    2                         '1000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP2',
    2                         ,
    2                         SMG$M_KEY_TERMINATE,
    2                         '2000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
       .
       .
       .
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP9',
    2                         ,
    2                         SMG$M_KEY_TERMINATE,
    2                         '9000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! Pressing KP1 through KP9 in the BYTEN state is like
    ! typing 10000 through 90000 and pressing return
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP1',
    2                         'BYTEN',
    2                         SMG$M_KEY_TERMINATE,
    2                         '10000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP2',
    2                         'BYTEN',
    2                         SMG$M_KEY_TERMINATE,
    2                         '20000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
       .
       .
       .
    STATUS = SMG$ADD_KEY_DEF (TABLEID,
    2                         'KP9',
    2                         'BYTEN',
    2                         SMG$M_KEY_TERMINATE,
    2                         '90000')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
    ! End loading key definition table
       .
       .
       .
    ! Read input which substitutes key definitions where appropriate
    STATUS = SMG$READ_COMPOSED_LINE (KBID,
    2                                TABLEID,
    2                                STRING,
    2                                SIZE,
    2                                VDID)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
       .
       .
       .

Use the SMG$DELETE_KEY_DEF routine to delete a key definition; use the SMG$GET_KEY_DEF routine to examine a key definition. You can also load key definition tables with the SMG$DEFINE_KEY and SMG$LOAD_KEY_DEFS routines; use the DCL command DEFINE/KEY to specify input to these routines.

To use keypad keys 0 through 9, the keypad must be in application mode. For details, see SMG$SET_KEYPAD_MODE in the OpenVMS RTL Screen Management (SMG$) Manual.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_059.HTML