                          A SHORT STOS TUTORIAL
                                    
                               For ICTARI
                                    
                            By David Preston
                                    
                                Episode 1
                                    

     When home computers first became available and popular there were 
lots of magazines available, which all carried program listings. In my 
humble opinion this was probably the best way to learn how to program. 
Following annotated listings is a great way of becoming familiar with 
how programs work.

     So in these three little tutorials we'll examine a slideshow 
program. This first episode will look at a 'bare bones' program. It 
works pretty well, but will be improved in parts 2 and 3.

     What we want to end up with is a slideshow we can use, useful and 
configurable, both as a utility (for scanning quickly through picture 
files to find one we want) and as a slideshow (with lots of fades and 
appear effects). We'll just be using native STOS without any extensions, 
but you may wish to add your own enhancements using features from 
whatever extensions you use, later.


     The Listing

Lines 10-90 : REM statements to identify the listing.

10 rem  ____________________________
20 rem |                            |
30 rem |  STOS Tutorial for ICTARI  |
40 rem |     Slideshow program      |
50 rem |            #1              |
60 rem |                            |
70 rem |  David Preston  - Oct '96  |
80 rem |____________________________|
90 rem


Now for the program proper - first we'll lose the function key 
definition panel and the cursor. Then we deal with the mouse. It is 
perfectly possible to use this program as a STOS accessory (save it as 
something like SLIDESHW.ACB), so we want to make sure that the mouse 
will be visible when we want it to be. Refer to the manual for the 
differences between SHOW/SHOW ON and HIDE/HIDE ON.

100 key off : curs off : show on : hide


Then we'll say a polite "Ta ta" to mono monitor users.

110 if mode=2 then locate 0,10 : centre "Colour systems only - Press a 
key..." : wait key : default : end


I like to use a line consisting just of a colon to separate blocks of 
code and make the listing a bit clearer to read. This is the only time 
this will be mentioned, but you'll see other similar lines elsewhere in 
the program.

120  :


For the time being at least, we'll stick to low-res pictures. We've 
already kicked out mono systems, so we can simply switch the display 
using MODE.

130 mode 0


Although we could load files directly into screen memory, we will be 
displaying them with a little more panache, so we'll reserve a 
screenbank to load them into, from whence we can transfer them to the 
physical screen. Because we only anticipate using the one memory bank, 
we'll use bank 5. Take a look at the manual for the usual uses for banks 
1-4.

140 reserve as screen 5


The program will identify picture files by their extenders, so we'll 
define a sting variable against which we can test them. For this 
exercise we're only interested in Degas low-res (*.PI1) and Neochrome 
(*.NEO) files.

150 TEST$="PI1NEO"
160  :


One of the features which will set our slideshow apart is that it will 
be able to display files from any directory, not just the one it was run 
from. To do this we'll use the fileselector. I've grouped all the 
statements together on the one line because they go together. First 
'show' the mouse, then make sure we can see the fileselector by changing 
the palette of colour registers 0 & 1, then call the selector itself. 
Finally we hide the mouse pointer again.

170 show : palette $666,$0 : DUMMY$=file select$("*.*","Select path for 
picture files.  (Enter 'Q' in filename to Quit)") : hide

This is the point in the program we want the user to be able to quit the 
program but I don't know how to read the 'Cancel' button, so we'll ask 
the user to put a 'Q' in the filename box. If that happens we tidy up 
and exit gracefully. By testing only the first character of the returned 
string (DUMMY$), we can cope with an over-enthusiastic user who enters 
'QUIT'.

180 if DUMMY$<>"" and left$(DUMMY$,1)="Q" then default : end
190  :


Now for the main program loop. This reads the disk directory and 
branches to subroutines as necessary. We'll examine it line by line.

First a REM to make reading the listing easier.

200 rem /// Main loop ///

The guts of the loop includes two nested REPEAT...UNTIL loops. We want a 
tidy way of exiting them so we'll use a 'flag' variable.

210 EXIT_FLAG=false

The reason we need _two_ loops is that the program is to display the 
picture files ad infinitum, until the user tells it to stop, but that 
reading is in two distinct phases. The first is the DIR FIRST$() 
function, which finds the first directory entry satisfying the criteria 
we specify. After that repeating DIR NEXT will find all the other 
files.

220 repeat

You'll notice that I've created indenting by using colons to make the 
loops easier to see. This is the DIR FIRST$ function. We are asking it 
for the first directory entry satisfying a file mask of '*.*' ie. all 
files, and that they are 'ordinary' files. Refer to the manual for more 
detail.

230  : F$=dir first$("*.*",32)

It is possible that by accident or design the user might point the 
program at an empty directory. So we'll trap that possibility, print a 
message and jump to the end of the outer loop, after setting EXIT_FLAG 
to 'true' so we'll exit the loop at that point.

240  : if F$="" then cls : locate 0,10 : centre "No pictures! Press a 
key..." : wait key : EXIT_FLAG=true : goto 370

Next we start the inner loop that reads DIR NEXT repeatedly.

250  : repeat

Because we want the user to be able to either quit the program or change 
directories (or later in the series choose some other options), we need 
to read the keyboard now & again, so we'll branch to an appropriate 
routine.

260  :  : gosub 410

When we ask for a directory entry we get more than just the file name, 
we get the file size, date & time stamps etc., so we'll slice off the 
first 12 characters (8 for the name, 1 for the full stop and 3 for the 
extender) and use STOS's ability to subtract from strings to strip off 
any trailing spaces.

270  :  : F$=left$(F$,12)-" "

Hmmm... I've just spotted a goof! Still, it's probably a happy accident 
so I'll leave it in for now and we'll put it right in part 2. We've 
already said that the file extender will be used to identify which files 
can or can't be loaded, and what I was trying to achieve was to make 
sure that what we got in EXT$ was the real extender and not just the 
last 3 characters of the file name. See if you can spot why this line 
_won't_ do that properly! (Think about a file called eg. "MYFILEPI.1", 
or "FAKENEO".) Try to come up with a replacement which _will_ filter out 
such files. (Don't worry, it works as it is so long as it doesn't come 
across awkward file names like these, but well-written software should 
be able to cope with any eventuality!)

