Version 3 Technical Highlights - Input.Char
Published By | Date | Version | Knowledge Level | Keywords |
---|---|---|---|---|
Sprezzatura Ltd | 01 OCT 1992 | 3.0+ | EXPERT | INPUT.CHAR, MOUSE, VIDEO.RW, BORDER.UP, INRECT |
The central system routine for keyboard input has been modified to be "mouse aware". It now returns additional codes permitting the user to know where the mouse was when a button was clicked, and what status line button has been pressed. Thus there are now five functions of Input.Char, 1 - to handle background processing/@Priority.Int etc. 2 - To return a pressed key. 3 - To provide the mouse position when a button is clicked. 4 - To identify the status line cell that has been clicked on. 5 - To permit clicking on the top screen line to display the menu. As 1 and 2 have not changed they will not be dealt with here.
Mouse Position
Input.Char now accepts a second additional parameter MousePosFlag. If this is set to true, then if a mouse button is clicked (regardless of which mouse button) a string of length four characters will be returned in the first parameter having the format Char(0) : Char(0) : Char(X) : Char(Y) where X and Y are the ascii values representing the X and Y position of the mouse respectively. Thus if the cursor was at 65, 10, the string returned would be Char(0) : Char(0) : Char(65) : Char(10).
Status Line Cells
To display custom "mouseable" buttons on the status line requires a knowledge of status record structures. All status line images are stored in the SYSTEXT table with a row key of Name*Status where Name is the name of the status line image and Status is the literal "Status", e.g. WINDOW*STATUS. In release 3.0 this record has five fields, each field being a dynamic array having a structure as follows
<1> | Normally the name of the status line (Name above), although can be different if required. |
<2> | The information to display in each cell, value mark delimited. |
<3> | Format information for the dynamic section of cell 3. |
<4> | Reserved for compiled status line image. |
<5> | Array of start positions and lengths for active "mouseable" areas of the status line. This is a multivalue for each "mouseable" section of the status line. Each multivalue has two subvalues. The first being the start position of the area (note the relative position not the absolute position, thus the first character is 1 not 0), and the second being the length. Thus to define a hot spot with 1 at the first character of the status line, a hot spot width 10 in the middle of the status line, and a hot spot width one at the far right of the status line, field 5 would contain 1ü1ý35ü10ý80ü1 |
- Note that it is the job of the programmer to ensure that hot areas correspond to screen literals.
As many "hot areas" can be defined as are required by the application.
When a "hot area" is clicked on, Input.Char returns a string indicating which numbered hot area has been selected. This has a similar structure to the X/Y information but is only three bytes long, in this case Char(0) : Char(0) : Char(X) where X is the position in the "hot area" array. It is then the job of the programmer to act upon this information.
Note that due to the way in which this has been implemented (hot areas are not associated with code and commands, rather they just tell the calling program which area has been chosen) it is not possible to alter functionality of existing status lines. Hot area locations and legends may be changed, but choosing hot area 4 in a window will always display "Options " regardless of the legend/position. For reference there are 6 hot areas defined for the Window status line, as follows
1 | Browse previous |
2 | Browse |
3 | Browse next |
4 | Options |
5 | Softkeys |
6 | Save |
The following code shows the use of INPUT.CHAR in its modified form along with INRECT to provide a "Radio Button" window which takes as input a field mark delimited set of button names and displays a small window allowing the user to mouse to each button to toggle the button status, or tab and use the space bar to toggle status. Note that in the real world this would be rewritten using VSpace but space considerations preclude that here. Whilst it would be possible to achieve a similar result using hooks in the window processor this is shown as 3GL code merely to illustrate the use of the new routines and return values.
Function Radio_Window(ButtonLabels) /* Author AMcA, CC Date Sept 92 Purpose To display a field mark delimited set of prompts with a corresponding radio button for each prompt. These may be toggled using mouse and/or tab/spacebar and will return a dynamic array of results when <Save> is moused, or an empty array if Esc or the close button are pressed. */ Declare Function Min, Max, Esc.To.Attr, InRect Declare Subroutine Msg,Video.RW,Border.Up,Input.Char,Delay $Insert SysInclude, Logical Equ Escape$ to \1B\ Equ Tab$ to \09\ Equ BackTab$ to \000F\ GoSub SetUp GoSub DisplayScreen GoSub ProcessMouse Return ResultArray SetUp: Colour4 = \1B\:'C1O' Colour1 = Esc.To.Attr(Colour4) ButtonCtr = Count(ButtonLabels, @Fm) + (ButtonLabels#"") ResultArray = str(0:@fm,ButtonCtr) ResultArray[-1,1] = '' Rectangles = '' MaxWidth = 6 ; Pos = 0 ; Mark = 0 ; Screen = "" Ptr = 2 ; Depth = ButtonCtr * 2 Ypos = Int((@CrtHigh-(Depth+3))/2) ScreenTop = Ypos - 2 OldYpos = Ypos Loop Remove NextLabel From ButtonLabels At Pos Setting Mark MaxWidth = Max(MaxWidth, Len(NextLabel)) Screen := @(2, Ypos) : NextLabel Ypos += 2 While Mark Repeat For X = 1 To ButtonCtr Screen := @(4 + MaxWidth, OldYpos) : "[ ]" ThisBox = Char(5 + MaxWidth) : Char(OldYpos) Rectangles := ThisBox:ThisBox OldYpos += 2 Next BottomLine = '<Save>' Screen := @(2, Ypos) : BottomLine Rectangles := Char(3):Char(Ypos):Char(6):Char(Ypos) Rectangles :=Char(3):Char(ScreenTop):Char(3):Char(ScreenTop) OldYpos += 2 Return DisplayScreen: Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'R', Image) Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'C',' ':Colour1) Border.Up(1,Screentop,7+MaxWidth,OldYpos,1,Colour4) Print @(2,ScreenTop):'[':@fm:']' Print Colour4:Screen CurrentButton = 1 Print @(5 + MaxWidth, ScreenTop +2): Return ProcessMouse: ExitSet = False$ Loop Until ExitSet Input.Char(Chr,True$) Begin Case Case Len(Chr) = 4 * A Mouse Button was pressed - a slight delay is in order here ! Delay(0.25) MouseX = Seq(Chr[3,1]) MouseY = Seq(Chr[4,1]) * Now see if the mouse press was somewhere we need to act on Rectangle = InRect(MouseX, MouseY, Rectangles, '') Begin Case Case Rectangle = ButtonCtr + 2 * Border "Cancel" icon. ExitSet = True$ Resultarray = '' Case Rectangle = ButtonCtr + 1 * <Save> icon. ExitSet = True$ Case Rectangle > 0 If ResultArray<Rectangle> Then ResultArray<Rectangle> = 0 ; Choice = ' ' End Else ResultArray<Rectangle> = 1 ; Choice = @fm End Print @(5+MaxWidth,ScreenTop+(Rectangle*2)):Choice Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)): End Case Case Chr = Tab$ CurrentButton += 1 If CurrentButton > ButtonCtr then CurrentButton = 1 Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): Case Chr = BackTab$ CurrentButton -= 1 If CurrentButton < 1 then CurrentButton = ButtonCtr Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): Case Chr = ' ' If ResultArray<CurrentButton> then Choice = ' ' ; ResultArray<CurrentButton> = 0 End Else Choice = @fm ; ResultArray<CurrentButton> = 1 End Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)):Choice Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): Case Chr = Escape$ ExitSet = True$ ; ResultArray = '' End Case Repeat Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'W',Image) Return
(Volume 4, Issue 5, Pages 7-10)