This month we will add the routines to perform text handling and screen update to the Notepad. Start by adding this month's listing to the !RunImage program from last month, making sure that the original has not been renumbered at all. You will find there are still gaps in the line numbering, and these are for the addition of the final part next month. You should also delete line 570 which was included in last month's listing. This line is not in fact needed until next month, and at the moment causes spurious errors when starting new applications from the Desktop.
By now, the Notepad is usable to the extent that it can function as a jotter. It is not yet possible to load or save the contents, or to print them out.
When you open the Notepad window you will see the work area with a line across the top and two arrows and the page number above this line. The border is a pale yellow to show that the window will accept key presses, and a red caret can be seen in the top left hand corner. There are eight pages in all, each with fifteen lines of forty characters. You can move backwards and forwards through the pages by clicking on the arrows, and move the caret around the page with the cursor keys, or by moving the pointer and clicking.
There are two modes of text entry - Insert and Overtype. Pressing the menu button while over the Notepad window will bring up a menu, the first two options of which allow you to change entry mode. The current mode is shown by a tick, the default being Insert. As the names suggest, overtype mode causes existing characters to be overwritten, while insert mode pushes characters to the right to fit the new one in. The text is totally free format, and inserting a character will cause all the text beyond it to be shuffled. As text is entered the caret is moved automatically, and running off the end of one page will cause the next to be displayed. The Return key will move the caret to the start of the next line without entering any character into the text.
The Delete key will delete the character to the left of the caret. In overtype mode the character is replaced with a space, while in insert mode the gap is closed up by moving the remaining text back. The Copy key will delete the character to the right of the caret, and will always close the gap regardless of the entry mode. Finally, the Insert key will insert a space to the right of the caret. This is useful for adding one or two characters without having to enter insert mode.
As already said, the menu button will bring up a menu. The first two options control the entry mode as already explained. The third option will wipe all the pages of the notepad clean and, as no warning is given, should be used with care. The fourth and fifth entries are 'Print' and 'Save' respectively, and these will be implemented next month.
The basic structure of the program is very similar to that of a normal WIMP based program, although there are a few obvious differences. If you are not familiar with a single-tasking WIMP program then it is perhaps worth reading the series in RISC User Volume 1 Issues 5 to 7. The best way to understand the listing is to work through the program with reference to both the Programmer's Reference Manual and the notes below.
The first point to note is the way in which SYS "Wimp_Initialise" is called in line 170. This is called with three parameters. The first is the version number of the oldest Window Manager with which this program will work. This should be left as 200 in all programs. The second parameter is a four byte value made up of the characters 'TASK'. This tells the Window Manager that this program is multi-tasking. The final parameter is a text string which will be used by the Task Manager when it displays the table of memory usage. This should be kept short, but should give a clear indication of the function of the program. Finally, the SYS call returns a value which the program assigns to the variable task. This is the task handle, and is a unique value which the Window Manager can use to identify our task.
The next important stage is the creation of a user sprite area in lines 210 to 240. This is essential when using sprites in a multi-tasking program, for the reasons discussed last month. The program 'peeps' at the sprite file before loading it so that the area set up can be exactly the right length. You will notice the use of the operating system variable
The two RND functions in line 250 randomise where on the screen the Notepad window will appear when it is first opened. This is so that if the program is installed several times, and each incarnation opened one after the other, all the windows will not stack exactly on top of each other.
The next section of code (lines 260 to 340) sets up a number of icons. The icon worthy of mention is that defined in line 280 where the icon is placed in window -1. This in fact refers to the right-hand side of the iconbar, and it is this statement which places the Notepad icon on the iconbar.
The all-important polling loop comes next. Again, this is very similar to that of a single-tasking program. The value passed to Wimp_Poll is set to prevent null reason codes being returned. Claiming these would slow down all the other active tasks. The other major change is the recognition of the new reason codes 17 and 18 in line 470. These are used to signal to our program that another task is sending us a message. Messages are effectively just blocks of data, and we will cover them in detail next month. For now, all that we need to know is that when a message is received, the word at offset sixteen in the returned parameter block indicates what purpose the message serves. The only value we are interested in at the moment is zero, which is a message sent by the task manager to tell us to shut down. This will occur either when the user kills our program from the task display, or when the Desktop is about to shut down. Line 550 of the program sets our 'Quit' flag when this message is received. To demonstrate the effect of the message, remove this line and try exiting from the Desktop.
The next section of the program is relatively standard. One point to note is that whenever the Window Manager refers to our icon on the iconbar, it uses a window handle of -2 to represent the iconbar. This can be seen in line 930 where button presses are detected, and line 1670 when the menus are popped up. Other things to note are the dimensions of the menu entries in PROCdrawmenu, and the positioning of the 'Quit' menu in line 1680. These values should be used in all multi-tasking programs so that menus appear uniform from program to program.
Lines 2170 to 2220 constitute the error trapping routine. This starts by cancelling any active drag box, setting a parameter block to contain the error information and then calling the routine SYS "Wimp_ReportError". This displays an error box and returns when the user clicks on the OK button. At this point our program jumps back into the polling loop.
Most of the rest of the program is concerned with the text handling. You should note in particular the key processing routine (PROCkey). Any keys which are not recognised must be passed back to the Window Manager using SYS "Wimp_ProcessKey. This is so that other tasks which respond to particular keys can react properly. If you remove line 2510, then pressing F12 to bring up a star prompt will no longer work if the Notepad has the input focus.
Finally, PROCretitle closes a window and immediately reopens it. The purpose of this is to update the window title if it has been changed (such as a '*' being added when the text is modified).
Next month we will add the file handling and print routines, and conclude with an explanation of some of the more subtle points of the program.
160 $fi="Notes":mod=FALSE
190 PROCwipe:insert=true
200 PROCassemble
340 void=FNtexticon(main,280,-36,376,-4,&7000119,pno,-1,7)
450 WHEN 8:PROCkey(block)
820 PROCworkarea
980 open=TRUE:PROCmovecaret
1000 WHEN main
1010 CASE b!16 OF
1020 WHEN -1:PROCputcaret(b)
1030 WHEN left:IF NOT FNbpage VDU 7
1040 WHEN right:IF NOT FNfpage VDU 7
1050 ENDCASE
1350 :
1360 DEF PROCworkarea
1370 ox=block!4-block!20
1380 oy=block!16-block!24
1390 MOVE ox,oy-40:DRAW BY 656,0
1400 ptr=data+page*600:oy-=56:ox+=8
1410 FOR line=0 TO 14
1420 IF NOT(block!40<oy-28 OR block!32>oy) THEN MOVE ox,oy:SYS "OS_WriteN",ptr,40
1430 oy-=32:ptr+=40
1440 NEXT
1450 ENDPROC
1520 DEF FNtexticon(window,x0,y0,x1,y1,flags,tptr,vptr,len)
1530 block!24=tptr:block!28=vptr
1540 block!32=len
1550 =FNiconblk(window,x0,y0,x1,y1,flags)
1560 :
1690 WHEN main:PROCdrawmenu(2,"Note Pad,Insert,Over,Clear,Print,Save")
1700 IF insert THEN
1720 menu!32=menu!32 OR 1
1730 ELSE
1750 menu!56=menu!56 OR 1
1760 ENDIF
1780 SYS "Wimp_CreateMenu",,menu+4,!b-32,b!4+16
2070 WHEN 2
2080 CASE !b OF
2090 WHEN 0:insert=TRUE
2100 WHEN 1:insert=FALSE
2110 WHEN 2:PROCclear
2120 WHEN 3:PROCprint
2130 ENDCASE
2230 :
2240 DEF PROCputcaret(b)
2250 x=!b:y=b!4:!block=main
2260 SYS "Wimp_GetWindowState",,block
2270 x=x-block!4+block!20-8
2280 y=y-block!16+block!24+56
2290 IF y>=16 THEN ENDPROC
2300 IF y>0 THEN y=0
2310 IF y<-476 THEN y=-476
2320 IF x<0 THEN x=0
2330 IF x>632 THEN x=632
2340 x=(x AND NOT15)-16*((x AND 15)>7)
2350 tx=x DIV 16:ty=-y DIV 32
2360 IF tx=40 AND ty<>14 THEN tx=0:ty+=1
2370 IF tx=40 AND ty=14 THEN tx=39
2380 PROCmovecaret
2390 ENDPROC
2400 :
2410 DEF PROCkey(b)
2420 IF !b=main THEN
2430 key=b!24
2440 CASE TRUE OF
2450 WHEN key=&18B:PROCdelete(TRUE)
2460 WHEN key=&7F:PROCdelete(FALSE)
2470 WHEN key=&D:PROCnewline
2480 WHEN key=&1CD:PROCinsert
2490 WHEN key<&100 AND key>&1F:PROCchar(key)
2500 WHEN key>=&18C AND key<=&18F:PROCcursor(key-&18C)
2510 OTHERWISE SYS "Wimp_ProcessKey",key
2520 ENDCASE
2530 ENDIF
2540 ENDPROC
2550 :
2560 DEF PROCcursor(dir)
2570 CASE dir OF
2580 WHEN 0:tx-=1
2590 WHEN 1:tx+=1
2600 WHEN 2:ty+=1
2610 WHEN 3:ty-=1
2620 ENDCASE
2630 IF tx<0 THEN tx=39:ty-=1
2640 IF tx>39 THEN tx=0:ty+=1
2650 IF ty<0 THEN ty=-14*FNbpage
2660 IF ty>14 THEN ty=-14*NOT FNfpage
2670 PROCmovecaret
2680 ENDPROC
2690 :
2700 DEF FNbpage
2710 IF page=0 THEN =FALSE
2720 page-=1:$pno="Page "+STR$(page+1)
2730 SYS "Wimp_ForceRedraw",main,0,-544,656,0
2740 =TRUE
2750 :
2760 DEF FNfpage
2770 IF page=maxpage THEN =FALSE
2780 page+=1:$pno="Page "+STR$(page+1)
2790 SYS "Wimp_ForceRedraw",main,0,-544,656,0
2800 =TRUE
2810 :
2820 DEF PROCmovecaret
2830 SYS "Wimp_SetCaretPosition",main,-1,tx*16+8,-ty*32-88,40+(1<<24),-1
2840 ENDPROC
2850 :
2860 DEF PROCwipe
2870 FOR ptr=0 TO (maxpage+1)*600-1 STEP 4
2880 data!ptr=&20202020
2890 NEXT:tx=0:ty=0
2900 page=0:$pno="Page "+STR$(page+1)
2910 ENDPROC
2920 :
2930 DEF PROCclear
2940 PROCwipe
2950 PROCretitle(main)
2960 SYS "Wimp_ForceRedraw",main,0,-544,656,0
2970 ENDPROC
2980 :
2990 DEF PROCchar(key)
3000 ptr=page*600+ty*40+tx
3010 IF insert THEN
3020 IF data?4799=ASC" " THEN
3030 PROCshunt(ptr,TRUE)
3040 data?ptr=key
3050 SYS "Wimp_ForceRedraw",main,0,-544,656,-(52+32*ty)
3060 ELSE VDU7
3070 ENDIF
3080 ELSE
3090 data?ptr=key
3100 SYS "Wimp_ForceRedraw",main,8+16*tx,-(87+32*ty),24+16*tx,-(52+32*ty)
3110 ENDIF
3120 PROCmodified
3130 PROCcursor(1)
3140 ENDPROC
3150 :
3160 DEF PROCshunt(from,dir)
3170 A%=data+from
3180 B%=data+(maxpage+1)*600-1
3190 IF dir THEN C%=1 ELSE C%=-1
3200 CALL code
3210 ENDPROC
3220 :
3230 DEF PROCmodified
3240 IF NOT mod THEN
3250 mod=TRUE:$mt+=" *"
3260 PROCretitle(main)
3270 ENDIF
3280 ENDPROC
3290 :
3300 DEF PROCinsert
3310 LOCAL insert:insert=TRUE
3320 PROCchar(32):PROCcursor(0)
3330 ENDPROC
3340 :
3350 DEF PROCdelete(dir)
3360 IF NOT(insert OR dir) THEN
3370 PROCcursor(0):PROCchar(32)
3380 PROCcursor(0)
3390 ELSE
3400 ptr=page*600+ty*40+tx+(dir=FALSE)
3410 PROCshunt(ptr,FALSE)
3420 data?((maxpage+1)*600-1)=ASC" "
3430 SYS "Wimp_ForceRedraw",main,0,-544,656,-(52+32*ty)
3440 IF NOT dir THEN PROCcursor(0)
3450 IF NOT dir AND tx=39 THEN SYS "Wimp_ForceRedraw",main,8+16*tx,-(87+32*ty),24+16*tx,-(52+32*ty)
3460 ENDIF
3470 ENDPROC
3480 :
3490 DEF PROCnewline
3500 tx=0:PROCcursor(2)
3510 ENDPROC
3520 :
3530 DEF PROCassemble
3540 DIM code 200
3550 FOR pass=0 TO 2 STEP 2
3560 P%=code
3570 [OPT pass
3580 \Move (R0)...(R1) up/down 1 byte
3590 MOVS R2,R2:BMI startlo
3600 .loop LDRB R2,[R1]
3610 STRB R2,[R1,#1]:SUB R1,R1,#1
3620 CMP R1,R0:BCS loop
3630 MOV PC,R14
3640 .startlo LDRB R2,[R0,#1]
3650 STRB R2,[R0]:ADD R0,R0,#1
3660 CMP R0,R1:BLS startlo
3670 MOV PC,R14
3680 ]NEXT
3690 ENDPROC
3700 :
3710 DEF PROCretitle(!block)
3720 SYS "Wimp_GetWindowState",,block
3730 SYS "Wimp_CloseWindow",,block
3740 SYS "Wimp_OpenWindow",,block
3750 PROCmovecaret:open=TRUE
3760 ENDPROC