280  :  : EXT$=right$(F$,4)-"."

Check the keyboard again.

290  :  : gosub 410

Alright, where are we up to? Well, the directory has given us a file 
name and we've now got an extender (of a sort!) to work with. So now we 
need to test if the file we are working with _is_ one we can load and 
display. Before we go away and deal with that, we'll define a variable 
as a flag so that subsequent routines will know if we have a file to use 
or not. Note that L0ADED includes a 0 (number zero) instead of an O 
(capital letter o). This is because the STOS editor would interpret 
LOADED as 'load ED' otherwise. (This is a handy trick for game writers 
who want a variable SC0RE not 'SC or E'.)

300  :  : L0ADED=false

Then branch to do the test on the extender in EXT$.

310  :  : gosub 460

And check the keyboard again.

320  :  : gosub 410

If we have got a file loaded then go away and display it.

330  :  : if L0ADED then gosub 560

Better check for keyboard input again!

340  :  : gosub 410

The first time through this loop we were dealing with the filename found 
by DIR FIRST$, so before we repeat the loop we'd better get another one! 
Then on subsequent passes we'll be dealing with the filename found by 
this function.

350  :  : F$=dir next$

And we get to the end of the inner loop. The filename returned by DIR 
NEXT$ will be null if it has read past the last item, so we can exit 
this loop and restart from DIR FIRST$.

360  : until F$=""

This is the end of the outer loop, beyond which program flow will only 
pass if we earlier found an empty directory or the user pressed a key we 
want to cause an exit.

370 until EXIT_FLAG

If program flow has reached this point we want to restart from the file 
selector, so we'll head up there now.

380 goto 170

Well, that's the end of the main loop. Apart from the problem with the 
file extender, that part of the program won't change very much, if at 
all, when we add features in parts 2 & 3. That's because we've written 
it so that the subroutines below leave scope for additions and 
amendments to be made without messing with overall program logic. This 
is always the best policy and, for me, the most compelling argument in 
favour of structured programs.


Now for the subroutines:

First, reading the keyboard. Although we don't yet use the scancode, 
it's there in case we need it later. ASCII code 27 is the <Esc> key.

390  :
400 rem /// Check for ESC key ///
410 K$=inkey$ : SC=scancode : AXI=asc(K$)
420 if AXI=27 then EXIT_FLAG=true
430 return
440  :


This routine tests EXT$ against TEST$. At the moment we are only dealing 
with *.NEO and *.PI1 files, both of which STOS can load on its own, so 
whichever we are loading the same routine will work. We could add extra 
routines to load other file types simply by changing TEST$ and adding 
other routines to the 'on...gosub' in line 470. See if you can work out 
just how line 460 returns a 0 if EXT$ doesn't appear in TEST$ and 1 or 
2 if it does.

450 rem /// Test file extender and branch to load routine ///
460 FTYPE=(instr(TEST$,EXT$)+2)/3
470 on FTYPE gosub 510,510
480 return
490  :


This routine uses STOS's own built in facilities to load Degas and 
Neochrome files.

500 rem /// Load Degas (*.PI1) or Neochrome (*.NEO) ///
510 load F$,5
520 L0ADED=true
530 return
540  :


In coming parts of this tutorial we'll add lots of special wipes, fades 
and stuff, but for now, because we're only going to use the STOS 
'APPEAR' command this is just here to allow for that future expansion.

550 rem /// Choose FX ///
560 FX=1
570 on FX gosub 610
580 return
590  :


For now the only way to put a picture on screen is by 'APPEAR'ing it. 
But that command doesn't change the palette, so we need to do that as 
well. 'FADE' will change the system palette to that of bank 5, and 
because it works on interrupt we can set it going then 'APPEAR' and 
they'll seem to be working simultaneously. Thus both the bitmap and the 
palette will change smoothly from one picture to the next.

600 rem /// FX ///
610 fade 12 to 5
620 appear 5
630 return



And that's it for now!!!

Still to come, however are some extra user features and loads of extra 
wipes and stuff (tiles, blinds, gelatin, etc.). Because of the way the 
basic program is structured these should be pretty easy to slot into the 
existing code.

We _might_ also look at adding med-res support and possibly hi-res 
emulation. There are also other file types like Tiny, Degas Elite etc., 
however I need your feedback on these. Do you want to add support 
yourself, using the facilities of any STOS Extensions you use, or 
routines (which will be a bit slower) written in STOS basic? Let me know 
through Ictari!!



David
