THE RISC USER NOTEPAD

David Spencer presents a genuine RISC OS multi-tasking application.

Over the next three issues, I will be showing how to write a fairly simple, but comprehensive, multi-tasking application for RISC OS. The program will be a notepad utility, allowing short notes and memos to be 'jotted down', and either saved for later use or printed out. This application was chosen both because it has some practical use, and is also basic enough not to result in a massively long program. Although the purpose of these articles is to demonstrate the development of a RISC OS multi-tasking application, it is not feasible to give a complete line by line account of the program because of the complexity of the overall system. To understand the workings of the program, a basic knowledge of the WIMP system is necessary.

THE APPLICATION DIRECTORY

The first step in writing our application is to create an application directory as explained last month (page 20). This directory will have the name '!NotePad', and will contain five files:
!Boot
!Run
!Sprites
!RunImage
Sprites

The purpose of the first three was explained in the article last month. The fourth one, '!RunImage', is the application program itself, while 'Sprites' will contain various sprites used by the program.

You should start by creating the directory anywhere on your working disc using *CDIR !NotePad. Secondly, the !Boot and !Run obey files should be entered, and saved in the application directory. The contents of these files is given in listings 1 and 2 respectively. The comment lines (those starting with '|' can be omitted if you wish, but for clarity I suggest that at least the filename appears somewhere in the file. The command files can be entered using a text editor such as Twin or RISC OS's ArcEdit (see article in this issue), or using *BUILD. However, in the case of *BUILD, all occurrences of '|' and '<' in the text must be preceded by a '|' (giving '||' and '|<') when the text is entered. This prevents *BUILD from trying to interpret the lines as they are entered. In all cases, the file type of both files should be set to 'Obey'. If you are using ArcEdit, this will be done automatically provided you start by selecting the 'Create Obey File' option from the iconbar menu. If the files are entered any other way, the commands:
*SETTYPE $.!NotePad.!Boot Obey
*SETTYPE $.!NotePad.!Run Obey

will be needed to set the correct filetype.

The comments in the two obey files should give you an idea of the functions they perform, especially if you followed last month's article on application directories. The !Boot file sets up a name for a chosen filetype and then an alias to specify what happens when a Notepad is run. File type &FEE is used because this was previously allocated to the Arthur 1.20 Notepad. The final action of !Boot is to load in the sprites used to represent the application, and its data files, in a directory viewer.

The !Run file starts by repeating all the actions of !Boot, because in some cases it is possible that !Boot is never executed (for example, if two applications have the same name). It then sets the system variable 'NotePad$Dir' to the pathname of the application directory and ensures that 32K of memory is available. This latter function is achieved using the command *WimpSlot which informs the task manager of the amount of memory needed by this application. Finally, !Run actually runs the Basic program !RunImage which is the application itself.

SPRITE FILES

The next stage is to create the two sprite files needed by the application. Specifying sprite definitions in a magazine article is particularly awkward, and we have decided to adopt the approach of listing 3. This reads the definitions from a string of DATA statements, and creates the two sprite files. If you have any alternative suggestions for specifying sprite definitions in the future then please let us know. One point to watch out for is that this listing is formatted to 43 columns for readability, rather than our usual 40.

The file '!Sprites' contains sprites called '!notepad' and 'file_fee'. The first of these, which has the same name as the application directory, is used to display an icon for the application in the filer, and we will also use it to represent the application on the iconbar. The second sprite is used for data files that are recognised by our application. (Any file of filetype &FEE.)

The second sprite file, 'Sprites' contains sprites used solely by this particular application. There are two sprites called 'leftarrow' and 'rightarrow', representing left and right pointing arrows. The difference between the two files is the way in which they are loaded. The file '!Sprites' is loaded into the WIMP's common sprite pool using the command *ICONSPRITES, while the two sprites from the file 'Sprites' are loaded into a user sprite area set up by our program. This is to ensure that our specific sprites don't interface with any having the same name, but belonging to other applications.

!RUNIMAGE

The final file to create in the application directory is !RunImage. This is the actual application, and is a sizeable Basic program. The first part of this is given in listing 4, which should be entered and saved in the application directory (noting the uneven line numbering). At this stage, you can now enter the Desktop and open the disc containing the Notepad. You should see the application complete with icon in the filer window, and double clicking on this should cause it to install itself on the iconbar. Double clicking on the iconbar icon will open the Notepad window, which at present will be blank except for an arrow in each top corner. Pressing the menu button over the icon will bring up a quit option. Selecting this will remove the Notepad.

Next month we will add the text handling routines to the program, and start to explain how it actually works.

Listing 1

| !Boot file for RISC User Note Pad
| by David Spencer
| Set up file type data
Set File$Type_FEE Note Pad
Set Alias$@RunType_FEE Run .!Run %%*0
| (%% to ensure substitution takes place
| when file is run, and not when command
| is obeyed.)
| Load wimp's sprites
IconSprites .!Sprites

Listing 2

| !Run file for RISC User Note Pad
| by David Spencer
| First bit as for !Boot
Set File$Type_FEE Note Pad
Set Alias$@RunType_FEE Run .!Run %%*0
IconSprites .!Sprites
| Find our path
Set NotePad$Dir
| Check memory allocation
WimpSlot -min 32K -max 32K
| Start program
Run .!RunImage %*0
| (Just one %, so parameters are
| substiuted before !RunImage is run.
| 'Run' at start is necessary to
| prevent filing system name being
| treated as a temporary filing system
| for the duration of the command.)

Listing 3

10 REM >SprGen
20 REPEAT READ file$
30 IF file$<>"*" THEN
40 X%=OPENOUT file$
50 READ len,check:sum=0
60 REPEAT READ data$
70 REPEAT
80 byte=EVAL("&"+LEFT$(data$,2))
90 sum+=byte:BPUT #X%,byte
100 len-=1:data$=MID$(data$,3)
110 UNTILdata$=""
120 UNTILlen=0
130 CLOSE #X%
140 OSCLI "SETTYPE "+file$+" Sprite"
150 IF sum<>check THEN PRINT "Data error in ";file$
160 ENDIF
170 UNTILfile$="*"
180 END
190 :
200 DATA !Sprites,780,40798
210 DATA 02000000100000001003000080010000
220 DATA 216E6F74657061640000000004000000
230 DATA 1000000000000000070000002C000000
240 DATA 2C0000000C0000001177117711771177
250 DATA 11771177117711771100000011771177
260 DATA 11771177117711771177117711000000
270 DATA 77777777777777777777777777777777
280 DATA 77000000770000000000000000000000
290 DATA 00000000770000007700BB000B00B00B
300 DATA 00B0BBBB00BBBB0B770000007700BB00
310 DATA 0BB00BB00B00B000000B000077000000
320 DATA 77000B0B0BB00BB00B00B00000BBBB00
330 DATA 7700000077000BB00BB00BB00B00B000
340 DATA 000B00007700000077000BB00B00B00B
350 DATA 0000B00000BBBB0B7700000077000000
360 DATA 00000000000000000000000077000000
370 DATA 77000000880800000800808800000000
380 DATA 77000000770000000880008080008000
390 DATA 08000070770000007700000088080088
400 DATA 88088000080000277700000077000000
410 DATA 08000008000880880000702277000000
420 DATA 77777777777777777777777777772722
430 DATA 77000000772222222222222222222222
440 DATA 22222222770000007777777777777777
450 DATA 77777777777777777700000080010000
460 DATA 66696C655F6665650000000004000000
470 DATA 1000000000000000070000002C000000
480 DATA 2C0000000C0000001177117711771177
490 DATA 11771177117711771100000011771177
500 DATA 11771177117711771177117711000000
510 DATA 77777777777777777777777777777777
520 DATA 77000000770000000000000000000000
530 DATA 00000000770000007700DDD0DD0DDDDD
540 DATA 0D0D0DDDDD0D00007700000077000000
550 DATA 00000000000000000000000077000000
560 DATA 77000DDDDDD00DD00DDD0DD0DDDD0D00
570 DATA 77000000770000000000000000000000
580 DATA 00000000770000007700DDDD0DD0DD00
590 DATA DDDD0DDD0D0D00007700000077000000
600 DATA 00000000000000000000000077000000
610 DATA 7700DD0D00DDDDDDDD0DD0DD0DDDDD00
620 DATA 77000000770000000000000000000000
630 DATA 00000070770000007700DDDDDD00D0DD
640 DATA 0D00DDDD0D000D277700000077000000
650 DATA 00000000000000000000702277000000
660 DATA 77777777777777777777777777772722
670 DATA 77000000772222222222222222222222
680 DATA 22222222770000007777777777777777
690 DATA 777777777777777777000000
700 DATA Sprites,228,9963
710 DATA 0200000010000000E80000006C000000
720 DATA 6C6566746172726F7700000001000000
730 DATA 07000000000000001F0000002C000000
740 DATA 2C0000000C0000000070770000000000
750 DATA 00777700000000007077777777777777
760 DATA 77777777777777777077777777777777
770 DATA 00777700000000000070770000000000
780 DATA 00000000000000006C00000072696768
790 DATA 746172726F7700000100000007000000
800 DATA 000000001F0000002C0000002C000000
810 DATA 0C000000000000000077070000000000
820 DATA 00777700777777777777770777777777
830 DATA 77777777777777777777770700000000
840 DATA 00777700000000000077070000000000
850 DATA 00000000
860 DATA *

Listing 4

10 REM >$.!NotePad.!RunImage
20 REM Program Note Pad Utility
30 REM Version A 1.0
40 REM Author David Spencer
50 REM RISC User April 1989
60 REM Program Subject to Copyright
70 :
140 maxpage=7:DIM block 200, mt 100, st 256, data (600*(maxpage+1)), menu 150,
fi 100, pno 20
150 $mt="<Untitled>":$st="Save as:"
170 $block="TASK":SYS "Wimp_Initialise",200,!block,"Note Pad" TO ,task
180 ON ERROR PROCerror
210 S%=OPENIN ".Sprites":T%=EXT#S%+16:CLOSE #S%
220 DIM sp T%:!sp=T%:sp!4=0
230 sp!8=16:sp!12=16
240 SYS "OS_SpriteOp",&10A,sp,".Sprites"
250 X=RND(624)-1:Y=RND(480)-1
260 main=FNcreate(X,Y,656,544,&FF000002,0,656,544,3,mt)
280 sicon=FNspriteicon(-1,0,0,68,68,&3102,1,"!notepad")
290 left=FNspriteicon(main,8,-36,40,-4,&3102,sp,"leftarrow")
300 right=FNspriteicon(main,616,-36,648,-4,&3102,sp,"rightarrow")
350 quit=FALSE:tx=0:ty=0
360 open=FALSE
370 REPEAT
380 SYS "Wimp_Poll",1,block TO reason
390 CASE reason OF
400 WHEN 1:PROCredraw(!block)
410 WHEN 2:SYS "Wimp_OpenWindow",,block
420 WHEN 3:PROCclose(!block)
430 WHEN 6:PROCbuttons(block)
460 WHEN 9:PROCmenuselect(block)
470 WHEN 17,18:PROCreceive(block)
480 ENDCASE
490 UNTIL quit
500 SYS "Wimp_CloseDown"
510 END
520 :
530 DEF PROCreceive(b)
540 CASE b!16 OF
550 WHEN 0:quit=TRUE
560 WHEN 2:PROCdatasave(b)
570 WHEN 3,5:IF b!12=0 THEN PROCdataload(b)
580 ENDCASE
590 ENDPROC
600 :
610 DEF FNcreate(vx,vy,w,h,flags,bcol,x,y,waf,title)
620 $block=STRING$(88,CHR$0)
630 !block=vx:block!4=vy
640 block!8=vx+w:block!12=vy+h
650 block!24=-1:block!28=flags
660 block?32=7:block?33=2
670 block?34=7:block?35=bcol
680 block?36=3:block?37=1
690 block?38=12
700 block!44=-y:block!48=x
710 block!56=&13D:block!60=waf<<12
720 block!72=title:block!76=-1
730 block!80=LEN$title
740 SYS "Wimp_CreateWindow",,block TO handle
750 =handle
760 :
770 DEF PROCredraw(handle)
780 IF handle=main THEN
790 !block=handle
800 SYS "Wimp_RedrawWindow",,block TO more
810 WHILE more
830 SYS "Wimp_GetRectangle",,block TO more
840 ENDWHILE
850 ENDIF
860 ENDPROC
870 :
880 DEF PROCbuttons(b)
890 IF b!8 AND 2 THEN
900 PROCmenu(b)
910 ELSE
920 CASE b!12 OF
930 WHEN -2:REM Iconbar
940 IF (b!16=sicon) AND NOTopen THEN
950 !block=main
960 SYS "Wimp_GetWindowState",,block
970 SYS "Wimp_OpenWindow",,block
980 open=TRUE
990 ENDIF
1260 ENDCASE
1270 ENDIF
1280 ENDPROC
1290 :
1300 DEF PROCclose(handle)
1310 IF handle=main THEN open=FALSE
1320 !block=handle
1330 SYS "Wimp_CloseWindow",,block
1340 ENDPROC
1460 :
1470 DEF FNspriteicon(window,x0,y0,x1,y1,flags,sptr,sname$)
1480 DIM block!24 LENsname$+1:block!28=sptr
1490 block!32=LENsname$+1:$block!24=sname$
1500 =FNiconblk(window,x0,y0,x1,y1,flags)
1510 :
1570 DEF FNiconblk(window,x0,y0,x1,y1,flags)
1580 !block=window
1590 block!4=x0:block!8=y0
1600 block!12=x1:block!16=y1
1610 block!20=flags
1620 SYS "Wimp_CreateIcon",,block TO icon
1630 =icon
1640 :
1650 DEF PROCmenu(b)
1660 CASE b!12 OF
1670 WHEN -2:PROCdrawmenu(1,"Note Pad,Quit")
1680 SYS "Wimp_CreateMenu",,menu+4,!b-64,136
1790 ENDCASE
1800 ENDPROC
1810 :
1820 DEF PROCdrawmenu(handle,menu$)
1830 !menu=handle:menu?16=7
1840 menu?17=2:menu?18=7:menu?19=0
1850 menu!20=156:menu!24=40
1860 menu!28=0:ptr=menu+32
1870 $(menu+4)=LEFT$(menu$,INSTR(menu$,",")-1)
1880 menu$=menu$+","
1890 WHILE menu$<>""
1900 menu$=MID$(menu$,INSTR(menu$,",")+1)
1910 IF menu$<>"" THEN
1920 !ptr=0:ptr!4=-1
1930 ptr!8=&7000021
1940 $(ptr+12)=LEFT$(menu$,INSTR(menu$,",")-1)
1950 ptr+=24
1960 ENDIF
1970 ENDWHILE
1980 ptr!-24=ptr!-24 OR &80
1990 ENDPROC
2000 :
2010 DEF PROCmenuselect(b)
2020 CASE !menu OF
2030 WHEN 1
2040 CASE !b OF
2050 WHEN 0:quit=TRUE
2060 ENDCASE
2140 ENDCASE
2150 ENDPROC
2160 :
2170 DEF PROCerror
2180 SYS "Wimp_DragBox",,-1
2190 !block=ERR
2200 $(block+4)=REPORT$+" (Internal error code "+STR$ERL+")"+CHR$0
2210 SYS "Wimp_ReportError",block,1,"Note Pad"
2220 GOTO 370