Description | Windows are very much in vogue at present, and several features have appeared in Your Commodore recently on WIMP systems for the 64. This article describes a set of window-handling utilities for the PLUS 4 and attempts to give a slice of the action to owners of CBM's second most popular 64k micro. There is no reason why the program should not run on a C16 if re-assembled to an address in the C16's range, though I have not been able to try this out; but I doubt that the C16 has sufficient store to allow much use to be made of the package.
Astute readers will have recalled that the +4 already has a window facility, so a short explanation may be in order. The standard Commodore offering allows a box to be defined on the screen to which all print output is routed; this window can be scrolled up and down or cleared by simple PRINT commands. Now, I would guess that the two major uses of windows are:- 1) pull-down (or pop-up) menus, and 2) concurrent output channels. The first of these requires a way of saving the area of screen under the menu, and of later restoring it, and the second requires the ability to have more than one window open - and the +4 as standard has neither of these facilities. Help is at hand, however, in the shape of the utilities described here which can easily be accessed from BASIC, and which interface with the routines in the +4 ROM to remedy just those deficiencies.
Facilities offered
The standard entry points to the code are accessed by a jump table starting at address 'WM', which is $7C00 (decimal 31744) in the Basic loader version. They allow the user to:
1) open a new window; up to ten windows may be open concurrently. When a window is opened the data below the window - whether from a window opened earlier or from the standard screen - and the associated colour data is stored, along with the previous cursor position and screen dimensions. The window is cleared, and the cursor left in the top left corner. The syntax of the OPEN WINDOW command is: SYS WM,X,Y,width,depth,colour,luminance,reverse where: X = column no. of top left of window (0-36) Y = row no. (0-21) width = width of window (1-37) depth = depth (1-22) colour= text colour (1-16, as in COLOR command) luminance = 0 to 7, as in COLOR reverse = 0 or 1; if set to 1 the text area of the window is set to reverse spaces. There is nothing to stop you opening more than ten windows; but the data overwritten by the eleventh and subsequent windows is not saved and cannot be restored.
2) close the last window opened. When a window is closed the data stacked during OPEN WINDOW is restored, causing the window to disappear without trace. The command to close the current window is: SYS WM+3
3) invert a line. Since the likeliest use for windows is menus, I have included a facility to invert the 'reverse' bit on a given line in the window last opened. This makes it easy to highlight a chosen option by reversing the characters; and calling the routine again with unchanged parameters will cancel the highlighting. The syntax is: SYS WM+6,line number where the top line is line 1.
4) reactivate a window. Normally the window in use (the 'active' window) is the window last opened. This command allows a window opened earlier to be nominated as the active window, and any subsequent print commands will be directed to it. The format is: SYS WM+9,window number with window number in the range 1-10.
5) window print. Under normal circumstances output to a window is performed by the Basic PRINT command. However when printing simultaneously to multiple windows, this entry point, which combines the functions of 'reactivate window' and PRINT, becomes necessary. This is because the PRINT command has no means of updating the stored cursor position used by 'reactivate', which would therefore always result in printing starting from the HOME position. Window print does update the cursor position; its syntax is: SYS WM+12,window number,string where 'string' is any standard +4 string expression, for example: "this is a string" A$+STR$(NN)+CHR$(127) NA$(1)+MID$(NB$,3,1) Line feed/return must be invoked specifically e.g. SYS WM+12,4,"line 1"+CHR$(13)
6) reset. This simply resets the number of windows currently open to zero, and wipes any windows on the screen (without restoring any previous data). Then either the screen is cleared, or the cursor is HOME'd. SYS WM+15,flag flag = 0: home cursor = 1: clear screen
Using Windows
To be certain of starting from a clean state, I would recommend calling reset (WM+15) during the initialisation phase of your program. When opening windows, bear in mind that they are limited to a maximum of 37 bytes wide and 22 deep. This is a result of the frame around the window, and the shadow on the bottom and right side. Specifying too wide a window, or one starting too far to the right to allow the shadow and/or frame to fit, will result in a corrupt screen, and, since your BASIC program follows the screen immediately in memory, specifying too deep a window will result in a corrupt program. The straightforward way of sending text to a window once opened is via the BASIC 'PRINT' command: it is easily readable, self-documenting and has many features for ease of use. The advantage of integrating these routines with the standard +4 utility is that there is no need to take any special steps to position the cursor before printing within a window. The output will always automatically fit into the window; and if you change the location of the window, you need make no change to the print statements - they will move too. All the standard Plus 4 escape sequences remain useable, of course; particularly useful ones are:- ESC/M to turn off scrolling (and ESC/L to turn it back on) ESC/V to scroll a window up ESC/W to scroll a window down
Listing 4 is a simple demonstration program. It is REMmed fairly comprehensively, but obviously there is no need to type in the comments as well as the program.
Loading the code
To load the program, you have the choice of a Basic loader or the Assembler source in the two listings alongside. To use the Basic loader, which pokes the code into $7C00 (31744) onwards, type in the program in listing 1. SAVE IT BEFORE RUNNING. The loader will set up the machine code, lower the top of BASIC for protection and then delete itself. A BASIC loader, although the simplest method of publishing a program, is rather slow for everyday use. The listing below is the basis of a simple machine code loader which executes far more quickly. To set it up follow this sequence:-
1) type in, SAVE and run the Basic loader as normal.
2) type NEW to clear out the loader, then enter the listing below EXACTLY AS SHOWN.
1 POKE95,96:POKE96,16 2 POKE90,96:POKE91,20 3 POKE88,0:POKE89,128 4 SYS35015 5 POKE55,0:POKE56,124:NEW
The length of the program is crucial, and extra REMs or spaces may well prevent it from working.
3) type MONITOR to enter Monitor
4) in Monitor, type the command: T 7C00 8000 1060 This will append the Windows code to the loader program. 5) type X to leave Monitor
6) type:- POKE 45,96:POKE 46,20 to set the end of the Basic program after the machine code. €*ma3 7) You can now SAVE or DSAVE the program normally: when LOADed and RUN, it will transfer the code to $7C00 onwards almost instantaneously.
The alternative to a loader is the assembler source in listing 2, which is formatted to suit the excellent +4 assembler in the December issue of YC. Any C16 user who would like to try the program out will, I am afraid, have to amend it to suit Joe Nicholson's assembler from the June '85 or June '86 issue of YC.
HOW IT WORKS I do not propose to describe in detail how the code works; those interested can refer to the assembler source, which is reasonably well commented. I thought, however, some mention of the routines called in the +4 ROM might be of interest, since little seems to have been published on this. The routines for parameter-handling are probably of general interest to +4 machine code programmers; for reference they are: $9491 - check for comma $9314 - evaluate arithmetic expression to floating-point accumulator (FAC1) $9DE4 - convert FAC1 to integer in $14/$15 $932C - evaluate expression: if string set address in $64/$65 and length in A $9C4E - discard unwanted string: leave pointer in $22/$23 |
|