| |
Wimp
|
|
WIMP Programming on RiscOSThis is basically a partially
in-depth look at how to make WIMP programs in RiscOS in BASIC.
Personally, I think BASIC is easy to use but can be a bit slow.
However, I learnt in BASIC and I think everyone else should
also. WIMP stands for Windows Icon Menu Programming. It is a way
of writing your programs with a nice, pretty interface which
everyone can use. It also involves a basic (hah) knowledge of BASIC
which I shall assume. I have posted my WIMP Skeleton and that of
Radiac in the downloads section. But more of that later.
Tutorial 1The easiest way to set up a WIMP application is
to create a directory with a name with a "!" at the front. Instead
of a normal directory, this creates an application directory. To
open it, hold down SHIFT whilst double-clicking. If you don't hold
down SHIFT, then the WIMP (I shall refer to the 'god' of RiscOS as
the WIMP) will look for a file inside the directory called !Run and
try to execute it. So, after creating your directory, it should look
like this.
So, we have a
directory, with nothing in it. It would be nice to have a picture on
the directory. To do this, create a sprite file in 256 colours and
32x32 pixels. Give the sprite the same name as the program so in my
case this would be !myprog (Sprites can't have capitals). Save the
whole sprite file as something inside the program. !Sprites or
!Sprites22 is the usual name and I shall use !Sprites22 as !Sprites
is usually reserved for the old 2x1 pixel format on old versions of
RiscOS Now you need to create a small obey script to tell the WIMP
that the sprite is in the sprite file. Therefore create a file with
the following line:
Iconsprites
.!Sprites22
The command Iconsprites tells
the WIMP to load all the sprites in the given file. is
just the current directory. Save this file with type "Obey" and a
name of !Boot inside the application. If you run the !boot file, the
sprite should appear on the application icon. A picture may clarify
things.
The !boot file is
run every time you open the directory containing the application.
Now we need a file telling the WIMP what to do when the application
is run. Cunningly enough, this is an obey file called !Run. In this
file, the main program is executed along with a few more things. In
this case we shall give the application directory a system variable.
This is done by adding the line:
Set myprog$dir
Now, every time is called as
part of a filename, it will go to the application directory. This is
useful because the will change every time an application
does a task. The second line of the !Run file is to run the BASIC
program with any necessary arguments. This is done like
this:
Filer_Run .!RunImage
I
usually call the BASIC file "!RunImage" because I was taught that
way. Your BASIC file can do anything you want. But we shall come
onto what you want later...
Tutorial 2 - IconsFor the purposes of this exercise, I
shall use Radiac's WIMP skeleton and explain everything along the
way. OK, looking at the skeleton. The first line is simple, non-WIMP
error handler. The second line will set all the variables. It
defines found memory arrays (if you don't know what these are, ask
someone else); blk%, temp_blk% and errorblk% and mainind%. These
come in useful later. The other variables are self-explanatory
except to point out that they are set up to save looking at the PRM
(Programmer's Reference Manual) every time you want to know what the
WIMP calls a select click on the mouse (64, thanks for asking). An
important variable is quit%. If set to FALSE, the program will run
normally. If at any point it is set to TRUE, a procedure cuts in and
quits the program. The third line is very important. It calls a SWI
call (System WIMP Interface or something). This particular SWI call,
"Wimp_Initialise" tells the WIMP that there is a program here which
would like to register with the WIMP. It sends off various bits, the
only important one being the name of the application, set in
app_name$. The only important thing it returns it the handle of the
application given by this_task%. The main thing you notice about
WIMP programs is that they have an icon on the icon bar. Therefore
in the fourth line, a function is called, FNput_icon_on_bar. and
this returns the icon handle of the icon. Looking at the function,
we find a whole lot of complicated stuff. Inside the array called
temp_blk% which is basically a bit of memory, we can set various
bites to various things. These are normally in chunks of 4 bytes.
Now, we need to create an icon so the "Wimp_CreateIcon" SWI may be a
good bet. Looking in my trusty !Stronghelp manual, I am told that R0
(the first argument ) is only required if the window handle is less
than -3 (it isn't, trust me). R1 (the second argument) requires a
pointer to block (the array or bit of memory). It says that bytes 0
to 3 is the window handle or icon bar location. As we want to put an
icon on the right hand side, we want to set this to -1. Therefore we
say !temp_blk%=-1. We are now told that 4 to 31 is an icon block.
Here we set specific things about the icon as described in the
manual. We want the minx and min y to be 0 so these are set, and the
max x and max y to be 68 so these are set. The 16th byte of the icon
block or the 20th byte of the main block is a 32 bit number giving
the icon flags. Each bit is set to 1 (for yes) or 0 (for no). For
example the first bit (icon contains text) we don't want so we set
to 0. For this icon, the flags we want give a 32 bit binary number
remembering that bit 0 is on the right. The number is
10111000000000010000000101010 or &1700202A as it is given in
Hex. The 20th byte in the icon block is basically the string of the
sprite name. This is therefore set accordingly. One the block is set
up, the SWI is called and everybody is happy.
Tutorial 3 - Templates and MenusWindows are quite important
because without them, WIMP would be spelt IMP. Windows are usually
created with Templates although you can go mad and create them all
from scratch from the code. Get a decent Template editor (I
recommend !Templed). Design two windows and call one "info" and the
other "main".
The procedure
"PROCload_tempwins" will look inside the file called "Templates" and
find use lots of SWI's to give each window a handle and a bit of
memory. In this case "main" is given the handle "mainwin%" and
"info" is given the handle "infowin%". Now that we have a window
handle and a number for each icon in each window we can do clever
things with them. More of that later. For the moment we shall look
at creating a menu which appears when you click on the icon with the
middle button. On line 6 of the Skeleton, FNmenu is called. This
actually creates the menu and gives it a pointer for it's memory
area, in this case, menu%. Here we create a menu according to the
requirements by the "Wimp_CreateMenu" SWI. As can be seen, the first
28 bytes of this block gives parameters for the whole menu and then
after that there are separate 24byte blocks for each item in the
menu. Technically you can have as many items as you want, the limit
being the amount of memory you have. Each item in the menu is
treated like an icon with its own set of flags. Menus are therefore
versatile things and can have icons or text, be writable etc. What
we want is a simple two item menu with an "info" and a "quit". In
FNmenu, the title is defined as are the parameters. Note that you
input a single byte with a "?" as opposed to a "!" which inputs 4
bytes into the block. The first item begins at 28. It has a flag of
0 which means none of the item flags are set. The next 4 bytes give
the window "infowin%" which means that the item can be slid across
to open up this window. The flags are the same for icons and the
icon data is basically the name of the item depending on the flags.
The second menu item starts at 52 but this time the item flag is
&80 meaning the 7th bit is set. It is always necessary to do
this to tell the WIMP that this is the last item in the menu.
Because this item is just a 'click' item, the pointer is -1. We
could open other menus by giving these 4 bytes a menu pointer
instead. The final bytes are the same as before. Before we can run
the program, I need to say a few things about polling. You will
notice that after the proper WIMP error handler is stated with a
nice procedure to produce an error box, a procedure called
"PROCwimp_poll" is called. This is a repeat loop with the condition
that it stops if quit%=TRUE. If this happens, the procedure is
finished and PROCquit is called. On every loop, the SWI
"Wimp_PollIdle" is called. This SWI will go and ask the WIMP what is
happening with the program. The WIMP will then send back a message
from 0 to 19 depending on the 19 different possibilities that the
user could be doing. Depending on what the 'event' is, the WIMP will
load a different set of data into the block which was sent to the
call. This needs to be in a repeat loop so that the program is
constantly asking the WIMP what is going on. If nothing is
happening, the WIMP will return 0. In the skeleton, there are
procedures for every important event. Because this is only a
skeleton, most of these are empty. If however, you want your program
to execute a procedure when there is nothing happening, this you put
it in PROCnull. The most important event is number 6, or "mouse
click". In our program, we want it to open up the main window with a
select click and a menu with a menu click. To see how this is done,
look at PROCmouse_button. As can be seen, the information stored in
the block is specific to this event. The block returns the
co-ordinates of the mouse, the button pressed, the window handle of
the window and the icon handle of the icon which was clicked on. In
the skeleton, the code checks to see if the window handle is the
icon bar because that is where our icon is. The procedure called
checks to see which button was pressed. Instead of having to
remember which buttons are which numbers, they were set to variables
back in the variables procedure. Here, if the click is a menu click,
there is a piece of code which creates a menu with the handle
"menu%". Now if you run the program, you can see that clicking on
the middle button on the icon will create the menu.
As can be seen the
info window can be opened by sliding across from the info item.
Tutorial 4 - Playing aboutNow that we have a wonderful
working program, we need it to do something useful. Lets say that
every time you click on the button in the main window, it adds 1 to
the number already in the icon next to it. Firstly we need to open
the window when the select button is clicked on the icon-bar icon.
To do this you go to the "WHEN selclk%" line in the icon_bar_click
procedure. on the next line, use the function
"PROCopen_window(mainwin%)" to open up the main window. I won't
explain how this procedure works but you can take a look if you are
interested. Even if we run the program now, clicking on the icon
will open the window. However, this is not enough for us. We need it
so that 1 is added to the number in the icon when the button in
mainwin is pressed. To do this, we need to put a number into the
icon to start with. To do this, find out the number of the icon. You
can use !Templed to do this or you could guess. the icon number
starts at 0 and because there are only 2 icons (the button is an
icon as well) in my window, they are 0 and 1. Looking in !Templed, I
find that the icon I want to write to is 1. To put the number 15
(for example) into this icon every time this window is opened, you
need to look at the icon bar click again. After opening the window,
you need to put the string "15" into the icon number 1 on mainwin%.
There is a clever procedure called PROCput_icon_text which will do
this for you. Just add the line:
PROCput_icon_text(mainwin%,1,"15")
after you
open the window and everything should work out fine.
Now, we want to add 1
to that number every time the button is clicked. So we go back to
the mouse click event procedure and put in the following lines after
the icon_bar_click procedure is called:
WHEN
mainwin% CASE icon_handle% OF WHEN
0 PROCadd_1_to_number ENDCASE
This will be
called if mainwin% is the window being clicked in (it is). This
checks to see what the icon handle is. If it is 0, the button, then
it will call the procedure. At the bottom of the program you can
write the procedure to add a number to the number already there. The
procedure I used is:
DEF PROCadd_1_to_number LOCAL
num$,num% num$=FNget_icon_text(mainwin%,1) num%=VAL(num$) num%+=1 PROCput_icon_text(mainwin%,1,STR$(num%)) ENDPROC
Quite
simple really...
If you notice, this will add a number
whatever button is pressed. As an exercise (heh), you could get it
to add 1 with the left button, take off 1 with the right button and
if you are feeling adventurous, use the middle button to open a new
menu with options on how to add any number you like.
The
finished program is available zipped here or arc'ed
here.
|