|
|||||||
Version 3 Technical Highlights - Input.CharThe 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 PositionInput.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 CellsTo 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. 0001 Function Radio_Window(ButtonLabels) 0002 /* 0003 Author AMcA, CC 0004 Date Sept 92 0005 Purpose To display a field mark delimited set of prompts with a 0006 corresponding radio button for each prompt. These may be 0007 toggled using mouse and/or tab/spacebar and will return a 0008 dynamic array of results when <Save> is moused, or an empty 0009 array if Esc or the close button are pressed. 0010 */ 0011 Declare Function Min, Max, Esc.To.Attr, InRect 0012 Declare Subroutine Msg,Video.RW,Border.Up,Input.Char,Delay 0013 $Insert SysInclude, Logical 0014 Equ Escape$ to \1B\ 0015 Equ Tab$ to \09\ 0016 Equ BackTab$ to \000F\ 0017 GoSub SetUp 0018 GoSub DisplayScreen 0019 GoSub ProcessMouse 0020 Return ResultArray 0021 0022 SetUp: 0023 Colour4 = \1B\:'C1O' 0024 Colour1 = Esc.To.Attr(Colour4) 0025 ButtonCtr = Count(ButtonLabels, @Fm) + (ButtonLabels#"") 0026 ResultArray = str(0:@fm,ButtonCtr) 0027 ResultArray[-1,1] = '' 0028 Rectangles = '' 0029 MaxWidth = 6 ; Pos = 0 ; Mark = 0 ; Screen = "" 0030 Ptr = 2 ; Depth = ButtonCtr * 2 0031 Ypos = Int((@CrtHigh-(Depth+3))/2) 0032 ScreenTop = Ypos - 2 0033 OldYpos = Ypos 0034 Loop 0035 Remove NextLabel From ButtonLabels At Pos Setting Mark 0036 MaxWidth = Max(MaxWidth, Len(NextLabel)) 0037 Screen := @(2, Ypos) : NextLabel 0038 Ypos += 2 0039 While Mark 0040 Repeat 0041 For X = 1 To ButtonCtr 0042 Screen := @(4 + MaxWidth, OldYpos) : "[ ]" 0043 ThisBox = Char(5 + MaxWidth) : Char(OldYpos) 0044 Rectangles := ThisBox:ThisBox 0045 OldYpos += 2 0046 Next 0047 BottomLine = '<Save>' 0048 Screen := @(2, Ypos) : BottomLine 0049 Rectangles := Char(3):Char(Ypos):Char(6):Char(Ypos) 0050 Rectangles :=Char(3):Char(ScreenTop):Char(3):Char(ScreenTop) 0051 OldYpos += 2 0052 Return 0053 0054 DisplayScreen: 0055 Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'R', Image) 0056 Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'C',' ':Colour1) 0057 Border.Up(1,Screentop,7+MaxWidth,OldYpos,1,Colour4) 0058 Print @(2,ScreenTop):'[':@fm:']' 0059 Print Colour4:Screen 0060 CurrentButton = 1 0061 Print @(5 + MaxWidth, ScreenTop +2): 0062 Return 0063 0064 ProcessMouse: 0065 ExitSet = False$ 0066 Loop Until ExitSet 0067 Input.Char(Chr,True$) 0068 Begin Case 0069 Case Len(Chr) = 4 0070 * A Mouse Button was pressed - a slight delay is in order here ! 0071 Delay(0.25) 0072 MouseX = Seq(Chr[3,1]) 0073 MouseY = Seq(Chr[4,1]) 0074 * Now see if the mouse press was somewhere we need to act on 0075 Rectangle = InRect(MouseX, MouseY, Rectangles, '') 0076 Begin Case 0077 Case Rectangle = ButtonCtr + 2 0078 * Border "Cancel" icon. 0079 ExitSet = True$ 0080 Resultarray = '' 0081 Case Rectangle = ButtonCtr + 1 0082 * <Save> icon. 0083 ExitSet = True$ 0084 Case Rectangle > 0 0085 If ResultArray<Rectangle> Then 0086 ResultArray<Rectangle> = 0 ; Choice = ' ' 0087 End Else 0088 ResultArray<Rectangle> = 1 ; Choice = @fm 0089 End 0090 Print @(5+MaxWidth,ScreenTop+(Rectangle*2)):Choice 0091 Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)): 0092 End Case 0093 Case Chr = Tab$ 0094 CurrentButton += 1 0095 If CurrentButton > ButtonCtr then CurrentButton = 1 0096 Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): 0097 Case Chr = BackTab$ 0098 CurrentButton -= 1 0099 If CurrentButton < 1 then CurrentButton = ButtonCtr 0100 Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): 0101 Case Chr = ' ' 0102 If ResultArray<CurrentButton> then 0103 Choice = ' ' ; ResultArray<CurrentButton> = 0 0104 End Else 0105 Choice = @fm ; ResultArray<CurrentButton> = 1 0106 End 0107 Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)):Choice 0108 Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)): 0109 Case Chr = Escape$ 0110 ExitSet = True$ ; ResultArray = '' 0111 End Case 0112 Repeat 0113 Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'W',Image) 0114 Return (Volume 4, Issue 5, Pages 7-10) |
|||||||
| |||||||