About Me
   Big numbers
   Computer Building
Misc Stuff

WIMP Programming on RiscOS

This 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 1

The 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 - Icons

For 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 Menus

Windows 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 about

Now 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:

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

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%

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.