|
OpenVMS Programming Concepts Manual
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.
22.4.9 Controlling Screen Updates
If your program needs to make a number of changes to a virtual display,
you can use SMG$ routines to make all of the changes before updating
the display. The SMG$BEGIN_DISPLAY_UPDATE routine causes output
operations to a pasted display to be reflected only in the display's
buffers. The SMG$END_DISPLAY_UPDATE routine writes the display's buffer
to the pasteboard.
The SMG$BEGIN_DISPLAY_UPDATE and SMG$END_DISPLAY_UPDATE routines
increment and decrement a counter. When this counter's value is 0,
output to the virtual display is sent to the pasteboard immediately.
The counter mechanism allows a subroutine to request and turn off
batching without disturbing the batching state of the calling program.
A second set of routines, SMG$BEGIN_PASTEBOARD_UPDATE and
SMG$END_PASTEBOARD_UPDATE, allow you to buffer output to a pasteboard
in a similar manner.
22.4.10 Maintaining Modularity
When using the SMG$ routines, you must take care not to corrupt the
mapping between the screen appearance and the internal representation
of the screen. Therefore, observe the following guidelines:
|